From 9ac5d838b07832066cb177d93dc3c66b701eeaf4 Mon Sep 17 00:00:00 2001
From: andycall <dongtiangche@outlook.com>
Date: Sat, 17 Sep 2022 21:22:48 +0800
Subject: [PATCH] feat: split out quickjs.c into multiple files

---
 cutils.h => include/quickjs/cutils.h          |     0
 libbf.h => include/quickjs/libbf.h            |     0
 .../quickjs/libregexp-opcode.h                |     0
 libregexp.h => include/quickjs/libregexp.h    |     0
 include/quickjs/libunicode-table.h            |  4368 ++
 libunicode.h => include/quickjs/libunicode.h  |     0
 list.h => include/quickjs/list.h              |     6 +-
 .../quickjs/quickjs-atom.h                    |     0
 .../quickjs/quickjs-opcode.h                  |     0
 quickjs.h => include/quickjs/quickjs.h        |   834 +-
 libunicode-table.h                            |  4449 --
 quickjs.c                                     | 54061 ----------------
 src/core/base.h                               |   119 +
 src/core/builtins/js-array.c                  |  1753 +
 src/core/builtins/js-array.h                  |   100 +
 src/core/builtins/js-async-function.c         |   310 +
 src/core/builtins/js-async-function.h         |    59 +
 src/core/builtins/js-async-generator.c        |   440 +
 src/core/builtins/js-async-generator.h        |   107 +
 src/core/builtins/js-atomics.c                |   527 +
 src/core/builtins/js-atomics.h                |    36 +
 src/core/builtins/js-big-num.c                |  4637 ++
 src/core/builtins/js-big-num.h                |   124 +
 src/core/builtins/js-boolean.c                |    67 +
 src/core/builtins/js-boolean.h                |    36 +
 src/core/builtins/js-closures.c               |   195 +
 src/core/builtins/js-closures.h               |    49 +
 src/core/builtins/js-date.c                   |   970 +
 src/core/builtins/js-date.h                   |    81 +
 src/core/builtins/js-function.c               |   644 +
 src/core/builtins/js-function.h               |   114 +
 src/core/builtins/js-generator.c              |   187 +
 src/core/builtins/js-generator.h              |    66 +
 src/core/builtins/js-json.c                   |   738 +
 src/core/builtins/js-json.h                   |    31 +
 src/core/builtins/js-map.c                    |   811 +
 src/core/builtins/js-map.h                    |    33 +
 src/core/builtins/js-math.c                   |   238 +
 src/core/builtins/js-math.h                   |    54 +
 src/core/builtins/js-number.c                 |   308 +
 src/core/builtins/js-number.h                 |    64 +
 src/core/builtins/js-object.c                 |  1090 +
 src/core/builtins/js-object.h                 |    80 +
 src/core/builtins/js-operator.c               |   813 +
 src/core/builtins/js-operator.h               |    79 +
 src/core/builtins/js-promise.c                |  1321 +
 src/core/builtins/js-promise.h                |    40 +
 src/core/builtins/js-proxy.c                  |   989 +
 src/core/builtins/js-proxy.h                  |    78 +
 src/core/builtins/js-reflect.c                |   176 +
 src/core/builtins/js-reflect.h                |    48 +
 src/core/builtins/js-regexp.c                 |  1491 +
 src/core/builtins/js-regexp.h                 |    36 +
 src/core/builtins/js-string.c                 |  1497 +
 src/core/builtins/js-string.h                 |    91 +
 src/core/builtins/js-symbol.c                 |   127 +
 src/core/builtins/js-symbol.h                 |    44 +
 src/core/builtins/js-typed-array.c            |  2269 +
 src/core/builtins/js-typed-array.h            |    40 +
 src/core/bytecode.c                           |  2093 +
 src/core/bytecode.h                           |    38 +
 src/core/convertion.c                         |  1674 +
 src/core/convertion.h                         |   168 +
 src/core/exception.c                          |   257 +
 src/core/exception.h                          |    78 +
 src/core/function.c                           |  2879 +
 src/core/function.h                           |   153 +
 src/core/gc.c                                 |   806 +
 src/core/gc.h                                 |   120 +
 src/core/malloc.c                             |   242 +
 src/core/malloc.h                             |    59 +
 src/core/memory.c                             |   529 +
 src/core/memory.h                             |    32 +
 src/core/module.c                             |  1298 +
 src/core/module.h                             |    85 +
 src/core/object.c                             |  2217 +
 src/core/object.h                             |   170 +
 src/core/parser.c                             | 12208 ++++
 src/core/parser.h                             |   424 +
 src/core/runtime.c                            |  3059 +
 src/core/runtime.h                            |   251 +
 src/core/shape.c                              |   587 +
 src/core/shape.h                              |    91 +
 src/core/string.c                             |  1631 +
 src/core/string.h                             |   263 +
 src/core/types.h                              |   946 +
 cutils.c => src/cutils.c                      |     2 +-
 libbf.c => src/libbf.c                        |    25 +-
 libregexp.c => src/libregexp.c                |     8 +-
 libunicode.c => src/libunicode.c              |     6 +-
 test262.conf                                  |    10 -
 unicode_download.sh                           |    10 +-
 unicode_gen_def.h                             |     5 -
 93 files changed, 60325 insertions(+), 59024 deletions(-)
 rename cutils.h => include/quickjs/cutils.h (100%)
 rename libbf.h => include/quickjs/libbf.h (100%)
 rename libregexp-opcode.h => include/quickjs/libregexp-opcode.h (100%)
 rename libregexp.h => include/quickjs/libregexp.h (100%)
 create mode 100644 include/quickjs/libunicode-table.h
 rename libunicode.h => include/quickjs/libunicode.h (100%)
 rename list.h => include/quickjs/list.h (97%)
 rename quickjs-atom.h => include/quickjs/quickjs-atom.h (100%)
 rename quickjs-opcode.h => include/quickjs/quickjs-opcode.h (100%)
 rename quickjs.h => include/quickjs/quickjs.h (53%)
 delete mode 100644 libunicode-table.h
 delete mode 100644 quickjs.c
 create mode 100644 src/core/base.h
 create mode 100644 src/core/builtins/js-array.c
 create mode 100644 src/core/builtins/js-array.h
 create mode 100644 src/core/builtins/js-async-function.c
 create mode 100644 src/core/builtins/js-async-function.h
 create mode 100644 src/core/builtins/js-async-generator.c
 create mode 100644 src/core/builtins/js-async-generator.h
 create mode 100644 src/core/builtins/js-atomics.c
 create mode 100644 src/core/builtins/js-atomics.h
 create mode 100644 src/core/builtins/js-big-num.c
 create mode 100644 src/core/builtins/js-big-num.h
 create mode 100644 src/core/builtins/js-boolean.c
 create mode 100644 src/core/builtins/js-boolean.h
 create mode 100644 src/core/builtins/js-closures.c
 create mode 100644 src/core/builtins/js-closures.h
 create mode 100644 src/core/builtins/js-date.c
 create mode 100644 src/core/builtins/js-date.h
 create mode 100644 src/core/builtins/js-function.c
 create mode 100644 src/core/builtins/js-function.h
 create mode 100644 src/core/builtins/js-generator.c
 create mode 100644 src/core/builtins/js-generator.h
 create mode 100644 src/core/builtins/js-json.c
 create mode 100644 src/core/builtins/js-json.h
 create mode 100644 src/core/builtins/js-map.c
 create mode 100644 src/core/builtins/js-map.h
 create mode 100644 src/core/builtins/js-math.c
 create mode 100644 src/core/builtins/js-math.h
 create mode 100644 src/core/builtins/js-number.c
 create mode 100644 src/core/builtins/js-number.h
 create mode 100644 src/core/builtins/js-object.c
 create mode 100644 src/core/builtins/js-object.h
 create mode 100644 src/core/builtins/js-operator.c
 create mode 100644 src/core/builtins/js-operator.h
 create mode 100644 src/core/builtins/js-promise.c
 create mode 100644 src/core/builtins/js-promise.h
 create mode 100644 src/core/builtins/js-proxy.c
 create mode 100644 src/core/builtins/js-proxy.h
 create mode 100644 src/core/builtins/js-reflect.c
 create mode 100644 src/core/builtins/js-reflect.h
 create mode 100644 src/core/builtins/js-regexp.c
 create mode 100644 src/core/builtins/js-regexp.h
 create mode 100644 src/core/builtins/js-string.c
 create mode 100644 src/core/builtins/js-string.h
 create mode 100644 src/core/builtins/js-symbol.c
 create mode 100644 src/core/builtins/js-symbol.h
 create mode 100644 src/core/builtins/js-typed-array.c
 create mode 100644 src/core/builtins/js-typed-array.h
 create mode 100644 src/core/bytecode.c
 create mode 100644 src/core/bytecode.h
 create mode 100644 src/core/convertion.c
 create mode 100644 src/core/convertion.h
 create mode 100644 src/core/exception.c
 create mode 100644 src/core/exception.h
 create mode 100644 src/core/function.c
 create mode 100644 src/core/function.h
 create mode 100644 src/core/gc.c
 create mode 100644 src/core/gc.h
 create mode 100644 src/core/malloc.c
 create mode 100644 src/core/malloc.h
 create mode 100644 src/core/memory.c
 create mode 100644 src/core/memory.h
 create mode 100644 src/core/module.c
 create mode 100644 src/core/module.h
 create mode 100644 src/core/object.c
 create mode 100644 src/core/object.h
 create mode 100644 src/core/parser.c
 create mode 100644 src/core/parser.h
 create mode 100644 src/core/runtime.c
 create mode 100644 src/core/runtime.h
 create mode 100644 src/core/shape.c
 create mode 100644 src/core/shape.h
 create mode 100644 src/core/string.c
 create mode 100644 src/core/string.h
 create mode 100644 src/core/types.h
 rename cutils.c => src/cutils.c (99%)
 rename libbf.c => src/libbf.c (99%)
 rename libregexp.c => src/libregexp.c (99%)
 rename libunicode.c => src/libunicode.c (99%)

diff --git a/cutils.h b/include/quickjs/cutils.h
similarity index 100%
rename from cutils.h
rename to include/quickjs/cutils.h
diff --git a/libbf.h b/include/quickjs/libbf.h
similarity index 100%
rename from libbf.h
rename to include/quickjs/libbf.h
diff --git a/libregexp-opcode.h b/include/quickjs/libregexp-opcode.h
similarity index 100%
rename from libregexp-opcode.h
rename to include/quickjs/libregexp-opcode.h
diff --git a/libregexp.h b/include/quickjs/libregexp.h
similarity index 100%
rename from libregexp.h
rename to include/quickjs/libregexp.h
diff --git a/include/quickjs/libunicode-table.h b/include/quickjs/libunicode-table.h
new file mode 100644
index 000000000..0ef211356
--- /dev/null
+++ b/include/quickjs/libunicode-table.h
@@ -0,0 +1,4368 @@
+/* Compressed unicode tables */
+/* Automatically generated file - do not edit */
+
+#include <stdint.h>
+
+static const uint32_t case_conv_table1[361] = {
+    0x00209a30, 0x00309a00, 0x005a8173, 0x00601730,
+    0x006c0730, 0x006f81b3, 0x00701700, 0x007c0700,
+    0x007f8100, 0x00803040, 0x009801c3, 0x00988190,
+    0x00990640, 0x009c9040, 0x00a481b4, 0x00a52e40,
+    0x00bc0130, 0x00bc8640, 0x00bf8170, 0x00c00100,
+    0x00c08130, 0x00c10440, 0x00c30130, 0x00c38240,
+    0x00c48230, 0x00c58240, 0x00c70130, 0x00c78130,
+    0x00c80130, 0x00c88240, 0x00c98130, 0x00ca0130,
+    0x00ca8100, 0x00cb0130, 0x00cb8130, 0x00cc0240,
+    0x00cd0100, 0x00ce0130, 0x00ce8130, 0x00cf0100,
+    0x00cf8130, 0x00d00640, 0x00d30130, 0x00d38240,
+    0x00d48130, 0x00d60240, 0x00d70130, 0x00d78240,
+    0x00d88230, 0x00d98440, 0x00db8130, 0x00dc0240,
+    0x00de0240, 0x00df8100, 0x00e20350, 0x00e38350,
+    0x00e50350, 0x00e69040, 0x00ee8100, 0x00ef1240,
+    0x00f801b4, 0x00f88350, 0x00fa0240, 0x00fb0130,
+    0x00fb8130, 0x00fc2840, 0x01100130, 0x01111240,
+    0x011d0131, 0x011d8240, 0x011e8130, 0x011f0131,
+    0x011f8201, 0x01208240, 0x01218130, 0x01220130,
+    0x01228130, 0x01230a40, 0x01280101, 0x01288101,
+    0x01290101, 0x01298100, 0x012a0100, 0x012b0200,
+    0x012c8100, 0x012d8100, 0x012e0101, 0x01300100,
+    0x01308101, 0x01318100, 0x01328101, 0x01330101,
+    0x01340100, 0x01348100, 0x01350101, 0x01358101,
+    0x01360101, 0x01378100, 0x01388101, 0x01390100,
+    0x013a8100, 0x013e8101, 0x01400100, 0x01410101,
+    0x01418100, 0x01438101, 0x01440100, 0x01448100,
+    0x01450200, 0x01460100, 0x01490100, 0x014e8101,
+    0x014f0101, 0x01a28173, 0x01b80440, 0x01bb0240,
+    0x01bd8300, 0x01bf8130, 0x01c30130, 0x01c40330,
+    0x01c60130, 0x01c70230, 0x01c801d0, 0x01c89130,
+    0x01d18930, 0x01d60100, 0x01d68300, 0x01d801d3,
+    0x01d89100, 0x01e10173, 0x01e18900, 0x01e60100,
+    0x01e68200, 0x01e78130, 0x01e80173, 0x01e88173,
+    0x01ea8173, 0x01eb0173, 0x01eb8100, 0x01ec1840,
+    0x01f80173, 0x01f88173, 0x01f90100, 0x01f98100,
+    0x01fa01a0, 0x01fa8173, 0x01fb8240, 0x01fc8130,
+    0x01fd0240, 0x01fe8330, 0x02001030, 0x02082030,
+    0x02182000, 0x02281000, 0x02302240, 0x02453640,
+    0x02600130, 0x02608e40, 0x02678100, 0x02686040,
+    0x0298a630, 0x02b0a600, 0x02c381b5, 0x08502631,
+    0x08638131, 0x08668131, 0x08682b00, 0x087e8300,
+    0x09d05011, 0x09f80610, 0x09fc0620, 0x0e400174,
+    0x0e408174, 0x0e410174, 0x0e418174, 0x0e420174,
+    0x0e428174, 0x0e430174, 0x0e438180, 0x0e440180,
+    0x0e482b30, 0x0e5e8330, 0x0ebc8101, 0x0ebe8101,
+    0x0ec70101, 0x0f007e40, 0x0f3f1840, 0x0f4b01b5,
+    0x0f4b81b6, 0x0f4c01b6, 0x0f4c81b6, 0x0f4d01b7,
+    0x0f4d8180, 0x0f4f0130, 0x0f506040, 0x0f800800,
+    0x0f840830, 0x0f880600, 0x0f8c0630, 0x0f900800,
+    0x0f940830, 0x0f980800, 0x0f9c0830, 0x0fa00600,
+    0x0fa40630, 0x0fa801b0, 0x0fa88100, 0x0fa901d3,
+    0x0fa98100, 0x0faa01d3, 0x0faa8100, 0x0fab01d3,
+    0x0fab8100, 0x0fac8130, 0x0fad8130, 0x0fae8130,
+    0x0faf8130, 0x0fb00800, 0x0fb40830, 0x0fb80200,
+    0x0fb90400, 0x0fbb0200, 0x0fbc0201, 0x0fbd0201,
+    0x0fbe0201, 0x0fc008b7, 0x0fc40867, 0x0fc808b8,
+    0x0fcc0868, 0x0fd008b8, 0x0fd40868, 0x0fd80200,
+    0x0fd901b9, 0x0fd981b1, 0x0fda01b9, 0x0fdb01b1,
+    0x0fdb81d7, 0x0fdc0230, 0x0fdd0230, 0x0fde0161,
+    0x0fdf0173, 0x0fe101b9, 0x0fe181b2, 0x0fe201ba,
+    0x0fe301b2, 0x0fe381d8, 0x0fe40430, 0x0fe60162,
+    0x0fe80200, 0x0fe901d0, 0x0fe981d0, 0x0feb01b0,
+    0x0feb81d0, 0x0fec0230, 0x0fed0230, 0x0ff00201,
+    0x0ff101d3, 0x0ff181d3, 0x0ff201ba, 0x0ff28101,
+    0x0ff301b0, 0x0ff381d3, 0x0ff40230, 0x0ff50230,
+    0x0ff60131, 0x0ff901ba, 0x0ff981b2, 0x0ffa01bb,
+    0x0ffb01b2, 0x0ffb81d9, 0x0ffc0230, 0x0ffd0230,
+    0x0ffe0162, 0x109301a0, 0x109501a0, 0x109581a0,
+    0x10990131, 0x10a70101, 0x10b01031, 0x10b81001,
+    0x10c18240, 0x125b1a31, 0x12681a01, 0x16002f31,
+    0x16182f01, 0x16300240, 0x16310130, 0x16318130,
+    0x16320130, 0x16328100, 0x16330100, 0x16338640,
+    0x16368130, 0x16370130, 0x16378130, 0x16380130,
+    0x16390240, 0x163a8240, 0x163f0230, 0x16406440,
+    0x16758440, 0x16790240, 0x16802600, 0x16938100,
+    0x16968100, 0x53202e40, 0x53401c40, 0x53910e40,
+    0x53993e40, 0x53bc8440, 0x53be8130, 0x53bf0a40,
+    0x53c58240, 0x53c68130, 0x53c80440, 0x53ca0101,
+    0x53cb1440, 0x53d50130, 0x53d58130, 0x53d60130,
+    0x53d68130, 0x53d70130, 0x53d80130, 0x53d88130,
+    0x53d90130, 0x53d98131, 0x53da0c40, 0x53e10240,
+    0x53e20131, 0x53e28130, 0x53e30130, 0x53e38440,
+    0x53fa8240, 0x55a98101, 0x55b85020, 0x7d8001b2,
+    0x7d8081b2, 0x7d8101b2, 0x7d8181da, 0x7d8201da,
+    0x7d8281b3, 0x7d8301b3, 0x7d8981bb, 0x7d8a01bb,
+    0x7d8a81bb, 0x7d8b01bc, 0x7d8b81bb, 0x7f909a31,
+    0x7fa09a01, 0x82002831, 0x82142801, 0x82582431,
+    0x826c2401, 0x86403331, 0x86603301, 0x8c502031,
+    0x8c602001, 0xb7202031, 0xb7302001, 0xf4802231,
+    0xf4912201,
+};
+
+static const uint8_t case_conv_table2[361] = {
+    0x01, 0x00, 0x9c, 0x06, 0x07, 0x4d, 0x03, 0x04,
+    0x10, 0x00, 0x8f, 0x0b, 0x00, 0x00, 0x11, 0x00,
+    0x08, 0x00, 0x53, 0x4a, 0x51, 0x00, 0x52, 0x00,
+    0x53, 0x00, 0x3a, 0x54, 0x55, 0x00, 0x57, 0x59,
+    0x3f, 0x5d, 0x5c, 0x00, 0x46, 0x61, 0x63, 0x42,
+    0x64, 0x00, 0x66, 0x00, 0x68, 0x00, 0x6a, 0x00,
+    0x6c, 0x00, 0x6e, 0x00, 0x00, 0x40, 0x00, 0x00,
+    0x00, 0x00, 0x1a, 0x00, 0x93, 0x00, 0x00, 0x20,
+    0x35, 0x00, 0x27, 0x00, 0x21, 0x00, 0x24, 0x22,
+    0x2a, 0x00, 0x13, 0x6b, 0x6d, 0x00, 0x26, 0x24,
+    0x27, 0x14, 0x16, 0x18, 0x1b, 0x1c, 0x3e, 0x1e,
+    0x3f, 0x1f, 0x39, 0x3d, 0x22, 0x21, 0x41, 0x1e,
+    0x40, 0x25, 0x25, 0x26, 0x28, 0x20, 0x2a, 0x49,
+    0x2c, 0x43, 0x2e, 0x4b, 0x30, 0x4c, 0x32, 0x44,
+    0x42, 0x99, 0x00, 0x00, 0x95, 0x8f, 0x7d, 0x7e,
+    0x83, 0x84, 0x12, 0x80, 0x82, 0x76, 0x77, 0x12,
+    0x7b, 0xa3, 0x7c, 0x78, 0x79, 0x8a, 0x92, 0x98,
+    0xa6, 0xa0, 0x85, 0x00, 0x9a, 0xa1, 0x93, 0x75,
+    0x33, 0x95, 0x00, 0x8e, 0x00, 0x74, 0x99, 0x98,
+    0x97, 0x96, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00,
+    0xa1, 0xa0, 0x15, 0x2e, 0x2f, 0x30, 0xb4, 0xb5,
+    0x4e, 0xaa, 0xa9, 0x12, 0x14, 0x1e, 0x21, 0x22,
+    0x22, 0x2a, 0x34, 0x35, 0xa6, 0xa7, 0x36, 0x1f,
+    0x4a, 0x00, 0x00, 0x97, 0x01, 0x5a, 0xda, 0x1d,
+    0x36, 0x05, 0x00, 0xc4, 0xc3, 0xc6, 0xc5, 0xc8,
+    0xc7, 0xca, 0xc9, 0xcc, 0xcb, 0xc4, 0xd5, 0x45,
+    0xd6, 0x42, 0xd7, 0x46, 0xd8, 0xce, 0xd0, 0xd2,
+    0xd4, 0xda, 0xd9, 0xee, 0xf6, 0xfe, 0x0e, 0x07,
+    0x0f, 0x80, 0x9f, 0x00, 0x21, 0x80, 0xa3, 0xed,
+    0x00, 0xc0, 0x40, 0xc6, 0x60, 0xe7, 0xdb, 0xe6,
+    0x99, 0xc0, 0x00, 0x00, 0x06, 0x60, 0xdc, 0x29,
+    0xfd, 0x15, 0x12, 0x06, 0x16, 0xf8, 0xdd, 0x06,
+    0x15, 0x12, 0x84, 0x08, 0xc6, 0x16, 0xff, 0xdf,
+    0x03, 0xc0, 0x40, 0x00, 0x46, 0x60, 0xde, 0xe0,
+    0x6d, 0x37, 0x38, 0x39, 0x15, 0x14, 0x17, 0x16,
+    0x00, 0x1a, 0x19, 0x1c, 0x1b, 0x00, 0x5f, 0xb7,
+    0x65, 0x44, 0x47, 0x00, 0x4f, 0x62, 0x4e, 0x50,
+    0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xa3, 0xa4,
+    0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x00,
+    0x00, 0x5a, 0x00, 0x48, 0x00, 0x5b, 0x56, 0x58,
+    0x60, 0x5e, 0x70, 0x69, 0x6f, 0x4d, 0x00, 0x00,
+    0x3b, 0x67, 0xb8, 0x00, 0x00, 0x45, 0xa8, 0x8a,
+    0x8b, 0x8c, 0xab, 0xac, 0x58, 0x58, 0xaf, 0x94,
+    0xb0, 0x6f, 0xb2, 0x5c, 0x5b, 0x5e, 0x5d, 0x60,
+    0x5f, 0x62, 0x61, 0x64, 0x63, 0x66, 0x65, 0x68,
+    0x67,
+};
+
+static const uint16_t case_conv_ext[58] = {
+    0x0399, 0x0308, 0x0301, 0x03a5, 0x0313, 0x0300, 0x0342, 0x0391,
+    0x0397, 0x03a9, 0x0046, 0x0049, 0x004c, 0x0053, 0x0069, 0x0307,
+    0x02bc, 0x004e, 0x004a, 0x030c, 0x0535, 0x0552, 0x0048, 0x0331,
+    0x0054, 0x0057, 0x030a, 0x0059, 0x0041, 0x02be, 0x1f08, 0x1f80,
+    0x1f28, 0x1f90, 0x1f68, 0x1fa0, 0x1fba, 0x0386, 0x1fb3, 0x1fca,
+    0x0389, 0x1fc3, 0x03a1, 0x1ffa, 0x038f, 0x1ff3, 0x0544, 0x0546,
+    0x053b, 0x054e, 0x053d, 0x03b8, 0x0462, 0xa64a, 0x1e60, 0x03c9,
+    0x006b, 0x00e5,
+};
+
+static const uint8_t unicode_prop_Cased1_table[172] = {
+    0x40, 0xa9, 0x80, 0x8e, 0x80, 0xfc, 0x80, 0xd3,
+    0x80, 0x8c, 0x80, 0x8d, 0x81, 0x8d, 0x02, 0x80,
+    0xe1, 0x80, 0x91, 0x85, 0x9a, 0x01, 0x00, 0x01,
+    0x11, 0x00, 0x01, 0x04, 0x08, 0x01, 0x08, 0x30,
+    0x08, 0x01, 0x15, 0x20, 0x00, 0x39, 0x99, 0x31,
+    0x9d, 0x84, 0x40, 0x94, 0x80, 0xd6, 0x82, 0xa6,
+    0x80, 0x41, 0x62, 0x80, 0xa6, 0x80, 0x57, 0x76,
+    0xf8, 0x02, 0x80, 0x8f, 0x80, 0xb0, 0x40, 0xdb,
+    0x08, 0x80, 0x41, 0xd0, 0x80, 0x8c, 0x80, 0x8f,
+    0x8c, 0xe4, 0x03, 0x01, 0x89, 0x00, 0x14, 0x28,
+    0x10, 0x11, 0x02, 0x01, 0x18, 0x0b, 0x24, 0x4b,
+    0x26, 0x01, 0x01, 0x86, 0xe5, 0x80, 0x60, 0x79,
+    0xb6, 0x81, 0x40, 0x91, 0x81, 0xbd, 0x88, 0x94,
+    0x05, 0x80, 0x98, 0x80, 0xc7, 0x82, 0x43, 0x34,
+    0xa2, 0x06, 0x80, 0x8c, 0x61, 0x28, 0x96, 0xd4,
+    0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b, 0x80, 0x8b,
+    0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f, 0x06, 0x80,
+    0x9b, 0x03, 0x04, 0x00, 0x16, 0x80, 0x41, 0x53,
+    0x81, 0x98, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98,
+    0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98,
+    0x80, 0x9e, 0x80, 0x98, 0x07, 0x59, 0x63, 0x99,
+    0x85, 0x99, 0x85, 0x99,
+};
+
+static const uint8_t unicode_prop_Cased1_index[18] = {
+    0xb9, 0x02, 0xe0, 0xa0, 0x1e, 0x40, 0x9e, 0xa6,
+    0x40, 0xba, 0xd4, 0x01, 0x89, 0xd7, 0x01, 0x8a,
+    0xf1, 0x01,
+};
+
+static const uint8_t unicode_prop_Case_Ignorable_table[692] = {
+    0xa6, 0x05, 0x80, 0x8a, 0x80, 0xa2, 0x00, 0x80,
+    0xc6, 0x03, 0x00, 0x03, 0x01, 0x81, 0x41, 0xf6,
+    0x40, 0xbf, 0x19, 0x18, 0x88, 0x08, 0x80, 0x40,
+    0xfa, 0x86, 0x40, 0xce, 0x04, 0x80, 0xb0, 0xac,
+    0x00, 0x01, 0x01, 0x00, 0xab, 0x80, 0x8a, 0x85,
+    0x89, 0x8a, 0x00, 0xa2, 0x80, 0x89, 0x94, 0x8f,
+    0x80, 0xe4, 0x38, 0x89, 0x03, 0xa0, 0x00, 0x80,
+    0x9d, 0x9a, 0xda, 0x8a, 0xb9, 0x8a, 0x18, 0x08,
+    0x97, 0x97, 0xaa, 0x82, 0xf6, 0xaf, 0xb6, 0x00,
+    0x03, 0x3b, 0x02, 0x86, 0x89, 0x81, 0x8c, 0x80,
+    0x8e, 0x80, 0xb9, 0x03, 0x1f, 0x80, 0x93, 0x81,
+    0x99, 0x01, 0x81, 0xb8, 0x03, 0x0b, 0x09, 0x12,
+    0x80, 0x9d, 0x0a, 0x80, 0x8a, 0x81, 0xb8, 0x03,
+    0x20, 0x0b, 0x80, 0x93, 0x81, 0x95, 0x28, 0x80,
+    0xb9, 0x01, 0x00, 0x1f, 0x06, 0x81, 0x8a, 0x81,
+    0x9d, 0x80, 0xbc, 0x80, 0x8b, 0x80, 0xb1, 0x02,
+    0x80, 0xb8, 0x14, 0x10, 0x1e, 0x81, 0x8a, 0x81,
+    0x9c, 0x80, 0xb9, 0x01, 0x05, 0x04, 0x81, 0x93,
+    0x81, 0x9b, 0x81, 0xb8, 0x0b, 0x1f, 0x80, 0x93,
+    0x81, 0x9c, 0x80, 0xc7, 0x06, 0x10, 0x80, 0xd9,
+    0x01, 0x86, 0x8a, 0x88, 0xe1, 0x01, 0x88, 0x88,
+    0x00, 0x85, 0xc9, 0x81, 0x9a, 0x00, 0x00, 0x80,
+    0xb6, 0x8d, 0x04, 0x01, 0x84, 0x8a, 0x80, 0xa3,
+    0x88, 0x80, 0xe5, 0x18, 0x28, 0x09, 0x81, 0x98,
+    0x0b, 0x82, 0x8f, 0x83, 0x8c, 0x01, 0x0d, 0x80,
+    0x8e, 0x80, 0xdd, 0x80, 0x42, 0x5f, 0x82, 0x43,
+    0xb1, 0x82, 0x9c, 0x82, 0x9c, 0x81, 0x9d, 0x81,
+    0xbf, 0x08, 0x37, 0x01, 0x8a, 0x10, 0x20, 0xac,
+    0x83, 0xb3, 0x80, 0xc0, 0x81, 0xa1, 0x80, 0xf5,
+    0x13, 0x81, 0x88, 0x05, 0x82, 0x40, 0xda, 0x09,
+    0x80, 0xb9, 0x00, 0x30, 0x00, 0x01, 0x3d, 0x89,
+    0x08, 0xa6, 0x07, 0x90, 0xbe, 0x83, 0xaf, 0x00,
+    0x20, 0x04, 0x80, 0xa7, 0x88, 0x8b, 0x81, 0x9f,
+    0x19, 0x08, 0x82, 0xb7, 0x00, 0x0a, 0x00, 0x82,
+    0xb9, 0x39, 0x81, 0xbf, 0x85, 0xd1, 0x10, 0x8c,
+    0x06, 0x18, 0x28, 0x11, 0xb1, 0xbe, 0x8c, 0x80,
+    0xa1, 0xde, 0x04, 0x41, 0xbc, 0x00, 0x82, 0x8a,
+    0x82, 0x8c, 0x82, 0x8c, 0x82, 0x8c, 0x81, 0x8b,
+    0x27, 0x81, 0x89, 0x01, 0x01, 0x84, 0xb0, 0x20,
+    0x89, 0x00, 0x8c, 0x80, 0x8f, 0x8c, 0xb2, 0xa0,
+    0x4b, 0x8a, 0x81, 0xf0, 0x82, 0xfc, 0x80, 0x8e,
+    0x80, 0xdf, 0x9f, 0xae, 0x80, 0x41, 0xd4, 0x80,
+    0xa3, 0x1a, 0x24, 0x80, 0xdc, 0x85, 0xdc, 0x82,
+    0x60, 0x6f, 0x15, 0x80, 0x44, 0xe1, 0x85, 0x41,
+    0x0d, 0x80, 0xe1, 0x18, 0x89, 0x00, 0x9b, 0x83,
+    0xcf, 0x81, 0x8d, 0xa1, 0xcd, 0x80, 0x96, 0x82,
+    0xec, 0x0f, 0x02, 0x03, 0x80, 0x98, 0x0c, 0x80,
+    0x40, 0x96, 0x81, 0x99, 0x91, 0x8c, 0x80, 0xa5,
+    0x87, 0x98, 0x8a, 0xad, 0x82, 0xaf, 0x01, 0x19,
+    0x81, 0x90, 0x80, 0x94, 0x81, 0xc1, 0x29, 0x09,
+    0x81, 0x8b, 0x07, 0x80, 0xa2, 0x80, 0x8a, 0x80,
+    0xb2, 0x00, 0x11, 0x0c, 0x08, 0x80, 0x9a, 0x80,
+    0x8d, 0x0c, 0x08, 0x80, 0xe3, 0x84, 0x88, 0x82,
+    0xf8, 0x01, 0x03, 0x80, 0x60, 0x4f, 0x2f, 0x80,
+    0x40, 0x92, 0x8f, 0x42, 0x3d, 0x8f, 0x10, 0x8b,
+    0x8f, 0xa1, 0x01, 0x80, 0x40, 0xa8, 0x06, 0x05,
+    0x80, 0x8a, 0x80, 0xa2, 0x00, 0x80, 0xae, 0x80,
+    0xac, 0x81, 0xc2, 0x80, 0x94, 0x82, 0x42, 0x00,
+    0x80, 0x40, 0xe1, 0x80, 0x40, 0x94, 0x84, 0x46,
+    0x85, 0x10, 0x0c, 0x83, 0xa7, 0x13, 0x80, 0x40,
+    0xa4, 0x81, 0x42, 0x3c, 0x83, 0x41, 0x82, 0x81,
+    0x40, 0x98, 0x8a, 0x40, 0xaf, 0x80, 0xb5, 0x8e,
+    0xb7, 0x82, 0xb0, 0x19, 0x09, 0x80, 0x8e, 0x80,
+    0xb1, 0x82, 0xa3, 0x20, 0x87, 0xbd, 0x80, 0x8b,
+    0x81, 0xb3, 0x88, 0x89, 0x19, 0x80, 0xde, 0x11,
+    0x00, 0x0d, 0x80, 0x40, 0x9f, 0x02, 0x87, 0x94,
+    0x81, 0xb8, 0x0a, 0x80, 0xa4, 0x32, 0x84, 0x40,
+    0xc2, 0x39, 0x10, 0x80, 0x96, 0x80, 0xd3, 0x28,
+    0x03, 0x08, 0x81, 0x40, 0xed, 0x1d, 0x08, 0x81,
+    0x9a, 0x81, 0xd4, 0x39, 0x00, 0x81, 0xe9, 0x00,
+    0x01, 0x28, 0x80, 0xe4, 0x11, 0x18, 0x84, 0x41,
+    0x02, 0x88, 0x01, 0x40, 0xff, 0x08, 0x03, 0x80,
+    0x40, 0x8f, 0x19, 0x0b, 0x80, 0x9f, 0x89, 0xa7,
+    0x29, 0x1f, 0x80, 0x88, 0x29, 0x82, 0xad, 0x8c,
+    0x01, 0x41, 0x95, 0x30, 0x28, 0x80, 0xd1, 0x95,
+    0x0e, 0x01, 0x01, 0xf9, 0x2a, 0x00, 0x08, 0x30,
+    0x80, 0xc7, 0x0a, 0x00, 0x80, 0x41, 0x5a, 0x81,
+    0x55, 0x3a, 0x88, 0x60, 0x36, 0xb6, 0x84, 0xba,
+    0x86, 0x88, 0x83, 0x44, 0x0a, 0x80, 0xbe, 0x90,
+    0xbf, 0x08, 0x81, 0x60, 0x4c, 0xb7, 0x08, 0x83,
+    0x54, 0xc2, 0x82, 0x88, 0x8f, 0x0e, 0x9d, 0x83,
+    0x40, 0x93, 0x82, 0x47, 0xba, 0xb6, 0x83, 0xb1,
+    0x38, 0x8d, 0x80, 0x95, 0x20, 0x8e, 0x45, 0x4f,
+    0x30, 0x90, 0x0e, 0x01, 0x04, 0x41, 0x04, 0x8d,
+    0x41, 0xad, 0x83, 0x45, 0xdf, 0x86, 0xec, 0x87,
+    0x4a, 0xae, 0x84, 0x6c, 0x0c, 0x00, 0x80, 0x9d,
+    0xdf, 0xff, 0x40, 0xef,
+};
+
+static const uint8_t unicode_prop_Case_Ignorable_index[66] = {
+    0xbe, 0x05, 0x00, 0xfe, 0x07, 0x00, 0x52, 0x0a,
+    0x20, 0x05, 0x0c, 0x20, 0x3b, 0x0e, 0x40, 0x61,
+    0x10, 0x40, 0x0f, 0x18, 0x20, 0x43, 0x1b, 0x60,
+    0x79, 0x1d, 0x00, 0xf1, 0x20, 0x00, 0x0d, 0xa6,
+    0x40, 0x2e, 0xa9, 0x20, 0xde, 0xaa, 0x00, 0x0f,
+    0xff, 0x20, 0xe7, 0x0a, 0x41, 0x82, 0x11, 0x21,
+    0xc4, 0x14, 0x61, 0x44, 0x19, 0x01, 0x48, 0x1d,
+    0x21, 0xa4, 0xbc, 0x01, 0x3e, 0xe1, 0x01, 0xf0,
+    0x01, 0x0e,
+};
+
+static const uint8_t unicode_prop_ID_Start_table[1045] = {
+    0xc0, 0x99, 0x85, 0x99, 0xae, 0x80, 0x89, 0x03,
+    0x04, 0x96, 0x80, 0x9e, 0x80, 0x41, 0xc9, 0x83,
+    0x8b, 0x8d, 0x26, 0x00, 0x80, 0x40, 0x80, 0x20,
+    0x09, 0x18, 0x05, 0x00, 0x10, 0x00, 0x93, 0x80,
+    0xd2, 0x80, 0x40, 0x8a, 0x87, 0x40, 0xa5, 0x80,
+    0xa5, 0x08, 0x85, 0xa8, 0xc6, 0x9a, 0x1b, 0xac,
+    0xaa, 0xa2, 0x08, 0xe2, 0x00, 0x8e, 0x0e, 0x81,
+    0x89, 0x11, 0x80, 0x8f, 0x00, 0x9d, 0x9c, 0xd8,
+    0x8a, 0x80, 0x97, 0xa0, 0x88, 0x0b, 0x04, 0x95,
+    0x18, 0x88, 0x02, 0x80, 0x96, 0x98, 0x86, 0x8a,
+    0xb4, 0x94, 0x80, 0x91, 0xbb, 0xb5, 0x10, 0x91,
+    0x06, 0x89, 0x8e, 0x8f, 0x1f, 0x09, 0x81, 0x95,
+    0x06, 0x00, 0x13, 0x10, 0x8f, 0x80, 0x8c, 0x08,
+    0x82, 0x8d, 0x81, 0x89, 0x07, 0x2b, 0x09, 0x95,
+    0x06, 0x01, 0x01, 0x01, 0x9e, 0x18, 0x80, 0x92,
+    0x82, 0x8f, 0x88, 0x02, 0x80, 0x95, 0x06, 0x01,
+    0x04, 0x10, 0x91, 0x80, 0x8e, 0x81, 0x96, 0x80,
+    0x8a, 0x39, 0x09, 0x95, 0x06, 0x01, 0x04, 0x10,
+    0x9d, 0x08, 0x82, 0x8e, 0x80, 0x90, 0x00, 0x2a,
+    0x10, 0x1a, 0x08, 0x00, 0x0a, 0x0a, 0x12, 0x8b,
+    0x95, 0x80, 0xb3, 0x38, 0x10, 0x96, 0x80, 0x8f,
+    0x10, 0x99, 0x14, 0x81, 0x9d, 0x03, 0x38, 0x10,
+    0x96, 0x80, 0x89, 0x04, 0x10, 0x9f, 0x00, 0x81,
+    0x8e, 0x81, 0x90, 0x88, 0x02, 0x80, 0xa8, 0x08,
+    0x8f, 0x04, 0x17, 0x82, 0x97, 0x2c, 0x91, 0x82,
+    0x97, 0x80, 0x88, 0x00, 0x0e, 0xb9, 0xaf, 0x01,
+    0x8b, 0x86, 0xb9, 0x08, 0x00, 0x20, 0x97, 0x00,
+    0x80, 0x89, 0x01, 0x88, 0x01, 0x20, 0x80, 0x94,
+    0x83, 0x9f, 0x80, 0xbe, 0x38, 0xa3, 0x9a, 0x84,
+    0xf2, 0xaa, 0x93, 0x80, 0x8f, 0x2b, 0x1a, 0x02,
+    0x0e, 0x13, 0x8c, 0x8b, 0x80, 0x90, 0xa5, 0x00,
+    0x20, 0x81, 0xaa, 0x80, 0x41, 0x4c, 0x03, 0x0e,
+    0x00, 0x03, 0x81, 0xa8, 0x03, 0x81, 0xa0, 0x03,
+    0x0e, 0x00, 0x03, 0x81, 0x8e, 0x80, 0xb8, 0x03,
+    0x81, 0xc2, 0xa4, 0x8f, 0x8f, 0xd5, 0x0d, 0x82,
+    0x42, 0x6b, 0x81, 0x90, 0x80, 0x99, 0x84, 0xca,
+    0x82, 0x8a, 0x86, 0x8c, 0x03, 0x8d, 0x91, 0x8d,
+    0x91, 0x8d, 0x8c, 0x02, 0x8e, 0xb3, 0xa2, 0x03,
+    0x80, 0xc2, 0xd8, 0x86, 0xa8, 0x00, 0x84, 0xc5,
+    0x89, 0x9e, 0xb0, 0x9d, 0x0c, 0x8a, 0xab, 0x83,
+    0x99, 0xb5, 0x96, 0x88, 0xb4, 0xd1, 0x80, 0xdc,
+    0xae, 0x90, 0x86, 0xb6, 0x9d, 0x8c, 0x81, 0x89,
+    0xab, 0x99, 0xa3, 0xa8, 0x82, 0x89, 0xa3, 0x81,
+    0x88, 0x86, 0xaa, 0x0a, 0xa8, 0x18, 0x28, 0x0a,
+    0x04, 0x40, 0xbf, 0xbf, 0x41, 0x15, 0x0d, 0x81,
+    0xa5, 0x0d, 0x0f, 0x00, 0x00, 0x00, 0x80, 0x9e,
+    0x81, 0xb4, 0x06, 0x00, 0x12, 0x06, 0x13, 0x0d,
+    0x83, 0x8c, 0x22, 0x06, 0xf3, 0x80, 0x8c, 0x80,
+    0x8f, 0x8c, 0xe4, 0x03, 0x01, 0x89, 0x00, 0x0d,
+    0x28, 0x00, 0x00, 0x80, 0x8f, 0x0b, 0x24, 0x18,
+    0x90, 0xa8, 0x4a, 0x76, 0xae, 0x80, 0xae, 0x80,
+    0x40, 0x84, 0x2b, 0x11, 0x8b, 0xa5, 0x00, 0x20,
+    0x81, 0xb7, 0x30, 0x8f, 0x96, 0x88, 0x30, 0x30,
+    0x30, 0x30, 0x30, 0x30, 0x30, 0x86, 0x42, 0x25,
+    0x82, 0x98, 0x88, 0x34, 0x0c, 0x83, 0xd5, 0x1c,
+    0x80, 0xd9, 0x03, 0x84, 0xaa, 0x80, 0xdd, 0x90,
+    0x9f, 0xaf, 0x8f, 0x41, 0xff, 0x59, 0xbf, 0xbf,
+    0x60, 0x51, 0xfc, 0x82, 0x44, 0x8c, 0xc2, 0xad,
+    0x81, 0x41, 0x0c, 0x82, 0x8f, 0x89, 0x81, 0x93,
+    0xae, 0x8f, 0x9e, 0x81, 0xcf, 0xa6, 0x88, 0x81,
+    0xe6, 0x81, 0xb4, 0x81, 0x88, 0xa9, 0x8c, 0x02,
+    0x03, 0x80, 0x96, 0x9c, 0xb3, 0x8d, 0xb1, 0xbd,
+    0x2a, 0x00, 0x81, 0x8a, 0x9b, 0x89, 0x96, 0x98,
+    0x9c, 0x86, 0xae, 0x9b, 0x80, 0x8f, 0x20, 0x89,
+    0x89, 0x20, 0xa8, 0x96, 0x10, 0x87, 0x93, 0x96,
+    0x10, 0x82, 0xb1, 0x00, 0x11, 0x0c, 0x08, 0x00,
+    0x97, 0x11, 0x8a, 0x32, 0x8b, 0x29, 0x29, 0x85,
+    0x88, 0x30, 0x30, 0xaa, 0x80, 0x8d, 0x85, 0xf2,
+    0x9c, 0x60, 0x2b, 0xa3, 0x8b, 0x96, 0x83, 0xb0,
+    0x60, 0x21, 0x03, 0x41, 0x6d, 0x81, 0xe9, 0xa5,
+    0x86, 0x8b, 0x24, 0x00, 0x89, 0x80, 0x8c, 0x04,
+    0x00, 0x01, 0x01, 0x80, 0xeb, 0xa0, 0x41, 0x6a,
+    0x91, 0xbf, 0x81, 0xb5, 0xa7, 0x8b, 0xf3, 0x20,
+    0x40, 0x86, 0xa3, 0x99, 0x85, 0x99, 0x8a, 0xd8,
+    0x15, 0x0d, 0x0d, 0x0a, 0xa2, 0x8b, 0x80, 0x99,
+    0x80, 0x92, 0x01, 0x80, 0x8e, 0x81, 0x8d, 0xa1,
+    0xfa, 0xc4, 0xb4, 0x41, 0x0a, 0x9c, 0x82, 0xb0,
+    0xae, 0x9f, 0x8c, 0x9d, 0x84, 0xa5, 0x89, 0x9d,
+    0x81, 0xa3, 0x1f, 0x04, 0xa9, 0x40, 0x9d, 0x91,
+    0xa3, 0x83, 0xa3, 0x83, 0xa7, 0x87, 0xb3, 0x40,
+    0x9b, 0x41, 0x36, 0x88, 0x95, 0x89, 0x87, 0x40,
+    0x97, 0x29, 0x00, 0xab, 0x01, 0x10, 0x81, 0x96,
+    0x89, 0x96, 0x88, 0x9e, 0xc0, 0x92, 0x01, 0x89,
+    0x95, 0x89, 0x99, 0xc5, 0xb7, 0x29, 0xbf, 0x80,
+    0x8e, 0x18, 0x10, 0x9c, 0xa9, 0x9c, 0x82, 0x9c,
+    0xa2, 0x38, 0x9b, 0x9a, 0xb5, 0x89, 0x95, 0x89,
+    0x92, 0x8c, 0x91, 0xed, 0xc8, 0xb6, 0xb2, 0x8c,
+    0xb2, 0x8c, 0xa3, 0x41, 0x5b, 0xa9, 0x29, 0xcd,
+    0x9c, 0x89, 0x07, 0x95, 0xe9, 0x94, 0x9a, 0x96,
+    0x8b, 0xb4, 0xca, 0xac, 0x9f, 0x98, 0x99, 0xa3,
+    0x9c, 0x01, 0x07, 0xa2, 0x10, 0x8b, 0xaf, 0x8d,
+    0x83, 0x94, 0x00, 0x80, 0xa2, 0x91, 0x80, 0x98,
+    0xd3, 0x30, 0x00, 0x18, 0x8e, 0x80, 0x89, 0x86,
+    0xae, 0xa5, 0x39, 0x09, 0x95, 0x06, 0x01, 0x04,
+    0x10, 0x91, 0x80, 0x8b, 0x84, 0x40, 0x9d, 0xb4,
+    0x91, 0x83, 0x93, 0x82, 0x9d, 0xaf, 0x93, 0x08,
+    0x80, 0x40, 0xb7, 0xae, 0xa8, 0x83, 0xa3, 0xaf,
+    0x93, 0x80, 0xba, 0xaa, 0x8c, 0x80, 0xc6, 0x9a,
+    0x40, 0xe4, 0xab, 0xf3, 0xbf, 0x9e, 0x39, 0x01,
+    0x38, 0x08, 0x97, 0x8e, 0x00, 0x80, 0xdd, 0x39,
+    0xa6, 0x8f, 0x00, 0x80, 0x9b, 0x80, 0x89, 0xa7,
+    0x30, 0x94, 0x80, 0x8a, 0xad, 0x92, 0x80, 0xa1,
+    0xb8, 0x41, 0x06, 0x88, 0x80, 0xa4, 0x90, 0x80,
+    0xb0, 0x9d, 0xef, 0x30, 0x08, 0xa5, 0x94, 0x80,
+    0x98, 0x28, 0x08, 0x9f, 0x8d, 0x80, 0x41, 0x46,
+    0x92, 0x40, 0xbc, 0x80, 0xce, 0x43, 0x99, 0xe5,
+    0xee, 0x90, 0x40, 0xc3, 0x4a, 0xbb, 0x44, 0x2e,
+    0x4f, 0xd0, 0x42, 0x46, 0x60, 0x21, 0xb8, 0x42,
+    0x38, 0x86, 0x9e, 0xf0, 0x9d, 0x91, 0xaf, 0x8f,
+    0x83, 0x9e, 0x94, 0x84, 0x92, 0x42, 0xaf, 0xbf,
+    0xff, 0xca, 0x20, 0xc1, 0x8c, 0xbf, 0x08, 0x80,
+    0x9b, 0x57, 0xf7, 0x87, 0x44, 0xd5, 0xa9, 0x88,
+    0x60, 0x22, 0xf6, 0x41, 0x1e, 0xb0, 0x82, 0x90,
+    0x1f, 0x41, 0x8b, 0x49, 0x03, 0xea, 0x84, 0x8c,
+    0x82, 0x88, 0x86, 0x89, 0x57, 0x65, 0xd4, 0x80,
+    0xc6, 0x01, 0x08, 0x09, 0x0b, 0x80, 0x8b, 0x00,
+    0x06, 0x80, 0xc0, 0x03, 0x0f, 0x06, 0x80, 0x9b,
+    0x03, 0x04, 0x00, 0x16, 0x80, 0x41, 0x53, 0x81,
+    0x98, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80,
+    0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80,
+    0x9e, 0x80, 0x98, 0x07, 0x49, 0x33, 0xac, 0x89,
+    0x86, 0x8f, 0x80, 0x41, 0x70, 0xab, 0x45, 0x13,
+    0x40, 0xc4, 0xba, 0xc3, 0x30, 0x44, 0xb3, 0x18,
+    0x9a, 0x01, 0x00, 0x08, 0x80, 0x89, 0x03, 0x00,
+    0x00, 0x28, 0x18, 0x00, 0x00, 0x02, 0x01, 0x00,
+    0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0b,
+    0x06, 0x03, 0x03, 0x00, 0x80, 0x89, 0x80, 0x90,
+    0x22, 0x04, 0x80, 0x90, 0x51, 0x43, 0x60, 0xa6,
+    0xdd, 0xa1, 0x50, 0x34, 0x8a, 0x40, 0xdd, 0x81,
+    0x56, 0x81, 0x8d, 0x5d, 0x30, 0x4c, 0x1e, 0x42,
+    0x1d, 0x45, 0xe1, 0x53, 0x4a,
+};
+
+static const uint8_t unicode_prop_ID_Start_index[99] = {
+    0xf6, 0x03, 0x20, 0xa6, 0x07, 0x00, 0xa9, 0x09,
+    0x00, 0xb4, 0x0a, 0x00, 0xba, 0x0b, 0x00, 0x3e,
+    0x0d, 0x00, 0xe0, 0x0e, 0x20, 0x57, 0x12, 0x00,
+    0xeb, 0x16, 0x00, 0xca, 0x19, 0x20, 0xc0, 0x1d,
+    0x60, 0x80, 0x20, 0x00, 0x2e, 0x2d, 0x00, 0xc0,
+    0x31, 0x20, 0x89, 0xa7, 0x20, 0xf0, 0xa9, 0x00,
+    0xe3, 0xab, 0x00, 0x3e, 0xfd, 0x00, 0xfb, 0x00,
+    0x21, 0x37, 0x07, 0x61, 0x01, 0x0a, 0x01, 0x1d,
+    0x0f, 0x21, 0x2c, 0x12, 0x01, 0xc8, 0x14, 0x21,
+    0xd1, 0x19, 0x21, 0x47, 0x1d, 0x01, 0x39, 0x6a,
+    0x21, 0x09, 0x8d, 0x01, 0xbc, 0xd4, 0x01, 0xa9,
+    0xd7, 0x21, 0x3a, 0xee, 0x01, 0xde, 0xa6, 0x22,
+    0x4b, 0x13, 0x03,
+};
+
+static const uint8_t unicode_prop_ID_Continue1_table[626] = {
+    0xaf, 0x89, 0xa4, 0x80, 0xd6, 0x80, 0x42, 0x47,
+    0xef, 0x96, 0x80, 0x40, 0xfa, 0x84, 0x41, 0x08,
+    0xac, 0x00, 0x01, 0x01, 0x00, 0xc7, 0x8a, 0xaf,
+    0x9e, 0x28, 0xe4, 0x31, 0x29, 0x08, 0x19, 0x89,
+    0x96, 0x80, 0x9d, 0x9a, 0xda, 0x8a, 0x8e, 0x89,
+    0xa0, 0x88, 0x88, 0x80, 0x97, 0x18, 0x88, 0x02,
+    0x04, 0xaa, 0x82, 0xf6, 0x8e, 0x80, 0xa0, 0xb5,
+    0x10, 0x91, 0x06, 0x89, 0x09, 0x89, 0x90, 0x82,
+    0xb7, 0x00, 0x31, 0x09, 0x82, 0x88, 0x80, 0x89,
+    0x09, 0x89, 0x8d, 0x01, 0x82, 0xb7, 0x00, 0x23,
+    0x09, 0x12, 0x80, 0x93, 0x8b, 0x10, 0x8a, 0x82,
+    0xb7, 0x00, 0x38, 0x10, 0x82, 0x93, 0x09, 0x89,
+    0x89, 0x28, 0x82, 0xb7, 0x00, 0x31, 0x09, 0x16,
+    0x82, 0x89, 0x09, 0x89, 0x91, 0x80, 0xba, 0x22,
+    0x10, 0x83, 0x88, 0x80, 0x8d, 0x89, 0x8f, 0x84,
+    0xb8, 0x30, 0x10, 0x1e, 0x81, 0x8a, 0x09, 0x89,
+    0x90, 0x82, 0xb7, 0x00, 0x30, 0x10, 0x1e, 0x81,
+    0x8a, 0x09, 0x89, 0x8f, 0x83, 0xb6, 0x08, 0x30,
+    0x10, 0x83, 0x88, 0x80, 0x89, 0x09, 0x89, 0x90,
+    0x82, 0xc5, 0x03, 0x28, 0x00, 0x3d, 0x89, 0x09,
+    0xbc, 0x01, 0x86, 0x8b, 0x38, 0x89, 0xd6, 0x01,
+    0x88, 0x8a, 0x29, 0x89, 0xbd, 0x0d, 0x89, 0x8a,
+    0x00, 0x00, 0x03, 0x81, 0xb0, 0x93, 0x01, 0x84,
+    0x8a, 0x80, 0xa3, 0x88, 0x80, 0xe3, 0x93, 0x80,
+    0x89, 0x8b, 0x1b, 0x10, 0x11, 0x32, 0x83, 0x8c,
+    0x8b, 0x80, 0x8e, 0x42, 0xbe, 0x82, 0x88, 0x88,
+    0x43, 0x9f, 0x82, 0x9c, 0x82, 0x9c, 0x81, 0x9d,
+    0x81, 0xbf, 0x9f, 0x88, 0x01, 0x89, 0xa0, 0x11,
+    0x89, 0x40, 0x8e, 0x80, 0xf5, 0x8b, 0x83, 0x8b,
+    0x89, 0x89, 0xff, 0x8a, 0xbb, 0x84, 0xb8, 0x89,
+    0x80, 0x9c, 0x81, 0x8a, 0x85, 0x89, 0x95, 0x8d,
+    0x01, 0xbe, 0x84, 0xae, 0x90, 0x8a, 0x89, 0x90,
+    0x88, 0x8b, 0x82, 0x9d, 0x8c, 0x81, 0x89, 0xab,
+    0x8d, 0xaf, 0x93, 0x87, 0x89, 0x85, 0x89, 0xf5,
+    0x10, 0x94, 0x18, 0x28, 0x0a, 0x40, 0xc5, 0xb9,
+    0x04, 0x42, 0x3e, 0x81, 0x92, 0x80, 0xfa, 0x8c,
+    0x18, 0x82, 0x8b, 0x4b, 0xfd, 0x82, 0x40, 0x8c,
+    0x80, 0xdf, 0x9f, 0x42, 0x29, 0x85, 0xe8, 0x81,
+    0x60, 0x75, 0x84, 0x89, 0xc4, 0x03, 0x89, 0x9f,
+    0x81, 0xcf, 0x81, 0x41, 0x0f, 0x02, 0x03, 0x80,
+    0x96, 0x23, 0x80, 0xd2, 0x81, 0xb1, 0x91, 0x89,
+    0x89, 0x85, 0x91, 0x8c, 0x8a, 0x9b, 0x87, 0x98,
+    0x8c, 0xab, 0x83, 0xae, 0x8d, 0x8e, 0x89, 0x8a,
+    0x80, 0x89, 0x89, 0xae, 0x8d, 0x8b, 0x07, 0x09,
+    0x89, 0xa0, 0x82, 0xb1, 0x00, 0x11, 0x0c, 0x08,
+    0x80, 0xa8, 0x24, 0x81, 0x40, 0xeb, 0x38, 0x09,
+    0x89, 0x60, 0x4f, 0x23, 0x80, 0x42, 0xe0, 0x8f,
+    0x8f, 0x8f, 0x11, 0x97, 0x82, 0x40, 0xbf, 0x89,
+    0xa4, 0x80, 0x42, 0xbc, 0x80, 0x40, 0xe1, 0x80,
+    0x40, 0x94, 0x84, 0x41, 0x24, 0x89, 0x45, 0x56,
+    0x10, 0x0c, 0x83, 0xa7, 0x13, 0x80, 0x40, 0xa4,
+    0x81, 0x42, 0x3c, 0x1f, 0x89, 0x41, 0x70, 0x81,
+    0x40, 0x98, 0x8a, 0x40, 0xae, 0x82, 0xb4, 0x8e,
+    0x9e, 0x89, 0x8e, 0x83, 0xac, 0x8a, 0xb4, 0x89,
+    0x2a, 0xa3, 0x8d, 0x80, 0x89, 0x21, 0xab, 0x80,
+    0x8b, 0x82, 0xaf, 0x8d, 0x3b, 0x80, 0x8b, 0xd1,
+    0x8b, 0x28, 0x40, 0x9f, 0x8b, 0x84, 0x89, 0x2b,
+    0xb6, 0x08, 0x31, 0x09, 0x82, 0x88, 0x80, 0x89,
+    0x09, 0x32, 0x84, 0x40, 0xbf, 0x91, 0x88, 0x89,
+    0x18, 0xd0, 0x93, 0x8b, 0x89, 0x40, 0xd4, 0x31,
+    0x88, 0x9a, 0x81, 0xd1, 0x90, 0x8e, 0x89, 0xd0,
+    0x8c, 0x87, 0x89, 0xd2, 0x8e, 0x83, 0x89, 0x40,
+    0xf1, 0x8e, 0x40, 0xa4, 0x89, 0xc5, 0x28, 0x09,
+    0x18, 0x00, 0x81, 0x8b, 0x89, 0xf6, 0x31, 0x32,
+    0x80, 0x9b, 0x89, 0xa7, 0x30, 0x1f, 0x80, 0x88,
+    0x8a, 0xad, 0x8f, 0x41, 0x94, 0x38, 0x87, 0x8f,
+    0x89, 0xb7, 0x95, 0x80, 0x8d, 0xf9, 0x2a, 0x00,
+    0x08, 0x30, 0x07, 0x89, 0xaf, 0x20, 0x08, 0x27,
+    0x89, 0x41, 0x48, 0x83, 0x60, 0x4b, 0x68, 0x89,
+    0x40, 0x85, 0x84, 0xba, 0x86, 0x98, 0x89, 0x43,
+    0xf4, 0x00, 0xb6, 0x33, 0xd0, 0x80, 0x8a, 0x81,
+    0x60, 0x4c, 0xaa, 0x81, 0x54, 0xc5, 0x22, 0x2f,
+    0x39, 0x86, 0x9d, 0x83, 0x40, 0x93, 0x82, 0x45,
+    0x88, 0xb1, 0x41, 0xff, 0xb6, 0x83, 0xb1, 0x38,
+    0x8d, 0x80, 0x95, 0x20, 0x8e, 0x45, 0x4f, 0x30,
+    0x90, 0x0e, 0x01, 0x04, 0x41, 0x04, 0x86, 0x88,
+    0x89, 0x41, 0xa1, 0x8d, 0x45, 0xd5, 0x86, 0xec,
+    0x34, 0x89, 0x52, 0x95, 0x89, 0x6c, 0x05, 0x05,
+    0x40, 0xef,
+};
+
+static const uint8_t unicode_prop_ID_Continue1_index[60] = {
+    0xfa, 0x06, 0x00, 0x84, 0x09, 0x00, 0xf0, 0x0a,
+    0x00, 0x70, 0x0c, 0x00, 0xf4, 0x0d, 0x00, 0x4a,
+    0x10, 0x20, 0x1a, 0x18, 0x20, 0x74, 0x1b, 0x20,
+    0xdd, 0x20, 0x00, 0x0c, 0xa8, 0x00, 0x5a, 0xaa,
+    0x20, 0x1a, 0xff, 0x00, 0xad, 0x0e, 0x01, 0x38,
+    0x12, 0x21, 0xc1, 0x15, 0x21, 0xe5, 0x19, 0x21,
+    0xaa, 0x1d, 0x21, 0x8c, 0xd1, 0x41, 0x4a, 0xe1,
+    0x21, 0xf0, 0x01, 0x0e,
+};
+
+#ifdef CONFIG_ALL_UNICODE
+
+static const uint8_t unicode_cc_table[851] = {
+    0xb2, 0xcf, 0xd4, 0x00, 0xe8, 0x03, 0xdc, 0x00,
+    0xe8, 0x00, 0xd8, 0x04, 0xdc, 0x01, 0xca, 0x03,
+    0xdc, 0x01, 0xca, 0x0a, 0xdc, 0x04, 0x01, 0x03,
+    0xdc, 0xc7, 0x00, 0xf0, 0xc0, 0x02, 0xdc, 0xc2,
+    0x01, 0xdc, 0x80, 0xc2, 0x03, 0xdc, 0xc0, 0x00,
+    0xe8, 0x01, 0xdc, 0xc0, 0x41, 0xe9, 0x00, 0xea,
+    0x41, 0xe9, 0x00, 0xea, 0x00, 0xe9, 0xcc, 0xb0,
+    0xe2, 0xc4, 0xb0, 0xd8, 0x00, 0xdc, 0xc3, 0x00,
+    0xdc, 0xc2, 0x00, 0xde, 0x00, 0xdc, 0xc5, 0x05,
+    0xdc, 0xc1, 0x00, 0xdc, 0xc1, 0x00, 0xde, 0x00,
+    0xe4, 0xc0, 0x49, 0x0a, 0x43, 0x13, 0x80, 0x00,
+    0x17, 0x80, 0x41, 0x18, 0x80, 0xc0, 0x00, 0xdc,
+    0x80, 0x00, 0x12, 0xb0, 0x17, 0xc7, 0x42, 0x1e,
+    0xaf, 0x47, 0x1b, 0xc1, 0x01, 0xdc, 0xc4, 0x00,
+    0xdc, 0xc1, 0x00, 0xdc, 0x8f, 0x00, 0x23, 0xb0,
+    0x34, 0xc6, 0x81, 0xc3, 0x00, 0xdc, 0xc0, 0x81,
+    0xc1, 0x80, 0x00, 0xdc, 0xc1, 0x00, 0xdc, 0xa2,
+    0x00, 0x24, 0x9d, 0xc0, 0x00, 0xdc, 0xc1, 0x00,
+    0xdc, 0xc1, 0x02, 0xdc, 0xc0, 0x01, 0xdc, 0xc0,
+    0x00, 0xdc, 0xc2, 0x00, 0xdc, 0xc0, 0x00, 0xdc,
+    0xc0, 0x00, 0xdc, 0xc0, 0x00, 0xdc, 0xc1, 0xb0,
+    0x6f, 0xc6, 0x00, 0xdc, 0xc0, 0x88, 0x00, 0xdc,
+    0x97, 0xc3, 0x80, 0xc8, 0x80, 0xc2, 0x80, 0xc4,
+    0xaa, 0x02, 0xdc, 0xb0, 0x46, 0x00, 0xdc, 0xcd,
+    0x80, 0x00, 0xdc, 0xc1, 0x00, 0xdc, 0xc1, 0x00,
+    0xdc, 0xc2, 0x02, 0xdc, 0x42, 0x1b, 0xc2, 0x00,
+    0xdc, 0xc1, 0x01, 0xdc, 0xc4, 0xb0, 0x0b, 0x00,
+    0x07, 0x8f, 0x00, 0x09, 0x82, 0xc0, 0x00, 0xdc,
+    0xc1, 0xb0, 0x36, 0x00, 0x07, 0x8f, 0x00, 0x09,
+    0xaf, 0xc0, 0xb0, 0x0c, 0x00, 0x07, 0x8f, 0x00,
+    0x09, 0xb0, 0x3d, 0x00, 0x07, 0x8f, 0x00, 0x09,
+    0xb0, 0x3d, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0,
+    0x4e, 0x00, 0x09, 0xb0, 0x4e, 0x00, 0x09, 0x86,
+    0x00, 0x54, 0x00, 0x5b, 0xb0, 0x34, 0x00, 0x07,
+    0x8f, 0x00, 0x09, 0xb0, 0x3c, 0x01, 0x09, 0x8f,
+    0x00, 0x09, 0xb0, 0x4b, 0x00, 0x09, 0xb0, 0x3c,
+    0x01, 0x67, 0x00, 0x09, 0x8c, 0x03, 0x6b, 0xb0,
+    0x3b, 0x01, 0x76, 0x00, 0x09, 0x8c, 0x03, 0x7a,
+    0xb0, 0x1b, 0x01, 0xdc, 0x9a, 0x00, 0xdc, 0x80,
+    0x00, 0xdc, 0x80, 0x00, 0xd8, 0xb0, 0x06, 0x41,
+    0x81, 0x80, 0x00, 0x84, 0x84, 0x03, 0x82, 0x81,
+    0x00, 0x82, 0x80, 0xc1, 0x00, 0x09, 0x80, 0xc1,
+    0xb0, 0x0d, 0x00, 0xdc, 0xb0, 0x3f, 0x00, 0x07,
+    0x80, 0x01, 0x09, 0xb0, 0x21, 0x00, 0xdc, 0xb2,
+    0x9e, 0xc2, 0xb3, 0x83, 0x00, 0x09, 0x9e, 0x00,
+    0x09, 0xb0, 0x6c, 0x00, 0x09, 0x89, 0xc0, 0xb0,
+    0x9a, 0x00, 0xe4, 0xb0, 0x5e, 0x00, 0xde, 0xc0,
+    0x00, 0xdc, 0xb0, 0xaa, 0xc0, 0x00, 0xdc, 0xb0,
+    0x16, 0x00, 0x09, 0x93, 0xc7, 0x81, 0x00, 0xdc,
+    0xaf, 0xc4, 0x05, 0xdc, 0xc1, 0x00, 0xdc, 0x80,
+    0x01, 0xdc, 0xb0, 0x42, 0x00, 0x07, 0x8e, 0x00,
+    0x09, 0xa5, 0xc0, 0x00, 0xdc, 0xc6, 0xb0, 0x05,
+    0x01, 0x09, 0xb0, 0x09, 0x00, 0x07, 0x8a, 0x01,
+    0x09, 0xb0, 0x12, 0x00, 0x07, 0xb0, 0x67, 0xc2,
+    0x41, 0x00, 0x04, 0xdc, 0xc1, 0x03, 0xdc, 0xc0,
+    0x41, 0x00, 0x05, 0x01, 0x83, 0x00, 0xdc, 0x85,
+    0xc0, 0x82, 0xc1, 0xb0, 0x95, 0xc1, 0x00, 0xdc,
+    0xc6, 0x00, 0xdc, 0xc1, 0x00, 0xea, 0x00, 0xd6,
+    0x00, 0xdc, 0x00, 0xca, 0xe4, 0x00, 0xe8, 0x01,
+    0xe4, 0x00, 0xdc, 0x80, 0xc0, 0x00, 0xe9, 0x00,
+    0xdc, 0xc0, 0x00, 0xdc, 0xb2, 0x9f, 0xc1, 0x01,
+    0x01, 0xc3, 0x02, 0x01, 0xc1, 0x83, 0xc0, 0x82,
+    0x01, 0x01, 0xc0, 0x00, 0xdc, 0xc0, 0x01, 0x01,
+    0x03, 0xdc, 0xc0, 0xb8, 0x03, 0xcd, 0xc2, 0xb0,
+    0x5c, 0x00, 0x09, 0xb0, 0x2f, 0xdf, 0xb1, 0xf9,
+    0x00, 0xda, 0x00, 0xe4, 0x00, 0xe8, 0x00, 0xde,
+    0x01, 0xe0, 0xb0, 0x38, 0x01, 0x08, 0xb8, 0x6d,
+    0xa3, 0xc0, 0x83, 0xc9, 0x9f, 0xc1, 0xb0, 0x1f,
+    0xc1, 0xb0, 0xe3, 0x00, 0x09, 0xa4, 0x00, 0x09,
+    0xb0, 0x66, 0x00, 0x09, 0x9a, 0xd1, 0xb0, 0x08,
+    0x02, 0xdc, 0xa4, 0x00, 0x09, 0xb0, 0x2e, 0x00,
+    0x07, 0x8b, 0x00, 0x09, 0xb0, 0xbe, 0xc0, 0x80,
+    0xc1, 0x00, 0xdc, 0x81, 0xc1, 0x84, 0xc1, 0x80,
+    0xc0, 0xb0, 0x03, 0x00, 0x09, 0xb0, 0xc5, 0x00,
+    0x09, 0xb8, 0x46, 0xff, 0x00, 0x1a, 0xb2, 0xd0,
+    0xc6, 0x06, 0xdc, 0xc1, 0xb3, 0x9c, 0x00, 0xdc,
+    0xb0, 0xb1, 0x00, 0xdc, 0xb0, 0x64, 0xc4, 0xb6,
+    0x61, 0x00, 0xdc, 0x80, 0xc0, 0xa7, 0xc0, 0x00,
+    0x01, 0x00, 0xdc, 0x83, 0x00, 0x09, 0xb0, 0x74,
+    0xc0, 0x00, 0xdc, 0xb2, 0x0c, 0xc3, 0xb1, 0x52,
+    0xc1, 0xb0, 0x68, 0x01, 0xdc, 0xc2, 0x00, 0xdc,
+    0xc0, 0x03, 0xdc, 0xb0, 0xc4, 0x00, 0x09, 0xb0,
+    0x07, 0x00, 0x09, 0xb0, 0x08, 0x00, 0x09, 0x00,
+    0x07, 0xb0, 0x14, 0xc2, 0xaf, 0x01, 0x09, 0xb0,
+    0x0d, 0x00, 0x07, 0xb0, 0x1b, 0x00, 0x09, 0x88,
+    0x00, 0x07, 0xb0, 0x39, 0x00, 0x09, 0x00, 0x07,
+    0xb0, 0x81, 0x00, 0x07, 0x00, 0x09, 0xb0, 0x1f,
+    0x01, 0x07, 0x8f, 0x00, 0x09, 0x97, 0xc6, 0x82,
+    0xc4, 0xb0, 0x9c, 0x00, 0x09, 0x82, 0x00, 0x07,
+    0x96, 0xc0, 0xb0, 0x32, 0x00, 0x09, 0x00, 0x07,
+    0xb0, 0xca, 0x00, 0x09, 0x00, 0x07, 0xb0, 0x4d,
+    0x00, 0x09, 0xb0, 0x45, 0x00, 0x09, 0x00, 0x07,
+    0xb0, 0x42, 0x00, 0x09, 0xb0, 0xdc, 0x00, 0x09,
+    0x00, 0x07, 0xb0, 0xd1, 0x01, 0x09, 0x83, 0x00,
+    0x07, 0xb0, 0x6b, 0x00, 0x09, 0xb0, 0x22, 0x00,
+    0x09, 0x91, 0x00, 0x09, 0xb0, 0x20, 0x00, 0x09,
+    0xb1, 0x74, 0x00, 0x09, 0xb0, 0xd1, 0x00, 0x07,
+    0x80, 0x01, 0x09, 0xb0, 0x20, 0x00, 0x09, 0xb8,
+    0x45, 0x27, 0x04, 0x01, 0xb0, 0x0a, 0xc6, 0xb4,
+    0x88, 0x01, 0x06, 0xb8, 0x44, 0x7b, 0x00, 0x01,
+    0xb8, 0x0c, 0x95, 0x01, 0xd8, 0x02, 0x01, 0x82,
+    0x00, 0xe2, 0x04, 0xd8, 0x87, 0x07, 0xdc, 0x81,
+    0xc4, 0x01, 0xdc, 0x9d, 0xc3, 0xb0, 0x63, 0xc2,
+    0xb8, 0x05, 0x8a, 0xc6, 0x80, 0xd0, 0x81, 0xc6,
+    0x80, 0xc1, 0x80, 0xc4, 0xb0, 0xd4, 0xc6, 0xb1,
+    0x84, 0xc3, 0xb5, 0xaf, 0x06, 0xdc, 0xb0, 0x3c,
+    0xc5, 0x00, 0x07,
+};
+
+static const uint8_t unicode_cc_index[81] = {
+    0x4d, 0x03, 0x00, 0x97, 0x05, 0x20, 0xc6, 0x05,
+    0x00, 0xe7, 0x06, 0x00, 0x45, 0x07, 0x00, 0xe2,
+    0x08, 0x00, 0x53, 0x09, 0x00, 0xcd, 0x0b, 0x20,
+    0x38, 0x0e, 0x00, 0x73, 0x0f, 0x20, 0x5d, 0x13,
+    0x20, 0x60, 0x1a, 0x20, 0xaa, 0x1b, 0x00, 0xf4,
+    0x1c, 0x00, 0xfe, 0x1d, 0x20, 0x7f, 0x2d, 0x20,
+    0xf0, 0xa6, 0x00, 0xb2, 0xaa, 0x00, 0xfe, 0x01,
+    0x01, 0xab, 0x0e, 0x01, 0x73, 0x11, 0x21, 0x70,
+    0x13, 0x01, 0xb8, 0x16, 0x01, 0x9a, 0x1a, 0x01,
+    0x9f, 0xbc, 0x01, 0x22, 0xe0, 0x01, 0x4b, 0xe9,
+    0x01,
+};
+
+static const uint32_t unicode_decomp_table1[690] = {
+    0x00280081, 0x002a0097, 0x002a8081, 0x002bc097,
+    0x002c8115, 0x002d0097, 0x002d4081, 0x002e0097,
+    0x002e4115, 0x002f0199, 0x00302016, 0x00400842,
+    0x00448a42, 0x004a0442, 0x004c0096, 0x004c8117,
+    0x004d0242, 0x004e4342, 0x004fc12f, 0x0050c342,
+    0x005240bf, 0x00530342, 0x00550942, 0x005a0842,
+    0x005e0096, 0x005e4342, 0x005fc081, 0x00680142,
+    0x006bc142, 0x00710185, 0x0071c317, 0x00734844,
+    0x00778344, 0x00798342, 0x007b02be, 0x007c4197,
+    0x007d0142, 0x007e0444, 0x00800e42, 0x00878142,
+    0x00898744, 0x00ac0483, 0x00b60317, 0x00b80283,
+    0x00d00214, 0x00d10096, 0x00dd0080, 0x00de8097,
+    0x00df8080, 0x00e10097, 0x00e1413e, 0x00e1c080,
+    0x00e204be, 0x00ea83ae, 0x00f282ae, 0x00f401ad,
+    0x00f4c12e, 0x00f54103, 0x00fc0303, 0x00fe4081,
+    0x0100023e, 0x0101c0be, 0x010301be, 0x010640be,
+    0x010e40be, 0x0114023e, 0x0115c0be, 0x011701be,
+    0x011d8144, 0x01304144, 0x01340244, 0x01358144,
+    0x01368344, 0x01388344, 0x013a8644, 0x013e0144,
+    0x0161c085, 0x018882ae, 0x019d422f, 0x01b00184,
+    0x01b4c084, 0x024a4084, 0x024c4084, 0x024d0084,
+    0x0256042e, 0x0272c12e, 0x02770120, 0x0277c084,
+    0x028cc084, 0x028d8084, 0x029641ae, 0x02978084,
+    0x02d20084, 0x02d2c12e, 0x02d70120, 0x02e50084,
+    0x02f281ae, 0x03120084, 0x03300084, 0x0331c122,
+    0x0332812e, 0x035281ae, 0x03768084, 0x037701ae,
+    0x038cc085, 0x03acc085, 0x03b7012f, 0x03c30081,
+    0x03d0c084, 0x03d34084, 0x03d48084, 0x03d5c084,
+    0x03d70084, 0x03da4084, 0x03dcc084, 0x03dd412e,
+    0x03ddc085, 0x03de0084, 0x03de4085, 0x03e04084,
+    0x03e4c084, 0x03e74084, 0x03e88084, 0x03e9c084,
+    0x03eb0084, 0x03ee4084, 0x04098084, 0x043f0081,
+    0x06c18484, 0x06c48084, 0x06cec184, 0x06d00120,
+    0x06d0c084, 0x074b0383, 0x074cc41f, 0x074f1783,
+    0x075e0081, 0x0766d283, 0x07801d44, 0x078e8942,
+    0x07931844, 0x079f0d42, 0x07a58216, 0x07a68085,
+    0x07a6c0be, 0x07a80d44, 0x07aea044, 0x07c00122,
+    0x07c08344, 0x07c20122, 0x07c28344, 0x07c40122,
+    0x07c48244, 0x07c60122, 0x07c68244, 0x07c8113e,
+    0x07d08244, 0x07d20122, 0x07d28244, 0x07d40122,
+    0x07d48344, 0x07d64c3e, 0x07dc4080, 0x07dc80be,
+    0x07dcc080, 0x07dd00be, 0x07dd4080, 0x07dd80be,
+    0x07ddc080, 0x07de00be, 0x07de4080, 0x07de80be,
+    0x07dec080, 0x07df00be, 0x07df4080, 0x07e00820,
+    0x07e40820, 0x07e80820, 0x07ec05be, 0x07eec080,
+    0x07ef00be, 0x07ef4097, 0x07ef8080, 0x07efc117,
+    0x07f0443e, 0x07f24080, 0x07f280be, 0x07f2c080,
+    0x07f303be, 0x07f4c080, 0x07f582ae, 0x07f6c080,
+    0x07f7433e, 0x07f8c080, 0x07f903ae, 0x07fac080,
+    0x07fb013e, 0x07fb8102, 0x07fc83be, 0x07fe4080,
+    0x07fe80be, 0x07fec080, 0x07ff00be, 0x07ff4080,
+    0x07ff8097, 0x0800011e, 0x08008495, 0x08044081,
+    0x0805c097, 0x08090081, 0x08094097, 0x08098099,
+    0x080bc081, 0x080cc085, 0x080d00b1, 0x080d8085,
+    0x080dc0b1, 0x080f0197, 0x0811c197, 0x0815c0b3,
+    0x0817c081, 0x081c0595, 0x081ec081, 0x081f0215,
+    0x0820051f, 0x08228583, 0x08254415, 0x082a0097,
+    0x08400119, 0x08408081, 0x0840c0bf, 0x08414119,
+    0x0841c081, 0x084240bf, 0x0842852d, 0x08454081,
+    0x08458097, 0x08464295, 0x08480097, 0x08484099,
+    0x08488097, 0x08490081, 0x08498080, 0x084a0081,
+    0x084a8102, 0x084b0495, 0x084d421f, 0x084e4081,
+    0x084ec099, 0x084f0283, 0x08514295, 0x08540119,
+    0x0854809b, 0x0854c619, 0x0857c097, 0x08580081,
+    0x08584097, 0x08588099, 0x0858c097, 0x08590081,
+    0x08594097, 0x08598099, 0x0859c09b, 0x085a0097,
+    0x085a4081, 0x085a8097, 0x085ac099, 0x085b0295,
+    0x085c4097, 0x085c8099, 0x085cc097, 0x085d0081,
+    0x085d4097, 0x085d8099, 0x085dc09b, 0x085e0097,
+    0x085e4081, 0x085e8097, 0x085ec099, 0x085f0215,
+    0x08624099, 0x0866813e, 0x086b80be, 0x087341be,
+    0x088100be, 0x088240be, 0x088300be, 0x088901be,
+    0x088b0085, 0x088b40b1, 0x088bc085, 0x088c00b1,
+    0x089040be, 0x089100be, 0x0891c1be, 0x089801be,
+    0x089b42be, 0x089d0144, 0x089e0144, 0x08a00144,
+    0x08a10144, 0x08a20144, 0x08ab023e, 0x08b80244,
+    0x08ba8220, 0x08ca411e, 0x0918049f, 0x091a4523,
+    0x091cc097, 0x091d04a5, 0x091f452b, 0x0921c09b,
+    0x092204a1, 0x09244525, 0x0926c099, 0x09270d25,
+    0x092d8d1f, 0x09340d1f, 0x093a8081, 0x0a8300b3,
+    0x0a9d0099, 0x0a9d4097, 0x0a9d8099, 0x0ab700be,
+    0x0b1f0115, 0x0b5bc081, 0x0ba7c081, 0x0bbcc081,
+    0x0bc004ad, 0x0bc244ad, 0x0bc484ad, 0x0bc6f383,
+    0x0be0852d, 0x0be31d03, 0x0bf1882d, 0x0c000081,
+    0x0c0d8283, 0x0c130b84, 0x0c194284, 0x0c1c0122,
+    0x0c1cc122, 0x0c1d8122, 0x0c1e4122, 0x0c1f0122,
+    0x0c250084, 0x0c26c123, 0x0c278084, 0x0c27c085,
+    0x0c2b0b84, 0x0c314284, 0x0c340122, 0x0c34c122,
+    0x0c358122, 0x0c364122, 0x0c370122, 0x0c3d0084,
+    0x0c3dc220, 0x0c3f8084, 0x0c3fc085, 0x0c4c4a2d,
+    0x0c51451f, 0x0c53ca9f, 0x0c5915ad, 0x0c648703,
+    0x0c800741, 0x0c838089, 0x0c83c129, 0x0c8441a9,
+    0x0c850089, 0x0c854129, 0x0c85c2a9, 0x0c870089,
+    0x0c87408f, 0x0c87808d, 0x0c881241, 0x0c910203,
+    0x0c940099, 0x0c9444a3, 0x0c968323, 0x0c98072d,
+    0x0c9b84af, 0x0c9dc2a1, 0x0c9f00b5, 0x0c9f40b3,
+    0x0c9f8085, 0x0ca01883, 0x0cac4223, 0x0cad4523,
+    0x0cafc097, 0x0cb004a1, 0x0cb241a5, 0x0cb30097,
+    0x0cb34099, 0x0cb38097, 0x0cb3c099, 0x0cb417ad,
+    0x0cbfc085, 0x0cc001b3, 0x0cc0c0b1, 0x0cc100b3,
+    0x0cc14131, 0x0cc1c0b5, 0x0cc200b3, 0x0cc241b1,
+    0x0cc30133, 0x0cc38131, 0x0cc40085, 0x0cc440b1,
+    0x0cc48133, 0x0cc50085, 0x0cc540b5, 0x0cc580b7,
+    0x0cc5c0b5, 0x0cc600b1, 0x0cc64135, 0x0cc6c0b3,
+    0x0cc701b1, 0x0cc7c0b3, 0x0cc800b5, 0x0cc840b3,
+    0x0cc881b1, 0x0cc9422f, 0x0cca4131, 0x0ccac0b5,
+    0x0ccb00b1, 0x0ccb40b3, 0x0ccb80b5, 0x0ccbc0b1,
+    0x0ccc012f, 0x0ccc80b5, 0x0cccc0b3, 0x0ccd00b5,
+    0x0ccd40b1, 0x0ccd80b5, 0x0ccdc085, 0x0cce02b1,
+    0x0ccf40b3, 0x0ccf80b1, 0x0ccfc085, 0x0cd001b1,
+    0x0cd0c0b3, 0x0cd101b1, 0x0cd1c0b5, 0x0cd200b3,
+    0x0cd24085, 0x0cd280b5, 0x0cd2c085, 0x0cd30133,
+    0x0cd381b1, 0x0cd440b3, 0x0cd48085, 0x0cd4c0b1,
+    0x0cd500b3, 0x0cd54085, 0x0cd580b5, 0x0cd5c0b1,
+    0x0cd60521, 0x0cd88525, 0x0cdb02a5, 0x0cdc4099,
+    0x0cdc8117, 0x0cdd0099, 0x0cdd4197, 0x0cde0127,
+    0x0cde8285, 0x0cdfc089, 0x0ce0043f, 0x0ce20099,
+    0x0ce2409b, 0x0ce283bf, 0x0ce44219, 0x0ce54205,
+    0x0ce6433f, 0x0ce7c131, 0x0ce84085, 0x0ce881b1,
+    0x0ce94085, 0x0ce98107, 0x0cea0089, 0x0cea4097,
+    0x0cea8219, 0x0ceb809d, 0x0cebc08d, 0x0cec083f,
+    0x0cf00105, 0x0cf0809b, 0x0cf0c197, 0x0cf1809b,
+    0x0cf1c099, 0x0cf20517, 0x0cf48099, 0x0cf4c117,
+    0x0cf54119, 0x0cf5c097, 0x0cf6009b, 0x0cf64099,
+    0x0cf68217, 0x0cf78119, 0x0cf804a1, 0x0cfa4525,
+    0x0cfcc525, 0x0cff4125, 0x0cffc099, 0x29a70103,
+    0x29dc0081, 0x29fe0103, 0x2ad70203, 0x2ada4081,
+    0x3e401482, 0x3e4a7f82, 0x3e6a3f82, 0x3e8aa102,
+    0x3e9b0110, 0x3e9c2f82, 0x3eb3c590, 0x3ec00197,
+    0x3ec0c119, 0x3ec1413f, 0x3ec4c2af, 0x3ec74184,
+    0x3ec804ad, 0x3eca4081, 0x3eca8304, 0x3ecc03a0,
+    0x3ece02a0, 0x3ecf8084, 0x3ed00120, 0x3ed0c120,
+    0x3ed184ae, 0x3ed3c085, 0x3ed4312d, 0x3ef4cbad,
+    0x3efa892f, 0x3eff022d, 0x3f002f2f, 0x3f1782a5,
+    0x3f18c0b1, 0x3f1907af, 0x3f1cffaf, 0x3f3c81a5,
+    0x3f3d64af, 0x3f542031, 0x3f649b31, 0x3f7c0131,
+    0x3f7c83b3, 0x3f7e40b1, 0x3f7e80bd, 0x3f7ec0bb,
+    0x3f7f00b3, 0x3f840503, 0x3f8c01ad, 0x3f8cc315,
+    0x3f8e462d, 0x3f91cc03, 0x3f97c695, 0x3f9c01af,
+    0x3f9d0085, 0x3f9d852f, 0x3fa03aad, 0x3fbd442f,
+    0x3fc06f1f, 0x3fd7c11f, 0x3fd85fad, 0x3fe80081,
+    0x3fe84f1f, 0x3ff0831f, 0x3ff2831f, 0x3ff4831f,
+    0x3ff6819f, 0x3ff80783, 0x44268192, 0x442ac092,
+    0x444b8112, 0x44d2c112, 0x452ec212, 0x456e8112,
+    0x464e0092, 0x74578392, 0x746ec312, 0x75000d1f,
+    0x75068d1f, 0x750d0d1f, 0x7513839f, 0x7515891f,
+    0x751a0d1f, 0x75208d1f, 0x75271015, 0x752f439f,
+    0x7531459f, 0x75340d1f, 0x753a8d1f, 0x75410395,
+    0x7543441f, 0x7545839f, 0x75478d1f, 0x754e0795,
+    0x7552839f, 0x75548d1f, 0x755b0d1f, 0x75618d1f,
+    0x75680d1f, 0x756e8d1f, 0x75750d1f, 0x757b8d1f,
+    0x75820d1f, 0x75888d1f, 0x758f0d1f, 0x75958d1f,
+    0x759c0d1f, 0x75a28d1f, 0x75a90103, 0x75aa089f,
+    0x75ae4081, 0x75ae839f, 0x75b04081, 0x75b08c9f,
+    0x75b6c081, 0x75b7032d, 0x75b8889f, 0x75bcc081,
+    0x75bd039f, 0x75bec081, 0x75bf0c9f, 0x75c54081,
+    0x75c5832d, 0x75c7089f, 0x75cb4081, 0x75cb839f,
+    0x75cd4081, 0x75cd8c9f, 0x75d3c081, 0x75d4032d,
+    0x75d5889f, 0x75d9c081, 0x75da039f, 0x75dbc081,
+    0x75dc0c9f, 0x75e24081, 0x75e2832d, 0x75e4089f,
+    0x75e84081, 0x75e8839f, 0x75ea4081, 0x75ea8c9f,
+    0x75f0c081, 0x75f1042d, 0x75f3851f, 0x75f6051f,
+    0x75f8851f, 0x75fb051f, 0x75fd851f, 0x7b80022d,
+    0x7b814dad, 0x7b884203, 0x7b89c081, 0x7b8a452d,
+    0x7b8d0403, 0x7b908081, 0x7b91dc03, 0x7ba0052d,
+    0x7ba2c8ad, 0x7ba84483, 0x7baac8ad, 0x7c400097,
+    0x7c404521, 0x7c440d25, 0x7c4a8087, 0x7c4ac115,
+    0x7c4b4117, 0x7c4c0d1f, 0x7c528217, 0x7c538099,
+    0x7c53c097, 0x7c5a8197, 0x7c640097, 0x7c80012f,
+    0x7c808081, 0x7c841603, 0x7c9004c1, 0x7c940103,
+    0x7efc051f, 0xbe0001ac, 0xbe00d110, 0xbe0947ac,
+    0xbe0d3910, 0xbe29872c, 0xbe2d022c, 0xbe2e3790,
+    0xbe49ff90, 0xbe69bc10,
+};
+
+static const uint16_t unicode_decomp_table2[690] = {
+    0x0020, 0x0000, 0x0061, 0x0002, 0x0004, 0x0006, 0x03bc, 0x0008,
+    0x000a, 0x000c, 0x0015, 0x0095, 0x00a5, 0x00b9, 0x00c1, 0x00c3,
+    0x00c7, 0x00cb, 0x00d1, 0x00d7, 0x00dd, 0x00e0, 0x00e6, 0x00f8,
+    0x0108, 0x010a, 0x0073, 0x0110, 0x0112, 0x0114, 0x0120, 0x012c,
+    0x0144, 0x014d, 0x0153, 0x0162, 0x0168, 0x016a, 0x0176, 0x0192,
+    0x0194, 0x01a9, 0x01bb, 0x01c7, 0x01d1, 0x01d5, 0x02b9, 0x01d7,
+    0x003b, 0x01d9, 0x01db, 0x00b7, 0x01e1, 0x01fc, 0x020c, 0x0218,
+    0x021d, 0x0223, 0x0227, 0x03a3, 0x0233, 0x023f, 0x0242, 0x024b,
+    0x024e, 0x0251, 0x025d, 0x0260, 0x0269, 0x026c, 0x026f, 0x0275,
+    0x0278, 0x0281, 0x028a, 0x029c, 0x029f, 0x02a3, 0x02af, 0x02b9,
+    0x02c5, 0x02c9, 0x02cd, 0x02d1, 0x02d5, 0x02e7, 0x02ed, 0x02f1,
+    0x02f5, 0x02f9, 0x02fd, 0x0305, 0x0309, 0x030d, 0x0313, 0x0317,
+    0x031b, 0x0323, 0x0327, 0x032b, 0x032f, 0x0335, 0x033d, 0x0341,
+    0x0349, 0x034d, 0x0351, 0x0f0b, 0x0357, 0x035b, 0x035f, 0x0363,
+    0x0367, 0x036b, 0x036f, 0x0373, 0x0379, 0x037d, 0x0381, 0x0385,
+    0x0389, 0x038d, 0x0391, 0x0395, 0x0399, 0x039d, 0x03a1, 0x10dc,
+    0x03a5, 0x03c9, 0x03cd, 0x03d9, 0x03dd, 0x03e1, 0x03ef, 0x03f1,
+    0x043d, 0x044f, 0x0499, 0x04f0, 0x0502, 0x054a, 0x0564, 0x056c,
+    0x0570, 0x0573, 0x059a, 0x05fa, 0x05fe, 0x0607, 0x060b, 0x0614,
+    0x0618, 0x061e, 0x0622, 0x0628, 0x068e, 0x0694, 0x0698, 0x069e,
+    0x06a2, 0x06ab, 0x03ac, 0x06f3, 0x03ad, 0x06f6, 0x03ae, 0x06f9,
+    0x03af, 0x06fc, 0x03cc, 0x06ff, 0x03cd, 0x0702, 0x03ce, 0x0705,
+    0x0709, 0x070d, 0x0711, 0x0386, 0x0732, 0x0735, 0x03b9, 0x0737,
+    0x073b, 0x0388, 0x0753, 0x0389, 0x0756, 0x0390, 0x076b, 0x038a,
+    0x0777, 0x03b0, 0x0789, 0x038e, 0x0799, 0x079f, 0x07a3, 0x038c,
+    0x07b8, 0x038f, 0x07bb, 0x00b4, 0x07be, 0x07c0, 0x07c2, 0x2010,
+    0x07cb, 0x002e, 0x07cd, 0x07cf, 0x0020, 0x07d2, 0x07d6, 0x07db,
+    0x07df, 0x07e4, 0x07ea, 0x07f0, 0x0020, 0x07f6, 0x2212, 0x0801,
+    0x0805, 0x0807, 0x081d, 0x0825, 0x0827, 0x0043, 0x082d, 0x0830,
+    0x0190, 0x0836, 0x0839, 0x004e, 0x0845, 0x0847, 0x084c, 0x084e,
+    0x0851, 0x005a, 0x03a9, 0x005a, 0x0853, 0x0857, 0x0860, 0x0069,
+    0x0862, 0x0865, 0x086f, 0x0874, 0x087a, 0x087e, 0x08a2, 0x0049,
+    0x08a4, 0x08a6, 0x08a9, 0x0056, 0x08ab, 0x08ad, 0x08b0, 0x08b4,
+    0x0058, 0x08b6, 0x08b8, 0x08bb, 0x08c0, 0x08c2, 0x08c5, 0x0076,
+    0x08c7, 0x08c9, 0x08cc, 0x08d0, 0x0078, 0x08d2, 0x08d4, 0x08d7,
+    0x08db, 0x08de, 0x08e4, 0x08e7, 0x08f0, 0x08f3, 0x08f6, 0x08f9,
+    0x0902, 0x0906, 0x090b, 0x090f, 0x0914, 0x0917, 0x091a, 0x0923,
+    0x092c, 0x093b, 0x093e, 0x0941, 0x0944, 0x0947, 0x094a, 0x0956,
+    0x095c, 0x0960, 0x0962, 0x0964, 0x0968, 0x096a, 0x0970, 0x0978,
+    0x097c, 0x0980, 0x0986, 0x0989, 0x098f, 0x0991, 0x0030, 0x0993,
+    0x0999, 0x099c, 0x099e, 0x09a1, 0x09a4, 0x2d61, 0x6bcd, 0x9f9f,
+    0x09a6, 0x09b1, 0x09bc, 0x09c7, 0x0a95, 0x0aa1, 0x0b15, 0x0020,
+    0x0b27, 0x0b31, 0x0b8d, 0x0ba1, 0x0ba5, 0x0ba9, 0x0bad, 0x0bb1,
+    0x0bb5, 0x0bb9, 0x0bbd, 0x0bc1, 0x0bc5, 0x0c21, 0x0c35, 0x0c39,
+    0x0c3d, 0x0c41, 0x0c45, 0x0c49, 0x0c4d, 0x0c51, 0x0c55, 0x0c59,
+    0x0c6f, 0x0c71, 0x0c73, 0x0ca0, 0x0cbc, 0x0cdc, 0x0ce4, 0x0cec,
+    0x0cf4, 0x0cfc, 0x0d04, 0x0d0c, 0x0d14, 0x0d22, 0x0d2e, 0x0d7a,
+    0x0d82, 0x0d85, 0x0d89, 0x0d8d, 0x0d9d, 0x0db1, 0x0db5, 0x0dbc,
+    0x0dc2, 0x0dc6, 0x0e28, 0x0e2c, 0x0e30, 0x0e32, 0x0e36, 0x0e3c,
+    0x0e3e, 0x0e41, 0x0e43, 0x0e46, 0x0e77, 0x0e7b, 0x0e89, 0x0e8e,
+    0x0e94, 0x0e9c, 0x0ea3, 0x0ea9, 0x0eb4, 0x0ebe, 0x0ec6, 0x0eca,
+    0x0ecf, 0x0ed9, 0x0edd, 0x0ee4, 0x0eec, 0x0ef3, 0x0ef8, 0x0f04,
+    0x0f0a, 0x0f15, 0x0f1b, 0x0f22, 0x0f28, 0x0f33, 0x0f3d, 0x0f45,
+    0x0f4c, 0x0f51, 0x0f57, 0x0f5e, 0x0f63, 0x0f69, 0x0f70, 0x0f76,
+    0x0f7d, 0x0f82, 0x0f89, 0x0f8d, 0x0f9e, 0x0fa4, 0x0fa9, 0x0fad,
+    0x0fb8, 0x0fbe, 0x0fc9, 0x0fd0, 0x0fd6, 0x0fda, 0x0fe1, 0x0fe5,
+    0x0fef, 0x0ffa, 0x1000, 0x1004, 0x1009, 0x100f, 0x1013, 0x101a,
+    0x101f, 0x1023, 0x1029, 0x102f, 0x1032, 0x1036, 0x1039, 0x103f,
+    0x1045, 0x1059, 0x1061, 0x1079, 0x107c, 0x1080, 0x1095, 0x10a1,
+    0x10b1, 0x10c3, 0x10cb, 0x10cf, 0x10da, 0x10de, 0x10ea, 0x10f2,
+    0x10f4, 0x1100, 0x1105, 0x1111, 0x1141, 0x1149, 0x114d, 0x1153,
+    0x1157, 0x115a, 0x116e, 0x1171, 0x1175, 0x117b, 0x117d, 0x1181,
+    0x1184, 0x118c, 0x1192, 0x1196, 0x119c, 0x11a2, 0x11a8, 0x11ab,
+    0xa76f, 0x11af, 0x11b3, 0x028d, 0x11bb, 0x120d, 0x130b, 0x1409,
+    0x148d, 0x1492, 0x1550, 0x1569, 0x156f, 0x1575, 0x157b, 0x1587,
+    0x1593, 0x002b, 0x159e, 0x15b6, 0x15ba, 0x15be, 0x15c2, 0x15c6,
+    0x15ca, 0x15de, 0x15e2, 0x1646, 0x165f, 0x1685, 0x168b, 0x1749,
+    0x174f, 0x1754, 0x1774, 0x1874, 0x187a, 0x190e, 0x19d0, 0x1a74,
+    0x1a7c, 0x1a9a, 0x1a9f, 0x1ab3, 0x1abd, 0x1ac3, 0x1ad7, 0x1adc,
+    0x1ae2, 0x1af0, 0x1b20, 0x1b2d, 0x1b35, 0x1b39, 0x1b4f, 0x1bc6,
+    0x1bd8, 0x1bda, 0x1bdc, 0x3164, 0x1c1d, 0x1c1f, 0x1c21, 0x1c23,
+    0x1c25, 0x1c27, 0x1c45, 0x1c53, 0x1c58, 0x1c61, 0x1c6a, 0x1c7c,
+    0x1c85, 0x1c8a, 0x1caa, 0x1cc5, 0x1cc7, 0x1cc9, 0x1ccb, 0x1ccd,
+    0x1ccf, 0x1cd1, 0x1cd3, 0x1cf3, 0x1cf5, 0x1cf7, 0x1cf9, 0x1cfb,
+    0x1d02, 0x1d04, 0x1d06, 0x1d08, 0x1d17, 0x1d19, 0x1d1b, 0x1d1d,
+    0x1d1f, 0x1d21, 0x1d23, 0x1d25, 0x1d27, 0x1d29, 0x1d2b, 0x1d2d,
+    0x1d2f, 0x1d31, 0x1d33, 0x1d37, 0x03f4, 0x1d39, 0x2207, 0x1d3b,
+    0x2202, 0x1d3d, 0x1d45, 0x03f4, 0x1d47, 0x2207, 0x1d49, 0x2202,
+    0x1d4b, 0x1d53, 0x03f4, 0x1d55, 0x2207, 0x1d57, 0x2202, 0x1d59,
+    0x1d61, 0x03f4, 0x1d63, 0x2207, 0x1d65, 0x2202, 0x1d67, 0x1d6f,
+    0x03f4, 0x1d71, 0x2207, 0x1d73, 0x2202, 0x1d75, 0x1d7f, 0x1d81,
+    0x1d83, 0x1d85, 0x1d87, 0x1d89, 0x1d8f, 0x1dac, 0x062d, 0x1db4,
+    0x1dc0, 0x062c, 0x1dd0, 0x1e40, 0x1e4c, 0x1e5f, 0x1e71, 0x1e84,
+    0x1e86, 0x1e8a, 0x1e90, 0x1e96, 0x1e98, 0x1e9c, 0x1e9e, 0x1ea6,
+    0x1ea9, 0x1eab, 0x1eb1, 0x1eb3, 0x30b5, 0x1eb9, 0x1f11, 0x1f27,
+    0x1f2b, 0x1f2d, 0x1f32, 0x1f7f, 0x1f90, 0x2091, 0x20a1, 0x20a7,
+    0x21a1, 0x22bf,
+};
+
+static const uint8_t unicode_decomp_data[9165] = {
+    0x20, 0x88, 0x20, 0x84, 0x32, 0x33, 0x20, 0x81,
+    0x20, 0xa7, 0x31, 0x6f, 0x31, 0xd0, 0x34, 0x31,
+    0xd0, 0x32, 0x33, 0xd0, 0x34, 0x41, 0x80, 0x41,
+    0x81, 0x41, 0x82, 0x41, 0x83, 0x41, 0x88, 0x41,
+    0x8a, 0x00, 0x00, 0x43, 0xa7, 0x45, 0x80, 0x45,
+    0x81, 0x45, 0x82, 0x45, 0x88, 0x49, 0x80, 0x49,
+    0x81, 0x49, 0x82, 0x49, 0x88, 0x00, 0x00, 0x4e,
+    0x83, 0x4f, 0x80, 0x4f, 0x81, 0x4f, 0x82, 0x4f,
+    0x83, 0x4f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x55,
+    0x80, 0x55, 0x81, 0x55, 0x82, 0x55, 0x88, 0x59,
+    0x81, 0x00, 0x00, 0x00, 0x00, 0x61, 0x80, 0x61,
+    0x81, 0x61, 0x82, 0x61, 0x83, 0x61, 0x88, 0x61,
+    0x8a, 0x00, 0x00, 0x63, 0xa7, 0x65, 0x80, 0x65,
+    0x81, 0x65, 0x82, 0x65, 0x88, 0x69, 0x80, 0x69,
+    0x81, 0x69, 0x82, 0x69, 0x88, 0x00, 0x00, 0x6e,
+    0x83, 0x6f, 0x80, 0x6f, 0x81, 0x6f, 0x82, 0x6f,
+    0x83, 0x6f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x75,
+    0x80, 0x75, 0x81, 0x75, 0x82, 0x75, 0x88, 0x79,
+    0x81, 0x00, 0x00, 0x79, 0x88, 0x41, 0x84, 0x41,
+    0x86, 0x41, 0xa8, 0x43, 0x81, 0x43, 0x82, 0x43,
+    0x87, 0x43, 0x8c, 0x44, 0x8c, 0x45, 0x84, 0x45,
+    0x86, 0x45, 0x87, 0x45, 0xa8, 0x45, 0x8c, 0x47,
+    0x82, 0x47, 0x86, 0x47, 0x87, 0x47, 0xa7, 0x48,
+    0x82, 0x49, 0x83, 0x49, 0x84, 0x49, 0x86, 0x49,
+    0xa8, 0x49, 0x87, 0x49, 0x4a, 0x69, 0x6a, 0x4a,
+    0x82, 0x4b, 0xa7, 0x4c, 0x81, 0x4c, 0xa7, 0x4c,
+    0x8c, 0x4c, 0x00, 0x00, 0x6b, 0x20, 0x6b, 0x4e,
+    0x81, 0x4e, 0xa7, 0x4e, 0x8c, 0xbc, 0x02, 0x6e,
+    0x4f, 0x84, 0x4f, 0x86, 0x4f, 0x8b, 0x52, 0x81,
+    0x52, 0xa7, 0x52, 0x8c, 0x53, 0x81, 0x53, 0x82,
+    0x53, 0xa7, 0x53, 0x8c, 0x54, 0xa7, 0x54, 0x8c,
+    0x55, 0x83, 0x55, 0x84, 0x55, 0x86, 0x55, 0x8a,
+    0x55, 0x8b, 0x55, 0xa8, 0x57, 0x82, 0x59, 0x82,
+    0x59, 0x88, 0x5a, 0x81, 0x5a, 0x87, 0x5a, 0x8c,
+    0x4f, 0x9b, 0x55, 0x9b, 0x44, 0x00, 0x7d, 0x01,
+    0x44, 0x00, 0x7e, 0x01, 0x64, 0x00, 0x7e, 0x01,
+    0x4c, 0x4a, 0x4c, 0x6a, 0x6c, 0x6a, 0x4e, 0x4a,
+    0x4e, 0x6a, 0x6e, 0x6a, 0x41, 0x00, 0x8c, 0x49,
+    0x00, 0x8c, 0x4f, 0x00, 0x8c, 0x55, 0x00, 0x8c,
+    0xdc, 0x00, 0x84, 0xdc, 0x00, 0x81, 0xdc, 0x00,
+    0x8c, 0xdc, 0x00, 0x80, 0xc4, 0x00, 0x84, 0x26,
+    0x02, 0x84, 0xc6, 0x00, 0x84, 0x47, 0x8c, 0x4b,
+    0x8c, 0x4f, 0xa8, 0xea, 0x01, 0x84, 0xeb, 0x01,
+    0x84, 0xb7, 0x01, 0x8c, 0x92, 0x02, 0x8c, 0x6a,
+    0x00, 0x8c, 0x44, 0x5a, 0x44, 0x7a, 0x64, 0x7a,
+    0x47, 0x81, 0x4e, 0x00, 0x80, 0xc5, 0x00, 0x81,
+    0xc6, 0x00, 0x81, 0xd8, 0x00, 0x81, 0x41, 0x8f,
+    0x41, 0x91, 0x45, 0x8f, 0x45, 0x91, 0x49, 0x8f,
+    0x49, 0x91, 0x4f, 0x8f, 0x4f, 0x91, 0x52, 0x8f,
+    0x52, 0x91, 0x55, 0x8f, 0x55, 0x91, 0x53, 0xa6,
+    0x54, 0xa6, 0x48, 0x8c, 0x41, 0x00, 0x87, 0x45,
+    0x00, 0xa7, 0xd6, 0x00, 0x84, 0xd5, 0x00, 0x84,
+    0x4f, 0x00, 0x87, 0x2e, 0x02, 0x84, 0x59, 0x00,
+    0x84, 0x68, 0x00, 0x66, 0x02, 0x6a, 0x00, 0x72,
+    0x00, 0x79, 0x02, 0x7b, 0x02, 0x81, 0x02, 0x77,
+    0x00, 0x79, 0x00, 0x20, 0x86, 0x20, 0x87, 0x20,
+    0x8a, 0x20, 0xa8, 0x20, 0x83, 0x20, 0x8b, 0x63,
+    0x02, 0x6c, 0x00, 0x73, 0x00, 0x78, 0x00, 0x95,
+    0x02, 0x80, 0x81, 0x00, 0x93, 0x88, 0x81, 0x20,
+    0xc5, 0x20, 0x81, 0xa8, 0x00, 0x81, 0x91, 0x03,
+    0x81, 0x95, 0x03, 0x81, 0x97, 0x03, 0x81, 0x99,
+    0x03, 0x81, 0x00, 0x00, 0x00, 0x9f, 0x03, 0x81,
+    0x00, 0x00, 0x00, 0xa5, 0x03, 0x81, 0xa9, 0x03,
+    0x81, 0xca, 0x03, 0x81, 0x01, 0x03, 0x98, 0x07,
+    0xa4, 0x07, 0xb0, 0x00, 0xb4, 0x00, 0xb6, 0x00,
+    0xb8, 0x00, 0xca, 0x00, 0x01, 0x03, 0xb8, 0x07,
+    0xc4, 0x07, 0xbe, 0x00, 0xc4, 0x00, 0xc8, 0x00,
+    0xa5, 0x03, 0x0d, 0x13, 0x00, 0x01, 0x03, 0xd1,
+    0x00, 0xd1, 0x07, 0xc6, 0x03, 0xc0, 0x03, 0xba,
+    0x03, 0xc1, 0x03, 0xc2, 0x03, 0x00, 0x00, 0x98,
+    0x03, 0xb5, 0x03, 0x15, 0x04, 0x80, 0x15, 0x04,
+    0x88, 0x00, 0x00, 0x00, 0x13, 0x04, 0x81, 0x06,
+    0x04, 0x88, 0x1a, 0x04, 0x81, 0x18, 0x04, 0x80,
+    0x23, 0x04, 0x86, 0x18, 0x04, 0x86, 0x38, 0x04,
+    0x86, 0x35, 0x04, 0x80, 0x35, 0x04, 0x88, 0x00,
+    0x00, 0x00, 0x33, 0x04, 0x81, 0x56, 0x04, 0x88,
+    0x3a, 0x04, 0x81, 0x38, 0x04, 0x80, 0x43, 0x04,
+    0x86, 0x74, 0x04, 0x8f, 0x16, 0x04, 0x86, 0x10,
+    0x04, 0x86, 0x10, 0x04, 0x88, 0x15, 0x04, 0x86,
+    0xd8, 0x04, 0x88, 0x16, 0x04, 0x88, 0x17, 0x04,
+    0x88, 0x18, 0x04, 0x84, 0x18, 0x04, 0x88, 0x1e,
+    0x04, 0x88, 0xe8, 0x04, 0x88, 0x2d, 0x04, 0x88,
+    0x23, 0x04, 0x84, 0x23, 0x04, 0x88, 0x23, 0x04,
+    0x8b, 0x27, 0x04, 0x88, 0x2b, 0x04, 0x88, 0x65,
+    0x05, 0x82, 0x05, 0x27, 0x06, 0x00, 0x2c, 0x00,
+    0x2d, 0x21, 0x2d, 0x00, 0x2e, 0x23, 0x2d, 0x27,
+    0x06, 0x00, 0x4d, 0x21, 0x4d, 0xa0, 0x4d, 0x23,
+    0x4d, 0xd5, 0x06, 0x54, 0x06, 0x00, 0x00, 0x00,
+    0x00, 0xc1, 0x06, 0x54, 0x06, 0xd2, 0x06, 0x54,
+    0x06, 0x28, 0x09, 0x3c, 0x09, 0x30, 0x09, 0x3c,
+    0x09, 0x33, 0x09, 0x3c, 0x09, 0x15, 0x09, 0x00,
+    0x27, 0x01, 0x27, 0x02, 0x27, 0x07, 0x27, 0x0c,
+    0x27, 0x0d, 0x27, 0x16, 0x27, 0x1a, 0x27, 0xbe,
+    0x09, 0x09, 0x00, 0x09, 0x19, 0xa1, 0x09, 0xbc,
+    0x09, 0xaf, 0x09, 0xbc, 0x09, 0x32, 0x0a, 0x3c,
+    0x0a, 0x38, 0x0a, 0x3c, 0x0a, 0x16, 0x0a, 0x00,
+    0x26, 0x01, 0x26, 0x06, 0x26, 0x2b, 0x0a, 0x3c,
+    0x0a, 0x47, 0x0b, 0x56, 0x0b, 0x3e, 0x0b, 0x09,
+    0x00, 0x09, 0x19, 0x21, 0x0b, 0x3c, 0x0b, 0x92,
+    0x0b, 0xd7, 0x0b, 0xbe, 0x0b, 0x08, 0x00, 0x09,
+    0x00, 0x08, 0x19, 0x46, 0x0c, 0x56, 0x0c, 0xbf,
+    0x0c, 0xd5, 0x0c, 0xc6, 0x0c, 0xd5, 0x0c, 0xc2,
+    0x0c, 0x04, 0x00, 0x08, 0x13, 0x3e, 0x0d, 0x08,
+    0x00, 0x09, 0x00, 0x08, 0x19, 0xd9, 0x0d, 0xca,
+    0x0d, 0xca, 0x0d, 0x0f, 0x05, 0x12, 0x00, 0x0f,
+    0x15, 0x4d, 0x0e, 0x32, 0x0e, 0xcd, 0x0e, 0xb2,
+    0x0e, 0x99, 0x0e, 0x12, 0x00, 0x12, 0x08, 0x42,
+    0x0f, 0xb7, 0x0f, 0x4c, 0x0f, 0xb7, 0x0f, 0x51,
+    0x0f, 0xb7, 0x0f, 0x56, 0x0f, 0xb7, 0x0f, 0x5b,
+    0x0f, 0xb7, 0x0f, 0x40, 0x0f, 0xb5, 0x0f, 0x71,
+    0x0f, 0x72, 0x0f, 0x71, 0x0f, 0x00, 0x03, 0x41,
+    0x0f, 0xb2, 0x0f, 0x81, 0x0f, 0xb3, 0x0f, 0x80,
+    0x0f, 0xb3, 0x0f, 0x81, 0x0f, 0x71, 0x0f, 0x80,
+    0x0f, 0x92, 0x0f, 0xb7, 0x0f, 0x9c, 0x0f, 0xb7,
+    0x0f, 0xa1, 0x0f, 0xb7, 0x0f, 0xa6, 0x0f, 0xb7,
+    0x0f, 0xab, 0x0f, 0xb7, 0x0f, 0x90, 0x0f, 0xb5,
+    0x0f, 0x25, 0x10, 0x2e, 0x10, 0x05, 0x1b, 0x35,
+    0x1b, 0x00, 0x00, 0x00, 0x00, 0x07, 0x1b, 0x35,
+    0x1b, 0x00, 0x00, 0x00, 0x00, 0x09, 0x1b, 0x35,
+    0x1b, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x1b, 0x35,
+    0x1b, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x1b, 0x35,
+    0x1b, 0x11, 0x1b, 0x35, 0x1b, 0x3a, 0x1b, 0x35,
+    0x1b, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1b, 0x35,
+    0x1b, 0x3e, 0x1b, 0x35, 0x1b, 0x42, 0x1b, 0x35,
+    0x1b, 0x41, 0x00, 0xc6, 0x00, 0x42, 0x00, 0x00,
+    0x00, 0x44, 0x00, 0x45, 0x00, 0x8e, 0x01, 0x47,
+    0x00, 0x4f, 0x00, 0x22, 0x02, 0x50, 0x00, 0x52,
+    0x00, 0x54, 0x00, 0x55, 0x00, 0x57, 0x00, 0x61,
+    0x00, 0x50, 0x02, 0x51, 0x02, 0x02, 0x1d, 0x62,
+    0x00, 0x64, 0x00, 0x65, 0x00, 0x59, 0x02, 0x5b,
+    0x02, 0x5c, 0x02, 0x67, 0x00, 0x00, 0x00, 0x6b,
+    0x00, 0x6d, 0x00, 0x4b, 0x01, 0x6f, 0x00, 0x54,
+    0x02, 0x16, 0x1d, 0x17, 0x1d, 0x70, 0x00, 0x74,
+    0x00, 0x75, 0x00, 0x1d, 0x1d, 0x6f, 0x02, 0x76,
+    0x00, 0x25, 0x1d, 0xb2, 0x03, 0xb3, 0x03, 0xb4,
+    0x03, 0xc6, 0x03, 0xc7, 0x03, 0x69, 0x00, 0x72,
+    0x00, 0x75, 0x00, 0x76, 0x00, 0xb2, 0x03, 0xb3,
+    0x03, 0xc1, 0x03, 0xc6, 0x03, 0xc7, 0x03, 0x52,
+    0x02, 0x63, 0x00, 0x55, 0x02, 0xf0, 0x00, 0x5c,
+    0x02, 0x66, 0x00, 0x5f, 0x02, 0x61, 0x02, 0x65,
+    0x02, 0x68, 0x02, 0x69, 0x02, 0x6a, 0x02, 0x7b,
+    0x1d, 0x9d, 0x02, 0x6d, 0x02, 0x85, 0x1d, 0x9f,
+    0x02, 0x71, 0x02, 0x70, 0x02, 0x72, 0x02, 0x73,
+    0x02, 0x74, 0x02, 0x75, 0x02, 0x78, 0x02, 0x82,
+    0x02, 0x83, 0x02, 0xab, 0x01, 0x89, 0x02, 0x8a,
+    0x02, 0x1c, 0x1d, 0x8b, 0x02, 0x8c, 0x02, 0x7a,
+    0x00, 0x90, 0x02, 0x91, 0x02, 0x92, 0x02, 0xb8,
+    0x03, 0x41, 0x00, 0xa5, 0x42, 0x00, 0x87, 0x42,
+    0x00, 0xa3, 0x42, 0x00, 0xb1, 0xc7, 0x00, 0x81,
+    0x44, 0x00, 0x87, 0x44, 0x00, 0xa3, 0x44, 0x00,
+    0xb1, 0x44, 0x00, 0xa7, 0x44, 0x00, 0xad, 0x12,
+    0x01, 0x80, 0x12, 0x01, 0x81, 0x45, 0x00, 0xad,
+    0x45, 0x00, 0xb0, 0x28, 0x02, 0x86, 0x46, 0x00,
+    0x87, 0x47, 0x00, 0x84, 0x48, 0x00, 0x87, 0x48,
+    0x00, 0xa3, 0x48, 0x00, 0x88, 0x48, 0x00, 0xa7,
+    0x48, 0x00, 0xae, 0x49, 0x00, 0xb0, 0xcf, 0x00,
+    0x81, 0x4b, 0x00, 0x81, 0x4b, 0x00, 0xa3, 0x4b,
+    0x00, 0xb1, 0x4c, 0x00, 0xa3, 0x36, 0x1e, 0x84,
+    0x4c, 0xb1, 0x4c, 0xad, 0x4d, 0x81, 0x4d, 0x87,
+    0x4d, 0xa3, 0x4e, 0x87, 0x4e, 0xa3, 0x4e, 0xb1,
+    0x4e, 0xad, 0xd5, 0x00, 0x81, 0xd5, 0x00, 0x88,
+    0x4c, 0x01, 0x80, 0x4c, 0x01, 0x81, 0x50, 0x00,
+    0x81, 0x50, 0x00, 0x87, 0x52, 0x00, 0x87, 0x52,
+    0x00, 0xa3, 0x5a, 0x1e, 0x84, 0x52, 0x00, 0xb1,
+    0x53, 0x00, 0x87, 0x53, 0x00, 0xa3, 0x5a, 0x01,
+    0x87, 0x60, 0x01, 0x87, 0x62, 0x1e, 0x87, 0x54,
+    0x00, 0x87, 0x54, 0x00, 0xa3, 0x54, 0x00, 0xb1,
+    0x54, 0x00, 0xad, 0x55, 0x00, 0xa4, 0x55, 0x00,
+    0xb0, 0x55, 0x00, 0xad, 0x68, 0x01, 0x81, 0x6a,
+    0x01, 0x88, 0x56, 0x83, 0x56, 0xa3, 0x57, 0x80,
+    0x57, 0x81, 0x57, 0x88, 0x57, 0x87, 0x57, 0xa3,
+    0x58, 0x87, 0x58, 0x88, 0x59, 0x87, 0x5a, 0x82,
+    0x5a, 0xa3, 0x5a, 0xb1, 0x68, 0xb1, 0x74, 0x88,
+    0x77, 0x8a, 0x79, 0x8a, 0x61, 0x00, 0xbe, 0x02,
+    0x7f, 0x01, 0x87, 0x41, 0x00, 0xa3, 0x41, 0x00,
+    0x89, 0xc2, 0x00, 0x81, 0xc2, 0x00, 0x80, 0xc2,
+    0x00, 0x89, 0xc2, 0x00, 0x83, 0xa0, 0x1e, 0x82,
+    0x02, 0x01, 0x81, 0x02, 0x01, 0x80, 0x02, 0x01,
+    0x89, 0x02, 0x01, 0x83, 0xa0, 0x1e, 0x86, 0x45,
+    0x00, 0xa3, 0x45, 0x00, 0x89, 0x45, 0x00, 0x83,
+    0xca, 0x00, 0x81, 0xca, 0x00, 0x80, 0xca, 0x00,
+    0x89, 0xca, 0x00, 0x83, 0xb8, 0x1e, 0x82, 0x49,
+    0x00, 0x89, 0x49, 0x00, 0xa3, 0x4f, 0x00, 0xa3,
+    0x4f, 0x00, 0x89, 0xd4, 0x00, 0x81, 0xd4, 0x00,
+    0x80, 0xd4, 0x00, 0x89, 0xd4, 0x00, 0x83, 0xcc,
+    0x1e, 0x82, 0xa0, 0x01, 0x81, 0xa0, 0x01, 0x80,
+    0xa0, 0x01, 0x89, 0xa0, 0x01, 0x83, 0xa0, 0x01,
+    0xa3, 0x55, 0x00, 0xa3, 0x55, 0x00, 0x89, 0xaf,
+    0x01, 0x81, 0xaf, 0x01, 0x80, 0xaf, 0x01, 0x89,
+    0xaf, 0x01, 0x83, 0xaf, 0x01, 0xa3, 0x59, 0x00,
+    0x80, 0x59, 0x00, 0xa3, 0x59, 0x00, 0x89, 0x59,
+    0x00, 0x83, 0xb1, 0x03, 0x13, 0x03, 0x00, 0x1f,
+    0x80, 0x00, 0x1f, 0x81, 0x00, 0x1f, 0xc2, 0x91,
+    0x03, 0x13, 0x03, 0x08, 0x1f, 0x80, 0x08, 0x1f,
+    0x81, 0x08, 0x1f, 0xc2, 0xb5, 0x03, 0x13, 0x03,
+    0x10, 0x1f, 0x80, 0x10, 0x1f, 0x81, 0x95, 0x03,
+    0x13, 0x03, 0x18, 0x1f, 0x80, 0x18, 0x1f, 0x81,
+    0xb7, 0x03, 0x93, 0xb7, 0x03, 0x94, 0x20, 0x1f,
+    0x80, 0x21, 0x1f, 0x80, 0x20, 0x1f, 0x81, 0x21,
+    0x1f, 0x81, 0x20, 0x1f, 0xc2, 0x21, 0x1f, 0xc2,
+    0x97, 0x03, 0x93, 0x97, 0x03, 0x94, 0x28, 0x1f,
+    0x80, 0x29, 0x1f, 0x80, 0x28, 0x1f, 0x81, 0x29,
+    0x1f, 0x81, 0x28, 0x1f, 0xc2, 0x29, 0x1f, 0xc2,
+    0xb9, 0x03, 0x93, 0xb9, 0x03, 0x94, 0x30, 0x1f,
+    0x80, 0x31, 0x1f, 0x80, 0x30, 0x1f, 0x81, 0x31,
+    0x1f, 0x81, 0x30, 0x1f, 0xc2, 0x31, 0x1f, 0xc2,
+    0x99, 0x03, 0x93, 0x99, 0x03, 0x94, 0x38, 0x1f,
+    0x80, 0x39, 0x1f, 0x80, 0x38, 0x1f, 0x81, 0x39,
+    0x1f, 0x81, 0x38, 0x1f, 0xc2, 0x39, 0x1f, 0xc2,
+    0xbf, 0x03, 0x93, 0xbf, 0x03, 0x94, 0x40, 0x1f,
+    0x80, 0x40, 0x1f, 0x81, 0x9f, 0x03, 0x13, 0x03,
+    0x48, 0x1f, 0x80, 0x48, 0x1f, 0x81, 0xc5, 0x03,
+    0x13, 0x03, 0x50, 0x1f, 0x80, 0x50, 0x1f, 0x81,
+    0x50, 0x1f, 0xc2, 0xa5, 0x03, 0x94, 0x00, 0x00,
+    0x00, 0x59, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x59,
+    0x1f, 0x81, 0x00, 0x00, 0x00, 0x59, 0x1f, 0xc2,
+    0xc9, 0x03, 0x93, 0xc9, 0x03, 0x94, 0x60, 0x1f,
+    0x80, 0x61, 0x1f, 0x80, 0x60, 0x1f, 0x81, 0x61,
+    0x1f, 0x81, 0x60, 0x1f, 0xc2, 0x61, 0x1f, 0xc2,
+    0xa9, 0x03, 0x93, 0xa9, 0x03, 0x94, 0x68, 0x1f,
+    0x80, 0x69, 0x1f, 0x80, 0x68, 0x1f, 0x81, 0x69,
+    0x1f, 0x81, 0x68, 0x1f, 0xc2, 0x69, 0x1f, 0xc2,
+    0xb1, 0x03, 0x80, 0xb5, 0x03, 0x80, 0xb7, 0x03,
+    0x80, 0xb9, 0x03, 0x80, 0xbf, 0x03, 0x80, 0xc5,
+    0x03, 0x80, 0xc9, 0x03, 0x80, 0x00, 0x1f, 0x45,
+    0x03, 0x20, 0x1f, 0x45, 0x03, 0x60, 0x1f, 0x45,
+    0x03, 0xb1, 0x03, 0x86, 0xb1, 0x03, 0x84, 0x70,
+    0x1f, 0xc5, 0xb1, 0x03, 0xc5, 0xac, 0x03, 0xc5,
+    0x00, 0x00, 0x00, 0xb1, 0x03, 0xc2, 0xb6, 0x1f,
+    0xc5, 0x91, 0x03, 0x86, 0x91, 0x03, 0x84, 0x91,
+    0x03, 0x80, 0x91, 0x03, 0xc5, 0x20, 0x93, 0x20,
+    0x93, 0x20, 0xc2, 0xa8, 0x00, 0xc2, 0x74, 0x1f,
+    0xc5, 0xb7, 0x03, 0xc5, 0xae, 0x03, 0xc5, 0x00,
+    0x00, 0x00, 0xb7, 0x03, 0xc2, 0xc6, 0x1f, 0xc5,
+    0x95, 0x03, 0x80, 0x97, 0x03, 0x80, 0x97, 0x03,
+    0xc5, 0xbf, 0x1f, 0x80, 0xbf, 0x1f, 0x81, 0xbf,
+    0x1f, 0xc2, 0xb9, 0x03, 0x86, 0xb9, 0x03, 0x84,
+    0xca, 0x03, 0x80, 0x00, 0x03, 0xb9, 0x42, 0xca,
+    0x42, 0x99, 0x06, 0x99, 0x04, 0x99, 0x00, 0xfe,
+    0x1f, 0x80, 0xfe, 0x1f, 0x81, 0xfe, 0x1f, 0xc2,
+    0xc5, 0x03, 0x86, 0xc5, 0x03, 0x84, 0xcb, 0x03,
+    0x80, 0x00, 0x03, 0xc1, 0x13, 0xc1, 0x14, 0xc5,
+    0x42, 0xcb, 0x42, 0xa5, 0x06, 0xa5, 0x04, 0xa5,
+    0x00, 0xa1, 0x03, 0x94, 0xa8, 0x00, 0x80, 0x85,
+    0x03, 0x60, 0x00, 0x7c, 0x1f, 0xc5, 0xc9, 0x03,
+    0xc5, 0xce, 0x03, 0xc5, 0x00, 0x00, 0x00, 0xc9,
+    0x03, 0xc2, 0xf6, 0x1f, 0xc5, 0x9f, 0x03, 0x80,
+    0xa9, 0x03, 0x80, 0xa9, 0x03, 0xc5, 0x20, 0x94,
+    0x02, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+    0x20, 0x20, 0x20, 0x20, 0xb3, 0x2e, 0x2e, 0x2e,
+    0x2e, 0x2e, 0x32, 0x20, 0x32, 0x20, 0x32, 0x20,
+    0x00, 0x00, 0x00, 0x35, 0x20, 0x35, 0x20, 0x35,
+    0x20, 0x00, 0x00, 0x00, 0x21, 0x21, 0x00, 0x00,
+    0x20, 0x85, 0x3f, 0x3f, 0x3f, 0x21, 0x21, 0x3f,
+    0x32, 0x20, 0x00, 0x00, 0x00, 0x00, 0x30, 0x69,
+    0x00, 0x00, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+    0x2b, 0x3d, 0x28, 0x29, 0x6e, 0x30, 0x00, 0x2b,
+    0x00, 0x12, 0x22, 0x3d, 0x00, 0x28, 0x00, 0x29,
+    0x00, 0x00, 0x00, 0x61, 0x00, 0x65, 0x00, 0x6f,
+    0x00, 0x78, 0x00, 0x59, 0x02, 0x68, 0x6b, 0x6c,
+    0x6d, 0x6e, 0x70, 0x73, 0x74, 0x52, 0x73, 0x61,
+    0x2f, 0x63, 0x61, 0x2f, 0x73, 0xb0, 0x00, 0x43,
+    0x63, 0x2f, 0x6f, 0x63, 0x2f, 0x75, 0xb0, 0x00,
+    0x46, 0x48, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20,
+    0xdf, 0x01, 0x01, 0x04, 0x24, 0x4e, 0x6f, 0x50,
+    0x51, 0x52, 0x52, 0x52, 0x53, 0x4d, 0x54, 0x45,
+    0x4c, 0x54, 0x4d, 0x4b, 0x00, 0xc5, 0x00, 0x42,
+    0x43, 0x00, 0x65, 0x45, 0x46, 0x00, 0x4d, 0x6f,
+    0xd0, 0x05, 0x46, 0x41, 0x58, 0xc0, 0x03, 0xb3,
+    0x03, 0x93, 0x03, 0xa0, 0x03, 0x11, 0x22, 0x44,
+    0x64, 0x65, 0x69, 0x6a, 0x31, 0xd0, 0x37, 0x31,
+    0xd0, 0x39, 0x31, 0xd0, 0x31, 0x30, 0x31, 0xd0,
+    0x33, 0x32, 0xd0, 0x33, 0x31, 0xd0, 0x35, 0x32,
+    0xd0, 0x35, 0x33, 0xd0, 0x35, 0x34, 0xd0, 0x35,
+    0x31, 0xd0, 0x36, 0x35, 0xd0, 0x36, 0x31, 0xd0,
+    0x38, 0x33, 0xd0, 0x38, 0x35, 0xd0, 0x38, 0x37,
+    0xd0, 0x38, 0x31, 0xd0, 0x49, 0x49, 0x49, 0x49,
+    0x49, 0x49, 0x56, 0x56, 0x49, 0x56, 0x49, 0x49,
+    0x56, 0x49, 0x49, 0x49, 0x49, 0x58, 0x58, 0x49,
+    0x58, 0x49, 0x49, 0x4c, 0x43, 0x44, 0x4d, 0x69,
+    0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x76, 0x76,
+    0x69, 0x76, 0x69, 0x69, 0x76, 0x69, 0x69, 0x69,
+    0x69, 0x78, 0x78, 0x69, 0x78, 0x69, 0x69, 0x6c,
+    0x63, 0x64, 0x6d, 0x30, 0xd0, 0x33, 0x90, 0x21,
+    0xb8, 0x92, 0x21, 0xb8, 0x94, 0x21, 0xb8, 0xd0,
+    0x21, 0xb8, 0xd4, 0x21, 0xb8, 0xd2, 0x21, 0xb8,
+    0x03, 0x22, 0xb8, 0x08, 0x22, 0xb8, 0x0b, 0x22,
+    0xb8, 0x23, 0x22, 0xb8, 0x00, 0x00, 0x00, 0x25,
+    0x22, 0xb8, 0x2b, 0x22, 0x2b, 0x22, 0x2b, 0x22,
+    0x00, 0x00, 0x00, 0x2e, 0x22, 0x2e, 0x22, 0x2e,
+    0x22, 0x00, 0x00, 0x00, 0x3c, 0x22, 0xb8, 0x43,
+    0x22, 0xb8, 0x45, 0x22, 0xb8, 0x00, 0x00, 0x00,
+    0x48, 0x22, 0xb8, 0x3d, 0x00, 0xb8, 0x00, 0x00,
+    0x00, 0x61, 0x22, 0xb8, 0x4d, 0x22, 0xb8, 0x3c,
+    0x00, 0xb8, 0x3e, 0x00, 0xb8, 0x64, 0x22, 0xb8,
+    0x65, 0x22, 0xb8, 0x72, 0x22, 0xb8, 0x76, 0x22,
+    0xb8, 0x7a, 0x22, 0xb8, 0x82, 0x22, 0xb8, 0x86,
+    0x22, 0xb8, 0xa2, 0x22, 0xb8, 0xa8, 0x22, 0xb8,
+    0xa9, 0x22, 0xb8, 0xab, 0x22, 0xb8, 0x7c, 0x22,
+    0xb8, 0x91, 0x22, 0xb8, 0xb2, 0x22, 0x38, 0x03,
+    0x08, 0x30, 0x31, 0x00, 0x31, 0x00, 0x30, 0x00,
+    0x32, 0x30, 0x28, 0x00, 0x31, 0x00, 0x29, 0x00,
+    0x28, 0x00, 0x31, 0x00, 0x30, 0x00, 0x29, 0x00,
+    0x28, 0x32, 0x30, 0x29, 0x31, 0x00, 0x2e, 0x00,
+    0x31, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x32, 0x30,
+    0x2e, 0x28, 0x00, 0x61, 0x00, 0x29, 0x00, 0x41,
+    0x00, 0x61, 0x00, 0x2b, 0x22, 0x00, 0x00, 0x00,
+    0x00, 0x3a, 0x3a, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
+    0x3d, 0xdd, 0x2a, 0xb8, 0x6a, 0x56, 0x00, 0x4e,
+    0x00, 0x28, 0x36, 0x3f, 0x59, 0x85, 0x8c, 0xa0,
+    0xba, 0x3f, 0x51, 0x00, 0x26, 0x2c, 0x43, 0x57,
+    0x6c, 0xa1, 0xb6, 0xc1, 0x9b, 0x52, 0x00, 0x5e,
+    0x7a, 0x7f, 0x9d, 0xa6, 0xc1, 0xce, 0xe7, 0xb6,
+    0x53, 0xc8, 0x53, 0xe3, 0x53, 0xd7, 0x56, 0x1f,
+    0x57, 0xeb, 0x58, 0x02, 0x59, 0x0a, 0x59, 0x15,
+    0x59, 0x27, 0x59, 0x73, 0x59, 0x50, 0x5b, 0x80,
+    0x5b, 0xf8, 0x5b, 0x0f, 0x5c, 0x22, 0x5c, 0x38,
+    0x5c, 0x6e, 0x5c, 0x71, 0x5c, 0xdb, 0x5d, 0xe5,
+    0x5d, 0xf1, 0x5d, 0xfe, 0x5d, 0x72, 0x5e, 0x7a,
+    0x5e, 0x7f, 0x5e, 0xf4, 0x5e, 0xfe, 0x5e, 0x0b,
+    0x5f, 0x13, 0x5f, 0x50, 0x5f, 0x61, 0x5f, 0x73,
+    0x5f, 0xc3, 0x5f, 0x08, 0x62, 0x36, 0x62, 0x4b,
+    0x62, 0x2f, 0x65, 0x34, 0x65, 0x87, 0x65, 0x97,
+    0x65, 0xa4, 0x65, 0xb9, 0x65, 0xe0, 0x65, 0xe5,
+    0x65, 0xf0, 0x66, 0x08, 0x67, 0x28, 0x67, 0x20,
+    0x6b, 0x62, 0x6b, 0x79, 0x6b, 0xb3, 0x6b, 0xcb,
+    0x6b, 0xd4, 0x6b, 0xdb, 0x6b, 0x0f, 0x6c, 0x14,
+    0x6c, 0x34, 0x6c, 0x6b, 0x70, 0x2a, 0x72, 0x36,
+    0x72, 0x3b, 0x72, 0x3f, 0x72, 0x47, 0x72, 0x59,
+    0x72, 0x5b, 0x72, 0xac, 0x72, 0x84, 0x73, 0x89,
+    0x73, 0xdc, 0x74, 0xe6, 0x74, 0x18, 0x75, 0x1f,
+    0x75, 0x28, 0x75, 0x30, 0x75, 0x8b, 0x75, 0x92,
+    0x75, 0x76, 0x76, 0x7d, 0x76, 0xae, 0x76, 0xbf,
+    0x76, 0xee, 0x76, 0xdb, 0x77, 0xe2, 0x77, 0xf3,
+    0x77, 0x3a, 0x79, 0xb8, 0x79, 0xbe, 0x79, 0x74,
+    0x7a, 0xcb, 0x7a, 0xf9, 0x7a, 0x73, 0x7c, 0xf8,
+    0x7c, 0x36, 0x7f, 0x51, 0x7f, 0x8a, 0x7f, 0xbd,
+    0x7f, 0x01, 0x80, 0x0c, 0x80, 0x12, 0x80, 0x33,
+    0x80, 0x7f, 0x80, 0x89, 0x80, 0xe3, 0x81, 0x00,
+    0x07, 0x10, 0x19, 0x29, 0x38, 0x3c, 0x8b, 0x8f,
+    0x95, 0x4d, 0x86, 0x6b, 0x86, 0x40, 0x88, 0x4c,
+    0x88, 0x63, 0x88, 0x7e, 0x89, 0x8b, 0x89, 0xd2,
+    0x89, 0x00, 0x8a, 0x37, 0x8c, 0x46, 0x8c, 0x55,
+    0x8c, 0x78, 0x8c, 0x9d, 0x8c, 0x64, 0x8d, 0x70,
+    0x8d, 0xb3, 0x8d, 0xab, 0x8e, 0xca, 0x8e, 0x9b,
+    0x8f, 0xb0, 0x8f, 0xb5, 0x8f, 0x91, 0x90, 0x49,
+    0x91, 0xc6, 0x91, 0xcc, 0x91, 0xd1, 0x91, 0x77,
+    0x95, 0x80, 0x95, 0x1c, 0x96, 0xb6, 0x96, 0xb9,
+    0x96, 0xe8, 0x96, 0x51, 0x97, 0x5e, 0x97, 0x62,
+    0x97, 0x69, 0x97, 0xcb, 0x97, 0xed, 0x97, 0xf3,
+    0x97, 0x01, 0x98, 0xa8, 0x98, 0xdb, 0x98, 0xdf,
+    0x98, 0x96, 0x99, 0x99, 0x99, 0xac, 0x99, 0xa8,
+    0x9a, 0xd8, 0x9a, 0xdf, 0x9a, 0x25, 0x9b, 0x2f,
+    0x9b, 0x32, 0x9b, 0x3c, 0x9b, 0x5a, 0x9b, 0xe5,
+    0x9c, 0x75, 0x9e, 0x7f, 0x9e, 0xa5, 0x9e, 0x00,
+    0x16, 0x1e, 0x28, 0x2c, 0x54, 0x58, 0x69, 0x6e,
+    0x7b, 0x96, 0xa5, 0xad, 0xe8, 0xf7, 0xfb, 0x12,
+    0x30, 0x00, 0x00, 0x41, 0x53, 0x44, 0x53, 0x45,
+    0x53, 0x4b, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
+    0x00, 0x4d, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
+    0x00, 0x4f, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
+    0x00, 0x51, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
+    0x00, 0x53, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
+    0x00, 0x55, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
+    0x00, 0x57, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
+    0x00, 0x59, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
+    0x00, 0x5b, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
+    0x00, 0x5d, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
+    0x00, 0x5f, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
+    0x00, 0x61, 0x30, 0x99, 0x30, 0x64, 0x30, 0x99,
+    0x30, 0x00, 0x00, 0x00, 0x00, 0x66, 0x30, 0x99,
+    0x30, 0x00, 0x00, 0x00, 0x00, 0x68, 0x30, 0x99,
+    0x30, 0x6f, 0x30, 0x99, 0x30, 0x72, 0x30, 0x99,
+    0x30, 0x75, 0x30, 0x99, 0x30, 0x78, 0x30, 0x99,
+    0x30, 0x7b, 0x30, 0x99, 0x30, 0x46, 0x30, 0x99,
+    0x30, 0x20, 0x00, 0x99, 0x30, 0x9d, 0x30, 0x99,
+    0x30, 0x88, 0x30, 0x8a, 0x30, 0xab, 0x30, 0x99,
+    0x30, 0x00, 0x00, 0x00, 0x00, 0xad, 0x30, 0x99,
+    0x30, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x30, 0x99,
+    0x30, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x30, 0x99,
+    0x30, 0x00, 0x00, 0x00, 0x00, 0xb3, 0x30, 0x99,
+    0x30, 0x00, 0x00, 0x00, 0x00, 0xb5, 0x30, 0x99,
+    0x30, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x30, 0x99,
+    0x30, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x30, 0x99,
+    0x30, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x30, 0x99,
+    0x30, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x30, 0x99,
+    0x30, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x30, 0x99,
+    0x30, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x30, 0x99,
+    0x30, 0xc4, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
+    0x00, 0xc6, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
+    0x00, 0xc8, 0x30, 0x99, 0x30, 0xcf, 0x30, 0x99,
+    0x30, 0xd2, 0x30, 0x99, 0x30, 0xd5, 0x30, 0x99,
+    0x30, 0xd8, 0x30, 0x99, 0x30, 0xdb, 0x30, 0x99,
+    0x30, 0xa6, 0x30, 0x99, 0x30, 0xef, 0x30, 0x99,
+    0x30, 0xfd, 0x30, 0x99, 0x30, 0xb3, 0x30, 0xc8,
+    0x30, 0x00, 0x11, 0x00, 0x01, 0xaa, 0x02, 0xac,
+    0xad, 0x03, 0x04, 0x05, 0xb0, 0xb1, 0xb2, 0xb3,
+    0xb4, 0xb5, 0x1a, 0x06, 0x07, 0x08, 0x21, 0x09,
+    0x11, 0x61, 0x11, 0x14, 0x11, 0x4c, 0x00, 0x01,
+    0xb3, 0xb4, 0xb8, 0xba, 0xbf, 0xc3, 0xc5, 0x08,
+    0xc9, 0xcb, 0x09, 0x0a, 0x0c, 0x0e, 0x0f, 0x13,
+    0x15, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x22,
+    0x2c, 0x33, 0x38, 0xdd, 0xde, 0x43, 0x44, 0x45,
+    0x70, 0x71, 0x74, 0x7d, 0x7e, 0x80, 0x8a, 0x8d,
+    0x00, 0x4e, 0x8c, 0x4e, 0x09, 0x4e, 0xdb, 0x56,
+    0x0a, 0x4e, 0x2d, 0x4e, 0x0b, 0x4e, 0x32, 0x75,
+    0x59, 0x4e, 0x19, 0x4e, 0x01, 0x4e, 0x29, 0x59,
+    0x30, 0x57, 0xba, 0x4e, 0x28, 0x00, 0x29, 0x00,
+    0x00, 0x11, 0x02, 0x11, 0x03, 0x11, 0x05, 0x11,
+    0x06, 0x11, 0x07, 0x11, 0x09, 0x11, 0x0b, 0x11,
+    0x0c, 0x11, 0x0e, 0x11, 0x0f, 0x11, 0x10, 0x11,
+    0x11, 0x11, 0x12, 0x11, 0x28, 0x00, 0x00, 0x11,
+    0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x02, 0x11,
+    0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x05, 0x11,
+    0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x09, 0x11,
+    0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11,
+    0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0e, 0x11,
+    0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0c, 0x11,
+    0x6e, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11,
+    0x69, 0x11, 0x0c, 0x11, 0x65, 0x11, 0xab, 0x11,
+    0x29, 0x00, 0x28, 0x00, 0x0b, 0x11, 0x69, 0x11,
+    0x12, 0x11, 0x6e, 0x11, 0x29, 0x00, 0x28, 0x00,
+    0x29, 0x00, 0x00, 0x4e, 0x8c, 0x4e, 0x09, 0x4e,
+    0xdb, 0x56, 0x94, 0x4e, 0x6d, 0x51, 0x03, 0x4e,
+    0x6b, 0x51, 0x5d, 0x4e, 0x41, 0x53, 0x08, 0x67,
+    0x6b, 0x70, 0x34, 0x6c, 0x28, 0x67, 0xd1, 0x91,
+    0x1f, 0x57, 0xe5, 0x65, 0x2a, 0x68, 0x09, 0x67,
+    0x3e, 0x79, 0x0d, 0x54, 0x79, 0x72, 0xa1, 0x8c,
+    0x5d, 0x79, 0xb4, 0x52, 0xe3, 0x4e, 0x7c, 0x54,
+    0x66, 0x5b, 0xe3, 0x76, 0x01, 0x4f, 0xc7, 0x8c,
+    0x54, 0x53, 0x6d, 0x79, 0x11, 0x4f, 0xea, 0x81,
+    0xf3, 0x81, 0x4f, 0x55, 0x7c, 0x5e, 0x87, 0x65,
+    0x8f, 0x7b, 0x50, 0x54, 0x45, 0x32, 0x00, 0x31,
+    0x00, 0x33, 0x00, 0x30, 0x00, 0x00, 0x11, 0x00,
+    0x02, 0x03, 0x05, 0x06, 0x07, 0x09, 0x0b, 0x0c,
+    0x0e, 0x0f, 0x10, 0x11, 0x12, 0x00, 0x11, 0x00,
+    0x61, 0x02, 0x61, 0x03, 0x61, 0x05, 0x61, 0x06,
+    0x61, 0x07, 0x61, 0x09, 0x61, 0x0b, 0x61, 0x0c,
+    0x61, 0x0e, 0x11, 0x61, 0x11, 0x00, 0x11, 0x0e,
+    0x61, 0xb7, 0x00, 0x69, 0x0b, 0x11, 0x01, 0x63,
+    0x00, 0x69, 0x0b, 0x11, 0x6e, 0x11, 0x00, 0x4e,
+    0x8c, 0x4e, 0x09, 0x4e, 0xdb, 0x56, 0x94, 0x4e,
+    0x6d, 0x51, 0x03, 0x4e, 0x6b, 0x51, 0x5d, 0x4e,
+    0x41, 0x53, 0x08, 0x67, 0x6b, 0x70, 0x34, 0x6c,
+    0x28, 0x67, 0xd1, 0x91, 0x1f, 0x57, 0xe5, 0x65,
+    0x2a, 0x68, 0x09, 0x67, 0x3e, 0x79, 0x0d, 0x54,
+    0x79, 0x72, 0xa1, 0x8c, 0x5d, 0x79, 0xb4, 0x52,
+    0xd8, 0x79, 0x37, 0x75, 0x73, 0x59, 0x69, 0x90,
+    0x2a, 0x51, 0x70, 0x53, 0xe8, 0x6c, 0x05, 0x98,
+    0x11, 0x4f, 0x99, 0x51, 0x63, 0x6b, 0x0a, 0x4e,
+    0x2d, 0x4e, 0x0b, 0x4e, 0xe6, 0x5d, 0xf3, 0x53,
+    0x3b, 0x53, 0x97, 0x5b, 0x66, 0x5b, 0xe3, 0x76,
+    0x01, 0x4f, 0xc7, 0x8c, 0x54, 0x53, 0x1c, 0x59,
+    0x33, 0x00, 0x36, 0x00, 0x34, 0x00, 0x30, 0x00,
+    0x35, 0x30, 0x31, 0x00, 0x08, 0x67, 0x31, 0x00,
+    0x30, 0x00, 0x08, 0x67, 0x48, 0x67, 0x65, 0x72,
+    0x67, 0x65, 0x56, 0x4c, 0x54, 0x44, 0xa2, 0x30,
+    0x00, 0x02, 0x04, 0x06, 0x08, 0x09, 0x0b, 0x0d,
+    0x0f, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1b, 0x1d,
+    0x1f, 0x22, 0x24, 0x26, 0x28, 0x29, 0x2a, 0x2b,
+    0x2c, 0x2d, 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3d,
+    0x3e, 0x3f, 0x40, 0x42, 0x44, 0x46, 0x47, 0x48,
+    0x49, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x50, 0xe4,
+    0x4e, 0x8c, 0x54, 0xa1, 0x30, 0x01, 0x30, 0x5b,
+    0x27, 0x01, 0x4a, 0x34, 0x00, 0x01, 0x52, 0x39,
+    0x01, 0xa2, 0x30, 0x00, 0x5a, 0x49, 0xa4, 0x30,
+    0x00, 0x27, 0x4f, 0x0c, 0xa4, 0x30, 0x00, 0x4f,
+    0x1d, 0x02, 0x05, 0x4f, 0xa8, 0x30, 0x00, 0x11,
+    0x07, 0x54, 0x21, 0xa8, 0x30, 0x00, 0x54, 0x03,
+    0x54, 0xa4, 0x30, 0x06, 0x4f, 0x15, 0x06, 0x58,
+    0x3c, 0x07, 0x00, 0x46, 0xab, 0x30, 0x00, 0x3e,
+    0x18, 0x1d, 0x00, 0x42, 0x3f, 0x51, 0xac, 0x30,
+    0x00, 0x41, 0x47, 0x00, 0x47, 0x32, 0xae, 0x30,
+    0xac, 0x30, 0xae, 0x30, 0x00, 0x1d, 0x4e, 0xad,
+    0x30, 0x00, 0x38, 0x3d, 0x4f, 0x01, 0x3e, 0x13,
+    0x4f, 0xad, 0x30, 0xed, 0x30, 0xad, 0x30, 0x00,
+    0x40, 0x03, 0x3c, 0x33, 0xad, 0x30, 0x00, 0x40,
+    0x34, 0x4f, 0x1b, 0x3e, 0xad, 0x30, 0x00, 0x40,
+    0x42, 0x16, 0x1b, 0xb0, 0x30, 0x00, 0x39, 0x30,
+    0xa4, 0x30, 0x0c, 0x45, 0x3c, 0x24, 0x4f, 0x0b,
+    0x47, 0x18, 0x00, 0x49, 0xaf, 0x30, 0x00, 0x3e,
+    0x4d, 0x1e, 0xb1, 0x30, 0x00, 0x4b, 0x08, 0x02,
+    0x3a, 0x19, 0x02, 0x4b, 0x2c, 0xa4, 0x30, 0x11,
+    0x00, 0x0b, 0x47, 0xb5, 0x30, 0x00, 0x3e, 0x0c,
+    0x47, 0x2b, 0xb0, 0x30, 0x07, 0x3a, 0x43, 0x00,
+    0xb9, 0x30, 0x02, 0x3a, 0x08, 0x02, 0x3a, 0x0f,
+    0x07, 0x43, 0x00, 0xb7, 0x30, 0x10, 0x00, 0x12,
+    0x34, 0x11, 0x3c, 0x13, 0x17, 0xa4, 0x30, 0x2a,
+    0x1f, 0x24, 0x2b, 0x00, 0x20, 0xbb, 0x30, 0x16,
+    0x41, 0x00, 0x38, 0x0d, 0xc4, 0x30, 0x0d, 0x38,
+    0x00, 0xd0, 0x30, 0x00, 0x2c, 0x1c, 0x1b, 0xa2,
+    0x30, 0x32, 0x00, 0x17, 0x26, 0x49, 0xaf, 0x30,
+    0x25, 0x00, 0x3c, 0xb3, 0x30, 0x21, 0x00, 0x20,
+    0x38, 0xa1, 0x30, 0x34, 0x00, 0x48, 0x22, 0x28,
+    0xa3, 0x30, 0x32, 0x00, 0x59, 0x25, 0xa7, 0x30,
+    0x2f, 0x1c, 0x10, 0x00, 0x44, 0xd5, 0x30, 0x00,
+    0x14, 0x1e, 0xaf, 0x30, 0x29, 0x00, 0x10, 0x4d,
+    0x3c, 0xda, 0x30, 0xbd, 0x30, 0xb8, 0x30, 0x22,
+    0x13, 0x1a, 0x20, 0x33, 0x0c, 0x22, 0x3b, 0x01,
+    0x22, 0x44, 0x00, 0x21, 0x44, 0x07, 0xa4, 0x30,
+    0x39, 0x00, 0x4f, 0x24, 0xc8, 0x30, 0x14, 0x23,
+    0x00, 0xdb, 0x30, 0xf3, 0x30, 0xc9, 0x30, 0x14,
+    0x2a, 0x00, 0x12, 0x33, 0x22, 0x12, 0x33, 0x2a,
+    0xa4, 0x30, 0x3a, 0x00, 0x0b, 0x49, 0xa4, 0x30,
+    0x3a, 0x00, 0x47, 0x3a, 0x1f, 0x2b, 0x3a, 0x47,
+    0x0b, 0xb7, 0x30, 0x27, 0x3c, 0x00, 0x30, 0x3c,
+    0xaf, 0x30, 0x30, 0x00, 0x3e, 0x44, 0xdf, 0x30,
+    0xea, 0x30, 0xd0, 0x30, 0x0f, 0x1a, 0x00, 0x2c,
+    0x1b, 0xe1, 0x30, 0xac, 0x30, 0xac, 0x30, 0x35,
+    0x00, 0x1c, 0x47, 0x35, 0x50, 0x1c, 0x3f, 0xa2,
+    0x30, 0x42, 0x5a, 0x27, 0x42, 0x5a, 0x49, 0x44,
+    0x00, 0x51, 0xc3, 0x30, 0x27, 0x00, 0x05, 0x28,
+    0xea, 0x30, 0xe9, 0x30, 0xd4, 0x30, 0x17, 0x00,
+    0x28, 0xd6, 0x30, 0x15, 0x26, 0x00, 0x15, 0xec,
+    0x30, 0xe0, 0x30, 0xb2, 0x30, 0x3a, 0x41, 0x16,
+    0x00, 0x41, 0xc3, 0x30, 0x2c, 0x00, 0x05, 0x30,
+    0x00, 0xb9, 0x70, 0x31, 0x00, 0x30, 0x00, 0xb9,
+    0x70, 0x32, 0x00, 0x30, 0x00, 0xb9, 0x70, 0x68,
+    0x50, 0x61, 0x64, 0x61, 0x41, 0x55, 0x62, 0x61,
+    0x72, 0x6f, 0x56, 0x70, 0x63, 0x64, 0x6d, 0x64,
+    0x00, 0x6d, 0x00, 0xb2, 0x00, 0x49, 0x00, 0x55,
+    0x00, 0x73, 0x5e, 0x10, 0x62, 0x2d, 0x66, 0x8c,
+    0x54, 0x27, 0x59, 0x63, 0x6b, 0x0e, 0x66, 0xbb,
+    0x6c, 0x2a, 0x68, 0x0f, 0x5f, 0x1a, 0x4f, 0x3e,
+    0x79, 0x70, 0x00, 0x41, 0x6e, 0x00, 0x41, 0xbc,
+    0x03, 0x41, 0x6d, 0x00, 0x41, 0x6b, 0x00, 0x41,
+    0x4b, 0x00, 0x42, 0x4d, 0x00, 0x42, 0x47, 0x00,
+    0x42, 0x63, 0x61, 0x6c, 0x6b, 0x63, 0x61, 0x6c,
+    0x70, 0x00, 0x46, 0x6e, 0x00, 0x46, 0xbc, 0x03,
+    0x46, 0xbc, 0x03, 0x67, 0x6d, 0x00, 0x67, 0x6b,
+    0x00, 0x67, 0x48, 0x00, 0x7a, 0x6b, 0x48, 0x7a,
+    0x4d, 0x48, 0x7a, 0x47, 0x48, 0x7a, 0x54, 0x48,
+    0x7a, 0xbc, 0x03, 0x13, 0x21, 0x6d, 0x00, 0x13,
+    0x21, 0x64, 0x00, 0x13, 0x21, 0x6b, 0x00, 0x13,
+    0x21, 0x66, 0x00, 0x6d, 0x6e, 0x00, 0x6d, 0xbc,
+    0x03, 0x6d, 0x6d, 0x00, 0x6d, 0x63, 0x00, 0x6d,
+    0x6b, 0x00, 0x6d, 0x63, 0x00, 0x0a, 0x0a, 0x4f,
+    0x00, 0x0a, 0x4f, 0x6d, 0x00, 0xb2, 0x00, 0x63,
+    0x00, 0x08, 0x0a, 0x4f, 0x0a, 0x0a, 0x50, 0x00,
+    0x0a, 0x50, 0x6d, 0x00, 0xb3, 0x00, 0x6b, 0x00,
+    0x6d, 0x00, 0xb3, 0x00, 0x6d, 0x00, 0x15, 0x22,
+    0x73, 0x00, 0x6d, 0x00, 0x15, 0x22, 0x73, 0x00,
+    0xb2, 0x00, 0x50, 0x61, 0x6b, 0x50, 0x61, 0x4d,
+    0x50, 0x61, 0x47, 0x50, 0x61, 0x72, 0x61, 0x64,
+    0x72, 0x61, 0x64, 0xd1, 0x73, 0x72, 0x00, 0x61,
+    0x00, 0x64, 0x00, 0x15, 0x22, 0x73, 0x00, 0xb2,
+    0x00, 0x70, 0x00, 0x73, 0x6e, 0x00, 0x73, 0xbc,
+    0x03, 0x73, 0x6d, 0x00, 0x73, 0x70, 0x00, 0x56,
+    0x6e, 0x00, 0x56, 0xbc, 0x03, 0x56, 0x6d, 0x00,
+    0x56, 0x6b, 0x00, 0x56, 0x4d, 0x00, 0x56, 0x70,
+    0x00, 0x57, 0x6e, 0x00, 0x57, 0xbc, 0x03, 0x57,
+    0x6d, 0x00, 0x57, 0x6b, 0x00, 0x57, 0x4d, 0x00,
+    0x57, 0x6b, 0x00, 0xa9, 0x03, 0x4d, 0x00, 0xa9,
+    0x03, 0x61, 0x2e, 0x6d, 0x2e, 0x42, 0x71, 0x63,
+    0x63, 0x63, 0x64, 0x43, 0xd1, 0x6b, 0x67, 0x43,
+    0x6f, 0x2e, 0x64, 0x42, 0x47, 0x79, 0x68, 0x61,
+    0x48, 0x50, 0x69, 0x6e, 0x4b, 0x4b, 0x4b, 0x4d,
+    0x6b, 0x74, 0x6c, 0x6d, 0x6c, 0x6e, 0x6c, 0x6f,
+    0x67, 0x6c, 0x78, 0x6d, 0x62, 0x6d, 0x69, 0x6c,
+    0x6d, 0x6f, 0x6c, 0x50, 0x48, 0x70, 0x2e, 0x6d,
+    0x2e, 0x50, 0x50, 0x4d, 0x50, 0x52, 0x73, 0x72,
+    0x53, 0x76, 0x57, 0x62, 0x56, 0xd1, 0x6d, 0x41,
+    0xd1, 0x6d, 0x31, 0x00, 0xe5, 0x65, 0x31, 0x00,
+    0x30, 0x00, 0xe5, 0x65, 0x32, 0x00, 0x30, 0x00,
+    0xe5, 0x65, 0x33, 0x00, 0x30, 0x00, 0xe5, 0x65,
+    0x67, 0x61, 0x6c, 0x4a, 0x04, 0x4c, 0x04, 0x26,
+    0x01, 0x53, 0x01, 0x27, 0xa7, 0x37, 0xab, 0x6b,
+    0x02, 0x52, 0xab, 0x48, 0x8c, 0xf4, 0x66, 0xca,
+    0x8e, 0xc8, 0x8c, 0xd1, 0x6e, 0x32, 0x4e, 0xe5,
+    0x53, 0x9c, 0x9f, 0x9c, 0x9f, 0x51, 0x59, 0xd1,
+    0x91, 0x87, 0x55, 0x48, 0x59, 0xf6, 0x61, 0x69,
+    0x76, 0x85, 0x7f, 0x3f, 0x86, 0xba, 0x87, 0xf8,
+    0x88, 0x8f, 0x90, 0x02, 0x6a, 0x1b, 0x6d, 0xd9,
+    0x70, 0xde, 0x73, 0x3d, 0x84, 0x6a, 0x91, 0xf1,
+    0x99, 0x82, 0x4e, 0x75, 0x53, 0x04, 0x6b, 0x1b,
+    0x72, 0x2d, 0x86, 0x1e, 0x9e, 0x50, 0x5d, 0xeb,
+    0x6f, 0xcd, 0x85, 0x64, 0x89, 0xc9, 0x62, 0xd8,
+    0x81, 0x1f, 0x88, 0xca, 0x5e, 0x17, 0x67, 0x6a,
+    0x6d, 0xfc, 0x72, 0xce, 0x90, 0x86, 0x4f, 0xb7,
+    0x51, 0xde, 0x52, 0xc4, 0x64, 0xd3, 0x6a, 0x10,
+    0x72, 0xe7, 0x76, 0x01, 0x80, 0x06, 0x86, 0x5c,
+    0x86, 0xef, 0x8d, 0x32, 0x97, 0x6f, 0x9b, 0xfa,
+    0x9d, 0x8c, 0x78, 0x7f, 0x79, 0xa0, 0x7d, 0xc9,
+    0x83, 0x04, 0x93, 0x7f, 0x9e, 0xd6, 0x8a, 0xdf,
+    0x58, 0x04, 0x5f, 0x60, 0x7c, 0x7e, 0x80, 0x62,
+    0x72, 0xca, 0x78, 0xc2, 0x8c, 0xf7, 0x96, 0xd8,
+    0x58, 0x62, 0x5c, 0x13, 0x6a, 0xda, 0x6d, 0x0f,
+    0x6f, 0x2f, 0x7d, 0x37, 0x7e, 0x4b, 0x96, 0xd2,
+    0x52, 0x8b, 0x80, 0xdc, 0x51, 0xcc, 0x51, 0x1c,
+    0x7a, 0xbe, 0x7d, 0xf1, 0x83, 0x75, 0x96, 0x80,
+    0x8b, 0xcf, 0x62, 0x02, 0x6a, 0xfe, 0x8a, 0x39,
+    0x4e, 0xe7, 0x5b, 0x12, 0x60, 0x87, 0x73, 0x70,
+    0x75, 0x17, 0x53, 0xfb, 0x78, 0xbf, 0x4f, 0xa9,
+    0x5f, 0x0d, 0x4e, 0xcc, 0x6c, 0x78, 0x65, 0x22,
+    0x7d, 0xc3, 0x53, 0x5e, 0x58, 0x01, 0x77, 0x49,
+    0x84, 0xaa, 0x8a, 0xba, 0x6b, 0xb0, 0x8f, 0x88,
+    0x6c, 0xfe, 0x62, 0xe5, 0x82, 0xa0, 0x63, 0x65,
+    0x75, 0xae, 0x4e, 0x69, 0x51, 0xc9, 0x51, 0x81,
+    0x68, 0xe7, 0x7c, 0x6f, 0x82, 0xd2, 0x8a, 0xcf,
+    0x91, 0xf5, 0x52, 0x42, 0x54, 0x73, 0x59, 0xec,
+    0x5e, 0xc5, 0x65, 0xfe, 0x6f, 0x2a, 0x79, 0xad,
+    0x95, 0x6a, 0x9a, 0x97, 0x9e, 0xce, 0x9e, 0x9b,
+    0x52, 0xc6, 0x66, 0x77, 0x6b, 0x62, 0x8f, 0x74,
+    0x5e, 0x90, 0x61, 0x00, 0x62, 0x9a, 0x64, 0x23,
+    0x6f, 0x49, 0x71, 0x89, 0x74, 0xca, 0x79, 0xf4,
+    0x7d, 0x6f, 0x80, 0x26, 0x8f, 0xee, 0x84, 0x23,
+    0x90, 0x4a, 0x93, 0x17, 0x52, 0xa3, 0x52, 0xbd,
+    0x54, 0xc8, 0x70, 0xc2, 0x88, 0xaa, 0x8a, 0xc9,
+    0x5e, 0xf5, 0x5f, 0x7b, 0x63, 0xae, 0x6b, 0x3e,
+    0x7c, 0x75, 0x73, 0xe4, 0x4e, 0xf9, 0x56, 0xe7,
+    0x5b, 0xba, 0x5d, 0x1c, 0x60, 0xb2, 0x73, 0x69,
+    0x74, 0x9a, 0x7f, 0x46, 0x80, 0x34, 0x92, 0xf6,
+    0x96, 0x48, 0x97, 0x18, 0x98, 0x8b, 0x4f, 0xae,
+    0x79, 0xb4, 0x91, 0xb8, 0x96, 0xe1, 0x60, 0x86,
+    0x4e, 0xda, 0x50, 0xee, 0x5b, 0x3f, 0x5c, 0x99,
+    0x65, 0x02, 0x6a, 0xce, 0x71, 0x42, 0x76, 0xfc,
+    0x84, 0x7c, 0x90, 0x8d, 0x9f, 0x88, 0x66, 0x2e,
+    0x96, 0x89, 0x52, 0x7b, 0x67, 0xf3, 0x67, 0x41,
+    0x6d, 0x9c, 0x6e, 0x09, 0x74, 0x59, 0x75, 0x6b,
+    0x78, 0x10, 0x7d, 0x5e, 0x98, 0x6d, 0x51, 0x2e,
+    0x62, 0x78, 0x96, 0x2b, 0x50, 0x19, 0x5d, 0xea,
+    0x6d, 0x2a, 0x8f, 0x8b, 0x5f, 0x44, 0x61, 0x17,
+    0x68, 0x87, 0x73, 0x86, 0x96, 0x29, 0x52, 0x0f,
+    0x54, 0x65, 0x5c, 0x13, 0x66, 0x4e, 0x67, 0xa8,
+    0x68, 0xe5, 0x6c, 0x06, 0x74, 0xe2, 0x75, 0x79,
+    0x7f, 0xcf, 0x88, 0xe1, 0x88, 0xcc, 0x91, 0xe2,
+    0x96, 0x3f, 0x53, 0xba, 0x6e, 0x1d, 0x54, 0xd0,
+    0x71, 0x98, 0x74, 0xfa, 0x85, 0xa3, 0x96, 0x57,
+    0x9c, 0x9f, 0x9e, 0x97, 0x67, 0xcb, 0x6d, 0xe8,
+    0x81, 0xcb, 0x7a, 0x20, 0x7b, 0x92, 0x7c, 0xc0,
+    0x72, 0x99, 0x70, 0x58, 0x8b, 0xc0, 0x4e, 0x36,
+    0x83, 0x3a, 0x52, 0x07, 0x52, 0xa6, 0x5e, 0xd3,
+    0x62, 0xd6, 0x7c, 0x85, 0x5b, 0x1e, 0x6d, 0xb4,
+    0x66, 0x3b, 0x8f, 0x4c, 0x88, 0x4d, 0x96, 0x8b,
+    0x89, 0xd3, 0x5e, 0x40, 0x51, 0xc0, 0x55, 0x00,
+    0x00, 0x00, 0x00, 0x5a, 0x58, 0x00, 0x00, 0x74,
+    0x66, 0x00, 0x00, 0x00, 0x00, 0xde, 0x51, 0x2a,
+    0x73, 0xca, 0x76, 0x3c, 0x79, 0x5e, 0x79, 0x65,
+    0x79, 0x8f, 0x79, 0x56, 0x97, 0xbe, 0x7c, 0xbd,
+    0x7f, 0x00, 0x00, 0x12, 0x86, 0x00, 0x00, 0xf8,
+    0x8a, 0x00, 0x00, 0x00, 0x00, 0x38, 0x90, 0xfd,
+    0x90, 0xef, 0x98, 0xfc, 0x98, 0x28, 0x99, 0xb4,
+    0x9d, 0xde, 0x90, 0xb7, 0x96, 0xae, 0x4f, 0xe7,
+    0x50, 0x4d, 0x51, 0xc9, 0x52, 0xe4, 0x52, 0x51,
+    0x53, 0x9d, 0x55, 0x06, 0x56, 0x68, 0x56, 0x40,
+    0x58, 0xa8, 0x58, 0x64, 0x5c, 0x6e, 0x5c, 0x94,
+    0x60, 0x68, 0x61, 0x8e, 0x61, 0xf2, 0x61, 0x4f,
+    0x65, 0xe2, 0x65, 0x91, 0x66, 0x85, 0x68, 0x77,
+    0x6d, 0x1a, 0x6e, 0x22, 0x6f, 0x6e, 0x71, 0x2b,
+    0x72, 0x22, 0x74, 0x91, 0x78, 0x3e, 0x79, 0x49,
+    0x79, 0x48, 0x79, 0x50, 0x79, 0x56, 0x79, 0x5d,
+    0x79, 0x8d, 0x79, 0x8e, 0x79, 0x40, 0x7a, 0x81,
+    0x7a, 0xc0, 0x7b, 0xf4, 0x7d, 0x09, 0x7e, 0x41,
+    0x7e, 0x72, 0x7f, 0x05, 0x80, 0xed, 0x81, 0x79,
+    0x82, 0x79, 0x82, 0x57, 0x84, 0x10, 0x89, 0x96,
+    0x89, 0x01, 0x8b, 0x39, 0x8b, 0xd3, 0x8c, 0x08,
+    0x8d, 0xb6, 0x8f, 0x38, 0x90, 0xe3, 0x96, 0xff,
+    0x97, 0x3b, 0x98, 0x75, 0x60, 0xee, 0x42, 0x18,
+    0x82, 0x02, 0x26, 0x4e, 0xb5, 0x51, 0x68, 0x51,
+    0x80, 0x4f, 0x45, 0x51, 0x80, 0x51, 0xc7, 0x52,
+    0xfa, 0x52, 0x9d, 0x55, 0x55, 0x55, 0x99, 0x55,
+    0xe2, 0x55, 0x5a, 0x58, 0xb3, 0x58, 0x44, 0x59,
+    0x54, 0x59, 0x62, 0x5a, 0x28, 0x5b, 0xd2, 0x5e,
+    0xd9, 0x5e, 0x69, 0x5f, 0xad, 0x5f, 0xd8, 0x60,
+    0x4e, 0x61, 0x08, 0x61, 0x8e, 0x61, 0x60, 0x61,
+    0xf2, 0x61, 0x34, 0x62, 0xc4, 0x63, 0x1c, 0x64,
+    0x52, 0x64, 0x56, 0x65, 0x74, 0x66, 0x17, 0x67,
+    0x1b, 0x67, 0x56, 0x67, 0x79, 0x6b, 0xba, 0x6b,
+    0x41, 0x6d, 0xdb, 0x6e, 0xcb, 0x6e, 0x22, 0x6f,
+    0x1e, 0x70, 0x6e, 0x71, 0xa7, 0x77, 0x35, 0x72,
+    0xaf, 0x72, 0x2a, 0x73, 0x71, 0x74, 0x06, 0x75,
+    0x3b, 0x75, 0x1d, 0x76, 0x1f, 0x76, 0xca, 0x76,
+    0xdb, 0x76, 0xf4, 0x76, 0x4a, 0x77, 0x40, 0x77,
+    0xcc, 0x78, 0xb1, 0x7a, 0xc0, 0x7b, 0x7b, 0x7c,
+    0x5b, 0x7d, 0xf4, 0x7d, 0x3e, 0x7f, 0x05, 0x80,
+    0x52, 0x83, 0xef, 0x83, 0x79, 0x87, 0x41, 0x89,
+    0x86, 0x89, 0x96, 0x89, 0xbf, 0x8a, 0xf8, 0x8a,
+    0xcb, 0x8a, 0x01, 0x8b, 0xfe, 0x8a, 0xed, 0x8a,
+    0x39, 0x8b, 0x8a, 0x8b, 0x08, 0x8d, 0x38, 0x8f,
+    0x72, 0x90, 0x99, 0x91, 0x76, 0x92, 0x7c, 0x96,
+    0xe3, 0x96, 0x56, 0x97, 0xdb, 0x97, 0xff, 0x97,
+    0x0b, 0x98, 0x3b, 0x98, 0x12, 0x9b, 0x9c, 0x9f,
+    0x4a, 0x28, 0x44, 0x28, 0xd5, 0x33, 0x9d, 0x3b,
+    0x18, 0x40, 0x39, 0x40, 0x49, 0x52, 0xd0, 0x5c,
+    0xd3, 0x7e, 0x43, 0x9f, 0x8e, 0x9f, 0x2a, 0xa0,
+    0x02, 0x66, 0x66, 0x66, 0x69, 0x66, 0x6c, 0x66,
+    0x66, 0x69, 0x66, 0x66, 0x6c, 0x7f, 0x01, 0x74,
+    0x73, 0x00, 0x74, 0x65, 0x05, 0x0f, 0x11, 0x0f,
+    0x00, 0x0f, 0x06, 0x19, 0x11, 0x0f, 0x08, 0xd9,
+    0x05, 0xb4, 0x05, 0x00, 0x00, 0x00, 0x00, 0xf2,
+    0x05, 0xb7, 0x05, 0xd0, 0x05, 0x12, 0x00, 0x03,
+    0x04, 0x0b, 0x0c, 0x0d, 0x18, 0x1a, 0xe9, 0x05,
+    0xc1, 0x05, 0xe9, 0x05, 0xc2, 0x05, 0x49, 0xfb,
+    0xc1, 0x05, 0x49, 0xfb, 0xc2, 0x05, 0xd0, 0x05,
+    0xb7, 0x05, 0xd0, 0x05, 0xb8, 0x05, 0xd0, 0x05,
+    0xbc, 0x05, 0xd8, 0x05, 0xbc, 0x05, 0xde, 0x05,
+    0xbc, 0x05, 0xe0, 0x05, 0xbc, 0x05, 0xe3, 0x05,
+    0xbc, 0x05, 0xb9, 0x05, 0x2d, 0x03, 0x2e, 0x03,
+    0x2f, 0x03, 0x30, 0x03, 0x31, 0x03, 0x1c, 0x00,
+    0x18, 0x06, 0x22, 0x06, 0x2b, 0x06, 0xd0, 0x05,
+    0xdc, 0x05, 0x71, 0x06, 0x00, 0x00, 0x0a, 0x0a,
+    0x0a, 0x0a, 0x0d, 0x0d, 0x0d, 0x0d, 0x0f, 0x0f,
+    0x0f, 0x0f, 0x09, 0x09, 0x09, 0x09, 0x0e, 0x0e,
+    0x0e, 0x0e, 0x08, 0x08, 0x08, 0x08, 0x33, 0x33,
+    0x33, 0x33, 0x35, 0x35, 0x35, 0x35, 0x13, 0x13,
+    0x13, 0x13, 0x12, 0x12, 0x12, 0x12, 0x15, 0x15,
+    0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x1c, 0x1c,
+    0x1b, 0x1b, 0x1d, 0x1d, 0x17, 0x17, 0x27, 0x27,
+    0x20, 0x20, 0x38, 0x38, 0x38, 0x38, 0x3e, 0x3e,
+    0x3e, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x40, 0x40,
+    0x40, 0x40, 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4a,
+    0x4f, 0x4f, 0x50, 0x50, 0x50, 0x50, 0x4d, 0x4d,
+    0x4d, 0x4d, 0x61, 0x61, 0x62, 0x62, 0x49, 0x06,
+    0x64, 0x64, 0x64, 0x64, 0x7e, 0x7e, 0x7d, 0x7d,
+    0x7f, 0x7f, 0x2e, 0x82, 0x82, 0x7c, 0x7c, 0x80,
+    0x80, 0x87, 0x87, 0x87, 0x87, 0x00, 0x00, 0x26,
+    0x06, 0x00, 0x01, 0x00, 0x01, 0x00, 0xaf, 0x00,
+    0xaf, 0x00, 0x22, 0x00, 0x22, 0x00, 0xa1, 0x00,
+    0xa1, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa2, 0x00,
+    0xa2, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00,
+    0x23, 0x00, 0x23, 0x00, 0x23, 0xcc, 0x06, 0x00,
+    0x00, 0x00, 0x00, 0x26, 0x06, 0x00, 0x06, 0x00,
+    0x07, 0x00, 0x1f, 0x00, 0x23, 0x00, 0x24, 0x02,
+    0x06, 0x02, 0x07, 0x02, 0x08, 0x02, 0x1f, 0x02,
+    0x23, 0x02, 0x24, 0x04, 0x06, 0x04, 0x07, 0x04,
+    0x08, 0x04, 0x1f, 0x04, 0x23, 0x04, 0x24, 0x05,
+    0x06, 0x05, 0x1f, 0x05, 0x23, 0x05, 0x24, 0x06,
+    0x07, 0x06, 0x1f, 0x07, 0x06, 0x07, 0x1f, 0x08,
+    0x06, 0x08, 0x07, 0x08, 0x1f, 0x0d, 0x06, 0x0d,
+    0x07, 0x0d, 0x08, 0x0d, 0x1f, 0x0f, 0x07, 0x0f,
+    0x1f, 0x10, 0x06, 0x10, 0x07, 0x10, 0x08, 0x10,
+    0x1f, 0x11, 0x07, 0x11, 0x1f, 0x12, 0x1f, 0x13,
+    0x06, 0x13, 0x1f, 0x14, 0x06, 0x14, 0x1f, 0x1b,
+    0x06, 0x1b, 0x07, 0x1b, 0x08, 0x1b, 0x1f, 0x1b,
+    0x23, 0x1b, 0x24, 0x1c, 0x07, 0x1c, 0x1f, 0x1c,
+    0x23, 0x1c, 0x24, 0x1d, 0x01, 0x1d, 0x06, 0x1d,
+    0x07, 0x1d, 0x08, 0x1d, 0x1e, 0x1d, 0x1f, 0x1d,
+    0x23, 0x1d, 0x24, 0x1e, 0x06, 0x1e, 0x07, 0x1e,
+    0x08, 0x1e, 0x1f, 0x1e, 0x23, 0x1e, 0x24, 0x1f,
+    0x06, 0x1f, 0x07, 0x1f, 0x08, 0x1f, 0x1f, 0x1f,
+    0x23, 0x1f, 0x24, 0x20, 0x06, 0x20, 0x07, 0x20,
+    0x08, 0x20, 0x1f, 0x20, 0x23, 0x20, 0x24, 0x21,
+    0x06, 0x21, 0x1f, 0x21, 0x23, 0x21, 0x24, 0x24,
+    0x06, 0x24, 0x07, 0x24, 0x08, 0x24, 0x1f, 0x24,
+    0x23, 0x24, 0x24, 0x0a, 0x4a, 0x0b, 0x4a, 0x23,
+    0x4a, 0x20, 0x00, 0x4c, 0x06, 0x51, 0x06, 0x51,
+    0x06, 0xff, 0x00, 0x1f, 0x26, 0x06, 0x00, 0x0b,
+    0x00, 0x0c, 0x00, 0x1f, 0x00, 0x20, 0x00, 0x23,
+    0x00, 0x24, 0x02, 0x0b, 0x02, 0x0c, 0x02, 0x1f,
+    0x02, 0x20, 0x02, 0x23, 0x02, 0x24, 0x04, 0x0b,
+    0x04, 0x0c, 0x04, 0x1f, 0x26, 0x06, 0x04, 0x20,
+    0x04, 0x23, 0x04, 0x24, 0x05, 0x0b, 0x05, 0x0c,
+    0x05, 0x1f, 0x05, 0x20, 0x05, 0x23, 0x05, 0x24,
+    0x1b, 0x23, 0x1b, 0x24, 0x1c, 0x23, 0x1c, 0x24,
+    0x1d, 0x01, 0x1d, 0x1e, 0x1d, 0x1f, 0x1d, 0x23,
+    0x1d, 0x24, 0x1e, 0x1f, 0x1e, 0x23, 0x1e, 0x24,
+    0x1f, 0x01, 0x1f, 0x1f, 0x20, 0x0b, 0x20, 0x0c,
+    0x20, 0x1f, 0x20, 0x20, 0x20, 0x23, 0x20, 0x24,
+    0x23, 0x4a, 0x24, 0x0b, 0x24, 0x0c, 0x24, 0x1f,
+    0x24, 0x20, 0x24, 0x23, 0x24, 0x24, 0x00, 0x06,
+    0x00, 0x07, 0x00, 0x08, 0x00, 0x1f, 0x00, 0x21,
+    0x02, 0x06, 0x02, 0x07, 0x02, 0x08, 0x02, 0x1f,
+    0x02, 0x21, 0x04, 0x06, 0x04, 0x07, 0x04, 0x08,
+    0x04, 0x1f, 0x04, 0x21, 0x05, 0x1f, 0x06, 0x07,
+    0x06, 0x1f, 0x07, 0x06, 0x07, 0x1f, 0x08, 0x06,
+    0x08, 0x1f, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x08,
+    0x0d, 0x1f, 0x0f, 0x07, 0x0f, 0x08, 0x0f, 0x1f,
+    0x10, 0x06, 0x10, 0x07, 0x10, 0x08, 0x10, 0x1f,
+    0x11, 0x07, 0x12, 0x1f, 0x13, 0x06, 0x13, 0x1f,
+    0x14, 0x06, 0x14, 0x1f, 0x1b, 0x06, 0x1b, 0x07,
+    0x1b, 0x08, 0x1b, 0x1f, 0x1c, 0x07, 0x1c, 0x1f,
+    0x1d, 0x06, 0x1d, 0x07, 0x1d, 0x08, 0x1d, 0x1e,
+    0x1d, 0x1f, 0x1e, 0x06, 0x1e, 0x07, 0x1e, 0x08,
+    0x1e, 0x1f, 0x1e, 0x21, 0x1f, 0x06, 0x1f, 0x07,
+    0x1f, 0x08, 0x1f, 0x1f, 0x20, 0x06, 0x20, 0x07,
+    0x20, 0x08, 0x20, 0x1f, 0x20, 0x21, 0x21, 0x06,
+    0x21, 0x1f, 0x21, 0x4a, 0x24, 0x06, 0x24, 0x07,
+    0x24, 0x08, 0x24, 0x1f, 0x24, 0x21, 0x00, 0x1f,
+    0x00, 0x21, 0x02, 0x1f, 0x02, 0x21, 0x04, 0x1f,
+    0x04, 0x21, 0x05, 0x1f, 0x05, 0x21, 0x0d, 0x1f,
+    0x0d, 0x21, 0x0e, 0x1f, 0x0e, 0x21, 0x1d, 0x1e,
+    0x1d, 0x1f, 0x1e, 0x1f, 0x20, 0x1f, 0x20, 0x21,
+    0x24, 0x1f, 0x24, 0x21, 0x40, 0x06, 0x4e, 0x06,
+    0x51, 0x06, 0x27, 0x06, 0x10, 0x22, 0x10, 0x23,
+    0x12, 0x22, 0x12, 0x23, 0x13, 0x22, 0x13, 0x23,
+    0x0c, 0x22, 0x0c, 0x23, 0x0d, 0x22, 0x0d, 0x23,
+    0x06, 0x22, 0x06, 0x23, 0x05, 0x22, 0x05, 0x23,
+    0x07, 0x22, 0x07, 0x23, 0x0e, 0x22, 0x0e, 0x23,
+    0x0f, 0x22, 0x0f, 0x23, 0x0d, 0x05, 0x0d, 0x06,
+    0x0d, 0x07, 0x0d, 0x1e, 0x0d, 0x0a, 0x0c, 0x0a,
+    0x0e, 0x0a, 0x0f, 0x0a, 0x10, 0x22, 0x10, 0x23,
+    0x12, 0x22, 0x12, 0x23, 0x13, 0x22, 0x13, 0x23,
+    0x0c, 0x22, 0x0c, 0x23, 0x0d, 0x22, 0x0d, 0x23,
+    0x06, 0x22, 0x06, 0x23, 0x05, 0x22, 0x05, 0x23,
+    0x07, 0x22, 0x07, 0x23, 0x0e, 0x22, 0x0e, 0x23,
+    0x0f, 0x22, 0x0f, 0x23, 0x0d, 0x05, 0x0d, 0x06,
+    0x0d, 0x07, 0x0d, 0x1e, 0x0d, 0x0a, 0x0c, 0x0a,
+    0x0e, 0x0a, 0x0f, 0x0a, 0x0d, 0x05, 0x0d, 0x06,
+    0x0d, 0x07, 0x0d, 0x1e, 0x0c, 0x20, 0x0d, 0x20,
+    0x10, 0x1e, 0x0c, 0x05, 0x0c, 0x06, 0x0c, 0x07,
+    0x0d, 0x05, 0x0d, 0x06, 0x0d, 0x07, 0x10, 0x1e,
+    0x11, 0x1e, 0x00, 0x24, 0x00, 0x24, 0x2a, 0x06,
+    0x00, 0x02, 0x1b, 0x00, 0x03, 0x02, 0x00, 0x03,
+    0x02, 0x00, 0x03, 0x1b, 0x00, 0x04, 0x1b, 0x00,
+    0x1b, 0x02, 0x00, 0x1b, 0x03, 0x00, 0x1b, 0x04,
+    0x02, 0x1b, 0x03, 0x02, 0x1b, 0x03, 0x03, 0x1b,
+    0x20, 0x03, 0x1b, 0x1f, 0x09, 0x03, 0x02, 0x09,
+    0x02, 0x03, 0x09, 0x02, 0x1f, 0x09, 0x1b, 0x03,
+    0x09, 0x1b, 0x03, 0x09, 0x1b, 0x02, 0x09, 0x1b,
+    0x1b, 0x09, 0x1b, 0x1b, 0x0b, 0x03, 0x03, 0x0b,
+    0x03, 0x03, 0x0b, 0x1b, 0x1b, 0x0a, 0x03, 0x1b,
+    0x0a, 0x03, 0x1b, 0x0a, 0x02, 0x20, 0x0a, 0x1b,
+    0x04, 0x0a, 0x1b, 0x04, 0x0a, 0x1b, 0x1b, 0x0a,
+    0x1b, 0x1b, 0x0c, 0x03, 0x1f, 0x0c, 0x04, 0x1b,
+    0x0c, 0x04, 0x1b, 0x0d, 0x1b, 0x03, 0x0d, 0x1b,
+    0x03, 0x0d, 0x1b, 0x1b, 0x0d, 0x1b, 0x20, 0x0f,
+    0x02, 0x1b, 0x0f, 0x1b, 0x1b, 0x0f, 0x1b, 0x1b,
+    0x0f, 0x1b, 0x1f, 0x10, 0x1b, 0x1b, 0x10, 0x1b,
+    0x20, 0x10, 0x1b, 0x1f, 0x17, 0x04, 0x1b, 0x17,
+    0x04, 0x1b, 0x18, 0x1b, 0x03, 0x18, 0x1b, 0x1b,
+    0x1a, 0x03, 0x1b, 0x1a, 0x03, 0x20, 0x1a, 0x03,
+    0x1f, 0x1a, 0x02, 0x02, 0x1a, 0x02, 0x02, 0x1a,
+    0x04, 0x1b, 0x1a, 0x04, 0x1b, 0x1a, 0x1b, 0x03,
+    0x1a, 0x1b, 0x03, 0x1b, 0x03, 0x02, 0x1b, 0x03,
+    0x1b, 0x1b, 0x03, 0x20, 0x1b, 0x02, 0x03, 0x1b,
+    0x02, 0x1b, 0x1b, 0x04, 0x02, 0x1b, 0x04, 0x1b,
+    0x28, 0x06, 0x1d, 0x04, 0x06, 0x1f, 0x1d, 0x04,
+    0x1f, 0x1d, 0x1d, 0x1e, 0x05, 0x1d, 0x1e, 0x05,
+    0x21, 0x1e, 0x04, 0x1d, 0x1e, 0x04, 0x1d, 0x1e,
+    0x04, 0x21, 0x1e, 0x1d, 0x22, 0x1e, 0x1d, 0x21,
+    0x22, 0x1d, 0x1d, 0x22, 0x1d, 0x1d, 0x00, 0x06,
+    0x22, 0x02, 0x04, 0x22, 0x02, 0x04, 0x21, 0x02,
+    0x06, 0x22, 0x02, 0x06, 0x21, 0x02, 0x1d, 0x22,
+    0x02, 0x1d, 0x21, 0x04, 0x1d, 0x22, 0x04, 0x05,
+    0x21, 0x04, 0x1d, 0x21, 0x0b, 0x06, 0x21, 0x0d,
+    0x05, 0x22, 0x0c, 0x05, 0x22, 0x0e, 0x05, 0x22,
+    0x1c, 0x04, 0x22, 0x1c, 0x1d, 0x22, 0x22, 0x05,
+    0x22, 0x22, 0x04, 0x22, 0x22, 0x1d, 0x22, 0x1d,
+    0x1d, 0x22, 0x1a, 0x1d, 0x22, 0x1e, 0x05, 0x22,
+    0x1a, 0x1d, 0x05, 0x1c, 0x05, 0x1d, 0x11, 0x1d,
+    0x22, 0x1b, 0x1d, 0x22, 0x1e, 0x04, 0x05, 0x1d,
+    0x06, 0x22, 0x1c, 0x04, 0x1d, 0x1b, 0x1d, 0x1d,
+    0x1c, 0x04, 0x1d, 0x1e, 0x04, 0x05, 0x04, 0x05,
+    0x22, 0x05, 0x04, 0x22, 0x1d, 0x04, 0x22, 0x19,
+    0x1d, 0x22, 0x00, 0x05, 0x22, 0x1b, 0x1d, 0x1d,
+    0x11, 0x04, 0x1d, 0x0d, 0x1d, 0x1d, 0x0b, 0x06,
+    0x22, 0x1e, 0x04, 0x22, 0x35, 0x06, 0x00, 0x0f,
+    0x9d, 0x0d, 0x0f, 0x9d, 0x27, 0x06, 0x00, 0x1d,
+    0x1d, 0x20, 0x00, 0x1c, 0x01, 0x0a, 0x1e, 0x06,
+    0x1e, 0x08, 0x0e, 0x1d, 0x12, 0x1e, 0x0a, 0x0c,
+    0x21, 0x1d, 0x12, 0x1d, 0x23, 0x20, 0x21, 0x0c,
+    0x1d, 0x1e, 0x35, 0x06, 0x00, 0x0f, 0x14, 0x27,
+    0x06, 0x0e, 0x1d, 0x22, 0xff, 0x00, 0x1d, 0x1d,
+    0x20, 0xff, 0x12, 0x1d, 0x23, 0x20, 0xff, 0x21,
+    0x0c, 0x1d, 0x1e, 0x27, 0x06, 0x05, 0x1d, 0xff,
+    0x05, 0x1d, 0x00, 0x1d, 0x20, 0x27, 0x06, 0x0a,
+    0xa5, 0x00, 0x1d, 0x2c, 0x00, 0x01, 0x30, 0x02,
+    0x30, 0x3a, 0x00, 0x3b, 0x00, 0x21, 0x00, 0x3f,
+    0x00, 0x16, 0x30, 0x17, 0x30, 0x26, 0x20, 0x13,
+    0x20, 0x12, 0x01, 0x00, 0x5f, 0x5f, 0x28, 0x29,
+    0x7b, 0x7d, 0x08, 0x30, 0x0c, 0x0d, 0x08, 0x09,
+    0x02, 0x03, 0x00, 0x01, 0x04, 0x05, 0x06, 0x07,
+    0x5b, 0x00, 0x5d, 0x00, 0x3e, 0x20, 0x3e, 0x20,
+    0x3e, 0x20, 0x3e, 0x20, 0x5f, 0x00, 0x5f, 0x00,
+    0x5f, 0x00, 0x2c, 0x00, 0x01, 0x30, 0x2e, 0x00,
+    0x00, 0x00, 0x3b, 0x00, 0x3a, 0x00, 0x3f, 0x00,
+    0x21, 0x00, 0x14, 0x20, 0x28, 0x00, 0x29, 0x00,
+    0x7b, 0x00, 0x7d, 0x00, 0x14, 0x30, 0x15, 0x30,
+    0x23, 0x26, 0x2a, 0x2b, 0x2d, 0x3c, 0x3e, 0x3d,
+    0x00, 0x5c, 0x24, 0x25, 0x40, 0x40, 0x06, 0xff,
+    0x0b, 0x00, 0x0b, 0xff, 0x0c, 0x20, 0x00, 0x4d,
+    0x06, 0x40, 0x06, 0xff, 0x0e, 0x00, 0x0e, 0xff,
+    0x0f, 0x00, 0x0f, 0xff, 0x10, 0x00, 0x10, 0xff,
+    0x11, 0x00, 0x11, 0xff, 0x12, 0x00, 0x12, 0x21,
+    0x06, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03,
+    0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06,
+    0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09,
+    0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b,
+    0x0b, 0x0b, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d,
+    0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x0f, 0x10, 0x10,
+    0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13,
+    0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15,
+    0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17,
+    0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19,
+    0x19, 0x19, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21,
+    0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23,
+    0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25,
+    0x25, 0x25, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27,
+    0x28, 0x28, 0x29, 0x29, 0x29, 0x29, 0x22, 0x06,
+    0x22, 0x00, 0x22, 0x00, 0x22, 0x01, 0x22, 0x01,
+    0x22, 0x03, 0x22, 0x03, 0x22, 0x05, 0x22, 0x05,
+    0x21, 0x00, 0x85, 0x29, 0x01, 0x30, 0x01, 0x0b,
+    0x0c, 0x00, 0xfa, 0xf1, 0xa0, 0xa2, 0xa4, 0xa6,
+    0xa8, 0xe2, 0xe4, 0xe6, 0xc2, 0xfb, 0xa1, 0xa3,
+    0xa5, 0xa7, 0xa9, 0xaa, 0xac, 0xae, 0xb0, 0xb2,
+    0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, 0xc0, 0xc3,
+    0xc5, 0xc7, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce,
+    0xd1, 0xd4, 0xd7, 0xda, 0xdd, 0xde, 0xdf, 0xe0,
+    0xe1, 0xe3, 0xe5, 0xe7, 0xe8, 0xe9, 0xea, 0xeb,
+    0xec, 0xee, 0xf2, 0x98, 0x99, 0x31, 0x31, 0x4f,
+    0x31, 0x55, 0x31, 0x5b, 0x31, 0x61, 0x31, 0xa2,
+    0x00, 0xa3, 0x00, 0xac, 0x00, 0xaf, 0x00, 0xa6,
+    0x00, 0xa5, 0x00, 0xa9, 0x20, 0x00, 0x00, 0x02,
+    0x25, 0x90, 0x21, 0x91, 0x21, 0x92, 0x21, 0x93,
+    0x21, 0xa0, 0x25, 0xcb, 0x25, 0x99, 0x10, 0xba,
+    0x10, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x10, 0xba,
+    0x10, 0x05, 0x05, 0xa5, 0x10, 0xba, 0x10, 0x05,
+    0x31, 0x11, 0x27, 0x11, 0x32, 0x11, 0x27, 0x11,
+    0x55, 0x47, 0x13, 0x3e, 0x13, 0x47, 0x13, 0x57,
+    0x13, 0x55, 0xb9, 0x14, 0xba, 0x14, 0xb9, 0x14,
+    0xb0, 0x14, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x14,
+    0xbd, 0x14, 0x55, 0x50, 0xb8, 0x15, 0xaf, 0x15,
+    0xb9, 0x15, 0xaf, 0x15, 0x55, 0x35, 0x19, 0x30,
+    0x19, 0x05, 0x57, 0xd1, 0x65, 0xd1, 0x58, 0xd1,
+    0x65, 0xd1, 0x5f, 0xd1, 0x6e, 0xd1, 0x5f, 0xd1,
+    0x6f, 0xd1, 0x5f, 0xd1, 0x70, 0xd1, 0x5f, 0xd1,
+    0x71, 0xd1, 0x5f, 0xd1, 0x72, 0xd1, 0x55, 0x55,
+    0x55, 0x05, 0xb9, 0xd1, 0x65, 0xd1, 0xba, 0xd1,
+    0x65, 0xd1, 0xbb, 0xd1, 0x6e, 0xd1, 0xbc, 0xd1,
+    0x6e, 0xd1, 0xbb, 0xd1, 0x6f, 0xd1, 0xbc, 0xd1,
+    0x6f, 0xd1, 0x55, 0x55, 0x55, 0x41, 0x00, 0x61,
+    0x00, 0x41, 0x00, 0x61, 0x00, 0x69, 0x00, 0x41,
+    0x00, 0x61, 0x00, 0x41, 0x00, 0x43, 0x44, 0x00,
+    0x00, 0x47, 0x00, 0x00, 0x4a, 0x4b, 0x00, 0x00,
+    0x4e, 0x4f, 0x50, 0x51, 0x00, 0x53, 0x54, 0x55,
+    0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63,
+    0x64, 0x00, 0x66, 0x68, 0x00, 0x70, 0x00, 0x41,
+    0x00, 0x61, 0x00, 0x41, 0x42, 0x00, 0x44, 0x45,
+    0x46, 0x47, 0x4a, 0x00, 0x53, 0x00, 0x61, 0x00,
+    0x41, 0x42, 0x00, 0x44, 0x45, 0x46, 0x47, 0x00,
+    0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x00, 0x4f, 0x53,
+    0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41,
+    0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41,
+    0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41,
+    0x00, 0x61, 0x00, 0x31, 0x01, 0x37, 0x02, 0x91,
+    0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24,
+    0x00, 0x1f, 0x04, 0x20, 0x05, 0x91, 0x03, 0xa3,
+    0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00, 0x1f,
+    0x04, 0x20, 0x05, 0x91, 0x03, 0xa3, 0x03, 0xb1,
+    0x03, 0xd1, 0x03, 0x24, 0x00, 0x1f, 0x04, 0x20,
+    0x05, 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1,
+    0x03, 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x91,
+    0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24,
+    0x00, 0x1f, 0x04, 0x20, 0x05, 0x0b, 0x0c, 0x30,
+    0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30,
+    0x00, 0x27, 0x06, 0x00, 0x01, 0x05, 0x08, 0x2a,
+    0x06, 0x1e, 0x08, 0x03, 0x0d, 0x20, 0x19, 0x1a,
+    0x1b, 0x1c, 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07,
+    0x0a, 0x00, 0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10,
+    0x44, 0x90, 0x77, 0x45, 0x28, 0x06, 0x2c, 0x06,
+    0x00, 0x00, 0x47, 0x06, 0x33, 0x06, 0x17, 0x10,
+    0x11, 0x12, 0x13, 0x00, 0x06, 0x0e, 0x02, 0x0f,
+    0x34, 0x06, 0x2a, 0x06, 0x2b, 0x06, 0x2e, 0x06,
+    0x00, 0x00, 0x36, 0x06, 0x00, 0x00, 0x3a, 0x06,
+    0x2d, 0x06, 0x00, 0x00, 0x4a, 0x06, 0x00, 0x00,
+    0x44, 0x06, 0x00, 0x00, 0x46, 0x06, 0x33, 0x06,
+    0x39, 0x06, 0x00, 0x00, 0x35, 0x06, 0x42, 0x06,
+    0x00, 0x00, 0x34, 0x06, 0x00, 0x00, 0x00, 0x00,
+    0x2e, 0x06, 0x00, 0x00, 0x36, 0x06, 0x00, 0x00,
+    0x3a, 0x06, 0x00, 0x00, 0xba, 0x06, 0x00, 0x00,
+    0x6f, 0x06, 0x00, 0x00, 0x28, 0x06, 0x2c, 0x06,
+    0x00, 0x00, 0x47, 0x06, 0x00, 0x00, 0x00, 0x00,
+    0x2d, 0x06, 0x37, 0x06, 0x4a, 0x06, 0x43, 0x06,
+    0x00, 0x00, 0x45, 0x06, 0x46, 0x06, 0x33, 0x06,
+    0x39, 0x06, 0x41, 0x06, 0x35, 0x06, 0x42, 0x06,
+    0x00, 0x00, 0x34, 0x06, 0x2a, 0x06, 0x2b, 0x06,
+    0x2e, 0x06, 0x00, 0x00, 0x36, 0x06, 0x38, 0x06,
+    0x3a, 0x06, 0x6e, 0x06, 0x00, 0x00, 0xa1, 0x06,
+    0x27, 0x06, 0x00, 0x01, 0x05, 0x08, 0x20, 0x21,
+    0x0b, 0x06, 0x10, 0x23, 0x2a, 0x06, 0x1a, 0x1b,
+    0x1c, 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, 0x0a,
+    0x00, 0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10, 0x28,
+    0x06, 0x2c, 0x06, 0x2f, 0x06, 0x00, 0x00, 0x48,
+    0x06, 0x32, 0x06, 0x2d, 0x06, 0x37, 0x06, 0x4a,
+    0x06, 0x2a, 0x06, 0x1a, 0x1b, 0x1c, 0x09, 0x0f,
+    0x17, 0x0b, 0x18, 0x07, 0x0a, 0x00, 0x01, 0x04,
+    0x06, 0x0c, 0x0e, 0x10, 0x30, 0x2e, 0x30, 0x00,
+    0x2c, 0x00, 0x28, 0x00, 0x41, 0x00, 0x29, 0x00,
+    0x14, 0x30, 0x53, 0x00, 0x15, 0x30, 0x43, 0x52,
+    0x43, 0x44, 0x57, 0x5a, 0x41, 0x00, 0x48, 0x56,
+    0x4d, 0x56, 0x53, 0x44, 0x53, 0x53, 0x50, 0x50,
+    0x56, 0x57, 0x43, 0x4d, 0x43, 0x4d, 0x44, 0x4d,
+    0x52, 0x44, 0x4a, 0x4b, 0x30, 0x30, 0x00, 0x68,
+    0x68, 0x4b, 0x62, 0x57, 0x5b, 0xcc, 0x53, 0xc7,
+    0x30, 0x8c, 0x4e, 0x1a, 0x59, 0xe3, 0x89, 0x29,
+    0x59, 0xa4, 0x4e, 0x20, 0x66, 0x21, 0x71, 0x99,
+    0x65, 0x4d, 0x52, 0x8c, 0x5f, 0x8d, 0x51, 0xb0,
+    0x65, 0x1d, 0x52, 0x42, 0x7d, 0x1f, 0x75, 0xa9,
+    0x8c, 0xf0, 0x58, 0x39, 0x54, 0x14, 0x6f, 0x95,
+    0x62, 0x55, 0x63, 0x00, 0x4e, 0x09, 0x4e, 0x4a,
+    0x90, 0xe6, 0x5d, 0x2d, 0x4e, 0xf3, 0x53, 0x07,
+    0x63, 0x70, 0x8d, 0x53, 0x62, 0x81, 0x79, 0x7a,
+    0x7a, 0x08, 0x54, 0x80, 0x6e, 0x09, 0x67, 0x08,
+    0x67, 0x33, 0x75, 0x72, 0x52, 0xb6, 0x55, 0x4d,
+    0x91, 0x14, 0x30, 0x15, 0x30, 0x2c, 0x67, 0x09,
+    0x4e, 0x8c, 0x4e, 0x89, 0x5b, 0xb9, 0x70, 0x53,
+    0x62, 0xd7, 0x76, 0xdd, 0x52, 0x57, 0x65, 0x97,
+    0x5f, 0xef, 0x53, 0x30, 0x00, 0x38, 0x4e, 0x05,
+    0x00, 0x09, 0x22, 0x01, 0x60, 0x4f, 0xae, 0x4f,
+    0xbb, 0x4f, 0x02, 0x50, 0x7a, 0x50, 0x99, 0x50,
+    0xe7, 0x50, 0xcf, 0x50, 0x9e, 0x34, 0x3a, 0x06,
+    0x4d, 0x51, 0x54, 0x51, 0x64, 0x51, 0x77, 0x51,
+    0x1c, 0x05, 0xb9, 0x34, 0x67, 0x51, 0x8d, 0x51,
+    0x4b, 0x05, 0x97, 0x51, 0xa4, 0x51, 0xcc, 0x4e,
+    0xac, 0x51, 0xb5, 0x51, 0xdf, 0x91, 0xf5, 0x51,
+    0x03, 0x52, 0xdf, 0x34, 0x3b, 0x52, 0x46, 0x52,
+    0x72, 0x52, 0x77, 0x52, 0x15, 0x35, 0x02, 0x00,
+    0x20, 0x80, 0x80, 0x00, 0x08, 0x00, 0x00, 0xc7,
+    0x52, 0x00, 0x02, 0x1d, 0x33, 0x3e, 0x3f, 0x50,
+    0x82, 0x8a, 0x93, 0xac, 0xb6, 0xb8, 0xb8, 0xb8,
+    0x2c, 0x0a, 0x70, 0x70, 0xca, 0x53, 0xdf, 0x53,
+    0x63, 0x0b, 0xeb, 0x53, 0xf1, 0x53, 0x06, 0x54,
+    0x9e, 0x54, 0x38, 0x54, 0x48, 0x54, 0x68, 0x54,
+    0xa2, 0x54, 0xf6, 0x54, 0x10, 0x55, 0x53, 0x55,
+    0x63, 0x55, 0x84, 0x55, 0x84, 0x55, 0x99, 0x55,
+    0xab, 0x55, 0xb3, 0x55, 0xc2, 0x55, 0x16, 0x57,
+    0x06, 0x56, 0x17, 0x57, 0x51, 0x56, 0x74, 0x56,
+    0x07, 0x52, 0xee, 0x58, 0xce, 0x57, 0xf4, 0x57,
+    0x0d, 0x58, 0x8b, 0x57, 0x32, 0x58, 0x31, 0x58,
+    0xac, 0x58, 0xe4, 0x14, 0xf2, 0x58, 0xf7, 0x58,
+    0x06, 0x59, 0x1a, 0x59, 0x22, 0x59, 0x62, 0x59,
+    0xa8, 0x16, 0xea, 0x16, 0xec, 0x59, 0x1b, 0x5a,
+    0x27, 0x5a, 0xd8, 0x59, 0x66, 0x5a, 0xee, 0x36,
+    0xfc, 0x36, 0x08, 0x5b, 0x3e, 0x5b, 0x3e, 0x5b,
+    0xc8, 0x19, 0xc3, 0x5b, 0xd8, 0x5b, 0xe7, 0x5b,
+    0xf3, 0x5b, 0x18, 0x1b, 0xff, 0x5b, 0x06, 0x5c,
+    0x53, 0x5f, 0x22, 0x5c, 0x81, 0x37, 0x60, 0x5c,
+    0x6e, 0x5c, 0xc0, 0x5c, 0x8d, 0x5c, 0xe4, 0x1d,
+    0x43, 0x5d, 0xe6, 0x1d, 0x6e, 0x5d, 0x6b, 0x5d,
+    0x7c, 0x5d, 0xe1, 0x5d, 0xe2, 0x5d, 0x2f, 0x38,
+    0xfd, 0x5d, 0x28, 0x5e, 0x3d, 0x5e, 0x69, 0x5e,
+    0x62, 0x38, 0x83, 0x21, 0x7c, 0x38, 0xb0, 0x5e,
+    0xb3, 0x5e, 0xb6, 0x5e, 0xca, 0x5e, 0x92, 0xa3,
+    0xfe, 0x5e, 0x31, 0x23, 0x31, 0x23, 0x01, 0x82,
+    0x22, 0x5f, 0x22, 0x5f, 0xc7, 0x38, 0xb8, 0x32,
+    0xda, 0x61, 0x62, 0x5f, 0x6b, 0x5f, 0xe3, 0x38,
+    0x9a, 0x5f, 0xcd, 0x5f, 0xd7, 0x5f, 0xf9, 0x5f,
+    0x81, 0x60, 0x3a, 0x39, 0x1c, 0x39, 0x94, 0x60,
+    0xd4, 0x26, 0xc7, 0x60, 0x02, 0x02, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0a,
+    0x00, 0x00, 0x02, 0x08, 0x00, 0x80, 0x08, 0x00,
+    0x00, 0x08, 0x80, 0x28, 0x80, 0x02, 0x00, 0x00,
+    0x02, 0x48, 0x61, 0x00, 0x04, 0x06, 0x04, 0x32,
+    0x46, 0x6a, 0x5c, 0x67, 0x96, 0xaa, 0xae, 0xc8,
+    0xd3, 0x5d, 0x62, 0x00, 0x54, 0x77, 0xf3, 0x0c,
+    0x2b, 0x3d, 0x63, 0xfc, 0x62, 0x68, 0x63, 0x83,
+    0x63, 0xe4, 0x63, 0xf1, 0x2b, 0x22, 0x64, 0xc5,
+    0x63, 0xa9, 0x63, 0x2e, 0x3a, 0x69, 0x64, 0x7e,
+    0x64, 0x9d, 0x64, 0x77, 0x64, 0x6c, 0x3a, 0x4f,
+    0x65, 0x6c, 0x65, 0x0a, 0x30, 0xe3, 0x65, 0xf8,
+    0x66, 0x49, 0x66, 0x19, 0x3b, 0x91, 0x66, 0x08,
+    0x3b, 0xe4, 0x3a, 0x92, 0x51, 0x95, 0x51, 0x00,
+    0x67, 0x9c, 0x66, 0xad, 0x80, 0xd9, 0x43, 0x17,
+    0x67, 0x1b, 0x67, 0x21, 0x67, 0x5e, 0x67, 0x53,
+    0x67, 0xc3, 0x33, 0x49, 0x3b, 0xfa, 0x67, 0x85,
+    0x67, 0x52, 0x68, 0x85, 0x68, 0x6d, 0x34, 0x8e,
+    0x68, 0x1f, 0x68, 0x14, 0x69, 0x9d, 0x3b, 0x42,
+    0x69, 0xa3, 0x69, 0xea, 0x69, 0xa8, 0x6a, 0xa3,
+    0x36, 0xdb, 0x6a, 0x18, 0x3c, 0x21, 0x6b, 0xa7,
+    0x38, 0x54, 0x6b, 0x4e, 0x3c, 0x72, 0x6b, 0x9f,
+    0x6b, 0xba, 0x6b, 0xbb, 0x6b, 0x8d, 0x3a, 0x0b,
+    0x1d, 0xfa, 0x3a, 0x4e, 0x6c, 0xbc, 0x3c, 0xbf,
+    0x6c, 0xcd, 0x6c, 0x67, 0x6c, 0x16, 0x6d, 0x3e,
+    0x6d, 0x77, 0x6d, 0x41, 0x6d, 0x69, 0x6d, 0x78,
+    0x6d, 0x85, 0x6d, 0x1e, 0x3d, 0x34, 0x6d, 0x2f,
+    0x6e, 0x6e, 0x6e, 0x33, 0x3d, 0xcb, 0x6e, 0xc7,
+    0x6e, 0xd1, 0x3e, 0xf9, 0x6d, 0x6e, 0x6f, 0x5e,
+    0x3f, 0x8e, 0x3f, 0xc6, 0x6f, 0x39, 0x70, 0x1e,
+    0x70, 0x1b, 0x70, 0x96, 0x3d, 0x4a, 0x70, 0x7d,
+    0x70, 0x77, 0x70, 0xad, 0x70, 0x25, 0x05, 0x45,
+    0x71, 0x63, 0x42, 0x9c, 0x71, 0xab, 0x43, 0x28,
+    0x72, 0x35, 0x72, 0x50, 0x72, 0x08, 0x46, 0x80,
+    0x72, 0x95, 0x72, 0x35, 0x47, 0x02, 0x20, 0x00,
+    0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80,
+    0x00, 0x00, 0x02, 0x02, 0x80, 0x8a, 0x00, 0x00,
+    0x20, 0x00, 0x08, 0x0a, 0x00, 0x80, 0x88, 0x80,
+    0x20, 0x14, 0x48, 0x7a, 0x73, 0x8b, 0x73, 0xac,
+    0x3e, 0xa5, 0x73, 0xb8, 0x3e, 0xb8, 0x3e, 0x47,
+    0x74, 0x5c, 0x74, 0x71, 0x74, 0x85, 0x74, 0xca,
+    0x74, 0x1b, 0x3f, 0x24, 0x75, 0x36, 0x4c, 0x3e,
+    0x75, 0x92, 0x4c, 0x70, 0x75, 0x9f, 0x21, 0x10,
+    0x76, 0xa1, 0x4f, 0xb8, 0x4f, 0x44, 0x50, 0xfc,
+    0x3f, 0x08, 0x40, 0xf4, 0x76, 0xf3, 0x50, 0xf2,
+    0x50, 0x19, 0x51, 0x33, 0x51, 0x1e, 0x77, 0x1f,
+    0x77, 0x1f, 0x77, 0x4a, 0x77, 0x39, 0x40, 0x8b,
+    0x77, 0x46, 0x40, 0x96, 0x40, 0x1d, 0x54, 0x4e,
+    0x78, 0x8c, 0x78, 0xcc, 0x78, 0xe3, 0x40, 0x26,
+    0x56, 0x56, 0x79, 0x9a, 0x56, 0xc5, 0x56, 0x8f,
+    0x79, 0xeb, 0x79, 0x2f, 0x41, 0x40, 0x7a, 0x4a,
+    0x7a, 0x4f, 0x7a, 0x7c, 0x59, 0xa7, 0x5a, 0xa7,
+    0x5a, 0xee, 0x7a, 0x02, 0x42, 0xab, 0x5b, 0xc6,
+    0x7b, 0xc9, 0x7b, 0x27, 0x42, 0x80, 0x5c, 0xd2,
+    0x7c, 0xa0, 0x42, 0xe8, 0x7c, 0xe3, 0x7c, 0x00,
+    0x7d, 0x86, 0x5f, 0x63, 0x7d, 0x01, 0x43, 0xc7,
+    0x7d, 0x02, 0x7e, 0x45, 0x7e, 0x34, 0x43, 0x28,
+    0x62, 0x47, 0x62, 0x59, 0x43, 0xd9, 0x62, 0x7a,
+    0x7f, 0x3e, 0x63, 0x95, 0x7f, 0xfa, 0x7f, 0x05,
+    0x80, 0xda, 0x64, 0x23, 0x65, 0x60, 0x80, 0xa8,
+    0x65, 0x70, 0x80, 0x5f, 0x33, 0xd5, 0x43, 0xb2,
+    0x80, 0x03, 0x81, 0x0b, 0x44, 0x3e, 0x81, 0xb5,
+    0x5a, 0xa7, 0x67, 0xb5, 0x67, 0x93, 0x33, 0x9c,
+    0x33, 0x01, 0x82, 0x04, 0x82, 0x9e, 0x8f, 0x6b,
+    0x44, 0x91, 0x82, 0x8b, 0x82, 0x9d, 0x82, 0xb3,
+    0x52, 0xb1, 0x82, 0xb3, 0x82, 0xbd, 0x82, 0xe6,
+    0x82, 0x3c, 0x6b, 0xe5, 0x82, 0x1d, 0x83, 0x63,
+    0x83, 0xad, 0x83, 0x23, 0x83, 0xbd, 0x83, 0xe7,
+    0x83, 0x57, 0x84, 0x53, 0x83, 0xca, 0x83, 0xcc,
+    0x83, 0xdc, 0x83, 0x36, 0x6c, 0x6b, 0x6d, 0x02,
+    0x00, 0x00, 0x20, 0x22, 0x2a, 0xa0, 0x0a, 0x00,
+    0x20, 0x80, 0x28, 0x00, 0xa8, 0x20, 0x20, 0x00,
+    0x02, 0x80, 0x22, 0x02, 0x8a, 0x08, 0x00, 0xaa,
+    0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x28, 0xd5,
+    0x6c, 0x2b, 0x45, 0xf1, 0x84, 0xf3, 0x84, 0x16,
+    0x85, 0xca, 0x73, 0x64, 0x85, 0x2c, 0x6f, 0x5d,
+    0x45, 0x61, 0x45, 0xb1, 0x6f, 0xd2, 0x70, 0x6b,
+    0x45, 0x50, 0x86, 0x5c, 0x86, 0x67, 0x86, 0x69,
+    0x86, 0xa9, 0x86, 0x88, 0x86, 0x0e, 0x87, 0xe2,
+    0x86, 0x79, 0x87, 0x28, 0x87, 0x6b, 0x87, 0x86,
+    0x87, 0xd7, 0x45, 0xe1, 0x87, 0x01, 0x88, 0xf9,
+    0x45, 0x60, 0x88, 0x63, 0x88, 0x67, 0x76, 0xd7,
+    0x88, 0xde, 0x88, 0x35, 0x46, 0xfa, 0x88, 0xbb,
+    0x34, 0xae, 0x78, 0x66, 0x79, 0xbe, 0x46, 0xc7,
+    0x46, 0xa0, 0x8a, 0xed, 0x8a, 0x8a, 0x8b, 0x55,
+    0x8c, 0xa8, 0x7c, 0xab, 0x8c, 0xc1, 0x8c, 0x1b,
+    0x8d, 0x77, 0x8d, 0x2f, 0x7f, 0x04, 0x08, 0xcb,
+    0x8d, 0xbc, 0x8d, 0xf0, 0x8d, 0xde, 0x08, 0xd4,
+    0x8e, 0x38, 0x8f, 0xd2, 0x85, 0xed, 0x85, 0x94,
+    0x90, 0xf1, 0x90, 0x11, 0x91, 0x2e, 0x87, 0x1b,
+    0x91, 0x38, 0x92, 0xd7, 0x92, 0xd8, 0x92, 0x7c,
+    0x92, 0xf9, 0x93, 0x15, 0x94, 0xfa, 0x8b, 0x8b,
+    0x95, 0x95, 0x49, 0xb7, 0x95, 0x77, 0x8d, 0xe6,
+    0x49, 0xc3, 0x96, 0xb2, 0x5d, 0x23, 0x97, 0x45,
+    0x91, 0x1a, 0x92, 0x6e, 0x4a, 0x76, 0x4a, 0xe0,
+    0x97, 0x0a, 0x94, 0xb2, 0x4a, 0x96, 0x94, 0x0b,
+    0x98, 0x0b, 0x98, 0x29, 0x98, 0xb6, 0x95, 0xe2,
+    0x98, 0x33, 0x4b, 0x29, 0x99, 0xa7, 0x99, 0xc2,
+    0x99, 0xfe, 0x99, 0xce, 0x4b, 0x30, 0x9b, 0x12,
+    0x9b, 0x40, 0x9c, 0xfd, 0x9c, 0xce, 0x4c, 0xed,
+    0x4c, 0x67, 0x9d, 0xce, 0xa0, 0xf8, 0x4c, 0x05,
+    0xa1, 0x0e, 0xa2, 0x91, 0xa2, 0xbb, 0x9e, 0x56,
+    0x4d, 0xf9, 0x9e, 0xfe, 0x9e, 0x05, 0x9f, 0x0f,
+    0x9f, 0x16, 0x9f, 0x3b, 0x9f, 0x00, 0xa6, 0x02,
+    0x88, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
+    0x28, 0x00, 0x08, 0xa0, 0x80, 0xa0, 0x80, 0x00,
+    0x80, 0x80, 0x00, 0x0a, 0x88, 0x80, 0x00, 0x80,
+    0x00, 0x20, 0x2a, 0x00, 0x80,
+};
+
+static const uint16_t unicode_comp_table[945] = {
+    0x4a01, 0x49c0, 0x4a02, 0x0280, 0x0281, 0x0282, 0x0283, 0x02c0,
+    0x02c2, 0x0a00, 0x0284, 0x2442, 0x0285, 0x07c0, 0x0980, 0x0982,
+    0x2440, 0x2280, 0x02c4, 0x2282, 0x2284, 0x2286, 0x02c6, 0x02c8,
+    0x02ca, 0x02cc, 0x0287, 0x228a, 0x02ce, 0x228c, 0x2290, 0x2292,
+    0x228e, 0x0288, 0x0289, 0x028a, 0x2482, 0x0300, 0x0302, 0x0304,
+    0x028b, 0x2480, 0x0308, 0x0984, 0x0986, 0x2458, 0x0a02, 0x0306,
+    0x2298, 0x229a, 0x229e, 0x0900, 0x030a, 0x22a0, 0x030c, 0x030e,
+    0x0840, 0x0310, 0x0312, 0x22a2, 0x22a6, 0x09c0, 0x22a4, 0x22a8,
+    0x22aa, 0x028c, 0x028d, 0x028e, 0x0340, 0x0342, 0x0344, 0x0380,
+    0x028f, 0x248e, 0x07c2, 0x0988, 0x098a, 0x2490, 0x0346, 0x22ac,
+    0x0400, 0x22b0, 0x0842, 0x22b2, 0x0402, 0x22b4, 0x0440, 0x0444,
+    0x22b6, 0x0442, 0x22c2, 0x22c0, 0x22c4, 0x22c6, 0x22c8, 0x0940,
+    0x04c0, 0x0291, 0x22ca, 0x04c4, 0x22cc, 0x04c2, 0x22d0, 0x22ce,
+    0x0292, 0x0293, 0x0294, 0x0295, 0x0540, 0x0542, 0x0a08, 0x0296,
+    0x2494, 0x0544, 0x07c4, 0x098c, 0x098e, 0x06c0, 0x2492, 0x0844,
+    0x2308, 0x230a, 0x0580, 0x230c, 0x0584, 0x0990, 0x0992, 0x230e,
+    0x0582, 0x2312, 0x0586, 0x0588, 0x2314, 0x058c, 0x2316, 0x0998,
+    0x058a, 0x231e, 0x0590, 0x2320, 0x099a, 0x058e, 0x2324, 0x2322,
+    0x0299, 0x029a, 0x029b, 0x05c0, 0x05c2, 0x05c4, 0x029c, 0x24ac,
+    0x05c6, 0x05c8, 0x07c6, 0x0994, 0x0996, 0x0700, 0x24aa, 0x2326,
+    0x05ca, 0x232a, 0x2328, 0x2340, 0x2342, 0x2344, 0x2346, 0x05cc,
+    0x234a, 0x2348, 0x234c, 0x234e, 0x2350, 0x24b8, 0x029d, 0x05ce,
+    0x24be, 0x0a0c, 0x2352, 0x0600, 0x24bc, 0x24ba, 0x0640, 0x2354,
+    0x0642, 0x0644, 0x2356, 0x2358, 0x02a0, 0x02a1, 0x02a2, 0x02a3,
+    0x02c1, 0x02c3, 0x0a01, 0x02a4, 0x2443, 0x02a5, 0x07c1, 0x0981,
+    0x0983, 0x2441, 0x2281, 0x02c5, 0x2283, 0x2285, 0x2287, 0x02c7,
+    0x02c9, 0x02cb, 0x02cd, 0x02a7, 0x228b, 0x02cf, 0x228d, 0x2291,
+    0x2293, 0x228f, 0x02a8, 0x02a9, 0x02aa, 0x2483, 0x0301, 0x0303,
+    0x0305, 0x02ab, 0x2481, 0x0309, 0x0985, 0x0987, 0x2459, 0x0a03,
+    0x0307, 0x2299, 0x229b, 0x229f, 0x0901, 0x030b, 0x22a1, 0x030d,
+    0x030f, 0x0841, 0x0311, 0x0313, 0x22a3, 0x22a7, 0x09c1, 0x22a5,
+    0x22a9, 0x22ab, 0x2380, 0x02ac, 0x02ad, 0x02ae, 0x0341, 0x0343,
+    0x0345, 0x02af, 0x248f, 0x07c3, 0x0989, 0x098b, 0x2491, 0x0347,
+    0x22ad, 0x0401, 0x0884, 0x22b1, 0x0843, 0x22b3, 0x0403, 0x22b5,
+    0x0441, 0x0445, 0x22b7, 0x0443, 0x22c3, 0x22c1, 0x22c5, 0x22c7,
+    0x22c9, 0x0941, 0x04c1, 0x02b1, 0x22cb, 0x04c5, 0x22cd, 0x04c3,
+    0x22d1, 0x22cf, 0x02b2, 0x02b3, 0x02b4, 0x02b5, 0x0541, 0x0543,
+    0x0a09, 0x02b6, 0x2495, 0x0545, 0x07c5, 0x098d, 0x098f, 0x06c1,
+    0x2493, 0x0845, 0x2309, 0x230b, 0x0581, 0x230d, 0x0585, 0x0991,
+    0x0993, 0x230f, 0x0583, 0x2313, 0x0587, 0x0589, 0x2315, 0x058d,
+    0x2317, 0x0999, 0x058b, 0x231f, 0x2381, 0x0591, 0x2321, 0x099b,
+    0x058f, 0x2325, 0x2323, 0x02b9, 0x02ba, 0x02bb, 0x05c1, 0x05c3,
+    0x05c5, 0x02bc, 0x24ad, 0x05c7, 0x05c9, 0x07c7, 0x0995, 0x0997,
+    0x0701, 0x24ab, 0x2327, 0x05cb, 0x232b, 0x2329, 0x2341, 0x2343,
+    0x2345, 0x2347, 0x05cd, 0x234b, 0x2349, 0x2382, 0x234d, 0x234f,
+    0x2351, 0x24b9, 0x02bd, 0x05cf, 0x24bf, 0x0a0d, 0x2353, 0x02bf,
+    0x24bd, 0x2383, 0x24bb, 0x0641, 0x2355, 0x0643, 0x0645, 0x2357,
+    0x2359, 0x3101, 0x0c80, 0x2e00, 0x2446, 0x2444, 0x244a, 0x2448,
+    0x0800, 0x0942, 0x0944, 0x0804, 0x2288, 0x2486, 0x2484, 0x248a,
+    0x2488, 0x22ae, 0x2498, 0x2496, 0x249c, 0x249a, 0x2300, 0x0a06,
+    0x2302, 0x0a04, 0x0946, 0x07ce, 0x07ca, 0x07c8, 0x07cc, 0x2447,
+    0x2445, 0x244b, 0x2449, 0x0801, 0x0943, 0x0945, 0x0805, 0x2289,
+    0x2487, 0x2485, 0x248b, 0x2489, 0x22af, 0x2499, 0x2497, 0x249d,
+    0x249b, 0x2301, 0x0a07, 0x2303, 0x0a05, 0x0947, 0x07cf, 0x07cb,
+    0x07c9, 0x07cd, 0x2450, 0x244e, 0x2454, 0x2452, 0x2451, 0x244f,
+    0x2455, 0x2453, 0x2294, 0x2296, 0x2295, 0x2297, 0x2304, 0x2306,
+    0x2305, 0x2307, 0x2318, 0x2319, 0x231a, 0x231b, 0x232c, 0x232d,
+    0x232e, 0x232f, 0x2400, 0x24a2, 0x24a0, 0x24a6, 0x24a4, 0x24a8,
+    0x24a3, 0x24a1, 0x24a7, 0x24a5, 0x24a9, 0x24b0, 0x24ae, 0x24b4,
+    0x24b2, 0x24b6, 0x24b1, 0x24af, 0x24b5, 0x24b3, 0x24b7, 0x0882,
+    0x0880, 0x0881, 0x0802, 0x0803, 0x229c, 0x229d, 0x0a0a, 0x0a0b,
+    0x0883, 0x0b40, 0x2c8a, 0x0c81, 0x2c89, 0x2c88, 0x2540, 0x2541,
+    0x2d00, 0x2e07, 0x0d00, 0x2640, 0x2641, 0x2e80, 0x0d01, 0x26c8,
+    0x26c9, 0x2f00, 0x2f84, 0x0d02, 0x2f83, 0x2f82, 0x0d40, 0x26d8,
+    0x26d9, 0x3186, 0x0d04, 0x2740, 0x2741, 0x3100, 0x3086, 0x0d06,
+    0x3085, 0x3084, 0x0d41, 0x2840, 0x3200, 0x0d07, 0x284f, 0x2850,
+    0x3280, 0x2c84, 0x2e03, 0x2857, 0x0d42, 0x2c81, 0x2c80, 0x24c0,
+    0x24c1, 0x2c86, 0x2c83, 0x28c0, 0x0d43, 0x25c0, 0x25c1, 0x2940,
+    0x0d44, 0x26c0, 0x26c1, 0x2e05, 0x2e02, 0x29c0, 0x0d45, 0x2f05,
+    0x2f04, 0x0d80, 0x26d0, 0x26d1, 0x2f80, 0x2a40, 0x0d82, 0x26e0,
+    0x26e1, 0x3080, 0x3081, 0x2ac0, 0x0d83, 0x3004, 0x3003, 0x0d81,
+    0x27c0, 0x27c1, 0x3082, 0x2b40, 0x0d84, 0x2847, 0x2848, 0x3184,
+    0x3181, 0x2f06, 0x0d08, 0x2f81, 0x3005, 0x0d46, 0x3083, 0x3182,
+    0x0e00, 0x0e01, 0x0f40, 0x1180, 0x1182, 0x0f03, 0x0f00, 0x11c0,
+    0x0f01, 0x1140, 0x1202, 0x1204, 0x0f81, 0x1240, 0x0fc0, 0x1242,
+    0x0f80, 0x1244, 0x1284, 0x0f82, 0x1286, 0x1288, 0x128a, 0x12c0,
+    0x1282, 0x1181, 0x1183, 0x1043, 0x1040, 0x11c1, 0x1041, 0x1141,
+    0x1203, 0x1205, 0x10c1, 0x1241, 0x1000, 0x1243, 0x10c0, 0x1245,
+    0x1285, 0x10c2, 0x1287, 0x1289, 0x128b, 0x12c1, 0x1283, 0x1080,
+    0x1100, 0x1101, 0x1200, 0x1201, 0x1280, 0x1281, 0x1340, 0x1341,
+    0x1343, 0x1342, 0x1344, 0x13c2, 0x1400, 0x13c0, 0x1440, 0x1480,
+    0x14c0, 0x1540, 0x1541, 0x1740, 0x1700, 0x1741, 0x17c0, 0x1800,
+    0x1802, 0x1801, 0x1840, 0x1880, 0x1900, 0x18c0, 0x18c1, 0x1901,
+    0x1940, 0x1942, 0x1941, 0x1980, 0x19c0, 0x19c2, 0x19c1, 0x1c80,
+    0x1cc0, 0x1dc0, 0x1f80, 0x2000, 0x2002, 0x2004, 0x2006, 0x2008,
+    0x2040, 0x2080, 0x2082, 0x20c0, 0x20c1, 0x2100, 0x22b8, 0x22b9,
+    0x2310, 0x2311, 0x231c, 0x231d, 0x244c, 0x2456, 0x244d, 0x2457,
+    0x248c, 0x248d, 0x249e, 0x249f, 0x2500, 0x2502, 0x2504, 0x2bc0,
+    0x2501, 0x2503, 0x2505, 0x2bc1, 0x2bc2, 0x2bc3, 0x2bc4, 0x2bc5,
+    0x2bc6, 0x2bc7, 0x2580, 0x2582, 0x2584, 0x2bc8, 0x2581, 0x2583,
+    0x2585, 0x2bc9, 0x2bca, 0x2bcb, 0x2bcc, 0x2bcd, 0x2bce, 0x2bcf,
+    0x2600, 0x2602, 0x2601, 0x2603, 0x2680, 0x2682, 0x2681, 0x2683,
+    0x26c2, 0x26c4, 0x26c6, 0x2c00, 0x26c3, 0x26c5, 0x26c7, 0x2c01,
+    0x2c02, 0x2c03, 0x2c04, 0x2c05, 0x2c06, 0x2c07, 0x26ca, 0x26cc,
+    0x26ce, 0x2c08, 0x26cb, 0x26cd, 0x26cf, 0x2c09, 0x2c0a, 0x2c0b,
+    0x2c0c, 0x2c0d, 0x2c0e, 0x2c0f, 0x26d2, 0x26d4, 0x26d6, 0x26d3,
+    0x26d5, 0x26d7, 0x26da, 0x26dc, 0x26de, 0x26db, 0x26dd, 0x26df,
+    0x2700, 0x2702, 0x2701, 0x2703, 0x2780, 0x2782, 0x2781, 0x2783,
+    0x2800, 0x2802, 0x2804, 0x2801, 0x2803, 0x2805, 0x2842, 0x2844,
+    0x2846, 0x2849, 0x284b, 0x284d, 0x2c40, 0x284a, 0x284c, 0x284e,
+    0x2c41, 0x2c42, 0x2c43, 0x2c44, 0x2c45, 0x2c46, 0x2c47, 0x2851,
+    0x2853, 0x2855, 0x2c48, 0x2852, 0x2854, 0x2856, 0x2c49, 0x2c4a,
+    0x2c4b, 0x2c4c, 0x2c4d, 0x2c4e, 0x2c4f, 0x2c82, 0x2e01, 0x3180,
+    0x2c87, 0x2f01, 0x2f02, 0x2f03, 0x2e06, 0x3185, 0x3000, 0x3001,
+    0x3002, 0x4640, 0x4641, 0x4680, 0x46c0, 0x46c2, 0x46c1, 0x4700,
+    0x4740, 0x4780, 0x47c0, 0x47c2, 0x4900, 0x4940, 0x4980, 0x4982,
+    0x4a00, 0x49c2, 0x4a03, 0x4a04, 0x4a40, 0x4a41, 0x4a80, 0x4a81,
+    0x4ac0, 0x4ac1, 0x4bc0, 0x4bc1, 0x4b00, 0x4b01, 0x4b40, 0x4b41,
+    0x4bc2, 0x4bc3, 0x4b80, 0x4b81, 0x4b82, 0x4b83, 0x4c00, 0x4c01,
+    0x4c02, 0x4c03, 0x5600, 0x5440, 0x5442, 0x5444, 0x5446, 0x5448,
+    0x544a, 0x544c, 0x544e, 0x5450, 0x5452, 0x5454, 0x5456, 0x5480,
+    0x5482, 0x5484, 0x54c0, 0x54c1, 0x5500, 0x5501, 0x5540, 0x5541,
+    0x5580, 0x5581, 0x55c0, 0x55c1, 0x5680, 0x58c0, 0x5700, 0x5702,
+    0x5704, 0x5706, 0x5708, 0x570a, 0x570c, 0x570e, 0x5710, 0x5712,
+    0x5714, 0x5716, 0x5740, 0x5742, 0x5744, 0x5780, 0x5781, 0x57c0,
+    0x57c1, 0x5800, 0x5801, 0x5840, 0x5841, 0x5880, 0x5881, 0x5900,
+    0x5901, 0x5902, 0x5903, 0x5940, 0x8e80, 0x8e82, 0x8ec0, 0x8f00,
+    0x8f01, 0x8f40, 0x8f41, 0x8f81, 0x8f80, 0x8f83, 0x8fc0, 0x8fc1,
+    0x9000,
+};
+
+typedef enum {
+    UNICODE_GC_Cn,
+    UNICODE_GC_Lu,
+    UNICODE_GC_Ll,
+    UNICODE_GC_Lt,
+    UNICODE_GC_Lm,
+    UNICODE_GC_Lo,
+    UNICODE_GC_Mn,
+    UNICODE_GC_Mc,
+    UNICODE_GC_Me,
+    UNICODE_GC_Nd,
+    UNICODE_GC_Nl,
+    UNICODE_GC_No,
+    UNICODE_GC_Sm,
+    UNICODE_GC_Sc,
+    UNICODE_GC_Sk,
+    UNICODE_GC_So,
+    UNICODE_GC_Pc,
+    UNICODE_GC_Pd,
+    UNICODE_GC_Ps,
+    UNICODE_GC_Pe,
+    UNICODE_GC_Pi,
+    UNICODE_GC_Pf,
+    UNICODE_GC_Po,
+    UNICODE_GC_Zs,
+    UNICODE_GC_Zl,
+    UNICODE_GC_Zp,
+    UNICODE_GC_Cc,
+    UNICODE_GC_Cf,
+    UNICODE_GC_Cs,
+    UNICODE_GC_Co,
+    UNICODE_GC_LC,
+    UNICODE_GC_L,
+    UNICODE_GC_M,
+    UNICODE_GC_N,
+    UNICODE_GC_S,
+    UNICODE_GC_P,
+    UNICODE_GC_Z,
+    UNICODE_GC_C,
+    UNICODE_GC_COUNT,
+} UnicodeGCEnum;
+
+static const char unicode_gc_name_table[] =
+    "Cn,Unassigned"            "\0"
+    "Lu,Uppercase_Letter"      "\0"
+    "Ll,Lowercase_Letter"      "\0"
+    "Lt,Titlecase_Letter"      "\0"
+    "Lm,Modifier_Letter"       "\0"
+    "Lo,Other_Letter"          "\0"
+    "Mn,Nonspacing_Mark"       "\0"
+    "Mc,Spacing_Mark"          "\0"
+    "Me,Enclosing_Mark"        "\0"
+    "Nd,Decimal_Number,digit"  "\0"
+    "Nl,Letter_Number"         "\0"
+    "No,Other_Number"          "\0"
+    "Sm,Math_Symbol"           "\0"
+    "Sc,Currency_Symbol"       "\0"
+    "Sk,Modifier_Symbol"       "\0"
+    "So,Other_Symbol"          "\0"
+    "Pc,Connector_Punctuation" "\0"
+    "Pd,Dash_Punctuation"      "\0"
+    "Ps,Open_Punctuation"      "\0"
+    "Pe,Close_Punctuation"     "\0"
+    "Pi,Initial_Punctuation"   "\0"
+    "Pf,Final_Punctuation"     "\0"
+    "Po,Other_Punctuation"     "\0"
+    "Zs,Space_Separator"       "\0"
+    "Zl,Line_Separator"        "\0"
+    "Zp,Paragraph_Separator"   "\0"
+    "Cc,Control,cntrl"         "\0"
+    "Cf,Format"                "\0"
+    "Cs,Surrogate"             "\0"
+    "Co,Private_Use"           "\0"
+    "LC,Cased_Letter"          "\0"
+    "L,Letter"                 "\0"
+    "M,Mark,Combining_Mark"    "\0"
+    "N,Number"                 "\0"
+    "S,Symbol"                 "\0"
+    "P,Punctuation,punct"      "\0"
+    "Z,Separator"              "\0"
+    "C,Other"                  "\0"
+;
+
+static const uint8_t unicode_gc_table[3790] = {
+    0xfa, 0x18, 0x17, 0x56, 0x0d, 0x56, 0x12, 0x13,
+    0x16, 0x0c, 0x16, 0x11, 0x36, 0xe9, 0x02, 0x36,
+    0x4c, 0x36, 0xe1, 0x12, 0x12, 0x16, 0x13, 0x0e,
+    0x10, 0x0e, 0xe2, 0x12, 0x12, 0x0c, 0x13, 0x0c,
+    0xfa, 0x19, 0x17, 0x16, 0x6d, 0x0f, 0x16, 0x0e,
+    0x0f, 0x05, 0x14, 0x0c, 0x1b, 0x0f, 0x0e, 0x0f,
+    0x0c, 0x2b, 0x0e, 0x02, 0x36, 0x0e, 0x0b, 0x05,
+    0x15, 0x4b, 0x16, 0xe1, 0x0f, 0x0c, 0xc1, 0xe2,
+    0x10, 0x0c, 0xe2, 0x00, 0xff, 0x30, 0x02, 0xff,
+    0x08, 0x02, 0xff, 0x27, 0xbf, 0x22, 0x21, 0x02,
+    0x5f, 0x5f, 0x21, 0x22, 0x61, 0x02, 0x21, 0x02,
+    0x41, 0x42, 0x21, 0x02, 0x21, 0x02, 0x9f, 0x7f,
+    0x02, 0x5f, 0x5f, 0x21, 0x02, 0x5f, 0x3f, 0x02,
+    0x05, 0x3f, 0x22, 0x65, 0x01, 0x03, 0x02, 0x01,
+    0x03, 0x02, 0x01, 0x03, 0x02, 0xff, 0x08, 0x02,
+    0xff, 0x0a, 0x02, 0x01, 0x03, 0x02, 0x5f, 0x21,
+    0x02, 0xff, 0x32, 0xa2, 0x21, 0x02, 0x21, 0x22,
+    0x5f, 0x41, 0x02, 0xff, 0x00, 0xe2, 0x3c, 0x05,
+    0xe2, 0x13, 0xe4, 0x0a, 0x6e, 0xe4, 0x04, 0xee,
+    0x06, 0x84, 0xce, 0x04, 0x0e, 0x04, 0xee, 0x09,
+    0xe6, 0x68, 0x7f, 0x04, 0x0e, 0x3f, 0x20, 0x04,
+    0x42, 0x16, 0x01, 0x60, 0x2e, 0x01, 0x16, 0x41,
+    0x00, 0x01, 0x00, 0x21, 0x02, 0xe1, 0x09, 0x00,
+    0xe1, 0x01, 0xe2, 0x1b, 0x3f, 0x02, 0x41, 0x42,
+    0xff, 0x10, 0x62, 0x3f, 0x0c, 0x5f, 0x3f, 0x02,
+    0xe1, 0x2b, 0xe2, 0x28, 0xff, 0x1a, 0x0f, 0x86,
+    0x28, 0xff, 0x2f, 0xff, 0x06, 0x02, 0xff, 0x58,
+    0x00, 0xe1, 0x1e, 0x20, 0x04, 0xb6, 0xe2, 0x21,
+    0x16, 0x11, 0x20, 0x2f, 0x0d, 0x00, 0xe6, 0x25,
+    0x11, 0x06, 0x16, 0x26, 0x16, 0x26, 0x16, 0x06,
+    0xe0, 0x00, 0xe5, 0x13, 0x60, 0x65, 0x36, 0xe0,
+    0x03, 0xbb, 0x4c, 0x36, 0x0d, 0x36, 0x2f, 0xe6,
+    0x03, 0x16, 0x1b, 0x00, 0x36, 0xe5, 0x18, 0x04,
+    0xe5, 0x02, 0xe6, 0x0d, 0xe9, 0x02, 0x76, 0x25,
+    0x06, 0xe5, 0x5b, 0x16, 0x05, 0xc6, 0x1b, 0x0f,
+    0xa6, 0x24, 0x26, 0x0f, 0x66, 0x25, 0xe9, 0x02,
+    0x45, 0x2f, 0x05, 0xf6, 0x06, 0x00, 0x1b, 0x05,
+    0x06, 0xe5, 0x16, 0xe6, 0x13, 0x20, 0xe5, 0x51,
+    0xe6, 0x03, 0x05, 0xe0, 0x06, 0xe9, 0x02, 0xe5,
+    0x19, 0xe6, 0x01, 0x24, 0x0f, 0x56, 0x04, 0x20,
+    0x06, 0x2d, 0xe5, 0x0e, 0x66, 0x04, 0xe6, 0x01,
+    0x04, 0x46, 0x04, 0x86, 0x20, 0xf6, 0x07, 0x00,
+    0xe5, 0x11, 0x46, 0x20, 0x16, 0x00, 0xe5, 0x03,
+    0xe0, 0x2d, 0xe5, 0x0d, 0x00, 0xe5, 0x0a, 0xe0,
+    0x03, 0xe6, 0x07, 0x1b, 0xe6, 0x18, 0x07, 0xe5,
+    0x2e, 0x06, 0x07, 0x06, 0x05, 0x47, 0xe6, 0x00,
+    0x67, 0x06, 0x27, 0x05, 0xc6, 0xe5, 0x02, 0x26,
+    0x36, 0xe9, 0x02, 0x16, 0x04, 0xe5, 0x07, 0x06,
+    0x27, 0x00, 0xe5, 0x00, 0x20, 0x25, 0x20, 0xe5,
+    0x0e, 0x00, 0xc5, 0x00, 0x05, 0x40, 0x65, 0x20,
+    0x06, 0x05, 0x47, 0x66, 0x20, 0x27, 0x20, 0x27,
+    0x06, 0x05, 0xe0, 0x00, 0x07, 0x60, 0x25, 0x00,
+    0x45, 0x26, 0x20, 0xe9, 0x02, 0x25, 0x2d, 0xab,
+    0x0f, 0x0d, 0x05, 0x16, 0x06, 0x20, 0x26, 0x07,
+    0x00, 0xa5, 0x60, 0x25, 0x20, 0xe5, 0x0e, 0x00,
+    0xc5, 0x00, 0x25, 0x00, 0x25, 0x00, 0x25, 0x20,
+    0x06, 0x00, 0x47, 0x26, 0x60, 0x26, 0x20, 0x46,
+    0x40, 0x06, 0xc0, 0x65, 0x00, 0x05, 0xc0, 0xe9,
+    0x02, 0x26, 0x45, 0x06, 0x16, 0xe0, 0x02, 0x26,
+    0x07, 0x00, 0xe5, 0x01, 0x00, 0x45, 0x00, 0xe5,
+    0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00, 0x85, 0x20,
+    0x06, 0x05, 0x47, 0x86, 0x00, 0x26, 0x07, 0x00,
+    0x27, 0x06, 0x20, 0x05, 0xe0, 0x07, 0x25, 0x26,
+    0x20, 0xe9, 0x02, 0x16, 0x0d, 0xc0, 0x05, 0xa6,
+    0x00, 0x06, 0x27, 0x00, 0xe5, 0x00, 0x20, 0x25,
+    0x20, 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00,
+    0x85, 0x20, 0x06, 0x05, 0x07, 0x06, 0x07, 0x66,
+    0x20, 0x27, 0x20, 0x27, 0x06, 0xc0, 0x26, 0x07,
+    0x60, 0x25, 0x00, 0x45, 0x26, 0x20, 0xe9, 0x02,
+    0x0f, 0x05, 0xab, 0xe0, 0x02, 0x06, 0x05, 0x00,
+    0xa5, 0x40, 0x45, 0x00, 0x65, 0x40, 0x25, 0x00,
+    0x05, 0x00, 0x25, 0x40, 0x25, 0x40, 0x45, 0x40,
+    0xe5, 0x04, 0x60, 0x27, 0x06, 0x27, 0x40, 0x47,
+    0x00, 0x47, 0x06, 0x20, 0x05, 0xa0, 0x07, 0xe0,
+    0x06, 0xe9, 0x02, 0x4b, 0xaf, 0x0d, 0x0f, 0x80,
+    0x06, 0x47, 0x06, 0xe5, 0x00, 0x00, 0x45, 0x00,
+    0xe5, 0x0f, 0x00, 0xe5, 0x08, 0x40, 0x05, 0x46,
+    0x67, 0x00, 0x46, 0x00, 0x66, 0xc0, 0x26, 0x00,
+    0x45, 0x80, 0x25, 0x26, 0x20, 0xe9, 0x02, 0xc0,
+    0x16, 0xcb, 0x0f, 0x05, 0x06, 0x27, 0x16, 0xe5,
+    0x00, 0x00, 0x45, 0x00, 0xe5, 0x0f, 0x00, 0xe5,
+    0x02, 0x00, 0x85, 0x20, 0x06, 0x05, 0x07, 0x06,
+    0x87, 0x00, 0x06, 0x27, 0x00, 0x27, 0x26, 0xc0,
+    0x27, 0xc0, 0x05, 0x00, 0x25, 0x26, 0x20, 0xe9,
+    0x02, 0x00, 0x25, 0xe0, 0x05, 0x26, 0x27, 0xe5,
+    0x01, 0x00, 0x45, 0x00, 0xe5, 0x21, 0x26, 0x05,
+    0x47, 0x66, 0x00, 0x47, 0x00, 0x47, 0x06, 0x05,
+    0x0f, 0x60, 0x45, 0x07, 0xcb, 0x45, 0x26, 0x20,
+    0xe9, 0x02, 0xeb, 0x01, 0x0f, 0xa5, 0x00, 0x06,
+    0x27, 0x00, 0xe5, 0x0a, 0x40, 0xe5, 0x10, 0x00,
+    0xe5, 0x01, 0x00, 0x05, 0x20, 0xc5, 0x40, 0x06,
+    0x60, 0x47, 0x46, 0x00, 0x06, 0x00, 0xe7, 0x00,
+    0xa0, 0xe9, 0x02, 0x20, 0x27, 0x16, 0xe0, 0x04,
+    0xe5, 0x28, 0x06, 0x25, 0xc6, 0x60, 0x0d, 0xa5,
+    0x04, 0xe6, 0x00, 0x16, 0xe9, 0x02, 0x36, 0xe0,
+    0x1d, 0x25, 0x00, 0x05, 0x00, 0x85, 0x00, 0xe5,
+    0x10, 0x00, 0x05, 0x00, 0xe5, 0x02, 0x06, 0x25,
+    0xe6, 0x01, 0x05, 0x20, 0x85, 0x00, 0x04, 0x00,
+    0xa6, 0x20, 0xe9, 0x02, 0x20, 0x65, 0xe0, 0x18,
+    0x05, 0x4f, 0xf6, 0x07, 0x0f, 0x16, 0x4f, 0x26,
+    0xaf, 0xe9, 0x02, 0xeb, 0x02, 0x0f, 0x06, 0x0f,
+    0x06, 0x0f, 0x06, 0x12, 0x13, 0x12, 0x13, 0x27,
+    0xe5, 0x00, 0x00, 0xe5, 0x1c, 0x60, 0xe6, 0x06,
+    0x07, 0x86, 0x16, 0x26, 0x85, 0xe6, 0x03, 0x00,
+    0xe6, 0x1c, 0x00, 0xef, 0x00, 0x06, 0xaf, 0x00,
+    0x2f, 0x96, 0x6f, 0x36, 0xe0, 0x1d, 0xe5, 0x23,
+    0x27, 0x66, 0x07, 0xa6, 0x07, 0x26, 0x27, 0x26,
+    0x05, 0xe9, 0x02, 0xb6, 0xa5, 0x27, 0x26, 0x65,
+    0x46, 0x05, 0x47, 0x25, 0xc7, 0x45, 0x66, 0xe5,
+    0x05, 0x06, 0x27, 0x26, 0xa7, 0x06, 0x05, 0x07,
+    0xe9, 0x02, 0x47, 0x06, 0x2f, 0xe1, 0x1e, 0x00,
+    0x01, 0x80, 0x01, 0x20, 0xe2, 0x23, 0x16, 0x04,
+    0x42, 0xe5, 0x80, 0xc1, 0x00, 0x65, 0x20, 0xc5,
+    0x00, 0x05, 0x00, 0x65, 0x20, 0xe5, 0x21, 0x00,
+    0x65, 0x20, 0xe5, 0x19, 0x00, 0x65, 0x20, 0xc5,
+    0x00, 0x05, 0x00, 0x65, 0x20, 0xe5, 0x07, 0x00,
+    0xe5, 0x31, 0x00, 0x65, 0x20, 0xe5, 0x3b, 0x20,
+    0x46, 0xf6, 0x01, 0xeb, 0x0c, 0x40, 0xe5, 0x08,
+    0xef, 0x02, 0xa0, 0xe1, 0x4e, 0x20, 0xa2, 0x20,
+    0x11, 0xe5, 0x81, 0xe4, 0x0f, 0x16, 0xe5, 0x09,
+    0x17, 0xe5, 0x12, 0x12, 0x13, 0x40, 0xe5, 0x43,
+    0x56, 0x4a, 0xe5, 0x00, 0xc0, 0xe5, 0x05, 0x00,
+    0x65, 0x46, 0xe0, 0x03, 0xe5, 0x0a, 0x46, 0x36,
+    0xe0, 0x01, 0xe5, 0x0a, 0x26, 0xe0, 0x04, 0xe5,
+    0x05, 0x00, 0x45, 0x00, 0x26, 0xe0, 0x04, 0xe5,
+    0x2c, 0x26, 0x07, 0xc6, 0xe7, 0x00, 0x06, 0x27,
+    0xe6, 0x03, 0x56, 0x04, 0x56, 0x0d, 0x05, 0x06,
+    0x20, 0xe9, 0x02, 0xa0, 0xeb, 0x02, 0xa0, 0xb6,
+    0x11, 0x76, 0x46, 0x1b, 0x00, 0xe9, 0x02, 0xa0,
+    0xe5, 0x1b, 0x04, 0xe5, 0x2d, 0xc0, 0x85, 0x26,
+    0xe5, 0x1a, 0x06, 0x05, 0x80, 0xe5, 0x3e, 0xe0,
+    0x02, 0xe5, 0x17, 0x00, 0x46, 0x67, 0x26, 0x47,
+    0x60, 0x27, 0x06, 0xa7, 0x46, 0x60, 0x0f, 0x40,
+    0x36, 0xe9, 0x02, 0xe5, 0x16, 0x20, 0x85, 0xe0,
+    0x03, 0xe5, 0x24, 0x60, 0xe5, 0x12, 0xa0, 0xe9,
+    0x02, 0x0b, 0x40, 0xef, 0x1a, 0xe5, 0x0f, 0x26,
+    0x27, 0x06, 0x20, 0x36, 0xe5, 0x2d, 0x07, 0x06,
+    0x07, 0xc6, 0x00, 0x06, 0x07, 0x06, 0x27, 0xe6,
+    0x00, 0xa7, 0xe6, 0x02, 0x20, 0x06, 0xe9, 0x02,
+    0xa0, 0xe9, 0x02, 0xa0, 0xd6, 0x04, 0xb6, 0x20,
+    0xe6, 0x06, 0x08, 0x26, 0xe0, 0x37, 0x66, 0x07,
+    0xe5, 0x27, 0x06, 0x07, 0x86, 0x07, 0x06, 0x87,
+    0x06, 0x27, 0xc5, 0x60, 0xe9, 0x02, 0xd6, 0xef,
+    0x02, 0xe6, 0x01, 0xef, 0x01, 0x40, 0x26, 0x07,
+    0xe5, 0x16, 0x07, 0x66, 0x27, 0x26, 0x07, 0x46,
+    0x25, 0xe9, 0x02, 0xe5, 0x24, 0x06, 0x07, 0x26,
+    0x47, 0x06, 0x07, 0x46, 0x27, 0xe0, 0x00, 0x76,
+    0xe5, 0x1c, 0xe7, 0x00, 0xe6, 0x00, 0x27, 0x26,
+    0x40, 0x96, 0xe9, 0x02, 0x40, 0x45, 0xe9, 0x02,
+    0xe5, 0x16, 0xa4, 0x36, 0xe2, 0x01, 0xc0, 0xe1,
+    0x23, 0x20, 0x41, 0xf6, 0x00, 0xe0, 0x00, 0x46,
+    0x16, 0xe6, 0x05, 0x07, 0xc6, 0x65, 0x06, 0xa5,
+    0x06, 0x25, 0x07, 0x26, 0x05, 0x80, 0xe2, 0x24,
+    0xe4, 0x37, 0xe2, 0x05, 0x04, 0xe2, 0x1a, 0xe4,
+    0x1d, 0xe6, 0x32, 0x00, 0x86, 0xff, 0x80, 0x0e,
+    0xe2, 0x00, 0xff, 0x5a, 0xe2, 0x00, 0xe1, 0x00,
+    0xa2, 0x20, 0xa1, 0x20, 0xe2, 0x00, 0xe1, 0x00,
+    0xe2, 0x00, 0xe1, 0x00, 0xa2, 0x20, 0xa1, 0x20,
+    0xe2, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01,
+    0x00, 0x3f, 0xc2, 0xe1, 0x00, 0xe2, 0x06, 0x20,
+    0xe2, 0x00, 0xe3, 0x00, 0xe2, 0x00, 0xe3, 0x00,
+    0xe2, 0x00, 0xe3, 0x00, 0x82, 0x00, 0x22, 0x61,
+    0x03, 0x0e, 0x02, 0x4e, 0x42, 0x00, 0x22, 0x61,
+    0x03, 0x4e, 0x62, 0x20, 0x22, 0x61, 0x00, 0x4e,
+    0xe2, 0x00, 0x81, 0x4e, 0x20, 0x42, 0x00, 0x22,
+    0x61, 0x03, 0x2e, 0x00, 0xf7, 0x03, 0x9b, 0xb1,
+    0x36, 0x14, 0x15, 0x12, 0x34, 0x15, 0x12, 0x14,
+    0xf6, 0x00, 0x18, 0x19, 0x9b, 0x17, 0xf6, 0x01,
+    0x14, 0x15, 0x76, 0x30, 0x56, 0x0c, 0x12, 0x13,
+    0xf6, 0x03, 0x0c, 0x16, 0x10, 0xf6, 0x02, 0x17,
+    0x9b, 0x00, 0xfb, 0x02, 0x0b, 0x04, 0x20, 0xab,
+    0x4c, 0x12, 0x13, 0x04, 0xeb, 0x02, 0x4c, 0x12,
+    0x13, 0x00, 0xe4, 0x05, 0x40, 0xed, 0x18, 0xe0,
+    0x08, 0xe6, 0x05, 0x68, 0x06, 0x48, 0xe6, 0x04,
+    0xe0, 0x07, 0x2f, 0x01, 0x6f, 0x01, 0x2f, 0x02,
+    0x41, 0x22, 0x41, 0x02, 0x0f, 0x01, 0x2f, 0x0c,
+    0x81, 0xaf, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f,
+    0x61, 0x0f, 0x02, 0x61, 0x02, 0x65, 0x02, 0x2f,
+    0x22, 0x21, 0x8c, 0x3f, 0x42, 0x0f, 0x0c, 0x2f,
+    0x02, 0x0f, 0xeb, 0x08, 0xea, 0x1b, 0x3f, 0x6a,
+    0x0b, 0x2f, 0x60, 0x8c, 0x8f, 0x2c, 0x6f, 0x0c,
+    0x2f, 0x0c, 0x2f, 0x0c, 0xcf, 0x0c, 0xef, 0x17,
+    0x2c, 0x2f, 0x0c, 0x0f, 0x0c, 0xef, 0x17, 0xec,
+    0x80, 0x84, 0xef, 0x00, 0x12, 0x13, 0x12, 0x13,
+    0xef, 0x0c, 0x2c, 0xcf, 0x12, 0x13, 0xef, 0x49,
+    0x0c, 0xef, 0x16, 0xec, 0x11, 0xef, 0x20, 0xac,
+    0xef, 0x3d, 0xe0, 0x11, 0xef, 0x03, 0xe0, 0x0d,
+    0xeb, 0x34, 0xef, 0x46, 0xeb, 0x0e, 0xef, 0x80,
+    0x2f, 0x0c, 0xef, 0x01, 0x0c, 0xef, 0x2e, 0xec,
+    0x00, 0xef, 0x67, 0x0c, 0xef, 0x80, 0x70, 0x12,
+    0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12,
+    0x13, 0x12, 0x13, 0x12, 0x13, 0xeb, 0x16, 0xef,
+    0x24, 0x8c, 0x12, 0x13, 0xec, 0x17, 0x12, 0x13,
+    0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
+    0xec, 0x08, 0xef, 0x80, 0x78, 0xec, 0x7b, 0x12,
+    0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12,
+    0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12,
+    0x13, 0x12, 0x13, 0x12, 0x13, 0xec, 0x37, 0x12,
+    0x13, 0x12, 0x13, 0xec, 0x18, 0x12, 0x13, 0xec,
+    0x80, 0x7a, 0xef, 0x28, 0xec, 0x0d, 0x2f, 0xac,
+    0xef, 0x1f, 0x20, 0xef, 0x18, 0x00, 0xef, 0x61,
+    0xe1, 0x27, 0x00, 0xe2, 0x27, 0x00, 0x5f, 0x21,
+    0x22, 0xdf, 0x41, 0x02, 0x3f, 0x02, 0x3f, 0x82,
+    0x24, 0x41, 0x02, 0xff, 0x5a, 0x02, 0xaf, 0x7f,
+    0x46, 0x3f, 0x80, 0x76, 0x0b, 0x36, 0xe2, 0x1e,
+    0x00, 0x02, 0x80, 0x02, 0x20, 0xe5, 0x30, 0xc0,
+    0x04, 0x16, 0xe0, 0x06, 0x06, 0xe5, 0x0f, 0xe0,
+    0x01, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5,
+    0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5,
+    0x00, 0xe6, 0x18, 0x36, 0x14, 0x15, 0x14, 0x15,
+    0x56, 0x14, 0x15, 0x16, 0x14, 0x15, 0xf6, 0x01,
+    0x11, 0x36, 0x11, 0x16, 0x14, 0x15, 0x36, 0x14,
+    0x15, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12,
+    0x13, 0x96, 0x04, 0xf6, 0x02, 0x31, 0x76, 0x11,
+    0x16, 0x12, 0xf6, 0x05, 0x2f, 0x16, 0xe0, 0x25,
+    0xef, 0x12, 0x00, 0xef, 0x51, 0xe0, 0x04, 0xef,
+    0x80, 0x4e, 0xe0, 0x12, 0xef, 0x04, 0x60, 0x17,
+    0x56, 0x0f, 0x04, 0x05, 0x0a, 0x12, 0x13, 0x12,
+    0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x2f,
+    0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
+    0x11, 0x12, 0x33, 0x0f, 0xea, 0x01, 0x66, 0x27,
+    0x11, 0x84, 0x2f, 0x4a, 0x04, 0x05, 0x16, 0x2f,
+    0x00, 0xe5, 0x4e, 0x20, 0x26, 0x2e, 0x24, 0x05,
+    0x11, 0xe5, 0x52, 0x16, 0x44, 0x05, 0x80, 0xe5,
+    0x23, 0x00, 0xe5, 0x56, 0x00, 0x2f, 0x6b, 0xef,
+    0x02, 0xe5, 0x18, 0xef, 0x1c, 0xe0, 0x04, 0xe5,
+    0x08, 0xef, 0x17, 0x00, 0xeb, 0x02, 0xef, 0x16,
+    0xeb, 0x00, 0x0f, 0xeb, 0x07, 0xef, 0x18, 0xeb,
+    0x02, 0xef, 0x1f, 0xeb, 0x07, 0xef, 0x80, 0xb8,
+    0xe5, 0x99, 0x38, 0xef, 0x38, 0xe5, 0xc0, 0x11,
+    0x75, 0x40, 0xe5, 0x0d, 0x04, 0xe5, 0x83, 0xef,
+    0x40, 0xef, 0x2f, 0xe0, 0x01, 0xe5, 0x20, 0xa4,
+    0x36, 0xe5, 0x80, 0x84, 0x04, 0x56, 0xe5, 0x08,
+    0xe9, 0x02, 0x25, 0xe0, 0x0c, 0xff, 0x26, 0x05,
+    0x06, 0x48, 0x16, 0xe6, 0x02, 0x16, 0x04, 0xff,
+    0x14, 0x24, 0x26, 0xe5, 0x3e, 0xea, 0x02, 0x26,
+    0xb6, 0xe0, 0x00, 0xee, 0x0f, 0xe4, 0x01, 0x2e,
+    0xff, 0x06, 0x22, 0xff, 0x36, 0x04, 0xe2, 0x00,
+    0x9f, 0xff, 0x02, 0x04, 0x2e, 0x7f, 0x05, 0x7f,
+    0x22, 0xff, 0x0d, 0x61, 0x02, 0x81, 0x02, 0xff,
+    0x02, 0x20, 0x5f, 0x41, 0x02, 0x3f, 0xe0, 0x22,
+    0x3f, 0x05, 0x24, 0x02, 0xc5, 0x06, 0x45, 0x06,
+    0x65, 0x06, 0xe5, 0x0f, 0x27, 0x26, 0x07, 0x6f,
+    0x06, 0x40, 0xab, 0x2f, 0x0d, 0x0f, 0xa0, 0xe5,
+    0x2c, 0x76, 0xe0, 0x00, 0x27, 0xe5, 0x2a, 0xe7,
+    0x08, 0x26, 0xe0, 0x00, 0x36, 0xe9, 0x02, 0xa0,
+    0xe6, 0x0a, 0xa5, 0x56, 0x05, 0x16, 0x25, 0x06,
+    0xe9, 0x02, 0xe5, 0x14, 0xe6, 0x00, 0x36, 0xe5,
+    0x0f, 0xe6, 0x03, 0x27, 0xe0, 0x03, 0x16, 0xe5,
+    0x15, 0x40, 0x46, 0x07, 0xe5, 0x27, 0x06, 0x27,
+    0x66, 0x27, 0x26, 0x47, 0xf6, 0x05, 0x00, 0x04,
+    0xe9, 0x02, 0x60, 0x36, 0x85, 0x06, 0x04, 0xe5,
+    0x01, 0xe9, 0x02, 0x85, 0x00, 0xe5, 0x21, 0xa6,
+    0x27, 0x26, 0x27, 0x26, 0xe0, 0x01, 0x45, 0x06,
+    0xe5, 0x00, 0x06, 0x07, 0x20, 0xe9, 0x02, 0x20,
+    0x76, 0xe5, 0x08, 0x04, 0xa5, 0x4f, 0x05, 0x07,
+    0x06, 0x07, 0xe5, 0x2a, 0x06, 0x05, 0x46, 0x25,
+    0x26, 0x85, 0x26, 0x05, 0x06, 0x05, 0xe0, 0x10,
+    0x25, 0x04, 0x36, 0xe5, 0x03, 0x07, 0x26, 0x27,
+    0x36, 0x05, 0x24, 0x07, 0x06, 0xe0, 0x02, 0xa5,
+    0x20, 0xa5, 0x20, 0xa5, 0xe0, 0x01, 0xc5, 0x00,
+    0xc5, 0x00, 0xe2, 0x23, 0x0e, 0x64, 0xe2, 0x01,
+    0x04, 0x2e, 0x60, 0xe2, 0x48, 0xe5, 0x1b, 0x27,
+    0x06, 0x27, 0x06, 0x27, 0x16, 0x07, 0x06, 0x20,
+    0xe9, 0x02, 0xa0, 0xe5, 0xab, 0x1c, 0xe0, 0x04,
+    0xe5, 0x0f, 0x60, 0xe5, 0x29, 0x60, 0xfc, 0x87,
+    0x78, 0xfd, 0x98, 0x78, 0xe5, 0x80, 0xe6, 0x20,
+    0xe5, 0x62, 0xe0, 0x1e, 0xc2, 0xe0, 0x04, 0x82,
+    0x80, 0x05, 0x06, 0xe5, 0x02, 0x0c, 0xe5, 0x05,
+    0x00, 0x85, 0x00, 0x05, 0x00, 0x25, 0x00, 0x25,
+    0x00, 0xe5, 0x64, 0xee, 0x08, 0xe0, 0x09, 0xe5,
+    0x80, 0xe3, 0x13, 0x12, 0xe0, 0x08, 0xe5, 0x38,
+    0x20, 0xe5, 0x2e, 0xe0, 0x20, 0xe5, 0x04, 0x0d,
+    0x0f, 0x20, 0xe6, 0x08, 0xd6, 0x12, 0x13, 0x16,
+    0xa0, 0xe6, 0x08, 0x16, 0x31, 0x30, 0x12, 0x13,
+    0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
+    0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x36, 0x12,
+    0x13, 0x76, 0x50, 0x56, 0x00, 0x76, 0x11, 0x12,
+    0x13, 0x12, 0x13, 0x12, 0x13, 0x56, 0x0c, 0x11,
+    0x4c, 0x00, 0x16, 0x0d, 0x36, 0x60, 0x85, 0x00,
+    0xe5, 0x7f, 0x20, 0x1b, 0x00, 0x56, 0x0d, 0x56,
+    0x12, 0x13, 0x16, 0x0c, 0x16, 0x11, 0x36, 0xe9,
+    0x02, 0x36, 0x4c, 0x36, 0xe1, 0x12, 0x12, 0x16,
+    0x13, 0x0e, 0x10, 0x0e, 0xe2, 0x12, 0x12, 0x0c,
+    0x13, 0x0c, 0x12, 0x13, 0x16, 0x12, 0x13, 0x36,
+    0xe5, 0x02, 0x04, 0xe5, 0x25, 0x24, 0xe5, 0x17,
+    0x40, 0xa5, 0x20, 0xa5, 0x20, 0xa5, 0x20, 0x45,
+    0x40, 0x2d, 0x0c, 0x0e, 0x0f, 0x2d, 0x00, 0x0f,
+    0x6c, 0x2f, 0xe0, 0x02, 0x5b, 0x2f, 0x20, 0xe5,
+    0x04, 0x00, 0xe5, 0x12, 0x00, 0xe5, 0x0b, 0x00,
+    0x25, 0x00, 0xe5, 0x07, 0x20, 0xe5, 0x06, 0xe0,
+    0x1a, 0xe5, 0x73, 0x80, 0x56, 0x60, 0xeb, 0x25,
+    0x40, 0xef, 0x01, 0xea, 0x2d, 0x6b, 0xef, 0x09,
+    0x2b, 0x4f, 0x00, 0xef, 0x05, 0x40, 0x0f, 0xe0,
+    0x27, 0xef, 0x25, 0x06, 0xe0, 0x7a, 0xe5, 0x15,
+    0x40, 0xe5, 0x29, 0xe0, 0x07, 0x06, 0xeb, 0x13,
+    0x60, 0xe5, 0x18, 0x6b, 0xe0, 0x01, 0xe5, 0x0c,
+    0x0a, 0xe5, 0x00, 0x0a, 0x80, 0xe5, 0x1e, 0x86,
+    0x80, 0xe5, 0x16, 0x00, 0x16, 0xe5, 0x1c, 0x60,
+    0xe5, 0x00, 0x16, 0x8a, 0xe0, 0x22, 0xe1, 0x20,
+    0xe2, 0x20, 0xe5, 0x46, 0x20, 0xe9, 0x02, 0xa0,
+    0xe1, 0x1c, 0x60, 0xe2, 0x1c, 0x60, 0xe5, 0x20,
+    0xe0, 0x00, 0xe5, 0x2c, 0xe0, 0x03, 0x16, 0xe0,
+    0x80, 0x08, 0xe5, 0x80, 0xaf, 0xe0, 0x01, 0xe5,
+    0x0e, 0xe0, 0x02, 0xe5, 0x00, 0xe0, 0x80, 0x10,
+    0xa5, 0x20, 0x05, 0x00, 0xe5, 0x24, 0x00, 0x25,
+    0x40, 0x05, 0x20, 0xe5, 0x0f, 0x00, 0x16, 0xeb,
+    0x00, 0xe5, 0x0f, 0x2f, 0xcb, 0xe5, 0x17, 0xe0,
+    0x00, 0xeb, 0x01, 0xe0, 0x28, 0xe5, 0x0b, 0x00,
+    0x25, 0x80, 0x8b, 0xe5, 0x0e, 0xab, 0x40, 0x16,
+    0xe5, 0x12, 0x80, 0x16, 0xe0, 0x38, 0xe5, 0x30,
+    0x60, 0x2b, 0x25, 0xeb, 0x08, 0x20, 0xeb, 0x26,
+    0x05, 0x46, 0x00, 0x26, 0x80, 0x66, 0x65, 0x00,
+    0x45, 0x00, 0xe5, 0x15, 0x20, 0x46, 0x60, 0x06,
+    0xeb, 0x01, 0xc0, 0xf6, 0x01, 0xc0, 0xe5, 0x15,
+    0x2b, 0x16, 0xe5, 0x15, 0x4b, 0xe0, 0x18, 0xe5,
+    0x00, 0x0f, 0xe5, 0x14, 0x26, 0x60, 0x8b, 0xd6,
+    0xe0, 0x01, 0xe5, 0x2e, 0x40, 0xd6, 0xe5, 0x0e,
+    0x20, 0xeb, 0x00, 0xe5, 0x0b, 0x80, 0xeb, 0x00,
+    0xe5, 0x0a, 0xc0, 0x76, 0xe0, 0x04, 0xcb, 0xe0,
+    0x48, 0xe5, 0x41, 0xe0, 0x2f, 0xe1, 0x2b, 0xe0,
+    0x05, 0xe2, 0x2b, 0xc0, 0xab, 0xe5, 0x1c, 0x66,
+    0xe0, 0x00, 0xe9, 0x02, 0xe0, 0x80, 0x9e, 0xeb,
+    0x17, 0x00, 0xe5, 0x22, 0x00, 0x26, 0x11, 0x20,
+    0x25, 0xe0, 0x46, 0xe5, 0x15, 0xeb, 0x02, 0x05,
+    0xe0, 0x00, 0xe5, 0x0e, 0xe6, 0x03, 0x6b, 0x96,
+    0xe0, 0x4e, 0xe5, 0x0d, 0xcb, 0xe0, 0x0c, 0xe5,
+    0x0f, 0xe0, 0x01, 0x07, 0x06, 0x07, 0xe5, 0x2d,
+    0xe6, 0x07, 0xd6, 0x60, 0xeb, 0x0c, 0xe9, 0x02,
+    0xe0, 0x07, 0x46, 0x07, 0xe5, 0x25, 0x47, 0x66,
+    0x27, 0x26, 0x36, 0x1b, 0x76, 0xe0, 0x03, 0x1b,
+    0x20, 0xe5, 0x11, 0xc0, 0xe9, 0x02, 0xa0, 0x46,
+    0xe5, 0x1c, 0x86, 0x07, 0xe6, 0x00, 0x00, 0xe9,
+    0x02, 0x76, 0x05, 0x27, 0x05, 0xe0, 0x00, 0xe5,
+    0x1b, 0x06, 0x36, 0x05, 0xe0, 0x01, 0x26, 0x07,
+    0xe5, 0x28, 0x47, 0xe6, 0x01, 0x27, 0x65, 0x76,
+    0x66, 0x16, 0x07, 0x06, 0xe9, 0x02, 0x05, 0x16,
+    0x05, 0x56, 0x00, 0xeb, 0x0c, 0xe0, 0x03, 0xe5,
+    0x0a, 0x00, 0xe5, 0x11, 0x47, 0x46, 0x27, 0x06,
+    0x07, 0x26, 0xb6, 0x06, 0xe0, 0x39, 0xc5, 0x00,
+    0x05, 0x00, 0x65, 0x00, 0xe5, 0x07, 0x00, 0xe5,
+    0x02, 0x16, 0xa0, 0xe5, 0x27, 0x06, 0x47, 0xe6,
+    0x00, 0x80, 0xe9, 0x02, 0xa0, 0x26, 0x27, 0x00,
+    0xe5, 0x00, 0x20, 0x25, 0x20, 0xe5, 0x0e, 0x00,
+    0xc5, 0x00, 0x25, 0x00, 0x85, 0x00, 0x26, 0x05,
+    0x27, 0x06, 0x67, 0x20, 0x27, 0x20, 0x47, 0x20,
+    0x05, 0xa0, 0x07, 0x80, 0x85, 0x27, 0x20, 0xc6,
+    0x40, 0x86, 0xe0, 0x80, 0x03, 0xe5, 0x2d, 0x47,
+    0xe6, 0x00, 0x27, 0x46, 0x07, 0x06, 0x65, 0x96,
+    0xe9, 0x02, 0x36, 0x00, 0x16, 0x06, 0x45, 0xe0,
+    0x16, 0xe5, 0x28, 0x47, 0xa6, 0x07, 0x06, 0x67,
+    0x26, 0x07, 0x26, 0x25, 0x16, 0x05, 0xe0, 0x00,
+    0xe9, 0x02, 0xe0, 0x80, 0x1e, 0xe5, 0x27, 0x47,
+    0x66, 0x20, 0x67, 0x26, 0x07, 0x26, 0xf6, 0x0f,
+    0x65, 0x26, 0xe0, 0x1a, 0xe5, 0x28, 0x47, 0xe6,
+    0x00, 0x27, 0x06, 0x07, 0x26, 0x56, 0x05, 0xe0,
+    0x03, 0xe9, 0x02, 0xa0, 0xf6, 0x05, 0xe0, 0x0b,
+    0xe5, 0x23, 0x06, 0x07, 0x06, 0x27, 0xa6, 0x07,
+    0x06, 0x05, 0xc0, 0xe9, 0x02, 0xe0, 0x2e, 0xe5,
+    0x13, 0x20, 0x46, 0x27, 0x66, 0x07, 0x86, 0x60,
+    0xe9, 0x02, 0x2b, 0x56, 0x0f, 0xe0, 0x80, 0x38,
+    0xe5, 0x24, 0x47, 0xe6, 0x01, 0x07, 0x26, 0x16,
+    0xe0, 0x5c, 0xe1, 0x18, 0xe2, 0x18, 0xe9, 0x02,
+    0xeb, 0x01, 0xe0, 0x04, 0xe5, 0x00, 0x20, 0x05,
+    0x20, 0xe5, 0x00, 0x00, 0x25, 0x00, 0xe5, 0x10,
+    0xa7, 0x00, 0x27, 0x20, 0x26, 0x07, 0x06, 0x05,
+    0x07, 0x05, 0x07, 0x06, 0x56, 0xe0, 0x01, 0xe9,
+    0x02, 0xe0, 0x3e, 0xe5, 0x00, 0x20, 0xe5, 0x1f,
+    0x47, 0x66, 0x20, 0x26, 0x67, 0x06, 0x05, 0x16,
+    0x05, 0x07, 0xe0, 0x13, 0x05, 0xe6, 0x02, 0xe5,
+    0x20, 0xa6, 0x07, 0x05, 0x66, 0xf6, 0x00, 0x06,
+    0xe0, 0x00, 0x05, 0xa6, 0x27, 0x46, 0xe5, 0x26,
+    0xe6, 0x05, 0x07, 0x26, 0x56, 0x05, 0x96, 0xe0,
+    0x15, 0xe5, 0x31, 0xe0, 0x80, 0x7f, 0xe5, 0x01,
+    0x00, 0xe5, 0x1d, 0x07, 0xc6, 0x00, 0xa6, 0x07,
+    0x06, 0x05, 0x96, 0xe0, 0x02, 0xe9, 0x02, 0xeb,
+    0x0b, 0x40, 0x36, 0xe5, 0x16, 0x20, 0xe6, 0x0e,
+    0x00, 0x07, 0xc6, 0x07, 0x26, 0x07, 0x26, 0xe0,
+    0x41, 0xc5, 0x00, 0x25, 0x00, 0xe5, 0x1e, 0xa6,
+    0x40, 0x06, 0x00, 0x26, 0x00, 0xc6, 0x05, 0x06,
+    0xe0, 0x00, 0xe9, 0x02, 0xa0, 0xa5, 0x00, 0x25,
+    0x00, 0xe5, 0x18, 0x87, 0x00, 0x26, 0x00, 0x27,
+    0x06, 0x07, 0x06, 0x05, 0xc0, 0xe9, 0x02, 0xe0,
+    0x80, 0xae, 0xe5, 0x0b, 0x26, 0x27, 0x36, 0xe0,
+    0x80, 0x2f, 0x05, 0xe0, 0x07, 0xeb, 0x0d, 0xef,
+    0x00, 0x6d, 0xef, 0x09, 0xe0, 0x05, 0x16, 0xe5,
+    0x83, 0x12, 0xe0, 0x5e, 0xea, 0x67, 0x00, 0x96,
+    0xe0, 0x03, 0xe5, 0x80, 0x3c, 0xe0, 0x8a, 0x34,
+    0xe5, 0x83, 0xa7, 0x00, 0xfb, 0x01, 0xe0, 0x8f,
+    0x3f, 0xe5, 0x81, 0xbf, 0xe0, 0xa1, 0x31, 0xe5,
+    0x81, 0xb1, 0xc0, 0xe5, 0x17, 0x00, 0xe9, 0x02,
+    0x60, 0x36, 0xe0, 0x58, 0xe5, 0x16, 0x20, 0x86,
+    0x16, 0xe0, 0x02, 0xe5, 0x28, 0xc6, 0x96, 0x6f,
+    0x64, 0x16, 0x0f, 0xe0, 0x02, 0xe9, 0x02, 0x00,
+    0xcb, 0x00, 0xe5, 0x0d, 0x80, 0xe5, 0x0b, 0xe0,
+    0x82, 0x28, 0xe1, 0x18, 0xe2, 0x18, 0xeb, 0x0f,
+    0x76, 0xe0, 0x5d, 0xe5, 0x43, 0x60, 0x06, 0x05,
+    0xe7, 0x2f, 0xc0, 0x66, 0xe4, 0x05, 0xe0, 0x38,
+    0x24, 0x16, 0x04, 0x06, 0xe0, 0x03, 0x27, 0xe0,
+    0x06, 0xe5, 0x97, 0x70, 0xe0, 0x00, 0xe5, 0x84,
+    0x4e, 0xe0, 0x22, 0xe5, 0x01, 0xe0, 0xa2, 0x6f,
+    0xe5, 0x80, 0x97, 0xe0, 0x29, 0x45, 0xe0, 0x09,
+    0x65, 0xe0, 0x00, 0xe5, 0x81, 0x04, 0xe0, 0x88,
+    0x7c, 0xe5, 0x63, 0x80, 0xe5, 0x05, 0x40, 0xe5,
+    0x01, 0xc0, 0xe5, 0x02, 0x20, 0x0f, 0x26, 0x16,
+    0x7b, 0xe0, 0x92, 0xd4, 0xef, 0x80, 0x6e, 0xe0,
+    0x02, 0xef, 0x1f, 0x20, 0xef, 0x34, 0x27, 0x46,
+    0x4f, 0xa7, 0xfb, 0x00, 0xe6, 0x00, 0x2f, 0xc6,
+    0xef, 0x16, 0x66, 0xef, 0x33, 0xe0, 0x0f, 0xef,
+    0x3a, 0x46, 0x0f, 0xe0, 0x80, 0x12, 0xeb, 0x0c,
+    0xe0, 0x04, 0xef, 0x4f, 0xe0, 0x01, 0xeb, 0x11,
+    0xe0, 0x7f, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12,
+    0xc2, 0x00, 0xe2, 0x0a, 0xe1, 0x12, 0xe2, 0x12,
+    0x01, 0x00, 0x21, 0x20, 0x01, 0x20, 0x21, 0x20,
+    0x61, 0x00, 0xe1, 0x00, 0x62, 0x00, 0x02, 0x00,
+    0xc2, 0x00, 0xe2, 0x03, 0xe1, 0x12, 0xe2, 0x12,
+    0x21, 0x00, 0x61, 0x20, 0xe1, 0x00, 0x00, 0xc1,
+    0x00, 0xe2, 0x12, 0x21, 0x00, 0x61, 0x00, 0x81,
+    0x00, 0x01, 0x40, 0xc1, 0x00, 0xe2, 0x12, 0xe1,
+    0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1,
+    0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1,
+    0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x14, 0x20,
+    0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1,
+    0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11,
+    0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c,
+    0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2,
+    0x11, 0x0c, 0xa2, 0x3f, 0x20, 0xe9, 0x2a, 0xef,
+    0x81, 0x78, 0xe6, 0x2f, 0x6f, 0xe6, 0x2a, 0xef,
+    0x00, 0x06, 0xef, 0x06, 0x06, 0x2f, 0x96, 0xe0,
+    0x07, 0x86, 0x00, 0xe6, 0x07, 0xe0, 0x84, 0xc8,
+    0xc6, 0x00, 0xe6, 0x09, 0x20, 0xc6, 0x00, 0x26,
+    0x00, 0x86, 0xe0, 0x80, 0x4d, 0xe5, 0x25, 0x40,
+    0xc6, 0xc4, 0x20, 0xe9, 0x02, 0x60, 0x05, 0x0f,
+    0xe0, 0x80, 0xe8, 0xe5, 0x24, 0x66, 0xe9, 0x02,
+    0x80, 0x0d, 0xe0, 0x84, 0x78, 0xe5, 0x80, 0x3d,
+    0x20, 0xeb, 0x01, 0xc6, 0xe0, 0x21, 0xe1, 0x1a,
+    0xe2, 0x1a, 0xc6, 0x04, 0x60, 0xe9, 0x02, 0x60,
+    0x36, 0xe0, 0x82, 0x89, 0xeb, 0x33, 0x0f, 0x4b,
+    0x0d, 0x6b, 0xe0, 0x44, 0xeb, 0x25, 0x0f, 0xeb,
+    0x07, 0xe0, 0x80, 0x3a, 0x65, 0x00, 0xe5, 0x13,
+    0x00, 0x25, 0x00, 0x05, 0x20, 0x05, 0x00, 0xe5,
+    0x02, 0x00, 0x65, 0x00, 0x05, 0x00, 0x05, 0xa0,
+    0x05, 0x60, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00,
+    0x45, 0x00, 0x25, 0x00, 0x05, 0x20, 0x05, 0x00,
+    0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00,
+    0x25, 0x00, 0x05, 0x20, 0x65, 0x00, 0xc5, 0x00,
+    0x65, 0x00, 0x65, 0x00, 0x05, 0x00, 0xe5, 0x02,
+    0x00, 0xe5, 0x09, 0x80, 0x45, 0x00, 0x85, 0x00,
+    0xe5, 0x09, 0xe0, 0x2c, 0x2c, 0xe0, 0x80, 0x86,
+    0xef, 0x24, 0x60, 0xef, 0x5c, 0xe0, 0x04, 0xef,
+    0x07, 0x20, 0xef, 0x07, 0x00, 0xef, 0x07, 0x00,
+    0xef, 0x1d, 0xe0, 0x02, 0xeb, 0x05, 0xef, 0x80,
+    0x19, 0xe0, 0x30, 0xef, 0x15, 0xe0, 0x05, 0xef,
+    0x24, 0x60, 0xef, 0x01, 0xc0, 0x2f, 0xe0, 0x06,
+    0xaf, 0xe0, 0x80, 0x12, 0xef, 0x80, 0x73, 0x8e,
+    0xef, 0x82, 0x50, 0xe0, 0x00, 0xef, 0x05, 0x40,
+    0xef, 0x05, 0x40, 0xef, 0x6c, 0xe0, 0x04, 0xef,
+    0x51, 0xc0, 0xef, 0x04, 0xe0, 0x0c, 0xef, 0x04,
+    0x60, 0xef, 0x30, 0xe0, 0x00, 0xef, 0x02, 0xa0,
+    0xef, 0x20, 0xe0, 0x00, 0xef, 0x16, 0x20, 0x2f,
+    0xe0, 0x46, 0xef, 0x71, 0x00, 0xef, 0x4a, 0x00,
+    0xef, 0x7f, 0xe0, 0x04, 0xef, 0x06, 0x20, 0x8f,
+    0x40, 0x4f, 0x80, 0xcf, 0xe0, 0x01, 0xef, 0x11,
+    0xc0, 0xcf, 0xe0, 0x01, 0x4f, 0xe0, 0x05, 0xcf,
+    0xe0, 0x21, 0xef, 0x80, 0x0b, 0x00, 0xef, 0x2f,
+    0xe0, 0x1d, 0xe9, 0x02, 0xe0, 0x83, 0x7e, 0xe5,
+    0xc0, 0x66, 0x56, 0xe0, 0x1a, 0xe5, 0x8f, 0xad,
+    0xe0, 0x03, 0xe5, 0x80, 0x56, 0x20, 0xe5, 0x95,
+    0xfa, 0xe0, 0x06, 0xe5, 0x9c, 0xa9, 0xe0, 0x8b,
+    0x97, 0xe5, 0x81, 0x96, 0xe0, 0x85, 0x5a, 0xe5,
+    0x92, 0xc3, 0xe0, 0xca, 0xac, 0x2e, 0x1b, 0xe0,
+    0x16, 0xfb, 0x58, 0xe0, 0x78, 0xe6, 0x80, 0x68,
+    0xe0, 0xc0, 0xbd, 0x88, 0xfd, 0xc0, 0xbf, 0x76,
+    0x20, 0xfd, 0xc0, 0xbf, 0x76, 0x20,
+};
+
+typedef enum {
+    UNICODE_SCRIPT_Unknown,
+    UNICODE_SCRIPT_Adlam,
+    UNICODE_SCRIPT_Ahom,
+    UNICODE_SCRIPT_Anatolian_Hieroglyphs,
+    UNICODE_SCRIPT_Arabic,
+    UNICODE_SCRIPT_Armenian,
+    UNICODE_SCRIPT_Avestan,
+    UNICODE_SCRIPT_Balinese,
+    UNICODE_SCRIPT_Bamum,
+    UNICODE_SCRIPT_Bassa_Vah,
+    UNICODE_SCRIPT_Batak,
+    UNICODE_SCRIPT_Bengali,
+    UNICODE_SCRIPT_Bhaiksuki,
+    UNICODE_SCRIPT_Bopomofo,
+    UNICODE_SCRIPT_Brahmi,
+    UNICODE_SCRIPT_Braille,
+    UNICODE_SCRIPT_Buginese,
+    UNICODE_SCRIPT_Buhid,
+    UNICODE_SCRIPT_Canadian_Aboriginal,
+    UNICODE_SCRIPT_Carian,
+    UNICODE_SCRIPT_Caucasian_Albanian,
+    UNICODE_SCRIPT_Chakma,
+    UNICODE_SCRIPT_Cham,
+    UNICODE_SCRIPT_Cherokee,
+    UNICODE_SCRIPT_Chorasmian,
+    UNICODE_SCRIPT_Common,
+    UNICODE_SCRIPT_Coptic,
+    UNICODE_SCRIPT_Cuneiform,
+    UNICODE_SCRIPT_Cypriot,
+    UNICODE_SCRIPT_Cyrillic,
+    UNICODE_SCRIPT_Deseret,
+    UNICODE_SCRIPT_Devanagari,
+    UNICODE_SCRIPT_Dives_Akuru,
+    UNICODE_SCRIPT_Dogra,
+    UNICODE_SCRIPT_Duployan,
+    UNICODE_SCRIPT_Egyptian_Hieroglyphs,
+    UNICODE_SCRIPT_Elbasan,
+    UNICODE_SCRIPT_Elymaic,
+    UNICODE_SCRIPT_Ethiopic,
+    UNICODE_SCRIPT_Georgian,
+    UNICODE_SCRIPT_Glagolitic,
+    UNICODE_SCRIPT_Gothic,
+    UNICODE_SCRIPT_Grantha,
+    UNICODE_SCRIPT_Greek,
+    UNICODE_SCRIPT_Gujarati,
+    UNICODE_SCRIPT_Gunjala_Gondi,
+    UNICODE_SCRIPT_Gurmukhi,
+    UNICODE_SCRIPT_Han,
+    UNICODE_SCRIPT_Hangul,
+    UNICODE_SCRIPT_Hanifi_Rohingya,
+    UNICODE_SCRIPT_Hanunoo,
+    UNICODE_SCRIPT_Hatran,
+    UNICODE_SCRIPT_Hebrew,
+    UNICODE_SCRIPT_Hiragana,
+    UNICODE_SCRIPT_Imperial_Aramaic,
+    UNICODE_SCRIPT_Inherited,
+    UNICODE_SCRIPT_Inscriptional_Pahlavi,
+    UNICODE_SCRIPT_Inscriptional_Parthian,
+    UNICODE_SCRIPT_Javanese,
+    UNICODE_SCRIPT_Kaithi,
+    UNICODE_SCRIPT_Kannada,
+    UNICODE_SCRIPT_Katakana,
+    UNICODE_SCRIPT_Kayah_Li,
+    UNICODE_SCRIPT_Kharoshthi,
+    UNICODE_SCRIPT_Khmer,
+    UNICODE_SCRIPT_Khojki,
+    UNICODE_SCRIPT_Khitan_Small_Script,
+    UNICODE_SCRIPT_Khudawadi,
+    UNICODE_SCRIPT_Lao,
+    UNICODE_SCRIPT_Latin,
+    UNICODE_SCRIPT_Lepcha,
+    UNICODE_SCRIPT_Limbu,
+    UNICODE_SCRIPT_Linear_A,
+    UNICODE_SCRIPT_Linear_B,
+    UNICODE_SCRIPT_Lisu,
+    UNICODE_SCRIPT_Lycian,
+    UNICODE_SCRIPT_Lydian,
+    UNICODE_SCRIPT_Makasar,
+    UNICODE_SCRIPT_Mahajani,
+    UNICODE_SCRIPT_Malayalam,
+    UNICODE_SCRIPT_Mandaic,
+    UNICODE_SCRIPT_Manichaean,
+    UNICODE_SCRIPT_Marchen,
+    UNICODE_SCRIPT_Masaram_Gondi,
+    UNICODE_SCRIPT_Medefaidrin,
+    UNICODE_SCRIPT_Meetei_Mayek,
+    UNICODE_SCRIPT_Mende_Kikakui,
+    UNICODE_SCRIPT_Meroitic_Cursive,
+    UNICODE_SCRIPT_Meroitic_Hieroglyphs,
+    UNICODE_SCRIPT_Miao,
+    UNICODE_SCRIPT_Modi,
+    UNICODE_SCRIPT_Mongolian,
+    UNICODE_SCRIPT_Mro,
+    UNICODE_SCRIPT_Multani,
+    UNICODE_SCRIPT_Myanmar,
+    UNICODE_SCRIPT_Nabataean,
+    UNICODE_SCRIPT_Nandinagari,
+    UNICODE_SCRIPT_New_Tai_Lue,
+    UNICODE_SCRIPT_Newa,
+    UNICODE_SCRIPT_Nko,
+    UNICODE_SCRIPT_Nushu,
+    UNICODE_SCRIPT_Nyiakeng_Puachue_Hmong,
+    UNICODE_SCRIPT_Ogham,
+    UNICODE_SCRIPT_Ol_Chiki,
+    UNICODE_SCRIPT_Old_Hungarian,
+    UNICODE_SCRIPT_Old_Italic,
+    UNICODE_SCRIPT_Old_North_Arabian,
+    UNICODE_SCRIPT_Old_Permic,
+    UNICODE_SCRIPT_Old_Persian,
+    UNICODE_SCRIPT_Old_Sogdian,
+    UNICODE_SCRIPT_Old_South_Arabian,
+    UNICODE_SCRIPT_Old_Turkic,
+    UNICODE_SCRIPT_Oriya,
+    UNICODE_SCRIPT_Osage,
+    UNICODE_SCRIPT_Osmanya,
+    UNICODE_SCRIPT_Pahawh_Hmong,
+    UNICODE_SCRIPT_Palmyrene,
+    UNICODE_SCRIPT_Pau_Cin_Hau,
+    UNICODE_SCRIPT_Phags_Pa,
+    UNICODE_SCRIPT_Phoenician,
+    UNICODE_SCRIPT_Psalter_Pahlavi,
+    UNICODE_SCRIPT_Rejang,
+    UNICODE_SCRIPT_Runic,
+    UNICODE_SCRIPT_Samaritan,
+    UNICODE_SCRIPT_Saurashtra,
+    UNICODE_SCRIPT_Sharada,
+    UNICODE_SCRIPT_Shavian,
+    UNICODE_SCRIPT_Siddham,
+    UNICODE_SCRIPT_SignWriting,
+    UNICODE_SCRIPT_Sinhala,
+    UNICODE_SCRIPT_Sogdian,
+    UNICODE_SCRIPT_Sora_Sompeng,
+    UNICODE_SCRIPT_Soyombo,
+    UNICODE_SCRIPT_Sundanese,
+    UNICODE_SCRIPT_Syloti_Nagri,
+    UNICODE_SCRIPT_Syriac,
+    UNICODE_SCRIPT_Tagalog,
+    UNICODE_SCRIPT_Tagbanwa,
+    UNICODE_SCRIPT_Tai_Le,
+    UNICODE_SCRIPT_Tai_Tham,
+    UNICODE_SCRIPT_Tai_Viet,
+    UNICODE_SCRIPT_Takri,
+    UNICODE_SCRIPT_Tamil,
+    UNICODE_SCRIPT_Tangut,
+    UNICODE_SCRIPT_Telugu,
+    UNICODE_SCRIPT_Thaana,
+    UNICODE_SCRIPT_Thai,
+    UNICODE_SCRIPT_Tibetan,
+    UNICODE_SCRIPT_Tifinagh,
+    UNICODE_SCRIPT_Tirhuta,
+    UNICODE_SCRIPT_Ugaritic,
+    UNICODE_SCRIPT_Vai,
+    UNICODE_SCRIPT_Wancho,
+    UNICODE_SCRIPT_Warang_Citi,
+    UNICODE_SCRIPT_Yezidi,
+    UNICODE_SCRIPT_Yi,
+    UNICODE_SCRIPT_Zanabazar_Square,
+    UNICODE_SCRIPT_COUNT,
+} UnicodeScriptEnum;
+
+static const char unicode_script_name_table[] =
+    "Adlam,Adlm"                  "\0"
+    "Ahom,Ahom"                   "\0"
+    "Anatolian_Hieroglyphs,Hluw"  "\0"
+    "Arabic,Arab"                 "\0"
+    "Armenian,Armn"               "\0"
+    "Avestan,Avst"                "\0"
+    "Balinese,Bali"               "\0"
+    "Bamum,Bamu"                  "\0"
+    "Bassa_Vah,Bass"              "\0"
+    "Batak,Batk"                  "\0"
+    "Bengali,Beng"                "\0"
+    "Bhaiksuki,Bhks"              "\0"
+    "Bopomofo,Bopo"               "\0"
+    "Brahmi,Brah"                 "\0"
+    "Braille,Brai"                "\0"
+    "Buginese,Bugi"               "\0"
+    "Buhid,Buhd"                  "\0"
+    "Canadian_Aboriginal,Cans"    "\0"
+    "Carian,Cari"                 "\0"
+    "Caucasian_Albanian,Aghb"     "\0"
+    "Chakma,Cakm"                 "\0"
+    "Cham,Cham"                   "\0"
+    "Cherokee,Cher"               "\0"
+    "Chorasmian,Chrs"             "\0"
+    "Common,Zyyy"                 "\0"
+    "Coptic,Copt,Qaac"            "\0"
+    "Cuneiform,Xsux"              "\0"
+    "Cypriot,Cprt"                "\0"
+    "Cyrillic,Cyrl"               "\0"
+    "Deseret,Dsrt"                "\0"
+    "Devanagari,Deva"             "\0"
+    "Dives_Akuru,Diak"            "\0"
+    "Dogra,Dogr"                  "\0"
+    "Duployan,Dupl"               "\0"
+    "Egyptian_Hieroglyphs,Egyp"   "\0"
+    "Elbasan,Elba"                "\0"
+    "Elymaic,Elym"                "\0"
+    "Ethiopic,Ethi"               "\0"
+    "Georgian,Geor"               "\0"
+    "Glagolitic,Glag"             "\0"
+    "Gothic,Goth"                 "\0"
+    "Grantha,Gran"                "\0"
+    "Greek,Grek"                  "\0"
+    "Gujarati,Gujr"               "\0"
+    "Gunjala_Gondi,Gong"          "\0"
+    "Gurmukhi,Guru"               "\0"
+    "Han,Hani"                    "\0"
+    "Hangul,Hang"                 "\0"
+    "Hanifi_Rohingya,Rohg"        "\0"
+    "Hanunoo,Hano"                "\0"
+    "Hatran,Hatr"                 "\0"
+    "Hebrew,Hebr"                 "\0"
+    "Hiragana,Hira"               "\0"
+    "Imperial_Aramaic,Armi"       "\0"
+    "Inherited,Zinh,Qaai"         "\0"
+    "Inscriptional_Pahlavi,Phli"  "\0"
+    "Inscriptional_Parthian,Prti" "\0"
+    "Javanese,Java"               "\0"
+    "Kaithi,Kthi"                 "\0"
+    "Kannada,Knda"                "\0"
+    "Katakana,Kana"               "\0"
+    "Kayah_Li,Kali"               "\0"
+    "Kharoshthi,Khar"             "\0"
+    "Khmer,Khmr"                  "\0"
+    "Khojki,Khoj"                 "\0"
+    "Khitan_Small_Script,Kits"    "\0"
+    "Khudawadi,Sind"              "\0"
+    "Lao,Laoo"                    "\0"
+    "Latin,Latn"                  "\0"
+    "Lepcha,Lepc"                 "\0"
+    "Limbu,Limb"                  "\0"
+    "Linear_A,Lina"               "\0"
+    "Linear_B,Linb"               "\0"
+    "Lisu,Lisu"                   "\0"
+    "Lycian,Lyci"                 "\0"
+    "Lydian,Lydi"                 "\0"
+    "Makasar,Maka"                "\0"
+    "Mahajani,Mahj"               "\0"
+    "Malayalam,Mlym"              "\0"
+    "Mandaic,Mand"                "\0"
+    "Manichaean,Mani"             "\0"
+    "Marchen,Marc"                "\0"
+    "Masaram_Gondi,Gonm"          "\0"
+    "Medefaidrin,Medf"            "\0"
+    "Meetei_Mayek,Mtei"           "\0"
+    "Mende_Kikakui,Mend"          "\0"
+    "Meroitic_Cursive,Merc"       "\0"
+    "Meroitic_Hieroglyphs,Mero"   "\0"
+    "Miao,Plrd"                   "\0"
+    "Modi,Modi"                   "\0"
+    "Mongolian,Mong"              "\0"
+    "Mro,Mroo"                    "\0"
+    "Multani,Mult"                "\0"
+    "Myanmar,Mymr"                "\0"
+    "Nabataean,Nbat"              "\0"
+    "Nandinagari,Nand"            "\0"
+    "New_Tai_Lue,Talu"            "\0"
+    "Newa,Newa"                   "\0"
+    "Nko,Nkoo"                    "\0"
+    "Nushu,Nshu"                  "\0"
+    "Nyiakeng_Puachue_Hmong,Hmnp" "\0"
+    "Ogham,Ogam"                  "\0"
+    "Ol_Chiki,Olck"               "\0"
+    "Old_Hungarian,Hung"          "\0"
+    "Old_Italic,Ital"             "\0"
+    "Old_North_Arabian,Narb"      "\0"
+    "Old_Permic,Perm"             "\0"
+    "Old_Persian,Xpeo"            "\0"
+    "Old_Sogdian,Sogo"            "\0"
+    "Old_South_Arabian,Sarb"      "\0"
+    "Old_Turkic,Orkh"             "\0"
+    "Oriya,Orya"                  "\0"
+    "Osage,Osge"                  "\0"
+    "Osmanya,Osma"                "\0"
+    "Pahawh_Hmong,Hmng"           "\0"
+    "Palmyrene,Palm"              "\0"
+    "Pau_Cin_Hau,Pauc"            "\0"
+    "Phags_Pa,Phag"               "\0"
+    "Phoenician,Phnx"             "\0"
+    "Psalter_Pahlavi,Phlp"        "\0"
+    "Rejang,Rjng"                 "\0"
+    "Runic,Runr"                  "\0"
+    "Samaritan,Samr"              "\0"
+    "Saurashtra,Saur"             "\0"
+    "Sharada,Shrd"                "\0"
+    "Shavian,Shaw"                "\0"
+    "Siddham,Sidd"                "\0"
+    "SignWriting,Sgnw"            "\0"
+    "Sinhala,Sinh"                "\0"
+    "Sogdian,Sogd"                "\0"
+    "Sora_Sompeng,Sora"           "\0"
+    "Soyombo,Soyo"                "\0"
+    "Sundanese,Sund"              "\0"
+    "Syloti_Nagri,Sylo"           "\0"
+    "Syriac,Syrc"                 "\0"
+    "Tagalog,Tglg"                "\0"
+    "Tagbanwa,Tagb"               "\0"
+    "Tai_Le,Tale"                 "\0"
+    "Tai_Tham,Lana"               "\0"
+    "Tai_Viet,Tavt"               "\0"
+    "Takri,Takr"                  "\0"
+    "Tamil,Taml"                  "\0"
+    "Tangut,Tang"                 "\0"
+    "Telugu,Telu"                 "\0"
+    "Thaana,Thaa"                 "\0"
+    "Thai,Thai"                   "\0"
+    "Tibetan,Tibt"                "\0"
+    "Tifinagh,Tfng"               "\0"
+    "Tirhuta,Tirh"                "\0"
+    "Ugaritic,Ugar"               "\0"
+    "Vai,Vaii"                    "\0"
+    "Wancho,Wcho"                 "\0"
+    "Warang_Citi,Wara"            "\0"
+    "Yezidi,Yezi"                 "\0"
+    "Yi,Yiii"                     "\0"
+    "Zanabazar_Square,Zanb"       "\0"
+;
+
+static const uint8_t unicode_script_table[2609] = {
+    0xc0, 0x19, 0x99, 0x45, 0x85, 0x19, 0x99, 0x45,
+    0xae, 0x19, 0x80, 0x45, 0x8e, 0x19, 0x80, 0x45,
+    0x84, 0x19, 0x96, 0x45, 0x80, 0x19, 0x9e, 0x45,
+    0x80, 0x19, 0xe1, 0x60, 0x45, 0xa6, 0x19, 0x84,
+    0x45, 0x84, 0x19, 0x81, 0x0d, 0x93, 0x19, 0xe0,
+    0x0f, 0x37, 0x83, 0x2b, 0x80, 0x19, 0x82, 0x2b,
+    0x01, 0x83, 0x2b, 0x80, 0x19, 0x80, 0x2b, 0x03,
+    0x80, 0x2b, 0x80, 0x19, 0x80, 0x2b, 0x80, 0x19,
+    0x82, 0x2b, 0x00, 0x80, 0x2b, 0x00, 0x93, 0x2b,
+    0x00, 0xbe, 0x2b, 0x8d, 0x1a, 0x8f, 0x2b, 0xe0,
+    0x24, 0x1d, 0x81, 0x37, 0xe0, 0x48, 0x1d, 0x00,
+    0xa5, 0x05, 0x01, 0xb1, 0x05, 0x01, 0x82, 0x05,
+    0x00, 0xb6, 0x34, 0x07, 0x9a, 0x34, 0x03, 0x85,
+    0x34, 0x0a, 0x84, 0x04, 0x80, 0x19, 0x85, 0x04,
+    0x80, 0x19, 0x8d, 0x04, 0x80, 0x19, 0x80, 0x04,
+    0x00, 0x80, 0x04, 0x80, 0x19, 0x9f, 0x04, 0x80,
+    0x19, 0x89, 0x04, 0x8a, 0x37, 0x99, 0x04, 0x80,
+    0x37, 0xe0, 0x0b, 0x04, 0x80, 0x19, 0xa1, 0x04,
+    0x8d, 0x87, 0x00, 0xbb, 0x87, 0x01, 0x82, 0x87,
+    0xaf, 0x04, 0xb1, 0x91, 0x0d, 0xba, 0x63, 0x01,
+    0x82, 0x63, 0xad, 0x7b, 0x01, 0x8e, 0x7b, 0x00,
+    0x9b, 0x50, 0x01, 0x80, 0x50, 0x00, 0x8a, 0x87,
+    0x34, 0x94, 0x04, 0x00, 0x91, 0x04, 0x0a, 0x8e,
+    0x04, 0x80, 0x19, 0x9c, 0x04, 0xd0, 0x1f, 0x83,
+    0x37, 0x8e, 0x1f, 0x81, 0x19, 0x99, 0x1f, 0x83,
+    0x0b, 0x00, 0x87, 0x0b, 0x01, 0x81, 0x0b, 0x01,
+    0x95, 0x0b, 0x00, 0x86, 0x0b, 0x00, 0x80, 0x0b,
+    0x02, 0x83, 0x0b, 0x01, 0x88, 0x0b, 0x01, 0x81,
+    0x0b, 0x01, 0x83, 0x0b, 0x07, 0x80, 0x0b, 0x03,
+    0x81, 0x0b, 0x00, 0x84, 0x0b, 0x01, 0x98, 0x0b,
+    0x01, 0x82, 0x2e, 0x00, 0x85, 0x2e, 0x03, 0x81,
+    0x2e, 0x01, 0x95, 0x2e, 0x00, 0x86, 0x2e, 0x00,
+    0x81, 0x2e, 0x00, 0x81, 0x2e, 0x00, 0x81, 0x2e,
+    0x01, 0x80, 0x2e, 0x00, 0x84, 0x2e, 0x03, 0x81,
+    0x2e, 0x01, 0x82, 0x2e, 0x02, 0x80, 0x2e, 0x06,
+    0x83, 0x2e, 0x00, 0x80, 0x2e, 0x06, 0x90, 0x2e,
+    0x09, 0x82, 0x2c, 0x00, 0x88, 0x2c, 0x00, 0x82,
+    0x2c, 0x00, 0x95, 0x2c, 0x00, 0x86, 0x2c, 0x00,
+    0x81, 0x2c, 0x00, 0x84, 0x2c, 0x01, 0x89, 0x2c,
+    0x00, 0x82, 0x2c, 0x00, 0x82, 0x2c, 0x01, 0x80,
+    0x2c, 0x0e, 0x83, 0x2c, 0x01, 0x8b, 0x2c, 0x06,
+    0x86, 0x2c, 0x00, 0x82, 0x70, 0x00, 0x87, 0x70,
+    0x01, 0x81, 0x70, 0x01, 0x95, 0x70, 0x00, 0x86,
+    0x70, 0x00, 0x81, 0x70, 0x00, 0x84, 0x70, 0x01,
+    0x88, 0x70, 0x01, 0x81, 0x70, 0x01, 0x82, 0x70,
+    0x06, 0x82, 0x70, 0x03, 0x81, 0x70, 0x00, 0x84,
+    0x70, 0x01, 0x91, 0x70, 0x09, 0x81, 0x8e, 0x00,
+    0x85, 0x8e, 0x02, 0x82, 0x8e, 0x00, 0x83, 0x8e,
+    0x02, 0x81, 0x8e, 0x00, 0x80, 0x8e, 0x00, 0x81,
+    0x8e, 0x02, 0x81, 0x8e, 0x02, 0x82, 0x8e, 0x02,
+    0x8b, 0x8e, 0x03, 0x84, 0x8e, 0x02, 0x82, 0x8e,
+    0x00, 0x83, 0x8e, 0x01, 0x80, 0x8e, 0x05, 0x80,
+    0x8e, 0x0d, 0x94, 0x8e, 0x04, 0x8c, 0x90, 0x00,
+    0x82, 0x90, 0x00, 0x96, 0x90, 0x00, 0x8f, 0x90,
+    0x02, 0x87, 0x90, 0x00, 0x82, 0x90, 0x00, 0x83,
+    0x90, 0x06, 0x81, 0x90, 0x00, 0x82, 0x90, 0x04,
+    0x83, 0x90, 0x01, 0x89, 0x90, 0x06, 0x88, 0x90,
+    0x8c, 0x3c, 0x00, 0x82, 0x3c, 0x00, 0x96, 0x3c,
+    0x00, 0x89, 0x3c, 0x00, 0x84, 0x3c, 0x01, 0x88,
+    0x3c, 0x00, 0x82, 0x3c, 0x00, 0x83, 0x3c, 0x06,
+    0x81, 0x3c, 0x06, 0x80, 0x3c, 0x00, 0x83, 0x3c,
+    0x01, 0x89, 0x3c, 0x00, 0x81, 0x3c, 0x0c, 0x8c,
+    0x4f, 0x00, 0x82, 0x4f, 0x00, 0xb2, 0x4f, 0x00,
+    0x82, 0x4f, 0x00, 0x85, 0x4f, 0x03, 0x8f, 0x4f,
+    0x01, 0x99, 0x4f, 0x00, 0x82, 0x81, 0x00, 0x91,
+    0x81, 0x02, 0x97, 0x81, 0x00, 0x88, 0x81, 0x00,
+    0x80, 0x81, 0x01, 0x86, 0x81, 0x02, 0x80, 0x81,
+    0x03, 0x85, 0x81, 0x00, 0x80, 0x81, 0x00, 0x87,
+    0x81, 0x05, 0x89, 0x81, 0x01, 0x82, 0x81, 0x0b,
+    0xb9, 0x92, 0x03, 0x80, 0x19, 0x9b, 0x92, 0x24,
+    0x81, 0x44, 0x00, 0x80, 0x44, 0x00, 0x84, 0x44,
+    0x00, 0x97, 0x44, 0x00, 0x80, 0x44, 0x00, 0x96,
+    0x44, 0x01, 0x84, 0x44, 0x00, 0x80, 0x44, 0x00,
+    0x85, 0x44, 0x01, 0x89, 0x44, 0x01, 0x83, 0x44,
+    0x1f, 0xc7, 0x93, 0x00, 0xa3, 0x93, 0x03, 0xa6,
+    0x93, 0x00, 0xa3, 0x93, 0x00, 0x8e, 0x93, 0x00,
+    0x86, 0x93, 0x83, 0x19, 0x81, 0x93, 0x24, 0xe0,
+    0x3f, 0x5e, 0xa5, 0x27, 0x00, 0x80, 0x27, 0x04,
+    0x80, 0x27, 0x01, 0xaa, 0x27, 0x80, 0x19, 0x83,
+    0x27, 0xe0, 0x9f, 0x30, 0xc8, 0x26, 0x00, 0x83,
+    0x26, 0x01, 0x86, 0x26, 0x00, 0x80, 0x26, 0x00,
+    0x83, 0x26, 0x01, 0xa8, 0x26, 0x00, 0x83, 0x26,
+    0x01, 0xa0, 0x26, 0x00, 0x83, 0x26, 0x01, 0x86,
+    0x26, 0x00, 0x80, 0x26, 0x00, 0x83, 0x26, 0x01,
+    0x8e, 0x26, 0x00, 0xb8, 0x26, 0x00, 0x83, 0x26,
+    0x01, 0xc2, 0x26, 0x01, 0x9f, 0x26, 0x02, 0x99,
+    0x26, 0x05, 0xd5, 0x17, 0x01, 0x85, 0x17, 0x01,
+    0xe2, 0x1f, 0x12, 0x9c, 0x66, 0x02, 0xca, 0x7a,
+    0x82, 0x19, 0x8a, 0x7a, 0x06, 0x8c, 0x88, 0x00,
+    0x86, 0x88, 0x0a, 0x94, 0x32, 0x81, 0x19, 0x08,
+    0x93, 0x11, 0x0b, 0x8c, 0x89, 0x00, 0x82, 0x89,
+    0x00, 0x81, 0x89, 0x0b, 0xdd, 0x40, 0x01, 0x89,
+    0x40, 0x05, 0x89, 0x40, 0x05, 0x81, 0x5b, 0x81,
+    0x19, 0x80, 0x5b, 0x80, 0x19, 0x88, 0x5b, 0x00,
+    0x89, 0x5b, 0x05, 0xd8, 0x5b, 0x06, 0xaa, 0x5b,
+    0x04, 0xc5, 0x12, 0x09, 0x9e, 0x47, 0x00, 0x8b,
+    0x47, 0x03, 0x8b, 0x47, 0x03, 0x80, 0x47, 0x02,
+    0x8b, 0x47, 0x9d, 0x8a, 0x01, 0x84, 0x8a, 0x0a,
+    0xab, 0x61, 0x03, 0x99, 0x61, 0x05, 0x8a, 0x61,
+    0x02, 0x81, 0x61, 0x9f, 0x40, 0x9b, 0x10, 0x01,
+    0x81, 0x10, 0xbe, 0x8b, 0x00, 0x9c, 0x8b, 0x01,
+    0x8a, 0x8b, 0x05, 0x89, 0x8b, 0x05, 0x8d, 0x8b,
+    0x01, 0x90, 0x37, 0x3e, 0xcb, 0x07, 0x03, 0xac,
+    0x07, 0x02, 0xbf, 0x85, 0xb3, 0x0a, 0x07, 0x83,
+    0x0a, 0xb7, 0x46, 0x02, 0x8e, 0x46, 0x02, 0x82,
+    0x46, 0xaf, 0x67, 0x88, 0x1d, 0x06, 0xaa, 0x27,
+    0x01, 0x82, 0x27, 0x87, 0x85, 0x07, 0x82, 0x37,
+    0x80, 0x19, 0x8c, 0x37, 0x80, 0x19, 0x86, 0x37,
+    0x83, 0x19, 0x80, 0x37, 0x85, 0x19, 0x80, 0x37,
+    0x82, 0x19, 0x81, 0x37, 0x80, 0x19, 0x04, 0xa5,
+    0x45, 0x84, 0x2b, 0x80, 0x1d, 0xb0, 0x45, 0x84,
+    0x2b, 0x83, 0x45, 0x84, 0x2b, 0x8c, 0x45, 0x80,
+    0x1d, 0xc5, 0x45, 0x80, 0x2b, 0xb9, 0x37, 0x00,
+    0x84, 0x37, 0xe0, 0x9f, 0x45, 0x95, 0x2b, 0x01,
+    0x85, 0x2b, 0x01, 0xa5, 0x2b, 0x01, 0x85, 0x2b,
+    0x01, 0x87, 0x2b, 0x00, 0x80, 0x2b, 0x00, 0x80,
+    0x2b, 0x00, 0x80, 0x2b, 0x00, 0x9e, 0x2b, 0x01,
+    0xb4, 0x2b, 0x00, 0x8e, 0x2b, 0x00, 0x8d, 0x2b,
+    0x01, 0x85, 0x2b, 0x00, 0x92, 0x2b, 0x01, 0x82,
+    0x2b, 0x00, 0x88, 0x2b, 0x00, 0x8b, 0x19, 0x81,
+    0x37, 0xd6, 0x19, 0x00, 0x8a, 0x19, 0x80, 0x45,
+    0x01, 0x8a, 0x19, 0x80, 0x45, 0x8e, 0x19, 0x00,
+    0x8c, 0x45, 0x02, 0x9f, 0x19, 0x0f, 0xa0, 0x37,
+    0x0e, 0xa5, 0x19, 0x80, 0x2b, 0x82, 0x19, 0x81,
+    0x45, 0x85, 0x19, 0x80, 0x45, 0x9a, 0x19, 0x80,
+    0x45, 0x90, 0x19, 0xa8, 0x45, 0x82, 0x19, 0x03,
+    0xe2, 0x36, 0x19, 0x18, 0x8a, 0x19, 0x14, 0xe3,
+    0x3f, 0x19, 0xe0, 0x9f, 0x0f, 0xe2, 0x13, 0x19,
+    0x01, 0x9f, 0x19, 0x00, 0xe0, 0x08, 0x19, 0xae,
+    0x28, 0x00, 0xae, 0x28, 0x00, 0x9f, 0x45, 0xe0,
+    0x13, 0x1a, 0x04, 0x86, 0x1a, 0xa5, 0x27, 0x00,
+    0x80, 0x27, 0x04, 0x80, 0x27, 0x01, 0xb7, 0x94,
+    0x06, 0x81, 0x94, 0x0d, 0x80, 0x94, 0x96, 0x26,
+    0x08, 0x86, 0x26, 0x00, 0x86, 0x26, 0x00, 0x86,
+    0x26, 0x00, 0x86, 0x26, 0x00, 0x86, 0x26, 0x00,
+    0x86, 0x26, 0x00, 0x86, 0x26, 0x00, 0x86, 0x26,
+    0x00, 0x9f, 0x1d, 0xd2, 0x19, 0x2c, 0x99, 0x2f,
+    0x00, 0xd8, 0x2f, 0x0b, 0xe0, 0x75, 0x2f, 0x19,
+    0x8b, 0x19, 0x03, 0x84, 0x19, 0x80, 0x2f, 0x80,
+    0x19, 0x80, 0x2f, 0x98, 0x19, 0x88, 0x2f, 0x83,
+    0x37, 0x81, 0x30, 0x87, 0x19, 0x83, 0x2f, 0x83,
+    0x19, 0x00, 0xd5, 0x35, 0x01, 0x81, 0x37, 0x81,
+    0x19, 0x82, 0x35, 0x80, 0x19, 0xd9, 0x3d, 0x81,
+    0x19, 0x82, 0x3d, 0x04, 0xaa, 0x0d, 0x00, 0xdd,
+    0x30, 0x00, 0x8f, 0x19, 0x9f, 0x0d, 0xa3, 0x19,
+    0x0b, 0x8f, 0x3d, 0x9e, 0x30, 0x00, 0xbf, 0x19,
+    0x9e, 0x30, 0xd0, 0x19, 0xae, 0x3d, 0x80, 0x19,
+    0xd7, 0x3d, 0xe0, 0x47, 0x19, 0xf0, 0x09, 0x5f,
+    0x2f, 0xbf, 0x19, 0xf0, 0x41, 0x9c, 0x2f, 0x02,
+    0xe4, 0x2c, 0x9b, 0x02, 0xb6, 0x9b, 0x08, 0xaf,
+    0x4a, 0xe0, 0xcb, 0x97, 0x13, 0xdf, 0x1d, 0xd7,
+    0x08, 0x07, 0xa1, 0x19, 0xe0, 0x05, 0x45, 0x82,
+    0x19, 0xb4, 0x45, 0x01, 0x88, 0x45, 0x29, 0x8a,
+    0x45, 0xac, 0x86, 0x02, 0x89, 0x19, 0x05, 0xb7,
+    0x76, 0x07, 0xc5, 0x7c, 0x07, 0x8b, 0x7c, 0x05,
+    0x9f, 0x1f, 0xad, 0x3e, 0x80, 0x19, 0x80, 0x3e,
+    0xa3, 0x79, 0x0a, 0x80, 0x79, 0x9c, 0x30, 0x02,
+    0xcd, 0x3a, 0x00, 0x80, 0x19, 0x89, 0x3a, 0x03,
+    0x81, 0x3a, 0x9e, 0x5e, 0x00, 0xb6, 0x16, 0x08,
+    0x8d, 0x16, 0x01, 0x89, 0x16, 0x01, 0x83, 0x16,
+    0x9f, 0x5e, 0xc2, 0x8c, 0x17, 0x84, 0x8c, 0x96,
+    0x55, 0x09, 0x85, 0x26, 0x01, 0x85, 0x26, 0x01,
+    0x85, 0x26, 0x08, 0x86, 0x26, 0x00, 0x86, 0x26,
+    0x00, 0xaa, 0x45, 0x80, 0x19, 0x88, 0x45, 0x80,
+    0x2b, 0x83, 0x45, 0x81, 0x19, 0x03, 0xcf, 0x17,
+    0xad, 0x55, 0x01, 0x89, 0x55, 0x05, 0xf0, 0x1b,
+    0x43, 0x30, 0x0b, 0x96, 0x30, 0x03, 0xb0, 0x30,
+    0x70, 0x10, 0xa3, 0xe1, 0x0d, 0x2f, 0x01, 0xe0,
+    0x09, 0x2f, 0x25, 0x86, 0x45, 0x0b, 0x84, 0x05,
+    0x04, 0x99, 0x34, 0x00, 0x84, 0x34, 0x00, 0x80,
+    0x34, 0x00, 0x81, 0x34, 0x00, 0x81, 0x34, 0x00,
+    0x89, 0x34, 0xe0, 0x11, 0x04, 0x10, 0xe1, 0x0a,
+    0x04, 0x81, 0x19, 0x0f, 0xbf, 0x04, 0x01, 0xb5,
+    0x04, 0x27, 0x8d, 0x04, 0x01, 0x8f, 0x37, 0x89,
+    0x19, 0x05, 0x8d, 0x37, 0x81, 0x1d, 0xa2, 0x19,
+    0x00, 0x92, 0x19, 0x00, 0x83, 0x19, 0x03, 0x84,
+    0x04, 0x00, 0xe0, 0x26, 0x04, 0x01, 0x80, 0x19,
+    0x00, 0x9f, 0x19, 0x99, 0x45, 0x85, 0x19, 0x99,
+    0x45, 0x8a, 0x19, 0x89, 0x3d, 0x80, 0x19, 0xac,
+    0x3d, 0x81, 0x19, 0x9e, 0x30, 0x02, 0x85, 0x30,
+    0x01, 0x85, 0x30, 0x01, 0x85, 0x30, 0x01, 0x82,
+    0x30, 0x02, 0x86, 0x19, 0x00, 0x86, 0x19, 0x09,
+    0x84, 0x19, 0x01, 0x8b, 0x49, 0x00, 0x99, 0x49,
+    0x00, 0x92, 0x49, 0x00, 0x81, 0x49, 0x00, 0x8e,
+    0x49, 0x01, 0x8d, 0x49, 0x21, 0xe0, 0x1a, 0x49,
+    0x04, 0x82, 0x19, 0x03, 0xac, 0x19, 0x02, 0x88,
+    0x19, 0xce, 0x2b, 0x00, 0x8c, 0x19, 0x02, 0x80,
+    0x2b, 0x2e, 0xac, 0x19, 0x80, 0x37, 0x60, 0x21,
+    0x9c, 0x4b, 0x02, 0xb0, 0x13, 0x0e, 0x80, 0x37,
+    0x9a, 0x19, 0x03, 0xa3, 0x69, 0x08, 0x82, 0x69,
+    0x9a, 0x29, 0x04, 0xaa, 0x6b, 0x04, 0x9d, 0x96,
+    0x00, 0x80, 0x96, 0xa3, 0x6c, 0x03, 0x8d, 0x6c,
+    0x29, 0xcf, 0x1e, 0xaf, 0x7e, 0x9d, 0x72, 0x01,
+    0x89, 0x72, 0x05, 0xa3, 0x71, 0x03, 0xa3, 0x71,
+    0x03, 0xa7, 0x24, 0x07, 0xb3, 0x14, 0x0a, 0x80,
+    0x14, 0x60, 0x2f, 0xe0, 0xd6, 0x48, 0x08, 0x95,
+    0x48, 0x09, 0x87, 0x48, 0x60, 0x37, 0x85, 0x1c,
+    0x01, 0x80, 0x1c, 0x00, 0xab, 0x1c, 0x00, 0x81,
+    0x1c, 0x02, 0x80, 0x1c, 0x01, 0x80, 0x1c, 0x95,
+    0x36, 0x00, 0x88, 0x36, 0x9f, 0x74, 0x9e, 0x5f,
+    0x07, 0x88, 0x5f, 0x2f, 0x92, 0x33, 0x00, 0x81,
+    0x33, 0x04, 0x84, 0x33, 0x9b, 0x77, 0x02, 0x80,
+    0x77, 0x99, 0x4c, 0x04, 0x80, 0x4c, 0x3f, 0x9f,
+    0x58, 0x97, 0x57, 0x03, 0x93, 0x57, 0x01, 0xad,
+    0x57, 0x83, 0x3f, 0x00, 0x81, 0x3f, 0x04, 0x87,
+    0x3f, 0x00, 0x82, 0x3f, 0x00, 0x9c, 0x3f, 0x01,
+    0x82, 0x3f, 0x03, 0x89, 0x3f, 0x06, 0x88, 0x3f,
+    0x06, 0x9f, 0x6e, 0x9f, 0x6a, 0x1f, 0xa6, 0x51,
+    0x03, 0x8b, 0x51, 0x08, 0xb5, 0x06, 0x02, 0x86,
+    0x06, 0x95, 0x39, 0x01, 0x87, 0x39, 0x92, 0x38,
+    0x04, 0x87, 0x38, 0x91, 0x78, 0x06, 0x83, 0x78,
+    0x0b, 0x86, 0x78, 0x4f, 0xc8, 0x6f, 0x36, 0xb2,
+    0x68, 0x0c, 0xb2, 0x68, 0x06, 0x85, 0x68, 0xa7,
+    0x31, 0x07, 0x89, 0x31, 0x60, 0xc5, 0x9e, 0x04,
+    0x00, 0xa9, 0x9a, 0x00, 0x82, 0x9a, 0x01, 0x81,
+    0x9a, 0x4d, 0xa7, 0x6d, 0x07, 0xa9, 0x82, 0x55,
+    0x9b, 0x18, 0x13, 0x96, 0x25, 0x08, 0xcd, 0x0e,
+    0x03, 0x9d, 0x0e, 0x0e, 0x80, 0x0e, 0xc1, 0x3b,
+    0x0a, 0x80, 0x3b, 0x01, 0x98, 0x83, 0x06, 0x89,
+    0x83, 0x05, 0xb4, 0x15, 0x00, 0x91, 0x15, 0x07,
+    0xa6, 0x4e, 0x08, 0xdf, 0x7d, 0x00, 0x93, 0x81,
+    0x0a, 0x91, 0x41, 0x00, 0xab, 0x41, 0x40, 0x86,
+    0x5d, 0x00, 0x80, 0x5d, 0x00, 0x83, 0x5d, 0x00,
+    0x8e, 0x5d, 0x00, 0x8a, 0x5d, 0x05, 0xba, 0x43,
+    0x04, 0x89, 0x43, 0x05, 0x83, 0x2a, 0x00, 0x87,
+    0x2a, 0x01, 0x81, 0x2a, 0x01, 0x95, 0x2a, 0x00,
+    0x86, 0x2a, 0x00, 0x81, 0x2a, 0x00, 0x84, 0x2a,
+    0x00, 0x80, 0x37, 0x88, 0x2a, 0x01, 0x81, 0x2a,
+    0x01, 0x82, 0x2a, 0x01, 0x80, 0x2a, 0x05, 0x80,
+    0x2a, 0x04, 0x86, 0x2a, 0x01, 0x86, 0x2a, 0x02,
+    0x84, 0x2a, 0x60, 0x2a, 0xdb, 0x62, 0x00, 0x84,
+    0x62, 0x1d, 0xc7, 0x95, 0x07, 0x89, 0x95, 0x60,
+    0x45, 0xb5, 0x7f, 0x01, 0xa5, 0x7f, 0x21, 0xc4,
+    0x5a, 0x0a, 0x89, 0x5a, 0x05, 0x8c, 0x5b, 0x12,
+    0xb8, 0x8d, 0x06, 0x89, 0x8d, 0x35, 0x9a, 0x02,
+    0x01, 0x8e, 0x02, 0x03, 0x8f, 0x02, 0x60, 0x5f,
+    0xbb, 0x21, 0x60, 0x03, 0xd2, 0x99, 0x0b, 0x80,
+    0x99, 0x86, 0x20, 0x01, 0x80, 0x20, 0x01, 0x87,
+    0x20, 0x00, 0x81, 0x20, 0x00, 0x9d, 0x20, 0x00,
+    0x81, 0x20, 0x01, 0x8b, 0x20, 0x08, 0x89, 0x20,
+    0x45, 0x87, 0x60, 0x01, 0xad, 0x60, 0x01, 0x8a,
+    0x60, 0x1a, 0xc7, 0x9c, 0x07, 0xd2, 0x84, 0x1c,
+    0xb8, 0x75, 0x60, 0xa6, 0x88, 0x0c, 0x00, 0xac,
+    0x0c, 0x00, 0x8d, 0x0c, 0x09, 0x9c, 0x0c, 0x02,
+    0x9f, 0x52, 0x01, 0x95, 0x52, 0x00, 0x8d, 0x52,
+    0x48, 0x86, 0x53, 0x00, 0x81, 0x53, 0x00, 0xab,
+    0x53, 0x02, 0x80, 0x53, 0x00, 0x81, 0x53, 0x00,
+    0x88, 0x53, 0x07, 0x89, 0x53, 0x05, 0x85, 0x2d,
+    0x00, 0x81, 0x2d, 0x00, 0xa4, 0x2d, 0x00, 0x81,
+    0x2d, 0x00, 0x85, 0x2d, 0x06, 0x89, 0x2d, 0x60,
+    0xd5, 0x98, 0x4d, 0x60, 0x56, 0x80, 0x4a, 0x0e,
+    0xb1, 0x8e, 0x0c, 0x80, 0x8e, 0xe3, 0x39, 0x1b,
+    0x60, 0x05, 0xe0, 0x0e, 0x1b, 0x00, 0x84, 0x1b,
+    0x0a, 0xe0, 0x63, 0x1b, 0x6a, 0x5b, 0xe3, 0xce,
+    0x23, 0x00, 0x88, 0x23, 0x6f, 0x66, 0xe1, 0xe6,
+    0x03, 0x70, 0x11, 0x58, 0xe1, 0xd8, 0x08, 0x06,
+    0x9e, 0x5c, 0x00, 0x89, 0x5c, 0x03, 0x81, 0x5c,
+    0x5f, 0x9d, 0x09, 0x01, 0x85, 0x09, 0x09, 0xc5,
+    0x73, 0x09, 0x89, 0x73, 0x00, 0x86, 0x73, 0x00,
+    0x94, 0x73, 0x04, 0x92, 0x73, 0x62, 0x4f, 0xda,
+    0x54, 0x60, 0x04, 0xca, 0x59, 0x03, 0xb8, 0x59,
+    0x06, 0x90, 0x59, 0x3f, 0x80, 0x8f, 0x80, 0x64,
+    0x81, 0x19, 0x80, 0x42, 0x0a, 0x81, 0x2f, 0x0d,
+    0xf0, 0x07, 0x97, 0x8f, 0x07, 0xe2, 0x9f, 0x8f,
+    0xe1, 0x75, 0x42, 0x29, 0x88, 0x8f, 0x70, 0x12,
+    0x96, 0x80, 0x3d, 0xe0, 0xbd, 0x35, 0x30, 0x82,
+    0x35, 0x10, 0x83, 0x3d, 0x07, 0xe1, 0x2b, 0x64,
+    0x68, 0xa3, 0xe0, 0x0a, 0x22, 0x04, 0x8c, 0x22,
+    0x02, 0x88, 0x22, 0x06, 0x89, 0x22, 0x01, 0x83,
+    0x22, 0x83, 0x19, 0x70, 0x02, 0xfb, 0xe0, 0x95,
+    0x19, 0x09, 0xa6, 0x19, 0x01, 0xbd, 0x19, 0x82,
+    0x37, 0x90, 0x19, 0x87, 0x37, 0x81, 0x19, 0x86,
+    0x37, 0x9d, 0x19, 0x83, 0x37, 0xba, 0x19, 0x16,
+    0xc5, 0x2b, 0x60, 0x39, 0x93, 0x19, 0x0b, 0xd6,
+    0x19, 0x08, 0x98, 0x19, 0x60, 0x26, 0xd4, 0x19,
+    0x00, 0xc6, 0x19, 0x00, 0x81, 0x19, 0x01, 0x80,
+    0x19, 0x01, 0x81, 0x19, 0x01, 0x83, 0x19, 0x00,
+    0x8b, 0x19, 0x00, 0x80, 0x19, 0x00, 0x86, 0x19,
+    0x00, 0xc0, 0x19, 0x00, 0x83, 0x19, 0x01, 0x87,
+    0x19, 0x00, 0x86, 0x19, 0x00, 0x9b, 0x19, 0x00,
+    0x83, 0x19, 0x00, 0x84, 0x19, 0x00, 0x80, 0x19,
+    0x02, 0x86, 0x19, 0x00, 0xe0, 0xf3, 0x19, 0x01,
+    0xe0, 0xc3, 0x19, 0x01, 0xb1, 0x19, 0xe2, 0x2b,
+    0x80, 0x0e, 0x84, 0x80, 0x00, 0x8e, 0x80, 0x64,
+    0xef, 0x86, 0x28, 0x00, 0x90, 0x28, 0x01, 0x86,
+    0x28, 0x00, 0x81, 0x28, 0x00, 0x84, 0x28, 0x60,
+    0x74, 0xac, 0x65, 0x02, 0x8d, 0x65, 0x01, 0x89,
+    0x65, 0x03, 0x81, 0x65, 0x61, 0x0f, 0xb9, 0x98,
+    0x04, 0x80, 0x98, 0x64, 0x9f, 0xe0, 0x64, 0x56,
+    0x01, 0x8f, 0x56, 0x28, 0xcb, 0x01, 0x03, 0x89,
+    0x01, 0x03, 0x81, 0x01, 0x62, 0xb0, 0xc3, 0x19,
+    0x4b, 0xbc, 0x19, 0x60, 0x61, 0x83, 0x04, 0x00,
+    0x9a, 0x04, 0x00, 0x81, 0x04, 0x00, 0x80, 0x04,
+    0x01, 0x80, 0x04, 0x00, 0x89, 0x04, 0x00, 0x83,
+    0x04, 0x00, 0x80, 0x04, 0x00, 0x80, 0x04, 0x05,
+    0x80, 0x04, 0x03, 0x80, 0x04, 0x00, 0x80, 0x04,
+    0x00, 0x80, 0x04, 0x00, 0x82, 0x04, 0x00, 0x81,
+    0x04, 0x00, 0x80, 0x04, 0x01, 0x80, 0x04, 0x00,
+    0x80, 0x04, 0x00, 0x80, 0x04, 0x00, 0x80, 0x04,
+    0x00, 0x80, 0x04, 0x00, 0x81, 0x04, 0x00, 0x80,
+    0x04, 0x01, 0x83, 0x04, 0x00, 0x86, 0x04, 0x00,
+    0x83, 0x04, 0x00, 0x83, 0x04, 0x00, 0x80, 0x04,
+    0x00, 0x89, 0x04, 0x00, 0x90, 0x04, 0x04, 0x82,
+    0x04, 0x00, 0x84, 0x04, 0x00, 0x90, 0x04, 0x33,
+    0x81, 0x04, 0x60, 0xad, 0xab, 0x19, 0x03, 0xe0,
+    0x03, 0x19, 0x0b, 0x8e, 0x19, 0x01, 0x8e, 0x19,
+    0x00, 0x8e, 0x19, 0x00, 0xa4, 0x19, 0x09, 0xe0,
+    0x4d, 0x19, 0x37, 0x99, 0x19, 0x80, 0x35, 0x81,
+    0x19, 0x0c, 0xab, 0x19, 0x03, 0x88, 0x19, 0x06,
+    0x81, 0x19, 0x0d, 0x85, 0x19, 0x60, 0x39, 0xe3,
+    0x77, 0x19, 0x07, 0x8c, 0x19, 0x02, 0x8c, 0x19,
+    0x02, 0xe0, 0x13, 0x19, 0x0b, 0xd8, 0x19, 0x06,
+    0x8b, 0x19, 0x13, 0x8b, 0x19, 0x03, 0xb7, 0x19,
+    0x07, 0x89, 0x19, 0x05, 0xa7, 0x19, 0x07, 0x9d,
+    0x19, 0x01, 0x81, 0x19, 0x4d, 0xe0, 0x18, 0x19,
+    0x00, 0xd1, 0x19, 0x00, 0xe0, 0x26, 0x19, 0x0b,
+    0x8d, 0x19, 0x01, 0x84, 0x19, 0x02, 0x82, 0x19,
+    0x04, 0x86, 0x19, 0x08, 0x98, 0x19, 0x06, 0x86,
+    0x19, 0x08, 0x82, 0x19, 0x0c, 0x86, 0x19, 0x28,
+    0xe0, 0x32, 0x19, 0x00, 0xb6, 0x19, 0x24, 0x89,
+    0x19, 0x63, 0xa5, 0xf0, 0x96, 0x7d, 0x2f, 0x21,
+    0xef, 0xd4, 0x2f, 0x0a, 0xe0, 0x7d, 0x2f, 0x01,
+    0xf0, 0x06, 0x21, 0x2f, 0x0d, 0xf0, 0x0c, 0xd0,
+    0x2f, 0x6b, 0xbe, 0xe1, 0xbd, 0x2f, 0x65, 0x81,
+    0xf0, 0x02, 0xea, 0x2f, 0x7a, 0xdc, 0x55, 0x80,
+    0x19, 0x1d, 0xdf, 0x19, 0x60, 0x1f, 0xe0, 0x8f,
+    0x37,
+};
+
+static const uint8_t unicode_script_ext_table[799] = {
+    0x82, 0xc1, 0x00, 0x00, 0x01, 0x2b, 0x01, 0x00,
+    0x00, 0x01, 0x2b, 0x1c, 0x00, 0x0c, 0x01, 0x45,
+    0x80, 0x92, 0x00, 0x00, 0x02, 0x1d, 0x6b, 0x00,
+    0x02, 0x1d, 0x28, 0x01, 0x02, 0x1d, 0x45, 0x00,
+    0x02, 0x1d, 0x28, 0x81, 0x03, 0x00, 0x00, 0x05,
+    0x04, 0x31, 0x87, 0x91, 0x9a, 0x0d, 0x00, 0x00,
+    0x05, 0x04, 0x31, 0x87, 0x91, 0x9a, 0x00, 0x03,
+    0x04, 0x87, 0x91, 0x01, 0x00, 0x00, 0x05, 0x04,
+    0x31, 0x87, 0x91, 0x9a, 0x1f, 0x00, 0x00, 0x08,
+    0x01, 0x04, 0x50, 0x51, 0x78, 0x31, 0x82, 0x87,
+    0x09, 0x00, 0x0a, 0x02, 0x04, 0x87, 0x09, 0x00,
+    0x09, 0x03, 0x04, 0x91, 0x9a, 0x05, 0x00, 0x00,
+    0x02, 0x04, 0x87, 0x62, 0x00, 0x00, 0x02, 0x04,
+    0x31, 0x81, 0xfb, 0x00, 0x00, 0x0d, 0x0b, 0x1f,
+    0x2a, 0x2c, 0x2e, 0x3c, 0x45, 0x4f, 0x70, 0x7d,
+    0x8e, 0x90, 0x95, 0x00, 0x0c, 0x0b, 0x1f, 0x2a,
+    0x2c, 0x2e, 0x3c, 0x45, 0x4f, 0x70, 0x8e, 0x90,
+    0x95, 0x10, 0x00, 0x00, 0x14, 0x0b, 0x1f, 0x21,
+    0x2d, 0x53, 0x2a, 0x2c, 0x2e, 0x3c, 0x4e, 0x4f,
+    0x60, 0x70, 0x43, 0x81, 0x86, 0x8d, 0x8e, 0x90,
+    0x95, 0x00, 0x15, 0x0b, 0x1f, 0x21, 0x2d, 0x53,
+    0x2a, 0x2c, 0x2e, 0x3c, 0x47, 0x4e, 0x4f, 0x60,
+    0x70, 0x43, 0x81, 0x86, 0x8d, 0x8e, 0x90, 0x95,
+    0x09, 0x04, 0x1f, 0x21, 0x3b, 0x4e, 0x75, 0x00,
+    0x09, 0x03, 0x0b, 0x15, 0x86, 0x75, 0x00, 0x09,
+    0x02, 0x2e, 0x5d, 0x75, 0x00, 0x09, 0x02, 0x2c,
+    0x41, 0x80, 0x75, 0x00, 0x0d, 0x02, 0x2a, 0x8e,
+    0x80, 0x71, 0x00, 0x09, 0x02, 0x3c, 0x60, 0x82,
+    0xcf, 0x00, 0x09, 0x03, 0x15, 0x5e, 0x8a, 0x80,
+    0x30, 0x00, 0x00, 0x02, 0x27, 0x45, 0x85, 0xb8,
+    0x00, 0x01, 0x04, 0x11, 0x32, 0x89, 0x88, 0x80,
+    0x4a, 0x00, 0x01, 0x02, 0x5b, 0x76, 0x00, 0x00,
+    0x00, 0x02, 0x5b, 0x76, 0x84, 0x49, 0x00, 0x00,
+    0x04, 0x0b, 0x1f, 0x2a, 0x3c, 0x00, 0x01, 0x1f,
+    0x00, 0x04, 0x0b, 0x1f, 0x2a, 0x3c, 0x00, 0x02,
+    0x1f, 0x2a, 0x00, 0x01, 0x1f, 0x01, 0x02, 0x0b,
+    0x1f, 0x00, 0x02, 0x1f, 0x7d, 0x00, 0x02, 0x0b,
+    0x1f, 0x00, 0x02, 0x1f, 0x7d, 0x00, 0x06, 0x1f,
+    0x3c, 0x4f, 0x70, 0x8e, 0x90, 0x00, 0x01, 0x1f,
+    0x01, 0x02, 0x1f, 0x7d, 0x01, 0x01, 0x1f, 0x00,
+    0x02, 0x1f, 0x7d, 0x00, 0x02, 0x0b, 0x1f, 0x06,
+    0x01, 0x1f, 0x00, 0x02, 0x1f, 0x60, 0x00, 0x02,
+    0x0b, 0x1f, 0x01, 0x01, 0x1f, 0x00, 0x02, 0x0b,
+    0x1f, 0x03, 0x01, 0x1f, 0x00, 0x08, 0x0b, 0x1f,
+    0x2a, 0x3c, 0x60, 0x70, 0x90, 0x95, 0x00, 0x02,
+    0x1f, 0x2a, 0x00, 0x03, 0x1f, 0x2a, 0x3c, 0x01,
+    0x02, 0x0b, 0x1f, 0x00, 0x01, 0x0b, 0x01, 0x02,
+    0x1f, 0x2a, 0x00, 0x01, 0x60, 0x80, 0x44, 0x00,
+    0x01, 0x01, 0x2b, 0x35, 0x00, 0x00, 0x02, 0x1d,
+    0x87, 0x81, 0xb5, 0x00, 0x00, 0x02, 0x45, 0x5b,
+    0x80, 0x3f, 0x00, 0x00, 0x03, 0x1f, 0x2a, 0x45,
+    0x8c, 0xd1, 0x00, 0x00, 0x02, 0x1d, 0x28, 0x81,
+    0x3c, 0x00, 0x01, 0x06, 0x0d, 0x30, 0x2f, 0x35,
+    0x3d, 0x9b, 0x00, 0x05, 0x0d, 0x30, 0x2f, 0x35,
+    0x3d, 0x01, 0x00, 0x00, 0x01, 0x2f, 0x00, 0x00,
+    0x09, 0x06, 0x0d, 0x30, 0x2f, 0x35, 0x3d, 0x9b,
+    0x00, 0x00, 0x00, 0x05, 0x0d, 0x30, 0x2f, 0x35,
+    0x3d, 0x07, 0x06, 0x0d, 0x30, 0x2f, 0x35, 0x3d,
+    0x9b, 0x03, 0x05, 0x0d, 0x30, 0x2f, 0x35, 0x3d,
+    0x09, 0x00, 0x03, 0x02, 0x0d, 0x2f, 0x01, 0x00,
+    0x00, 0x05, 0x0d, 0x30, 0x2f, 0x35, 0x3d, 0x04,
+    0x02, 0x35, 0x3d, 0x00, 0x00, 0x00, 0x05, 0x0d,
+    0x30, 0x2f, 0x35, 0x3d, 0x03, 0x00, 0x01, 0x03,
+    0x2f, 0x35, 0x3d, 0x01, 0x01, 0x2f, 0x58, 0x00,
+    0x03, 0x02, 0x35, 0x3d, 0x02, 0x00, 0x00, 0x02,
+    0x35, 0x3d, 0x59, 0x00, 0x00, 0x06, 0x0d, 0x30,
+    0x2f, 0x35, 0x3d, 0x9b, 0x00, 0x02, 0x35, 0x3d,
+    0x80, 0x12, 0x00, 0x0f, 0x01, 0x2f, 0x1f, 0x00,
+    0x23, 0x01, 0x2f, 0x3b, 0x00, 0x27, 0x01, 0x2f,
+    0x37, 0x00, 0x30, 0x01, 0x2f, 0x0e, 0x00, 0x0b,
+    0x01, 0x2f, 0x32, 0x00, 0x00, 0x01, 0x2f, 0x57,
+    0x00, 0x18, 0x01, 0x2f, 0x09, 0x00, 0x04, 0x01,
+    0x2f, 0x5f, 0x00, 0x1e, 0x01, 0x2f, 0xc0, 0x31,
+    0xef, 0x00, 0x00, 0x02, 0x1d, 0x28, 0x80, 0x0f,
+    0x00, 0x07, 0x02, 0x2f, 0x45, 0x80, 0xa7, 0x00,
+    0x02, 0x0e, 0x1f, 0x21, 0x2c, 0x2e, 0x41, 0x3c,
+    0x3b, 0x4e, 0x4f, 0x5a, 0x60, 0x43, 0x8d, 0x95,
+    0x02, 0x0d, 0x1f, 0x21, 0x2c, 0x2e, 0x41, 0x3c,
+    0x3b, 0x4e, 0x5a, 0x60, 0x43, 0x8d, 0x95, 0x03,
+    0x0b, 0x1f, 0x21, 0x2c, 0x2e, 0x41, 0x3b, 0x4e,
+    0x5a, 0x43, 0x8d, 0x95, 0x80, 0x36, 0x00, 0x00,
+    0x02, 0x0b, 0x1f, 0x00, 0x00, 0x00, 0x02, 0x1f,
+    0x8e, 0x39, 0x00, 0x00, 0x03, 0x3e, 0x45, 0x5e,
+    0x80, 0x1f, 0x00, 0x00, 0x02, 0x10, 0x3a, 0xc0,
+    0x13, 0xa1, 0x00, 0x00, 0x02, 0x04, 0x91, 0x09,
+    0x00, 0x00, 0x02, 0x04, 0x91, 0x46, 0x00, 0x01,
+    0x05, 0x0d, 0x30, 0x2f, 0x35, 0x3d, 0x80, 0x99,
+    0x00, 0x04, 0x06, 0x0d, 0x30, 0x2f, 0x35, 0x3d,
+    0x9b, 0x09, 0x00, 0x00, 0x02, 0x35, 0x3d, 0x2c,
+    0x00, 0x01, 0x02, 0x35, 0x3d, 0x80, 0xdf, 0x00,
+    0x02, 0x02, 0x1c, 0x49, 0x03, 0x00, 0x2c, 0x03,
+    0x1c, 0x48, 0x49, 0x02, 0x00, 0x08, 0x02, 0x1c,
+    0x49, 0x81, 0x1f, 0x00, 0x1b, 0x02, 0x04, 0x1a,
+    0x8f, 0x84, 0x00, 0x00, 0x02, 0x2a, 0x8e, 0x00,
+    0x00, 0x00, 0x02, 0x2a, 0x8e, 0x36, 0x00, 0x01,
+    0x02, 0x2a, 0x8e, 0x8c, 0x12, 0x00, 0x01, 0x02,
+    0x2a, 0x8e, 0x00, 0x00, 0x00, 0x02, 0x2a, 0x8e,
+    0xc0, 0x5c, 0x4b, 0x00, 0x03, 0x01, 0x22, 0x96,
+    0x3b, 0x00, 0x11, 0x01, 0x2f, 0x9e, 0x5d, 0x00,
+    0x01, 0x01, 0x2f, 0xce, 0xcd, 0x2d, 0x00,
+};
+
+static const uint8_t unicode_prop_Hyphen_table[28] = {
+    0xac, 0x80, 0xfe, 0x80, 0x44, 0xdb, 0x80, 0x52,
+    0x7a, 0x80, 0x48, 0x08, 0x81, 0x4e, 0x04, 0x80,
+    0x42, 0xe2, 0x80, 0x60, 0xcd, 0x66, 0x80, 0x40,
+    0xa8, 0x80, 0xd6, 0x80,
+};
+
+static const uint8_t unicode_prop_Other_Math_table[200] = {
+    0xdd, 0x80, 0x43, 0x70, 0x11, 0x80, 0x99, 0x09,
+    0x81, 0x5c, 0x1f, 0x80, 0x9a, 0x82, 0x8a, 0x80,
+    0x9f, 0x83, 0x97, 0x81, 0x8d, 0x81, 0xc0, 0x8c,
+    0x18, 0x11, 0x1c, 0x91, 0x03, 0x01, 0x89, 0x00,
+    0x14, 0x28, 0x11, 0x09, 0x02, 0x05, 0x13, 0x24,
+    0xca, 0x21, 0x18, 0x08, 0x08, 0x00, 0x21, 0x0b,
+    0x0b, 0x91, 0x09, 0x00, 0x06, 0x00, 0x29, 0x41,
+    0x21, 0x83, 0x40, 0xa7, 0x08, 0x80, 0x97, 0x80,
+    0x90, 0x80, 0x41, 0xbc, 0x81, 0x8b, 0x88, 0x24,
+    0x21, 0x09, 0x14, 0x8d, 0x00, 0x01, 0x85, 0x97,
+    0x81, 0xb8, 0x00, 0x80, 0x9c, 0x83, 0x88, 0x81,
+    0x41, 0x55, 0x81, 0x9e, 0x89, 0x41, 0x92, 0x95,
+    0xbe, 0x83, 0x9f, 0x81, 0x60, 0xd4, 0x62, 0x00,
+    0x03, 0x80, 0x40, 0xd2, 0x00, 0x80, 0x60, 0xd4,
+    0xc0, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b,
+    0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f,
+    0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80,
+    0x41, 0x53, 0x81, 0x98, 0x80, 0x98, 0x80, 0x9e,
+    0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e,
+    0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x07, 0x81,
+    0xb1, 0x55, 0xff, 0x18, 0x9a, 0x01, 0x00, 0x08,
+    0x80, 0x89, 0x03, 0x00, 0x00, 0x28, 0x18, 0x00,
+    0x00, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,
+    0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00,
+    0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90,
+};
+
+static const uint8_t unicode_prop_Other_Alphabetic_table[411] = {
+    0x43, 0x44, 0x80, 0x42, 0x69, 0x8d, 0x00, 0x01,
+    0x01, 0x00, 0xc7, 0x8a, 0xaf, 0x8c, 0x06, 0x8f,
+    0x80, 0xe4, 0x33, 0x19, 0x0b, 0x80, 0xa2, 0x80,
+    0x9d, 0x8f, 0xe5, 0x8a, 0xe4, 0x0a, 0x88, 0x02,
+    0x03, 0x40, 0xa6, 0x8b, 0x16, 0x85, 0x93, 0xb5,
+    0x09, 0x8e, 0x01, 0x22, 0x89, 0x81, 0x9c, 0x82,
+    0xb9, 0x31, 0x09, 0x81, 0x89, 0x80, 0x89, 0x81,
+    0x9c, 0x82, 0xb9, 0x23, 0x09, 0x0b, 0x80, 0x9d,
+    0x0a, 0x80, 0x8a, 0x82, 0xb9, 0x38, 0x10, 0x81,
+    0x94, 0x81, 0x95, 0x13, 0x82, 0xb9, 0x31, 0x09,
+    0x81, 0x88, 0x81, 0x89, 0x81, 0x9d, 0x80, 0xba,
+    0x22, 0x10, 0x82, 0x89, 0x80, 0xa7, 0x83, 0xb9,
+    0x30, 0x10, 0x17, 0x81, 0x8a, 0x81, 0x9c, 0x82,
+    0xb9, 0x30, 0x10, 0x17, 0x81, 0x8a, 0x81, 0x9b,
+    0x83, 0xb9, 0x30, 0x10, 0x82, 0x89, 0x80, 0x89,
+    0x81, 0x9c, 0x82, 0xca, 0x28, 0x00, 0x87, 0x91,
+    0x81, 0xbc, 0x01, 0x86, 0x91, 0x80, 0xe2, 0x01,
+    0x28, 0x81, 0x8f, 0x80, 0x40, 0xa2, 0x90, 0x8a,
+    0x8a, 0x80, 0xa3, 0xed, 0x8b, 0x00, 0x0b, 0x96,
+    0x1b, 0x10, 0x11, 0x32, 0x83, 0x8c, 0x8b, 0x00,
+    0x89, 0x83, 0x46, 0x73, 0x81, 0x9d, 0x81, 0x9d,
+    0x81, 0x9d, 0x81, 0xc1, 0x92, 0x40, 0xbb, 0x81,
+    0xa1, 0x80, 0xf5, 0x8b, 0x83, 0x88, 0x40, 0xdd,
+    0x84, 0xb8, 0x89, 0x81, 0x93, 0xc9, 0x81, 0xbe,
+    0x84, 0xaf, 0x8e, 0xbb, 0x82, 0x9d, 0x88, 0x09,
+    0xb8, 0x8a, 0xb1, 0x92, 0x41, 0xaf, 0x8d, 0x46,
+    0xc0, 0xb3, 0x48, 0xf5, 0x9f, 0x60, 0x78, 0x73,
+    0x87, 0xa1, 0x81, 0x41, 0x61, 0x07, 0x80, 0x96,
+    0x84, 0xd7, 0x81, 0xb1, 0x8f, 0x00, 0xb8, 0x80,
+    0xa5, 0x84, 0x9b, 0x8b, 0xac, 0x83, 0xaf, 0x8b,
+    0xa4, 0x80, 0xc2, 0x8d, 0x8b, 0x07, 0x81, 0xac,
+    0x82, 0xb1, 0x00, 0x11, 0x0c, 0x80, 0xab, 0x24,
+    0x80, 0x40, 0xec, 0x87, 0x60, 0x4f, 0x32, 0x80,
+    0x48, 0x56, 0x84, 0x46, 0x85, 0x10, 0x0c, 0x83,
+    0x43, 0x13, 0x83, 0x41, 0x82, 0x81, 0x41, 0x52,
+    0x82, 0xb4, 0x8d, 0xbb, 0x80, 0xac, 0x88, 0xc6,
+    0x82, 0xa3, 0x8b, 0x91, 0x81, 0xb8, 0x82, 0xaf,
+    0x8c, 0x8d, 0x81, 0xdb, 0x88, 0x08, 0x28, 0x40,
+    0x9f, 0x89, 0x96, 0x83, 0xb9, 0x31, 0x09, 0x81,
+    0x89, 0x80, 0x89, 0x81, 0x40, 0xd0, 0x8c, 0x02,
+    0xe9, 0x91, 0x40, 0xec, 0x31, 0x86, 0x9c, 0x81,
+    0xd1, 0x8e, 0x00, 0xe9, 0x8a, 0xe6, 0x8d, 0x41,
+    0x00, 0x8c, 0x40, 0xf6, 0x28, 0x09, 0x0a, 0x00,
+    0x80, 0x40, 0x8d, 0x31, 0x2b, 0x80, 0x9b, 0x89,
+    0xa9, 0x20, 0x83, 0x91, 0x8a, 0xad, 0x8d, 0x41,
+    0x96, 0x38, 0x86, 0xd2, 0x95, 0x80, 0x8d, 0xf9,
+    0x2a, 0x00, 0x08, 0x10, 0x02, 0x80, 0xc1, 0x20,
+    0x08, 0x83, 0x41, 0x5b, 0x83, 0x60, 0x50, 0x57,
+    0x00, 0xb6, 0x33, 0xdc, 0x81, 0x60, 0x4c, 0xab,
+    0x80, 0x60, 0x23, 0x60, 0x30, 0x90, 0x0e, 0x01,
+    0x04, 0x49, 0x1b, 0x80, 0x47, 0xe7, 0x99, 0x85,
+    0x99, 0x85, 0x99,
+};
+
+static const uint8_t unicode_prop_Other_Lowercase_table[51] = {
+    0x40, 0xa9, 0x80, 0x8e, 0x80, 0x41, 0xf4, 0x88,
+    0x31, 0x9d, 0x84, 0xdf, 0x80, 0xb3, 0x80, 0x59,
+    0xb0, 0xbe, 0x8c, 0x80, 0xa1, 0xa4, 0x42, 0xb0,
+    0x80, 0x8c, 0x80, 0x8f, 0x8c, 0x40, 0xd2, 0x8f,
+    0x43, 0x4f, 0x99, 0x47, 0x91, 0x81, 0x60, 0x7a,
+    0x1d, 0x81, 0x40, 0xd1, 0x80, 0x40, 0x86, 0x81,
+    0x43, 0x61, 0x83,
+};
+
+static const uint8_t unicode_prop_Other_Uppercase_table[15] = {
+    0x60, 0x21, 0x5f, 0x8f, 0x43, 0x45, 0x99, 0x61,
+    0xcc, 0x5f, 0x99, 0x85, 0x99, 0x85, 0x99,
+};
+
+static const uint8_t unicode_prop_Other_Grapheme_Extend_table[65] = {
+    0x49, 0xbd, 0x80, 0x97, 0x80, 0x41, 0x65, 0x80,
+    0x97, 0x80, 0xe5, 0x80, 0x97, 0x80, 0x40, 0xe9,
+    0x80, 0x91, 0x81, 0xe6, 0x80, 0x97, 0x80, 0xf6,
+    0x80, 0x8e, 0x80, 0x4d, 0x54, 0x80, 0x44, 0xd5,
+    0x80, 0x50, 0x20, 0x81, 0x60, 0xcf, 0x6d, 0x81,
+    0x53, 0x9d, 0x80, 0x97, 0x80, 0x41, 0x57, 0x80,
+    0x8b, 0x80, 0x40, 0xf0, 0x80, 0x43, 0x7f, 0x80,
+    0x60, 0xb8, 0x33, 0x07, 0x84, 0x6c, 0x2e, 0xac,
+    0xdf,
+};
+
+static const uint8_t unicode_prop_Other_Default_Ignorable_Code_Point_table[32] = {
+    0x43, 0x4e, 0x80, 0x4e, 0x0e, 0x81, 0x46, 0x52,
+    0x81, 0x48, 0xae, 0x80, 0x50, 0xfd, 0x80, 0x60,
+    0xce, 0x3a, 0x80, 0xce, 0x88, 0x6d, 0x00, 0x06,
+    0x00, 0x9d, 0xdf, 0xff, 0x40, 0xef, 0x4e, 0x0f,
+};
+
+static const uint8_t unicode_prop_Other_ID_Start_table[11] = {
+    0x58, 0x84, 0x81, 0x48, 0x90, 0x80, 0x94, 0x80,
+    0x4f, 0x6b, 0x81,
+};
+
+static const uint8_t unicode_prop_Other_ID_Continue_table[12] = {
+    0x40, 0xb6, 0x80, 0x42, 0xce, 0x80, 0x4f, 0xe0,
+    0x88, 0x46, 0x67, 0x80,
+};
+
+static const uint8_t unicode_prop_Prepended_Concatenation_Mark_table[17] = {
+    0x45, 0xff, 0x85, 0x40, 0xd6, 0x80, 0xb0, 0x80,
+    0x41, 0xd1, 0x80, 0x61, 0x07, 0xd9, 0x80, 0x8e,
+    0x80,
+};
+
+static const uint8_t unicode_prop_XID_Start1_table[31] = {
+    0x43, 0x79, 0x80, 0x4a, 0xb7, 0x80, 0xfe, 0x80,
+    0x60, 0x21, 0xe6, 0x81, 0x60, 0xcb, 0xc0, 0x85,
+    0x41, 0x95, 0x81, 0xf3, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x80, 0x41, 0x1e, 0x81,
+};
+
+static const uint8_t unicode_prop_XID_Continue1_table[23] = {
+    0x43, 0x79, 0x80, 0x60, 0x2d, 0x1f, 0x81, 0x60,
+    0xcb, 0xc0, 0x85, 0x41, 0x95, 0x81, 0xf3, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+};
+
+static const uint8_t unicode_prop_Changes_When_Titlecased1_table[22] = {
+    0x41, 0xc3, 0x08, 0x08, 0x81, 0xa4, 0x81, 0x4e,
+    0xdc, 0xaa, 0x0a, 0x4e, 0x87, 0x3f, 0x3f, 0x87,
+    0x8b, 0x80, 0x8e, 0x80, 0xae, 0x80,
+};
+
+static const uint8_t unicode_prop_Changes_When_Casefolded1_table[33] = {
+    0x40, 0xde, 0x80, 0xcf, 0x80, 0x97, 0x80, 0x44,
+    0x3c, 0x80, 0x59, 0x11, 0x80, 0x40, 0xe4, 0x3f,
+    0x3f, 0x87, 0x89, 0x11, 0x05, 0x02, 0x11, 0x80,
+    0xa9, 0x11, 0x80, 0x60, 0xdb, 0x07, 0x86, 0x8b,
+    0x84,
+};
+
+static const uint8_t unicode_prop_Changes_When_NFKC_Casefolded1_table[441] = {
+    0x40, 0x9f, 0x06, 0x00, 0x01, 0x00, 0x01, 0x12,
+    0x10, 0x82, 0x9f, 0x80, 0xcf, 0x01, 0x80, 0x8b,
+    0x07, 0x80, 0xfb, 0x01, 0x01, 0x80, 0xa5, 0x80,
+    0x40, 0xbb, 0x88, 0x9e, 0x29, 0x84, 0xda, 0x08,
+    0x81, 0x89, 0x80, 0xa3, 0x04, 0x02, 0x04, 0x08,
+    0x80, 0xc9, 0x82, 0x9c, 0x80, 0x41, 0x93, 0x80,
+    0x40, 0x93, 0x80, 0xd7, 0x83, 0x42, 0xde, 0x87,
+    0xfb, 0x08, 0x80, 0xd2, 0x01, 0x80, 0xa1, 0x11,
+    0x80, 0x40, 0xfc, 0x81, 0x42, 0xd4, 0x80, 0xfe,
+    0x80, 0xa7, 0x81, 0xad, 0x80, 0xb5, 0x80, 0x88,
+    0x03, 0x03, 0x03, 0x80, 0x8b, 0x80, 0x88, 0x00,
+    0x26, 0x80, 0x90, 0x80, 0x88, 0x03, 0x03, 0x03,
+    0x80, 0x8b, 0x80, 0x41, 0x41, 0x80, 0xe1, 0x81,
+    0x46, 0x52, 0x81, 0xd4, 0x83, 0x45, 0x1c, 0x10,
+    0x8a, 0x80, 0x91, 0x80, 0x9b, 0x8c, 0x80, 0xa1,
+    0xa4, 0x40, 0xd9, 0x80, 0x40, 0xd5, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x01, 0x3f, 0x3f, 0x87,
+    0x89, 0x11, 0x04, 0x00, 0x29, 0x04, 0x12, 0x80,
+    0x88, 0x12, 0x80, 0x88, 0x11, 0x11, 0x04, 0x08,
+    0x8f, 0x00, 0x20, 0x8b, 0x12, 0x2a, 0x08, 0x0b,
+    0x00, 0x07, 0x82, 0x8c, 0x06, 0x92, 0x81, 0x9a,
+    0x80, 0x8c, 0x8a, 0x80, 0xd6, 0x18, 0x10, 0x8a,
+    0x01, 0x0c, 0x0a, 0x00, 0x10, 0x11, 0x02, 0x06,
+    0x05, 0x1c, 0x85, 0x8f, 0x8f, 0x8f, 0x88, 0x80,
+    0x40, 0xa1, 0x08, 0x81, 0x40, 0xf7, 0x81, 0x41,
+    0x34, 0xd5, 0x99, 0x9a, 0x45, 0x20, 0x80, 0xe6,
+    0x82, 0xe4, 0x80, 0x41, 0x9e, 0x81, 0x40, 0xf0,
+    0x80, 0x41, 0x2e, 0x80, 0xd2, 0x80, 0x8b, 0x40,
+    0xd5, 0xa9, 0x80, 0xb4, 0x00, 0x82, 0xdf, 0x09,
+    0x80, 0xde, 0x80, 0xb0, 0xdd, 0x82, 0x8d, 0xdf,
+    0x9e, 0x80, 0xa7, 0x87, 0xae, 0x80, 0x41, 0x7f,
+    0x60, 0x72, 0x9b, 0x81, 0x40, 0xd1, 0x80, 0x40,
+    0x86, 0x81, 0x43, 0x61, 0x83, 0x88, 0x80, 0x60,
+    0x4d, 0x95, 0x41, 0x0d, 0x08, 0x00, 0x81, 0x89,
+    0x00, 0x00, 0x09, 0x82, 0xc3, 0x81, 0xe9, 0xa5,
+    0x86, 0x8b, 0x24, 0x00, 0x97, 0x04, 0x00, 0x01,
+    0x01, 0x80, 0xeb, 0xa0, 0x41, 0x6a, 0x91, 0xbf,
+    0x81, 0xb5, 0xa7, 0x8c, 0x82, 0x99, 0x95, 0x94,
+    0x81, 0x8b, 0x80, 0x92, 0x03, 0x1a, 0x00, 0x80,
+    0x40, 0x86, 0x08, 0x80, 0x9f, 0x99, 0x40, 0x83,
+    0x15, 0x0d, 0x0d, 0x0a, 0x16, 0x06, 0x80, 0x88,
+    0x60, 0xbc, 0xa6, 0x83, 0x54, 0xb9, 0x86, 0x8d,
+    0x87, 0xbf, 0x85, 0x42, 0x3e, 0xd4, 0x80, 0xc6,
+    0x01, 0x08, 0x09, 0x0b, 0x80, 0x8b, 0x00, 0x06,
+    0x80, 0xc0, 0x03, 0x0f, 0x06, 0x80, 0x9b, 0x03,
+    0x04, 0x00, 0x16, 0x80, 0x41, 0x53, 0x81, 0x41,
+    0x23, 0x81, 0xb1, 0x55, 0xff, 0x18, 0x9a, 0x01,
+    0x00, 0x08, 0x80, 0x89, 0x03, 0x00, 0x00, 0x28,
+    0x18, 0x00, 0x00, 0x02, 0x01, 0x00, 0x08, 0x00,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x06, 0x03,
+    0x03, 0x00, 0x80, 0x89, 0x80, 0x90, 0x22, 0x04,
+    0x80, 0x90, 0x42, 0x43, 0x8a, 0x84, 0x9e, 0x80,
+    0x9f, 0x99, 0x82, 0xa2, 0x80, 0xee, 0x82, 0x8c,
+    0xab, 0x83, 0x88, 0x31, 0x49, 0x9d, 0x89, 0x60,
+    0xfc, 0x05, 0x42, 0x1d, 0x6b, 0x05, 0xe1, 0x4f,
+    0xff,
+};
+
+static const uint8_t unicode_prop_ASCII_Hex_Digit_table[5] = {
+    0xaf, 0x89, 0x35, 0x99, 0x85,
+};
+
+static const uint8_t unicode_prop_Bidi_Control_table[10] = {
+    0x46, 0x1b, 0x80, 0x59, 0xf0, 0x81, 0x99, 0x84,
+    0xb6, 0x83,
+};
+
+static const uint8_t unicode_prop_Dash_table[53] = {
+    0xac, 0x80, 0x45, 0x5b, 0x80, 0xb2, 0x80, 0x4e,
+    0x40, 0x80, 0x44, 0x04, 0x80, 0x48, 0x08, 0x85,
+    0xbc, 0x80, 0xa6, 0x80, 0x8e, 0x80, 0x41, 0x85,
+    0x80, 0x4c, 0x03, 0x01, 0x80, 0x9e, 0x0b, 0x80,
+    0x41, 0xda, 0x80, 0x92, 0x80, 0xee, 0x80, 0x60,
+    0xcd, 0x8f, 0x81, 0xa4, 0x80, 0x89, 0x80, 0x40,
+    0xa8, 0x80, 0x4f, 0x9e, 0x80,
+};
+
+static const uint8_t unicode_prop_Deprecated_table[23] = {
+    0x41, 0x48, 0x80, 0x45, 0x28, 0x80, 0x49, 0x02,
+    0x00, 0x80, 0x48, 0x28, 0x81, 0x48, 0xc4, 0x85,
+    0x42, 0xb8, 0x81, 0x6d, 0xdc, 0xd5, 0x80,
+};
+
+static const uint8_t unicode_prop_Diacritic_table[358] = {
+    0xdd, 0x00, 0x80, 0xc6, 0x05, 0x03, 0x01, 0x81,
+    0x41, 0xf6, 0x40, 0x9e, 0x07, 0x25, 0x90, 0x0b,
+    0x80, 0x88, 0x81, 0x40, 0xfc, 0x84, 0x40, 0xd0,
+    0x80, 0xb6, 0x90, 0x80, 0x9a, 0x00, 0x01, 0x00,
+    0x40, 0x85, 0x3b, 0x81, 0x40, 0x85, 0x0b, 0x0a,
+    0x82, 0xc2, 0x9a, 0xda, 0x8a, 0xb9, 0x8a, 0xa1,
+    0x81, 0x40, 0xc8, 0x9b, 0xbc, 0x80, 0x8f, 0x02,
+    0x83, 0x9b, 0x80, 0xc9, 0x80, 0x8f, 0x80, 0xed,
+    0x80, 0x8f, 0x80, 0xed, 0x80, 0x8f, 0x80, 0xae,
+    0x82, 0xbb, 0x80, 0x8f, 0x06, 0x80, 0xf6, 0x80,
+    0xfe, 0x80, 0xed, 0x80, 0x8f, 0x80, 0xec, 0x81,
+    0x8f, 0x80, 0xfb, 0x80, 0xfb, 0x28, 0x80, 0xea,
+    0x80, 0x8c, 0x84, 0xca, 0x81, 0x9a, 0x00, 0x00,
+    0x03, 0x81, 0xc1, 0x10, 0x81, 0xbd, 0x80, 0xef,
+    0x00, 0x81, 0xa7, 0x0b, 0x84, 0x98, 0x30, 0x80,
+    0x89, 0x81, 0x42, 0xc0, 0x82, 0x44, 0x68, 0x8a,
+    0x88, 0x80, 0x41, 0x5a, 0x82, 0x41, 0x38, 0x39,
+    0x80, 0xaf, 0x8d, 0xf5, 0x80, 0x8e, 0x80, 0xa5,
+    0x88, 0xb5, 0x81, 0x40, 0x89, 0x81, 0xbf, 0x85,
+    0xd1, 0x98, 0x18, 0x28, 0x0a, 0xb1, 0xbe, 0xd8,
+    0x8b, 0xa4, 0x22, 0x82, 0x41, 0xbc, 0x00, 0x82,
+    0x8a, 0x82, 0x8c, 0x82, 0x8c, 0x82, 0x8c, 0x81,
+    0x4c, 0xef, 0x82, 0x41, 0x3c, 0x80, 0x41, 0xf9,
+    0x85, 0xe8, 0x83, 0xde, 0x80, 0x60, 0x75, 0x71,
+    0x80, 0x8b, 0x08, 0x80, 0x9b, 0x81, 0xd1, 0x81,
+    0x8d, 0xa1, 0xe5, 0x82, 0xec, 0x81, 0x40, 0xc9,
+    0x80, 0x9a, 0x91, 0xb8, 0x83, 0xa3, 0x80, 0xde,
+    0x80, 0x8b, 0x80, 0xa3, 0x80, 0x40, 0x94, 0x82,
+    0xc0, 0x83, 0xb2, 0x80, 0xe3, 0x84, 0x88, 0x82,
+    0xff, 0x81, 0x60, 0x4f, 0x2f, 0x80, 0x43, 0x00,
+    0x8f, 0x41, 0x0d, 0x00, 0x80, 0xae, 0x80, 0xac,
+    0x81, 0xc2, 0x80, 0x42, 0xfb, 0x80, 0x48, 0x03,
+    0x81, 0x42, 0x3a, 0x85, 0x42, 0x1d, 0x8a, 0x41,
+    0x67, 0x81, 0xf7, 0x81, 0xbd, 0x80, 0xcb, 0x80,
+    0x88, 0x82, 0xe7, 0x81, 0x40, 0xb1, 0x81, 0xd0,
+    0x80, 0x8f, 0x80, 0x97, 0x32, 0x84, 0x40, 0xcc,
+    0x02, 0x80, 0xfa, 0x81, 0x40, 0xfa, 0x81, 0xfd,
+    0x80, 0xf5, 0x81, 0xf2, 0x80, 0x41, 0x0c, 0x81,
+    0x41, 0x01, 0x0b, 0x80, 0x40, 0x9b, 0x80, 0xd2,
+    0x80, 0x91, 0x80, 0xd0, 0x80, 0x41, 0xa4, 0x80,
+    0x41, 0x01, 0x00, 0x81, 0xd0, 0x80, 0x60, 0x4d,
+    0x57, 0x84, 0xba, 0x86, 0x44, 0x57, 0x90, 0xcf,
+    0x81, 0x60, 0x61, 0x74, 0x12, 0x2f, 0x39, 0x86,
+    0x9d, 0x83, 0x4f, 0x81, 0x86, 0x41, 0xb4, 0x83,
+    0x45, 0xdf, 0x86, 0xec, 0x10, 0x82,
+};
+
+static const uint8_t unicode_prop_Extender_table[89] = {
+    0x40, 0xb6, 0x80, 0x42, 0x17, 0x81, 0x43, 0x6d,
+    0x80, 0x41, 0xb8, 0x80, 0x43, 0x59, 0x80, 0x42,
+    0xef, 0x80, 0xfe, 0x80, 0x49, 0x42, 0x80, 0xb7,
+    0x80, 0x42, 0x62, 0x80, 0x41, 0x8d, 0x80, 0xc3,
+    0x80, 0x53, 0x88, 0x80, 0xaa, 0x84, 0xe6, 0x81,
+    0xdc, 0x82, 0x60, 0x6f, 0x15, 0x80, 0x45, 0xf5,
+    0x80, 0x43, 0xc1, 0x80, 0x95, 0x80, 0x40, 0x88,
+    0x80, 0xeb, 0x80, 0x94, 0x81, 0x60, 0x54, 0x7a,
+    0x80, 0x53, 0xeb, 0x80, 0x42, 0x67, 0x82, 0x44,
+    0xce, 0x80, 0x60, 0x50, 0xa8, 0x81, 0x44, 0x9b,
+    0x08, 0x80, 0x60, 0x71, 0x57, 0x81, 0x48, 0x05,
+    0x82,
+};
+
+static const uint8_t unicode_prop_Hex_Digit_table[12] = {
+    0xaf, 0x89, 0x35, 0x99, 0x85, 0x60, 0xfe, 0xa8,
+    0x89, 0x35, 0x99, 0x85,
+};
+
+static const uint8_t unicode_prop_IDS_Binary_Operator_table[5] = {
+    0x60, 0x2f, 0xef, 0x09, 0x87,
+};
+
+static const uint8_t unicode_prop_IDS_Trinary_Operator_table[4] = {
+    0x60, 0x2f, 0xf1, 0x81,
+};
+
+static const uint8_t unicode_prop_Ideographic_table[66] = {
+    0x60, 0x30, 0x05, 0x81, 0x98, 0x88, 0x8d, 0x82,
+    0x43, 0xc4, 0x59, 0xbf, 0xbf, 0x60, 0x51, 0xfc,
+    0x60, 0x59, 0x02, 0x41, 0x6d, 0x81, 0xe9, 0x60,
+    0x75, 0x09, 0x80, 0x9a, 0x57, 0xf7, 0x87, 0x44,
+    0xd5, 0xa9, 0x88, 0x60, 0x24, 0x66, 0x41, 0x8b,
+    0x60, 0x4d, 0x03, 0x60, 0xa6, 0xdd, 0xa1, 0x50,
+    0x34, 0x8a, 0x40, 0xdd, 0x81, 0x56, 0x81, 0x8d,
+    0x5d, 0x30, 0x4c, 0x1e, 0x42, 0x1d, 0x45, 0xe1,
+    0x53, 0x4a,
+};
+
+static const uint8_t unicode_prop_Join_Control_table[4] = {
+    0x60, 0x20, 0x0b, 0x81,
+};
+
+static const uint8_t unicode_prop_Logical_Order_Exception_table[15] = {
+    0x4e, 0x3f, 0x84, 0xfa, 0x84, 0x4a, 0xef, 0x11,
+    0x80, 0x60, 0x90, 0xf9, 0x09, 0x00, 0x81,
+};
+
+static const uint8_t unicode_prop_Noncharacter_Code_Point_table[71] = {
+    0x60, 0xfd, 0xcf, 0x9f, 0x42, 0x0d, 0x81, 0x60,
+    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
+    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
+    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
+    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
+    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
+    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
+    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
+    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81,
+};
+
+static const uint8_t unicode_prop_Pattern_Syntax_table[58] = {
+    0xa0, 0x8e, 0x89, 0x86, 0x99, 0x18, 0x80, 0x99,
+    0x83, 0xa1, 0x30, 0x00, 0x08, 0x00, 0x0b, 0x03,
+    0x02, 0x80, 0x96, 0x80, 0x9e, 0x80, 0x5f, 0x17,
+    0x97, 0x87, 0x8e, 0x81, 0x92, 0x80, 0x89, 0x41,
+    0x30, 0x42, 0xcf, 0x40, 0x9f, 0x42, 0x75, 0x9d,
+    0x44, 0x6b, 0x41, 0xff, 0xff, 0x41, 0x80, 0x13,
+    0x98, 0x8e, 0x80, 0x60, 0xcd, 0x0c, 0x81, 0x41,
+    0x04, 0x81,
+};
+
+static const uint8_t unicode_prop_Pattern_White_Space_table[11] = {
+    0x88, 0x84, 0x91, 0x80, 0xe3, 0x80, 0x5f, 0x87,
+    0x81, 0x97, 0x81,
+};
+
+static const uint8_t unicode_prop_Quotation_Mark_table[31] = {
+    0xa1, 0x03, 0x80, 0x40, 0x82, 0x80, 0x8e, 0x80,
+    0x5f, 0x5b, 0x87, 0x98, 0x81, 0x4e, 0x06, 0x80,
+    0x41, 0xc8, 0x83, 0x8c, 0x82, 0x60, 0xce, 0x20,
+    0x83, 0x40, 0xbc, 0x03, 0x80, 0xd9, 0x81,
+};
+
+static const uint8_t unicode_prop_Radical_table[9] = {
+    0x60, 0x2e, 0x7f, 0x99, 0x80, 0xd8, 0x8b, 0x40,
+    0xd5,
+};
+
+static const uint8_t unicode_prop_Regional_Indicator_table[4] = {
+    0x61, 0xf1, 0xe5, 0x99,
+};
+
+static const uint8_t unicode_prop_Sentence_Terminal_table[188] = {
+    0xa0, 0x80, 0x8b, 0x80, 0x8f, 0x80, 0x45, 0x48,
+    0x80, 0x40, 0x93, 0x81, 0x40, 0xb3, 0x80, 0xaa,
+    0x82, 0x40, 0xf5, 0x80, 0xbc, 0x00, 0x02, 0x81,
+    0x41, 0x24, 0x81, 0x46, 0xe3, 0x81, 0x43, 0x15,
+    0x03, 0x81, 0x43, 0x04, 0x80, 0x40, 0xc5, 0x81,
+    0x40, 0xcb, 0x04, 0x80, 0x41, 0x39, 0x81, 0x41,
+    0x61, 0x83, 0x40, 0xad, 0x09, 0x81, 0x40, 0xda,
+    0x81, 0xc0, 0x81, 0x43, 0xbb, 0x81, 0x88, 0x82,
+    0x4d, 0xe3, 0x80, 0x8c, 0x80, 0x41, 0xc4, 0x80,
+    0x60, 0x74, 0xfb, 0x80, 0x41, 0x0d, 0x81, 0x40,
+    0xe2, 0x02, 0x80, 0x41, 0x7d, 0x81, 0xd5, 0x81,
+    0xde, 0x80, 0x40, 0x97, 0x81, 0x40, 0x92, 0x82,
+    0x40, 0x8f, 0x81, 0x40, 0xf8, 0x80, 0x60, 0x52,
+    0x65, 0x02, 0x81, 0x40, 0xa8, 0x80, 0x8b, 0x80,
+    0x8f, 0x80, 0xc0, 0x80, 0x4a, 0xf3, 0x81, 0x44,
+    0xfc, 0x84, 0x40, 0xec, 0x81, 0xf4, 0x83, 0xfe,
+    0x82, 0x40, 0x80, 0x0d, 0x80, 0x8f, 0x81, 0xd7,
+    0x08, 0x81, 0xeb, 0x80, 0x41, 0xa0, 0x81, 0x41,
+    0x74, 0x0c, 0x8e, 0xe8, 0x81, 0x40, 0xf8, 0x82,
+    0x42, 0x04, 0x00, 0x80, 0x40, 0xfa, 0x81, 0xd6,
+    0x81, 0x41, 0xa3, 0x81, 0x42, 0xb3, 0x81, 0x60,
+    0x4b, 0x74, 0x81, 0x40, 0x84, 0x80, 0xc0, 0x81,
+    0x8a, 0x80, 0x43, 0x52, 0x80, 0x60, 0x4e, 0x05,
+    0x80, 0x5d, 0xe7, 0x80,
+};
+
+static const uint8_t unicode_prop_Soft_Dotted_table[71] = {
+    0xe8, 0x81, 0x40, 0xc3, 0x80, 0x41, 0x18, 0x80,
+    0x9d, 0x80, 0xb3, 0x80, 0x93, 0x80, 0x41, 0x3f,
+    0x80, 0xe1, 0x00, 0x80, 0x59, 0x08, 0x80, 0xb2,
+    0x80, 0x8c, 0x02, 0x80, 0x40, 0x83, 0x80, 0x40,
+    0x9c, 0x80, 0x41, 0xa4, 0x80, 0x40, 0xd5, 0x81,
+    0x4b, 0x31, 0x80, 0x61, 0xa7, 0xa4, 0x81, 0xb1,
+    0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1,
+    0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1,
+    0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81,
+};
+
+static const uint8_t unicode_prop_Terminal_Punctuation_table[241] = {
+    0xa0, 0x80, 0x89, 0x00, 0x80, 0x8a, 0x0a, 0x80,
+    0x43, 0x3d, 0x07, 0x80, 0x42, 0x00, 0x80, 0xb8,
+    0x80, 0xc7, 0x80, 0x8d, 0x01, 0x81, 0x40, 0xb3,
+    0x80, 0xaa, 0x8a, 0x00, 0x40, 0xea, 0x81, 0xb5,
+    0x8e, 0x9e, 0x80, 0x41, 0x04, 0x81, 0x44, 0xf3,
+    0x81, 0x40, 0xab, 0x03, 0x85, 0x41, 0x36, 0x81,
+    0x43, 0x14, 0x87, 0x43, 0x04, 0x80, 0xfb, 0x82,
+    0xc6, 0x81, 0x40, 0x9c, 0x12, 0x80, 0xa6, 0x19,
+    0x81, 0x41, 0x39, 0x81, 0x41, 0x61, 0x83, 0x40,
+    0xad, 0x08, 0x82, 0x40, 0xda, 0x84, 0xbd, 0x81,
+    0x43, 0xbb, 0x81, 0x88, 0x82, 0x4d, 0xe3, 0x80,
+    0x8c, 0x03, 0x80, 0x89, 0x00, 0x81, 0x41, 0xb0,
+    0x81, 0x60, 0x74, 0xfa, 0x81, 0x41, 0x0c, 0x82,
+    0x40, 0xe2, 0x84, 0x41, 0x7d, 0x81, 0xd5, 0x81,
+    0xde, 0x80, 0x40, 0x96, 0x82, 0x40, 0x92, 0x82,
+    0xfe, 0x80, 0x8f, 0x81, 0x40, 0xf8, 0x80, 0x60,
+    0x52, 0x63, 0x10, 0x83, 0x40, 0xa8, 0x80, 0x89,
+    0x00, 0x80, 0x8a, 0x0a, 0x80, 0xc0, 0x01, 0x80,
+    0x44, 0x39, 0x80, 0xaf, 0x80, 0x44, 0x85, 0x80,
+    0x40, 0xc6, 0x80, 0x41, 0x35, 0x81, 0x40, 0x97,
+    0x85, 0xc3, 0x85, 0xd8, 0x83, 0x43, 0xb7, 0x84,
+    0x40, 0xec, 0x86, 0xef, 0x83, 0xfe, 0x82, 0x40,
+    0x80, 0x0d, 0x80, 0x8f, 0x81, 0xd7, 0x84, 0xeb,
+    0x80, 0x41, 0xa0, 0x82, 0x8b, 0x81, 0x41, 0x65,
+    0x1a, 0x8e, 0xe8, 0x81, 0x40, 0xf8, 0x82, 0x42,
+    0x04, 0x00, 0x80, 0x40, 0xfa, 0x81, 0xd6, 0x0b,
+    0x81, 0x41, 0x9d, 0x82, 0xac, 0x80, 0x42, 0x84,
+    0x81, 0x45, 0x76, 0x84, 0x60, 0x45, 0xf8, 0x81,
+    0x40, 0x84, 0x80, 0xc0, 0x82, 0x89, 0x80, 0x43,
+    0x51, 0x81, 0x60, 0x4e, 0x05, 0x80, 0x5d, 0xe6,
+    0x83,
+};
+
+static const uint8_t unicode_prop_Unified_Ideograph_table[42] = {
+    0x60, 0x33, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x51,
+    0xfc, 0x60, 0x5a, 0x10, 0x08, 0x00, 0x81, 0x89,
+    0x00, 0x00, 0x09, 0x82, 0x61, 0x05, 0xd5, 0x60,
+    0xa6, 0xdd, 0xa1, 0x50, 0x34, 0x8a, 0x40, 0xdd,
+    0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x54, 0x1e,
+    0x53, 0x4a,
+};
+
+static const uint8_t unicode_prop_Variation_Selector_table[12] = {
+    0x58, 0x0a, 0x82, 0x60, 0xe5, 0xf1, 0x8f, 0x6d,
+    0x02, 0xef, 0x40, 0xef,
+};
+
+static const uint8_t unicode_prop_White_Space_table[22] = {
+    0x88, 0x84, 0x91, 0x80, 0xe3, 0x80, 0x99, 0x80,
+    0x55, 0xde, 0x80, 0x49, 0x7e, 0x8a, 0x9c, 0x0c,
+    0x80, 0xae, 0x80, 0x4f, 0x9f, 0x80,
+};
+
+static const uint8_t unicode_prop_Bidi_Mirrored_table[171] = {
+    0xa7, 0x81, 0x91, 0x00, 0x80, 0x9b, 0x00, 0x80,
+    0x9c, 0x00, 0x80, 0xac, 0x80, 0x8e, 0x80, 0x4e,
+    0x7d, 0x83, 0x47, 0x5c, 0x81, 0x49, 0x9b, 0x81,
+    0x89, 0x81, 0xb5, 0x81, 0x8d, 0x81, 0x40, 0xb0,
+    0x80, 0x40, 0xbf, 0x1a, 0x2a, 0x02, 0x0a, 0x18,
+    0x18, 0x00, 0x03, 0x88, 0x20, 0x80, 0x91, 0x23,
+    0x88, 0x08, 0x00, 0x39, 0x9e, 0x0b, 0x20, 0x88,
+    0x09, 0x92, 0x21, 0x88, 0x21, 0x0b, 0x97, 0x81,
+    0x8f, 0x3b, 0x93, 0x0e, 0x81, 0x44, 0x3c, 0x8d,
+    0xc9, 0x01, 0x18, 0x08, 0x14, 0x1c, 0x12, 0x8d,
+    0x41, 0x92, 0x95, 0x0d, 0x80, 0x8d, 0x38, 0x35,
+    0x10, 0x1c, 0x01, 0x0c, 0x18, 0x02, 0x09, 0x89,
+    0x29, 0x81, 0x8b, 0x92, 0x03, 0x08, 0x00, 0x08,
+    0x03, 0x21, 0x2a, 0x97, 0x81, 0x8a, 0x0b, 0x18,
+    0x09, 0x0b, 0xaa, 0x0f, 0x80, 0xa7, 0x20, 0x00,
+    0x14, 0x22, 0x18, 0x14, 0x00, 0x40, 0xff, 0x80,
+    0x42, 0x02, 0x1a, 0x08, 0x81, 0x8d, 0x09, 0x89,
+    0x41, 0xdd, 0x89, 0x0f, 0x60, 0xce, 0x3c, 0x2c,
+    0x81, 0x40, 0xa1, 0x81, 0x91, 0x00, 0x80, 0x9b,
+    0x00, 0x80, 0x9c, 0x00, 0x00, 0x08, 0x81, 0x60,
+    0xd7, 0x76, 0x80, 0xb8, 0x80, 0xb8, 0x80, 0xb8,
+    0x80, 0xb8, 0x80,
+};
+
+static const uint8_t unicode_prop_Emoji_table[238] = {
+    0xa2, 0x05, 0x04, 0x89, 0xee, 0x03, 0x80, 0x5f,
+    0x8c, 0x80, 0x8b, 0x80, 0x40, 0xd7, 0x80, 0x95,
+    0x80, 0xd9, 0x85, 0x8e, 0x81, 0x41, 0x6e, 0x81,
+    0x8b, 0x80, 0x40, 0xa5, 0x80, 0x98, 0x8a, 0x1a,
+    0x40, 0xc6, 0x80, 0x40, 0xe6, 0x81, 0x89, 0x80,
+    0x88, 0x80, 0xb9, 0x18, 0x84, 0x88, 0x01, 0x01,
+    0x09, 0x03, 0x01, 0x00, 0x09, 0x02, 0x02, 0x0f,
+    0x14, 0x00, 0x04, 0x8b, 0x8a, 0x09, 0x00, 0x08,
+    0x80, 0x91, 0x01, 0x81, 0x91, 0x28, 0x00, 0x0a,
+    0x0c, 0x01, 0x0b, 0x81, 0x8a, 0x0c, 0x09, 0x04,
+    0x08, 0x00, 0x81, 0x93, 0x0c, 0x28, 0x19, 0x03,
+    0x01, 0x01, 0x28, 0x01, 0x00, 0x00, 0x05, 0x02,
+    0x05, 0x80, 0x89, 0x81, 0x8e, 0x01, 0x03, 0x00,
+    0x03, 0x10, 0x80, 0x8a, 0x81, 0xaf, 0x82, 0x88,
+    0x80, 0x8d, 0x80, 0x8d, 0x80, 0x41, 0x73, 0x81,
+    0x41, 0xce, 0x82, 0x92, 0x81, 0xb2, 0x03, 0x80,
+    0x44, 0xd9, 0x80, 0x8b, 0x80, 0x42, 0x58, 0x00,
+    0x80, 0x61, 0xbd, 0x69, 0x80, 0x40, 0xc9, 0x80,
+    0x40, 0x9f, 0x81, 0x8b, 0x81, 0x8d, 0x01, 0x89,
+    0xca, 0x99, 0x01, 0x96, 0x80, 0x93, 0x01, 0x88,
+    0x94, 0x81, 0x40, 0xad, 0xa1, 0x81, 0xef, 0x09,
+    0x02, 0x81, 0xd2, 0x0a, 0x80, 0x41, 0x06, 0x80,
+    0xbe, 0x8a, 0x28, 0x97, 0x31, 0x0f, 0x8b, 0x01,
+    0x19, 0x03, 0x81, 0x8c, 0x09, 0x07, 0x81, 0x88,
+    0x04, 0x82, 0x8b, 0x17, 0x11, 0x00, 0x03, 0x05,
+    0x02, 0x05, 0xd5, 0xaf, 0xc5, 0x27, 0x0a, 0x3d,
+    0x10, 0x01, 0x10, 0x81, 0x89, 0x40, 0xe2, 0x8b,
+    0x41, 0x1f, 0xae, 0x80, 0x89, 0x80, 0xb1, 0x80,
+    0xd1, 0x80, 0xb2, 0xef, 0x22, 0x14, 0x86, 0x88,
+    0x98, 0x36, 0x88, 0x82, 0x8c, 0x86,
+};
+
+static const uint8_t unicode_prop_Emoji_Component_table[28] = {
+    0xa2, 0x05, 0x04, 0x89, 0x5f, 0xd2, 0x80, 0x40,
+    0xd4, 0x80, 0x60, 0xdd, 0x2a, 0x80, 0x60, 0xf3,
+    0xd5, 0x99, 0x41, 0xfa, 0x84, 0x45, 0xaf, 0x83,
+    0x6c, 0x06, 0x6b, 0xdf,
+};
+
+static const uint8_t unicode_prop_Emoji_Modifier_table[4] = {
+    0x61, 0xf3, 0xfa, 0x84,
+};
+
+static const uint8_t unicode_prop_Emoji_Modifier_Base_table[66] = {
+    0x60, 0x26, 0x1c, 0x80, 0x40, 0xda, 0x80, 0x8f,
+    0x83, 0x61, 0xcc, 0x76, 0x80, 0xbb, 0x11, 0x01,
+    0x82, 0xf4, 0x09, 0x8a, 0x94, 0x92, 0x10, 0x1a,
+    0x02, 0x30, 0x00, 0x97, 0x80, 0x40, 0xc8, 0x0b,
+    0x80, 0x94, 0x03, 0x81, 0x40, 0xad, 0x12, 0x84,
+    0xd2, 0x80, 0x8f, 0x82, 0x88, 0x80, 0x8a, 0x80,
+    0x42, 0x3e, 0x01, 0x07, 0x3d, 0x80, 0x88, 0x89,
+    0x0a, 0xb7, 0x80, 0xbc, 0x08, 0x08, 0x80, 0x90,
+    0x10, 0x8c,
+};
+
+static const uint8_t unicode_prop_Emoji_Presentation_table[144] = {
+    0x60, 0x23, 0x19, 0x81, 0x40, 0xcc, 0x1a, 0x01,
+    0x80, 0x42, 0x08, 0x81, 0x94, 0x81, 0xb1, 0x8b,
+    0xaa, 0x80, 0x92, 0x80, 0x8c, 0x07, 0x81, 0x90,
+    0x0c, 0x0f, 0x04, 0x80, 0x94, 0x06, 0x08, 0x03,
+    0x01, 0x06, 0x03, 0x81, 0x9b, 0x80, 0xa2, 0x00,
+    0x03, 0x10, 0x80, 0xbc, 0x82, 0x97, 0x80, 0x8d,
+    0x80, 0x43, 0x5a, 0x81, 0xb2, 0x03, 0x80, 0x61,
+    0xc4, 0xad, 0x80, 0x40, 0xc9, 0x80, 0x40, 0xbd,
+    0x01, 0x89, 0xca, 0x99, 0x00, 0x97, 0x80, 0x93,
+    0x01, 0x20, 0x82, 0x94, 0x81, 0x40, 0xad, 0xa0,
+    0x8b, 0x88, 0x80, 0xc5, 0x80, 0x95, 0x8b, 0xaa,
+    0x1c, 0x8b, 0x90, 0x10, 0x82, 0xc6, 0x00, 0x80,
+    0x40, 0xba, 0x81, 0xbe, 0x8c, 0x18, 0x97, 0x91,
+    0x80, 0x99, 0x81, 0x8c, 0x80, 0xd5, 0xd4, 0xaf,
+    0xc5, 0x28, 0x12, 0x0a, 0x92, 0x0e, 0x88, 0x40,
+    0xe2, 0x8b, 0x41, 0x1f, 0xae, 0x80, 0x89, 0x80,
+    0xb1, 0x80, 0xd1, 0x80, 0xb2, 0xef, 0x22, 0x14,
+    0x86, 0x88, 0x98, 0x36, 0x88, 0x82, 0x8c, 0x86,
+};
+
+static const uint8_t unicode_prop_Extended_Pictographic_table[156] = {
+    0x40, 0xa8, 0x03, 0x80, 0x5f, 0x8c, 0x80, 0x8b,
+    0x80, 0x40, 0xd7, 0x80, 0x95, 0x80, 0xd9, 0x85,
+    0x8e, 0x81, 0x41, 0x6e, 0x81, 0x8b, 0x80, 0xde,
+    0x80, 0xc5, 0x80, 0x98, 0x8a, 0x1a, 0x40, 0xc6,
+    0x80, 0x40, 0xe6, 0x81, 0x89, 0x80, 0x88, 0x80,
+    0xb9, 0x18, 0x28, 0x8b, 0x80, 0xf1, 0x89, 0xf5,
+    0x81, 0x8a, 0x00, 0x00, 0x28, 0x10, 0x28, 0x89,
+    0x81, 0x8e, 0x01, 0x03, 0x00, 0x03, 0x10, 0x80,
+    0x8a, 0x84, 0xac, 0x82, 0x88, 0x80, 0x8d, 0x80,
+    0x8d, 0x80, 0x41, 0x73, 0x81, 0x41, 0xce, 0x82,
+    0x92, 0x81, 0xb2, 0x03, 0x80, 0x44, 0xd9, 0x80,
+    0x8b, 0x80, 0x42, 0x58, 0x00, 0x80, 0x61, 0xbd,
+    0x65, 0x40, 0xff, 0x8c, 0x82, 0x9e, 0x80, 0xbb,
+    0x85, 0x8b, 0x81, 0x8d, 0x01, 0x89, 0x91, 0xb8,
+    0x9a, 0x8e, 0x89, 0x80, 0x93, 0x01, 0x88, 0x03,
+    0x88, 0x41, 0xb1, 0x84, 0x41, 0x3d, 0x87, 0x41,
+    0x09, 0xaf, 0xff, 0xf3, 0x8b, 0xd4, 0xaa, 0x8b,
+    0x83, 0xb7, 0x87, 0x89, 0x85, 0xa7, 0x87, 0x9d,
+    0xd1, 0x8b, 0xae, 0x80, 0x89, 0x80, 0x41, 0xb8,
+    0x40, 0xff, 0x43, 0xfd,
+};
+
+static const uint8_t unicode_prop_Default_Ignorable_Code_Point_table[51] = {
+    0x40, 0xac, 0x80, 0x42, 0xa0, 0x80, 0x42, 0xcb,
+    0x80, 0x4b, 0x41, 0x81, 0x46, 0x52, 0x81, 0xd4,
+    0x83, 0x47, 0xfb, 0x84, 0x99, 0x84, 0xb0, 0x8f,
+    0x50, 0xf3, 0x80, 0x60, 0xcc, 0x9a, 0x8f, 0x40,
+    0xee, 0x80, 0x40, 0x9f, 0x80, 0xce, 0x88, 0x60,
+    0xbc, 0xa6, 0x83, 0x54, 0xce, 0x87, 0x6c, 0x2e,
+    0x84, 0x4f, 0xff,
+};
+
+typedef enum {
+    UNICODE_PROP_Hyphen,
+    UNICODE_PROP_Other_Math,
+    UNICODE_PROP_Other_Alphabetic,
+    UNICODE_PROP_Other_Lowercase,
+    UNICODE_PROP_Other_Uppercase,
+    UNICODE_PROP_Other_Grapheme_Extend,
+    UNICODE_PROP_Other_Default_Ignorable_Code_Point,
+    UNICODE_PROP_Other_ID_Start,
+    UNICODE_PROP_Other_ID_Continue,
+    UNICODE_PROP_Prepended_Concatenation_Mark,
+    UNICODE_PROP_ID_Continue1,
+    UNICODE_PROP_XID_Start1,
+    UNICODE_PROP_XID_Continue1,
+    UNICODE_PROP_Changes_When_Titlecased1,
+    UNICODE_PROP_Changes_When_Casefolded1,
+    UNICODE_PROP_Changes_When_NFKC_Casefolded1,
+    UNICODE_PROP_ASCII_Hex_Digit,
+    UNICODE_PROP_Bidi_Control,
+    UNICODE_PROP_Dash,
+    UNICODE_PROP_Deprecated,
+    UNICODE_PROP_Diacritic,
+    UNICODE_PROP_Extender,
+    UNICODE_PROP_Hex_Digit,
+    UNICODE_PROP_IDS_Binary_Operator,
+    UNICODE_PROP_IDS_Trinary_Operator,
+    UNICODE_PROP_Ideographic,
+    UNICODE_PROP_Join_Control,
+    UNICODE_PROP_Logical_Order_Exception,
+    UNICODE_PROP_Noncharacter_Code_Point,
+    UNICODE_PROP_Pattern_Syntax,
+    UNICODE_PROP_Pattern_White_Space,
+    UNICODE_PROP_Quotation_Mark,
+    UNICODE_PROP_Radical,
+    UNICODE_PROP_Regional_Indicator,
+    UNICODE_PROP_Sentence_Terminal,
+    UNICODE_PROP_Soft_Dotted,
+    UNICODE_PROP_Terminal_Punctuation,
+    UNICODE_PROP_Unified_Ideograph,
+    UNICODE_PROP_Variation_Selector,
+    UNICODE_PROP_White_Space,
+    UNICODE_PROP_Bidi_Mirrored,
+    UNICODE_PROP_Emoji,
+    UNICODE_PROP_Emoji_Component,
+    UNICODE_PROP_Emoji_Modifier,
+    UNICODE_PROP_Emoji_Modifier_Base,
+    UNICODE_PROP_Emoji_Presentation,
+    UNICODE_PROP_Extended_Pictographic,
+    UNICODE_PROP_Default_Ignorable_Code_Point,
+    UNICODE_PROP_ID_Start,
+    UNICODE_PROP_Case_Ignorable,
+    UNICODE_PROP_ASCII,
+    UNICODE_PROP_Alphabetic,
+    UNICODE_PROP_Any,
+    UNICODE_PROP_Assigned,
+    UNICODE_PROP_Cased,
+    UNICODE_PROP_Changes_When_Casefolded,
+    UNICODE_PROP_Changes_When_Casemapped,
+    UNICODE_PROP_Changes_When_Lowercased,
+    UNICODE_PROP_Changes_When_NFKC_Casefolded,
+    UNICODE_PROP_Changes_When_Titlecased,
+    UNICODE_PROP_Changes_When_Uppercased,
+    UNICODE_PROP_Grapheme_Base,
+    UNICODE_PROP_Grapheme_Extend,
+    UNICODE_PROP_ID_Continue,
+    UNICODE_PROP_Lowercase,
+    UNICODE_PROP_Math,
+    UNICODE_PROP_Uppercase,
+    UNICODE_PROP_XID_Continue,
+    UNICODE_PROP_XID_Start,
+    UNICODE_PROP_Cased1,
+    UNICODE_PROP_COUNT,
+} UnicodePropertyEnum;
+
+static const char unicode_prop_name_table[] =
+    "ASCII_Hex_Digit,AHex"               "\0"
+    "Bidi_Control,Bidi_C"                "\0"
+    "Dash"                               "\0"
+    "Deprecated,Dep"                     "\0"
+    "Diacritic,Dia"                      "\0"
+    "Extender,Ext"                       "\0"
+    "Hex_Digit,Hex"                      "\0"
+    "IDS_Binary_Operator,IDSB"           "\0"
+    "IDS_Trinary_Operator,IDST"          "\0"
+    "Ideographic,Ideo"                   "\0"
+    "Join_Control,Join_C"                "\0"
+    "Logical_Order_Exception,LOE"        "\0"
+    "Noncharacter_Code_Point,NChar"      "\0"
+    "Pattern_Syntax,Pat_Syn"             "\0"
+    "Pattern_White_Space,Pat_WS"         "\0"
+    "Quotation_Mark,QMark"               "\0"
+    "Radical"                            "\0"
+    "Regional_Indicator,RI"              "\0"
+    "Sentence_Terminal,STerm"            "\0"
+    "Soft_Dotted,SD"                     "\0"
+    "Terminal_Punctuation,Term"          "\0"
+    "Unified_Ideograph,UIdeo"            "\0"
+    "Variation_Selector,VS"              "\0"
+    "White_Space,space"                  "\0"
+    "Bidi_Mirrored,Bidi_M"               "\0"
+    "Emoji"                              "\0"
+    "Emoji_Component,EComp"              "\0"
+    "Emoji_Modifier,EMod"                "\0"
+    "Emoji_Modifier_Base,EBase"          "\0"
+    "Emoji_Presentation,EPres"           "\0"
+    "Extended_Pictographic,ExtPict"      "\0"
+    "Default_Ignorable_Code_Point,DI"    "\0"
+    "ID_Start,IDS"                       "\0"
+    "Case_Ignorable,CI"                  "\0"
+    "ASCII"                              "\0"
+    "Alphabetic,Alpha"                   "\0"
+    "Any"                                "\0"
+    "Assigned"                           "\0"
+    "Cased"                              "\0"
+    "Changes_When_Casefolded,CWCF"       "\0"
+    "Changes_When_Casemapped,CWCM"       "\0"
+    "Changes_When_Lowercased,CWL"        "\0"
+    "Changes_When_NFKC_Casefolded,CWKCF" "\0"
+    "Changes_When_Titlecased,CWT"        "\0"
+    "Changes_When_Uppercased,CWU"        "\0"
+    "Grapheme_Base,Gr_Base"              "\0"
+    "Grapheme_Extend,Gr_Ext"             "\0"
+    "ID_Continue,IDC"                    "\0"
+    "Lowercase,Lower"                    "\0"
+    "Math"                               "\0"
+    "Uppercase,Upper"                    "\0"
+    "XID_Continue,XIDC"                  "\0"
+    "XID_Start,XIDS"                     "\0"
+;
+
+static const uint8_t * const unicode_prop_table[] = {
+    unicode_prop_Hyphen_table,
+    unicode_prop_Other_Math_table,
+    unicode_prop_Other_Alphabetic_table,
+    unicode_prop_Other_Lowercase_table,
+    unicode_prop_Other_Uppercase_table,
+    unicode_prop_Other_Grapheme_Extend_table,
+    unicode_prop_Other_Default_Ignorable_Code_Point_table,
+    unicode_prop_Other_ID_Start_table,
+    unicode_prop_Other_ID_Continue_table,
+    unicode_prop_Prepended_Concatenation_Mark_table,
+    unicode_prop_ID_Continue1_table,
+    unicode_prop_XID_Start1_table,
+    unicode_prop_XID_Continue1_table,
+    unicode_prop_Changes_When_Titlecased1_table,
+    unicode_prop_Changes_When_Casefolded1_table,
+    unicode_prop_Changes_When_NFKC_Casefolded1_table,
+    unicode_prop_ASCII_Hex_Digit_table,
+    unicode_prop_Bidi_Control_table,
+    unicode_prop_Dash_table,
+    unicode_prop_Deprecated_table,
+    unicode_prop_Diacritic_table,
+    unicode_prop_Extender_table,
+    unicode_prop_Hex_Digit_table,
+    unicode_prop_IDS_Binary_Operator_table,
+    unicode_prop_IDS_Trinary_Operator_table,
+    unicode_prop_Ideographic_table,
+    unicode_prop_Join_Control_table,
+    unicode_prop_Logical_Order_Exception_table,
+    unicode_prop_Noncharacter_Code_Point_table,
+    unicode_prop_Pattern_Syntax_table,
+    unicode_prop_Pattern_White_Space_table,
+    unicode_prop_Quotation_Mark_table,
+    unicode_prop_Radical_table,
+    unicode_prop_Regional_Indicator_table,
+    unicode_prop_Sentence_Terminal_table,
+    unicode_prop_Soft_Dotted_table,
+    unicode_prop_Terminal_Punctuation_table,
+    unicode_prop_Unified_Ideograph_table,
+    unicode_prop_Variation_Selector_table,
+    unicode_prop_White_Space_table,
+    unicode_prop_Bidi_Mirrored_table,
+    unicode_prop_Emoji_table,
+    unicode_prop_Emoji_Component_table,
+    unicode_prop_Emoji_Modifier_table,
+    unicode_prop_Emoji_Modifier_Base_table,
+    unicode_prop_Emoji_Presentation_table,
+    unicode_prop_Extended_Pictographic_table,
+    unicode_prop_Default_Ignorable_Code_Point_table,
+    unicode_prop_ID_Start_table,
+    unicode_prop_Case_Ignorable_table,
+};
+
+static const uint16_t unicode_prop_len_table[] = {
+    countof(unicode_prop_Hyphen_table),
+    countof(unicode_prop_Other_Math_table),
+    countof(unicode_prop_Other_Alphabetic_table),
+    countof(unicode_prop_Other_Lowercase_table),
+    countof(unicode_prop_Other_Uppercase_table),
+    countof(unicode_prop_Other_Grapheme_Extend_table),
+    countof(unicode_prop_Other_Default_Ignorable_Code_Point_table),
+    countof(unicode_prop_Other_ID_Start_table),
+    countof(unicode_prop_Other_ID_Continue_table),
+    countof(unicode_prop_Prepended_Concatenation_Mark_table),
+    countof(unicode_prop_ID_Continue1_table),
+    countof(unicode_prop_XID_Start1_table),
+    countof(unicode_prop_XID_Continue1_table),
+    countof(unicode_prop_Changes_When_Titlecased1_table),
+    countof(unicode_prop_Changes_When_Casefolded1_table),
+    countof(unicode_prop_Changes_When_NFKC_Casefolded1_table),
+    countof(unicode_prop_ASCII_Hex_Digit_table),
+    countof(unicode_prop_Bidi_Control_table),
+    countof(unicode_prop_Dash_table),
+    countof(unicode_prop_Deprecated_table),
+    countof(unicode_prop_Diacritic_table),
+    countof(unicode_prop_Extender_table),
+    countof(unicode_prop_Hex_Digit_table),
+    countof(unicode_prop_IDS_Binary_Operator_table),
+    countof(unicode_prop_IDS_Trinary_Operator_table),
+    countof(unicode_prop_Ideographic_table),
+    countof(unicode_prop_Join_Control_table),
+    countof(unicode_prop_Logical_Order_Exception_table),
+    countof(unicode_prop_Noncharacter_Code_Point_table),
+    countof(unicode_prop_Pattern_Syntax_table),
+    countof(unicode_prop_Pattern_White_Space_table),
+    countof(unicode_prop_Quotation_Mark_table),
+    countof(unicode_prop_Radical_table),
+    countof(unicode_prop_Regional_Indicator_table),
+    countof(unicode_prop_Sentence_Terminal_table),
+    countof(unicode_prop_Soft_Dotted_table),
+    countof(unicode_prop_Terminal_Punctuation_table),
+    countof(unicode_prop_Unified_Ideograph_table),
+    countof(unicode_prop_Variation_Selector_table),
+    countof(unicode_prop_White_Space_table),
+    countof(unicode_prop_Bidi_Mirrored_table),
+    countof(unicode_prop_Emoji_table),
+    countof(unicode_prop_Emoji_Component_table),
+    countof(unicode_prop_Emoji_Modifier_table),
+    countof(unicode_prop_Emoji_Modifier_Base_table),
+    countof(unicode_prop_Emoji_Presentation_table),
+    countof(unicode_prop_Extended_Pictographic_table),
+    countof(unicode_prop_Default_Ignorable_Code_Point_table),
+    countof(unicode_prop_ID_Start_table),
+    countof(unicode_prop_Case_Ignorable_table),
+};
+
+#endif /* CONFIG_ALL_UNICODE */
diff --git a/libunicode.h b/include/quickjs/libunicode.h
similarity index 100%
rename from libunicode.h
rename to include/quickjs/libunicode.h
diff --git a/list.h b/include/quickjs/list.h
similarity index 97%
rename from list.h
rename to include/quickjs/list.h
index 0a1bc5a49..46ee90e8c 100644
--- a/list.h
+++ b/include/quickjs/list.h
@@ -1,6 +1,6 @@
 /*
  * Linux klist like system
- * 
+ *
  * Copyright (c) 2016-2017 Fabrice Bellard
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -28,6 +28,8 @@
 #include <stddef.h>
 #endif
 
+#include <stdio.h>
+
 struct list_head {
     struct list_head *prev;
     struct list_head *next;
@@ -46,7 +48,7 @@ static inline void init_list_head(struct list_head *head)
 }
 
 /* insert 'el' between 'prev' and 'next' */
-static inline void __list_add(struct list_head *el, 
+static inline void __list_add(struct list_head *el,
                               struct list_head *prev, struct list_head *next)
 {
     prev->next = el;
diff --git a/quickjs-atom.h b/include/quickjs/quickjs-atom.h
similarity index 100%
rename from quickjs-atom.h
rename to include/quickjs/quickjs-atom.h
diff --git a/quickjs-opcode.h b/include/quickjs/quickjs-opcode.h
similarity index 100%
rename from quickjs-opcode.h
rename to include/quickjs/quickjs-opcode.h
diff --git a/quickjs.h b/include/quickjs/quickjs.h
similarity index 53%
rename from quickjs.h
rename to include/quickjs/quickjs.h
index d4a5cd311..0a5a0c302 100644
--- a/quickjs.h
+++ b/include/quickjs/quickjs.h
@@ -65,50 +65,50 @@ typedef uint32_t JSAtom;
 #endif
 
 enum {
-    /* all tags with a reference count are negative */
-    JS_TAG_FIRST       = -11, /* first negative tag */
-    JS_TAG_BIG_DECIMAL = -11,
-    JS_TAG_BIG_INT     = -10,
-    JS_TAG_BIG_FLOAT   = -9,
-    JS_TAG_SYMBOL      = -8,
-    JS_TAG_STRING      = -7,
-    JS_TAG_MODULE      = -3, /* used internally */
-    JS_TAG_FUNCTION_BYTECODE = -2, /* used internally */
-    JS_TAG_OBJECT      = -1,
-
-    JS_TAG_INT         = 0,
-    JS_TAG_BOOL        = 1,
-    JS_TAG_NULL        = 2,
-    JS_TAG_UNDEFINED   = 3,
-    JS_TAG_UNINITIALIZED = 4,
-    JS_TAG_CATCH_OFFSET = 5,
-    JS_TAG_EXCEPTION   = 6,
-    JS_TAG_FLOAT64     = 7,
-    /* any larger tag is FLOAT64 if JS_NAN_BOXING */
+  /* all tags with a reference count are negative */
+  JS_TAG_FIRST = -11, /* first negative tag */
+  JS_TAG_BIG_DECIMAL = -11,
+  JS_TAG_BIG_INT = -10,
+  JS_TAG_BIG_FLOAT = -9,
+  JS_TAG_SYMBOL = -8,
+  JS_TAG_STRING = -7,
+  JS_TAG_MODULE = -3,            /* used internally */
+  JS_TAG_FUNCTION_BYTECODE = -2, /* used internally */
+  JS_TAG_OBJECT = -1,
+
+  JS_TAG_INT = 0,
+  JS_TAG_BOOL = 1,
+  JS_TAG_NULL = 2,
+  JS_TAG_UNDEFINED = 3,
+  JS_TAG_UNINITIALIZED = 4,
+  JS_TAG_CATCH_OFFSET = 5,
+  JS_TAG_EXCEPTION = 6,
+  JS_TAG_FLOAT64 = 7,
+  /* any larger tag is FLOAT64 if JS_NAN_BOXING */
 };
 
 typedef struct JSRefCountHeader {
-    int ref_count;
+  int ref_count;
 } JSRefCountHeader;
 
 #define JS_FLOAT64_NAN NAN
 
 #ifdef CONFIG_CHECK_JSVALUE
 /* JSValue consistency : it is not possible to run the code in this
-   mode, but it is useful to detect simple reference counting
-   errors. It would be interesting to modify a static C analyzer to
-   handle specific annotations (clang has such annotations but only
-   for objective C) */
-typedef struct __JSValue *JSValue;
-typedef const struct __JSValue *JSValueConst;
-
-#define JS_VALUE_GET_TAG(v) (int)((uintptr_t)(v) & 0xf)
+  mode, but it is useful to detect simple reference counting
+  errors. It would be interesting to modify a static C analyzer to
+  handle specific annotations (clang has such annotations but only
+  for objective C) */
+typedef struct __JSValue* JSValue;
+typedef const struct __JSValue* JSValueConst;
+
+#define JS_VALUE_GET_TAG(v) (int)((uintptr_t)(v)&0xf)
 /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */
 #define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v)
 #define JS_VALUE_GET_INT(v) (int)((intptr_t)(v) >> 4)
 #define JS_VALUE_GET_BOOL(v) JS_VALUE_GET_INT(v)
 #define JS_VALUE_GET_FLOAT64(v) (double)JS_VALUE_GET_INT(v)
-#define JS_VALUE_GET_PTR(v) (void *)((intptr_t)(v) & ~0xf)
+#define JS_VALUE_GET_PTR(v) (void*)((intptr_t)(v) & ~0xf)
 
 #define JS_MKVAL(tag, val) (JSValue)(intptr_t)(((val) << 4) | (tag))
 #define JS_MKPTR(tag, p) (JSValue)((intptr_t)(p) | (tag))
@@ -117,16 +117,14 @@ typedef const struct __JSValue *JSValueConst;
 
 #define JS_NAN JS_MKVAL(JS_TAG_FLOAT64, 1)
 
-static inline JSValue __JS_NewFloat64(JSContext *ctx, double d)
-{
-    return JS_MKVAL(JS_TAG_FLOAT64, (int)d);
+static inline JSValue __JS_NewFloat64(JSContext* ctx, double d) {
+  return JS_MKVAL(JS_TAG_FLOAT64, (int)d);
 }
 
-static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
-{
-    return 0;
+static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) {
+  return 0;
 }
-    
+
 #elif defined(JS_NAN_BOXING)
 
 typedef uint64_t JSValue;
@@ -136,73 +134,69 @@ typedef uint64_t JSValue;
 #define JS_VALUE_GET_TAG(v) (int)((v) >> 32)
 #define JS_VALUE_GET_INT(v) (int)(v)
 #define JS_VALUE_GET_BOOL(v) (int)(v)
-#define JS_VALUE_GET_PTR(v) (void *)(intptr_t)(v)
+#define JS_VALUE_GET_PTR(v) (void*)(intptr_t)(v)
 
 #define JS_MKVAL(tag, val) (((uint64_t)(tag) << 32) | (uint32_t)(val))
 #define JS_MKPTR(tag, ptr) (((uint64_t)(tag) << 32) | (uintptr_t)(ptr))
 
 #define JS_FLOAT64_TAG_ADDEND (0x7ff80000 - JS_TAG_FIRST + 1) /* quiet NaN encoding */
 
-static inline double JS_VALUE_GET_FLOAT64(JSValue v)
-{
-    union {
-        JSValue v;
-        double d;
-    } u;
-    u.v = v;
-    u.v += (uint64_t)JS_FLOAT64_TAG_ADDEND << 32;
-    return u.d;
+static inline double JS_VALUE_GET_FLOAT64(JSValue v) {
+  union {
+    JSValue v;
+    double d;
+  } u;
+  u.v = v;
+  u.v += (uint64_t)JS_FLOAT64_TAG_ADDEND << 32;
+  return u.d;
 }
 
 #define JS_NAN (0x7ff8000000000000 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32))
 
-static inline JSValue __JS_NewFloat64(JSContext *ctx, double d)
-{
-    union {
-        double d;
-        uint64_t u64;
-    } u;
-    JSValue v;
-    u.d = d;
-    /* normalize NaN */
-    if (js_unlikely((u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000))
-        v = JS_NAN;
-    else
-        v = u.u64 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32);
-    return v;
+static inline JSValue __JS_NewFloat64(JSContext* ctx, double d) {
+  union {
+    double d;
+    uint64_t u64;
+  } u;
+  JSValue v;
+  u.d = d;
+  /* normalize NaN */
+  if (js_unlikely((u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000))
+    v = JS_NAN;
+  else
+    v = u.u64 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32);
+  return v;
 }
 
-#define JS_TAG_IS_FLOAT64(tag) ((unsigned)((tag) - JS_TAG_FIRST) >= (JS_TAG_FLOAT64 - JS_TAG_FIRST))
+#define JS_TAG_IS_FLOAT64(tag) ((unsigned)((tag)-JS_TAG_FIRST) >= (JS_TAG_FLOAT64 - JS_TAG_FIRST))
 
 /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */
-static inline int JS_VALUE_GET_NORM_TAG(JSValue v)
-{
-    uint32_t tag;
-    tag = JS_VALUE_GET_TAG(v);
-    if (JS_TAG_IS_FLOAT64(tag))
-        return JS_TAG_FLOAT64;
-    else
-        return tag;
+static inline int JS_VALUE_GET_NORM_TAG(JSValue v) {
+  uint32_t tag;
+  tag = JS_VALUE_GET_TAG(v);
+  if (JS_TAG_IS_FLOAT64(tag))
+    return JS_TAG_FLOAT64;
+  else
+    return tag;
 }
 
-static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
-{
-    uint32_t tag;
-    tag = JS_VALUE_GET_TAG(v);
-    return tag == (JS_NAN >> 32);
+static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) {
+  uint32_t tag;
+  tag = JS_VALUE_GET_TAG(v);
+  return tag == (JS_NAN >> 32);
 }
-    
+
 #else /* !JS_NAN_BOXING */
 
 typedef union JSValueUnion {
-    int32_t int32;
-    double float64;
-    void *ptr;
+  int32_t int32;
+  double float64;
+  void* ptr;
 } JSValueUnion;
 
 typedef struct JSValue {
-    JSValueUnion u;
-    int64_t tag;
+  JSValueUnion u;
+  int64_t tag;
 } JSValue;
 
 #define JSValueConst JSValue
@@ -222,24 +216,22 @@ typedef struct JSValue {
 
 #define JS_NAN (JSValue){ .u.float64 = JS_FLOAT64_NAN, JS_TAG_FLOAT64 }
 
-static inline JSValue __JS_NewFloat64(JSContext *ctx, double d)
-{
-    JSValue v;
-    v.tag = JS_TAG_FLOAT64;
-    v.u.float64 = d;
-    return v;
+static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) {
+  JSValue v;
+  v.tag = JS_TAG_FLOAT64;
+  v.u.float64 = d;
+  return v;
 }
 
-static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
-{
-    union {
-        double d;
-        uint64_t u64;
-    } u;
-    if (v.tag != JS_TAG_FLOAT64)
-        return 0;
-    u.d = v.u.float64;
-    return (u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000;
+static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v) {
+  union {
+    double d;
+    uint64_t u64;
+  } u;
+  if (v.tag != JS_TAG_FLOAT64)
+    return 0;
+  u.d = v.u.float64;
+  return (u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000;
 }
 
 #endif /* !JS_NAN_BOXING */
@@ -281,10 +273,10 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
 #define JS_PROP_HAS_VALUE        (1 << 13)
 
 /* throw an exception if false would be returned
-   (JS_DefineProperty/JS_SetProperty) */
+  (JS_DefineProperty/JS_SetProperty) */
 #define JS_PROP_THROW            (1 << 14)
 /* throw an exception if false would be returned in strict mode
-   (JS_SetProperty) */
+  (JS_SetProperty) */
 #define JS_PROP_THROW_STRICT     (1 << 15)
 
 #define JS_PROP_NO_ADD           (1 << 16) /* internal use */
@@ -302,8 +294,8 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
 #define JS_EVAL_FLAG_STRICT   (1 << 3) /* force 'strict' mode */
 #define JS_EVAL_FLAG_STRIP    (1 << 4) /* force 'strip' mode */
 /* compile but do not run. The result is an object with a
-   JS_TAG_FUNCTION_BYTECODE or JS_TAG_MODULE tag. It can be executed
-   with JS_EvalFunction(). */
+  JS_TAG_FUNCTION_BYTECODE or JS_TAG_MODULE tag. It can be executed
+  with JS_EvalFunction(). */
 #define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5)
 /* don't include the stack frames before this eval in the Error() backtraces */
 #define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6)
@@ -313,17 +305,17 @@ typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc
 typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data);
 
 typedef struct JSMallocState {
-    size_t malloc_count;
-    size_t malloc_size;
-    size_t malloc_limit;
-    void *opaque; /* user opaque */
+  size_t malloc_count;
+  size_t malloc_size;
+  size_t malloc_limit;
+  void* opaque; /* user opaque */
 } JSMallocState;
 
 typedef struct JSMallocFunctions {
-    void *(*js_malloc)(JSMallocState *s, size_t size);
-    void (*js_free)(JSMallocState *s, void *ptr);
-    void *(*js_realloc)(JSMallocState *s, void *ptr, size_t size);
-    size_t (*js_malloc_usable_size)(const void *ptr);
+  void* (*js_malloc)(JSMallocState* s, size_t size);
+  void (*js_free)(JSMallocState* s, void* ptr);
+  void* (*js_realloc)(JSMallocState* s, void* ptr, size_t size);
+  size_t (*js_malloc_usable_size)(const void* ptr);
 } JSMallocFunctions;
 
 typedef struct JSGCObjectHeader JSGCObjectHeader;
@@ -336,7 +328,7 @@ void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold);
 /* use 0 to disable maximum stack size check */
 void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size);
 /* should be called when changing thread to update the stack top value
-   used to check stack overflow. */
+  used to check stack overflow. */
 void JS_UpdateStackTop(JSRuntime *rt);
 JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque);
 void JS_FreeRuntime(JSRuntime *rt);
@@ -357,7 +349,7 @@ void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj);
 JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id);
 
 /* the following functions are used to select the intrinsic object to
-   save memory */
+  save memory */
 JSContext *JS_NewContextRaw(JSRuntime *rt);
 void JS_AddIntrinsicBaseObjects(JSContext *ctx);
 void JS_AddIntrinsicDate(JSContext *ctx);
@@ -378,8 +370,7 @@ void JS_AddIntrinsicOperators(JSContext *ctx);
 /* enable "use math" */
 void JS_EnableBignumExt(JSContext *ctx, JS_BOOL enable);
 
-JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv);
+JSValue js_string_codePointRange(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
 
 void *js_malloc_rt(JSRuntime *rt, size_t size);
 void js_free_rt(JSRuntime *rt, void *ptr);
@@ -397,19 +388,19 @@ char *js_strdup(JSContext *ctx, const char *str);
 char *js_strndup(JSContext *ctx, const char *s, size_t n);
 
 typedef struct JSMemoryUsage {
-    int64_t malloc_size, malloc_limit, memory_used_size;
-    int64_t malloc_count;
-    int64_t memory_used_count;
-    int64_t atom_count, atom_size;
-    int64_t str_count, str_size;
-    int64_t obj_count, obj_size;
-    int64_t prop_count, prop_size;
-    int64_t shape_count, shape_size;
-    int64_t js_func_count, js_func_size, js_func_code_size;
-    int64_t js_func_pc2line_count, js_func_pc2line_size;
-    int64_t c_func_count, array_count;
-    int64_t fast_array_count, fast_array_elements;
-    int64_t binary_object_count, binary_object_size;
+  int64_t malloc_size, malloc_limit, memory_used_size;
+  int64_t malloc_count;
+  int64_t memory_used_count;
+  int64_t atom_count, atom_size;
+  int64_t str_count, str_size;
+  int64_t obj_count, obj_size;
+  int64_t prop_count, prop_size;
+  int64_t shape_count, shape_size;
+  int64_t js_func_count, js_func_size, js_func_code_size;
+  int64_t js_func_pc2line_count, js_func_pc2line_size;
+  int64_t c_func_count, array_count;
+  int64_t fast_array_count, fast_array_elements;
+  int64_t binary_object_count, binary_object_size;
 } JSMemoryUsage;
 
 void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s);
@@ -432,68 +423,57 @@ JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val);
 /* object class support */
 
 typedef struct JSPropertyEnum {
-    JS_BOOL is_enumerable;
-    JSAtom atom;
+  JS_BOOL is_enumerable;
+  JSAtom atom;
 } JSPropertyEnum;
 
 typedef struct JSPropertyDescriptor {
-    int flags;
-    JSValue value;
-    JSValue getter;
-    JSValue setter;
+  int flags;
+  JSValue value;
+  JSValue getter;
+  JSValue setter;
 } JSPropertyDescriptor;
 
 typedef struct JSClassExoticMethods {
-    /* Return -1 if exception (can only happen in case of Proxy object),
-       FALSE if the property does not exists, TRUE if it exists. If 1 is
-       returned, the property descriptor 'desc' is filled if != NULL. */
-    int (*get_own_property)(JSContext *ctx, JSPropertyDescriptor *desc,
-                             JSValueConst obj, JSAtom prop);
-    /* '*ptab' should hold the '*plen' property keys. Return 0 if OK,
-       -1 if exception. The 'is_enumerable' field is ignored.
-    */
-    int (*get_own_property_names)(JSContext *ctx, JSPropertyEnum **ptab,
-                                  uint32_t *plen,
-                                  JSValueConst obj);
-    /* return < 0 if exception, or TRUE/FALSE */
-    int (*delete_property)(JSContext *ctx, JSValueConst obj, JSAtom prop);
-    /* return < 0 if exception or TRUE/FALSE */
-    int (*define_own_property)(JSContext *ctx, JSValueConst this_obj,
-                               JSAtom prop, JSValueConst val,
-                               JSValueConst getter, JSValueConst setter,
-                               int flags);
-    /* The following methods can be emulated with the previous ones,
-       so they are usually not needed */
-    /* return < 0 if exception or TRUE/FALSE */
-    int (*has_property)(JSContext *ctx, JSValueConst obj, JSAtom atom);
-    JSValue (*get_property)(JSContext *ctx, JSValueConst obj, JSAtom atom,
-                            JSValueConst receiver);
-    /* return < 0 if exception or TRUE/FALSE */
-    int (*set_property)(JSContext *ctx, JSValueConst obj, JSAtom atom,
-                        JSValueConst value, JSValueConst receiver, int flags);
+  /* Return -1 if exception (can only happen in case of Proxy object),
+     FALSE if the property does not exists, TRUE if it exists. If 1 is
+     returned, the property descriptor 'desc' is filled if != NULL. */
+  int (*get_own_property)(JSContext* ctx, JSPropertyDescriptor* desc, JSValueConst obj, JSAtom prop);
+  /* '*ptab' should hold the '*plen' property keys. Return 0 if OK,
+     -1 if exception. The 'is_enumerable' field is ignored.
+  */
+  int (*get_own_property_names)(JSContext* ctx, JSPropertyEnum** ptab, uint32_t* plen, JSValueConst obj);
+  /* return < 0 if exception, or TRUE/FALSE */
+  int (*delete_property)(JSContext* ctx, JSValueConst obj, JSAtom prop);
+  /* return < 0 if exception or TRUE/FALSE */
+  int (*define_own_property)(JSContext* ctx, JSValueConst this_obj, JSAtom prop, JSValueConst val, JSValueConst getter, JSValueConst setter, int flags);
+  /* The following methods can be emulated with the previous ones,
+     so they are usually not needed */
+  /* return < 0 if exception or TRUE/FALSE */
+  int (*has_property)(JSContext* ctx, JSValueConst obj, JSAtom atom);
+  JSValue (*get_property)(JSContext* ctx, JSValueConst obj, JSAtom atom, JSValueConst receiver);
+  /* return < 0 if exception or TRUE/FALSE */
+  int (*set_property)(JSContext* ctx, JSValueConst obj, JSAtom atom, JSValueConst value, JSValueConst receiver, int flags);
 } JSClassExoticMethods;
 
-typedef void JSClassFinalizer(JSRuntime *rt, JSValue val);
-typedef void JSClassGCMark(JSRuntime *rt, JSValueConst val,
-                           JS_MarkFunc *mark_func);
+typedef void JSClassFinalizer(JSRuntime* rt, JSValue val);
+typedef void JSClassGCMark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func);
 #define JS_CALL_FLAG_CONSTRUCTOR (1 << 0)
-typedef JSValue JSClassCall(JSContext *ctx, JSValueConst func_obj,
-                            JSValueConst this_val, int argc, JSValueConst *argv,
-                            int flags);
+typedef JSValue JSClassCall(JSContext* ctx, JSValueConst func_obj, JSValueConst this_val, int argc, JSValueConst* argv, int flags);
 
 typedef struct JSClassDef {
-    const char *class_name;
-    JSClassFinalizer *finalizer;
-    JSClassGCMark *gc_mark;
-    /* if call != NULL, the object is a function. If (flags &
-       JS_CALL_FLAG_CONSTRUCTOR) != 0, the function is called as a
-       constructor. In this case, 'this_val' is new.target. A
-       constructor call only happens if the object constructor bit is
-       set (see JS_SetConstructorBit()). */
-    JSClassCall *call;
-    /* XXX: suppress this indirection ? It is here only to save memory
-       because only a few classes need these methods */
-    JSClassExoticMethods *exotic;
+  const char* class_name;
+  JSClassFinalizer* finalizer;
+  JSClassGCMark* gc_mark;
+  /* if call != NULL, the object is a function. If (flags &
+     JS_CALL_FLAG_CONSTRUCTOR) != 0, the function is called as a
+     constructor. In this case, 'this_val' is new.target. A
+     constructor call only happens if the object constructor bit is
+     set (see JS_SetConstructorBit()). */
+  JSClassCall* call;
+  /* XXX: suppress this indirection ? It is here only to save memory
+     because only a few classes need these methods */
+  JSClassExoticMethods* exotic;
 } JSClassDef;
 
 JSClassID JS_NewClassID(JSClassID *pclass_id);
@@ -504,127 +484,120 @@ int JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id);
 
 static js_force_inline JSValue JS_NewBool(JSContext *ctx, JS_BOOL val)
 {
-    return JS_MKVAL(JS_TAG_BOOL, (val != 0));
+  return JS_MKVAL(JS_TAG_BOOL, (val != 0));
 }
 
 static js_force_inline JSValue JS_NewInt32(JSContext *ctx, int32_t val)
 {
-    return JS_MKVAL(JS_TAG_INT, val);
+  return JS_MKVAL(JS_TAG_INT, val);
 }
 
 static js_force_inline JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val)
 {
-    return JS_MKVAL(JS_TAG_CATCH_OFFSET, val);
+  return JS_MKVAL(JS_TAG_CATCH_OFFSET, val);
 }
 
-static js_force_inline JSValue JS_NewInt64(JSContext *ctx, int64_t val)
-{
-    JSValue v;
-    if (val == (int32_t)val) {
-        v = JS_NewInt32(ctx, val);
-    } else {
-        v = __JS_NewFloat64(ctx, val);
-    }
-    return v;
+static js_force_inline JSValue JS_NewInt64(JSContext *ctx, int64_t val) {
+  JSValue v;
+  if (val == (int32_t)val) {
+    v = JS_NewInt32(ctx, val);
+  } else {
+    v = __JS_NewFloat64(ctx, val);
+  }
+  return v;
 }
 
-static js_force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val)
-{
-    JSValue v;
-    if (val <= 0x7fffffff) {
-        v = JS_NewInt32(ctx, val);
-    } else {
-        v = __JS_NewFloat64(ctx, val);
-    }
-    return v;
+static js_force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val) {
+  JSValue v;
+  if (val <= 0x7fffffff) {
+    v = JS_NewInt32(ctx, val);
+  } else {
+    v = __JS_NewFloat64(ctx, val);
+  }
+  return v;
 }
 
 JSValue JS_NewBigInt64(JSContext *ctx, int64_t v);
 JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v);
 
-static js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double d)
-{
-    JSValue v;
-    int32_t val;
-    union {
-        double d;
-        uint64_t u;
-    } u, t;
-    u.d = d;
-    val = (int32_t)d;
-    t.d = val;
-    /* -0 cannot be represented as integer, so we compare the bit
-        representation */
-    if (u.u == t.u) {
-        v = JS_MKVAL(JS_TAG_INT, val);
-    } else {
-        v = __JS_NewFloat64(ctx, d);
-    }
-    return v;
+static js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double d) {
+  JSValue v;
+  int32_t val;
+  union {
+    double d;
+    uint64_t u;
+  } u, t;
+  u.d = d;
+  val = (int32_t)d;
+  t.d = val;
+  /* -0 cannot be represented as integer, so we compare the bit
+      representation */
+  if (u.u == t.u) {
+    v = JS_MKVAL(JS_TAG_INT, val);
+  } else {
+    v = __JS_NewFloat64(ctx, d);
+  }
+  return v;
 }
 
-static inline JS_BOOL JS_IsNumber(JSValueConst v)
-{
-    int tag = JS_VALUE_GET_TAG(v);
-    return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag);
+static inline JS_BOOL JS_IsNumber(JSValueConst v) {
+  int tag = JS_VALUE_GET_TAG(v);
+  return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag);
 }
 
-static inline JS_BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v)
-{
-    int tag = JS_VALUE_GET_TAG(v);
-    return tag == JS_TAG_BIG_INT;
+static inline JS_BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v) {
+  int tag = JS_VALUE_GET_TAG(v);
+  return tag == JS_TAG_BIG_INT;
 }
 
-static inline JS_BOOL JS_IsBigFloat(JSValueConst v)
-{
-    int tag = JS_VALUE_GET_TAG(v);
-    return tag == JS_TAG_BIG_FLOAT;
+static inline JS_BOOL JS_IsBigFloat(JSValueConst v) {
+  int tag = JS_VALUE_GET_TAG(v);
+  return tag == JS_TAG_BIG_FLOAT;
 }
 
-static inline JS_BOOL JS_IsBigDecimal(JSValueConst v)
-{
-    int tag = JS_VALUE_GET_TAG(v);
-    return tag == JS_TAG_BIG_DECIMAL;
+static inline JS_BOOL JS_IsBigDecimal(JSValueConst v) {
+  int tag = JS_VALUE_GET_TAG(v);
+  return tag == JS_TAG_BIG_DECIMAL;
 }
 
 static inline JS_BOOL JS_IsBool(JSValueConst v)
 {
-    return JS_VALUE_GET_TAG(v) == JS_TAG_BOOL;
+  return JS_VALUE_GET_TAG(v) == JS_TAG_BOOL;
 }
 
 static inline JS_BOOL JS_IsNull(JSValueConst v)
 {
-    return JS_VALUE_GET_TAG(v) == JS_TAG_NULL;
+  return JS_VALUE_GET_TAG(v) == JS_TAG_NULL;
 }
 
 static inline JS_BOOL JS_IsUndefined(JSValueConst v)
 {
-    return JS_VALUE_GET_TAG(v) == JS_TAG_UNDEFINED;
+  return JS_VALUE_GET_TAG(v) == JS_TAG_UNDEFINED;
 }
 
 static inline JS_BOOL JS_IsException(JSValueConst v)
 {
-    return js_unlikely(JS_VALUE_GET_TAG(v) == JS_TAG_EXCEPTION);
+  return js_unlikely(JS_VALUE_GET_TAG(v) == JS_TAG_EXCEPTION);
 }
 
 static inline JS_BOOL JS_IsUninitialized(JSValueConst v)
 {
-    return js_unlikely(JS_VALUE_GET_TAG(v) == JS_TAG_UNINITIALIZED);
+  return js_unlikely(JS_VALUE_GET_TAG(v) == JS_TAG_UNINITIALIZED);
 }
 
 static inline JS_BOOL JS_IsString(JSValueConst v)
 {
-    return JS_VALUE_GET_TAG(v) == JS_TAG_STRING;
+  return JS_VALUE_GET_TAG(v) == JS_TAG_STRING;
 }
 
 static inline JS_BOOL JS_IsSymbol(JSValueConst v)
 {
-    return JS_VALUE_GET_TAG(v) == JS_TAG_SYMBOL;
+  return JS_VALUE_GET_TAG(v) == JS_TAG_SYMBOL;
 }
 
 static inline JS_BOOL JS_IsObject(JSValueConst v)
 {
-    return JS_VALUE_GET_TAG(v) == JS_TAG_OBJECT;
+  return JS_VALUE_GET_TAG(v) == JS_TAG_OBJECT;
 }
 
 JSValue JS_Throw(JSContext *ctx, JSValue obj);
@@ -640,49 +613,45 @@ JSValue __js_printf_like(2, 3) JS_ThrowInternalError(JSContext *ctx, const char
 JSValue JS_ThrowOutOfMemory(JSContext *ctx);
 
 void __JS_FreeValue(JSContext *ctx, JSValue v);
-static inline void JS_FreeValue(JSContext *ctx, JSValue v)
-{
-    if (JS_VALUE_HAS_REF_COUNT(v)) {
-        JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
-        if (--p->ref_count <= 0) {
-            __JS_FreeValue(ctx, v);
-        }
+static inline void JS_FreeValue(JSContext *ctx, JSValue v) {
+  if (JS_VALUE_HAS_REF_COUNT(v)) {
+    JSRefCountHeader* p = (JSRefCountHeader*)JS_VALUE_GET_PTR(v);
+    if (--p->ref_count <= 0) {
+      __JS_FreeValue(ctx, v);
     }
+  }
 }
 void __JS_FreeValueRT(JSRuntime *rt, JSValue v);
-static inline void JS_FreeValueRT(JSRuntime *rt, JSValue v)
-{
-    if (JS_VALUE_HAS_REF_COUNT(v)) {
-        JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
-        if (--p->ref_count <= 0) {
-            __JS_FreeValueRT(rt, v);
-        }
+static inline void JS_FreeValueRT(JSRuntime *rt, JSValue v) {
+  if (JS_VALUE_HAS_REF_COUNT(v)) {
+    JSRefCountHeader* p = (JSRefCountHeader*)JS_VALUE_GET_PTR(v);
+    if (--p->ref_count <= 0) {
+      __JS_FreeValueRT(rt, v);
     }
+  }
 }
 
-static inline JSValue JS_DupValue(JSContext *ctx, JSValueConst v)
-{
-    if (JS_VALUE_HAS_REF_COUNT(v)) {
-        JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
-        p->ref_count++;
-    }
-    return (JSValue)v;
+static inline JSValue JS_DupValue(JSContext *ctx, JSValueConst v) {
+  if (JS_VALUE_HAS_REF_COUNT(v)) {
+    JSRefCountHeader* p = (JSRefCountHeader*)JS_VALUE_GET_PTR(v);
+    p->ref_count++;
+  }
+  return (JSValue)v;
 }
 
-static inline JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v)
-{
-    if (JS_VALUE_HAS_REF_COUNT(v)) {
-        JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
-        p->ref_count++;
-    }
-    return (JSValue)v;
+static inline JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v) {
+  if (JS_VALUE_HAS_REF_COUNT(v)) {
+    JSRefCountHeader* p = (JSRefCountHeader*)JS_VALUE_GET_PTR(v);
+    p->ref_count++;
+  }
+  return (JSValue)v;
 }
 
 int JS_ToBool(JSContext *ctx, JSValueConst val); /* return -1 for JS_EXCEPTION */
 int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val);
 static inline int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val)
 {
-    return JS_ToInt32(ctx, (int32_t*)pres, val);
+  return JS_ToInt32(ctx, (int32_t*)pres, val);
 }
 int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val);
 int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val);
@@ -700,11 +669,11 @@ JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val);
 const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, JS_BOOL cesu8);
 static inline const char *JS_ToCStringLen(JSContext *ctx, size_t *plen, JSValueConst val1)
 {
-    return JS_ToCStringLen2(ctx, plen, val1, 0);
+  return JS_ToCStringLen2(ctx, plen, val1, 0);
 }
 static inline const char *JS_ToCString(JSContext *ctx, JSValueConst val1)
 {
-    return JS_ToCStringLen2(ctx, NULL, val1, 0);
+  return JS_ToCStringLen2(ctx, NULL, val1, 0);
 }
 void JS_FreeCString(JSContext *ctx, const char *ptr);
 
@@ -720,34 +689,21 @@ JS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, JS_BOOL val)
 JSValue JS_NewArray(JSContext *ctx);
 int JS_IsArray(JSContext *ctx, JSValueConst val);
 
-JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
-                               JSAtom prop, JSValueConst receiver,
-                               JS_BOOL throw_ref_error);
-static js_force_inline JSValue JS_GetProperty(JSContext *ctx, JSValueConst this_obj,
-                                              JSAtom prop)
-{
-    return JS_GetPropertyInternal(ctx, this_obj, prop, this_obj, 0);
+JSValue JS_GetPropertyInternal(JSContext* ctx, JSValueConst obj, JSAtom prop, JSValueConst receiver, JS_BOOL throw_ref_error);
+static js_force_inline JSValue JS_GetProperty(JSContext* ctx, JSValueConst this_obj, JSAtom prop) {
+  return JS_GetPropertyInternal(ctx, this_obj, prop, this_obj, 0);
 }
-JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj,
-                          const char *prop);
-JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
-                             uint32_t idx);
-
-int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj,
-                           JSAtom prop, JSValue val,
-                           int flags);
-static inline int JS_SetProperty(JSContext *ctx, JSValueConst this_obj,
-                                 JSAtom prop, JSValue val)
-{
-    return JS_SetPropertyInternal(ctx, this_obj, prop, val, JS_PROP_THROW);
+JSValue JS_GetPropertyStr(JSContext* ctx, JSValueConst this_obj, const char* prop);
+JSValue JS_GetPropertyUint32(JSContext* ctx, JSValueConst this_obj, uint32_t idx);
+
+int JS_SetPropertyInternal(JSContext* ctx, JSValueConst this_obj, JSAtom prop, JSValue val, int flags);
+static inline int JS_SetProperty(JSContext* ctx, JSValueConst this_obj, JSAtom prop, JSValue val) {
+  return JS_SetPropertyInternal(ctx, this_obj, prop, val, JS_PROP_THROW);
 }
-int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
-                         uint32_t idx, JSValue val);
-int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj,
-                        int64_t idx, JSValue val);
-int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj,
-                      const char *prop, JSValue val);
-int JS_HasProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop);
+int JS_SetPropertyUint32(JSContext* ctx, JSValueConst this_obj, uint32_t idx, JSValue val);
+int JS_SetPropertyInt64(JSContext* ctx, JSValueConst this_obj, int64_t idx, JSValue val);
+int JS_SetPropertyStr(JSContext* ctx, JSValueConst this_obj, const char* prop, JSValue val);
+int JS_HasProperty(JSContext* ctx, JSValueConst this_obj, JSAtom prop);
 int JS_IsExtensible(JSContext *ctx, JSValueConst obj);
 int JS_PreventExtensions(JSContext *ctx, JSValueConst obj);
 int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags);
@@ -762,81 +718,53 @@ JSValue JS_GetPrototype(JSContext *ctx, JSValueConst val);
 /* set theJSPropertyEnum.is_enumerable field */
 #define JS_GPN_SET_ENUM     (1 << 5)
 
-int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab,
-                           uint32_t *plen, JSValueConst obj, int flags);
-int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc,
-                      JSValueConst obj, JSAtom prop);
-
-JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj,
-                int argc, JSValueConst *argv);
-JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom,
-                  int argc, JSValueConst *argv);
-JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj,
-                           int argc, JSValueConst *argv);
-JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj,
-                            JSValueConst new_target,
-                            int argc, JSValueConst *argv);
-JS_BOOL JS_DetectModule(const char *input, size_t input_len);
+int JS_GetOwnPropertyNames(JSContext* ctx, JSPropertyEnum** ptab, uint32_t* plen, JSValueConst obj, int flags);
+int JS_GetOwnProperty(JSContext* ctx, JSPropertyDescriptor* desc, JSValueConst obj, JSAtom prop);
+
+JSValue JS_Call(JSContext* ctx, JSValueConst func_obj, JSValueConst this_obj, int argc, JSValueConst* argv);
+JSValue JS_Invoke(JSContext* ctx, JSValueConst this_val, JSAtom atom, int argc, JSValueConst* argv);
+JSValue JS_CallConstructor(JSContext* ctx, JSValueConst func_obj, int argc, JSValueConst* argv);
+JSValue JS_CallConstructor2(JSContext* ctx, JSValueConst func_obj, JSValueConst new_target, int argc, JSValueConst* argv);
+JS_BOOL JS_DetectModule(const char* input, size_t input_len);
 /* 'input' must be zero terminated i.e. input[input_len] = '\0'. */
-JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
-                const char *filename, int eval_flags);
+JSValue JS_Eval(JSContext* ctx, const char* input, size_t input_len, const char* filename, int eval_flags);
 /* same as JS_Eval() but with an explicit 'this_obj' parameter */
-JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj,
-                    const char *input, size_t input_len,
-                    const char *filename, int eval_flags);
-JSValue JS_GetGlobalObject(JSContext *ctx);
-int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj);
-int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
-                      JSAtom prop, JSValueConst val,
-                      JSValueConst getter, JSValueConst setter, int flags);
-int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj,
-                           JSAtom prop, JSValue val, int flags);
-int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj,
-                                 uint32_t idx, JSValue val, int flags);
-int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj,
-                              const char *prop, JSValue val, int flags);
-int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj,
-                            JSAtom prop, JSValue getter, JSValue setter,
-                            int flags);
-void JS_SetOpaque(JSValue obj, void *opaque);
+JSValue JS_EvalThis(JSContext* ctx, JSValueConst this_obj, const char* input, size_t input_len, const char* filename, int eval_flags);
+JSValue JS_GetGlobalObject(JSContext* ctx);
+int JS_IsInstanceOf(JSContext* ctx, JSValueConst val, JSValueConst obj);
+int JS_DefineProperty(JSContext* ctx, JSValueConst this_obj, JSAtom prop, JSValueConst val, JSValueConst getter, JSValueConst setter, int flags);
+int JS_DefinePropertyValue(JSContext* ctx, JSValueConst this_obj, JSAtom prop, JSValue val, int flags);
+int JS_DefinePropertyValueUint32(JSContext* ctx, JSValueConst this_obj, uint32_t idx, JSValue val, int flags);
+int JS_DefinePropertyValueStr(JSContext* ctx, JSValueConst this_obj, const char* prop, JSValue val, int flags);
+int JS_DefinePropertyGetSet(JSContext* ctx, JSValueConst this_obj, JSAtom prop, JSValue getter, JSValue setter, int flags);
+void JS_SetOpaque(JSValue obj, void* opaque);
 void *JS_GetOpaque(JSValueConst obj, JSClassID class_id);
 void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id);
 
 /* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */
-JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
-                     const char *filename);
+JSValue JS_ParseJSON(JSContext* ctx, const char* buf, size_t buf_len, const char* filename);
 #define JS_PARSE_JSON_EXT (1 << 0) /* allow extended JSON */
-JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
-                      const char *filename, int flags);
-JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
-                         JSValueConst replacer, JSValueConst space0);
+JSValue JS_ParseJSON2(JSContext* ctx, const char* buf, size_t buf_len, const char* filename, int flags);
+JSValue JS_JSONStringify(JSContext* ctx, JSValueConst obj, JSValueConst replacer, JSValueConst space0);
 
 typedef void JSFreeArrayBufferDataFunc(JSRuntime *rt, void *opaque, void *ptr);
-JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len,
-                          JSFreeArrayBufferDataFunc *free_func, void *opaque,
-                          JS_BOOL is_shared);
-JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len);
+JSValue JS_NewArrayBuffer(JSContext* ctx, uint8_t* buf, size_t len, JSFreeArrayBufferDataFunc* free_func, void* opaque, JS_BOOL is_shared);
+JSValue JS_NewArrayBufferCopy(JSContext* ctx, const uint8_t* buf, size_t len);
 void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj);
-uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj);
-JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj,
-                               size_t *pbyte_offset,
-                               size_t *pbyte_length,
-                               size_t *pbytes_per_element);
+uint8_t* JS_GetArrayBuffer(JSContext* ctx, size_t* psize, JSValueConst obj);
+JSValue JS_GetTypedArrayBuffer(JSContext* ctx, JSValueConst obj, size_t* pbyte_offset, size_t* pbyte_length, size_t* pbytes_per_element);
 typedef struct {
-    void *(*sab_alloc)(void *opaque, size_t size);
-    void (*sab_free)(void *opaque, void *ptr);
-    void (*sab_dup)(void *opaque, void *ptr);
-    void *sab_opaque;
+  void* (*sab_alloc)(void* opaque, size_t size);
+  void (*sab_free)(void* opaque, void* ptr);
+  void (*sab_dup)(void* opaque, void* ptr);
+  void* sab_opaque;
 } JSSharedArrayBufferFunctions;
-void JS_SetSharedArrayBufferFunctions(JSRuntime *rt,
-                                      const JSSharedArrayBufferFunctions *sf);
+void JS_SetSharedArrayBufferFunctions(JSRuntime* rt, const JSSharedArrayBufferFunctions* sf);
 
 JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs);
 
 /* is_handled = TRUE means that the rejection is handled */
-typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValueConst promise,
-                                           JSValueConst reason,
-                                           JS_BOOL is_handled, void *opaque);
+typedef void JSHostPromiseRejectionTracker(JSContext* ctx, JSValueConst promise, JSValueConst reason, JS_BOOL is_handled, void* opaque);
 void JS_SetHostPromiseRejectionTracker(JSRuntime *rt, JSHostPromiseRejectionTracker *cb, void *opaque);
 
 /* return != 0 if the JS code needs to be interrupted */
@@ -850,20 +778,15 @@ void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj);
 typedef struct JSModuleDef JSModuleDef;
 
 /* return the module specifier (allocated with js_malloc()) or NULL if
-   exception */
-typedef char *JSModuleNormalizeFunc(JSContext *ctx,
-                                    const char *module_base_name,
-                                    const char *module_name, void *opaque);
-typedef JSModuleDef *JSModuleLoaderFunc(JSContext *ctx,
-                                        const char *module_name, void *opaque);
+  exception */
+typedef char* JSModuleNormalizeFunc(JSContext* ctx, const char* module_base_name, const char* module_name, void* opaque);
+typedef JSModuleDef* JSModuleLoaderFunc(JSContext* ctx, const char* module_name, void* opaque);
 
 /* module_normalize = NULL is allowed and invokes the default module
-   filename normalizer */
-void JS_SetModuleLoaderFunc(JSRuntime *rt,
-                            JSModuleNormalizeFunc *module_normalize,
-                            JSModuleLoaderFunc *module_loader, void *opaque);
+  filename normalizer */
+void JS_SetModuleLoaderFunc(JSRuntime* rt, JSModuleNormalizeFunc* module_normalize, JSModuleLoaderFunc* module_loader, void* opaque);
 /* return the import.meta object of a module */
-JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m);
+JSValue JS_GetImportMeta(JSContext* ctx, JSModuleDef* m);
 JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m);
 
 /* JS Job support */
@@ -878,118 +801,103 @@ int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx);
 #define JS_WRITE_OBJ_BYTECODE  (1 << 0) /* allow function/module */
 #define JS_WRITE_OBJ_BSWAP     (1 << 1) /* byte swapped output */
 #define JS_WRITE_OBJ_SAB       (1 << 2) /* allow SharedArrayBuffer */
-#define JS_WRITE_OBJ_REFERENCE (1 << 3) /* allow object references to
-                                           encode arbitrary object
-                                           graph */
-uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj,
-                        int flags);
-uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj,
-                         int flags, uint8_t ***psab_tab, size_t *psab_tab_len);
+#define JS_WRITE_OBJ_REFERENCE (1 << 3) /* allow object references to \
+             encode arbitrary object     \
+             graph */
+uint8_t* JS_WriteObject(JSContext* ctx, size_t* psize, JSValueConst obj, int flags);
+uint8_t* JS_WriteObject2(JSContext* ctx, size_t* psize, JSValueConst obj, int flags, uint8_t*** psab_tab, size_t* psab_tab_len);
 
 #define JS_READ_OBJ_BYTECODE  (1 << 0) /* allow function/module */
 #define JS_READ_OBJ_ROM_DATA  (1 << 1) /* avoid duplicating 'buf' data */
 #define JS_READ_OBJ_SAB       (1 << 2) /* allow SharedArrayBuffer */
 #define JS_READ_OBJ_REFERENCE (1 << 3) /* allow object references */
-JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len,
-                      int flags);
+JSValue JS_ReadObject(JSContext* ctx, const uint8_t* buf, size_t buf_len, int flags);
 /* instantiate and evaluate a bytecode function. Only used when
-   reading a script or module with JS_ReadObject() */
-JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj);
+  reading a script or module with JS_ReadObject() */
+JSValue JS_EvalFunction(JSContext* ctx, JSValue fun_obj);
 /* load the dependencies of the module 'obj'. Useful when JS_ReadObject()
-   returns a module. */
+  returns a module. */
 int JS_ResolveModule(JSContext *ctx, JSValueConst obj);
 
 /* only exported for os.Worker() */
-JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels);
+JSAtom JS_GetScriptOrModuleName(JSContext* ctx, int n_stack_levels);
 /* only exported for os.Worker() */
-JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename,
-                          const char *filename);
+JSModuleDef* JS_RunModule(JSContext* ctx, const char* basename, const char* filename);
 
 /* C function definition */
-typedef enum JSCFunctionEnum {  /* XXX: should rename for namespace isolation */
-    JS_CFUNC_generic,
-    JS_CFUNC_generic_magic,
-    JS_CFUNC_constructor,
-    JS_CFUNC_constructor_magic,
-    JS_CFUNC_constructor_or_func,
-    JS_CFUNC_constructor_or_func_magic,
-    JS_CFUNC_f_f,
-    JS_CFUNC_f_f_f,
-    JS_CFUNC_getter,
-    JS_CFUNC_setter,
-    JS_CFUNC_getter_magic,
-    JS_CFUNC_setter_magic,
-    JS_CFUNC_iterator_next,
+typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */
+                               JS_CFUNC_generic,
+                               JS_CFUNC_generic_magic,
+                               JS_CFUNC_constructor,
+                               JS_CFUNC_constructor_magic,
+                               JS_CFUNC_constructor_or_func,
+                               JS_CFUNC_constructor_or_func_magic,
+                               JS_CFUNC_f_f,
+                               JS_CFUNC_f_f_f,
+                               JS_CFUNC_getter,
+                               JS_CFUNC_setter,
+                               JS_CFUNC_getter_magic,
+                               JS_CFUNC_setter_magic,
+                               JS_CFUNC_iterator_next,
 } JSCFunctionEnum;
 
 typedef union JSCFunctionType {
-    JSCFunction *generic;
-    JSValue (*generic_magic)(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic);
-    JSCFunction *constructor;
-    JSValue (*constructor_magic)(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv, int magic);
-    JSCFunction *constructor_or_func;
-    double (*f_f)(double);
-    double (*f_f_f)(double, double);
-    JSValue (*getter)(JSContext *ctx, JSValueConst this_val);
-    JSValue (*setter)(JSContext *ctx, JSValueConst this_val, JSValueConst val);
-    JSValue (*getter_magic)(JSContext *ctx, JSValueConst this_val, int magic);
-    JSValue (*setter_magic)(JSContext *ctx, JSValueConst this_val, JSValueConst val, int magic);
-    JSValue (*iterator_next)(JSContext *ctx, JSValueConst this_val,
-                             int argc, JSValueConst *argv, int *pdone, int magic);
+  JSCFunction* generic;
+  JSValue (*generic_magic)(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic);
+  JSCFunction* constructor;
+  JSValue (*constructor_magic)(JSContext* ctx, JSValueConst new_target, int argc, JSValueConst* argv, int magic);
+  JSCFunction* constructor_or_func;
+  double (*f_f)(double);
+  double (*f_f_f)(double, double);
+  JSValue (*getter)(JSContext* ctx, JSValueConst this_val);
+  JSValue (*setter)(JSContext* ctx, JSValueConst this_val, JSValueConst val);
+  JSValue (*getter_magic)(JSContext* ctx, JSValueConst this_val, int magic);
+  JSValue (*setter_magic)(JSContext* ctx, JSValueConst this_val, JSValueConst val, int magic);
+  JSValue (*iterator_next)(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int* pdone, int magic);
 } JSCFunctionType;
 
-JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func,
-                         const char *name,
-                         int length, JSCFunctionEnum cproto, int magic);
-JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,
-                            int length, int magic, int data_len,
-                            JSValueConst *data);
+JSValue JS_NewCFunction2(JSContext* ctx, JSCFunction* func, const char* name, int length, JSCFunctionEnum cproto, int magic);
+JSValue JS_NewCFunctionData(JSContext* ctx, JSCFunctionData* func, int length, int magic, int data_len, JSValueConst* data);
 
-static inline JSValue JS_NewCFunction(JSContext *ctx, JSCFunction *func, const char *name,
-                                      int length)
-{
-    return JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_generic, 0);
+static inline JSValue JS_NewCFunction(JSContext* ctx, JSCFunction* func, const char* name, int length) {
+  return JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_generic, 0);
 }
 
-static inline JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *func,
-                                           const char *name,
-                                           int length, JSCFunctionEnum cproto, int magic)
-{
-    return JS_NewCFunction2(ctx, (JSCFunction *)func, name, length, cproto, magic);
+static inline JSValue JS_NewCFunctionMagic(JSContext* ctx, JSCFunctionMagic* func, const char* name, int length, JSCFunctionEnum cproto, int magic) {
+  return JS_NewCFunction2(ctx, (JSCFunction*)func, name, length, cproto, magic);
 }
-void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, 
-                       JSValueConst proto);
+void JS_SetConstructor(JSContext* ctx, JSValueConst func_obj, JSValueConst proto);
 
 /* C property definition */
 
 typedef struct JSCFunctionListEntry {
-    const char *name;
-    uint8_t prop_flags;
-    uint8_t def_type;
-    int16_t magic;
-    union {
-        struct {
-            uint8_t length; /* XXX: should move outside union */
-            uint8_t cproto; /* XXX: should move outside union */
-            JSCFunctionType cfunc;
-        } func;
-        struct {
-            JSCFunctionType get;
-            JSCFunctionType set;
-        } getset;
-        struct {
-            const char *name;
-            int base;
-        } alias;
-        struct {
-            const struct JSCFunctionListEntry *tab;
-            int len;
-        } prop_list;
-        const char *str;
-        int32_t i32;
-        int64_t i64;
-        double f64;
-    } u;
+  const char* name;
+  uint8_t prop_flags;
+  uint8_t def_type;
+  int16_t magic;
+  union {
+    struct {
+      uint8_t length; /* XXX: should move outside union */
+      uint8_t cproto; /* XXX: should move outside union */
+      JSCFunctionType cfunc;
+    } func;
+    struct {
+      JSCFunctionType get;
+      JSCFunctionType set;
+    } getset;
+    struct {
+      const char* name;
+      int base;
+    } alias;
+    struct {
+      const struct JSCFunctionListEntry* tab;
+      int len;
+    } prop_list;
+    const char* str;
+    int32_t i32;
+    int64_t i64;
+    double f64;
+  } u;
 } JSCFunctionListEntry;
 
 #define JS_DEF_CFUNC          0
@@ -1019,25 +927,19 @@ typedef struct JSCFunctionListEntry {
 #define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, -1 } } }
 #define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, base } } }
 
-void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
-                                const JSCFunctionListEntry *tab,
-                                int len);
+void JS_SetPropertyFunctionList(JSContext* ctx, JSValueConst obj, const JSCFunctionListEntry* tab, int len);
 
 /* C module definition */
 
 typedef int JSModuleInitFunc(JSContext *ctx, JSModuleDef *m);
 
-JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str,
-                           JSModuleInitFunc *func);
+JSModuleDef* JS_NewCModule(JSContext* ctx, const char* name_str, JSModuleInitFunc* func);
 /* can only be called before the module is instantiated */
-int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *name_str);
-int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m,
-                           const JSCFunctionListEntry *tab, int len);
+int JS_AddModuleExport(JSContext* ctx, JSModuleDef* m, const char* name_str);
+int JS_AddModuleExportList(JSContext* ctx, JSModuleDef* m, const JSCFunctionListEntry* tab, int len);
 /* can only be called after the module is instantiated */
-int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name,
-                       JSValue val);
-int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,
-                           const JSCFunctionListEntry *tab, int len);
+int JS_SetModuleExport(JSContext* ctx, JSModuleDef* m, const char* export_name, JSValue val);
+int JS_SetModuleExportList(JSContext* ctx, JSModuleDef* m, const JSCFunctionListEntry* tab, int len);
 
 #undef js_unlikely
 #undef js_force_inline
diff --git a/libunicode-table.h b/libunicode-table.h
deleted file mode 100644
index 1727525fb..000000000
--- a/libunicode-table.h
+++ /dev/null
@@ -1,4449 +0,0 @@
-/* Compressed unicode tables */
-/* Automatically generated file - do not edit */
-
-#include <stdint.h>
-
-static const uint32_t case_conv_table1[370] = {
-    0x00209a30, 0x00309a00, 0x005a8173, 0x00601730,
-    0x006c0730, 0x006f81b3, 0x00701700, 0x007c0700,
-    0x007f8100, 0x00803040, 0x009801c3, 0x00988190,
-    0x00990640, 0x009c9040, 0x00a481b4, 0x00a52e40,
-    0x00bc0130, 0x00bc8640, 0x00bf8170, 0x00c00100,
-    0x00c08130, 0x00c10440, 0x00c30130, 0x00c38240,
-    0x00c48230, 0x00c58240, 0x00c70130, 0x00c78130,
-    0x00c80130, 0x00c88240, 0x00c98130, 0x00ca0130,
-    0x00ca8100, 0x00cb0130, 0x00cb8130, 0x00cc0240,
-    0x00cd0100, 0x00ce0130, 0x00ce8130, 0x00cf0100,
-    0x00cf8130, 0x00d00640, 0x00d30130, 0x00d38240,
-    0x00d48130, 0x00d60240, 0x00d70130, 0x00d78240,
-    0x00d88230, 0x00d98440, 0x00db8130, 0x00dc0240,
-    0x00de0240, 0x00df8100, 0x00e20350, 0x00e38350,
-    0x00e50350, 0x00e69040, 0x00ee8100, 0x00ef1240,
-    0x00f801b4, 0x00f88350, 0x00fa0240, 0x00fb0130,
-    0x00fb8130, 0x00fc2840, 0x01100130, 0x01111240,
-    0x011d0131, 0x011d8240, 0x011e8130, 0x011f0131,
-    0x011f8201, 0x01208240, 0x01218130, 0x01220130,
-    0x01228130, 0x01230a40, 0x01280101, 0x01288101,
-    0x01290101, 0x01298100, 0x012a0100, 0x012b0200,
-    0x012c8100, 0x012d8100, 0x012e0101, 0x01300100,
-    0x01308101, 0x01318100, 0x01328101, 0x01330101,
-    0x01340100, 0x01348100, 0x01350101, 0x01358101,
-    0x01360101, 0x01378100, 0x01388101, 0x01390100,
-    0x013a8100, 0x013e8101, 0x01400100, 0x01410101,
-    0x01418100, 0x01438101, 0x01440100, 0x01448100,
-    0x01450200, 0x01460100, 0x01490100, 0x014e8101,
-    0x014f0101, 0x01a28173, 0x01b80440, 0x01bb0240,
-    0x01bd8300, 0x01bf8130, 0x01c30130, 0x01c40330,
-    0x01c60130, 0x01c70230, 0x01c801d0, 0x01c89130,
-    0x01d18930, 0x01d60100, 0x01d68300, 0x01d801d3,
-    0x01d89100, 0x01e10173, 0x01e18900, 0x01e60100,
-    0x01e68200, 0x01e78130, 0x01e80173, 0x01e88173,
-    0x01ea8173, 0x01eb0173, 0x01eb8100, 0x01ec1840,
-    0x01f80173, 0x01f88173, 0x01f90100, 0x01f98100,
-    0x01fa01a0, 0x01fa8173, 0x01fb8240, 0x01fc8130,
-    0x01fd0240, 0x01fe8330, 0x02001030, 0x02082030,
-    0x02182000, 0x02281000, 0x02302240, 0x02453640,
-    0x02600130, 0x02608e40, 0x02678100, 0x02686040,
-    0x0298a630, 0x02b0a600, 0x02c381b5, 0x08502631,
-    0x08638131, 0x08668131, 0x08682b00, 0x087e8300,
-    0x09d05011, 0x09f80610, 0x09fc0620, 0x0e400174,
-    0x0e408174, 0x0e410174, 0x0e418174, 0x0e420174,
-    0x0e428174, 0x0e430174, 0x0e438180, 0x0e440180,
-    0x0e482b30, 0x0e5e8330, 0x0ebc8101, 0x0ebe8101,
-    0x0ec70101, 0x0f007e40, 0x0f3f1840, 0x0f4b01b5,
-    0x0f4b81b6, 0x0f4c01b6, 0x0f4c81b6, 0x0f4d01b7,
-    0x0f4d8180, 0x0f4f0130, 0x0f506040, 0x0f800800,
-    0x0f840830, 0x0f880600, 0x0f8c0630, 0x0f900800,
-    0x0f940830, 0x0f980800, 0x0f9c0830, 0x0fa00600,
-    0x0fa40630, 0x0fa801b0, 0x0fa88100, 0x0fa901d3,
-    0x0fa98100, 0x0faa01d3, 0x0faa8100, 0x0fab01d3,
-    0x0fab8100, 0x0fac8130, 0x0fad8130, 0x0fae8130,
-    0x0faf8130, 0x0fb00800, 0x0fb40830, 0x0fb80200,
-    0x0fb90400, 0x0fbb0200, 0x0fbc0201, 0x0fbd0201,
-    0x0fbe0201, 0x0fc008b7, 0x0fc40867, 0x0fc808b8,
-    0x0fcc0868, 0x0fd008b8, 0x0fd40868, 0x0fd80200,
-    0x0fd901b9, 0x0fd981b1, 0x0fda01b9, 0x0fdb01b1,
-    0x0fdb81d7, 0x0fdc0230, 0x0fdd0230, 0x0fde0161,
-    0x0fdf0173, 0x0fe101b9, 0x0fe181b2, 0x0fe201ba,
-    0x0fe301b2, 0x0fe381d8, 0x0fe40430, 0x0fe60162,
-    0x0fe80200, 0x0fe901d0, 0x0fe981d0, 0x0feb01b0,
-    0x0feb81d0, 0x0fec0230, 0x0fed0230, 0x0ff00201,
-    0x0ff101d3, 0x0ff181d3, 0x0ff201ba, 0x0ff28101,
-    0x0ff301b0, 0x0ff381d3, 0x0ff40230, 0x0ff50230,
-    0x0ff60131, 0x0ff901ba, 0x0ff981b2, 0x0ffa01bb,
-    0x0ffb01b2, 0x0ffb81d9, 0x0ffc0230, 0x0ffd0230,
-    0x0ffe0162, 0x109301a0, 0x109501a0, 0x109581a0,
-    0x10990131, 0x10a70101, 0x10b01031, 0x10b81001,
-    0x10c18240, 0x125b1a31, 0x12681a01, 0x16003031,
-    0x16183001, 0x16300240, 0x16310130, 0x16318130,
-    0x16320130, 0x16328100, 0x16330100, 0x16338640,
-    0x16368130, 0x16370130, 0x16378130, 0x16380130,
-    0x16390240, 0x163a8240, 0x163f0230, 0x16406440,
-    0x16758440, 0x16790240, 0x16802600, 0x16938100,
-    0x16968100, 0x53202e40, 0x53401c40, 0x53910e40,
-    0x53993e40, 0x53bc8440, 0x53be8130, 0x53bf0a40,
-    0x53c58240, 0x53c68130, 0x53c80440, 0x53ca0101,
-    0x53cb1440, 0x53d50130, 0x53d58130, 0x53d60130,
-    0x53d68130, 0x53d70130, 0x53d80130, 0x53d88130,
-    0x53d90130, 0x53d98131, 0x53da1040, 0x53e20131,
-    0x53e28130, 0x53e30130, 0x53e38440, 0x53e80240,
-    0x53eb0440, 0x53fa8240, 0x55a98101, 0x55b85020,
-    0x7d8001b2, 0x7d8081b2, 0x7d8101b2, 0x7d8181da,
-    0x7d8201da, 0x7d8281b3, 0x7d8301b3, 0x7d8981bb,
-    0x7d8a01bb, 0x7d8a81bb, 0x7d8b01bc, 0x7d8b81bb,
-    0x7f909a31, 0x7fa09a01, 0x82002831, 0x82142801,
-    0x82582431, 0x826c2401, 0x82b80b31, 0x82be0f31,
-    0x82c60731, 0x82ca0231, 0x82cb8b01, 0x82d18f01,
-    0x82d98701, 0x82dd8201, 0x86403331, 0x86603301,
-    0x8c502031, 0x8c602001, 0xb7202031, 0xb7302001,
-    0xf4802231, 0xf4912201,
-};
-
-static const uint8_t case_conv_table2[370] = {
-    0x01, 0x00, 0x9c, 0x06, 0x07, 0x4d, 0x03, 0x04,
-    0x10, 0x00, 0x8f, 0x0b, 0x00, 0x00, 0x11, 0x00,
-    0x08, 0x00, 0x53, 0x4a, 0x51, 0x00, 0x52, 0x00,
-    0x53, 0x00, 0x3a, 0x54, 0x55, 0x00, 0x57, 0x59,
-    0x3f, 0x5d, 0x5c, 0x00, 0x46, 0x61, 0x63, 0x42,
-    0x64, 0x00, 0x66, 0x00, 0x68, 0x00, 0x6a, 0x00,
-    0x6c, 0x00, 0x6e, 0x00, 0x00, 0x40, 0x00, 0x00,
-    0x00, 0x00, 0x1a, 0x00, 0x93, 0x00, 0x00, 0x20,
-    0x35, 0x00, 0x27, 0x00, 0x21, 0x00, 0x24, 0x22,
-    0x2a, 0x00, 0x13, 0x6b, 0x6d, 0x00, 0x26, 0x24,
-    0x27, 0x14, 0x16, 0x18, 0x1b, 0x1c, 0x3e, 0x1e,
-    0x3f, 0x1f, 0x39, 0x3d, 0x22, 0x21, 0x41, 0x1e,
-    0x40, 0x25, 0x25, 0x26, 0x28, 0x20, 0x2a, 0x48,
-    0x2c, 0x43, 0x2e, 0x4b, 0x30, 0x4c, 0x32, 0x44,
-    0x42, 0x99, 0x00, 0x00, 0x95, 0x8f, 0x7d, 0x7e,
-    0x83, 0x84, 0x12, 0x80, 0x82, 0x76, 0x77, 0x12,
-    0x7b, 0xa3, 0x7c, 0x78, 0x79, 0x8a, 0x92, 0x98,
-    0xa6, 0xa0, 0x85, 0x00, 0x9a, 0xa1, 0x93, 0x75,
-    0x33, 0x95, 0x00, 0x8e, 0x00, 0x74, 0x99, 0x98,
-    0x97, 0x96, 0x00, 0x00, 0x9e, 0x00, 0x9c, 0x00,
-    0xa1, 0xa0, 0x15, 0x2e, 0x2f, 0x30, 0xb4, 0xb5,
-    0x4f, 0xaa, 0xa9, 0x12, 0x14, 0x1e, 0x21, 0x22,
-    0x22, 0x2a, 0x34, 0x35, 0xa6, 0xa7, 0x36, 0x1f,
-    0x49, 0x00, 0x00, 0x97, 0x01, 0x5a, 0xda, 0x1d,
-    0x36, 0x05, 0x00, 0xc4, 0xc3, 0xc6, 0xc5, 0xc8,
-    0xc7, 0xca, 0xc9, 0xcc, 0xcb, 0xc4, 0xd5, 0x45,
-    0xd6, 0x42, 0xd7, 0x46, 0xd8, 0xce, 0xd0, 0xd2,
-    0xd4, 0xda, 0xd9, 0xee, 0xf6, 0xfe, 0x0e, 0x07,
-    0x0f, 0x80, 0x9f, 0x00, 0x21, 0x80, 0xa3, 0xed,
-    0x00, 0xc0, 0x40, 0xc6, 0x60, 0xe7, 0xdb, 0xe6,
-    0x99, 0xc0, 0x00, 0x00, 0x06, 0x60, 0xdc, 0x29,
-    0xfd, 0x15, 0x12, 0x06, 0x16, 0xf8, 0xdd, 0x06,
-    0x15, 0x12, 0x84, 0x08, 0xc6, 0x16, 0xff, 0xdf,
-    0x03, 0xc0, 0x40, 0x00, 0x46, 0x60, 0xde, 0xe0,
-    0x6d, 0x37, 0x38, 0x39, 0x15, 0x14, 0x17, 0x16,
-    0x00, 0x1a, 0x19, 0x1c, 0x1b, 0x00, 0x5f, 0xb7,
-    0x65, 0x44, 0x47, 0x00, 0x4f, 0x62, 0x4e, 0x50,
-    0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xa3, 0xa4,
-    0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x00,
-    0x00, 0x5a, 0x00, 0x47, 0x00, 0x5b, 0x56, 0x58,
-    0x60, 0x5e, 0x70, 0x69, 0x6f, 0x4e, 0x00, 0x3b,
-    0x67, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x45, 0xa8,
-    0x8a, 0x8b, 0x8c, 0xab, 0xac, 0x58, 0x58, 0xaf,
-    0x94, 0xb0, 0x6f, 0xb2, 0x5d, 0x5c, 0x5f, 0x5e,
-    0x61, 0x60, 0x66, 0x67, 0x68, 0x69, 0x62, 0x63,
-    0x64, 0x65, 0x6b, 0x6a, 0x6d, 0x6c, 0x6f, 0x6e,
-    0x71, 0x70,
-};
-
-static const uint16_t case_conv_ext[58] = {
-    0x0399, 0x0308, 0x0301, 0x03a5, 0x0313, 0x0300, 0x0342, 0x0391,
-    0x0397, 0x03a9, 0x0046, 0x0049, 0x004c, 0x0053, 0x0069, 0x0307,
-    0x02bc, 0x004e, 0x004a, 0x030c, 0x0535, 0x0552, 0x0048, 0x0331,
-    0x0054, 0x0057, 0x030a, 0x0059, 0x0041, 0x02be, 0x1f08, 0x1f80,
-    0x1f28, 0x1f90, 0x1f68, 0x1fa0, 0x1fba, 0x0386, 0x1fb3, 0x1fca,
-    0x0389, 0x1fc3, 0x03a1, 0x1ffa, 0x038f, 0x1ff3, 0x0544, 0x0546,
-    0x053b, 0x054e, 0x053d, 0x03b8, 0x0462, 0xa64a, 0x1e60, 0x03c9,
-    0x006b, 0x00e5,
-};
-
-static const uint8_t unicode_prop_Cased1_table[188] = {
-    0x40, 0xa9, 0x80, 0x8e, 0x80, 0xfc, 0x80, 0xd3,
-    0x80, 0x8c, 0x80, 0x8d, 0x81, 0x8d, 0x02, 0x80,
-    0xe1, 0x80, 0x91, 0x85, 0x9a, 0x01, 0x00, 0x01,
-    0x11, 0x00, 0x01, 0x04, 0x08, 0x01, 0x08, 0x30,
-    0x08, 0x01, 0x15, 0x20, 0x00, 0x39, 0x99, 0x31,
-    0x9d, 0x84, 0x40, 0x94, 0x80, 0xd6, 0x82, 0xa6,
-    0x80, 0x41, 0x62, 0x80, 0xa6, 0x80, 0x57, 0x76,
-    0xf8, 0x02, 0x80, 0x8f, 0x80, 0xb0, 0x40, 0xdb,
-    0x08, 0x80, 0x41, 0xd0, 0x80, 0x8c, 0x80, 0x8f,
-    0x8c, 0xe4, 0x03, 0x01, 0x89, 0x00, 0x14, 0x28,
-    0x10, 0x11, 0x02, 0x01, 0x18, 0x0b, 0x24, 0x4b,
-    0x26, 0x01, 0x01, 0x86, 0xe5, 0x80, 0x60, 0x79,
-    0xb6, 0x81, 0x40, 0x91, 0x81, 0xbd, 0x88, 0x94,
-    0x05, 0x80, 0x98, 0x80, 0xa2, 0x00, 0x80, 0xa1,
-    0x82, 0x43, 0x34, 0xa2, 0x06, 0x80, 0x8c, 0x60,
-    0x5c, 0x16, 0x01, 0x10, 0xa9, 0x80, 0x88, 0x60,
-    0xcc, 0x44, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09,
-    0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03,
-    0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16,
-    0x80, 0x41, 0x53, 0x81, 0x98, 0x80, 0x98, 0x80,
-    0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80,
-    0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x07,
-    0x47, 0x33, 0x89, 0x80, 0x93, 0x52, 0x10, 0x99,
-    0x85, 0x99, 0x85, 0x99,
-};
-
-static const uint8_t unicode_prop_Cased1_index[18] = {
-    0xb9, 0x02, 0xe0, 0xa0, 0x1e, 0x40, 0x9e, 0xa6,
-    0x40, 0x55, 0xd4, 0x61, 0xfb, 0xd6, 0x21, 0x8a,
-    0xf1, 0x01,
-};
-
-static const uint8_t unicode_prop_Case_Ignorable_table[720] = {
-    0xa6, 0x05, 0x80, 0x8a, 0x80, 0xa2, 0x00, 0x80,
-    0xc6, 0x03, 0x00, 0x03, 0x01, 0x81, 0x41, 0xf6,
-    0x40, 0xbf, 0x19, 0x18, 0x88, 0x08, 0x80, 0x40,
-    0xfa, 0x86, 0x40, 0xce, 0x04, 0x80, 0xb0, 0xac,
-    0x00, 0x01, 0x01, 0x00, 0xab, 0x80, 0x8a, 0x85,
-    0x89, 0x8a, 0x00, 0xa2, 0x80, 0x89, 0x94, 0x8f,
-    0x80, 0xe4, 0x38, 0x89, 0x03, 0xa0, 0x00, 0x80,
-    0x9d, 0x9a, 0xda, 0x8a, 0xb9, 0x8a, 0x18, 0x08,
-    0x97, 0x97, 0xaa, 0x82, 0xab, 0x06, 0x0d, 0x87,
-    0xa8, 0xb9, 0xb6, 0x00, 0x03, 0x3b, 0x02, 0x86,
-    0x89, 0x81, 0x8c, 0x80, 0x8e, 0x80, 0xb9, 0x03,
-    0x1f, 0x80, 0x93, 0x81, 0x99, 0x01, 0x81, 0xb8,
-    0x03, 0x0b, 0x09, 0x12, 0x80, 0x9d, 0x0a, 0x80,
-    0x8a, 0x81, 0xb8, 0x03, 0x20, 0x0b, 0x80, 0x93,
-    0x81, 0x95, 0x28, 0x80, 0xb9, 0x01, 0x00, 0x1f,
-    0x06, 0x81, 0x8a, 0x81, 0x9d, 0x80, 0xbc, 0x80,
-    0x8b, 0x80, 0xb1, 0x02, 0x80, 0xb6, 0x00, 0x14,
-    0x10, 0x1e, 0x81, 0x8a, 0x81, 0x9c, 0x80, 0xb9,
-    0x01, 0x05, 0x04, 0x81, 0x93, 0x81, 0x9b, 0x81,
-    0xb8, 0x0b, 0x1f, 0x80, 0x93, 0x81, 0x9c, 0x80,
-    0xc7, 0x06, 0x10, 0x80, 0xd9, 0x01, 0x86, 0x8a,
-    0x88, 0xe1, 0x01, 0x88, 0x88, 0x00, 0x85, 0xc9,
-    0x81, 0x9a, 0x00, 0x00, 0x80, 0xb6, 0x8d, 0x04,
-    0x01, 0x84, 0x8a, 0x80, 0xa3, 0x88, 0x80, 0xe5,
-    0x18, 0x28, 0x09, 0x81, 0x98, 0x0b, 0x82, 0x8f,
-    0x83, 0x8c, 0x01, 0x0d, 0x80, 0x8e, 0x80, 0xdd,
-    0x80, 0x42, 0x5f, 0x82, 0x43, 0xb1, 0x82, 0x9c,
-    0x81, 0x9d, 0x81, 0x9d, 0x81, 0xbf, 0x08, 0x37,
-    0x01, 0x8a, 0x10, 0x20, 0xac, 0x84, 0xb2, 0x80,
-    0xc0, 0x81, 0xa1, 0x80, 0xf5, 0x13, 0x81, 0x88,
-    0x05, 0x82, 0x40, 0xda, 0x09, 0x80, 0xb9, 0x00,
-    0x30, 0x00, 0x01, 0x3d, 0x89, 0x08, 0xa6, 0x07,
-    0x9e, 0xb0, 0x83, 0xaf, 0x00, 0x20, 0x04, 0x80,
-    0xa7, 0x88, 0x8b, 0x81, 0x9f, 0x19, 0x08, 0x82,
-    0xb7, 0x00, 0x0a, 0x00, 0x82, 0xb9, 0x39, 0x81,
-    0xbf, 0x85, 0xd1, 0x10, 0x8c, 0x06, 0x18, 0x28,
-    0x11, 0xb1, 0xbe, 0x8c, 0x80, 0xa1, 0xe4, 0x41,
-    0xbc, 0x00, 0x82, 0x8a, 0x82, 0x8c, 0x82, 0x8c,
-    0x82, 0x8c, 0x81, 0x8b, 0x27, 0x81, 0x89, 0x01,
-    0x01, 0x84, 0xb0, 0x20, 0x89, 0x00, 0x8c, 0x80,
-    0x8f, 0x8c, 0xb2, 0xa0, 0x4b, 0x8a, 0x81, 0xf0,
-    0x82, 0xfc, 0x80, 0x8e, 0x80, 0xdf, 0x9f, 0xae,
-    0x80, 0x41, 0xd4, 0x80, 0xa3, 0x1a, 0x24, 0x80,
-    0xdc, 0x85, 0xdc, 0x82, 0x60, 0x6f, 0x15, 0x80,
-    0x44, 0xe1, 0x85, 0x41, 0x0d, 0x80, 0xe1, 0x18,
-    0x89, 0x00, 0x9b, 0x83, 0xcf, 0x81, 0x8d, 0xa1,
-    0xcd, 0x80, 0x96, 0x82, 0xe6, 0x12, 0x0f, 0x02,
-    0x03, 0x80, 0x98, 0x0c, 0x80, 0x40, 0x96, 0x81,
-    0x99, 0x91, 0x8c, 0x80, 0xa5, 0x87, 0x98, 0x8a,
-    0xad, 0x82, 0xaf, 0x01, 0x19, 0x81, 0x90, 0x80,
-    0x94, 0x81, 0xc1, 0x29, 0x09, 0x81, 0x8b, 0x07,
-    0x80, 0xa2, 0x80, 0x8a, 0x80, 0xb2, 0x00, 0x11,
-    0x0c, 0x08, 0x80, 0x9a, 0x80, 0x8d, 0x0c, 0x08,
-    0x80, 0xe3, 0x84, 0x88, 0x82, 0xf8, 0x01, 0x03,
-    0x80, 0x60, 0x4f, 0x2f, 0x80, 0x40, 0x92, 0x90,
-    0x42, 0x3c, 0x8f, 0x10, 0x8b, 0x8f, 0xa1, 0x01,
-    0x80, 0x40, 0xa8, 0x06, 0x05, 0x80, 0x8a, 0x80,
-    0xa2, 0x00, 0x80, 0xae, 0x80, 0xac, 0x81, 0xc2,
-    0x80, 0x94, 0x82, 0x42, 0x00, 0x80, 0x40, 0xe1,
-    0x80, 0x40, 0x94, 0x84, 0x44, 0x04, 0x28, 0xa9,
-    0x80, 0x88, 0x42, 0x45, 0x10, 0x0c, 0x83, 0xa7,
-    0x13, 0x80, 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x83,
-    0x41, 0x82, 0x81, 0x40, 0x98, 0x8a, 0xb0, 0x83,
-    0xfa, 0x80, 0xb5, 0x8e, 0xa8, 0x01, 0x81, 0x89,
-    0x82, 0xb0, 0x19, 0x09, 0x03, 0x80, 0x89, 0x80,
-    0xb1, 0x82, 0xa3, 0x20, 0x87, 0xbd, 0x80, 0x8b,
-    0x81, 0xb3, 0x88, 0x89, 0x19, 0x80, 0xde, 0x11,
-    0x00, 0x0d, 0x80, 0x40, 0x9f, 0x02, 0x87, 0x94,
-    0x81, 0xb8, 0x0a, 0x80, 0xa4, 0x32, 0x84, 0x40,
-    0xc2, 0x39, 0x10, 0x80, 0x96, 0x80, 0xd3, 0x28,
-    0x03, 0x08, 0x81, 0x40, 0xed, 0x1d, 0x08, 0x81,
-    0x9a, 0x81, 0xd4, 0x39, 0x00, 0x81, 0xe9, 0x00,
-    0x01, 0x28, 0x80, 0xe4, 0x11, 0x18, 0x84, 0x41,
-    0x02, 0x88, 0x01, 0x40, 0xff, 0x08, 0x03, 0x80,
-    0x40, 0x8f, 0x19, 0x0b, 0x80, 0x9f, 0x89, 0xa7,
-    0x29, 0x1f, 0x80, 0x88, 0x29, 0x82, 0xad, 0x8c,
-    0x01, 0x41, 0x95, 0x30, 0x28, 0x80, 0xd1, 0x95,
-    0x0e, 0x01, 0x01, 0xf9, 0x2a, 0x00, 0x08, 0x30,
-    0x80, 0xc7, 0x0a, 0x00, 0x80, 0x41, 0x5a, 0x81,
-    0x55, 0x3a, 0x88, 0x60, 0x36, 0xb6, 0x84, 0xba,
-    0x86, 0x88, 0x83, 0x44, 0x0a, 0x80, 0xbe, 0x90,
-    0xbf, 0x08, 0x81, 0x60, 0x40, 0x0a, 0x18, 0x30,
-    0x81, 0x4c, 0x9d, 0x08, 0x83, 0x52, 0x5b, 0xad,
-    0x81, 0x96, 0x42, 0x1f, 0x82, 0x88, 0x8f, 0x0e,
-    0x9d, 0x83, 0x40, 0x93, 0x82, 0x47, 0xba, 0xb6,
-    0x83, 0xb1, 0x38, 0x8d, 0x80, 0x95, 0x20, 0x8e,
-    0x45, 0x4f, 0x30, 0x90, 0x0e, 0x01, 0x04, 0x41,
-    0x04, 0x8d, 0x41, 0x6f, 0x80, 0xbc, 0x83, 0x45,
-    0xdf, 0x86, 0xec, 0x87, 0x4a, 0xae, 0x84, 0x6c,
-    0x0c, 0x00, 0x80, 0x9d, 0xdf, 0xff, 0x40, 0xef,
-};
-
-static const uint8_t unicode_prop_Case_Ignorable_index[69] = {
-    0xbe, 0x05, 0x00, 0xfe, 0x07, 0x00, 0x52, 0x0a,
-    0xa0, 0xc1, 0x0b, 0x00, 0x82, 0x0d, 0x00, 0x3f,
-    0x10, 0x80, 0xd4, 0x17, 0x40, 0xcf, 0x1a, 0x20,
-    0xf5, 0x1c, 0x00, 0x80, 0x20, 0x00, 0x16, 0xa0,
-    0x00, 0xc6, 0xa8, 0x00, 0xc2, 0xaa, 0x60, 0x56,
-    0xfe, 0x20, 0xb1, 0x07, 0x01, 0x82, 0x10, 0x21,
-    0x02, 0x13, 0x21, 0xb8, 0x16, 0x61, 0x97, 0x1a,
-    0x01, 0x37, 0x6b, 0x21, 0x8c, 0xd1, 0x01, 0xd7,
-    0xe8, 0x41, 0xf0, 0x01, 0x0e,
-};
-
-static const uint8_t unicode_prop_ID_Start_table[1079] = {
-    0xc0, 0x99, 0x85, 0x99, 0xae, 0x80, 0x89, 0x03,
-    0x04, 0x96, 0x80, 0x9e, 0x80, 0x41, 0xc9, 0x83,
-    0x8b, 0x8d, 0x26, 0x00, 0x80, 0x40, 0x80, 0x20,
-    0x09, 0x18, 0x05, 0x00, 0x10, 0x00, 0x93, 0x80,
-    0xd2, 0x80, 0x40, 0x8a, 0x87, 0x40, 0xa5, 0x80,
-    0xa5, 0x08, 0x85, 0xa8, 0xc6, 0x9a, 0x1b, 0xac,
-    0xaa, 0xa2, 0x08, 0xe2, 0x00, 0x8e, 0x0e, 0x81,
-    0x89, 0x11, 0x80, 0x8f, 0x00, 0x9d, 0x9c, 0xd8,
-    0x8a, 0x80, 0x97, 0xa0, 0x88, 0x0b, 0x04, 0x95,
-    0x18, 0x88, 0x02, 0x80, 0x96, 0x98, 0x86, 0x8a,
-    0x84, 0x97, 0x05, 0x90, 0xa9, 0xb9, 0xb5, 0x10,
-    0x91, 0x06, 0x89, 0x8e, 0x8f, 0x1f, 0x09, 0x81,
-    0x95, 0x06, 0x00, 0x13, 0x10, 0x8f, 0x80, 0x8c,
-    0x08, 0x82, 0x8d, 0x81, 0x89, 0x07, 0x2b, 0x09,
-    0x95, 0x06, 0x01, 0x01, 0x01, 0x9e, 0x18, 0x80,
-    0x92, 0x82, 0x8f, 0x88, 0x02, 0x80, 0x95, 0x06,
-    0x01, 0x04, 0x10, 0x91, 0x80, 0x8e, 0x81, 0x96,
-    0x80, 0x8a, 0x39, 0x09, 0x95, 0x06, 0x01, 0x04,
-    0x10, 0x9d, 0x08, 0x82, 0x8e, 0x80, 0x90, 0x00,
-    0x2a, 0x10, 0x1a, 0x08, 0x00, 0x0a, 0x0a, 0x12,
-    0x8b, 0x95, 0x80, 0xb3, 0x38, 0x10, 0x96, 0x80,
-    0x8f, 0x10, 0x99, 0x11, 0x01, 0x81, 0x9d, 0x03,
-    0x38, 0x10, 0x96, 0x80, 0x89, 0x04, 0x10, 0x9e,
-    0x08, 0x81, 0x8e, 0x81, 0x90, 0x88, 0x02, 0x80,
-    0xa8, 0x08, 0x8f, 0x04, 0x17, 0x82, 0x97, 0x2c,
-    0x91, 0x82, 0x97, 0x80, 0x88, 0x00, 0x0e, 0xb9,
-    0xaf, 0x01, 0x8b, 0x86, 0xb9, 0x08, 0x00, 0x20,
-    0x97, 0x00, 0x80, 0x89, 0x01, 0x88, 0x01, 0x20,
-    0x80, 0x94, 0x83, 0x9f, 0x80, 0xbe, 0x38, 0xa3,
-    0x9a, 0x84, 0xf2, 0xaa, 0x93, 0x80, 0x8f, 0x2b,
-    0x1a, 0x02, 0x0e, 0x13, 0x8c, 0x8b, 0x80, 0x90,
-    0xa5, 0x00, 0x20, 0x81, 0xaa, 0x80, 0x41, 0x4c,
-    0x03, 0x0e, 0x00, 0x03, 0x81, 0xa8, 0x03, 0x81,
-    0xa0, 0x03, 0x0e, 0x00, 0x03, 0x81, 0x8e, 0x80,
-    0xb8, 0x03, 0x81, 0xc2, 0xa4, 0x8f, 0x8f, 0xd5,
-    0x0d, 0x82, 0x42, 0x6b, 0x81, 0x90, 0x80, 0x99,
-    0x84, 0xca, 0x82, 0x8a, 0x86, 0x91, 0x8c, 0x92,
-    0x8d, 0x91, 0x8d, 0x8c, 0x02, 0x8e, 0xb3, 0xa2,
-    0x03, 0x80, 0xc2, 0xd8, 0x86, 0xa8, 0x00, 0x84,
-    0xc5, 0x89, 0x9e, 0xb0, 0x9d, 0x0c, 0x8a, 0xab,
-    0x83, 0x99, 0xb5, 0x96, 0x88, 0xb4, 0xd1, 0x80,
-    0xdc, 0xae, 0x90, 0x87, 0xb5, 0x9d, 0x8c, 0x81,
-    0x89, 0xab, 0x99, 0xa3, 0xa8, 0x82, 0x89, 0xa3,
-    0x81, 0x88, 0x86, 0xaa, 0x0a, 0xa8, 0x18, 0x28,
-    0x0a, 0x04, 0x40, 0xbf, 0xbf, 0x41, 0x15, 0x0d,
-    0x81, 0xa5, 0x0d, 0x0f, 0x00, 0x00, 0x00, 0x80,
-    0x9e, 0x81, 0xb4, 0x06, 0x00, 0x12, 0x06, 0x13,
-    0x0d, 0x83, 0x8c, 0x22, 0x06, 0xf3, 0x80, 0x8c,
-    0x80, 0x8f, 0x8c, 0xe4, 0x03, 0x01, 0x89, 0x00,
-    0x0d, 0x28, 0x00, 0x00, 0x80, 0x8f, 0x0b, 0x24,
-    0x18, 0x90, 0xa8, 0x4a, 0x76, 0x40, 0xe4, 0x2b,
-    0x11, 0x8b, 0xa5, 0x00, 0x20, 0x81, 0xb7, 0x30,
-    0x8f, 0x96, 0x88, 0x30, 0x30, 0x30, 0x30, 0x30,
-    0x30, 0x30, 0x86, 0x42, 0x25, 0x82, 0x98, 0x88,
-    0x34, 0x0c, 0x83, 0xd5, 0x1c, 0x80, 0xd9, 0x03,
-    0x84, 0xaa, 0x80, 0xdd, 0x90, 0x9f, 0xaf, 0x8f,
-    0x41, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x56, 0x8c,
-    0xc2, 0xad, 0x81, 0x41, 0x0c, 0x82, 0x8f, 0x89,
-    0x81, 0x93, 0xae, 0x8f, 0x9e, 0x81, 0xcf, 0xa6,
-    0x88, 0x81, 0xe6, 0x81, 0xbf, 0x21, 0x00, 0x04,
-    0x97, 0x8f, 0x02, 0x03, 0x80, 0x96, 0x9c, 0xb3,
-    0x8d, 0xb1, 0xbd, 0x2a, 0x00, 0x81, 0x8a, 0x9b,
-    0x89, 0x96, 0x98, 0x9c, 0x86, 0xae, 0x9b, 0x80,
-    0x8f, 0x20, 0x89, 0x89, 0x20, 0xa8, 0x96, 0x10,
-    0x87, 0x93, 0x96, 0x10, 0x82, 0xb1, 0x00, 0x11,
-    0x0c, 0x08, 0x00, 0x97, 0x11, 0x8a, 0x32, 0x8b,
-    0x29, 0x29, 0x85, 0x88, 0x30, 0x30, 0xaa, 0x80,
-    0x8d, 0x85, 0xf2, 0x9c, 0x60, 0x2b, 0xa3, 0x8b,
-    0x96, 0x83, 0xb0, 0x60, 0x21, 0x03, 0x41, 0x6d,
-    0x81, 0xe9, 0xa5, 0x86, 0x8b, 0x24, 0x00, 0x89,
-    0x80, 0x8c, 0x04, 0x00, 0x01, 0x01, 0x80, 0xeb,
-    0xa0, 0x41, 0x6a, 0x91, 0xbf, 0x81, 0xb5, 0xa7,
-    0x8b, 0xf3, 0x20, 0x40, 0x86, 0xa3, 0x99, 0x85,
-    0x99, 0x8a, 0xd8, 0x15, 0x0d, 0x0d, 0x0a, 0xa2,
-    0x8b, 0x80, 0x99, 0x80, 0x92, 0x01, 0x80, 0x8e,
-    0x81, 0x8d, 0xa1, 0xfa, 0xc4, 0xb4, 0x41, 0x0a,
-    0x9c, 0x82, 0xb0, 0xae, 0x9f, 0x8c, 0x9d, 0x84,
-    0xa5, 0x89, 0x9d, 0x81, 0xa3, 0x1f, 0x04, 0xa9,
-    0x40, 0x9d, 0x91, 0xa3, 0x83, 0xa3, 0x83, 0xa7,
-    0x87, 0xb3, 0x8b, 0x8a, 0x80, 0x8e, 0x06, 0x01,
-    0x80, 0x8a, 0x80, 0x8e, 0x06, 0x01, 0xc2, 0x41,
-    0x36, 0x88, 0x95, 0x89, 0x87, 0x97, 0x28, 0xa9,
-    0x80, 0x88, 0xc4, 0x29, 0x00, 0xab, 0x01, 0x10,
-    0x81, 0x96, 0x89, 0x96, 0x88, 0x9e, 0xc0, 0x92,
-    0x01, 0x89, 0x95, 0x89, 0x99, 0xc5, 0xb7, 0x29,
-    0xbf, 0x80, 0x8e, 0x18, 0x10, 0x9c, 0xa9, 0x9c,
-    0x82, 0x9c, 0xa2, 0x38, 0x9b, 0x9a, 0xb5, 0x89,
-    0x95, 0x89, 0x92, 0x8c, 0x91, 0xed, 0xc8, 0xb6,
-    0xb2, 0x8c, 0xb2, 0x8c, 0xa3, 0x41, 0x5b, 0xa9,
-    0x29, 0xcd, 0x9c, 0x89, 0x07, 0x95, 0xa9, 0x91,
-    0xad, 0x94, 0x9a, 0x96, 0x8b, 0xb4, 0xb8, 0x09,
-    0x80, 0x8c, 0xac, 0x9f, 0x98, 0x99, 0xa3, 0x9c,
-    0x01, 0x07, 0xa2, 0x10, 0x8b, 0xaf, 0x8d, 0x83,
-    0x94, 0x00, 0x80, 0xa2, 0x91, 0x80, 0x98, 0xd3,
-    0x30, 0x00, 0x18, 0x8e, 0x80, 0x89, 0x86, 0xae,
-    0xa5, 0x39, 0x09, 0x95, 0x06, 0x01, 0x04, 0x10,
-    0x91, 0x80, 0x8b, 0x84, 0x40, 0x9d, 0xb4, 0x91,
-    0x83, 0x93, 0x82, 0x9d, 0xaf, 0x93, 0x08, 0x80,
-    0x40, 0xb7, 0xae, 0xa8, 0x83, 0xa3, 0xaf, 0x93,
-    0x80, 0xba, 0xaa, 0x8c, 0x80, 0xc6, 0x9a, 0xa4,
-    0x86, 0x40, 0xb8, 0xab, 0xf3, 0xbf, 0x9e, 0x39,
-    0x01, 0x38, 0x08, 0x97, 0x8e, 0x00, 0x80, 0xdd,
-    0x39, 0xa6, 0x8f, 0x00, 0x80, 0x9b, 0x80, 0x89,
-    0xa7, 0x30, 0x94, 0x80, 0x8a, 0xad, 0x92, 0x80,
-    0x91, 0xc8, 0x41, 0x06, 0x88, 0x80, 0xa4, 0x90,
-    0x80, 0xb0, 0x9d, 0xef, 0x30, 0x08, 0xa5, 0x94,
-    0x80, 0x98, 0x28, 0x08, 0x9f, 0x8d, 0x80, 0x41,
-    0x46, 0x92, 0x40, 0xbc, 0x80, 0xce, 0x43, 0x99,
-    0xe5, 0xee, 0x90, 0x40, 0xc3, 0x4a, 0x4b, 0xe0,
-    0x8e, 0x44, 0x2e, 0x4f, 0xd0, 0x42, 0x46, 0x60,
-    0x21, 0xb8, 0x42, 0x38, 0x86, 0x9e, 0x90, 0xce,
-    0x90, 0x9d, 0x91, 0xaf, 0x8f, 0x83, 0x9e, 0x94,
-    0x84, 0x92, 0x42, 0xaf, 0xbf, 0xff, 0xca, 0x20,
-    0xc1, 0x8c, 0xbf, 0x08, 0x80, 0x9b, 0x57, 0xf7,
-    0x87, 0x44, 0xd5, 0xa9, 0x88, 0x60, 0x22, 0xe6,
-    0x18, 0x30, 0x08, 0x41, 0x22, 0xac, 0x82, 0x90,
-    0x1f, 0x41, 0x8b, 0x49, 0x03, 0xea, 0x84, 0x8c,
-    0x82, 0x88, 0x86, 0x89, 0x57, 0x65, 0xd4, 0x80,
-    0xc6, 0x01, 0x08, 0x09, 0x0b, 0x80, 0x8b, 0x00,
-    0x06, 0x80, 0xc0, 0x03, 0x0f, 0x06, 0x80, 0x9b,
-    0x03, 0x04, 0x00, 0x16, 0x80, 0x41, 0x53, 0x81,
-    0x98, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80,
-    0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80,
-    0x9e, 0x80, 0x98, 0x07, 0x47, 0x33, 0x9e, 0x41,
-    0xe0, 0xac, 0x89, 0x86, 0x8f, 0x80, 0x41, 0x40,
-    0x9d, 0x91, 0xab, 0x44, 0xf3, 0x30, 0x18, 0x08,
-    0x8e, 0x80, 0x40, 0xc4, 0xba, 0xc3, 0x30, 0x44,
-    0xb3, 0x18, 0x9a, 0x01, 0x00, 0x08, 0x80, 0x89,
-    0x03, 0x00, 0x00, 0x28, 0x18, 0x00, 0x00, 0x02,
-    0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01,
-    0x00, 0x0b, 0x06, 0x03, 0x03, 0x00, 0x80, 0x89,
-    0x80, 0x90, 0x22, 0x04, 0x80, 0x90, 0x51, 0x43,
-    0x60, 0xa6, 0xdf, 0x9f, 0x50, 0x38, 0x86, 0x40,
-    0xdd, 0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x4c,
-    0x1e, 0x42, 0x1d, 0x45, 0xe1, 0x53, 0x4a,
-};
-
-static const uint8_t unicode_prop_ID_Start_index[102] = {
-    0xf6, 0x03, 0x20, 0xa6, 0x07, 0x00, 0xa9, 0x09,
-    0x20, 0xb1, 0x0a, 0x00, 0xba, 0x0b, 0x20, 0x3b,
-    0x0d, 0x20, 0xc7, 0x0e, 0x20, 0x49, 0x12, 0x00,
-    0x9b, 0x16, 0x00, 0xac, 0x19, 0x00, 0xc0, 0x1d,
-    0x80, 0x80, 0x20, 0x20, 0x70, 0x2d, 0x00, 0x00,
-    0x32, 0x00, 0xda, 0xa7, 0x00, 0x4c, 0xaa, 0x20,
-    0xc7, 0xd7, 0x20, 0xfc, 0xfd, 0x20, 0x9d, 0x02,
-    0x21, 0x96, 0x05, 0x01, 0xf3, 0x08, 0x01, 0xb3,
-    0x0c, 0x21, 0x73, 0x11, 0x61, 0x3e, 0x13, 0x01,
-    0x47, 0x17, 0x21, 0x9e, 0x1a, 0x01, 0x9a, 0x23,
-    0x01, 0x78, 0x6b, 0x01, 0xfc, 0xb2, 0x61, 0x3a,
-    0xd5, 0x01, 0x2d, 0xe1, 0x41, 0x33, 0xee, 0x01,
-    0xe0, 0xa6, 0x62, 0x4b, 0x13, 0x03,
-};
-
-static const uint8_t unicode_prop_ID_Continue1_table[640] = {
-    0xaf, 0x89, 0xa4, 0x80, 0xd6, 0x80, 0x42, 0x47,
-    0xef, 0x96, 0x80, 0x40, 0xfa, 0x84, 0x41, 0x08,
-    0xac, 0x00, 0x01, 0x01, 0x00, 0xc7, 0x8a, 0xaf,
-    0x9e, 0x28, 0xe4, 0x31, 0x29, 0x08, 0x19, 0x89,
-    0x96, 0x80, 0x9d, 0x9a, 0xda, 0x8a, 0x8e, 0x89,
-    0xa0, 0x88, 0x88, 0x80, 0x97, 0x18, 0x88, 0x02,
-    0x04, 0xaa, 0x82, 0xbb, 0x87, 0xa9, 0x97, 0x80,
-    0xa0, 0xb5, 0x10, 0x91, 0x06, 0x89, 0x09, 0x89,
-    0x90, 0x82, 0xb7, 0x00, 0x31, 0x09, 0x82, 0x88,
-    0x80, 0x89, 0x09, 0x89, 0x8d, 0x01, 0x82, 0xb7,
-    0x00, 0x23, 0x09, 0x12, 0x80, 0x93, 0x8b, 0x10,
-    0x8a, 0x82, 0xb7, 0x00, 0x38, 0x10, 0x82, 0x93,
-    0x09, 0x89, 0x89, 0x28, 0x82, 0xb7, 0x00, 0x31,
-    0x09, 0x16, 0x82, 0x89, 0x09, 0x89, 0x91, 0x80,
-    0xba, 0x22, 0x10, 0x83, 0x88, 0x80, 0x8d, 0x89,
-    0x8f, 0x84, 0xb6, 0x00, 0x30, 0x10, 0x1e, 0x81,
-    0x8a, 0x09, 0x89, 0x90, 0x82, 0xb7, 0x00, 0x30,
-    0x10, 0x1e, 0x81, 0x8a, 0x09, 0x89, 0x8f, 0x83,
-    0xb6, 0x08, 0x30, 0x10, 0x83, 0x88, 0x80, 0x89,
-    0x09, 0x89, 0x90, 0x82, 0xc5, 0x03, 0x28, 0x00,
-    0x3d, 0x89, 0x09, 0xbc, 0x01, 0x86, 0x8b, 0x38,
-    0x89, 0xd6, 0x01, 0x88, 0x8a, 0x29, 0x89, 0xbd,
-    0x0d, 0x89, 0x8a, 0x00, 0x00, 0x03, 0x81, 0xb0,
-    0x93, 0x01, 0x84, 0x8a, 0x80, 0xa3, 0x88, 0x80,
-    0xe3, 0x93, 0x80, 0x89, 0x8b, 0x1b, 0x10, 0x11,
-    0x32, 0x83, 0x8c, 0x8b, 0x80, 0x8e, 0x42, 0xbe,
-    0x82, 0x88, 0x88, 0x43, 0x9f, 0x83, 0x9b, 0x82,
-    0x9c, 0x81, 0x9d, 0x81, 0xbf, 0x9f, 0x88, 0x01,
-    0x89, 0xa0, 0x10, 0x8a, 0x40, 0x8e, 0x80, 0xf5,
-    0x8b, 0x83, 0x8b, 0x89, 0x89, 0xff, 0x8a, 0xbb,
-    0x84, 0xb8, 0x89, 0x80, 0x9c, 0x81, 0x8a, 0x85,
-    0x89, 0x95, 0x8d, 0x80, 0x8f, 0xb0, 0x84, 0xae,
-    0x90, 0x8a, 0x89, 0x90, 0x88, 0x8b, 0x82, 0x9d,
-    0x8c, 0x81, 0x89, 0xab, 0x8d, 0xaf, 0x93, 0x87,
-    0x89, 0x85, 0x89, 0xf5, 0x10, 0x94, 0x18, 0x28,
-    0x0a, 0x40, 0xc5, 0xbf, 0x42, 0x3e, 0x81, 0x92,
-    0x80, 0xfa, 0x8c, 0x18, 0x82, 0x8b, 0x4b, 0xfd,
-    0x82, 0x40, 0x8c, 0x80, 0xdf, 0x9f, 0x42, 0x29,
-    0x85, 0xe8, 0x81, 0x60, 0x75, 0x84, 0x89, 0xc4,
-    0x03, 0x89, 0x9f, 0x81, 0xcf, 0x81, 0x41, 0x0f,
-    0x02, 0x03, 0x80, 0x96, 0x23, 0x80, 0xd2, 0x81,
-    0xb1, 0x91, 0x89, 0x89, 0x85, 0x91, 0x8c, 0x8a,
-    0x9b, 0x87, 0x98, 0x8c, 0xab, 0x83, 0xae, 0x8d,
-    0x8e, 0x89, 0x8a, 0x80, 0x89, 0x89, 0xae, 0x8d,
-    0x8b, 0x07, 0x09, 0x89, 0xa0, 0x82, 0xb1, 0x00,
-    0x11, 0x0c, 0x08, 0x80, 0xa8, 0x24, 0x81, 0x40,
-    0xeb, 0x38, 0x09, 0x89, 0x60, 0x4f, 0x23, 0x80,
-    0x42, 0xe0, 0x8f, 0x8f, 0x8f, 0x11, 0x97, 0x82,
-    0x40, 0xbf, 0x89, 0xa4, 0x80, 0x42, 0xbc, 0x80,
-    0x40, 0xe1, 0x80, 0x40, 0x94, 0x84, 0x41, 0x24,
-    0x89, 0x45, 0x56, 0x10, 0x0c, 0x83, 0xa7, 0x13,
-    0x80, 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x1f, 0x89,
-    0x41, 0x70, 0x81, 0x40, 0x98, 0x8a, 0xb0, 0x83,
-    0xf9, 0x82, 0xb4, 0x8e, 0x9e, 0x8a, 0x09, 0x89,
-    0x83, 0xac, 0x8a, 0x30, 0xac, 0x89, 0x2a, 0xa3,
-    0x8d, 0x80, 0x89, 0x21, 0xab, 0x80, 0x8b, 0x82,
-    0xaf, 0x8d, 0x3b, 0x80, 0x8b, 0xd1, 0x8b, 0x28,
-    0x40, 0x9f, 0x8b, 0x84, 0x89, 0x2b, 0xb6, 0x08,
-    0x31, 0x09, 0x82, 0x88, 0x80, 0x89, 0x09, 0x32,
-    0x84, 0x40, 0xbf, 0x91, 0x88, 0x89, 0x18, 0xd0,
-    0x93, 0x8b, 0x89, 0x40, 0xd4, 0x31, 0x88, 0x9a,
-    0x81, 0xd1, 0x90, 0x8e, 0x89, 0xd0, 0x8c, 0x87,
-    0x89, 0xd2, 0x8e, 0x83, 0x89, 0x40, 0xf1, 0x8e,
-    0x40, 0xa4, 0x89, 0xc5, 0x28, 0x09, 0x18, 0x00,
-    0x81, 0x8b, 0x89, 0xf6, 0x31, 0x32, 0x80, 0x9b,
-    0x89, 0xa7, 0x30, 0x1f, 0x80, 0x88, 0x8a, 0xad,
-    0x8f, 0x41, 0x94, 0x38, 0x87, 0x8f, 0x89, 0xb7,
-    0x95, 0x80, 0x8d, 0xf9, 0x2a, 0x00, 0x08, 0x30,
-    0x07, 0x89, 0xaf, 0x20, 0x08, 0x27, 0x89, 0x41,
-    0x48, 0x83, 0x60, 0x4b, 0x68, 0x89, 0xd5, 0x89,
-    0xa5, 0x84, 0xba, 0x86, 0x98, 0x89, 0x43, 0xf4,
-    0x00, 0xb6, 0x33, 0xd0, 0x80, 0x8a, 0x81, 0x60,
-    0x4c, 0xaa, 0x81, 0x52, 0x60, 0xad, 0x81, 0x96,
-    0x42, 0x1d, 0x22, 0x2f, 0x39, 0x86, 0x9d, 0x83,
-    0x40, 0x93, 0x82, 0x45, 0x88, 0xb1, 0x41, 0xff,
-    0xb6, 0x83, 0xb1, 0x38, 0x8d, 0x80, 0x95, 0x20,
-    0x8e, 0x45, 0x4f, 0x30, 0x90, 0x0e, 0x01, 0x04,
-    0x41, 0x04, 0x86, 0x88, 0x89, 0x41, 0x63, 0x80,
-    0xbc, 0x8d, 0x45, 0xd5, 0x86, 0xec, 0x34, 0x89,
-    0x52, 0x95, 0x89, 0x6c, 0x05, 0x05, 0x40, 0xef,
-};
-
-static const uint8_t unicode_prop_ID_Continue1_index[60] = {
-    0xfa, 0x06, 0x00, 0x70, 0x09, 0x00, 0xf0, 0x0a,
-    0x40, 0x57, 0x0c, 0x00, 0xf0, 0x0d, 0x40, 0xc7,
-    0x0f, 0x00, 0xea, 0x17, 0x20, 0x45, 0x1b, 0x20,
-    0x55, 0x20, 0x20, 0x0c, 0xa8, 0x60, 0x37, 0xaa,
-    0x00, 0x50, 0xfe, 0x00, 0x3a, 0x0d, 0x01, 0x83,
-    0x11, 0x01, 0xc4, 0x14, 0x21, 0x44, 0x19, 0x21,
-    0x5a, 0x1d, 0x41, 0x9f, 0xbc, 0x61, 0xb0, 0xda,
-    0x21, 0xf0, 0x01, 0x0e,
-};
-
-#ifdef CONFIG_ALL_UNICODE
-
-static const uint8_t unicode_cc_table[881] = {
-    0xb2, 0xcf, 0xd4, 0x00, 0xe8, 0x03, 0xdc, 0x00,
-    0xe8, 0x00, 0xd8, 0x04, 0xdc, 0x01, 0xca, 0x03,
-    0xdc, 0x01, 0xca, 0x0a, 0xdc, 0x04, 0x01, 0x03,
-    0xdc, 0xc7, 0x00, 0xf0, 0xc0, 0x02, 0xdc, 0xc2,
-    0x01, 0xdc, 0x80, 0xc2, 0x03, 0xdc, 0xc0, 0x00,
-    0xe8, 0x01, 0xdc, 0xc0, 0x41, 0xe9, 0x00, 0xea,
-    0x41, 0xe9, 0x00, 0xea, 0x00, 0xe9, 0xcc, 0xb0,
-    0xe2, 0xc4, 0xb0, 0xd8, 0x00, 0xdc, 0xc3, 0x00,
-    0xdc, 0xc2, 0x00, 0xde, 0x00, 0xdc, 0xc5, 0x05,
-    0xdc, 0xc1, 0x00, 0xdc, 0xc1, 0x00, 0xde, 0x00,
-    0xe4, 0xc0, 0x49, 0x0a, 0x43, 0x13, 0x80, 0x00,
-    0x17, 0x80, 0x41, 0x18, 0x80, 0xc0, 0x00, 0xdc,
-    0x80, 0x00, 0x12, 0xb0, 0x17, 0xc7, 0x42, 0x1e,
-    0xaf, 0x47, 0x1b, 0xc1, 0x01, 0xdc, 0xc4, 0x00,
-    0xdc, 0xc1, 0x00, 0xdc, 0x8f, 0x00, 0x23, 0xb0,
-    0x34, 0xc6, 0x81, 0xc3, 0x00, 0xdc, 0xc0, 0x81,
-    0xc1, 0x80, 0x00, 0xdc, 0xc1, 0x00, 0xdc, 0xa2,
-    0x00, 0x24, 0x9d, 0xc0, 0x00, 0xdc, 0xc1, 0x00,
-    0xdc, 0xc1, 0x02, 0xdc, 0xc0, 0x01, 0xdc, 0xc0,
-    0x00, 0xdc, 0xc2, 0x00, 0xdc, 0xc0, 0x00, 0xdc,
-    0xc0, 0x00, 0xdc, 0xc0, 0x00, 0xdc, 0xc1, 0xb0,
-    0x6f, 0xc6, 0x00, 0xdc, 0xc0, 0x88, 0x00, 0xdc,
-    0x97, 0xc3, 0x80, 0xc8, 0x80, 0xc2, 0x80, 0xc4,
-    0xaa, 0x02, 0xdc, 0xb0, 0x0b, 0xc0, 0x02, 0xdc,
-    0xc3, 0xa9, 0xc4, 0x04, 0xdc, 0xcd, 0x80, 0x00,
-    0xdc, 0xc1, 0x00, 0xdc, 0xc1, 0x00, 0xdc, 0xc2,
-    0x02, 0xdc, 0x42, 0x1b, 0xc2, 0x00, 0xdc, 0xc1,
-    0x01, 0xdc, 0xc4, 0xb0, 0x0b, 0x00, 0x07, 0x8f,
-    0x00, 0x09, 0x82, 0xc0, 0x00, 0xdc, 0xc1, 0xb0,
-    0x36, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xaf, 0xc0,
-    0xb0, 0x0c, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0,
-    0x3d, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0, 0x3d,
-    0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0, 0x4e, 0x00,
-    0x09, 0xb0, 0x3d, 0x00, 0x07, 0x8f, 0x00, 0x09,
-    0x86, 0x00, 0x54, 0x00, 0x5b, 0xb0, 0x34, 0x00,
-    0x07, 0x8f, 0x00, 0x09, 0xb0, 0x3c, 0x01, 0x09,
-    0x8f, 0x00, 0x09, 0xb0, 0x4b, 0x00, 0x09, 0xb0,
-    0x3c, 0x01, 0x67, 0x00, 0x09, 0x8c, 0x03, 0x6b,
-    0xb0, 0x3b, 0x01, 0x76, 0x00, 0x09, 0x8c, 0x03,
-    0x7a, 0xb0, 0x1b, 0x01, 0xdc, 0x9a, 0x00, 0xdc,
-    0x80, 0x00, 0xdc, 0x80, 0x00, 0xd8, 0xb0, 0x06,
-    0x41, 0x81, 0x80, 0x00, 0x84, 0x84, 0x03, 0x82,
-    0x81, 0x00, 0x82, 0x80, 0xc1, 0x00, 0x09, 0x80,
-    0xc1, 0xb0, 0x0d, 0x00, 0xdc, 0xb0, 0x3f, 0x00,
-    0x07, 0x80, 0x01, 0x09, 0xb0, 0x21, 0x00, 0xdc,
-    0xb2, 0x9e, 0xc2, 0xb3, 0x83, 0x01, 0x09, 0x9d,
-    0x00, 0x09, 0xb0, 0x6c, 0x00, 0x09, 0x89, 0xc0,
-    0xb0, 0x9a, 0x00, 0xe4, 0xb0, 0x5e, 0x00, 0xde,
-    0xc0, 0x00, 0xdc, 0xb0, 0xaa, 0xc0, 0x00, 0xdc,
-    0xb0, 0x16, 0x00, 0x09, 0x93, 0xc7, 0x81, 0x00,
-    0xdc, 0xaf, 0xc4, 0x05, 0xdc, 0xc1, 0x00, 0xdc,
-    0x80, 0x01, 0xdc, 0xc1, 0x01, 0xdc, 0xc4, 0x00,
-    0xdc, 0xc3, 0xb0, 0x34, 0x00, 0x07, 0x8e, 0x00,
-    0x09, 0xa5, 0xc0, 0x00, 0xdc, 0xc6, 0xb0, 0x05,
-    0x01, 0x09, 0xb0, 0x09, 0x00, 0x07, 0x8a, 0x01,
-    0x09, 0xb0, 0x12, 0x00, 0x07, 0xb0, 0x67, 0xc2,
-    0x41, 0x00, 0x04, 0xdc, 0xc1, 0x03, 0xdc, 0xc0,
-    0x41, 0x00, 0x05, 0x01, 0x83, 0x00, 0xdc, 0x85,
-    0xc0, 0x82, 0xc1, 0xb0, 0x95, 0xc1, 0x00, 0xdc,
-    0xc6, 0x00, 0xdc, 0xc1, 0x00, 0xea, 0x00, 0xd6,
-    0x00, 0xdc, 0x00, 0xca, 0xe4, 0x00, 0xe8, 0x01,
-    0xe4, 0x00, 0xdc, 0x00, 0xda, 0xc0, 0x00, 0xe9,
-    0x00, 0xdc, 0xc0, 0x00, 0xdc, 0xb2, 0x9f, 0xc1,
-    0x01, 0x01, 0xc3, 0x02, 0x01, 0xc1, 0x83, 0xc0,
-    0x82, 0x01, 0x01, 0xc0, 0x00, 0xdc, 0xc0, 0x01,
-    0x01, 0x03, 0xdc, 0xc0, 0xb8, 0x03, 0xcd, 0xc2,
-    0xb0, 0x5c, 0x00, 0x09, 0xb0, 0x2f, 0xdf, 0xb1,
-    0xf9, 0x00, 0xda, 0x00, 0xe4, 0x00, 0xe8, 0x00,
-    0xde, 0x01, 0xe0, 0xb0, 0x38, 0x01, 0x08, 0xb8,
-    0x6d, 0xa3, 0xc0, 0x83, 0xc9, 0x9f, 0xc1, 0xb0,
-    0x1f, 0xc1, 0xb0, 0xe3, 0x00, 0x09, 0xa4, 0x00,
-    0x09, 0xb0, 0x66, 0x00, 0x09, 0x9a, 0xd1, 0xb0,
-    0x08, 0x02, 0xdc, 0xa4, 0x00, 0x09, 0xb0, 0x2e,
-    0x00, 0x07, 0x8b, 0x00, 0x09, 0xb0, 0xbe, 0xc0,
-    0x80, 0xc1, 0x00, 0xdc, 0x81, 0xc1, 0x84, 0xc1,
-    0x80, 0xc0, 0xb0, 0x03, 0x00, 0x09, 0xb0, 0xc5,
-    0x00, 0x09, 0xb8, 0x46, 0xff, 0x00, 0x1a, 0xb2,
-    0xd0, 0xc6, 0x06, 0xdc, 0xc1, 0xb3, 0x9c, 0x00,
-    0xdc, 0xb0, 0xb1, 0x00, 0xdc, 0xb0, 0x64, 0xc4,
-    0xb6, 0x61, 0x00, 0xdc, 0x80, 0xc0, 0xa7, 0xc0,
-    0x00, 0x01, 0x00, 0xdc, 0x83, 0x00, 0x09, 0xb0,
-    0x74, 0xc0, 0x00, 0xdc, 0xb2, 0x0c, 0xc3, 0xb1,
-    0x52, 0xc1, 0xb0, 0x68, 0x01, 0xdc, 0xc2, 0x00,
-    0xdc, 0xc0, 0x03, 0xdc, 0xb0, 0x00, 0xc0, 0x00,
-    0xdc, 0xc0, 0x00, 0xdc, 0xb0, 0x8f, 0x00, 0x09,
-    0xa8, 0x00, 0x09, 0x8d, 0x00, 0x09, 0xb0, 0x08,
-    0x00, 0x09, 0x00, 0x07, 0xb0, 0x14, 0xc2, 0xaf,
-    0x01, 0x09, 0xb0, 0x0d, 0x00, 0x07, 0xb0, 0x1b,
-    0x00, 0x09, 0x88, 0x00, 0x07, 0xb0, 0x39, 0x00,
-    0x09, 0x00, 0x07, 0xb0, 0x81, 0x00, 0x07, 0x00,
-    0x09, 0xb0, 0x1f, 0x01, 0x07, 0x8f, 0x00, 0x09,
-    0x97, 0xc6, 0x82, 0xc4, 0xb0, 0x9c, 0x00, 0x09,
-    0x82, 0x00, 0x07, 0x96, 0xc0, 0xb0, 0x32, 0x00,
-    0x09, 0x00, 0x07, 0xb0, 0xca, 0x00, 0x09, 0x00,
-    0x07, 0xb0, 0x4d, 0x00, 0x09, 0xb0, 0x45, 0x00,
-    0x09, 0x00, 0x07, 0xb0, 0x42, 0x00, 0x09, 0xb0,
-    0xdc, 0x00, 0x09, 0x00, 0x07, 0xb0, 0xd1, 0x01,
-    0x09, 0x83, 0x00, 0x07, 0xb0, 0x6b, 0x00, 0x09,
-    0xb0, 0x22, 0x00, 0x09, 0x91, 0x00, 0x09, 0xb0,
-    0x20, 0x00, 0x09, 0xb1, 0x74, 0x00, 0x09, 0xb0,
-    0xd1, 0x00, 0x07, 0x80, 0x01, 0x09, 0xb0, 0x20,
-    0x00, 0x09, 0xb8, 0x45, 0x27, 0x04, 0x01, 0xb0,
-    0x0a, 0xc6, 0xb4, 0x88, 0x01, 0x06, 0xb8, 0x44,
-    0x7b, 0x00, 0x01, 0xb8, 0x0c, 0x95, 0x01, 0xd8,
-    0x02, 0x01, 0x82, 0x00, 0xe2, 0x04, 0xd8, 0x87,
-    0x07, 0xdc, 0x81, 0xc4, 0x01, 0xdc, 0x9d, 0xc3,
-    0xb0, 0x63, 0xc2, 0xb8, 0x05, 0x8a, 0xc6, 0x80,
-    0xd0, 0x81, 0xc6, 0x80, 0xc1, 0x80, 0xc4, 0xb0,
-    0xd4, 0xc6, 0xb1, 0x46, 0xc0, 0xb0, 0x0c, 0xc3,
-    0xb5, 0xaf, 0x06, 0xdc, 0xb0, 0x3c, 0xc5, 0x00,
-    0x07,
-};
-
-static const uint8_t unicode_cc_index[84] = {
-    0x4d, 0x03, 0x00, 0x97, 0x05, 0x20, 0xc6, 0x05,
-    0x00, 0xe7, 0x06, 0x00, 0x45, 0x07, 0x00, 0x9c,
-    0x08, 0x00, 0x4d, 0x09, 0x00, 0x3c, 0x0b, 0x00,
-    0x3d, 0x0d, 0x00, 0x36, 0x0f, 0x00, 0x38, 0x10,
-    0x20, 0x3a, 0x19, 0x00, 0xcb, 0x1a, 0x20, 0xd3,
-    0x1c, 0x00, 0xcf, 0x1d, 0x00, 0xe2, 0x20, 0x00,
-    0x2e, 0x30, 0x20, 0x2b, 0xa9, 0x20, 0xed, 0xab,
-    0x00, 0x39, 0x0a, 0x01, 0x84, 0x0f, 0x21, 0xc0,
-    0x11, 0x01, 0x43, 0x14, 0x01, 0x39, 0x18, 0x21,
-    0x42, 0x1d, 0x21, 0x67, 0xd1, 0x01, 0x30, 0xe1,
-    0x21, 0x4b, 0xe9, 0x01,
-};
-
-static const uint32_t unicode_decomp_table1[693] = {
-    0x00280081, 0x002a0097, 0x002a8081, 0x002bc097,
-    0x002c8115, 0x002d0097, 0x002d4081, 0x002e0097,
-    0x002e4115, 0x002f0199, 0x00302016, 0x00400842,
-    0x00448a42, 0x004a0442, 0x004c0096, 0x004c8117,
-    0x004d0242, 0x004e4342, 0x004fc12f, 0x0050c342,
-    0x005240bf, 0x00530342, 0x00550942, 0x005a0842,
-    0x005e0096, 0x005e4342, 0x005fc081, 0x00680142,
-    0x006bc142, 0x00710185, 0x0071c317, 0x00734844,
-    0x00778344, 0x00798342, 0x007b02be, 0x007c4197,
-    0x007d0142, 0x007e0444, 0x00800e42, 0x00878142,
-    0x00898744, 0x00ac0483, 0x00b60317, 0x00b80283,
-    0x00d00214, 0x00d10096, 0x00dd0080, 0x00de8097,
-    0x00df8080, 0x00e10097, 0x00e1413e, 0x00e1c080,
-    0x00e204be, 0x00ea83ae, 0x00f282ae, 0x00f401ad,
-    0x00f4c12e, 0x00f54103, 0x00fc0303, 0x00fe4081,
-    0x0100023e, 0x0101c0be, 0x010301be, 0x010640be,
-    0x010e40be, 0x0114023e, 0x0115c0be, 0x011701be,
-    0x011d8144, 0x01304144, 0x01340244, 0x01358144,
-    0x01368344, 0x01388344, 0x013a8644, 0x013e0144,
-    0x0161c085, 0x018882ae, 0x019d422f, 0x01b00184,
-    0x01b4c084, 0x024a4084, 0x024c4084, 0x024d0084,
-    0x0256042e, 0x0272c12e, 0x02770120, 0x0277c084,
-    0x028cc084, 0x028d8084, 0x029641ae, 0x02978084,
-    0x02d20084, 0x02d2c12e, 0x02d70120, 0x02e50084,
-    0x02f281ae, 0x03120084, 0x03300084, 0x0331c122,
-    0x0332812e, 0x035281ae, 0x03768084, 0x037701ae,
-    0x038cc085, 0x03acc085, 0x03b7012f, 0x03c30081,
-    0x03d0c084, 0x03d34084, 0x03d48084, 0x03d5c084,
-    0x03d70084, 0x03da4084, 0x03dcc084, 0x03dd412e,
-    0x03ddc085, 0x03de0084, 0x03de4085, 0x03e04084,
-    0x03e4c084, 0x03e74084, 0x03e88084, 0x03e9c084,
-    0x03eb0084, 0x03ee4084, 0x04098084, 0x043f0081,
-    0x06c18484, 0x06c48084, 0x06cec184, 0x06d00120,
-    0x06d0c084, 0x074b0383, 0x074cc41f, 0x074f1783,
-    0x075e0081, 0x0766d283, 0x07801d44, 0x078e8942,
-    0x07931844, 0x079f0d42, 0x07a58216, 0x07a68085,
-    0x07a6c0be, 0x07a80d44, 0x07aea044, 0x07c00122,
-    0x07c08344, 0x07c20122, 0x07c28344, 0x07c40122,
-    0x07c48244, 0x07c60122, 0x07c68244, 0x07c8113e,
-    0x07d08244, 0x07d20122, 0x07d28244, 0x07d40122,
-    0x07d48344, 0x07d64c3e, 0x07dc4080, 0x07dc80be,
-    0x07dcc080, 0x07dd00be, 0x07dd4080, 0x07dd80be,
-    0x07ddc080, 0x07de00be, 0x07de4080, 0x07de80be,
-    0x07dec080, 0x07df00be, 0x07df4080, 0x07e00820,
-    0x07e40820, 0x07e80820, 0x07ec05be, 0x07eec080,
-    0x07ef00be, 0x07ef4097, 0x07ef8080, 0x07efc117,
-    0x07f0443e, 0x07f24080, 0x07f280be, 0x07f2c080,
-    0x07f303be, 0x07f4c080, 0x07f582ae, 0x07f6c080,
-    0x07f7433e, 0x07f8c080, 0x07f903ae, 0x07fac080,
-    0x07fb013e, 0x07fb8102, 0x07fc83be, 0x07fe4080,
-    0x07fe80be, 0x07fec080, 0x07ff00be, 0x07ff4080,
-    0x07ff8097, 0x0800011e, 0x08008495, 0x08044081,
-    0x0805c097, 0x08090081, 0x08094097, 0x08098099,
-    0x080bc081, 0x080cc085, 0x080d00b1, 0x080d8085,
-    0x080dc0b1, 0x080f0197, 0x0811c197, 0x0815c0b3,
-    0x0817c081, 0x081c0595, 0x081ec081, 0x081f0215,
-    0x0820051f, 0x08228583, 0x08254415, 0x082a0097,
-    0x08400119, 0x08408081, 0x0840c0bf, 0x08414119,
-    0x0841c081, 0x084240bf, 0x0842852d, 0x08454081,
-    0x08458097, 0x08464295, 0x08480097, 0x08484099,
-    0x08488097, 0x08490081, 0x08498080, 0x084a0081,
-    0x084a8102, 0x084b0495, 0x084d421f, 0x084e4081,
-    0x084ec099, 0x084f0283, 0x08514295, 0x08540119,
-    0x0854809b, 0x0854c619, 0x0857c097, 0x08580081,
-    0x08584097, 0x08588099, 0x0858c097, 0x08590081,
-    0x08594097, 0x08598099, 0x0859c09b, 0x085a0097,
-    0x085a4081, 0x085a8097, 0x085ac099, 0x085b0295,
-    0x085c4097, 0x085c8099, 0x085cc097, 0x085d0081,
-    0x085d4097, 0x085d8099, 0x085dc09b, 0x085e0097,
-    0x085e4081, 0x085e8097, 0x085ec099, 0x085f0215,
-    0x08624099, 0x0866813e, 0x086b80be, 0x087341be,
-    0x088100be, 0x088240be, 0x088300be, 0x088901be,
-    0x088b0085, 0x088b40b1, 0x088bc085, 0x088c00b1,
-    0x089040be, 0x089100be, 0x0891c1be, 0x089801be,
-    0x089b42be, 0x089d0144, 0x089e0144, 0x08a00144,
-    0x08a10144, 0x08a20144, 0x08ab023e, 0x08b80244,
-    0x08ba8220, 0x08ca411e, 0x0918049f, 0x091a4523,
-    0x091cc097, 0x091d04a5, 0x091f452b, 0x0921c09b,
-    0x092204a1, 0x09244525, 0x0926c099, 0x09270d25,
-    0x092d8d1f, 0x09340d1f, 0x093a8081, 0x0a8300b3,
-    0x0a9d0099, 0x0a9d4097, 0x0a9d8099, 0x0ab700be,
-    0x0b1f0115, 0x0b5bc081, 0x0ba7c081, 0x0bbcc081,
-    0x0bc004ad, 0x0bc244ad, 0x0bc484ad, 0x0bc6f383,
-    0x0be0852d, 0x0be31d03, 0x0bf1882d, 0x0c000081,
-    0x0c0d8283, 0x0c130b84, 0x0c194284, 0x0c1c0122,
-    0x0c1cc122, 0x0c1d8122, 0x0c1e4122, 0x0c1f0122,
-    0x0c250084, 0x0c26c123, 0x0c278084, 0x0c27c085,
-    0x0c2b0b84, 0x0c314284, 0x0c340122, 0x0c34c122,
-    0x0c358122, 0x0c364122, 0x0c370122, 0x0c3d0084,
-    0x0c3dc220, 0x0c3f8084, 0x0c3fc085, 0x0c4c4a2d,
-    0x0c51451f, 0x0c53ca9f, 0x0c5915ad, 0x0c648703,
-    0x0c800741, 0x0c838089, 0x0c83c129, 0x0c8441a9,
-    0x0c850089, 0x0c854129, 0x0c85c2a9, 0x0c870089,
-    0x0c87408f, 0x0c87808d, 0x0c881241, 0x0c910203,
-    0x0c940099, 0x0c9444a3, 0x0c968323, 0x0c98072d,
-    0x0c9b84af, 0x0c9dc2a1, 0x0c9f00b5, 0x0c9f40b3,
-    0x0c9f8085, 0x0ca01883, 0x0cac4223, 0x0cad4523,
-    0x0cafc097, 0x0cb004a1, 0x0cb241a5, 0x0cb30097,
-    0x0cb34099, 0x0cb38097, 0x0cb3c099, 0x0cb417ad,
-    0x0cbfc085, 0x0cc001b3, 0x0cc0c0b1, 0x0cc100b3,
-    0x0cc14131, 0x0cc1c0b5, 0x0cc200b3, 0x0cc241b1,
-    0x0cc30133, 0x0cc38131, 0x0cc40085, 0x0cc440b1,
-    0x0cc48133, 0x0cc50085, 0x0cc540b5, 0x0cc580b7,
-    0x0cc5c0b5, 0x0cc600b1, 0x0cc64135, 0x0cc6c0b3,
-    0x0cc701b1, 0x0cc7c0b3, 0x0cc800b5, 0x0cc840b3,
-    0x0cc881b1, 0x0cc9422f, 0x0cca4131, 0x0ccac0b5,
-    0x0ccb00b1, 0x0ccb40b3, 0x0ccb80b5, 0x0ccbc0b1,
-    0x0ccc012f, 0x0ccc80b5, 0x0cccc0b3, 0x0ccd00b5,
-    0x0ccd40b1, 0x0ccd80b5, 0x0ccdc085, 0x0cce02b1,
-    0x0ccf40b3, 0x0ccf80b1, 0x0ccfc085, 0x0cd001b1,
-    0x0cd0c0b3, 0x0cd101b1, 0x0cd1c0b5, 0x0cd200b3,
-    0x0cd24085, 0x0cd280b5, 0x0cd2c085, 0x0cd30133,
-    0x0cd381b1, 0x0cd440b3, 0x0cd48085, 0x0cd4c0b1,
-    0x0cd500b3, 0x0cd54085, 0x0cd580b5, 0x0cd5c0b1,
-    0x0cd60521, 0x0cd88525, 0x0cdb02a5, 0x0cdc4099,
-    0x0cdc8117, 0x0cdd0099, 0x0cdd4197, 0x0cde0127,
-    0x0cde8285, 0x0cdfc089, 0x0ce0043f, 0x0ce20099,
-    0x0ce2409b, 0x0ce283bf, 0x0ce44219, 0x0ce54205,
-    0x0ce6433f, 0x0ce7c131, 0x0ce84085, 0x0ce881b1,
-    0x0ce94085, 0x0ce98107, 0x0cea0089, 0x0cea4097,
-    0x0cea8219, 0x0ceb809d, 0x0cebc08d, 0x0cec083f,
-    0x0cf00105, 0x0cf0809b, 0x0cf0c197, 0x0cf1809b,
-    0x0cf1c099, 0x0cf20517, 0x0cf48099, 0x0cf4c117,
-    0x0cf54119, 0x0cf5c097, 0x0cf6009b, 0x0cf64099,
-    0x0cf68217, 0x0cf78119, 0x0cf804a1, 0x0cfa4525,
-    0x0cfcc525, 0x0cff4125, 0x0cffc099, 0x29a70103,
-    0x29dc0081, 0x29fc8195, 0x29fe0103, 0x2ad70203,
-    0x2ada4081, 0x3e401482, 0x3e4a7f82, 0x3e6a3f82,
-    0x3e8aa102, 0x3e9b0110, 0x3e9c2f82, 0x3eb3c590,
-    0x3ec00197, 0x3ec0c119, 0x3ec1413f, 0x3ec4c2af,
-    0x3ec74184, 0x3ec804ad, 0x3eca4081, 0x3eca8304,
-    0x3ecc03a0, 0x3ece02a0, 0x3ecf8084, 0x3ed00120,
-    0x3ed0c120, 0x3ed184ae, 0x3ed3c085, 0x3ed4312d,
-    0x3ef4cbad, 0x3efa892f, 0x3eff022d, 0x3f002f2f,
-    0x3f1782a5, 0x3f18c0b1, 0x3f1907af, 0x3f1cffaf,
-    0x3f3c81a5, 0x3f3d64af, 0x3f542031, 0x3f649b31,
-    0x3f7c0131, 0x3f7c83b3, 0x3f7e40b1, 0x3f7e80bd,
-    0x3f7ec0bb, 0x3f7f00b3, 0x3f840503, 0x3f8c01ad,
-    0x3f8cc315, 0x3f8e462d, 0x3f91cc03, 0x3f97c695,
-    0x3f9c01af, 0x3f9d0085, 0x3f9d852f, 0x3fa03aad,
-    0x3fbd442f, 0x3fc06f1f, 0x3fd7c11f, 0x3fd85fad,
-    0x3fe80081, 0x3fe84f1f, 0x3ff0831f, 0x3ff2831f,
-    0x3ff4831f, 0x3ff6819f, 0x3ff80783, 0x41e04d83,
-    0x41e70f91, 0x44268192, 0x442ac092, 0x444b8112,
-    0x44d2c112, 0x452ec212, 0x456e8112, 0x464e0092,
-    0x74578392, 0x746ec312, 0x75000d1f, 0x75068d1f,
-    0x750d0d1f, 0x7513839f, 0x7515891f, 0x751a0d1f,
-    0x75208d1f, 0x75271015, 0x752f439f, 0x7531459f,
-    0x75340d1f, 0x753a8d1f, 0x75410395, 0x7543441f,
-    0x7545839f, 0x75478d1f, 0x754e0795, 0x7552839f,
-    0x75548d1f, 0x755b0d1f, 0x75618d1f, 0x75680d1f,
-    0x756e8d1f, 0x75750d1f, 0x757b8d1f, 0x75820d1f,
-    0x75888d1f, 0x758f0d1f, 0x75958d1f, 0x759c0d1f,
-    0x75a28d1f, 0x75a90103, 0x75aa089f, 0x75ae4081,
-    0x75ae839f, 0x75b04081, 0x75b08c9f, 0x75b6c081,
-    0x75b7032d, 0x75b8889f, 0x75bcc081, 0x75bd039f,
-    0x75bec081, 0x75bf0c9f, 0x75c54081, 0x75c5832d,
-    0x75c7089f, 0x75cb4081, 0x75cb839f, 0x75cd4081,
-    0x75cd8c9f, 0x75d3c081, 0x75d4032d, 0x75d5889f,
-    0x75d9c081, 0x75da039f, 0x75dbc081, 0x75dc0c9f,
-    0x75e24081, 0x75e2832d, 0x75e4089f, 0x75e84081,
-    0x75e8839f, 0x75ea4081, 0x75ea8c9f, 0x75f0c081,
-    0x75f1042d, 0x75f3851f, 0x75f6051f, 0x75f8851f,
-    0x75fb051f, 0x75fd851f, 0x7b80022d, 0x7b814dad,
-    0x7b884203, 0x7b89c081, 0x7b8a452d, 0x7b8d0403,
-    0x7b908081, 0x7b91dc03, 0x7ba0052d, 0x7ba2c8ad,
-    0x7ba84483, 0x7baac8ad, 0x7c400097, 0x7c404521,
-    0x7c440d25, 0x7c4a8087, 0x7c4ac115, 0x7c4b4117,
-    0x7c4c0d1f, 0x7c528217, 0x7c538099, 0x7c53c097,
-    0x7c5a8197, 0x7c640097, 0x7c80012f, 0x7c808081,
-    0x7c841603, 0x7c9004c1, 0x7c940103, 0x7efc051f,
-    0xbe0001ac, 0xbe00d110, 0xbe0947ac, 0xbe0d3910,
-    0xbe29872c, 0xbe2d022c, 0xbe2e3790, 0xbe49ff90,
-    0xbe69bc10,
-};
-
-static const uint16_t unicode_decomp_table2[693] = {
-    0x0020, 0x0000, 0x0061, 0x0002, 0x0004, 0x0006, 0x03bc, 0x0008,
-    0x000a, 0x000c, 0x0015, 0x0095, 0x00a5, 0x00b9, 0x00c1, 0x00c3,
-    0x00c7, 0x00cb, 0x00d1, 0x00d7, 0x00dd, 0x00e0, 0x00e6, 0x00f8,
-    0x0108, 0x010a, 0x0073, 0x0110, 0x0112, 0x0114, 0x0120, 0x012c,
-    0x0144, 0x014d, 0x0153, 0x0162, 0x0168, 0x016a, 0x0176, 0x0192,
-    0x0194, 0x01a9, 0x01bb, 0x01c7, 0x01d1, 0x01d5, 0x02b9, 0x01d7,
-    0x003b, 0x01d9, 0x01db, 0x00b7, 0x01e1, 0x01fc, 0x020c, 0x0218,
-    0x021d, 0x0223, 0x0227, 0x03a3, 0x0233, 0x023f, 0x0242, 0x024b,
-    0x024e, 0x0251, 0x025d, 0x0260, 0x0269, 0x026c, 0x026f, 0x0275,
-    0x0278, 0x0281, 0x028a, 0x029c, 0x029f, 0x02a3, 0x02af, 0x02b9,
-    0x02c5, 0x02c9, 0x02cd, 0x02d1, 0x02d5, 0x02e7, 0x02ed, 0x02f1,
-    0x02f5, 0x02f9, 0x02fd, 0x0305, 0x0309, 0x030d, 0x0313, 0x0317,
-    0x031b, 0x0323, 0x0327, 0x032b, 0x032f, 0x0335, 0x033d, 0x0341,
-    0x0349, 0x034d, 0x0351, 0x0f0b, 0x0357, 0x035b, 0x035f, 0x0363,
-    0x0367, 0x036b, 0x036f, 0x0373, 0x0379, 0x037d, 0x0381, 0x0385,
-    0x0389, 0x038d, 0x0391, 0x0395, 0x0399, 0x039d, 0x03a1, 0x10dc,
-    0x03a5, 0x03c9, 0x03cd, 0x03d9, 0x03dd, 0x03e1, 0x03ef, 0x03f1,
-    0x043d, 0x044f, 0x0499, 0x04f0, 0x0502, 0x054a, 0x0564, 0x056c,
-    0x0570, 0x0573, 0x059a, 0x05fa, 0x05fe, 0x0607, 0x060b, 0x0614,
-    0x0618, 0x061e, 0x0622, 0x0628, 0x068e, 0x0694, 0x0698, 0x069e,
-    0x06a2, 0x06ab, 0x03ac, 0x06f3, 0x03ad, 0x06f6, 0x03ae, 0x06f9,
-    0x03af, 0x06fc, 0x03cc, 0x06ff, 0x03cd, 0x0702, 0x03ce, 0x0705,
-    0x0709, 0x070d, 0x0711, 0x0386, 0x0732, 0x0735, 0x03b9, 0x0737,
-    0x073b, 0x0388, 0x0753, 0x0389, 0x0756, 0x0390, 0x076b, 0x038a,
-    0x0777, 0x03b0, 0x0789, 0x038e, 0x0799, 0x079f, 0x07a3, 0x038c,
-    0x07b8, 0x038f, 0x07bb, 0x00b4, 0x07be, 0x07c0, 0x07c2, 0x2010,
-    0x07cb, 0x002e, 0x07cd, 0x07cf, 0x0020, 0x07d2, 0x07d6, 0x07db,
-    0x07df, 0x07e4, 0x07ea, 0x07f0, 0x0020, 0x07f6, 0x2212, 0x0801,
-    0x0805, 0x0807, 0x081d, 0x0825, 0x0827, 0x0043, 0x082d, 0x0830,
-    0x0190, 0x0836, 0x0839, 0x004e, 0x0845, 0x0847, 0x084c, 0x084e,
-    0x0851, 0x005a, 0x03a9, 0x005a, 0x0853, 0x0857, 0x0860, 0x0069,
-    0x0862, 0x0865, 0x086f, 0x0874, 0x087a, 0x087e, 0x08a2, 0x0049,
-    0x08a4, 0x08a6, 0x08a9, 0x0056, 0x08ab, 0x08ad, 0x08b0, 0x08b4,
-    0x0058, 0x08b6, 0x08b8, 0x08bb, 0x08c0, 0x08c2, 0x08c5, 0x0076,
-    0x08c7, 0x08c9, 0x08cc, 0x08d0, 0x0078, 0x08d2, 0x08d4, 0x08d7,
-    0x08db, 0x08de, 0x08e4, 0x08e7, 0x08f0, 0x08f3, 0x08f6, 0x08f9,
-    0x0902, 0x0906, 0x090b, 0x090f, 0x0914, 0x0917, 0x091a, 0x0923,
-    0x092c, 0x093b, 0x093e, 0x0941, 0x0944, 0x0947, 0x094a, 0x0956,
-    0x095c, 0x0960, 0x0962, 0x0964, 0x0968, 0x096a, 0x0970, 0x0978,
-    0x097c, 0x0980, 0x0986, 0x0989, 0x098f, 0x0991, 0x0030, 0x0993,
-    0x0999, 0x099c, 0x099e, 0x09a1, 0x09a4, 0x2d61, 0x6bcd, 0x9f9f,
-    0x09a6, 0x09b1, 0x09bc, 0x09c7, 0x0a95, 0x0aa1, 0x0b15, 0x0020,
-    0x0b27, 0x0b31, 0x0b8d, 0x0ba1, 0x0ba5, 0x0ba9, 0x0bad, 0x0bb1,
-    0x0bb5, 0x0bb9, 0x0bbd, 0x0bc1, 0x0bc5, 0x0c21, 0x0c35, 0x0c39,
-    0x0c3d, 0x0c41, 0x0c45, 0x0c49, 0x0c4d, 0x0c51, 0x0c55, 0x0c59,
-    0x0c6f, 0x0c71, 0x0c73, 0x0ca0, 0x0cbc, 0x0cdc, 0x0ce4, 0x0cec,
-    0x0cf4, 0x0cfc, 0x0d04, 0x0d0c, 0x0d14, 0x0d22, 0x0d2e, 0x0d7a,
-    0x0d82, 0x0d85, 0x0d89, 0x0d8d, 0x0d9d, 0x0db1, 0x0db5, 0x0dbc,
-    0x0dc2, 0x0dc6, 0x0e28, 0x0e2c, 0x0e30, 0x0e32, 0x0e36, 0x0e3c,
-    0x0e3e, 0x0e41, 0x0e43, 0x0e46, 0x0e77, 0x0e7b, 0x0e89, 0x0e8e,
-    0x0e94, 0x0e9c, 0x0ea3, 0x0ea9, 0x0eb4, 0x0ebe, 0x0ec6, 0x0eca,
-    0x0ecf, 0x0ed9, 0x0edd, 0x0ee4, 0x0eec, 0x0ef3, 0x0ef8, 0x0f04,
-    0x0f0a, 0x0f15, 0x0f1b, 0x0f22, 0x0f28, 0x0f33, 0x0f3d, 0x0f45,
-    0x0f4c, 0x0f51, 0x0f57, 0x0f5e, 0x0f63, 0x0f69, 0x0f70, 0x0f76,
-    0x0f7d, 0x0f82, 0x0f89, 0x0f8d, 0x0f9e, 0x0fa4, 0x0fa9, 0x0fad,
-    0x0fb8, 0x0fbe, 0x0fc9, 0x0fd0, 0x0fd6, 0x0fda, 0x0fe1, 0x0fe5,
-    0x0fef, 0x0ffa, 0x1000, 0x1004, 0x1009, 0x100f, 0x1013, 0x101a,
-    0x101f, 0x1023, 0x1029, 0x102f, 0x1032, 0x1036, 0x1039, 0x103f,
-    0x1045, 0x1059, 0x1061, 0x1079, 0x107c, 0x1080, 0x1095, 0x10a1,
-    0x10b1, 0x10c3, 0x10cb, 0x10cf, 0x10da, 0x10de, 0x10ea, 0x10f2,
-    0x10f4, 0x1100, 0x1105, 0x1111, 0x1141, 0x1149, 0x114d, 0x1153,
-    0x1157, 0x115a, 0x116e, 0x1171, 0x1175, 0x117b, 0x117d, 0x1181,
-    0x1184, 0x118c, 0x1192, 0x1196, 0x119c, 0x11a2, 0x11a8, 0x11ab,
-    0xa76f, 0x11af, 0x11b2, 0x11b6, 0x028d, 0x11be, 0x1210, 0x130e,
-    0x140c, 0x1490, 0x1495, 0x1553, 0x156c, 0x1572, 0x1578, 0x157e,
-    0x158a, 0x1596, 0x002b, 0x15a1, 0x15b9, 0x15bd, 0x15c1, 0x15c5,
-    0x15c9, 0x15cd, 0x15e1, 0x15e5, 0x1649, 0x1662, 0x1688, 0x168e,
-    0x174c, 0x1752, 0x1757, 0x1777, 0x1877, 0x187d, 0x1911, 0x19d3,
-    0x1a77, 0x1a7f, 0x1a9d, 0x1aa2, 0x1ab6, 0x1ac0, 0x1ac6, 0x1ada,
-    0x1adf, 0x1ae5, 0x1af3, 0x1b23, 0x1b30, 0x1b38, 0x1b3c, 0x1b52,
-    0x1bc9, 0x1bdb, 0x1bdd, 0x1bdf, 0x3164, 0x1c20, 0x1c22, 0x1c24,
-    0x1c26, 0x1c28, 0x1c2a, 0x1c48, 0x1c7e, 0x1cc4, 0x1cd2, 0x1cd7,
-    0x1ce0, 0x1ce9, 0x1cfb, 0x1d04, 0x1d09, 0x1d29, 0x1d44, 0x1d46,
-    0x1d48, 0x1d4a, 0x1d4c, 0x1d4e, 0x1d50, 0x1d52, 0x1d72, 0x1d74,
-    0x1d76, 0x1d78, 0x1d7a, 0x1d81, 0x1d83, 0x1d85, 0x1d87, 0x1d96,
-    0x1d98, 0x1d9a, 0x1d9c, 0x1d9e, 0x1da0, 0x1da2, 0x1da4, 0x1da6,
-    0x1da8, 0x1daa, 0x1dac, 0x1dae, 0x1db0, 0x1db2, 0x1db6, 0x03f4,
-    0x1db8, 0x2207, 0x1dba, 0x2202, 0x1dbc, 0x1dc4, 0x03f4, 0x1dc6,
-    0x2207, 0x1dc8, 0x2202, 0x1dca, 0x1dd2, 0x03f4, 0x1dd4, 0x2207,
-    0x1dd6, 0x2202, 0x1dd8, 0x1de0, 0x03f4, 0x1de2, 0x2207, 0x1de4,
-    0x2202, 0x1de6, 0x1dee, 0x03f4, 0x1df0, 0x2207, 0x1df2, 0x2202,
-    0x1df4, 0x1dfe, 0x1e00, 0x1e02, 0x1e04, 0x1e06, 0x1e08, 0x1e0e,
-    0x1e2b, 0x062d, 0x1e33, 0x1e3f, 0x062c, 0x1e4f, 0x1ebf, 0x1ecb,
-    0x1ede, 0x1ef0, 0x1f03, 0x1f05, 0x1f09, 0x1f0f, 0x1f15, 0x1f17,
-    0x1f1b, 0x1f1d, 0x1f25, 0x1f28, 0x1f2a, 0x1f30, 0x1f32, 0x30b5,
-    0x1f38, 0x1f90, 0x1fa6, 0x1faa, 0x1fac, 0x1fb1, 0x1ffe, 0x200f,
-    0x2110, 0x2120, 0x2126, 0x2220, 0x233e,
-};
-
-static const uint8_t unicode_decomp_data[9292] = {
-    0x20, 0x88, 0x20, 0x84, 0x32, 0x33, 0x20, 0x81,
-    0x20, 0xa7, 0x31, 0x6f, 0x31, 0xd0, 0x34, 0x31,
-    0xd0, 0x32, 0x33, 0xd0, 0x34, 0x41, 0x80, 0x41,
-    0x81, 0x41, 0x82, 0x41, 0x83, 0x41, 0x88, 0x41,
-    0x8a, 0x00, 0x00, 0x43, 0xa7, 0x45, 0x80, 0x45,
-    0x81, 0x45, 0x82, 0x45, 0x88, 0x49, 0x80, 0x49,
-    0x81, 0x49, 0x82, 0x49, 0x88, 0x00, 0x00, 0x4e,
-    0x83, 0x4f, 0x80, 0x4f, 0x81, 0x4f, 0x82, 0x4f,
-    0x83, 0x4f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x55,
-    0x80, 0x55, 0x81, 0x55, 0x82, 0x55, 0x88, 0x59,
-    0x81, 0x00, 0x00, 0x00, 0x00, 0x61, 0x80, 0x61,
-    0x81, 0x61, 0x82, 0x61, 0x83, 0x61, 0x88, 0x61,
-    0x8a, 0x00, 0x00, 0x63, 0xa7, 0x65, 0x80, 0x65,
-    0x81, 0x65, 0x82, 0x65, 0x88, 0x69, 0x80, 0x69,
-    0x81, 0x69, 0x82, 0x69, 0x88, 0x00, 0x00, 0x6e,
-    0x83, 0x6f, 0x80, 0x6f, 0x81, 0x6f, 0x82, 0x6f,
-    0x83, 0x6f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x75,
-    0x80, 0x75, 0x81, 0x75, 0x82, 0x75, 0x88, 0x79,
-    0x81, 0x00, 0x00, 0x79, 0x88, 0x41, 0x84, 0x41,
-    0x86, 0x41, 0xa8, 0x43, 0x81, 0x43, 0x82, 0x43,
-    0x87, 0x43, 0x8c, 0x44, 0x8c, 0x45, 0x84, 0x45,
-    0x86, 0x45, 0x87, 0x45, 0xa8, 0x45, 0x8c, 0x47,
-    0x82, 0x47, 0x86, 0x47, 0x87, 0x47, 0xa7, 0x48,
-    0x82, 0x49, 0x83, 0x49, 0x84, 0x49, 0x86, 0x49,
-    0xa8, 0x49, 0x87, 0x49, 0x4a, 0x69, 0x6a, 0x4a,
-    0x82, 0x4b, 0xa7, 0x4c, 0x81, 0x4c, 0xa7, 0x4c,
-    0x8c, 0x4c, 0x00, 0x00, 0x6b, 0x20, 0x6b, 0x4e,
-    0x81, 0x4e, 0xa7, 0x4e, 0x8c, 0xbc, 0x02, 0x6e,
-    0x4f, 0x84, 0x4f, 0x86, 0x4f, 0x8b, 0x52, 0x81,
-    0x52, 0xa7, 0x52, 0x8c, 0x53, 0x81, 0x53, 0x82,
-    0x53, 0xa7, 0x53, 0x8c, 0x54, 0xa7, 0x54, 0x8c,
-    0x55, 0x83, 0x55, 0x84, 0x55, 0x86, 0x55, 0x8a,
-    0x55, 0x8b, 0x55, 0xa8, 0x57, 0x82, 0x59, 0x82,
-    0x59, 0x88, 0x5a, 0x81, 0x5a, 0x87, 0x5a, 0x8c,
-    0x4f, 0x9b, 0x55, 0x9b, 0x44, 0x00, 0x7d, 0x01,
-    0x44, 0x00, 0x7e, 0x01, 0x64, 0x00, 0x7e, 0x01,
-    0x4c, 0x4a, 0x4c, 0x6a, 0x6c, 0x6a, 0x4e, 0x4a,
-    0x4e, 0x6a, 0x6e, 0x6a, 0x41, 0x00, 0x8c, 0x49,
-    0x00, 0x8c, 0x4f, 0x00, 0x8c, 0x55, 0x00, 0x8c,
-    0xdc, 0x00, 0x84, 0xdc, 0x00, 0x81, 0xdc, 0x00,
-    0x8c, 0xdc, 0x00, 0x80, 0xc4, 0x00, 0x84, 0x26,
-    0x02, 0x84, 0xc6, 0x00, 0x84, 0x47, 0x8c, 0x4b,
-    0x8c, 0x4f, 0xa8, 0xea, 0x01, 0x84, 0xeb, 0x01,
-    0x84, 0xb7, 0x01, 0x8c, 0x92, 0x02, 0x8c, 0x6a,
-    0x00, 0x8c, 0x44, 0x5a, 0x44, 0x7a, 0x64, 0x7a,
-    0x47, 0x81, 0x4e, 0x00, 0x80, 0xc5, 0x00, 0x81,
-    0xc6, 0x00, 0x81, 0xd8, 0x00, 0x81, 0x41, 0x8f,
-    0x41, 0x91, 0x45, 0x8f, 0x45, 0x91, 0x49, 0x8f,
-    0x49, 0x91, 0x4f, 0x8f, 0x4f, 0x91, 0x52, 0x8f,
-    0x52, 0x91, 0x55, 0x8f, 0x55, 0x91, 0x53, 0xa6,
-    0x54, 0xa6, 0x48, 0x8c, 0x41, 0x00, 0x87, 0x45,
-    0x00, 0xa7, 0xd6, 0x00, 0x84, 0xd5, 0x00, 0x84,
-    0x4f, 0x00, 0x87, 0x2e, 0x02, 0x84, 0x59, 0x00,
-    0x84, 0x68, 0x00, 0x66, 0x02, 0x6a, 0x00, 0x72,
-    0x00, 0x79, 0x02, 0x7b, 0x02, 0x81, 0x02, 0x77,
-    0x00, 0x79, 0x00, 0x20, 0x86, 0x20, 0x87, 0x20,
-    0x8a, 0x20, 0xa8, 0x20, 0x83, 0x20, 0x8b, 0x63,
-    0x02, 0x6c, 0x00, 0x73, 0x00, 0x78, 0x00, 0x95,
-    0x02, 0x80, 0x81, 0x00, 0x93, 0x88, 0x81, 0x20,
-    0xc5, 0x20, 0x81, 0xa8, 0x00, 0x81, 0x91, 0x03,
-    0x81, 0x95, 0x03, 0x81, 0x97, 0x03, 0x81, 0x99,
-    0x03, 0x81, 0x00, 0x00, 0x00, 0x9f, 0x03, 0x81,
-    0x00, 0x00, 0x00, 0xa5, 0x03, 0x81, 0xa9, 0x03,
-    0x81, 0xca, 0x03, 0x81, 0x01, 0x03, 0x98, 0x07,
-    0xa4, 0x07, 0xb0, 0x00, 0xb4, 0x00, 0xb6, 0x00,
-    0xb8, 0x00, 0xca, 0x00, 0x01, 0x03, 0xb8, 0x07,
-    0xc4, 0x07, 0xbe, 0x00, 0xc4, 0x00, 0xc8, 0x00,
-    0xa5, 0x03, 0x0d, 0x13, 0x00, 0x01, 0x03, 0xd1,
-    0x00, 0xd1, 0x07, 0xc6, 0x03, 0xc0, 0x03, 0xba,
-    0x03, 0xc1, 0x03, 0xc2, 0x03, 0x00, 0x00, 0x98,
-    0x03, 0xb5, 0x03, 0x15, 0x04, 0x80, 0x15, 0x04,
-    0x88, 0x00, 0x00, 0x00, 0x13, 0x04, 0x81, 0x06,
-    0x04, 0x88, 0x1a, 0x04, 0x81, 0x18, 0x04, 0x80,
-    0x23, 0x04, 0x86, 0x18, 0x04, 0x86, 0x38, 0x04,
-    0x86, 0x35, 0x04, 0x80, 0x35, 0x04, 0x88, 0x00,
-    0x00, 0x00, 0x33, 0x04, 0x81, 0x56, 0x04, 0x88,
-    0x3a, 0x04, 0x81, 0x38, 0x04, 0x80, 0x43, 0x04,
-    0x86, 0x74, 0x04, 0x8f, 0x16, 0x04, 0x86, 0x10,
-    0x04, 0x86, 0x10, 0x04, 0x88, 0x15, 0x04, 0x86,
-    0xd8, 0x04, 0x88, 0x16, 0x04, 0x88, 0x17, 0x04,
-    0x88, 0x18, 0x04, 0x84, 0x18, 0x04, 0x88, 0x1e,
-    0x04, 0x88, 0xe8, 0x04, 0x88, 0x2d, 0x04, 0x88,
-    0x23, 0x04, 0x84, 0x23, 0x04, 0x88, 0x23, 0x04,
-    0x8b, 0x27, 0x04, 0x88, 0x2b, 0x04, 0x88, 0x65,
-    0x05, 0x82, 0x05, 0x27, 0x06, 0x00, 0x2c, 0x00,
-    0x2d, 0x21, 0x2d, 0x00, 0x2e, 0x23, 0x2d, 0x27,
-    0x06, 0x00, 0x4d, 0x21, 0x4d, 0xa0, 0x4d, 0x23,
-    0x4d, 0xd5, 0x06, 0x54, 0x06, 0x00, 0x00, 0x00,
-    0x00, 0xc1, 0x06, 0x54, 0x06, 0xd2, 0x06, 0x54,
-    0x06, 0x28, 0x09, 0x3c, 0x09, 0x30, 0x09, 0x3c,
-    0x09, 0x33, 0x09, 0x3c, 0x09, 0x15, 0x09, 0x00,
-    0x27, 0x01, 0x27, 0x02, 0x27, 0x07, 0x27, 0x0c,
-    0x27, 0x0d, 0x27, 0x16, 0x27, 0x1a, 0x27, 0xbe,
-    0x09, 0x09, 0x00, 0x09, 0x19, 0xa1, 0x09, 0xbc,
-    0x09, 0xaf, 0x09, 0xbc, 0x09, 0x32, 0x0a, 0x3c,
-    0x0a, 0x38, 0x0a, 0x3c, 0x0a, 0x16, 0x0a, 0x00,
-    0x26, 0x01, 0x26, 0x06, 0x26, 0x2b, 0x0a, 0x3c,
-    0x0a, 0x47, 0x0b, 0x56, 0x0b, 0x3e, 0x0b, 0x09,
-    0x00, 0x09, 0x19, 0x21, 0x0b, 0x3c, 0x0b, 0x92,
-    0x0b, 0xd7, 0x0b, 0xbe, 0x0b, 0x08, 0x00, 0x09,
-    0x00, 0x08, 0x19, 0x46, 0x0c, 0x56, 0x0c, 0xbf,
-    0x0c, 0xd5, 0x0c, 0xc6, 0x0c, 0xd5, 0x0c, 0xc2,
-    0x0c, 0x04, 0x00, 0x08, 0x13, 0x3e, 0x0d, 0x08,
-    0x00, 0x09, 0x00, 0x08, 0x19, 0xd9, 0x0d, 0xca,
-    0x0d, 0xca, 0x0d, 0x0f, 0x05, 0x12, 0x00, 0x0f,
-    0x15, 0x4d, 0x0e, 0x32, 0x0e, 0xcd, 0x0e, 0xb2,
-    0x0e, 0x99, 0x0e, 0x12, 0x00, 0x12, 0x08, 0x42,
-    0x0f, 0xb7, 0x0f, 0x4c, 0x0f, 0xb7, 0x0f, 0x51,
-    0x0f, 0xb7, 0x0f, 0x56, 0x0f, 0xb7, 0x0f, 0x5b,
-    0x0f, 0xb7, 0x0f, 0x40, 0x0f, 0xb5, 0x0f, 0x71,
-    0x0f, 0x72, 0x0f, 0x71, 0x0f, 0x00, 0x03, 0x41,
-    0x0f, 0xb2, 0x0f, 0x81, 0x0f, 0xb3, 0x0f, 0x80,
-    0x0f, 0xb3, 0x0f, 0x81, 0x0f, 0x71, 0x0f, 0x80,
-    0x0f, 0x92, 0x0f, 0xb7, 0x0f, 0x9c, 0x0f, 0xb7,
-    0x0f, 0xa1, 0x0f, 0xb7, 0x0f, 0xa6, 0x0f, 0xb7,
-    0x0f, 0xab, 0x0f, 0xb7, 0x0f, 0x90, 0x0f, 0xb5,
-    0x0f, 0x25, 0x10, 0x2e, 0x10, 0x05, 0x1b, 0x35,
-    0x1b, 0x00, 0x00, 0x00, 0x00, 0x07, 0x1b, 0x35,
-    0x1b, 0x00, 0x00, 0x00, 0x00, 0x09, 0x1b, 0x35,
-    0x1b, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x1b, 0x35,
-    0x1b, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x1b, 0x35,
-    0x1b, 0x11, 0x1b, 0x35, 0x1b, 0x3a, 0x1b, 0x35,
-    0x1b, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1b, 0x35,
-    0x1b, 0x3e, 0x1b, 0x35, 0x1b, 0x42, 0x1b, 0x35,
-    0x1b, 0x41, 0x00, 0xc6, 0x00, 0x42, 0x00, 0x00,
-    0x00, 0x44, 0x00, 0x45, 0x00, 0x8e, 0x01, 0x47,
-    0x00, 0x4f, 0x00, 0x22, 0x02, 0x50, 0x00, 0x52,
-    0x00, 0x54, 0x00, 0x55, 0x00, 0x57, 0x00, 0x61,
-    0x00, 0x50, 0x02, 0x51, 0x02, 0x02, 0x1d, 0x62,
-    0x00, 0x64, 0x00, 0x65, 0x00, 0x59, 0x02, 0x5b,
-    0x02, 0x5c, 0x02, 0x67, 0x00, 0x00, 0x00, 0x6b,
-    0x00, 0x6d, 0x00, 0x4b, 0x01, 0x6f, 0x00, 0x54,
-    0x02, 0x16, 0x1d, 0x17, 0x1d, 0x70, 0x00, 0x74,
-    0x00, 0x75, 0x00, 0x1d, 0x1d, 0x6f, 0x02, 0x76,
-    0x00, 0x25, 0x1d, 0xb2, 0x03, 0xb3, 0x03, 0xb4,
-    0x03, 0xc6, 0x03, 0xc7, 0x03, 0x69, 0x00, 0x72,
-    0x00, 0x75, 0x00, 0x76, 0x00, 0xb2, 0x03, 0xb3,
-    0x03, 0xc1, 0x03, 0xc6, 0x03, 0xc7, 0x03, 0x52,
-    0x02, 0x63, 0x00, 0x55, 0x02, 0xf0, 0x00, 0x5c,
-    0x02, 0x66, 0x00, 0x5f, 0x02, 0x61, 0x02, 0x65,
-    0x02, 0x68, 0x02, 0x69, 0x02, 0x6a, 0x02, 0x7b,
-    0x1d, 0x9d, 0x02, 0x6d, 0x02, 0x85, 0x1d, 0x9f,
-    0x02, 0x71, 0x02, 0x70, 0x02, 0x72, 0x02, 0x73,
-    0x02, 0x74, 0x02, 0x75, 0x02, 0x78, 0x02, 0x82,
-    0x02, 0x83, 0x02, 0xab, 0x01, 0x89, 0x02, 0x8a,
-    0x02, 0x1c, 0x1d, 0x8b, 0x02, 0x8c, 0x02, 0x7a,
-    0x00, 0x90, 0x02, 0x91, 0x02, 0x92, 0x02, 0xb8,
-    0x03, 0x41, 0x00, 0xa5, 0x42, 0x00, 0x87, 0x42,
-    0x00, 0xa3, 0x42, 0x00, 0xb1, 0xc7, 0x00, 0x81,
-    0x44, 0x00, 0x87, 0x44, 0x00, 0xa3, 0x44, 0x00,
-    0xb1, 0x44, 0x00, 0xa7, 0x44, 0x00, 0xad, 0x12,
-    0x01, 0x80, 0x12, 0x01, 0x81, 0x45, 0x00, 0xad,
-    0x45, 0x00, 0xb0, 0x28, 0x02, 0x86, 0x46, 0x00,
-    0x87, 0x47, 0x00, 0x84, 0x48, 0x00, 0x87, 0x48,
-    0x00, 0xa3, 0x48, 0x00, 0x88, 0x48, 0x00, 0xa7,
-    0x48, 0x00, 0xae, 0x49, 0x00, 0xb0, 0xcf, 0x00,
-    0x81, 0x4b, 0x00, 0x81, 0x4b, 0x00, 0xa3, 0x4b,
-    0x00, 0xb1, 0x4c, 0x00, 0xa3, 0x36, 0x1e, 0x84,
-    0x4c, 0xb1, 0x4c, 0xad, 0x4d, 0x81, 0x4d, 0x87,
-    0x4d, 0xa3, 0x4e, 0x87, 0x4e, 0xa3, 0x4e, 0xb1,
-    0x4e, 0xad, 0xd5, 0x00, 0x81, 0xd5, 0x00, 0x88,
-    0x4c, 0x01, 0x80, 0x4c, 0x01, 0x81, 0x50, 0x00,
-    0x81, 0x50, 0x00, 0x87, 0x52, 0x00, 0x87, 0x52,
-    0x00, 0xa3, 0x5a, 0x1e, 0x84, 0x52, 0x00, 0xb1,
-    0x53, 0x00, 0x87, 0x53, 0x00, 0xa3, 0x5a, 0x01,
-    0x87, 0x60, 0x01, 0x87, 0x62, 0x1e, 0x87, 0x54,
-    0x00, 0x87, 0x54, 0x00, 0xa3, 0x54, 0x00, 0xb1,
-    0x54, 0x00, 0xad, 0x55, 0x00, 0xa4, 0x55, 0x00,
-    0xb0, 0x55, 0x00, 0xad, 0x68, 0x01, 0x81, 0x6a,
-    0x01, 0x88, 0x56, 0x83, 0x56, 0xa3, 0x57, 0x80,
-    0x57, 0x81, 0x57, 0x88, 0x57, 0x87, 0x57, 0xa3,
-    0x58, 0x87, 0x58, 0x88, 0x59, 0x87, 0x5a, 0x82,
-    0x5a, 0xa3, 0x5a, 0xb1, 0x68, 0xb1, 0x74, 0x88,
-    0x77, 0x8a, 0x79, 0x8a, 0x61, 0x00, 0xbe, 0x02,
-    0x7f, 0x01, 0x87, 0x41, 0x00, 0xa3, 0x41, 0x00,
-    0x89, 0xc2, 0x00, 0x81, 0xc2, 0x00, 0x80, 0xc2,
-    0x00, 0x89, 0xc2, 0x00, 0x83, 0xa0, 0x1e, 0x82,
-    0x02, 0x01, 0x81, 0x02, 0x01, 0x80, 0x02, 0x01,
-    0x89, 0x02, 0x01, 0x83, 0xa0, 0x1e, 0x86, 0x45,
-    0x00, 0xa3, 0x45, 0x00, 0x89, 0x45, 0x00, 0x83,
-    0xca, 0x00, 0x81, 0xca, 0x00, 0x80, 0xca, 0x00,
-    0x89, 0xca, 0x00, 0x83, 0xb8, 0x1e, 0x82, 0x49,
-    0x00, 0x89, 0x49, 0x00, 0xa3, 0x4f, 0x00, 0xa3,
-    0x4f, 0x00, 0x89, 0xd4, 0x00, 0x81, 0xd4, 0x00,
-    0x80, 0xd4, 0x00, 0x89, 0xd4, 0x00, 0x83, 0xcc,
-    0x1e, 0x82, 0xa0, 0x01, 0x81, 0xa0, 0x01, 0x80,
-    0xa0, 0x01, 0x89, 0xa0, 0x01, 0x83, 0xa0, 0x01,
-    0xa3, 0x55, 0x00, 0xa3, 0x55, 0x00, 0x89, 0xaf,
-    0x01, 0x81, 0xaf, 0x01, 0x80, 0xaf, 0x01, 0x89,
-    0xaf, 0x01, 0x83, 0xaf, 0x01, 0xa3, 0x59, 0x00,
-    0x80, 0x59, 0x00, 0xa3, 0x59, 0x00, 0x89, 0x59,
-    0x00, 0x83, 0xb1, 0x03, 0x13, 0x03, 0x00, 0x1f,
-    0x80, 0x00, 0x1f, 0x81, 0x00, 0x1f, 0xc2, 0x91,
-    0x03, 0x13, 0x03, 0x08, 0x1f, 0x80, 0x08, 0x1f,
-    0x81, 0x08, 0x1f, 0xc2, 0xb5, 0x03, 0x13, 0x03,
-    0x10, 0x1f, 0x80, 0x10, 0x1f, 0x81, 0x95, 0x03,
-    0x13, 0x03, 0x18, 0x1f, 0x80, 0x18, 0x1f, 0x81,
-    0xb7, 0x03, 0x93, 0xb7, 0x03, 0x94, 0x20, 0x1f,
-    0x80, 0x21, 0x1f, 0x80, 0x20, 0x1f, 0x81, 0x21,
-    0x1f, 0x81, 0x20, 0x1f, 0xc2, 0x21, 0x1f, 0xc2,
-    0x97, 0x03, 0x93, 0x97, 0x03, 0x94, 0x28, 0x1f,
-    0x80, 0x29, 0x1f, 0x80, 0x28, 0x1f, 0x81, 0x29,
-    0x1f, 0x81, 0x28, 0x1f, 0xc2, 0x29, 0x1f, 0xc2,
-    0xb9, 0x03, 0x93, 0xb9, 0x03, 0x94, 0x30, 0x1f,
-    0x80, 0x31, 0x1f, 0x80, 0x30, 0x1f, 0x81, 0x31,
-    0x1f, 0x81, 0x30, 0x1f, 0xc2, 0x31, 0x1f, 0xc2,
-    0x99, 0x03, 0x93, 0x99, 0x03, 0x94, 0x38, 0x1f,
-    0x80, 0x39, 0x1f, 0x80, 0x38, 0x1f, 0x81, 0x39,
-    0x1f, 0x81, 0x38, 0x1f, 0xc2, 0x39, 0x1f, 0xc2,
-    0xbf, 0x03, 0x93, 0xbf, 0x03, 0x94, 0x40, 0x1f,
-    0x80, 0x40, 0x1f, 0x81, 0x9f, 0x03, 0x13, 0x03,
-    0x48, 0x1f, 0x80, 0x48, 0x1f, 0x81, 0xc5, 0x03,
-    0x13, 0x03, 0x50, 0x1f, 0x80, 0x50, 0x1f, 0x81,
-    0x50, 0x1f, 0xc2, 0xa5, 0x03, 0x94, 0x00, 0x00,
-    0x00, 0x59, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x59,
-    0x1f, 0x81, 0x00, 0x00, 0x00, 0x59, 0x1f, 0xc2,
-    0xc9, 0x03, 0x93, 0xc9, 0x03, 0x94, 0x60, 0x1f,
-    0x80, 0x61, 0x1f, 0x80, 0x60, 0x1f, 0x81, 0x61,
-    0x1f, 0x81, 0x60, 0x1f, 0xc2, 0x61, 0x1f, 0xc2,
-    0xa9, 0x03, 0x93, 0xa9, 0x03, 0x94, 0x68, 0x1f,
-    0x80, 0x69, 0x1f, 0x80, 0x68, 0x1f, 0x81, 0x69,
-    0x1f, 0x81, 0x68, 0x1f, 0xc2, 0x69, 0x1f, 0xc2,
-    0xb1, 0x03, 0x80, 0xb5, 0x03, 0x80, 0xb7, 0x03,
-    0x80, 0xb9, 0x03, 0x80, 0xbf, 0x03, 0x80, 0xc5,
-    0x03, 0x80, 0xc9, 0x03, 0x80, 0x00, 0x1f, 0x45,
-    0x03, 0x20, 0x1f, 0x45, 0x03, 0x60, 0x1f, 0x45,
-    0x03, 0xb1, 0x03, 0x86, 0xb1, 0x03, 0x84, 0x70,
-    0x1f, 0xc5, 0xb1, 0x03, 0xc5, 0xac, 0x03, 0xc5,
-    0x00, 0x00, 0x00, 0xb1, 0x03, 0xc2, 0xb6, 0x1f,
-    0xc5, 0x91, 0x03, 0x86, 0x91, 0x03, 0x84, 0x91,
-    0x03, 0x80, 0x91, 0x03, 0xc5, 0x20, 0x93, 0x20,
-    0x93, 0x20, 0xc2, 0xa8, 0x00, 0xc2, 0x74, 0x1f,
-    0xc5, 0xb7, 0x03, 0xc5, 0xae, 0x03, 0xc5, 0x00,
-    0x00, 0x00, 0xb7, 0x03, 0xc2, 0xc6, 0x1f, 0xc5,
-    0x95, 0x03, 0x80, 0x97, 0x03, 0x80, 0x97, 0x03,
-    0xc5, 0xbf, 0x1f, 0x80, 0xbf, 0x1f, 0x81, 0xbf,
-    0x1f, 0xc2, 0xb9, 0x03, 0x86, 0xb9, 0x03, 0x84,
-    0xca, 0x03, 0x80, 0x00, 0x03, 0xb9, 0x42, 0xca,
-    0x42, 0x99, 0x06, 0x99, 0x04, 0x99, 0x00, 0xfe,
-    0x1f, 0x80, 0xfe, 0x1f, 0x81, 0xfe, 0x1f, 0xc2,
-    0xc5, 0x03, 0x86, 0xc5, 0x03, 0x84, 0xcb, 0x03,
-    0x80, 0x00, 0x03, 0xc1, 0x13, 0xc1, 0x14, 0xc5,
-    0x42, 0xcb, 0x42, 0xa5, 0x06, 0xa5, 0x04, 0xa5,
-    0x00, 0xa1, 0x03, 0x94, 0xa8, 0x00, 0x80, 0x85,
-    0x03, 0x60, 0x00, 0x7c, 0x1f, 0xc5, 0xc9, 0x03,
-    0xc5, 0xce, 0x03, 0xc5, 0x00, 0x00, 0x00, 0xc9,
-    0x03, 0xc2, 0xf6, 0x1f, 0xc5, 0x9f, 0x03, 0x80,
-    0xa9, 0x03, 0x80, 0xa9, 0x03, 0xc5, 0x20, 0x94,
-    0x02, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-    0x20, 0x20, 0x20, 0x20, 0xb3, 0x2e, 0x2e, 0x2e,
-    0x2e, 0x2e, 0x32, 0x20, 0x32, 0x20, 0x32, 0x20,
-    0x00, 0x00, 0x00, 0x35, 0x20, 0x35, 0x20, 0x35,
-    0x20, 0x00, 0x00, 0x00, 0x21, 0x21, 0x00, 0x00,
-    0x20, 0x85, 0x3f, 0x3f, 0x3f, 0x21, 0x21, 0x3f,
-    0x32, 0x20, 0x00, 0x00, 0x00, 0x00, 0x30, 0x69,
-    0x00, 0x00, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
-    0x2b, 0x3d, 0x28, 0x29, 0x6e, 0x30, 0x00, 0x2b,
-    0x00, 0x12, 0x22, 0x3d, 0x00, 0x28, 0x00, 0x29,
-    0x00, 0x00, 0x00, 0x61, 0x00, 0x65, 0x00, 0x6f,
-    0x00, 0x78, 0x00, 0x59, 0x02, 0x68, 0x6b, 0x6c,
-    0x6d, 0x6e, 0x70, 0x73, 0x74, 0x52, 0x73, 0x61,
-    0x2f, 0x63, 0x61, 0x2f, 0x73, 0xb0, 0x00, 0x43,
-    0x63, 0x2f, 0x6f, 0x63, 0x2f, 0x75, 0xb0, 0x00,
-    0x46, 0x48, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20,
-    0xdf, 0x01, 0x01, 0x04, 0x24, 0x4e, 0x6f, 0x50,
-    0x51, 0x52, 0x52, 0x52, 0x53, 0x4d, 0x54, 0x45,
-    0x4c, 0x54, 0x4d, 0x4b, 0x00, 0xc5, 0x00, 0x42,
-    0x43, 0x00, 0x65, 0x45, 0x46, 0x00, 0x4d, 0x6f,
-    0xd0, 0x05, 0x46, 0x41, 0x58, 0xc0, 0x03, 0xb3,
-    0x03, 0x93, 0x03, 0xa0, 0x03, 0x11, 0x22, 0x44,
-    0x64, 0x65, 0x69, 0x6a, 0x31, 0xd0, 0x37, 0x31,
-    0xd0, 0x39, 0x31, 0xd0, 0x31, 0x30, 0x31, 0xd0,
-    0x33, 0x32, 0xd0, 0x33, 0x31, 0xd0, 0x35, 0x32,
-    0xd0, 0x35, 0x33, 0xd0, 0x35, 0x34, 0xd0, 0x35,
-    0x31, 0xd0, 0x36, 0x35, 0xd0, 0x36, 0x31, 0xd0,
-    0x38, 0x33, 0xd0, 0x38, 0x35, 0xd0, 0x38, 0x37,
-    0xd0, 0x38, 0x31, 0xd0, 0x49, 0x49, 0x49, 0x49,
-    0x49, 0x49, 0x56, 0x56, 0x49, 0x56, 0x49, 0x49,
-    0x56, 0x49, 0x49, 0x49, 0x49, 0x58, 0x58, 0x49,
-    0x58, 0x49, 0x49, 0x4c, 0x43, 0x44, 0x4d, 0x69,
-    0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x76, 0x76,
-    0x69, 0x76, 0x69, 0x69, 0x76, 0x69, 0x69, 0x69,
-    0x69, 0x78, 0x78, 0x69, 0x78, 0x69, 0x69, 0x6c,
-    0x63, 0x64, 0x6d, 0x30, 0xd0, 0x33, 0x90, 0x21,
-    0xb8, 0x92, 0x21, 0xb8, 0x94, 0x21, 0xb8, 0xd0,
-    0x21, 0xb8, 0xd4, 0x21, 0xb8, 0xd2, 0x21, 0xb8,
-    0x03, 0x22, 0xb8, 0x08, 0x22, 0xb8, 0x0b, 0x22,
-    0xb8, 0x23, 0x22, 0xb8, 0x00, 0x00, 0x00, 0x25,
-    0x22, 0xb8, 0x2b, 0x22, 0x2b, 0x22, 0x2b, 0x22,
-    0x00, 0x00, 0x00, 0x2e, 0x22, 0x2e, 0x22, 0x2e,
-    0x22, 0x00, 0x00, 0x00, 0x3c, 0x22, 0xb8, 0x43,
-    0x22, 0xb8, 0x45, 0x22, 0xb8, 0x00, 0x00, 0x00,
-    0x48, 0x22, 0xb8, 0x3d, 0x00, 0xb8, 0x00, 0x00,
-    0x00, 0x61, 0x22, 0xb8, 0x4d, 0x22, 0xb8, 0x3c,
-    0x00, 0xb8, 0x3e, 0x00, 0xb8, 0x64, 0x22, 0xb8,
-    0x65, 0x22, 0xb8, 0x72, 0x22, 0xb8, 0x76, 0x22,
-    0xb8, 0x7a, 0x22, 0xb8, 0x82, 0x22, 0xb8, 0x86,
-    0x22, 0xb8, 0xa2, 0x22, 0xb8, 0xa8, 0x22, 0xb8,
-    0xa9, 0x22, 0xb8, 0xab, 0x22, 0xb8, 0x7c, 0x22,
-    0xb8, 0x91, 0x22, 0xb8, 0xb2, 0x22, 0x38, 0x03,
-    0x08, 0x30, 0x31, 0x00, 0x31, 0x00, 0x30, 0x00,
-    0x32, 0x30, 0x28, 0x00, 0x31, 0x00, 0x29, 0x00,
-    0x28, 0x00, 0x31, 0x00, 0x30, 0x00, 0x29, 0x00,
-    0x28, 0x32, 0x30, 0x29, 0x31, 0x00, 0x2e, 0x00,
-    0x31, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x32, 0x30,
-    0x2e, 0x28, 0x00, 0x61, 0x00, 0x29, 0x00, 0x41,
-    0x00, 0x61, 0x00, 0x2b, 0x22, 0x00, 0x00, 0x00,
-    0x00, 0x3a, 0x3a, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
-    0x3d, 0xdd, 0x2a, 0xb8, 0x6a, 0x56, 0x00, 0x4e,
-    0x00, 0x28, 0x36, 0x3f, 0x59, 0x85, 0x8c, 0xa0,
-    0xba, 0x3f, 0x51, 0x00, 0x26, 0x2c, 0x43, 0x57,
-    0x6c, 0xa1, 0xb6, 0xc1, 0x9b, 0x52, 0x00, 0x5e,
-    0x7a, 0x7f, 0x9d, 0xa6, 0xc1, 0xce, 0xe7, 0xb6,
-    0x53, 0xc8, 0x53, 0xe3, 0x53, 0xd7, 0x56, 0x1f,
-    0x57, 0xeb, 0x58, 0x02, 0x59, 0x0a, 0x59, 0x15,
-    0x59, 0x27, 0x59, 0x73, 0x59, 0x50, 0x5b, 0x80,
-    0x5b, 0xf8, 0x5b, 0x0f, 0x5c, 0x22, 0x5c, 0x38,
-    0x5c, 0x6e, 0x5c, 0x71, 0x5c, 0xdb, 0x5d, 0xe5,
-    0x5d, 0xf1, 0x5d, 0xfe, 0x5d, 0x72, 0x5e, 0x7a,
-    0x5e, 0x7f, 0x5e, 0xf4, 0x5e, 0xfe, 0x5e, 0x0b,
-    0x5f, 0x13, 0x5f, 0x50, 0x5f, 0x61, 0x5f, 0x73,
-    0x5f, 0xc3, 0x5f, 0x08, 0x62, 0x36, 0x62, 0x4b,
-    0x62, 0x2f, 0x65, 0x34, 0x65, 0x87, 0x65, 0x97,
-    0x65, 0xa4, 0x65, 0xb9, 0x65, 0xe0, 0x65, 0xe5,
-    0x65, 0xf0, 0x66, 0x08, 0x67, 0x28, 0x67, 0x20,
-    0x6b, 0x62, 0x6b, 0x79, 0x6b, 0xb3, 0x6b, 0xcb,
-    0x6b, 0xd4, 0x6b, 0xdb, 0x6b, 0x0f, 0x6c, 0x14,
-    0x6c, 0x34, 0x6c, 0x6b, 0x70, 0x2a, 0x72, 0x36,
-    0x72, 0x3b, 0x72, 0x3f, 0x72, 0x47, 0x72, 0x59,
-    0x72, 0x5b, 0x72, 0xac, 0x72, 0x84, 0x73, 0x89,
-    0x73, 0xdc, 0x74, 0xe6, 0x74, 0x18, 0x75, 0x1f,
-    0x75, 0x28, 0x75, 0x30, 0x75, 0x8b, 0x75, 0x92,
-    0x75, 0x76, 0x76, 0x7d, 0x76, 0xae, 0x76, 0xbf,
-    0x76, 0xee, 0x76, 0xdb, 0x77, 0xe2, 0x77, 0xf3,
-    0x77, 0x3a, 0x79, 0xb8, 0x79, 0xbe, 0x79, 0x74,
-    0x7a, 0xcb, 0x7a, 0xf9, 0x7a, 0x73, 0x7c, 0xf8,
-    0x7c, 0x36, 0x7f, 0x51, 0x7f, 0x8a, 0x7f, 0xbd,
-    0x7f, 0x01, 0x80, 0x0c, 0x80, 0x12, 0x80, 0x33,
-    0x80, 0x7f, 0x80, 0x89, 0x80, 0xe3, 0x81, 0x00,
-    0x07, 0x10, 0x19, 0x29, 0x38, 0x3c, 0x8b, 0x8f,
-    0x95, 0x4d, 0x86, 0x6b, 0x86, 0x40, 0x88, 0x4c,
-    0x88, 0x63, 0x88, 0x7e, 0x89, 0x8b, 0x89, 0xd2,
-    0x89, 0x00, 0x8a, 0x37, 0x8c, 0x46, 0x8c, 0x55,
-    0x8c, 0x78, 0x8c, 0x9d, 0x8c, 0x64, 0x8d, 0x70,
-    0x8d, 0xb3, 0x8d, 0xab, 0x8e, 0xca, 0x8e, 0x9b,
-    0x8f, 0xb0, 0x8f, 0xb5, 0x8f, 0x91, 0x90, 0x49,
-    0x91, 0xc6, 0x91, 0xcc, 0x91, 0xd1, 0x91, 0x77,
-    0x95, 0x80, 0x95, 0x1c, 0x96, 0xb6, 0x96, 0xb9,
-    0x96, 0xe8, 0x96, 0x51, 0x97, 0x5e, 0x97, 0x62,
-    0x97, 0x69, 0x97, 0xcb, 0x97, 0xed, 0x97, 0xf3,
-    0x97, 0x01, 0x98, 0xa8, 0x98, 0xdb, 0x98, 0xdf,
-    0x98, 0x96, 0x99, 0x99, 0x99, 0xac, 0x99, 0xa8,
-    0x9a, 0xd8, 0x9a, 0xdf, 0x9a, 0x25, 0x9b, 0x2f,
-    0x9b, 0x32, 0x9b, 0x3c, 0x9b, 0x5a, 0x9b, 0xe5,
-    0x9c, 0x75, 0x9e, 0x7f, 0x9e, 0xa5, 0x9e, 0x00,
-    0x16, 0x1e, 0x28, 0x2c, 0x54, 0x58, 0x69, 0x6e,
-    0x7b, 0x96, 0xa5, 0xad, 0xe8, 0xf7, 0xfb, 0x12,
-    0x30, 0x00, 0x00, 0x41, 0x53, 0x44, 0x53, 0x45,
-    0x53, 0x4b, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
-    0x00, 0x4d, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
-    0x00, 0x4f, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
-    0x00, 0x51, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
-    0x00, 0x53, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
-    0x00, 0x55, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
-    0x00, 0x57, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
-    0x00, 0x59, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
-    0x00, 0x5b, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
-    0x00, 0x5d, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
-    0x00, 0x5f, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
-    0x00, 0x61, 0x30, 0x99, 0x30, 0x64, 0x30, 0x99,
-    0x30, 0x00, 0x00, 0x00, 0x00, 0x66, 0x30, 0x99,
-    0x30, 0x00, 0x00, 0x00, 0x00, 0x68, 0x30, 0x99,
-    0x30, 0x6f, 0x30, 0x99, 0x30, 0x72, 0x30, 0x99,
-    0x30, 0x75, 0x30, 0x99, 0x30, 0x78, 0x30, 0x99,
-    0x30, 0x7b, 0x30, 0x99, 0x30, 0x46, 0x30, 0x99,
-    0x30, 0x20, 0x00, 0x99, 0x30, 0x9d, 0x30, 0x99,
-    0x30, 0x88, 0x30, 0x8a, 0x30, 0xab, 0x30, 0x99,
-    0x30, 0x00, 0x00, 0x00, 0x00, 0xad, 0x30, 0x99,
-    0x30, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x30, 0x99,
-    0x30, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x30, 0x99,
-    0x30, 0x00, 0x00, 0x00, 0x00, 0xb3, 0x30, 0x99,
-    0x30, 0x00, 0x00, 0x00, 0x00, 0xb5, 0x30, 0x99,
-    0x30, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x30, 0x99,
-    0x30, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x30, 0x99,
-    0x30, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x30, 0x99,
-    0x30, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x30, 0x99,
-    0x30, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x30, 0x99,
-    0x30, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x30, 0x99,
-    0x30, 0xc4, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
-    0x00, 0xc6, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,
-    0x00, 0xc8, 0x30, 0x99, 0x30, 0xcf, 0x30, 0x99,
-    0x30, 0xd2, 0x30, 0x99, 0x30, 0xd5, 0x30, 0x99,
-    0x30, 0xd8, 0x30, 0x99, 0x30, 0xdb, 0x30, 0x99,
-    0x30, 0xa6, 0x30, 0x99, 0x30, 0xef, 0x30, 0x99,
-    0x30, 0xfd, 0x30, 0x99, 0x30, 0xb3, 0x30, 0xc8,
-    0x30, 0x00, 0x11, 0x00, 0x01, 0xaa, 0x02, 0xac,
-    0xad, 0x03, 0x04, 0x05, 0xb0, 0xb1, 0xb2, 0xb3,
-    0xb4, 0xb5, 0x1a, 0x06, 0x07, 0x08, 0x21, 0x09,
-    0x11, 0x61, 0x11, 0x14, 0x11, 0x4c, 0x00, 0x01,
-    0xb3, 0xb4, 0xb8, 0xba, 0xbf, 0xc3, 0xc5, 0x08,
-    0xc9, 0xcb, 0x09, 0x0a, 0x0c, 0x0e, 0x0f, 0x13,
-    0x15, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x22,
-    0x2c, 0x33, 0x38, 0xdd, 0xde, 0x43, 0x44, 0x45,
-    0x70, 0x71, 0x74, 0x7d, 0x7e, 0x80, 0x8a, 0x8d,
-    0x00, 0x4e, 0x8c, 0x4e, 0x09, 0x4e, 0xdb, 0x56,
-    0x0a, 0x4e, 0x2d, 0x4e, 0x0b, 0x4e, 0x32, 0x75,
-    0x59, 0x4e, 0x19, 0x4e, 0x01, 0x4e, 0x29, 0x59,
-    0x30, 0x57, 0xba, 0x4e, 0x28, 0x00, 0x29, 0x00,
-    0x00, 0x11, 0x02, 0x11, 0x03, 0x11, 0x05, 0x11,
-    0x06, 0x11, 0x07, 0x11, 0x09, 0x11, 0x0b, 0x11,
-    0x0c, 0x11, 0x0e, 0x11, 0x0f, 0x11, 0x10, 0x11,
-    0x11, 0x11, 0x12, 0x11, 0x28, 0x00, 0x00, 0x11,
-    0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x02, 0x11,
-    0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x05, 0x11,
-    0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x09, 0x11,
-    0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11,
-    0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0e, 0x11,
-    0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0c, 0x11,
-    0x6e, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11,
-    0x69, 0x11, 0x0c, 0x11, 0x65, 0x11, 0xab, 0x11,
-    0x29, 0x00, 0x28, 0x00, 0x0b, 0x11, 0x69, 0x11,
-    0x12, 0x11, 0x6e, 0x11, 0x29, 0x00, 0x28, 0x00,
-    0x29, 0x00, 0x00, 0x4e, 0x8c, 0x4e, 0x09, 0x4e,
-    0xdb, 0x56, 0x94, 0x4e, 0x6d, 0x51, 0x03, 0x4e,
-    0x6b, 0x51, 0x5d, 0x4e, 0x41, 0x53, 0x08, 0x67,
-    0x6b, 0x70, 0x34, 0x6c, 0x28, 0x67, 0xd1, 0x91,
-    0x1f, 0x57, 0xe5, 0x65, 0x2a, 0x68, 0x09, 0x67,
-    0x3e, 0x79, 0x0d, 0x54, 0x79, 0x72, 0xa1, 0x8c,
-    0x5d, 0x79, 0xb4, 0x52, 0xe3, 0x4e, 0x7c, 0x54,
-    0x66, 0x5b, 0xe3, 0x76, 0x01, 0x4f, 0xc7, 0x8c,
-    0x54, 0x53, 0x6d, 0x79, 0x11, 0x4f, 0xea, 0x81,
-    0xf3, 0x81, 0x4f, 0x55, 0x7c, 0x5e, 0x87, 0x65,
-    0x8f, 0x7b, 0x50, 0x54, 0x45, 0x32, 0x00, 0x31,
-    0x00, 0x33, 0x00, 0x30, 0x00, 0x00, 0x11, 0x00,
-    0x02, 0x03, 0x05, 0x06, 0x07, 0x09, 0x0b, 0x0c,
-    0x0e, 0x0f, 0x10, 0x11, 0x12, 0x00, 0x11, 0x00,
-    0x61, 0x02, 0x61, 0x03, 0x61, 0x05, 0x61, 0x06,
-    0x61, 0x07, 0x61, 0x09, 0x61, 0x0b, 0x61, 0x0c,
-    0x61, 0x0e, 0x11, 0x61, 0x11, 0x00, 0x11, 0x0e,
-    0x61, 0xb7, 0x00, 0x69, 0x0b, 0x11, 0x01, 0x63,
-    0x00, 0x69, 0x0b, 0x11, 0x6e, 0x11, 0x00, 0x4e,
-    0x8c, 0x4e, 0x09, 0x4e, 0xdb, 0x56, 0x94, 0x4e,
-    0x6d, 0x51, 0x03, 0x4e, 0x6b, 0x51, 0x5d, 0x4e,
-    0x41, 0x53, 0x08, 0x67, 0x6b, 0x70, 0x34, 0x6c,
-    0x28, 0x67, 0xd1, 0x91, 0x1f, 0x57, 0xe5, 0x65,
-    0x2a, 0x68, 0x09, 0x67, 0x3e, 0x79, 0x0d, 0x54,
-    0x79, 0x72, 0xa1, 0x8c, 0x5d, 0x79, 0xb4, 0x52,
-    0xd8, 0x79, 0x37, 0x75, 0x73, 0x59, 0x69, 0x90,
-    0x2a, 0x51, 0x70, 0x53, 0xe8, 0x6c, 0x05, 0x98,
-    0x11, 0x4f, 0x99, 0x51, 0x63, 0x6b, 0x0a, 0x4e,
-    0x2d, 0x4e, 0x0b, 0x4e, 0xe6, 0x5d, 0xf3, 0x53,
-    0x3b, 0x53, 0x97, 0x5b, 0x66, 0x5b, 0xe3, 0x76,
-    0x01, 0x4f, 0xc7, 0x8c, 0x54, 0x53, 0x1c, 0x59,
-    0x33, 0x00, 0x36, 0x00, 0x34, 0x00, 0x30, 0x00,
-    0x35, 0x30, 0x31, 0x00, 0x08, 0x67, 0x31, 0x00,
-    0x30, 0x00, 0x08, 0x67, 0x48, 0x67, 0x65, 0x72,
-    0x67, 0x65, 0x56, 0x4c, 0x54, 0x44, 0xa2, 0x30,
-    0x00, 0x02, 0x04, 0x06, 0x08, 0x09, 0x0b, 0x0d,
-    0x0f, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1b, 0x1d,
-    0x1f, 0x22, 0x24, 0x26, 0x28, 0x29, 0x2a, 0x2b,
-    0x2c, 0x2d, 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3d,
-    0x3e, 0x3f, 0x40, 0x42, 0x44, 0x46, 0x47, 0x48,
-    0x49, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x50, 0xe4,
-    0x4e, 0x8c, 0x54, 0xa1, 0x30, 0x01, 0x30, 0x5b,
-    0x27, 0x01, 0x4a, 0x34, 0x00, 0x01, 0x52, 0x39,
-    0x01, 0xa2, 0x30, 0x00, 0x5a, 0x49, 0xa4, 0x30,
-    0x00, 0x27, 0x4f, 0x0c, 0xa4, 0x30, 0x00, 0x4f,
-    0x1d, 0x02, 0x05, 0x4f, 0xa8, 0x30, 0x00, 0x11,
-    0x07, 0x54, 0x21, 0xa8, 0x30, 0x00, 0x54, 0x03,
-    0x54, 0xa4, 0x30, 0x06, 0x4f, 0x15, 0x06, 0x58,
-    0x3c, 0x07, 0x00, 0x46, 0xab, 0x30, 0x00, 0x3e,
-    0x18, 0x1d, 0x00, 0x42, 0x3f, 0x51, 0xac, 0x30,
-    0x00, 0x41, 0x47, 0x00, 0x47, 0x32, 0xae, 0x30,
-    0xac, 0x30, 0xae, 0x30, 0x00, 0x1d, 0x4e, 0xad,
-    0x30, 0x00, 0x38, 0x3d, 0x4f, 0x01, 0x3e, 0x13,
-    0x4f, 0xad, 0x30, 0xed, 0x30, 0xad, 0x30, 0x00,
-    0x40, 0x03, 0x3c, 0x33, 0xad, 0x30, 0x00, 0x40,
-    0x34, 0x4f, 0x1b, 0x3e, 0xad, 0x30, 0x00, 0x40,
-    0x42, 0x16, 0x1b, 0xb0, 0x30, 0x00, 0x39, 0x30,
-    0xa4, 0x30, 0x0c, 0x45, 0x3c, 0x24, 0x4f, 0x0b,
-    0x47, 0x18, 0x00, 0x49, 0xaf, 0x30, 0x00, 0x3e,
-    0x4d, 0x1e, 0xb1, 0x30, 0x00, 0x4b, 0x08, 0x02,
-    0x3a, 0x19, 0x02, 0x4b, 0x2c, 0xa4, 0x30, 0x11,
-    0x00, 0x0b, 0x47, 0xb5, 0x30, 0x00, 0x3e, 0x0c,
-    0x47, 0x2b, 0xb0, 0x30, 0x07, 0x3a, 0x43, 0x00,
-    0xb9, 0x30, 0x02, 0x3a, 0x08, 0x02, 0x3a, 0x0f,
-    0x07, 0x43, 0x00, 0xb7, 0x30, 0x10, 0x00, 0x12,
-    0x34, 0x11, 0x3c, 0x13, 0x17, 0xa4, 0x30, 0x2a,
-    0x1f, 0x24, 0x2b, 0x00, 0x20, 0xbb, 0x30, 0x16,
-    0x41, 0x00, 0x38, 0x0d, 0xc4, 0x30, 0x0d, 0x38,
-    0x00, 0xd0, 0x30, 0x00, 0x2c, 0x1c, 0x1b, 0xa2,
-    0x30, 0x32, 0x00, 0x17, 0x26, 0x49, 0xaf, 0x30,
-    0x25, 0x00, 0x3c, 0xb3, 0x30, 0x21, 0x00, 0x20,
-    0x38, 0xa1, 0x30, 0x34, 0x00, 0x48, 0x22, 0x28,
-    0xa3, 0x30, 0x32, 0x00, 0x59, 0x25, 0xa7, 0x30,
-    0x2f, 0x1c, 0x10, 0x00, 0x44, 0xd5, 0x30, 0x00,
-    0x14, 0x1e, 0xaf, 0x30, 0x29, 0x00, 0x10, 0x4d,
-    0x3c, 0xda, 0x30, 0xbd, 0x30, 0xb8, 0x30, 0x22,
-    0x13, 0x1a, 0x20, 0x33, 0x0c, 0x22, 0x3b, 0x01,
-    0x22, 0x44, 0x00, 0x21, 0x44, 0x07, 0xa4, 0x30,
-    0x39, 0x00, 0x4f, 0x24, 0xc8, 0x30, 0x14, 0x23,
-    0x00, 0xdb, 0x30, 0xf3, 0x30, 0xc9, 0x30, 0x14,
-    0x2a, 0x00, 0x12, 0x33, 0x22, 0x12, 0x33, 0x2a,
-    0xa4, 0x30, 0x3a, 0x00, 0x0b, 0x49, 0xa4, 0x30,
-    0x3a, 0x00, 0x47, 0x3a, 0x1f, 0x2b, 0x3a, 0x47,
-    0x0b, 0xb7, 0x30, 0x27, 0x3c, 0x00, 0x30, 0x3c,
-    0xaf, 0x30, 0x30, 0x00, 0x3e, 0x44, 0xdf, 0x30,
-    0xea, 0x30, 0xd0, 0x30, 0x0f, 0x1a, 0x00, 0x2c,
-    0x1b, 0xe1, 0x30, 0xac, 0x30, 0xac, 0x30, 0x35,
-    0x00, 0x1c, 0x47, 0x35, 0x50, 0x1c, 0x3f, 0xa2,
-    0x30, 0x42, 0x5a, 0x27, 0x42, 0x5a, 0x49, 0x44,
-    0x00, 0x51, 0xc3, 0x30, 0x27, 0x00, 0x05, 0x28,
-    0xea, 0x30, 0xe9, 0x30, 0xd4, 0x30, 0x17, 0x00,
-    0x28, 0xd6, 0x30, 0x15, 0x26, 0x00, 0x15, 0xec,
-    0x30, 0xe0, 0x30, 0xb2, 0x30, 0x3a, 0x41, 0x16,
-    0x00, 0x41, 0xc3, 0x30, 0x2c, 0x00, 0x05, 0x30,
-    0x00, 0xb9, 0x70, 0x31, 0x00, 0x30, 0x00, 0xb9,
-    0x70, 0x32, 0x00, 0x30, 0x00, 0xb9, 0x70, 0x68,
-    0x50, 0x61, 0x64, 0x61, 0x41, 0x55, 0x62, 0x61,
-    0x72, 0x6f, 0x56, 0x70, 0x63, 0x64, 0x6d, 0x64,
-    0x00, 0x6d, 0x00, 0xb2, 0x00, 0x49, 0x00, 0x55,
-    0x00, 0x73, 0x5e, 0x10, 0x62, 0x2d, 0x66, 0x8c,
-    0x54, 0x27, 0x59, 0x63, 0x6b, 0x0e, 0x66, 0xbb,
-    0x6c, 0x2a, 0x68, 0x0f, 0x5f, 0x1a, 0x4f, 0x3e,
-    0x79, 0x70, 0x00, 0x41, 0x6e, 0x00, 0x41, 0xbc,
-    0x03, 0x41, 0x6d, 0x00, 0x41, 0x6b, 0x00, 0x41,
-    0x4b, 0x00, 0x42, 0x4d, 0x00, 0x42, 0x47, 0x00,
-    0x42, 0x63, 0x61, 0x6c, 0x6b, 0x63, 0x61, 0x6c,
-    0x70, 0x00, 0x46, 0x6e, 0x00, 0x46, 0xbc, 0x03,
-    0x46, 0xbc, 0x03, 0x67, 0x6d, 0x00, 0x67, 0x6b,
-    0x00, 0x67, 0x48, 0x00, 0x7a, 0x6b, 0x48, 0x7a,
-    0x4d, 0x48, 0x7a, 0x47, 0x48, 0x7a, 0x54, 0x48,
-    0x7a, 0xbc, 0x03, 0x13, 0x21, 0x6d, 0x00, 0x13,
-    0x21, 0x64, 0x00, 0x13, 0x21, 0x6b, 0x00, 0x13,
-    0x21, 0x66, 0x00, 0x6d, 0x6e, 0x00, 0x6d, 0xbc,
-    0x03, 0x6d, 0x6d, 0x00, 0x6d, 0x63, 0x00, 0x6d,
-    0x6b, 0x00, 0x6d, 0x63, 0x00, 0x0a, 0x0a, 0x4f,
-    0x00, 0x0a, 0x4f, 0x6d, 0x00, 0xb2, 0x00, 0x63,
-    0x00, 0x08, 0x0a, 0x4f, 0x0a, 0x0a, 0x50, 0x00,
-    0x0a, 0x50, 0x6d, 0x00, 0xb3, 0x00, 0x6b, 0x00,
-    0x6d, 0x00, 0xb3, 0x00, 0x6d, 0x00, 0x15, 0x22,
-    0x73, 0x00, 0x6d, 0x00, 0x15, 0x22, 0x73, 0x00,
-    0xb2, 0x00, 0x50, 0x61, 0x6b, 0x50, 0x61, 0x4d,
-    0x50, 0x61, 0x47, 0x50, 0x61, 0x72, 0x61, 0x64,
-    0x72, 0x61, 0x64, 0xd1, 0x73, 0x72, 0x00, 0x61,
-    0x00, 0x64, 0x00, 0x15, 0x22, 0x73, 0x00, 0xb2,
-    0x00, 0x70, 0x00, 0x73, 0x6e, 0x00, 0x73, 0xbc,
-    0x03, 0x73, 0x6d, 0x00, 0x73, 0x70, 0x00, 0x56,
-    0x6e, 0x00, 0x56, 0xbc, 0x03, 0x56, 0x6d, 0x00,
-    0x56, 0x6b, 0x00, 0x56, 0x4d, 0x00, 0x56, 0x70,
-    0x00, 0x57, 0x6e, 0x00, 0x57, 0xbc, 0x03, 0x57,
-    0x6d, 0x00, 0x57, 0x6b, 0x00, 0x57, 0x4d, 0x00,
-    0x57, 0x6b, 0x00, 0xa9, 0x03, 0x4d, 0x00, 0xa9,
-    0x03, 0x61, 0x2e, 0x6d, 0x2e, 0x42, 0x71, 0x63,
-    0x63, 0x63, 0x64, 0x43, 0xd1, 0x6b, 0x67, 0x43,
-    0x6f, 0x2e, 0x64, 0x42, 0x47, 0x79, 0x68, 0x61,
-    0x48, 0x50, 0x69, 0x6e, 0x4b, 0x4b, 0x4b, 0x4d,
-    0x6b, 0x74, 0x6c, 0x6d, 0x6c, 0x6e, 0x6c, 0x6f,
-    0x67, 0x6c, 0x78, 0x6d, 0x62, 0x6d, 0x69, 0x6c,
-    0x6d, 0x6f, 0x6c, 0x50, 0x48, 0x70, 0x2e, 0x6d,
-    0x2e, 0x50, 0x50, 0x4d, 0x50, 0x52, 0x73, 0x72,
-    0x53, 0x76, 0x57, 0x62, 0x56, 0xd1, 0x6d, 0x41,
-    0xd1, 0x6d, 0x31, 0x00, 0xe5, 0x65, 0x31, 0x00,
-    0x30, 0x00, 0xe5, 0x65, 0x32, 0x00, 0x30, 0x00,
-    0xe5, 0x65, 0x33, 0x00, 0x30, 0x00, 0xe5, 0x65,
-    0x67, 0x61, 0x6c, 0x4a, 0x04, 0x4c, 0x04, 0x43,
-    0x46, 0x51, 0x26, 0x01, 0x53, 0x01, 0x27, 0xa7,
-    0x37, 0xab, 0x6b, 0x02, 0x52, 0xab, 0x48, 0x8c,
-    0xf4, 0x66, 0xca, 0x8e, 0xc8, 0x8c, 0xd1, 0x6e,
-    0x32, 0x4e, 0xe5, 0x53, 0x9c, 0x9f, 0x9c, 0x9f,
-    0x51, 0x59, 0xd1, 0x91, 0x87, 0x55, 0x48, 0x59,
-    0xf6, 0x61, 0x69, 0x76, 0x85, 0x7f, 0x3f, 0x86,
-    0xba, 0x87, 0xf8, 0x88, 0x8f, 0x90, 0x02, 0x6a,
-    0x1b, 0x6d, 0xd9, 0x70, 0xde, 0x73, 0x3d, 0x84,
-    0x6a, 0x91, 0xf1, 0x99, 0x82, 0x4e, 0x75, 0x53,
-    0x04, 0x6b, 0x1b, 0x72, 0x2d, 0x86, 0x1e, 0x9e,
-    0x50, 0x5d, 0xeb, 0x6f, 0xcd, 0x85, 0x64, 0x89,
-    0xc9, 0x62, 0xd8, 0x81, 0x1f, 0x88, 0xca, 0x5e,
-    0x17, 0x67, 0x6a, 0x6d, 0xfc, 0x72, 0xce, 0x90,
-    0x86, 0x4f, 0xb7, 0x51, 0xde, 0x52, 0xc4, 0x64,
-    0xd3, 0x6a, 0x10, 0x72, 0xe7, 0x76, 0x01, 0x80,
-    0x06, 0x86, 0x5c, 0x86, 0xef, 0x8d, 0x32, 0x97,
-    0x6f, 0x9b, 0xfa, 0x9d, 0x8c, 0x78, 0x7f, 0x79,
-    0xa0, 0x7d, 0xc9, 0x83, 0x04, 0x93, 0x7f, 0x9e,
-    0xd6, 0x8a, 0xdf, 0x58, 0x04, 0x5f, 0x60, 0x7c,
-    0x7e, 0x80, 0x62, 0x72, 0xca, 0x78, 0xc2, 0x8c,
-    0xf7, 0x96, 0xd8, 0x58, 0x62, 0x5c, 0x13, 0x6a,
-    0xda, 0x6d, 0x0f, 0x6f, 0x2f, 0x7d, 0x37, 0x7e,
-    0x4b, 0x96, 0xd2, 0x52, 0x8b, 0x80, 0xdc, 0x51,
-    0xcc, 0x51, 0x1c, 0x7a, 0xbe, 0x7d, 0xf1, 0x83,
-    0x75, 0x96, 0x80, 0x8b, 0xcf, 0x62, 0x02, 0x6a,
-    0xfe, 0x8a, 0x39, 0x4e, 0xe7, 0x5b, 0x12, 0x60,
-    0x87, 0x73, 0x70, 0x75, 0x17, 0x53, 0xfb, 0x78,
-    0xbf, 0x4f, 0xa9, 0x5f, 0x0d, 0x4e, 0xcc, 0x6c,
-    0x78, 0x65, 0x22, 0x7d, 0xc3, 0x53, 0x5e, 0x58,
-    0x01, 0x77, 0x49, 0x84, 0xaa, 0x8a, 0xba, 0x6b,
-    0xb0, 0x8f, 0x88, 0x6c, 0xfe, 0x62, 0xe5, 0x82,
-    0xa0, 0x63, 0x65, 0x75, 0xae, 0x4e, 0x69, 0x51,
-    0xc9, 0x51, 0x81, 0x68, 0xe7, 0x7c, 0x6f, 0x82,
-    0xd2, 0x8a, 0xcf, 0x91, 0xf5, 0x52, 0x42, 0x54,
-    0x73, 0x59, 0xec, 0x5e, 0xc5, 0x65, 0xfe, 0x6f,
-    0x2a, 0x79, 0xad, 0x95, 0x6a, 0x9a, 0x97, 0x9e,
-    0xce, 0x9e, 0x9b, 0x52, 0xc6, 0x66, 0x77, 0x6b,
-    0x62, 0x8f, 0x74, 0x5e, 0x90, 0x61, 0x00, 0x62,
-    0x9a, 0x64, 0x23, 0x6f, 0x49, 0x71, 0x89, 0x74,
-    0xca, 0x79, 0xf4, 0x7d, 0x6f, 0x80, 0x26, 0x8f,
-    0xee, 0x84, 0x23, 0x90, 0x4a, 0x93, 0x17, 0x52,
-    0xa3, 0x52, 0xbd, 0x54, 0xc8, 0x70, 0xc2, 0x88,
-    0xaa, 0x8a, 0xc9, 0x5e, 0xf5, 0x5f, 0x7b, 0x63,
-    0xae, 0x6b, 0x3e, 0x7c, 0x75, 0x73, 0xe4, 0x4e,
-    0xf9, 0x56, 0xe7, 0x5b, 0xba, 0x5d, 0x1c, 0x60,
-    0xb2, 0x73, 0x69, 0x74, 0x9a, 0x7f, 0x46, 0x80,
-    0x34, 0x92, 0xf6, 0x96, 0x48, 0x97, 0x18, 0x98,
-    0x8b, 0x4f, 0xae, 0x79, 0xb4, 0x91, 0xb8, 0x96,
-    0xe1, 0x60, 0x86, 0x4e, 0xda, 0x50, 0xee, 0x5b,
-    0x3f, 0x5c, 0x99, 0x65, 0x02, 0x6a, 0xce, 0x71,
-    0x42, 0x76, 0xfc, 0x84, 0x7c, 0x90, 0x8d, 0x9f,
-    0x88, 0x66, 0x2e, 0x96, 0x89, 0x52, 0x7b, 0x67,
-    0xf3, 0x67, 0x41, 0x6d, 0x9c, 0x6e, 0x09, 0x74,
-    0x59, 0x75, 0x6b, 0x78, 0x10, 0x7d, 0x5e, 0x98,
-    0x6d, 0x51, 0x2e, 0x62, 0x78, 0x96, 0x2b, 0x50,
-    0x19, 0x5d, 0xea, 0x6d, 0x2a, 0x8f, 0x8b, 0x5f,
-    0x44, 0x61, 0x17, 0x68, 0x87, 0x73, 0x86, 0x96,
-    0x29, 0x52, 0x0f, 0x54, 0x65, 0x5c, 0x13, 0x66,
-    0x4e, 0x67, 0xa8, 0x68, 0xe5, 0x6c, 0x06, 0x74,
-    0xe2, 0x75, 0x79, 0x7f, 0xcf, 0x88, 0xe1, 0x88,
-    0xcc, 0x91, 0xe2, 0x96, 0x3f, 0x53, 0xba, 0x6e,
-    0x1d, 0x54, 0xd0, 0x71, 0x98, 0x74, 0xfa, 0x85,
-    0xa3, 0x96, 0x57, 0x9c, 0x9f, 0x9e, 0x97, 0x67,
-    0xcb, 0x6d, 0xe8, 0x81, 0xcb, 0x7a, 0x20, 0x7b,
-    0x92, 0x7c, 0xc0, 0x72, 0x99, 0x70, 0x58, 0x8b,
-    0xc0, 0x4e, 0x36, 0x83, 0x3a, 0x52, 0x07, 0x52,
-    0xa6, 0x5e, 0xd3, 0x62, 0xd6, 0x7c, 0x85, 0x5b,
-    0x1e, 0x6d, 0xb4, 0x66, 0x3b, 0x8f, 0x4c, 0x88,
-    0x4d, 0x96, 0x8b, 0x89, 0xd3, 0x5e, 0x40, 0x51,
-    0xc0, 0x55, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x58,
-    0x00, 0x00, 0x74, 0x66, 0x00, 0x00, 0x00, 0x00,
-    0xde, 0x51, 0x2a, 0x73, 0xca, 0x76, 0x3c, 0x79,
-    0x5e, 0x79, 0x65, 0x79, 0x8f, 0x79, 0x56, 0x97,
-    0xbe, 0x7c, 0xbd, 0x7f, 0x00, 0x00, 0x12, 0x86,
-    0x00, 0x00, 0xf8, 0x8a, 0x00, 0x00, 0x00, 0x00,
-    0x38, 0x90, 0xfd, 0x90, 0xef, 0x98, 0xfc, 0x98,
-    0x28, 0x99, 0xb4, 0x9d, 0xde, 0x90, 0xb7, 0x96,
-    0xae, 0x4f, 0xe7, 0x50, 0x4d, 0x51, 0xc9, 0x52,
-    0xe4, 0x52, 0x51, 0x53, 0x9d, 0x55, 0x06, 0x56,
-    0x68, 0x56, 0x40, 0x58, 0xa8, 0x58, 0x64, 0x5c,
-    0x6e, 0x5c, 0x94, 0x60, 0x68, 0x61, 0x8e, 0x61,
-    0xf2, 0x61, 0x4f, 0x65, 0xe2, 0x65, 0x91, 0x66,
-    0x85, 0x68, 0x77, 0x6d, 0x1a, 0x6e, 0x22, 0x6f,
-    0x6e, 0x71, 0x2b, 0x72, 0x22, 0x74, 0x91, 0x78,
-    0x3e, 0x79, 0x49, 0x79, 0x48, 0x79, 0x50, 0x79,
-    0x56, 0x79, 0x5d, 0x79, 0x8d, 0x79, 0x8e, 0x79,
-    0x40, 0x7a, 0x81, 0x7a, 0xc0, 0x7b, 0xf4, 0x7d,
-    0x09, 0x7e, 0x41, 0x7e, 0x72, 0x7f, 0x05, 0x80,
-    0xed, 0x81, 0x79, 0x82, 0x79, 0x82, 0x57, 0x84,
-    0x10, 0x89, 0x96, 0x89, 0x01, 0x8b, 0x39, 0x8b,
-    0xd3, 0x8c, 0x08, 0x8d, 0xb6, 0x8f, 0x38, 0x90,
-    0xe3, 0x96, 0xff, 0x97, 0x3b, 0x98, 0x75, 0x60,
-    0xee, 0x42, 0x18, 0x82, 0x02, 0x26, 0x4e, 0xb5,
-    0x51, 0x68, 0x51, 0x80, 0x4f, 0x45, 0x51, 0x80,
-    0x51, 0xc7, 0x52, 0xfa, 0x52, 0x9d, 0x55, 0x55,
-    0x55, 0x99, 0x55, 0xe2, 0x55, 0x5a, 0x58, 0xb3,
-    0x58, 0x44, 0x59, 0x54, 0x59, 0x62, 0x5a, 0x28,
-    0x5b, 0xd2, 0x5e, 0xd9, 0x5e, 0x69, 0x5f, 0xad,
-    0x5f, 0xd8, 0x60, 0x4e, 0x61, 0x08, 0x61, 0x8e,
-    0x61, 0x60, 0x61, 0xf2, 0x61, 0x34, 0x62, 0xc4,
-    0x63, 0x1c, 0x64, 0x52, 0x64, 0x56, 0x65, 0x74,
-    0x66, 0x17, 0x67, 0x1b, 0x67, 0x56, 0x67, 0x79,
-    0x6b, 0xba, 0x6b, 0x41, 0x6d, 0xdb, 0x6e, 0xcb,
-    0x6e, 0x22, 0x6f, 0x1e, 0x70, 0x6e, 0x71, 0xa7,
-    0x77, 0x35, 0x72, 0xaf, 0x72, 0x2a, 0x73, 0x71,
-    0x74, 0x06, 0x75, 0x3b, 0x75, 0x1d, 0x76, 0x1f,
-    0x76, 0xca, 0x76, 0xdb, 0x76, 0xf4, 0x76, 0x4a,
-    0x77, 0x40, 0x77, 0xcc, 0x78, 0xb1, 0x7a, 0xc0,
-    0x7b, 0x7b, 0x7c, 0x5b, 0x7d, 0xf4, 0x7d, 0x3e,
-    0x7f, 0x05, 0x80, 0x52, 0x83, 0xef, 0x83, 0x79,
-    0x87, 0x41, 0x89, 0x86, 0x89, 0x96, 0x89, 0xbf,
-    0x8a, 0xf8, 0x8a, 0xcb, 0x8a, 0x01, 0x8b, 0xfe,
-    0x8a, 0xed, 0x8a, 0x39, 0x8b, 0x8a, 0x8b, 0x08,
-    0x8d, 0x38, 0x8f, 0x72, 0x90, 0x99, 0x91, 0x76,
-    0x92, 0x7c, 0x96, 0xe3, 0x96, 0x56, 0x97, 0xdb,
-    0x97, 0xff, 0x97, 0x0b, 0x98, 0x3b, 0x98, 0x12,
-    0x9b, 0x9c, 0x9f, 0x4a, 0x28, 0x44, 0x28, 0xd5,
-    0x33, 0x9d, 0x3b, 0x18, 0x40, 0x39, 0x40, 0x49,
-    0x52, 0xd0, 0x5c, 0xd3, 0x7e, 0x43, 0x9f, 0x8e,
-    0x9f, 0x2a, 0xa0, 0x02, 0x66, 0x66, 0x66, 0x69,
-    0x66, 0x6c, 0x66, 0x66, 0x69, 0x66, 0x66, 0x6c,
-    0x7f, 0x01, 0x74, 0x73, 0x00, 0x74, 0x65, 0x05,
-    0x0f, 0x11, 0x0f, 0x00, 0x0f, 0x06, 0x19, 0x11,
-    0x0f, 0x08, 0xd9, 0x05, 0xb4, 0x05, 0x00, 0x00,
-    0x00, 0x00, 0xf2, 0x05, 0xb7, 0x05, 0xd0, 0x05,
-    0x12, 0x00, 0x03, 0x04, 0x0b, 0x0c, 0x0d, 0x18,
-    0x1a, 0xe9, 0x05, 0xc1, 0x05, 0xe9, 0x05, 0xc2,
-    0x05, 0x49, 0xfb, 0xc1, 0x05, 0x49, 0xfb, 0xc2,
-    0x05, 0xd0, 0x05, 0xb7, 0x05, 0xd0, 0x05, 0xb8,
-    0x05, 0xd0, 0x05, 0xbc, 0x05, 0xd8, 0x05, 0xbc,
-    0x05, 0xde, 0x05, 0xbc, 0x05, 0xe0, 0x05, 0xbc,
-    0x05, 0xe3, 0x05, 0xbc, 0x05, 0xb9, 0x05, 0x2d,
-    0x03, 0x2e, 0x03, 0x2f, 0x03, 0x30, 0x03, 0x31,
-    0x03, 0x1c, 0x00, 0x18, 0x06, 0x22, 0x06, 0x2b,
-    0x06, 0xd0, 0x05, 0xdc, 0x05, 0x71, 0x06, 0x00,
-    0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0d, 0x0d, 0x0d,
-    0x0d, 0x0f, 0x0f, 0x0f, 0x0f, 0x09, 0x09, 0x09,
-    0x09, 0x0e, 0x0e, 0x0e, 0x0e, 0x08, 0x08, 0x08,
-    0x08, 0x33, 0x33, 0x33, 0x33, 0x35, 0x35, 0x35,
-    0x35, 0x13, 0x13, 0x13, 0x13, 0x12, 0x12, 0x12,
-    0x12, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16,
-    0x16, 0x1c, 0x1c, 0x1b, 0x1b, 0x1d, 0x1d, 0x17,
-    0x17, 0x27, 0x27, 0x20, 0x20, 0x38, 0x38, 0x38,
-    0x38, 0x3e, 0x3e, 0x3e, 0x3e, 0x42, 0x42, 0x42,
-    0x42, 0x40, 0x40, 0x40, 0x40, 0x49, 0x49, 0x4a,
-    0x4a, 0x4a, 0x4a, 0x4f, 0x4f, 0x50, 0x50, 0x50,
-    0x50, 0x4d, 0x4d, 0x4d, 0x4d, 0x61, 0x61, 0x62,
-    0x62, 0x49, 0x06, 0x64, 0x64, 0x64, 0x64, 0x7e,
-    0x7e, 0x7d, 0x7d, 0x7f, 0x7f, 0x2e, 0x82, 0x82,
-    0x7c, 0x7c, 0x80, 0x80, 0x87, 0x87, 0x87, 0x87,
-    0x00, 0x00, 0x26, 0x06, 0x00, 0x01, 0x00, 0x01,
-    0x00, 0xaf, 0x00, 0xaf, 0x00, 0x22, 0x00, 0x22,
-    0x00, 0xa1, 0x00, 0xa1, 0x00, 0xa0, 0x00, 0xa0,
-    0x00, 0xa2, 0x00, 0xa2, 0x00, 0xaa, 0x00, 0xaa,
-    0x00, 0xaa, 0x00, 0x23, 0x00, 0x23, 0x00, 0x23,
-    0xcc, 0x06, 0x00, 0x00, 0x00, 0x00, 0x26, 0x06,
-    0x00, 0x06, 0x00, 0x07, 0x00, 0x1f, 0x00, 0x23,
-    0x00, 0x24, 0x02, 0x06, 0x02, 0x07, 0x02, 0x08,
-    0x02, 0x1f, 0x02, 0x23, 0x02, 0x24, 0x04, 0x06,
-    0x04, 0x07, 0x04, 0x08, 0x04, 0x1f, 0x04, 0x23,
-    0x04, 0x24, 0x05, 0x06, 0x05, 0x1f, 0x05, 0x23,
-    0x05, 0x24, 0x06, 0x07, 0x06, 0x1f, 0x07, 0x06,
-    0x07, 0x1f, 0x08, 0x06, 0x08, 0x07, 0x08, 0x1f,
-    0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x08, 0x0d, 0x1f,
-    0x0f, 0x07, 0x0f, 0x1f, 0x10, 0x06, 0x10, 0x07,
-    0x10, 0x08, 0x10, 0x1f, 0x11, 0x07, 0x11, 0x1f,
-    0x12, 0x1f, 0x13, 0x06, 0x13, 0x1f, 0x14, 0x06,
-    0x14, 0x1f, 0x1b, 0x06, 0x1b, 0x07, 0x1b, 0x08,
-    0x1b, 0x1f, 0x1b, 0x23, 0x1b, 0x24, 0x1c, 0x07,
-    0x1c, 0x1f, 0x1c, 0x23, 0x1c, 0x24, 0x1d, 0x01,
-    0x1d, 0x06, 0x1d, 0x07, 0x1d, 0x08, 0x1d, 0x1e,
-    0x1d, 0x1f, 0x1d, 0x23, 0x1d, 0x24, 0x1e, 0x06,
-    0x1e, 0x07, 0x1e, 0x08, 0x1e, 0x1f, 0x1e, 0x23,
-    0x1e, 0x24, 0x1f, 0x06, 0x1f, 0x07, 0x1f, 0x08,
-    0x1f, 0x1f, 0x1f, 0x23, 0x1f, 0x24, 0x20, 0x06,
-    0x20, 0x07, 0x20, 0x08, 0x20, 0x1f, 0x20, 0x23,
-    0x20, 0x24, 0x21, 0x06, 0x21, 0x1f, 0x21, 0x23,
-    0x21, 0x24, 0x24, 0x06, 0x24, 0x07, 0x24, 0x08,
-    0x24, 0x1f, 0x24, 0x23, 0x24, 0x24, 0x0a, 0x4a,
-    0x0b, 0x4a, 0x23, 0x4a, 0x20, 0x00, 0x4c, 0x06,
-    0x51, 0x06, 0x51, 0x06, 0xff, 0x00, 0x1f, 0x26,
-    0x06, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x1f, 0x00,
-    0x20, 0x00, 0x23, 0x00, 0x24, 0x02, 0x0b, 0x02,
-    0x0c, 0x02, 0x1f, 0x02, 0x20, 0x02, 0x23, 0x02,
-    0x24, 0x04, 0x0b, 0x04, 0x0c, 0x04, 0x1f, 0x26,
-    0x06, 0x04, 0x20, 0x04, 0x23, 0x04, 0x24, 0x05,
-    0x0b, 0x05, 0x0c, 0x05, 0x1f, 0x05, 0x20, 0x05,
-    0x23, 0x05, 0x24, 0x1b, 0x23, 0x1b, 0x24, 0x1c,
-    0x23, 0x1c, 0x24, 0x1d, 0x01, 0x1d, 0x1e, 0x1d,
-    0x1f, 0x1d, 0x23, 0x1d, 0x24, 0x1e, 0x1f, 0x1e,
-    0x23, 0x1e, 0x24, 0x1f, 0x01, 0x1f, 0x1f, 0x20,
-    0x0b, 0x20, 0x0c, 0x20, 0x1f, 0x20, 0x20, 0x20,
-    0x23, 0x20, 0x24, 0x23, 0x4a, 0x24, 0x0b, 0x24,
-    0x0c, 0x24, 0x1f, 0x24, 0x20, 0x24, 0x23, 0x24,
-    0x24, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00,
-    0x1f, 0x00, 0x21, 0x02, 0x06, 0x02, 0x07, 0x02,
-    0x08, 0x02, 0x1f, 0x02, 0x21, 0x04, 0x06, 0x04,
-    0x07, 0x04, 0x08, 0x04, 0x1f, 0x04, 0x21, 0x05,
-    0x1f, 0x06, 0x07, 0x06, 0x1f, 0x07, 0x06, 0x07,
-    0x1f, 0x08, 0x06, 0x08, 0x1f, 0x0d, 0x06, 0x0d,
-    0x07, 0x0d, 0x08, 0x0d, 0x1f, 0x0f, 0x07, 0x0f,
-    0x08, 0x0f, 0x1f, 0x10, 0x06, 0x10, 0x07, 0x10,
-    0x08, 0x10, 0x1f, 0x11, 0x07, 0x12, 0x1f, 0x13,
-    0x06, 0x13, 0x1f, 0x14, 0x06, 0x14, 0x1f, 0x1b,
-    0x06, 0x1b, 0x07, 0x1b, 0x08, 0x1b, 0x1f, 0x1c,
-    0x07, 0x1c, 0x1f, 0x1d, 0x06, 0x1d, 0x07, 0x1d,
-    0x08, 0x1d, 0x1e, 0x1d, 0x1f, 0x1e, 0x06, 0x1e,
-    0x07, 0x1e, 0x08, 0x1e, 0x1f, 0x1e, 0x21, 0x1f,
-    0x06, 0x1f, 0x07, 0x1f, 0x08, 0x1f, 0x1f, 0x20,
-    0x06, 0x20, 0x07, 0x20, 0x08, 0x20, 0x1f, 0x20,
-    0x21, 0x21, 0x06, 0x21, 0x1f, 0x21, 0x4a, 0x24,
-    0x06, 0x24, 0x07, 0x24, 0x08, 0x24, 0x1f, 0x24,
-    0x21, 0x00, 0x1f, 0x00, 0x21, 0x02, 0x1f, 0x02,
-    0x21, 0x04, 0x1f, 0x04, 0x21, 0x05, 0x1f, 0x05,
-    0x21, 0x0d, 0x1f, 0x0d, 0x21, 0x0e, 0x1f, 0x0e,
-    0x21, 0x1d, 0x1e, 0x1d, 0x1f, 0x1e, 0x1f, 0x20,
-    0x1f, 0x20, 0x21, 0x24, 0x1f, 0x24, 0x21, 0x40,
-    0x06, 0x4e, 0x06, 0x51, 0x06, 0x27, 0x06, 0x10,
-    0x22, 0x10, 0x23, 0x12, 0x22, 0x12, 0x23, 0x13,
-    0x22, 0x13, 0x23, 0x0c, 0x22, 0x0c, 0x23, 0x0d,
-    0x22, 0x0d, 0x23, 0x06, 0x22, 0x06, 0x23, 0x05,
-    0x22, 0x05, 0x23, 0x07, 0x22, 0x07, 0x23, 0x0e,
-    0x22, 0x0e, 0x23, 0x0f, 0x22, 0x0f, 0x23, 0x0d,
-    0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e, 0x0d,
-    0x0a, 0x0c, 0x0a, 0x0e, 0x0a, 0x0f, 0x0a, 0x10,
-    0x22, 0x10, 0x23, 0x12, 0x22, 0x12, 0x23, 0x13,
-    0x22, 0x13, 0x23, 0x0c, 0x22, 0x0c, 0x23, 0x0d,
-    0x22, 0x0d, 0x23, 0x06, 0x22, 0x06, 0x23, 0x05,
-    0x22, 0x05, 0x23, 0x07, 0x22, 0x07, 0x23, 0x0e,
-    0x22, 0x0e, 0x23, 0x0f, 0x22, 0x0f, 0x23, 0x0d,
-    0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e, 0x0d,
-    0x0a, 0x0c, 0x0a, 0x0e, 0x0a, 0x0f, 0x0a, 0x0d,
-    0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e, 0x0c,
-    0x20, 0x0d, 0x20, 0x10, 0x1e, 0x0c, 0x05, 0x0c,
-    0x06, 0x0c, 0x07, 0x0d, 0x05, 0x0d, 0x06, 0x0d,
-    0x07, 0x10, 0x1e, 0x11, 0x1e, 0x00, 0x24, 0x00,
-    0x24, 0x2a, 0x06, 0x00, 0x02, 0x1b, 0x00, 0x03,
-    0x02, 0x00, 0x03, 0x02, 0x00, 0x03, 0x1b, 0x00,
-    0x04, 0x1b, 0x00, 0x1b, 0x02, 0x00, 0x1b, 0x03,
-    0x00, 0x1b, 0x04, 0x02, 0x1b, 0x03, 0x02, 0x1b,
-    0x03, 0x03, 0x1b, 0x20, 0x03, 0x1b, 0x1f, 0x09,
-    0x03, 0x02, 0x09, 0x02, 0x03, 0x09, 0x02, 0x1f,
-    0x09, 0x1b, 0x03, 0x09, 0x1b, 0x03, 0x09, 0x1b,
-    0x02, 0x09, 0x1b, 0x1b, 0x09, 0x1b, 0x1b, 0x0b,
-    0x03, 0x03, 0x0b, 0x03, 0x03, 0x0b, 0x1b, 0x1b,
-    0x0a, 0x03, 0x1b, 0x0a, 0x03, 0x1b, 0x0a, 0x02,
-    0x20, 0x0a, 0x1b, 0x04, 0x0a, 0x1b, 0x04, 0x0a,
-    0x1b, 0x1b, 0x0a, 0x1b, 0x1b, 0x0c, 0x03, 0x1f,
-    0x0c, 0x04, 0x1b, 0x0c, 0x04, 0x1b, 0x0d, 0x1b,
-    0x03, 0x0d, 0x1b, 0x03, 0x0d, 0x1b, 0x1b, 0x0d,
-    0x1b, 0x20, 0x0f, 0x02, 0x1b, 0x0f, 0x1b, 0x1b,
-    0x0f, 0x1b, 0x1b, 0x0f, 0x1b, 0x1f, 0x10, 0x1b,
-    0x1b, 0x10, 0x1b, 0x20, 0x10, 0x1b, 0x1f, 0x17,
-    0x04, 0x1b, 0x17, 0x04, 0x1b, 0x18, 0x1b, 0x03,
-    0x18, 0x1b, 0x1b, 0x1a, 0x03, 0x1b, 0x1a, 0x03,
-    0x20, 0x1a, 0x03, 0x1f, 0x1a, 0x02, 0x02, 0x1a,
-    0x02, 0x02, 0x1a, 0x04, 0x1b, 0x1a, 0x04, 0x1b,
-    0x1a, 0x1b, 0x03, 0x1a, 0x1b, 0x03, 0x1b, 0x03,
-    0x02, 0x1b, 0x03, 0x1b, 0x1b, 0x03, 0x20, 0x1b,
-    0x02, 0x03, 0x1b, 0x02, 0x1b, 0x1b, 0x04, 0x02,
-    0x1b, 0x04, 0x1b, 0x28, 0x06, 0x1d, 0x04, 0x06,
-    0x1f, 0x1d, 0x04, 0x1f, 0x1d, 0x1d, 0x1e, 0x05,
-    0x1d, 0x1e, 0x05, 0x21, 0x1e, 0x04, 0x1d, 0x1e,
-    0x04, 0x1d, 0x1e, 0x04, 0x21, 0x1e, 0x1d, 0x22,
-    0x1e, 0x1d, 0x21, 0x22, 0x1d, 0x1d, 0x22, 0x1d,
-    0x1d, 0x00, 0x06, 0x22, 0x02, 0x04, 0x22, 0x02,
-    0x04, 0x21, 0x02, 0x06, 0x22, 0x02, 0x06, 0x21,
-    0x02, 0x1d, 0x22, 0x02, 0x1d, 0x21, 0x04, 0x1d,
-    0x22, 0x04, 0x05, 0x21, 0x04, 0x1d, 0x21, 0x0b,
-    0x06, 0x21, 0x0d, 0x05, 0x22, 0x0c, 0x05, 0x22,
-    0x0e, 0x05, 0x22, 0x1c, 0x04, 0x22, 0x1c, 0x1d,
-    0x22, 0x22, 0x05, 0x22, 0x22, 0x04, 0x22, 0x22,
-    0x1d, 0x22, 0x1d, 0x1d, 0x22, 0x1a, 0x1d, 0x22,
-    0x1e, 0x05, 0x22, 0x1a, 0x1d, 0x05, 0x1c, 0x05,
-    0x1d, 0x11, 0x1d, 0x22, 0x1b, 0x1d, 0x22, 0x1e,
-    0x04, 0x05, 0x1d, 0x06, 0x22, 0x1c, 0x04, 0x1d,
-    0x1b, 0x1d, 0x1d, 0x1c, 0x04, 0x1d, 0x1e, 0x04,
-    0x05, 0x04, 0x05, 0x22, 0x05, 0x04, 0x22, 0x1d,
-    0x04, 0x22, 0x19, 0x1d, 0x22, 0x00, 0x05, 0x22,
-    0x1b, 0x1d, 0x1d, 0x11, 0x04, 0x1d, 0x0d, 0x1d,
-    0x1d, 0x0b, 0x06, 0x22, 0x1e, 0x04, 0x22, 0x35,
-    0x06, 0x00, 0x0f, 0x9d, 0x0d, 0x0f, 0x9d, 0x27,
-    0x06, 0x00, 0x1d, 0x1d, 0x20, 0x00, 0x1c, 0x01,
-    0x0a, 0x1e, 0x06, 0x1e, 0x08, 0x0e, 0x1d, 0x12,
-    0x1e, 0x0a, 0x0c, 0x21, 0x1d, 0x12, 0x1d, 0x23,
-    0x20, 0x21, 0x0c, 0x1d, 0x1e, 0x35, 0x06, 0x00,
-    0x0f, 0x14, 0x27, 0x06, 0x0e, 0x1d, 0x22, 0xff,
-    0x00, 0x1d, 0x1d, 0x20, 0xff, 0x12, 0x1d, 0x23,
-    0x20, 0xff, 0x21, 0x0c, 0x1d, 0x1e, 0x27, 0x06,
-    0x05, 0x1d, 0xff, 0x05, 0x1d, 0x00, 0x1d, 0x20,
-    0x27, 0x06, 0x0a, 0xa5, 0x00, 0x1d, 0x2c, 0x00,
-    0x01, 0x30, 0x02, 0x30, 0x3a, 0x00, 0x3b, 0x00,
-    0x21, 0x00, 0x3f, 0x00, 0x16, 0x30, 0x17, 0x30,
-    0x26, 0x20, 0x13, 0x20, 0x12, 0x01, 0x00, 0x5f,
-    0x5f, 0x28, 0x29, 0x7b, 0x7d, 0x08, 0x30, 0x0c,
-    0x0d, 0x08, 0x09, 0x02, 0x03, 0x00, 0x01, 0x04,
-    0x05, 0x06, 0x07, 0x5b, 0x00, 0x5d, 0x00, 0x3e,
-    0x20, 0x3e, 0x20, 0x3e, 0x20, 0x3e, 0x20, 0x5f,
-    0x00, 0x5f, 0x00, 0x5f, 0x00, 0x2c, 0x00, 0x01,
-    0x30, 0x2e, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x3a,
-    0x00, 0x3f, 0x00, 0x21, 0x00, 0x14, 0x20, 0x28,
-    0x00, 0x29, 0x00, 0x7b, 0x00, 0x7d, 0x00, 0x14,
-    0x30, 0x15, 0x30, 0x23, 0x26, 0x2a, 0x2b, 0x2d,
-    0x3c, 0x3e, 0x3d, 0x00, 0x5c, 0x24, 0x25, 0x40,
-    0x40, 0x06, 0xff, 0x0b, 0x00, 0x0b, 0xff, 0x0c,
-    0x20, 0x00, 0x4d, 0x06, 0x40, 0x06, 0xff, 0x0e,
-    0x00, 0x0e, 0xff, 0x0f, 0x00, 0x0f, 0xff, 0x10,
-    0x00, 0x10, 0xff, 0x11, 0x00, 0x11, 0xff, 0x12,
-    0x00, 0x12, 0x21, 0x06, 0x00, 0x01, 0x01, 0x02,
-    0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x05,
-    0x05, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08,
-    0x08, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a,
-    0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c,
-    0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f,
-    0x0f, 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x12,
-    0x12, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14,
-    0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16,
-    0x16, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18,
-    0x18, 0x19, 0x19, 0x19, 0x19, 0x20, 0x20, 0x20,
-    0x20, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22,
-    0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24,
-    0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26,
-    0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x29, 0x29,
-    0x29, 0x22, 0x06, 0x22, 0x00, 0x22, 0x00, 0x22,
-    0x01, 0x22, 0x01, 0x22, 0x03, 0x22, 0x03, 0x22,
-    0x05, 0x22, 0x05, 0x21, 0x00, 0x85, 0x29, 0x01,
-    0x30, 0x01, 0x0b, 0x0c, 0x00, 0xfa, 0xf1, 0xa0,
-    0xa2, 0xa4, 0xa6, 0xa8, 0xe2, 0xe4, 0xe6, 0xc2,
-    0xfb, 0xa1, 0xa3, 0xa5, 0xa7, 0xa9, 0xaa, 0xac,
-    0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc,
-    0xbe, 0xc0, 0xc3, 0xc5, 0xc7, 0xc9, 0xca, 0xcb,
-    0xcc, 0xcd, 0xce, 0xd1, 0xd4, 0xd7, 0xda, 0xdd,
-    0xde, 0xdf, 0xe0, 0xe1, 0xe3, 0xe5, 0xe7, 0xe8,
-    0xe9, 0xea, 0xeb, 0xec, 0xee, 0xf2, 0x98, 0x99,
-    0x31, 0x31, 0x4f, 0x31, 0x55, 0x31, 0x5b, 0x31,
-    0x61, 0x31, 0xa2, 0x00, 0xa3, 0x00, 0xac, 0x00,
-    0xaf, 0x00, 0xa6, 0x00, 0xa5, 0x00, 0xa9, 0x20,
-    0x00, 0x00, 0x02, 0x25, 0x90, 0x21, 0x91, 0x21,
-    0x92, 0x21, 0x93, 0x21, 0xa0, 0x25, 0xcb, 0x25,
-    0xd0, 0x02, 0xd1, 0x02, 0xe6, 0x00, 0x99, 0x02,
-    0x53, 0x02, 0x00, 0x00, 0xa3, 0x02, 0x66, 0xab,
-    0xa5, 0x02, 0xa4, 0x02, 0x56, 0x02, 0x57, 0x02,
-    0x91, 0x1d, 0x58, 0x02, 0x5e, 0x02, 0xa9, 0x02,
-    0x64, 0x02, 0x62, 0x02, 0x60, 0x02, 0x9b, 0x02,
-    0x27, 0x01, 0x9c, 0x02, 0x67, 0x02, 0x84, 0x02,
-    0xaa, 0x02, 0xab, 0x02, 0x6c, 0x02, 0x04, 0xdf,
-    0x8e, 0xa7, 0x6e, 0x02, 0x05, 0xdf, 0x8e, 0x02,
-    0x06, 0xdf, 0xf8, 0x00, 0x76, 0x02, 0x77, 0x02,
-    0x71, 0x00, 0x7a, 0x02, 0x08, 0xdf, 0x7d, 0x02,
-    0x7e, 0x02, 0x80, 0x02, 0xa8, 0x02, 0xa6, 0x02,
-    0x67, 0xab, 0xa7, 0x02, 0x88, 0x02, 0x71, 0x2c,
-    0x00, 0x00, 0x8f, 0x02, 0xa1, 0x02, 0xa2, 0x02,
-    0x98, 0x02, 0xc0, 0x01, 0xc1, 0x01, 0xc2, 0x01,
-    0x0a, 0xdf, 0x1e, 0xdf, 0x41, 0x04, 0x40, 0x00,
-    0x00, 0x00, 0x00, 0x14, 0x99, 0x10, 0xba, 0x10,
-    0x00, 0x00, 0x00, 0x00, 0x9b, 0x10, 0xba, 0x10,
-    0x05, 0x05, 0xa5, 0x10, 0xba, 0x10, 0x05, 0x31,
-    0x11, 0x27, 0x11, 0x32, 0x11, 0x27, 0x11, 0x55,
-    0x47, 0x13, 0x3e, 0x13, 0x47, 0x13, 0x57, 0x13,
-    0x55, 0xb9, 0x14, 0xba, 0x14, 0xb9, 0x14, 0xb0,
-    0x14, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x14, 0xbd,
-    0x14, 0x55, 0x50, 0xb8, 0x15, 0xaf, 0x15, 0xb9,
-    0x15, 0xaf, 0x15, 0x55, 0x35, 0x19, 0x30, 0x19,
-    0x05, 0x57, 0xd1, 0x65, 0xd1, 0x58, 0xd1, 0x65,
-    0xd1, 0x5f, 0xd1, 0x6e, 0xd1, 0x5f, 0xd1, 0x6f,
-    0xd1, 0x5f, 0xd1, 0x70, 0xd1, 0x5f, 0xd1, 0x71,
-    0xd1, 0x5f, 0xd1, 0x72, 0xd1, 0x55, 0x55, 0x55,
-    0x05, 0xb9, 0xd1, 0x65, 0xd1, 0xba, 0xd1, 0x65,
-    0xd1, 0xbb, 0xd1, 0x6e, 0xd1, 0xbc, 0xd1, 0x6e,
-    0xd1, 0xbb, 0xd1, 0x6f, 0xd1, 0xbc, 0xd1, 0x6f,
-    0xd1, 0x55, 0x55, 0x55, 0x41, 0x00, 0x61, 0x00,
-    0x41, 0x00, 0x61, 0x00, 0x69, 0x00, 0x41, 0x00,
-    0x61, 0x00, 0x41, 0x00, 0x43, 0x44, 0x00, 0x00,
-    0x47, 0x00, 0x00, 0x4a, 0x4b, 0x00, 0x00, 0x4e,
-    0x4f, 0x50, 0x51, 0x00, 0x53, 0x54, 0x55, 0x56,
-    0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64,
-    0x00, 0x66, 0x68, 0x00, 0x70, 0x00, 0x41, 0x00,
-    0x61, 0x00, 0x41, 0x42, 0x00, 0x44, 0x45, 0x46,
-    0x47, 0x4a, 0x00, 0x53, 0x00, 0x61, 0x00, 0x41,
-    0x42, 0x00, 0x44, 0x45, 0x46, 0x47, 0x00, 0x49,
-    0x4a, 0x4b, 0x4c, 0x4d, 0x00, 0x4f, 0x53, 0x00,
-    0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00,
-    0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00,
-    0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00,
-    0x61, 0x00, 0x31, 0x01, 0x37, 0x02, 0x91, 0x03,
-    0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00,
-    0x1f, 0x04, 0x20, 0x05, 0x91, 0x03, 0xa3, 0x03,
-    0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00, 0x1f, 0x04,
-    0x20, 0x05, 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03,
-    0xd1, 0x03, 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05,
-    0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03,
-    0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x91, 0x03,
-    0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00,
-    0x1f, 0x04, 0x20, 0x05, 0x0b, 0x0c, 0x30, 0x00,
-    0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00,
-    0x27, 0x06, 0x00, 0x01, 0x05, 0x08, 0x2a, 0x06,
-    0x1e, 0x08, 0x03, 0x0d, 0x20, 0x19, 0x1a, 0x1b,
-    0x1c, 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, 0x0a,
-    0x00, 0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10, 0x44,
-    0x90, 0x77, 0x45, 0x28, 0x06, 0x2c, 0x06, 0x00,
-    0x00, 0x47, 0x06, 0x33, 0x06, 0x17, 0x10, 0x11,
-    0x12, 0x13, 0x00, 0x06, 0x0e, 0x02, 0x0f, 0x34,
-    0x06, 0x2a, 0x06, 0x2b, 0x06, 0x2e, 0x06, 0x00,
-    0x00, 0x36, 0x06, 0x00, 0x00, 0x3a, 0x06, 0x2d,
-    0x06, 0x00, 0x00, 0x4a, 0x06, 0x00, 0x00, 0x44,
-    0x06, 0x00, 0x00, 0x46, 0x06, 0x33, 0x06, 0x39,
-    0x06, 0x00, 0x00, 0x35, 0x06, 0x42, 0x06, 0x00,
-    0x00, 0x34, 0x06, 0x00, 0x00, 0x00, 0x00, 0x2e,
-    0x06, 0x00, 0x00, 0x36, 0x06, 0x00, 0x00, 0x3a,
-    0x06, 0x00, 0x00, 0xba, 0x06, 0x00, 0x00, 0x6f,
-    0x06, 0x00, 0x00, 0x28, 0x06, 0x2c, 0x06, 0x00,
-    0x00, 0x47, 0x06, 0x00, 0x00, 0x00, 0x00, 0x2d,
-    0x06, 0x37, 0x06, 0x4a, 0x06, 0x43, 0x06, 0x00,
-    0x00, 0x45, 0x06, 0x46, 0x06, 0x33, 0x06, 0x39,
-    0x06, 0x41, 0x06, 0x35, 0x06, 0x42, 0x06, 0x00,
-    0x00, 0x34, 0x06, 0x2a, 0x06, 0x2b, 0x06, 0x2e,
-    0x06, 0x00, 0x00, 0x36, 0x06, 0x38, 0x06, 0x3a,
-    0x06, 0x6e, 0x06, 0x00, 0x00, 0xa1, 0x06, 0x27,
-    0x06, 0x00, 0x01, 0x05, 0x08, 0x20, 0x21, 0x0b,
-    0x06, 0x10, 0x23, 0x2a, 0x06, 0x1a, 0x1b, 0x1c,
-    0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, 0x0a, 0x00,
-    0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10, 0x28, 0x06,
-    0x2c, 0x06, 0x2f, 0x06, 0x00, 0x00, 0x48, 0x06,
-    0x32, 0x06, 0x2d, 0x06, 0x37, 0x06, 0x4a, 0x06,
-    0x2a, 0x06, 0x1a, 0x1b, 0x1c, 0x09, 0x0f, 0x17,
-    0x0b, 0x18, 0x07, 0x0a, 0x00, 0x01, 0x04, 0x06,
-    0x0c, 0x0e, 0x10, 0x30, 0x2e, 0x30, 0x00, 0x2c,
-    0x00, 0x28, 0x00, 0x41, 0x00, 0x29, 0x00, 0x14,
-    0x30, 0x53, 0x00, 0x15, 0x30, 0x43, 0x52, 0x43,
-    0x44, 0x57, 0x5a, 0x41, 0x00, 0x48, 0x56, 0x4d,
-    0x56, 0x53, 0x44, 0x53, 0x53, 0x50, 0x50, 0x56,
-    0x57, 0x43, 0x4d, 0x43, 0x4d, 0x44, 0x4d, 0x52,
-    0x44, 0x4a, 0x4b, 0x30, 0x30, 0x00, 0x68, 0x68,
-    0x4b, 0x62, 0x57, 0x5b, 0xcc, 0x53, 0xc7, 0x30,
-    0x8c, 0x4e, 0x1a, 0x59, 0xe3, 0x89, 0x29, 0x59,
-    0xa4, 0x4e, 0x20, 0x66, 0x21, 0x71, 0x99, 0x65,
-    0x4d, 0x52, 0x8c, 0x5f, 0x8d, 0x51, 0xb0, 0x65,
-    0x1d, 0x52, 0x42, 0x7d, 0x1f, 0x75, 0xa9, 0x8c,
-    0xf0, 0x58, 0x39, 0x54, 0x14, 0x6f, 0x95, 0x62,
-    0x55, 0x63, 0x00, 0x4e, 0x09, 0x4e, 0x4a, 0x90,
-    0xe6, 0x5d, 0x2d, 0x4e, 0xf3, 0x53, 0x07, 0x63,
-    0x70, 0x8d, 0x53, 0x62, 0x81, 0x79, 0x7a, 0x7a,
-    0x08, 0x54, 0x80, 0x6e, 0x09, 0x67, 0x08, 0x67,
-    0x33, 0x75, 0x72, 0x52, 0xb6, 0x55, 0x4d, 0x91,
-    0x14, 0x30, 0x15, 0x30, 0x2c, 0x67, 0x09, 0x4e,
-    0x8c, 0x4e, 0x89, 0x5b, 0xb9, 0x70, 0x53, 0x62,
-    0xd7, 0x76, 0xdd, 0x52, 0x57, 0x65, 0x97, 0x5f,
-    0xef, 0x53, 0x30, 0x00, 0x38, 0x4e, 0x05, 0x00,
-    0x09, 0x22, 0x01, 0x60, 0x4f, 0xae, 0x4f, 0xbb,
-    0x4f, 0x02, 0x50, 0x7a, 0x50, 0x99, 0x50, 0xe7,
-    0x50, 0xcf, 0x50, 0x9e, 0x34, 0x3a, 0x06, 0x4d,
-    0x51, 0x54, 0x51, 0x64, 0x51, 0x77, 0x51, 0x1c,
-    0x05, 0xb9, 0x34, 0x67, 0x51, 0x8d, 0x51, 0x4b,
-    0x05, 0x97, 0x51, 0xa4, 0x51, 0xcc, 0x4e, 0xac,
-    0x51, 0xb5, 0x51, 0xdf, 0x91, 0xf5, 0x51, 0x03,
-    0x52, 0xdf, 0x34, 0x3b, 0x52, 0x46, 0x52, 0x72,
-    0x52, 0x77, 0x52, 0x15, 0x35, 0x02, 0x00, 0x20,
-    0x80, 0x80, 0x00, 0x08, 0x00, 0x00, 0xc7, 0x52,
-    0x00, 0x02, 0x1d, 0x33, 0x3e, 0x3f, 0x50, 0x82,
-    0x8a, 0x93, 0xac, 0xb6, 0xb8, 0xb8, 0xb8, 0x2c,
-    0x0a, 0x70, 0x70, 0xca, 0x53, 0xdf, 0x53, 0x63,
-    0x0b, 0xeb, 0x53, 0xf1, 0x53, 0x06, 0x54, 0x9e,
-    0x54, 0x38, 0x54, 0x48, 0x54, 0x68, 0x54, 0xa2,
-    0x54, 0xf6, 0x54, 0x10, 0x55, 0x53, 0x55, 0x63,
-    0x55, 0x84, 0x55, 0x84, 0x55, 0x99, 0x55, 0xab,
-    0x55, 0xb3, 0x55, 0xc2, 0x55, 0x16, 0x57, 0x06,
-    0x56, 0x17, 0x57, 0x51, 0x56, 0x74, 0x56, 0x07,
-    0x52, 0xee, 0x58, 0xce, 0x57, 0xf4, 0x57, 0x0d,
-    0x58, 0x8b, 0x57, 0x32, 0x58, 0x31, 0x58, 0xac,
-    0x58, 0xe4, 0x14, 0xf2, 0x58, 0xf7, 0x58, 0x06,
-    0x59, 0x1a, 0x59, 0x22, 0x59, 0x62, 0x59, 0xa8,
-    0x16, 0xea, 0x16, 0xec, 0x59, 0x1b, 0x5a, 0x27,
-    0x5a, 0xd8, 0x59, 0x66, 0x5a, 0xee, 0x36, 0xfc,
-    0x36, 0x08, 0x5b, 0x3e, 0x5b, 0x3e, 0x5b, 0xc8,
-    0x19, 0xc3, 0x5b, 0xd8, 0x5b, 0xe7, 0x5b, 0xf3,
-    0x5b, 0x18, 0x1b, 0xff, 0x5b, 0x06, 0x5c, 0x53,
-    0x5f, 0x22, 0x5c, 0x81, 0x37, 0x60, 0x5c, 0x6e,
-    0x5c, 0xc0, 0x5c, 0x8d, 0x5c, 0xe4, 0x1d, 0x43,
-    0x5d, 0xe6, 0x1d, 0x6e, 0x5d, 0x6b, 0x5d, 0x7c,
-    0x5d, 0xe1, 0x5d, 0xe2, 0x5d, 0x2f, 0x38, 0xfd,
-    0x5d, 0x28, 0x5e, 0x3d, 0x5e, 0x69, 0x5e, 0x62,
-    0x38, 0x83, 0x21, 0x7c, 0x38, 0xb0, 0x5e, 0xb3,
-    0x5e, 0xb6, 0x5e, 0xca, 0x5e, 0x92, 0xa3, 0xfe,
-    0x5e, 0x31, 0x23, 0x31, 0x23, 0x01, 0x82, 0x22,
-    0x5f, 0x22, 0x5f, 0xc7, 0x38, 0xb8, 0x32, 0xda,
-    0x61, 0x62, 0x5f, 0x6b, 0x5f, 0xe3, 0x38, 0x9a,
-    0x5f, 0xcd, 0x5f, 0xd7, 0x5f, 0xf9, 0x5f, 0x81,
-    0x60, 0x3a, 0x39, 0x1c, 0x39, 0x94, 0x60, 0xd4,
-    0x26, 0xc7, 0x60, 0x02, 0x02, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0a, 0x00,
-    0x00, 0x02, 0x08, 0x00, 0x80, 0x08, 0x00, 0x00,
-    0x08, 0x80, 0x28, 0x80, 0x02, 0x00, 0x00, 0x02,
-    0x48, 0x61, 0x00, 0x04, 0x06, 0x04, 0x32, 0x46,
-    0x6a, 0x5c, 0x67, 0x96, 0xaa, 0xae, 0xc8, 0xd3,
-    0x5d, 0x62, 0x00, 0x54, 0x77, 0xf3, 0x0c, 0x2b,
-    0x3d, 0x63, 0xfc, 0x62, 0x68, 0x63, 0x83, 0x63,
-    0xe4, 0x63, 0xf1, 0x2b, 0x22, 0x64, 0xc5, 0x63,
-    0xa9, 0x63, 0x2e, 0x3a, 0x69, 0x64, 0x7e, 0x64,
-    0x9d, 0x64, 0x77, 0x64, 0x6c, 0x3a, 0x4f, 0x65,
-    0x6c, 0x65, 0x0a, 0x30, 0xe3, 0x65, 0xf8, 0x66,
-    0x49, 0x66, 0x19, 0x3b, 0x91, 0x66, 0x08, 0x3b,
-    0xe4, 0x3a, 0x92, 0x51, 0x95, 0x51, 0x00, 0x67,
-    0x9c, 0x66, 0xad, 0x80, 0xd9, 0x43, 0x17, 0x67,
-    0x1b, 0x67, 0x21, 0x67, 0x5e, 0x67, 0x53, 0x67,
-    0xc3, 0x33, 0x49, 0x3b, 0xfa, 0x67, 0x85, 0x67,
-    0x52, 0x68, 0x85, 0x68, 0x6d, 0x34, 0x8e, 0x68,
-    0x1f, 0x68, 0x14, 0x69, 0x9d, 0x3b, 0x42, 0x69,
-    0xa3, 0x69, 0xea, 0x69, 0xa8, 0x6a, 0xa3, 0x36,
-    0xdb, 0x6a, 0x18, 0x3c, 0x21, 0x6b, 0xa7, 0x38,
-    0x54, 0x6b, 0x4e, 0x3c, 0x72, 0x6b, 0x9f, 0x6b,
-    0xba, 0x6b, 0xbb, 0x6b, 0x8d, 0x3a, 0x0b, 0x1d,
-    0xfa, 0x3a, 0x4e, 0x6c, 0xbc, 0x3c, 0xbf, 0x6c,
-    0xcd, 0x6c, 0x67, 0x6c, 0x16, 0x6d, 0x3e, 0x6d,
-    0x77, 0x6d, 0x41, 0x6d, 0x69, 0x6d, 0x78, 0x6d,
-    0x85, 0x6d, 0x1e, 0x3d, 0x34, 0x6d, 0x2f, 0x6e,
-    0x6e, 0x6e, 0x33, 0x3d, 0xcb, 0x6e, 0xc7, 0x6e,
-    0xd1, 0x3e, 0xf9, 0x6d, 0x6e, 0x6f, 0x5e, 0x3f,
-    0x8e, 0x3f, 0xc6, 0x6f, 0x39, 0x70, 0x1e, 0x70,
-    0x1b, 0x70, 0x96, 0x3d, 0x4a, 0x70, 0x7d, 0x70,
-    0x77, 0x70, 0xad, 0x70, 0x25, 0x05, 0x45, 0x71,
-    0x63, 0x42, 0x9c, 0x71, 0xab, 0x43, 0x28, 0x72,
-    0x35, 0x72, 0x50, 0x72, 0x08, 0x46, 0x80, 0x72,
-    0x95, 0x72, 0x35, 0x47, 0x02, 0x20, 0x00, 0x00,
-    0x20, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00,
-    0x00, 0x02, 0x02, 0x80, 0x8a, 0x00, 0x00, 0x20,
-    0x00, 0x08, 0x0a, 0x00, 0x80, 0x88, 0x80, 0x20,
-    0x14, 0x48, 0x7a, 0x73, 0x8b, 0x73, 0xac, 0x3e,
-    0xa5, 0x73, 0xb8, 0x3e, 0xb8, 0x3e, 0x47, 0x74,
-    0x5c, 0x74, 0x71, 0x74, 0x85, 0x74, 0xca, 0x74,
-    0x1b, 0x3f, 0x24, 0x75, 0x36, 0x4c, 0x3e, 0x75,
-    0x92, 0x4c, 0x70, 0x75, 0x9f, 0x21, 0x10, 0x76,
-    0xa1, 0x4f, 0xb8, 0x4f, 0x44, 0x50, 0xfc, 0x3f,
-    0x08, 0x40, 0xf4, 0x76, 0xf3, 0x50, 0xf2, 0x50,
-    0x19, 0x51, 0x33, 0x51, 0x1e, 0x77, 0x1f, 0x77,
-    0x1f, 0x77, 0x4a, 0x77, 0x39, 0x40, 0x8b, 0x77,
-    0x46, 0x40, 0x96, 0x40, 0x1d, 0x54, 0x4e, 0x78,
-    0x8c, 0x78, 0xcc, 0x78, 0xe3, 0x40, 0x26, 0x56,
-    0x56, 0x79, 0x9a, 0x56, 0xc5, 0x56, 0x8f, 0x79,
-    0xeb, 0x79, 0x2f, 0x41, 0x40, 0x7a, 0x4a, 0x7a,
-    0x4f, 0x7a, 0x7c, 0x59, 0xa7, 0x5a, 0xa7, 0x5a,
-    0xee, 0x7a, 0x02, 0x42, 0xab, 0x5b, 0xc6, 0x7b,
-    0xc9, 0x7b, 0x27, 0x42, 0x80, 0x5c, 0xd2, 0x7c,
-    0xa0, 0x42, 0xe8, 0x7c, 0xe3, 0x7c, 0x00, 0x7d,
-    0x86, 0x5f, 0x63, 0x7d, 0x01, 0x43, 0xc7, 0x7d,
-    0x02, 0x7e, 0x45, 0x7e, 0x34, 0x43, 0x28, 0x62,
-    0x47, 0x62, 0x59, 0x43, 0xd9, 0x62, 0x7a, 0x7f,
-    0x3e, 0x63, 0x95, 0x7f, 0xfa, 0x7f, 0x05, 0x80,
-    0xda, 0x64, 0x23, 0x65, 0x60, 0x80, 0xa8, 0x65,
-    0x70, 0x80, 0x5f, 0x33, 0xd5, 0x43, 0xb2, 0x80,
-    0x03, 0x81, 0x0b, 0x44, 0x3e, 0x81, 0xb5, 0x5a,
-    0xa7, 0x67, 0xb5, 0x67, 0x93, 0x33, 0x9c, 0x33,
-    0x01, 0x82, 0x04, 0x82, 0x9e, 0x8f, 0x6b, 0x44,
-    0x91, 0x82, 0x8b, 0x82, 0x9d, 0x82, 0xb3, 0x52,
-    0xb1, 0x82, 0xb3, 0x82, 0xbd, 0x82, 0xe6, 0x82,
-    0x3c, 0x6b, 0xe5, 0x82, 0x1d, 0x83, 0x63, 0x83,
-    0xad, 0x83, 0x23, 0x83, 0xbd, 0x83, 0xe7, 0x83,
-    0x57, 0x84, 0x53, 0x83, 0xca, 0x83, 0xcc, 0x83,
-    0xdc, 0x83, 0x36, 0x6c, 0x6b, 0x6d, 0x02, 0x00,
-    0x00, 0x20, 0x22, 0x2a, 0xa0, 0x0a, 0x00, 0x20,
-    0x80, 0x28, 0x00, 0xa8, 0x20, 0x20, 0x00, 0x02,
-    0x80, 0x22, 0x02, 0x8a, 0x08, 0x00, 0xaa, 0x00,
-    0x00, 0x00, 0x02, 0x00, 0x00, 0x28, 0xd5, 0x6c,
-    0x2b, 0x45, 0xf1, 0x84, 0xf3, 0x84, 0x16, 0x85,
-    0xca, 0x73, 0x64, 0x85, 0x2c, 0x6f, 0x5d, 0x45,
-    0x61, 0x45, 0xb1, 0x6f, 0xd2, 0x70, 0x6b, 0x45,
-    0x50, 0x86, 0x5c, 0x86, 0x67, 0x86, 0x69, 0x86,
-    0xa9, 0x86, 0x88, 0x86, 0x0e, 0x87, 0xe2, 0x86,
-    0x79, 0x87, 0x28, 0x87, 0x6b, 0x87, 0x86, 0x87,
-    0xd7, 0x45, 0xe1, 0x87, 0x01, 0x88, 0xf9, 0x45,
-    0x60, 0x88, 0x63, 0x88, 0x67, 0x76, 0xd7, 0x88,
-    0xde, 0x88, 0x35, 0x46, 0xfa, 0x88, 0xbb, 0x34,
-    0xae, 0x78, 0x66, 0x79, 0xbe, 0x46, 0xc7, 0x46,
-    0xa0, 0x8a, 0xed, 0x8a, 0x8a, 0x8b, 0x55, 0x8c,
-    0xa8, 0x7c, 0xab, 0x8c, 0xc1, 0x8c, 0x1b, 0x8d,
-    0x77, 0x8d, 0x2f, 0x7f, 0x04, 0x08, 0xcb, 0x8d,
-    0xbc, 0x8d, 0xf0, 0x8d, 0xde, 0x08, 0xd4, 0x8e,
-    0x38, 0x8f, 0xd2, 0x85, 0xed, 0x85, 0x94, 0x90,
-    0xf1, 0x90, 0x11, 0x91, 0x2e, 0x87, 0x1b, 0x91,
-    0x38, 0x92, 0xd7, 0x92, 0xd8, 0x92, 0x7c, 0x92,
-    0xf9, 0x93, 0x15, 0x94, 0xfa, 0x8b, 0x8b, 0x95,
-    0x95, 0x49, 0xb7, 0x95, 0x77, 0x8d, 0xe6, 0x49,
-    0xc3, 0x96, 0xb2, 0x5d, 0x23, 0x97, 0x45, 0x91,
-    0x1a, 0x92, 0x6e, 0x4a, 0x76, 0x4a, 0xe0, 0x97,
-    0x0a, 0x94, 0xb2, 0x4a, 0x96, 0x94, 0x0b, 0x98,
-    0x0b, 0x98, 0x29, 0x98, 0xb6, 0x95, 0xe2, 0x98,
-    0x33, 0x4b, 0x29, 0x99, 0xa7, 0x99, 0xc2, 0x99,
-    0xfe, 0x99, 0xce, 0x4b, 0x30, 0x9b, 0x12, 0x9b,
-    0x40, 0x9c, 0xfd, 0x9c, 0xce, 0x4c, 0xed, 0x4c,
-    0x67, 0x9d, 0xce, 0xa0, 0xf8, 0x4c, 0x05, 0xa1,
-    0x0e, 0xa2, 0x91, 0xa2, 0xbb, 0x9e, 0x56, 0x4d,
-    0xf9, 0x9e, 0xfe, 0x9e, 0x05, 0x9f, 0x0f, 0x9f,
-    0x16, 0x9f, 0x3b, 0x9f, 0x00, 0xa6, 0x02, 0x88,
-    0xa0, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x28,
-    0x00, 0x08, 0xa0, 0x80, 0xa0, 0x80, 0x00, 0x80,
-    0x80, 0x00, 0x0a, 0x88, 0x80, 0x00, 0x80, 0x00,
-    0x20, 0x2a, 0x00, 0x80,
-};
-
-static const uint16_t unicode_comp_table[945] = {
-    0x4a01, 0x49c0, 0x4a02, 0x0280, 0x0281, 0x0282, 0x0283, 0x02c0,
-    0x02c2, 0x0a00, 0x0284, 0x2442, 0x0285, 0x07c0, 0x0980, 0x0982,
-    0x2440, 0x2280, 0x02c4, 0x2282, 0x2284, 0x2286, 0x02c6, 0x02c8,
-    0x02ca, 0x02cc, 0x0287, 0x228a, 0x02ce, 0x228c, 0x2290, 0x2292,
-    0x228e, 0x0288, 0x0289, 0x028a, 0x2482, 0x0300, 0x0302, 0x0304,
-    0x028b, 0x2480, 0x0308, 0x0984, 0x0986, 0x2458, 0x0a02, 0x0306,
-    0x2298, 0x229a, 0x229e, 0x0900, 0x030a, 0x22a0, 0x030c, 0x030e,
-    0x0840, 0x0310, 0x0312, 0x22a2, 0x22a6, 0x09c0, 0x22a4, 0x22a8,
-    0x22aa, 0x028c, 0x028d, 0x028e, 0x0340, 0x0342, 0x0344, 0x0380,
-    0x028f, 0x248e, 0x07c2, 0x0988, 0x098a, 0x2490, 0x0346, 0x22ac,
-    0x0400, 0x22b0, 0x0842, 0x22b2, 0x0402, 0x22b4, 0x0440, 0x0444,
-    0x22b6, 0x0442, 0x22c2, 0x22c0, 0x22c4, 0x22c6, 0x22c8, 0x0940,
-    0x04c0, 0x0291, 0x22ca, 0x04c4, 0x22cc, 0x04c2, 0x22d0, 0x22ce,
-    0x0292, 0x0293, 0x0294, 0x0295, 0x0540, 0x0542, 0x0a08, 0x0296,
-    0x2494, 0x0544, 0x07c4, 0x098c, 0x098e, 0x06c0, 0x2492, 0x0844,
-    0x2308, 0x230a, 0x0580, 0x230c, 0x0584, 0x0990, 0x0992, 0x230e,
-    0x0582, 0x2312, 0x0586, 0x0588, 0x2314, 0x058c, 0x2316, 0x0998,
-    0x058a, 0x231e, 0x0590, 0x2320, 0x099a, 0x058e, 0x2324, 0x2322,
-    0x0299, 0x029a, 0x029b, 0x05c0, 0x05c2, 0x05c4, 0x029c, 0x24ac,
-    0x05c6, 0x05c8, 0x07c6, 0x0994, 0x0996, 0x0700, 0x24aa, 0x2326,
-    0x05ca, 0x232a, 0x2328, 0x2340, 0x2342, 0x2344, 0x2346, 0x05cc,
-    0x234a, 0x2348, 0x234c, 0x234e, 0x2350, 0x24b8, 0x029d, 0x05ce,
-    0x24be, 0x0a0c, 0x2352, 0x0600, 0x24bc, 0x24ba, 0x0640, 0x2354,
-    0x0642, 0x0644, 0x2356, 0x2358, 0x02a0, 0x02a1, 0x02a2, 0x02a3,
-    0x02c1, 0x02c3, 0x0a01, 0x02a4, 0x2443, 0x02a5, 0x07c1, 0x0981,
-    0x0983, 0x2441, 0x2281, 0x02c5, 0x2283, 0x2285, 0x2287, 0x02c7,
-    0x02c9, 0x02cb, 0x02cd, 0x02a7, 0x228b, 0x02cf, 0x228d, 0x2291,
-    0x2293, 0x228f, 0x02a8, 0x02a9, 0x02aa, 0x2483, 0x0301, 0x0303,
-    0x0305, 0x02ab, 0x2481, 0x0309, 0x0985, 0x0987, 0x2459, 0x0a03,
-    0x0307, 0x2299, 0x229b, 0x229f, 0x0901, 0x030b, 0x22a1, 0x030d,
-    0x030f, 0x0841, 0x0311, 0x0313, 0x22a3, 0x22a7, 0x09c1, 0x22a5,
-    0x22a9, 0x22ab, 0x2380, 0x02ac, 0x02ad, 0x02ae, 0x0341, 0x0343,
-    0x0345, 0x02af, 0x248f, 0x07c3, 0x0989, 0x098b, 0x2491, 0x0347,
-    0x22ad, 0x0401, 0x0884, 0x22b1, 0x0843, 0x22b3, 0x0403, 0x22b5,
-    0x0441, 0x0445, 0x22b7, 0x0443, 0x22c3, 0x22c1, 0x22c5, 0x22c7,
-    0x22c9, 0x0941, 0x04c1, 0x02b1, 0x22cb, 0x04c5, 0x22cd, 0x04c3,
-    0x22d1, 0x22cf, 0x02b2, 0x02b3, 0x02b4, 0x02b5, 0x0541, 0x0543,
-    0x0a09, 0x02b6, 0x2495, 0x0545, 0x07c5, 0x098d, 0x098f, 0x06c1,
-    0x2493, 0x0845, 0x2309, 0x230b, 0x0581, 0x230d, 0x0585, 0x0991,
-    0x0993, 0x230f, 0x0583, 0x2313, 0x0587, 0x0589, 0x2315, 0x058d,
-    0x2317, 0x0999, 0x058b, 0x231f, 0x2381, 0x0591, 0x2321, 0x099b,
-    0x058f, 0x2325, 0x2323, 0x02b9, 0x02ba, 0x02bb, 0x05c1, 0x05c3,
-    0x05c5, 0x02bc, 0x24ad, 0x05c7, 0x05c9, 0x07c7, 0x0995, 0x0997,
-    0x0701, 0x24ab, 0x2327, 0x05cb, 0x232b, 0x2329, 0x2341, 0x2343,
-    0x2345, 0x2347, 0x05cd, 0x234b, 0x2349, 0x2382, 0x234d, 0x234f,
-    0x2351, 0x24b9, 0x02bd, 0x05cf, 0x24bf, 0x0a0d, 0x2353, 0x02bf,
-    0x24bd, 0x2383, 0x24bb, 0x0641, 0x2355, 0x0643, 0x0645, 0x2357,
-    0x2359, 0x3101, 0x0c80, 0x2e00, 0x2446, 0x2444, 0x244a, 0x2448,
-    0x0800, 0x0942, 0x0944, 0x0804, 0x2288, 0x2486, 0x2484, 0x248a,
-    0x2488, 0x22ae, 0x2498, 0x2496, 0x249c, 0x249a, 0x2300, 0x0a06,
-    0x2302, 0x0a04, 0x0946, 0x07ce, 0x07ca, 0x07c8, 0x07cc, 0x2447,
-    0x2445, 0x244b, 0x2449, 0x0801, 0x0943, 0x0945, 0x0805, 0x2289,
-    0x2487, 0x2485, 0x248b, 0x2489, 0x22af, 0x2499, 0x2497, 0x249d,
-    0x249b, 0x2301, 0x0a07, 0x2303, 0x0a05, 0x0947, 0x07cf, 0x07cb,
-    0x07c9, 0x07cd, 0x2450, 0x244e, 0x2454, 0x2452, 0x2451, 0x244f,
-    0x2455, 0x2453, 0x2294, 0x2296, 0x2295, 0x2297, 0x2304, 0x2306,
-    0x2305, 0x2307, 0x2318, 0x2319, 0x231a, 0x231b, 0x232c, 0x232d,
-    0x232e, 0x232f, 0x2400, 0x24a2, 0x24a0, 0x24a6, 0x24a4, 0x24a8,
-    0x24a3, 0x24a1, 0x24a7, 0x24a5, 0x24a9, 0x24b0, 0x24ae, 0x24b4,
-    0x24b2, 0x24b6, 0x24b1, 0x24af, 0x24b5, 0x24b3, 0x24b7, 0x0882,
-    0x0880, 0x0881, 0x0802, 0x0803, 0x229c, 0x229d, 0x0a0a, 0x0a0b,
-    0x0883, 0x0b40, 0x2c8a, 0x0c81, 0x2c89, 0x2c88, 0x2540, 0x2541,
-    0x2d00, 0x2e07, 0x0d00, 0x2640, 0x2641, 0x2e80, 0x0d01, 0x26c8,
-    0x26c9, 0x2f00, 0x2f84, 0x0d02, 0x2f83, 0x2f82, 0x0d40, 0x26d8,
-    0x26d9, 0x3186, 0x0d04, 0x2740, 0x2741, 0x3100, 0x3086, 0x0d06,
-    0x3085, 0x3084, 0x0d41, 0x2840, 0x3200, 0x0d07, 0x284f, 0x2850,
-    0x3280, 0x2c84, 0x2e03, 0x2857, 0x0d42, 0x2c81, 0x2c80, 0x24c0,
-    0x24c1, 0x2c86, 0x2c83, 0x28c0, 0x0d43, 0x25c0, 0x25c1, 0x2940,
-    0x0d44, 0x26c0, 0x26c1, 0x2e05, 0x2e02, 0x29c0, 0x0d45, 0x2f05,
-    0x2f04, 0x0d80, 0x26d0, 0x26d1, 0x2f80, 0x2a40, 0x0d82, 0x26e0,
-    0x26e1, 0x3080, 0x3081, 0x2ac0, 0x0d83, 0x3004, 0x3003, 0x0d81,
-    0x27c0, 0x27c1, 0x3082, 0x2b40, 0x0d84, 0x2847, 0x2848, 0x3184,
-    0x3181, 0x2f06, 0x0d08, 0x2f81, 0x3005, 0x0d46, 0x3083, 0x3182,
-    0x0e00, 0x0e01, 0x0f40, 0x1180, 0x1182, 0x0f03, 0x0f00, 0x11c0,
-    0x0f01, 0x1140, 0x1202, 0x1204, 0x0f81, 0x1240, 0x0fc0, 0x1242,
-    0x0f80, 0x1244, 0x1284, 0x0f82, 0x1286, 0x1288, 0x128a, 0x12c0,
-    0x1282, 0x1181, 0x1183, 0x1043, 0x1040, 0x11c1, 0x1041, 0x1141,
-    0x1203, 0x1205, 0x10c1, 0x1241, 0x1000, 0x1243, 0x10c0, 0x1245,
-    0x1285, 0x10c2, 0x1287, 0x1289, 0x128b, 0x12c1, 0x1283, 0x1080,
-    0x1100, 0x1101, 0x1200, 0x1201, 0x1280, 0x1281, 0x1340, 0x1341,
-    0x1343, 0x1342, 0x1344, 0x13c2, 0x1400, 0x13c0, 0x1440, 0x1480,
-    0x14c0, 0x1540, 0x1541, 0x1740, 0x1700, 0x1741, 0x17c0, 0x1800,
-    0x1802, 0x1801, 0x1840, 0x1880, 0x1900, 0x18c0, 0x18c1, 0x1901,
-    0x1940, 0x1942, 0x1941, 0x1980, 0x19c0, 0x19c2, 0x19c1, 0x1c80,
-    0x1cc0, 0x1dc0, 0x1f80, 0x2000, 0x2002, 0x2004, 0x2006, 0x2008,
-    0x2040, 0x2080, 0x2082, 0x20c0, 0x20c1, 0x2100, 0x22b8, 0x22b9,
-    0x2310, 0x2311, 0x231c, 0x231d, 0x244c, 0x2456, 0x244d, 0x2457,
-    0x248c, 0x248d, 0x249e, 0x249f, 0x2500, 0x2502, 0x2504, 0x2bc0,
-    0x2501, 0x2503, 0x2505, 0x2bc1, 0x2bc2, 0x2bc3, 0x2bc4, 0x2bc5,
-    0x2bc6, 0x2bc7, 0x2580, 0x2582, 0x2584, 0x2bc8, 0x2581, 0x2583,
-    0x2585, 0x2bc9, 0x2bca, 0x2bcb, 0x2bcc, 0x2bcd, 0x2bce, 0x2bcf,
-    0x2600, 0x2602, 0x2601, 0x2603, 0x2680, 0x2682, 0x2681, 0x2683,
-    0x26c2, 0x26c4, 0x26c6, 0x2c00, 0x26c3, 0x26c5, 0x26c7, 0x2c01,
-    0x2c02, 0x2c03, 0x2c04, 0x2c05, 0x2c06, 0x2c07, 0x26ca, 0x26cc,
-    0x26ce, 0x2c08, 0x26cb, 0x26cd, 0x26cf, 0x2c09, 0x2c0a, 0x2c0b,
-    0x2c0c, 0x2c0d, 0x2c0e, 0x2c0f, 0x26d2, 0x26d4, 0x26d6, 0x26d3,
-    0x26d5, 0x26d7, 0x26da, 0x26dc, 0x26de, 0x26db, 0x26dd, 0x26df,
-    0x2700, 0x2702, 0x2701, 0x2703, 0x2780, 0x2782, 0x2781, 0x2783,
-    0x2800, 0x2802, 0x2804, 0x2801, 0x2803, 0x2805, 0x2842, 0x2844,
-    0x2846, 0x2849, 0x284b, 0x284d, 0x2c40, 0x284a, 0x284c, 0x284e,
-    0x2c41, 0x2c42, 0x2c43, 0x2c44, 0x2c45, 0x2c46, 0x2c47, 0x2851,
-    0x2853, 0x2855, 0x2c48, 0x2852, 0x2854, 0x2856, 0x2c49, 0x2c4a,
-    0x2c4b, 0x2c4c, 0x2c4d, 0x2c4e, 0x2c4f, 0x2c82, 0x2e01, 0x3180,
-    0x2c87, 0x2f01, 0x2f02, 0x2f03, 0x2e06, 0x3185, 0x3000, 0x3001,
-    0x3002, 0x4640, 0x4641, 0x4680, 0x46c0, 0x46c2, 0x46c1, 0x4700,
-    0x4740, 0x4780, 0x47c0, 0x47c2, 0x4900, 0x4940, 0x4980, 0x4982,
-    0x4a00, 0x49c2, 0x4a03, 0x4a04, 0x4a40, 0x4a41, 0x4a80, 0x4a81,
-    0x4ac0, 0x4ac1, 0x4bc0, 0x4bc1, 0x4b00, 0x4b01, 0x4b40, 0x4b41,
-    0x4bc2, 0x4bc3, 0x4b80, 0x4b81, 0x4b82, 0x4b83, 0x4c00, 0x4c01,
-    0x4c02, 0x4c03, 0x5600, 0x5440, 0x5442, 0x5444, 0x5446, 0x5448,
-    0x544a, 0x544c, 0x544e, 0x5450, 0x5452, 0x5454, 0x5456, 0x5480,
-    0x5482, 0x5484, 0x54c0, 0x54c1, 0x5500, 0x5501, 0x5540, 0x5541,
-    0x5580, 0x5581, 0x55c0, 0x55c1, 0x5680, 0x58c0, 0x5700, 0x5702,
-    0x5704, 0x5706, 0x5708, 0x570a, 0x570c, 0x570e, 0x5710, 0x5712,
-    0x5714, 0x5716, 0x5740, 0x5742, 0x5744, 0x5780, 0x5781, 0x57c0,
-    0x57c1, 0x5800, 0x5801, 0x5840, 0x5841, 0x5880, 0x5881, 0x5900,
-    0x5901, 0x5902, 0x5903, 0x5940, 0x8f40, 0x8f42, 0x8f80, 0x8fc0,
-    0x8fc1, 0x9000, 0x9001, 0x9041, 0x9040, 0x9043, 0x9080, 0x9081,
-    0x90c0,
-};
-
-typedef enum {
-    UNICODE_GC_Cn,
-    UNICODE_GC_Lu,
-    UNICODE_GC_Ll,
-    UNICODE_GC_Lt,
-    UNICODE_GC_Lm,
-    UNICODE_GC_Lo,
-    UNICODE_GC_Mn,
-    UNICODE_GC_Mc,
-    UNICODE_GC_Me,
-    UNICODE_GC_Nd,
-    UNICODE_GC_Nl,
-    UNICODE_GC_No,
-    UNICODE_GC_Sm,
-    UNICODE_GC_Sc,
-    UNICODE_GC_Sk,
-    UNICODE_GC_So,
-    UNICODE_GC_Pc,
-    UNICODE_GC_Pd,
-    UNICODE_GC_Ps,
-    UNICODE_GC_Pe,
-    UNICODE_GC_Pi,
-    UNICODE_GC_Pf,
-    UNICODE_GC_Po,
-    UNICODE_GC_Zs,
-    UNICODE_GC_Zl,
-    UNICODE_GC_Zp,
-    UNICODE_GC_Cc,
-    UNICODE_GC_Cf,
-    UNICODE_GC_Cs,
-    UNICODE_GC_Co,
-    UNICODE_GC_LC,
-    UNICODE_GC_L,
-    UNICODE_GC_M,
-    UNICODE_GC_N,
-    UNICODE_GC_S,
-    UNICODE_GC_P,
-    UNICODE_GC_Z,
-    UNICODE_GC_C,
-    UNICODE_GC_COUNT,
-} UnicodeGCEnum;
-
-static const char unicode_gc_name_table[] =
-    "Cn,Unassigned"            "\0"
-    "Lu,Uppercase_Letter"      "\0"
-    "Ll,Lowercase_Letter"      "\0"
-    "Lt,Titlecase_Letter"      "\0"
-    "Lm,Modifier_Letter"       "\0"
-    "Lo,Other_Letter"          "\0"
-    "Mn,Nonspacing_Mark"       "\0"
-    "Mc,Spacing_Mark"          "\0"
-    "Me,Enclosing_Mark"        "\0"
-    "Nd,Decimal_Number,digit"  "\0"
-    "Nl,Letter_Number"         "\0"
-    "No,Other_Number"          "\0"
-    "Sm,Math_Symbol"           "\0"
-    "Sc,Currency_Symbol"       "\0"
-    "Sk,Modifier_Symbol"       "\0"
-    "So,Other_Symbol"          "\0"
-    "Pc,Connector_Punctuation" "\0"
-    "Pd,Dash_Punctuation"      "\0"
-    "Ps,Open_Punctuation"      "\0"
-    "Pe,Close_Punctuation"     "\0"
-    "Pi,Initial_Punctuation"   "\0"
-    "Pf,Final_Punctuation"     "\0"
-    "Po,Other_Punctuation"     "\0"
-    "Zs,Space_Separator"       "\0"
-    "Zl,Line_Separator"        "\0"
-    "Zp,Paragraph_Separator"   "\0"
-    "Cc,Control,cntrl"         "\0"
-    "Cf,Format"                "\0"
-    "Cs,Surrogate"             "\0"
-    "Co,Private_Use"           "\0"
-    "LC,Cased_Letter"          "\0"
-    "L,Letter"                 "\0"
-    "M,Mark,Combining_Mark"    "\0"
-    "N,Number"                 "\0"
-    "S,Symbol"                 "\0"
-    "P,Punctuation,punct"      "\0"
-    "Z,Separator"              "\0"
-    "C,Other"                  "\0"
-;
-
-static const uint8_t unicode_gc_table[3897] = {
-    0xfa, 0x18, 0x17, 0x56, 0x0d, 0x56, 0x12, 0x13,
-    0x16, 0x0c, 0x16, 0x11, 0x36, 0xe9, 0x02, 0x36,
-    0x4c, 0x36, 0xe1, 0x12, 0x12, 0x16, 0x13, 0x0e,
-    0x10, 0x0e, 0xe2, 0x12, 0x12, 0x0c, 0x13, 0x0c,
-    0xfa, 0x19, 0x17, 0x16, 0x6d, 0x0f, 0x16, 0x0e,
-    0x0f, 0x05, 0x14, 0x0c, 0x1b, 0x0f, 0x0e, 0x0f,
-    0x0c, 0x2b, 0x0e, 0x02, 0x36, 0x0e, 0x0b, 0x05,
-    0x15, 0x4b, 0x16, 0xe1, 0x0f, 0x0c, 0xc1, 0xe2,
-    0x10, 0x0c, 0xe2, 0x00, 0xff, 0x30, 0x02, 0xff,
-    0x08, 0x02, 0xff, 0x27, 0xbf, 0x22, 0x21, 0x02,
-    0x5f, 0x5f, 0x21, 0x22, 0x61, 0x02, 0x21, 0x02,
-    0x41, 0x42, 0x21, 0x02, 0x21, 0x02, 0x9f, 0x7f,
-    0x02, 0x5f, 0x5f, 0x21, 0x02, 0x5f, 0x3f, 0x02,
-    0x05, 0x3f, 0x22, 0x65, 0x01, 0x03, 0x02, 0x01,
-    0x03, 0x02, 0x01, 0x03, 0x02, 0xff, 0x08, 0x02,
-    0xff, 0x0a, 0x02, 0x01, 0x03, 0x02, 0x5f, 0x21,
-    0x02, 0xff, 0x32, 0xa2, 0x21, 0x02, 0x21, 0x22,
-    0x5f, 0x41, 0x02, 0xff, 0x00, 0xe2, 0x3c, 0x05,
-    0xe2, 0x13, 0xe4, 0x0a, 0x6e, 0xe4, 0x04, 0xee,
-    0x06, 0x84, 0xce, 0x04, 0x0e, 0x04, 0xee, 0x09,
-    0xe6, 0x68, 0x7f, 0x04, 0x0e, 0x3f, 0x20, 0x04,
-    0x42, 0x16, 0x01, 0x60, 0x2e, 0x01, 0x16, 0x41,
-    0x00, 0x01, 0x00, 0x21, 0x02, 0xe1, 0x09, 0x00,
-    0xe1, 0x01, 0xe2, 0x1b, 0x3f, 0x02, 0x41, 0x42,
-    0xff, 0x10, 0x62, 0x3f, 0x0c, 0x5f, 0x3f, 0x02,
-    0xe1, 0x2b, 0xe2, 0x28, 0xff, 0x1a, 0x0f, 0x86,
-    0x28, 0xff, 0x2f, 0xff, 0x06, 0x02, 0xff, 0x58,
-    0x00, 0xe1, 0x1e, 0x20, 0x04, 0xb6, 0xe2, 0x21,
-    0x16, 0x11, 0x20, 0x2f, 0x0d, 0x00, 0xe6, 0x25,
-    0x11, 0x06, 0x16, 0x26, 0x16, 0x26, 0x16, 0x06,
-    0xe0, 0x00, 0xe5, 0x13, 0x60, 0x65, 0x36, 0xe0,
-    0x03, 0xbb, 0x4c, 0x36, 0x0d, 0x36, 0x2f, 0xe6,
-    0x03, 0x16, 0x1b, 0x56, 0xe5, 0x18, 0x04, 0xe5,
-    0x02, 0xe6, 0x0d, 0xe9, 0x02, 0x76, 0x25, 0x06,
-    0xe5, 0x5b, 0x16, 0x05, 0xc6, 0x1b, 0x0f, 0xa6,
-    0x24, 0x26, 0x0f, 0x66, 0x25, 0xe9, 0x02, 0x45,
-    0x2f, 0x05, 0xf6, 0x06, 0x00, 0x1b, 0x05, 0x06,
-    0xe5, 0x16, 0xe6, 0x13, 0x20, 0xe5, 0x51, 0xe6,
-    0x03, 0x05, 0xe0, 0x06, 0xe9, 0x02, 0xe5, 0x19,
-    0xe6, 0x01, 0x24, 0x0f, 0x56, 0x04, 0x20, 0x06,
-    0x2d, 0xe5, 0x0e, 0x66, 0x04, 0xe6, 0x01, 0x04,
-    0x46, 0x04, 0x86, 0x20, 0xf6, 0x07, 0x00, 0xe5,
-    0x11, 0x46, 0x20, 0x16, 0x00, 0xe5, 0x03, 0x80,
-    0xe5, 0x10, 0x0e, 0xa5, 0x00, 0x3b, 0xa0, 0xe6,
-    0x00, 0xe5, 0x21, 0x04, 0xe6, 0x10, 0x1b, 0xe6,
-    0x18, 0x07, 0xe5, 0x2e, 0x06, 0x07, 0x06, 0x05,
-    0x47, 0xe6, 0x00, 0x67, 0x06, 0x27, 0x05, 0xc6,
-    0xe5, 0x02, 0x26, 0x36, 0xe9, 0x02, 0x16, 0x04,
-    0xe5, 0x07, 0x06, 0x27, 0x00, 0xe5, 0x00, 0x20,
-    0x25, 0x20, 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x05,
-    0x40, 0x65, 0x20, 0x06, 0x05, 0x47, 0x66, 0x20,
-    0x27, 0x20, 0x27, 0x06, 0x05, 0xe0, 0x00, 0x07,
-    0x60, 0x25, 0x00, 0x45, 0x26, 0x20, 0xe9, 0x02,
-    0x25, 0x2d, 0xab, 0x0f, 0x0d, 0x05, 0x16, 0x06,
-    0x20, 0x26, 0x07, 0x00, 0xa5, 0x60, 0x25, 0x20,
-    0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00, 0x25,
-    0x00, 0x25, 0x20, 0x06, 0x00, 0x47, 0x26, 0x60,
-    0x26, 0x20, 0x46, 0x40, 0x06, 0xc0, 0x65, 0x00,
-    0x05, 0xc0, 0xe9, 0x02, 0x26, 0x45, 0x06, 0x16,
-    0xe0, 0x02, 0x26, 0x07, 0x00, 0xe5, 0x01, 0x00,
-    0x45, 0x00, 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25,
-    0x00, 0x85, 0x20, 0x06, 0x05, 0x47, 0x86, 0x00,
-    0x26, 0x07, 0x00, 0x27, 0x06, 0x20, 0x05, 0xe0,
-    0x07, 0x25, 0x26, 0x20, 0xe9, 0x02, 0x16, 0x0d,
-    0xc0, 0x05, 0xa6, 0x00, 0x06, 0x27, 0x00, 0xe5,
-    0x00, 0x20, 0x25, 0x20, 0xe5, 0x0e, 0x00, 0xc5,
-    0x00, 0x25, 0x00, 0x85, 0x20, 0x06, 0x05, 0x07,
-    0x06, 0x07, 0x66, 0x20, 0x27, 0x20, 0x27, 0x06,
-    0xc0, 0x26, 0x07, 0x60, 0x25, 0x00, 0x45, 0x26,
-    0x20, 0xe9, 0x02, 0x0f, 0x05, 0xab, 0xe0, 0x02,
-    0x06, 0x05, 0x00, 0xa5, 0x40, 0x45, 0x00, 0x65,
-    0x40, 0x25, 0x00, 0x05, 0x00, 0x25, 0x40, 0x25,
-    0x40, 0x45, 0x40, 0xe5, 0x04, 0x60, 0x27, 0x06,
-    0x27, 0x40, 0x47, 0x00, 0x47, 0x06, 0x20, 0x05,
-    0xa0, 0x07, 0xe0, 0x06, 0xe9, 0x02, 0x4b, 0xaf,
-    0x0d, 0x0f, 0x80, 0x06, 0x47, 0x06, 0xe5, 0x00,
-    0x00, 0x45, 0x00, 0xe5, 0x0f, 0x00, 0xe5, 0x08,
-    0x20, 0x06, 0x05, 0x46, 0x67, 0x00, 0x46, 0x00,
-    0x66, 0xc0, 0x26, 0x00, 0x45, 0x20, 0x05, 0x20,
-    0x25, 0x26, 0x20, 0xe9, 0x02, 0xc0, 0x16, 0xcb,
-    0x0f, 0x05, 0x06, 0x27, 0x16, 0xe5, 0x00, 0x00,
-    0x45, 0x00, 0xe5, 0x0f, 0x00, 0xe5, 0x02, 0x00,
-    0x85, 0x20, 0x06, 0x05, 0x07, 0x06, 0x87, 0x00,
-    0x06, 0x27, 0x00, 0x27, 0x26, 0xc0, 0x27, 0xa0,
-    0x25, 0x00, 0x25, 0x26, 0x20, 0xe9, 0x02, 0x00,
-    0x25, 0xe0, 0x05, 0x26, 0x27, 0xe5, 0x01, 0x00,
-    0x45, 0x00, 0xe5, 0x21, 0x26, 0x05, 0x47, 0x66,
-    0x00, 0x47, 0x00, 0x47, 0x06, 0x05, 0x0f, 0x60,
-    0x45, 0x07, 0xcb, 0x45, 0x26, 0x20, 0xe9, 0x02,
-    0xeb, 0x01, 0x0f, 0xa5, 0x00, 0x06, 0x27, 0x00,
-    0xe5, 0x0a, 0x40, 0xe5, 0x10, 0x00, 0xe5, 0x01,
-    0x00, 0x05, 0x20, 0xc5, 0x40, 0x06, 0x60, 0x47,
-    0x46, 0x00, 0x06, 0x00, 0xe7, 0x00, 0xa0, 0xe9,
-    0x02, 0x20, 0x27, 0x16, 0xe0, 0x04, 0xe5, 0x28,
-    0x06, 0x25, 0xc6, 0x60, 0x0d, 0xa5, 0x04, 0xe6,
-    0x00, 0x16, 0xe9, 0x02, 0x36, 0xe0, 0x1d, 0x25,
-    0x00, 0x05, 0x00, 0x85, 0x00, 0xe5, 0x10, 0x00,
-    0x05, 0x00, 0xe5, 0x02, 0x06, 0x25, 0xe6, 0x01,
-    0x05, 0x20, 0x85, 0x00, 0x04, 0x00, 0xa6, 0x20,
-    0xe9, 0x02, 0x20, 0x65, 0xe0, 0x18, 0x05, 0x4f,
-    0xf6, 0x07, 0x0f, 0x16, 0x4f, 0x26, 0xaf, 0xe9,
-    0x02, 0xeb, 0x02, 0x0f, 0x06, 0x0f, 0x06, 0x0f,
-    0x06, 0x12, 0x13, 0x12, 0x13, 0x27, 0xe5, 0x00,
-    0x00, 0xe5, 0x1c, 0x60, 0xe6, 0x06, 0x07, 0x86,
-    0x16, 0x26, 0x85, 0xe6, 0x03, 0x00, 0xe6, 0x1c,
-    0x00, 0xef, 0x00, 0x06, 0xaf, 0x00, 0x2f, 0x96,
-    0x6f, 0x36, 0xe0, 0x1d, 0xe5, 0x23, 0x27, 0x66,
-    0x07, 0xa6, 0x07, 0x26, 0x27, 0x26, 0x05, 0xe9,
-    0x02, 0xb6, 0xa5, 0x27, 0x26, 0x65, 0x46, 0x05,
-    0x47, 0x25, 0xc7, 0x45, 0x66, 0xe5, 0x05, 0x06,
-    0x27, 0x26, 0xa7, 0x06, 0x05, 0x07, 0xe9, 0x02,
-    0x47, 0x06, 0x2f, 0xe1, 0x1e, 0x00, 0x01, 0x80,
-    0x01, 0x20, 0xe2, 0x23, 0x16, 0x04, 0x42, 0xe5,
-    0x80, 0xc1, 0x00, 0x65, 0x20, 0xc5, 0x00, 0x05,
-    0x00, 0x65, 0x20, 0xe5, 0x21, 0x00, 0x65, 0x20,
-    0xe5, 0x19, 0x00, 0x65, 0x20, 0xc5, 0x00, 0x05,
-    0x00, 0x65, 0x20, 0xe5, 0x07, 0x00, 0xe5, 0x31,
-    0x00, 0x65, 0x20, 0xe5, 0x3b, 0x20, 0x46, 0xf6,
-    0x01, 0xeb, 0x0c, 0x40, 0xe5, 0x08, 0xef, 0x02,
-    0xa0, 0xe1, 0x4e, 0x20, 0xa2, 0x20, 0x11, 0xe5,
-    0x81, 0xe4, 0x0f, 0x16, 0xe5, 0x09, 0x17, 0xe5,
-    0x12, 0x12, 0x13, 0x40, 0xe5, 0x43, 0x56, 0x4a,
-    0xe5, 0x00, 0xc0, 0xe5, 0x0a, 0x46, 0x07, 0xe0,
-    0x01, 0xe5, 0x0b, 0x26, 0x07, 0x36, 0xe0, 0x01,
-    0xe5, 0x0a, 0x26, 0xe0, 0x04, 0xe5, 0x05, 0x00,
-    0x45, 0x00, 0x26, 0xe0, 0x04, 0xe5, 0x2c, 0x26,
-    0x07, 0xc6, 0xe7, 0x00, 0x06, 0x27, 0xe6, 0x03,
-    0x56, 0x04, 0x56, 0x0d, 0x05, 0x06, 0x20, 0xe9,
-    0x02, 0xa0, 0xeb, 0x02, 0xa0, 0xb6, 0x11, 0x76,
-    0x46, 0x1b, 0x06, 0xe9, 0x02, 0xa0, 0xe5, 0x1b,
-    0x04, 0xe5, 0x2d, 0xc0, 0x85, 0x26, 0xe5, 0x1a,
-    0x06, 0x05, 0x80, 0xe5, 0x3e, 0xe0, 0x02, 0xe5,
-    0x17, 0x00, 0x46, 0x67, 0x26, 0x47, 0x60, 0x27,
-    0x06, 0xa7, 0x46, 0x60, 0x0f, 0x40, 0x36, 0xe9,
-    0x02, 0xe5, 0x16, 0x20, 0x85, 0xe0, 0x03, 0xe5,
-    0x24, 0x60, 0xe5, 0x12, 0xa0, 0xe9, 0x02, 0x0b,
-    0x40, 0xef, 0x1a, 0xe5, 0x0f, 0x26, 0x27, 0x06,
-    0x20, 0x36, 0xe5, 0x2d, 0x07, 0x06, 0x07, 0xc6,
-    0x00, 0x06, 0x07, 0x06, 0x27, 0xe6, 0x00, 0xa7,
-    0xe6, 0x02, 0x20, 0x06, 0xe9, 0x02, 0xa0, 0xe9,
-    0x02, 0xa0, 0xd6, 0x04, 0xb6, 0x20, 0xe6, 0x06,
-    0x08, 0xe6, 0x08, 0xe0, 0x29, 0x66, 0x07, 0xe5,
-    0x27, 0x06, 0x07, 0x86, 0x07, 0x06, 0x87, 0x06,
-    0x27, 0xe5, 0x00, 0x40, 0xe9, 0x02, 0xd6, 0xef,
-    0x02, 0xe6, 0x01, 0xef, 0x01, 0x36, 0x00, 0x26,
-    0x07, 0xe5, 0x16, 0x07, 0x66, 0x27, 0x26, 0x07,
-    0x46, 0x25, 0xe9, 0x02, 0xe5, 0x24, 0x06, 0x07,
-    0x26, 0x47, 0x06, 0x07, 0x46, 0x27, 0xe0, 0x00,
-    0x76, 0xe5, 0x1c, 0xe7, 0x00, 0xe6, 0x00, 0x27,
-    0x26, 0x40, 0x96, 0xe9, 0x02, 0x40, 0x45, 0xe9,
-    0x02, 0xe5, 0x16, 0xa4, 0x36, 0xe2, 0x01, 0xc0,
-    0xe1, 0x23, 0x20, 0x41, 0xf6, 0x00, 0xe0, 0x00,
-    0x46, 0x16, 0xe6, 0x05, 0x07, 0xc6, 0x65, 0x06,
-    0xa5, 0x06, 0x25, 0x07, 0x26, 0x05, 0x80, 0xe2,
-    0x24, 0xe4, 0x37, 0xe2, 0x05, 0x04, 0xe2, 0x1a,
-    0xe4, 0x1d, 0xe6, 0x38, 0xff, 0x80, 0x0e, 0xe2,
-    0x00, 0xff, 0x5a, 0xe2, 0x00, 0xe1, 0x00, 0xa2,
-    0x20, 0xa1, 0x20, 0xe2, 0x00, 0xe1, 0x00, 0xe2,
-    0x00, 0xe1, 0x00, 0xa2, 0x20, 0xa1, 0x20, 0xe2,
-    0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
-    0x3f, 0xc2, 0xe1, 0x00, 0xe2, 0x06, 0x20, 0xe2,
-    0x00, 0xe3, 0x00, 0xe2, 0x00, 0xe3, 0x00, 0xe2,
-    0x00, 0xe3, 0x00, 0x82, 0x00, 0x22, 0x61, 0x03,
-    0x0e, 0x02, 0x4e, 0x42, 0x00, 0x22, 0x61, 0x03,
-    0x4e, 0x62, 0x20, 0x22, 0x61, 0x00, 0x4e, 0xe2,
-    0x00, 0x81, 0x4e, 0x20, 0x42, 0x00, 0x22, 0x61,
-    0x03, 0x2e, 0x00, 0xf7, 0x03, 0x9b, 0xb1, 0x36,
-    0x14, 0x15, 0x12, 0x34, 0x15, 0x12, 0x14, 0xf6,
-    0x00, 0x18, 0x19, 0x9b, 0x17, 0xf6, 0x01, 0x14,
-    0x15, 0x76, 0x30, 0x56, 0x0c, 0x12, 0x13, 0xf6,
-    0x03, 0x0c, 0x16, 0x10, 0xf6, 0x02, 0x17, 0x9b,
-    0x00, 0xfb, 0x02, 0x0b, 0x04, 0x20, 0xab, 0x4c,
-    0x12, 0x13, 0x04, 0xeb, 0x02, 0x4c, 0x12, 0x13,
-    0x00, 0xe4, 0x05, 0x40, 0xed, 0x19, 0xe0, 0x07,
-    0xe6, 0x05, 0x68, 0x06, 0x48, 0xe6, 0x04, 0xe0,
-    0x07, 0x2f, 0x01, 0x6f, 0x01, 0x2f, 0x02, 0x41,
-    0x22, 0x41, 0x02, 0x0f, 0x01, 0x2f, 0x0c, 0x81,
-    0xaf, 0x01, 0x0f, 0x01, 0x0f, 0x01, 0x0f, 0x61,
-    0x0f, 0x02, 0x61, 0x02, 0x65, 0x02, 0x2f, 0x22,
-    0x21, 0x8c, 0x3f, 0x42, 0x0f, 0x0c, 0x2f, 0x02,
-    0x0f, 0xeb, 0x08, 0xea, 0x1b, 0x3f, 0x6a, 0x0b,
-    0x2f, 0x60, 0x8c, 0x8f, 0x2c, 0x6f, 0x0c, 0x2f,
-    0x0c, 0x2f, 0x0c, 0xcf, 0x0c, 0xef, 0x17, 0x2c,
-    0x2f, 0x0c, 0x0f, 0x0c, 0xef, 0x17, 0xec, 0x80,
-    0x84, 0xef, 0x00, 0x12, 0x13, 0x12, 0x13, 0xef,
-    0x0c, 0x2c, 0xcf, 0x12, 0x13, 0xef, 0x49, 0x0c,
-    0xef, 0x16, 0xec, 0x11, 0xef, 0x20, 0xac, 0xef,
-    0x3d, 0xe0, 0x11, 0xef, 0x03, 0xe0, 0x0d, 0xeb,
-    0x34, 0xef, 0x46, 0xeb, 0x0e, 0xef, 0x80, 0x2f,
-    0x0c, 0xef, 0x01, 0x0c, 0xef, 0x2e, 0xec, 0x00,
-    0xef, 0x67, 0x0c, 0xef, 0x80, 0x70, 0x12, 0x13,
-    0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
-    0x12, 0x13, 0x12, 0x13, 0xeb, 0x16, 0xef, 0x24,
-    0x8c, 0x12, 0x13, 0xec, 0x17, 0x12, 0x13, 0x12,
-    0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0xec,
-    0x08, 0xef, 0x80, 0x78, 0xec, 0x7b, 0x12, 0x13,
-    0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
-    0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
-    0x12, 0x13, 0x12, 0x13, 0xec, 0x37, 0x12, 0x13,
-    0x12, 0x13, 0xec, 0x18, 0x12, 0x13, 0xec, 0x80,
-    0x7a, 0xef, 0x28, 0xec, 0x0d, 0x2f, 0xac, 0xef,
-    0x1f, 0x20, 0xef, 0x18, 0x00, 0xef, 0x61, 0xe1,
-    0x28, 0xe2, 0x28, 0x5f, 0x21, 0x22, 0xdf, 0x41,
-    0x02, 0x3f, 0x02, 0x3f, 0x82, 0x24, 0x41, 0x02,
-    0xff, 0x5a, 0x02, 0xaf, 0x7f, 0x46, 0x3f, 0x80,
-    0x76, 0x0b, 0x36, 0xe2, 0x1e, 0x00, 0x02, 0x80,
-    0x02, 0x20, 0xe5, 0x30, 0xc0, 0x04, 0x16, 0xe0,
-    0x06, 0x06, 0xe5, 0x0f, 0xe0, 0x01, 0xc5, 0x00,
-    0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00,
-    0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xe6, 0x18,
-    0x36, 0x14, 0x15, 0x14, 0x15, 0x56, 0x14, 0x15,
-    0x16, 0x14, 0x15, 0xf6, 0x01, 0x11, 0x36, 0x11,
-    0x16, 0x14, 0x15, 0x36, 0x14, 0x15, 0x12, 0x13,
-    0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x96, 0x04,
-    0xf6, 0x02, 0x31, 0x76, 0x11, 0x16, 0x12, 0xf6,
-    0x05, 0x2f, 0x56, 0x12, 0x13, 0x12, 0x13, 0x12,
-    0x13, 0x12, 0x13, 0x11, 0xe0, 0x1a, 0xef, 0x12,
-    0x00, 0xef, 0x51, 0xe0, 0x04, 0xef, 0x80, 0x4e,
-    0xe0, 0x12, 0xef, 0x04, 0x60, 0x17, 0x56, 0x0f,
-    0x04, 0x05, 0x0a, 0x12, 0x13, 0x12, 0x13, 0x12,
-    0x13, 0x12, 0x13, 0x12, 0x13, 0x2f, 0x12, 0x13,
-    0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x11, 0x12,
-    0x33, 0x0f, 0xea, 0x01, 0x66, 0x27, 0x11, 0x84,
-    0x2f, 0x4a, 0x04, 0x05, 0x16, 0x2f, 0x00, 0xe5,
-    0x4e, 0x20, 0x26, 0x2e, 0x24, 0x05, 0x11, 0xe5,
-    0x52, 0x16, 0x44, 0x05, 0x80, 0xe5, 0x23, 0x00,
-    0xe5, 0x56, 0x00, 0x2f, 0x6b, 0xef, 0x02, 0xe5,
-    0x18, 0xef, 0x1c, 0xe0, 0x04, 0xe5, 0x08, 0xef,
-    0x17, 0x00, 0xeb, 0x02, 0xef, 0x16, 0xeb, 0x00,
-    0x0f, 0xeb, 0x07, 0xef, 0x18, 0xeb, 0x02, 0xef,
-    0x1f, 0xeb, 0x07, 0xef, 0x80, 0xb8, 0xe5, 0x99,
-    0x38, 0xef, 0x38, 0xe5, 0xc0, 0x11, 0x8d, 0x04,
-    0xe5, 0x83, 0xef, 0x40, 0xef, 0x2f, 0xe0, 0x01,
-    0xe5, 0x20, 0xa4, 0x36, 0xe5, 0x80, 0x84, 0x04,
-    0x56, 0xe5, 0x08, 0xe9, 0x02, 0x25, 0xe0, 0x0c,
-    0xff, 0x26, 0x05, 0x06, 0x48, 0x16, 0xe6, 0x02,
-    0x16, 0x04, 0xff, 0x14, 0x24, 0x26, 0xe5, 0x3e,
-    0xea, 0x02, 0x26, 0xb6, 0xe0, 0x00, 0xee, 0x0f,
-    0xe4, 0x01, 0x2e, 0xff, 0x06, 0x22, 0xff, 0x36,
-    0x04, 0xe2, 0x00, 0x9f, 0xff, 0x02, 0x04, 0x2e,
-    0x7f, 0x05, 0x7f, 0x22, 0xff, 0x0d, 0x61, 0x02,
-    0x81, 0x02, 0xff, 0x07, 0x41, 0x02, 0x3f, 0x80,
-    0x3f, 0x00, 0x02, 0x00, 0x02, 0x7f, 0xe0, 0x10,
-    0x44, 0x3f, 0x05, 0x24, 0x02, 0xc5, 0x06, 0x45,
-    0x06, 0x65, 0x06, 0xe5, 0x0f, 0x27, 0x26, 0x07,
-    0x6f, 0x06, 0x40, 0xab, 0x2f, 0x0d, 0x0f, 0xa0,
-    0xe5, 0x2c, 0x76, 0xe0, 0x00, 0x27, 0xe5, 0x2a,
-    0xe7, 0x08, 0x26, 0xe0, 0x00, 0x36, 0xe9, 0x02,
-    0xa0, 0xe6, 0x0a, 0xa5, 0x56, 0x05, 0x16, 0x25,
-    0x06, 0xe9, 0x02, 0xe5, 0x14, 0xe6, 0x00, 0x36,
-    0xe5, 0x0f, 0xe6, 0x03, 0x27, 0xe0, 0x03, 0x16,
-    0xe5, 0x15, 0x40, 0x46, 0x07, 0xe5, 0x27, 0x06,
-    0x27, 0x66, 0x27, 0x26, 0x47, 0xf6, 0x05, 0x00,
-    0x04, 0xe9, 0x02, 0x60, 0x36, 0x85, 0x06, 0x04,
-    0xe5, 0x01, 0xe9, 0x02, 0x85, 0x00, 0xe5, 0x21,
-    0xa6, 0x27, 0x26, 0x27, 0x26, 0xe0, 0x01, 0x45,
-    0x06, 0xe5, 0x00, 0x06, 0x07, 0x20, 0xe9, 0x02,
-    0x20, 0x76, 0xe5, 0x08, 0x04, 0xa5, 0x4f, 0x05,
-    0x07, 0x06, 0x07, 0xe5, 0x2a, 0x06, 0x05, 0x46,
-    0x25, 0x26, 0x85, 0x26, 0x05, 0x06, 0x05, 0xe0,
-    0x10, 0x25, 0x04, 0x36, 0xe5, 0x03, 0x07, 0x26,
-    0x27, 0x36, 0x05, 0x24, 0x07, 0x06, 0xe0, 0x02,
-    0xa5, 0x20, 0xa5, 0x20, 0xa5, 0xe0, 0x01, 0xc5,
-    0x00, 0xc5, 0x00, 0xe2, 0x23, 0x0e, 0x64, 0xe2,
-    0x01, 0x04, 0x2e, 0x60, 0xe2, 0x48, 0xe5, 0x1b,
-    0x27, 0x06, 0x27, 0x06, 0x27, 0x16, 0x07, 0x06,
-    0x20, 0xe9, 0x02, 0xa0, 0xe5, 0xab, 0x1c, 0xe0,
-    0x04, 0xe5, 0x0f, 0x60, 0xe5, 0x29, 0x60, 0xfc,
-    0x87, 0x78, 0xfd, 0x98, 0x78, 0xe5, 0x80, 0xe6,
-    0x20, 0xe5, 0x62, 0xe0, 0x1e, 0xc2, 0xe0, 0x04,
-    0x82, 0x80, 0x05, 0x06, 0xe5, 0x02, 0x0c, 0xe5,
-    0x05, 0x00, 0x85, 0x00, 0x05, 0x00, 0x25, 0x00,
-    0x25, 0x00, 0xe5, 0x64, 0xee, 0x09, 0xe0, 0x08,
-    0xe5, 0x80, 0xe3, 0x13, 0x12, 0xef, 0x08, 0xe5,
-    0x38, 0x20, 0xe5, 0x2e, 0xc0, 0x0f, 0xe0, 0x18,
-    0xe5, 0x04, 0x0d, 0x4f, 0xe6, 0x08, 0xd6, 0x12,
-    0x13, 0x16, 0xa0, 0xe6, 0x08, 0x16, 0x31, 0x30,
-    0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
-    0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,
-    0x36, 0x12, 0x13, 0x76, 0x50, 0x56, 0x00, 0x76,
-    0x11, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x56,
-    0x0c, 0x11, 0x4c, 0x00, 0x16, 0x0d, 0x36, 0x60,
-    0x85, 0x00, 0xe5, 0x7f, 0x20, 0x1b, 0x00, 0x56,
-    0x0d, 0x56, 0x12, 0x13, 0x16, 0x0c, 0x16, 0x11,
-    0x36, 0xe9, 0x02, 0x36, 0x4c, 0x36, 0xe1, 0x12,
-    0x12, 0x16, 0x13, 0x0e, 0x10, 0x0e, 0xe2, 0x12,
-    0x12, 0x0c, 0x13, 0x0c, 0x12, 0x13, 0x16, 0x12,
-    0x13, 0x36, 0xe5, 0x02, 0x04, 0xe5, 0x25, 0x24,
-    0xe5, 0x17, 0x40, 0xa5, 0x20, 0xa5, 0x20, 0xa5,
-    0x20, 0x45, 0x40, 0x2d, 0x0c, 0x0e, 0x0f, 0x2d,
-    0x00, 0x0f, 0x6c, 0x2f, 0xe0, 0x02, 0x5b, 0x2f,
-    0x20, 0xe5, 0x04, 0x00, 0xe5, 0x12, 0x00, 0xe5,
-    0x0b, 0x00, 0x25, 0x00, 0xe5, 0x07, 0x20, 0xe5,
-    0x06, 0xe0, 0x1a, 0xe5, 0x73, 0x80, 0x56, 0x60,
-    0xeb, 0x25, 0x40, 0xef, 0x01, 0xea, 0x2d, 0x6b,
-    0xef, 0x09, 0x2b, 0x4f, 0x00, 0xef, 0x05, 0x40,
-    0x0f, 0xe0, 0x27, 0xef, 0x25, 0x06, 0xe0, 0x7a,
-    0xe5, 0x15, 0x40, 0xe5, 0x29, 0xe0, 0x07, 0x06,
-    0xeb, 0x13, 0x60, 0xe5, 0x18, 0x6b, 0xe0, 0x01,
-    0xe5, 0x0c, 0x0a, 0xe5, 0x00, 0x0a, 0x80, 0xe5,
-    0x1e, 0x86, 0x80, 0xe5, 0x16, 0x00, 0x16, 0xe5,
-    0x1c, 0x60, 0xe5, 0x00, 0x16, 0x8a, 0xe0, 0x22,
-    0xe1, 0x20, 0xe2, 0x20, 0xe5, 0x46, 0x20, 0xe9,
-    0x02, 0xa0, 0xe1, 0x1c, 0x60, 0xe2, 0x1c, 0x60,
-    0xe5, 0x20, 0xe0, 0x00, 0xe5, 0x2c, 0xe0, 0x03,
-    0x16, 0xe1, 0x03, 0x00, 0xe1, 0x07, 0x00, 0xc1,
-    0x00, 0x21, 0x00, 0xe2, 0x03, 0x00, 0xe2, 0x07,
-    0x00, 0xc2, 0x00, 0x22, 0xe0, 0x3b, 0xe5, 0x80,
-    0xaf, 0xe0, 0x01, 0xe5, 0x0e, 0xe0, 0x02, 0xe5,
-    0x00, 0xe0, 0x10, 0xa4, 0x00, 0xe4, 0x22, 0x00,
-    0xe4, 0x01, 0xe0, 0x3d, 0xa5, 0x20, 0x05, 0x00,
-    0xe5, 0x24, 0x00, 0x25, 0x40, 0x05, 0x20, 0xe5,
-    0x0f, 0x00, 0x16, 0xeb, 0x00, 0xe5, 0x0f, 0x2f,
-    0xcb, 0xe5, 0x17, 0xe0, 0x00, 0xeb, 0x01, 0xe0,
-    0x28, 0xe5, 0x0b, 0x00, 0x25, 0x80, 0x8b, 0xe5,
-    0x0e, 0xab, 0x40, 0x16, 0xe5, 0x12, 0x80, 0x16,
-    0xe0, 0x38, 0xe5, 0x30, 0x60, 0x2b, 0x25, 0xeb,
-    0x08, 0x20, 0xeb, 0x26, 0x05, 0x46, 0x00, 0x26,
-    0x80, 0x66, 0x65, 0x00, 0x45, 0x00, 0xe5, 0x15,
-    0x20, 0x46, 0x60, 0x06, 0xeb, 0x01, 0xc0, 0xf6,
-    0x01, 0xc0, 0xe5, 0x15, 0x2b, 0x16, 0xe5, 0x15,
-    0x4b, 0xe0, 0x18, 0xe5, 0x00, 0x0f, 0xe5, 0x14,
-    0x26, 0x60, 0x8b, 0xd6, 0xe0, 0x01, 0xe5, 0x2e,
-    0x40, 0xd6, 0xe5, 0x0e, 0x20, 0xeb, 0x00, 0xe5,
-    0x0b, 0x80, 0xeb, 0x00, 0xe5, 0x0a, 0xc0, 0x76,
-    0xe0, 0x04, 0xcb, 0xe0, 0x48, 0xe5, 0x41, 0xe0,
-    0x2f, 0xe1, 0x2b, 0xe0, 0x05, 0xe2, 0x2b, 0xc0,
-    0xab, 0xe5, 0x1c, 0x66, 0xe0, 0x00, 0xe9, 0x02,
-    0xe0, 0x80, 0x9e, 0xeb, 0x17, 0x00, 0xe5, 0x22,
-    0x00, 0x26, 0x11, 0x20, 0x25, 0xe0, 0x46, 0xe5,
-    0x15, 0xeb, 0x02, 0x05, 0xe0, 0x00, 0xe5, 0x0e,
-    0xe6, 0x03, 0x6b, 0x96, 0xe0, 0x0e, 0xe5, 0x0a,
-    0x66, 0x76, 0xe0, 0x1e, 0xe5, 0x0d, 0xcb, 0xe0,
-    0x0c, 0xe5, 0x0f, 0xe0, 0x01, 0x07, 0x06, 0x07,
-    0xe5, 0x2d, 0xe6, 0x07, 0xd6, 0x60, 0xeb, 0x0c,
-    0xe9, 0x02, 0x06, 0x25, 0x26, 0x05, 0xe0, 0x01,
-    0x46, 0x07, 0xe5, 0x25, 0x47, 0x66, 0x27, 0x26,
-    0x36, 0x1b, 0x76, 0x06, 0xe0, 0x02, 0x1b, 0x20,
-    0xe5, 0x11, 0xc0, 0xe9, 0x02, 0xa0, 0x46, 0xe5,
-    0x1c, 0x86, 0x07, 0xe6, 0x00, 0x00, 0xe9, 0x02,
-    0x76, 0x05, 0x27, 0x05, 0xe0, 0x00, 0xe5, 0x1b,
-    0x06, 0x36, 0x05, 0xe0, 0x01, 0x26, 0x07, 0xe5,
-    0x28, 0x47, 0xe6, 0x01, 0x27, 0x65, 0x76, 0x66,
-    0x16, 0x07, 0x06, 0xe9, 0x02, 0x05, 0x16, 0x05,
-    0x56, 0x00, 0xeb, 0x0c, 0xe0, 0x03, 0xe5, 0x0a,
-    0x00, 0xe5, 0x11, 0x47, 0x46, 0x27, 0x06, 0x07,
-    0x26, 0xb6, 0x06, 0xe0, 0x39, 0xc5, 0x00, 0x05,
-    0x00, 0x65, 0x00, 0xe5, 0x07, 0x00, 0xe5, 0x02,
-    0x16, 0xa0, 0xe5, 0x27, 0x06, 0x47, 0xe6, 0x00,
-    0x80, 0xe9, 0x02, 0xa0, 0x26, 0x27, 0x00, 0xe5,
-    0x00, 0x20, 0x25, 0x20, 0xe5, 0x0e, 0x00, 0xc5,
-    0x00, 0x25, 0x00, 0x85, 0x00, 0x26, 0x05, 0x27,
-    0x06, 0x67, 0x20, 0x27, 0x20, 0x47, 0x20, 0x05,
-    0xa0, 0x07, 0x80, 0x85, 0x27, 0x20, 0xc6, 0x40,
-    0x86, 0xe0, 0x80, 0x03, 0xe5, 0x2d, 0x47, 0xe6,
-    0x00, 0x27, 0x46, 0x07, 0x06, 0x65, 0x96, 0xe9,
-    0x02, 0x36, 0x00, 0x16, 0x06, 0x45, 0xe0, 0x16,
-    0xe5, 0x28, 0x47, 0xa6, 0x07, 0x06, 0x67, 0x26,
-    0x07, 0x26, 0x25, 0x16, 0x05, 0xe0, 0x00, 0xe9,
-    0x02, 0xe0, 0x80, 0x1e, 0xe5, 0x27, 0x47, 0x66,
-    0x20, 0x67, 0x26, 0x07, 0x26, 0xf6, 0x0f, 0x65,
-    0x26, 0xe0, 0x1a, 0xe5, 0x28, 0x47, 0xe6, 0x00,
-    0x27, 0x06, 0x07, 0x26, 0x56, 0x05, 0xe0, 0x03,
-    0xe9, 0x02, 0xa0, 0xf6, 0x05, 0xe0, 0x0b, 0xe5,
-    0x23, 0x06, 0x07, 0x06, 0x27, 0xa6, 0x07, 0x06,
-    0x05, 0x16, 0xa0, 0xe9, 0x02, 0xe0, 0x2e, 0xe5,
-    0x13, 0x20, 0x46, 0x27, 0x66, 0x07, 0x86, 0x60,
-    0xe9, 0x02, 0x2b, 0x56, 0x0f, 0xc5, 0xe0, 0x80,
-    0x31, 0xe5, 0x24, 0x47, 0xe6, 0x01, 0x07, 0x26,
-    0x16, 0xe0, 0x5c, 0xe1, 0x18, 0xe2, 0x18, 0xe9,
-    0x02, 0xeb, 0x01, 0xe0, 0x04, 0xe5, 0x00, 0x20,
-    0x05, 0x20, 0xe5, 0x00, 0x00, 0x25, 0x00, 0xe5,
-    0x10, 0xa7, 0x00, 0x27, 0x20, 0x26, 0x07, 0x06,
-    0x05, 0x07, 0x05, 0x07, 0x06, 0x56, 0xe0, 0x01,
-    0xe9, 0x02, 0xe0, 0x3e, 0xe5, 0x00, 0x20, 0xe5,
-    0x1f, 0x47, 0x66, 0x20, 0x26, 0x67, 0x06, 0x05,
-    0x16, 0x05, 0x07, 0xe0, 0x13, 0x05, 0xe6, 0x02,
-    0xe5, 0x20, 0xa6, 0x07, 0x05, 0x66, 0xf6, 0x00,
-    0x06, 0xe0, 0x00, 0x05, 0xa6, 0x27, 0x46, 0xe5,
-    0x26, 0xe6, 0x05, 0x07, 0x26, 0x56, 0x05, 0x96,
-    0xe0, 0x05, 0xe5, 0x41, 0xe0, 0x80, 0x7f, 0xe5,
-    0x01, 0x00, 0xe5, 0x1d, 0x07, 0xc6, 0x00, 0xa6,
-    0x07, 0x06, 0x05, 0x96, 0xe0, 0x02, 0xe9, 0x02,
-    0xeb, 0x0b, 0x40, 0x36, 0xe5, 0x16, 0x20, 0xe6,
-    0x0e, 0x00, 0x07, 0xc6, 0x07, 0x26, 0x07, 0x26,
-    0xe0, 0x41, 0xc5, 0x00, 0x25, 0x00, 0xe5, 0x1e,
-    0xa6, 0x40, 0x06, 0x00, 0x26, 0x00, 0xc6, 0x05,
-    0x06, 0xe0, 0x00, 0xe9, 0x02, 0xa0, 0xa5, 0x00,
-    0x25, 0x00, 0xe5, 0x18, 0x87, 0x00, 0x26, 0x00,
-    0x27, 0x06, 0x07, 0x06, 0x05, 0xc0, 0xe9, 0x02,
-    0xe0, 0x80, 0xae, 0xe5, 0x0b, 0x26, 0x27, 0x36,
-    0xe0, 0x80, 0x2f, 0x05, 0xe0, 0x07, 0xeb, 0x0d,
-    0xef, 0x00, 0x6d, 0xef, 0x09, 0xe0, 0x05, 0x16,
-    0xe5, 0x83, 0x12, 0xe0, 0x5e, 0xea, 0x67, 0x00,
-    0x96, 0xe0, 0x03, 0xe5, 0x80, 0x3c, 0xe0, 0x89,
-    0xc4, 0xe5, 0x59, 0x36, 0xe0, 0x05, 0xe5, 0x83,
-    0xa7, 0x00, 0xfb, 0x01, 0xe0, 0x8f, 0x3f, 0xe5,
-    0x81, 0xbf, 0xe0, 0xa1, 0x31, 0xe5, 0x81, 0xb1,
-    0xc0, 0xe5, 0x17, 0x00, 0xe9, 0x02, 0x60, 0x36,
-    0xe5, 0x47, 0x00, 0xe9, 0x02, 0xa0, 0xe5, 0x16,
-    0x20, 0x86, 0x16, 0xe0, 0x02, 0xe5, 0x28, 0xc6,
-    0x96, 0x6f, 0x64, 0x16, 0x0f, 0xe0, 0x02, 0xe9,
-    0x02, 0x00, 0xcb, 0x00, 0xe5, 0x0d, 0x80, 0xe5,
-    0x0b, 0xe0, 0x82, 0x28, 0xe1, 0x18, 0xe2, 0x18,
-    0xeb, 0x0f, 0x76, 0xe0, 0x5d, 0xe5, 0x43, 0x60,
-    0x06, 0x05, 0xe7, 0x2f, 0xc0, 0x66, 0xe4, 0x05,
-    0xe0, 0x38, 0x24, 0x16, 0x04, 0x06, 0xe0, 0x03,
-    0x27, 0xe0, 0x06, 0xe5, 0x97, 0x70, 0xe0, 0x00,
-    0xe5, 0x84, 0x4e, 0xe0, 0x22, 0xe5, 0x01, 0xe0,
-    0xa2, 0x5f, 0x64, 0x00, 0xc4, 0x00, 0x24, 0x00,
-    0xe5, 0x80, 0x9b, 0xe0, 0x25, 0x45, 0xe0, 0x09,
-    0x65, 0xe0, 0x00, 0xe5, 0x81, 0x04, 0xe0, 0x88,
-    0x7c, 0xe5, 0x63, 0x80, 0xe5, 0x05, 0x40, 0xe5,
-    0x01, 0xc0, 0xe5, 0x02, 0x20, 0x0f, 0x26, 0x16,
-    0x7b, 0xe0, 0x91, 0xd4, 0xe6, 0x26, 0x20, 0xe6,
-    0x0f, 0xe0, 0x01, 0xef, 0x6c, 0xe0, 0x34, 0xef,
-    0x80, 0x6e, 0xe0, 0x02, 0xef, 0x1f, 0x20, 0xef,
-    0x34, 0x27, 0x46, 0x4f, 0xa7, 0xfb, 0x00, 0xe6,
-    0x00, 0x2f, 0xc6, 0xef, 0x16, 0x66, 0xef, 0x35,
-    0xe0, 0x0d, 0xef, 0x3a, 0x46, 0x0f, 0xe0, 0x80,
-    0x12, 0xeb, 0x0c, 0xe0, 0x04, 0xef, 0x4f, 0xe0,
-    0x01, 0xeb, 0x11, 0xe0, 0x7f, 0xe1, 0x12, 0xe2,
-    0x12, 0xe1, 0x12, 0xc2, 0x00, 0xe2, 0x0a, 0xe1,
-    0x12, 0xe2, 0x12, 0x01, 0x00, 0x21, 0x20, 0x01,
-    0x20, 0x21, 0x20, 0x61, 0x00, 0xe1, 0x00, 0x62,
-    0x00, 0x02, 0x00, 0xc2, 0x00, 0xe2, 0x03, 0xe1,
-    0x12, 0xe2, 0x12, 0x21, 0x00, 0x61, 0x20, 0xe1,
-    0x00, 0x00, 0xc1, 0x00, 0xe2, 0x12, 0x21, 0x00,
-    0x61, 0x00, 0x81, 0x00, 0x01, 0x40, 0xc1, 0x00,
-    0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12,
-    0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12,
-    0xe2, 0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12,
-    0xe2, 0x14, 0x20, 0xe1, 0x11, 0x0c, 0xe2, 0x11,
-    0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c,
-    0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2,
-    0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1,
-    0x11, 0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0x3f, 0x20,
-    0xe9, 0x2a, 0xef, 0x81, 0x78, 0xe6, 0x2f, 0x6f,
-    0xe6, 0x2a, 0xef, 0x00, 0x06, 0xef, 0x06, 0x06,
-    0x2f, 0x96, 0xe0, 0x07, 0x86, 0x00, 0xe6, 0x07,
-    0xe0, 0x83, 0xc8, 0xe2, 0x02, 0x05, 0xe2, 0x0c,
-    0xe0, 0x80, 0x59, 0xc6, 0x00, 0xe6, 0x09, 0x20,
-    0xc6, 0x00, 0x26, 0x00, 0x86, 0xe0, 0x80, 0x4d,
-    0xe5, 0x25, 0x40, 0xc6, 0xc4, 0x20, 0xe9, 0x02,
-    0x60, 0x05, 0x0f, 0xe0, 0x80, 0xb8, 0xe5, 0x16,
-    0x06, 0xe0, 0x09, 0xe5, 0x24, 0x66, 0xe9, 0x02,
-    0x80, 0x0d, 0xe0, 0x84, 0x58, 0xc5, 0x00, 0x65,
-    0x00, 0x25, 0x00, 0xe5, 0x07, 0x00, 0xe5, 0x80,
-    0x3d, 0x20, 0xeb, 0x01, 0xc6, 0xe0, 0x21, 0xe1,
-    0x1a, 0xe2, 0x1a, 0xc6, 0x04, 0x60, 0xe9, 0x02,
-    0x60, 0x36, 0xe0, 0x82, 0x89, 0xeb, 0x33, 0x0f,
-    0x4b, 0x0d, 0x6b, 0xe0, 0x44, 0xeb, 0x25, 0x0f,
-    0xeb, 0x07, 0xe0, 0x80, 0x3a, 0x65, 0x00, 0xe5,
-    0x13, 0x00, 0x25, 0x00, 0x05, 0x20, 0x05, 0x00,
-    0xe5, 0x02, 0x00, 0x65, 0x00, 0x05, 0x00, 0x05,
-    0xa0, 0x05, 0x60, 0x05, 0x00, 0x05, 0x00, 0x05,
-    0x00, 0x45, 0x00, 0x25, 0x00, 0x05, 0x20, 0x05,
-    0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05,
-    0x00, 0x25, 0x00, 0x05, 0x20, 0x65, 0x00, 0xc5,
-    0x00, 0x65, 0x00, 0x65, 0x00, 0x05, 0x00, 0xe5,
-    0x02, 0x00, 0xe5, 0x09, 0x80, 0x45, 0x00, 0x85,
-    0x00, 0xe5, 0x09, 0xe0, 0x2c, 0x2c, 0xe0, 0x80,
-    0x86, 0xef, 0x24, 0x60, 0xef, 0x5c, 0xe0, 0x04,
-    0xef, 0x07, 0x20, 0xef, 0x07, 0x00, 0xef, 0x07,
-    0x00, 0xef, 0x1d, 0xe0, 0x02, 0xeb, 0x05, 0xef,
-    0x80, 0x19, 0xe0, 0x30, 0xef, 0x15, 0xe0, 0x05,
-    0xef, 0x24, 0x60, 0xef, 0x01, 0xc0, 0x2f, 0xe0,
-    0x06, 0xaf, 0xe0, 0x80, 0x12, 0xef, 0x80, 0x73,
-    0x8e, 0xef, 0x82, 0x50, 0x80, 0xef, 0x08, 0x40,
-    0xef, 0x05, 0x40, 0xef, 0x6c, 0xe0, 0x04, 0xef,
-    0x51, 0xc0, 0xef, 0x04, 0x60, 0x0f, 0xe0, 0x07,
-    0xef, 0x04, 0x60, 0xef, 0x30, 0xe0, 0x00, 0xef,
-    0x02, 0xa0, 0xef, 0x20, 0xe0, 0x00, 0xef, 0x16,
-    0x20, 0x2f, 0xe0, 0x46, 0xef, 0x80, 0xcc, 0xe0,
-    0x04, 0xef, 0x06, 0x20, 0x8f, 0x40, 0x8f, 0x40,
-    0xcf, 0xe0, 0x01, 0xef, 0x15, 0x40, 0xef, 0x03,
-    0x80, 0xaf, 0xe0, 0x02, 0xef, 0x02, 0xa0, 0xef,
-    0x00, 0xe0, 0x00, 0xcf, 0xe0, 0x01, 0xef, 0x80,
-    0x0b, 0x00, 0xef, 0x2f, 0xe0, 0x1d, 0xe9, 0x02,
-    0xe0, 0x83, 0x7e, 0xe5, 0xc0, 0x66, 0x58, 0xe0,
-    0x18, 0xe5, 0x8f, 0xb1, 0xc0, 0xe5, 0x80, 0x56,
-    0x20, 0xe5, 0x95, 0xfa, 0xe0, 0x06, 0xe5, 0x9c,
-    0xa9, 0xe0, 0x8b, 0x97, 0xe5, 0x81, 0x96, 0xe0,
-    0x85, 0x5a, 0xe5, 0x92, 0xc3, 0xe0, 0xca, 0xac,
-    0x2e, 0x1b, 0xe0, 0x16, 0xfb, 0x58, 0xe0, 0x78,
-    0xe6, 0x80, 0x68, 0xe0, 0xc0, 0xbd, 0x88, 0xfd,
-    0xc0, 0xbf, 0x76, 0x20, 0xfd, 0xc0, 0xbf, 0x76,
-    0x20,
-};
-
-typedef enum {
-    UNICODE_SCRIPT_Unknown,
-    UNICODE_SCRIPT_Adlam,
-    UNICODE_SCRIPT_Ahom,
-    UNICODE_SCRIPT_Anatolian_Hieroglyphs,
-    UNICODE_SCRIPT_Arabic,
-    UNICODE_SCRIPT_Armenian,
-    UNICODE_SCRIPT_Avestan,
-    UNICODE_SCRIPT_Balinese,
-    UNICODE_SCRIPT_Bamum,
-    UNICODE_SCRIPT_Bassa_Vah,
-    UNICODE_SCRIPT_Batak,
-    UNICODE_SCRIPT_Bengali,
-    UNICODE_SCRIPT_Bhaiksuki,
-    UNICODE_SCRIPT_Bopomofo,
-    UNICODE_SCRIPT_Brahmi,
-    UNICODE_SCRIPT_Braille,
-    UNICODE_SCRIPT_Buginese,
-    UNICODE_SCRIPT_Buhid,
-    UNICODE_SCRIPT_Canadian_Aboriginal,
-    UNICODE_SCRIPT_Carian,
-    UNICODE_SCRIPT_Caucasian_Albanian,
-    UNICODE_SCRIPT_Chakma,
-    UNICODE_SCRIPT_Cham,
-    UNICODE_SCRIPT_Cherokee,
-    UNICODE_SCRIPT_Chorasmian,
-    UNICODE_SCRIPT_Common,
-    UNICODE_SCRIPT_Coptic,
-    UNICODE_SCRIPT_Cuneiform,
-    UNICODE_SCRIPT_Cypriot,
-    UNICODE_SCRIPT_Cyrillic,
-    UNICODE_SCRIPT_Cypro_Minoan,
-    UNICODE_SCRIPT_Deseret,
-    UNICODE_SCRIPT_Devanagari,
-    UNICODE_SCRIPT_Dives_Akuru,
-    UNICODE_SCRIPT_Dogra,
-    UNICODE_SCRIPT_Duployan,
-    UNICODE_SCRIPT_Egyptian_Hieroglyphs,
-    UNICODE_SCRIPT_Elbasan,
-    UNICODE_SCRIPT_Elymaic,
-    UNICODE_SCRIPT_Ethiopic,
-    UNICODE_SCRIPT_Georgian,
-    UNICODE_SCRIPT_Glagolitic,
-    UNICODE_SCRIPT_Gothic,
-    UNICODE_SCRIPT_Grantha,
-    UNICODE_SCRIPT_Greek,
-    UNICODE_SCRIPT_Gujarati,
-    UNICODE_SCRIPT_Gunjala_Gondi,
-    UNICODE_SCRIPT_Gurmukhi,
-    UNICODE_SCRIPT_Han,
-    UNICODE_SCRIPT_Hangul,
-    UNICODE_SCRIPT_Hanifi_Rohingya,
-    UNICODE_SCRIPT_Hanunoo,
-    UNICODE_SCRIPT_Hatran,
-    UNICODE_SCRIPT_Hebrew,
-    UNICODE_SCRIPT_Hiragana,
-    UNICODE_SCRIPT_Imperial_Aramaic,
-    UNICODE_SCRIPT_Inherited,
-    UNICODE_SCRIPT_Inscriptional_Pahlavi,
-    UNICODE_SCRIPT_Inscriptional_Parthian,
-    UNICODE_SCRIPT_Javanese,
-    UNICODE_SCRIPT_Kaithi,
-    UNICODE_SCRIPT_Kannada,
-    UNICODE_SCRIPT_Katakana,
-    UNICODE_SCRIPT_Kayah_Li,
-    UNICODE_SCRIPT_Kharoshthi,
-    UNICODE_SCRIPT_Khmer,
-    UNICODE_SCRIPT_Khojki,
-    UNICODE_SCRIPT_Khitan_Small_Script,
-    UNICODE_SCRIPT_Khudawadi,
-    UNICODE_SCRIPT_Lao,
-    UNICODE_SCRIPT_Latin,
-    UNICODE_SCRIPT_Lepcha,
-    UNICODE_SCRIPT_Limbu,
-    UNICODE_SCRIPT_Linear_A,
-    UNICODE_SCRIPT_Linear_B,
-    UNICODE_SCRIPT_Lisu,
-    UNICODE_SCRIPT_Lycian,
-    UNICODE_SCRIPT_Lydian,
-    UNICODE_SCRIPT_Makasar,
-    UNICODE_SCRIPT_Mahajani,
-    UNICODE_SCRIPT_Malayalam,
-    UNICODE_SCRIPT_Mandaic,
-    UNICODE_SCRIPT_Manichaean,
-    UNICODE_SCRIPT_Marchen,
-    UNICODE_SCRIPT_Masaram_Gondi,
-    UNICODE_SCRIPT_Medefaidrin,
-    UNICODE_SCRIPT_Meetei_Mayek,
-    UNICODE_SCRIPT_Mende_Kikakui,
-    UNICODE_SCRIPT_Meroitic_Cursive,
-    UNICODE_SCRIPT_Meroitic_Hieroglyphs,
-    UNICODE_SCRIPT_Miao,
-    UNICODE_SCRIPT_Modi,
-    UNICODE_SCRIPT_Mongolian,
-    UNICODE_SCRIPT_Mro,
-    UNICODE_SCRIPT_Multani,
-    UNICODE_SCRIPT_Myanmar,
-    UNICODE_SCRIPT_Nabataean,
-    UNICODE_SCRIPT_Nandinagari,
-    UNICODE_SCRIPT_New_Tai_Lue,
-    UNICODE_SCRIPT_Newa,
-    UNICODE_SCRIPT_Nko,
-    UNICODE_SCRIPT_Nushu,
-    UNICODE_SCRIPT_Nyiakeng_Puachue_Hmong,
-    UNICODE_SCRIPT_Ogham,
-    UNICODE_SCRIPT_Ol_Chiki,
-    UNICODE_SCRIPT_Old_Hungarian,
-    UNICODE_SCRIPT_Old_Italic,
-    UNICODE_SCRIPT_Old_North_Arabian,
-    UNICODE_SCRIPT_Old_Permic,
-    UNICODE_SCRIPT_Old_Persian,
-    UNICODE_SCRIPT_Old_Sogdian,
-    UNICODE_SCRIPT_Old_South_Arabian,
-    UNICODE_SCRIPT_Old_Turkic,
-    UNICODE_SCRIPT_Old_Uyghur,
-    UNICODE_SCRIPT_Oriya,
-    UNICODE_SCRIPT_Osage,
-    UNICODE_SCRIPT_Osmanya,
-    UNICODE_SCRIPT_Pahawh_Hmong,
-    UNICODE_SCRIPT_Palmyrene,
-    UNICODE_SCRIPT_Pau_Cin_Hau,
-    UNICODE_SCRIPT_Phags_Pa,
-    UNICODE_SCRIPT_Phoenician,
-    UNICODE_SCRIPT_Psalter_Pahlavi,
-    UNICODE_SCRIPT_Rejang,
-    UNICODE_SCRIPT_Runic,
-    UNICODE_SCRIPT_Samaritan,
-    UNICODE_SCRIPT_Saurashtra,
-    UNICODE_SCRIPT_Sharada,
-    UNICODE_SCRIPT_Shavian,
-    UNICODE_SCRIPT_Siddham,
-    UNICODE_SCRIPT_SignWriting,
-    UNICODE_SCRIPT_Sinhala,
-    UNICODE_SCRIPT_Sogdian,
-    UNICODE_SCRIPT_Sora_Sompeng,
-    UNICODE_SCRIPT_Soyombo,
-    UNICODE_SCRIPT_Sundanese,
-    UNICODE_SCRIPT_Syloti_Nagri,
-    UNICODE_SCRIPT_Syriac,
-    UNICODE_SCRIPT_Tagalog,
-    UNICODE_SCRIPT_Tagbanwa,
-    UNICODE_SCRIPT_Tai_Le,
-    UNICODE_SCRIPT_Tai_Tham,
-    UNICODE_SCRIPT_Tai_Viet,
-    UNICODE_SCRIPT_Takri,
-    UNICODE_SCRIPT_Tamil,
-    UNICODE_SCRIPT_Tangut,
-    UNICODE_SCRIPT_Telugu,
-    UNICODE_SCRIPT_Thaana,
-    UNICODE_SCRIPT_Thai,
-    UNICODE_SCRIPT_Tibetan,
-    UNICODE_SCRIPT_Tifinagh,
-    UNICODE_SCRIPT_Tirhuta,
-    UNICODE_SCRIPT_Tangsa,
-    UNICODE_SCRIPT_Toto,
-    UNICODE_SCRIPT_Ugaritic,
-    UNICODE_SCRIPT_Vai,
-    UNICODE_SCRIPT_Vithkuqi,
-    UNICODE_SCRIPT_Wancho,
-    UNICODE_SCRIPT_Warang_Citi,
-    UNICODE_SCRIPT_Yezidi,
-    UNICODE_SCRIPT_Yi,
-    UNICODE_SCRIPT_Zanabazar_Square,
-    UNICODE_SCRIPT_COUNT,
-} UnicodeScriptEnum;
-
-static const char unicode_script_name_table[] =
-    "Adlam,Adlm"                  "\0"
-    "Ahom,Ahom"                   "\0"
-    "Anatolian_Hieroglyphs,Hluw"  "\0"
-    "Arabic,Arab"                 "\0"
-    "Armenian,Armn"               "\0"
-    "Avestan,Avst"                "\0"
-    "Balinese,Bali"               "\0"
-    "Bamum,Bamu"                  "\0"
-    "Bassa_Vah,Bass"              "\0"
-    "Batak,Batk"                  "\0"
-    "Bengali,Beng"                "\0"
-    "Bhaiksuki,Bhks"              "\0"
-    "Bopomofo,Bopo"               "\0"
-    "Brahmi,Brah"                 "\0"
-    "Braille,Brai"                "\0"
-    "Buginese,Bugi"               "\0"
-    "Buhid,Buhd"                  "\0"
-    "Canadian_Aboriginal,Cans"    "\0"
-    "Carian,Cari"                 "\0"
-    "Caucasian_Albanian,Aghb"     "\0"
-    "Chakma,Cakm"                 "\0"
-    "Cham,Cham"                   "\0"
-    "Cherokee,Cher"               "\0"
-    "Chorasmian,Chrs"             "\0"
-    "Common,Zyyy"                 "\0"
-    "Coptic,Copt,Qaac"            "\0"
-    "Cuneiform,Xsux"              "\0"
-    "Cypriot,Cprt"                "\0"
-    "Cyrillic,Cyrl"               "\0"
-    "Cypro_Minoan,Cpmn"           "\0"
-    "Deseret,Dsrt"                "\0"
-    "Devanagari,Deva"             "\0"
-    "Dives_Akuru,Diak"            "\0"
-    "Dogra,Dogr"                  "\0"
-    "Duployan,Dupl"               "\0"
-    "Egyptian_Hieroglyphs,Egyp"   "\0"
-    "Elbasan,Elba"                "\0"
-    "Elymaic,Elym"                "\0"
-    "Ethiopic,Ethi"               "\0"
-    "Georgian,Geor"               "\0"
-    "Glagolitic,Glag"             "\0"
-    "Gothic,Goth"                 "\0"
-    "Grantha,Gran"                "\0"
-    "Greek,Grek"                  "\0"
-    "Gujarati,Gujr"               "\0"
-    "Gunjala_Gondi,Gong"          "\0"
-    "Gurmukhi,Guru"               "\0"
-    "Han,Hani"                    "\0"
-    "Hangul,Hang"                 "\0"
-    "Hanifi_Rohingya,Rohg"        "\0"
-    "Hanunoo,Hano"                "\0"
-    "Hatran,Hatr"                 "\0"
-    "Hebrew,Hebr"                 "\0"
-    "Hiragana,Hira"               "\0"
-    "Imperial_Aramaic,Armi"       "\0"
-    "Inherited,Zinh,Qaai"         "\0"
-    "Inscriptional_Pahlavi,Phli"  "\0"
-    "Inscriptional_Parthian,Prti" "\0"
-    "Javanese,Java"               "\0"
-    "Kaithi,Kthi"                 "\0"
-    "Kannada,Knda"                "\0"
-    "Katakana,Kana"               "\0"
-    "Kayah_Li,Kali"               "\0"
-    "Kharoshthi,Khar"             "\0"
-    "Khmer,Khmr"                  "\0"
-    "Khojki,Khoj"                 "\0"
-    "Khitan_Small_Script,Kits"    "\0"
-    "Khudawadi,Sind"              "\0"
-    "Lao,Laoo"                    "\0"
-    "Latin,Latn"                  "\0"
-    "Lepcha,Lepc"                 "\0"
-    "Limbu,Limb"                  "\0"
-    "Linear_A,Lina"               "\0"
-    "Linear_B,Linb"               "\0"
-    "Lisu,Lisu"                   "\0"
-    "Lycian,Lyci"                 "\0"
-    "Lydian,Lydi"                 "\0"
-    "Makasar,Maka"                "\0"
-    "Mahajani,Mahj"               "\0"
-    "Malayalam,Mlym"              "\0"
-    "Mandaic,Mand"                "\0"
-    "Manichaean,Mani"             "\0"
-    "Marchen,Marc"                "\0"
-    "Masaram_Gondi,Gonm"          "\0"
-    "Medefaidrin,Medf"            "\0"
-    "Meetei_Mayek,Mtei"           "\0"
-    "Mende_Kikakui,Mend"          "\0"
-    "Meroitic_Cursive,Merc"       "\0"
-    "Meroitic_Hieroglyphs,Mero"   "\0"
-    "Miao,Plrd"                   "\0"
-    "Modi,Modi"                   "\0"
-    "Mongolian,Mong"              "\0"
-    "Mro,Mroo"                    "\0"
-    "Multani,Mult"                "\0"
-    "Myanmar,Mymr"                "\0"
-    "Nabataean,Nbat"              "\0"
-    "Nandinagari,Nand"            "\0"
-    "New_Tai_Lue,Talu"            "\0"
-    "Newa,Newa"                   "\0"
-    "Nko,Nkoo"                    "\0"
-    "Nushu,Nshu"                  "\0"
-    "Nyiakeng_Puachue_Hmong,Hmnp" "\0"
-    "Ogham,Ogam"                  "\0"
-    "Ol_Chiki,Olck"               "\0"
-    "Old_Hungarian,Hung"          "\0"
-    "Old_Italic,Ital"             "\0"
-    "Old_North_Arabian,Narb"      "\0"
-    "Old_Permic,Perm"             "\0"
-    "Old_Persian,Xpeo"            "\0"
-    "Old_Sogdian,Sogo"            "\0"
-    "Old_South_Arabian,Sarb"      "\0"
-    "Old_Turkic,Orkh"             "\0"
-    "Old_Uyghur,Ougr"             "\0"
-    "Oriya,Orya"                  "\0"
-    "Osage,Osge"                  "\0"
-    "Osmanya,Osma"                "\0"
-    "Pahawh_Hmong,Hmng"           "\0"
-    "Palmyrene,Palm"              "\0"
-    "Pau_Cin_Hau,Pauc"            "\0"
-    "Phags_Pa,Phag"               "\0"
-    "Phoenician,Phnx"             "\0"
-    "Psalter_Pahlavi,Phlp"        "\0"
-    "Rejang,Rjng"                 "\0"
-    "Runic,Runr"                  "\0"
-    "Samaritan,Samr"              "\0"
-    "Saurashtra,Saur"             "\0"
-    "Sharada,Shrd"                "\0"
-    "Shavian,Shaw"                "\0"
-    "Siddham,Sidd"                "\0"
-    "SignWriting,Sgnw"            "\0"
-    "Sinhala,Sinh"                "\0"
-    "Sogdian,Sogd"                "\0"
-    "Sora_Sompeng,Sora"           "\0"
-    "Soyombo,Soyo"                "\0"
-    "Sundanese,Sund"              "\0"
-    "Syloti_Nagri,Sylo"           "\0"
-    "Syriac,Syrc"                 "\0"
-    "Tagalog,Tglg"                "\0"
-    "Tagbanwa,Tagb"               "\0"
-    "Tai_Le,Tale"                 "\0"
-    "Tai_Tham,Lana"               "\0"
-    "Tai_Viet,Tavt"               "\0"
-    "Takri,Takr"                  "\0"
-    "Tamil,Taml"                  "\0"
-    "Tangut,Tang"                 "\0"
-    "Telugu,Telu"                 "\0"
-    "Thaana,Thaa"                 "\0"
-    "Thai,Thai"                   "\0"
-    "Tibetan,Tibt"                "\0"
-    "Tifinagh,Tfng"               "\0"
-    "Tirhuta,Tirh"                "\0"
-    "Tangsa,Tnsa"                 "\0"
-    "Toto,Toto"                   "\0"
-    "Ugaritic,Ugar"               "\0"
-    "Vai,Vaii"                    "\0"
-    "Vithkuqi,Vith"               "\0"
-    "Wancho,Wcho"                 "\0"
-    "Warang_Citi,Wara"            "\0"
-    "Yezidi,Yezi"                 "\0"
-    "Yi,Yiii"                     "\0"
-    "Zanabazar_Square,Zanb"       "\0"
-;
-
-static const uint8_t unicode_script_table[2690] = {
-    0xc0, 0x19, 0x99, 0x46, 0x85, 0x19, 0x99, 0x46,
-    0xae, 0x19, 0x80, 0x46, 0x8e, 0x19, 0x80, 0x46,
-    0x84, 0x19, 0x96, 0x46, 0x80, 0x19, 0x9e, 0x46,
-    0x80, 0x19, 0xe1, 0x60, 0x46, 0xa6, 0x19, 0x84,
-    0x46, 0x84, 0x19, 0x81, 0x0d, 0x93, 0x19, 0xe0,
-    0x0f, 0x38, 0x83, 0x2c, 0x80, 0x19, 0x82, 0x2c,
-    0x01, 0x83, 0x2c, 0x80, 0x19, 0x80, 0x2c, 0x03,
-    0x80, 0x2c, 0x80, 0x19, 0x80, 0x2c, 0x80, 0x19,
-    0x82, 0x2c, 0x00, 0x80, 0x2c, 0x00, 0x93, 0x2c,
-    0x00, 0xbe, 0x2c, 0x8d, 0x1a, 0x8f, 0x2c, 0xe0,
-    0x24, 0x1d, 0x81, 0x38, 0xe0, 0x48, 0x1d, 0x00,
-    0xa5, 0x05, 0x01, 0xb1, 0x05, 0x01, 0x82, 0x05,
-    0x00, 0xb6, 0x35, 0x07, 0x9a, 0x35, 0x03, 0x85,
-    0x35, 0x0a, 0x84, 0x04, 0x80, 0x19, 0x85, 0x04,
-    0x80, 0x19, 0x8d, 0x04, 0x80, 0x19, 0x82, 0x04,
-    0x80, 0x19, 0x9f, 0x04, 0x80, 0x19, 0x89, 0x04,
-    0x8a, 0x38, 0x99, 0x04, 0x80, 0x38, 0xe0, 0x0b,
-    0x04, 0x80, 0x19, 0xa1, 0x04, 0x8d, 0x89, 0x00,
-    0xbb, 0x89, 0x01, 0x82, 0x89, 0xaf, 0x04, 0xb1,
-    0x93, 0x0d, 0xba, 0x64, 0x01, 0x82, 0x64, 0xad,
-    0x7d, 0x01, 0x8e, 0x7d, 0x00, 0x9b, 0x51, 0x01,
-    0x80, 0x51, 0x00, 0x8a, 0x89, 0x04, 0x9e, 0x04,
-    0x00, 0x81, 0x04, 0x05, 0xc9, 0x04, 0x80, 0x19,
-    0x9c, 0x04, 0xd0, 0x20, 0x83, 0x38, 0x8e, 0x20,
-    0x81, 0x19, 0x99, 0x20, 0x83, 0x0b, 0x00, 0x87,
-    0x0b, 0x01, 0x81, 0x0b, 0x01, 0x95, 0x0b, 0x00,
-    0x86, 0x0b, 0x00, 0x80, 0x0b, 0x02, 0x83, 0x0b,
-    0x01, 0x88, 0x0b, 0x01, 0x81, 0x0b, 0x01, 0x83,
-    0x0b, 0x07, 0x80, 0x0b, 0x03, 0x81, 0x0b, 0x00,
-    0x84, 0x0b, 0x01, 0x98, 0x0b, 0x01, 0x82, 0x2f,
-    0x00, 0x85, 0x2f, 0x03, 0x81, 0x2f, 0x01, 0x95,
-    0x2f, 0x00, 0x86, 0x2f, 0x00, 0x81, 0x2f, 0x00,
-    0x81, 0x2f, 0x00, 0x81, 0x2f, 0x01, 0x80, 0x2f,
-    0x00, 0x84, 0x2f, 0x03, 0x81, 0x2f, 0x01, 0x82,
-    0x2f, 0x02, 0x80, 0x2f, 0x06, 0x83, 0x2f, 0x00,
-    0x80, 0x2f, 0x06, 0x90, 0x2f, 0x09, 0x82, 0x2d,
-    0x00, 0x88, 0x2d, 0x00, 0x82, 0x2d, 0x00, 0x95,
-    0x2d, 0x00, 0x86, 0x2d, 0x00, 0x81, 0x2d, 0x00,
-    0x84, 0x2d, 0x01, 0x89, 0x2d, 0x00, 0x82, 0x2d,
-    0x00, 0x82, 0x2d, 0x01, 0x80, 0x2d, 0x0e, 0x83,
-    0x2d, 0x01, 0x8b, 0x2d, 0x06, 0x86, 0x2d, 0x00,
-    0x82, 0x72, 0x00, 0x87, 0x72, 0x01, 0x81, 0x72,
-    0x01, 0x95, 0x72, 0x00, 0x86, 0x72, 0x00, 0x81,
-    0x72, 0x00, 0x84, 0x72, 0x01, 0x88, 0x72, 0x01,
-    0x81, 0x72, 0x01, 0x82, 0x72, 0x06, 0x82, 0x72,
-    0x03, 0x81, 0x72, 0x00, 0x84, 0x72, 0x01, 0x91,
-    0x72, 0x09, 0x81, 0x90, 0x00, 0x85, 0x90, 0x02,
-    0x82, 0x90, 0x00, 0x83, 0x90, 0x02, 0x81, 0x90,
-    0x00, 0x80, 0x90, 0x00, 0x81, 0x90, 0x02, 0x81,
-    0x90, 0x02, 0x82, 0x90, 0x02, 0x8b, 0x90, 0x03,
-    0x84, 0x90, 0x02, 0x82, 0x90, 0x00, 0x83, 0x90,
-    0x01, 0x80, 0x90, 0x05, 0x80, 0x90, 0x0d, 0x94,
-    0x90, 0x04, 0x8c, 0x92, 0x00, 0x82, 0x92, 0x00,
-    0x96, 0x92, 0x00, 0x8f, 0x92, 0x01, 0x88, 0x92,
-    0x00, 0x82, 0x92, 0x00, 0x83, 0x92, 0x06, 0x81,
-    0x92, 0x00, 0x82, 0x92, 0x01, 0x80, 0x92, 0x01,
-    0x83, 0x92, 0x01, 0x89, 0x92, 0x06, 0x88, 0x92,
-    0x8c, 0x3d, 0x00, 0x82, 0x3d, 0x00, 0x96, 0x3d,
-    0x00, 0x89, 0x3d, 0x00, 0x84, 0x3d, 0x01, 0x88,
-    0x3d, 0x00, 0x82, 0x3d, 0x00, 0x83, 0x3d, 0x06,
-    0x81, 0x3d, 0x05, 0x81, 0x3d, 0x00, 0x83, 0x3d,
-    0x01, 0x89, 0x3d, 0x00, 0x81, 0x3d, 0x0c, 0x8c,
-    0x50, 0x00, 0x82, 0x50, 0x00, 0xb2, 0x50, 0x00,
-    0x82, 0x50, 0x00, 0x85, 0x50, 0x03, 0x8f, 0x50,
-    0x01, 0x99, 0x50, 0x00, 0x82, 0x83, 0x00, 0x91,
-    0x83, 0x02, 0x97, 0x83, 0x00, 0x88, 0x83, 0x00,
-    0x80, 0x83, 0x01, 0x86, 0x83, 0x02, 0x80, 0x83,
-    0x03, 0x85, 0x83, 0x00, 0x80, 0x83, 0x00, 0x87,
-    0x83, 0x05, 0x89, 0x83, 0x01, 0x82, 0x83, 0x0b,
-    0xb9, 0x94, 0x03, 0x80, 0x19, 0x9b, 0x94, 0x24,
-    0x81, 0x45, 0x00, 0x80, 0x45, 0x00, 0x84, 0x45,
-    0x00, 0x97, 0x45, 0x00, 0x80, 0x45, 0x00, 0x96,
-    0x45, 0x01, 0x84, 0x45, 0x00, 0x80, 0x45, 0x00,
-    0x85, 0x45, 0x01, 0x89, 0x45, 0x01, 0x83, 0x45,
-    0x1f, 0xc7, 0x95, 0x00, 0xa3, 0x95, 0x03, 0xa6,
-    0x95, 0x00, 0xa3, 0x95, 0x00, 0x8e, 0x95, 0x00,
-    0x86, 0x95, 0x83, 0x19, 0x81, 0x95, 0x24, 0xe0,
-    0x3f, 0x5f, 0xa5, 0x28, 0x00, 0x80, 0x28, 0x04,
-    0x80, 0x28, 0x01, 0xaa, 0x28, 0x80, 0x19, 0x83,
-    0x28, 0xe0, 0x9f, 0x31, 0xc8, 0x27, 0x00, 0x83,
-    0x27, 0x01, 0x86, 0x27, 0x00, 0x80, 0x27, 0x00,
-    0x83, 0x27, 0x01, 0xa8, 0x27, 0x00, 0x83, 0x27,
-    0x01, 0xa0, 0x27, 0x00, 0x83, 0x27, 0x01, 0x86,
-    0x27, 0x00, 0x80, 0x27, 0x00, 0x83, 0x27, 0x01,
-    0x8e, 0x27, 0x00, 0xb8, 0x27, 0x00, 0x83, 0x27,
-    0x01, 0xc2, 0x27, 0x01, 0x9f, 0x27, 0x02, 0x99,
-    0x27, 0x05, 0xd5, 0x17, 0x01, 0x85, 0x17, 0x01,
-    0xe2, 0x1f, 0x12, 0x9c, 0x67, 0x02, 0xca, 0x7c,
-    0x82, 0x19, 0x8a, 0x7c, 0x06, 0x95, 0x8a, 0x08,
-    0x80, 0x8a, 0x94, 0x33, 0x81, 0x19, 0x08, 0x93,
-    0x11, 0x0b, 0x8c, 0x8b, 0x00, 0x82, 0x8b, 0x00,
-    0x81, 0x8b, 0x0b, 0xdd, 0x41, 0x01, 0x89, 0x41,
-    0x05, 0x89, 0x41, 0x05, 0x81, 0x5c, 0x81, 0x19,
-    0x80, 0x5c, 0x80, 0x19, 0x93, 0x5c, 0x05, 0xd8,
-    0x5c, 0x06, 0xaa, 0x5c, 0x04, 0xc5, 0x12, 0x09,
-    0x9e, 0x48, 0x00, 0x8b, 0x48, 0x03, 0x8b, 0x48,
-    0x03, 0x80, 0x48, 0x02, 0x8b, 0x48, 0x9d, 0x8c,
-    0x01, 0x84, 0x8c, 0x0a, 0xab, 0x62, 0x03, 0x99,
-    0x62, 0x05, 0x8a, 0x62, 0x02, 0x81, 0x62, 0x9f,
-    0x41, 0x9b, 0x10, 0x01, 0x81, 0x10, 0xbe, 0x8d,
-    0x00, 0x9c, 0x8d, 0x01, 0x8a, 0x8d, 0x05, 0x89,
-    0x8d, 0x05, 0x8d, 0x8d, 0x01, 0x9e, 0x38, 0x30,
-    0xcc, 0x07, 0x02, 0xae, 0x07, 0x00, 0xbf, 0x87,
-    0xb3, 0x0a, 0x07, 0x83, 0x0a, 0xb7, 0x47, 0x02,
-    0x8e, 0x47, 0x02, 0x82, 0x47, 0xaf, 0x68, 0x88,
-    0x1d, 0x06, 0xaa, 0x28, 0x01, 0x82, 0x28, 0x87,
-    0x87, 0x07, 0x82, 0x38, 0x80, 0x19, 0x8c, 0x38,
-    0x80, 0x19, 0x86, 0x38, 0x83, 0x19, 0x80, 0x38,
-    0x85, 0x19, 0x80, 0x38, 0x82, 0x19, 0x81, 0x38,
-    0x80, 0x19, 0x04, 0xa5, 0x46, 0x84, 0x2c, 0x80,
-    0x1d, 0xb0, 0x46, 0x84, 0x2c, 0x83, 0x46, 0x84,
-    0x2c, 0x8c, 0x46, 0x80, 0x1d, 0xc5, 0x46, 0x80,
-    0x2c, 0xbf, 0x38, 0xe0, 0x9f, 0x46, 0x95, 0x2c,
-    0x01, 0x85, 0x2c, 0x01, 0xa5, 0x2c, 0x01, 0x85,
-    0x2c, 0x01, 0x87, 0x2c, 0x00, 0x80, 0x2c, 0x00,
-    0x80, 0x2c, 0x00, 0x80, 0x2c, 0x00, 0x9e, 0x2c,
-    0x01, 0xb4, 0x2c, 0x00, 0x8e, 0x2c, 0x00, 0x8d,
-    0x2c, 0x01, 0x85, 0x2c, 0x00, 0x92, 0x2c, 0x01,
-    0x82, 0x2c, 0x00, 0x88, 0x2c, 0x00, 0x8b, 0x19,
-    0x81, 0x38, 0xd6, 0x19, 0x00, 0x8a, 0x19, 0x80,
-    0x46, 0x01, 0x8a, 0x19, 0x80, 0x46, 0x8e, 0x19,
-    0x00, 0x8c, 0x46, 0x02, 0xa0, 0x19, 0x0e, 0xa0,
-    0x38, 0x0e, 0xa5, 0x19, 0x80, 0x2c, 0x82, 0x19,
-    0x81, 0x46, 0x85, 0x19, 0x80, 0x46, 0x9a, 0x19,
-    0x80, 0x46, 0x90, 0x19, 0xa8, 0x46, 0x82, 0x19,
-    0x03, 0xe2, 0x36, 0x19, 0x18, 0x8a, 0x19, 0x14,
-    0xe3, 0x3f, 0x19, 0xe0, 0x9f, 0x0f, 0xe2, 0x13,
-    0x19, 0x01, 0x9f, 0x19, 0x00, 0xe0, 0x08, 0x19,
-    0xdf, 0x29, 0x9f, 0x46, 0xe0, 0x13, 0x1a, 0x04,
-    0x86, 0x1a, 0xa5, 0x28, 0x00, 0x80, 0x28, 0x04,
-    0x80, 0x28, 0x01, 0xb7, 0x96, 0x06, 0x81, 0x96,
-    0x0d, 0x80, 0x96, 0x96, 0x27, 0x08, 0x86, 0x27,
-    0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x86,
-    0x27, 0x00, 0x86, 0x27, 0x00, 0x86, 0x27, 0x00,
-    0x86, 0x27, 0x00, 0x86, 0x27, 0x00, 0x9f, 0x1d,
-    0xdd, 0x19, 0x21, 0x99, 0x30, 0x00, 0xd8, 0x30,
-    0x0b, 0xe0, 0x75, 0x30, 0x19, 0x8b, 0x19, 0x03,
-    0x84, 0x19, 0x80, 0x30, 0x80, 0x19, 0x80, 0x30,
-    0x98, 0x19, 0x88, 0x30, 0x83, 0x38, 0x81, 0x31,
-    0x87, 0x19, 0x83, 0x30, 0x83, 0x19, 0x00, 0xd5,
-    0x36, 0x01, 0x81, 0x38, 0x81, 0x19, 0x82, 0x36,
-    0x80, 0x19, 0xd9, 0x3e, 0x81, 0x19, 0x82, 0x3e,
-    0x04, 0xaa, 0x0d, 0x00, 0xdd, 0x31, 0x00, 0x8f,
-    0x19, 0x9f, 0x0d, 0xa3, 0x19, 0x0b, 0x8f, 0x3e,
-    0x9e, 0x31, 0x00, 0xbf, 0x19, 0x9e, 0x31, 0xd0,
-    0x19, 0xae, 0x3e, 0x80, 0x19, 0xd7, 0x3e, 0xe0,
-    0x47, 0x19, 0xf0, 0x09, 0x5f, 0x30, 0xbf, 0x19,
-    0xf0, 0x41, 0x9f, 0x30, 0xe4, 0x2c, 0xa0, 0x02,
-    0xb6, 0xa0, 0x08, 0xaf, 0x4b, 0xe0, 0xcb, 0x9b,
-    0x13, 0xdf, 0x1d, 0xd7, 0x08, 0x07, 0xa1, 0x19,
-    0xe0, 0x05, 0x46, 0x82, 0x19, 0xbf, 0x46, 0x04,
-    0x81, 0x46, 0x00, 0x80, 0x46, 0x00, 0x84, 0x46,
-    0x17, 0x8d, 0x46, 0xac, 0x88, 0x02, 0x89, 0x19,
-    0x05, 0xb7, 0x78, 0x07, 0xc5, 0x7e, 0x07, 0x8b,
-    0x7e, 0x05, 0x9f, 0x20, 0xad, 0x3f, 0x80, 0x19,
-    0x80, 0x3f, 0xa3, 0x7b, 0x0a, 0x80, 0x7b, 0x9c,
-    0x31, 0x02, 0xcd, 0x3b, 0x00, 0x80, 0x19, 0x89,
-    0x3b, 0x03, 0x81, 0x3b, 0x9e, 0x5f, 0x00, 0xb6,
-    0x16, 0x08, 0x8d, 0x16, 0x01, 0x89, 0x16, 0x01,
-    0x83, 0x16, 0x9f, 0x5f, 0xc2, 0x8e, 0x17, 0x84,
-    0x8e, 0x96, 0x56, 0x09, 0x85, 0x27, 0x01, 0x85,
-    0x27, 0x01, 0x85, 0x27, 0x08, 0x86, 0x27, 0x00,
-    0x86, 0x27, 0x00, 0xaa, 0x46, 0x80, 0x19, 0x88,
-    0x46, 0x80, 0x2c, 0x83, 0x46, 0x81, 0x19, 0x03,
-    0xcf, 0x17, 0xad, 0x56, 0x01, 0x89, 0x56, 0x05,
-    0xf0, 0x1b, 0x43, 0x31, 0x0b, 0x96, 0x31, 0x03,
-    0xb0, 0x31, 0x70, 0x10, 0xa3, 0xe1, 0x0d, 0x30,
-    0x01, 0xe0, 0x09, 0x30, 0x25, 0x86, 0x46, 0x0b,
-    0x84, 0x05, 0x04, 0x99, 0x35, 0x00, 0x84, 0x35,
-    0x00, 0x80, 0x35, 0x00, 0x81, 0x35, 0x00, 0x81,
-    0x35, 0x00, 0x89, 0x35, 0xe0, 0x12, 0x04, 0x0f,
-    0xe1, 0x0a, 0x04, 0x81, 0x19, 0xcf, 0x04, 0x01,
-    0xb5, 0x04, 0x06, 0x80, 0x04, 0x1f, 0x8f, 0x04,
-    0x8f, 0x38, 0x89, 0x19, 0x05, 0x8d, 0x38, 0x81,
-    0x1d, 0xa2, 0x19, 0x00, 0x92, 0x19, 0x00, 0x83,
-    0x19, 0x03, 0x84, 0x04, 0x00, 0xe0, 0x26, 0x04,
-    0x01, 0x80, 0x19, 0x00, 0x9f, 0x19, 0x99, 0x46,
-    0x85, 0x19, 0x99, 0x46, 0x8a, 0x19, 0x89, 0x3e,
-    0x80, 0x19, 0xac, 0x3e, 0x81, 0x19, 0x9e, 0x31,
-    0x02, 0x85, 0x31, 0x01, 0x85, 0x31, 0x01, 0x85,
-    0x31, 0x01, 0x82, 0x31, 0x02, 0x86, 0x19, 0x00,
-    0x86, 0x19, 0x09, 0x84, 0x19, 0x01, 0x8b, 0x4a,
-    0x00, 0x99, 0x4a, 0x00, 0x92, 0x4a, 0x00, 0x81,
-    0x4a, 0x00, 0x8e, 0x4a, 0x01, 0x8d, 0x4a, 0x21,
-    0xe0, 0x1a, 0x4a, 0x04, 0x82, 0x19, 0x03, 0xac,
-    0x19, 0x02, 0x88, 0x19, 0xce, 0x2c, 0x00, 0x8c,
-    0x19, 0x02, 0x80, 0x2c, 0x2e, 0xac, 0x19, 0x80,
-    0x38, 0x60, 0x21, 0x9c, 0x4c, 0x02, 0xb0, 0x13,
-    0x0e, 0x80, 0x38, 0x9a, 0x19, 0x03, 0xa3, 0x6a,
-    0x08, 0x82, 0x6a, 0x9a, 0x2a, 0x04, 0xaa, 0x6c,
-    0x04, 0x9d, 0x9a, 0x00, 0x80, 0x9a, 0xa3, 0x6d,
-    0x03, 0x8d, 0x6d, 0x29, 0xcf, 0x1f, 0xaf, 0x80,
-    0x9d, 0x74, 0x01, 0x89, 0x74, 0x05, 0xa3, 0x73,
-    0x03, 0xa3, 0x73, 0x03, 0xa7, 0x25, 0x07, 0xb3,
-    0x14, 0x0a, 0x80, 0x14, 0x8a, 0x9c, 0x00, 0x8e,
-    0x9c, 0x00, 0x86, 0x9c, 0x00, 0x81, 0x9c, 0x00,
-    0x8a, 0x9c, 0x00, 0x8e, 0x9c, 0x00, 0x86, 0x9c,
-    0x00, 0x81, 0x9c, 0x42, 0xe0, 0xd6, 0x49, 0x08,
-    0x95, 0x49, 0x09, 0x87, 0x49, 0x17, 0x85, 0x46,
-    0x00, 0xa9, 0x46, 0x00, 0x88, 0x46, 0x44, 0x85,
-    0x1c, 0x01, 0x80, 0x1c, 0x00, 0xab, 0x1c, 0x00,
-    0x81, 0x1c, 0x02, 0x80, 0x1c, 0x01, 0x80, 0x1c,
-    0x95, 0x37, 0x00, 0x88, 0x37, 0x9f, 0x76, 0x9e,
-    0x60, 0x07, 0x88, 0x60, 0x2f, 0x92, 0x34, 0x00,
-    0x81, 0x34, 0x04, 0x84, 0x34, 0x9b, 0x79, 0x02,
-    0x80, 0x79, 0x99, 0x4d, 0x04, 0x80, 0x4d, 0x3f,
-    0x9f, 0x59, 0x97, 0x58, 0x03, 0x93, 0x58, 0x01,
-    0xad, 0x58, 0x83, 0x40, 0x00, 0x81, 0x40, 0x04,
-    0x87, 0x40, 0x00, 0x82, 0x40, 0x00, 0x9c, 0x40,
-    0x01, 0x82, 0x40, 0x03, 0x89, 0x40, 0x06, 0x88,
-    0x40, 0x06, 0x9f, 0x6f, 0x9f, 0x6b, 0x1f, 0xa6,
-    0x52, 0x03, 0x8b, 0x52, 0x08, 0xb5, 0x06, 0x02,
-    0x86, 0x06, 0x95, 0x3a, 0x01, 0x87, 0x3a, 0x92,
-    0x39, 0x04, 0x87, 0x39, 0x91, 0x7a, 0x06, 0x83,
-    0x7a, 0x0b, 0x86, 0x7a, 0x4f, 0xc8, 0x70, 0x36,
-    0xb2, 0x69, 0x0c, 0xb2, 0x69, 0x06, 0x85, 0x69,
-    0xa7, 0x32, 0x07, 0x89, 0x32, 0x60, 0xc5, 0x9e,
-    0x04, 0x00, 0xa9, 0x9f, 0x00, 0x82, 0x9f, 0x01,
-    0x81, 0x9f, 0x4d, 0xa7, 0x6e, 0x07, 0xa9, 0x84,
-    0x15, 0x99, 0x71, 0x25, 0x9b, 0x18, 0x13, 0x96,
-    0x26, 0x08, 0xcd, 0x0e, 0x03, 0xa3, 0x0e, 0x08,
-    0x80, 0x0e, 0xc2, 0x3c, 0x09, 0x80, 0x3c, 0x01,
-    0x98, 0x85, 0x06, 0x89, 0x85, 0x05, 0xb4, 0x15,
-    0x00, 0x91, 0x15, 0x07, 0xa6, 0x4f, 0x08, 0xdf,
-    0x7f, 0x00, 0x93, 0x83, 0x0a, 0x91, 0x42, 0x00,
-    0xab, 0x42, 0x40, 0x86, 0x5e, 0x00, 0x80, 0x5e,
-    0x00, 0x83, 0x5e, 0x00, 0x8e, 0x5e, 0x00, 0x8a,
-    0x5e, 0x05, 0xba, 0x44, 0x04, 0x89, 0x44, 0x05,
-    0x83, 0x2b, 0x00, 0x87, 0x2b, 0x01, 0x81, 0x2b,
-    0x01, 0x95, 0x2b, 0x00, 0x86, 0x2b, 0x00, 0x81,
-    0x2b, 0x00, 0x84, 0x2b, 0x00, 0x80, 0x38, 0x88,
-    0x2b, 0x01, 0x81, 0x2b, 0x01, 0x82, 0x2b, 0x01,
-    0x80, 0x2b, 0x05, 0x80, 0x2b, 0x04, 0x86, 0x2b,
-    0x01, 0x86, 0x2b, 0x02, 0x84, 0x2b, 0x60, 0x2a,
-    0xdb, 0x63, 0x00, 0x84, 0x63, 0x1d, 0xc7, 0x97,
-    0x07, 0x89, 0x97, 0x60, 0x45, 0xb5, 0x81, 0x01,
-    0xa5, 0x81, 0x21, 0xc4, 0x5b, 0x0a, 0x89, 0x5b,
-    0x05, 0x8c, 0x5c, 0x12, 0xb9, 0x8f, 0x05, 0x89,
-    0x8f, 0x35, 0x9a, 0x02, 0x01, 0x8e, 0x02, 0x03,
-    0x96, 0x02, 0x60, 0x58, 0xbb, 0x22, 0x60, 0x03,
-    0xd2, 0x9e, 0x0b, 0x80, 0x9e, 0x86, 0x21, 0x01,
-    0x80, 0x21, 0x01, 0x87, 0x21, 0x00, 0x81, 0x21,
-    0x00, 0x9d, 0x21, 0x00, 0x81, 0x21, 0x01, 0x8b,
-    0x21, 0x08, 0x89, 0x21, 0x45, 0x87, 0x61, 0x01,
-    0xad, 0x61, 0x01, 0x8a, 0x61, 0x1a, 0xc7, 0xa1,
-    0x07, 0xd2, 0x86, 0x0c, 0x8f, 0x12, 0xb8, 0x77,
-    0x60, 0xa6, 0x88, 0x0c, 0x00, 0xac, 0x0c, 0x00,
-    0x8d, 0x0c, 0x09, 0x9c, 0x0c, 0x02, 0x9f, 0x53,
-    0x01, 0x95, 0x53, 0x00, 0x8d, 0x53, 0x48, 0x86,
-    0x54, 0x00, 0x81, 0x54, 0x00, 0xab, 0x54, 0x02,
-    0x80, 0x54, 0x00, 0x81, 0x54, 0x00, 0x88, 0x54,
-    0x07, 0x89, 0x54, 0x05, 0x85, 0x2e, 0x00, 0x81,
-    0x2e, 0x00, 0xa4, 0x2e, 0x00, 0x81, 0x2e, 0x00,
-    0x85, 0x2e, 0x06, 0x89, 0x2e, 0x60, 0xd5, 0x98,
-    0x4e, 0x60, 0x56, 0x80, 0x4b, 0x0e, 0xb1, 0x90,
-    0x0c, 0x80, 0x90, 0xe3, 0x39, 0x1b, 0x60, 0x05,
-    0xe0, 0x0e, 0x1b, 0x00, 0x84, 0x1b, 0x0a, 0xe0,
-    0x63, 0x1b, 0x69, 0xeb, 0xe0, 0x02, 0x1e, 0x0c,
-    0xe3, 0xce, 0x24, 0x00, 0x88, 0x24, 0x6f, 0x66,
-    0xe1, 0xe6, 0x03, 0x70, 0x11, 0x58, 0xe1, 0xd8,
-    0x08, 0x06, 0x9e, 0x5d, 0x00, 0x89, 0x5d, 0x03,
-    0x81, 0x5d, 0xce, 0x98, 0x00, 0x89, 0x98, 0x05,
-    0x9d, 0x09, 0x01, 0x85, 0x09, 0x09, 0xc5, 0x75,
-    0x09, 0x89, 0x75, 0x00, 0x86, 0x75, 0x00, 0x94,
-    0x75, 0x04, 0x92, 0x75, 0x62, 0x4f, 0xda, 0x55,
-    0x60, 0x04, 0xca, 0x5a, 0x03, 0xb8, 0x5a, 0x06,
-    0x90, 0x5a, 0x3f, 0x80, 0x91, 0x80, 0x65, 0x81,
-    0x30, 0x80, 0x43, 0x0a, 0x81, 0x30, 0x0d, 0xf0,
-    0x07, 0x97, 0x91, 0x07, 0xe2, 0x9f, 0x91, 0xe1,
-    0x75, 0x43, 0x29, 0x88, 0x91, 0x70, 0x12, 0x86,
-    0x83, 0x3e, 0x00, 0x86, 0x3e, 0x00, 0x81, 0x3e,
-    0x00, 0x80, 0x3e, 0xe0, 0xbe, 0x36, 0x82, 0x3e,
-    0x2c, 0x82, 0x36, 0x10, 0x83, 0x3e, 0x07, 0xe1,
-    0x2b, 0x65, 0x68, 0xa3, 0xe0, 0x0a, 0x23, 0x04,
-    0x8c, 0x23, 0x02, 0x88, 0x23, 0x06, 0x89, 0x23,
-    0x01, 0x83, 0x23, 0x83, 0x19, 0x70, 0x01, 0xfb,
-    0xad, 0x38, 0x01, 0x96, 0x38, 0x08, 0xe0, 0x13,
-    0x19, 0x3b, 0xe0, 0x95, 0x19, 0x09, 0xa6, 0x19,
-    0x01, 0xbd, 0x19, 0x82, 0x38, 0x90, 0x19, 0x87,
-    0x38, 0x81, 0x19, 0x86, 0x38, 0x9d, 0x19, 0x83,
-    0x38, 0xbc, 0x19, 0x14, 0xc5, 0x2c, 0x60, 0x39,
-    0x93, 0x19, 0x0b, 0xd6, 0x19, 0x08, 0x98, 0x19,
-    0x60, 0x26, 0xd4, 0x19, 0x00, 0xc6, 0x19, 0x00,
-    0x81, 0x19, 0x01, 0x80, 0x19, 0x01, 0x81, 0x19,
-    0x01, 0x83, 0x19, 0x00, 0x8b, 0x19, 0x00, 0x80,
-    0x19, 0x00, 0x86, 0x19, 0x00, 0xc0, 0x19, 0x00,
-    0x83, 0x19, 0x01, 0x87, 0x19, 0x00, 0x86, 0x19,
-    0x00, 0x9b, 0x19, 0x00, 0x83, 0x19, 0x00, 0x84,
-    0x19, 0x00, 0x80, 0x19, 0x02, 0x86, 0x19, 0x00,
-    0xe0, 0xf3, 0x19, 0x01, 0xe0, 0xc3, 0x19, 0x01,
-    0xb1, 0x19, 0xe2, 0x2b, 0x82, 0x0e, 0x84, 0x82,
-    0x00, 0x8e, 0x82, 0x63, 0xef, 0x9e, 0x46, 0x60,
-    0x80, 0x86, 0x29, 0x00, 0x90, 0x29, 0x01, 0x86,
-    0x29, 0x00, 0x81, 0x29, 0x00, 0x84, 0x29, 0x60,
-    0x74, 0xac, 0x66, 0x02, 0x8d, 0x66, 0x01, 0x89,
-    0x66, 0x03, 0x81, 0x66, 0x60, 0xdf, 0x9e, 0x99,
-    0x10, 0xb9, 0x9d, 0x04, 0x80, 0x9d, 0x64, 0x7f,
-    0x86, 0x27, 0x00, 0x83, 0x27, 0x00, 0x81, 0x27,
-    0x00, 0x8e, 0x27, 0x00, 0xe0, 0x64, 0x57, 0x01,
-    0x8f, 0x57, 0x28, 0xcb, 0x01, 0x03, 0x89, 0x01,
-    0x03, 0x81, 0x01, 0x62, 0xb0, 0xc3, 0x19, 0x4b,
-    0xbc, 0x19, 0x60, 0x61, 0x83, 0x04, 0x00, 0x9a,
-    0x04, 0x00, 0x81, 0x04, 0x00, 0x80, 0x04, 0x01,
-    0x80, 0x04, 0x00, 0x89, 0x04, 0x00, 0x83, 0x04,
-    0x00, 0x80, 0x04, 0x00, 0x80, 0x04, 0x05, 0x80,
-    0x04, 0x03, 0x80, 0x04, 0x00, 0x80, 0x04, 0x00,
-    0x80, 0x04, 0x00, 0x82, 0x04, 0x00, 0x81, 0x04,
-    0x00, 0x80, 0x04, 0x01, 0x80, 0x04, 0x00, 0x80,
-    0x04, 0x00, 0x80, 0x04, 0x00, 0x80, 0x04, 0x00,
-    0x80, 0x04, 0x00, 0x81, 0x04, 0x00, 0x80, 0x04,
-    0x01, 0x83, 0x04, 0x00, 0x86, 0x04, 0x00, 0x83,
-    0x04, 0x00, 0x83, 0x04, 0x00, 0x80, 0x04, 0x00,
-    0x89, 0x04, 0x00, 0x90, 0x04, 0x04, 0x82, 0x04,
-    0x00, 0x84, 0x04, 0x00, 0x90, 0x04, 0x33, 0x81,
-    0x04, 0x60, 0xad, 0xab, 0x19, 0x03, 0xe0, 0x03,
-    0x19, 0x0b, 0x8e, 0x19, 0x01, 0x8e, 0x19, 0x00,
-    0x8e, 0x19, 0x00, 0xa4, 0x19, 0x09, 0xe0, 0x4d,
-    0x19, 0x37, 0x99, 0x19, 0x80, 0x36, 0x81, 0x19,
-    0x0c, 0xab, 0x19, 0x03, 0x88, 0x19, 0x06, 0x81,
-    0x19, 0x0d, 0x85, 0x19, 0x60, 0x39, 0xe3, 0x77,
-    0x19, 0x04, 0x8f, 0x19, 0x02, 0x8c, 0x19, 0x02,
-    0xe0, 0x13, 0x19, 0x0b, 0xd8, 0x19, 0x06, 0x8b,
-    0x19, 0x03, 0x80, 0x19, 0x0e, 0x8b, 0x19, 0x03,
-    0xb7, 0x19, 0x07, 0x89, 0x19, 0x05, 0xa7, 0x19,
-    0x07, 0x9d, 0x19, 0x01, 0x81, 0x19, 0x4d, 0xe0,
-    0xf3, 0x19, 0x0b, 0x8d, 0x19, 0x01, 0x84, 0x19,
-    0x02, 0x84, 0x19, 0x02, 0x86, 0x19, 0x08, 0x9c,
-    0x19, 0x02, 0x8a, 0x19, 0x04, 0x85, 0x19, 0x09,
-    0x89, 0x19, 0x05, 0x87, 0x19, 0x07, 0x86, 0x19,
-    0x08, 0xe0, 0x32, 0x19, 0x00, 0xb6, 0x19, 0x24,
-    0x89, 0x19, 0x63, 0xa5, 0xf0, 0x96, 0x7f, 0x30,
-    0x1f, 0xef, 0xd8, 0x30, 0x06, 0xe0, 0x7d, 0x30,
-    0x01, 0xf0, 0x06, 0x21, 0x30, 0x0d, 0xf0, 0x0c,
-    0xd0, 0x30, 0x6b, 0xbe, 0xe1, 0xbd, 0x30, 0x65,
-    0x81, 0xf0, 0x02, 0xea, 0x30, 0x7a, 0xdc, 0x55,
-    0x80, 0x19, 0x1d, 0xdf, 0x19, 0x60, 0x1f, 0xe0,
-    0x8f, 0x38,
-};
-
-static const uint8_t unicode_script_ext_table[828] = {
-    0x82, 0xc1, 0x00, 0x00, 0x01, 0x2c, 0x01, 0x00,
-    0x00, 0x01, 0x2c, 0x1c, 0x00, 0x0c, 0x01, 0x46,
-    0x80, 0x92, 0x00, 0x00, 0x02, 0x1d, 0x6c, 0x00,
-    0x02, 0x1d, 0x29, 0x01, 0x02, 0x1d, 0x46, 0x00,
-    0x02, 0x1d, 0x29, 0x81, 0x03, 0x00, 0x00, 0x06,
-    0x04, 0x64, 0x32, 0x89, 0x93, 0x9f, 0x0d, 0x00,
-    0x00, 0x06, 0x04, 0x64, 0x32, 0x89, 0x93, 0x9f,
-    0x00, 0x03, 0x04, 0x89, 0x93, 0x01, 0x00, 0x00,
-    0x07, 0x01, 0x04, 0x64, 0x32, 0x89, 0x93, 0x9f,
-    0x1f, 0x00, 0x00, 0x09, 0x01, 0x04, 0x51, 0x52,
-    0x71, 0x7a, 0x32, 0x84, 0x89, 0x09, 0x00, 0x0a,
-    0x02, 0x04, 0x89, 0x09, 0x00, 0x09, 0x03, 0x04,
-    0x93, 0x9f, 0x05, 0x00, 0x00, 0x02, 0x04, 0x89,
-    0x62, 0x00, 0x00, 0x02, 0x04, 0x32, 0x81, 0xfb,
-    0x00, 0x00, 0x0d, 0x0b, 0x20, 0x2b, 0x2d, 0x2f,
-    0x3d, 0x46, 0x50, 0x72, 0x7f, 0x90, 0x92, 0x97,
-    0x00, 0x0c, 0x0b, 0x20, 0x2b, 0x2d, 0x2f, 0x3d,
-    0x46, 0x50, 0x72, 0x90, 0x92, 0x97, 0x10, 0x00,
-    0x00, 0x14, 0x0b, 0x20, 0x22, 0x2e, 0x54, 0x2b,
-    0x2d, 0x2f, 0x3d, 0x4f, 0x50, 0x61, 0x72, 0x44,
-    0x83, 0x88, 0x8f, 0x90, 0x92, 0x97, 0x00, 0x15,
-    0x0b, 0x20, 0x22, 0x2e, 0x54, 0x2b, 0x2d, 0x2f,
-    0x3d, 0x48, 0x4f, 0x50, 0x61, 0x72, 0x44, 0x83,
-    0x88, 0x8f, 0x90, 0x92, 0x97, 0x09, 0x04, 0x20,
-    0x22, 0x3c, 0x4f, 0x75, 0x00, 0x09, 0x03, 0x0b,
-    0x15, 0x88, 0x75, 0x00, 0x09, 0x02, 0x2f, 0x5e,
-    0x75, 0x00, 0x09, 0x02, 0x2d, 0x42, 0x80, 0x75,
-    0x00, 0x0d, 0x02, 0x2b, 0x90, 0x80, 0x71, 0x00,
-    0x09, 0x02, 0x3d, 0x61, 0x82, 0xcf, 0x00, 0x09,
-    0x03, 0x15, 0x5f, 0x8c, 0x80, 0x30, 0x00, 0x00,
-    0x02, 0x28, 0x46, 0x85, 0xb8, 0x00, 0x01, 0x04,
-    0x11, 0x33, 0x8b, 0x8a, 0x80, 0x4a, 0x00, 0x01,
-    0x02, 0x5c, 0x78, 0x00, 0x00, 0x00, 0x02, 0x5c,
-    0x78, 0x84, 0x49, 0x00, 0x00, 0x04, 0x0b, 0x20,
-    0x2b, 0x3d, 0x00, 0x01, 0x20, 0x00, 0x04, 0x0b,
-    0x20, 0x2b, 0x3d, 0x00, 0x02, 0x20, 0x2b, 0x00,
-    0x01, 0x20, 0x01, 0x02, 0x0b, 0x20, 0x00, 0x02,
-    0x20, 0x7f, 0x00, 0x02, 0x0b, 0x20, 0x00, 0x02,
-    0x20, 0x7f, 0x00, 0x06, 0x20, 0x3d, 0x50, 0x72,
-    0x90, 0x92, 0x00, 0x01, 0x20, 0x01, 0x02, 0x20,
-    0x7f, 0x01, 0x01, 0x20, 0x00, 0x02, 0x20, 0x7f,
-    0x00, 0x02, 0x0b, 0x20, 0x06, 0x01, 0x20, 0x00,
-    0x02, 0x20, 0x61, 0x00, 0x02, 0x0b, 0x20, 0x01,
-    0x01, 0x20, 0x00, 0x02, 0x0b, 0x20, 0x03, 0x01,
-    0x20, 0x00, 0x08, 0x0b, 0x20, 0x2b, 0x3d, 0x61,
-    0x72, 0x92, 0x97, 0x00, 0x02, 0x20, 0x2b, 0x00,
-    0x03, 0x20, 0x2b, 0x3d, 0x01, 0x02, 0x0b, 0x20,
-    0x00, 0x01, 0x0b, 0x01, 0x02, 0x20, 0x2b, 0x00,
-    0x01, 0x61, 0x80, 0x44, 0x00, 0x01, 0x01, 0x2c,
-    0x35, 0x00, 0x00, 0x02, 0x1d, 0x89, 0x00, 0x00,
-    0x00, 0x01, 0x89, 0x81, 0xb3, 0x00, 0x00, 0x02,
-    0x46, 0x5c, 0x80, 0x3f, 0x00, 0x00, 0x03, 0x20,
-    0x2b, 0x46, 0x8c, 0xd1, 0x00, 0x00, 0x02, 0x1d,
-    0x29, 0x81, 0x3c, 0x00, 0x01, 0x06, 0x0d, 0x31,
-    0x30, 0x36, 0x3e, 0xa0, 0x00, 0x05, 0x0d, 0x31,
-    0x30, 0x36, 0x3e, 0x01, 0x00, 0x00, 0x01, 0x30,
-    0x00, 0x00, 0x09, 0x06, 0x0d, 0x31, 0x30, 0x36,
-    0x3e, 0xa0, 0x00, 0x00, 0x00, 0x05, 0x0d, 0x31,
-    0x30, 0x36, 0x3e, 0x07, 0x06, 0x0d, 0x31, 0x30,
-    0x36, 0x3e, 0xa0, 0x03, 0x05, 0x0d, 0x31, 0x30,
-    0x36, 0x3e, 0x09, 0x00, 0x03, 0x02, 0x0d, 0x30,
-    0x01, 0x00, 0x00, 0x05, 0x0d, 0x31, 0x30, 0x36,
-    0x3e, 0x04, 0x02, 0x36, 0x3e, 0x00, 0x00, 0x00,
-    0x05, 0x0d, 0x31, 0x30, 0x36, 0x3e, 0x03, 0x00,
-    0x01, 0x03, 0x30, 0x36, 0x3e, 0x01, 0x01, 0x30,
-    0x58, 0x00, 0x03, 0x02, 0x36, 0x3e, 0x02, 0x00,
-    0x00, 0x02, 0x36, 0x3e, 0x59, 0x00, 0x00, 0x06,
-    0x0d, 0x31, 0x30, 0x36, 0x3e, 0xa0, 0x00, 0x02,
-    0x36, 0x3e, 0x80, 0x12, 0x00, 0x0f, 0x01, 0x30,
-    0x1f, 0x00, 0x23, 0x01, 0x30, 0x3b, 0x00, 0x27,
-    0x01, 0x30, 0x37, 0x00, 0x30, 0x01, 0x30, 0x0e,
-    0x00, 0x0b, 0x01, 0x30, 0x32, 0x00, 0x00, 0x01,
-    0x30, 0x57, 0x00, 0x18, 0x01, 0x30, 0x09, 0x00,
-    0x04, 0x01, 0x30, 0x5f, 0x00, 0x1e, 0x01, 0x30,
-    0xc0, 0x31, 0xef, 0x00, 0x00, 0x02, 0x1d, 0x29,
-    0x80, 0x0f, 0x00, 0x07, 0x02, 0x30, 0x46, 0x80,
-    0xa7, 0x00, 0x02, 0x0e, 0x20, 0x22, 0x2d, 0x2f,
-    0x42, 0x3d, 0x3c, 0x4f, 0x50, 0x5b, 0x61, 0x44,
-    0x8f, 0x97, 0x02, 0x0d, 0x20, 0x22, 0x2d, 0x2f,
-    0x42, 0x3d, 0x3c, 0x4f, 0x5b, 0x61, 0x44, 0x8f,
-    0x97, 0x03, 0x0b, 0x20, 0x22, 0x2d, 0x2f, 0x42,
-    0x3c, 0x4f, 0x5b, 0x44, 0x8f, 0x97, 0x80, 0x36,
-    0x00, 0x00, 0x02, 0x0b, 0x20, 0x00, 0x00, 0x00,
-    0x02, 0x20, 0x90, 0x39, 0x00, 0x00, 0x03, 0x3f,
-    0x46, 0x5f, 0x80, 0x1f, 0x00, 0x00, 0x02, 0x10,
-    0x3b, 0xc0, 0x12, 0xed, 0x00, 0x01, 0x02, 0x04,
-    0x64, 0x80, 0x31, 0x00, 0x00, 0x02, 0x04, 0x93,
-    0x09, 0x00, 0x00, 0x02, 0x04, 0x93, 0x46, 0x00,
-    0x01, 0x05, 0x0d, 0x31, 0x30, 0x36, 0x3e, 0x80,
-    0x99, 0x00, 0x04, 0x06, 0x0d, 0x31, 0x30, 0x36,
-    0x3e, 0xa0, 0x09, 0x00, 0x00, 0x02, 0x36, 0x3e,
-    0x2c, 0x00, 0x01, 0x02, 0x36, 0x3e, 0x80, 0xdf,
-    0x00, 0x01, 0x03, 0x1e, 0x1c, 0x4a, 0x00, 0x02,
-    0x1c, 0x4a, 0x03, 0x00, 0x2c, 0x03, 0x1c, 0x49,
-    0x4a, 0x02, 0x00, 0x08, 0x02, 0x1c, 0x4a, 0x81,
-    0x1f, 0x00, 0x1b, 0x02, 0x04, 0x1a, 0x87, 0x75,
-    0x00, 0x00, 0x02, 0x52, 0x71, 0x87, 0x8d, 0x00,
-    0x00, 0x02, 0x2b, 0x90, 0x00, 0x00, 0x00, 0x02,
-    0x2b, 0x90, 0x36, 0x00, 0x01, 0x02, 0x2b, 0x90,
-    0x8c, 0x12, 0x00, 0x01, 0x02, 0x2b, 0x90, 0x00,
-    0x00, 0x00, 0x02, 0x2b, 0x90, 0xc0, 0x5c, 0x4b,
-    0x00, 0x03, 0x01, 0x23, 0x96, 0x3b, 0x00, 0x11,
-    0x01, 0x30, 0x9e, 0x5d, 0x00, 0x01, 0x01, 0x30,
-    0xce, 0xcd, 0x2d, 0x00,
-};
-
-static const uint8_t unicode_prop_Hyphen_table[28] = {
-    0xac, 0x80, 0xfe, 0x80, 0x44, 0xdb, 0x80, 0x52,
-    0x7a, 0x80, 0x48, 0x08, 0x81, 0x4e, 0x04, 0x80,
-    0x42, 0xe2, 0x80, 0x60, 0xcd, 0x66, 0x80, 0x40,
-    0xa8, 0x80, 0xd6, 0x80,
-};
-
-static const uint8_t unicode_prop_Other_Math_table[200] = {
-    0xdd, 0x80, 0x43, 0x70, 0x11, 0x80, 0x99, 0x09,
-    0x81, 0x5c, 0x1f, 0x80, 0x9a, 0x82, 0x8a, 0x80,
-    0x9f, 0x83, 0x97, 0x81, 0x8d, 0x81, 0xc0, 0x8c,
-    0x18, 0x11, 0x1c, 0x91, 0x03, 0x01, 0x89, 0x00,
-    0x14, 0x28, 0x11, 0x09, 0x02, 0x05, 0x13, 0x24,
-    0xca, 0x21, 0x18, 0x08, 0x08, 0x00, 0x21, 0x0b,
-    0x0b, 0x91, 0x09, 0x00, 0x06, 0x00, 0x29, 0x41,
-    0x21, 0x83, 0x40, 0xa7, 0x08, 0x80, 0x97, 0x80,
-    0x90, 0x80, 0x41, 0xbc, 0x81, 0x8b, 0x88, 0x24,
-    0x21, 0x09, 0x14, 0x8d, 0x00, 0x01, 0x85, 0x97,
-    0x81, 0xb8, 0x00, 0x80, 0x9c, 0x83, 0x88, 0x81,
-    0x41, 0x55, 0x81, 0x9e, 0x89, 0x41, 0x92, 0x95,
-    0xbe, 0x83, 0x9f, 0x81, 0x60, 0xd4, 0x62, 0x00,
-    0x03, 0x80, 0x40, 0xd2, 0x00, 0x80, 0x60, 0xd4,
-    0xc0, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b,
-    0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f,
-    0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80,
-    0x41, 0x53, 0x81, 0x98, 0x80, 0x98, 0x80, 0x9e,
-    0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e,
-    0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x07, 0x81,
-    0xb1, 0x55, 0xff, 0x18, 0x9a, 0x01, 0x00, 0x08,
-    0x80, 0x89, 0x03, 0x00, 0x00, 0x28, 0x18, 0x00,
-    0x00, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,
-    0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00,
-    0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90,
-};
-
-static const uint8_t unicode_prop_Other_Alphabetic_table[417] = {
-    0x43, 0x44, 0x80, 0x42, 0x69, 0x8d, 0x00, 0x01,
-    0x01, 0x00, 0xc7, 0x8a, 0xaf, 0x8c, 0x06, 0x8f,
-    0x80, 0xe4, 0x33, 0x19, 0x0b, 0x80, 0xa2, 0x80,
-    0x9d, 0x8f, 0xe5, 0x8a, 0xe4, 0x0a, 0x88, 0x02,
-    0x03, 0x40, 0xa6, 0x8b, 0x16, 0x85, 0x93, 0xb5,
-    0x09, 0x8e, 0x01, 0x22, 0x89, 0x81, 0x9c, 0x82,
-    0xb9, 0x31, 0x09, 0x81, 0x89, 0x80, 0x89, 0x81,
-    0x9c, 0x82, 0xb9, 0x23, 0x09, 0x0b, 0x80, 0x9d,
-    0x0a, 0x80, 0x8a, 0x82, 0xb9, 0x38, 0x10, 0x81,
-    0x94, 0x81, 0x95, 0x13, 0x82, 0xb9, 0x31, 0x09,
-    0x81, 0x88, 0x81, 0x89, 0x81, 0x9d, 0x80, 0xba,
-    0x22, 0x10, 0x82, 0x89, 0x80, 0xa7, 0x83, 0xb9,
-    0x30, 0x10, 0x17, 0x81, 0x8a, 0x81, 0x9c, 0x82,
-    0xb9, 0x30, 0x10, 0x17, 0x81, 0x8a, 0x81, 0x9b,
-    0x83, 0xb9, 0x30, 0x10, 0x82, 0x89, 0x80, 0x89,
-    0x81, 0x9c, 0x82, 0xca, 0x28, 0x00, 0x87, 0x91,
-    0x81, 0xbc, 0x01, 0x86, 0x91, 0x80, 0xe2, 0x01,
-    0x28, 0x81, 0x8f, 0x80, 0x40, 0xa2, 0x90, 0x8a,
-    0x8a, 0x80, 0xa3, 0xed, 0x8b, 0x00, 0x0b, 0x96,
-    0x1b, 0x10, 0x11, 0x32, 0x83, 0x8c, 0x8b, 0x00,
-    0x89, 0x83, 0x46, 0x73, 0x81, 0x9d, 0x81, 0x9d,
-    0x81, 0x9d, 0x81, 0xc1, 0x92, 0x40, 0xbb, 0x81,
-    0xa1, 0x80, 0xf5, 0x8b, 0x83, 0x88, 0x40, 0xdd,
-    0x84, 0xb8, 0x89, 0x81, 0x93, 0xc9, 0x81, 0x8a,
-    0x82, 0xb0, 0x84, 0xaf, 0x8e, 0xbb, 0x82, 0x9d,
-    0x88, 0x09, 0xb8, 0x8a, 0xb1, 0x92, 0x41, 0xaf,
-    0x8d, 0x46, 0xc0, 0xb3, 0x48, 0xf5, 0x9f, 0x60,
-    0x78, 0x73, 0x87, 0xa1, 0x81, 0x41, 0x61, 0x07,
-    0x80, 0x96, 0x84, 0xd7, 0x81, 0xb1, 0x8f, 0x00,
-    0xb8, 0x80, 0xa5, 0x84, 0x9b, 0x8b, 0xac, 0x83,
-    0xaf, 0x8b, 0xa4, 0x80, 0xc2, 0x8d, 0x8b, 0x07,
-    0x81, 0xac, 0x82, 0xb1, 0x00, 0x11, 0x0c, 0x80,
-    0xab, 0x24, 0x80, 0x40, 0xec, 0x87, 0x60, 0x4f,
-    0x32, 0x80, 0x48, 0x56, 0x84, 0x46, 0x85, 0x10,
-    0x0c, 0x83, 0x43, 0x13, 0x83, 0x41, 0x82, 0x81,
-    0x41, 0x52, 0x82, 0xb4, 0x8d, 0xac, 0x81, 0x8c,
-    0x80, 0xac, 0x88, 0x88, 0x80, 0xbc, 0x82, 0xa3,
-    0x8b, 0x91, 0x81, 0xb8, 0x82, 0xaf, 0x8c, 0x8d,
-    0x81, 0xdb, 0x88, 0x08, 0x28, 0x40, 0x9f, 0x89,
-    0x96, 0x83, 0xb9, 0x31, 0x09, 0x81, 0x89, 0x80,
-    0x89, 0x81, 0x40, 0xd0, 0x8c, 0x02, 0xe9, 0x91,
-    0x40, 0xec, 0x31, 0x86, 0x9c, 0x81, 0xd1, 0x8e,
-    0x00, 0xe9, 0x8a, 0xe6, 0x8d, 0x41, 0x00, 0x8c,
-    0x40, 0xf6, 0x28, 0x09, 0x0a, 0x00, 0x80, 0x40,
-    0x8d, 0x31, 0x2b, 0x80, 0x9b, 0x89, 0xa9, 0x20,
-    0x83, 0x91, 0x8a, 0xad, 0x8d, 0x41, 0x96, 0x38,
-    0x86, 0xd2, 0x95, 0x80, 0x8d, 0xf9, 0x2a, 0x00,
-    0x08, 0x10, 0x02, 0x80, 0xc1, 0x20, 0x08, 0x83,
-    0x41, 0x5b, 0x83, 0x60, 0x50, 0x57, 0x00, 0xb6,
-    0x33, 0xdc, 0x81, 0x60, 0x4c, 0xab, 0x80, 0x60,
-    0x23, 0x60, 0x30, 0x90, 0x0e, 0x01, 0x04, 0x49,
-    0x1b, 0x80, 0x47, 0xe7, 0x99, 0x85, 0x99, 0x85,
-    0x99,
-};
-
-static const uint8_t unicode_prop_Other_Lowercase_table[59] = {
-    0x40, 0xa9, 0x80, 0x8e, 0x80, 0x41, 0xf4, 0x88,
-    0x31, 0x9d, 0x84, 0xdf, 0x80, 0xb3, 0x80, 0x59,
-    0xb0, 0xbe, 0x8c, 0x80, 0xa1, 0xa4, 0x42, 0xb0,
-    0x80, 0x8c, 0x80, 0x8f, 0x8c, 0x40, 0xd2, 0x8f,
-    0x43, 0x4f, 0x99, 0x47, 0x91, 0x81, 0x60, 0x7a,
-    0x1d, 0x81, 0x40, 0xd1, 0x80, 0x40, 0x86, 0x81,
-    0x43, 0x61, 0x83, 0x60, 0x5c, 0x1f, 0x01, 0x10,
-    0xa9, 0x80, 0x88,
-};
-
-static const uint8_t unicode_prop_Other_Uppercase_table[15] = {
-    0x60, 0x21, 0x5f, 0x8f, 0x43, 0x45, 0x99, 0x61,
-    0xcc, 0x5f, 0x99, 0x85, 0x99, 0x85, 0x99,
-};
-
-static const uint8_t unicode_prop_Other_Grapheme_Extend_table[65] = {
-    0x49, 0xbd, 0x80, 0x97, 0x80, 0x41, 0x65, 0x80,
-    0x97, 0x80, 0xe5, 0x80, 0x97, 0x80, 0x40, 0xe9,
-    0x80, 0x91, 0x81, 0xe6, 0x80, 0x97, 0x80, 0xf6,
-    0x80, 0x8e, 0x80, 0x4d, 0x54, 0x80, 0x44, 0xd5,
-    0x80, 0x50, 0x20, 0x81, 0x60, 0xcf, 0x6d, 0x81,
-    0x53, 0x9d, 0x80, 0x97, 0x80, 0x41, 0x57, 0x80,
-    0x8b, 0x80, 0x40, 0xf0, 0x80, 0x43, 0x7f, 0x80,
-    0x60, 0xb8, 0x33, 0x07, 0x84, 0x6c, 0x2e, 0xac,
-    0xdf,
-};
-
-static const uint8_t unicode_prop_Other_Default_Ignorable_Code_Point_table[32] = {
-    0x43, 0x4e, 0x80, 0x4e, 0x0e, 0x81, 0x46, 0x52,
-    0x81, 0x48, 0xae, 0x80, 0x50, 0xfd, 0x80, 0x60,
-    0xce, 0x3a, 0x80, 0xce, 0x88, 0x6d, 0x00, 0x06,
-    0x00, 0x9d, 0xdf, 0xff, 0x40, 0xef, 0x4e, 0x0f,
-};
-
-static const uint8_t unicode_prop_Other_ID_Start_table[11] = {
-    0x58, 0x84, 0x81, 0x48, 0x90, 0x80, 0x94, 0x80,
-    0x4f, 0x6b, 0x81,
-};
-
-static const uint8_t unicode_prop_Other_ID_Continue_table[12] = {
-    0x40, 0xb6, 0x80, 0x42, 0xce, 0x80, 0x4f, 0xe0,
-    0x88, 0x46, 0x67, 0x80,
-};
-
-static const uint8_t unicode_prop_Prepended_Concatenation_Mark_table[19] = {
-    0x45, 0xff, 0x85, 0x40, 0xd6, 0x80, 0xb0, 0x80,
-    0x41, 0x7f, 0x81, 0xcf, 0x80, 0x61, 0x07, 0xd9,
-    0x80, 0x8e, 0x80,
-};
-
-static const uint8_t unicode_prop_XID_Start1_table[31] = {
-    0x43, 0x79, 0x80, 0x4a, 0xb7, 0x80, 0xfe, 0x80,
-    0x60, 0x21, 0xe6, 0x81, 0x60, 0xcb, 0xc0, 0x85,
-    0x41, 0x95, 0x81, 0xf3, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x80, 0x41, 0x1e, 0x81,
-};
-
-static const uint8_t unicode_prop_XID_Continue1_table[23] = {
-    0x43, 0x79, 0x80, 0x60, 0x2d, 0x1f, 0x81, 0x60,
-    0xcb, 0xc0, 0x85, 0x41, 0x95, 0x81, 0xf3, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-};
-
-static const uint8_t unicode_prop_Changes_When_Titlecased1_table[22] = {
-    0x41, 0xc3, 0x08, 0x08, 0x81, 0xa4, 0x81, 0x4e,
-    0xdc, 0xaa, 0x0a, 0x4e, 0x87, 0x3f, 0x3f, 0x87,
-    0x8b, 0x80, 0x8e, 0x80, 0xae, 0x80,
-};
-
-static const uint8_t unicode_prop_Changes_When_Casefolded1_table[33] = {
-    0x40, 0xde, 0x80, 0xcf, 0x80, 0x97, 0x80, 0x44,
-    0x3c, 0x80, 0x59, 0x11, 0x80, 0x40, 0xe4, 0x3f,
-    0x3f, 0x87, 0x89, 0x11, 0x05, 0x02, 0x11, 0x80,
-    0xa9, 0x11, 0x80, 0x60, 0xdb, 0x07, 0x86, 0x8b,
-    0x84,
-};
-
-static const uint8_t unicode_prop_Changes_When_NFKC_Casefolded1_table[448] = {
-    0x40, 0x9f, 0x06, 0x00, 0x01, 0x00, 0x01, 0x12,
-    0x10, 0x82, 0x9f, 0x80, 0xcf, 0x01, 0x80, 0x8b,
-    0x07, 0x80, 0xfb, 0x01, 0x01, 0x80, 0xa5, 0x80,
-    0x40, 0xbb, 0x88, 0x9e, 0x29, 0x84, 0xda, 0x08,
-    0x81, 0x89, 0x80, 0xa3, 0x04, 0x02, 0x04, 0x08,
-    0x80, 0xc9, 0x82, 0x9c, 0x80, 0x41, 0x93, 0x80,
-    0x40, 0x93, 0x80, 0xd7, 0x83, 0x42, 0xde, 0x87,
-    0xfb, 0x08, 0x80, 0xd2, 0x01, 0x80, 0xa1, 0x11,
-    0x80, 0x40, 0xfc, 0x81, 0x42, 0xd4, 0x80, 0xfe,
-    0x80, 0xa7, 0x81, 0xad, 0x80, 0xb5, 0x80, 0x88,
-    0x03, 0x03, 0x03, 0x80, 0x8b, 0x80, 0x88, 0x00,
-    0x26, 0x80, 0x90, 0x80, 0x88, 0x03, 0x03, 0x03,
-    0x80, 0x8b, 0x80, 0x41, 0x41, 0x80, 0xe1, 0x81,
-    0x46, 0x52, 0x81, 0xd4, 0x84, 0x45, 0x1b, 0x10,
-    0x8a, 0x80, 0x91, 0x80, 0x9b, 0x8c, 0x80, 0xa1,
-    0xa4, 0x40, 0xd9, 0x80, 0x40, 0xd5, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x01, 0x3f, 0x3f, 0x87,
-    0x89, 0x11, 0x04, 0x00, 0x29, 0x04, 0x12, 0x80,
-    0x88, 0x12, 0x80, 0x88, 0x11, 0x11, 0x04, 0x08,
-    0x8f, 0x00, 0x20, 0x8b, 0x12, 0x2a, 0x08, 0x0b,
-    0x00, 0x07, 0x82, 0x8c, 0x06, 0x92, 0x81, 0x9a,
-    0x80, 0x8c, 0x8a, 0x80, 0xd6, 0x18, 0x10, 0x8a,
-    0x01, 0x0c, 0x0a, 0x00, 0x10, 0x11, 0x02, 0x06,
-    0x05, 0x1c, 0x85, 0x8f, 0x8f, 0x8f, 0x88, 0x80,
-    0x40, 0xa1, 0x08, 0x81, 0x40, 0xf7, 0x81, 0x41,
-    0x34, 0xd5, 0x99, 0x9a, 0x45, 0x20, 0x80, 0xe6,
-    0x82, 0xe4, 0x80, 0x41, 0x9e, 0x81, 0x40, 0xf0,
-    0x80, 0x41, 0x2e, 0x80, 0xd2, 0x80, 0x8b, 0x40,
-    0xd5, 0xa9, 0x80, 0xb4, 0x00, 0x82, 0xdf, 0x09,
-    0x80, 0xde, 0x80, 0xb0, 0xdd, 0x82, 0x8d, 0xdf,
-    0x9e, 0x80, 0xa7, 0x87, 0xae, 0x80, 0x41, 0x7f,
-    0x60, 0x72, 0x9b, 0x81, 0x40, 0xd1, 0x80, 0x40,
-    0x80, 0x12, 0x81, 0x43, 0x61, 0x83, 0x88, 0x80,
-    0x60, 0x4d, 0x95, 0x41, 0x0d, 0x08, 0x00, 0x81,
-    0x89, 0x00, 0x00, 0x09, 0x82, 0xc3, 0x81, 0xe9,
-    0xa5, 0x86, 0x8b, 0x24, 0x00, 0x97, 0x04, 0x00,
-    0x01, 0x01, 0x80, 0xeb, 0xa0, 0x41, 0x6a, 0x91,
-    0xbf, 0x81, 0xb5, 0xa7, 0x8c, 0x82, 0x99, 0x95,
-    0x94, 0x81, 0x8b, 0x80, 0x92, 0x03, 0x1a, 0x00,
-    0x80, 0x40, 0x86, 0x08, 0x80, 0x9f, 0x99, 0x40,
-    0x83, 0x15, 0x0d, 0x0d, 0x0a, 0x16, 0x06, 0x80,
-    0x88, 0x47, 0x87, 0x20, 0xa9, 0x80, 0x88, 0x60,
-    0xb4, 0xe4, 0x83, 0x54, 0xb9, 0x86, 0x8d, 0x87,
-    0xbf, 0x85, 0x42, 0x3e, 0xd4, 0x80, 0xc6, 0x01,
-    0x08, 0x09, 0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80,
-    0xc0, 0x03, 0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04,
-    0x00, 0x16, 0x80, 0x41, 0x53, 0x81, 0x41, 0x23,
-    0x81, 0xb1, 0x55, 0xff, 0x18, 0x9a, 0x01, 0x00,
-    0x08, 0x80, 0x89, 0x03, 0x00, 0x00, 0x28, 0x18,
-    0x00, 0x00, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00,
-    0x00, 0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, 0x03,
-    0x00, 0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80,
-    0x90, 0x42, 0x43, 0x8a, 0x84, 0x9e, 0x80, 0x9f,
-    0x99, 0x82, 0xa2, 0x80, 0xee, 0x82, 0x8c, 0xab,
-    0x83, 0x88, 0x31, 0x49, 0x9d, 0x89, 0x60, 0xfc,
-    0x05, 0x42, 0x1d, 0x6b, 0x05, 0xe1, 0x4f, 0xff,
-};
-
-static const uint8_t unicode_prop_ASCII_Hex_Digit_table[5] = {
-    0xaf, 0x89, 0x35, 0x99, 0x85,
-};
-
-static const uint8_t unicode_prop_Bidi_Control_table[10] = {
-    0x46, 0x1b, 0x80, 0x59, 0xf0, 0x81, 0x99, 0x84,
-    0xb6, 0x83,
-};
-
-static const uint8_t unicode_prop_Dash_table[55] = {
-    0xac, 0x80, 0x45, 0x5b, 0x80, 0xb2, 0x80, 0x4e,
-    0x40, 0x80, 0x44, 0x04, 0x80, 0x48, 0x08, 0x85,
-    0xbc, 0x80, 0xa6, 0x80, 0x8e, 0x80, 0x41, 0x85,
-    0x80, 0x4c, 0x03, 0x01, 0x80, 0x9e, 0x0b, 0x80,
-    0x9b, 0x80, 0x41, 0xbd, 0x80, 0x92, 0x80, 0xee,
-    0x80, 0x60, 0xcd, 0x8f, 0x81, 0xa4, 0x80, 0x89,
-    0x80, 0x40, 0xa8, 0x80, 0x4f, 0x9e, 0x80,
-};
-
-static const uint8_t unicode_prop_Deprecated_table[23] = {
-    0x41, 0x48, 0x80, 0x45, 0x28, 0x80, 0x49, 0x02,
-    0x00, 0x80, 0x48, 0x28, 0x81, 0x48, 0xc4, 0x85,
-    0x42, 0xb8, 0x81, 0x6d, 0xdc, 0xd5, 0x80,
-};
-
-static const uint8_t unicode_prop_Diacritic_table[391] = {
-    0xdd, 0x00, 0x80, 0xc6, 0x05, 0x03, 0x01, 0x81,
-    0x41, 0xf6, 0x40, 0x9e, 0x07, 0x25, 0x90, 0x0b,
-    0x80, 0x88, 0x81, 0x40, 0xfc, 0x84, 0x40, 0xd0,
-    0x80, 0xb6, 0x90, 0x80, 0x9a, 0x00, 0x01, 0x00,
-    0x40, 0x85, 0x3b, 0x81, 0x40, 0x85, 0x0b, 0x0a,
-    0x82, 0xc2, 0x9a, 0xda, 0x8a, 0xb9, 0x8a, 0xa1,
-    0x81, 0xfd, 0x87, 0xa8, 0x89, 0x8f, 0x9b, 0xbc,
-    0x80, 0x8f, 0x02, 0x83, 0x9b, 0x80, 0xc9, 0x80,
-    0x8f, 0x80, 0xed, 0x80, 0x8f, 0x80, 0xed, 0x80,
-    0x8f, 0x80, 0xae, 0x82, 0xbb, 0x80, 0x8f, 0x06,
-    0x80, 0xf6, 0x80, 0xed, 0x80, 0x8f, 0x80, 0xed,
-    0x80, 0x8f, 0x80, 0xec, 0x81, 0x8f, 0x80, 0xfb,
-    0x80, 0xfb, 0x28, 0x80, 0xea, 0x80, 0x8c, 0x84,
-    0xca, 0x81, 0x9a, 0x00, 0x00, 0x03, 0x81, 0xc1,
-    0x10, 0x81, 0xbd, 0x80, 0xef, 0x00, 0x81, 0xa7,
-    0x0b, 0x84, 0x98, 0x30, 0x80, 0x89, 0x81, 0x42,
-    0xc0, 0x82, 0x43, 0xb3, 0x81, 0x40, 0xb2, 0x8a,
-    0x88, 0x80, 0x41, 0x5a, 0x82, 0x41, 0x38, 0x39,
-    0x80, 0xaf, 0x8e, 0x81, 0x8a, 0xe7, 0x80, 0x8e,
-    0x80, 0xa5, 0x88, 0xb5, 0x81, 0x40, 0x89, 0x81,
-    0xbf, 0x85, 0xd1, 0x98, 0x18, 0x28, 0x0a, 0xb1,
-    0xbe, 0xd8, 0x8b, 0xa4, 0x8a, 0x41, 0xbc, 0x00,
-    0x82, 0x8a, 0x82, 0x8c, 0x82, 0x8c, 0x82, 0x8c,
-    0x81, 0x4c, 0xef, 0x82, 0x41, 0x3c, 0x80, 0x41,
-    0xf9, 0x85, 0xe8, 0x83, 0xde, 0x80, 0x60, 0x75,
-    0x71, 0x80, 0x8b, 0x08, 0x80, 0x9b, 0x81, 0xd1,
-    0x81, 0x8d, 0xa1, 0xe5, 0x82, 0xec, 0x81, 0x40,
-    0xc9, 0x80, 0x9a, 0x91, 0xb8, 0x83, 0xa3, 0x80,
-    0xde, 0x80, 0x8b, 0x80, 0xa3, 0x80, 0x40, 0x94,
-    0x82, 0xc0, 0x83, 0xb2, 0x80, 0xe3, 0x84, 0x88,
-    0x82, 0xff, 0x81, 0x60, 0x4f, 0x2f, 0x80, 0x43,
-    0x00, 0x8f, 0x41, 0x0d, 0x00, 0x80, 0xae, 0x80,
-    0xac, 0x81, 0xc2, 0x80, 0x42, 0xfb, 0x80, 0x44,
-    0x9e, 0x28, 0xa9, 0x80, 0x88, 0x43, 0x29, 0x81,
-    0x42, 0x3a, 0x85, 0x42, 0x1d, 0x8a, 0xb0, 0x83,
-    0x40, 0xbf, 0x80, 0xa8, 0x80, 0xc7, 0x81, 0xf7,
-    0x81, 0xbd, 0x80, 0xcb, 0x80, 0x88, 0x82, 0xe7,
-    0x81, 0x40, 0xb1, 0x81, 0xd0, 0x80, 0x8f, 0x80,
-    0x97, 0x32, 0x84, 0x40, 0xcc, 0x02, 0x80, 0xfa,
-    0x81, 0x40, 0xfa, 0x81, 0xfd, 0x80, 0xf5, 0x81,
-    0xf2, 0x80, 0x41, 0x0c, 0x81, 0x41, 0x01, 0x0b,
-    0x80, 0x40, 0x9b, 0x80, 0xd2, 0x80, 0x91, 0x80,
-    0xd0, 0x80, 0x41, 0xa4, 0x80, 0x41, 0x01, 0x00,
-    0x81, 0xd0, 0x80, 0x60, 0x4d, 0x57, 0x84, 0xba,
-    0x86, 0x44, 0x57, 0x90, 0xcf, 0x81, 0x60, 0x3f,
-    0xfd, 0x18, 0x30, 0x81, 0x5f, 0x00, 0xad, 0x81,
-    0x96, 0x42, 0x1f, 0x12, 0x2f, 0x39, 0x86, 0x9d,
-    0x83, 0x4f, 0x81, 0x86, 0x41, 0x76, 0x80, 0xbc,
-    0x83, 0x45, 0xdf, 0x86, 0xec, 0x10, 0x82,
-};
-
-static const uint8_t unicode_prop_Extender_table[92] = {
-    0x40, 0xb6, 0x80, 0x42, 0x17, 0x81, 0x43, 0x6d,
-    0x80, 0x41, 0xb8, 0x80, 0x43, 0x59, 0x80, 0x42,
-    0xef, 0x80, 0xfe, 0x80, 0x49, 0x42, 0x80, 0xb7,
-    0x80, 0x42, 0x62, 0x80, 0x41, 0x8d, 0x80, 0xc3,
-    0x80, 0x53, 0x88, 0x80, 0xaa, 0x84, 0xe6, 0x81,
-    0xdc, 0x82, 0x60, 0x6f, 0x15, 0x80, 0x45, 0xf5,
-    0x80, 0x43, 0xc1, 0x80, 0x95, 0x80, 0x40, 0x88,
-    0x80, 0xeb, 0x80, 0x94, 0x81, 0x60, 0x54, 0x7a,
-    0x80, 0x48, 0x0f, 0x81, 0x4b, 0xd9, 0x80, 0x42,
-    0x67, 0x82, 0x44, 0xce, 0x80, 0x60, 0x50, 0xa8,
-    0x81, 0x44, 0x9b, 0x08, 0x80, 0x60, 0x71, 0x57,
-    0x81, 0x48, 0x05, 0x82,
-};
-
-static const uint8_t unicode_prop_Hex_Digit_table[12] = {
-    0xaf, 0x89, 0x35, 0x99, 0x85, 0x60, 0xfe, 0xa8,
-    0x89, 0x35, 0x99, 0x85,
-};
-
-static const uint8_t unicode_prop_IDS_Binary_Operator_table[5] = {
-    0x60, 0x2f, 0xef, 0x09, 0x87,
-};
-
-static const uint8_t unicode_prop_IDS_Trinary_Operator_table[4] = {
-    0x60, 0x2f, 0xf1, 0x81,
-};
-
-static const uint8_t unicode_prop_Ideographic_table[66] = {
-    0x60, 0x30, 0x05, 0x81, 0x98, 0x88, 0x8d, 0x82,
-    0x43, 0xc4, 0x59, 0xbf, 0xbf, 0x60, 0x51, 0xff,
-    0x60, 0x58, 0xff, 0x41, 0x6d, 0x81, 0xe9, 0x60,
-    0x75, 0x09, 0x80, 0x9a, 0x57, 0xf7, 0x87, 0x44,
-    0xd5, 0xa9, 0x88, 0x60, 0x24, 0x66, 0x41, 0x8b,
-    0x60, 0x4d, 0x03, 0x60, 0xa6, 0xdf, 0x9f, 0x50,
-    0x38, 0x86, 0x40, 0xdd, 0x81, 0x56, 0x81, 0x8d,
-    0x5d, 0x30, 0x4c, 0x1e, 0x42, 0x1d, 0x45, 0xe1,
-    0x53, 0x4a,
-};
-
-static const uint8_t unicode_prop_Join_Control_table[4] = {
-    0x60, 0x20, 0x0b, 0x81,
-};
-
-static const uint8_t unicode_prop_Logical_Order_Exception_table[15] = {
-    0x4e, 0x3f, 0x84, 0xfa, 0x84, 0x4a, 0xef, 0x11,
-    0x80, 0x60, 0x90, 0xf9, 0x09, 0x00, 0x81,
-};
-
-static const uint8_t unicode_prop_Noncharacter_Code_Point_table[71] = {
-    0x60, 0xfd, 0xcf, 0x9f, 0x42, 0x0d, 0x81, 0x60,
-    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
-    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
-    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
-    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
-    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
-    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
-    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,
-    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81,
-};
-
-static const uint8_t unicode_prop_Pattern_Syntax_table[58] = {
-    0xa0, 0x8e, 0x89, 0x86, 0x99, 0x18, 0x80, 0x99,
-    0x83, 0xa1, 0x30, 0x00, 0x08, 0x00, 0x0b, 0x03,
-    0x02, 0x80, 0x96, 0x80, 0x9e, 0x80, 0x5f, 0x17,
-    0x97, 0x87, 0x8e, 0x81, 0x92, 0x80, 0x89, 0x41,
-    0x30, 0x42, 0xcf, 0x40, 0x9f, 0x42, 0x75, 0x9d,
-    0x44, 0x6b, 0x41, 0xff, 0xff, 0x41, 0x80, 0x13,
-    0x98, 0x8e, 0x80, 0x60, 0xcd, 0x0c, 0x81, 0x41,
-    0x04, 0x81,
-};
-
-static const uint8_t unicode_prop_Pattern_White_Space_table[11] = {
-    0x88, 0x84, 0x91, 0x80, 0xe3, 0x80, 0x5f, 0x87,
-    0x81, 0x97, 0x81,
-};
-
-static const uint8_t unicode_prop_Quotation_Mark_table[31] = {
-    0xa1, 0x03, 0x80, 0x40, 0x82, 0x80, 0x8e, 0x80,
-    0x5f, 0x5b, 0x87, 0x98, 0x81, 0x4e, 0x06, 0x80,
-    0x41, 0xc8, 0x83, 0x8c, 0x82, 0x60, 0xce, 0x20,
-    0x83, 0x40, 0xbc, 0x03, 0x80, 0xd9, 0x81,
-};
-
-static const uint8_t unicode_prop_Radical_table[9] = {
-    0x60, 0x2e, 0x7f, 0x99, 0x80, 0xd8, 0x8b, 0x40,
-    0xd5,
-};
-
-static const uint8_t unicode_prop_Regional_Indicator_table[4] = {
-    0x61, 0xf1, 0xe5, 0x99,
-};
-
-static const uint8_t unicode_prop_Sentence_Terminal_table[194] = {
-    0xa0, 0x80, 0x8b, 0x80, 0x8f, 0x80, 0x45, 0x48,
-    0x80, 0x40, 0x92, 0x82, 0x40, 0xb3, 0x80, 0xaa,
-    0x82, 0x40, 0xf5, 0x80, 0xbc, 0x00, 0x02, 0x81,
-    0x41, 0x24, 0x81, 0x46, 0xe3, 0x81, 0x43, 0x15,
-    0x03, 0x81, 0x43, 0x04, 0x80, 0x40, 0xc5, 0x81,
-    0x40, 0xcb, 0x04, 0x80, 0x41, 0x39, 0x81, 0x41,
-    0x61, 0x83, 0x40, 0xad, 0x09, 0x81, 0x9c, 0x81,
-    0x40, 0xbb, 0x81, 0xc0, 0x81, 0x43, 0xbb, 0x81,
-    0x88, 0x82, 0x4d, 0xe3, 0x80, 0x8c, 0x80, 0x95,
-    0x81, 0x41, 0xac, 0x80, 0x60, 0x74, 0xfb, 0x80,
-    0x41, 0x0d, 0x81, 0x40, 0xe2, 0x02, 0x80, 0x41,
-    0x7d, 0x81, 0xd5, 0x81, 0xde, 0x80, 0x40, 0x97,
-    0x81, 0x40, 0x92, 0x82, 0x40, 0x8f, 0x81, 0x40,
-    0xf8, 0x80, 0x60, 0x52, 0x65, 0x02, 0x81, 0x40,
-    0xa8, 0x80, 0x8b, 0x80, 0x8f, 0x80, 0xc0, 0x80,
-    0x4a, 0xf3, 0x81, 0x44, 0xfc, 0x84, 0xab, 0x83,
-    0x40, 0xbc, 0x81, 0xf4, 0x83, 0xfe, 0x82, 0x40,
-    0x80, 0x0d, 0x80, 0x8f, 0x81, 0xd7, 0x08, 0x81,
-    0xeb, 0x80, 0x41, 0xa0, 0x81, 0x41, 0x74, 0x0c,
-    0x8e, 0xe8, 0x81, 0x40, 0xf8, 0x82, 0x42, 0x04,
-    0x00, 0x80, 0x40, 0xfa, 0x81, 0xd6, 0x81, 0x41,
-    0xa3, 0x81, 0x42, 0xb3, 0x81, 0x60, 0x4b, 0x74,
-    0x81, 0x40, 0x84, 0x80, 0xc0, 0x81, 0x8a, 0x80,
-    0x43, 0x52, 0x80, 0x60, 0x4e, 0x05, 0x80, 0x5d,
-    0xe7, 0x80,
-};
-
-static const uint8_t unicode_prop_Soft_Dotted_table[74] = {
-    0xe8, 0x81, 0x40, 0xc3, 0x80, 0x41, 0x18, 0x80,
-    0x9d, 0x80, 0xb3, 0x80, 0x93, 0x80, 0x41, 0x3f,
-    0x80, 0xe1, 0x00, 0x80, 0x59, 0x08, 0x80, 0xb2,
-    0x80, 0x8c, 0x02, 0x80, 0x40, 0x83, 0x80, 0x40,
-    0x9c, 0x80, 0x41, 0xa4, 0x80, 0x40, 0xd5, 0x81,
-    0x4b, 0x31, 0x80, 0x61, 0xa7, 0xa4, 0x81, 0xb1,
-    0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1,
-    0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1,
-    0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0x48,
-    0x85, 0x80,
-};
-
-static const uint8_t unicode_prop_Terminal_Punctuation_table[246] = {
-    0xa0, 0x80, 0x89, 0x00, 0x80, 0x8a, 0x0a, 0x80,
-    0x43, 0x3d, 0x07, 0x80, 0x42, 0x00, 0x80, 0xb8,
-    0x80, 0xc7, 0x80, 0x8d, 0x00, 0x82, 0x40, 0xb3,
-    0x80, 0xaa, 0x8a, 0x00, 0x40, 0xea, 0x81, 0xb5,
-    0x8e, 0x9e, 0x80, 0x41, 0x04, 0x81, 0x44, 0xf3,
-    0x81, 0x40, 0xab, 0x03, 0x85, 0x41, 0x36, 0x81,
-    0x43, 0x14, 0x87, 0x43, 0x04, 0x80, 0xfb, 0x82,
-    0xc6, 0x81, 0x40, 0x9c, 0x12, 0x80, 0xa6, 0x19,
-    0x81, 0x41, 0x39, 0x81, 0x41, 0x61, 0x83, 0x40,
-    0xad, 0x08, 0x82, 0x9c, 0x81, 0x40, 0xbb, 0x84,
-    0xbd, 0x81, 0x43, 0xbb, 0x81, 0x88, 0x82, 0x4d,
-    0xe3, 0x80, 0x8c, 0x03, 0x80, 0x89, 0x00, 0x0a,
-    0x81, 0x41, 0xab, 0x81, 0x60, 0x74, 0xfa, 0x81,
-    0x41, 0x0c, 0x82, 0x40, 0xe2, 0x84, 0x41, 0x7d,
-    0x81, 0xd5, 0x81, 0xde, 0x80, 0x40, 0x96, 0x82,
-    0x40, 0x92, 0x82, 0xfe, 0x80, 0x8f, 0x81, 0x40,
-    0xf8, 0x80, 0x60, 0x52, 0x63, 0x10, 0x83, 0x40,
-    0xa8, 0x80, 0x89, 0x00, 0x80, 0x8a, 0x0a, 0x80,
-    0xc0, 0x01, 0x80, 0x44, 0x39, 0x80, 0xaf, 0x80,
-    0x44, 0x85, 0x80, 0x40, 0xc6, 0x80, 0x41, 0x35,
-    0x81, 0x40, 0x97, 0x85, 0xc3, 0x85, 0xd8, 0x83,
-    0x43, 0xb7, 0x84, 0xab, 0x83, 0x40, 0xbc, 0x86,
-    0xef, 0x83, 0xfe, 0x82, 0x40, 0x80, 0x0d, 0x80,
-    0x8f, 0x81, 0xd7, 0x84, 0xeb, 0x80, 0x41, 0xa0,
-    0x82, 0x8b, 0x81, 0x41, 0x65, 0x1a, 0x8e, 0xe8,
-    0x81, 0x40, 0xf8, 0x82, 0x42, 0x04, 0x00, 0x80,
-    0x40, 0xfa, 0x81, 0xd6, 0x0b, 0x81, 0x41, 0x9d,
-    0x82, 0xac, 0x80, 0x42, 0x84, 0x81, 0x45, 0x76,
-    0x84, 0x60, 0x45, 0xf8, 0x81, 0x40, 0x84, 0x80,
-    0xc0, 0x82, 0x89, 0x80, 0x43, 0x51, 0x81, 0x60,
-    0x4e, 0x05, 0x80, 0x5d, 0xe6, 0x83,
-};
-
-static const uint8_t unicode_prop_Unified_Ideograph_table[42] = {
-    0x60, 0x33, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x51,
-    0xff, 0x60, 0x5a, 0x0d, 0x08, 0x00, 0x81, 0x89,
-    0x00, 0x00, 0x09, 0x82, 0x61, 0x05, 0xd5, 0x60,
-    0xa6, 0xdf, 0x9f, 0x50, 0x38, 0x86, 0x40, 0xdd,
-    0x81, 0x56, 0x81, 0x8d, 0x5d, 0x30, 0x54, 0x1e,
-    0x53, 0x4a,
-};
-
-static const uint8_t unicode_prop_Variation_Selector_table[13] = {
-    0x58, 0x0a, 0x10, 0x80, 0x60, 0xe5, 0xef, 0x8f,
-    0x6d, 0x02, 0xef, 0x40, 0xef,
-};
-
-static const uint8_t unicode_prop_White_Space_table[22] = {
-    0x88, 0x84, 0x91, 0x80, 0xe3, 0x80, 0x99, 0x80,
-    0x55, 0xde, 0x80, 0x49, 0x7e, 0x8a, 0x9c, 0x0c,
-    0x80, 0xae, 0x80, 0x4f, 0x9f, 0x80,
-};
-
-static const uint8_t unicode_prop_Bidi_Mirrored_table[173] = {
-    0xa7, 0x81, 0x91, 0x00, 0x80, 0x9b, 0x00, 0x80,
-    0x9c, 0x00, 0x80, 0xac, 0x80, 0x8e, 0x80, 0x4e,
-    0x7d, 0x83, 0x47, 0x5c, 0x81, 0x49, 0x9b, 0x81,
-    0x89, 0x81, 0xb5, 0x81, 0x8d, 0x81, 0x40, 0xb0,
-    0x80, 0x40, 0xbf, 0x1a, 0x2a, 0x02, 0x0a, 0x18,
-    0x18, 0x00, 0x03, 0x88, 0x20, 0x80, 0x91, 0x23,
-    0x88, 0x08, 0x00, 0x39, 0x9e, 0x0b, 0x20, 0x88,
-    0x09, 0x92, 0x21, 0x88, 0x21, 0x0b, 0x97, 0x81,
-    0x8f, 0x3b, 0x93, 0x0e, 0x81, 0x44, 0x3c, 0x8d,
-    0xc9, 0x01, 0x18, 0x08, 0x14, 0x1c, 0x12, 0x8d,
-    0x41, 0x92, 0x95, 0x0d, 0x80, 0x8d, 0x38, 0x35,
-    0x10, 0x1c, 0x01, 0x0c, 0x18, 0x02, 0x09, 0x89,
-    0x29, 0x81, 0x8b, 0x92, 0x03, 0x08, 0x00, 0x08,
-    0x03, 0x21, 0x2a, 0x97, 0x81, 0x8a, 0x0b, 0x18,
-    0x09, 0x0b, 0xaa, 0x0f, 0x80, 0xa7, 0x20, 0x00,
-    0x14, 0x22, 0x18, 0x14, 0x00, 0x40, 0xff, 0x80,
-    0x42, 0x02, 0x1a, 0x08, 0x81, 0x8d, 0x09, 0x89,
-    0xaa, 0x87, 0x41, 0xaa, 0x89, 0x0f, 0x60, 0xce,
-    0x3c, 0x2c, 0x81, 0x40, 0xa1, 0x81, 0x91, 0x00,
-    0x80, 0x9b, 0x00, 0x80, 0x9c, 0x00, 0x00, 0x08,
-    0x81, 0x60, 0xd7, 0x76, 0x80, 0xb8, 0x80, 0xb8,
-    0x80, 0xb8, 0x80, 0xb8, 0x80,
-};
-
-static const uint8_t unicode_prop_Emoji_table[239] = {
-    0xa2, 0x05, 0x04, 0x89, 0xee, 0x03, 0x80, 0x5f,
-    0x8c, 0x80, 0x8b, 0x80, 0x40, 0xd7, 0x80, 0x95,
-    0x80, 0xd9, 0x85, 0x8e, 0x81, 0x41, 0x6e, 0x81,
-    0x8b, 0x80, 0x40, 0xa5, 0x80, 0x98, 0x8a, 0x1a,
-    0x40, 0xc6, 0x80, 0x40, 0xe6, 0x81, 0x89, 0x80,
-    0x88, 0x80, 0xb9, 0x18, 0x84, 0x88, 0x01, 0x01,
-    0x09, 0x03, 0x01, 0x00, 0x09, 0x02, 0x02, 0x0f,
-    0x14, 0x00, 0x04, 0x8b, 0x8a, 0x09, 0x00, 0x08,
-    0x80, 0x91, 0x01, 0x81, 0x91, 0x28, 0x00, 0x0a,
-    0x0c, 0x01, 0x0b, 0x81, 0x8a, 0x0c, 0x09, 0x04,
-    0x08, 0x00, 0x81, 0x93, 0x0c, 0x28, 0x19, 0x03,
-    0x01, 0x01, 0x28, 0x01, 0x00, 0x00, 0x05, 0x02,
-    0x05, 0x80, 0x89, 0x81, 0x8e, 0x01, 0x03, 0x00,
-    0x03, 0x10, 0x80, 0x8a, 0x81, 0xaf, 0x82, 0x88,
-    0x80, 0x8d, 0x80, 0x8d, 0x80, 0x41, 0x73, 0x81,
-    0x41, 0xce, 0x82, 0x92, 0x81, 0xb2, 0x03, 0x80,
-    0x44, 0xd9, 0x80, 0x8b, 0x80, 0x42, 0x58, 0x00,
-    0x80, 0x61, 0xbd, 0x69, 0x80, 0x40, 0xc9, 0x80,
-    0x40, 0x9f, 0x81, 0x8b, 0x81, 0x8d, 0x01, 0x89,
-    0xca, 0x99, 0x01, 0x96, 0x80, 0x93, 0x01, 0x88,
-    0x94, 0x81, 0x40, 0xad, 0xa1, 0x81, 0xef, 0x09,
-    0x02, 0x81, 0xd2, 0x0a, 0x80, 0x41, 0x06, 0x80,
-    0xbe, 0x8a, 0x28, 0x97, 0x31, 0x0f, 0x8b, 0x01,
-    0x19, 0x03, 0x81, 0x8c, 0x09, 0x07, 0x81, 0x88,
-    0x04, 0x82, 0x8b, 0x17, 0x11, 0x00, 0x03, 0x05,
-    0x02, 0x05, 0xd5, 0xaf, 0xc5, 0x27, 0x0a, 0x84,
-    0x88, 0x10, 0x01, 0x10, 0x81, 0x89, 0x40, 0xe2,
-    0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80, 0x89, 0x80,
-    0x40, 0xb8, 0xef, 0x22, 0x22, 0x86, 0x88, 0x9c,
-    0x82, 0x8a, 0x25, 0x89, 0x89, 0x2f, 0x3e,
-};
-
-static const uint8_t unicode_prop_Emoji_Component_table[28] = {
-    0xa2, 0x05, 0x04, 0x89, 0x5f, 0xd2, 0x80, 0x40,
-    0xd4, 0x80, 0x60, 0xdd, 0x2a, 0x80, 0x60, 0xf3,
-    0xd5, 0x99, 0x41, 0xfa, 0x84, 0x45, 0xaf, 0x83,
-    0x6c, 0x06, 0x6b, 0xdf,
-};
-
-static const uint8_t unicode_prop_Emoji_Modifier_table[4] = {
-    0x61, 0xf3, 0xfa, 0x84,
-};
-
-static const uint8_t unicode_prop_Emoji_Modifier_Base_table[71] = {
-    0x60, 0x26, 0x1c, 0x80, 0x40, 0xda, 0x80, 0x8f,
-    0x83, 0x61, 0xcc, 0x76, 0x80, 0xbb, 0x11, 0x01,
-    0x82, 0xf4, 0x09, 0x8a, 0x94, 0x92, 0x10, 0x1a,
-    0x02, 0x30, 0x00, 0x97, 0x80, 0x40, 0xc8, 0x0b,
-    0x80, 0x94, 0x03, 0x81, 0x40, 0xad, 0x12, 0x84,
-    0xd2, 0x80, 0x8f, 0x82, 0x88, 0x80, 0x8a, 0x80,
-    0x42, 0x3e, 0x01, 0x07, 0x3d, 0x80, 0x88, 0x89,
-    0x0a, 0xb7, 0x80, 0xbc, 0x08, 0x08, 0x80, 0x90,
-    0x10, 0x8c, 0x40, 0xe4, 0x82, 0xa9, 0x86,
-};
-
-static const uint8_t unicode_prop_Emoji_Presentation_table[145] = {
-    0x60, 0x23, 0x19, 0x81, 0x40, 0xcc, 0x1a, 0x01,
-    0x80, 0x42, 0x08, 0x81, 0x94, 0x81, 0xb1, 0x8b,
-    0xaa, 0x80, 0x92, 0x80, 0x8c, 0x07, 0x81, 0x90,
-    0x0c, 0x0f, 0x04, 0x80, 0x94, 0x06, 0x08, 0x03,
-    0x01, 0x06, 0x03, 0x81, 0x9b, 0x80, 0xa2, 0x00,
-    0x03, 0x10, 0x80, 0xbc, 0x82, 0x97, 0x80, 0x8d,
-    0x80, 0x43, 0x5a, 0x81, 0xb2, 0x03, 0x80, 0x61,
-    0xc4, 0xad, 0x80, 0x40, 0xc9, 0x80, 0x40, 0xbd,
-    0x01, 0x89, 0xca, 0x99, 0x00, 0x97, 0x80, 0x93,
-    0x01, 0x20, 0x82, 0x94, 0x81, 0x40, 0xad, 0xa0,
-    0x8b, 0x88, 0x80, 0xc5, 0x80, 0x95, 0x8b, 0xaa,
-    0x1c, 0x8b, 0x90, 0x10, 0x82, 0xc6, 0x00, 0x80,
-    0x40, 0xba, 0x81, 0xbe, 0x8c, 0x18, 0x97, 0x91,
-    0x80, 0x99, 0x81, 0x8c, 0x80, 0xd5, 0xd4, 0xaf,
-    0xc5, 0x28, 0x12, 0x0a, 0x22, 0x8a, 0x0e, 0x88,
-    0x40, 0xe2, 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80,
-    0x89, 0x80, 0x40, 0xb8, 0xef, 0x22, 0x22, 0x86,
-    0x88, 0x9c, 0x82, 0x8a, 0x25, 0x89, 0x89, 0x2f,
-    0x3e,
-};
-
-static const uint8_t unicode_prop_Extended_Pictographic_table[156] = {
-    0x40, 0xa8, 0x03, 0x80, 0x5f, 0x8c, 0x80, 0x8b,
-    0x80, 0x40, 0xd7, 0x80, 0x95, 0x80, 0xd9, 0x85,
-    0x8e, 0x81, 0x41, 0x6e, 0x81, 0x8b, 0x80, 0xde,
-    0x80, 0xc5, 0x80, 0x98, 0x8a, 0x1a, 0x40, 0xc6,
-    0x80, 0x40, 0xe6, 0x81, 0x89, 0x80, 0x88, 0x80,
-    0xb9, 0x18, 0x28, 0x8b, 0x80, 0xf1, 0x89, 0xf5,
-    0x81, 0x8a, 0x00, 0x00, 0x28, 0x10, 0x28, 0x89,
-    0x81, 0x8e, 0x01, 0x03, 0x00, 0x03, 0x10, 0x80,
-    0x8a, 0x84, 0xac, 0x82, 0x88, 0x80, 0x8d, 0x80,
-    0x8d, 0x80, 0x41, 0x73, 0x81, 0x41, 0xce, 0x82,
-    0x92, 0x81, 0xb2, 0x03, 0x80, 0x44, 0xd9, 0x80,
-    0x8b, 0x80, 0x42, 0x58, 0x00, 0x80, 0x61, 0xbd,
-    0x65, 0x40, 0xff, 0x8c, 0x82, 0x9e, 0x80, 0xbb,
-    0x85, 0x8b, 0x81, 0x8d, 0x01, 0x89, 0x91, 0xb8,
-    0x9a, 0x8e, 0x89, 0x80, 0x93, 0x01, 0x88, 0x03,
-    0x88, 0x41, 0xb1, 0x84, 0x41, 0x3d, 0x87, 0x41,
-    0x09, 0xaf, 0xff, 0xf3, 0x8b, 0xd4, 0xaa, 0x8b,
-    0x83, 0xb7, 0x87, 0x89, 0x85, 0xa7, 0x87, 0x9d,
-    0xd1, 0x8b, 0xae, 0x80, 0x89, 0x80, 0x41, 0xb8,
-    0x40, 0xff, 0x43, 0xfd,
-};
-
-static const uint8_t unicode_prop_Default_Ignorable_Code_Point_table[51] = {
-    0x40, 0xac, 0x80, 0x42, 0xa0, 0x80, 0x42, 0xcb,
-    0x80, 0x4b, 0x41, 0x81, 0x46, 0x52, 0x81, 0xd4,
-    0x84, 0x47, 0xfa, 0x84, 0x99, 0x84, 0xb0, 0x8f,
-    0x50, 0xf3, 0x80, 0x60, 0xcc, 0x9a, 0x8f, 0x40,
-    0xee, 0x80, 0x40, 0x9f, 0x80, 0xce, 0x88, 0x60,
-    0xbc, 0xa6, 0x83, 0x54, 0xce, 0x87, 0x6c, 0x2e,
-    0x84, 0x4f, 0xff,
-};
-
-typedef enum {
-    UNICODE_PROP_Hyphen,
-    UNICODE_PROP_Other_Math,
-    UNICODE_PROP_Other_Alphabetic,
-    UNICODE_PROP_Other_Lowercase,
-    UNICODE_PROP_Other_Uppercase,
-    UNICODE_PROP_Other_Grapheme_Extend,
-    UNICODE_PROP_Other_Default_Ignorable_Code_Point,
-    UNICODE_PROP_Other_ID_Start,
-    UNICODE_PROP_Other_ID_Continue,
-    UNICODE_PROP_Prepended_Concatenation_Mark,
-    UNICODE_PROP_ID_Continue1,
-    UNICODE_PROP_XID_Start1,
-    UNICODE_PROP_XID_Continue1,
-    UNICODE_PROP_Changes_When_Titlecased1,
-    UNICODE_PROP_Changes_When_Casefolded1,
-    UNICODE_PROP_Changes_When_NFKC_Casefolded1,
-    UNICODE_PROP_ASCII_Hex_Digit,
-    UNICODE_PROP_Bidi_Control,
-    UNICODE_PROP_Dash,
-    UNICODE_PROP_Deprecated,
-    UNICODE_PROP_Diacritic,
-    UNICODE_PROP_Extender,
-    UNICODE_PROP_Hex_Digit,
-    UNICODE_PROP_IDS_Binary_Operator,
-    UNICODE_PROP_IDS_Trinary_Operator,
-    UNICODE_PROP_Ideographic,
-    UNICODE_PROP_Join_Control,
-    UNICODE_PROP_Logical_Order_Exception,
-    UNICODE_PROP_Noncharacter_Code_Point,
-    UNICODE_PROP_Pattern_Syntax,
-    UNICODE_PROP_Pattern_White_Space,
-    UNICODE_PROP_Quotation_Mark,
-    UNICODE_PROP_Radical,
-    UNICODE_PROP_Regional_Indicator,
-    UNICODE_PROP_Sentence_Terminal,
-    UNICODE_PROP_Soft_Dotted,
-    UNICODE_PROP_Terminal_Punctuation,
-    UNICODE_PROP_Unified_Ideograph,
-    UNICODE_PROP_Variation_Selector,
-    UNICODE_PROP_White_Space,
-    UNICODE_PROP_Bidi_Mirrored,
-    UNICODE_PROP_Emoji,
-    UNICODE_PROP_Emoji_Component,
-    UNICODE_PROP_Emoji_Modifier,
-    UNICODE_PROP_Emoji_Modifier_Base,
-    UNICODE_PROP_Emoji_Presentation,
-    UNICODE_PROP_Extended_Pictographic,
-    UNICODE_PROP_Default_Ignorable_Code_Point,
-    UNICODE_PROP_ID_Start,
-    UNICODE_PROP_Case_Ignorable,
-    UNICODE_PROP_ASCII,
-    UNICODE_PROP_Alphabetic,
-    UNICODE_PROP_Any,
-    UNICODE_PROP_Assigned,
-    UNICODE_PROP_Cased,
-    UNICODE_PROP_Changes_When_Casefolded,
-    UNICODE_PROP_Changes_When_Casemapped,
-    UNICODE_PROP_Changes_When_Lowercased,
-    UNICODE_PROP_Changes_When_NFKC_Casefolded,
-    UNICODE_PROP_Changes_When_Titlecased,
-    UNICODE_PROP_Changes_When_Uppercased,
-    UNICODE_PROP_Grapheme_Base,
-    UNICODE_PROP_Grapheme_Extend,
-    UNICODE_PROP_ID_Continue,
-    UNICODE_PROP_Lowercase,
-    UNICODE_PROP_Math,
-    UNICODE_PROP_Uppercase,
-    UNICODE_PROP_XID_Continue,
-    UNICODE_PROP_XID_Start,
-    UNICODE_PROP_Cased1,
-    UNICODE_PROP_COUNT,
-} UnicodePropertyEnum;
-
-static const char unicode_prop_name_table[] =
-    "ASCII_Hex_Digit,AHex"               "\0"
-    "Bidi_Control,Bidi_C"                "\0"
-    "Dash"                               "\0"
-    "Deprecated,Dep"                     "\0"
-    "Diacritic,Dia"                      "\0"
-    "Extender,Ext"                       "\0"
-    "Hex_Digit,Hex"                      "\0"
-    "IDS_Binary_Operator,IDSB"           "\0"
-    "IDS_Trinary_Operator,IDST"          "\0"
-    "Ideographic,Ideo"                   "\0"
-    "Join_Control,Join_C"                "\0"
-    "Logical_Order_Exception,LOE"        "\0"
-    "Noncharacter_Code_Point,NChar"      "\0"
-    "Pattern_Syntax,Pat_Syn"             "\0"
-    "Pattern_White_Space,Pat_WS"         "\0"
-    "Quotation_Mark,QMark"               "\0"
-    "Radical"                            "\0"
-    "Regional_Indicator,RI"              "\0"
-    "Sentence_Terminal,STerm"            "\0"
-    "Soft_Dotted,SD"                     "\0"
-    "Terminal_Punctuation,Term"          "\0"
-    "Unified_Ideograph,UIdeo"            "\0"
-    "Variation_Selector,VS"              "\0"
-    "White_Space,space"                  "\0"
-    "Bidi_Mirrored,Bidi_M"               "\0"
-    "Emoji"                              "\0"
-    "Emoji_Component,EComp"              "\0"
-    "Emoji_Modifier,EMod"                "\0"
-    "Emoji_Modifier_Base,EBase"          "\0"
-    "Emoji_Presentation,EPres"           "\0"
-    "Extended_Pictographic,ExtPict"      "\0"
-    "Default_Ignorable_Code_Point,DI"    "\0"
-    "ID_Start,IDS"                       "\0"
-    "Case_Ignorable,CI"                  "\0"
-    "ASCII"                              "\0"
-    "Alphabetic,Alpha"                   "\0"
-    "Any"                                "\0"
-    "Assigned"                           "\0"
-    "Cased"                              "\0"
-    "Changes_When_Casefolded,CWCF"       "\0"
-    "Changes_When_Casemapped,CWCM"       "\0"
-    "Changes_When_Lowercased,CWL"        "\0"
-    "Changes_When_NFKC_Casefolded,CWKCF" "\0"
-    "Changes_When_Titlecased,CWT"        "\0"
-    "Changes_When_Uppercased,CWU"        "\0"
-    "Grapheme_Base,Gr_Base"              "\0"
-    "Grapheme_Extend,Gr_Ext"             "\0"
-    "ID_Continue,IDC"                    "\0"
-    "Lowercase,Lower"                    "\0"
-    "Math"                               "\0"
-    "Uppercase,Upper"                    "\0"
-    "XID_Continue,XIDC"                  "\0"
-    "XID_Start,XIDS"                     "\0"
-;
-
-static const uint8_t * const unicode_prop_table[] = {
-    unicode_prop_Hyphen_table,
-    unicode_prop_Other_Math_table,
-    unicode_prop_Other_Alphabetic_table,
-    unicode_prop_Other_Lowercase_table,
-    unicode_prop_Other_Uppercase_table,
-    unicode_prop_Other_Grapheme_Extend_table,
-    unicode_prop_Other_Default_Ignorable_Code_Point_table,
-    unicode_prop_Other_ID_Start_table,
-    unicode_prop_Other_ID_Continue_table,
-    unicode_prop_Prepended_Concatenation_Mark_table,
-    unicode_prop_ID_Continue1_table,
-    unicode_prop_XID_Start1_table,
-    unicode_prop_XID_Continue1_table,
-    unicode_prop_Changes_When_Titlecased1_table,
-    unicode_prop_Changes_When_Casefolded1_table,
-    unicode_prop_Changes_When_NFKC_Casefolded1_table,
-    unicode_prop_ASCII_Hex_Digit_table,
-    unicode_prop_Bidi_Control_table,
-    unicode_prop_Dash_table,
-    unicode_prop_Deprecated_table,
-    unicode_prop_Diacritic_table,
-    unicode_prop_Extender_table,
-    unicode_prop_Hex_Digit_table,
-    unicode_prop_IDS_Binary_Operator_table,
-    unicode_prop_IDS_Trinary_Operator_table,
-    unicode_prop_Ideographic_table,
-    unicode_prop_Join_Control_table,
-    unicode_prop_Logical_Order_Exception_table,
-    unicode_prop_Noncharacter_Code_Point_table,
-    unicode_prop_Pattern_Syntax_table,
-    unicode_prop_Pattern_White_Space_table,
-    unicode_prop_Quotation_Mark_table,
-    unicode_prop_Radical_table,
-    unicode_prop_Regional_Indicator_table,
-    unicode_prop_Sentence_Terminal_table,
-    unicode_prop_Soft_Dotted_table,
-    unicode_prop_Terminal_Punctuation_table,
-    unicode_prop_Unified_Ideograph_table,
-    unicode_prop_Variation_Selector_table,
-    unicode_prop_White_Space_table,
-    unicode_prop_Bidi_Mirrored_table,
-    unicode_prop_Emoji_table,
-    unicode_prop_Emoji_Component_table,
-    unicode_prop_Emoji_Modifier_table,
-    unicode_prop_Emoji_Modifier_Base_table,
-    unicode_prop_Emoji_Presentation_table,
-    unicode_prop_Extended_Pictographic_table,
-    unicode_prop_Default_Ignorable_Code_Point_table,
-    unicode_prop_ID_Start_table,
-    unicode_prop_Case_Ignorable_table,
-};
-
-static const uint16_t unicode_prop_len_table[] = {
-    countof(unicode_prop_Hyphen_table),
-    countof(unicode_prop_Other_Math_table),
-    countof(unicode_prop_Other_Alphabetic_table),
-    countof(unicode_prop_Other_Lowercase_table),
-    countof(unicode_prop_Other_Uppercase_table),
-    countof(unicode_prop_Other_Grapheme_Extend_table),
-    countof(unicode_prop_Other_Default_Ignorable_Code_Point_table),
-    countof(unicode_prop_Other_ID_Start_table),
-    countof(unicode_prop_Other_ID_Continue_table),
-    countof(unicode_prop_Prepended_Concatenation_Mark_table),
-    countof(unicode_prop_ID_Continue1_table),
-    countof(unicode_prop_XID_Start1_table),
-    countof(unicode_prop_XID_Continue1_table),
-    countof(unicode_prop_Changes_When_Titlecased1_table),
-    countof(unicode_prop_Changes_When_Casefolded1_table),
-    countof(unicode_prop_Changes_When_NFKC_Casefolded1_table),
-    countof(unicode_prop_ASCII_Hex_Digit_table),
-    countof(unicode_prop_Bidi_Control_table),
-    countof(unicode_prop_Dash_table),
-    countof(unicode_prop_Deprecated_table),
-    countof(unicode_prop_Diacritic_table),
-    countof(unicode_prop_Extender_table),
-    countof(unicode_prop_Hex_Digit_table),
-    countof(unicode_prop_IDS_Binary_Operator_table),
-    countof(unicode_prop_IDS_Trinary_Operator_table),
-    countof(unicode_prop_Ideographic_table),
-    countof(unicode_prop_Join_Control_table),
-    countof(unicode_prop_Logical_Order_Exception_table),
-    countof(unicode_prop_Noncharacter_Code_Point_table),
-    countof(unicode_prop_Pattern_Syntax_table),
-    countof(unicode_prop_Pattern_White_Space_table),
-    countof(unicode_prop_Quotation_Mark_table),
-    countof(unicode_prop_Radical_table),
-    countof(unicode_prop_Regional_Indicator_table),
-    countof(unicode_prop_Sentence_Terminal_table),
-    countof(unicode_prop_Soft_Dotted_table),
-    countof(unicode_prop_Terminal_Punctuation_table),
-    countof(unicode_prop_Unified_Ideograph_table),
-    countof(unicode_prop_Variation_Selector_table),
-    countof(unicode_prop_White_Space_table),
-    countof(unicode_prop_Bidi_Mirrored_table),
-    countof(unicode_prop_Emoji_table),
-    countof(unicode_prop_Emoji_Component_table),
-    countof(unicode_prop_Emoji_Modifier_table),
-    countof(unicode_prop_Emoji_Modifier_Base_table),
-    countof(unicode_prop_Emoji_Presentation_table),
-    countof(unicode_prop_Extended_Pictographic_table),
-    countof(unicode_prop_Default_Ignorable_Code_Point_table),
-    countof(unicode_prop_ID_Start_table),
-    countof(unicode_prop_Case_Ignorable_table),
-};
-
-#endif /* CONFIG_ALL_UNICODE */
diff --git a/quickjs.c b/quickjs.c
deleted file mode 100644
index 791601391..000000000
--- a/quickjs.c
+++ /dev/null
@@ -1,54061 +0,0 @@
-/*
- * QuickJS Javascript Engine
- * 
- * Copyright (c) 2017-2021 Fabrice Bellard
- * Copyright (c) 2017-2021 Charlie Gordon
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <inttypes.h>
-#include <string.h>
-#include <assert.h>
-#include <sys/time.h>
-#include <time.h>
-#include <fenv.h>
-#include <math.h>
-#if defined(__APPLE__)
-#include <malloc/malloc.h>
-#elif defined(__linux__)
-#include <malloc.h>
-#elif defined(__FreeBSD__)
-#include <malloc_np.h>
-#endif
-
-#include "cutils.h"
-#include "list.h"
-#include "quickjs.h"
-#include "libregexp.h"
-#ifdef CONFIG_BIGNUM
-#include "libbf.h"
-#endif
-
-#define OPTIMIZE         1
-#define SHORT_OPCODES    1
-#if defined(EMSCRIPTEN)
-#define DIRECT_DISPATCH  0
-#else
-#define DIRECT_DISPATCH  1
-#endif
-
-#if defined(__APPLE__)
-#define MALLOC_OVERHEAD  0
-#else
-#define MALLOC_OVERHEAD  8
-#endif
-
-#if !defined(_WIN32)
-/* define it if printf uses the RNDN rounding mode instead of RNDNA */
-#define CONFIG_PRINTF_RNDN
-#endif
-
-/* define to include Atomics.* operations which depend on the OS
-   threads */
-#if !defined(EMSCRIPTEN)
-#define CONFIG_ATOMICS
-#endif
-
-#if !defined(EMSCRIPTEN)
-/* enable stack limitation */
-#define CONFIG_STACK_CHECK
-#endif
-
-
-/* dump object free */
-//#define DUMP_FREE
-//#define DUMP_CLOSURE
-/* dump the bytecode of the compiled functions: combination of bits
-   1: dump pass 3 final byte code
-   2: dump pass 2 code
-   4: dump pass 1 code
-   8: dump stdlib functions
-  16: dump bytecode in hex
-  32: dump line number table
- */
-//#define DUMP_BYTECODE  (1)
-/* dump the occurence of the automatic GC */
-//#define DUMP_GC
-/* dump objects freed by the garbage collector */
-//#define DUMP_GC_FREE
-/* dump objects leaking when freeing the runtime */
-//#define DUMP_LEAKS  1
-/* dump memory usage before running the garbage collector */
-//#define DUMP_MEM
-//#define DUMP_OBJECTS    /* dump objects in JS_FreeContext */
-//#define DUMP_ATOMS      /* dump atoms in JS_FreeContext */
-//#define DUMP_SHAPES     /* dump shapes in JS_FreeContext */
-//#define DUMP_MODULE_RESOLVE
-//#define DUMP_PROMISE
-//#define DUMP_READ_OBJECT
-
-/* test the GC by forcing it before each object allocation */
-//#define FORCE_GC_AT_MALLOC
-
-#ifdef CONFIG_ATOMICS
-#include <pthread.h>
-#include <stdatomic.h>
-#include <errno.h>
-#endif
-
-enum {
-    /* classid tag        */    /* union usage   | properties */
-    JS_CLASS_OBJECT = 1,        /* must be first */
-    JS_CLASS_ARRAY,             /* u.array       | length */
-    JS_CLASS_ERROR,
-    JS_CLASS_NUMBER,            /* u.object_data */
-    JS_CLASS_STRING,            /* u.object_data */
-    JS_CLASS_BOOLEAN,           /* u.object_data */
-    JS_CLASS_SYMBOL,            /* u.object_data */
-    JS_CLASS_ARGUMENTS,         /* u.array       | length */
-    JS_CLASS_MAPPED_ARGUMENTS,  /*               | length */
-    JS_CLASS_DATE,              /* u.object_data */
-    JS_CLASS_MODULE_NS,
-    JS_CLASS_C_FUNCTION,        /* u.cfunc */
-    JS_CLASS_BYTECODE_FUNCTION, /* u.func */
-    JS_CLASS_BOUND_FUNCTION,    /* u.bound_function */
-    JS_CLASS_C_FUNCTION_DATA,   /* u.c_function_data_record */
-    JS_CLASS_GENERATOR_FUNCTION, /* u.func */
-    JS_CLASS_FOR_IN_ITERATOR,   /* u.for_in_iterator */
-    JS_CLASS_REGEXP,            /* u.regexp */
-    JS_CLASS_ARRAY_BUFFER,      /* u.array_buffer */
-    JS_CLASS_SHARED_ARRAY_BUFFER, /* u.array_buffer */
-    JS_CLASS_UINT8C_ARRAY,      /* u.array (typed_array) */
-    JS_CLASS_INT8_ARRAY,        /* u.array (typed_array) */
-    JS_CLASS_UINT8_ARRAY,       /* u.array (typed_array) */
-    JS_CLASS_INT16_ARRAY,       /* u.array (typed_array) */
-    JS_CLASS_UINT16_ARRAY,      /* u.array (typed_array) */
-    JS_CLASS_INT32_ARRAY,       /* u.array (typed_array) */
-    JS_CLASS_UINT32_ARRAY,      /* u.array (typed_array) */
-#ifdef CONFIG_BIGNUM
-    JS_CLASS_BIG_INT64_ARRAY,   /* u.array (typed_array) */
-    JS_CLASS_BIG_UINT64_ARRAY,  /* u.array (typed_array) */
-#endif
-    JS_CLASS_FLOAT32_ARRAY,     /* u.array (typed_array) */
-    JS_CLASS_FLOAT64_ARRAY,     /* u.array (typed_array) */
-    JS_CLASS_DATAVIEW,          /* u.typed_array */
-#ifdef CONFIG_BIGNUM
-    JS_CLASS_BIG_INT,           /* u.object_data */
-    JS_CLASS_BIG_FLOAT,         /* u.object_data */
-    JS_CLASS_FLOAT_ENV,         /* u.float_env */
-    JS_CLASS_BIG_DECIMAL,       /* u.object_data */
-    JS_CLASS_OPERATOR_SET,      /* u.operator_set */
-#endif
-    JS_CLASS_MAP,               /* u.map_state */
-    JS_CLASS_SET,               /* u.map_state */
-    JS_CLASS_WEAKMAP,           /* u.map_state */
-    JS_CLASS_WEAKSET,           /* u.map_state */
-    JS_CLASS_MAP_ITERATOR,      /* u.map_iterator_data */
-    JS_CLASS_SET_ITERATOR,      /* u.map_iterator_data */
-    JS_CLASS_ARRAY_ITERATOR,    /* u.array_iterator_data */
-    JS_CLASS_STRING_ITERATOR,   /* u.array_iterator_data */
-    JS_CLASS_REGEXP_STRING_ITERATOR,   /* u.regexp_string_iterator_data */
-    JS_CLASS_GENERATOR,         /* u.generator_data */
-    JS_CLASS_PROXY,             /* u.proxy_data */
-    JS_CLASS_PROMISE,           /* u.promise_data */
-    JS_CLASS_PROMISE_RESOLVE_FUNCTION,  /* u.promise_function_data */
-    JS_CLASS_PROMISE_REJECT_FUNCTION,   /* u.promise_function_data */
-    JS_CLASS_ASYNC_FUNCTION,            /* u.func */
-    JS_CLASS_ASYNC_FUNCTION_RESOLVE,    /* u.async_function_data */
-    JS_CLASS_ASYNC_FUNCTION_REJECT,     /* u.async_function_data */
-    JS_CLASS_ASYNC_FROM_SYNC_ITERATOR,  /* u.async_from_sync_iterator_data */
-    JS_CLASS_ASYNC_GENERATOR_FUNCTION,  /* u.func */
-    JS_CLASS_ASYNC_GENERATOR,   /* u.async_generator_data */
-
-    JS_CLASS_INIT_COUNT, /* last entry for predefined classes */
-};
-
-/* number of typed array types */
-#define JS_TYPED_ARRAY_COUNT  (JS_CLASS_FLOAT64_ARRAY - JS_CLASS_UINT8C_ARRAY + 1)
-static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT];
-#define typed_array_size_log2(classid)  (typed_array_size_log2[(classid)- JS_CLASS_UINT8C_ARRAY])
-
-typedef enum JSErrorEnum {
-    JS_EVAL_ERROR,
-    JS_RANGE_ERROR,
-    JS_REFERENCE_ERROR,
-    JS_SYNTAX_ERROR,
-    JS_TYPE_ERROR,
-    JS_URI_ERROR,
-    JS_INTERNAL_ERROR,
-    JS_AGGREGATE_ERROR,
-    
-    JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */
-} JSErrorEnum;
-
-#define JS_MAX_LOCAL_VARS 65536
-#define JS_STACK_SIZE_MAX 65534
-#define JS_STRING_LEN_MAX ((1 << 30) - 1)
-
-#define __exception __attribute__((warn_unused_result))
-
-typedef struct JSShape JSShape;
-typedef struct JSString JSString;
-typedef struct JSString JSAtomStruct;
-
-typedef enum {
-    JS_GC_PHASE_NONE,
-    JS_GC_PHASE_DECREF,
-    JS_GC_PHASE_REMOVE_CYCLES,
-} JSGCPhaseEnum;
-
-typedef enum OPCodeEnum OPCodeEnum;
-
-#ifdef CONFIG_BIGNUM
-/* function pointers are used for numeric operations so that it is
-   possible to remove some numeric types */
-typedef struct {
-    JSValue (*to_string)(JSContext *ctx, JSValueConst val);
-    JSValue (*from_string)(JSContext *ctx, const char *buf,
-                           int radix, int flags, slimb_t *pexponent);
-    int (*unary_arith)(JSContext *ctx,
-                       JSValue *pres, OPCodeEnum op, JSValue op1);
-    int (*binary_arith)(JSContext *ctx, OPCodeEnum op,
-                        JSValue *pres, JSValue op1, JSValue op2);
-    int (*compare)(JSContext *ctx, OPCodeEnum op,
-                   JSValue op1, JSValue op2);
-    /* only for bigfloat: */
-    JSValue (*mul_pow10_to_float64)(JSContext *ctx, const bf_t *a,
-                                    int64_t exponent);
-    int (*mul_pow10)(JSContext *ctx, JSValue *sp);
-} JSNumericOperations;
-#endif
-
-struct JSRuntime {
-    JSMallocFunctions mf;
-    JSMallocState malloc_state;
-    const char *rt_info;
-
-    int atom_hash_size; /* power of two */
-    int atom_count;
-    int atom_size;
-    int atom_count_resize; /* resize hash table at this count */
-    uint32_t *atom_hash;
-    JSAtomStruct **atom_array;
-    int atom_free_index; /* 0 = none */
-
-    int class_count;    /* size of class_array */
-    JSClass *class_array;
-
-    struct list_head context_list; /* list of JSContext.link */
-    /* list of JSGCObjectHeader.link. List of allocated GC objects (used
-       by the garbage collector) */
-    struct list_head gc_obj_list;
-    /* list of JSGCObjectHeader.link. Used during JS_FreeValueRT() */
-    struct list_head gc_zero_ref_count_list; 
-    struct list_head tmp_obj_list; /* used during GC */
-    JSGCPhaseEnum gc_phase : 8;
-    size_t malloc_gc_threshold;
-#ifdef DUMP_LEAKS
-    struct list_head string_list; /* list of JSString.link */
-#endif
-    /* stack limitation */
-    uintptr_t stack_size; /* in bytes, 0 if no limit */
-    uintptr_t stack_top;
-    uintptr_t stack_limit; /* lower stack limit */
-    
-    JSValue current_exception;
-    /* true if inside an out of memory error, to avoid recursing */
-    BOOL in_out_of_memory : 8;
-
-    struct JSStackFrame *current_stack_frame;
-
-    JSInterruptHandler *interrupt_handler;
-    void *interrupt_opaque;
-
-    JSHostPromiseRejectionTracker *host_promise_rejection_tracker;
-    void *host_promise_rejection_tracker_opaque;
-    
-    struct list_head job_list; /* list of JSJobEntry.link */
-
-    JSModuleNormalizeFunc *module_normalize_func;
-    JSModuleLoaderFunc *module_loader_func;
-    void *module_loader_opaque;
-
-    BOOL can_block : 8; /* TRUE if Atomics.wait can block */
-    /* used to allocate, free and clone SharedArrayBuffers */
-    JSSharedArrayBufferFunctions sab_funcs;
-    
-    /* Shape hash table */
-    int shape_hash_bits;
-    int shape_hash_size;
-    int shape_hash_count; /* number of hashed shapes */
-    JSShape **shape_hash;
-#ifdef CONFIG_BIGNUM
-    bf_context_t bf_ctx;
-    JSNumericOperations bigint_ops;
-    JSNumericOperations bigfloat_ops;
-    JSNumericOperations bigdecimal_ops;
-    uint32_t operator_count;
-#endif
-    void *user_opaque;
-};
-
-struct JSClass {
-    uint32_t class_id; /* 0 means free entry */
-    JSAtom class_name;
-    JSClassFinalizer *finalizer;
-    JSClassGCMark *gc_mark;
-    JSClassCall *call;
-    /* pointers for exotic behavior, can be NULL if none are present */
-    const JSClassExoticMethods *exotic;
-};
-
-#define JS_MODE_STRICT (1 << 0)
-#define JS_MODE_STRIP  (1 << 1)
-#define JS_MODE_MATH   (1 << 2)
-
-typedef struct JSStackFrame {
-    struct JSStackFrame *prev_frame; /* NULL if first stack frame */
-    JSValue cur_func; /* current function, JS_UNDEFINED if the frame is detached */
-    JSValue *arg_buf; /* arguments */
-    JSValue *var_buf; /* variables */
-    struct list_head var_ref_list; /* list of JSVarRef.link */
-    const uint8_t *cur_pc; /* only used in bytecode functions : PC of the
-                        instruction after the call */
-    int arg_count;
-    int js_mode; /* 0 or JS_MODE_MATH for C functions */
-    /* only used in generators. Current stack pointer value. NULL if
-       the function is running. */ 
-    JSValue *cur_sp;
-} JSStackFrame;
-
-typedef enum {
-    JS_GC_OBJ_TYPE_JS_OBJECT,
-    JS_GC_OBJ_TYPE_FUNCTION_BYTECODE,
-    JS_GC_OBJ_TYPE_SHAPE,
-    JS_GC_OBJ_TYPE_VAR_REF,
-    JS_GC_OBJ_TYPE_ASYNC_FUNCTION,
-    JS_GC_OBJ_TYPE_JS_CONTEXT,
-} JSGCObjectTypeEnum;
-
-/* header for GC objects. GC objects are C data structures with a
-   reference count that can reference other GC objects. JS Objects are
-   a particular type of GC object. */
-struct JSGCObjectHeader {
-    int ref_count; /* must come first, 32-bit */
-    JSGCObjectTypeEnum gc_obj_type : 4;
-    uint8_t mark : 4; /* used by the GC */
-    uint8_t dummy1; /* not used by the GC */
-    uint16_t dummy2; /* not used by the GC */
-    struct list_head link;
-};
-
-typedef struct JSVarRef {
-    union {
-        JSGCObjectHeader header; /* must come first */
-        struct {
-            int __gc_ref_count; /* corresponds to header.ref_count */
-            uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
-
-            /* 0 : the JSVarRef is on the stack. header.link is an element
-               of JSStackFrame.var_ref_list.
-               1 : the JSVarRef is detached. header.link has the normal meanning 
-            */
-            uint8_t is_detached : 1; 
-            uint8_t is_arg : 1;
-            uint16_t var_idx; /* index of the corresponding function variable on
-                                 the stack */
-        };
-    };
-    JSValue *pvalue; /* pointer to the value, either on the stack or
-                        to 'value' */
-    JSValue value; /* used when the variable is no longer on the stack */
-} JSVarRef;
-
-#ifdef CONFIG_BIGNUM
-typedef struct JSFloatEnv {
-    limb_t prec;
-    bf_flags_t flags;
-    unsigned int status;
-} JSFloatEnv;
-
-/* the same structure is used for big integers and big floats. Big
-   integers are never infinite or NaNs */
-typedef struct JSBigFloat {
-    JSRefCountHeader header; /* must come first, 32-bit */
-    bf_t num;
-} JSBigFloat;
-
-typedef struct JSBigDecimal {
-    JSRefCountHeader header; /* must come first, 32-bit */
-    bfdec_t num;
-} JSBigDecimal;
-#endif
-
-typedef enum {
-    JS_AUTOINIT_ID_PROTOTYPE,
-    JS_AUTOINIT_ID_MODULE_NS,
-    JS_AUTOINIT_ID_PROP,
-} JSAutoInitIDEnum;
-
-/* must be large enough to have a negligible runtime cost and small
-   enough to call the interrupt callback often. */
-#define JS_INTERRUPT_COUNTER_INIT 10000
-
-struct JSContext {
-    JSGCObjectHeader header; /* must come first */
-    JSRuntime *rt;
-    struct list_head link;
-
-    uint16_t binary_object_count;
-    int binary_object_size;
-
-    JSShape *array_shape;   /* initial shape for Array objects */
-
-    JSValue *class_proto;
-    JSValue function_proto;
-    JSValue function_ctor;
-    JSValue array_ctor;
-    JSValue regexp_ctor;
-    JSValue promise_ctor;
-    JSValue native_error_proto[JS_NATIVE_ERROR_COUNT];
-    JSValue iterator_proto;
-    JSValue async_iterator_proto;
-    JSValue array_proto_values;
-    JSValue throw_type_error;
-    JSValue eval_obj;
-
-    JSValue global_obj; /* global object */
-    JSValue global_var_obj; /* contains the global let/const definitions */
-
-    uint64_t random_state;
-#ifdef CONFIG_BIGNUM
-    bf_context_t *bf_ctx;   /* points to rt->bf_ctx, shared by all contexts */
-    JSFloatEnv fp_env; /* global FP environment */
-    BOOL bignum_ext : 8; /* enable math mode */
-    BOOL allow_operator_overloading : 8;
-#endif
-    /* when the counter reaches zero, JSRutime.interrupt_handler is called */
-    int interrupt_counter;
-    BOOL is_error_property_enabled;
-
-    struct list_head loaded_modules; /* list of JSModuleDef.link */
-
-    /* if NULL, RegExp compilation is not supported */
-    JSValue (*compile_regexp)(JSContext *ctx, JSValueConst pattern,
-                              JSValueConst flags);
-    /* if NULL, eval is not supported */
-    JSValue (*eval_internal)(JSContext *ctx, JSValueConst this_obj,
-                             const char *input, size_t input_len,
-                             const char *filename, int flags, int scope_idx);
-    void *user_opaque;
-};
-
-typedef union JSFloat64Union {
-    double d;
-    uint64_t u64;
-    uint32_t u32[2];
-} JSFloat64Union;
-
-enum {
-    JS_ATOM_TYPE_STRING = 1,
-    JS_ATOM_TYPE_GLOBAL_SYMBOL,
-    JS_ATOM_TYPE_SYMBOL,
-    JS_ATOM_TYPE_PRIVATE,
-};
-
-enum {
-    JS_ATOM_HASH_SYMBOL,
-    JS_ATOM_HASH_PRIVATE,
-};
-
-typedef enum {
-    JS_ATOM_KIND_STRING,
-    JS_ATOM_KIND_SYMBOL,
-    JS_ATOM_KIND_PRIVATE,
-} JSAtomKindEnum;
-
-#define JS_ATOM_HASH_MASK  ((1 << 30) - 1)
-
-struct JSString {
-    JSRefCountHeader header; /* must come first, 32-bit */
-    uint32_t len : 31;
-    uint8_t is_wide_char : 1; /* 0 = 8 bits, 1 = 16 bits characters */
-    /* for JS_ATOM_TYPE_SYMBOL: hash = 0, atom_type = 3,
-       for JS_ATOM_TYPE_PRIVATE: hash = 1, atom_type = 3
-       XXX: could change encoding to have one more bit in hash */
-    uint32_t hash : 30;
-    uint8_t atom_type : 2; /* != 0 if atom, JS_ATOM_TYPE_x */
-    uint32_t hash_next; /* atom_index for JS_ATOM_TYPE_SYMBOL */
-#ifdef DUMP_LEAKS
-    struct list_head link; /* string list */
-#endif
-    union {
-        uint8_t str8[0]; /* 8 bit strings will get an extra null terminator */
-        uint16_t str16[0];
-    } u;
-};
-
-typedef struct JSClosureVar {
-    uint8_t is_local : 1;
-    uint8_t is_arg : 1;
-    uint8_t is_const : 1;
-    uint8_t is_lexical : 1;
-    uint8_t var_kind : 4; /* see JSVarKindEnum */
-    /* 8 bits available */
-    uint16_t var_idx; /* is_local = TRUE: index to a normal variable of the
-                    parent function. otherwise: index to a closure
-                    variable of the parent function */
-    JSAtom var_name;
-} JSClosureVar;
-
-#define ARG_SCOPE_INDEX 1
-#define ARG_SCOPE_END (-2)
-
-typedef struct JSVarScope {
-    int parent;  /* index into fd->scopes of the enclosing scope */
-    int first;   /* index into fd->vars of the last variable in this scope */
-} JSVarScope;
-
-typedef enum {
-    /* XXX: add more variable kinds here instead of using bit fields */
-    JS_VAR_NORMAL,
-    JS_VAR_FUNCTION_DECL, /* lexical var with function declaration */
-    JS_VAR_NEW_FUNCTION_DECL, /* lexical var with async/generator
-                                 function declaration */
-    JS_VAR_CATCH,
-    JS_VAR_FUNCTION_NAME, /* function expression name */
-    JS_VAR_PRIVATE_FIELD,
-    JS_VAR_PRIVATE_METHOD,
-    JS_VAR_PRIVATE_GETTER,
-    JS_VAR_PRIVATE_SETTER, /* must come after JS_VAR_PRIVATE_GETTER */
-    JS_VAR_PRIVATE_GETTER_SETTER, /* must come after JS_VAR_PRIVATE_SETTER */
-} JSVarKindEnum;
-
-/* XXX: could use a different structure in bytecode functions to save
-   memory */
-typedef struct JSVarDef {
-    JSAtom var_name;
-    /* index into fd->scopes of this variable lexical scope */
-    int scope_level;
-    /* during compilation: 
-        - if scope_level = 0: scope in which the variable is defined
-        - if scope_level != 0: index into fd->vars of the next
-          variable in the same or enclosing lexical scope
-       in a bytecode function:
-       index into fd->vars of the next
-       variable in the same or enclosing lexical scope
-    */
-    int scope_next;    
-    uint8_t is_const : 1;
-    uint8_t is_lexical : 1;
-    uint8_t is_captured : 1;
-    uint8_t var_kind : 4; /* see JSVarKindEnum */
-    /* only used during compilation: function pool index for lexical
-       variables with var_kind =
-       JS_VAR_FUNCTION_DECL/JS_VAR_NEW_FUNCTION_DECL or scope level of
-       the definition of the 'var' variables (they have scope_level =
-       0) */
-    int func_pool_idx : 24; /* only used during compilation : index in
-                               the constant pool for hoisted function
-                               definition */
-} JSVarDef;
-
-/* for the encoding of the pc2line table */
-#define PC2LINE_BASE     (-1)
-#define PC2LINE_RANGE    5
-#define PC2LINE_OP_FIRST 1
-#define PC2LINE_DIFF_PC_MAX ((255 - PC2LINE_OP_FIRST) / PC2LINE_RANGE)
-
-typedef enum JSFunctionKindEnum {
-    JS_FUNC_NORMAL = 0,
-    JS_FUNC_GENERATOR = (1 << 0),
-    JS_FUNC_ASYNC = (1 << 1),
-    JS_FUNC_ASYNC_GENERATOR = (JS_FUNC_GENERATOR | JS_FUNC_ASYNC),
-} JSFunctionKindEnum;
-
-typedef struct JSFunctionBytecode {
-    JSGCObjectHeader header; /* must come first */
-    uint8_t js_mode;
-    uint8_t has_prototype : 1; /* true if a prototype field is necessary */
-    uint8_t has_simple_parameter_list : 1;
-    uint8_t is_derived_class_constructor : 1;
-    /* true if home_object needs to be initialized */
-    uint8_t need_home_object : 1;
-    uint8_t func_kind : 2;
-    uint8_t new_target_allowed : 1;
-    uint8_t super_call_allowed : 1;
-    uint8_t super_allowed : 1;
-    uint8_t arguments_allowed : 1;
-    uint8_t has_debug : 1;
-    uint8_t backtrace_barrier : 1; /* stop backtrace on this function */
-    uint8_t read_only_bytecode : 1;
-    /* XXX: 4 bits available */
-    uint8_t *byte_code_buf; /* (self pointer) */
-    int byte_code_len;
-    JSAtom func_name;
-    JSVarDef *vardefs; /* arguments + local variables (arg_count + var_count) (self pointer) */
-    JSClosureVar *closure_var; /* list of variables in the closure (self pointer) */
-    uint16_t arg_count;
-    uint16_t var_count;
-    uint16_t defined_arg_count; /* for length function property */
-    uint16_t stack_size; /* maximum stack size */
-    JSContext *realm; /* function realm */
-    JSValue *cpool; /* constant pool (self pointer) */
-    int cpool_count;
-    int closure_var_count;
-    struct {
-        /* debug info, move to separate structure to save memory? */
-        JSAtom filename;
-        int line_num;
-        int source_len;
-        int pc2line_len;
-        uint8_t *pc2line_buf;
-        char *source;
-    } debug;
-} JSFunctionBytecode;
-
-typedef struct JSBoundFunction {
-    JSValue func_obj;
-    JSValue this_val;
-    int argc;
-    JSValue argv[0];
-} JSBoundFunction;
-
-typedef enum JSIteratorKindEnum {
-    JS_ITERATOR_KIND_KEY,
-    JS_ITERATOR_KIND_VALUE,
-    JS_ITERATOR_KIND_KEY_AND_VALUE,
-} JSIteratorKindEnum;
-
-typedef struct JSForInIterator {
-    JSValue obj;
-    BOOL is_array;
-    uint32_t array_length;
-    uint32_t idx;
-} JSForInIterator;
-
-typedef struct JSRegExp {
-    JSString *pattern;
-    JSString *bytecode; /* also contains the flags */
-} JSRegExp;
-
-typedef struct JSProxyData {
-    JSValue target;
-    JSValue handler;
-    uint8_t is_func;
-    uint8_t is_revoked;
-} JSProxyData;
-
-typedef struct JSArrayBuffer {
-    int byte_length; /* 0 if detached */
-    uint8_t detached;
-    uint8_t shared; /* if shared, the array buffer cannot be detached */
-    uint8_t *data; /* NULL if detached */
-    struct list_head array_list;
-    void *opaque;
-    JSFreeArrayBufferDataFunc *free_func;
-} JSArrayBuffer;
-
-typedef struct JSTypedArray {
-    struct list_head link; /* link to arraybuffer */
-    JSObject *obj; /* back pointer to the TypedArray/DataView object */
-    JSObject *buffer; /* based array buffer */
-    uint32_t offset; /* offset in the array buffer */
-    uint32_t length; /* length in the array buffer */
-} JSTypedArray;
-
-typedef struct JSAsyncFunctionState {
-    JSValue this_val; /* 'this' generator argument */
-    int argc; /* number of function arguments */
-    BOOL throw_flag; /* used to throw an exception in JS_CallInternal() */
-    JSStackFrame frame;
-} JSAsyncFunctionState;
-
-/* XXX: could use an object instead to avoid the
-   JS_TAG_ASYNC_FUNCTION tag for the GC */
-typedef struct JSAsyncFunctionData {
-    JSGCObjectHeader header; /* must come first */
-    JSValue resolving_funcs[2];
-    BOOL is_active; /* true if the async function state is valid */
-    JSAsyncFunctionState func_state;
-} JSAsyncFunctionData;
-
-typedef enum {
-   /* binary operators */
-   JS_OVOP_ADD,
-   JS_OVOP_SUB,
-   JS_OVOP_MUL,
-   JS_OVOP_DIV,
-   JS_OVOP_MOD,
-   JS_OVOP_POW,
-   JS_OVOP_OR,
-   JS_OVOP_AND,
-   JS_OVOP_XOR,
-   JS_OVOP_SHL,
-   JS_OVOP_SAR,
-   JS_OVOP_SHR,
-   JS_OVOP_EQ,
-   JS_OVOP_LESS,
-
-   JS_OVOP_BINARY_COUNT,
-   /* unary operators */
-   JS_OVOP_POS = JS_OVOP_BINARY_COUNT,
-   JS_OVOP_NEG,
-   JS_OVOP_INC,
-   JS_OVOP_DEC,
-   JS_OVOP_NOT,
-
-   JS_OVOP_COUNT,
-} JSOverloadableOperatorEnum;
-
-typedef struct {
-    uint32_t operator_index;
-    JSObject *ops[JS_OVOP_BINARY_COUNT]; /* self operators */
-} JSBinaryOperatorDefEntry;
-
-typedef struct {
-    int count;
-    JSBinaryOperatorDefEntry *tab;
-} JSBinaryOperatorDef;
-
-typedef struct {
-    uint32_t operator_counter;
-    BOOL is_primitive; /* OperatorSet for a primitive type */
-    /* NULL if no operator is defined */
-    JSObject *self_ops[JS_OVOP_COUNT]; /* self operators */
-    JSBinaryOperatorDef left;
-    JSBinaryOperatorDef right;
-} JSOperatorSetData;
-
-typedef struct JSReqModuleEntry {
-    JSAtom module_name;
-    JSModuleDef *module; /* used using resolution */
-} JSReqModuleEntry;
-
-typedef enum JSExportTypeEnum {
-    JS_EXPORT_TYPE_LOCAL,
-    JS_EXPORT_TYPE_INDIRECT,
-} JSExportTypeEnum;
-
-typedef struct JSExportEntry {
-    union {
-        struct {
-            int var_idx; /* closure variable index */
-            JSVarRef *var_ref; /* if != NULL, reference to the variable */
-        } local; /* for local export */
-        int req_module_idx; /* module for indirect export */
-    } u;
-    JSExportTypeEnum export_type;
-    JSAtom local_name; /* '*' if export ns from. not used for local
-                          export after compilation */
-    JSAtom export_name; /* exported variable name */
-} JSExportEntry;
-
-typedef struct JSStarExportEntry {
-    int req_module_idx; /* in req_module_entries */
-} JSStarExportEntry;
-
-typedef struct JSImportEntry {
-    int var_idx; /* closure variable index */
-    JSAtom import_name;
-    int req_module_idx; /* in req_module_entries */
-} JSImportEntry;
-
-struct JSModuleDef {
-    JSRefCountHeader header; /* must come first, 32-bit */
-    JSAtom module_name;
-    struct list_head link;
-
-    JSReqModuleEntry *req_module_entries;
-    int req_module_entries_count;
-    int req_module_entries_size;
-
-    JSExportEntry *export_entries;
-    int export_entries_count;
-    int export_entries_size;
-
-    JSStarExportEntry *star_export_entries;
-    int star_export_entries_count;
-    int star_export_entries_size;
-
-    JSImportEntry *import_entries;
-    int import_entries_count;
-    int import_entries_size;
-
-    JSValue module_ns;
-    JSValue func_obj; /* only used for JS modules */
-    JSModuleInitFunc *init_func; /* only used for C modules */
-    BOOL resolved : 8;
-    BOOL func_created : 8;
-    BOOL instantiated : 8;
-    BOOL evaluated : 8;
-    BOOL eval_mark : 8; /* temporary use during js_evaluate_module() */
-    /* true if evaluation yielded an exception. It is saved in
-       eval_exception */
-    BOOL eval_has_exception : 8; 
-    JSValue eval_exception;
-    JSValue meta_obj; /* for import.meta */
-};
-
-typedef struct JSJobEntry {
-    struct list_head link;
-    JSContext *ctx;
-    JSJobFunc *job_func;
-    int argc;
-    JSValue argv[0];
-} JSJobEntry;
-
-typedef struct JSProperty {
-    union {
-        JSValue value;      /* JS_PROP_NORMAL */
-        struct {            /* JS_PROP_GETSET */
-            JSObject *getter; /* NULL if undefined */
-            JSObject *setter; /* NULL if undefined */
-        } getset;
-        JSVarRef *var_ref;  /* JS_PROP_VARREF */
-        struct {            /* JS_PROP_AUTOINIT */
-            /* in order to use only 2 pointers, we compress the realm
-               and the init function pointer */
-            uintptr_t realm_and_id; /* realm and init_id (JS_AUTOINIT_ID_x)
-                                       in the 2 low bits */
-            void *opaque;
-        } init;
-    } u;
-} JSProperty;
-
-#define JS_PROP_INITIAL_SIZE 2
-#define JS_PROP_INITIAL_HASH_SIZE 4 /* must be a power of two */
-#define JS_ARRAY_INITIAL_SIZE 2
-
-typedef struct JSShapeProperty {
-    uint32_t hash_next : 26; /* 0 if last in list */
-    uint32_t flags : 6;   /* JS_PROP_XXX */
-    JSAtom atom; /* JS_ATOM_NULL = free property entry */
-} JSShapeProperty;
-
-struct JSShape {
-    /* hash table of size hash_mask + 1 before the start of the
-       structure (see prop_hash_end()). */
-    JSGCObjectHeader header;
-    /* true if the shape is inserted in the shape hash table. If not,
-       JSShape.hash is not valid */
-    uint8_t is_hashed;
-    /* If true, the shape may have small array index properties 'n' with 0
-       <= n <= 2^31-1. If false, the shape is guaranteed not to have
-       small array index properties */
-    uint8_t has_small_array_index;
-    uint32_t hash; /* current hash value */
-    uint32_t prop_hash_mask;
-    int prop_size; /* allocated properties */
-    int prop_count; /* include deleted properties */
-    int deleted_prop_count;
-    JSShape *shape_hash_next; /* in JSRuntime.shape_hash[h] list */
-    JSObject *proto;
-    JSShapeProperty prop[0]; /* prop_size elements */
-};
-
-struct JSObject {
-    union {
-        JSGCObjectHeader header;
-        struct {
-            int __gc_ref_count; /* corresponds to header.ref_count */
-            uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
-            
-            uint8_t extensible : 1;
-            uint8_t free_mark : 1; /* only used when freeing objects with cycles */
-            uint8_t is_exotic : 1; /* TRUE if object has exotic property handlers */
-            uint8_t fast_array : 1; /* TRUE if u.array is used for get/put (for JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS and typed arrays) */
-            uint8_t is_constructor : 1; /* TRUE if object is a constructor function */
-            uint8_t is_uncatchable_error : 1; /* if TRUE, error is not catchable */
-            uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */
-            uint8_t is_HTMLDDA : 1; /* specific annex B IsHtmlDDA behavior */
-            uint16_t class_id; /* see JS_CLASS_x */
-        };
-    };
-    /* byte offsets: 16/24 */
-    JSShape *shape; /* prototype and property names + flag */
-    JSProperty *prop; /* array of properties */
-    /* byte offsets: 24/40 */
-    struct JSMapRecord *first_weak_ref; /* XXX: use a bit and an external hash table? */
-    /* byte offsets: 28/48 */
-    union {
-        void *opaque;
-        struct JSBoundFunction *bound_function; /* JS_CLASS_BOUND_FUNCTION */
-        struct JSCFunctionDataRecord *c_function_data_record; /* JS_CLASS_C_FUNCTION_DATA */
-        struct JSForInIterator *for_in_iterator; /* JS_CLASS_FOR_IN_ITERATOR */
-        struct JSArrayBuffer *array_buffer; /* JS_CLASS_ARRAY_BUFFER, JS_CLASS_SHARED_ARRAY_BUFFER */
-        struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_DATAVIEW */
-#ifdef CONFIG_BIGNUM
-        struct JSFloatEnv *float_env; /* JS_CLASS_FLOAT_ENV */
-        struct JSOperatorSetData *operator_set; /* JS_CLASS_OPERATOR_SET */
-#endif
-        struct JSMapState *map_state;   /* JS_CLASS_MAP..JS_CLASS_WEAKSET */
-        struct JSMapIteratorData *map_iterator_data; /* JS_CLASS_MAP_ITERATOR, JS_CLASS_SET_ITERATOR */
-        struct JSArrayIteratorData *array_iterator_data; /* JS_CLASS_ARRAY_ITERATOR, JS_CLASS_STRING_ITERATOR */
-        struct JSRegExpStringIteratorData *regexp_string_iterator_data; /* JS_CLASS_REGEXP_STRING_ITERATOR */
-        struct JSGeneratorData *generator_data; /* JS_CLASS_GENERATOR */
-        struct JSProxyData *proxy_data; /* JS_CLASS_PROXY */
-        struct JSPromiseData *promise_data; /* JS_CLASS_PROMISE */
-        struct JSPromiseFunctionData *promise_function_data; /* JS_CLASS_PROMISE_RESOLVE_FUNCTION, JS_CLASS_PROMISE_REJECT_FUNCTION */
-        struct JSAsyncFunctionData *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */
-        struct JSAsyncFromSyncIteratorData *async_from_sync_iterator_data; /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */
-        struct JSAsyncGeneratorData *async_generator_data; /* JS_CLASS_ASYNC_GENERATOR */
-        struct { /* JS_CLASS_BYTECODE_FUNCTION: 12/24 bytes */
-            /* also used by JS_CLASS_GENERATOR_FUNCTION, JS_CLASS_ASYNC_FUNCTION and JS_CLASS_ASYNC_GENERATOR_FUNCTION */
-            struct JSFunctionBytecode *function_bytecode;
-            JSVarRef **var_refs;
-            JSObject *home_object; /* for 'super' access */
-        } func;
-        struct { /* JS_CLASS_C_FUNCTION: 12/20 bytes */
-            JSContext *realm;
-            JSCFunctionType c_function;
-            uint8_t length;
-            uint8_t cproto;
-            int16_t magic;
-        } cfunc;
-        /* array part for fast arrays and typed arrays */
-        struct { /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS, JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
-            union {
-                uint32_t size;          /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */
-                struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
-            } u1;
-            union {
-                JSValue *values;        /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */ 
-                void *ptr;              /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
-                int8_t *int8_ptr;       /* JS_CLASS_INT8_ARRAY */
-                uint8_t *uint8_ptr;     /* JS_CLASS_UINT8_ARRAY, JS_CLASS_UINT8C_ARRAY */
-                int16_t *int16_ptr;     /* JS_CLASS_INT16_ARRAY */
-                uint16_t *uint16_ptr;   /* JS_CLASS_UINT16_ARRAY */
-                int32_t *int32_ptr;     /* JS_CLASS_INT32_ARRAY */
-                uint32_t *uint32_ptr;   /* JS_CLASS_UINT32_ARRAY */
-                int64_t *int64_ptr;     /* JS_CLASS_INT64_ARRAY */
-                uint64_t *uint64_ptr;   /* JS_CLASS_UINT64_ARRAY */
-                float *float_ptr;       /* JS_CLASS_FLOAT32_ARRAY */
-                double *double_ptr;     /* JS_CLASS_FLOAT64_ARRAY */
-            } u;
-            uint32_t count; /* <= 2^31-1. 0 for a detached typed array */
-        } array;    /* 12/20 bytes */
-        JSRegExp regexp;    /* JS_CLASS_REGEXP: 8/16 bytes */
-        JSValue object_data;    /* for JS_SetObjectData(): 8/16/16 bytes */
-    } u;
-    /* byte sizes: 40/48/72 */
-};
-enum {
-    __JS_ATOM_NULL = JS_ATOM_NULL,
-#define DEF(name, str) JS_ATOM_ ## name,
-#include "quickjs-atom.h"
-#undef DEF
-    JS_ATOM_END,
-};
-#define JS_ATOM_LAST_KEYWORD JS_ATOM_super
-#define JS_ATOM_LAST_STRICT_KEYWORD JS_ATOM_yield
-
-static const char js_atom_init[] =
-#define DEF(name, str) str "\0"
-#include "quickjs-atom.h"
-#undef DEF
-;
-
-typedef enum OPCodeFormat {
-#define FMT(f) OP_FMT_ ## f,
-#define DEF(id, size, n_pop, n_push, f)
-#include "quickjs-opcode.h"
-#undef DEF
-#undef FMT
-} OPCodeFormat;
-
-enum OPCodeEnum {
-#define FMT(f)
-#define DEF(id, size, n_pop, n_push, f) OP_ ## id,
-#define def(id, size, n_pop, n_push, f)
-#include "quickjs-opcode.h"
-#undef def
-#undef DEF
-#undef FMT
-    OP_COUNT, /* excluding temporary opcodes */
-    /* temporary opcodes : overlap with the short opcodes */
-    OP_TEMP_START = OP_nop + 1,
-    OP___dummy = OP_TEMP_START - 1,
-#define FMT(f)
-#define DEF(id, size, n_pop, n_push, f)
-#define def(id, size, n_pop, n_push, f) OP_ ## id,
-#include "quickjs-opcode.h"
-#undef def
-#undef DEF
-#undef FMT
-    OP_TEMP_END,
-};
-
-static int JS_InitAtoms(JSRuntime *rt);
-static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
-                               int atom_type);
-static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p);
-static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b);
-static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
-                                  JSValueConst this_obj,
-                                  int argc, JSValueConst *argv, int flags);
-static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj,
-                                      JSValueConst this_obj,
-                                      int argc, JSValueConst *argv, int flags);
-static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
-                               JSValueConst this_obj, JSValueConst new_target,
-                               int argc, JSValue *argv, int flags);
-static JSValue JS_CallConstructorInternal(JSContext *ctx,
-                                          JSValueConst func_obj,
-                                          JSValueConst new_target,
-                                          int argc, JSValue *argv, int flags);
-static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj,
-                           int argc, JSValueConst *argv);
-static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
-                             int argc, JSValueConst *argv);
-static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
-                                            JSValue val, BOOL is_array_ctor);
-static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
-                             JSValueConst val, int flags, int scope_idx);
-JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...);
-static __maybe_unused void JS_DumpAtoms(JSRuntime *rt);
-static __maybe_unused void JS_DumpString(JSRuntime *rt,
-                                                  const JSString *p);
-static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt);
-static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p);
-static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p);
-static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
-                                                      JSValueConst val);
-static __maybe_unused void JS_DumpValue(JSContext *ctx, JSValueConst val);
-static __maybe_unused void JS_PrintValue(JSContext *ctx,
-                                                  const char *str,
-                                                  JSValueConst val);
-static __maybe_unused void JS_DumpShapes(JSRuntime *rt);
-static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv, int magic);
-static void js_array_finalizer(JSRuntime *rt, JSValue val);
-static void js_array_mark(JSRuntime *rt, JSValueConst val,
-                          JS_MarkFunc *mark_func);
-static void js_object_data_finalizer(JSRuntime *rt, JSValue val);
-static void js_object_data_mark(JSRuntime *rt, JSValueConst val,
-                                JS_MarkFunc *mark_func);
-static void js_c_function_finalizer(JSRuntime *rt, JSValue val);
-static void js_c_function_mark(JSRuntime *rt, JSValueConst val,
-                               JS_MarkFunc *mark_func);
-static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val);
-static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
-                                JS_MarkFunc *mark_func);
-static void js_bound_function_finalizer(JSRuntime *rt, JSValue val);
-static void js_bound_function_mark(JSRuntime *rt, JSValueConst val,
-                                JS_MarkFunc *mark_func);
-static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val);
-static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val,
-                                JS_MarkFunc *mark_func);
-static void js_regexp_finalizer(JSRuntime *rt, JSValue val);
-static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val);
-static void js_typed_array_finalizer(JSRuntime *rt, JSValue val);
-static void js_typed_array_mark(JSRuntime *rt, JSValueConst val,
-                                JS_MarkFunc *mark_func);
-static void js_proxy_finalizer(JSRuntime *rt, JSValue val);
-static void js_proxy_mark(JSRuntime *rt, JSValueConst val,
-                                JS_MarkFunc *mark_func);
-static void js_map_finalizer(JSRuntime *rt, JSValue val);
-static void js_map_mark(JSRuntime *rt, JSValueConst val,
-                                JS_MarkFunc *mark_func);
-static void js_map_iterator_finalizer(JSRuntime *rt, JSValue val);
-static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val,
-                                JS_MarkFunc *mark_func);
-static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val);
-static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val,
-                                JS_MarkFunc *mark_func);
-static void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val);
-static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val,
-                                JS_MarkFunc *mark_func);
-static void js_generator_finalizer(JSRuntime *rt, JSValue obj);
-static void js_generator_mark(JSRuntime *rt, JSValueConst val,
-                                JS_MarkFunc *mark_func);
-static void js_promise_finalizer(JSRuntime *rt, JSValue val);
-static void js_promise_mark(JSRuntime *rt, JSValueConst val,
-                                JS_MarkFunc *mark_func);
-static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val);
-static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
-                                JS_MarkFunc *mark_func);
-#ifdef CONFIG_BIGNUM
-static void js_operator_set_finalizer(JSRuntime *rt, JSValue val);
-static void js_operator_set_mark(JSRuntime *rt, JSValueConst val,
-                                 JS_MarkFunc *mark_func);
-#endif
-static JSValue JS_ToStringFree(JSContext *ctx, JSValue val);
-static int JS_ToBoolFree(JSContext *ctx, JSValue val);
-static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val);
-static int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val);
-static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val);
-static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
-                                 JSValueConst flags);
-static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor,
-                                              JSValue pattern, JSValue bc);
-static void gc_decref(JSRuntime *rt);
-static int JS_NewClass1(JSRuntime *rt, JSClassID class_id,
-                        const JSClassDef *class_def, JSAtom name);
-
-typedef enum JSStrictEqModeEnum {
-    JS_EQ_STRICT,
-    JS_EQ_SAME_VALUE,
-    JS_EQ_SAME_VALUE_ZERO,
-} JSStrictEqModeEnum;
-
-static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
-                          JSStrictEqModeEnum eq_mode);
-static BOOL js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2);
-static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2);
-static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2);
-static JSValue JS_ToObject(JSContext *ctx, JSValueConst val);
-static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val);
-static JSProperty *add_property(JSContext *ctx,
-                                JSObject *p, JSAtom prop, int prop_flags);
-#ifdef CONFIG_BIGNUM
-static void js_float_env_finalizer(JSRuntime *rt, JSValue val);
-static JSValue JS_NewBigFloat(JSContext *ctx);
-static inline bf_t *JS_GetBigFloat(JSValueConst val)
-{
-    JSBigFloat *p = JS_VALUE_GET_PTR(val);
-    return &p->num;
-}
-static JSValue JS_NewBigDecimal(JSContext *ctx);
-static inline bfdec_t *JS_GetBigDecimal(JSValueConst val)
-{
-    JSBigDecimal *p = JS_VALUE_GET_PTR(val);
-    return &p->num;
-}
-static JSValue JS_NewBigInt(JSContext *ctx);
-static inline bf_t *JS_GetBigInt(JSValueConst val)
-{
-    JSBigFloat *p = JS_VALUE_GET_PTR(val);
-    return &p->num;
-}
-static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
-                                 BOOL convert_to_safe_integer);
-static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val);
-static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val);
-static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val);
-static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf);
-static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val);
-static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
-                                   BOOL allow_null_or_undefined);
-static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val);
-#endif
-JSValue JS_ThrowOutOfMemory(JSContext *ctx);
-static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx);
-static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj);
-static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
-                                   JSValueConst proto_val, BOOL throw_flag);
-static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj);
-static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj);
-static int js_proxy_isArray(JSContext *ctx, JSValueConst obj);
-static int JS_CreateProperty(JSContext *ctx, JSObject *p,
-                             JSAtom prop, JSValueConst val,
-                             JSValueConst getter, JSValueConst setter,
-                             int flags);
-static int js_string_memcmp(const JSString *p1, const JSString *p2, int len);
-static void reset_weak_ref(JSRuntime *rt, JSObject *p);
-static JSValue js_array_buffer_constructor3(JSContext *ctx,
-                                            JSValueConst new_target,
-                                            uint64_t len, JSClassID class_id,
-                                            uint8_t *buf,
-                                            JSFreeArrayBufferDataFunc *free_func,
-                                            void *opaque, BOOL alloc_flag);
-static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj);
-static JSValue js_typed_array_constructor(JSContext *ctx,
-                                          JSValueConst this_val,
-                                          int argc, JSValueConst *argv,
-                                          int classid);
-static BOOL typed_array_is_detached(JSContext *ctx, JSObject *p);
-static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p);
-static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx);
-static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx,
-                             BOOL is_arg);
-static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
-                                          JSValueConst this_obj,
-                                          int argc, JSValueConst *argv,
-                                          int flags);
-static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val);
-static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,
-                                           JS_MarkFunc *mark_func);
-static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
-                               const char *input, size_t input_len,
-                               const char *filename, int flags, int scope_idx);
-static void js_free_module_def(JSContext *ctx, JSModuleDef *m);
-static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
-                               JS_MarkFunc *mark_func);
-static JSValue js_import_meta(JSContext *ctx);
-static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier);
-static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref);
-static JSValue js_new_promise_capability(JSContext *ctx,
-                                         JSValue *resolving_funcs,
-                                         JSValueConst ctor);
-static __exception int perform_promise_then(JSContext *ctx,
-                                            JSValueConst promise,
-                                            JSValueConst *resolve_reject,
-                                            JSValueConst *cap_resolving_funcs);
-static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
-                                  int argc, JSValueConst *argv, int magic);
-static int js_string_compare(JSContext *ctx,
-                             const JSString *p1, const JSString *p2);
-static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val);
-static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
-                               JSValue prop, JSValue val, int flags);
-static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val);
-static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val);
-static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val);
-static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc,
-                                     JSObject *p, JSAtom prop);
-static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc);
-static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s,
-                            JS_MarkFunc *mark_func);
-static void JS_AddIntrinsicBasicObjects(JSContext *ctx);
-static void js_free_shape(JSRuntime *rt, JSShape *sh);
-static void js_free_shape_null(JSRuntime *rt, JSShape *sh);
-static int js_shape_prepare_update(JSContext *ctx, JSObject *p,
-                                   JSShapeProperty **pprs);
-static int init_shape_hash(JSRuntime *rt);
-static __exception int js_get_length32(JSContext *ctx, uint32_t *pres,
-                                       JSValueConst obj);
-static __exception int js_get_length64(JSContext *ctx, int64_t *pres,
-                                       JSValueConst obj);
-static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len);
-static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
-                               JSValueConst array_arg);
-static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj,
-                              JSValue **arrpp, uint32_t *countp);
-static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx,
-                                              JSValueConst sync_iter);
-static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val);
-static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val,
-                                    JS_MarkFunc *mark_func);
-static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj,
-                                       JSValueConst this_val,
-                                       int argc, JSValueConst *argv, int flags);
-static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val);
-static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
-                          JSGCObjectTypeEnum type);
-static void remove_gc_object(JSGCObjectHeader *h);
-static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s);
-static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
-static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
-                                 void *opaque);
-static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,
-                                               JSAtom atom, void *opaque);
-void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag);
-
-static const JSClassExoticMethods js_arguments_exotic_methods;
-static const JSClassExoticMethods js_string_exotic_methods;
-static const JSClassExoticMethods js_proxy_exotic_methods;
-static const JSClassExoticMethods js_module_ns_exotic_methods;
-static JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT;
-
-static void js_trigger_gc(JSRuntime *rt, size_t size)
-{
-    BOOL force_gc;
-#ifdef FORCE_GC_AT_MALLOC
-    force_gc = TRUE;
-#else
-    force_gc = ((rt->malloc_state.malloc_size + size) >
-                rt->malloc_gc_threshold);
-#endif
-    if (force_gc) {
-#ifdef DUMP_GC
-        printf("GC: size=%" PRIu64 "\n",
-               (uint64_t)rt->malloc_state.malloc_size);
-#endif
-        JS_RunGC(rt);
-        rt->malloc_gc_threshold = rt->malloc_state.malloc_size +
-            (rt->malloc_state.malloc_size >> 1);
-    }
-}
-
-static size_t js_malloc_usable_size_unknown(const void *ptr)
-{
-    return 0;
-}
-
-void *js_malloc_rt(JSRuntime *rt, size_t size)
-{
-    return rt->mf.js_malloc(&rt->malloc_state, size);
-}
-
-void js_free_rt(JSRuntime *rt, void *ptr)
-{
-    rt->mf.js_free(&rt->malloc_state, ptr);
-}
-
-void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size)
-{
-    return rt->mf.js_realloc(&rt->malloc_state, ptr, size);
-}
-
-size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr)
-{
-    return rt->mf.js_malloc_usable_size(ptr);
-}
-
-void *js_mallocz_rt(JSRuntime *rt, size_t size)
-{
-    void *ptr;
-    ptr = js_malloc_rt(rt, size);
-    if (!ptr)
-        return NULL;
-    return memset(ptr, 0, size);
-}
-
-#ifdef CONFIG_BIGNUM
-/* called by libbf */
-static void *js_bf_realloc(void *opaque, void *ptr, size_t size)
-{
-    JSRuntime *rt = opaque;
-    return js_realloc_rt(rt, ptr, size);
-}
-#endif /* CONFIG_BIGNUM */
-
-/* Throw out of memory in case of error */
-void *js_malloc(JSContext *ctx, size_t size)
-{
-    void *ptr;
-    ptr = js_malloc_rt(ctx->rt, size);
-    if (unlikely(!ptr)) {
-        JS_ThrowOutOfMemory(ctx);
-        return NULL;
-    }
-    return ptr;
-}
-
-/* Throw out of memory in case of error */
-void *js_mallocz(JSContext *ctx, size_t size)
-{
-    void *ptr;
-    ptr = js_mallocz_rt(ctx->rt, size);
-    if (unlikely(!ptr)) {
-        JS_ThrowOutOfMemory(ctx);
-        return NULL;
-    }
-    return ptr;
-}
-
-void js_free(JSContext *ctx, void *ptr)
-{
-    js_free_rt(ctx->rt, ptr);
-}
-
-/* Throw out of memory in case of error */
-void *js_realloc(JSContext *ctx, void *ptr, size_t size)
-{
-    void *ret;
-    ret = js_realloc_rt(ctx->rt, ptr, size);
-    if (unlikely(!ret && size != 0)) {
-        JS_ThrowOutOfMemory(ctx);
-        return NULL;
-    }
-    return ret;
-}
-
-/* store extra allocated size in *pslack if successful */
-void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack)
-{
-    void *ret;
-    ret = js_realloc_rt(ctx->rt, ptr, size);
-    if (unlikely(!ret && size != 0)) {
-        JS_ThrowOutOfMemory(ctx);
-        return NULL;
-    }
-    if (pslack) {
-        size_t new_size = js_malloc_usable_size_rt(ctx->rt, ret);
-        *pslack = (new_size > size) ? new_size - size : 0;
-    }
-    return ret;
-}
-
-size_t js_malloc_usable_size(JSContext *ctx, const void *ptr)
-{
-    return js_malloc_usable_size_rt(ctx->rt, ptr);
-}
-
-/* Throw out of memory exception in case of error */
-char *js_strndup(JSContext *ctx, const char *s, size_t n)
-{
-    char *ptr;
-    ptr = js_malloc(ctx, n + 1);
-    if (ptr) {
-        memcpy(ptr, s, n);
-        ptr[n] = '\0';
-    }
-    return ptr;
-}
-
-char *js_strdup(JSContext *ctx, const char *str)
-{
-    return js_strndup(ctx, str, strlen(str));
-}
-
-static no_inline int js_realloc_array(JSContext *ctx, void **parray,
-                                      int elem_size, int *psize, int req_size)
-{
-    int new_size;
-    size_t slack;
-    void *new_array;
-    /* XXX: potential arithmetic overflow */
-    new_size = max_int(req_size, *psize * 3 / 2);
-    new_array = js_realloc2(ctx, *parray, new_size * elem_size, &slack);
-    if (!new_array)
-        return -1;
-    new_size += slack / elem_size;
-    *psize = new_size;
-    *parray = new_array;
-    return 0;
-}
-
-/* resize the array and update its size if req_size > *psize */
-static inline int js_resize_array(JSContext *ctx, void **parray, int elem_size,
-                                  int *psize, int req_size)
-{
-    if (unlikely(req_size > *psize))
-        return js_realloc_array(ctx, parray, elem_size, psize, req_size);
-    else
-        return 0;
-}
-
-static inline void js_dbuf_init(JSContext *ctx, DynBuf *s)
-{
-    dbuf_init2(s, ctx->rt, (DynBufReallocFunc *)js_realloc_rt);
-}
-
-static inline int is_digit(int c) {
-    return c >= '0' && c <= '9';
-}
-
-typedef struct JSClassShortDef {
-    JSAtom class_name;
-    JSClassFinalizer *finalizer;
-    JSClassGCMark *gc_mark;
-} JSClassShortDef;
-
-static JSClassShortDef const js_std_class_def[] = {
-    { JS_ATOM_Object, NULL, NULL },                             /* JS_CLASS_OBJECT */
-    { JS_ATOM_Array, js_array_finalizer, js_array_mark },       /* JS_CLASS_ARRAY */
-    { JS_ATOM_Error, NULL, NULL }, /* JS_CLASS_ERROR */
-    { JS_ATOM_Number, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_NUMBER */
-    { JS_ATOM_String, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_STRING */
-    { JS_ATOM_Boolean, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BOOLEAN */
-    { JS_ATOM_Symbol, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_SYMBOL */
-    { JS_ATOM_Arguments, js_array_finalizer, js_array_mark },   /* JS_CLASS_ARGUMENTS */
-    { JS_ATOM_Arguments, NULL, NULL },                          /* JS_CLASS_MAPPED_ARGUMENTS */
-    { JS_ATOM_Date, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_DATE */
-    { JS_ATOM_Object, NULL, NULL },                             /* JS_CLASS_MODULE_NS */
-    { JS_ATOM_Function, js_c_function_finalizer, js_c_function_mark }, /* JS_CLASS_C_FUNCTION */
-    { JS_ATOM_Function, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_BYTECODE_FUNCTION */
-    { JS_ATOM_Function, js_bound_function_finalizer, js_bound_function_mark }, /* JS_CLASS_BOUND_FUNCTION */
-    { JS_ATOM_Function, js_c_function_data_finalizer, js_c_function_data_mark }, /* JS_CLASS_C_FUNCTION_DATA */
-    { JS_ATOM_GeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_GENERATOR_FUNCTION */
-    { JS_ATOM_ForInIterator, js_for_in_iterator_finalizer, js_for_in_iterator_mark },      /* JS_CLASS_FOR_IN_ITERATOR */
-    { JS_ATOM_RegExp, js_regexp_finalizer, NULL },                              /* JS_CLASS_REGEXP */
-    { JS_ATOM_ArrayBuffer, js_array_buffer_finalizer, NULL },                   /* JS_CLASS_ARRAY_BUFFER */
-    { JS_ATOM_SharedArrayBuffer, js_array_buffer_finalizer, NULL },             /* JS_CLASS_SHARED_ARRAY_BUFFER */
-    { JS_ATOM_Uint8ClampedArray, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT8C_ARRAY */
-    { JS_ATOM_Int8Array, js_typed_array_finalizer, js_typed_array_mark },       /* JS_CLASS_INT8_ARRAY */
-    { JS_ATOM_Uint8Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_UINT8_ARRAY */
-    { JS_ATOM_Int16Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_INT16_ARRAY */
-    { JS_ATOM_Uint16Array, js_typed_array_finalizer, js_typed_array_mark },     /* JS_CLASS_UINT16_ARRAY */
-    { JS_ATOM_Int32Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_INT32_ARRAY */
-    { JS_ATOM_Uint32Array, js_typed_array_finalizer, js_typed_array_mark },     /* JS_CLASS_UINT32_ARRAY */
-#ifdef CONFIG_BIGNUM
-    { JS_ATOM_BigInt64Array, js_typed_array_finalizer, js_typed_array_mark },   /* JS_CLASS_BIG_INT64_ARRAY */
-    { JS_ATOM_BigUint64Array, js_typed_array_finalizer, js_typed_array_mark },  /* JS_CLASS_BIG_UINT64_ARRAY */
-#endif
-    { JS_ATOM_Float32Array, js_typed_array_finalizer, js_typed_array_mark },    /* JS_CLASS_FLOAT32_ARRAY */
-    { JS_ATOM_Float64Array, js_typed_array_finalizer, js_typed_array_mark },    /* JS_CLASS_FLOAT64_ARRAY */
-    { JS_ATOM_DataView, js_typed_array_finalizer, js_typed_array_mark },        /* JS_CLASS_DATAVIEW */
-#ifdef CONFIG_BIGNUM
-    { JS_ATOM_BigInt, js_object_data_finalizer, js_object_data_mark },      /* JS_CLASS_BIG_INT */
-    { JS_ATOM_BigFloat, js_object_data_finalizer, js_object_data_mark },    /* JS_CLASS_BIG_FLOAT */
-    { JS_ATOM_BigFloatEnv, js_float_env_finalizer, NULL },      /* JS_CLASS_FLOAT_ENV */
-    { JS_ATOM_BigDecimal, js_object_data_finalizer, js_object_data_mark },    /* JS_CLASS_BIG_DECIMAL */
-    { JS_ATOM_OperatorSet, js_operator_set_finalizer, js_operator_set_mark },    /* JS_CLASS_OPERATOR_SET */
-#endif
-    { JS_ATOM_Map, js_map_finalizer, js_map_mark },             /* JS_CLASS_MAP */
-    { JS_ATOM_Set, js_map_finalizer, js_map_mark },             /* JS_CLASS_SET */
-    { JS_ATOM_WeakMap, js_map_finalizer, js_map_mark },         /* JS_CLASS_WEAKMAP */
-    { JS_ATOM_WeakSet, js_map_finalizer, js_map_mark },         /* JS_CLASS_WEAKSET */
-    { JS_ATOM_Map_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_MAP_ITERATOR */
-    { JS_ATOM_Set_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_SET_ITERATOR */
-    { JS_ATOM_Array_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_ARRAY_ITERATOR */
-    { JS_ATOM_String_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_STRING_ITERATOR */
-    { JS_ATOM_RegExp_String_Iterator, js_regexp_string_iterator_finalizer, js_regexp_string_iterator_mark }, /* JS_CLASS_REGEXP_STRING_ITERATOR */
-    { JS_ATOM_Generator, js_generator_finalizer, js_generator_mark }, /* JS_CLASS_GENERATOR */
-};
-
-static int init_class_range(JSRuntime *rt, JSClassShortDef const *tab,
-                            int start, int count)
-{
-    JSClassDef cm_s, *cm = &cm_s;
-    int i, class_id;
-
-    for(i = 0; i < count; i++) {
-        class_id = i + start;
-        memset(cm, 0, sizeof(*cm));
-        cm->finalizer = tab[i].finalizer;
-        cm->gc_mark = tab[i].gc_mark;
-        if (JS_NewClass1(rt, class_id, cm, tab[i].class_name) < 0)
-            return -1;
-    }
-    return 0;
-}
-
-#ifdef CONFIG_BIGNUM
-static JSValue JS_ThrowUnsupportedOperation(JSContext *ctx)
-{
-    return JS_ThrowTypeError(ctx, "unsupported operation");
-}
-
-static JSValue invalid_to_string(JSContext *ctx, JSValueConst val)
-{
-    return JS_ThrowUnsupportedOperation(ctx);
-}
-
-static JSValue invalid_from_string(JSContext *ctx, const char *buf,
-                                   int radix, int flags, slimb_t *pexponent)
-{
-    return JS_NAN;
-}
-
-static int invalid_unary_arith(JSContext *ctx,
-                               JSValue *pres, OPCodeEnum op, JSValue op1)
-{
-    JS_FreeValue(ctx, op1);
-    JS_ThrowUnsupportedOperation(ctx);
-    return -1;
-}
-
-static int invalid_binary_arith(JSContext *ctx, OPCodeEnum op,
-                                JSValue *pres, JSValue op1, JSValue op2)
-{
-    JS_FreeValue(ctx, op1);
-    JS_FreeValue(ctx, op2);
-    JS_ThrowUnsupportedOperation(ctx);
-    return -1;
-}
-
-static JSValue invalid_mul_pow10_to_float64(JSContext *ctx, const bf_t *a,
-                                            int64_t exponent)
-{
-    return JS_ThrowUnsupportedOperation(ctx);
-}
-
-static int invalid_mul_pow10(JSContext *ctx, JSValue *sp)
-{
-    JS_ThrowUnsupportedOperation(ctx);
-    return -1;
-}
-
-static void set_dummy_numeric_ops(JSNumericOperations *ops)
-{
-    ops->to_string = invalid_to_string;
-    ops->from_string = invalid_from_string;
-    ops->unary_arith = invalid_unary_arith;
-    ops->binary_arith = invalid_binary_arith;
-    ops->mul_pow10_to_float64 = invalid_mul_pow10_to_float64;
-    ops->mul_pow10 = invalid_mul_pow10;
-}
-
-#endif /* CONFIG_BIGNUM */
-
-#if !defined(CONFIG_STACK_CHECK)
-/* no stack limitation */
-static inline uintptr_t js_get_stack_pointer(void)
-{
-    return 0;
-}
-
-static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
-{
-    return FALSE;
-}
-#else
-/* Note: OS and CPU dependent */
-static inline uintptr_t js_get_stack_pointer(void)
-{
-    return (uintptr_t)__builtin_frame_address(0);
-}
-
-static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
-{
-    uintptr_t sp;
-    sp = js_get_stack_pointer() - alloca_size;
-    return unlikely(sp < rt->stack_limit);
-}
-#endif
-
-JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
-{
-    JSRuntime *rt;
-    JSMallocState ms;
-
-    memset(&ms, 0, sizeof(ms));
-    ms.opaque = opaque;
-    ms.malloc_limit = -1;
-
-    rt = mf->js_malloc(&ms, sizeof(JSRuntime));
-    if (!rt)
-        return NULL;
-    memset(rt, 0, sizeof(*rt));
-    rt->mf = *mf;
-    if (!rt->mf.js_malloc_usable_size) {
-        /* use dummy function if none provided */
-        rt->mf.js_malloc_usable_size = js_malloc_usable_size_unknown;
-    }
-    rt->malloc_state = ms;
-    rt->malloc_gc_threshold = 256 * 1024;
-
-#ifdef CONFIG_BIGNUM
-    bf_context_init(&rt->bf_ctx, js_bf_realloc, rt);
-    set_dummy_numeric_ops(&rt->bigint_ops);
-    set_dummy_numeric_ops(&rt->bigfloat_ops);
-    set_dummy_numeric_ops(&rt->bigdecimal_ops);
-#endif
-
-    init_list_head(&rt->context_list);
-    init_list_head(&rt->gc_obj_list);
-    init_list_head(&rt->gc_zero_ref_count_list);
-    rt->gc_phase = JS_GC_PHASE_NONE;
-    
-#ifdef DUMP_LEAKS
-    init_list_head(&rt->string_list);
-#endif
-    init_list_head(&rt->job_list);
-
-    if (JS_InitAtoms(rt))
-        goto fail;
-
-    /* create the object, array and function classes */
-    if (init_class_range(rt, js_std_class_def, JS_CLASS_OBJECT,
-                         countof(js_std_class_def)) < 0)
-        goto fail;
-    rt->class_array[JS_CLASS_ARGUMENTS].exotic = &js_arguments_exotic_methods;
-    rt->class_array[JS_CLASS_STRING].exotic = &js_string_exotic_methods;
-    rt->class_array[JS_CLASS_MODULE_NS].exotic = &js_module_ns_exotic_methods;
-
-    rt->class_array[JS_CLASS_C_FUNCTION].call = js_call_c_function;
-    rt->class_array[JS_CLASS_C_FUNCTION_DATA].call = js_c_function_data_call;
-    rt->class_array[JS_CLASS_BOUND_FUNCTION].call = js_call_bound_function;
-    rt->class_array[JS_CLASS_GENERATOR_FUNCTION].call = js_generator_function_call;
-    if (init_shape_hash(rt))
-        goto fail;
-
-    rt->stack_size = JS_DEFAULT_STACK_SIZE;
-    JS_UpdateStackTop(rt);
-
-    rt->current_exception = JS_NULL;
-
-    return rt;
- fail:
-    JS_FreeRuntime(rt);
-    return NULL;
-}
-
-void *JS_GetRuntimeOpaque(JSRuntime *rt)
-{
-    return rt->user_opaque;
-}
-
-void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque)
-{
-    rt->user_opaque = opaque;
-}
-
-/* default memory allocation functions with memory limitation */
-static inline size_t js_def_malloc_usable_size(void *ptr)
-{
-#if defined(__APPLE__)
-    return malloc_size(ptr);
-#elif defined(_WIN32)
-    return _msize(ptr);
-#elif defined(EMSCRIPTEN)
-    return 0;
-#elif defined(__linux__)
-    return malloc_usable_size(ptr);
-#else
-    /* change this to `return 0;` if compilation fails */
-    return malloc_usable_size(ptr);
-#endif
-}
-
-static void *js_def_malloc(JSMallocState *s, size_t size)
-{
-    void *ptr;
-
-    /* Do not allocate zero bytes: behavior is platform dependent */
-    assert(size != 0);
-
-    if (unlikely(s->malloc_size + size > s->malloc_limit))
-        return NULL;
-
-    ptr = malloc(size);
-    if (!ptr)
-        return NULL;
-
-    s->malloc_count++;
-    s->malloc_size += js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
-    return ptr;
-}
-
-static void js_def_free(JSMallocState *s, void *ptr)
-{
-    if (!ptr)
-        return;
-
-    s->malloc_count--;
-    s->malloc_size -= js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
-    free(ptr);
-}
-
-static void *js_def_realloc(JSMallocState *s, void *ptr, size_t size)
-{
-    size_t old_size;
-
-    if (!ptr) {
-        if (size == 0)
-            return NULL;
-        return js_def_malloc(s, size);
-    }
-    old_size = js_def_malloc_usable_size(ptr);
-    if (size == 0) {
-        s->malloc_count--;
-        s->malloc_size -= old_size + MALLOC_OVERHEAD;
-        free(ptr);
-        return NULL;
-    }
-    if (s->malloc_size + size - old_size > s->malloc_limit)
-        return NULL;
-
-    ptr = realloc(ptr, size);
-    if (!ptr)
-        return NULL;
-
-    s->malloc_size += js_def_malloc_usable_size(ptr) - old_size;
-    return ptr;
-}
-
-static const JSMallocFunctions def_malloc_funcs = {
-    js_def_malloc,
-    js_def_free,
-    js_def_realloc,
-#if defined(__APPLE__)
-    malloc_size,
-#elif defined(_WIN32)
-    (size_t (*)(const void *))_msize,
-#elif defined(EMSCRIPTEN)
-    NULL,
-#elif defined(__linux__)
-    (size_t (*)(const void *))malloc_usable_size,
-#else
-    /* change this to `NULL,` if compilation fails */
-    malloc_usable_size,
-#endif
-};
-
-JSRuntime *JS_NewRuntime(void)
-{
-    return JS_NewRuntime2(&def_malloc_funcs, NULL);
-}
-
-void JS_SetMemoryLimit(JSRuntime *rt, size_t limit)
-{
-    rt->malloc_state.malloc_limit = limit;
-}
-
-/* use -1 to disable automatic GC */
-void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold)
-{
-    rt->malloc_gc_threshold = gc_threshold;
-}
-
-#define malloc(s) malloc_is_forbidden(s)
-#define free(p) free_is_forbidden(p)
-#define realloc(p,s) realloc_is_forbidden(p,s)
-
-void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque)
-{
-    rt->interrupt_handler = cb;
-    rt->interrupt_opaque = opaque;
-}
-
-void JS_SetCanBlock(JSRuntime *rt, BOOL can_block)
-{
-    rt->can_block = can_block;
-}
-
-void JS_SetSharedArrayBufferFunctions(JSRuntime *rt,
-                                      const JSSharedArrayBufferFunctions *sf)
-{
-    rt->sab_funcs = *sf;
-}
-
-/* return 0 if OK, < 0 if exception */
-int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func,
-                  int argc, JSValueConst *argv)
-{
-    JSRuntime *rt = ctx->rt;
-    JSJobEntry *e;
-    int i;
-
-    e = js_malloc(ctx, sizeof(*e) + argc * sizeof(JSValue));
-    if (!e)
-        return -1;
-    e->ctx = ctx;
-    e->job_func = job_func;
-    e->argc = argc;
-    for(i = 0; i < argc; i++) {
-        e->argv[i] = JS_DupValue(ctx, argv[i]);
-    }
-    list_add_tail(&e->link, &rt->job_list);
-    return 0;
-}
-
-BOOL JS_IsJobPending(JSRuntime *rt)
-{
-    return !list_empty(&rt->job_list);
-}
-
-/* return < 0 if exception, 0 if no job pending, 1 if a job was
-   executed successfully. the context of the job is stored in '*pctx' */
-int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx)
-{
-    JSContext *ctx;
-    JSJobEntry *e;
-    JSValue res;
-    int i, ret;
-
-    if (list_empty(&rt->job_list)) {
-        *pctx = NULL;
-        return 0;
-    }
-
-    /* get the first pending job and execute it */
-    e = list_entry(rt->job_list.next, JSJobEntry, link);
-    list_del(&e->link);
-    ctx = e->ctx;
-    res = e->job_func(e->ctx, e->argc, (JSValueConst *)e->argv);
-    for(i = 0; i < e->argc; i++)
-        JS_FreeValue(ctx, e->argv[i]);
-    if (JS_IsException(res))
-        ret = -1;
-    else
-        ret = 1;
-    JS_FreeValue(ctx, res);
-    js_free(ctx, e);
-    *pctx = ctx;
-    return ret;
-}
-
-static inline uint32_t atom_get_free(const JSAtomStruct *p)
-{
-    return (uintptr_t)p >> 1;
-}
-
-static inline BOOL atom_is_free(const JSAtomStruct *p)
-{
-    return (uintptr_t)p & 1;
-}
-
-static inline JSAtomStruct *atom_set_free(uint32_t v)
-{
-    return (JSAtomStruct *)(((uintptr_t)v << 1) | 1);
-}
-
-/* Note: the string contents are uninitialized */
-static JSString *js_alloc_string_rt(JSRuntime *rt, int max_len, int is_wide_char)
-{
-    JSString *str;
-    str = js_malloc_rt(rt, sizeof(JSString) + (max_len << is_wide_char) + 1 - is_wide_char);
-    if (unlikely(!str))
-        return NULL;
-    str->header.ref_count = 1;
-    str->is_wide_char = is_wide_char;
-    str->len = max_len;
-    str->atom_type = 0;
-    str->hash = 0;          /* optional but costless */
-    str->hash_next = 0;     /* optional */
-#ifdef DUMP_LEAKS
-    list_add_tail(&str->link, &rt->string_list);
-#endif
-    return str;
-}
-
-static JSString *js_alloc_string(JSContext *ctx, int max_len, int is_wide_char)
-{
-    JSString *p;
-    p = js_alloc_string_rt(ctx->rt, max_len, is_wide_char);
-    if (unlikely(!p)) {
-        JS_ThrowOutOfMemory(ctx);
-        return NULL;
-    }
-    return p;
-}
-
-/* same as JS_FreeValueRT() but faster */
-static inline void js_free_string(JSRuntime *rt, JSString *str)
-{
-    if (--str->header.ref_count <= 0) {
-        if (str->atom_type) {
-            JS_FreeAtomStruct(rt, str);
-        } else {
-#ifdef DUMP_LEAKS
-            list_del(&str->link);
-#endif
-            js_free_rt(rt, str);
-        }
-    }
-}
-
-void JS_SetRuntimeInfo(JSRuntime *rt, const char *s)
-{
-    if (rt)
-        rt->rt_info = s;
-}
-
-void JS_FreeRuntime(JSRuntime *rt)
-{
-    struct list_head *el, *el1;
-    int i;
-
-    JS_FreeValueRT(rt, rt->current_exception);
-
-    list_for_each_safe(el, el1, &rt->job_list) {
-        JSJobEntry *e = list_entry(el, JSJobEntry, link);
-        for(i = 0; i < e->argc; i++)
-            JS_FreeValueRT(rt, e->argv[i]);
-        js_free_rt(rt, e);
-    }
-    init_list_head(&rt->job_list);
-
-    JS_RunGC(rt);
-
-#ifdef DUMP_LEAKS
-    /* leaking objects */
-    {
-        BOOL header_done;
-        JSGCObjectHeader *p;
-        int count;
-
-        /* remove the internal refcounts to display only the object
-           referenced externally */
-        list_for_each(el, &rt->gc_obj_list) {
-            p = list_entry(el, JSGCObjectHeader, link);
-            p->mark = 0;
-        }
-        gc_decref(rt);
-
-        header_done = FALSE;
-        list_for_each(el, &rt->gc_obj_list) {
-            p = list_entry(el, JSGCObjectHeader, link);
-            if (p->ref_count != 0) {
-                if (!header_done) {
-                    printf("Object leaks:\n");
-                    JS_DumpObjectHeader(rt);
-                    header_done = TRUE;
-                }
-                JS_DumpGCObject(rt, p);
-            }
-        }
-
-        count = 0;
-        list_for_each(el, &rt->gc_obj_list) {
-            p = list_entry(el, JSGCObjectHeader, link);
-            if (p->ref_count == 0) {
-                count++;
-            }
-        }
-        if (count != 0)
-            printf("Secondary object leaks: %d\n", count);
-    }
-#endif
-    assert(list_empty(&rt->gc_obj_list));
-
-    /* free the classes */
-    for(i = 0; i < rt->class_count; i++) {
-        JSClass *cl = &rt->class_array[i];
-        if (cl->class_id != 0) {
-            JS_FreeAtomRT(rt, cl->class_name);
-        }
-    }
-    js_free_rt(rt, rt->class_array);
-
-#ifdef CONFIG_BIGNUM
-    bf_context_end(&rt->bf_ctx);
-#endif
-
-#ifdef DUMP_LEAKS
-    /* only the atoms defined in JS_InitAtoms() should be left */
-    {
-        BOOL header_done = FALSE;
-
-        for(i = 0; i < rt->atom_size; i++) {
-            JSAtomStruct *p = rt->atom_array[i];
-            if (!atom_is_free(p) /* && p->str*/) {
-                if (i >= JS_ATOM_END || p->header.ref_count != 1) {
-                    if (!header_done) {
-                        header_done = TRUE;
-                        if (rt->rt_info) {
-                            printf("%s:1: atom leakage:", rt->rt_info);
-                        } else {
-                            printf("Atom leaks:\n"
-                                   "    %6s %6s %s\n",
-                                   "ID", "REFCNT", "NAME");
-                        }
-                    }
-                    if (rt->rt_info) {
-                        printf(" ");
-                    } else {
-                        printf("    %6u %6u ", i, p->header.ref_count);
-                    }
-                    switch (p->atom_type) {
-                    case JS_ATOM_TYPE_STRING:
-                        JS_DumpString(rt, p);
-                        break;
-                    case JS_ATOM_TYPE_GLOBAL_SYMBOL:
-                        printf("Symbol.for(");
-                        JS_DumpString(rt, p);
-                        printf(")");
-                        break;
-                    case JS_ATOM_TYPE_SYMBOL:
-                        if (p->hash == JS_ATOM_HASH_SYMBOL) {
-                            printf("Symbol(");
-                            JS_DumpString(rt, p);
-                            printf(")");
-                        } else {
-                            printf("Private(");
-                            JS_DumpString(rt, p);
-                            printf(")");
-                        }
-                        break;
-                    }
-                    if (rt->rt_info) {
-                        printf(":%u", p->header.ref_count);
-                    } else {
-                        printf("\n");
-                    }
-                }
-            }
-        }
-        if (rt->rt_info && header_done)
-            printf("\n");
-    }
-#endif
-
-    /* free the atoms */
-    for(i = 0; i < rt->atom_size; i++) {
-        JSAtomStruct *p = rt->atom_array[i];
-        if (!atom_is_free(p)) {
-#ifdef DUMP_LEAKS
-            list_del(&p->link);
-#endif
-            js_free_rt(rt, p);
-        }
-    }
-    js_free_rt(rt, rt->atom_array);
-    js_free_rt(rt, rt->atom_hash);
-    js_free_rt(rt, rt->shape_hash);
-#ifdef DUMP_LEAKS
-    if (!list_empty(&rt->string_list)) {
-        if (rt->rt_info) {
-            printf("%s:1: string leakage:", rt->rt_info);
-        } else {
-            printf("String leaks:\n"
-                   "    %6s %s\n",
-                   "REFCNT", "VALUE");
-        }
-        list_for_each_safe(el, el1, &rt->string_list) {
-            JSString *str = list_entry(el, JSString, link);
-            if (rt->rt_info) {
-                printf(" ");
-            } else {
-                printf("    %6u ", str->header.ref_count);
-            }
-            JS_DumpString(rt, str);
-            if (rt->rt_info) {
-                printf(":%u", str->header.ref_count);
-            } else {
-                printf("\n");
-            }
-            list_del(&str->link);
-            js_free_rt(rt, str);
-        }
-        if (rt->rt_info)
-            printf("\n");
-    }
-    {
-        JSMallocState *s = &rt->malloc_state;
-        if (s->malloc_count > 1) {
-            if (rt->rt_info)
-                printf("%s:1: ", rt->rt_info);
-            printf("Memory leak: %"PRIu64" bytes lost in %"PRIu64" block%s\n",
-                   (uint64_t)(s->malloc_size - sizeof(JSRuntime)),
-                   (uint64_t)(s->malloc_count - 1), &"s"[s->malloc_count == 2]);
-        }
-    }
-#endif
-
-    {
-        JSMallocState ms = rt->malloc_state;
-        rt->mf.js_free(&ms, rt);
-    }
-}
-
-JSContext *JS_NewContextRaw(JSRuntime *rt)
-{
-    JSContext *ctx;
-    int i;
-
-    ctx = js_mallocz_rt(rt, sizeof(JSContext));
-    if (!ctx)
-        return NULL;
-    ctx->header.ref_count = 1;
-    add_gc_object(rt, &ctx->header, JS_GC_OBJ_TYPE_JS_CONTEXT);
-
-    ctx->class_proto = js_malloc_rt(rt, sizeof(ctx->class_proto[0]) *
-                                    rt->class_count);
-    if (!ctx->class_proto) {
-        js_free_rt(rt, ctx);
-        return NULL;
-    }
-    ctx->rt = rt;
-    list_add_tail(&ctx->link, &rt->context_list);
-#ifdef CONFIG_BIGNUM
-    ctx->bf_ctx = &rt->bf_ctx;
-    ctx->fp_env.prec = 113;
-    ctx->fp_env.flags = bf_set_exp_bits(15) | BF_RNDN | BF_FLAG_SUBNORMAL;
-#endif
-    for(i = 0; i < rt->class_count; i++)
-        ctx->class_proto[i] = JS_NULL;
-    ctx->array_ctor = JS_NULL;
-    ctx->regexp_ctor = JS_NULL;
-    ctx->promise_ctor = JS_NULL;
-    init_list_head(&ctx->loaded_modules);
-
-    JS_AddIntrinsicBasicObjects(ctx);
-    return ctx;
-}
-
-JSContext *JS_NewContext(JSRuntime *rt)
-{
-    JSContext *ctx;
-
-    ctx = JS_NewContextRaw(rt);
-    if (!ctx)
-        return NULL;
-
-    JS_AddIntrinsicBaseObjects(ctx);
-    JS_AddIntrinsicDate(ctx);
-    JS_AddIntrinsicEval(ctx);
-    JS_AddIntrinsicStringNormalize(ctx);
-    JS_AddIntrinsicRegExp(ctx);
-    JS_AddIntrinsicJSON(ctx);
-    JS_AddIntrinsicProxy(ctx);
-    JS_AddIntrinsicMapSet(ctx);
-    JS_AddIntrinsicTypedArrays(ctx);
-    JS_AddIntrinsicPromise(ctx);
-#ifdef CONFIG_BIGNUM
-    JS_AddIntrinsicBigInt(ctx);
-#endif
-    return ctx;
-}
-
-void *JS_GetContextOpaque(JSContext *ctx)
-{
-    return ctx->user_opaque;
-}
-
-void JS_SetContextOpaque(JSContext *ctx, void *opaque)
-{
-    ctx->user_opaque = opaque;
-}
-
-/* set the new value and free the old value after (freeing the value
-   can reallocate the object data) */
-static inline void set_value(JSContext *ctx, JSValue *pval, JSValue new_val)
-{
-    JSValue old_val;
-    old_val = *pval;
-    *pval = new_val;
-    JS_FreeValue(ctx, old_val);
-}
-
-void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj)
-{
-    JSRuntime *rt = ctx->rt;
-    assert(class_id < rt->class_count);
-    set_value(ctx, &ctx->class_proto[class_id], obj);
-}
-
-JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id)
-{
-    JSRuntime *rt = ctx->rt;
-    assert(class_id < rt->class_count);
-    return JS_DupValue(ctx, ctx->class_proto[class_id]);
-}
-
-typedef enum JSFreeModuleEnum {
-    JS_FREE_MODULE_ALL,
-    JS_FREE_MODULE_NOT_RESOLVED,
-    JS_FREE_MODULE_NOT_EVALUATED,
-} JSFreeModuleEnum;
-
-/* XXX: would be more efficient with separate module lists */
-static void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag)
-{
-    struct list_head *el, *el1;
-    list_for_each_safe(el, el1, &ctx->loaded_modules) {
-        JSModuleDef *m = list_entry(el, JSModuleDef, link);
-        if (flag == JS_FREE_MODULE_ALL ||
-            (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved) ||
-            (flag == JS_FREE_MODULE_NOT_EVALUATED && !m->evaluated)) {
-            js_free_module_def(ctx, m);
-        }
-    }
-}
-
-JSContext *JS_DupContext(JSContext *ctx)
-{
-    ctx->header.ref_count++;
-    return ctx;
-}
-
-/* used by the GC */
-static void JS_MarkContext(JSRuntime *rt, JSContext *ctx,
-                           JS_MarkFunc *mark_func)
-{
-    int i;
-    struct list_head *el;
-
-    /* modules are not seen by the GC, so we directly mark the objects
-       referenced by each module */
-    list_for_each(el, &ctx->loaded_modules) {
-        JSModuleDef *m = list_entry(el, JSModuleDef, link);
-        js_mark_module_def(rt, m, mark_func);
-    }
-
-    JS_MarkValue(rt, ctx->global_obj, mark_func);
-    JS_MarkValue(rt, ctx->global_var_obj, mark_func);
-
-    JS_MarkValue(rt, ctx->throw_type_error, mark_func);
-    JS_MarkValue(rt, ctx->eval_obj, mark_func);
-
-    JS_MarkValue(rt, ctx->array_proto_values, mark_func);
-    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
-        JS_MarkValue(rt, ctx->native_error_proto[i], mark_func);
-    }
-    for(i = 0; i < rt->class_count; i++) {
-        JS_MarkValue(rt, ctx->class_proto[i], mark_func);
-    }
-    JS_MarkValue(rt, ctx->iterator_proto, mark_func);
-    JS_MarkValue(rt, ctx->async_iterator_proto, mark_func);
-    JS_MarkValue(rt, ctx->promise_ctor, mark_func);
-    JS_MarkValue(rt, ctx->array_ctor, mark_func);
-    JS_MarkValue(rt, ctx->regexp_ctor, mark_func);
-    JS_MarkValue(rt, ctx->function_ctor, mark_func);
-    JS_MarkValue(rt, ctx->function_proto, mark_func);
-
-    if (ctx->array_shape)
-        mark_func(rt, &ctx->array_shape->header);
-}
-
-void JS_FreeContext(JSContext *ctx)
-{
-    JSRuntime *rt = ctx->rt;
-    int i;
-
-    if (--ctx->header.ref_count > 0)
-        return;
-    assert(ctx->header.ref_count == 0);
-    
-#ifdef DUMP_ATOMS
-    JS_DumpAtoms(ctx->rt);
-#endif
-#ifdef DUMP_SHAPES
-    JS_DumpShapes(ctx->rt);
-#endif
-#ifdef DUMP_OBJECTS
-    {
-        struct list_head *el;
-        JSGCObjectHeader *p;
-        printf("JSObjects: {\n");
-        JS_DumpObjectHeader(ctx->rt);
-        list_for_each(el, &rt->gc_obj_list) {
-            p = list_entry(el, JSGCObjectHeader, link);
-            JS_DumpGCObject(rt, p);
-        }
-        printf("}\n");
-    }
-#endif
-#ifdef DUMP_MEM
-    {
-        JSMemoryUsage stats;
-        JS_ComputeMemoryUsage(rt, &stats);
-        JS_DumpMemoryUsage(stdout, &stats, rt);
-    }
-#endif
-
-    js_free_modules(ctx, JS_FREE_MODULE_ALL);
-
-    JS_FreeValue(ctx, ctx->global_obj);
-    JS_FreeValue(ctx, ctx->global_var_obj);
-
-    JS_FreeValue(ctx, ctx->throw_type_error);
-    JS_FreeValue(ctx, ctx->eval_obj);
-
-    JS_FreeValue(ctx, ctx->array_proto_values);
-    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
-        JS_FreeValue(ctx, ctx->native_error_proto[i]);
-    }
-    for(i = 0; i < rt->class_count; i++) {
-        JS_FreeValue(ctx, ctx->class_proto[i]);
-    }
-    js_free_rt(rt, ctx->class_proto);
-    JS_FreeValue(ctx, ctx->iterator_proto);
-    JS_FreeValue(ctx, ctx->async_iterator_proto);
-    JS_FreeValue(ctx, ctx->promise_ctor);
-    JS_FreeValue(ctx, ctx->array_ctor);
-    JS_FreeValue(ctx, ctx->regexp_ctor);
-    JS_FreeValue(ctx, ctx->function_ctor);
-    JS_FreeValue(ctx, ctx->function_proto);
-
-    js_free_shape_null(ctx->rt, ctx->array_shape);
-
-    list_del(&ctx->link);
-    remove_gc_object(&ctx->header);
-    js_free_rt(ctx->rt, ctx);
-}
-
-JSRuntime *JS_GetRuntime(JSContext *ctx)
-{
-    return ctx->rt;
-}
-
-static void update_stack_limit(JSRuntime *rt)
-{
-    if (rt->stack_size == 0) {
-        rt->stack_limit = 0; /* no limit */
-    } else {
-        rt->stack_limit = rt->stack_top - rt->stack_size;
-    }
-}
-
-void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size)
-{
-    rt->stack_size = stack_size;
-    update_stack_limit(rt);
-}
-
-void JS_UpdateStackTop(JSRuntime *rt)
-{
-    rt->stack_top = js_get_stack_pointer();
-    update_stack_limit(rt);
-}
-
-static inline BOOL is_strict_mode(JSContext *ctx)
-{
-    JSStackFrame *sf = ctx->rt->current_stack_frame;
-    return (sf && (sf->js_mode & JS_MODE_STRICT));
-}
-
-#ifdef CONFIG_BIGNUM
-static inline BOOL is_math_mode(JSContext *ctx)
-{
-    JSStackFrame *sf = ctx->rt->current_stack_frame;
-    return (sf && (sf->js_mode & JS_MODE_MATH));
-}
-#endif
-
-/* JSAtom support */
-
-#define JS_ATOM_TAG_INT (1U << 31)
-#define JS_ATOM_MAX_INT (JS_ATOM_TAG_INT - 1)
-#define JS_ATOM_MAX     ((1U << 30) - 1)
-
-/* return the max count from the hash size */
-#define JS_ATOM_COUNT_RESIZE(n) ((n) * 2)
-
-static inline BOOL __JS_AtomIsConst(JSAtom v)
-{
-#if defined(DUMP_LEAKS) && DUMP_LEAKS > 1
-        return (int32_t)v <= 0;
-#else
-        return (int32_t)v < JS_ATOM_END;
-#endif
-}
-
-static inline BOOL __JS_AtomIsTaggedInt(JSAtom v)
-{
-    return (v & JS_ATOM_TAG_INT) != 0;
-}
-
-static inline JSAtom __JS_AtomFromUInt32(uint32_t v)
-{
-    return v | JS_ATOM_TAG_INT;
-}
-
-static inline uint32_t __JS_AtomToUInt32(JSAtom atom)
-{
-    return atom & ~JS_ATOM_TAG_INT;
-}
-
-static inline int is_num(int c)
-{
-    return c >= '0' && c <= '9';
-}
-
-/* return TRUE if the string is a number n with 0 <= n <= 2^32-1 */
-static inline BOOL is_num_string(uint32_t *pval, const JSString *p)
-{
-    uint32_t n;
-    uint64_t n64;
-    int c, i, len;
-
-    len = p->len;
-    if (len == 0 || len > 10)
-        return FALSE;
-    if (p->is_wide_char)
-        c = p->u.str16[0];
-    else
-        c = p->u.str8[0];
-    if (is_num(c)) {
-        if (c == '0') {
-            if (len != 1)
-                return FALSE;
-            n = 0;
-        } else {
-            n = c - '0';
-            for(i = 1; i < len; i++) {
-                if (p->is_wide_char)
-                    c = p->u.str16[i];
-                else
-                    c = p->u.str8[i];
-                if (!is_num(c))
-                    return FALSE;
-                n64 = (uint64_t)n * 10 + (c - '0');
-                if ((n64 >> 32) != 0)
-                    return FALSE;
-                n = n64;
-            }
-        }
-        *pval = n;
-        return TRUE;
-    } else {
-        return FALSE;
-    }
-}
-
-/* XXX: could use faster version ? */
-static inline uint32_t hash_string8(const uint8_t *str, size_t len, uint32_t h)
-{
-    size_t i;
-
-    for(i = 0; i < len; i++)
-        h = h * 263 + str[i];
-    return h;
-}
-
-static inline uint32_t hash_string16(const uint16_t *str,
-                                     size_t len, uint32_t h)
-{
-    size_t i;
-
-    for(i = 0; i < len; i++)
-        h = h * 263 + str[i];
-    return h;
-}
-
-static uint32_t hash_string(const JSString *str, uint32_t h)
-{
-    if (str->is_wide_char)
-        h = hash_string16(str->u.str16, str->len, h);
-    else
-        h = hash_string8(str->u.str8, str->len, h);
-    return h;
-}
-
-static __maybe_unused void JS_DumpString(JSRuntime *rt,
-                                                  const JSString *p)
-{
-    int i, c, sep;
-
-    if (p == NULL) {
-        printf("<null>");
-        return;
-    }
-    printf("%d", p->header.ref_count);
-    sep = (p->header.ref_count == 1) ? '\"' : '\'';
-    putchar(sep);
-    for(i = 0; i < p->len; i++) {
-        if (p->is_wide_char)
-            c = p->u.str16[i];
-        else
-            c = p->u.str8[i];
-        if (c == sep || c == '\\') {
-            putchar('\\');
-            putchar(c);
-        } else if (c >= ' ' && c <= 126) {
-            putchar(c);
-        } else if (c == '\n') {
-            putchar('\\');
-            putchar('n');
-        } else {
-            printf("\\u%04x", c);
-        }
-    }
-    putchar(sep);
-}
-
-static __maybe_unused void JS_DumpAtoms(JSRuntime *rt)
-{
-    JSAtomStruct *p;
-    int h, i;
-    /* This only dumps hashed atoms, not JS_ATOM_TYPE_SYMBOL atoms */
-    printf("JSAtom count=%d size=%d hash_size=%d:\n",
-           rt->atom_count, rt->atom_size, rt->atom_hash_size);
-    printf("JSAtom hash table: {\n");
-    for(i = 0; i < rt->atom_hash_size; i++) {
-        h = rt->atom_hash[i];
-        if (h) {
-            printf("  %d:", i);
-            while (h) {
-                p = rt->atom_array[h];
-                printf(" ");
-                JS_DumpString(rt, p);
-                h = p->hash_next;
-            }
-            printf("\n");
-        }
-    }
-    printf("}\n");
-    printf("JSAtom table: {\n");
-    for(i = 0; i < rt->atom_size; i++) {
-        p = rt->atom_array[i];
-        if (!atom_is_free(p)) {
-            printf("  %d: { %d %08x ", i, p->atom_type, p->hash);
-            if (!(p->len == 0 && p->is_wide_char != 0))
-                JS_DumpString(rt, p);
-            printf(" %d }\n", p->hash_next);
-        }
-    }
-    printf("}\n");
-}
-
-static int JS_ResizeAtomHash(JSRuntime *rt, int new_hash_size)
-{
-    JSAtomStruct *p;
-    uint32_t new_hash_mask, h, i, hash_next1, j, *new_hash;
-
-    assert((new_hash_size & (new_hash_size - 1)) == 0); /* power of two */
-    new_hash_mask = new_hash_size - 1;
-    new_hash = js_mallocz_rt(rt, sizeof(rt->atom_hash[0]) * new_hash_size);
-    if (!new_hash)
-        return -1;
-    for(i = 0; i < rt->atom_hash_size; i++) {
-        h = rt->atom_hash[i];
-        while (h != 0) {
-            p = rt->atom_array[h];
-            hash_next1 = p->hash_next;
-            /* add in new hash table */
-            j = p->hash & new_hash_mask;
-            p->hash_next = new_hash[j];
-            new_hash[j] = h;
-            h = hash_next1;
-        }
-    }
-    js_free_rt(rt, rt->atom_hash);
-    rt->atom_hash = new_hash;
-    rt->atom_hash_size = new_hash_size;
-    rt->atom_count_resize = JS_ATOM_COUNT_RESIZE(new_hash_size);
-    //    JS_DumpAtoms(rt);
-    return 0;
-}
-
-static int JS_InitAtoms(JSRuntime *rt)
-{
-    int i, len, atom_type;
-    const char *p;
-
-    rt->atom_hash_size = 0;
-    rt->atom_hash = NULL;
-    rt->atom_count = 0;
-    rt->atom_size = 0;
-    rt->atom_free_index = 0;
-    if (JS_ResizeAtomHash(rt, 256))     /* there are at least 195 predefined atoms */
-        return -1;
-
-    p = js_atom_init;
-    for(i = 1; i < JS_ATOM_END; i++) {
-        if (i == JS_ATOM_Private_brand)
-            atom_type = JS_ATOM_TYPE_PRIVATE;
-        else if (i >= JS_ATOM_Symbol_toPrimitive)
-            atom_type = JS_ATOM_TYPE_SYMBOL;
-        else
-            atom_type = JS_ATOM_TYPE_STRING;
-        len = strlen(p);
-        if (__JS_NewAtomInit(rt, p, len, atom_type) == JS_ATOM_NULL)
-            return -1;
-        p = p + len + 1;
-    }
-    return 0;
-}
-
-static JSAtom JS_DupAtomRT(JSRuntime *rt, JSAtom v)
-{
-    JSAtomStruct *p;
-
-    if (!__JS_AtomIsConst(v)) {
-        p = rt->atom_array[v];
-        p->header.ref_count++;
-    }
-    return v;
-}
-
-JSAtom JS_DupAtom(JSContext *ctx, JSAtom v)
-{
-    JSRuntime *rt;
-    JSAtomStruct *p;
-
-    if (!__JS_AtomIsConst(v)) {
-        rt = ctx->rt;
-        p = rt->atom_array[v];
-        p->header.ref_count++;
-    }
-    return v;
-}
-
-static JSAtomKindEnum JS_AtomGetKind(JSContext *ctx, JSAtom v)
-{
-    JSRuntime *rt;
-    JSAtomStruct *p;
-
-    rt = ctx->rt;
-    if (__JS_AtomIsTaggedInt(v))
-        return JS_ATOM_KIND_STRING;
-    p = rt->atom_array[v];
-    switch(p->atom_type) {
-    case JS_ATOM_TYPE_STRING:
-        return JS_ATOM_KIND_STRING;
-    case JS_ATOM_TYPE_GLOBAL_SYMBOL:
-        return JS_ATOM_KIND_SYMBOL;
-    case JS_ATOM_TYPE_SYMBOL:
-        switch(p->hash) {
-        case JS_ATOM_HASH_SYMBOL:
-            return JS_ATOM_KIND_SYMBOL;
-        case JS_ATOM_HASH_PRIVATE:
-            return JS_ATOM_KIND_PRIVATE;
-        default:
-            abort();
-        }
-    default:
-        abort();
-    }
-}
-
-static BOOL JS_AtomIsString(JSContext *ctx, JSAtom v)
-{
-    return JS_AtomGetKind(ctx, v) == JS_ATOM_KIND_STRING;
-}
-
-static JSAtom js_get_atom_index(JSRuntime *rt, JSAtomStruct *p)
-{
-    uint32_t i = p->hash_next;  /* atom_index */
-    if (p->atom_type != JS_ATOM_TYPE_SYMBOL) {
-        JSAtomStruct *p1;
-
-        i = rt->atom_hash[p->hash & (rt->atom_hash_size - 1)];
-        p1 = rt->atom_array[i];
-        while (p1 != p) {
-            assert(i != 0);
-            i = p1->hash_next;
-            p1 = rt->atom_array[i];
-        }
-    }
-    return i;
-}
-
-/* string case (internal). Return JS_ATOM_NULL if error. 'str' is
-   freed. */
-static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type)
-{
-    uint32_t h, h1, i;
-    JSAtomStruct *p;
-    int len;
-
-#if 0
-    printf("__JS_NewAtom: ");  JS_DumpString(rt, str); printf("\n");
-#endif
-    if (atom_type < JS_ATOM_TYPE_SYMBOL) {
-        /* str is not NULL */
-        if (str->atom_type == atom_type) {
-            /* str is the atom, return its index */
-            i = js_get_atom_index(rt, str);
-            /* reduce string refcount and increase atom's unless constant */
-            if (__JS_AtomIsConst(i))
-                str->header.ref_count--;
-            return i;
-        }
-        /* try and locate an already registered atom */
-        len = str->len;
-        h = hash_string(str, atom_type);
-        h &= JS_ATOM_HASH_MASK;
-        h1 = h & (rt->atom_hash_size - 1);
-        i = rt->atom_hash[h1];
-        while (i != 0) {
-            p = rt->atom_array[i];
-            if (p->hash == h &&
-                p->atom_type == atom_type &&
-                p->len == len &&
-                js_string_memcmp(p, str, len) == 0) {
-                if (!__JS_AtomIsConst(i))
-                    p->header.ref_count++;
-                goto done;
-            }
-            i = p->hash_next;
-        }
-    } else {
-        h1 = 0; /* avoid warning */
-        if (atom_type == JS_ATOM_TYPE_SYMBOL) {
-            h = JS_ATOM_HASH_SYMBOL;
-        } else {
-            h = JS_ATOM_HASH_PRIVATE;
-            atom_type = JS_ATOM_TYPE_SYMBOL;
-        }
-    }
-
-    if (rt->atom_free_index == 0) {
-        /* allow new atom entries */
-        uint32_t new_size, start;
-        JSAtomStruct **new_array;
-
-        /* alloc new with size progression 3/2:
-           4 6 9 13 19 28 42 63 94 141 211 316 474 711 1066 1599 2398 3597 5395 8092
-           preallocating space for predefined atoms (at least 195).
-         */
-        new_size = max_int(211, rt->atom_size * 3 / 2);
-        if (new_size > JS_ATOM_MAX)
-            goto fail;
-        /* XXX: should use realloc2 to use slack space */
-        new_array = js_realloc_rt(rt, rt->atom_array, sizeof(*new_array) * new_size);
-        if (!new_array)
-            goto fail;
-        /* Note: the atom 0 is not used */
-        start = rt->atom_size;
-        if (start == 0) {
-            /* JS_ATOM_NULL entry */
-            p = js_mallocz_rt(rt, sizeof(JSAtomStruct));
-            if (!p) {
-                js_free_rt(rt, new_array);
-                goto fail;
-            }
-            p->header.ref_count = 1;  /* not refcounted */
-            p->atom_type = JS_ATOM_TYPE_SYMBOL;
-#ifdef DUMP_LEAKS
-            list_add_tail(&p->link, &rt->string_list);
-#endif
-            new_array[0] = p;
-            rt->atom_count++;
-            start = 1;
-        }
-        rt->atom_size = new_size;
-        rt->atom_array = new_array;
-        rt->atom_free_index = start;
-        for(i = start; i < new_size; i++) {
-            uint32_t next;
-            if (i == (new_size - 1))
-                next = 0;
-            else
-                next = i + 1;
-            rt->atom_array[i] = atom_set_free(next);
-        }
-    }
-
-    if (str) {
-        if (str->atom_type == 0) {
-            p = str;
-            p->atom_type = atom_type;
-        } else {
-            p = js_malloc_rt(rt, sizeof(JSString) +
-                             (str->len << str->is_wide_char) +
-                             1 - str->is_wide_char);
-            if (unlikely(!p))
-                goto fail;
-            p->header.ref_count = 1;
-            p->is_wide_char = str->is_wide_char;
-            p->len = str->len;
-#ifdef DUMP_LEAKS
-            list_add_tail(&p->link, &rt->string_list);
-#endif
-            memcpy(p->u.str8, str->u.str8, (str->len << str->is_wide_char) +
-                   1 - str->is_wide_char);
-            js_free_string(rt, str);
-        }
-    } else {
-        p = js_malloc_rt(rt, sizeof(JSAtomStruct)); /* empty wide string */
-        if (!p)
-            return JS_ATOM_NULL;
-        p->header.ref_count = 1;
-        p->is_wide_char = 1;    /* Hack to represent NULL as a JSString */
-        p->len = 0;
-#ifdef DUMP_LEAKS
-        list_add_tail(&p->link, &rt->string_list);
-#endif
-    }
-
-    /* use an already free entry */
-    i = rt->atom_free_index;
-    rt->atom_free_index = atom_get_free(rt->atom_array[i]);
-    rt->atom_array[i] = p;
-
-    p->hash = h;
-    p->hash_next = i;   /* atom_index */
-    p->atom_type = atom_type;
-
-    rt->atom_count++;
-
-    if (atom_type != JS_ATOM_TYPE_SYMBOL) {
-        p->hash_next = rt->atom_hash[h1];
-        rt->atom_hash[h1] = i;
-        if (unlikely(rt->atom_count >= rt->atom_count_resize))
-            JS_ResizeAtomHash(rt, rt->atom_hash_size * 2);
-    }
-
-    //    JS_DumpAtoms(rt);
-    return i;
-
- fail:
-    i = JS_ATOM_NULL;
- done:
-    if (str)
-        js_free_string(rt, str);
-    return i;
-}
-
-/* only works with zero terminated 8 bit strings */
-static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
-                               int atom_type)
-{
-    JSString *p;
-    p = js_alloc_string_rt(rt, len, 0);
-    if (!p)
-        return JS_ATOM_NULL;
-    memcpy(p->u.str8, str, len);
-    p->u.str8[len] = '\0';
-    return __JS_NewAtom(rt, p, atom_type);
-}
-
-static JSAtom __JS_FindAtom(JSRuntime *rt, const char *str, size_t len,
-                            int atom_type)
-{
-    uint32_t h, h1, i;
-    JSAtomStruct *p;
-
-    h = hash_string8((const uint8_t *)str, len, JS_ATOM_TYPE_STRING);
-    h &= JS_ATOM_HASH_MASK;
-    h1 = h & (rt->atom_hash_size - 1);
-    i = rt->atom_hash[h1];
-    while (i != 0) {
-        p = rt->atom_array[i];
-        if (p->hash == h &&
-            p->atom_type == JS_ATOM_TYPE_STRING &&
-            p->len == len &&
-            p->is_wide_char == 0 &&
-            memcmp(p->u.str8, str, len) == 0) {
-            if (!__JS_AtomIsConst(i))
-                p->header.ref_count++;
-            return i;
-        }
-        i = p->hash_next;
-    }
-    return JS_ATOM_NULL;
-}
-
-static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p)
-{
-#if 0   /* JS_ATOM_NULL is not refcounted: __JS_AtomIsConst() includes 0 */
-    if (unlikely(i == JS_ATOM_NULL)) {
-        p->header.ref_count = INT32_MAX / 2;
-        return;
-    }
-#endif
-    uint32_t i = p->hash_next;  /* atom_index */
-    if (p->atom_type != JS_ATOM_TYPE_SYMBOL) {
-        JSAtomStruct *p0, *p1;
-        uint32_t h0;
-
-        h0 = p->hash & (rt->atom_hash_size - 1);
-        i = rt->atom_hash[h0];
-        p1 = rt->atom_array[i];
-        if (p1 == p) {
-            rt->atom_hash[h0] = p1->hash_next;
-        } else {
-            for(;;) {
-                assert(i != 0);
-                p0 = p1;
-                i = p1->hash_next;
-                p1 = rt->atom_array[i];
-                if (p1 == p) {
-                    p0->hash_next = p1->hash_next;
-                    break;
-                }
-            }
-        }
-    }
-    /* insert in free atom list */
-    rt->atom_array[i] = atom_set_free(rt->atom_free_index);
-    rt->atom_free_index = i;
-    /* free the string structure */
-#ifdef DUMP_LEAKS
-    list_del(&p->link);
-#endif
-    js_free_rt(rt, p);
-    rt->atom_count--;
-    assert(rt->atom_count >= 0);
-}
-
-static void __JS_FreeAtom(JSRuntime *rt, uint32_t i)
-{
-    JSAtomStruct *p;
-
-    p = rt->atom_array[i];
-    if (--p->header.ref_count > 0)
-        return;
-    JS_FreeAtomStruct(rt, p);
-}
-
-/* Warning: 'p' is freed */
-static JSAtom JS_NewAtomStr(JSContext *ctx, JSString *p)
-{
-    JSRuntime *rt = ctx->rt;
-    uint32_t n;
-    if (is_num_string(&n, p)) {
-        if (n <= JS_ATOM_MAX_INT) {
-            js_free_string(rt, p);
-            return __JS_AtomFromUInt32(n);
-        }
-    }
-    /* XXX: should generate an exception */
-    return __JS_NewAtom(rt, p, JS_ATOM_TYPE_STRING);
-}
-
-JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len)
-{
-    JSValue val;
-
-    if (len == 0 || !is_digit(*str)) {
-        JSAtom atom = __JS_FindAtom(ctx->rt, str, len, JS_ATOM_TYPE_STRING);
-        if (atom)
-            return atom;
-    }
-    val = JS_NewStringLen(ctx, str, len);
-    if (JS_IsException(val))
-        return JS_ATOM_NULL;
-    return JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(val));
-}
-
-JSAtom JS_NewAtom(JSContext *ctx, const char *str)
-{
-    return JS_NewAtomLen(ctx, str, strlen(str));
-}
-
-JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n)
-{
-    if (n <= JS_ATOM_MAX_INT) {
-        return __JS_AtomFromUInt32(n);
-    } else {
-        char buf[11];
-        JSValue val;
-        snprintf(buf, sizeof(buf), "%u", n);
-        val = JS_NewString(ctx, buf);
-        if (JS_IsException(val))
-            return JS_ATOM_NULL;
-        return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),
-                            JS_ATOM_TYPE_STRING);
-    }
-}
-
-static JSAtom JS_NewAtomInt64(JSContext *ctx, int64_t n)
-{
-    if ((uint64_t)n <= JS_ATOM_MAX_INT) {
-        return __JS_AtomFromUInt32((uint32_t)n);
-    } else {
-        char buf[24];
-        JSValue val;
-        snprintf(buf, sizeof(buf), "%" PRId64 , n);
-        val = JS_NewString(ctx, buf);
-        if (JS_IsException(val))
-            return JS_ATOM_NULL;
-        return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),
-                            JS_ATOM_TYPE_STRING);
-    }
-}
-
-/* 'p' is freed */
-static JSValue JS_NewSymbol(JSContext *ctx, JSString *p, int atom_type)
-{
-    JSRuntime *rt = ctx->rt;
-    JSAtom atom;
-    atom = __JS_NewAtom(rt, p, atom_type);
-    if (atom == JS_ATOM_NULL)
-        return JS_ThrowOutOfMemory(ctx);
-    return JS_MKPTR(JS_TAG_SYMBOL, rt->atom_array[atom]);
-}
-
-/* descr must be a non-numeric string atom */
-static JSValue JS_NewSymbolFromAtom(JSContext *ctx, JSAtom descr,
-                                    int atom_type)
-{
-    JSRuntime *rt = ctx->rt;
-    JSString *p;
-
-    assert(!__JS_AtomIsTaggedInt(descr));
-    assert(descr < rt->atom_size);
-    p = rt->atom_array[descr];
-    JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
-    return JS_NewSymbol(ctx, p, atom_type);
-}
-
-#define ATOM_GET_STR_BUF_SIZE 64
-
-/* Should only be used for debug. */
-static const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size,
-                                   JSAtom atom)
-{
-    if (__JS_AtomIsTaggedInt(atom)) {
-        snprintf(buf, buf_size, "%u", __JS_AtomToUInt32(atom));
-    } else {
-        JSAtomStruct *p;
-        assert(atom < rt->atom_size);
-        if (atom == JS_ATOM_NULL) {
-            snprintf(buf, buf_size, "<null>");
-        } else {
-            int i, c;
-            char *q;
-            JSString *str;
-
-            q = buf;
-            p = rt->atom_array[atom];
-            assert(!atom_is_free(p));
-            str = p;
-            if (str) {
-                if (!str->is_wide_char) {
-                    /* special case ASCII strings */
-                    c = 0;
-                    for(i = 0; i < str->len; i++) {
-                        c |= str->u.str8[i];
-                    }
-                    if (c < 0x80)
-                        return (const char *)str->u.str8;
-                }
-                for(i = 0; i < str->len; i++) {
-                    if (str->is_wide_char)
-                        c = str->u.str16[i];
-                    else
-                        c = str->u.str8[i];
-                    if ((q - buf) >= buf_size - UTF8_CHAR_LEN_MAX)
-                        break;
-                    if (c < 128) {
-                        *q++ = c;
-                    } else {
-                        q += unicode_to_utf8((uint8_t *)q, c);
-                    }
-                }
-            }
-            *q = '\0';
-        }
-    }
-    return buf;
-}
-
-static const char *JS_AtomGetStr(JSContext *ctx, char *buf, int buf_size, JSAtom atom)
-{
-    return JS_AtomGetStrRT(ctx->rt, buf, buf_size, atom);
-}
-
-static JSValue __JS_AtomToValue(JSContext *ctx, JSAtom atom, BOOL force_string)
-{
-    char buf[ATOM_GET_STR_BUF_SIZE];
-
-    if (__JS_AtomIsTaggedInt(atom)) {
-        snprintf(buf, sizeof(buf), "%u", __JS_AtomToUInt32(atom));
-        return JS_NewString(ctx, buf);
-    } else {
-        JSRuntime *rt = ctx->rt;
-        JSAtomStruct *p;
-        assert(atom < rt->atom_size);
-        p = rt->atom_array[atom];
-        if (p->atom_type == JS_ATOM_TYPE_STRING) {
-            goto ret_string;
-        } else if (force_string) {
-            if (p->len == 0 && p->is_wide_char != 0) {
-                /* no description string */
-                p = rt->atom_array[JS_ATOM_empty_string];
-            }
-        ret_string:
-            return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
-        } else {
-            return JS_DupValue(ctx, JS_MKPTR(JS_TAG_SYMBOL, p));
-        }
-    }
-}
-
-JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom)
-{
-    return __JS_AtomToValue(ctx, atom, FALSE);
-}
-
-JSValue JS_AtomToString(JSContext *ctx, JSAtom atom)
-{
-    return __JS_AtomToValue(ctx, atom, TRUE);
-}
-
-/* return TRUE if the atom is an array index (i.e. 0 <= index <=
-   2^32-2 and return its value */
-static BOOL JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom)
-{
-    if (__JS_AtomIsTaggedInt(atom)) {
-        *pval = __JS_AtomToUInt32(atom);
-        return TRUE;
-    } else {
-        JSRuntime *rt = ctx->rt;
-        JSAtomStruct *p;
-        uint32_t val;
-
-        assert(atom < rt->atom_size);
-        p = rt->atom_array[atom];
-        if (p->atom_type == JS_ATOM_TYPE_STRING &&
-            is_num_string(&val, p) && val != -1) {
-            *pval = val;
-            return TRUE;
-        } else {
-            *pval = 0;
-            return FALSE;
-        }
-    }
-}
-
-/* This test must be fast if atom is not a numeric index (e.g. a
-   method name). Return JS_UNDEFINED if not a numeric
-   index. JS_EXCEPTION can also be returned. */
-static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom)
-{
-    JSRuntime *rt = ctx->rt;
-    JSAtomStruct *p1;
-    JSString *p;
-    int c, len, ret;
-    JSValue num, str;
-
-    if (__JS_AtomIsTaggedInt(atom))
-        return JS_NewInt32(ctx, __JS_AtomToUInt32(atom));
-    assert(atom < rt->atom_size);
-    p1 = rt->atom_array[atom];
-    if (p1->atom_type != JS_ATOM_TYPE_STRING)
-        return JS_UNDEFINED;
-    p = p1;
-    len = p->len;
-    if (p->is_wide_char) {
-        const uint16_t *r = p->u.str16, *r_end = p->u.str16 + len;
-        if (r >= r_end)
-            return JS_UNDEFINED;
-        c = *r;
-        if (c == '-') {
-            if (r >= r_end)
-                return JS_UNDEFINED;
-            r++;
-            c = *r;
-            /* -0 case is specific */
-            if (c == '0' && len == 2)
-                goto minus_zero;
-        }
-        /* XXX: should test NaN, but the tests do not check it */
-        if (!is_num(c)) {
-            /* XXX: String should be normalized, therefore 8-bit only */
-            const uint16_t nfinity16[7] = { 'n', 'f', 'i', 'n', 'i', 't', 'y' };
-            if (!(c =='I' && (r_end - r) == 8 &&
-                  !memcmp(r + 1, nfinity16, sizeof(nfinity16))))
-                return JS_UNDEFINED;
-        }
-    } else {
-        const uint8_t *r = p->u.str8, *r_end = p->u.str8 + len;
-        if (r >= r_end)
-            return JS_UNDEFINED;
-        c = *r;
-        if (c == '-') {
-            if (r >= r_end)
-                return JS_UNDEFINED;
-            r++;
-            c = *r;
-            /* -0 case is specific */
-            if (c == '0' && len == 2) {
-            minus_zero:
-                return __JS_NewFloat64(ctx, -0.0);
-            }
-        }
-        if (!is_num(c)) {
-            if (!(c =='I' && (r_end - r) == 8 &&
-                  !memcmp(r + 1, "nfinity", 7)))
-                return JS_UNDEFINED;
-        }
-    }
-    /* XXX: bignum: would be better to only accept integer to avoid
-       relying on current floating point precision */
-    /* this is ECMA CanonicalNumericIndexString primitive */
-    num = JS_ToNumber(ctx, JS_MKPTR(JS_TAG_STRING, p));
-    if (JS_IsException(num))
-        return num;
-    str = JS_ToString(ctx, num);
-    if (JS_IsException(str)) {
-        JS_FreeValue(ctx, num);
-        return str;
-    }
-    ret = js_string_compare(ctx, p, JS_VALUE_GET_STRING(str));
-    JS_FreeValue(ctx, str);
-    if (ret == 0) {
-        return num;
-    } else {
-        JS_FreeValue(ctx, num);
-        return JS_UNDEFINED;
-    }
-}
-
-/* return -1 if exception or TRUE/FALSE */
-static int JS_AtomIsNumericIndex(JSContext *ctx, JSAtom atom)
-{
-    JSValue num;
-    num = JS_AtomIsNumericIndex1(ctx, atom);
-    if (likely(JS_IsUndefined(num)))
-        return FALSE;
-    if (JS_IsException(num))
-        return -1;
-    JS_FreeValue(ctx, num);
-    return TRUE;
-}
-
-void JS_FreeAtom(JSContext *ctx, JSAtom v)
-{
-    if (!__JS_AtomIsConst(v))
-        __JS_FreeAtom(ctx->rt, v);
-}
-
-void JS_FreeAtomRT(JSRuntime *rt, JSAtom v)
-{
-    if (!__JS_AtomIsConst(v))
-        __JS_FreeAtom(rt, v);
-}
-
-/* return TRUE if 'v' is a symbol with a string description */
-static BOOL JS_AtomSymbolHasDescription(JSContext *ctx, JSAtom v)
-{
-    JSRuntime *rt;
-    JSAtomStruct *p;
-
-    rt = ctx->rt;
-    if (__JS_AtomIsTaggedInt(v))
-        return FALSE;
-    p = rt->atom_array[v];
-    return (((p->atom_type == JS_ATOM_TYPE_SYMBOL &&
-              p->hash == JS_ATOM_HASH_SYMBOL) ||
-             p->atom_type == JS_ATOM_TYPE_GLOBAL_SYMBOL) &&
-            !(p->len == 0 && p->is_wide_char != 0));
-}
-
-static __maybe_unused void print_atom(JSContext *ctx, JSAtom atom)
-{
-    char buf[ATOM_GET_STR_BUF_SIZE];
-    const char *p;
-    int i;
-
-    /* XXX: should handle embedded null characters */
-    /* XXX: should move encoding code to JS_AtomGetStr */
-    p = JS_AtomGetStr(ctx, buf, sizeof(buf), atom);
-    for (i = 0; p[i]; i++) {
-        int c = (unsigned char)p[i];
-        if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
-              (c == '_' || c == '$') || (c >= '0' && c <= '9' && i > 0)))
-            break;
-    }
-    if (i > 0 && p[i] == '\0') {
-        printf("%s", p);
-    } else {
-        putchar('"');
-        printf("%.*s", i, p);
-        for (; p[i]; i++) {
-            int c = (unsigned char)p[i];
-            if (c == '\"' || c == '\\') {
-                putchar('\\');
-                putchar(c);
-            } else if (c >= ' ' && c <= 126) {
-                putchar(c);
-            } else if (c == '\n') {
-                putchar('\\');
-                putchar('n');
-            } else {
-                printf("\\u%04x", c);
-            }
-        }
-        putchar('\"');
-    }
-}
-
-/* free with JS_FreeCString() */
-const char *JS_AtomToCString(JSContext *ctx, JSAtom atom)
-{
-    JSValue str;
-    const char *cstr;
-
-    str = JS_AtomToString(ctx, atom);
-    if (JS_IsException(str))
-        return NULL;
-    cstr = JS_ToCString(ctx, str);
-    JS_FreeValue(ctx, str);
-    return cstr;
-}
-
-/* return a string atom containing name concatenated with str1 */
-static JSAtom js_atom_concat_str(JSContext *ctx, JSAtom name, const char *str1)
-{
-    JSValue str;
-    JSAtom atom;
-    const char *cstr;
-    char *cstr2;
-    size_t len, len1;
-    
-    str = JS_AtomToString(ctx, name);
-    if (JS_IsException(str))
-        return JS_ATOM_NULL;
-    cstr = JS_ToCStringLen(ctx, &len, str);
-    if (!cstr)
-        goto fail;
-    len1 = strlen(str1);
-    cstr2 = js_malloc(ctx, len + len1 + 1);
-    if (!cstr2)
-        goto fail;
-    memcpy(cstr2, cstr, len);
-    memcpy(cstr2 + len, str1, len1);
-    cstr2[len + len1] = '\0';
-    atom = JS_NewAtomLen(ctx, cstr2, len + len1);
-    js_free(ctx, cstr2);
-    JS_FreeCString(ctx, cstr);
-    JS_FreeValue(ctx, str);
-    return atom;
- fail:
-    JS_FreeCString(ctx, cstr);
-    JS_FreeValue(ctx, str);
-    return JS_ATOM_NULL;
-}
-
-static JSAtom js_atom_concat_num(JSContext *ctx, JSAtom name, uint32_t n)
-{
-    char buf[16];
-    snprintf(buf, sizeof(buf), "%u", n);
-    return js_atom_concat_str(ctx, name, buf);
-}
-
-static inline BOOL JS_IsEmptyString(JSValueConst v)
-{
-    return JS_VALUE_GET_TAG(v) == JS_TAG_STRING && JS_VALUE_GET_STRING(v)->len == 0;
-}
-
-/* JSClass support */
-
-/* a new class ID is allocated if *pclass_id != 0 */
-JSClassID JS_NewClassID(JSClassID *pclass_id)
-{
-    JSClassID class_id;
-    /* XXX: make it thread safe */
-    class_id = *pclass_id;
-    if (class_id == 0) {
-        class_id = js_class_id_alloc++;
-        *pclass_id = class_id;
-    }
-    return class_id;
-}
-
-BOOL JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id)
-{
-    return (class_id < rt->class_count &&
-            rt->class_array[class_id].class_id != 0);
-}
-
-/* create a new object internal class. Return -1 if error, 0 if
-   OK. The finalizer can be NULL if none is needed. */
-static int JS_NewClass1(JSRuntime *rt, JSClassID class_id,
-                        const JSClassDef *class_def, JSAtom name)
-{
-    int new_size, i;
-    JSClass *cl, *new_class_array;
-    struct list_head *el;
-
-    if (class_id >= (1 << 16))
-        return -1;
-    if (class_id < rt->class_count &&
-        rt->class_array[class_id].class_id != 0)
-        return -1;
-
-    if (class_id >= rt->class_count) {
-        new_size = max_int(JS_CLASS_INIT_COUNT,
-                           max_int(class_id + 1, rt->class_count * 3 / 2));
-
-        /* reallocate the context class prototype array, if any */
-        list_for_each(el, &rt->context_list) {
-            JSContext *ctx = list_entry(el, JSContext, link);
-            JSValue *new_tab;
-            new_tab = js_realloc_rt(rt, ctx->class_proto,
-                                    sizeof(ctx->class_proto[0]) * new_size);
-            if (!new_tab)
-                return -1;
-            for(i = rt->class_count; i < new_size; i++)
-                new_tab[i] = JS_NULL;
-            ctx->class_proto = new_tab;
-        }
-        /* reallocate the class array */
-        new_class_array = js_realloc_rt(rt, rt->class_array,
-                                        sizeof(JSClass) * new_size);
-        if (!new_class_array)
-            return -1;
-        memset(new_class_array + rt->class_count, 0,
-               (new_size - rt->class_count) * sizeof(JSClass));
-        rt->class_array = new_class_array;
-        rt->class_count = new_size;
-    }
-    cl = &rt->class_array[class_id];
-    cl->class_id = class_id;
-    cl->class_name = JS_DupAtomRT(rt, name);
-    cl->finalizer = class_def->finalizer;
-    cl->gc_mark = class_def->gc_mark;
-    cl->call = class_def->call;
-    cl->exotic = class_def->exotic;
-    return 0;
-}
-
-int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def)
-{
-    int ret, len;
-    JSAtom name;
-
-    len = strlen(class_def->class_name);
-    name = __JS_FindAtom(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
-    if (name == JS_ATOM_NULL) {
-        name = __JS_NewAtomInit(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
-        if (name == JS_ATOM_NULL)
-            return -1;
-    }
-    ret = JS_NewClass1(rt, class_id, class_def, name);
-    JS_FreeAtomRT(rt, name);
-    return ret;
-}
-
-static JSValue js_new_string8(JSContext *ctx, const uint8_t *buf, int len)
-{
-    JSString *str;
-
-    if (len <= 0) {
-        return JS_AtomToString(ctx, JS_ATOM_empty_string);
-    }
-    str = js_alloc_string(ctx, len, 0);
-    if (!str)
-        return JS_EXCEPTION;
-    memcpy(str->u.str8, buf, len);
-    str->u.str8[len] = '\0';
-    return JS_MKPTR(JS_TAG_STRING, str);
-}
-
-static JSValue js_new_string16(JSContext *ctx, const uint16_t *buf, int len)
-{
-    JSString *str;
-    str = js_alloc_string(ctx, len, 1);
-    if (!str)
-        return JS_EXCEPTION;
-    memcpy(str->u.str16, buf, len * 2);
-    return JS_MKPTR(JS_TAG_STRING, str);
-}
-
-static JSValue js_new_string_char(JSContext *ctx, uint16_t c)
-{
-    if (c < 0x100) {
-        uint8_t ch8 = c;
-        return js_new_string8(ctx, &ch8, 1);
-    } else {
-        uint16_t ch16 = c;
-        return js_new_string16(ctx, &ch16, 1);
-    }
-}
-
-static JSValue js_sub_string(JSContext *ctx, JSString *p, int start, int end)
-{
-    int len = end - start;
-    if (start == 0 && end == p->len) {
-        return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
-    }
-    if (p->is_wide_char && len > 0) {
-        JSString *str;
-        int i;
-        uint16_t c = 0;
-        for (i = start; i < end; i++) {
-            c |= p->u.str16[i];
-        }
-        if (c > 0xFF)
-            return js_new_string16(ctx, p->u.str16 + start, len);
-
-        str = js_alloc_string(ctx, len, 0);
-        if (!str)
-            return JS_EXCEPTION;
-        for (i = 0; i < len; i++) {
-            str->u.str8[i] = p->u.str16[start + i];
-        }
-        str->u.str8[len] = '\0';
-        return JS_MKPTR(JS_TAG_STRING, str);
-    } else {
-        return js_new_string8(ctx, p->u.str8 + start, len);
-    }
-}
-
-typedef struct StringBuffer {
-    JSContext *ctx;
-    JSString *str;
-    int len;
-    int size;
-    int is_wide_char;
-    int error_status;
-} StringBuffer;
-
-/* It is valid to call string_buffer_end() and all string_buffer functions even
-   if string_buffer_init() or another string_buffer function returns an error.
-   If the error_status is set, string_buffer_end() returns JS_EXCEPTION.
- */
-static int string_buffer_init2(JSContext *ctx, StringBuffer *s, int size,
-                               int is_wide)
-{
-    s->ctx = ctx;
-    s->size = size;
-    s->len = 0;
-    s->is_wide_char = is_wide;
-    s->error_status = 0;
-    s->str = js_alloc_string(ctx, size, is_wide);
-    if (unlikely(!s->str)) {
-        s->size = 0;
-        return s->error_status = -1;
-    }
-#ifdef DUMP_LEAKS
-    /* the StringBuffer may reallocate the JSString, only link it at the end */
-    list_del(&s->str->link);
-#endif
-    return 0;
-}
-
-static inline int string_buffer_init(JSContext *ctx, StringBuffer *s, int size)
-{
-    return string_buffer_init2(ctx, s, size, 0);
-}
-
-static void string_buffer_free(StringBuffer *s)
-{
-    js_free(s->ctx, s->str);
-    s->str = NULL;
-}
-
-static int string_buffer_set_error(StringBuffer *s)
-{
-    js_free(s->ctx, s->str);
-    s->str = NULL;
-    s->size = 0;
-    s->len = 0;
-    return s->error_status = -1;
-}
-
-static no_inline int string_buffer_widen(StringBuffer *s, int size)
-{
-    JSString *str;
-    size_t slack;
-    int i;
-
-    if (s->error_status)
-        return -1;
-
-    str = js_realloc2(s->ctx, s->str, sizeof(JSString) + (size << 1), &slack);
-    if (!str)
-        return string_buffer_set_error(s);
-    size += slack >> 1;
-    for(i = s->len; i-- > 0;) {
-        str->u.str16[i] = str->u.str8[i];
-    }
-    s->is_wide_char = 1;
-    s->size = size;
-    s->str = str;
-    return 0;
-}
-
-static no_inline int string_buffer_realloc(StringBuffer *s, int new_len, int c)
-{
-    JSString *new_str;
-    int new_size;
-    size_t new_size_bytes, slack;
-
-    if (s->error_status)
-        return -1;
-
-    if (new_len > JS_STRING_LEN_MAX) {
-        JS_ThrowInternalError(s->ctx, "string too long");
-        return string_buffer_set_error(s);
-    }
-    new_size = min_int(max_int(new_len, s->size * 3 / 2), JS_STRING_LEN_MAX);
-    if (!s->is_wide_char && c >= 0x100) {
-        return string_buffer_widen(s, new_size);
-    }
-    new_size_bytes = sizeof(JSString) + (new_size << s->is_wide_char) + 1 - s->is_wide_char;
-    new_str = js_realloc2(s->ctx, s->str, new_size_bytes, &slack);
-    if (!new_str)
-        return string_buffer_set_error(s);
-    new_size = min_int(new_size + (slack >> s->is_wide_char), JS_STRING_LEN_MAX);
-    s->size = new_size;
-    s->str = new_str;
-    return 0;
-}
-
-static no_inline int string_buffer_putc_slow(StringBuffer *s, uint32_t c)
-{
-    if (unlikely(s->len >= s->size)) {
-        if (string_buffer_realloc(s, s->len + 1, c))
-            return -1;
-    }
-    if (s->is_wide_char) {
-        s->str->u.str16[s->len++] = c;
-    } else if (c < 0x100) {
-        s->str->u.str8[s->len++] = c;
-    } else {
-        if (string_buffer_widen(s, s->size))
-            return -1;
-        s->str->u.str16[s->len++] = c;
-    }
-    return 0;
-}
-
-/* 0 <= c <= 0xff */
-static int string_buffer_putc8(StringBuffer *s, uint32_t c)
-{
-    if (unlikely(s->len >= s->size)) {
-        if (string_buffer_realloc(s, s->len + 1, c))
-            return -1;
-    }
-    if (s->is_wide_char) {
-        s->str->u.str16[s->len++] = c;
-    } else {
-        s->str->u.str8[s->len++] = c;
-    }
-    return 0;
-}
-
-/* 0 <= c <= 0xffff */
-static int string_buffer_putc16(StringBuffer *s, uint32_t c)
-{
-    if (likely(s->len < s->size)) {
-        if (s->is_wide_char) {
-            s->str->u.str16[s->len++] = c;
-            return 0;
-        } else if (c < 0x100) {
-            s->str->u.str8[s->len++] = c;
-            return 0;
-        }
-    }
-    return string_buffer_putc_slow(s, c);
-}
-
-/* 0 <= c <= 0x10ffff */
-static int string_buffer_putc(StringBuffer *s, uint32_t c)
-{
-    if (unlikely(c >= 0x10000)) {
-        /* surrogate pair */
-        c -= 0x10000;
-        if (string_buffer_putc16(s, (c >> 10) + 0xd800))
-            return -1;
-        c = (c & 0x3ff) + 0xdc00;
-    }
-    return string_buffer_putc16(s, c);
-}
-
-static int string_get(const JSString *p, int idx) {
-    return p->is_wide_char ? p->u.str16[idx] : p->u.str8[idx];
-}
-
-static int string_getc(const JSString *p, int *pidx)
-{
-    int idx, c, c1;
-    idx = *pidx;
-    if (p->is_wide_char) {
-        c = p->u.str16[idx++];
-        if (c >= 0xd800 && c < 0xdc00 && idx < p->len) {
-            c1 = p->u.str16[idx];
-            if (c1 >= 0xdc00 && c1 < 0xe000) {
-                c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
-                idx++;
-            }
-        }
-    } else {
-        c = p->u.str8[idx++];
-    }
-    *pidx = idx;
-    return c;
-}
-
-static int string_buffer_write8(StringBuffer *s, const uint8_t *p, int len)
-{
-    int i;
-
-    if (s->len + len > s->size) {
-        if (string_buffer_realloc(s, s->len + len, 0))
-            return -1;
-    }
-    if (s->is_wide_char) {
-        for (i = 0; i < len; i++) {
-            s->str->u.str16[s->len + i] = p[i];
-        }
-        s->len += len;
-    } else {
-        memcpy(&s->str->u.str8[s->len], p, len);
-        s->len += len;
-    }
-    return 0;
-}
-
-static int string_buffer_write16(StringBuffer *s, const uint16_t *p, int len)
-{
-    int c = 0, i;
-
-    for (i = 0; i < len; i++) {
-        c |= p[i];
-    }
-    if (s->len + len > s->size) {
-        if (string_buffer_realloc(s, s->len + len, c))
-            return -1;
-    } else if (!s->is_wide_char && c >= 0x100) {
-        if (string_buffer_widen(s, s->size))
-            return -1;
-    }
-    if (s->is_wide_char) {
-        memcpy(&s->str->u.str16[s->len], p, len << 1);
-        s->len += len;
-    } else {
-        for (i = 0; i < len; i++) {
-            s->str->u.str8[s->len + i] = p[i];
-        }
-        s->len += len;
-    }
-    return 0;
-}
-
-/* appending an ASCII string */
-static int string_buffer_puts8(StringBuffer *s, const char *str)
-{
-    return string_buffer_write8(s, (const uint8_t *)str, strlen(str));
-}
-
-static int string_buffer_concat(StringBuffer *s, const JSString *p,
-                                uint32_t from, uint32_t to)
-{
-    if (to <= from)
-        return 0;
-    if (p->is_wide_char)
-        return string_buffer_write16(s, p->u.str16 + from, to - from);
-    else
-        return string_buffer_write8(s, p->u.str8 + from, to - from);
-}
-
-static int string_buffer_concat_value(StringBuffer *s, JSValueConst v)
-{
-    JSString *p;
-    JSValue v1;
-    int res;
-
-    if (s->error_status) {
-        /* prevent exception overload */
-        return -1;
-    }
-    if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) {
-        v1 = JS_ToString(s->ctx, v);
-        if (JS_IsException(v1))
-            return string_buffer_set_error(s);
-        p = JS_VALUE_GET_STRING(v1);
-        res = string_buffer_concat(s, p, 0, p->len);
-        JS_FreeValue(s->ctx, v1);
-        return res;
-    }
-    p = JS_VALUE_GET_STRING(v);
-    return string_buffer_concat(s, p, 0, p->len);
-}
-
-static int string_buffer_concat_value_free(StringBuffer *s, JSValue v)
-{
-    JSString *p;
-    int res;
-
-    if (s->error_status) {
-        /* prevent exception overload */
-        JS_FreeValue(s->ctx, v);
-        return -1;
-    }
-    if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) {
-        v = JS_ToStringFree(s->ctx, v);
-        if (JS_IsException(v))
-            return string_buffer_set_error(s);
-    }
-    p = JS_VALUE_GET_STRING(v);
-    res = string_buffer_concat(s, p, 0, p->len);
-    JS_FreeValue(s->ctx, v);
-    return res;
-}
-
-static int string_buffer_fill(StringBuffer *s, int c, int count)
-{
-    /* XXX: optimize */
-    if (s->len + count > s->size) {
-        if (string_buffer_realloc(s, s->len + count, c))
-            return -1;
-    }
-    while (count-- > 0) {
-        if (string_buffer_putc16(s, c))
-            return -1;
-    }
-    return 0;
-}
-
-static JSValue string_buffer_end(StringBuffer *s)
-{
-    JSString *str;
-    str = s->str;
-    if (s->error_status)
-        return JS_EXCEPTION;
-    if (s->len == 0) {
-        js_free(s->ctx, str);
-        s->str = NULL;
-        return JS_AtomToString(s->ctx, JS_ATOM_empty_string);
-    }
-    if (s->len < s->size) {
-        /* smaller size so js_realloc should not fail, but OK if it does */
-        /* XXX: should add some slack to avoid unnecessary calls */
-        /* XXX: might need to use malloc+free to ensure smaller size */
-        str = js_realloc_rt(s->ctx->rt, str, sizeof(JSString) +
-                            (s->len << s->is_wide_char) + 1 - s->is_wide_char);
-        if (str == NULL)
-            str = s->str;
-        s->str = str;
-    }
-    if (!s->is_wide_char)
-        str->u.str8[s->len] = 0;
-#ifdef DUMP_LEAKS
-    list_add_tail(&str->link, &s->ctx->rt->string_list);
-#endif
-    str->is_wide_char = s->is_wide_char;
-    str->len = s->len;
-    s->str = NULL;
-    return JS_MKPTR(JS_TAG_STRING, str);
-}
-
-/* create a string from a UTF-8 buffer */
-JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len)
-{
-    const uint8_t *p, *p_end, *p_start, *p_next;
-    uint32_t c;
-    StringBuffer b_s, *b = &b_s;
-    size_t len1;
-    
-    p_start = (const uint8_t *)buf;
-    p_end = p_start + buf_len;
-    p = p_start;
-    while (p < p_end && *p < 128)
-        p++;
-    len1 = p - p_start;
-    if (len1 > JS_STRING_LEN_MAX)
-        return JS_ThrowInternalError(ctx, "string too long");
-    if (p == p_end) {
-        /* ASCII string */
-        return js_new_string8(ctx, (const uint8_t *)buf, buf_len);
-    } else {
-        if (string_buffer_init(ctx, b, buf_len))
-            goto fail;
-        string_buffer_write8(b, p_start, len1);
-        while (p < p_end) {
-            if (*p < 128) {
-                string_buffer_putc8(b, *p++);
-            } else {
-                /* parse utf-8 sequence, return 0xFFFFFFFF for error */
-                c = unicode_from_utf8(p, p_end - p, &p_next);
-                if (c < 0x10000) {
-                    p = p_next;
-                } else if (c <= 0x10FFFF) {
-                    p = p_next;
-                    /* surrogate pair */
-                    c -= 0x10000;
-                    string_buffer_putc16(b, (c >> 10) + 0xd800);
-                    c = (c & 0x3ff) + 0xdc00;
-                } else {
-                    /* invalid char */
-                    c = 0xfffd;
-                    /* skip the invalid chars */
-                    /* XXX: seems incorrect. Why not just use c = *p++; ? */
-                    while (p < p_end && (*p >= 0x80 && *p < 0xc0))
-                        p++;
-                    if (p < p_end) {
-                        p++;
-                        while (p < p_end && (*p >= 0x80 && *p < 0xc0))
-                            p++;
-                    }
-                }
-                string_buffer_putc16(b, c);
-            }
-        }
-    }
-    return string_buffer_end(b);
-
- fail:
-    string_buffer_free(b);
-    return JS_EXCEPTION;
-}
-
-static JSValue JS_ConcatString3(JSContext *ctx, const char *str1,
-                                JSValue str2, const char *str3)
-{
-    StringBuffer b_s, *b = &b_s;
-    int len1, len3;
-    JSString *p;
-
-    if (unlikely(JS_VALUE_GET_TAG(str2) != JS_TAG_STRING)) {
-        str2 = JS_ToStringFree(ctx, str2);
-        if (JS_IsException(str2))
-            goto fail;
-    }
-    p = JS_VALUE_GET_STRING(str2);
-    len1 = strlen(str1);
-    len3 = strlen(str3);
-
-    if (string_buffer_init2(ctx, b, len1 + p->len + len3, p->is_wide_char))
-        goto fail;
-
-    string_buffer_write8(b, (const uint8_t *)str1, len1);
-    string_buffer_concat(b, p, 0, p->len);
-    string_buffer_write8(b, (const uint8_t *)str3, len3);
-
-    JS_FreeValue(ctx, str2);
-    return string_buffer_end(b);
-
- fail:
-    JS_FreeValue(ctx, str2);
-    return JS_EXCEPTION;
-}
-
-JSValue JS_NewString(JSContext *ctx, const char *str)
-{
-    return JS_NewStringLen(ctx, str, strlen(str));
-}
-
-JSValue JS_NewAtomString(JSContext *ctx, const char *str)
-{
-    JSAtom atom = JS_NewAtom(ctx, str);
-    if (atom == JS_ATOM_NULL)
-        return JS_EXCEPTION;
-    JSValue val = JS_AtomToString(ctx, atom);
-    JS_FreeAtom(ctx, atom);
-    return val;
-}
-
-/* return (NULL, 0) if exception. */
-/* return pointer into a JSString with a live ref_count */
-/* cesu8 determines if non-BMP1 codepoints are encoded as 1 or 2 utf-8 sequences */
-const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, BOOL cesu8)
-{
-    JSValue val;
-    JSString *str, *str_new;
-    int pos, len, c, c1;
-    uint8_t *q;
-
-    if (JS_VALUE_GET_TAG(val1) != JS_TAG_STRING) {
-        val = JS_ToString(ctx, val1);
-        if (JS_IsException(val))
-            goto fail;
-    } else {
-        val = JS_DupValue(ctx, val1);
-    }
-
-    str = JS_VALUE_GET_STRING(val);
-    len = str->len;
-    if (!str->is_wide_char) {
-        const uint8_t *src = str->u.str8;
-        int count;
-
-        /* count the number of non-ASCII characters */
-        /* Scanning the whole string is required for ASCII strings,
-           and computing the number of non-ASCII bytes is less expensive
-           than testing each byte, hence this method is faster for ASCII
-           strings, which is the most common case.
-         */
-        count = 0;
-        for (pos = 0; pos < len; pos++) {
-            count += src[pos] >> 7;
-        }
-        if (count == 0) {
-            if (plen)
-                *plen = len;
-            return (const char *)src;
-        }
-        str_new = js_alloc_string(ctx, len + count, 0);
-        if (!str_new)
-            goto fail;
-        q = str_new->u.str8;
-        for (pos = 0; pos < len; pos++) {
-            c = src[pos];
-            if (c < 0x80) {
-                *q++ = c;
-            } else {
-                *q++ = (c >> 6) | 0xc0;
-                *q++ = (c & 0x3f) | 0x80;
-            }
-        }
-    } else {
-        const uint16_t *src = str->u.str16;
-        /* Allocate 3 bytes per 16 bit code point. Surrogate pairs may
-           produce 4 bytes but use 2 code points.
-         */
-        str_new = js_alloc_string(ctx, len * 3, 0);
-        if (!str_new)
-            goto fail;
-        q = str_new->u.str8;
-        pos = 0;
-        while (pos < len) {
-            c = src[pos++];
-            if (c < 0x80) {
-                *q++ = c;
-            } else {
-                if (c >= 0xd800 && c < 0xdc00) {
-                    if (pos < len && !cesu8) {
-                        c1 = src[pos];
-                        if (c1 >= 0xdc00 && c1 < 0xe000) {
-                            pos++;
-                            /* surrogate pair */
-                            c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
-                        } else {
-                            /* Keep unmatched surrogate code points */
-                            /* c = 0xfffd; */ /* error */
-                        }
-                    } else {
-                        /* Keep unmatched surrogate code points */
-                        /* c = 0xfffd; */ /* error */
-                    }
-                }
-                q += unicode_to_utf8(q, c);
-            }
-        }
-    }
-
-    *q = '\0';
-    str_new->len = q - str_new->u.str8;
-    JS_FreeValue(ctx, val);
-    if (plen)
-        *plen = str_new->len;
-    return (const char *)str_new->u.str8;
- fail:
-    if (plen)
-        *plen = 0;
-    return NULL;
-}
-
-void JS_FreeCString(JSContext *ctx, const char *ptr)
-{
-    JSString *p;
-    if (!ptr)
-        return;
-    /* purposely removing constness */
-    p = (JSString *)(void *)(ptr - offsetof(JSString, u));
-    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
-}
-
-static int memcmp16_8(const uint16_t *src1, const uint8_t *src2, int len)
-{
-    int c, i;
-    for(i = 0; i < len; i++) {
-        c = src1[i] - src2[i];
-        if (c != 0)
-            return c;
-    }
-    return 0;
-}
-
-static int memcmp16(const uint16_t *src1, const uint16_t *src2, int len)
-{
-    int c, i;
-    for(i = 0; i < len; i++) {
-        c = src1[i] - src2[i];
-        if (c != 0)
-            return c;
-    }
-    return 0;
-}
-
-static int js_string_memcmp(const JSString *p1, const JSString *p2, int len)
-{
-    int res;
-
-    if (likely(!p1->is_wide_char)) {
-        if (likely(!p2->is_wide_char))
-            res = memcmp(p1->u.str8, p2->u.str8, len);
-        else
-            res = -memcmp16_8(p2->u.str16, p1->u.str8, len);
-    } else {
-        if (!p2->is_wide_char)
-            res = memcmp16_8(p1->u.str16, p2->u.str8, len);
-        else
-            res = memcmp16(p1->u.str16, p2->u.str16, len);
-    }
-    return res;
-}
-
-/* return < 0, 0 or > 0 */
-static int js_string_compare(JSContext *ctx,
-                             const JSString *p1, const JSString *p2)
-{
-    int res, len;
-    len = min_int(p1->len, p2->len);
-    res = js_string_memcmp(p1, p2, len);
-    if (res == 0) {
-        if (p1->len == p2->len)
-            res = 0;
-        else if (p1->len < p2->len)
-            res = -1;
-        else
-            res = 1;
-    }
-    return res;
-}
-
-static void copy_str16(uint16_t *dst, const JSString *p, int offset, int len)
-{
-    if (p->is_wide_char) {
-        memcpy(dst, p->u.str16 + offset, len * 2);
-    } else {
-        const uint8_t *src1 = p->u.str8 + offset;
-        int i;
-
-        for(i = 0; i < len; i++)
-            dst[i] = src1[i];
-    }
-}
-
-static JSValue JS_ConcatString1(JSContext *ctx,
-                                const JSString *p1, const JSString *p2)
-{
-    JSString *p;
-    uint32_t len;
-    int is_wide_char;
-
-    len = p1->len + p2->len;
-    if (len > JS_STRING_LEN_MAX)
-        return JS_ThrowInternalError(ctx, "string too long");
-    is_wide_char = p1->is_wide_char | p2->is_wide_char;
-    p = js_alloc_string(ctx, len, is_wide_char);
-    if (!p)
-        return JS_EXCEPTION;
-    if (!is_wide_char) {
-        memcpy(p->u.str8, p1->u.str8, p1->len);
-        memcpy(p->u.str8 + p1->len, p2->u.str8, p2->len);
-        p->u.str8[len] = '\0';
-    } else {
-        copy_str16(p->u.str16, p1, 0, p1->len);
-        copy_str16(p->u.str16 + p1->len, p2, 0, p2->len);
-    }
-    return JS_MKPTR(JS_TAG_STRING, p);
-}
-
-/* op1 and op2 are converted to strings. For convience, op1 or op2 =
-   JS_EXCEPTION are accepted and return JS_EXCEPTION.  */
-static JSValue JS_ConcatString(JSContext *ctx, JSValue op1, JSValue op2)
-{
-    JSValue ret;
-    JSString *p1, *p2;
-
-    if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_STRING)) {
-        op1 = JS_ToStringFree(ctx, op1);
-        if (JS_IsException(op1)) {
-            JS_FreeValue(ctx, op2);
-            return JS_EXCEPTION;
-        }
-    }
-    if (unlikely(JS_VALUE_GET_TAG(op2) != JS_TAG_STRING)) {
-        op2 = JS_ToStringFree(ctx, op2);
-        if (JS_IsException(op2)) {
-            JS_FreeValue(ctx, op1);
-            return JS_EXCEPTION;
-        }
-    }
-    p1 = JS_VALUE_GET_STRING(op1);
-    p2 = JS_VALUE_GET_STRING(op2);
-
-    /* XXX: could also check if p1 is empty */
-    if (p2->len == 0) {
-        goto ret_op1;
-    }
-    if (p1->header.ref_count == 1 && p1->is_wide_char == p2->is_wide_char
-    &&  js_malloc_usable_size(ctx, p1) >= sizeof(*p1) + ((p1->len + p2->len) << p2->is_wide_char) + 1 - p1->is_wide_char) {
-        /* Concatenate in place in available space at the end of p1 */
-        if (p1->is_wide_char) {
-            memcpy(p1->u.str16 + p1->len, p2->u.str16, p2->len << 1);
-            p1->len += p2->len;
-        } else {
-            memcpy(p1->u.str8 + p1->len, p2->u.str8, p2->len);
-            p1->len += p2->len;
-            p1->u.str8[p1->len] = '\0';
-        }
-    ret_op1:
-        JS_FreeValue(ctx, op2);
-        return op1;
-    }
-    ret = JS_ConcatString1(ctx, p1, p2);
-    JS_FreeValue(ctx, op1);
-    JS_FreeValue(ctx, op2);
-    return ret;
-}
-
-/* Shape support */
-
-static inline size_t get_shape_size(size_t hash_size, size_t prop_size)
-{
-    return hash_size * sizeof(uint32_t) + sizeof(JSShape) +
-        prop_size * sizeof(JSShapeProperty);
-}
-
-static inline JSShape *get_shape_from_alloc(void *sh_alloc, size_t hash_size)
-{
-    return (JSShape *)(void *)((uint32_t *)sh_alloc + hash_size);
-}
-
-static inline uint32_t *prop_hash_end(JSShape *sh)
-{
-    return (uint32_t *)sh;
-}
-
-static inline void *get_alloc_from_shape(JSShape *sh)
-{
-    return prop_hash_end(sh) - ((intptr_t)sh->prop_hash_mask + 1);
-}
-
-static inline JSShapeProperty *get_shape_prop(JSShape *sh)
-{
-    return sh->prop;
-}
-
-static int init_shape_hash(JSRuntime *rt)
-{
-    rt->shape_hash_bits = 4;   /* 16 shapes */
-    rt->shape_hash_size = 1 << rt->shape_hash_bits;
-    rt->shape_hash_count = 0;
-    rt->shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) *
-                                   rt->shape_hash_size);
-    if (!rt->shape_hash)
-        return -1;
-    return 0;
-}
-
-/* same magic hash multiplier as the Linux kernel */
-static uint32_t shape_hash(uint32_t h, uint32_t val)
-{
-    return (h + val) * 0x9e370001;
-}
-
-/* truncate the shape hash to 'hash_bits' bits */
-static uint32_t get_shape_hash(uint32_t h, int hash_bits)
-{
-    return h >> (32 - hash_bits);
-}
-
-static uint32_t shape_initial_hash(JSObject *proto)
-{
-    uint32_t h;
-    h = shape_hash(1, (uintptr_t)proto);
-    if (sizeof(proto) > 4)
-        h = shape_hash(h, (uint64_t)(uintptr_t)proto >> 32);
-    return h;
-}
-
-static int resize_shape_hash(JSRuntime *rt, int new_shape_hash_bits)
-{
-    int new_shape_hash_size, i;
-    uint32_t h;
-    JSShape **new_shape_hash, *sh, *sh_next;
-
-    new_shape_hash_size = 1 << new_shape_hash_bits;
-    new_shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) *
-                                   new_shape_hash_size);
-    if (!new_shape_hash)
-        return -1;
-    for(i = 0; i < rt->shape_hash_size; i++) {
-        for(sh = rt->shape_hash[i]; sh != NULL; sh = sh_next) {
-            sh_next = sh->shape_hash_next;
-            h = get_shape_hash(sh->hash, new_shape_hash_bits);
-            sh->shape_hash_next = new_shape_hash[h];
-            new_shape_hash[h] = sh;
-        }
-    }
-    js_free_rt(rt, rt->shape_hash);
-    rt->shape_hash_bits = new_shape_hash_bits;
-    rt->shape_hash_size = new_shape_hash_size;
-    rt->shape_hash = new_shape_hash;
-    return 0;
-}
-
-static void js_shape_hash_link(JSRuntime *rt, JSShape *sh)
-{
-    uint32_t h;
-    h = get_shape_hash(sh->hash, rt->shape_hash_bits);
-    sh->shape_hash_next = rt->shape_hash[h];
-    rt->shape_hash[h] = sh;
-    rt->shape_hash_count++;
-}
-
-static void js_shape_hash_unlink(JSRuntime *rt, JSShape *sh)
-{
-    uint32_t h;
-    JSShape **psh;
-
-    h = get_shape_hash(sh->hash, rt->shape_hash_bits);
-    psh = &rt->shape_hash[h];
-    while (*psh != sh)
-        psh = &(*psh)->shape_hash_next;
-    *psh = sh->shape_hash_next;
-    rt->shape_hash_count--;
-}
-
-/* create a new empty shape with prototype 'proto' */
-static no_inline JSShape *js_new_shape2(JSContext *ctx, JSObject *proto,
-                                        int hash_size, int prop_size)
-{
-    JSRuntime *rt = ctx->rt;
-    void *sh_alloc;
-    JSShape *sh;
-
-    /* resize the shape hash table if necessary */
-    if (2 * (rt->shape_hash_count + 1) > rt->shape_hash_size) {
-        resize_shape_hash(rt, rt->shape_hash_bits + 1);
-    }
-
-    sh_alloc = js_malloc(ctx, get_shape_size(hash_size, prop_size));
-    if (!sh_alloc)
-        return NULL;
-    sh = get_shape_from_alloc(sh_alloc, hash_size);
-    sh->header.ref_count = 1;
-    add_gc_object(rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);
-    if (proto)
-        JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, proto));
-    sh->proto = proto;
-    memset(prop_hash_end(sh) - hash_size, 0, sizeof(prop_hash_end(sh)[0]) *
-           hash_size);
-    sh->prop_hash_mask = hash_size - 1;
-    sh->prop_size = prop_size;
-    sh->prop_count = 0;
-    sh->deleted_prop_count = 0;
-    
-    /* insert in the hash table */
-    sh->hash = shape_initial_hash(proto);
-    sh->is_hashed = TRUE;
-    sh->has_small_array_index = FALSE;
-    js_shape_hash_link(ctx->rt, sh);
-    return sh;
-}
-
-static JSShape *js_new_shape(JSContext *ctx, JSObject *proto)
-{
-    return js_new_shape2(ctx, proto, JS_PROP_INITIAL_HASH_SIZE,
-                         JS_PROP_INITIAL_SIZE);
-}
-
-/* The shape is cloned. The new shape is not inserted in the shape
-   hash table */
-static JSShape *js_clone_shape(JSContext *ctx, JSShape *sh1)
-{
-    JSShape *sh;
-    void *sh_alloc, *sh_alloc1;
-    size_t size;
-    JSShapeProperty *pr;
-    uint32_t i, hash_size;
-
-    hash_size = sh1->prop_hash_mask + 1;
-    size = get_shape_size(hash_size, sh1->prop_size);
-    sh_alloc = js_malloc(ctx, size);
-    if (!sh_alloc)
-        return NULL;
-    sh_alloc1 = get_alloc_from_shape(sh1);
-    memcpy(sh_alloc, sh_alloc1, size);
-    sh = get_shape_from_alloc(sh_alloc, hash_size);
-    sh->header.ref_count = 1;
-    add_gc_object(ctx->rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);
-    sh->is_hashed = FALSE;
-    if (sh->proto) {
-        JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
-    }
-    for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {
-        JS_DupAtom(ctx, pr->atom);
-    }
-    return sh;
-}
-
-static JSShape *js_dup_shape(JSShape *sh)
-{
-    sh->header.ref_count++;
-    return sh;
-}
-
-static void js_free_shape0(JSRuntime *rt, JSShape *sh)
-{
-    uint32_t i;
-    JSShapeProperty *pr;
-
-    assert(sh->header.ref_count == 0);
-    if (sh->is_hashed)
-        js_shape_hash_unlink(rt, sh);
-    if (sh->proto != NULL) {
-        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
-    }
-    pr = get_shape_prop(sh);
-    for(i = 0; i < sh->prop_count; i++) {
-        JS_FreeAtomRT(rt, pr->atom);
-        pr++;
-    }
-    remove_gc_object(&sh->header);
-    js_free_rt(rt, get_alloc_from_shape(sh));
-}
-
-static void js_free_shape(JSRuntime *rt, JSShape *sh)
-{
-    if (unlikely(--sh->header.ref_count <= 0)) {
-        js_free_shape0(rt, sh);
-    }
-}
-
-static void js_free_shape_null(JSRuntime *rt, JSShape *sh)
-{
-    if (sh)
-        js_free_shape(rt, sh);
-}
-
-/* make space to hold at least 'count' properties */
-static no_inline int resize_properties(JSContext *ctx, JSShape **psh,
-                                       JSObject *p, uint32_t count)
-{
-    JSShape *sh;
-    uint32_t new_size, new_hash_size, new_hash_mask, i;
-    JSShapeProperty *pr;
-    void *sh_alloc;
-    intptr_t h;
-
-    sh = *psh;
-    new_size = max_int(count, sh->prop_size * 3 / 2);
-    /* Reallocate prop array first to avoid crash or size inconsistency
-       in case of memory allocation failure */
-    if (p) {
-        JSProperty *new_prop;
-        new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size);
-        if (unlikely(!new_prop))
-            return -1;
-        p->prop = new_prop;
-    }
-    new_hash_size = sh->prop_hash_mask + 1;
-    while (new_hash_size < new_size)
-        new_hash_size = 2 * new_hash_size;
-    if (new_hash_size != (sh->prop_hash_mask + 1)) {
-        JSShape *old_sh;
-        /* resize the hash table and the properties */
-        old_sh = sh;
-        sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
-        if (!sh_alloc)
-            return -1;
-        sh = get_shape_from_alloc(sh_alloc, new_hash_size);
-        list_del(&old_sh->header.link);
-        /* copy all the fields and the properties */
-        memcpy(sh, old_sh,
-               sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count);
-        list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
-        new_hash_mask = new_hash_size - 1;
-        sh->prop_hash_mask = new_hash_mask;
-        memset(prop_hash_end(sh) - new_hash_size, 0,
-               sizeof(prop_hash_end(sh)[0]) * new_hash_size);
-        for(i = 0, pr = sh->prop; i < sh->prop_count; i++, pr++) {
-            if (pr->atom != JS_ATOM_NULL) {
-                h = ((uintptr_t)pr->atom & new_hash_mask);
-                pr->hash_next = prop_hash_end(sh)[-h - 1];
-                prop_hash_end(sh)[-h - 1] = i + 1;
-            }
-        }
-        js_free(ctx, get_alloc_from_shape(old_sh));
-    } else {
-        /* only resize the properties */
-        list_del(&sh->header.link);
-        sh_alloc = js_realloc(ctx, get_alloc_from_shape(sh),
-                              get_shape_size(new_hash_size, new_size));
-        if (unlikely(!sh_alloc)) {
-            /* insert again in the GC list */
-            list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
-            return -1;
-        }
-        sh = get_shape_from_alloc(sh_alloc, new_hash_size);
-        list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
-    }
-    *psh = sh;
-    sh->prop_size = new_size;
-    return 0;
-}
-
-/* remove the deleted properties. */
-static int compact_properties(JSContext *ctx, JSObject *p)
-{
-    JSShape *sh, *old_sh;
-    void *sh_alloc;
-    intptr_t h;
-    uint32_t new_hash_size, i, j, new_hash_mask, new_size;
-    JSShapeProperty *old_pr, *pr;
-    JSProperty *prop, *new_prop;
-    
-    sh = p->shape;
-    assert(!sh->is_hashed);
-
-    new_size = max_int(JS_PROP_INITIAL_SIZE,
-                       sh->prop_count - sh->deleted_prop_count);
-    assert(new_size <= sh->prop_size);
-
-    new_hash_size = sh->prop_hash_mask + 1;
-    while ((new_hash_size / 2) >= new_size)
-        new_hash_size = new_hash_size / 2;
-    new_hash_mask = new_hash_size - 1;
-
-    /* resize the hash table and the properties */
-    old_sh = sh;
-    sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
-    if (!sh_alloc)
-        return -1;
-    sh = get_shape_from_alloc(sh_alloc, new_hash_size);
-    list_del(&old_sh->header.link);
-    memcpy(sh, old_sh, sizeof(JSShape));
-    list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
-    
-    memset(prop_hash_end(sh) - new_hash_size, 0,
-           sizeof(prop_hash_end(sh)[0]) * new_hash_size);
-
-    j = 0;
-    old_pr = old_sh->prop;
-    pr = sh->prop;
-    prop = p->prop;
-    for(i = 0; i < sh->prop_count; i++) {
-        if (old_pr->atom != JS_ATOM_NULL) {
-            pr->atom = old_pr->atom;
-            pr->flags = old_pr->flags;
-            h = ((uintptr_t)old_pr->atom & new_hash_mask);
-            pr->hash_next = prop_hash_end(sh)[-h - 1];
-            prop_hash_end(sh)[-h - 1] = j + 1;
-            prop[j] = prop[i];
-            j++;
-            pr++;
-        }
-        old_pr++;
-    }
-    assert(j == (sh->prop_count - sh->deleted_prop_count));
-    sh->prop_hash_mask = new_hash_mask;
-    sh->prop_size = new_size;
-    sh->deleted_prop_count = 0;
-    sh->prop_count = j;
-
-    p->shape = sh;
-    js_free(ctx, get_alloc_from_shape(old_sh));
-    
-    /* reduce the size of the object properties */
-    new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size);
-    if (new_prop)
-        p->prop = new_prop;
-    return 0;
-}
-
-static int add_shape_property(JSContext *ctx, JSShape **psh,
-                              JSObject *p, JSAtom atom, int prop_flags)
-{
-    JSRuntime *rt = ctx->rt;
-    JSShape *sh = *psh;
-    JSShapeProperty *pr, *prop;
-    uint32_t hash_mask, new_shape_hash = 0;
-    intptr_t h;
-
-    /* update the shape hash */
-    if (sh->is_hashed) {
-        js_shape_hash_unlink(rt, sh);
-        new_shape_hash = shape_hash(shape_hash(sh->hash, atom), prop_flags);
-    }
-
-    if (unlikely(sh->prop_count >= sh->prop_size)) {
-        if (resize_properties(ctx, psh, p, sh->prop_count + 1)) {
-            /* in case of error, reinsert in the hash table.
-               sh is still valid if resize_properties() failed */
-            if (sh->is_hashed)
-                js_shape_hash_link(rt, sh);
-            return -1;
-        }
-        sh = *psh;
-    }
-    if (sh->is_hashed) {
-        sh->hash = new_shape_hash;
-        js_shape_hash_link(rt, sh);
-    }
-    /* Initialize the new shape property.
-       The object property at p->prop[sh->prop_count] is uninitialized */
-    prop = get_shape_prop(sh);
-    pr = &prop[sh->prop_count++];
-    pr->atom = JS_DupAtom(ctx, atom);
-    pr->flags = prop_flags;
-    sh->has_small_array_index |= __JS_AtomIsTaggedInt(atom);
-    /* add in hash table */
-    hash_mask = sh->prop_hash_mask;
-    h = atom & hash_mask;
-    pr->hash_next = prop_hash_end(sh)[-h - 1];
-    prop_hash_end(sh)[-h - 1] = sh->prop_count;
-    return 0;
-}
-
-/* find a hashed empty shape matching the prototype. Return NULL if
-   not found */
-static JSShape *find_hashed_shape_proto(JSRuntime *rt, JSObject *proto)
-{
-    JSShape *sh1;
-    uint32_t h, h1;
-
-    h = shape_initial_hash(proto);
-    h1 = get_shape_hash(h, rt->shape_hash_bits);
-    for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) {
-        if (sh1->hash == h &&
-            sh1->proto == proto &&
-            sh1->prop_count == 0) {
-            return sh1;
-        }
-    }
-    return NULL;
-}
-
-/* find a hashed shape matching sh + (prop, prop_flags). Return NULL if
-   not found */
-static JSShape *find_hashed_shape_prop(JSRuntime *rt, JSShape *sh,
-                                       JSAtom atom, int prop_flags)
-{
-    JSShape *sh1;
-    uint32_t h, h1, i, n;
-
-    h = sh->hash;
-    h = shape_hash(h, atom);
-    h = shape_hash(h, prop_flags);
-    h1 = get_shape_hash(h, rt->shape_hash_bits);
-    for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) {
-        /* we test the hash first so that the rest is done only if the
-           shapes really match */
-        if (sh1->hash == h &&
-            sh1->proto == sh->proto &&
-            sh1->prop_count == ((n = sh->prop_count) + 1)) {
-            for(i = 0; i < n; i++) {
-                if (unlikely(sh1->prop[i].atom != sh->prop[i].atom) ||
-                    unlikely(sh1->prop[i].flags != sh->prop[i].flags))
-                    goto next;
-            }
-            if (unlikely(sh1->prop[n].atom != atom) ||
-                unlikely(sh1->prop[n].flags != prop_flags))
-                goto next;
-            return sh1;
-        }
-    next: ;
-    }
-    return NULL;
-}
-
-static __maybe_unused void JS_DumpShape(JSRuntime *rt, int i, JSShape *sh)
-{
-    char atom_buf[ATOM_GET_STR_BUF_SIZE];
-    int j;
-
-    /* XXX: should output readable class prototype */
-    printf("%5d %3d%c %14p %5d %5d", i,
-           sh->header.ref_count, " *"[sh->is_hashed],
-           (void *)sh->proto, sh->prop_size, sh->prop_count);
-    for(j = 0; j < sh->prop_count; j++) {
-        printf(" %s", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf),
-                                      sh->prop[j].atom));
-    }
-    printf("\n");
-}
-
-static __maybe_unused void JS_DumpShapes(JSRuntime *rt)
-{
-    int i;
-    JSShape *sh;
-    struct list_head *el;
-    JSObject *p;
-    JSGCObjectHeader *gp;
-    
-    printf("JSShapes: {\n");
-    printf("%5s %4s %14s %5s %5s %s\n", "SLOT", "REFS", "PROTO", "SIZE", "COUNT", "PROPS");
-    for(i = 0; i < rt->shape_hash_size; i++) {
-        for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) {
-            JS_DumpShape(rt, i, sh);
-            assert(sh->is_hashed);
-        }
-    }
-    /* dump non-hashed shapes */
-    list_for_each(el, &rt->gc_obj_list) {
-        gp = list_entry(el, JSGCObjectHeader, link);
-        if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
-            p = (JSObject *)gp;
-            if (!p->shape->is_hashed) {
-                JS_DumpShape(rt, -1, p->shape);
-            }
-        }
-    }
-    printf("}\n");
-}
-
-static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID class_id)
-{
-    JSObject *p;
-
-    js_trigger_gc(ctx->rt, sizeof(JSObject));
-    p = js_malloc(ctx, sizeof(JSObject));
-    if (unlikely(!p))
-        goto fail;
-    p->class_id = class_id;
-    p->extensible = TRUE;
-    p->free_mark = 0;
-    p->is_exotic = 0;
-    p->fast_array = 0;
-    p->is_constructor = 0;
-    p->is_uncatchable_error = 0;
-    p->tmp_mark = 0;
-    p->is_HTMLDDA = 0;
-    p->first_weak_ref = NULL;
-    p->u.opaque = NULL;
-    p->shape = sh;
-    p->prop = js_malloc(ctx, sizeof(JSProperty) * sh->prop_size);
-    if (unlikely(!p->prop)) {
-        js_free(ctx, p);
-    fail:
-        js_free_shape(ctx->rt, sh);
-        return JS_EXCEPTION;
-    }
-
-    switch(class_id) {
-    case JS_CLASS_OBJECT:
-        break;
-    case JS_CLASS_ARRAY:
-        {
-            JSProperty *pr;
-            p->is_exotic = 1;
-            p->fast_array = 1;
-            p->u.array.u.values = NULL;
-            p->u.array.count = 0;
-            p->u.array.u1.size = 0;
-            /* the length property is always the first one */
-            if (likely(sh == ctx->array_shape)) {
-                pr = &p->prop[0];
-            } else {
-                /* only used for the first array */
-                /* cannot fail */
-                pr = add_property(ctx, p, JS_ATOM_length,
-                                  JS_PROP_WRITABLE | JS_PROP_LENGTH);
-            }
-            pr->u.value = JS_NewInt32(ctx, 0);
-        }
-        break;
-    case JS_CLASS_C_FUNCTION:
-        p->prop[0].u.value = JS_UNDEFINED;
-        break;
-    case JS_CLASS_ARGUMENTS:
-    case JS_CLASS_UINT8C_ARRAY:
-    case JS_CLASS_INT8_ARRAY:
-    case JS_CLASS_UINT8_ARRAY:
-    case JS_CLASS_INT16_ARRAY:
-    case JS_CLASS_UINT16_ARRAY:
-    case JS_CLASS_INT32_ARRAY:
-    case JS_CLASS_UINT32_ARRAY:
-#ifdef CONFIG_BIGNUM
-    case JS_CLASS_BIG_INT64_ARRAY:
-    case JS_CLASS_BIG_UINT64_ARRAY:
-#endif
-    case JS_CLASS_FLOAT32_ARRAY:
-    case JS_CLASS_FLOAT64_ARRAY:
-        p->is_exotic = 1;
-        p->fast_array = 1;
-        p->u.array.u.ptr = NULL;
-        p->u.array.count = 0;
-        break;
-    case JS_CLASS_DATAVIEW:
-        p->u.array.u.ptr = NULL;
-        p->u.array.count = 0;
-        break;
-    case JS_CLASS_NUMBER:
-    case JS_CLASS_STRING:
-    case JS_CLASS_BOOLEAN:
-    case JS_CLASS_SYMBOL:
-    case JS_CLASS_DATE:
-#ifdef CONFIG_BIGNUM
-    case JS_CLASS_BIG_INT:
-    case JS_CLASS_BIG_FLOAT:
-    case JS_CLASS_BIG_DECIMAL:
-#endif
-        p->u.object_data = JS_UNDEFINED;
-        goto set_exotic;
-    case JS_CLASS_REGEXP:
-        p->u.regexp.pattern = NULL;
-        p->u.regexp.bytecode = NULL;
-        goto set_exotic;
-    default:
-    set_exotic:
-        if (ctx->rt->class_array[class_id].exotic) {
-            p->is_exotic = 1;
-        }
-        break;
-    }
-    p->header.ref_count = 1;
-    add_gc_object(ctx->rt, &p->header, JS_GC_OBJ_TYPE_JS_OBJECT);
-    return JS_MKPTR(JS_TAG_OBJECT, p);
-}
-
-static JSObject *get_proto_obj(JSValueConst proto_val)
-{
-    if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT)
-        return NULL;
-    else
-        return JS_VALUE_GET_OBJ(proto_val);
-}
-
-/* WARNING: proto must be an object or JS_NULL */
-JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto_val,
-                               JSClassID class_id)
-{
-    JSShape *sh;
-    JSObject *proto;
-
-    proto = get_proto_obj(proto_val);
-    sh = find_hashed_shape_proto(ctx->rt, proto);
-    if (likely(sh)) {
-        sh = js_dup_shape(sh);
-    } else {
-        sh = js_new_shape(ctx, proto);
-        if (!sh)
-            return JS_EXCEPTION;
-    }
-    return JS_NewObjectFromShape(ctx, sh, class_id);
-}
-
-#if 0
-static JSValue JS_GetObjectData(JSContext *ctx, JSValueConst obj)
-{
-    JSObject *p;
-
-    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
-        p = JS_VALUE_GET_OBJ(obj);
-        switch(p->class_id) {
-        case JS_CLASS_NUMBER:
-        case JS_CLASS_STRING:
-        case JS_CLASS_BOOLEAN:
-        case JS_CLASS_SYMBOL:
-        case JS_CLASS_DATE:
-#ifdef CONFIG_BIGNUM
-        case JS_CLASS_BIG_INT:
-        case JS_CLASS_BIG_FLOAT:
-        case JS_CLASS_BIG_DECIMAL:
-#endif
-            return JS_DupValue(ctx, p->u.object_data);
-        }
-    }
-    return JS_UNDEFINED;
-}
-#endif
-
-static int JS_SetObjectData(JSContext *ctx, JSValueConst obj, JSValue val)
-{
-    JSObject *p;
-
-    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
-        p = JS_VALUE_GET_OBJ(obj);
-        switch(p->class_id) {
-        case JS_CLASS_NUMBER:
-        case JS_CLASS_STRING:
-        case JS_CLASS_BOOLEAN:
-        case JS_CLASS_SYMBOL:
-        case JS_CLASS_DATE:
-#ifdef CONFIG_BIGNUM
-        case JS_CLASS_BIG_INT:
-        case JS_CLASS_BIG_FLOAT:
-        case JS_CLASS_BIG_DECIMAL:
-#endif
-            JS_FreeValue(ctx, p->u.object_data);
-            p->u.object_data = val;
-            return 0;
-        }
-    }
-    JS_FreeValue(ctx, val);
-    if (!JS_IsException(obj))
-        JS_ThrowTypeError(ctx, "invalid object type");
-    return -1;
-}
-
-JSValue JS_NewObjectClass(JSContext *ctx, int class_id)
-{
-    return JS_NewObjectProtoClass(ctx, ctx->class_proto[class_id], class_id);
-}
-
-JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto)
-{
-    return JS_NewObjectProtoClass(ctx, proto, JS_CLASS_OBJECT);
-}
-
-JSValue JS_NewArray(JSContext *ctx)
-{
-    return JS_NewObjectFromShape(ctx, js_dup_shape(ctx->array_shape),
-                                 JS_CLASS_ARRAY);
-}
-
-JSValue JS_NewObject(JSContext *ctx)
-{
-    /* inline JS_NewObjectClass(ctx, JS_CLASS_OBJECT); */
-    return JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_OBJECT);
-}
-
-static void js_function_set_properties(JSContext *ctx, JSValueConst func_obj,
-                                       JSAtom name, int len)
-{
-    /* ES6 feature non compatible with ES5.1: length is configurable */
-    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length, JS_NewInt32(ctx, len),
-                           JS_PROP_CONFIGURABLE);
-    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name,
-                           JS_AtomToString(ctx, name), JS_PROP_CONFIGURABLE);
-}
-
-static BOOL js_class_has_bytecode(JSClassID class_id)
-{
-    return (class_id == JS_CLASS_BYTECODE_FUNCTION ||
-            class_id == JS_CLASS_GENERATOR_FUNCTION ||
-            class_id == JS_CLASS_ASYNC_FUNCTION ||
-            class_id == JS_CLASS_ASYNC_GENERATOR_FUNCTION);
-}
-
-/* return NULL without exception if not a function or no bytecode */
-static JSFunctionBytecode *JS_GetFunctionBytecode(JSValueConst val)
-{
-    JSObject *p;
-    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
-        return NULL;
-    p = JS_VALUE_GET_OBJ(val);
-    if (!js_class_has_bytecode(p->class_id))
-        return NULL;
-    return p->u.func.function_bytecode;
-}
-
-static void js_method_set_home_object(JSContext *ctx, JSValueConst func_obj,
-                                      JSValueConst home_obj)
-{
-    JSObject *p, *p1;
-    JSFunctionBytecode *b;
-
-    if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
-        return;
-    p = JS_VALUE_GET_OBJ(func_obj);
-    if (!js_class_has_bytecode(p->class_id))
-        return;
-    b = p->u.func.function_bytecode;
-    if (b->need_home_object) {
-        p1 = p->u.func.home_object;
-        if (p1) {
-            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
-        }
-        if (JS_VALUE_GET_TAG(home_obj) == JS_TAG_OBJECT)
-            p1 = JS_VALUE_GET_OBJ(JS_DupValue(ctx, home_obj));
-        else
-            p1 = NULL;
-        p->u.func.home_object = p1;
-    }
-}
-
-static JSValue js_get_function_name(JSContext *ctx, JSAtom name)
-{
-    JSValue name_str;
-
-    name_str = JS_AtomToString(ctx, name);
-    if (JS_AtomSymbolHasDescription(ctx, name)) {
-        name_str = JS_ConcatString3(ctx, "[", name_str, "]");
-    }
-    return name_str;
-}
-
-/* Modify the name of a method according to the atom and
-   'flags'. 'flags' is a bitmask of JS_PROP_HAS_GET and
-   JS_PROP_HAS_SET. Also set the home object of the method.
-   Return < 0 if exception. */
-static int js_method_set_properties(JSContext *ctx, JSValueConst func_obj,
-                                    JSAtom name, int flags, JSValueConst home_obj)
-{
-    JSValue name_str;
-
-    name_str = js_get_function_name(ctx, name);
-    if (flags & JS_PROP_HAS_GET) {
-        name_str = JS_ConcatString3(ctx, "get ", name_str, "");
-    } else if (flags & JS_PROP_HAS_SET) {
-        name_str = JS_ConcatString3(ctx, "set ", name_str, "");
-    }
-    if (JS_IsException(name_str))
-        return -1;
-    if (JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name_str,
-                               JS_PROP_CONFIGURABLE) < 0)
-        return -1;
-    js_method_set_home_object(ctx, func_obj, home_obj);
-    return 0;
-}
-
-/* Note: at least 'length' arguments will be readable in 'argv' */
-static JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func,
-                                const char *name,
-                                int length, JSCFunctionEnum cproto, int magic,
-                                JSValueConst proto_val)
-{
-    JSValue func_obj;
-    JSObject *p;
-    JSAtom name_atom;
-    
-    func_obj = JS_NewObjectProtoClass(ctx, proto_val, JS_CLASS_C_FUNCTION);
-    if (JS_IsException(func_obj))
-        return func_obj;
-    p = JS_VALUE_GET_OBJ(func_obj);
-    p->u.cfunc.realm = JS_DupContext(ctx);
-    p->u.cfunc.c_function.generic = func;
-    p->u.cfunc.length = length;
-    p->u.cfunc.cproto = cproto;
-    p->u.cfunc.magic = magic;
-    p->is_constructor = (cproto == JS_CFUNC_constructor ||
-                         cproto == JS_CFUNC_constructor_magic ||
-                         cproto == JS_CFUNC_constructor_or_func ||
-                         cproto == JS_CFUNC_constructor_or_func_magic);
-    if (!name)
-        name = "";
-    name_atom = JS_NewAtom(ctx, name);
-    js_function_set_properties(ctx, func_obj, name_atom, length);
-    JS_FreeAtom(ctx, name_atom);
-    return func_obj;
-}
-
-/* Note: at least 'length' arguments will be readable in 'argv' */
-JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func,
-                         const char *name,
-                         int length, JSCFunctionEnum cproto, int magic)
-{
-    return JS_NewCFunction3(ctx, func, name, length, cproto, magic,
-                            ctx->function_proto);
-}
-
-typedef struct JSCFunctionDataRecord {
-    JSCFunctionData *func;
-    uint8_t length;
-    uint8_t data_len;
-    uint16_t magic;
-    JSValue data[0];
-} JSCFunctionDataRecord;
-
-static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA);
-    int i;
-
-    if (s) {
-        for(i = 0; i < s->data_len; i++) {
-            JS_FreeValueRT(rt, s->data[i]);
-        }
-        js_free_rt(rt, s);
-    }
-}
-
-static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val,
-                                    JS_MarkFunc *mark_func)
-{
-    JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA);
-    int i;
-
-    if (s) {
-        for(i = 0; i < s->data_len; i++) {
-            JS_MarkValue(rt, s->data[i], mark_func);
-        }
-    }
-}
-
-static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj,
-                                       JSValueConst this_val,
-                                       int argc, JSValueConst *argv, int flags)
-{
-    JSCFunctionDataRecord *s = JS_GetOpaque(func_obj, JS_CLASS_C_FUNCTION_DATA);
-    JSValueConst *arg_buf;
-    int i;
-
-    /* XXX: could add the function on the stack for debug */
-    if (unlikely(argc < s->length)) {
-        arg_buf = alloca(sizeof(arg_buf[0]) * s->length);
-        for(i = 0; i < argc; i++)
-            arg_buf[i] = argv[i];
-        for(i = argc; i < s->length; i++)
-            arg_buf[i] = JS_UNDEFINED;
-    } else {
-        arg_buf = argv;
-    }
-
-    return s->func(ctx, this_val, argc, arg_buf, s->magic, s->data);
-}
-
-JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,
-                            int length, int magic, int data_len,
-                            JSValueConst *data)
-{
-    JSCFunctionDataRecord *s;
-    JSValue func_obj;
-    int i;
-
-    func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
-                                      JS_CLASS_C_FUNCTION_DATA);
-    if (JS_IsException(func_obj))
-        return func_obj;
-    s = js_malloc(ctx, sizeof(*s) + data_len * sizeof(JSValue));
-    if (!s) {
-        JS_FreeValue(ctx, func_obj);
-        return JS_EXCEPTION;
-    }
-    s->func = func;
-    s->length = length;
-    s->data_len = data_len;
-    s->magic = magic;
-    for(i = 0; i < data_len; i++)
-        s->data[i] = JS_DupValue(ctx, data[i]);
-    JS_SetOpaque(func_obj, s);
-    js_function_set_properties(ctx, func_obj,
-                               JS_ATOM_empty_string, length);
-    return func_obj;
-}
-
-static JSContext *js_autoinit_get_realm(JSProperty *pr)
-{
-    return (JSContext *)(pr->u.init.realm_and_id & ~3);
-}
-
-static JSAutoInitIDEnum js_autoinit_get_id(JSProperty *pr)
-{
-    return pr->u.init.realm_and_id & 3;
-}
-
-static void js_autoinit_free(JSRuntime *rt, JSProperty *pr)
-{
-    JS_FreeContext(js_autoinit_get_realm(pr));
-}
-
-static void js_autoinit_mark(JSRuntime *rt, JSProperty *pr,
-                             JS_MarkFunc *mark_func)
-{
-    mark_func(rt, &js_autoinit_get_realm(pr)->header);
-}
-
-static void free_property(JSRuntime *rt, JSProperty *pr, int prop_flags)
-{
-    if (unlikely(prop_flags & JS_PROP_TMASK)) {
-        if ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
-            if (pr->u.getset.getter)
-                JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
-            if (pr->u.getset.setter)
-                JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
-        } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
-            free_var_ref(rt, pr->u.var_ref);
-        } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
-            js_autoinit_free(rt, pr);
-        }
-    } else {
-        JS_FreeValueRT(rt, pr->u.value);
-    }
-}
-
-static force_inline JSShapeProperty *find_own_property1(JSObject *p,
-                                                        JSAtom atom)
-{
-    JSShape *sh;
-    JSShapeProperty *pr, *prop;
-    intptr_t h;
-    sh = p->shape;
-    h = (uintptr_t)atom & sh->prop_hash_mask;
-    h = prop_hash_end(sh)[-h - 1];
-    prop = get_shape_prop(sh);
-    while (h) {
-        pr = &prop[h - 1];
-        if (likely(pr->atom == atom)) {
-            return pr;
-        }
-        h = pr->hash_next;
-    }
-    return NULL;
-}
-
-static force_inline JSShapeProperty *find_own_property(JSProperty **ppr,
-                                                       JSObject *p,
-                                                       JSAtom atom)
-{
-    JSShape *sh;
-    JSShapeProperty *pr, *prop;
-    intptr_t h;
-    sh = p->shape;
-    h = (uintptr_t)atom & sh->prop_hash_mask;
-    h = prop_hash_end(sh)[-h - 1];
-    prop = get_shape_prop(sh);
-    while (h) {
-        pr = &prop[h - 1];
-        if (likely(pr->atom == atom)) {
-            *ppr = &p->prop[h - 1];
-            /* the compiler should be able to assume that pr != NULL here */
-            return pr;
-        }
-        h = pr->hash_next;
-    }
-    *ppr = NULL;
-    return NULL;
-}
-
-/* indicate that the object may be part of a function prototype cycle */
-static void set_cycle_flag(JSContext *ctx, JSValueConst obj)
-{
-}
-
-static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref)
-{
-    if (var_ref) {
-        assert(var_ref->header.ref_count > 0);
-        if (--var_ref->header.ref_count == 0) {
-            if (var_ref->is_detached) {
-                JS_FreeValueRT(rt, var_ref->value);
-                remove_gc_object(&var_ref->header);
-            } else {
-                list_del(&var_ref->header.link); /* still on the stack */
-            }
-            js_free_rt(rt, var_ref);
-        }
-    }
-}
-
-static void js_array_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    int i;
-
-    for(i = 0; i < p->u.array.count; i++) {
-        JS_FreeValueRT(rt, p->u.array.u.values[i]);
-    }
-    js_free_rt(rt, p->u.array.u.values);
-}
-
-static void js_array_mark(JSRuntime *rt, JSValueConst val,
-                          JS_MarkFunc *mark_func)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    int i;
-
-    for(i = 0; i < p->u.array.count; i++) {
-        JS_MarkValue(rt, p->u.array.u.values[i], mark_func);
-    }
-}
-
-static void js_object_data_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    JS_FreeValueRT(rt, p->u.object_data);
-    p->u.object_data = JS_UNDEFINED;
-}
-
-static void js_object_data_mark(JSRuntime *rt, JSValueConst val,
-                                JS_MarkFunc *mark_func)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    JS_MarkValue(rt, p->u.object_data, mark_func);
-}
-
-static void js_c_function_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-
-    if (p->u.cfunc.realm)
-        JS_FreeContext(p->u.cfunc.realm);
-}
-
-static void js_c_function_mark(JSRuntime *rt, JSValueConst val,
-                               JS_MarkFunc *mark_func)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-
-    if (p->u.cfunc.realm)
-        mark_func(rt, &p->u.cfunc.realm->header);
-}
-
-static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSObject *p1, *p = JS_VALUE_GET_OBJ(val);
-    JSFunctionBytecode *b;
-    JSVarRef **var_refs;
-    int i;
-
-    p1 = p->u.func.home_object;
-    if (p1) {
-        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, p1));
-    }
-    b = p->u.func.function_bytecode;
-    if (b) {
-        var_refs = p->u.func.var_refs;
-        if (var_refs) {
-            for(i = 0; i < b->closure_var_count; i++)
-                free_var_ref(rt, var_refs[i]);
-            js_free_rt(rt, var_refs);
-        }
-        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b));
-    }
-}
-
-static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
-                                      JS_MarkFunc *mark_func)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    JSVarRef **var_refs = p->u.func.var_refs;
-    JSFunctionBytecode *b = p->u.func.function_bytecode;
-    int i;
-
-    if (p->u.func.home_object) {
-        JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object),
-                     mark_func);
-    }
-    if (b) {
-        if (var_refs) {
-            for(i = 0; i < b->closure_var_count; i++) {
-                JSVarRef *var_ref = var_refs[i];
-                if (var_ref && var_ref->is_detached) {
-                    mark_func(rt, &var_ref->header);
-                }
-            }
-        }
-        /* must mark the function bytecode because template objects may be
-           part of a cycle */
-        JS_MarkValue(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b), mark_func);
-    }
-}
-
-static void js_bound_function_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    JSBoundFunction *bf = p->u.bound_function;
-    int i;
-
-    JS_FreeValueRT(rt, bf->func_obj);
-    JS_FreeValueRT(rt, bf->this_val);
-    for(i = 0; i < bf->argc; i++) {
-        JS_FreeValueRT(rt, bf->argv[i]);
-    }
-    js_free_rt(rt, bf);
-}
-
-static void js_bound_function_mark(JSRuntime *rt, JSValueConst val,
-                                JS_MarkFunc *mark_func)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    JSBoundFunction *bf = p->u.bound_function;
-    int i;
-
-    JS_MarkValue(rt, bf->func_obj, mark_func);
-    JS_MarkValue(rt, bf->this_val, mark_func);
-    for(i = 0; i < bf->argc; i++)
-        JS_MarkValue(rt, bf->argv[i], mark_func);
-}
-
-static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    JSForInIterator *it = p->u.for_in_iterator;
-    JS_FreeValueRT(rt, it->obj);
-    js_free_rt(rt, it);
-}
-
-static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val,
-                                JS_MarkFunc *mark_func)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    JSForInIterator *it = p->u.for_in_iterator;
-    JS_MarkValue(rt, it->obj, mark_func);
-}
-
-static void free_object(JSRuntime *rt, JSObject *p)
-{
-    int i;
-    JSClassFinalizer *finalizer;
-    JSShape *sh;
-    JSShapeProperty *pr;
-
-    p->free_mark = 1; /* used to tell the object is invalid when
-                         freeing cycles */
-    /* free all the fields */
-    sh = p->shape;
-    pr = get_shape_prop(sh);
-    for(i = 0; i < sh->prop_count; i++) {
-        free_property(rt, &p->prop[i], pr->flags);
-        pr++;
-    }
-    js_free_rt(rt, p->prop);
-    /* as an optimization we destroy the shape immediately without
-       putting it in gc_zero_ref_count_list */
-    js_free_shape(rt, sh);
-
-    /* fail safe */
-    p->shape = NULL;
-    p->prop = NULL;
-
-    if (unlikely(p->first_weak_ref)) {
-        reset_weak_ref(rt, p);
-    }
-
-    finalizer = rt->class_array[p->class_id].finalizer;
-    if (finalizer)
-        (*finalizer)(rt, JS_MKPTR(JS_TAG_OBJECT, p));
-
-    /* fail safe */
-    p->class_id = 0;
-    p->u.opaque = NULL;
-    p->u.func.var_refs = NULL;
-    p->u.func.home_object = NULL;
-
-    remove_gc_object(&p->header);
-    if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && p->header.ref_count != 0) {
-        list_add_tail(&p->header.link, &rt->gc_zero_ref_count_list);
-    } else {
-        js_free_rt(rt, p);
-    }
-}
-
-static void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp)
-{
-    switch(gp->gc_obj_type) {
-    case JS_GC_OBJ_TYPE_JS_OBJECT:
-        free_object(rt, (JSObject *)gp);
-        break;
-    case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
-        free_function_bytecode(rt, (JSFunctionBytecode *)gp);
-        break;
-    default:
-        abort();
-    }
-}
-
-static void free_zero_refcount(JSRuntime *rt)
-{
-    struct list_head *el;
-    JSGCObjectHeader *p;
-    
-    rt->gc_phase = JS_GC_PHASE_DECREF;
-    for(;;) {
-        el = rt->gc_zero_ref_count_list.next;
-        if (el == &rt->gc_zero_ref_count_list)
-            break;
-        p = list_entry(el, JSGCObjectHeader, link);
-        assert(p->ref_count == 0);
-        free_gc_object(rt, p);
-    }
-    rt->gc_phase = JS_GC_PHASE_NONE;
-}
-
-/* called with the ref_count of 'v' reaches zero. */
-void __JS_FreeValueRT(JSRuntime *rt, JSValue v)
-{
-    uint32_t tag = JS_VALUE_GET_TAG(v);
-
-#ifdef DUMP_FREE
-    {
-        printf("Freeing ");
-        if (tag == JS_TAG_OBJECT) {
-            JS_DumpObject(rt, JS_VALUE_GET_OBJ(v));
-        } else {
-            JS_DumpValueShort(rt, v);
-            printf("\n");
-        }
-    }
-#endif
-
-    switch(tag) {
-    case JS_TAG_STRING:
-        {
-            JSString *p = JS_VALUE_GET_STRING(v);
-            if (p->atom_type) {
-                JS_FreeAtomStruct(rt, p);
-            } else {
-#ifdef DUMP_LEAKS
-                list_del(&p->link);
-#endif
-                js_free_rt(rt, p);
-            }
-        }
-        break;
-    case JS_TAG_OBJECT:
-    case JS_TAG_FUNCTION_BYTECODE:
-        {
-            JSGCObjectHeader *p = JS_VALUE_GET_PTR(v);
-            if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {
-                list_del(&p->link);
-                list_add(&p->link, &rt->gc_zero_ref_count_list);
-                if (rt->gc_phase == JS_GC_PHASE_NONE) {
-                    free_zero_refcount(rt);
-                }
-            }
-        }
-        break;
-    case JS_TAG_MODULE:
-        abort(); /* never freed here */
-        break;
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_INT:
-    case JS_TAG_BIG_FLOAT:
-        {
-            JSBigFloat *bf = JS_VALUE_GET_PTR(v);
-            bf_delete(&bf->num);
-            js_free_rt(rt, bf);
-        }
-        break;
-    case JS_TAG_BIG_DECIMAL:
-        {
-            JSBigDecimal *bf = JS_VALUE_GET_PTR(v);
-            bfdec_delete(&bf->num);
-            js_free_rt(rt, bf);
-        }
-        break;
-#endif
-    case JS_TAG_SYMBOL:
-        {
-            JSAtomStruct *p = JS_VALUE_GET_PTR(v);
-            JS_FreeAtomStruct(rt, p);
-        }
-        break;
-    default:
-        printf("__JS_FreeValue: unknown tag=%d\n", tag);
-        abort();
-    }
-}
-
-void __JS_FreeValue(JSContext *ctx, JSValue v)
-{
-    __JS_FreeValueRT(ctx->rt, v);
-}
-
-/* garbage collection */
-
-static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
-                          JSGCObjectTypeEnum type)
-{
-    h->mark = 0;
-    h->gc_obj_type = type;
-    list_add_tail(&h->link, &rt->gc_obj_list);
-}
-
-static void remove_gc_object(JSGCObjectHeader *h)
-{
-    list_del(&h->link);
-}
-
-void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
-{
-    if (JS_VALUE_HAS_REF_COUNT(val)) {
-        switch(JS_VALUE_GET_TAG(val)) {
-        case JS_TAG_OBJECT:
-        case JS_TAG_FUNCTION_BYTECODE:
-            mark_func(rt, JS_VALUE_GET_PTR(val));
-            break;
-        default:
-            break;
-        }
-    }
-}
-
-static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp,
-                          JS_MarkFunc *mark_func)
-{
-    switch(gp->gc_obj_type) {
-    case JS_GC_OBJ_TYPE_JS_OBJECT:
-        {
-            JSObject *p = (JSObject *)gp;
-            JSShapeProperty *prs;
-            JSShape *sh;
-            int i;
-            sh = p->shape;
-            mark_func(rt, &sh->header);
-            /* mark all the fields */
-            prs = get_shape_prop(sh);
-            for(i = 0; i < sh->prop_count; i++) {
-                JSProperty *pr = &p->prop[i];
-                if (prs->atom != JS_ATOM_NULL) {
-                    if (prs->flags & JS_PROP_TMASK) {
-                        if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
-                            if (pr->u.getset.getter)
-                                mark_func(rt, &pr->u.getset.getter->header);
-                            if (pr->u.getset.setter)
-                                mark_func(rt, &pr->u.getset.setter->header);
-                        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
-                            if (pr->u.var_ref->is_detached) {
-                                /* Note: the tag does not matter
-                                   provided it is a GC object */
-                                mark_func(rt, &pr->u.var_ref->header);
-                            }
-                        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
-                            js_autoinit_mark(rt, pr, mark_func);
-                        }
-                    } else {
-                        JS_MarkValue(rt, pr->u.value, mark_func);
-                    }
-                }
-                prs++;
-            }
-
-            if (p->class_id != JS_CLASS_OBJECT) {
-                JSClassGCMark *gc_mark;
-                gc_mark = rt->class_array[p->class_id].gc_mark;
-                if (gc_mark)
-                    gc_mark(rt, JS_MKPTR(JS_TAG_OBJECT, p), mark_func);
-            }
-        }
-        break;
-    case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
-        /* the template objects can be part of a cycle */
-        {
-            JSFunctionBytecode *b = (JSFunctionBytecode *)gp;
-            int i;
-            for(i = 0; i < b->cpool_count; i++) {
-                JS_MarkValue(rt, b->cpool[i], mark_func);
-            }
-            if (b->realm)
-                mark_func(rt, &b->realm->header);
-        }
-        break;
-    case JS_GC_OBJ_TYPE_VAR_REF:
-        {
-            JSVarRef *var_ref = (JSVarRef *)gp;
-            /* only detached variable referenced are taken into account */
-            assert(var_ref->is_detached);
-            JS_MarkValue(rt, *var_ref->pvalue, mark_func);
-        }
-        break;
-    case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
-        {
-            JSAsyncFunctionData *s = (JSAsyncFunctionData *)gp;
-            if (s->is_active)
-                async_func_mark(rt, &s->func_state, mark_func);
-            JS_MarkValue(rt, s->resolving_funcs[0], mark_func);
-            JS_MarkValue(rt, s->resolving_funcs[1], mark_func);
-        }
-        break;
-    case JS_GC_OBJ_TYPE_SHAPE:
-        {
-            JSShape *sh = (JSShape *)gp;
-            if (sh->proto != NULL) {
-                mark_func(rt, &sh->proto->header);
-            }
-        }
-        break;
-    case JS_GC_OBJ_TYPE_JS_CONTEXT:
-        {
-            JSContext *ctx = (JSContext *)gp;
-            JS_MarkContext(rt, ctx, mark_func);
-        }
-        break;
-    default:
-        abort();
-    }
-}
-
-static void gc_decref_child(JSRuntime *rt, JSGCObjectHeader *p)
-{
-    assert(p->ref_count > 0);
-    p->ref_count--;
-    if (p->ref_count == 0 && p->mark == 1) {
-        list_del(&p->link);
-        list_add_tail(&p->link, &rt->tmp_obj_list);
-    }
-}
-
-static void gc_decref(JSRuntime *rt)
-{
-    struct list_head *el, *el1;
-    JSGCObjectHeader *p;
-    
-    init_list_head(&rt->tmp_obj_list);
-
-    /* decrement the refcount of all the children of all the GC
-       objects and move the GC objects with zero refcount to
-       tmp_obj_list */
-    list_for_each_safe(el, el1, &rt->gc_obj_list) {
-        p = list_entry(el, JSGCObjectHeader, link);
-        assert(p->mark == 0);
-        mark_children(rt, p, gc_decref_child);
-        p->mark = 1;
-        if (p->ref_count == 0) {
-            list_del(&p->link);
-            list_add_tail(&p->link, &rt->tmp_obj_list);
-        }
-    }
-}
-
-static void gc_scan_incref_child(JSRuntime *rt, JSGCObjectHeader *p)
-{
-    p->ref_count++;
-    if (p->ref_count == 1) {
-        /* ref_count was 0: remove from tmp_obj_list and add at the
-           end of gc_obj_list */
-        list_del(&p->link);
-        list_add_tail(&p->link, &rt->gc_obj_list);
-        p->mark = 0; /* reset the mark for the next GC call */
-    }
-}
-
-static void gc_scan_incref_child2(JSRuntime *rt, JSGCObjectHeader *p)
-{
-    p->ref_count++;
-}
-
-static void gc_scan(JSRuntime *rt)
-{
-    struct list_head *el;
-    JSGCObjectHeader *p;
-
-    /* keep the objects with a refcount > 0 and their children. */
-    list_for_each(el, &rt->gc_obj_list) {
-        p = list_entry(el, JSGCObjectHeader, link);
-        assert(p->ref_count > 0);
-        p->mark = 0; /* reset the mark for the next GC call */
-        mark_children(rt, p, gc_scan_incref_child);
-    }
-    
-    /* restore the refcount of the objects to be deleted. */
-    list_for_each(el, &rt->tmp_obj_list) {
-        p = list_entry(el, JSGCObjectHeader, link);
-        mark_children(rt, p, gc_scan_incref_child2);
-    }
-}
-
-static void gc_free_cycles(JSRuntime *rt)
-{
-    struct list_head *el, *el1;
-    JSGCObjectHeader *p;
-#ifdef DUMP_GC_FREE
-    BOOL header_done = FALSE;
-#endif
-
-    rt->gc_phase = JS_GC_PHASE_REMOVE_CYCLES;
-
-    for(;;) {
-        el = rt->tmp_obj_list.next;
-        if (el == &rt->tmp_obj_list)
-            break;
-        p = list_entry(el, JSGCObjectHeader, link);
-        /* Only need to free the GC object associated with JS
-           values. The rest will be automatically removed because they
-           must be referenced by them. */
-        switch(p->gc_obj_type) {
-        case JS_GC_OBJ_TYPE_JS_OBJECT:
-        case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
-#ifdef DUMP_GC_FREE
-            if (!header_done) {
-                printf("Freeing cycles:\n");
-                JS_DumpObjectHeader(rt);
-                header_done = TRUE;
-            }
-            JS_DumpGCObject(rt, p);
-#endif
-            free_gc_object(rt, p);
-            break;
-        default:
-            list_del(&p->link);
-            list_add_tail(&p->link, &rt->gc_zero_ref_count_list);
-            break;
-        }
-    }
-    rt->gc_phase = JS_GC_PHASE_NONE;
-           
-    list_for_each_safe(el, el1, &rt->gc_zero_ref_count_list) {
-        p = list_entry(el, JSGCObjectHeader, link);
-        assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT ||
-               p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
-        js_free_rt(rt, p);
-    }
-
-    init_list_head(&rt->gc_zero_ref_count_list);
-}
-
-void JS_RunGC(JSRuntime *rt)
-{
-    /* decrement the reference of the children of each object. mark =
-       1 after this pass. */
-    gc_decref(rt);
-
-    /* keep the GC objects with a non zero refcount and their childs */
-    gc_scan(rt);
-
-    /* free the GC objects in a cycle */
-    gc_free_cycles(rt);
-}
-
-/* Return false if not an object or if the object has already been
-   freed (zombie objects are visible in finalizers when freeing
-   cycles). */
-BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj)
-{
-    JSObject *p;
-    if (!JS_IsObject(obj))
-        return FALSE;
-    p = JS_VALUE_GET_OBJ(obj);
-    return !p->free_mark;
-}
-
-/* Compute memory used by various object types */
-/* XXX: poor man's approach to handling multiply referenced objects */
-typedef struct JSMemoryUsage_helper {
-    double memory_used_count;
-    double str_count;
-    double str_size;
-    int64_t js_func_count;
-    double js_func_size;
-    int64_t js_func_code_size;
-    int64_t js_func_pc2line_count;
-    int64_t js_func_pc2line_size;
-} JSMemoryUsage_helper;
-
-static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp);
-
-static void compute_jsstring_size(JSString *str, JSMemoryUsage_helper *hp)
-{
-    if (!str->atom_type) {  /* atoms are handled separately */
-        double s_ref_count = str->header.ref_count;
-        hp->str_count += 1 / s_ref_count;
-        hp->str_size += ((sizeof(*str) + (str->len << str->is_wide_char) +
-                          1 - str->is_wide_char) / s_ref_count);
-    }
-}
-
-static void compute_bytecode_size(JSFunctionBytecode *b, JSMemoryUsage_helper *hp)
-{
-    int memory_used_count, js_func_size, i;
-
-    memory_used_count = 0;
-    js_func_size = offsetof(JSFunctionBytecode, debug);
-    if (b->vardefs) {
-        js_func_size += (b->arg_count + b->var_count) * sizeof(*b->vardefs);
-    }
-    if (b->cpool) {
-        js_func_size += b->cpool_count * sizeof(*b->cpool);
-        for (i = 0; i < b->cpool_count; i++) {
-            JSValueConst val = b->cpool[i];
-            compute_value_size(val, hp);
-        }
-    }
-    if (b->closure_var) {
-        js_func_size += b->closure_var_count * sizeof(*b->closure_var);
-    }
-    if (!b->read_only_bytecode && b->byte_code_buf) {
-        hp->js_func_code_size += b->byte_code_len;
-    }
-    if (b->has_debug) {
-        js_func_size += sizeof(*b) - offsetof(JSFunctionBytecode, debug);
-        if (b->debug.source) {
-            memory_used_count++;
-            js_func_size += b->debug.source_len + 1;
-        }
-        if (b->debug.pc2line_len) {
-            memory_used_count++;
-            hp->js_func_pc2line_count += 1;
-            hp->js_func_pc2line_size += b->debug.pc2line_len;
-        }
-    }
-    hp->js_func_size += js_func_size;
-    hp->js_func_count += 1;
-    hp->memory_used_count += memory_used_count;
-}
-
-static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp)
-{
-    switch(JS_VALUE_GET_TAG(val)) {
-    case JS_TAG_STRING:
-        compute_jsstring_size(JS_VALUE_GET_STRING(val), hp);
-        break;
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_INT:
-    case JS_TAG_BIG_FLOAT:
-    case JS_TAG_BIG_DECIMAL:
-        /* should track JSBigFloat usage */
-        break;
-#endif
-    }
-}
-
-void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
-{
-    struct list_head *el, *el1;
-    int i;
-    JSMemoryUsage_helper mem = { 0 }, *hp = &mem;
-
-    memset(s, 0, sizeof(*s));
-    s->malloc_count = rt->malloc_state.malloc_count;
-    s->malloc_size = rt->malloc_state.malloc_size;
-    s->malloc_limit = rt->malloc_state.malloc_limit;
-
-    s->memory_used_count = 2; /* rt + rt->class_array */
-    s->memory_used_size = sizeof(JSRuntime) + sizeof(JSValue) * rt->class_count;
-
-    list_for_each(el, &rt->context_list) {
-        JSContext *ctx = list_entry(el, JSContext, link);
-        JSShape *sh = ctx->array_shape;
-        s->memory_used_count += 2; /* ctx + ctx->class_proto */
-        s->memory_used_size += sizeof(JSContext) +
-            sizeof(JSValue) * rt->class_count;
-        s->binary_object_count += ctx->binary_object_count;
-        s->binary_object_size += ctx->binary_object_size;
-
-        /* the hashed shapes are counted separately */
-        if (sh && !sh->is_hashed) {
-            int hash_size = sh->prop_hash_mask + 1;
-            s->shape_count++;
-            s->shape_size += get_shape_size(hash_size, sh->prop_size);
-        }
-        list_for_each(el1, &ctx->loaded_modules) {
-            JSModuleDef *m = list_entry(el1, JSModuleDef, link);
-            s->memory_used_count += 1;
-            s->memory_used_size += sizeof(*m);
-            if (m->req_module_entries) {
-                s->memory_used_count += 1;
-                s->memory_used_size += m->req_module_entries_count * sizeof(*m->req_module_entries);
-            }
-            if (m->export_entries) {
-                s->memory_used_count += 1;
-                s->memory_used_size += m->export_entries_count * sizeof(*m->export_entries);
-                for (i = 0; i < m->export_entries_count; i++) {
-                    JSExportEntry *me = &m->export_entries[i];
-                    if (me->export_type == JS_EXPORT_TYPE_LOCAL && me->u.local.var_ref) {
-                        /* potential multiple count */
-                        s->memory_used_count += 1;
-                        compute_value_size(me->u.local.var_ref->value, hp);
-                    }
-                }
-            }
-            if (m->star_export_entries) {
-                s->memory_used_count += 1;
-                s->memory_used_size += m->star_export_entries_count * sizeof(*m->star_export_entries);
-            }
-            if (m->import_entries) {
-                s->memory_used_count += 1;
-                s->memory_used_size += m->import_entries_count * sizeof(*m->import_entries);
-            }
-            compute_value_size(m->module_ns, hp);
-            compute_value_size(m->func_obj, hp);
-        }
-    }
-
-    list_for_each(el, &rt->gc_obj_list) {
-        JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link);
-        JSObject *p;
-        JSShape *sh;
-        JSShapeProperty *prs;
-
-        /* XXX: could count the other GC object types too */
-        if (gp->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE) {
-            compute_bytecode_size((JSFunctionBytecode *)gp, hp);
-            continue;
-        } else if (gp->gc_obj_type != JS_GC_OBJ_TYPE_JS_OBJECT) {
-            continue;
-        }
-        p = (JSObject *)gp;
-        sh = p->shape;
-        s->obj_count++;
-        if (p->prop) {
-            s->memory_used_count++;
-            s->prop_size += sh->prop_size * sizeof(*p->prop);
-            s->prop_count += sh->prop_count;
-            prs = get_shape_prop(sh);
-            for(i = 0; i < sh->prop_count; i++) {
-                JSProperty *pr = &p->prop[i];
-                if (prs->atom != JS_ATOM_NULL && !(prs->flags & JS_PROP_TMASK)) {
-                    compute_value_size(pr->u.value, hp);
-                }
-                prs++;
-            }
-        }
-        /* the hashed shapes are counted separately */
-        if (!sh->is_hashed) {
-            int hash_size = sh->prop_hash_mask + 1;
-            s->shape_count++;
-            s->shape_size += get_shape_size(hash_size, sh->prop_size);
-        }
-
-        switch(p->class_id) {
-        case JS_CLASS_ARRAY:             /* u.array | length */
-        case JS_CLASS_ARGUMENTS:         /* u.array | length */
-            s->array_count++;
-            if (p->fast_array) {
-                s->fast_array_count++;
-                if (p->u.array.u.values) {
-                    s->memory_used_count++;
-                    s->memory_used_size += p->u.array.count *
-                        sizeof(*p->u.array.u.values);
-                    s->fast_array_elements += p->u.array.count;
-                    for (i = 0; i < p->u.array.count; i++) {
-                        compute_value_size(p->u.array.u.values[i], hp);
-                    }
-                }
-            }
-            break;
-        case JS_CLASS_NUMBER:            /* u.object_data */
-        case JS_CLASS_STRING:            /* u.object_data */
-        case JS_CLASS_BOOLEAN:           /* u.object_data */
-        case JS_CLASS_SYMBOL:            /* u.object_data */
-        case JS_CLASS_DATE:              /* u.object_data */
-#ifdef CONFIG_BIGNUM
-        case JS_CLASS_BIG_INT:           /* u.object_data */
-        case JS_CLASS_BIG_FLOAT:         /* u.object_data */
-        case JS_CLASS_BIG_DECIMAL:         /* u.object_data */
-#endif
-            compute_value_size(p->u.object_data, hp);
-            break;
-        case JS_CLASS_C_FUNCTION:        /* u.cfunc */
-            s->c_func_count++;
-            break;
-        case JS_CLASS_BYTECODE_FUNCTION: /* u.func */
-            {
-                JSFunctionBytecode *b = p->u.func.function_bytecode;
-                JSVarRef **var_refs = p->u.func.var_refs;
-                /* home_object: object will be accounted for in list scan */
-                if (var_refs) {
-                    s->memory_used_count++;
-                    s->js_func_size += b->closure_var_count * sizeof(*var_refs);
-                    for (i = 0; i < b->closure_var_count; i++) {
-                        if (var_refs[i]) {
-                            double ref_count = var_refs[i]->header.ref_count;
-                            s->memory_used_count += 1 / ref_count;
-                            s->js_func_size += sizeof(*var_refs[i]) / ref_count;
-                            /* handle non object closed values */
-                            if (var_refs[i]->pvalue == &var_refs[i]->value) {
-                                /* potential multiple count */
-                                compute_value_size(var_refs[i]->value, hp);
-                            }
-                        }
-                    }
-                }
-            }
-            break;
-        case JS_CLASS_BOUND_FUNCTION:    /* u.bound_function */
-            {
-                JSBoundFunction *bf = p->u.bound_function;
-                /* func_obj and this_val are objects */
-                for (i = 0; i < bf->argc; i++) {
-                    compute_value_size(bf->argv[i], hp);
-                }
-                s->memory_used_count += 1;
-                s->memory_used_size += sizeof(*bf) + bf->argc * sizeof(*bf->argv);
-            }
-            break;
-        case JS_CLASS_C_FUNCTION_DATA:   /* u.c_function_data_record */
-            {
-                JSCFunctionDataRecord *fd = p->u.c_function_data_record;
-                if (fd) {
-                    for (i = 0; i < fd->data_len; i++) {
-                        compute_value_size(fd->data[i], hp);
-                    }
-                    s->memory_used_count += 1;
-                    s->memory_used_size += sizeof(*fd) + fd->data_len * sizeof(*fd->data);
-                }
-            }
-            break;
-        case JS_CLASS_REGEXP:            /* u.regexp */
-            compute_jsstring_size(p->u.regexp.pattern, hp);
-            compute_jsstring_size(p->u.regexp.bytecode, hp);
-            break;
-
-        case JS_CLASS_FOR_IN_ITERATOR:   /* u.for_in_iterator */
-            {
-                JSForInIterator *it = p->u.for_in_iterator;
-                if (it) {
-                    compute_value_size(it->obj, hp);
-                    s->memory_used_count += 1;
-                    s->memory_used_size += sizeof(*it);
-                }
-            }
-            break;
-        case JS_CLASS_ARRAY_BUFFER:      /* u.array_buffer */
-        case JS_CLASS_SHARED_ARRAY_BUFFER: /* u.array_buffer */
-            {
-                JSArrayBuffer *abuf = p->u.array_buffer;
-                if (abuf) {
-                    s->memory_used_count += 1;
-                    s->memory_used_size += sizeof(*abuf);
-                    if (abuf->data) {
-                        s->memory_used_count += 1;
-                        s->memory_used_size += abuf->byte_length;
-                    }
-                }
-            }
-            break;
-        case JS_CLASS_GENERATOR:         /* u.generator_data */
-        case JS_CLASS_UINT8C_ARRAY:      /* u.typed_array / u.array */
-        case JS_CLASS_INT8_ARRAY:        /* u.typed_array / u.array */
-        case JS_CLASS_UINT8_ARRAY:       /* u.typed_array / u.array */
-        case JS_CLASS_INT16_ARRAY:       /* u.typed_array / u.array */
-        case JS_CLASS_UINT16_ARRAY:      /* u.typed_array / u.array */
-        case JS_CLASS_INT32_ARRAY:       /* u.typed_array / u.array */
-        case JS_CLASS_UINT32_ARRAY:      /* u.typed_array / u.array */
-#ifdef CONFIG_BIGNUM
-        case JS_CLASS_BIG_INT64_ARRAY:   /* u.typed_array / u.array */
-        case JS_CLASS_BIG_UINT64_ARRAY:  /* u.typed_array / u.array */
-#endif
-        case JS_CLASS_FLOAT32_ARRAY:     /* u.typed_array / u.array */
-        case JS_CLASS_FLOAT64_ARRAY:     /* u.typed_array / u.array */
-        case JS_CLASS_DATAVIEW:          /* u.typed_array */
-#ifdef CONFIG_BIGNUM
-        case JS_CLASS_FLOAT_ENV:         /* u.float_env */
-#endif
-        case JS_CLASS_MAP:               /* u.map_state */
-        case JS_CLASS_SET:               /* u.map_state */
-        case JS_CLASS_WEAKMAP:           /* u.map_state */
-        case JS_CLASS_WEAKSET:           /* u.map_state */
-        case JS_CLASS_MAP_ITERATOR:      /* u.map_iterator_data */
-        case JS_CLASS_SET_ITERATOR:      /* u.map_iterator_data */
-        case JS_CLASS_ARRAY_ITERATOR:    /* u.array_iterator_data */
-        case JS_CLASS_STRING_ITERATOR:   /* u.array_iterator_data */
-        case JS_CLASS_PROXY:             /* u.proxy_data */
-        case JS_CLASS_PROMISE:           /* u.promise_data */
-        case JS_CLASS_PROMISE_RESOLVE_FUNCTION:  /* u.promise_function_data */
-        case JS_CLASS_PROMISE_REJECT_FUNCTION:   /* u.promise_function_data */
-        case JS_CLASS_ASYNC_FUNCTION_RESOLVE:    /* u.async_function_data */
-        case JS_CLASS_ASYNC_FUNCTION_REJECT:     /* u.async_function_data */
-        case JS_CLASS_ASYNC_FROM_SYNC_ITERATOR:  /* u.async_from_sync_iterator_data */
-        case JS_CLASS_ASYNC_GENERATOR:   /* u.async_generator_data */
-            /* TODO */
-        default:
-            /* XXX: class definition should have an opaque block size */
-            if (p->u.opaque) {
-                s->memory_used_count += 1;
-            }
-            break;
-        }
-    }
-    s->obj_size += s->obj_count * sizeof(JSObject);
-
-    /* hashed shapes */
-    s->memory_used_count++; /* rt->shape_hash */
-    s->memory_used_size += sizeof(rt->shape_hash[0]) * rt->shape_hash_size;
-    for(i = 0; i < rt->shape_hash_size; i++) {
-        JSShape *sh;
-        for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) {
-            int hash_size = sh->prop_hash_mask + 1;
-            s->shape_count++;
-            s->shape_size += get_shape_size(hash_size, sh->prop_size);
-        }
-    }
-
-    /* atoms */
-    s->memory_used_count += 2; /* rt->atom_array, rt->atom_hash */
-    s->atom_count = rt->atom_count;
-    s->atom_size = sizeof(rt->atom_array[0]) * rt->atom_size +
-        sizeof(rt->atom_hash[0]) * rt->atom_hash_size;
-    for(i = 0; i < rt->atom_size; i++) {
-        JSAtomStruct *p = rt->atom_array[i];
-        if (!atom_is_free(p)) {
-            s->atom_size += (sizeof(*p) + (p->len << p->is_wide_char) +
-                             1 - p->is_wide_char);
-        }
-    }
-    s->str_count = round(mem.str_count);
-    s->str_size = round(mem.str_size);
-    s->js_func_count = mem.js_func_count;
-    s->js_func_size = round(mem.js_func_size);
-    s->js_func_code_size = mem.js_func_code_size;
-    s->js_func_pc2line_count = mem.js_func_pc2line_count;
-    s->js_func_pc2line_size = mem.js_func_pc2line_size;
-    s->memory_used_count += round(mem.memory_used_count) +
-        s->atom_count + s->str_count +
-        s->obj_count + s->shape_count +
-        s->js_func_count + s->js_func_pc2line_count;
-    s->memory_used_size += s->atom_size + s->str_size +
-        s->obj_size + s->prop_size + s->shape_size +
-        s->js_func_size + s->js_func_code_size + s->js_func_pc2line_size;
-}
-
-void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt)
-{
-    fprintf(fp, "QuickJS memory usage -- "
-#ifdef CONFIG_BIGNUM
-            "BigNum "
-#endif
-            CONFIG_VERSION " version, %d-bit, malloc limit: %"PRId64"\n\n",
-            (int)sizeof(void *) * 8, (int64_t)(ssize_t)s->malloc_limit);
-#if 1
-    if (rt) {
-        static const struct {
-            const char *name;
-            size_t size;
-        } object_types[] = {
-            { "JSRuntime", sizeof(JSRuntime) },
-            { "JSContext", sizeof(JSContext) },
-            { "JSObject", sizeof(JSObject) },
-            { "JSString", sizeof(JSString) },
-            { "JSFunctionBytecode", sizeof(JSFunctionBytecode) },
-        };
-        int i, usage_size_ok = 0;
-        for(i = 0; i < countof(object_types); i++) {
-            unsigned int size = object_types[i].size;
-            void *p = js_malloc_rt(rt, size);
-            if (p) {
-                unsigned int size1 = js_malloc_usable_size_rt(rt, p);
-                if (size1 >= size) {
-                    usage_size_ok = 1;
-                    fprintf(fp, "  %3u + %-2u  %s\n",
-                            size, size1 - size, object_types[i].name);
-                }
-                js_free_rt(rt, p);
-            }
-        }
-        if (!usage_size_ok) {
-            fprintf(fp, "  malloc_usable_size unavailable\n");
-        }
-        {
-            int obj_classes[JS_CLASS_INIT_COUNT + 1] = { 0 };
-            int class_id;
-            struct list_head *el;
-            list_for_each(el, &rt->gc_obj_list) {
-                JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link);
-                JSObject *p;
-                if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
-                    p = (JSObject *)gp;
-                    obj_classes[min_uint32(p->class_id, JS_CLASS_INIT_COUNT)]++;
-                }
-            }
-            fprintf(fp, "\n" "JSObject classes\n");
-            if (obj_classes[0])
-                fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[0], 0, "none");
-            for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) {
-                if (obj_classes[class_id]) {
-                    char buf[ATOM_GET_STR_BUF_SIZE];
-                    fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[class_id], class_id,
-                            JS_AtomGetStrRT(rt, buf, sizeof(buf), js_std_class_def[class_id - 1].class_name));
-                }
-            }
-            if (obj_classes[JS_CLASS_INIT_COUNT])
-                fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[JS_CLASS_INIT_COUNT], 0, "other");
-        }
-        fprintf(fp, "\n");
-    }
-#endif
-    fprintf(fp, "%-20s %8s %8s\n", "NAME", "COUNT", "SIZE");
-
-    if (s->malloc_count) {
-        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per block)\n",
-                "memory allocated", s->malloc_count, s->malloc_size,
-                (double)s->malloc_size / s->malloc_count);
-        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%d overhead, %0.1f average slack)\n",
-                "memory used", s->memory_used_count, s->memory_used_size,
-                MALLOC_OVERHEAD, ((double)(s->malloc_size - s->memory_used_size) /
-                                  s->memory_used_count));
-    }
-    if (s->atom_count) {
-        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per atom)\n",
-                "atoms", s->atom_count, s->atom_size,
-                (double)s->atom_size / s->atom_count);
-    }
-    if (s->str_count) {
-        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per string)\n",
-                "strings", s->str_count, s->str_size,
-                (double)s->str_size / s->str_count);
-    }
-    if (s->obj_count) {
-        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per object)\n",
-                "objects", s->obj_count, s->obj_size,
-                (double)s->obj_size / s->obj_count);
-        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per object)\n",
-                "  properties", s->prop_count, s->prop_size,
-                (double)s->prop_count / s->obj_count);
-        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per shape)\n",
-                "  shapes", s->shape_count, s->shape_size,
-                (double)s->shape_size / s->shape_count);
-    }
-    if (s->js_func_count) {
-        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n",
-                "bytecode functions", s->js_func_count, s->js_func_size);
-        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per function)\n",
-                "  bytecode", s->js_func_count, s->js_func_code_size,
-                (double)s->js_func_code_size / s->js_func_count);
-        if (s->js_func_pc2line_count) {
-            fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per function)\n",
-                    "  pc2line", s->js_func_pc2line_count,
-                    s->js_func_pc2line_size,
-                    (double)s->js_func_pc2line_size / s->js_func_pc2line_count);
-        }
-    }
-    if (s->c_func_count) {
-        fprintf(fp, "%-20s %8"PRId64"\n", "C functions", s->c_func_count);
-    }
-    if (s->array_count) {
-        fprintf(fp, "%-20s %8"PRId64"\n", "arrays", s->array_count);
-        if (s->fast_array_count) {
-            fprintf(fp, "%-20s %8"PRId64"\n", "  fast arrays", s->fast_array_count);
-            fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per fast array)\n",
-                    "  elements", s->fast_array_elements,
-                    s->fast_array_elements * (int)sizeof(JSValue),
-                    (double)s->fast_array_elements / s->fast_array_count);
-        }
-    }
-    if (s->binary_object_count) {
-        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n",
-                "binary objects", s->binary_object_count, s->binary_object_size);
-    }
-}
-
-JSValue JS_GetGlobalObject(JSContext *ctx)
-{
-    return JS_DupValue(ctx, ctx->global_obj);
-}
-
-/* WARNING: obj is freed */
-JSValue JS_Throw(JSContext *ctx, JSValue obj)
-{
-    JSRuntime *rt = ctx->rt;
-    JS_FreeValue(ctx, rt->current_exception);
-    rt->current_exception = obj;
-    return JS_EXCEPTION;
-}
-
-/* return the pending exception (cannot be called twice). */
-JSValue JS_GetException(JSContext *ctx)
-{
-    JSValue val;
-    JSRuntime *rt = ctx->rt;
-    val = rt->current_exception;
-    rt->current_exception = JS_NULL;
-    return val;
-}
-
-static void dbuf_put_leb128(DynBuf *s, uint32_t v)
-{
-    uint32_t a;
-    for(;;) {
-        a = v & 0x7f;
-        v >>= 7;
-        if (v != 0) {
-            dbuf_putc(s, a | 0x80);
-        } else {
-            dbuf_putc(s, a);
-            break;
-        }
-    }
-}
-
-static void dbuf_put_sleb128(DynBuf *s, int32_t v1)
-{
-    uint32_t v = v1;
-    dbuf_put_leb128(s, (2 * v) ^ -(v >> 31));
-}
-
-static int get_leb128(uint32_t *pval, const uint8_t *buf,
-                      const uint8_t *buf_end)
-{
-    const uint8_t *ptr = buf;
-    uint32_t v, a, i;
-    v = 0;
-    for(i = 0; i < 5; i++) {
-        if (unlikely(ptr >= buf_end))
-            break;
-        a = *ptr++;
-        v |= (a & 0x7f) << (i * 7);
-        if (!(a & 0x80)) {
-            *pval = v;
-            return ptr - buf;
-        }
-    }
-    *pval = 0;
-    return -1;
-}
-
-static int get_sleb128(int32_t *pval, const uint8_t *buf,
-                       const uint8_t *buf_end)
-{
-    int ret;
-    uint32_t val;
-    ret = get_leb128(&val, buf, buf_end);
-    if (ret < 0) {
-        *pval = 0;
-        return -1;
-    }
-    *pval = (val >> 1) ^ -(val & 1);
-    return ret;
-}
-
-static int find_line_num(JSContext *ctx, JSFunctionBytecode *b,
-                         uint32_t pc_value)
-{
-    const uint8_t *p_end, *p;
-    int new_line_num, line_num, pc, v, ret;
-    unsigned int op;
-
-    if (!b->has_debug || !b->debug.pc2line_buf) {
-        /* function was stripped */
-        return -1;
-    }
-
-    p = b->debug.pc2line_buf;
-    p_end = p + b->debug.pc2line_len;
-    pc = 0;
-    line_num = b->debug.line_num;
-    while (p < p_end) {
-        op = *p++;
-        if (op == 0) {
-            uint32_t val;
-            ret = get_leb128(&val, p, p_end);
-            if (ret < 0)
-                goto fail;
-            pc += val;
-            p += ret;
-            ret = get_sleb128(&v, p, p_end);
-            if (ret < 0) {
-            fail:
-                /* should never happen */
-                return b->debug.line_num;
-            }
-            p += ret;
-            new_line_num = line_num + v;
-        } else {
-            op -= PC2LINE_OP_FIRST;
-            pc += (op / PC2LINE_RANGE);
-            new_line_num = line_num + (op % PC2LINE_RANGE) + PC2LINE_BASE;
-        }
-        if (pc_value < pc)
-            return line_num;
-        line_num = new_line_num;
-    }
-    return line_num;
-}
-
-/* in order to avoid executing arbitrary code during the stack trace
-   generation, we only look at simple 'name' properties containing a
-   string. */
-static const char *get_func_name(JSContext *ctx, JSValueConst func)
-{
-    JSProperty *pr;
-    JSShapeProperty *prs;
-    JSValueConst val;
-    
-    if (JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)
-        return NULL;
-    prs = find_own_property(&pr, JS_VALUE_GET_OBJ(func), JS_ATOM_name);
-    if (!prs)
-        return NULL;
-    if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
-        return NULL;
-    val = pr->u.value;
-    if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
-        return NULL;
-    return JS_ToCString(ctx, val);
-}
-
-#define JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL (1 << 0)
-/* only taken into account if filename is provided */
-#define JS_BACKTRACE_FLAG_SINGLE_LEVEL     (1 << 1)
-
-/* if filename != NULL, an additional level is added with the filename
-   and line number information (used for parse error). */
-static void build_backtrace(JSContext *ctx, JSValueConst error_obj,
-                            const char *filename, int line_num,
-                            int backtrace_flags)
-{
-    JSStackFrame *sf;
-    JSValue str;
-    DynBuf dbuf;
-    const char *func_name_str;
-    const char *str1;
-    JSObject *p;
-    BOOL backtrace_barrier;
-    
-    js_dbuf_init(ctx, &dbuf);
-    if (filename) {
-        dbuf_printf(&dbuf, "    at %s", filename);
-        if (line_num != -1)
-            dbuf_printf(&dbuf, ":%d", line_num);
-        dbuf_putc(&dbuf, '\n');
-        str = JS_NewString(ctx, filename);
-        JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_fileName, str,
-                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-        JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_lineNumber, JS_NewInt32(ctx, line_num),
-                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-        if (backtrace_flags & JS_BACKTRACE_FLAG_SINGLE_LEVEL)
-            goto done;
-    }
-    for(sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) {
-        if (backtrace_flags & JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL) {
-            backtrace_flags &= ~JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL;
-            continue;
-        }
-        func_name_str = get_func_name(ctx, sf->cur_func);
-        if (!func_name_str || func_name_str[0] == '\0')
-            str1 = "<anonymous>";
-        else
-            str1 = func_name_str;
-        dbuf_printf(&dbuf, "    at %s", str1);
-        JS_FreeCString(ctx, func_name_str);
-
-        p = JS_VALUE_GET_OBJ(sf->cur_func);
-        backtrace_barrier = FALSE;
-        if (js_class_has_bytecode(p->class_id)) {
-            JSFunctionBytecode *b;
-            const char *atom_str;
-            int line_num1;
-
-            b = p->u.func.function_bytecode;
-            backtrace_barrier = b->backtrace_barrier;
-            if (b->has_debug) {
-                line_num1 = find_line_num(ctx, b,
-                                          sf->cur_pc - b->byte_code_buf - 1);
-                atom_str = JS_AtomToCString(ctx, b->debug.filename);
-                dbuf_printf(&dbuf, " (%s",
-                            atom_str ? atom_str : "<null>");
-                JS_FreeCString(ctx, atom_str);
-                if (line_num1 != -1)
-                    dbuf_printf(&dbuf, ":%d", line_num1);
-                dbuf_putc(&dbuf, ')');
-            }
-        } else {
-            dbuf_printf(&dbuf, " (native)");
-        }
-        dbuf_putc(&dbuf, '\n');
-        /* stop backtrace if JS_EVAL_FLAG_BACKTRACE_BARRIER was used */
-        if (backtrace_barrier)
-            break;
-    }
- done:
-    dbuf_putc(&dbuf, '\0');
-    if (dbuf_error(&dbuf))
-        str = JS_NULL;
-    else
-        str = JS_NewString(ctx, (char *)dbuf.buf);
-    dbuf_free(&dbuf);
-    JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_stack, str,
-                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-}
-
-/* Note: it is important that no exception is returned by this function */
-static BOOL is_backtrace_needed(JSContext *ctx, JSValueConst obj)
-{
-    JSObject *p;
-    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
-        return FALSE;
-    p = JS_VALUE_GET_OBJ(obj);
-    if (p->class_id != JS_CLASS_ERROR)
-        return FALSE;
-    if (find_own_property1(p, JS_ATOM_stack))
-        return FALSE;
-    return TRUE;
-}
-
-JSValue JS_NewError(JSContext *ctx)
-{
-    return JS_NewObjectClass(ctx, JS_CLASS_ERROR);
-}
-
-static JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num,
-                              const char *fmt, va_list ap, BOOL add_backtrace)
-{
-    char buf[256];
-    JSValue obj, ret;
-
-    vsnprintf(buf, sizeof(buf), fmt, ap);
-    obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[error_num],
-                                 JS_CLASS_ERROR);
-    if (unlikely(JS_IsException(obj))) {
-        /* out of memory: throw JS_NULL to avoid recursing */
-        obj = JS_NULL;
-    } else {
-        JS_DefinePropertyValue(ctx, obj, JS_ATOM_message,
-                               JS_NewString(ctx, buf),
-                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-    }
-    if (add_backtrace) {
-        build_backtrace(ctx, obj, NULL, 0, 0);
-    }
-    ret = JS_Throw(ctx, obj);
-    return ret;
-}
-
-static JSValue JS_ThrowError(JSContext *ctx, JSErrorEnum error_num,
-                             const char *fmt, va_list ap)
-{
-    JSRuntime *rt = ctx->rt;
-    JSStackFrame *sf;
-    BOOL add_backtrace;
-
-    /* the backtrace is added later if called from a bytecode function */
-    sf = rt->current_stack_frame;
-    add_backtrace = !rt->in_out_of_memory &&
-        (!sf || (JS_GetFunctionBytecode(sf->cur_func) == NULL));
-    return JS_ThrowError2(ctx, error_num, fmt, ap, add_backtrace);
-}
-
-JSValue __attribute__((format(printf, 2, 3))) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...)
-{
-    JSValue val;
-    va_list ap;
-
-    va_start(ap, fmt);
-    val = JS_ThrowError(ctx, JS_SYNTAX_ERROR, fmt, ap);
-    va_end(ap);
-    return val;
-}
-
-JSValue __attribute__((format(printf, 2, 3))) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...)
-{
-    JSValue val;
-    va_list ap;
-
-    va_start(ap, fmt);
-    val = JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);
-    va_end(ap);
-    return val;
-}
-
-static int __attribute__((format(printf, 3, 4))) JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, const char *fmt, ...)
-{
-    va_list ap;
-
-    if ((flags & JS_PROP_THROW) ||
-        ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
-        va_start(ap, fmt);
-        JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);
-        va_end(ap);
-        return -1;
-    } else {
-        return FALSE;
-    }
-}
-
-/* never use it directly */
-static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowTypeErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
-{
-    char buf[ATOM_GET_STR_BUF_SIZE];
-    return JS_ThrowTypeError(ctx, fmt,
-                             JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
-}
-
-/* never use it directly */
-static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowSyntaxErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
-{
-    char buf[ATOM_GET_STR_BUF_SIZE];
-    return JS_ThrowSyntaxError(ctx, fmt,
-                             JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
-}
-
-/* %s is replaced by 'atom'. The macro is used so that gcc can check
-    the format string. */
-#define JS_ThrowTypeErrorAtom(ctx, fmt, atom) __JS_ThrowTypeErrorAtom(ctx, atom, fmt, "")
-#define JS_ThrowSyntaxErrorAtom(ctx, fmt, atom) __JS_ThrowSyntaxErrorAtom(ctx, atom, fmt, "")
-
-static int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int flags, JSAtom atom)
-{
-    if ((flags & JS_PROP_THROW) ||
-        ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
-        JS_ThrowTypeErrorAtom(ctx, "'%s' is read-only", atom);
-        return -1;
-    } else {
-        return FALSE;
-    }
-}
-
-JSValue __attribute__((format(printf, 2, 3))) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...)
-{
-    JSValue val;
-    va_list ap;
-
-    va_start(ap, fmt);
-    val = JS_ThrowError(ctx, JS_REFERENCE_ERROR, fmt, ap);
-    va_end(ap);
-    return val;
-}
-
-JSValue __attribute__((format(printf, 2, 3))) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...)
-{
-    JSValue val;
-    va_list ap;
-
-    va_start(ap, fmt);
-    val = JS_ThrowError(ctx, JS_RANGE_ERROR, fmt, ap);
-    va_end(ap);
-    return val;
-}
-
-JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...)
-{
-    JSValue val;
-    va_list ap;
-
-    va_start(ap, fmt);
-    val = JS_ThrowError(ctx, JS_INTERNAL_ERROR, fmt, ap);
-    va_end(ap);
-    return val;
-}
-
-JSValue JS_ThrowOutOfMemory(JSContext *ctx)
-{
-    JSRuntime *rt = ctx->rt;
-    if (!rt->in_out_of_memory) {
-        rt->in_out_of_memory = TRUE;
-        JS_ThrowInternalError(ctx, "out of memory");
-        rt->in_out_of_memory = FALSE;
-    }
-    return JS_EXCEPTION;
-}
-
-static JSValue JS_ThrowStackOverflow(JSContext *ctx)
-{
-    return JS_ThrowInternalError(ctx, "stack overflow");
-}
-
-static JSValue JS_ThrowTypeErrorNotAnObject(JSContext *ctx)
-{
-    return JS_ThrowTypeError(ctx, "not an object");
-}
-
-static JSValue JS_ThrowTypeErrorNotASymbol(JSContext *ctx)
-{
-    return JS_ThrowTypeError(ctx, "not a symbol");
-}
-
-static JSValue JS_ThrowReferenceErrorNotDefined(JSContext *ctx, JSAtom name)
-{
-    char buf[ATOM_GET_STR_BUF_SIZE];
-    return JS_ThrowReferenceError(ctx, "'%s' is not defined",
-                                  JS_AtomGetStr(ctx, buf, sizeof(buf), name));
-}
-
-static JSValue JS_ThrowReferenceErrorUninitialized(JSContext *ctx, JSAtom name)
-{
-    char buf[ATOM_GET_STR_BUF_SIZE];
-    return JS_ThrowReferenceError(ctx, "%s is not initialized",
-                                  name == JS_ATOM_NULL ? "lexical variable" :
-                                  JS_AtomGetStr(ctx, buf, sizeof(buf), name));
-}
-
-static JSValue JS_ThrowReferenceErrorUninitialized2(JSContext *ctx,
-                                                    JSFunctionBytecode *b,
-                                                    int idx, BOOL is_ref)
-{
-    JSAtom atom = JS_ATOM_NULL;
-    if (is_ref) {
-        atom = b->closure_var[idx].var_name;
-    } else {
-        /* not present if the function is stripped and contains no eval() */
-        if (b->vardefs)
-            atom = b->vardefs[b->arg_count + idx].var_name;
-    }
-    return JS_ThrowReferenceErrorUninitialized(ctx, atom);
-}
-
-static JSValue JS_ThrowTypeErrorInvalidClass(JSContext *ctx, int class_id)
-{
-    JSRuntime *rt = ctx->rt;
-    JSAtom name;
-    name = rt->class_array[class_id].class_name;
-    return JS_ThrowTypeErrorAtom(ctx, "%s object expected", name);
-}
-
-static no_inline __exception int __js_poll_interrupts(JSContext *ctx)
-{
-    JSRuntime *rt = ctx->rt;
-    ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT;
-    if (rt->interrupt_handler) {
-        if (rt->interrupt_handler(rt, rt->interrupt_opaque)) {
-            /* XXX: should set a specific flag to avoid catching */
-            JS_ThrowInternalError(ctx, "interrupted");
-            JS_SetUncatchableError(ctx, ctx->rt->current_exception, TRUE);
-            return -1;
-        }
-    }
-    return 0;
-}
-
-static inline __exception int js_poll_interrupts(JSContext *ctx)
-{
-    if (unlikely(--ctx->interrupt_counter <= 0)) {
-        return __js_poll_interrupts(ctx);
-    } else {
-        return 0;
-    }
-}
-
-/* return -1 (exception) or TRUE/FALSE */
-static int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj,
-                                   JSValueConst proto_val,
-                                   BOOL throw_flag)
-{
-    JSObject *proto, *p, *p1;
-    JSShape *sh;
-
-    if (throw_flag) {
-        if (JS_VALUE_GET_TAG(obj) == JS_TAG_NULL ||
-            JS_VALUE_GET_TAG(obj) == JS_TAG_UNDEFINED)
-            goto not_obj;
-    } else {
-        if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
-            goto not_obj;
-    }
-    p = JS_VALUE_GET_OBJ(obj);
-    if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT) {
-        if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_NULL) {
-        not_obj:
-            JS_ThrowTypeErrorNotAnObject(ctx);
-            return -1;
-        }
-        proto = NULL;
-    } else {
-        proto = JS_VALUE_GET_OBJ(proto_val);
-    }
-
-    if (throw_flag && JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
-        return TRUE;
-
-    if (unlikely(p->class_id == JS_CLASS_PROXY))
-        return js_proxy_setPrototypeOf(ctx, obj, proto_val, throw_flag);
-    sh = p->shape;
-    if (sh->proto == proto)
-        return TRUE;
-    if (!p->extensible) {
-        if (throw_flag) {
-            JS_ThrowTypeError(ctx, "object is not extensible");
-            return -1;
-        } else {
-            return FALSE;
-        }
-    }
-    if (proto) {
-        /* check if there is a cycle */
-        p1 = proto;
-        do {
-            if (p1 == p) {
-                if (throw_flag) {
-                    JS_ThrowTypeError(ctx, "circular prototype chain");
-                    return -1;
-                } else {
-                    return FALSE;
-                }
-            }
-            /* Note: for Proxy objects, proto is NULL */
-            p1 = p1->shape->proto;
-        } while (p1 != NULL);
-        JS_DupValue(ctx, proto_val);
-    }
-
-    if (js_shape_prepare_update(ctx, p, NULL))
-        return -1;
-    sh = p->shape;
-    if (sh->proto)
-        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
-    sh->proto = proto;
-    return TRUE;
-}
-
-/* return -1 (exception) or TRUE/FALSE */
-int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val)
-{
-    return JS_SetPrototypeInternal(ctx, obj, proto_val, TRUE);
-}
-
-/* Only works for primitive types, otherwise return JS_NULL. */
-static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val)
-{
-    switch(JS_VALUE_GET_NORM_TAG(val)) {
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_INT:
-        val = ctx->class_proto[JS_CLASS_BIG_INT];
-        break;
-    case JS_TAG_BIG_FLOAT:
-        val = ctx->class_proto[JS_CLASS_BIG_FLOAT];
-        break;
-    case JS_TAG_BIG_DECIMAL:
-        val = ctx->class_proto[JS_CLASS_BIG_DECIMAL];
-        break;
-#endif
-    case JS_TAG_INT:
-    case JS_TAG_FLOAT64:
-        val = ctx->class_proto[JS_CLASS_NUMBER];
-        break;
-    case JS_TAG_BOOL:
-        val = ctx->class_proto[JS_CLASS_BOOLEAN];
-        break;
-    case JS_TAG_STRING:
-        val = ctx->class_proto[JS_CLASS_STRING];
-        break;
-    case JS_TAG_SYMBOL:
-        val = ctx->class_proto[JS_CLASS_SYMBOL];
-        break;
-    case JS_TAG_OBJECT:
-    case JS_TAG_NULL:
-    case JS_TAG_UNDEFINED:
-    default:
-        val = JS_NULL;
-        break;
-    }
-    return val;
-}
-
-/* Return an Object, JS_NULL or JS_EXCEPTION in case of Proxy object. */
-JSValue JS_GetPrototype(JSContext *ctx, JSValueConst obj)
-{
-    JSValue val;
-    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
-        JSObject *p;
-        p = JS_VALUE_GET_OBJ(obj);
-        if (unlikely(p->class_id == JS_CLASS_PROXY)) {
-            val = js_proxy_getPrototypeOf(ctx, obj);
-        } else {
-            p = p->shape->proto;
-            if (!p)
-                val = JS_NULL;
-            else
-                val = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
-        }
-    } else {
-        val = JS_DupValue(ctx, JS_GetPrototypePrimitive(ctx, obj));
-    }
-    return val;
-}
-
-static JSValue JS_GetPrototypeFree(JSContext *ctx, JSValue obj)
-{
-    JSValue obj1;
-    obj1 = JS_GetPrototype(ctx, obj);
-    JS_FreeValue(ctx, obj);
-    return obj1;
-}
-
-/* return TRUE, FALSE or (-1) in case of exception */
-static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val,
-                                   JSValueConst obj)
-{
-    JSValue obj_proto;
-    JSObject *proto;
-    const JSObject *p, *proto1;
-    BOOL ret;
-
-    if (!JS_IsFunction(ctx, obj))
-        return FALSE;
-    p = JS_VALUE_GET_OBJ(obj);
-    if (p->class_id == JS_CLASS_BOUND_FUNCTION) {
-        JSBoundFunction *s = p->u.bound_function;
-        return JS_IsInstanceOf(ctx, val, s->func_obj);
-    }
-
-    /* Only explicitly boxed values are instances of constructors */
-    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
-        return FALSE;
-    obj_proto = JS_GetProperty(ctx, obj, JS_ATOM_prototype);
-    if (JS_VALUE_GET_TAG(obj_proto) != JS_TAG_OBJECT) {
-        if (!JS_IsException(obj_proto))
-            JS_ThrowTypeError(ctx, "operand 'prototype' property is not an object");
-        ret = -1;
-        goto done;
-    }
-    proto = JS_VALUE_GET_OBJ(obj_proto);
-    p = JS_VALUE_GET_OBJ(val);
-    for(;;) {
-        proto1 = p->shape->proto;
-        if (!proto1) {
-            /* slow case if proxy in the prototype chain */
-            if (unlikely(p->class_id == JS_CLASS_PROXY)) {
-                JSValue obj1;
-                obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, (JSObject *)p));
-                for(;;) {
-                    obj1 = JS_GetPrototypeFree(ctx, obj1);
-                    if (JS_IsException(obj1)) {
-                        ret = -1;
-                        break;
-                    }
-                    if (JS_IsNull(obj1)) {
-                        ret = FALSE;
-                        break;
-                    }
-                    if (proto == JS_VALUE_GET_OBJ(obj1)) {
-                        JS_FreeValue(ctx, obj1);
-                        ret = TRUE;
-                        break;
-                    }
-                    /* must check for timeout to avoid infinite loop */
-                    if (js_poll_interrupts(ctx)) {
-                        JS_FreeValue(ctx, obj1);
-                        ret = -1;
-                        break;
-                    }
-                }
-            } else {
-                ret = FALSE;
-            }
-            break;
-        }
-        p = proto1;
-        if (proto == p) {
-            ret = TRUE;
-            break;
-        }
-    }
-done:
-    JS_FreeValue(ctx, obj_proto);
-    return ret;
-}
-
-/* return TRUE, FALSE or (-1) in case of exception */
-int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj)
-{
-    JSValue method;
-
-    if (!JS_IsObject(obj))
-        goto fail;
-    method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_hasInstance);
-    if (JS_IsException(method))
-        return -1;
-    if (!JS_IsNull(method) && !JS_IsUndefined(method)) {
-        JSValue ret;
-        ret = JS_CallFree(ctx, method, obj, 1, &val);
-        return JS_ToBoolFree(ctx, ret);
-    }
-
-    /* legacy case */
-    if (!JS_IsFunction(ctx, obj)) {
-    fail:
-        JS_ThrowTypeError(ctx, "invalid 'instanceof' right operand");
-        return -1;
-    }
-    return JS_OrdinaryIsInstanceOf(ctx, val, obj);
-}
-
-/* return the value associated to the autoinit property or an exception */
-typedef JSValue JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
-
-static JSAutoInitFunc *js_autoinit_func_table[] = {
-    js_instantiate_prototype, /* JS_AUTOINIT_ID_PROTOTYPE */
-    js_module_ns_autoinit, /* JS_AUTOINIT_ID_MODULE_NS */
-    JS_InstantiateFunctionListItem2, /* JS_AUTOINIT_ID_PROP */
-};
-
-/* warning: 'prs' is reallocated after it */
-static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop,
-                               JSProperty *pr, JSShapeProperty *prs)
-{
-    JSValue val;
-    JSContext *realm;
-    JSAutoInitFunc *func;
-
-    if (js_shape_prepare_update(ctx, p, &prs))
-        return -1;
-
-    realm = js_autoinit_get_realm(pr);
-    func = js_autoinit_func_table[js_autoinit_get_id(pr)];
-    /* 'func' shall not modify the object properties 'pr' */
-    val = func(realm, p, prop, pr->u.init.opaque);
-    js_autoinit_free(ctx->rt, pr);
-    prs->flags &= ~JS_PROP_TMASK;
-    pr->u.value = JS_UNDEFINED;
-    if (JS_IsException(val))
-        return -1;
-    pr->u.value = val;
-    return 0;
-}
-
-JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
-                               JSAtom prop, JSValueConst this_obj,
-                               BOOL throw_ref_error)
-{
-    JSObject *p;
-    JSProperty *pr;
-    JSShapeProperty *prs;
-    uint32_t tag;
-
-    tag = JS_VALUE_GET_TAG(obj);
-    if (unlikely(tag != JS_TAG_OBJECT)) {
-        switch(tag) {
-        case JS_TAG_NULL:
-            return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of null", prop);
-        case JS_TAG_UNDEFINED:
-            return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of undefined", prop);
-        case JS_TAG_EXCEPTION:
-            return JS_EXCEPTION;
-        case JS_TAG_STRING:
-            {
-                JSString *p1 = JS_VALUE_GET_STRING(obj);
-                if (__JS_AtomIsTaggedInt(prop)) {
-                    uint32_t idx, ch;
-                    idx = __JS_AtomToUInt32(prop);
-                    if (idx < p1->len) {
-                        if (p1->is_wide_char)
-                            ch = p1->u.str16[idx];
-                        else
-                            ch = p1->u.str8[idx];
-                        return js_new_string_char(ctx, ch);
-                    }
-                } else if (prop == JS_ATOM_length) {
-                    return JS_NewInt32(ctx, p1->len);
-                }
-            }
-            break;
-        default:
-            break;
-        }
-        /* cannot raise an exception */
-        p = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj));
-        if (!p)
-            return JS_UNDEFINED;
-    } else {
-        p = JS_VALUE_GET_OBJ(obj);
-    }
-
-    for(;;) {
-        prs = find_own_property(&pr, p, prop);
-        if (prs) {
-            /* found */
-            if (unlikely(prs->flags & JS_PROP_TMASK)) {
-                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
-                    if (unlikely(!pr->u.getset.getter)) {
-                        return JS_UNDEFINED;
-                    } else {
-                        JSValue func = JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter);
-                        /* Note: the field could be removed in the getter */
-                        func = JS_DupValue(ctx, func);
-                        return JS_CallFree(ctx, func, this_obj, 0, NULL);
-                    }
-                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
-                    JSValue val = *pr->u.var_ref->pvalue;
-                    if (unlikely(JS_IsUninitialized(val)))
-                        return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
-                    return JS_DupValue(ctx, val);
-                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
-                    /* Instantiate property and retry */
-                    if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
-                        return JS_EXCEPTION;
-                    continue;
-                }
-            } else {
-                return JS_DupValue(ctx, pr->u.value);
-            }
-        }
-        if (unlikely(p->is_exotic)) {
-            /* exotic behaviors */
-            if (p->fast_array) {
-                if (__JS_AtomIsTaggedInt(prop)) {
-                    uint32_t idx = __JS_AtomToUInt32(prop);
-                    if (idx < p->u.array.count) {
-                        /* we avoid duplicating the code */
-                        return JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
-                    } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
-                               p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
-                        return JS_UNDEFINED;
-                    }
-                } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
-                           p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
-                    int ret;
-                    ret = JS_AtomIsNumericIndex(ctx, prop);
-                    if (ret != 0) {
-                        if (ret < 0)
-                            return JS_EXCEPTION;
-                        return JS_UNDEFINED;
-                    }
-                }
-            } else {
-                const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
-                if (em) {
-                    if (em->get_property) {
-                        JSValue obj1, retval;
-                        /* XXX: should pass throw_ref_error */
-                        /* Note: if 'p' is a prototype, it can be
-                           freed in the called function */
-                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
-                        retval = em->get_property(ctx, obj1, prop, this_obj);
-                        JS_FreeValue(ctx, obj1);
-                        return retval;
-                    }
-                    if (em->get_own_property) {
-                        JSPropertyDescriptor desc;
-                        int ret;
-                        JSValue obj1;
-
-                        /* Note: if 'p' is a prototype, it can be
-                           freed in the called function */
-                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
-                        ret = em->get_own_property(ctx, &desc, obj1, prop);
-                        JS_FreeValue(ctx, obj1);
-                        if (ret < 0)
-                            return JS_EXCEPTION;
-                        if (ret) {
-                            if (desc.flags & JS_PROP_GETSET) {
-                                JS_FreeValue(ctx, desc.setter);
-                                return JS_CallFree(ctx, desc.getter, this_obj, 0, NULL);
-                            } else {
-                                return desc.value;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        p = p->shape->proto;
-        if (!p)
-            break;
-    }
-    if (unlikely(throw_ref_error)) {
-        return JS_ThrowReferenceErrorNotDefined(ctx, prop);
-    } else {
-        return JS_UNDEFINED;
-    }
-}
-
-static JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom)
-{
-    return JS_ThrowTypeErrorAtom(ctx, "private class field '%s' does not exist",
-                                 atom);
-}
-
-/* Private fields can be added even on non extensible objects or
-   Proxies */
-static int JS_DefinePrivateField(JSContext *ctx, JSValueConst obj,
-                                 JSValueConst name, JSValue val)
-{
-    JSObject *p;
-    JSShapeProperty *prs;
-    JSProperty *pr;
-    JSAtom prop;
-
-    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
-        JS_ThrowTypeErrorNotAnObject(ctx);
-        goto fail;
-    }
-    /* safety check */
-    if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) {
-        JS_ThrowTypeErrorNotASymbol(ctx);
-        goto fail;
-    }
-    prop = js_symbol_to_atom(ctx, (JSValue)name);
-    p = JS_VALUE_GET_OBJ(obj);
-    prs = find_own_property(&pr, p, prop);
-    if (prs) {
-        JS_ThrowTypeErrorAtom(ctx, "private class field '%s' already exists",
-                              prop);
-        goto fail;
-    }
-    pr = add_property(ctx, p, prop, JS_PROP_C_W_E);
-    if (unlikely(!pr)) {
-    fail:
-        JS_FreeValue(ctx, val);
-        return -1;
-    }
-    pr->u.value = val;
-    return 0;
-}
-
-static JSValue JS_GetPrivateField(JSContext *ctx, JSValueConst obj,
-                                  JSValueConst name)
-{
-    JSObject *p;
-    JSShapeProperty *prs;
-    JSProperty *pr;
-    JSAtom prop;
-
-    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-    /* safety check */
-    if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL))
-        return JS_ThrowTypeErrorNotASymbol(ctx);
-    prop = js_symbol_to_atom(ctx, (JSValue)name);
-    p = JS_VALUE_GET_OBJ(obj);
-    prs = find_own_property(&pr, p, prop);
-    if (!prs) {
-        JS_ThrowTypeErrorPrivateNotFound(ctx, prop);
-        return JS_EXCEPTION;
-    }
-    return JS_DupValue(ctx, pr->u.value);
-}
-
-static int JS_SetPrivateField(JSContext *ctx, JSValueConst obj,
-                              JSValueConst name, JSValue val)
-{
-    JSObject *p;
-    JSShapeProperty *prs;
-    JSProperty *pr;
-    JSAtom prop;
-
-    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
-        JS_ThrowTypeErrorNotAnObject(ctx);
-        goto fail;
-    }
-    /* safety check */
-    if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) {
-        JS_ThrowTypeErrorNotASymbol(ctx);
-        goto fail;
-    }
-    prop = js_symbol_to_atom(ctx, (JSValue)name);
-    p = JS_VALUE_GET_OBJ(obj);
-    prs = find_own_property(&pr, p, prop);
-    if (!prs) {
-        JS_ThrowTypeErrorPrivateNotFound(ctx, prop);
-    fail:
-        JS_FreeValue(ctx, val);
-        return -1;
-    }
-    set_value(ctx, &pr->u.value, val);
-    return 0;
-}
-
-static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj)
-{
-    JSObject *p, *p1;
-    JSShapeProperty *prs;
-    JSProperty *pr;
-    JSValue brand;
-    JSAtom brand_atom;
-    
-    if (unlikely(JS_VALUE_GET_TAG(home_obj) != JS_TAG_OBJECT)) {
-        JS_ThrowTypeErrorNotAnObject(ctx);
-        return -1;
-    }
-    p = JS_VALUE_GET_OBJ(home_obj);
-    prs = find_own_property(&pr, p, JS_ATOM_Private_brand);
-    if (!prs) {
-        brand = JS_NewSymbolFromAtom(ctx, JS_ATOM_brand, JS_ATOM_TYPE_PRIVATE);
-        if (JS_IsException(brand))
-            return -1;
-        /* if the brand is not present, add it */
-        pr = add_property(ctx, p, JS_ATOM_Private_brand, JS_PROP_C_W_E);
-        if (!pr) {
-            JS_FreeValue(ctx, brand);
-            return -1;
-        }
-        pr->u.value = JS_DupValue(ctx, brand);
-    } else {
-        brand = JS_DupValue(ctx, pr->u.value);
-    }
-    brand_atom = js_symbol_to_atom(ctx, brand);
-    
-    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
-        JS_ThrowTypeErrorNotAnObject(ctx);
-        JS_FreeAtom(ctx, brand_atom);
-        return -1;
-    }
-    p1 = JS_VALUE_GET_OBJ(obj);
-    pr = add_property(ctx, p1, brand_atom, JS_PROP_C_W_E);
-    JS_FreeAtom(ctx, brand_atom);
-    if (!pr)
-        return -1;
-    pr->u.value = JS_UNDEFINED;
-    return 0;
-}
-
-static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func)
-{
-    JSObject *p, *p1, *home_obj;
-    JSShapeProperty *prs;
-    JSProperty *pr;
-    JSValueConst brand;
-    
-    /* get the home object of 'func' */
-    if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)) {
-    not_obj:
-        JS_ThrowTypeErrorNotAnObject(ctx);
-        return -1;
-    }
-    p1 = JS_VALUE_GET_OBJ(func);
-    if (!js_class_has_bytecode(p1->class_id))
-        goto not_obj;
-    home_obj = p1->u.func.home_object;
-    if (!home_obj)
-        goto not_obj;
-    prs = find_own_property(&pr, home_obj, JS_ATOM_Private_brand);
-    if (!prs) {
-        JS_ThrowTypeError(ctx, "expecting <brand> private field");
-        return -1;
-    }
-    brand = pr->u.value;
-    /* safety check */
-    if (unlikely(JS_VALUE_GET_TAG(brand) != JS_TAG_SYMBOL))
-        goto not_obj;
-    
-    /* get the brand array of 'obj' */
-    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
-        goto not_obj;
-    p = JS_VALUE_GET_OBJ(obj);
-    prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, (JSValue)brand));
-    if (!prs) {
-        JS_ThrowTypeError(ctx, "invalid brand on object");
-        return -1;
-    }
-    return 0;
-}
-
-static uint32_t js_string_obj_get_length(JSContext *ctx,
-                                         JSValueConst obj)
-{
-    JSObject *p;
-    JSString *p1;
-    uint32_t len = 0;
-
-    /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
-    p = JS_VALUE_GET_OBJ(obj);
-    if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
-        p1 = JS_VALUE_GET_STRING(p->u.object_data);
-        len = p1->len;
-    }
-    return len;
-}
-
-static int num_keys_cmp(const void *p1, const void *p2, void *opaque)
-{
-    JSContext *ctx = opaque;
-    JSAtom atom1 = ((const JSPropertyEnum *)p1)->atom;
-    JSAtom atom2 = ((const JSPropertyEnum *)p2)->atom;
-    uint32_t v1, v2;
-    BOOL atom1_is_integer, atom2_is_integer;
-
-    atom1_is_integer = JS_AtomIsArrayIndex(ctx, &v1, atom1);
-    atom2_is_integer = JS_AtomIsArrayIndex(ctx, &v2, atom2);
-    assert(atom1_is_integer && atom2_is_integer);
-    if (v1 < v2)
-        return -1;
-    else if (v1 == v2)
-        return 0;
-    else
-        return 1;
-}
-
-static void js_free_prop_enum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len)
-{
-    uint32_t i;
-    if (tab) {
-        for(i = 0; i < len; i++)
-            JS_FreeAtom(ctx, tab[i].atom);
-        js_free(ctx, tab);
-    }
-}
-
-/* return < 0 in case if exception, 0 if OK. ptab and its atoms must
-   be freed by the user. */
-static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
-                                                      JSPropertyEnum **ptab,
-                                                      uint32_t *plen,
-                                                      JSObject *p, int flags)
-{
-    int i, j;
-    JSShape *sh;
-    JSShapeProperty *prs;
-    JSPropertyEnum *tab_atom, *tab_exotic;
-    JSAtom atom;
-    uint32_t num_keys_count, str_keys_count, sym_keys_count, atom_count;
-    uint32_t num_index, str_index, sym_index, exotic_count, exotic_keys_count;
-    BOOL is_enumerable, num_sorted;
-    uint32_t num_key;
-    JSAtomKindEnum kind;
-    
-    /* clear pointer for consistency in case of failure */
-    *ptab = NULL;
-    *plen = 0;
-
-    /* compute the number of returned properties */
-    num_keys_count = 0;
-    str_keys_count = 0;
-    sym_keys_count = 0;
-    exotic_keys_count = 0;
-    exotic_count = 0;
-    tab_exotic = NULL;
-    sh = p->shape;
-    for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
-        atom = prs->atom;
-        if (atom != JS_ATOM_NULL) {
-            is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0);
-            kind = JS_AtomGetKind(ctx, atom);
-            if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
-                ((flags >> kind) & 1) != 0) {
-                /* need to raise an exception in case of the module
-                   name space (implicit GetOwnProperty) */
-                if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) &&
-                    (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY))) {
-                    JSVarRef *var_ref = p->prop[i].u.var_ref;
-                    if (unlikely(JS_IsUninitialized(*var_ref->pvalue))) {
-                        JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
-                        return -1;
-                    }
-                }
-                if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
-                    num_keys_count++;
-                } else if (kind == JS_ATOM_KIND_STRING) {
-                    str_keys_count++;
-                } else {
-                    sym_keys_count++;
-                }
-            }
-        }
-    }
-
-    if (p->is_exotic) {
-        if (p->fast_array) {
-            if (flags & JS_GPN_STRING_MASK) {
-                num_keys_count += p->u.array.count;
-            }
-        } else if (p->class_id == JS_CLASS_STRING) {
-            if (flags & JS_GPN_STRING_MASK) {
-                num_keys_count += js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
-            }
-        } else {
-            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
-            if (em && em->get_own_property_names) {
-                if (em->get_own_property_names(ctx, &tab_exotic, &exotic_count,
-                                               JS_MKPTR(JS_TAG_OBJECT, p)))
-                    return -1;
-                for(i = 0; i < exotic_count; i++) {
-                    atom = tab_exotic[i].atom;
-                    kind = JS_AtomGetKind(ctx, atom);
-                    if (((flags >> kind) & 1) != 0) {
-                        is_enumerable = FALSE;
-                        if (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY)) {
-                            JSPropertyDescriptor desc;
-                            int res;
-                            /* set the "is_enumerable" field if necessary */
-                            res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
-                            if (res < 0) {
-                                js_free_prop_enum(ctx, tab_exotic, exotic_count);
-                                return -1;
-                            }
-                            if (res) {
-                                is_enumerable =
-                                    ((desc.flags & JS_PROP_ENUMERABLE) != 0);
-                                js_free_desc(ctx, &desc);
-                            }
-                            tab_exotic[i].is_enumerable = is_enumerable;
-                        }
-                        if (!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) {
-                            exotic_keys_count++;
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /* fill them */
-
-    atom_count = num_keys_count + str_keys_count + sym_keys_count + exotic_keys_count;
-    /* avoid allocating 0 bytes */
-    tab_atom = js_malloc(ctx, sizeof(tab_atom[0]) * max_int(atom_count, 1));
-    if (!tab_atom) {
-        js_free_prop_enum(ctx, tab_exotic, exotic_count);
-        return -1;
-    }
-
-    num_index = 0;
-    str_index = num_keys_count;
-    sym_index = str_index + str_keys_count;
-
-    num_sorted = TRUE;
-    sh = p->shape;
-    for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
-        atom = prs->atom;
-        if (atom != JS_ATOM_NULL) {
-            is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0);
-            kind = JS_AtomGetKind(ctx, atom);
-            if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
-                ((flags >> kind) & 1) != 0) {
-                if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
-                    j = num_index++;
-                    num_sorted = FALSE;
-                } else if (kind == JS_ATOM_KIND_STRING) {
-                    j = str_index++;
-                } else {
-                    j = sym_index++;
-                }
-                tab_atom[j].atom = JS_DupAtom(ctx, atom);
-                tab_atom[j].is_enumerable = is_enumerable;
-            }
-        }
-    }
-
-    if (p->is_exotic) {
-        int len;
-        if (p->fast_array) {
-            if (flags & JS_GPN_STRING_MASK) {
-                len = p->u.array.count;
-                goto add_array_keys;
-            }
-        } else if (p->class_id == JS_CLASS_STRING) {
-            if (flags & JS_GPN_STRING_MASK) {
-                len = js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
-            add_array_keys:
-                for(i = 0; i < len; i++) {
-                    tab_atom[num_index].atom = __JS_AtomFromUInt32(i);
-                    if (tab_atom[num_index].atom == JS_ATOM_NULL) {
-                        js_free_prop_enum(ctx, tab_atom, num_index);
-                        return -1;
-                    }
-                    tab_atom[num_index].is_enumerable = TRUE;
-                    num_index++;
-                }
-            }
-        } else {
-            /* Note: exotic keys are not reordered and comes after the object own properties. */
-            for(i = 0; i < exotic_count; i++) {
-                atom = tab_exotic[i].atom;
-                is_enumerable = tab_exotic[i].is_enumerable;
-                kind = JS_AtomGetKind(ctx, atom);
-                if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
-                    ((flags >> kind) & 1) != 0) {
-                    tab_atom[sym_index].atom = atom;
-                    tab_atom[sym_index].is_enumerable = is_enumerable;
-                    sym_index++;
-                } else {
-                    JS_FreeAtom(ctx, atom);
-                }
-            }
-            js_free(ctx, tab_exotic);
-        }
-    }
-
-    assert(num_index == num_keys_count);
-    assert(str_index == num_keys_count + str_keys_count);
-    assert(sym_index == atom_count);
-
-    if (num_keys_count != 0 && !num_sorted) {
-        rqsort(tab_atom, num_keys_count, sizeof(tab_atom[0]), num_keys_cmp,
-               ctx);
-    }
-    *ptab = tab_atom;
-    *plen = atom_count;
-    return 0;
-}
-
-int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab,
-                           uint32_t *plen, JSValueConst obj, int flags)
-{
-    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
-        JS_ThrowTypeErrorNotAnObject(ctx);
-        return -1;
-    }
-    return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen,
-                                          JS_VALUE_GET_OBJ(obj), flags);
-}
-
-/* Return -1 if exception,
-   FALSE if the property does not exist, TRUE if it exists. If TRUE is
-   returned, the property descriptor 'desc' is filled present. */
-static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc,
-                                     JSObject *p, JSAtom prop)
-{
-    JSShapeProperty *prs;
-    JSProperty *pr;
-
-retry:
-    prs = find_own_property(&pr, p, prop);
-    if (prs) {
-        if (desc) {
-            desc->flags = prs->flags & JS_PROP_C_W_E;
-            desc->getter = JS_UNDEFINED;
-            desc->setter = JS_UNDEFINED;
-            desc->value = JS_UNDEFINED;
-            if (unlikely(prs->flags & JS_PROP_TMASK)) {
-                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
-                    desc->flags |= JS_PROP_GETSET;
-                    if (pr->u.getset.getter)
-                        desc->getter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
-                    if (pr->u.getset.setter)
-                        desc->setter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
-                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
-                    JSValue val = *pr->u.var_ref->pvalue;
-                    if (unlikely(JS_IsUninitialized(val))) {
-                        JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
-                        return -1;
-                    }
-                    desc->value = JS_DupValue(ctx, val);
-                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
-                    /* Instantiate property and retry */
-                    if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
-                        return -1;
-                    goto retry;
-                }
-            } else {
-                desc->value = JS_DupValue(ctx, pr->u.value);
-            }
-        } else {
-            /* for consistency, send the exception even if desc is NULL */
-            if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF)) {
-                if (unlikely(JS_IsUninitialized(*pr->u.var_ref->pvalue))) {
-                    JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
-                    return -1;
-                }
-            } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
-                /* nothing to do: delay instantiation until actual value and/or attributes are read */
-            }
-        }
-        return TRUE;
-    }
-    if (p->is_exotic) {
-        if (p->fast_array) {
-            /* specific case for fast arrays */
-            if (__JS_AtomIsTaggedInt(prop)) {
-                uint32_t idx;
-                idx = __JS_AtomToUInt32(prop);
-                if (idx < p->u.array.count) {
-                    if (desc) {
-                        desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE |
-                            JS_PROP_CONFIGURABLE;
-                        desc->getter = JS_UNDEFINED;
-                        desc->setter = JS_UNDEFINED;
-                        desc->value = JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
-                    }
-                    return TRUE;
-                }
-            }
-        } else {
-            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
-            if (em && em->get_own_property) {
-                return em->get_own_property(ctx, desc,
-                                            JS_MKPTR(JS_TAG_OBJECT, p), prop);
-            }
-        }
-    }
-    return FALSE;
-}
-
-int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc,
-                      JSValueConst obj, JSAtom prop)
-{
-    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
-        JS_ThrowTypeErrorNotAnObject(ctx);
-        return -1;
-    }
-    return JS_GetOwnPropertyInternal(ctx, desc, JS_VALUE_GET_OBJ(obj), prop);
-}
-
-/* return -1 if exception (Proxy object only) or TRUE/FALSE */
-int JS_IsExtensible(JSContext *ctx, JSValueConst obj)
-{
-    JSObject *p;
-
-    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
-        return FALSE;
-    p = JS_VALUE_GET_OBJ(obj);
-    if (unlikely(p->class_id == JS_CLASS_PROXY))
-        return js_proxy_isExtensible(ctx, obj);
-    else
-        return p->extensible;
-}
-
-/* return -1 if exception (Proxy object only) or TRUE/FALSE */
-int JS_PreventExtensions(JSContext *ctx, JSValueConst obj)
-{
-    JSObject *p;
-
-    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
-        return FALSE;
-    p = JS_VALUE_GET_OBJ(obj);
-    if (unlikely(p->class_id == JS_CLASS_PROXY))
-        return js_proxy_preventExtensions(ctx, obj);
-    p->extensible = FALSE;
-    return TRUE;
-}
-
-/* return -1 if exception otherwise TRUE or FALSE */
-int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop)
-{
-    JSObject *p;
-    int ret;
-    JSValue obj1;
-
-    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
-        return FALSE;
-    p = JS_VALUE_GET_OBJ(obj);
-    for(;;) {
-        if (p->is_exotic) {
-            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
-            if (em && em->has_property) {
-                /* has_property can free the prototype */
-                obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
-                ret = em->has_property(ctx, obj1, prop);
-                JS_FreeValue(ctx, obj1);
-                return ret;
-            }
-        }
-        /* JS_GetOwnPropertyInternal can free the prototype */
-        JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
-        ret = JS_GetOwnPropertyInternal(ctx, NULL, p, prop);
-        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
-        if (ret != 0)
-            return ret;
-        if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
-            p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
-            ret = JS_AtomIsNumericIndex(ctx, prop);
-            if (ret != 0) {
-                if (ret < 0)
-                    return -1;
-                return FALSE;
-            }
-        }
-        p = p->shape->proto;
-        if (!p)
-            break;
-    }
-    return FALSE;
-}
-
-/* val must be a symbol */
-static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val)
-{
-    JSAtomStruct *p = JS_VALUE_GET_PTR(val);
-    return js_get_atom_index(ctx->rt, p);
-}
-
-/* return JS_ATOM_NULL in case of exception */
-JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val)
-{
-    JSAtom atom;
-    uint32_t tag;
-    tag = JS_VALUE_GET_TAG(val);
-    if (tag == JS_TAG_INT &&
-        (uint32_t)JS_VALUE_GET_INT(val) <= JS_ATOM_MAX_INT) {
-        /* fast path for integer values */
-        atom = __JS_AtomFromUInt32(JS_VALUE_GET_INT(val));
-    } else if (tag == JS_TAG_SYMBOL) {
-        JSAtomStruct *p = JS_VALUE_GET_PTR(val);
-        atom = JS_DupAtom(ctx, js_get_atom_index(ctx->rt, p));
-    } else {
-        JSValue str;
-        str = JS_ToPropertyKey(ctx, val);
-        if (JS_IsException(str))
-            return JS_ATOM_NULL;
-        if (JS_VALUE_GET_TAG(str) == JS_TAG_SYMBOL) {
-            atom = js_symbol_to_atom(ctx, str);
-        } else {
-            atom = JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(str));
-        }
-    }
-    return atom;
-}
-
-static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,
-                                   JSValue prop)
-{
-    JSAtom atom;
-    JSValue ret;
-
-    if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT &&
-               JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {
-        JSObject *p;
-        uint32_t idx, len;
-        /* fast path for array access */
-        p = JS_VALUE_GET_OBJ(this_obj);
-        idx = JS_VALUE_GET_INT(prop);
-        len = (uint32_t)p->u.array.count;
-        if (unlikely(idx >= len))
-            goto slow_path;
-        switch(p->class_id) {
-        case JS_CLASS_ARRAY:
-        case JS_CLASS_ARGUMENTS:
-            return JS_DupValue(ctx, p->u.array.u.values[idx]);
-        case JS_CLASS_INT8_ARRAY:
-            return JS_NewInt32(ctx, p->u.array.u.int8_ptr[idx]);
-        case JS_CLASS_UINT8C_ARRAY:
-        case JS_CLASS_UINT8_ARRAY:
-            return JS_NewInt32(ctx, p->u.array.u.uint8_ptr[idx]);
-        case JS_CLASS_INT16_ARRAY:
-            return JS_NewInt32(ctx, p->u.array.u.int16_ptr[idx]);
-        case JS_CLASS_UINT16_ARRAY:
-            return JS_NewInt32(ctx, p->u.array.u.uint16_ptr[idx]);
-        case JS_CLASS_INT32_ARRAY:
-            return JS_NewInt32(ctx, p->u.array.u.int32_ptr[idx]);
-        case JS_CLASS_UINT32_ARRAY:
-            return JS_NewUint32(ctx, p->u.array.u.uint32_ptr[idx]);
-#ifdef CONFIG_BIGNUM
-        case JS_CLASS_BIG_INT64_ARRAY:
-            return JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]);
-        case JS_CLASS_BIG_UINT64_ARRAY:
-            return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]);
-#endif
-        case JS_CLASS_FLOAT32_ARRAY:
-            return __JS_NewFloat64(ctx, p->u.array.u.float_ptr[idx]);
-        case JS_CLASS_FLOAT64_ARRAY:
-            return __JS_NewFloat64(ctx, p->u.array.u.double_ptr[idx]);
-        default:
-            goto slow_path;
-        }
-    } else {
-    slow_path:
-        atom = JS_ValueToAtom(ctx, prop);
-        JS_FreeValue(ctx, prop);
-        if (unlikely(atom == JS_ATOM_NULL))
-            return JS_EXCEPTION;
-        ret = JS_GetProperty(ctx, this_obj, atom);
-        JS_FreeAtom(ctx, atom);
-        return ret;
-    }
-}
-
-JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
-                             uint32_t idx)
-{
-    return JS_GetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx));
-}
-
-/* Check if an object has a generalized numeric property. Return value:
-   -1 for exception,
-   TRUE if property exists, stored into *pval,
-   FALSE if proprty does not exist.
- */
-static int JS_TryGetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, JSValue *pval)
-{
-    JSValue val = JS_UNDEFINED;
-    JSAtom prop;
-    int present;
-
-    if (likely((uint64_t)idx <= JS_ATOM_MAX_INT)) {
-        /* fast path */
-        present = JS_HasProperty(ctx, obj, __JS_AtomFromUInt32(idx));
-        if (present > 0) {
-            val = JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx));
-            if (unlikely(JS_IsException(val)))
-                present = -1;
-        }
-    } else {
-        prop = JS_NewAtomInt64(ctx, idx);
-        present = -1;
-        if (likely(prop != JS_ATOM_NULL)) {
-            present = JS_HasProperty(ctx, obj, prop);
-            if (present > 0) {
-                val = JS_GetProperty(ctx, obj, prop);
-                if (unlikely(JS_IsException(val)))
-                    present = -1;
-            }
-            JS_FreeAtom(ctx, prop);
-        }
-    }
-    *pval = val;
-    return present;
-}
-
-static JSValue JS_GetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx)
-{
-    JSAtom prop;
-    JSValue val;
-
-    if ((uint64_t)idx <= INT32_MAX) {
-        /* fast path for fast arrays */
-        return JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx));
-    }
-    prop = JS_NewAtomInt64(ctx, idx);
-    if (prop == JS_ATOM_NULL)
-        return JS_EXCEPTION;
-
-    val = JS_GetProperty(ctx, obj, prop);
-    JS_FreeAtom(ctx, prop);
-    return val;
-}
-
-JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj,
-                          const char *prop)
-{
-    JSAtom atom;
-    JSValue ret;
-    atom = JS_NewAtom(ctx, prop);
-    ret = JS_GetProperty(ctx, this_obj, atom);
-    JS_FreeAtom(ctx, atom);
-    return ret;
-}
-
-/* Note: the property value is not initialized. Return NULL if memory
-   error. */
-static JSProperty *add_property(JSContext *ctx,
-                                JSObject *p, JSAtom prop, int prop_flags)
-{
-    JSShape *sh, *new_sh;
-
-    sh = p->shape;
-    if (sh->is_hashed) {
-        /* try to find an existing shape */
-        new_sh = find_hashed_shape_prop(ctx->rt, sh, prop, prop_flags);
-        if (new_sh) {
-            /* matching shape found: use it */
-            /*  the property array may need to be resized */
-            if (new_sh->prop_size != sh->prop_size) {
-                JSProperty *new_prop;
-                new_prop = js_realloc(ctx, p->prop, sizeof(p->prop[0]) *
-                                      new_sh->prop_size);
-                if (!new_prop)
-                    return NULL;
-                p->prop = new_prop;
-            }
-            p->shape = js_dup_shape(new_sh);
-            js_free_shape(ctx->rt, sh);
-            return &p->prop[new_sh->prop_count - 1];
-        } else if (sh->header.ref_count != 1) {
-            /* if the shape is shared, clone it */
-            new_sh = js_clone_shape(ctx, sh);
-            if (!new_sh)
-                return NULL;
-            /* hash the cloned shape */
-            new_sh->is_hashed = TRUE;
-            js_shape_hash_link(ctx->rt, new_sh);
-            js_free_shape(ctx->rt, p->shape);
-            p->shape = new_sh;
-        }
-    }
-    assert(p->shape->header.ref_count == 1);
-    if (add_shape_property(ctx, &p->shape, p, prop, prop_flags))
-        return NULL;
-    return &p->prop[p->shape->prop_count - 1];
-}
-
-/* can be called on Array or Arguments objects. return < 0 if
-   memory alloc error. */
-static no_inline __exception int convert_fast_array_to_array(JSContext *ctx,
-                                                             JSObject *p)
-{
-    JSProperty *pr;
-    JSShape *sh;
-    JSValue *tab;
-    uint32_t i, len, new_count;
-
-    if (js_shape_prepare_update(ctx, p, NULL))
-        return -1;
-    len = p->u.array.count;
-    /* resize the properties once to simplify the error handling */
-    sh = p->shape;
-    new_count = sh->prop_count + len;
-    if (new_count > sh->prop_size) {
-        if (resize_properties(ctx, &p->shape, p, new_count))
-            return -1;
-    }
-
-    tab = p->u.array.u.values;
-    for(i = 0; i < len; i++) {
-        /* add_property cannot fail here but
-           __JS_AtomFromUInt32(i) fails for i > INT32_MAX */
-        pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E);
-        pr->u.value = *tab++;
-    }
-    js_free(ctx, p->u.array.u.values);
-    p->u.array.count = 0;
-    p->u.array.u.values = NULL; /* fail safe */
-    p->u.array.u1.size = 0;
-    p->fast_array = 0;
-    return 0;
-}
-
-static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom)
-{
-    JSShape *sh;
-    JSShapeProperty *pr, *lpr, *prop;
-    JSProperty *pr1;
-    uint32_t lpr_idx;
-    intptr_t h, h1;
-
- redo:
-    sh = p->shape;
-    h1 = atom & sh->prop_hash_mask;
-    h = prop_hash_end(sh)[-h1 - 1];
-    prop = get_shape_prop(sh);
-    lpr = NULL;
-    lpr_idx = 0;   /* prevent warning */
-    while (h != 0) {
-        pr = &prop[h - 1];
-        if (likely(pr->atom == atom)) {
-            /* found ! */
-            if (!(pr->flags & JS_PROP_CONFIGURABLE))
-                return FALSE;
-            /* realloc the shape if needed */
-            if (lpr)
-                lpr_idx = lpr - get_shape_prop(sh);
-            if (js_shape_prepare_update(ctx, p, &pr))
-                return -1;
-            sh = p->shape;
-            /* remove property */
-            if (lpr) {
-                lpr = get_shape_prop(sh) + lpr_idx;
-                lpr->hash_next = pr->hash_next;
-            } else {
-                prop_hash_end(sh)[-h1 - 1] = pr->hash_next;
-            }
-            sh->deleted_prop_count++;
-            /* free the entry */
-            pr1 = &p->prop[h - 1];
-            free_property(ctx->rt, pr1, pr->flags);
-            JS_FreeAtom(ctx, pr->atom);
-            /* put default values */
-            pr->flags = 0;
-            pr->atom = JS_ATOM_NULL;
-            pr1->u.value = JS_UNDEFINED;
-
-            /* compact the properties if too many deleted properties */
-            if (sh->deleted_prop_count >= 8 &&
-                sh->deleted_prop_count >= ((unsigned)sh->prop_count / 2)) {
-                compact_properties(ctx, p);
-            }
-            return TRUE;
-        }
-        lpr = pr;
-        h = pr->hash_next;
-    }
-
-    if (p->is_exotic) {
-        if (p->fast_array) {
-            uint32_t idx;
-            if (JS_AtomIsArrayIndex(ctx, &idx, atom) &&
-                idx < p->u.array.count) {
-                if (p->class_id == JS_CLASS_ARRAY ||
-                    p->class_id == JS_CLASS_ARGUMENTS) {
-                    /* Special case deleting the last element of a fast Array */
-                    if (idx == p->u.array.count - 1) {
-                        JS_FreeValue(ctx, p->u.array.u.values[idx]);
-                        p->u.array.count = idx;
-                        return TRUE;
-                    }
-                    if (convert_fast_array_to_array(ctx, p))
-                        return -1;
-                    goto redo;
-                } else {
-                    return FALSE;
-                }
-            }
-        } else {
-            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
-            if (em && em->delete_property) {
-                return em->delete_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), atom);
-            }
-        }
-    }
-    /* not found */
-    return TRUE;
-}
-
-static int call_setter(JSContext *ctx, JSObject *setter,
-                       JSValueConst this_obj, JSValue val, int flags)
-{
-    JSValue ret, func;
-    if (likely(setter)) {
-        func = JS_MKPTR(JS_TAG_OBJECT, setter);
-        /* Note: the field could be removed in the setter */
-        func = JS_DupValue(ctx, func);
-        ret = JS_CallFree(ctx, func, this_obj, 1, (JSValueConst *)&val);
-        JS_FreeValue(ctx, val);
-        if (JS_IsException(ret))
-            return -1;
-        JS_FreeValue(ctx, ret);
-        return TRUE;
-    } else {
-        JS_FreeValue(ctx, val);
-        if ((flags & JS_PROP_THROW) ||
-            ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
-            JS_ThrowTypeError(ctx, "no setter for property");
-            return -1;
-        }
-        return FALSE;
-    }
-}
-
-/* set the array length and remove the array elements if necessary. */
-static int set_array_length(JSContext *ctx, JSObject *p, JSValue val,
-                            int flags)
-{
-    uint32_t len, idx, cur_len;
-    int i, ret;
-
-    /* Note: this call can reallocate the properties of 'p' */
-    ret = JS_ToArrayLengthFree(ctx, &len, val, FALSE);
-    if (ret)
-        return -1;
-    /* JS_ToArrayLengthFree() must be done before the read-only test */
-    if (unlikely(!(p->shape->prop[0].flags & JS_PROP_WRITABLE)))
-        return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
-
-    if (likely(p->fast_array)) {
-        uint32_t old_len = p->u.array.count;
-        if (len < old_len) {
-            for(i = len; i < old_len; i++) {
-                JS_FreeValue(ctx, p->u.array.u.values[i]);
-            }
-            p->u.array.count = len;
-        }
-        p->prop[0].u.value = JS_NewUint32(ctx, len);
-    } else {
-        /* Note: length is always a uint32 because the object is an
-           array */
-        JS_ToUint32(ctx, &cur_len, p->prop[0].u.value);
-        if (len < cur_len) {
-            uint32_t d;
-            JSShape *sh;
-            JSShapeProperty *pr;
-
-            d = cur_len - len;
-            sh = p->shape;
-            if (d <= sh->prop_count) {
-                JSAtom atom;
-
-                /* faster to iterate */
-                while (cur_len > len) {
-                    atom = JS_NewAtomUInt32(ctx, cur_len - 1);
-                    ret = delete_property(ctx, p, atom);
-                    JS_FreeAtom(ctx, atom);
-                    if (unlikely(!ret)) {
-                        /* unlikely case: property is not
-                           configurable */
-                        break;
-                    }
-                    cur_len--;
-                }
-            } else {
-                /* faster to iterate thru all the properties. Need two
-                   passes in case one of the property is not
-                   configurable */
-                cur_len = len;
-                for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count;
-                    i++, pr++) {
-                    if (pr->atom != JS_ATOM_NULL &&
-                        JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) {
-                        if (idx >= cur_len &&
-                            !(pr->flags & JS_PROP_CONFIGURABLE)) {
-                            cur_len = idx + 1;
-                        }
-                    }
-                }
-
-                for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count;
-                    i++, pr++) {
-                    if (pr->atom != JS_ATOM_NULL &&
-                        JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) {
-                        if (idx >= cur_len) {
-                            /* remove the property */
-                            delete_property(ctx, p, pr->atom);
-                            /* WARNING: the shape may have been modified */
-                            sh = p->shape;
-                            pr = get_shape_prop(sh) + i;
-                        }
-                    }
-                }
-            }
-        } else {
-            cur_len = len;
-        }
-        set_value(ctx, &p->prop[0].u.value, JS_NewUint32(ctx, cur_len));
-        if (unlikely(cur_len > len)) {
-            return JS_ThrowTypeErrorOrFalse(ctx, flags, "not configurable");
-        }
-    }
-    return TRUE;
-}
-
-/* return -1 if exception */
-static int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len)
-{
-    uint32_t new_size;
-    size_t slack;
-    JSValue *new_array_prop;
-    /* XXX: potential arithmetic overflow */
-    new_size = max_int(new_len, p->u.array.u1.size * 3 / 2);
-    new_array_prop = js_realloc2(ctx, p->u.array.u.values, sizeof(JSValue) * new_size, &slack);
-    if (!new_array_prop)
-        return -1;
-    new_size += slack / sizeof(*new_array_prop);
-    p->u.array.u.values = new_array_prop;
-    p->u.array.u1.size = new_size;
-    return 0;
-}
-
-/* Preconditions: 'p' must be of class JS_CLASS_ARRAY, p->fast_array =
-   TRUE and p->extensible = TRUE */
-static int add_fast_array_element(JSContext *ctx, JSObject *p,
-                                  JSValue val, int flags)
-{
-    uint32_t new_len, array_len;
-    /* extend the array by one */
-    /* XXX: convert to slow array if new_len > 2^31-1 elements */
-    new_len = p->u.array.count + 1;
-    /* update the length if necessary. We assume that if the length is
-       not an integer, then if it >= 2^31.  */
-    if (likely(JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT)) {
-        array_len = JS_VALUE_GET_INT(p->prop[0].u.value);
-        if (new_len > array_len) {
-            if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE))) {
-                JS_FreeValue(ctx, val);
-                return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
-            }
-            p->prop[0].u.value = JS_NewInt32(ctx, new_len);
-        }
-    }
-    if (unlikely(new_len > p->u.array.u1.size)) {
-        if (expand_fast_array(ctx, p, new_len)) {
-            JS_FreeValue(ctx, val);
-            return -1;
-        }
-    }
-    p->u.array.u.values[new_len - 1] = val;
-    p->u.array.count = new_len;
-    return TRUE;
-}
-
-static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc)
-{
-    JS_FreeValue(ctx, desc->getter);
-    JS_FreeValue(ctx, desc->setter);
-    JS_FreeValue(ctx, desc->value);
-}
-
-/* generic (and slower) version of JS_SetProperty() for
- * Reflect.set(). 'obj' must be an object.  */
-static int JS_SetPropertyGeneric(JSContext *ctx,
-                                 JSValueConst obj, JSAtom prop,
-                                 JSValue val, JSValueConst this_obj,
-                                 int flags)
-{
-    int ret;
-    JSPropertyDescriptor desc;
-    JSValue obj1;
-    JSObject *p;
-    
-    obj1 = JS_DupValue(ctx, obj);
-    for(;;) {
-        p = JS_VALUE_GET_OBJ(obj1);
-        if (p->is_exotic) {
-            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
-            if (em && em->set_property) {
-                ret = em->set_property(ctx, obj1, prop,
-                                       val, this_obj, flags);
-                JS_FreeValue(ctx, obj1);
-                JS_FreeValue(ctx, val);
-                return ret;
-            }
-        }
-
-        ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
-        if (ret < 0) {
-            JS_FreeValue(ctx, obj1);
-            JS_FreeValue(ctx, val);
-            return ret;
-        }
-        if (ret) {
-            if (desc.flags & JS_PROP_GETSET) {
-                JSObject *setter;
-                if (JS_IsUndefined(desc.setter))
-                    setter = NULL;
-                else
-                    setter = JS_VALUE_GET_OBJ(desc.setter);
-                ret = call_setter(ctx, setter, this_obj, val, flags);
-                JS_FreeValue(ctx, desc.getter);
-                JS_FreeValue(ctx, desc.setter);
-                JS_FreeValue(ctx, obj1);
-                return ret;
-            } else {
-                JS_FreeValue(ctx, desc.value);
-                if (!(desc.flags & JS_PROP_WRITABLE)) {
-                    JS_FreeValue(ctx, obj1);
-                    goto read_only_error;
-                }
-            }
-            break;
-        }
-        /* Note: at this point 'obj1' cannot be a proxy. XXX: may have
-           to check recursion */
-        obj1 = JS_GetPrototypeFree(ctx, obj1);
-        if (JS_IsNull(obj1))
-            break;
-    }
-    JS_FreeValue(ctx, obj1);
-
-    if (!JS_IsObject(this_obj)) {
-        JS_FreeValue(ctx, val);
-        return JS_ThrowTypeErrorOrFalse(ctx, flags, "receiver is not an object");
-    }
-    
-    p = JS_VALUE_GET_OBJ(this_obj);
-
-    /* modify the property in this_obj if it already exists */
-    ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
-    if (ret < 0) {
-        JS_FreeValue(ctx, val);
-        return ret;
-    }
-    if (ret) {
-        if (desc.flags & JS_PROP_GETSET) {
-            JS_FreeValue(ctx, desc.getter);
-            JS_FreeValue(ctx, desc.setter);
-            JS_FreeValue(ctx, val);
-            return JS_ThrowTypeErrorOrFalse(ctx, flags, "setter is forbidden");
-        } else {
-            JS_FreeValue(ctx, desc.value);
-            if (!(desc.flags & JS_PROP_WRITABLE) ||
-                p->class_id == JS_CLASS_MODULE_NS) {
-            read_only_error:
-                JS_FreeValue(ctx, val);
-                return JS_ThrowTypeErrorReadOnly(ctx, flags, prop);
-            }
-        }
-        ret = JS_DefineProperty(ctx, this_obj, prop, val,
-                                JS_UNDEFINED, JS_UNDEFINED,
-                                JS_PROP_HAS_VALUE);
-        JS_FreeValue(ctx, val);
-        return ret;
-    }
-
-    ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED,
-                            flags |
-                            JS_PROP_HAS_VALUE |
-                            JS_PROP_HAS_ENUMERABLE |
-                            JS_PROP_HAS_WRITABLE |
-                            JS_PROP_HAS_CONFIGURABLE |
-                            JS_PROP_C_W_E);
-    JS_FreeValue(ctx, val);
-    return ret;
-}
-
-/* return -1 in case of exception or TRUE or FALSE. Warning: 'val' is
-   freed by the function. 'flags' is a bitmask of JS_PROP_NO_ADD,
-   JS_PROP_THROW or JS_PROP_THROW_STRICT. If JS_PROP_NO_ADD is set,
-   the new property is not added and an error is raised. */
-int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj,
-                           JSAtom prop, JSValue val, int flags)
-{
-    JSObject *p, *p1;
-    JSShapeProperty *prs;
-    JSProperty *pr;
-    uint32_t tag;
-    JSPropertyDescriptor desc;
-    int ret;
-#if 0
-    printf("JS_SetPropertyInternal: "); print_atom(ctx, prop); printf("\n");
-#endif
-    tag = JS_VALUE_GET_TAG(this_obj);
-    if (unlikely(tag != JS_TAG_OBJECT)) {
-        switch(tag) {
-        case JS_TAG_NULL:
-            JS_FreeValue(ctx, val);
-            JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop);
-            return -1;
-        case JS_TAG_UNDEFINED:
-            JS_FreeValue(ctx, val);
-            JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop);
-            return -1;
-        default:
-            /* even on a primitive type we can have setters on the prototype */
-            p = NULL;
-            p1 = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, this_obj));
-            goto prototype_lookup;
-        }
-    }
-    p = JS_VALUE_GET_OBJ(this_obj);
-retry:
-    prs = find_own_property(&pr, p, prop);
-    if (prs) {
-        if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE |
-                                  JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) {
-            /* fast case */
-            set_value(ctx, &pr->u.value, val);
-            return TRUE;
-        } else if (prs->flags & JS_PROP_LENGTH) {
-            assert(p->class_id == JS_CLASS_ARRAY);
-            assert(prop == JS_ATOM_length);
-            return set_array_length(ctx, p, val, flags);
-        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
-            return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);
-        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
-            /* JS_PROP_WRITABLE is always true for variable
-               references, but they are write protected in module name
-               spaces. */
-            if (p->class_id == JS_CLASS_MODULE_NS)
-                goto read_only_prop;
-            set_value(ctx, pr->u.var_ref->pvalue, val);
-            return TRUE;
-        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
-            /* Instantiate property and retry (potentially useless) */
-            if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) {
-                JS_FreeValue(ctx, val);
-                return -1;
-            }
-            goto retry;
-        } else {
-            goto read_only_prop;
-        }
-    }
-
-    p1 = p;
-    for(;;) {
-        if (p1->is_exotic) {
-            if (p1->fast_array) {
-                if (__JS_AtomIsTaggedInt(prop)) {
-                    uint32_t idx = __JS_AtomToUInt32(prop);
-                    if (idx < p1->u.array.count) {
-                        if (unlikely(p == p1))
-                            return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val, flags);
-                        else
-                            break;
-                    } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY &&
-                               p1->class_id <= JS_CLASS_FLOAT64_ARRAY) {
-                        goto typed_array_oob;
-                    }
-                } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY &&
-                           p1->class_id <= JS_CLASS_FLOAT64_ARRAY) {
-                    ret = JS_AtomIsNumericIndex(ctx, prop);
-                    if (ret != 0) {
-                        if (ret < 0) {
-                            JS_FreeValue(ctx, val);
-                            return -1;
-                        }
-                    typed_array_oob:
-                        val = JS_ToNumberFree(ctx, val);
-                        JS_FreeValue(ctx, val);
-                        if (JS_IsException(val))
-                            return -1;
-                        return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
-                    }
-                }
-            } else {
-                const JSClassExoticMethods *em = ctx->rt->class_array[p1->class_id].exotic;
-                if (em) {
-                    JSValue obj1;
-                    if (em->set_property) {
-                        /* set_property can free the prototype */
-                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
-                        ret = em->set_property(ctx, obj1, prop,
-                                               val, this_obj, flags);
-                        JS_FreeValue(ctx, obj1);
-                        JS_FreeValue(ctx, val);
-                        return ret;
-                    }
-                    if (em->get_own_property) {
-                        /* get_own_property can free the prototype */
-                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
-                        ret = em->get_own_property(ctx, &desc,
-                                                   obj1, prop);
-                        JS_FreeValue(ctx, obj1);
-                        if (ret < 0) {
-                            JS_FreeValue(ctx, val);
-                            return ret;
-                        }
-                        if (ret) {
-                            if (desc.flags & JS_PROP_GETSET) {
-                                JSObject *setter;
-                                if (JS_IsUndefined(desc.setter))
-                                    setter = NULL;
-                                else
-                                    setter = JS_VALUE_GET_OBJ(desc.setter);
-                                ret = call_setter(ctx, setter, this_obj, val, flags);
-                                JS_FreeValue(ctx, desc.getter);
-                                JS_FreeValue(ctx, desc.setter);
-                                return ret;
-                            } else {
-                                JS_FreeValue(ctx, desc.value);
-                                if (!(desc.flags & JS_PROP_WRITABLE))
-                                    goto read_only_prop;
-                                if (likely(p == p1)) {
-                                    ret = JS_DefineProperty(ctx, this_obj, prop, val,
-                                                            JS_UNDEFINED, JS_UNDEFINED,
-                                                            JS_PROP_HAS_VALUE);
-                                    JS_FreeValue(ctx, val);
-                                    return ret;
-                                } else {
-                                    break;
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        p1 = p1->shape->proto;
-    prototype_lookup:
-        if (!p1)
-            break;
-
-    retry2:
-        prs = find_own_property(&pr, p1, prop);
-        if (prs) {
-            if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
-                return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);
-            } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
-                /* Instantiate property and retry (potentially useless) */
-                if (JS_AutoInitProperty(ctx, p1, prop, pr, prs))
-                    return -1;
-                goto retry2;
-            } else if (!(prs->flags & JS_PROP_WRITABLE)) {
-            read_only_prop:
-                JS_FreeValue(ctx, val);
-                return JS_ThrowTypeErrorReadOnly(ctx, flags, prop);
-            }
-        }
-    }
-
-    if (unlikely(flags & JS_PROP_NO_ADD)) {
-        JS_FreeValue(ctx, val);
-        JS_ThrowReferenceErrorNotDefined(ctx, prop);
-        return -1;
-    }
-
-    if (unlikely(!p)) {
-        JS_FreeValue(ctx, val);
-        return JS_ThrowTypeErrorOrFalse(ctx, flags, "not an object");
-    }
-
-    if (unlikely(!p->extensible)) {
-        JS_FreeValue(ctx, val);
-        return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible");
-    }
-
-    if (p->is_exotic) {
-        if (p->class_id == JS_CLASS_ARRAY && p->fast_array &&
-            __JS_AtomIsTaggedInt(prop)) {
-            uint32_t idx = __JS_AtomToUInt32(prop);
-            if (idx == p->u.array.count) {
-                /* fast case */
-                return add_fast_array_element(ctx, p, val, flags);
-            } else {
-                goto generic_create_prop;
-            }
-        } else {
-        generic_create_prop:
-            ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED,
-                                    flags |
-                                    JS_PROP_HAS_VALUE |
-                                    JS_PROP_HAS_ENUMERABLE |
-                                    JS_PROP_HAS_WRITABLE |
-                                    JS_PROP_HAS_CONFIGURABLE |
-                                    JS_PROP_C_W_E);
-            JS_FreeValue(ctx, val);
-            return ret;
-        }
-    }
-
-    pr = add_property(ctx, p, prop, JS_PROP_C_W_E);
-    if (unlikely(!pr)) {
-        JS_FreeValue(ctx, val);
-        return -1;
-    }
-    pr->u.value = val;
-    return TRUE;
-}
-
-/* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */
-static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
-                               JSValue prop, JSValue val, int flags)
-{
-    if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT &&
-               JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {
-        JSObject *p;
-        uint32_t idx;
-        double d;
-        int32_t v;
-
-        /* fast path for array access */
-        p = JS_VALUE_GET_OBJ(this_obj);
-        idx = JS_VALUE_GET_INT(prop);
-        switch(p->class_id) {
-        case JS_CLASS_ARRAY:
-            if (unlikely(idx >= (uint32_t)p->u.array.count)) {
-                JSObject *p1;
-                JSShape *sh1;
-
-                /* fast path to add an element to the array */
-                if (idx != (uint32_t)p->u.array.count ||
-                    !p->fast_array || !p->extensible)
-                    goto slow_path;
-                /* check if prototype chain has a numeric property */
-                p1 = p->shape->proto;
-                while (p1 != NULL) {
-                    sh1 = p1->shape;
-                    if (p1->class_id == JS_CLASS_ARRAY) {
-                        if (unlikely(!p1->fast_array))
-                            goto slow_path;
-                    } else if (p1->class_id == JS_CLASS_OBJECT) {
-                        if (unlikely(sh1->has_small_array_index))
-                            goto slow_path;
-                    } else {
-                        goto slow_path;
-                    }
-                    p1 = sh1->proto;
-                }
-                /* add element */
-                return add_fast_array_element(ctx, p, val, flags);
-            }
-            set_value(ctx, &p->u.array.u.values[idx], val);
-            break;
-        case JS_CLASS_ARGUMENTS:
-            if (unlikely(idx >= (uint32_t)p->u.array.count))
-                goto slow_path;
-            set_value(ctx, &p->u.array.u.values[idx], val);
-            break;
-        case JS_CLASS_UINT8C_ARRAY:
-            if (JS_ToUint8ClampFree(ctx, &v, val))
-                return -1;
-            /* Note: the conversion can detach the typed array, so the
-               array bound check must be done after */
-            if (unlikely(idx >= (uint32_t)p->u.array.count))
-                goto ta_out_of_bound;
-            p->u.array.u.uint8_ptr[idx] = v;
-            break;
-        case JS_CLASS_INT8_ARRAY:
-        case JS_CLASS_UINT8_ARRAY:
-            if (JS_ToInt32Free(ctx, &v, val))
-                return -1;
-            if (unlikely(idx >= (uint32_t)p->u.array.count))
-                goto ta_out_of_bound;
-            p->u.array.u.uint8_ptr[idx] = v;
-            break;
-        case JS_CLASS_INT16_ARRAY:
-        case JS_CLASS_UINT16_ARRAY:
-            if (JS_ToInt32Free(ctx, &v, val))
-                return -1;
-            if (unlikely(idx >= (uint32_t)p->u.array.count))
-                goto ta_out_of_bound;
-            p->u.array.u.uint16_ptr[idx] = v;
-            break;
-        case JS_CLASS_INT32_ARRAY:
-        case JS_CLASS_UINT32_ARRAY:
-            if (JS_ToInt32Free(ctx, &v, val))
-                return -1;
-            if (unlikely(idx >= (uint32_t)p->u.array.count))
-                goto ta_out_of_bound;
-            p->u.array.u.uint32_ptr[idx] = v;
-            break;
-#ifdef CONFIG_BIGNUM
-        case JS_CLASS_BIG_INT64_ARRAY:
-        case JS_CLASS_BIG_UINT64_ARRAY:
-            /* XXX: need specific conversion function */
-            {
-                int64_t v;
-                if (JS_ToBigInt64Free(ctx, &v, val))
-                    return -1;
-                if (unlikely(idx >= (uint32_t)p->u.array.count))
-                    goto ta_out_of_bound;
-                p->u.array.u.uint64_ptr[idx] = v;
-            }
-            break;
-#endif
-        case JS_CLASS_FLOAT32_ARRAY:
-            if (JS_ToFloat64Free(ctx, &d, val))
-                return -1;
-            if (unlikely(idx >= (uint32_t)p->u.array.count))
-                goto ta_out_of_bound;
-            p->u.array.u.float_ptr[idx] = d;
-            break;
-        case JS_CLASS_FLOAT64_ARRAY:
-            if (JS_ToFloat64Free(ctx, &d, val))
-                return -1;
-            if (unlikely(idx >= (uint32_t)p->u.array.count)) {
-            ta_out_of_bound:
-                return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
-            }
-            p->u.array.u.double_ptr[idx] = d;
-            break;
-        default:
-            goto slow_path;
-        }
-        return TRUE;
-    } else {
-        JSAtom atom;
-        int ret;
-    slow_path:
-        atom = JS_ValueToAtom(ctx, prop);
-        JS_FreeValue(ctx, prop);
-        if (unlikely(atom == JS_ATOM_NULL)) {
-            JS_FreeValue(ctx, val);
-            return -1;
-        }
-        ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, flags);
-        JS_FreeAtom(ctx, atom);
-        return ret;
-    }
-}
-
-int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
-                         uint32_t idx, JSValue val)
-{
-    return JS_SetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx), val,
-                               JS_PROP_THROW);
-}
-
-int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj,
-                        int64_t idx, JSValue val)
-{
-    JSAtom prop;
-    int res;
-
-    if ((uint64_t)idx <= INT32_MAX) {
-        /* fast path for fast arrays */
-        return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val,
-                                   JS_PROP_THROW);
-    }
-    prop = JS_NewAtomInt64(ctx, idx);
-    if (prop == JS_ATOM_NULL) {
-        JS_FreeValue(ctx, val);
-        return -1;
-    }
-    res = JS_SetProperty(ctx, this_obj, prop, val);
-    JS_FreeAtom(ctx, prop);
-    return res;
-}
-
-int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj,
-                      const char *prop, JSValue val)
-{
-    JSAtom atom;
-    int ret;
-    atom = JS_NewAtom(ctx, prop);
-    ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, JS_PROP_THROW);
-    JS_FreeAtom(ctx, atom);
-    return ret;
-}
-
-/* compute the property flags. For each flag: (JS_PROP_HAS_x forces
-   it, otherwise def_flags is used)
-   Note: makes assumption about the bit pattern of the flags
-*/
-static int get_prop_flags(int flags, int def_flags)
-{
-    int mask;
-    mask = (flags >> JS_PROP_HAS_SHIFT) & JS_PROP_C_W_E;
-    return (flags & mask) | (def_flags & ~mask);
-}
-
-static int JS_CreateProperty(JSContext *ctx, JSObject *p,
-                             JSAtom prop, JSValueConst val,
-                             JSValueConst getter, JSValueConst setter,
-                             int flags)
-{
-    JSProperty *pr;
-    int ret, prop_flags;
-
-    /* add a new property or modify an existing exotic one */
-    if (p->is_exotic) {
-        if (p->class_id == JS_CLASS_ARRAY) {
-            uint32_t idx, len;
-
-            if (p->fast_array) {
-                if (__JS_AtomIsTaggedInt(prop)) {
-                    idx = __JS_AtomToUInt32(prop);
-                    if (idx == p->u.array.count) {
-                        if (!p->extensible)
-                            goto not_extensible;
-                        if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET))
-                            goto convert_to_array;
-                        prop_flags = get_prop_flags(flags, 0);
-                        if (prop_flags != JS_PROP_C_W_E)
-                            goto convert_to_array;
-                        return add_fast_array_element(ctx, p,
-                                                      JS_DupValue(ctx, val), flags);
-                    } else {
-                        goto convert_to_array;
-                    }
-                } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) {
-                    /* convert the fast array to normal array */
-                convert_to_array:
-                    if (convert_fast_array_to_array(ctx, p))
-                        return -1;
-                    goto generic_array;
-                }
-            } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) {
-                JSProperty *plen;
-                JSShapeProperty *pslen;
-            generic_array:
-                /* update the length field */
-                plen = &p->prop[0];
-                JS_ToUint32(ctx, &len, plen->u.value);
-                if ((idx + 1) > len) {
-                    pslen = get_shape_prop(p->shape);
-                    if (unlikely(!(pslen->flags & JS_PROP_WRITABLE)))
-                        return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
-                    /* XXX: should update the length after defining
-                       the property */
-                    len = idx + 1;
-                    set_value(ctx, &plen->u.value, JS_NewUint32(ctx, len));
-                }
-            }
-        } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
-                   p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
-            ret = JS_AtomIsNumericIndex(ctx, prop);
-            if (ret != 0) {
-                if (ret < 0)
-                    return -1;
-                return JS_ThrowTypeErrorOrFalse(ctx, flags, "cannot create numeric index in typed array");
-            }
-        } else if (!(flags & JS_PROP_NO_EXOTIC)) {
-            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
-            if (em) {
-                if (em->define_own_property) {
-                    return em->define_own_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p),
-                                                   prop, val, getter, setter, flags);
-                }
-                ret = JS_IsExtensible(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
-                if (ret < 0)
-                    return -1;
-                if (!ret)
-                    goto not_extensible;
-            }
-        }
-    }
-
-    if (!p->extensible) {
-    not_extensible:
-        return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible");
-    }
-
-    if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
-        prop_flags = (flags & (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) |
-            JS_PROP_GETSET;
-    } else {
-        prop_flags = flags & JS_PROP_C_W_E;
-    }
-    pr = add_property(ctx, p, prop, prop_flags);
-    if (unlikely(!pr))
-        return -1;
-    if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
-        pr->u.getset.getter = NULL;
-        if ((flags & JS_PROP_HAS_GET) && JS_IsFunction(ctx, getter)) {
-            pr->u.getset.getter =
-                JS_VALUE_GET_OBJ(JS_DupValue(ctx, getter));
-        }
-        pr->u.getset.setter = NULL;
-        if ((flags & JS_PROP_HAS_SET) && JS_IsFunction(ctx, setter)) {
-            pr->u.getset.setter =
-                JS_VALUE_GET_OBJ(JS_DupValue(ctx, setter));
-        }
-    } else {
-        if (flags & JS_PROP_HAS_VALUE) {
-            pr->u.value = JS_DupValue(ctx, val);
-        } else {
-            pr->u.value = JS_UNDEFINED;
-        }
-    }
-    return TRUE;
-}
-
-/* return FALSE if not OK */
-static BOOL check_define_prop_flags(int prop_flags, int flags)
-{
-    BOOL has_accessor, is_getset;
-
-    if (!(prop_flags & JS_PROP_CONFIGURABLE)) {
-        if ((flags & (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) ==
-            (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) {
-            return FALSE;
-        }
-        if ((flags & JS_PROP_HAS_ENUMERABLE) &&
-            (flags & JS_PROP_ENUMERABLE) != (prop_flags & JS_PROP_ENUMERABLE))
-            return FALSE;
-    }
-    if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE |
-                 JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
-        if (!(prop_flags & JS_PROP_CONFIGURABLE)) {
-            has_accessor = ((flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) != 0);
-            is_getset = ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET);
-            if (has_accessor != is_getset)
-                return FALSE;
-            if (!has_accessor && !is_getset && !(prop_flags & JS_PROP_WRITABLE)) {
-                /* not writable: cannot set the writable bit */
-                if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
-                    (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE))
-                    return FALSE;
-            }
-        }
-    }
-    return TRUE;
-}
-
-/* ensure that the shape can be safely modified */
-static int js_shape_prepare_update(JSContext *ctx, JSObject *p,
-                                   JSShapeProperty **pprs)
-{
-    JSShape *sh;
-    uint32_t idx = 0;    /* prevent warning */
-
-    sh = p->shape;
-    if (sh->is_hashed) {
-        if (sh->header.ref_count != 1) {
-            if (pprs)
-                idx = *pprs - get_shape_prop(sh);
-            /* clone the shape (the resulting one is no longer hashed) */
-            sh = js_clone_shape(ctx, sh);
-            if (!sh)
-                return -1;
-            js_free_shape(ctx->rt, p->shape);
-            p->shape = sh;
-            if (pprs)
-                *pprs = get_shape_prop(sh) + idx;
-        } else {
-            js_shape_hash_unlink(ctx->rt, sh);
-            sh->is_hashed = FALSE;
-        }
-    }
-    return 0;
-}
-
-static int js_update_property_flags(JSContext *ctx, JSObject *p,
-                                    JSShapeProperty **pprs, int flags)
-{
-    if (flags != (*pprs)->flags) {
-        if (js_shape_prepare_update(ctx, p, pprs))
-            return -1;
-        (*pprs)->flags = flags;
-    }
-    return 0;
-}
-
-/* allowed flags:
-   JS_PROP_CONFIGURABLE, JS_PROP_WRITABLE, JS_PROP_ENUMERABLE
-   JS_PROP_HAS_GET, JS_PROP_HAS_SET, JS_PROP_HAS_VALUE,
-   JS_PROP_HAS_CONFIGURABLE, JS_PROP_HAS_WRITABLE, JS_PROP_HAS_ENUMERABLE,
-   JS_PROP_THROW, JS_PROP_NO_EXOTIC.
-   If JS_PROP_THROW is set, return an exception instead of FALSE.
-   if JS_PROP_NO_EXOTIC is set, do not call the exotic
-   define_own_property callback.
-   return -1 (exception), FALSE or TRUE.
-*/
-int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
-                      JSAtom prop, JSValueConst val,
-                      JSValueConst getter, JSValueConst setter, int flags)
-{
-    JSObject *p;
-    JSShapeProperty *prs;
-    JSProperty *pr;
-    int mask, res;
-
-    if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT) {
-        JS_ThrowTypeErrorNotAnObject(ctx);
-        return -1;
-    }
-    p = JS_VALUE_GET_OBJ(this_obj);
-
- redo_prop_update:
-    prs = find_own_property(&pr, p, prop);
-    if (prs) {
-        /* the range of the Array length property is always tested before */
-        if ((prs->flags & JS_PROP_LENGTH) && (flags & JS_PROP_HAS_VALUE)) {
-            uint32_t array_length;
-            if (JS_ToArrayLengthFree(ctx, &array_length,
-                                     JS_DupValue(ctx, val), FALSE)) {
-                return -1;
-            }
-            /* this code relies on the fact that Uint32 are never allocated */
-            val = (JSValueConst)JS_NewUint32(ctx, array_length);
-            /* prs may have been modified */
-            prs = find_own_property(&pr, p, prop);
-            assert(prs != NULL);
-        }
-        /* property already exists */
-        if (!check_define_prop_flags(prs->flags, flags)) {
-        not_configurable:
-            return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
-        }
-
-        if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
-            /* Instantiate property and retry */
-            if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
-                return -1;
-            goto redo_prop_update;
-        }
-
-        if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE |
-                     JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
-            if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
-                JSObject *new_getter, *new_setter;
-
-                if (JS_IsFunction(ctx, getter)) {
-                    new_getter = JS_VALUE_GET_OBJ(getter);
-                } else {
-                    new_getter = NULL;
-                }
-                if (JS_IsFunction(ctx, setter)) {
-                    new_setter = JS_VALUE_GET_OBJ(setter);
-                } else {
-                    new_setter = NULL;
-                }
-
-                if ((prs->flags & JS_PROP_TMASK) != JS_PROP_GETSET) {
-                    if (js_shape_prepare_update(ctx, p, &prs))
-                        return -1;
-                    /* convert to getset */
-                    if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
-                        free_var_ref(ctx->rt, pr->u.var_ref);
-                    } else {
-                        JS_FreeValue(ctx, pr->u.value);
-                    }
-                    prs->flags = (prs->flags &
-                                  (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) |
-                        JS_PROP_GETSET;
-                    pr->u.getset.getter = NULL;
-                    pr->u.getset.setter = NULL;
-                } else {
-                    if (!(prs->flags & JS_PROP_CONFIGURABLE)) {
-                        if ((flags & JS_PROP_HAS_GET) &&
-                            new_getter != pr->u.getset.getter) {
-                            goto not_configurable;
-                        }
-                        if ((flags & JS_PROP_HAS_SET) &&
-                            new_setter != pr->u.getset.setter) {
-                            goto not_configurable;
-                        }
-                    }
-                }
-                if (flags & JS_PROP_HAS_GET) {
-                    if (pr->u.getset.getter)
-                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
-                    if (new_getter)
-                        JS_DupValue(ctx, getter);
-                    pr->u.getset.getter = new_getter;
-                }
-                if (flags & JS_PROP_HAS_SET) {
-                    if (pr->u.getset.setter)
-                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
-                    if (new_setter)
-                        JS_DupValue(ctx, setter);
-                    pr->u.getset.setter = new_setter;
-                }
-            } else {
-                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
-                    /* convert to data descriptor */
-                    if (js_shape_prepare_update(ctx, p, &prs))
-                        return -1;
-                    if (pr->u.getset.getter)
-                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
-                    if (pr->u.getset.setter)
-                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
-                    prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
-                    pr->u.value = JS_UNDEFINED;
-                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
-                    /* Note: JS_PROP_VARREF is always writable */
-                } else {
-                    if ((prs->flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 &&
-                        (flags & JS_PROP_HAS_VALUE)) {
-                        if (!js_same_value(ctx, val, pr->u.value)) {
-                            goto not_configurable;
-                        } else {
-                            return TRUE;
-                        }
-                    }
-                }
-                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
-                    if (flags & JS_PROP_HAS_VALUE) {
-                        if (p->class_id == JS_CLASS_MODULE_NS) {
-                            /* JS_PROP_WRITABLE is always true for variable
-                               references, but they are write protected in module name
-                               spaces. */
-                            if (!js_same_value(ctx, val, *pr->u.var_ref->pvalue))
-                                goto not_configurable;
-                        }
-                        /* update the reference */
-                        set_value(ctx, pr->u.var_ref->pvalue,
-                                  JS_DupValue(ctx, val));
-                    }
-                    /* if writable is set to false, no longer a
-                       reference (for mapped arguments) */
-                    if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) {
-                        JSValue val1;
-                        if (js_shape_prepare_update(ctx, p, &prs))
-                            return -1;
-                        val1 = JS_DupValue(ctx, *pr->u.var_ref->pvalue);
-                        free_var_ref(ctx->rt, pr->u.var_ref);
-                        pr->u.value = val1;
-                        prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
-                    }
-                } else if (prs->flags & JS_PROP_LENGTH) {
-                    if (flags & JS_PROP_HAS_VALUE) {
-                        /* Note: no JS code is executable because
-                           'val' is guaranted to be a Uint32 */
-                        res = set_array_length(ctx, p, JS_DupValue(ctx, val),
-                                               flags);
-                    } else {
-                        res = TRUE;
-                    }
-                    /* still need to reset the writable flag if
-                       needed.  The JS_PROP_LENGTH is kept because the
-                       Uint32 test is still done if the length
-                       property is read-only. */
-                    if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
-                        JS_PROP_HAS_WRITABLE) {
-                        prs = get_shape_prop(p->shape);
-                        if (js_update_property_flags(ctx, p, &prs,
-                                                     prs->flags & ~JS_PROP_WRITABLE))
-                            return -1;
-                    }
-                    return res;
-                } else {
-                    if (flags & JS_PROP_HAS_VALUE) {
-                        JS_FreeValue(ctx, pr->u.value);
-                        pr->u.value = JS_DupValue(ctx, val);
-                    }
-                    if (flags & JS_PROP_HAS_WRITABLE) {
-                        if (js_update_property_flags(ctx, p, &prs,
-                                                     (prs->flags & ~JS_PROP_WRITABLE) |
-                                                     (flags & JS_PROP_WRITABLE)))
-                            return -1;
-                    }
-                }
-            }
-        }
-        mask = 0;
-        if (flags & JS_PROP_HAS_CONFIGURABLE)
-            mask |= JS_PROP_CONFIGURABLE;
-        if (flags & JS_PROP_HAS_ENUMERABLE)
-            mask |= JS_PROP_ENUMERABLE;
-        if (js_update_property_flags(ctx, p, &prs,
-                                     (prs->flags & ~mask) | (flags & mask)))
-            return -1;
-        return TRUE;
-    }
-
-    /* handle modification of fast array elements */
-    if (p->fast_array) {
-        uint32_t idx;
-        uint32_t prop_flags;
-        if (p->class_id == JS_CLASS_ARRAY) {
-            if (__JS_AtomIsTaggedInt(prop)) {
-                idx = __JS_AtomToUInt32(prop);
-                if (idx < p->u.array.count) {
-                    prop_flags = get_prop_flags(flags, JS_PROP_C_W_E);
-                    if (prop_flags != JS_PROP_C_W_E)
-                        goto convert_to_slow_array;
-                    if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
-                    convert_to_slow_array:
-                        if (convert_fast_array_to_array(ctx, p))
-                            return -1;
-                        else
-                            goto redo_prop_update;
-                    }
-                    if (flags & JS_PROP_HAS_VALUE) {
-                        set_value(ctx, &p->u.array.u.values[idx], JS_DupValue(ctx, val));
-                    }
-                    return TRUE;
-                }
-            }
-        } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
-                   p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
-            JSValue num;
-            int ret;
-
-            if (!__JS_AtomIsTaggedInt(prop)) {
-                /* slow path with to handle all numeric indexes */
-                num = JS_AtomIsNumericIndex1(ctx, prop);
-                if (JS_IsUndefined(num))
-                    goto typed_array_done;
-                if (JS_IsException(num))
-                    return -1;
-                ret = JS_NumberIsInteger(ctx, num);
-                if (ret < 0) {
-                    JS_FreeValue(ctx, num);
-                    return -1;
-                }
-                if (!ret) {
-                    JS_FreeValue(ctx, num);
-                    return JS_ThrowTypeErrorOrFalse(ctx, flags, "non integer index in typed array");
-                }
-                ret = JS_NumberIsNegativeOrMinusZero(ctx, num);
-                JS_FreeValue(ctx, num);
-                if (ret) {
-                    return JS_ThrowTypeErrorOrFalse(ctx, flags, "negative index in typed array");
-                }
-                if (!__JS_AtomIsTaggedInt(prop))
-                    goto typed_array_oob;
-            }
-            idx = __JS_AtomToUInt32(prop);
-            /* if the typed array is detached, p->u.array.count = 0 */
-            if (idx >= typed_array_get_length(ctx, p)) {
-            typed_array_oob:
-                return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound index in typed array");
-            }
-            prop_flags = get_prop_flags(flags, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-            if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET) ||
-                prop_flags != (JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE)) {
-                return JS_ThrowTypeErrorOrFalse(ctx, flags, "invalid descriptor flags");
-            }
-            if (flags & JS_PROP_HAS_VALUE) {
-                return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), JS_DupValue(ctx, val), flags);
-            }
-            return TRUE;
-        typed_array_done: ;
-        }
-    }
-
-    return JS_CreateProperty(ctx, p, prop, val, getter, setter, flags);
-}
-
-static int JS_DefineAutoInitProperty(JSContext *ctx, JSValueConst this_obj,
-                                     JSAtom prop, JSAutoInitIDEnum id,
-                                     void *opaque, int flags)
-{
-    JSObject *p;
-    JSProperty *pr;
-
-    if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT)
-        return FALSE;
-
-    p = JS_VALUE_GET_OBJ(this_obj);
-
-    if (find_own_property(&pr, p, prop)) {
-        /* property already exists */
-        abort();
-        return FALSE;
-    }
-
-    /* Specialized CreateProperty */
-    pr = add_property(ctx, p, prop, (flags & JS_PROP_C_W_E) | JS_PROP_AUTOINIT);
-    if (unlikely(!pr))
-        return -1;
-    pr->u.init.realm_and_id = (uintptr_t)JS_DupContext(ctx);
-    assert((pr->u.init.realm_and_id & 3) == 0);
-    assert(id <= 3);
-    pr->u.init.realm_and_id |= id;
-    pr->u.init.opaque = opaque;
-    return TRUE;
-}
-
-/* shortcut to add or redefine a new property value */
-int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj,
-                           JSAtom prop, JSValue val, int flags)
-{
-    int ret;
-    ret = JS_DefineProperty(ctx, this_obj, prop, val, JS_UNDEFINED, JS_UNDEFINED,
-                            flags | JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE);
-    JS_FreeValue(ctx, val);
-    return ret;
-}
-
-int JS_DefinePropertyValueValue(JSContext *ctx, JSValueConst this_obj,
-                                JSValue prop, JSValue val, int flags)
-{
-    JSAtom atom;
-    int ret;
-    atom = JS_ValueToAtom(ctx, prop);
-    JS_FreeValue(ctx, prop);
-    if (unlikely(atom == JS_ATOM_NULL)) {
-        JS_FreeValue(ctx, val);
-        return -1;
-    }
-    ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
-    JS_FreeAtom(ctx, atom);
-    return ret;
-}
-
-int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj,
-                                 uint32_t idx, JSValue val, int flags)
-{
-    return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewUint32(ctx, idx),
-                                       val, flags);
-}
-
-int JS_DefinePropertyValueInt64(JSContext *ctx, JSValueConst this_obj,
-                                int64_t idx, JSValue val, int flags)
-{
-    return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx),
-                                       val, flags);
-}
-
-int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj,
-                              const char *prop, JSValue val, int flags)
-{
-    JSAtom atom;
-    int ret;
-    atom = JS_NewAtom(ctx, prop);
-    ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
-    JS_FreeAtom(ctx, atom);
-    return ret;
-}
-
-/* shortcut to add getter & setter */
-int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj,
-                            JSAtom prop, JSValue getter, JSValue setter,
-                            int flags)
-{
-    int ret;
-    ret = JS_DefineProperty(ctx, this_obj, prop, JS_UNDEFINED, getter, setter,
-                            flags | JS_PROP_HAS_GET | JS_PROP_HAS_SET |
-                            JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE);
-    JS_FreeValue(ctx, getter);
-    JS_FreeValue(ctx, setter);
-    return ret;
-}
-
-static int JS_CreateDataPropertyUint32(JSContext *ctx, JSValueConst this_obj,
-                                       int64_t idx, JSValue val, int flags)
-{
-    return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx),
-                                       val, flags | JS_PROP_CONFIGURABLE |
-                                       JS_PROP_ENUMERABLE | JS_PROP_WRITABLE);
-}
-
-
-/* return TRUE if 'obj' has a non empty 'name' string */
-static BOOL js_object_has_name(JSContext *ctx, JSValueConst obj)
-{
-    JSProperty *pr;
-    JSShapeProperty *prs;
-    JSValueConst val;
-    JSString *p;
-    
-    prs = find_own_property(&pr, JS_VALUE_GET_OBJ(obj), JS_ATOM_name);
-    if (!prs)
-        return FALSE;
-    if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
-        return TRUE;
-    val = pr->u.value;
-    if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
-        return TRUE;
-    p = JS_VALUE_GET_STRING(val);
-    return (p->len != 0);
-}
-
-static int JS_DefineObjectName(JSContext *ctx, JSValueConst obj,
-                               JSAtom name, int flags)
-{
-    if (name != JS_ATOM_NULL
-    &&  JS_IsObject(obj)
-    &&  !js_object_has_name(ctx, obj)
-    &&  JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, JS_AtomToString(ctx, name), flags) < 0) {
-        return -1;
-    }
-    return 0;
-}
-
-static int JS_DefineObjectNameComputed(JSContext *ctx, JSValueConst obj,
-                                       JSValueConst str, int flags)
-{
-    if (JS_IsObject(obj) &&
-        !js_object_has_name(ctx, obj)) {
-        JSAtom prop;
-        JSValue name_str;
-        prop = JS_ValueToAtom(ctx, str);
-        if (prop == JS_ATOM_NULL)
-            return -1;
-        name_str = js_get_function_name(ctx, prop);
-        JS_FreeAtom(ctx, prop);
-        if (JS_IsException(name_str))
-            return -1;
-        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, name_str, flags) < 0)
-            return -1;
-    }
-    return 0;
-}
-
-#define DEFINE_GLOBAL_LEX_VAR (1 << 7)
-#define DEFINE_GLOBAL_FUNC_VAR (1 << 6)
-
-static JSValue JS_ThrowSyntaxErrorVarRedeclaration(JSContext *ctx, JSAtom prop)
-{
-    return JS_ThrowSyntaxErrorAtom(ctx, "redeclaration of '%s'", prop);
-}
-
-/* flags is 0, DEFINE_GLOBAL_LEX_VAR or DEFINE_GLOBAL_FUNC_VAR */
-/* XXX: could support exotic global object. */
-static int JS_CheckDefineGlobalVar(JSContext *ctx, JSAtom prop, int flags)
-{
-    JSObject *p;
-    JSShapeProperty *prs;
-
-    p = JS_VALUE_GET_OBJ(ctx->global_obj);
-    prs = find_own_property1(p, prop);
-    /* XXX: should handle JS_PROP_AUTOINIT */
-    if (flags & DEFINE_GLOBAL_LEX_VAR) {
-        if (prs && !(prs->flags & JS_PROP_CONFIGURABLE))
-            goto fail_redeclaration;
-    } else {
-        if (!prs && !p->extensible)
-            goto define_error;
-        if (flags & DEFINE_GLOBAL_FUNC_VAR) {
-            if (prs) {
-                if (!(prs->flags & JS_PROP_CONFIGURABLE) &&
-                    ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET ||
-                     ((prs->flags & (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)) !=
-                      (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)))) {
-                define_error:
-                    JS_ThrowTypeErrorAtom(ctx, "cannot define variable '%s'",
-                                          prop);
-                    return -1;
-                }
-            }
-        }
-    }
-    /* check if there already is a lexical declaration */
-    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
-    prs = find_own_property1(p, prop);
-    if (prs) {
-    fail_redeclaration:
-        JS_ThrowSyntaxErrorVarRedeclaration(ctx, prop);
-        return -1;
-    }
-    return 0;
-}
-
-/* def_flags is (0, DEFINE_GLOBAL_LEX_VAR) |
-   JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE */
-/* XXX: could support exotic global object. */
-static int JS_DefineGlobalVar(JSContext *ctx, JSAtom prop, int def_flags)
-{
-    JSObject *p;
-    JSShapeProperty *prs;
-    JSProperty *pr;
-    JSValue val;
-    int flags;
-
-    if (def_flags & DEFINE_GLOBAL_LEX_VAR) {
-        p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
-        flags = JS_PROP_ENUMERABLE | (def_flags & JS_PROP_WRITABLE) |
-            JS_PROP_CONFIGURABLE;
-        val = JS_UNINITIALIZED;
-    } else {
-        p = JS_VALUE_GET_OBJ(ctx->global_obj);
-        flags = JS_PROP_ENUMERABLE | JS_PROP_WRITABLE |
-            (def_flags & JS_PROP_CONFIGURABLE);
-        val = JS_UNDEFINED;
-    }
-    prs = find_own_property1(p, prop);
-    if (prs)
-        return 0;
-    if (!p->extensible)
-        return 0;
-    pr = add_property(ctx, p, prop, flags);
-    if (unlikely(!pr))
-        return -1;
-    pr->u.value = val;
-    return 0;
-}
-
-/* 'def_flags' is 0 or JS_PROP_CONFIGURABLE. */
-/* XXX: could support exotic global object. */
-static int JS_DefineGlobalFunction(JSContext *ctx, JSAtom prop,
-                                   JSValueConst func, int def_flags)
-{
-
-    JSObject *p;
-    JSShapeProperty *prs;
-    int flags;
-
-    p = JS_VALUE_GET_OBJ(ctx->global_obj);
-    prs = find_own_property1(p, prop);
-    flags = JS_PROP_HAS_VALUE | JS_PROP_THROW;
-    if (!prs || (prs->flags & JS_PROP_CONFIGURABLE)) {
-        flags |= JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | def_flags |
-            JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE;
-    }
-    if (JS_DefineProperty(ctx, ctx->global_obj, prop, func,
-                          JS_UNDEFINED, JS_UNDEFINED, flags) < 0)
-        return -1;
-    return 0;
-}
-
-static JSValue JS_GetGlobalVar(JSContext *ctx, JSAtom prop,
-                               BOOL throw_ref_error)
-{
-    JSObject *p;
-    JSShapeProperty *prs;
-    JSProperty *pr;
-
-    /* no exotic behavior is possible in global_var_obj */
-    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
-    prs = find_own_property(&pr, p, prop);
-    if (prs) {
-        /* XXX: should handle JS_PROP_TMASK properties */
-        if (unlikely(JS_IsUninitialized(pr->u.value)))
-            return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
-        return JS_DupValue(ctx, pr->u.value);
-    }
-    return JS_GetPropertyInternal(ctx, ctx->global_obj, prop,
-                                 ctx->global_obj, throw_ref_error);
-}
-
-/* construct a reference to a global variable */
-static int JS_GetGlobalVarRef(JSContext *ctx, JSAtom prop, JSValue *sp)
-{
-    JSObject *p;
-    JSShapeProperty *prs;
-    JSProperty *pr;
-
-    /* no exotic behavior is possible in global_var_obj */
-    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
-    prs = find_own_property(&pr, p, prop);
-    if (prs) {
-        /* XXX: should handle JS_PROP_AUTOINIT properties? */
-        /* XXX: conformance: do these tests in
-           OP_put_var_ref/OP_get_var_ref ? */
-        if (unlikely(JS_IsUninitialized(pr->u.value))) {
-            JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
-            return -1;
-        }
-        if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) {
-            return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop);
-        }
-        sp[0] = JS_DupValue(ctx, ctx->global_var_obj);
-    } else {
-        int ret;
-        ret = JS_HasProperty(ctx, ctx->global_obj, prop);
-        if (ret < 0)
-            return -1;
-        if (ret) {
-            sp[0] = JS_DupValue(ctx, ctx->global_obj);
-        } else {
-            sp[0] = JS_UNDEFINED;
-        }
-    }
-    sp[1] = JS_AtomToValue(ctx, prop);
-    return 0;
-}
-
-/* use for strict variable access: test if the variable exists */
-static int JS_CheckGlobalVar(JSContext *ctx, JSAtom prop)
-{
-    JSObject *p;
-    JSShapeProperty *prs;
-    int ret;
-
-    /* no exotic behavior is possible in global_var_obj */
-    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
-    prs = find_own_property1(p, prop);
-    if (prs) {
-        ret = TRUE;
-    } else {
-        ret = JS_HasProperty(ctx, ctx->global_obj, prop);
-        if (ret < 0)
-            return -1;
-    }
-    return ret;
-}
-
-/* flag = 0: normal variable write
-   flag = 1: initialize lexical variable
-   flag = 2: normal variable write, strict check was done before
-*/
-static int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val,
-                           int flag)
-{
-    JSObject *p;
-    JSShapeProperty *prs;
-    JSProperty *pr;
-    int flags;
-
-    /* no exotic behavior is possible in global_var_obj */
-    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
-    prs = find_own_property(&pr, p, prop);
-    if (prs) {
-        /* XXX: should handle JS_PROP_AUTOINIT properties? */
-        if (flag != 1) {
-            if (unlikely(JS_IsUninitialized(pr->u.value))) {
-                JS_FreeValue(ctx, val);
-                JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
-                return -1;
-            }
-            if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) {
-                JS_FreeValue(ctx, val);
-                return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop);
-            }
-        }
-        set_value(ctx, &pr->u.value, val);
-        return 0;
-    }
-    flags = JS_PROP_THROW_STRICT;
-    if (is_strict_mode(ctx)) 
-        flags |= JS_PROP_NO_ADD;
-    return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, flags);
-}
-
-/* return -1, FALSE or TRUE. return FALSE if not configurable or
-   invalid object. return -1 in case of exception.
-   flags can be 0, JS_PROP_THROW or JS_PROP_THROW_STRICT */
-int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags)
-{
-    JSValue obj1;
-    JSObject *p;
-    int res;
-    
-    obj1 = JS_ToObject(ctx, obj);
-    if (JS_IsException(obj1))
-        return -1;
-    p = JS_VALUE_GET_OBJ(obj1);
-    res = delete_property(ctx, p, prop);
-    JS_FreeValue(ctx, obj1);
-    if (res != FALSE)
-        return res;
-    if ((flags & JS_PROP_THROW) ||
-        ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
-        JS_ThrowTypeError(ctx, "could not delete property");
-        return -1;
-    }
-    return FALSE;
-}
-
-int JS_DeletePropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, int flags)
-{
-    JSAtom prop;
-    int res;
-
-    if ((uint64_t)idx <= JS_ATOM_MAX_INT) {
-        /* fast path for fast arrays */
-        return JS_DeleteProperty(ctx, obj, __JS_AtomFromUInt32(idx), flags);
-    }
-    prop = JS_NewAtomInt64(ctx, idx);
-    if (prop == JS_ATOM_NULL)
-        return -1;
-    res = JS_DeleteProperty(ctx, obj, prop, flags);
-    JS_FreeAtom(ctx, prop);
-    return res;
-}
-
-BOOL JS_IsFunction(JSContext *ctx, JSValueConst val)
-{
-    JSObject *p;
-    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
-        return FALSE;
-    p = JS_VALUE_GET_OBJ(val);
-    switch(p->class_id) {
-    case JS_CLASS_BYTECODE_FUNCTION:
-        return TRUE;
-    case JS_CLASS_PROXY:
-        return p->u.proxy_data->is_func;
-    default:
-        return (ctx->rt->class_array[p->class_id].call != NULL);
-    }
-}
-
-BOOL JS_IsCFunction(JSContext *ctx, JSValueConst val, JSCFunction *func, int magic)
-{
-    JSObject *p;
-    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
-        return FALSE;
-    p = JS_VALUE_GET_OBJ(val);
-    if (p->class_id == JS_CLASS_C_FUNCTION)
-        return (p->u.cfunc.c_function.generic == func && p->u.cfunc.magic == magic);
-    else
-        return FALSE;
-}
-
-BOOL JS_IsConstructor(JSContext *ctx, JSValueConst val)
-{
-    JSObject *p;
-    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
-        return FALSE;
-    p = JS_VALUE_GET_OBJ(val);
-    return p->is_constructor;
-}
-
-BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, BOOL val)
-{
-    JSObject *p;
-    if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
-        return FALSE;
-    p = JS_VALUE_GET_OBJ(func_obj);
-    p->is_constructor = val;
-    return TRUE;
-}
-
-BOOL JS_IsError(JSContext *ctx, JSValueConst val)
-{
-    JSObject *p;
-    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
-        return FALSE;
-    p = JS_VALUE_GET_OBJ(val);
-    return (p->class_id == JS_CLASS_ERROR);
-}
-
-/* used to avoid catching interrupt exceptions */
-BOOL JS_IsUncatchableError(JSContext *ctx, JSValueConst val)
-{
-    JSObject *p;
-    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
-        return FALSE;
-    p = JS_VALUE_GET_OBJ(val);
-    return p->class_id == JS_CLASS_ERROR && p->is_uncatchable_error;
-}
-
-void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag)
-{
-    JSObject *p;
-    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
-        return;
-    p = JS_VALUE_GET_OBJ(val);
-    if (p->class_id == JS_CLASS_ERROR)
-        p->is_uncatchable_error = flag;
-}
-
-void JS_ResetUncatchableError(JSContext *ctx)
-{
-    JS_SetUncatchableError(ctx, ctx->rt->current_exception, FALSE);
-}
-
-void JS_SetOpaque(JSValue obj, void *opaque)
-{
-   JSObject *p;
-    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
-        p = JS_VALUE_GET_OBJ(obj);
-        p->u.opaque = opaque;
-    }
-}
-
-/* return NULL if not an object of class class_id */
-void *JS_GetOpaque(JSValueConst obj, JSClassID class_id)
-{
-    JSObject *p;
-    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
-        return NULL;
-    p = JS_VALUE_GET_OBJ(obj);
-    if (p->class_id != class_id)
-        return NULL;
-    return p->u.opaque;
-}
-
-void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id)
-{
-    void *p = JS_GetOpaque(obj, class_id);
-    if (unlikely(!p)) {
-        JS_ThrowTypeErrorInvalidClass(ctx, class_id);
-    }
-    return p;
-}
-
-#define HINT_STRING  0
-#define HINT_NUMBER  1
-#define HINT_NONE    2
-/* don't try Symbol.toPrimitive */
-#define HINT_FORCE_ORDINARY (1 << 4)
-
-static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint)
-{
-    int i;
-    BOOL force_ordinary;
-
-    JSAtom method_name;
-    JSValue method, ret;
-    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
-        return val;
-    force_ordinary = hint & HINT_FORCE_ORDINARY;
-    hint &= ~HINT_FORCE_ORDINARY;
-    if (!force_ordinary) {
-        method = JS_GetProperty(ctx, val, JS_ATOM_Symbol_toPrimitive);
-        if (JS_IsException(method))
-            goto exception;
-        /* ECMA says *If exoticToPrim is not undefined* but tests in
-           test262 use null as a non callable converter */
-        if (!JS_IsUndefined(method) && !JS_IsNull(method)) {
-            JSAtom atom;
-            JSValue arg;
-            switch(hint) {
-            case HINT_STRING:
-                atom = JS_ATOM_string;
-                break;
-            case HINT_NUMBER:
-                atom = JS_ATOM_number;
-                break;
-            default:
-            case HINT_NONE:
-                atom = JS_ATOM_default;
-                break;
-            }
-            arg = JS_AtomToString(ctx, atom);
-            ret = JS_CallFree(ctx, method, val, 1, (JSValueConst *)&arg);
-            JS_FreeValue(ctx, arg);
-            if (JS_IsException(ret))
-                goto exception;
-            JS_FreeValue(ctx, val);
-            if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT)
-                return ret;
-            JS_FreeValue(ctx, ret);
-            return JS_ThrowTypeError(ctx, "toPrimitive");
-        }
-    }
-    if (hint != HINT_STRING)
-        hint = HINT_NUMBER;
-    for(i = 0; i < 2; i++) {
-        if ((i ^ hint) == 0) {
-            method_name = JS_ATOM_toString;
-        } else {
-            method_name = JS_ATOM_valueOf;
-        }
-        method = JS_GetProperty(ctx, val, method_name);
-        if (JS_IsException(method))
-            goto exception;
-        if (JS_IsFunction(ctx, method)) {
-            ret = JS_CallFree(ctx, method, val, 0, NULL);
-            if (JS_IsException(ret))
-                goto exception;
-            if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
-                JS_FreeValue(ctx, val);
-                return ret;
-            }
-            JS_FreeValue(ctx, ret);
-        } else {
-            JS_FreeValue(ctx, method);
-        }
-    }
-    JS_ThrowTypeError(ctx, "toPrimitive");
-exception:
-    JS_FreeValue(ctx, val);
-    return JS_EXCEPTION;
-}
-
-static JSValue JS_ToPrimitive(JSContext *ctx, JSValueConst val, int hint)
-{
-    return JS_ToPrimitiveFree(ctx, JS_DupValue(ctx, val), hint);
-}
-
-void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj)
-{
-    JSObject *p;
-    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
-        return;
-    p = JS_VALUE_GET_OBJ(obj);
-    p->is_HTMLDDA = TRUE;
-}
-
-static inline BOOL JS_IsHTMLDDA(JSContext *ctx, JSValueConst obj)
-{
-    JSObject *p;
-    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
-        return FALSE;
-    p = JS_VALUE_GET_OBJ(obj);
-    return p->is_HTMLDDA;
-}
-                         
-static int JS_ToBoolFree(JSContext *ctx, JSValue val)
-{
-    uint32_t tag = JS_VALUE_GET_TAG(val);
-    switch(tag) {
-    case JS_TAG_INT:
-        return JS_VALUE_GET_INT(val) != 0;
-    case JS_TAG_BOOL:
-    case JS_TAG_NULL:
-    case JS_TAG_UNDEFINED:
-        return JS_VALUE_GET_INT(val);
-    case JS_TAG_EXCEPTION:
-        return -1;
-    case JS_TAG_STRING:
-        {
-            BOOL ret = JS_VALUE_GET_STRING(val)->len != 0;
-            JS_FreeValue(ctx, val);
-            return ret;
-        }
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_INT:
-    case JS_TAG_BIG_FLOAT:
-        {
-            JSBigFloat *p = JS_VALUE_GET_PTR(val);
-            BOOL ret;
-            ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN;
-            JS_FreeValue(ctx, val);
-            return ret;
-        }
-    case JS_TAG_BIG_DECIMAL:
-        {
-            JSBigDecimal *p = JS_VALUE_GET_PTR(val);
-            BOOL ret;
-            ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN;
-            JS_FreeValue(ctx, val);
-            return ret;
-        }
-#endif
-    case JS_TAG_OBJECT:
-        {
-            JSObject *p = JS_VALUE_GET_OBJ(val);
-            BOOL ret;
-            ret = !p->is_HTMLDDA;
-            JS_FreeValue(ctx, val);
-            return ret;
-        }
-        break;
-    default:
-        if (JS_TAG_IS_FLOAT64(tag)) {
-            double d = JS_VALUE_GET_FLOAT64(val);
-            return !isnan(d) && d != 0;
-        } else {
-            JS_FreeValue(ctx, val);
-            return TRUE;
-        }
-    }
-}
-
-int JS_ToBool(JSContext *ctx, JSValueConst val)
-{
-    return JS_ToBoolFree(ctx, JS_DupValue(ctx, val));
-}
-
-static int skip_spaces(const char *pc)
-{
-    const uint8_t *p, *p_next, *p_start;
-    uint32_t c;
-
-    p = p_start = (const uint8_t *)pc;
-    for (;;) {
-        c = *p;
-        if (c < 128) {
-            if (!((c >= 0x09 && c <= 0x0d) || (c == 0x20)))
-                break;
-            p++;
-        } else {
-            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
-            if (!lre_is_space(c))
-                break;
-            p = p_next;
-        }
-    }
-    return p - p_start;
-}
-
-static inline int to_digit(int c)
-{
-    if (c >= '0' && c <= '9')
-        return c - '0';
-    else if (c >= 'A' && c <= 'Z')
-        return c - 'A' + 10;
-    else if (c >= 'a' && c <= 'z')
-        return c - 'a' + 10;
-    else
-        return 36;
-}
-
-/* XXX: remove */
-static double js_strtod(const char *p, int radix, BOOL is_float)
-{
-    double d;
-    int c;
-    
-    if (!is_float || radix != 10) {
-        uint64_t n_max, n;
-        int int_exp, is_neg;
-        
-        is_neg = 0;
-        if (*p == '-') {
-            is_neg = 1;
-            p++;
-        }
-
-        /* skip leading zeros */
-        while (*p == '0')
-            p++;
-        n = 0;
-        if (radix == 10)
-            n_max = ((uint64_t)-1 - 9) / 10; /* most common case */
-        else
-            n_max = ((uint64_t)-1 - (radix - 1)) / radix;
-        /* XXX: could be more precise */
-        int_exp = 0;
-        while (*p != '\0') {
-            c = to_digit((uint8_t)*p);
-            if (c >= radix)
-                break;
-            if (n <= n_max) {
-                n = n * radix + c;
-            } else {
-                int_exp++;
-            }
-            p++;
-        }
-        d = n;
-        if (int_exp != 0) {
-            d *= pow(radix, int_exp);
-        }
-        if (is_neg)
-            d = -d;
-    } else {
-        d = strtod(p, NULL);
-    }
-    return d;
-}
-
-#define ATOD_INT_ONLY        (1 << 0)
-/* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */
-#define ATOD_ACCEPT_BIN_OCT  (1 << 2)
-/* accept O prefix as octal if radix == 0 and properly formed (Annex B) */
-#define ATOD_ACCEPT_LEGACY_OCTAL  (1 << 4)
-/* accept _ between digits as a digit separator */
-#define ATOD_ACCEPT_UNDERSCORES  (1 << 5)
-/* allow a suffix to override the type */
-#define ATOD_ACCEPT_SUFFIX    (1 << 6) 
-/* default type */
-#define ATOD_TYPE_MASK        (3 << 7)
-#define ATOD_TYPE_FLOAT64     (0 << 7)
-#define ATOD_TYPE_BIG_INT     (1 << 7)
-#define ATOD_TYPE_BIG_FLOAT   (2 << 7)
-#define ATOD_TYPE_BIG_DECIMAL (3 << 7)
-/* assume bigint mode: floats are parsed as integers if no decimal
-   point nor exponent */
-#define ATOD_MODE_BIGINT      (1 << 9) 
-/* accept -0x1 */
-#define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10)
-
-#ifdef CONFIG_BIGNUM
-static JSValue js_string_to_bigint(JSContext *ctx, const char *buf,
-                                   int radix, int flags, slimb_t *pexponent)
-{
-    bf_t a_s, *a = &a_s;
-    int ret;
-    JSValue val;
-    val = JS_NewBigInt(ctx);
-    if (JS_IsException(val))
-        return val;
-    a = JS_GetBigInt(val);
-    ret = bf_atof(a, buf, NULL, radix, BF_PREC_INF, BF_RNDZ);
-    if (ret & BF_ST_MEM_ERROR) {
-        JS_FreeValue(ctx, val);
-        return JS_ThrowOutOfMemory(ctx);
-    }
-    val = JS_CompactBigInt1(ctx, val, (flags & ATOD_MODE_BIGINT) != 0);
-    return val;
-}
-
-static JSValue js_string_to_bigfloat(JSContext *ctx, const char *buf,
-                                     int radix, int flags, slimb_t *pexponent)
-{
-    bf_t *a;
-    int ret;
-    JSValue val;
-    
-    val = JS_NewBigFloat(ctx);
-    if (JS_IsException(val))
-        return val;
-    a = JS_GetBigFloat(val);
-    if (flags & ATOD_ACCEPT_SUFFIX) {
-        /* return the exponent to get infinite precision */
-        ret = bf_atof2(a, pexponent, buf, NULL, radix, BF_PREC_INF,
-                       BF_RNDZ | BF_ATOF_EXPONENT);
-    } else {
-        ret = bf_atof(a, buf, NULL, radix, ctx->fp_env.prec,
-                      ctx->fp_env.flags);
-    }
-    if (ret & BF_ST_MEM_ERROR) {
-        JS_FreeValue(ctx, val);
-        return JS_ThrowOutOfMemory(ctx);
-    }
-    return val;
-}
-
-static JSValue js_string_to_bigdecimal(JSContext *ctx, const char *buf,
-                                       int radix, int flags, slimb_t *pexponent)
-{
-    bfdec_t *a;
-    int ret;
-    JSValue val;
-    
-    val = JS_NewBigDecimal(ctx);
-    if (JS_IsException(val))
-        return val;
-    a = JS_GetBigDecimal(val);
-    ret = bfdec_atof(a, buf, NULL, BF_PREC_INF,
-                     BF_RNDZ | BF_ATOF_NO_NAN_INF);
-    if (ret & BF_ST_MEM_ERROR) {
-        JS_FreeValue(ctx, val);
-        return JS_ThrowOutOfMemory(ctx);
-    }
-    return val;
-}
-
-#endif
-
-/* return an exception in case of memory error. Return JS_NAN if
-   invalid syntax */
-#ifdef CONFIG_BIGNUM
-static JSValue js_atof2(JSContext *ctx, const char *str, const char **pp,
-                        int radix, int flags, slimb_t *pexponent)
-#else
-static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
-                       int radix, int flags)
-#endif
-{
-    const char *p, *p_start;
-    int sep, is_neg;
-    BOOL is_float, has_legacy_octal;
-    int atod_type = flags & ATOD_TYPE_MASK;
-    char buf1[64], *buf;
-    int i, j, len;
-    BOOL buf_allocated = FALSE;
-    JSValue val;
-    
-    /* optional separator between digits */
-    sep = (flags & ATOD_ACCEPT_UNDERSCORES) ? '_' : 256;
-    has_legacy_octal = FALSE;
-    
-    p = str;
-    p_start = p;
-    is_neg = 0;
-    if (p[0] == '+') {
-        p++;
-        p_start++;
-        if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN))
-            goto no_radix_prefix;
-    } else if (p[0] == '-') {
-        p++;
-        p_start++;
-        is_neg = 1;
-        if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN))
-            goto no_radix_prefix;
-    }
-    if (p[0] == '0') {
-        if ((p[1] == 'x' || p[1] == 'X') &&
-            (radix == 0 || radix == 16)) {
-            p += 2;
-            radix = 16;
-        } else if ((p[1] == 'o' || p[1] == 'O') &&
-                   radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) {
-            p += 2;
-            radix = 8;
-        } else if ((p[1] == 'b' || p[1] == 'B') &&
-                   radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) {
-            p += 2;
-            radix = 2;
-        } else if ((p[1] >= '0' && p[1] <= '9') &&
-                   radix == 0 && (flags & ATOD_ACCEPT_LEGACY_OCTAL)) {
-            int i;
-            has_legacy_octal = TRUE;
-            sep = 256;
-            for (i = 1; (p[i] >= '0' && p[i] <= '7'); i++)
-                continue;
-            if (p[i] == '8' || p[i] == '9')
-                goto no_prefix;
-            p += 1;
-            radix = 8;
-        } else {
-            goto no_prefix;
-        }
-        /* there must be a digit after the prefix */
-        if (to_digit((uint8_t)*p) >= radix)
-            goto fail;
-    no_prefix: ;
-    } else {
- no_radix_prefix:
-        if (!(flags & ATOD_INT_ONLY) &&
-            (atod_type == ATOD_TYPE_FLOAT64 ||
-             atod_type == ATOD_TYPE_BIG_FLOAT) &&
-            strstart(p, "Infinity", &p)) {
-#ifdef CONFIG_BIGNUM
-            if (atod_type == ATOD_TYPE_BIG_FLOAT) {
-                bf_t *a;
-                val = JS_NewBigFloat(ctx);
-                if (JS_IsException(val))
-                    goto done;
-                a = JS_GetBigFloat(val);
-                bf_set_inf(a, is_neg);
-            } else
-#endif
-            {
-                double d = 1.0 / 0.0;
-                if (is_neg)
-                    d = -d;
-                val = JS_NewFloat64(ctx, d);
-            }
-            goto done;
-        }
-    }
-    if (radix == 0)
-        radix = 10;
-    is_float = FALSE;
-    p_start = p;
-    while (to_digit((uint8_t)*p) < radix
-           ||  (*p == sep && (radix != 10 ||
-                              p != p_start + 1 || p[-1] != '0') &&
-                to_digit((uint8_t)p[1]) < radix)) {
-        p++;
-    }
-    if (!(flags & ATOD_INT_ONLY)) {
-        if (*p == '.' && (p > p_start || to_digit((uint8_t)p[1]) < radix)) {
-            is_float = TRUE;
-            p++;
-            if (*p == sep)
-                goto fail;
-            while (to_digit((uint8_t)*p) < radix ||
-                   (*p == sep && to_digit((uint8_t)p[1]) < radix))
-                p++;
-        }
-        if (p > p_start &&
-            (((*p == 'e' || *p == 'E') && radix == 10) ||
-             ((*p == 'p' || *p == 'P') && (radix == 2 || radix == 8 || radix == 16)))) {
-            const char *p1 = p + 1;
-            is_float = TRUE;
-            if (*p1 == '+') {
-                p1++;
-            } else if (*p1 == '-') {
-                p1++;
-            }
-            if (is_digit((uint8_t)*p1)) {
-                p = p1 + 1;
-                while (is_digit((uint8_t)*p) || (*p == sep && is_digit((uint8_t)p[1])))
-                    p++;
-            }
-        }
-    }
-    if (p == p_start)
-        goto fail;
-
-    buf = buf1;
-    buf_allocated = FALSE;
-    len = p - p_start;
-    if (unlikely((len + 2) > sizeof(buf1))) {
-        buf = js_malloc_rt(ctx->rt, len + 2); /* no exception raised */
-        if (!buf)
-            goto mem_error;
-        buf_allocated = TRUE;
-    }
-    /* remove the separators and the radix prefixes */
-    j = 0;
-    if (is_neg)
-        buf[j++] = '-';
-    for (i = 0; i < len; i++) {
-        if (p_start[i] != '_')
-            buf[j++] = p_start[i];
-    }
-    buf[j] = '\0';
-
-#ifdef CONFIG_BIGNUM
-    if (flags & ATOD_ACCEPT_SUFFIX) {
-        if (*p == 'n') {
-            p++;
-            atod_type = ATOD_TYPE_BIG_INT;
-        } else if (*p == 'l') {
-            p++;
-            atod_type = ATOD_TYPE_BIG_FLOAT;
-        } else if (*p == 'm') {
-            p++;
-            atod_type = ATOD_TYPE_BIG_DECIMAL;
-        } else {
-            if (flags & ATOD_MODE_BIGINT) {
-                if (!is_float)
-                    atod_type = ATOD_TYPE_BIG_INT;
-                if (has_legacy_octal)
-                    goto fail;
-            } else {
-                if (is_float && radix != 10)
-                    goto fail;
-            }
-        }
-    } else {
-        if (atod_type == ATOD_TYPE_FLOAT64) {
-            if (flags & ATOD_MODE_BIGINT) {
-                if (!is_float)
-                    atod_type = ATOD_TYPE_BIG_INT;
-                if (has_legacy_octal)
-                    goto fail;
-            } else {
-                if (is_float && radix != 10)
-                    goto fail;
-            }
-        }
-    }
-
-    switch(atod_type) {
-    case ATOD_TYPE_FLOAT64:
-        {
-            double d;
-            d = js_strtod(buf, radix, is_float);
-            /* return int or float64 */
-            val = JS_NewFloat64(ctx, d);
-        }
-        break;
-    case ATOD_TYPE_BIG_INT:
-        if (has_legacy_octal || is_float)
-            goto fail;
-        val = ctx->rt->bigint_ops.from_string(ctx, buf, radix, flags, NULL);
-        break;
-    case ATOD_TYPE_BIG_FLOAT:
-        if (has_legacy_octal)
-            goto fail;
-        val = ctx->rt->bigfloat_ops.from_string(ctx, buf, radix, flags,
-                                                pexponent);
-        break;
-    case ATOD_TYPE_BIG_DECIMAL:
-        if (radix != 10)
-            goto fail;
-        val = ctx->rt->bigdecimal_ops.from_string(ctx, buf, radix, flags, NULL);
-        break;
-    default:
-        abort();
-    }
-#else
-    {
-        double d;
-        (void)has_legacy_octal;
-        if (is_float && radix != 10)
-            goto fail;
-        d = js_strtod(buf, radix, is_float);
-        val = JS_NewFloat64(ctx, d);
-    }
-#endif
-    
-done:
-    if (buf_allocated)
-        js_free_rt(ctx->rt, buf);
-    if (pp)
-        *pp = p;
-    return val;
- fail:
-    val = JS_NAN;
-    goto done;
- mem_error:
-    val = JS_ThrowOutOfMemory(ctx);
-    goto done;
-}
-
-#ifdef CONFIG_BIGNUM
-static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
-                       int radix, int flags)
-{
-    return js_atof2(ctx, str, pp, radix, flags, NULL);
-}
-#endif
-
-typedef enum JSToNumberHintEnum {
-    TON_FLAG_NUMBER,
-    TON_FLAG_NUMERIC,
-} JSToNumberHintEnum;
-
-static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val,
-                                   JSToNumberHintEnum flag)
-{
-    uint32_t tag;
-    JSValue ret;
-
- redo:
-    tag = JS_VALUE_GET_NORM_TAG(val);
-    switch(tag) {
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_DECIMAL:
-        if (flag != TON_FLAG_NUMERIC) {
-            JS_FreeValue(ctx, val);
-            return JS_ThrowTypeError(ctx, "cannot convert bigdecimal to number");
-        }
-        ret = val;
-        break;
-    case JS_TAG_BIG_INT:
-        if (flag != TON_FLAG_NUMERIC) {
-            JS_FreeValue(ctx, val);
-            return JS_ThrowTypeError(ctx, "cannot convert bigint to number");
-        }
-        ret = val;
-        break;
-    case JS_TAG_BIG_FLOAT:
-        if (flag != TON_FLAG_NUMERIC) {
-            JS_FreeValue(ctx, val);
-            return JS_ThrowTypeError(ctx, "cannot convert bigfloat to number");
-        }
-        ret = val;
-        break;
-#endif
-    case JS_TAG_FLOAT64:
-    case JS_TAG_INT:
-    case JS_TAG_EXCEPTION:
-        ret = val;
-        break;
-    case JS_TAG_BOOL:
-    case JS_TAG_NULL:
-        ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));
-        break;
-    case JS_TAG_UNDEFINED:
-        ret = JS_NAN;
-        break;
-    case JS_TAG_OBJECT:
-        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
-        if (JS_IsException(val))
-            return JS_EXCEPTION;
-        goto redo;
-    case JS_TAG_STRING:
-        {
-            const char *str;
-            const char *p;
-            size_t len;
-            
-            str = JS_ToCStringLen(ctx, &len, val);
-            JS_FreeValue(ctx, val);
-            if (!str)
-                return JS_EXCEPTION;
-            p = str;
-            p += skip_spaces(p);
-            if ((p - str) == len) {
-                ret = JS_NewInt32(ctx, 0);
-            } else {
-                int flags = ATOD_ACCEPT_BIN_OCT;
-                ret = js_atof(ctx, p, &p, 0, flags);
-                if (!JS_IsException(ret)) {
-                    p += skip_spaces(p);
-                    if ((p - str) != len) {
-                        JS_FreeValue(ctx, ret);
-                        ret = JS_NAN;
-                    }
-                }
-            }
-            JS_FreeCString(ctx, str);
-        }
-        break;
-    case JS_TAG_SYMBOL:
-        JS_FreeValue(ctx, val);
-        return JS_ThrowTypeError(ctx, "cannot convert symbol to number");
-    default:
-        JS_FreeValue(ctx, val);
-        ret = JS_NAN;
-        break;
-    }
-    return ret;
-}
-
-static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val)
-{
-    return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMBER);
-}
-
-static JSValue JS_ToNumericFree(JSContext *ctx, JSValue val)
-{
-    return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC);
-}
-
-static JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val)
-{
-    return JS_ToNumericFree(ctx, JS_DupValue(ctx, val));
-}
-
-static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres,
-                                          JSValue val)
-{
-    double d;
-    uint32_t tag;
-
-    val = JS_ToNumberFree(ctx, val);
-    if (JS_IsException(val)) {
-        *pres = JS_FLOAT64_NAN;
-        return -1;
-    }
-    tag = JS_VALUE_GET_NORM_TAG(val);
-    switch(tag) {
-    case JS_TAG_INT:
-        d = JS_VALUE_GET_INT(val);
-        break;
-    case JS_TAG_FLOAT64:
-        d = JS_VALUE_GET_FLOAT64(val);
-        break;
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_INT:
-    case JS_TAG_BIG_FLOAT:
-        {
-            JSBigFloat *p = JS_VALUE_GET_PTR(val);
-            /* XXX: there can be a double rounding issue with some
-               primitives (such as JS_ToUint8ClampFree()), but it is
-               not critical to fix it. */
-            bf_get_float64(&p->num, &d, BF_RNDN);
-            JS_FreeValue(ctx, val);
-        }
-        break;
-#endif
-    default:
-        abort();
-    }
-    *pres = d;
-    return 0;
-}
-
-static inline int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val)
-{
-    uint32_t tag;
-
-    tag = JS_VALUE_GET_TAG(val);
-    if (tag <= JS_TAG_NULL) {
-        *pres = JS_VALUE_GET_INT(val);
-        return 0;
-    } else if (JS_TAG_IS_FLOAT64(tag)) {
-        *pres = JS_VALUE_GET_FLOAT64(val);
-        return 0;
-    } else {
-        return __JS_ToFloat64Free(ctx, pres, val);
-    }
-}
-
-int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val)
-{
-    return JS_ToFloat64Free(ctx, pres, JS_DupValue(ctx, val));
-}
-
-static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val)
-{
-    return JS_ToNumberFree(ctx, JS_DupValue(ctx, val));
-}
-
-/* same as JS_ToNumber() but return 0 in case of NaN/Undefined */
-static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
-{
-    uint32_t tag;
-    JSValue ret;
-
- redo:
-    tag = JS_VALUE_GET_NORM_TAG(val);
-    switch(tag) {
-    case JS_TAG_INT:
-    case JS_TAG_BOOL:
-    case JS_TAG_NULL:
-    case JS_TAG_UNDEFINED:
-        ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));
-        break;
-    case JS_TAG_FLOAT64:
-        {
-            double d = JS_VALUE_GET_FLOAT64(val);
-            if (isnan(d)) {
-                ret = JS_NewInt32(ctx, 0);
-            } else {
-                /* convert -0 to +0 */
-                d = trunc(d) + 0.0;
-                ret = JS_NewFloat64(ctx, d);
-            }
-        }
-        break;
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_FLOAT:
-        {
-            bf_t a_s, *a, r_s, *r = &r_s;
-            BOOL is_nan;
-
-            a = JS_ToBigFloat(ctx, &a_s, val);
-            if (!bf_is_finite(a)) {
-                is_nan = bf_is_nan(a);
-                if (is_nan)
-                    ret = JS_NewInt32(ctx, 0);
-                else
-                    ret = JS_DupValue(ctx, val);
-            } else {
-                ret = JS_NewBigInt(ctx);
-                if (!JS_IsException(ret)) {
-                    r = JS_GetBigInt(ret);
-                    bf_set(r, a);
-                    bf_rint(r, BF_RNDZ);
-                    ret = JS_CompactBigInt(ctx, ret);
-                }
-            }
-            if (a == &a_s)
-                bf_delete(a);
-            JS_FreeValue(ctx, val);
-        }
-        break;
-#endif
-    default:
-        val = JS_ToNumberFree(ctx, val);
-        if (JS_IsException(val))
-            return val;
-        goto redo;
-    }
-    return ret;
-}
-
-/* Note: the integer value is satured to 32 bits */
-static int JS_ToInt32SatFree(JSContext *ctx, int *pres, JSValue val)
-{
-    uint32_t tag;
-    int ret;
-
- redo:
-    tag = JS_VALUE_GET_NORM_TAG(val);
-    switch(tag) {
-    case JS_TAG_INT:
-    case JS_TAG_BOOL:
-    case JS_TAG_NULL:
-    case JS_TAG_UNDEFINED:
-        ret = JS_VALUE_GET_INT(val);
-        break;
-    case JS_TAG_EXCEPTION:
-        *pres = 0;
-        return -1;
-    case JS_TAG_FLOAT64:
-        {
-            double d = JS_VALUE_GET_FLOAT64(val);
-            if (isnan(d)) {
-                ret = 0;
-            } else {
-                if (d < INT32_MIN)
-                    ret = INT32_MIN;
-                else if (d > INT32_MAX)
-                    ret = INT32_MAX;
-                else
-                    ret = (int)d;
-            }
-        }
-        break;
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_FLOAT:
-        {
-            JSBigFloat *p = JS_VALUE_GET_PTR(val);
-            bf_get_int32(&ret, &p->num, 0);
-            JS_FreeValue(ctx, val);
-        }
-        break;
-#endif
-    default:
-        val = JS_ToNumberFree(ctx, val);
-        if (JS_IsException(val)) {
-            *pres = 0;
-            return -1;
-        }
-        goto redo;
-    }
-    *pres = ret;
-    return 0;
-}
-
-int JS_ToInt32Sat(JSContext *ctx, int *pres, JSValueConst val)
-{
-    return JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val));
-}
-
-int JS_ToInt32Clamp(JSContext *ctx, int *pres, JSValueConst val,
-                    int min, int max, int min_offset)
-{
-    int res = JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val));
-    if (res == 0) {
-        if (*pres < min) {
-            *pres += min_offset;
-            if (*pres < min)
-                *pres = min;
-        } else {
-            if (*pres > max)
-                *pres = max;
-        }
-    }
-    return res;
-}
-
-static int JS_ToInt64SatFree(JSContext *ctx, int64_t *pres, JSValue val)
-{
-    uint32_t tag;
-
- redo:
-    tag = JS_VALUE_GET_NORM_TAG(val);
-    switch(tag) {
-    case JS_TAG_INT:
-    case JS_TAG_BOOL:
-    case JS_TAG_NULL:
-    case JS_TAG_UNDEFINED:
-        *pres = JS_VALUE_GET_INT(val);
-        return 0;
-    case JS_TAG_EXCEPTION:
-        *pres = 0;
-        return -1;
-    case JS_TAG_FLOAT64:
-        {
-            double d = JS_VALUE_GET_FLOAT64(val);
-            if (isnan(d)) {
-                *pres = 0;
-            } else {
-                if (d < INT64_MIN)
-                    *pres = INT64_MIN;
-                else if (d > INT64_MAX)
-                    *pres = INT64_MAX;
-                else
-                    *pres = (int64_t)d;
-            }
-        }
-        return 0;
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_FLOAT:
-        {
-            JSBigFloat *p = JS_VALUE_GET_PTR(val);
-            bf_get_int64(pres, &p->num, 0);
-            JS_FreeValue(ctx, val);
-        }
-        return 0;
-#endif
-    default:
-        val = JS_ToNumberFree(ctx, val);
-        if (JS_IsException(val)) {
-            *pres = 0;
-            return -1;
-        }
-        goto redo;
-    }
-}
-
-int JS_ToInt64Sat(JSContext *ctx, int64_t *pres, JSValueConst val)
-{
-    return JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val));
-}
-
-int JS_ToInt64Clamp(JSContext *ctx, int64_t *pres, JSValueConst val,
-                    int64_t min, int64_t max, int64_t neg_offset)
-{
-    int res = JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val));
-    if (res == 0) {
-        if (*pres < 0)
-            *pres += neg_offset;
-        if (*pres < min)
-            *pres = min;
-        else if (*pres > max)
-            *pres = max;
-    }
-    return res;
-}
-
-/* Same as JS_ToInt32Free() but with a 64 bit result. Return (<0, 0)
-   in case of exception */
-static int JS_ToInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
-{
-    uint32_t tag;
-    int64_t ret;
-
- redo:
-    tag = JS_VALUE_GET_NORM_TAG(val);
-    switch(tag) {
-    case JS_TAG_INT:
-    case JS_TAG_BOOL:
-    case JS_TAG_NULL:
-    case JS_TAG_UNDEFINED:
-        ret = JS_VALUE_GET_INT(val);
-        break;
-    case JS_TAG_FLOAT64:
-        {
-            JSFloat64Union u;
-            double d;
-            int e;
-            d = JS_VALUE_GET_FLOAT64(val);
-            u.d = d;
-            /* we avoid doing fmod(x, 2^64) */
-            e = (u.u64 >> 52) & 0x7ff;
-            if (likely(e <= (1023 + 62))) {
-                /* fast case */
-                ret = (int64_t)d;
-            } else if (e <= (1023 + 62 + 53)) {
-                uint64_t v;
-                /* remainder modulo 2^64 */
-                v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);
-                ret = v << ((e - 1023) - 52);
-                /* take the sign into account */
-                if (u.u64 >> 63)
-                    ret = -ret;
-            } else {
-                ret = 0; /* also handles NaN and +inf */
-            }
-        }
-        break;
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_FLOAT:
-        {
-            JSBigFloat *p = JS_VALUE_GET_PTR(val);
-            bf_get_int64(&ret, &p->num, BF_GET_INT_MOD);
-            JS_FreeValue(ctx, val);
-        }
-        break;
-#endif
-    default:
-        val = JS_ToNumberFree(ctx, val);
-        if (JS_IsException(val)) {
-            *pres = 0;
-            return -1;
-        }
-        goto redo;
-    }
-    *pres = ret;
-    return 0;
-}
-
-int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
-{
-    return JS_ToInt64Free(ctx, pres, JS_DupValue(ctx, val));
-}
-
-int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val)
-{
-    if (JS_IsBigInt(ctx, val))
-        return JS_ToBigInt64(ctx, pres, val);
-    else
-        return JS_ToInt64(ctx, pres, val);
-}
-
-/* return (<0, 0) in case of exception */
-static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val)
-{
-    uint32_t tag;
-    int32_t ret;
-
- redo:
-    tag = JS_VALUE_GET_NORM_TAG(val);
-    switch(tag) {
-    case JS_TAG_INT:
-    case JS_TAG_BOOL:
-    case JS_TAG_NULL:
-    case JS_TAG_UNDEFINED:
-        ret = JS_VALUE_GET_INT(val);
-        break;
-    case JS_TAG_FLOAT64:
-        {
-            JSFloat64Union u;
-            double d;
-            int e;
-            d = JS_VALUE_GET_FLOAT64(val);
-            u.d = d;
-            /* we avoid doing fmod(x, 2^32) */
-            e = (u.u64 >> 52) & 0x7ff;
-            if (likely(e <= (1023 + 30))) {
-                /* fast case */
-                ret = (int32_t)d;
-            } else if (e <= (1023 + 30 + 53)) {
-                uint64_t v;
-                /* remainder modulo 2^32 */
-                v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);
-                v = v << ((e - 1023) - 52 + 32);
-                ret = v >> 32;
-                /* take the sign into account */
-                if (u.u64 >> 63)
-                    ret = -ret;
-            } else {
-                ret = 0; /* also handles NaN and +inf */
-            }
-        }
-        break;
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_FLOAT:
-        {
-            JSBigFloat *p = JS_VALUE_GET_PTR(val);
-            bf_get_int32(&ret, &p->num, BF_GET_INT_MOD);
-            JS_FreeValue(ctx, val);
-        }
-        break;
-#endif
-    default:
-        val = JS_ToNumberFree(ctx, val);
-        if (JS_IsException(val)) {
-            *pres = 0;
-            return -1;
-        }
-        goto redo;
-    }
-    *pres = ret;
-    return 0;
-}
-
-int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val)
-{
-    return JS_ToInt32Free(ctx, pres, JS_DupValue(ctx, val));
-}
-
-static inline int JS_ToUint32Free(JSContext *ctx, uint32_t *pres, JSValue val)
-{
-    return JS_ToInt32Free(ctx, (int32_t *)pres, val);
-}
-
-static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val)
-{
-    uint32_t tag;
-    int res;
-
- redo:
-    tag = JS_VALUE_GET_NORM_TAG(val);
-    switch(tag) {
-    case JS_TAG_INT:
-    case JS_TAG_BOOL:
-    case JS_TAG_NULL:
-    case JS_TAG_UNDEFINED:
-        res = JS_VALUE_GET_INT(val);
-#ifdef CONFIG_BIGNUM
-    int_clamp:
-#endif
-        res = max_int(0, min_int(255, res));
-        break;
-    case JS_TAG_FLOAT64:
-        {
-            double d = JS_VALUE_GET_FLOAT64(val);
-            if (isnan(d)) {
-                res = 0;
-            } else {
-                if (d < 0)
-                    res = 0;
-                else if (d > 255)
-                    res = 255;
-                else
-                    res = lrint(d);
-            }
-        }
-        break;
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_FLOAT:
-        {
-            JSBigFloat *p = JS_VALUE_GET_PTR(val);
-            bf_t r_s, *r = &r_s;
-            bf_init(ctx->bf_ctx, r);
-            bf_set(r, &p->num);
-            bf_rint(r, BF_RNDN);
-            bf_get_int32(&res, r, 0);
-            bf_delete(r);
-            JS_FreeValue(ctx, val);
-        }
-        goto int_clamp;
-#endif
-    default:
-        val = JS_ToNumberFree(ctx, val);
-        if (JS_IsException(val)) {
-            *pres = 0;
-            return -1;
-        }
-        goto redo;
-    }
-    *pres = res;
-    return 0;
-}
-
-static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
-                                            JSValue val, BOOL is_array_ctor)
-{
-    uint32_t tag, len;
-
-    tag = JS_VALUE_GET_TAG(val);
-    switch(tag) {
-    case JS_TAG_INT:
-    case JS_TAG_BOOL:
-    case JS_TAG_NULL:
-        {
-            int v;
-            v = JS_VALUE_GET_INT(val);
-            if (v < 0)
-                goto fail;
-            len = v;
-        }
-        break;
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_INT:
-    case JS_TAG_BIG_FLOAT:
-        {
-            JSBigFloat *p = JS_VALUE_GET_PTR(val);
-            bf_t a;
-            BOOL res;
-            bf_get_int32((int32_t *)&len, &p->num, BF_GET_INT_MOD);
-            bf_init(ctx->bf_ctx, &a);
-            bf_set_ui(&a, len);
-            res = bf_cmp_eq(&a, &p->num);
-            bf_delete(&a);
-            JS_FreeValue(ctx, val);
-            if (!res)
-                goto fail;
-        }
-        break;
-#endif
-    default:
-        if (JS_TAG_IS_FLOAT64(tag)) {
-            double d;
-            d = JS_VALUE_GET_FLOAT64(val);
-            len = (uint32_t)d;
-            if (len != d)
-                goto fail;
-        } else {
-            uint32_t len1;
-
-            if (is_array_ctor) {
-                val = JS_ToNumberFree(ctx, val);
-                if (JS_IsException(val))
-                    return -1;
-                /* cannot recurse because val is a number */
-                if (JS_ToArrayLengthFree(ctx, &len, val, TRUE))
-                    return -1;
-            } else {
-                /* legacy behavior: must do the conversion twice and compare */
-                if (JS_ToUint32(ctx, &len, val)) {
-                    JS_FreeValue(ctx, val);
-                    return -1;
-                }
-                val = JS_ToNumberFree(ctx, val);
-                if (JS_IsException(val))
-                    return -1;
-                /* cannot recurse because val is a number */
-                if (JS_ToArrayLengthFree(ctx, &len1, val, FALSE))
-                    return -1;
-                if (len1 != len) {
-                fail:
-                    JS_ThrowRangeError(ctx, "invalid array length");
-                    return -1;
-                }
-            }
-        }
-        break;
-    }
-    *plen = len;
-    return 0;
-}
-
-#define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1)
-
-static BOOL is_safe_integer(double d)
-{
-    return isfinite(d) && floor(d) == d &&
-        fabs(d) <= (double)MAX_SAFE_INTEGER;
-}
-
-int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val)
-{
-    int64_t v;
-    if (JS_ToInt64Sat(ctx, &v, val))
-        return -1;
-    if (v < 0 || v > MAX_SAFE_INTEGER) {
-        JS_ThrowRangeError(ctx, "invalid array index");
-        *plen = 0;
-        return -1;
-    }
-    *plen = v;
-    return 0;
-}
-
-/* convert a value to a length between 0 and MAX_SAFE_INTEGER.
-   return -1 for exception */
-static __exception int JS_ToLengthFree(JSContext *ctx, int64_t *plen,
-                                       JSValue val)
-{
-    int res = JS_ToInt64Clamp(ctx, plen, val, 0, MAX_SAFE_INTEGER, 0);
-    JS_FreeValue(ctx, val);
-    return res;
-}
-
-/* Note: can return an exception */
-static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val)
-{
-    double d;
-    if (!JS_IsNumber(val))
-        return FALSE;
-    if (unlikely(JS_ToFloat64(ctx, &d, val)))
-        return -1;
-    return isfinite(d) && floor(d) == d;
-}
-
-static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val)
-{
-    uint32_t tag;
-
-    tag = JS_VALUE_GET_NORM_TAG(val);
-    switch(tag) {
-    case JS_TAG_INT:
-        {
-            int v;
-            v = JS_VALUE_GET_INT(val);
-            return (v < 0);
-        }
-    case JS_TAG_FLOAT64:
-        {
-            JSFloat64Union u;
-            u.d = JS_VALUE_GET_FLOAT64(val);
-            return (u.u64 >> 63);
-        }
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_INT:
-        {
-            JSBigFloat *p = JS_VALUE_GET_PTR(val);
-            /* Note: integer zeros are not necessarily positive */
-            return p->num.sign && !bf_is_zero(&p->num);
-        }
-    case JS_TAG_BIG_FLOAT:
-        {
-            JSBigFloat *p = JS_VALUE_GET_PTR(val);
-            return p->num.sign;
-        }
-        break;
-    case JS_TAG_BIG_DECIMAL:
-        {
-            JSBigDecimal *p = JS_VALUE_GET_PTR(val);
-            return p->num.sign;
-        }
-        break;
-#endif
-    default:
-        return FALSE;
-    }
-}
-
-#ifdef CONFIG_BIGNUM
-
-static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix)
-{
-    JSValue ret;
-    bf_t a_s, *a;
-    char *str;
-    int saved_sign;
-
-    a = JS_ToBigInt(ctx, &a_s, val);
-    if (!a)
-        return JS_EXCEPTION;
-    saved_sign = a->sign;
-    if (a->expn == BF_EXP_ZERO)
-        a->sign = 0;
-    str = bf_ftoa(NULL, a, radix, 0, BF_RNDZ | BF_FTOA_FORMAT_FRAC |
-                  BF_FTOA_JS_QUIRKS);
-    a->sign = saved_sign;
-    JS_FreeBigInt(ctx, a, &a_s);
-    if (!str)
-        return JS_ThrowOutOfMemory(ctx);
-    ret = JS_NewString(ctx, str);
-    bf_free(ctx->bf_ctx, str);
-    return ret;
-}
-
-static JSValue js_bigint_to_string(JSContext *ctx, JSValueConst val)
-{
-    return js_bigint_to_string1(ctx, val, 10);
-}
-
-static JSValue js_ftoa(JSContext *ctx, JSValueConst val1, int radix,
-                       limb_t prec, bf_flags_t flags)
-{
-    JSValue val, ret;
-    bf_t a_s, *a;
-    char *str;
-    int saved_sign;
-
-    val = JS_ToNumeric(ctx, val1);
-    if (JS_IsException(val))
-        return val;
-    a = JS_ToBigFloat(ctx, &a_s, val);
-    saved_sign = a->sign;
-    if (a->expn == BF_EXP_ZERO)
-        a->sign = 0;
-    flags |= BF_FTOA_JS_QUIRKS;
-    if ((flags & BF_FTOA_FORMAT_MASK) == BF_FTOA_FORMAT_FREE_MIN) {
-        /* Note: for floating point numbers with a radix which is not
-           a power of two, the current precision is used to compute
-           the number of digits. */
-        if ((radix & (radix - 1)) != 0) {
-            bf_t r_s, *r = &r_s;
-            int prec, flags1;
-            /* must round first */
-            if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) {
-                prec = ctx->fp_env.prec;
-                flags1 = ctx->fp_env.flags &
-                    (BF_FLAG_SUBNORMAL | (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT));
-            } else {
-                prec = 53;
-                flags1 = bf_set_exp_bits(11) | BF_FLAG_SUBNORMAL;
-            }
-            bf_init(ctx->bf_ctx, r);
-            bf_set(r, a);
-            bf_round(r, prec, flags1 | BF_RNDN);
-            str = bf_ftoa(NULL, r, radix, prec, flags1 | flags);
-            bf_delete(r);
-        } else {
-            str = bf_ftoa(NULL, a, radix, BF_PREC_INF, flags);
-        }
-    } else {
-        str = bf_ftoa(NULL, a, radix, prec, flags);
-    }
-    a->sign = saved_sign;
-    if (a == &a_s)
-        bf_delete(a);
-    JS_FreeValue(ctx, val);
-    if (!str)
-        return JS_ThrowOutOfMemory(ctx);
-    ret = JS_NewString(ctx, str);
-    bf_free(ctx->bf_ctx, str);
-    return ret;
-}
-
-static JSValue js_bigfloat_to_string(JSContext *ctx, JSValueConst val)
-{
-    return js_ftoa(ctx, val, 10, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN);
-}
-
-static JSValue js_bigdecimal_to_string1(JSContext *ctx, JSValueConst val,
-                                        limb_t prec, int flags)
-{
-    JSValue ret;
-    bfdec_t *a;
-    char *str;
-    int saved_sign;
-
-    a = JS_ToBigDecimal(ctx, val);
-    saved_sign = a->sign;
-    if (a->expn == BF_EXP_ZERO)
-        a->sign = 0;
-    str = bfdec_ftoa(NULL, a, prec, flags | BF_FTOA_JS_QUIRKS);
-    a->sign = saved_sign;
-    if (!str)
-        return JS_ThrowOutOfMemory(ctx);
-    ret = JS_NewString(ctx, str);
-    bf_free(ctx->bf_ctx, str);
-    return ret;
-}
-
-static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val)
-{
-    return js_bigdecimal_to_string1(ctx, val, 0,
-                                    BF_RNDZ | BF_FTOA_FORMAT_FREE);
-}
-
-#endif /* CONFIG_BIGNUM */
-
-/* 2 <= base <= 36 */
-static char *i64toa(char *buf_end, int64_t n, unsigned int base)
-{
-    char *q = buf_end;
-    int digit, is_neg;
-
-    is_neg = 0;
-    if (n < 0) {
-        is_neg = 1;
-        n = -n;
-    }
-    *--q = '\0';
-    do {
-        digit = (uint64_t)n % base;
-        n = (uint64_t)n / base;
-        if (digit < 10)
-            digit += '0';
-        else
-            digit += 'a' - 10;
-        *--q = digit;
-    } while (n != 0);
-    if (is_neg)
-        *--q = '-';
-    return q;
-}
-
-/* buf1 contains the printf result */
-static void js_ecvt1(double d, int n_digits, int *decpt, int *sign, char *buf,
-                     int rounding_mode, char *buf1, int buf1_size)
-{
-    if (rounding_mode != FE_TONEAREST)
-        fesetround(rounding_mode);
-    snprintf(buf1, buf1_size, "%+.*e", n_digits - 1, d);
-    if (rounding_mode != FE_TONEAREST)
-        fesetround(FE_TONEAREST);
-    *sign = (buf1[0] == '-');
-    /* mantissa */
-    buf[0] = buf1[1];
-    if (n_digits > 1)
-        memcpy(buf + 1, buf1 + 3, n_digits - 1);
-    buf[n_digits] = '\0';
-    /* exponent */
-    *decpt = atoi(buf1 + n_digits + 2 + (n_digits > 1)) + 1;
-}
-
-/* maximum buffer size for js_dtoa */
-#define JS_DTOA_BUF_SIZE 128
-
-/* needed because ecvt usually limits the number of digits to
-   17. Return the number of digits. */
-static int js_ecvt(double d, int n_digits, int *decpt, int *sign, char *buf,
-                   BOOL is_fixed)
-{
-    int rounding_mode;
-    char buf_tmp[JS_DTOA_BUF_SIZE];
-
-    if (!is_fixed) {
-        unsigned int n_digits_min, n_digits_max;
-        /* find the minimum amount of digits (XXX: inefficient but simple) */
-        n_digits_min = 1;
-        n_digits_max = 17;
-        while (n_digits_min < n_digits_max) {
-            n_digits = (n_digits_min + n_digits_max) / 2;
-            js_ecvt1(d, n_digits, decpt, sign, buf, FE_TONEAREST,
-                     buf_tmp, sizeof(buf_tmp));
-            if (strtod(buf_tmp, NULL) == d) {
-                /* no need to keep the trailing zeros */
-                while (n_digits >= 2 && buf[n_digits - 1] == '0')
-                    n_digits--;
-                n_digits_max = n_digits;
-            } else {
-                n_digits_min = n_digits + 1;
-            }
-        }
-        n_digits = n_digits_max;
-        rounding_mode = FE_TONEAREST;
-    } else {
-        rounding_mode = FE_TONEAREST;
-#ifdef CONFIG_PRINTF_RNDN
-        {
-            char buf1[JS_DTOA_BUF_SIZE], buf2[JS_DTOA_BUF_SIZE];
-            int decpt1, sign1, decpt2, sign2;
-            /* The JS rounding is specified as round to nearest ties away
-               from zero (RNDNA), but in printf the "ties" case is not
-               specified (for example it is RNDN for glibc, RNDNA for
-               Windows), so we must round manually. */
-            js_ecvt1(d, n_digits + 1, &decpt1, &sign1, buf1, FE_TONEAREST,
-                     buf_tmp, sizeof(buf_tmp));
-            /* XXX: could use 2 digits to reduce the average running time */
-            if (buf1[n_digits] == '5') {
-                js_ecvt1(d, n_digits + 1, &decpt1, &sign1, buf1, FE_DOWNWARD,
-                         buf_tmp, sizeof(buf_tmp));
-                js_ecvt1(d, n_digits + 1, &decpt2, &sign2, buf2, FE_UPWARD,
-                         buf_tmp, sizeof(buf_tmp));
-                if (memcmp(buf1, buf2, n_digits + 1) == 0 && decpt1 == decpt2) {
-                    /* exact result: round away from zero */
-                    if (sign1)
-                        rounding_mode = FE_DOWNWARD;
-                    else
-                        rounding_mode = FE_UPWARD;
-                }
-            }
-        }
-#endif /* CONFIG_PRINTF_RNDN */
-    }
-    js_ecvt1(d, n_digits, decpt, sign, buf, rounding_mode,
-             buf_tmp, sizeof(buf_tmp));
-    return n_digits;
-}
-
-static int js_fcvt1(char *buf, int buf_size, double d, int n_digits,
-                    int rounding_mode)
-{
-    int n;
-    if (rounding_mode != FE_TONEAREST)
-        fesetround(rounding_mode);
-    n = snprintf(buf, buf_size, "%.*f", n_digits, d);
-    if (rounding_mode != FE_TONEAREST)
-        fesetround(FE_TONEAREST);
-    assert(n < buf_size);
-    return n;
-}
-
-static void js_fcvt(char *buf, int buf_size, double d, int n_digits)
-{
-    int rounding_mode;
-    rounding_mode = FE_TONEAREST;
-#ifdef CONFIG_PRINTF_RNDN
-    {
-        int n1, n2;
-        char buf1[JS_DTOA_BUF_SIZE];
-        char buf2[JS_DTOA_BUF_SIZE];
-
-        /* The JS rounding is specified as round to nearest ties away from
-           zero (RNDNA), but in printf the "ties" case is not specified
-           (for example it is RNDN for glibc, RNDNA for Windows), so we
-           must round manually. */
-        n1 = js_fcvt1(buf1, sizeof(buf1), d, n_digits + 1, FE_TONEAREST);
-        rounding_mode = FE_TONEAREST;
-        /* XXX: could use 2 digits to reduce the average running time */
-        if (buf1[n1 - 1] == '5') {
-            n1 = js_fcvt1(buf1, sizeof(buf1), d, n_digits + 1, FE_DOWNWARD);
-            n2 = js_fcvt1(buf2, sizeof(buf2), d, n_digits + 1, FE_UPWARD);
-            if (n1 == n2 && memcmp(buf1, buf2, n1) == 0) {
-                /* exact result: round away from zero */
-                if (buf1[0] == '-')
-                    rounding_mode = FE_DOWNWARD;
-                else
-                    rounding_mode = FE_UPWARD;
-            }
-        }
-    }
-#endif /* CONFIG_PRINTF_RNDN */
-    js_fcvt1(buf, buf_size, d, n_digits, rounding_mode);
-}
-
-/* radix != 10 is only supported with flags = JS_DTOA_VAR_FORMAT */
-/* use as many digits as necessary */
-#define JS_DTOA_VAR_FORMAT   (0 << 0)
-/* use n_digits significant digits (1 <= n_digits <= 101) */
-#define JS_DTOA_FIXED_FORMAT (1 << 0)
-/* force fractional format: [-]dd.dd with n_digits fractional digits */
-#define JS_DTOA_FRAC_FORMAT  (2 << 0)
-/* force exponential notation either in fixed or variable format */
-#define JS_DTOA_FORCE_EXP    (1 << 2)
-
-/* XXX: slow and maybe not fully correct. Use libbf when it is fast enough.
-   XXX: radix != 10 is only supported for small integers
-*/
-static void js_dtoa1(char *buf, double d, int radix, int n_digits, int flags)
-{
-    char *q;
-
-    if (!isfinite(d)) {
-        if (isnan(d)) {
-            strcpy(buf, "NaN");
-        } else {
-            q = buf;
-            if (d < 0)
-                *q++ = '-';
-            strcpy(q, "Infinity");
-        }
-    } else if (flags == JS_DTOA_VAR_FORMAT) {
-        int64_t i64;
-        char buf1[70], *ptr;
-        i64 = (int64_t)d;
-        if (d != i64 || i64 > MAX_SAFE_INTEGER || i64 < -MAX_SAFE_INTEGER)
-            goto generic_conv;
-        /* fast path for integers */
-        ptr = i64toa(buf1 + sizeof(buf1), i64, radix);
-        strcpy(buf, ptr);
-    } else {
-        if (d == 0.0)
-            d = 0.0; /* convert -0 to 0 */
-        if (flags == JS_DTOA_FRAC_FORMAT) {
-            js_fcvt(buf, JS_DTOA_BUF_SIZE, d, n_digits);
-        } else {
-            char buf1[JS_DTOA_BUF_SIZE];
-            int sign, decpt, k, n, i, p, n_max;
-            BOOL is_fixed;
-        generic_conv:
-            is_fixed = ((flags & 3) == JS_DTOA_FIXED_FORMAT);
-            if (is_fixed) {
-                n_max = n_digits;
-            } else {
-                n_max = 21;
-            }
-            /* the number has k digits (k >= 1) */
-            k = js_ecvt(d, n_digits, &decpt, &sign, buf1, is_fixed);
-            n = decpt; /* d=10^(n-k)*(buf1) i.e. d= < x.yyyy 10^(n-1) */
-            q = buf;
-            if (sign)
-                *q++ = '-';
-            if (flags & JS_DTOA_FORCE_EXP)
-                goto force_exp;
-            if (n >= 1 && n <= n_max) {
-                if (k <= n) {
-                    memcpy(q, buf1, k);
-                    q += k;
-                    for(i = 0; i < (n - k); i++)
-                        *q++ = '0';
-                    *q = '\0';
-                } else {
-                    /* k > n */
-                    memcpy(q, buf1, n);
-                    q += n;
-                    *q++ = '.';
-                    for(i = 0; i < (k - n); i++)
-                        *q++ = buf1[n + i];
-                    *q = '\0';
-                }
-            } else if (n >= -5 && n <= 0) {
-                *q++ = '0';
-                *q++ = '.';
-                for(i = 0; i < -n; i++)
-                    *q++ = '0';
-                memcpy(q, buf1, k);
-                q += k;
-                *q = '\0';
-            } else {
-            force_exp:
-                /* exponential notation */
-                *q++ = buf1[0];
-                if (k > 1) {
-                    *q++ = '.';
-                    for(i = 1; i < k; i++)
-                        *q++ = buf1[i];
-                }
-                *q++ = 'e';
-                p = n - 1;
-                if (p >= 0)
-                    *q++ = '+';
-                sprintf(q, "%d", p);
-            }
-        }
-    }
-}
-
-static JSValue js_dtoa(JSContext *ctx,
-                       double d, int radix, int n_digits, int flags)
-{
-    char buf[JS_DTOA_BUF_SIZE];
-    js_dtoa1(buf, d, radix, n_digits, flags);
-    return JS_NewString(ctx, buf);
-}
-
-JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToPropertyKey)
-{
-    uint32_t tag;
-    const char *str;
-    char buf[32];
-
-    tag = JS_VALUE_GET_NORM_TAG(val);
-    switch(tag) {
-    case JS_TAG_STRING:
-        return JS_DupValue(ctx, val);
-    case JS_TAG_INT:
-        snprintf(buf, sizeof(buf), "%d", JS_VALUE_GET_INT(val));
-        str = buf;
-        goto new_string;
-    case JS_TAG_BOOL:
-        return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ?
-                          JS_ATOM_true : JS_ATOM_false);
-    case JS_TAG_NULL:
-        return JS_AtomToString(ctx, JS_ATOM_null);
-    case JS_TAG_UNDEFINED:
-        return JS_AtomToString(ctx, JS_ATOM_undefined);
-    case JS_TAG_EXCEPTION:
-        return JS_EXCEPTION;
-    case JS_TAG_OBJECT:
-        {
-            JSValue val1, ret;
-            val1 = JS_ToPrimitive(ctx, val, HINT_STRING);
-            if (JS_IsException(val1))
-                return val1;
-            ret = JS_ToStringInternal(ctx, val1, is_ToPropertyKey);
-            JS_FreeValue(ctx, val1);
-            return ret;
-        }
-        break;
-    case JS_TAG_FUNCTION_BYTECODE:
-        str = "[function bytecode]";
-        goto new_string;
-    case JS_TAG_SYMBOL:
-        if (is_ToPropertyKey) {
-            return JS_DupValue(ctx, val);
-        } else {
-            return JS_ThrowTypeError(ctx, "cannot convert symbol to string");
-        }
-    case JS_TAG_FLOAT64:
-        return js_dtoa(ctx, JS_VALUE_GET_FLOAT64(val), 10, 0,
-                       JS_DTOA_VAR_FORMAT);
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_INT:
-        return ctx->rt->bigint_ops.to_string(ctx, val);
-    case JS_TAG_BIG_FLOAT:
-        return ctx->rt->bigfloat_ops.to_string(ctx, val);
-    case JS_TAG_BIG_DECIMAL:
-        return ctx->rt->bigdecimal_ops.to_string(ctx, val);
-#endif
-    default:
-        str = "[unsupported type]";
-    new_string:
-        return JS_NewString(ctx, str);
-    }
-}
-
-JSValue JS_ToString(JSContext *ctx, JSValueConst val)
-{
-    return JS_ToStringInternal(ctx, val, FALSE);
-}
-
-static JSValue JS_ToStringFree(JSContext *ctx, JSValue val)
-{
-    JSValue ret;
-    ret = JS_ToString(ctx, val);
-    JS_FreeValue(ctx, val);
-    return ret;
-}
-
-static JSValue JS_ToLocaleStringFree(JSContext *ctx, JSValue val)
-{
-    if (JS_IsUndefined(val) || JS_IsNull(val))
-        return JS_ToStringFree(ctx, val);
-    return JS_InvokeFree(ctx, val, JS_ATOM_toLocaleString, 0, NULL);
-}
-
-JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val)
-{
-    return JS_ToStringInternal(ctx, val, TRUE);
-}
-
-static JSValue JS_ToStringCheckObject(JSContext *ctx, JSValueConst val)
-{
-    uint32_t tag = JS_VALUE_GET_TAG(val);
-    if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)
-        return JS_ThrowTypeError(ctx, "null or undefined are forbidden");
-    return JS_ToString(ctx, val);
-}
-
-static JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1)
-{
-    JSValue val;
-    JSString *p;
-    int i;
-    uint32_t c;
-    StringBuffer b_s, *b = &b_s;
-    char buf[16];
-
-    val = JS_ToStringCheckObject(ctx, val1);
-    if (JS_IsException(val))
-        return val;
-    p = JS_VALUE_GET_STRING(val);
-
-    if (string_buffer_init(ctx, b, p->len + 2))
-        goto fail;
-
-    if (string_buffer_putc8(b, '\"'))
-        goto fail;
-    for(i = 0; i < p->len; ) {
-        c = string_getc(p, &i);
-        switch(c) {
-        case '\t':
-            c = 't';
-            goto quote;
-        case '\r':
-            c = 'r';
-            goto quote;
-        case '\n':
-            c = 'n';
-            goto quote;
-        case '\b':
-            c = 'b';
-            goto quote;
-        case '\f':
-            c = 'f';
-            goto quote;
-        case '\"':
-        case '\\':
-        quote:
-            if (string_buffer_putc8(b, '\\'))
-                goto fail;
-            if (string_buffer_putc8(b, c))
-                goto fail;
-            break;
-        default:
-            if (c < 32 || (c >= 0xd800 && c < 0xe000)) {
-                snprintf(buf, sizeof(buf), "\\u%04x", c);
-                if (string_buffer_puts8(b, buf))
-                    goto fail;
-            } else {
-                if (string_buffer_putc(b, c))
-                    goto fail;
-            }
-            break;
-        }
-    }
-    if (string_buffer_putc8(b, '\"'))
-        goto fail;
-    JS_FreeValue(ctx, val);
-    return string_buffer_end(b);
- fail:
-    JS_FreeValue(ctx, val);
-    string_buffer_free(b);
-    return JS_EXCEPTION;
-}
-
-static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt)
-{
-    printf("%14s %4s %4s %14s %10s %s\n",
-           "ADDRESS", "REFS", "SHRF", "PROTO", "CLASS", "PROPS");
-}
-
-/* for debug only: dump an object without side effect */
-static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
-{
-    uint32_t i;
-    char atom_buf[ATOM_GET_STR_BUF_SIZE];
-    JSShape *sh;
-    JSShapeProperty *prs;
-    JSProperty *pr;
-    BOOL is_first = TRUE;
-
-    /* XXX: should encode atoms with special characters */
-    sh = p->shape; /* the shape can be NULL while freeing an object */
-    printf("%14p %4d ",
-           (void *)p,
-           p->header.ref_count);
-    if (sh) {
-        printf("%3d%c %14p ",
-               sh->header.ref_count,
-               " *"[sh->is_hashed],
-               (void *)sh->proto);
-    } else {
-        printf("%3s  %14s ", "-", "-");
-    }
-    printf("%10s ",
-           JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), rt->class_array[p->class_id].class_name));
-    if (p->is_exotic && p->fast_array) {
-        printf("[ ");
-        for(i = 0; i < p->u.array.count; i++) {
-            if (i != 0)
-                printf(", ");
-            switch (p->class_id) {
-            case JS_CLASS_ARRAY:
-            case JS_CLASS_ARGUMENTS:
-                JS_DumpValueShort(rt, p->u.array.u.values[i]);
-                break;
-            case JS_CLASS_UINT8C_ARRAY:
-            case JS_CLASS_INT8_ARRAY:
-            case JS_CLASS_UINT8_ARRAY:
-            case JS_CLASS_INT16_ARRAY:
-            case JS_CLASS_UINT16_ARRAY:
-            case JS_CLASS_INT32_ARRAY:
-            case JS_CLASS_UINT32_ARRAY:
-#ifdef CONFIG_BIGNUM
-            case JS_CLASS_BIG_INT64_ARRAY:
-            case JS_CLASS_BIG_UINT64_ARRAY:
-#endif
-            case JS_CLASS_FLOAT32_ARRAY:
-            case JS_CLASS_FLOAT64_ARRAY:
-                {
-                    int size = 1 << typed_array_size_log2(p->class_id);
-                    const uint8_t *b = p->u.array.u.uint8_ptr + i * size;
-                    while (size-- > 0)
-                        printf("%02X", *b++);
-                }
-                break;
-            }
-        }
-        printf(" ] ");
-    }
-
-    if (sh) {
-        printf("{ ");
-        for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
-            if (prs->atom != JS_ATOM_NULL) {
-                pr = &p->prop[i];
-                if (!is_first)
-                    printf(", ");
-                printf("%s: ",
-                       JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), prs->atom));
-                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
-                    printf("[getset %p %p]", (void *)pr->u.getset.getter,
-                           (void *)pr->u.getset.setter);
-                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
-                    printf("[varref %p]", (void *)pr->u.var_ref);
-                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
-                    printf("[autoinit %p %d %p]",
-                           (void *)js_autoinit_get_realm(pr),
-                           js_autoinit_get_id(pr),
-                           (void *)pr->u.init.opaque);
-                } else {
-                    JS_DumpValueShort(rt, pr->u.value);
-                }
-                is_first = FALSE;
-            }
-        }
-        printf(" }");
-    }
-    
-    if (js_class_has_bytecode(p->class_id)) {
-        JSFunctionBytecode *b = p->u.func.function_bytecode;
-        JSVarRef **var_refs;
-        if (b->closure_var_count) {
-            var_refs = p->u.func.var_refs;
-            printf(" Closure:");
-            for(i = 0; i < b->closure_var_count; i++) {
-                printf(" ");
-                JS_DumpValueShort(rt, var_refs[i]->value);
-            }
-            if (p->u.func.home_object) {
-                printf(" HomeObject: ");
-                JS_DumpValueShort(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object));
-            }
-        }
-    }
-    printf("\n");
-}
-
-static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p)
-{
-    if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
-        JS_DumpObject(rt, (JSObject *)p);
-    } else {
-        printf("%14p %4d ",
-               (void *)p,
-               p->ref_count);
-        switch(p->gc_obj_type) {
-        case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
-            printf("[function bytecode]");
-            break;
-        case JS_GC_OBJ_TYPE_SHAPE:
-            printf("[shape]");
-            break;
-        case JS_GC_OBJ_TYPE_VAR_REF:
-            printf("[var_ref]");
-            break;
-        case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
-            printf("[async_function]");
-            break;
-        case JS_GC_OBJ_TYPE_JS_CONTEXT:
-            printf("[js_context]");
-            break;
-        default:
-            printf("[unknown %d]", p->gc_obj_type);
-            break;
-        }
-        printf("\n");
-    }
-}
-
-static __maybe_unused void JS_DumpValueShort(JSRuntime *rt,
-                                                      JSValueConst val)
-{
-    uint32_t tag = JS_VALUE_GET_NORM_TAG(val);
-    const char *str;
-
-    switch(tag) {
-    case JS_TAG_INT:
-        printf("%d", JS_VALUE_GET_INT(val));
-        break;
-    case JS_TAG_BOOL:
-        if (JS_VALUE_GET_BOOL(val))
-            str = "true";
-        else
-            str = "false";
-        goto print_str;
-    case JS_TAG_NULL:
-        str = "null";
-        goto print_str;
-    case JS_TAG_EXCEPTION:
-        str = "exception";
-        goto print_str;
-    case JS_TAG_UNINITIALIZED:
-        str = "uninitialized";
-        goto print_str;
-    case JS_TAG_UNDEFINED:
-        str = "undefined";
-    print_str:
-        printf("%s", str);
-        break;
-    case JS_TAG_FLOAT64:
-        printf("%.14g", JS_VALUE_GET_FLOAT64(val));
-        break;
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_INT:
-        {
-            JSBigFloat *p = JS_VALUE_GET_PTR(val);
-            char *str;
-            str = bf_ftoa(NULL, &p->num, 10, 0,
-                          BF_RNDZ | BF_FTOA_FORMAT_FRAC);
-            printf("%sn", str);
-            bf_realloc(&rt->bf_ctx, str, 0);
-        }
-        break;
-    case JS_TAG_BIG_FLOAT:
-        {
-            JSBigFloat *p = JS_VALUE_GET_PTR(val);
-            char *str;
-            str = bf_ftoa(NULL, &p->num, 16, BF_PREC_INF,
-                          BF_RNDZ | BF_FTOA_FORMAT_FREE | BF_FTOA_ADD_PREFIX);
-            printf("%sl", str);
-            bf_free(&rt->bf_ctx, str);
-        }
-        break;
-    case JS_TAG_BIG_DECIMAL:
-        {
-            JSBigDecimal *p = JS_VALUE_GET_PTR(val);
-            char *str;
-            str = bfdec_ftoa(NULL, &p->num, BF_PREC_INF,
-                             BF_RNDZ | BF_FTOA_FORMAT_FREE);
-            printf("%sm", str);
-            bf_free(&rt->bf_ctx, str);
-        }
-        break;
-#endif
-    case JS_TAG_STRING:
-        {
-            JSString *p;
-            p = JS_VALUE_GET_STRING(val);
-            JS_DumpString(rt, p);
-        }
-        break;
-    case JS_TAG_FUNCTION_BYTECODE:
-        {
-            JSFunctionBytecode *b = JS_VALUE_GET_PTR(val);
-            char buf[ATOM_GET_STR_BUF_SIZE];
-            printf("[bytecode %s]", JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
-        }
-        break;
-    case JS_TAG_OBJECT:
-        {
-            JSObject *p = JS_VALUE_GET_OBJ(val);
-            JSAtom atom = rt->class_array[p->class_id].class_name;
-            char atom_buf[ATOM_GET_STR_BUF_SIZE];
-            printf("[%s %p]",
-                   JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), atom), (void *)p);
-        }
-        break;
-    case JS_TAG_SYMBOL:
-        {
-            JSAtomStruct *p = JS_VALUE_GET_PTR(val);
-            char atom_buf[ATOM_GET_STR_BUF_SIZE];
-            printf("Symbol(%s)",
-                   JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), js_get_atom_index(rt, p)));
-        }
-        break;
-    case JS_TAG_MODULE:
-        printf("[module]");
-        break;
-    default:
-        printf("[unknown tag %d]", tag);
-        break;
-    }
-}
-
-static __maybe_unused void JS_DumpValue(JSContext *ctx,
-                                                 JSValueConst val)
-{
-    JS_DumpValueShort(ctx->rt, val);
-}
-
-static __maybe_unused void JS_PrintValue(JSContext *ctx,
-                                                  const char *str,
-                                                  JSValueConst val)
-{
-    printf("%s=", str);
-    JS_DumpValueShort(ctx->rt, val);
-    printf("\n");
-}
-
-/* return -1 if exception (proxy case) or TRUE/FALSE */
-int JS_IsArray(JSContext *ctx, JSValueConst val)
-{
-    JSObject *p;
-    if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {
-        p = JS_VALUE_GET_OBJ(val);
-        if (unlikely(p->class_id == JS_CLASS_PROXY))
-            return js_proxy_isArray(ctx, val);
-        else
-            return p->class_id == JS_CLASS_ARRAY;
-    } else {
-        return FALSE;
-    }
-}
-
-static double js_pow(double a, double b)
-{
-    if (unlikely(!isfinite(b)) && fabs(a) == 1) {
-        /* not compatible with IEEE 754 */
-        return JS_FLOAT64_NAN;
-    } else {
-        return pow(a, b);
-    }
-}
-
-#ifdef CONFIG_BIGNUM
-
-JSValue JS_NewBigInt64_1(JSContext *ctx, int64_t v)
-{
-    JSValue val;
-    bf_t *a;
-    val = JS_NewBigInt(ctx);
-    if (JS_IsException(val))
-        return val;
-    a = JS_GetBigInt(val);
-    if (bf_set_si(a, v)) {
-        JS_FreeValue(ctx, val);
-        return JS_ThrowOutOfMemory(ctx);
-    }
-    return val;
-}
-
-JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)
-{
-    if (is_math_mode(ctx) &&
-        v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) {
-        return JS_NewInt64(ctx, v);
-    } else {
-        return JS_NewBigInt64_1(ctx, v);
-    }
-}
-
-JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
-{
-    JSValue val;
-    if (is_math_mode(ctx) && v <= MAX_SAFE_INTEGER) {
-        val = JS_NewInt64(ctx, v);
-    } else {
-        bf_t *a;
-        val = JS_NewBigInt(ctx);
-        if (JS_IsException(val))
-            return val;
-        a = JS_GetBigInt(val);
-        if (bf_set_ui(a, v)) {
-            JS_FreeValue(ctx, val);
-            return JS_ThrowOutOfMemory(ctx);
-        }
-    }
-    return val;
-}
-
-/* if the returned bigfloat is allocated it is equal to
-   'buf'. Otherwise it is a pointer to the bigfloat in 'val'. Return
-   NULL in case of error. */
-static bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val)
-{
-    uint32_t tag;
-    bf_t *r;
-    JSBigFloat *p;
-
-    tag = JS_VALUE_GET_NORM_TAG(val);
-    switch(tag) {
-    case JS_TAG_INT:
-    case JS_TAG_BOOL:
-    case JS_TAG_NULL:
-        r = buf;
-        bf_init(ctx->bf_ctx, r);
-        if (bf_set_si(r, JS_VALUE_GET_INT(val)))
-            goto fail;
-        break;
-    case JS_TAG_FLOAT64:
-        r = buf;
-        bf_init(ctx->bf_ctx, r);
-        if (bf_set_float64(r, JS_VALUE_GET_FLOAT64(val))) {
-        fail:
-            bf_delete(r);
-            return NULL;
-        }
-        break;
-    case JS_TAG_BIG_INT:
-    case JS_TAG_BIG_FLOAT:
-        p = JS_VALUE_GET_PTR(val);
-        r = &p->num;
-        break;
-    case JS_TAG_UNDEFINED:
-    default:
-        r = buf;
-        bf_init(ctx->bf_ctx, r);
-        bf_set_nan(r);
-        break;
-    }
-    return r;
-}
-
-/* return NULL if invalid type */
-static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val)
-{
-    uint32_t tag;
-    JSBigDecimal *p;
-    bfdec_t *r;
-    
-    tag = JS_VALUE_GET_NORM_TAG(val);
-    switch(tag) {
-    case JS_TAG_BIG_DECIMAL:
-        p = JS_VALUE_GET_PTR(val);
-        r = &p->num;
-        break;
-    default:
-        JS_ThrowTypeError(ctx, "bigdecimal expected");
-        r = NULL;
-        break;
-    }
-    return r;
-}
-
-/* return NaN if bad bigint literal */
-static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val)
-{
-    const char *str, *p;
-    size_t len;
-    int flags;
-    
-    str = JS_ToCStringLen(ctx, &len, val);
-    JS_FreeValue(ctx, val);
-    if (!str)
-        return JS_EXCEPTION;
-    p = str;
-    p += skip_spaces(p);
-    if ((p - str) == len) {
-        val = JS_NewBigInt64(ctx, 0);
-    } else {
-        flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT;
-        if (is_math_mode(ctx))
-            flags |= ATOD_MODE_BIGINT;
-        val = js_atof(ctx, p, &p, 0, flags);
-        p += skip_spaces(p);
-        if (!JS_IsException(val)) {
-            if ((p - str) != len) {
-                JS_FreeValue(ctx, val);
-                val = JS_NAN;
-            }
-        }
-    }
-    JS_FreeCString(ctx, str);
-    return val;
-}
-
-static JSValue JS_StringToBigIntErr(JSContext *ctx, JSValue val)
-{
-    val = JS_StringToBigInt(ctx, val);
-    if (JS_VALUE_IS_NAN(val))
-        return JS_ThrowSyntaxError(ctx, "invalid bigint literal");
-    return val;
-}
-
-/* if the returned bigfloat is allocated it is equal to
-   'buf'. Otherwise it is a pointer to the bigfloat in 'val'. */
-static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val)
-{
-    uint32_t tag;
-    bf_t *r;
-    JSBigFloat *p;
-
- redo:
-    tag = JS_VALUE_GET_NORM_TAG(val);
-    switch(tag) {
-    case JS_TAG_INT:
-    case JS_TAG_NULL:
-    case JS_TAG_UNDEFINED:
-        if (!is_math_mode(ctx))
-            goto fail;
-        /* fall tru */
-    case JS_TAG_BOOL:
-        r = buf;
-        bf_init(ctx->bf_ctx, r);
-        bf_set_si(r, JS_VALUE_GET_INT(val));
-        break;
-    case JS_TAG_FLOAT64:
-        {
-            double d = JS_VALUE_GET_FLOAT64(val);
-            if (!is_math_mode(ctx))
-                goto fail;
-            if (!isfinite(d))
-                goto fail;
-            r = buf;
-            bf_init(ctx->bf_ctx, r);
-            d = trunc(d);
-            bf_set_float64(r, d);
-        }
-        break;
-    case JS_TAG_BIG_INT:
-        p = JS_VALUE_GET_PTR(val);
-        r = &p->num;
-        break;
-    case JS_TAG_BIG_FLOAT:
-        if (!is_math_mode(ctx))
-            goto fail;
-        p = JS_VALUE_GET_PTR(val);
-        if (!bf_is_finite(&p->num))
-            goto fail;
-        r = buf;
-        bf_init(ctx->bf_ctx, r);
-        bf_set(r, &p->num);
-        bf_rint(r, BF_RNDZ);
-        JS_FreeValue(ctx, val);
-        break;
-    case JS_TAG_STRING:
-        val = JS_StringToBigIntErr(ctx, val);
-        if (JS_IsException(val))
-            return NULL;
-        goto redo;
-    case JS_TAG_OBJECT:
-        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
-        if (JS_IsException(val))
-            return NULL;
-        goto redo;
-    default:
-    fail:
-        JS_FreeValue(ctx, val);
-        JS_ThrowTypeError(ctx, "cannot convert to bigint");
-        return NULL;
-    }
-    return r;
-}
-
-static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val)
-{
-    return JS_ToBigIntFree(ctx, buf, JS_DupValue(ctx, val));
-}
-
-static __maybe_unused JSValue JS_ToBigIntValueFree(JSContext *ctx, JSValue val)
-{
-    if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT) {
-        return val;
-    } else {
-        bf_t a_s, *a, *r;
-        int ret;
-        JSValue res; 
-
-        res = JS_NewBigInt(ctx);
-        if (JS_IsException(res))
-            return JS_EXCEPTION;
-        a = JS_ToBigIntFree(ctx, &a_s, val);
-        if (!a) {
-            JS_FreeValue(ctx, res);
-            return JS_EXCEPTION;
-        }
-        r = JS_GetBigInt(res);
-        ret = bf_set(r, a);
-        JS_FreeBigInt(ctx, a, &a_s);
-        if (ret) {
-            JS_FreeValue(ctx, res);
-            return JS_ThrowOutOfMemory(ctx);
-        }
-        return JS_CompactBigInt(ctx, res);
-    }
-}
-
-/* free the bf_t allocated by JS_ToBigInt */
-static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf)
-{
-    if (a == buf) {
-        bf_delete(a);
-    } else {
-        JSBigFloat *p = (JSBigFloat *)((uint8_t *)a -
-                                       offsetof(JSBigFloat, num));
-        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_BIG_FLOAT, p));
-    }
-}
-
-/* XXX: merge with JS_ToInt64Free with a specific flag */
-static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
-{
-    bf_t a_s, *a;
-
-    a = JS_ToBigIntFree(ctx, &a_s, val);
-    if (!a) {
-        *pres = 0;
-        return -1;
-    }
-    bf_get_int64(pres, a, BF_GET_INT_MOD);
-    JS_FreeBigInt(ctx, a, &a_s);
-    return 0;
-}
-
-int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
-{
-    return JS_ToBigInt64Free(ctx, pres, JS_DupValue(ctx, val));
-}
-
-static JSBigFloat *js_new_bf(JSContext *ctx)
-{
-    JSBigFloat *p;
-    p = js_malloc(ctx, sizeof(*p));
-    if (!p)
-        return NULL;
-    p->header.ref_count = 1;
-    bf_init(ctx->bf_ctx, &p->num);
-    return p;
-}
-
-static JSValue JS_NewBigFloat(JSContext *ctx)
-{
-    JSBigFloat *p;
-    p = js_malloc(ctx, sizeof(*p));
-    if (!p)
-        return JS_EXCEPTION;
-    p->header.ref_count = 1;
-    bf_init(ctx->bf_ctx, &p->num);
-    return JS_MKPTR(JS_TAG_BIG_FLOAT, p);
-}
-
-static JSValue JS_NewBigDecimal(JSContext *ctx)
-{
-    JSBigDecimal *p;
-    p = js_malloc(ctx, sizeof(*p));
-    if (!p)
-        return JS_EXCEPTION;
-    p->header.ref_count = 1;
-    bfdec_init(ctx->bf_ctx, &p->num);
-    return JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
-}
-
-static JSValue JS_NewBigInt(JSContext *ctx)
-{
-    JSBigFloat *p;
-    p = js_malloc(ctx, sizeof(*p));
-    if (!p)
-        return JS_EXCEPTION;
-    p->header.ref_count = 1;
-    bf_init(ctx->bf_ctx, &p->num);
-    return JS_MKPTR(JS_TAG_BIG_INT, p);
-}
-
-static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
-                                 BOOL convert_to_safe_integer)
-{
-    int64_t v;
-    bf_t *a;
-    
-    if (JS_VALUE_GET_TAG(val) != JS_TAG_BIG_INT)
-        return val; /* fail safe */
-    a = JS_GetBigInt(val);
-    if (convert_to_safe_integer && bf_get_int64(&v, a, 0) == 0 &&
-        v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) {
-        JS_FreeValue(ctx, val);
-        return JS_NewInt64(ctx, v);
-    } else if (a->expn == BF_EXP_ZERO && a->sign) {
-        JSBigFloat *p = JS_VALUE_GET_PTR(val);
-        assert(p->header.ref_count == 1);
-        a->sign = 0;
-    }
-    return val;
-}
-
-/* Convert the big int to a safe integer if in math mode. normalize
-   the zero representation. Could also be used to convert the bigint
-   to a short bigint value. The reference count of the value must be
-   1. Cannot fail */
-static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val)
-{
-    return JS_CompactBigInt1(ctx, val, is_math_mode(ctx));
-}
-
-/* must be kept in sync with JSOverloadableOperatorEnum */
-/* XXX: use atoms ? */
-static const char js_overloadable_operator_names[JS_OVOP_COUNT][4] = {
-    "+",
-    "-",
-    "*",
-    "/",
-    "%",
-    "**",
-    "|",
-    "&",
-    "^",
-    "<<",
-    ">>",
-    ">>>",
-    "==",
-    "<",
-    "pos",
-    "neg",
-    "++",
-    "--",
-    "~",
-};
-
-static int get_ovop_from_opcode(OPCodeEnum op)
-{
-    switch(op) {
-    case OP_add:
-        return JS_OVOP_ADD;
-    case OP_sub:
-        return JS_OVOP_SUB;
-    case OP_mul:
-        return JS_OVOP_MUL;
-    case OP_div:
-        return JS_OVOP_DIV;
-    case OP_mod:
-    case OP_math_mod:
-        return JS_OVOP_MOD;
-    case OP_pow:
-        return JS_OVOP_POW;
-    case OP_or:
-        return JS_OVOP_OR;
-    case OP_and:
-        return JS_OVOP_AND;
-    case OP_xor:
-        return JS_OVOP_XOR;
-    case OP_shl:
-        return JS_OVOP_SHL;
-    case OP_sar:
-        return JS_OVOP_SAR;
-    case OP_shr:
-        return JS_OVOP_SHR;
-    case OP_eq:
-    case OP_neq:
-        return JS_OVOP_EQ;
-    case OP_lt:
-    case OP_lte:
-    case OP_gt:
-    case OP_gte:
-        return JS_OVOP_LESS;
-    case OP_plus:
-        return JS_OVOP_POS;
-    case OP_neg:
-        return JS_OVOP_NEG;
-    case OP_inc:
-        return JS_OVOP_INC;
-    case OP_dec:
-        return JS_OVOP_DEC;
-    default:
-        abort();
-    }
-}
-
-/* return NULL if not present */
-static JSObject *find_binary_op(JSBinaryOperatorDef *def,
-                                uint32_t operator_index,
-                                JSOverloadableOperatorEnum op)
-{
-    JSBinaryOperatorDefEntry *ent;
-    int i;
-    for(i = 0; i < def->count; i++) {
-        ent = &def->tab[i];
-        if (ent->operator_index == operator_index)
-            return ent->ops[op];
-    }
-    return NULL;
-}
-
-/* return -1 if exception, 0 if no operator overloading, 1 if
-   overloaded operator called */
-static __exception int js_call_binary_op_fallback(JSContext *ctx,
-                                                  JSValue *pret,
-                                                  JSValueConst op1,
-                                                  JSValueConst op2,
-                                                  OPCodeEnum op,
-                                                  BOOL is_numeric,
-                                                  int hint)
-{
-    JSValue opset1_obj, opset2_obj, method, ret, new_op1, new_op2;
-    JSOperatorSetData *opset1, *opset2;
-    JSOverloadableOperatorEnum ovop;
-    JSObject *p;
-    JSValueConst args[2];
-    
-    if (!ctx->allow_operator_overloading)
-        return 0;
-    
-    opset2_obj = JS_UNDEFINED;
-    opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet);
-    if (JS_IsException(opset1_obj))
-        goto exception;
-    if (JS_IsUndefined(opset1_obj))
-        return 0;
-    opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
-    if (!opset1)
-        goto exception;
-
-    opset2_obj = JS_GetProperty(ctx, op2, JS_ATOM_Symbol_operatorSet);
-    if (JS_IsException(opset2_obj))
-        goto exception;
-    if (JS_IsUndefined(opset2_obj)) {
-        JS_FreeValue(ctx, opset1_obj);
-        return 0;
-    }
-    opset2 = JS_GetOpaque2(ctx, opset2_obj, JS_CLASS_OPERATOR_SET);
-    if (!opset2)
-        goto exception;
-
-    if (opset1->is_primitive && opset2->is_primitive) {
-        JS_FreeValue(ctx, opset1_obj);
-        JS_FreeValue(ctx, opset2_obj);
-        return 0;
-    }
-
-    ovop = get_ovop_from_opcode(op);
-    
-    if (opset1->operator_counter == opset2->operator_counter) {
-        p = opset1->self_ops[ovop];
-    } else if (opset1->operator_counter > opset2->operator_counter) {
-        p = find_binary_op(&opset1->left, opset2->operator_counter, ovop);
-    } else {
-        p = find_binary_op(&opset2->right, opset1->operator_counter, ovop);
-    }
-    if (!p) {
-        JS_ThrowTypeError(ctx, "operator %s: no function defined",
-                          js_overloadable_operator_names[ovop]);
-        goto exception;
-    }
-
-    if (opset1->is_primitive) {
-        if (is_numeric) {
-            new_op1 = JS_ToNumeric(ctx, op1);
-        } else {
-            new_op1 = JS_ToPrimitive(ctx, op1, hint);
-        }
-        if (JS_IsException(new_op1))
-            goto exception;
-    } else {
-        new_op1 = JS_DupValue(ctx, op1);
-    }
-    
-    if (opset2->is_primitive) {
-        if (is_numeric) {
-            new_op2 = JS_ToNumeric(ctx, op2);
-        } else {
-            new_op2 = JS_ToPrimitive(ctx, op2, hint);
-        }
-        if (JS_IsException(new_op2)) {
-            JS_FreeValue(ctx, new_op1);
-            goto exception;
-        }
-    } else {
-        new_op2 = JS_DupValue(ctx, op2);
-    }
-
-    /* XXX: could apply JS_ToPrimitive() if primitive type so that the
-       operator function does not get a value object */
-    
-    method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
-    if (ovop == JS_OVOP_LESS && (op == OP_lte || op == OP_gt)) {
-        args[0] = new_op2;
-        args[1] = new_op1;
-    } else {
-        args[0] = new_op1;
-        args[1] = new_op2;
-    }
-    ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
-    JS_FreeValue(ctx, new_op1);
-    JS_FreeValue(ctx, new_op2);
-    if (JS_IsException(ret))
-        goto exception;
-    if (ovop == JS_OVOP_EQ) {
-        BOOL res = JS_ToBoolFree(ctx, ret);
-        if (op == OP_neq)
-            res ^= 1;
-        ret = JS_NewBool(ctx, res);
-    } else if (ovop == JS_OVOP_LESS) {
-        if (JS_IsUndefined(ret)) {
-            ret = JS_FALSE;
-        } else {
-            BOOL res = JS_ToBoolFree(ctx, ret);
-            if (op == OP_lte || op == OP_gte)
-                res ^= 1;
-            ret = JS_NewBool(ctx, res);
-        }
-    }
-    JS_FreeValue(ctx, opset1_obj);
-    JS_FreeValue(ctx, opset2_obj);
-    *pret = ret;
-    return 1;
- exception:
-    JS_FreeValue(ctx, opset1_obj);
-    JS_FreeValue(ctx, opset2_obj);
-    *pret = JS_UNDEFINED;
-    return -1;
-}
-
-/* try to call the operation on the operatorSet field of 'obj'. Only
-   used for "/" and "**" on the BigInt prototype in math mode */
-static __exception int js_call_binary_op_simple(JSContext *ctx,
-                                                JSValue *pret,
-                                                JSValueConst obj,
-                                                JSValueConst op1,
-                                                JSValueConst op2,
-                                                OPCodeEnum op)
-{
-    JSValue opset1_obj, method, ret, new_op1, new_op2;
-    JSOperatorSetData *opset1;
-    JSOverloadableOperatorEnum ovop;
-    JSObject *p;
-    JSValueConst args[2];
-
-    opset1_obj = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet);
-    if (JS_IsException(opset1_obj))
-        goto exception;
-    if (JS_IsUndefined(opset1_obj))
-        return 0;
-    opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
-    if (!opset1)
-        goto exception;
-    ovop = get_ovop_from_opcode(op);
-
-    p = opset1->self_ops[ovop];
-    if (!p) {
-        JS_FreeValue(ctx, opset1_obj);
-        return 0;
-    }
-
-    new_op1 = JS_ToNumeric(ctx, op1);
-    if (JS_IsException(new_op1))
-        goto exception;
-    new_op2 = JS_ToNumeric(ctx, op2);
-    if (JS_IsException(new_op2)) {
-        JS_FreeValue(ctx, new_op1);
-        goto exception;
-    }
-
-    method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
-    args[0] = new_op1;
-    args[1] = new_op2;
-    ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
-    JS_FreeValue(ctx, new_op1);
-    JS_FreeValue(ctx, new_op2);
-    if (JS_IsException(ret))
-        goto exception;
-    JS_FreeValue(ctx, opset1_obj);
-    *pret = ret;
-    return 1;
- exception:
-    JS_FreeValue(ctx, opset1_obj);
-    *pret = JS_UNDEFINED;
-    return -1;
-}
-
-/* return -1 if exception, 0 if no operator overloading, 1 if
-   overloaded operator called */
-static __exception int js_call_unary_op_fallback(JSContext *ctx,
-                                                 JSValue *pret,
-                                                 JSValueConst op1,
-                                                 OPCodeEnum op)
-{
-    JSValue opset1_obj, method, ret;
-    JSOperatorSetData *opset1;
-    JSOverloadableOperatorEnum ovop;
-    JSObject *p;
-
-    if (!ctx->allow_operator_overloading)
-        return 0;
-    
-    opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet);
-    if (JS_IsException(opset1_obj))
-        goto exception;
-    if (JS_IsUndefined(opset1_obj))
-        return 0;
-    opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
-    if (!opset1)
-        goto exception;
-    if (opset1->is_primitive) {
-        JS_FreeValue(ctx, opset1_obj);
-        return 0;
-    }
-
-    ovop = get_ovop_from_opcode(op);
-
-    p = opset1->self_ops[ovop];
-    if (!p) {
-        JS_ThrowTypeError(ctx, "no overloaded operator %s",
-                          js_overloadable_operator_names[ovop]);
-        goto exception;
-    }
-    method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
-    ret = JS_CallFree(ctx, method, JS_UNDEFINED, 1, &op1);
-    if (JS_IsException(ret))
-        goto exception;
-    JS_FreeValue(ctx, opset1_obj);
-    *pret = ret;
-    return 1;
- exception:
-    JS_FreeValue(ctx, opset1_obj);
-    *pret = JS_UNDEFINED;
-    return -1;
-}
-
-static JSValue throw_bf_exception(JSContext *ctx, int status)
-{
-    const char *str;
-    if (status & BF_ST_MEM_ERROR)
-        return JS_ThrowOutOfMemory(ctx);
-    if (status & BF_ST_DIVIDE_ZERO) {
-        str = "division by zero";
-    } else if (status & BF_ST_INVALID_OP) {
-        str = "invalid operation";
-    } else {
-        str = "integer overflow";
-    }
-    return JS_ThrowRangeError(ctx, "%s", str);
-}
-
-static int js_unary_arith_bigint(JSContext *ctx,
-                                 JSValue *pres, OPCodeEnum op, JSValue op1)
-{
-    bf_t a_s, *r, *a;
-    int ret, v;
-    JSValue res;
-    
-    if (op == OP_plus && !is_math_mode(ctx)) {
-        JS_ThrowTypeError(ctx, "bigint argument with unary +");
-        JS_FreeValue(ctx, op1);
-        return -1;
-    }
-    res = JS_NewBigInt(ctx);
-    if (JS_IsException(res)) {
-        JS_FreeValue(ctx, op1);
-        return -1;
-    }
-    r = JS_GetBigInt(res);
-    a = JS_ToBigInt(ctx, &a_s, op1);
-    ret = 0;
-    switch(op) {
-    case OP_inc:
-    case OP_dec:
-        v = 2 * (op - OP_dec) - 1;
-        ret = bf_add_si(r, a, v, BF_PREC_INF, BF_RNDZ);
-        break;
-    case OP_plus:
-        ret = bf_set(r, a);
-        break;
-    case OP_neg:
-        ret = bf_set(r, a);
-        bf_neg(r);
-        break;
-    case OP_not:
-        ret = bf_add_si(r, a, 1, BF_PREC_INF, BF_RNDZ);
-        bf_neg(r);
-        break;
-    default:
-        abort();
-    }
-    JS_FreeBigInt(ctx, a, &a_s);
-    JS_FreeValue(ctx, op1);
-    if (unlikely(ret)) {
-        JS_FreeValue(ctx, res);
-        throw_bf_exception(ctx, ret);
-        return -1;
-    }
-    res = JS_CompactBigInt(ctx, res);
-    *pres = res;
-    return 0;
-}
-
-static int js_unary_arith_bigfloat(JSContext *ctx,
-                                   JSValue *pres, OPCodeEnum op, JSValue op1)
-{
-    bf_t a_s, *r, *a;
-    int ret, v;
-    JSValue res;
-    
-    if (op == OP_plus && !is_math_mode(ctx)) {
-        JS_ThrowTypeError(ctx, "bigfloat argument with unary +");
-        JS_FreeValue(ctx, op1);
-        return -1;
-    }
-
-    res = JS_NewBigFloat(ctx);
-    if (JS_IsException(res)) {
-        JS_FreeValue(ctx, op1);
-        return -1;
-    }
-    r = JS_GetBigFloat(res);
-    a = JS_ToBigFloat(ctx, &a_s, op1);
-    ret = 0;
-    switch(op) {
-    case OP_inc:
-    case OP_dec:
-        v = 2 * (op - OP_dec) - 1;
-        ret = bf_add_si(r, a, v, ctx->fp_env.prec, ctx->fp_env.flags);
-        break;
-    case OP_plus:
-        ret = bf_set(r, a);
-        break;
-    case OP_neg:
-        ret = bf_set(r, a);
-        bf_neg(r);
-        break;
-    default:
-        abort();
-    }
-    if (a == &a_s)
-        bf_delete(a);
-    JS_FreeValue(ctx, op1);
-    if (unlikely(ret & BF_ST_MEM_ERROR)) {
-        JS_FreeValue(ctx, res);
-        throw_bf_exception(ctx, ret);
-        return -1;
-    }
-    *pres = res;
-    return 0;
-}
-
-static int js_unary_arith_bigdecimal(JSContext *ctx,
-                                     JSValue *pres, OPCodeEnum op, JSValue op1)
-{
-    bfdec_t *r, *a;
-    int ret, v;
-    JSValue res;
-    
-    if (op == OP_plus && !is_math_mode(ctx)) {
-        JS_ThrowTypeError(ctx, "bigdecimal argument with unary +");
-        JS_FreeValue(ctx, op1);
-        return -1;
-    }
-
-    res = JS_NewBigDecimal(ctx);
-    if (JS_IsException(res)) {
-        JS_FreeValue(ctx, op1);
-        return -1;
-    }
-    r = JS_GetBigDecimal(res);
-    a = JS_ToBigDecimal(ctx, op1);
-    ret = 0;
-    switch(op) {
-    case OP_inc:
-    case OP_dec:
-        v = 2 * (op - OP_dec) - 1;
-        ret = bfdec_add_si(r, a, v, BF_PREC_INF, BF_RNDZ);
-        break;
-    case OP_plus:
-        ret = bfdec_set(r, a);
-        break;
-    case OP_neg:
-        ret = bfdec_set(r, a);
-        bfdec_neg(r);
-        break;
-    default:
-        abort();
-    }
-    JS_FreeValue(ctx, op1);
-    if (unlikely(ret)) {
-        JS_FreeValue(ctx, res);
-        throw_bf_exception(ctx, ret);
-        return -1;
-    }
-    *pres = res;
-    return 0;
-}
-
-static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
-                                                     JSValue *sp,
-                                                     OPCodeEnum op)
-{
-    JSValue op1, val;
-    int v, ret;
-    uint32_t tag;
-
-    op1 = sp[-1];
-    /* fast path for float64 */
-    if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)))
-        goto handle_float64;
-    if (JS_IsObject(op1)) {
-        ret = js_call_unary_op_fallback(ctx, &val, op1, op);
-        if (ret < 0)
-            return -1;
-        if (ret) {
-            JS_FreeValue(ctx, op1);
-            sp[-1] = val;
-            return 0;
-        }
-    }
-
-    op1 = JS_ToNumericFree(ctx, op1);
-    if (JS_IsException(op1))
-        goto exception;
-    tag = JS_VALUE_GET_TAG(op1);
-    switch(tag) {
-    case JS_TAG_INT:
-        {
-            int64_t v64;
-            v64 = JS_VALUE_GET_INT(op1);
-            switch(op) {
-            case OP_inc:
-            case OP_dec:
-                v = 2 * (op - OP_dec) - 1;
-                v64 += v;
-                break;
-            case OP_plus:
-                break;
-            case OP_neg:
-                if (v64 == 0) {
-                    sp[-1] = __JS_NewFloat64(ctx, -0.0);
-                    return 0;
-                } else {
-                    v64 = -v64;
-                }
-                break;
-            default:
-                abort();
-            }
-            sp[-1] = JS_NewInt64(ctx, v64);
-        }
-        break;
-    case JS_TAG_BIG_INT:
-    handle_bigint:
-        if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, op, op1))
-            goto exception;
-        break;
-    case JS_TAG_BIG_FLOAT:
-        if (ctx->rt->bigfloat_ops.unary_arith(ctx, sp - 1, op, op1))
-            goto exception;
-        break;
-    case JS_TAG_BIG_DECIMAL:
-        if (ctx->rt->bigdecimal_ops.unary_arith(ctx, sp - 1, op, op1))
-            goto exception;
-        break;
-    default:
-    handle_float64:
-        {
-            double d;
-            if (is_math_mode(ctx))
-                goto handle_bigint;
-            d = JS_VALUE_GET_FLOAT64(op1);
-            switch(op) {
-            case OP_inc:
-            case OP_dec:
-                v = 2 * (op - OP_dec) - 1;
-                d += v;
-                break;
-            case OP_plus:
-                break;
-            case OP_neg:
-                d = -d;
-                break;
-            default:
-                abort();
-            }
-            sp[-1] = __JS_NewFloat64(ctx, d);
-        }
-        break;
-    }
-    return 0;
- exception:
-    sp[-1] = JS_UNDEFINED;
-    return -1;
-}
-
-static __exception int js_post_inc_slow(JSContext *ctx,
-                                        JSValue *sp, OPCodeEnum op)
-{
-    JSValue op1;
-
-    /* XXX: allow custom operators */
-    op1 = sp[-1];
-    op1 = JS_ToNumericFree(ctx, op1);
-    if (JS_IsException(op1)) {
-        sp[-1] = JS_UNDEFINED;
-        return -1;
-    }
-    sp[-1] = op1;
-    sp[0] = JS_DupValue(ctx, op1);
-    return js_unary_arith_slow(ctx, sp + 1, op - OP_post_dec + OP_dec);
-}
-
-static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
-{
-    JSValue op1, val;
-    int ret;
-    
-    op1 = sp[-1];
-    if (JS_IsObject(op1)) {
-        ret = js_call_unary_op_fallback(ctx, &val, op1, OP_not);
-        if (ret < 0)
-            return -1;
-        if (ret) {
-            JS_FreeValue(ctx, op1);
-            sp[-1] = val;
-            return 0;
-        }
-    }
-
-    op1 = JS_ToNumericFree(ctx, op1);
-    if (JS_IsException(op1))
-        goto exception;
-    if (is_math_mode(ctx) || JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) {
-        if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, OP_not, op1))
-            goto exception;
-    } else {
-        int32_t v1;
-        if (unlikely(JS_ToInt32Free(ctx, &v1, op1)))
-            goto exception;
-        sp[-1] = JS_NewInt32(ctx, ~v1);
-    }
-    return 0;
- exception:
-    sp[-1] = JS_UNDEFINED;
-    return -1;
-}
-
-static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op,
-                                    JSValue *pres, JSValue op1, JSValue op2)
-{
-    bf_t a_s, b_s, *r, *a, *b;
-    int ret;
-    JSValue res;
-    
-    res = JS_NewBigFloat(ctx);
-    if (JS_IsException(res)) {
-        JS_FreeValue(ctx, op1);
-        JS_FreeValue(ctx, op2);
-        return -1;
-    }
-    r = JS_GetBigFloat(res);
-    a = JS_ToBigFloat(ctx, &a_s, op1);
-    b = JS_ToBigFloat(ctx, &b_s, op2);
-    bf_init(ctx->bf_ctx, r);
-    switch(op) {
-    case OP_add:
-        ret = bf_add(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
-        break;
-    case OP_sub:
-        ret = bf_sub(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
-        break;
-    case OP_mul:
-        ret = bf_mul(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
-        break;
-    case OP_div:
-        ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
-        break;
-    case OP_math_mod:
-        /* Euclidian remainder */
-        ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
-                     BF_DIVREM_EUCLIDIAN);
-        break;
-    case OP_mod:
-        ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
-                     BF_RNDZ);
-        break;
-    case OP_pow:
-        ret = bf_pow(r, a, b, ctx->fp_env.prec,
-                     ctx->fp_env.flags | BF_POW_JS_QUIRKS);
-        break;
-    default:
-        abort();
-    }
-    if (a == &a_s)
-        bf_delete(a);
-    if (b == &b_s)
-        bf_delete(b);
-    JS_FreeValue(ctx, op1);
-    JS_FreeValue(ctx, op2);
-    if (unlikely(ret & BF_ST_MEM_ERROR)) {
-        JS_FreeValue(ctx, res);
-        throw_bf_exception(ctx, ret);
-        return -1;
-    }
-    *pres = res;
-    return 0;
-}
-
-static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,
-                                  JSValue *pres, JSValue op1, JSValue op2)
-{
-    bf_t a_s, b_s, *r, *a, *b;
-    int ret;
-    JSValue res;
-    
-    res = JS_NewBigInt(ctx);
-    if (JS_IsException(res))
-        goto fail;
-    a = JS_ToBigInt(ctx, &a_s, op1);
-    if (!a)
-        goto fail;
-    b = JS_ToBigInt(ctx, &b_s, op2);
-    if (!b) {
-        JS_FreeBigInt(ctx, a, &a_s);
-        goto fail;
-    }
-    r = JS_GetBigInt(res);
-    ret = 0;
-    switch(op) {
-    case OP_add:
-        ret = bf_add(r, a, b, BF_PREC_INF, BF_RNDZ);
-        break;
-    case OP_sub:
-        ret = bf_sub(r, a, b, BF_PREC_INF, BF_RNDZ);
-        break;
-    case OP_mul:
-        ret = bf_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
-        break;
-    case OP_div:
-        if (!is_math_mode(ctx)) {
-            bf_t rem_s, *rem = &rem_s;
-            bf_init(ctx->bf_ctx, rem);
-            ret = bf_divrem(r, rem, a, b, BF_PREC_INF, BF_RNDZ,
-                            BF_RNDZ);
-            bf_delete(rem);
-        } else {
-            goto math_mode_div_pow;
-        }
-        break;
-    case OP_math_mod:
-        /* Euclidian remainder */
-        ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
-                     BF_DIVREM_EUCLIDIAN) & BF_ST_INVALID_OP;
-        break;
-    case OP_mod:
-        ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
-                     BF_RNDZ) & BF_ST_INVALID_OP;
-        break;
-    case OP_pow:
-        if (b->sign) {
-            if (!is_math_mode(ctx)) {
-                ret = BF_ST_INVALID_OP;
-            } else {
-            math_mode_div_pow:
-                JS_FreeValue(ctx, res);
-                ret = js_call_binary_op_simple(ctx, &res, ctx->class_proto[JS_CLASS_BIG_INT], op1, op2, op);
-                if (ret != 0) {
-                    JS_FreeBigInt(ctx, a, &a_s);
-                    JS_FreeBigInt(ctx, b, &b_s);
-                    JS_FreeValue(ctx, op1);
-                    JS_FreeValue(ctx, op2);
-                    if (ret < 0) {
-                        return -1;
-                    } else {
-                        *pres = res;
-                        return 0;
-                    }
-                }
-                /* if no BigInt power operator defined, return a
-                   bigfloat */
-                res = JS_NewBigFloat(ctx);
-                if (JS_IsException(res)) {
-                    JS_FreeBigInt(ctx, a, &a_s);
-                    JS_FreeBigInt(ctx, b, &b_s);
-                    goto fail;
-                }
-                r = JS_GetBigFloat(res);
-                if (op == OP_div) {
-                    ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags) & BF_ST_MEM_ERROR;
-                } else {
-                    ret = bf_pow(r, a, b, ctx->fp_env.prec,
-                                 ctx->fp_env.flags | BF_POW_JS_QUIRKS) & BF_ST_MEM_ERROR;
-                }
-                JS_FreeBigInt(ctx, a, &a_s);
-                JS_FreeBigInt(ctx, b, &b_s);
-                JS_FreeValue(ctx, op1);
-                JS_FreeValue(ctx, op2);
-                if (unlikely(ret)) {
-                    JS_FreeValue(ctx, res);
-                    throw_bf_exception(ctx, ret);
-                    return -1;
-                }
-                *pres = res;
-                return 0;
-            }
-        } else {
-            ret = bf_pow(r, a, b, BF_PREC_INF, BF_RNDZ | BF_POW_JS_QUIRKS);
-        }
-        break;
-
-        /* logical operations */
-    case OP_shl:
-    case OP_sar:
-        {
-            slimb_t v2;
-#if LIMB_BITS == 32
-            bf_get_int32(&v2, b, 0);
-            if (v2 == INT32_MIN)
-                v2 = INT32_MIN + 1;
-#else
-            bf_get_int64(&v2, b, 0);
-            if (v2 == INT64_MIN)
-                v2 = INT64_MIN + 1;
-#endif
-            if (op == OP_sar)
-                v2 = -v2;
-            ret = bf_set(r, a);
-            ret |= bf_mul_2exp(r, v2, BF_PREC_INF, BF_RNDZ);
-            if (v2 < 0) {
-                ret |= bf_rint(r, BF_RNDD) & (BF_ST_OVERFLOW | BF_ST_MEM_ERROR);
-            }
-        }
-        break;
-    case OP_and:
-        ret = bf_logic_and(r, a, b);
-        break;
-    case OP_or:
-        ret = bf_logic_or(r, a, b);
-        break;
-    case OP_xor:
-        ret = bf_logic_xor(r, a, b);
-        break;
-    default:
-        abort();
-    }
-    JS_FreeBigInt(ctx, a, &a_s);
-    JS_FreeBigInt(ctx, b, &b_s);
-    JS_FreeValue(ctx, op1);
-    JS_FreeValue(ctx, op2);
-    if (unlikely(ret)) {
-        JS_FreeValue(ctx, res);
-        throw_bf_exception(ctx, ret);
-        return -1;
-    }
-    *pres = JS_CompactBigInt(ctx, res);
-    return 0;
- fail:
-    JS_FreeValue(ctx, res);
-    JS_FreeValue(ctx, op1);
-    JS_FreeValue(ctx, op2);
-    return -1;
-}
-
-/* b must be a positive integer */
-static int js_bfdec_pow(bfdec_t *r, const bfdec_t *a, const bfdec_t *b)
-{
-    bfdec_t b1;
-    int32_t b2;
-    int ret;
-
-    bfdec_init(b->ctx, &b1);
-    ret = bfdec_set(&b1, b);
-    if (ret) {
-        bfdec_delete(&b1);
-        return ret;
-    }
-    ret = bfdec_rint(&b1, BF_RNDZ);
-    if (ret) {
-        bfdec_delete(&b1);
-        return BF_ST_INVALID_OP; /* must be an integer */
-    }
-    ret = bfdec_get_int32(&b2, &b1);
-    bfdec_delete(&b1);
-    if (ret)
-        return ret; /* overflow */
-    if (b2 < 0)
-        return BF_ST_INVALID_OP; /* must be positive */
-    return bfdec_pow_ui(r, a, b2);
-}
-
-static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op,
-                                      JSValue *pres, JSValue op1, JSValue op2)
-{
-    bfdec_t *r, *a, *b;
-    int ret;
-    JSValue res;
-
-    res = JS_NewBigDecimal(ctx);
-    if (JS_IsException(res))
-        goto fail;
-    r = JS_GetBigDecimal(res);
-    
-    a = JS_ToBigDecimal(ctx, op1);
-    if (!a)
-        goto fail;
-    b = JS_ToBigDecimal(ctx, op2);
-    if (!b)
-        goto fail;
-    switch(op) {
-    case OP_add:
-        ret = bfdec_add(r, a, b, BF_PREC_INF, BF_RNDZ);
-        break;
-    case OP_sub:
-        ret = bfdec_sub(r, a, b, BF_PREC_INF, BF_RNDZ);
-        break;
-    case OP_mul:
-        ret = bfdec_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
-        break;
-    case OP_div:
-        ret = bfdec_div(r, a, b, BF_PREC_INF, BF_RNDZ);
-        break;
-    case OP_math_mod:
-        /* Euclidian remainder */
-        ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_DIVREM_EUCLIDIAN);
-        break;
-    case OP_mod:
-        ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_RNDZ);
-        break;
-    case OP_pow:
-        ret = js_bfdec_pow(r, a, b);
-        break;
-    default:
-        abort();
-    }
-    JS_FreeValue(ctx, op1);
-    JS_FreeValue(ctx, op2);
-    if (unlikely(ret)) {
-        JS_FreeValue(ctx, res);
-        throw_bf_exception(ctx, ret);
-        return -1;
-    }
-    *pres = res;
-    return 0;
- fail:
-    JS_FreeValue(ctx, res);
-    JS_FreeValue(ctx, op1);
-    JS_FreeValue(ctx, op2);
-    return -1;
-}
-
-static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
-                                                      OPCodeEnum op)
-{
-    JSValue op1, op2, res;
-    uint32_t tag1, tag2;
-    int ret;
-    double d1, d2;
-
-    op1 = sp[-2];
-    op2 = sp[-1];
-    tag1 = JS_VALUE_GET_NORM_TAG(op1);
-    tag2 = JS_VALUE_GET_NORM_TAG(op2);
-    /* fast path for float operations */
-    if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) {
-        d1 = JS_VALUE_GET_FLOAT64(op1);
-        d2 = JS_VALUE_GET_FLOAT64(op2);
-        goto handle_float64;
-    }
-
-    /* try to call an overloaded operator */
-    if ((tag1 == JS_TAG_OBJECT &&
-         (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
-        (tag2 == JS_TAG_OBJECT &&
-         (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
-        ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
-        if (ret != 0) {
-            JS_FreeValue(ctx, op1);
-            JS_FreeValue(ctx, op2);
-            if (ret < 0) {
-                goto exception;
-            } else {
-                sp[-2] = res;
-                return 0;
-            }
-        }
-    }
-
-    op1 = JS_ToNumericFree(ctx, op1);
-    if (JS_IsException(op1)) {
-        JS_FreeValue(ctx, op2);
-        goto exception;
-    }
-    op2 = JS_ToNumericFree(ctx, op2);
-    if (JS_IsException(op2)) {
-        JS_FreeValue(ctx, op1);
-        goto exception;
-    }
-    tag1 = JS_VALUE_GET_NORM_TAG(op1);
-    tag2 = JS_VALUE_GET_NORM_TAG(op2);
-
-    if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
-        int32_t v1, v2;
-        int64_t v;
-        v1 = JS_VALUE_GET_INT(op1);
-        v2 = JS_VALUE_GET_INT(op2);
-        switch(op) {
-        case OP_sub:
-            v = (int64_t)v1 - (int64_t)v2;
-            break;
-        case OP_mul:
-            v = (int64_t)v1 * (int64_t)v2;
-            if (is_math_mode(ctx) &&
-                (v < -MAX_SAFE_INTEGER || v > MAX_SAFE_INTEGER))
-                goto handle_bigint;
-            if (v == 0 && (v1 | v2) < 0) {
-                sp[-2] = __JS_NewFloat64(ctx, -0.0);
-                return 0;
-            }
-            break;
-        case OP_div:
-            if (is_math_mode(ctx))
-                goto handle_bigint;
-            sp[-2] = __JS_NewFloat64(ctx, (double)v1 / (double)v2);
-            return 0;
-        case OP_math_mod:
-            if (unlikely(v2 == 0)) {
-                throw_bf_exception(ctx, BF_ST_DIVIDE_ZERO);
-                goto exception;
-            }
-            v = (int64_t)v1 % (int64_t)v2;
-            if (v < 0) {
-                if (v2 < 0)
-                    v -= v2;
-                else
-                    v += v2;
-            }
-            break;
-        case OP_mod:
-            if (v1 < 0 || v2 <= 0) {
-                sp[-2] = JS_NewFloat64(ctx, fmod(v1, v2));
-                return 0;
-            } else {
-                v = (int64_t)v1 % (int64_t)v2;
-            }
-            break;
-        case OP_pow:
-            if (!is_math_mode(ctx)) {
-                sp[-2] = JS_NewFloat64(ctx, js_pow(v1, v2));
-                return 0;
-            } else {
-                goto handle_bigint;
-            }
-            break;
-        default:
-            abort();
-        }
-        sp[-2] = JS_NewInt64(ctx, v);
-    } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
-        if (ctx->rt->bigdecimal_ops.binary_arith(ctx, op, sp - 2, op1, op2))
-            goto exception;
-    } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
-        if (ctx->rt->bigfloat_ops.binary_arith(ctx, op, sp - 2, op1, op2))
-            goto exception;
-    } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
-    handle_bigint:
-        if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
-            goto exception;
-    } else {
-        double dr;
-        /* float64 result */
-        if (JS_ToFloat64Free(ctx, &d1, op1)) {
-            JS_FreeValue(ctx, op2);
-            goto exception;
-        }
-        if (JS_ToFloat64Free(ctx, &d2, op2))
-            goto exception;
-    handle_float64:
-        if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2))
-            goto handle_bigint;
-        switch(op) {
-        case OP_sub:
-            dr = d1 - d2;
-            break;
-        case OP_mul:
-            dr = d1 * d2;
-            break;
-        case OP_div:
-            dr = d1 / d2;
-            break;
-        case OP_mod:
-            dr = fmod(d1, d2);
-            break;
-        case OP_math_mod:
-            d2 = fabs(d2);
-            dr = fmod(d1, d2);
-            /* XXX: loss of accuracy if dr < 0 */
-            if (dr < 0)
-                dr += d2;
-            break;
-        case OP_pow:
-            dr = js_pow(d1, d2);
-            break;
-        default:
-            abort();
-        }
-        sp[-2] = __JS_NewFloat64(ctx, dr);
-    }
-    return 0;
- exception:
-    sp[-2] = JS_UNDEFINED;
-    sp[-1] = JS_UNDEFINED;
-    return -1;
-}
-
-static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
-{
-    JSValue op1, op2, res;
-    uint32_t tag1, tag2;
-    int ret;
-
-    op1 = sp[-2];
-    op2 = sp[-1];
-
-    tag1 = JS_VALUE_GET_NORM_TAG(op1);
-    tag2 = JS_VALUE_GET_NORM_TAG(op2);
-    /* fast path for float64 */
-    if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) {
-        double d1, d2;
-        d1 = JS_VALUE_GET_FLOAT64(op1);
-        d2 = JS_VALUE_GET_FLOAT64(op2);
-        sp[-2] = __JS_NewFloat64(ctx, d1 + d2);
-        return 0;
-    }
-
-    if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) {
-        /* try to call an overloaded operator */
-        if ((tag1 == JS_TAG_OBJECT &&
-             (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED &&
-              tag2 != JS_TAG_STRING)) ||
-            (tag2 == JS_TAG_OBJECT &&
-             (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED &&
-              tag1 != JS_TAG_STRING))) {
-            ret = js_call_binary_op_fallback(ctx, &res, op1, op2, OP_add,
-                                             FALSE, HINT_NONE);
-            if (ret != 0) {
-                JS_FreeValue(ctx, op1);
-                JS_FreeValue(ctx, op2);
-                if (ret < 0) {
-                    goto exception;
-                } else {
-                    sp[-2] = res;
-                    return 0;
-                }
-            }
-        }
-
-        op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
-        if (JS_IsException(op1)) {
-            JS_FreeValue(ctx, op2);
-            goto exception;
-        }
-
-        op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
-        if (JS_IsException(op2)) {
-            JS_FreeValue(ctx, op1);
-            goto exception;
-        }
-        tag1 = JS_VALUE_GET_NORM_TAG(op1);
-        tag2 = JS_VALUE_GET_NORM_TAG(op2);
-    }
-
-    if (tag1 == JS_TAG_STRING || tag2 == JS_TAG_STRING) {
-        sp[-2] = JS_ConcatString(ctx, op1, op2);
-        if (JS_IsException(sp[-2]))
-            goto exception;
-        return 0;
-    }
-
-    op1 = JS_ToNumericFree(ctx, op1);
-    if (JS_IsException(op1)) {
-        JS_FreeValue(ctx, op2);
-        goto exception;
-    }
-    op2 = JS_ToNumericFree(ctx, op2);
-    if (JS_IsException(op2)) {
-        JS_FreeValue(ctx, op1);
-        goto exception;
-    }
-    tag1 = JS_VALUE_GET_NORM_TAG(op1);
-    tag2 = JS_VALUE_GET_NORM_TAG(op2);
-
-    if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
-        int32_t v1, v2;
-        int64_t v;
-        v1 = JS_VALUE_GET_INT(op1);
-        v2 = JS_VALUE_GET_INT(op2);
-        v = (int64_t)v1 + (int64_t)v2;
-        sp[-2] = JS_NewInt64(ctx, v);
-    } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
-        if (ctx->rt->bigdecimal_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
-            goto exception;
-    } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
-        if (ctx->rt->bigfloat_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
-            goto exception;
-    } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
-    handle_bigint:
-        if (ctx->rt->bigint_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
-            goto exception;
-    } else {
-        double d1, d2;
-        /* float64 result */
-        if (JS_ToFloat64Free(ctx, &d1, op1)) {
-            JS_FreeValue(ctx, op2);
-            goto exception;
-        }
-        if (JS_ToFloat64Free(ctx, &d2, op2))
-            goto exception;
-        if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2))
-            goto handle_bigint;
-        sp[-2] = __JS_NewFloat64(ctx, d1 + d2);
-    }
-    return 0;
- exception:
-    sp[-2] = JS_UNDEFINED;
-    sp[-1] = JS_UNDEFINED;
-    return -1;
-}
-
-static no_inline __exception int js_binary_logic_slow(JSContext *ctx,
-                                                      JSValue *sp,
-                                                      OPCodeEnum op)
-{
-    JSValue op1, op2, res;
-    int ret;
-    uint32_t tag1, tag2;
-    uint32_t v1, v2, r;
-
-    op1 = sp[-2];
-    op2 = sp[-1];
-    tag1 = JS_VALUE_GET_NORM_TAG(op1);
-    tag2 = JS_VALUE_GET_NORM_TAG(op2);
-
-    /* try to call an overloaded operator */
-    if ((tag1 == JS_TAG_OBJECT &&
-         (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
-        (tag2 == JS_TAG_OBJECT &&
-         (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
-        ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
-        if (ret != 0) {
-            JS_FreeValue(ctx, op1);
-            JS_FreeValue(ctx, op2);
-            if (ret < 0) {
-                goto exception;
-            } else {
-                sp[-2] = res;
-                return 0;
-            }
-        }
-    }
-
-    op1 = JS_ToNumericFree(ctx, op1);
-    if (JS_IsException(op1)) {
-        JS_FreeValue(ctx, op2);
-        goto exception;
-    }
-    op2 = JS_ToNumericFree(ctx, op2);
-    if (JS_IsException(op2)) {
-        JS_FreeValue(ctx, op1);
-        goto exception;
-    }
-
-    if (is_math_mode(ctx))
-        goto bigint_op;
-
-    tag1 = JS_VALUE_GET_TAG(op1);
-    tag2 = JS_VALUE_GET_TAG(op2);
-    if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
-        if (tag1 != tag2) {
-            JS_FreeValue(ctx, op1);
-            JS_FreeValue(ctx, op2);
-            JS_ThrowTypeError(ctx, "both operands must be bigint");
-            goto exception;
-        } else {
-        bigint_op:
-            if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
-                goto exception;
-        }
-    } else {
-        if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {
-            JS_FreeValue(ctx, op2);
-            goto exception;
-        }
-        if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2)))
-            goto exception;
-        switch(op) {
-        case OP_shl:
-            r = v1 << (v2 & 0x1f);
-            break;
-        case OP_sar:
-            r = (int)v1 >> (v2 & 0x1f);
-            break;
-        case OP_and:
-            r = v1 & v2;
-            break;
-        case OP_or:
-            r = v1 | v2;
-            break;
-        case OP_xor:
-            r = v1 ^ v2;
-            break;
-        default:
-            abort();
-        }
-        sp[-2] = JS_NewInt32(ctx, r);
-    }
-    return 0;
- exception:
-    sp[-2] = JS_UNDEFINED;
-    sp[-1] = JS_UNDEFINED;
-    return -1;
-}
-
-/* Note: also used for bigint */
-static int js_compare_bigfloat(JSContext *ctx, OPCodeEnum op,
-                               JSValue op1, JSValue op2)
-{
-    bf_t a_s, b_s, *a, *b;
-    int res;
-    
-    a = JS_ToBigFloat(ctx, &a_s, op1);
-    if (!a) {
-        JS_FreeValue(ctx, op2);
-        return -1;
-    }
-    b = JS_ToBigFloat(ctx, &b_s, op2);
-    if (!b) {
-        if (a == &a_s)
-            bf_delete(a);
-        JS_FreeValue(ctx, op1);
-        return -1;
-    }
-    switch(op) {
-    case OP_lt:
-        res = bf_cmp_lt(a, b); /* if NaN return false */
-        break;
-    case OP_lte:
-        res = bf_cmp_le(a, b); /* if NaN return false */
-        break;
-    case OP_gt:
-        res = bf_cmp_lt(b, a); /* if NaN return false */
-        break;
-    case OP_gte:
-        res = bf_cmp_le(b, a); /* if NaN return false */
-        break;
-    case OP_eq:
-        res = bf_cmp_eq(a, b); /* if NaN return false */
-        break;
-    default:
-        abort();
-    }
-    if (a == &a_s)
-        bf_delete(a);
-    if (b == &b_s)
-        bf_delete(b);
-    JS_FreeValue(ctx, op1);
-    JS_FreeValue(ctx, op2);
-    return res;
-}
-
-static int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op,
-                                 JSValue op1, JSValue op2)
-{
-    bfdec_t *a, *b;
-    int res;
-
-    /* Note: binary floats are converted to bigdecimal with
-       toString(). It is not mathematically correct but is consistent
-       with the BigDecimal() constructor behavior */
-    op1 = JS_ToBigDecimalFree(ctx, op1, TRUE);
-    if (JS_IsException(op1)) {
-        JS_FreeValue(ctx, op2);
-        return -1;
-    }
-    op2 = JS_ToBigDecimalFree(ctx, op2, TRUE);
-    if (JS_IsException(op2)) {
-        JS_FreeValue(ctx, op1);
-        return -1;
-    }
-    a = JS_ToBigDecimal(ctx, op1);
-    b = JS_ToBigDecimal(ctx, op2);
-    
-    switch(op) {
-    case OP_lt:
-        res = bfdec_cmp_lt(a, b); /* if NaN return false */
-        break;
-    case OP_lte:
-        res = bfdec_cmp_le(a, b); /* if NaN return false */
-        break;
-    case OP_gt:
-        res = bfdec_cmp_lt(b, a); /* if NaN return false */
-        break;
-    case OP_gte:
-        res = bfdec_cmp_le(b, a); /* if NaN return false */
-        break;
-    case OP_eq:
-        res = bfdec_cmp_eq(a, b); /* if NaN return false */
-        break;
-    default:
-        abort();
-    }
-    JS_FreeValue(ctx, op1);
-    JS_FreeValue(ctx, op2);
-    return res;
-}
-
-static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
-                                        OPCodeEnum op)
-{
-    JSValue op1, op2, ret;
-    int res;
-    uint32_t tag1, tag2;
-
-    op1 = sp[-2];
-    op2 = sp[-1];
-    tag1 = JS_VALUE_GET_NORM_TAG(op1);
-    tag2 = JS_VALUE_GET_NORM_TAG(op2);
-    /* try to call an overloaded operator */
-    if ((tag1 == JS_TAG_OBJECT &&
-         (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
-        (tag2 == JS_TAG_OBJECT &&
-         (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
-        res = js_call_binary_op_fallback(ctx, &ret, op1, op2, op,
-                                         FALSE, HINT_NUMBER);
-        if (res != 0) {
-            JS_FreeValue(ctx, op1);
-            JS_FreeValue(ctx, op2);
-            if (res < 0) {
-                goto exception;
-            } else {
-                sp[-2] = ret;
-                return 0;
-            }
-        }
-    }
-    op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER);
-    if (JS_IsException(op1)) {
-        JS_FreeValue(ctx, op2);
-        goto exception;
-    }
-    op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER);
-    if (JS_IsException(op2)) {
-        JS_FreeValue(ctx, op1);
-        goto exception;
-    }
-    tag1 = JS_VALUE_GET_NORM_TAG(op1);
-    tag2 = JS_VALUE_GET_NORM_TAG(op2);
-
-    if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) {
-        JSString *p1, *p2;
-        p1 = JS_VALUE_GET_STRING(op1);
-        p2 = JS_VALUE_GET_STRING(op2);
-        res = js_string_compare(ctx, p1, p2);
-        switch(op) {
-        case OP_lt:
-            res = (res < 0);
-            break;
-        case OP_lte:
-            res = (res <= 0);
-            break;
-        case OP_gt:
-            res = (res > 0);
-            break;
-        default:
-        case OP_gte:
-            res = (res >= 0);
-            break;
-        }
-        JS_FreeValue(ctx, op1);
-        JS_FreeValue(ctx, op2);
-    } else if ((tag1 <= JS_TAG_NULL || tag1 == JS_TAG_FLOAT64) &&
-               (tag2 <= JS_TAG_NULL || tag2 == JS_TAG_FLOAT64)) {
-        /* fast path for float64/int */
-        goto float64_compare;
-    } else {
-        if (((tag1 == JS_TAG_BIG_INT && tag2 == JS_TAG_STRING) ||
-             (tag2 == JS_TAG_BIG_INT && tag1 == JS_TAG_STRING)) &&
-            !is_math_mode(ctx)) {
-            if (tag1 == JS_TAG_STRING) {
-                op1 = JS_StringToBigInt(ctx, op1);
-                if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
-                    goto invalid_bigint_string;
-            }
-            if (tag2 == JS_TAG_STRING) {
-                op2 = JS_StringToBigInt(ctx, op2);
-                if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT) {
-                invalid_bigint_string:
-                    JS_FreeValue(ctx, op1);
-                    JS_FreeValue(ctx, op2);
-                    res = FALSE;
-                    goto done;
-                }
-            }
-        } else {
-            op1 = JS_ToNumericFree(ctx, op1);
-            if (JS_IsException(op1)) {
-                JS_FreeValue(ctx, op2);
-                goto exception;
-            }
-            op2 = JS_ToNumericFree(ctx, op2);
-            if (JS_IsException(op2)) {
-                JS_FreeValue(ctx, op1);
-                goto exception;
-            }
-        }
-
-        tag1 = JS_VALUE_GET_NORM_TAG(op1);
-        tag2 = JS_VALUE_GET_NORM_TAG(op2);
-
-        if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
-            res = ctx->rt->bigdecimal_ops.compare(ctx, op, op1, op2);
-            if (res < 0)
-                goto exception;
-        } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
-            res = ctx->rt->bigfloat_ops.compare(ctx, op, op1, op2);
-            if (res < 0)
-                goto exception;
-        } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
-            res = ctx->rt->bigint_ops.compare(ctx, op, op1, op2);
-            if (res < 0)
-                goto exception;
-        } else {
-            double d1, d2;
-
-        float64_compare:
-            /* can use floating point comparison */
-            if (tag1 == JS_TAG_FLOAT64) {
-                d1 = JS_VALUE_GET_FLOAT64(op1);
-            } else {
-                d1 = JS_VALUE_GET_INT(op1);
-            }
-            if (tag2 == JS_TAG_FLOAT64) {
-                d2 = JS_VALUE_GET_FLOAT64(op2);
-            } else {
-                d2 = JS_VALUE_GET_INT(op2);
-            }
-            switch(op) {
-            case OP_lt:
-                res = (d1 < d2); /* if NaN return false */
-                break;
-            case OP_lte:
-                res = (d1 <= d2); /* if NaN return false */
-                break;
-            case OP_gt:
-                res = (d1 > d2); /* if NaN return false */
-                break;
-            default:
-            case OP_gte:
-                res = (d1 >= d2); /* if NaN return false */
-                break;
-            }
-        }
-    }
- done:
-    sp[-2] = JS_NewBool(ctx, res);
-    return 0;
- exception:
-    sp[-2] = JS_UNDEFINED;
-    sp[-1] = JS_UNDEFINED;
-    return -1;
-}
-
-static BOOL tag_is_number(uint32_t tag)
-{
-    return (tag == JS_TAG_INT || tag == JS_TAG_BIG_INT ||
-            tag == JS_TAG_FLOAT64 || tag == JS_TAG_BIG_FLOAT ||
-            tag == JS_TAG_BIG_DECIMAL);
-}
-
-static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
-                                            BOOL is_neq)
-{
-    JSValue op1, op2, ret;
-    int res;
-    uint32_t tag1, tag2;
-
-    op1 = sp[-2];
-    op2 = sp[-1];
- redo:
-    tag1 = JS_VALUE_GET_NORM_TAG(op1);
-    tag2 = JS_VALUE_GET_NORM_TAG(op2);
-    if (tag_is_number(tag1) && tag_is_number(tag2)) {
-        if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
-            res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);
-        } else if ((tag1 == JS_TAG_FLOAT64 &&
-                    (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64)) ||
-                   (tag2 == JS_TAG_FLOAT64 &&
-                    (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64))) {
-            double d1, d2;
-            if (tag1 == JS_TAG_FLOAT64) {
-                d1 = JS_VALUE_GET_FLOAT64(op1);
-            } else {
-                d1 = JS_VALUE_GET_INT(op1);
-            }
-            if (tag2 == JS_TAG_FLOAT64) {
-                d2 = JS_VALUE_GET_FLOAT64(op2);
-            } else {
-                d2 = JS_VALUE_GET_INT(op2);
-            }
-            res = (d1 == d2);
-        } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
-            res = ctx->rt->bigdecimal_ops.compare(ctx, OP_eq, op1, op2);
-            if (res < 0)
-                goto exception;
-        } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
-            res = ctx->rt->bigfloat_ops.compare(ctx, OP_eq, op1, op2);
-            if (res < 0)
-                goto exception;
-        } else {
-            res = ctx->rt->bigint_ops.compare(ctx, OP_eq, op1, op2);
-            if (res < 0)
-                goto exception;
-        }
-    } else if (tag1 == tag2) {
-        if (tag1 == JS_TAG_OBJECT) {
-            /* try the fallback operator */
-            res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
-                                             is_neq ? OP_neq : OP_eq,
-                                             FALSE, HINT_NONE);
-            if (res != 0) {
-                JS_FreeValue(ctx, op1);
-                JS_FreeValue(ctx, op2);
-                if (res < 0) {
-                    goto exception;
-                } else {
-                    sp[-2] = ret;
-                    return 0;
-                }
-            }
-        }
-        res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
-    } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) ||
-               (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) {
-        res = TRUE;
-    } else if ((tag1 == JS_TAG_STRING && tag_is_number(tag2)) ||
-               (tag2 == JS_TAG_STRING && tag_is_number(tag1))) {
-
-        if ((tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) &&
-            !is_math_mode(ctx)) {
-            if (tag1 == JS_TAG_STRING) {
-                op1 = JS_StringToBigInt(ctx, op1);
-                if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
-                    goto invalid_bigint_string;
-            }
-            if (tag2 == JS_TAG_STRING) {
-                op2 = JS_StringToBigInt(ctx, op2);
-                if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT) {
-                invalid_bigint_string:
-                    JS_FreeValue(ctx, op1);
-                    JS_FreeValue(ctx, op2);
-                    res = FALSE;
-                    goto done;
-                }
-            }
-        } else {
-            op1 = JS_ToNumericFree(ctx, op1);
-            if (JS_IsException(op1)) {
-                JS_FreeValue(ctx, op2);
-                goto exception;
-            }
-            op2 = JS_ToNumericFree(ctx, op2);
-            if (JS_IsException(op2)) {
-                JS_FreeValue(ctx, op1);
-                goto exception;
-            }
-        }
-        res = js_strict_eq(ctx, op1, op2);
-    } else if (tag1 == JS_TAG_BOOL) {
-        op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1));
-        goto redo;
-    } else if (tag2 == JS_TAG_BOOL) {
-        op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2));
-        goto redo;
-    } else if ((tag1 == JS_TAG_OBJECT &&
-                (tag_is_number(tag2) || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) ||
-               (tag2 == JS_TAG_OBJECT &&
-                (tag_is_number(tag1) || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL))) {
-
-        /* try the fallback operator */
-        res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
-                                         is_neq ? OP_neq : OP_eq,
-                                         FALSE, HINT_NONE);
-        if (res != 0) {
-            JS_FreeValue(ctx, op1);
-            JS_FreeValue(ctx, op2);
-            if (res < 0) {
-                goto exception;
-            } else {
-                sp[-2] = ret;
-                return 0;
-            }
-        }
-
-        op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
-        if (JS_IsException(op1)) {
-            JS_FreeValue(ctx, op2);
-            goto exception;
-        }
-        op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
-        if (JS_IsException(op2)) {
-            JS_FreeValue(ctx, op1);
-            goto exception;
-        }
-        goto redo;
-    } else {
-        /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */
-        if ((JS_IsHTMLDDA(ctx, op1) &&
-             (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) ||
-            (JS_IsHTMLDDA(ctx, op2) &&
-             (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) {
-            res = TRUE;
-        } else {
-            res = FALSE;
-        }
-        JS_FreeValue(ctx, op1);
-        JS_FreeValue(ctx, op2);
-    }
- done:
-    sp[-2] = JS_NewBool(ctx, res ^ is_neq);
-    return 0;
- exception:
-    sp[-2] = JS_UNDEFINED;
-    sp[-1] = JS_UNDEFINED;
-    return -1;
-}
-
-static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp)
-{
-    JSValue op1, op2;
-    uint32_t v1, v2, r;
-
-    op1 = sp[-2];
-    op2 = sp[-1];
-    op1 = JS_ToNumericFree(ctx, op1);
-    if (JS_IsException(op1)) {
-        JS_FreeValue(ctx, op2);
-        goto exception;
-    }
-    op2 = JS_ToNumericFree(ctx, op2);
-    if (JS_IsException(op2)) {
-        JS_FreeValue(ctx, op1);
-        goto exception;
-    }
-    /* XXX: could forbid >>> in bignum mode */
-    if (!is_math_mode(ctx) &&
-        (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT ||
-         JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_INT)) {
-        JS_ThrowTypeError(ctx, "bigint operands are forbidden for >>>");
-        JS_FreeValue(ctx, op1);
-        JS_FreeValue(ctx, op2);
-        goto exception;
-    }
-    /* cannot give an exception */
-    JS_ToUint32Free(ctx, &v1, op1);
-    JS_ToUint32Free(ctx, &v2, op2);
-    r = v1 >> (v2 & 0x1f);
-    sp[-2] = JS_NewUint32(ctx, r);
-    return 0;
- exception:
-    sp[-2] = JS_UNDEFINED;
-    sp[-1] = JS_UNDEFINED;
-    return -1;
-}
-
-static JSValue js_mul_pow10_to_float64(JSContext *ctx, const bf_t *a,
-                                       int64_t exponent)
-{
-    bf_t r_s, *r = &r_s;
-    double d;
-    int ret;
-    
-    /* always convert to Float64 */
-    bf_init(ctx->bf_ctx, r);
-    ret = bf_mul_pow_radix(r, a, 10, exponent,
-                           53, bf_set_exp_bits(11) | BF_RNDN |
-                           BF_FLAG_SUBNORMAL);
-    bf_get_float64(r, &d, BF_RNDN);
-    bf_delete(r);
-    if (ret & BF_ST_MEM_ERROR)
-        return JS_ThrowOutOfMemory(ctx);
-    else
-        return __JS_NewFloat64(ctx, d);
-}
-
-static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp)
-{
-    bf_t a_s, *a, *r;
-    JSValue op1, op2, res;
-    int64_t e;
-    int ret;
-
-    res = JS_NewBigFloat(ctx);
-    if (JS_IsException(res))
-        return -1;
-    r = JS_GetBigFloat(res);
-    op1 = sp[-2];
-    op2 = sp[-1];
-    a = JS_ToBigFloat(ctx, &a_s, op1);
-    if (!a)
-        return -1;
-    if (JS_IsBigInt(ctx, op2)) {
-        ret = JS_ToBigInt64(ctx, &e, op2);
-    } else {
-        ret = JS_ToInt64(ctx, &e, op2);
-    }
-    if (ret) {
-        if (a == &a_s)
-            bf_delete(a);
-        JS_FreeValue(ctx, res);
-        return -1;
-    }
-
-    bf_mul_pow_radix(r, a, 10, e, ctx->fp_env.prec, ctx->fp_env.flags);
-    if (a == &a_s)
-        bf_delete(a);
-    JS_FreeValue(ctx, op1);
-    JS_FreeValue(ctx, op2);
-    sp[-2] = res;
-    return 0;
-}
-
-#else /* !CONFIG_BIGNUM */
-
-static JSValue JS_ThrowUnsupportedBigint(JSContext *ctx)
-{
-    return JS_ThrowTypeError(ctx, "bigint is not supported");
-}
-
-JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)
-{
-    return JS_ThrowUnsupportedBigint(ctx);
-}
-
-JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
-{
-    return JS_ThrowUnsupportedBigint(ctx);
-}
-
-int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
-{
-    JS_ThrowUnsupportedBigint(ctx);
-    *pres = 0;
-    return -1;
-}
-
-static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
-                                                     JSValue *sp,
-                                                     OPCodeEnum op)
-{
-    JSValue op1;
-    double d;
-
-    op1 = sp[-1];
-    if (unlikely(JS_ToFloat64Free(ctx, &d, op1))) {
-        sp[-1] = JS_UNDEFINED;
-        return -1;
-    }
-    switch(op) {
-    case OP_inc:
-        d++;
-        break;
-    case OP_dec:
-        d--;
-        break;
-    case OP_plus:
-        break;
-    case OP_neg:
-        d = -d;
-        break;
-    default:
-        abort();
-    }
-    sp[-1] = JS_NewFloat64(ctx, d);
-    return 0;
-}
-
-/* specific case necessary for correct return value semantics */
-static __exception int js_post_inc_slow(JSContext *ctx,
-                                        JSValue *sp, OPCodeEnum op)
-{
-    JSValue op1;
-    double d, r;
-
-    op1 = sp[-1];
-    if (unlikely(JS_ToFloat64Free(ctx, &d, op1))) {
-        sp[-1] = JS_UNDEFINED;
-        return -1;
-    }
-    r = d + 2 * (op - OP_post_dec) - 1;
-    sp[0] = JS_NewFloat64(ctx, r);
-    sp[-1] = JS_NewFloat64(ctx, d);
-    return 0;
-}
-
-static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
-                                                      OPCodeEnum op)
-{
-    JSValue op1, op2;
-    double d1, d2, r;
-
-    op1 = sp[-2];
-    op2 = sp[-1];
-    if (unlikely(JS_ToFloat64Free(ctx, &d1, op1))) {
-        JS_FreeValue(ctx, op2);
-        goto exception;
-    }
-    if (unlikely(JS_ToFloat64Free(ctx, &d2, op2))) {
-        goto exception;
-    }
-    switch(op) {
-    case OP_sub:
-        r = d1 - d2;
-        break;
-    case OP_mul:
-        r = d1 * d2;
-        break;
-    case OP_div:
-        r = d1 / d2;
-        break;
-    case OP_mod:
-        r = fmod(d1, d2);
-        break;
-    case OP_pow:
-        r = js_pow(d1, d2);
-        break;
-    default:
-        abort();
-    }
-    sp[-2] = JS_NewFloat64(ctx, r);
-    return 0;
- exception:
-    sp[-2] = JS_UNDEFINED;
-    sp[-1] = JS_UNDEFINED;
-    return -1;
-}
-
-static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
-{
-    JSValue op1, op2;
-    uint32_t tag1, tag2;
-
-    op1 = sp[-2];
-    op2 = sp[-1];
-    tag1 = JS_VALUE_GET_TAG(op1);
-    tag2 = JS_VALUE_GET_TAG(op2);
-    if ((tag1 == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag1)) &&
-        (tag2 == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag2))) {
-        goto add_numbers;
-    } else {
-        op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
-        if (JS_IsException(op1)) {
-            JS_FreeValue(ctx, op2);
-            goto exception;
-        }
-        op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
-        if (JS_IsException(op2)) {
-            JS_FreeValue(ctx, op1);
-            goto exception;
-        }
-        tag1 = JS_VALUE_GET_TAG(op1);
-        tag2 = JS_VALUE_GET_TAG(op2);
-        if (tag1 == JS_TAG_STRING || tag2 == JS_TAG_STRING) {
-            sp[-2] = JS_ConcatString(ctx, op1, op2);
-            if (JS_IsException(sp[-2]))
-                goto exception;
-        } else {
-            double d1, d2;
-        add_numbers:
-            if (JS_ToFloat64Free(ctx, &d1, op1)) {
-                JS_FreeValue(ctx, op2);
-                goto exception;
-            }
-            if (JS_ToFloat64Free(ctx, &d2, op2))
-                goto exception;
-            sp[-2] = JS_NewFloat64(ctx, d1 + d2);
-        }
-    }
-    return 0;
- exception:
-    sp[-2] = JS_UNDEFINED;
-    sp[-1] = JS_UNDEFINED;
-    return -1;
-}
-
-static no_inline __exception int js_binary_logic_slow(JSContext *ctx,
-                                                      JSValue *sp,
-                                                      OPCodeEnum op)
-{
-    JSValue op1, op2;
-    uint32_t v1, v2, r;
-
-    op1 = sp[-2];
-    op2 = sp[-1];
-    if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {
-        JS_FreeValue(ctx, op2);
-        goto exception;
-    }
-    if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2)))
-        goto exception;
-    switch(op) {
-    case OP_shl:
-        r = v1 << (v2 & 0x1f);
-        break;
-    case OP_sar:
-        r = (int)v1 >> (v2 & 0x1f);
-        break;
-    case OP_and:
-        r = v1 & v2;
-        break;
-    case OP_or:
-        r = v1 | v2;
-        break;
-    case OP_xor:
-        r = v1 ^ v2;
-        break;
-    default:
-        abort();
-    }
-    sp[-2] = JS_NewInt32(ctx, r);
-    return 0;
- exception:
-    sp[-2] = JS_UNDEFINED;
-    sp[-1] = JS_UNDEFINED;
-    return -1;
-}
-
-static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
-{
-    int32_t v1;
-
-    if (unlikely(JS_ToInt32Free(ctx, &v1, sp[-1]))) {
-        sp[-1] = JS_UNDEFINED;
-        return -1;
-    }
-    sp[-1] = JS_NewInt32(ctx, ~v1);
-    return 0;
-}
-
-static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
-                                        OPCodeEnum op)
-{
-    JSValue op1, op2;
-    int res;
-
-    op1 = sp[-2];
-    op2 = sp[-1];
-    op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER);
-    if (JS_IsException(op1)) {
-        JS_FreeValue(ctx, op2);
-        goto exception;
-    }
-    op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER);
-    if (JS_IsException(op2)) {
-        JS_FreeValue(ctx, op1);
-        goto exception;
-    }
-    if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING &&
-        JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {
-        JSString *p1, *p2;
-        p1 = JS_VALUE_GET_STRING(op1);
-        p2 = JS_VALUE_GET_STRING(op2);
-        res = js_string_compare(ctx, p1, p2);
-        JS_FreeValue(ctx, op1);
-        JS_FreeValue(ctx, op2);
-        switch(op) {
-        case OP_lt:
-            res = (res < 0);
-            break;
-        case OP_lte:
-            res = (res <= 0);
-            break;
-        case OP_gt:
-            res = (res > 0);
-            break;
-        default:
-        case OP_gte:
-            res = (res >= 0);
-            break;
-        }
-    } else {
-        double d1, d2;
-        if (JS_ToFloat64Free(ctx, &d1, op1)) {
-            JS_FreeValue(ctx, op2);
-            goto exception;
-        }
-        if (JS_ToFloat64Free(ctx, &d2, op2))
-            goto exception;
-        switch(op) {
-        case OP_lt:
-            res = (d1 < d2); /* if NaN return false */
-            break;
-        case OP_lte:
-            res = (d1 <= d2); /* if NaN return false */
-            break;
-        case OP_gt:
-            res = (d1 > d2); /* if NaN return false */
-            break;
-        default:
-        case OP_gte:
-            res = (d1 >= d2); /* if NaN return false */
-            break;
-        }
-    }
-    sp[-2] = JS_NewBool(ctx, res);
-    return 0;
- exception:
-    sp[-2] = JS_UNDEFINED;
-    sp[-1] = JS_UNDEFINED;
-    return -1;
-}
-
-static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
-                                            BOOL is_neq)
-{
-    JSValue op1, op2;
-    int tag1, tag2;
-    BOOL res;
-
-    op1 = sp[-2];
-    op2 = sp[-1];
- redo:
-    tag1 = JS_VALUE_GET_NORM_TAG(op1);
-    tag2 = JS_VALUE_GET_NORM_TAG(op2);
-    if (tag1 == tag2 ||
-        (tag1 == JS_TAG_INT && tag2 == JS_TAG_FLOAT64) ||
-        (tag2 == JS_TAG_INT && tag1 == JS_TAG_FLOAT64)) {
-        res = js_strict_eq(ctx, op1, op2);
-    } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) ||
-               (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) {
-        res = TRUE;
-    } else if ((tag1 == JS_TAG_STRING && (tag2 == JS_TAG_INT ||
-                                   tag2 == JS_TAG_FLOAT64)) ||
-        (tag2 == JS_TAG_STRING && (tag1 == JS_TAG_INT ||
-                                   tag1 == JS_TAG_FLOAT64))) {
-        double d1;
-        double d2;
-        if (JS_ToFloat64Free(ctx, &d1, op1)) {
-            JS_FreeValue(ctx, op2);
-            goto exception;
-        }
-        if (JS_ToFloat64Free(ctx, &d2, op2))
-            goto exception;
-        res = (d1 == d2);
-    } else if (tag1 == JS_TAG_BOOL) {
-        op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1));
-        goto redo;
-    } else if (tag2 == JS_TAG_BOOL) {
-        op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2));
-        goto redo;
-    } else if (tag1 == JS_TAG_OBJECT &&
-               (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64 || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) {
-        op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
-        if (JS_IsException(op1)) {
-            JS_FreeValue(ctx, op2);
-            goto exception;
-        }
-        goto redo;
-    } else if (tag2 == JS_TAG_OBJECT &&
-               (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64 || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL)) {
-        op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
-        if (JS_IsException(op2)) {
-            JS_FreeValue(ctx, op1);
-            goto exception;
-        }
-        goto redo;
-    } else {
-        /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */
-        if ((JS_IsHTMLDDA(ctx, op1) &&
-             (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) ||
-            (JS_IsHTMLDDA(ctx, op2) &&
-             (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) {
-            res = TRUE;
-        } else {
-            res = FALSE;
-        }
-        JS_FreeValue(ctx, op1);
-        JS_FreeValue(ctx, op2);
-    }
-    sp[-2] = JS_NewBool(ctx, res ^ is_neq);
-    return 0;
- exception:
-    sp[-2] = JS_UNDEFINED;
-    sp[-1] = JS_UNDEFINED;
-    return -1;
-}
-
-static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp)
-{
-    JSValue op1, op2;
-    uint32_t v1, v2, r;
-
-    op1 = sp[-2];
-    op2 = sp[-1];
-    if (unlikely(JS_ToUint32Free(ctx, &v1, op1))) {
-        JS_FreeValue(ctx, op2);
-        goto exception;
-    }
-    if (unlikely(JS_ToUint32Free(ctx, &v2, op2)))
-        goto exception;
-    r = v1 >> (v2 & 0x1f);
-    sp[-2] = JS_NewUint32(ctx, r);
-    return 0;
- exception:
-    sp[-2] = JS_UNDEFINED;
-    sp[-1] = JS_UNDEFINED;
-    return -1;
-}
-
-#endif /* !CONFIG_BIGNUM */
-
-/* XXX: Should take JSValueConst arguments */
-static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
-                          JSStrictEqModeEnum eq_mode)
-{
-    BOOL res;
-    int tag1, tag2;
-    double d1, d2;
-
-    tag1 = JS_VALUE_GET_NORM_TAG(op1);
-    tag2 = JS_VALUE_GET_NORM_TAG(op2);
-    switch(tag1) {
-    case JS_TAG_BOOL:
-        if (tag1 != tag2) {
-            res = FALSE;
-        } else {
-            res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);
-            goto done_no_free;
-        }
-        break;
-    case JS_TAG_NULL:
-    case JS_TAG_UNDEFINED:
-        res = (tag1 == tag2);
-        break;
-    case JS_TAG_STRING:
-        {
-            JSString *p1, *p2;
-            if (tag1 != tag2) {
-                res = FALSE;
-            } else {
-                p1 = JS_VALUE_GET_STRING(op1);
-                p2 = JS_VALUE_GET_STRING(op2);
-                res = (js_string_compare(ctx, p1, p2) == 0);
-            }
-        }
-        break;
-    case JS_TAG_SYMBOL:
-        {
-            JSAtomStruct *p1, *p2;
-            if (tag1 != tag2) {
-                res = FALSE;
-            } else {
-                p1 = JS_VALUE_GET_PTR(op1);
-                p2 = JS_VALUE_GET_PTR(op2);
-                res = (p1 == p2);
-            }
-        }
-        break;
-    case JS_TAG_OBJECT:
-        if (tag1 != tag2)
-            res = FALSE;
-        else
-            res = JS_VALUE_GET_OBJ(op1) == JS_VALUE_GET_OBJ(op2);
-        break;
-    case JS_TAG_INT:
-        d1 = JS_VALUE_GET_INT(op1);
-        if (tag2 == JS_TAG_INT) {
-            d2 = JS_VALUE_GET_INT(op2);
-            goto number_test;
-        } else if (tag2 == JS_TAG_FLOAT64) {
-            d2 = JS_VALUE_GET_FLOAT64(op2);
-            goto number_test;
-        } else {
-            res = FALSE;
-        }
-        break;
-    case JS_TAG_FLOAT64:
-        d1 = JS_VALUE_GET_FLOAT64(op1);
-        if (tag2 == JS_TAG_FLOAT64) {
-            d2 = JS_VALUE_GET_FLOAT64(op2);
-        } else if (tag2 == JS_TAG_INT) {
-            d2 = JS_VALUE_GET_INT(op2);
-        } else {
-            res = FALSE;
-            break;
-        }
-    number_test:
-        if (unlikely(eq_mode >= JS_EQ_SAME_VALUE)) {
-            JSFloat64Union u1, u2;
-            /* NaN is not always normalized, so this test is necessary */
-            if (isnan(d1) || isnan(d2)) {
-                res = isnan(d1) == isnan(d2);
-            } else if (eq_mode == JS_EQ_SAME_VALUE_ZERO) {
-                res = (d1 == d2); /* +0 == -0 */
-            } else {
-                u1.d = d1;
-                u2.d = d2;
-                res = (u1.u64 == u2.u64); /* +0 != -0 */
-            }
-        } else {
-            res = (d1 == d2); /* if NaN return false and +0 == -0 */
-        }
-        goto done_no_free;
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_INT:
-        {
-            bf_t a_s, *a, b_s, *b;
-            if (tag1 != tag2) {
-                res = FALSE;
-                break;
-            }
-            a = JS_ToBigFloat(ctx, &a_s, op1);
-            b = JS_ToBigFloat(ctx, &b_s, op2);
-            res = bf_cmp_eq(a, b);
-            if (a == &a_s)
-                bf_delete(a);
-            if (b == &b_s)
-                bf_delete(b);
-        }
-        break;
-    case JS_TAG_BIG_FLOAT:
-        {
-            JSBigFloat *p1, *p2;
-            const bf_t *a, *b;
-            if (tag1 != tag2) {
-                res = FALSE;
-                break;
-            }
-            p1 = JS_VALUE_GET_PTR(op1);
-            p2 = JS_VALUE_GET_PTR(op2);
-            a = &p1->num;
-            b = &p2->num;
-            if (unlikely(eq_mode >= JS_EQ_SAME_VALUE)) {
-                if (eq_mode == JS_EQ_SAME_VALUE_ZERO &&
-                           a->expn == BF_EXP_ZERO && b->expn == BF_EXP_ZERO) {
-                    res = TRUE;
-                } else {
-                    res = (bf_cmp_full(a, b) == 0);
-                }
-            } else {
-                res = bf_cmp_eq(a, b);
-            }
-        }
-        break;
-    case JS_TAG_BIG_DECIMAL:
-        {
-            JSBigDecimal *p1, *p2;
-            const bfdec_t *a, *b;
-            if (tag1 != tag2) {
-                res = FALSE;
-                break;
-            }
-            p1 = JS_VALUE_GET_PTR(op1);
-            p2 = JS_VALUE_GET_PTR(op2);
-            a = &p1->num;
-            b = &p2->num;
-            res = bfdec_cmp_eq(a, b);
-        }
-        break;
-#endif
-    default:
-        res = FALSE;
-        break;
-    }
-    JS_FreeValue(ctx, op1);
-    JS_FreeValue(ctx, op2);
- done_no_free:
-    return res;
-}
-
-static BOOL js_strict_eq(JSContext *ctx, JSValue op1, JSValue op2)
-{
-    return js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
-}
-
-static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2)
-{
-    return js_strict_eq2(ctx,
-                         JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),
-                         JS_EQ_SAME_VALUE);
-}
-
-static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2)
-{
-    return js_strict_eq2(ctx,
-                         JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),
-                         JS_EQ_SAME_VALUE_ZERO);
-}
-
-static no_inline int js_strict_eq_slow(JSContext *ctx, JSValue *sp,
-                                       BOOL is_neq)
-{
-    BOOL res;
-    res = js_strict_eq(ctx, sp[-2], sp[-1]);
-    sp[-2] = JS_NewBool(ctx, res ^ is_neq);
-    return 0;
-}
-
-static __exception int js_operator_in(JSContext *ctx, JSValue *sp)
-{
-    JSValue op1, op2;
-    JSAtom atom;
-    int ret;
-
-    op1 = sp[-2];
-    op2 = sp[-1];
-
-    if (JS_VALUE_GET_TAG(op2) != JS_TAG_OBJECT) {
-        JS_ThrowTypeError(ctx, "invalid 'in' operand");
-        return -1;
-    }
-    atom = JS_ValueToAtom(ctx, op1);
-    if (unlikely(atom == JS_ATOM_NULL))
-        return -1;
-    ret = JS_HasProperty(ctx, op2, atom);
-    JS_FreeAtom(ctx, atom);
-    if (ret < 0)
-        return -1;
-    JS_FreeValue(ctx, op1);
-    JS_FreeValue(ctx, op2);
-    sp[-2] = JS_NewBool(ctx, ret);
-    return 0;
-}
-
-static __exception int js_has_unscopable(JSContext *ctx, JSValueConst obj,
-                                         JSAtom atom)
-{
-    JSValue arr, val;
-    int ret;
-
-    arr = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_unscopables);
-    if (JS_IsException(arr))
-        return -1;
-    ret = 0;
-    if (JS_IsObject(arr)) {
-        val = JS_GetProperty(ctx, arr, atom);
-        ret = JS_ToBoolFree(ctx, val);
-    }
-    JS_FreeValue(ctx, arr);
-    return ret;
-}
-
-static __exception int js_operator_instanceof(JSContext *ctx, JSValue *sp)
-{
-    JSValue op1, op2;
-    BOOL ret;
-
-    op1 = sp[-2];
-    op2 = sp[-1];
-    ret = JS_IsInstanceOf(ctx, op1, op2);
-    if (ret < 0)
-        return ret;
-    JS_FreeValue(ctx, op1);
-    JS_FreeValue(ctx, op2);
-    sp[-2] = JS_NewBool(ctx, ret);
-    return 0;
-}
-
-static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1)
-{
-    JSAtom atom;
-    uint32_t tag;
-
-    tag = JS_VALUE_GET_NORM_TAG(op1);
-    switch(tag) {
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_INT:
-        atom = JS_ATOM_bigint;
-        break;
-    case JS_TAG_BIG_FLOAT:
-        atom = JS_ATOM_bigfloat;
-        break;
-    case JS_TAG_BIG_DECIMAL:
-        atom = JS_ATOM_bigdecimal;
-        break;
-#endif
-    case JS_TAG_INT:
-    case JS_TAG_FLOAT64:
-        atom = JS_ATOM_number;
-        break;
-    case JS_TAG_UNDEFINED:
-        atom = JS_ATOM_undefined;
-        break;
-    case JS_TAG_BOOL:
-        atom = JS_ATOM_boolean;
-        break;
-    case JS_TAG_STRING:
-        atom = JS_ATOM_string;
-        break;
-    case JS_TAG_OBJECT:
-        {
-            JSObject *p;
-            p = JS_VALUE_GET_OBJ(op1);
-            if (unlikely(p->is_HTMLDDA)) 
-                atom = JS_ATOM_undefined;
-            else if (JS_IsFunction(ctx, op1))
-                atom = JS_ATOM_function;
-            else
-                goto obj_type;
-        }
-        break;
-    case JS_TAG_NULL:
-    obj_type:
-        atom = JS_ATOM_object;
-        break;
-    case JS_TAG_SYMBOL:
-        atom = JS_ATOM_symbol;
-        break;
-    default:
-        atom = JS_ATOM_unknown;
-        break;
-    }
-    return atom;
-}
-
-static __exception int js_operator_delete(JSContext *ctx, JSValue *sp)
-{
-    JSValue op1, op2;
-    JSAtom atom;
-    int ret;
-
-    op1 = sp[-2];
-    op2 = sp[-1];
-    atom = JS_ValueToAtom(ctx, op2);
-    if (unlikely(atom == JS_ATOM_NULL))
-        return -1;
-    ret = JS_DeleteProperty(ctx, op1, atom, JS_PROP_THROW_STRICT);
-    JS_FreeAtom(ctx, atom);
-    if (unlikely(ret < 0))
-        return -1;
-    JS_FreeValue(ctx, op1);
-    JS_FreeValue(ctx, op2);
-    sp[-2] = JS_NewBool(ctx, ret);
-    return 0;
-}
-
-static JSValue js_throw_type_error(JSContext *ctx, JSValueConst this_val,
-                                   int argc, JSValueConst *argv)
-{
-    return JS_ThrowTypeError(ctx, "invalid property access");
-}
-
-/* XXX: not 100% compatible, but mozilla seems to use a similar
-   implementation to ensure that caller in non strict mode does not
-   throw (ES5 compatibility) */
-static JSValue js_function_proto_caller(JSContext *ctx, JSValueConst this_val,
-                                        int argc, JSValueConst *argv)
-{
-    JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
-    if (!b || (b->js_mode & JS_MODE_STRICT) || !b->has_prototype) {
-        return js_throw_type_error(ctx, this_val, 0, NULL);
-    }
-    return JS_UNDEFINED;
-}
-
-static JSValue js_function_proto_fileName(JSContext *ctx,
-                                          JSValueConst this_val)
-{
-    JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
-    if (b && b->has_debug) {
-        return JS_AtomToString(ctx, b->debug.filename);
-    }
-    return JS_UNDEFINED;
-}
-
-static JSValue js_function_proto_lineNumber(JSContext *ctx,
-                                            JSValueConst this_val)
-{
-    JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
-    if (b && b->has_debug) {
-        return JS_NewInt32(ctx, b->debug.line_num);
-    }
-    return JS_UNDEFINED;
-}
-
-static int js_arguments_define_own_property(JSContext *ctx,
-                                            JSValueConst this_obj,
-                                            JSAtom prop, JSValueConst val,
-                                            JSValueConst getter, JSValueConst setter, int flags)
-{
-    JSObject *p;
-    uint32_t idx;
-    p = JS_VALUE_GET_OBJ(this_obj);
-    /* convert to normal array when redefining an existing numeric field */
-    if (p->fast_array && JS_AtomIsArrayIndex(ctx, &idx, prop) &&
-        idx < p->u.array.count) {
-        if (convert_fast_array_to_array(ctx, p))
-            return -1;
-    }
-    /* run the default define own property */
-    return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter,
-                             flags | JS_PROP_NO_EXOTIC);
-}
-
-static const JSClassExoticMethods js_arguments_exotic_methods = {
-    .define_own_property = js_arguments_define_own_property,
-};
-
-static JSValue js_build_arguments(JSContext *ctx, int argc, JSValueConst *argv)
-{
-    JSValue val, *tab;
-    JSProperty *pr;
-    JSObject *p;
-    int i;
-
-    val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
-                                 JS_CLASS_ARGUMENTS);
-    if (JS_IsException(val))
-        return val;
-    p = JS_VALUE_GET_OBJ(val);
-
-    /* add the length field (cannot fail) */
-    pr = add_property(ctx, p, JS_ATOM_length,
-                      JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-    pr->u.value = JS_NewInt32(ctx, argc);
-
-    /* initialize the fast array part */
-    tab = NULL;
-    if (argc > 0) {
-        tab = js_malloc(ctx, sizeof(tab[0]) * argc);
-        if (!tab) {
-            JS_FreeValue(ctx, val);
-            return JS_EXCEPTION;
-        }
-        for(i = 0; i < argc; i++) {
-            tab[i] = JS_DupValue(ctx, argv[i]);
-        }
-    }
-    p->u.array.u.values = tab;
-    p->u.array.count = argc;
-
-    JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator,
-                           JS_DupValue(ctx, ctx->array_proto_values),
-                           JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
-    /* add callee property to throw a TypeError in strict mode */
-    JS_DefineProperty(ctx, val, JS_ATOM_callee, JS_UNDEFINED,
-                      ctx->throw_type_error, ctx->throw_type_error,
-                      JS_PROP_HAS_GET | JS_PROP_HAS_SET);
-    return val;
-}
-
-#define GLOBAL_VAR_OFFSET 0x40000000
-#define ARGUMENT_VAR_OFFSET 0x20000000
-
-/* legacy arguments object: add references to the function arguments */
-static JSValue js_build_mapped_arguments(JSContext *ctx, int argc,
-                                         JSValueConst *argv,
-                                         JSStackFrame *sf, int arg_count)
-{
-    JSValue val;
-    JSProperty *pr;
-    JSObject *p;
-    int i;
-
-    val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
-                                 JS_CLASS_MAPPED_ARGUMENTS);
-    if (JS_IsException(val))
-        return val;
-    p = JS_VALUE_GET_OBJ(val);
-
-    /* add the length field (cannot fail) */
-    pr = add_property(ctx, p, JS_ATOM_length,
-                      JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-    pr->u.value = JS_NewInt32(ctx, argc);
-
-    for(i = 0; i < arg_count; i++) {
-        JSVarRef *var_ref;
-        var_ref = get_var_ref(ctx, sf, i, TRUE);
-        if (!var_ref)
-            goto fail;
-        pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E | JS_PROP_VARREF);
-        if (!pr) {
-            free_var_ref(ctx->rt, var_ref);
-            goto fail;
-        }
-        pr->u.var_ref = var_ref;
-    }
-
-    /* the arguments not mapped to the arguments of the function can
-       be normal properties */
-    for(i = arg_count; i < argc; i++) {
-        if (JS_DefinePropertyValueUint32(ctx, val, i,
-                                         JS_DupValue(ctx, argv[i]),
-                                         JS_PROP_C_W_E) < 0)
-            goto fail;
-    }
-
-    JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator,
-                           JS_DupValue(ctx, ctx->array_proto_values),
-                           JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
-    /* callee returns this function in non strict mode */
-    JS_DefinePropertyValue(ctx, val, JS_ATOM_callee,
-                           JS_DupValue(ctx, ctx->rt->current_stack_frame->cur_func),
-                           JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
-    return val;
- fail:
-    JS_FreeValue(ctx, val);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_build_rest(JSContext *ctx, int first, int argc, JSValueConst *argv)
-{
-    JSValue val;
-    int i, ret;
-
-    val = JS_NewArray(ctx);
-    if (JS_IsException(val))
-        return val;
-    for (i = first; i < argc; i++) {
-        ret = JS_DefinePropertyValueUint32(ctx, val, i - first,
-                                           JS_DupValue(ctx, argv[i]),
-                                           JS_PROP_C_W_E);
-        if (ret < 0) {
-            JS_FreeValue(ctx, val);
-            return JS_EXCEPTION;
-        }
-    }
-    return val;
-}
-
-static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
-{
-    JSObject *p;
-    JSPropertyEnum *tab_atom;
-    int i;
-    JSValue enum_obj, obj1;
-    JSForInIterator *it;
-    uint32_t tag, tab_atom_count;
-
-    tag = JS_VALUE_GET_TAG(obj);
-    if (tag != JS_TAG_OBJECT && tag != JS_TAG_NULL && tag != JS_TAG_UNDEFINED) {
-        obj = JS_ToObjectFree(ctx, obj);
-    }
-
-    it = js_malloc(ctx, sizeof(*it));
-    if (!it) {
-        JS_FreeValue(ctx, obj);
-        return JS_EXCEPTION;
-    }
-    enum_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_FOR_IN_ITERATOR);
-    if (JS_IsException(enum_obj)) {
-        js_free(ctx, it);
-        JS_FreeValue(ctx, obj);
-        return JS_EXCEPTION;
-    }
-    it->is_array = FALSE;
-    it->obj = obj;
-    it->idx = 0;
-    p = JS_VALUE_GET_OBJ(enum_obj);
-    p->u.for_in_iterator = it;
-
-    if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)
-        return enum_obj;
-
-    /* fast path: assume no enumerable properties in the prototype chain */
-    obj1 = JS_DupValue(ctx, obj);
-    for(;;) {
-        obj1 = JS_GetPrototypeFree(ctx, obj1);
-        if (JS_IsNull(obj1))
-            break;
-        if (JS_IsException(obj1))
-            goto fail;
-        if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
-                                           JS_VALUE_GET_OBJ(obj1),
-                                           JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) {
-            JS_FreeValue(ctx, obj1);
-            goto fail;
-        }
-        js_free_prop_enum(ctx, tab_atom, tab_atom_count);
-        if (tab_atom_count != 0) {
-            JS_FreeValue(ctx, obj1);
-            goto slow_path;
-        }
-        /* must check for timeout to avoid infinite loop */
-        if (js_poll_interrupts(ctx)) {
-            JS_FreeValue(ctx, obj1);
-            goto fail;
-        }
-    }
-
-    p = JS_VALUE_GET_OBJ(obj);
-
-    if (p->fast_array) {
-        JSShape *sh;
-        JSShapeProperty *prs;
-        /* check that there are no enumerable normal fields */
-        sh = p->shape;
-        for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
-            if (prs->flags & JS_PROP_ENUMERABLE)
-                goto normal_case;
-        }
-        /* for fast arrays, we only store the number of elements */
-        it->is_array = TRUE;
-        it->array_length = p->u.array.count;
-    } else {
-    normal_case:
-        if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
-                                   JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY))
-            goto fail;
-        for(i = 0; i < tab_atom_count; i++) {
-            JS_SetPropertyInternal(ctx, enum_obj, tab_atom[i].atom, JS_NULL, 0);
-        }
-        js_free_prop_enum(ctx, tab_atom, tab_atom_count);
-    }
-    return enum_obj;
-
- slow_path:
-    /* non enumerable properties hide the enumerables ones in the
-       prototype chain */
-    obj1 = JS_DupValue(ctx, obj);
-    for(;;) {
-        if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
-                                           JS_VALUE_GET_OBJ(obj1),
-                                           JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
-            JS_FreeValue(ctx, obj1);
-            goto fail;
-        }
-        for(i = 0; i < tab_atom_count; i++) {
-            JS_DefinePropertyValue(ctx, enum_obj, tab_atom[i].atom, JS_NULL,
-                                   (tab_atom[i].is_enumerable ?
-                                    JS_PROP_ENUMERABLE : 0));
-        }
-        js_free_prop_enum(ctx, tab_atom, tab_atom_count);
-        obj1 = JS_GetPrototypeFree(ctx, obj1);
-        if (JS_IsNull(obj1))
-            break;
-        if (JS_IsException(obj1))
-            goto fail;
-        /* must check for timeout to avoid infinite loop */
-        if (js_poll_interrupts(ctx)) {
-            JS_FreeValue(ctx, obj1);
-            goto fail;
-        }
-    }
-    return enum_obj;
-
- fail:
-    JS_FreeValue(ctx, enum_obj);
-    return JS_EXCEPTION;
-}
-
-/* obj -> enum_obj */
-static __exception int js_for_in_start(JSContext *ctx, JSValue *sp)
-{
-    sp[-1] = build_for_in_iterator(ctx, sp[-1]);
-    if (JS_IsException(sp[-1]))
-        return -1;
-    return 0;
-}
-
-/* enum_obj -> enum_obj value done */
-static __exception int js_for_in_next(JSContext *ctx, JSValue *sp)
-{
-    JSValueConst enum_obj;
-    JSObject *p;
-    JSAtom prop;
-    JSForInIterator *it;
-    int ret;
-
-    enum_obj = sp[-1];
-    /* fail safe */
-    if (JS_VALUE_GET_TAG(enum_obj) != JS_TAG_OBJECT)
-        goto done;
-    p = JS_VALUE_GET_OBJ(enum_obj);
-    if (p->class_id != JS_CLASS_FOR_IN_ITERATOR)
-        goto done;
-    it = p->u.for_in_iterator;
-
-    for(;;) {
-        if (it->is_array) {
-            if (it->idx >= it->array_length)
-                goto done;
-            prop = __JS_AtomFromUInt32(it->idx);
-            it->idx++;
-        } else {
-            JSShape *sh = p->shape;
-            JSShapeProperty *prs;
-            if (it->idx >= sh->prop_count)
-                goto done;
-            prs = get_shape_prop(sh) + it->idx;
-            prop = prs->atom;
-            it->idx++;
-            if (prop == JS_ATOM_NULL || !(prs->flags & JS_PROP_ENUMERABLE))
-                continue;
-        }
-        /* check if the property was deleted */
-        ret = JS_HasProperty(ctx, it->obj, prop);
-        if (ret < 0)
-            return ret;
-        if (ret)
-            break;
-    }
-    /* return the property */
-    sp[0] = JS_AtomToValue(ctx, prop);
-    sp[1] = JS_FALSE;
-    return 0;
- done:
-    /* return the end */
-    sp[0] = JS_UNDEFINED;
-    sp[1] = JS_TRUE;
-    return 0;
-}
-
-static JSValue JS_GetIterator2(JSContext *ctx, JSValueConst obj,
-                               JSValueConst method)
-{
-    JSValue enum_obj;
-
-    enum_obj = JS_Call(ctx, method, obj, 0, NULL);
-    if (JS_IsException(enum_obj))
-        return enum_obj;
-    if (!JS_IsObject(enum_obj)) {
-        JS_FreeValue(ctx, enum_obj);
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-    }
-    return enum_obj;
-}
-
-static JSValue JS_GetIterator(JSContext *ctx, JSValueConst obj, BOOL is_async)
-{
-    JSValue method, ret, sync_iter;
-
-    if (is_async) {
-        method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_asyncIterator);
-        if (JS_IsException(method))
-            return method;
-        if (JS_IsUndefined(method) || JS_IsNull(method)) {
-            method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
-            if (JS_IsException(method))
-                return method;
-            sync_iter = JS_GetIterator2(ctx, obj, method);
-            JS_FreeValue(ctx, method);
-            if (JS_IsException(sync_iter))
-                return sync_iter;
-            ret = JS_CreateAsyncFromSyncIterator(ctx, sync_iter);
-            JS_FreeValue(ctx, sync_iter);
-            return ret;
-        }
-    } else {
-        method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
-        if (JS_IsException(method))
-            return method;
-    }
-    if (!JS_IsFunction(ctx, method)) {
-        JS_FreeValue(ctx, method);
-        return JS_ThrowTypeError(ctx, "value is not iterable");
-    }
-    ret = JS_GetIterator2(ctx, obj, method);
-    JS_FreeValue(ctx, method);
-    return ret;
-}
-
-/* return *pdone = 2 if the iterator object is not parsed */
-static JSValue JS_IteratorNext2(JSContext *ctx, JSValueConst enum_obj,
-                                JSValueConst method,
-                                int argc, JSValueConst *argv, int *pdone)
-{
-    JSValue obj;
-
-    /* fast path for the built-in iterators (avoid creating the
-       intermediate result object) */
-    if (JS_IsObject(method)) {
-        JSObject *p = JS_VALUE_GET_OBJ(method);
-        if (p->class_id == JS_CLASS_C_FUNCTION &&
-            p->u.cfunc.cproto == JS_CFUNC_iterator_next) {
-            JSCFunctionType func;
-            JSValueConst args[1];
-
-            /* in case the function expects one argument */
-            if (argc == 0) {
-                args[0] = JS_UNDEFINED;
-                argv = args;
-            }
-            func = p->u.cfunc.c_function;
-            return func.iterator_next(ctx, enum_obj, argc, argv,
-                                      pdone, p->u.cfunc.magic);
-        }
-    }
-    obj = JS_Call(ctx, method, enum_obj, argc, argv);
-    if (JS_IsException(obj))
-        goto fail;
-    if (!JS_IsObject(obj)) {
-        JS_FreeValue(ctx, obj);
-        JS_ThrowTypeError(ctx, "iterator must return an object");
-        goto fail;
-    }
-    *pdone = 2;
-    return obj;
- fail:
-    *pdone = FALSE;
-    return JS_EXCEPTION;
-}
-
-static JSValue JS_IteratorNext(JSContext *ctx, JSValueConst enum_obj,
-                               JSValueConst method,
-                               int argc, JSValueConst *argv, BOOL *pdone)
-{
-    JSValue obj, value, done_val;
-    int done;
-
-    obj = JS_IteratorNext2(ctx, enum_obj, method, argc, argv, &done);
-    if (JS_IsException(obj))
-        goto fail;
-    if (done != 2) {
-        *pdone = done;
-        return obj;
-    } else {
-        done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);
-        if (JS_IsException(done_val))
-            goto fail;
-        *pdone = JS_ToBoolFree(ctx, done_val);
-        value = JS_UNDEFINED;
-        if (!*pdone) {
-            value = JS_GetProperty(ctx, obj, JS_ATOM_value);
-        }
-        JS_FreeValue(ctx, obj);
-        return value;
-    }
- fail:
-    JS_FreeValue(ctx, obj);
-    *pdone = FALSE;
-    return JS_EXCEPTION;
-}
-
-/* return < 0 in case of exception */
-static int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj,
-                            BOOL is_exception_pending)
-{
-    JSValue method, ret, ex_obj;
-    int res;
-
-    if (is_exception_pending) {
-        ex_obj = ctx->rt->current_exception;
-        ctx->rt->current_exception = JS_NULL;
-        res = -1;
-    } else {
-        ex_obj = JS_UNDEFINED;
-        res = 0;
-    }
-    method = JS_GetProperty(ctx, enum_obj, JS_ATOM_return);
-    if (JS_IsException(method)) {
-        res = -1;
-        goto done;
-    }
-    if (JS_IsUndefined(method) || JS_IsNull(method)) {
-        goto done;
-    }
-    ret = JS_CallFree(ctx, method, enum_obj, 0, NULL);
-    if (!is_exception_pending) {
-        if (JS_IsException(ret)) {
-            res = -1;
-        } else if (!JS_IsObject(ret)) {
-            JS_ThrowTypeErrorNotAnObject(ctx);
-            res = -1;
-        }
-    }
-    JS_FreeValue(ctx, ret);
- done:
-    if (is_exception_pending) {
-        JS_Throw(ctx, ex_obj);
-    }
-    return res;
-}
-
-/* obj -> enum_rec (3 slots) */
-static __exception int js_for_of_start(JSContext *ctx, JSValue *sp,
-                                       BOOL is_async)
-{
-    JSValue op1, obj, method;
-    op1 = sp[-1];
-    obj = JS_GetIterator(ctx, op1, is_async);
-    if (JS_IsException(obj))
-        return -1;
-    JS_FreeValue(ctx, op1);
-    sp[-1] = obj;
-    method = JS_GetProperty(ctx, obj, JS_ATOM_next);
-    if (JS_IsException(method))
-        return -1;
-    sp[0] = method;
-    return 0;
-}
-
-/* enum_rec [objs] -> enum_rec [objs] value done. There are 'offset'
-   objs. If 'done' is true or in case of exception, 'enum_rec' is set
-   to undefined. If 'done' is true, 'value' is always set to
-   undefined. */
-static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset)
-{
-    JSValue value = JS_UNDEFINED;
-    int done = 1;
-
-    if (likely(!JS_IsUndefined(sp[offset]))) {
-        value = JS_IteratorNext(ctx, sp[offset], sp[offset + 1], 0, NULL, &done);
-        if (JS_IsException(value))
-            done = -1;
-        if (done) {
-            /* value is JS_UNDEFINED or JS_EXCEPTION */
-            /* replace the iteration object with undefined */
-            JS_FreeValue(ctx, sp[offset]);
-            sp[offset] = JS_UNDEFINED;
-            if (done < 0) {
-                return -1;
-            } else {
-                JS_FreeValue(ctx, value);
-                value = JS_UNDEFINED;
-            }
-        }
-    }
-    sp[0] = value;
-    sp[1] = JS_NewBool(ctx, done);
-    return 0;
-}
-
-static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValueConst obj,
-                                           BOOL *pdone)
-{
-    JSValue done_val, value;
-    BOOL done;
-    done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);
-    if (JS_IsException(done_val))
-        goto fail;
-    done = JS_ToBoolFree(ctx, done_val);
-    value = JS_GetProperty(ctx, obj, JS_ATOM_value);
-    if (JS_IsException(value))
-        goto fail;
-    *pdone = done;
-    return value;
- fail:
-    *pdone = FALSE;
-    return JS_EXCEPTION;
-}
-
-static __exception int js_iterator_get_value_done(JSContext *ctx, JSValue *sp)
-{
-    JSValue obj, value;
-    BOOL done;
-    obj = sp[-1];
-    if (!JS_IsObject(obj)) {
-        JS_ThrowTypeError(ctx, "iterator must return an object");
-        return -1;
-    }
-    value = JS_IteratorGetCompleteValue(ctx, obj, &done);
-    if (JS_IsException(value))
-        return -1;
-    JS_FreeValue(ctx, obj);
-    sp[-1] = value;
-    sp[0] = JS_NewBool(ctx, done);
-    return 0;
-}
-
-static JSValue js_create_iterator_result(JSContext *ctx,
-                                         JSValue val,
-                                         BOOL done)
-{
-    JSValue obj;
-    obj = JS_NewObject(ctx);
-    if (JS_IsException(obj)) {
-        JS_FreeValue(ctx, val);
-        return obj;
-    }
-    if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_value,
-                               val, JS_PROP_C_W_E) < 0) {
-        goto fail;
-    }
-    if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_done,
-                               JS_NewBool(ctx, done), JS_PROP_C_W_E) < 0) {
-    fail:
-        JS_FreeValue(ctx, obj);
-        return JS_EXCEPTION;
-    }
-    return obj;
-}
-
-static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val,
-                                      int argc, JSValueConst *argv,
-                                      BOOL *pdone, int magic);
-
-static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val,
-                                        int argc, JSValueConst *argv, int magic);
-
-static BOOL js_is_fast_array(JSContext *ctx, JSValueConst obj)
-{
-    /* Try and handle fast arrays explicitly */
-    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
-        JSObject *p = JS_VALUE_GET_OBJ(obj);
-        if (p->class_id == JS_CLASS_ARRAY && p->fast_array) {
-            return TRUE;
-        }
-    }
-    return FALSE;
-}
-
-/* Access an Array's internal JSValue array if available */
-static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj,
-                              JSValue **arrpp, uint32_t *countp)
-{
-    /* Try and handle fast arrays explicitly */
-    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
-        JSObject *p = JS_VALUE_GET_OBJ(obj);
-        if (p->class_id == JS_CLASS_ARRAY && p->fast_array) {
-            *countp = p->u.array.count;
-            *arrpp = p->u.array.u.values;
-            return TRUE;
-        }
-    }
-    return FALSE;
-}
-
-static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp)
-{
-    JSValue iterator, enumobj, method, value;
-    int is_array_iterator;
-    JSValue *arrp;
-    uint32_t i, count32, pos;
-    
-    if (JS_VALUE_GET_TAG(sp[-2]) != JS_TAG_INT) {
-        JS_ThrowInternalError(ctx, "invalid index for append");
-        return -1;
-    }
-
-    pos = JS_VALUE_GET_INT(sp[-2]);
-
-    /* XXX: further optimisations:
-       - use ctx->array_proto_values?
-       - check if array_iterator_prototype next method is built-in and
-         avoid constructing actual iterator object?
-       - build this into js_for_of_start and use in all `for (x of o)` loops
-     */
-    iterator = JS_GetProperty(ctx, sp[-1], JS_ATOM_Symbol_iterator);
-    if (JS_IsException(iterator))
-        return -1;
-    is_array_iterator = JS_IsCFunction(ctx, iterator,
-                                       (JSCFunction *)js_create_array_iterator,
-                                       JS_ITERATOR_KIND_VALUE);
-    JS_FreeValue(ctx, iterator);
-
-    enumobj = JS_GetIterator(ctx, sp[-1], FALSE);
-    if (JS_IsException(enumobj))
-        return -1;
-    method = JS_GetProperty(ctx, enumobj, JS_ATOM_next);
-    if (JS_IsException(method)) {
-        JS_FreeValue(ctx, enumobj);
-        return -1;
-    }
-    if (is_array_iterator
-    &&  JS_IsCFunction(ctx, method, (JSCFunction *)js_array_iterator_next, 0)
-    &&  js_get_fast_array(ctx, sp[-1], &arrp, &count32)) {
-        uint32_t len;
-        if (js_get_length32(ctx, &len, sp[-1]))
-            goto exception;
-        /* if len > count32, the elements >= count32 might be read in
-           the prototypes and might have side effects */
-        if (len != count32)
-            goto general_case;
-        /* Handle fast arrays explicitly */
-        for (i = 0; i < count32; i++) {
-            if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++,
-                                             JS_DupValue(ctx, arrp[i]), JS_PROP_C_W_E) < 0)
-                goto exception;
-        }
-    } else {
-    general_case:
-        for (;;) {
-            BOOL done;
-            value = JS_IteratorNext(ctx, enumobj, method, 0, NULL, &done);
-            if (JS_IsException(value))
-                goto exception;
-            if (done) {
-                /* value is JS_UNDEFINED */
-                break;
-            }
-            if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, value, JS_PROP_C_W_E) < 0)
-                goto exception;
-        }
-    }
-    /* Note: could raise an error if too many elements */
-    sp[-2] = JS_NewInt32(ctx, pos);
-    JS_FreeValue(ctx, enumobj);
-    JS_FreeValue(ctx, method);
-    return 0;
-
-exception:
-    JS_IteratorClose(ctx, enumobj, TRUE);
-    JS_FreeValue(ctx, enumobj);
-    JS_FreeValue(ctx, method);
-    return -1;
-}
-
-static __exception int JS_CopyDataProperties(JSContext *ctx,
-                                             JSValueConst target,
-                                             JSValueConst source,
-                                             JSValueConst excluded,
-                                             BOOL setprop)
-{
-    JSPropertyEnum *tab_atom;
-    JSValue val;
-    uint32_t i, tab_atom_count;
-    JSObject *p;
-    JSObject *pexcl = NULL;
-    int ret, gpn_flags;
-    JSPropertyDescriptor desc;
-    BOOL is_enumerable;
-    
-    if (JS_VALUE_GET_TAG(source) != JS_TAG_OBJECT)
-        return 0;
-
-    if (JS_VALUE_GET_TAG(excluded) == JS_TAG_OBJECT)
-        pexcl = JS_VALUE_GET_OBJ(excluded);
-
-    p = JS_VALUE_GET_OBJ(source);
-
-    gpn_flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK | JS_GPN_ENUM_ONLY;
-    if (p->is_exotic) {
-        const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
-        /* cannot use JS_GPN_ENUM_ONLY with e.g. proxies because it
-           introduces a visible change */
-        if (em && em->get_own_property_names) {
-            gpn_flags &= ~JS_GPN_ENUM_ONLY;
-        }
-    }
-    if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
-                                       gpn_flags))
-        return -1;
-    
-    for (i = 0; i < tab_atom_count; i++) {
-        if (pexcl) {
-            ret = JS_GetOwnPropertyInternal(ctx, NULL, pexcl, tab_atom[i].atom);
-            if (ret) {
-                if (ret < 0)
-                    goto exception;
-                continue;
-            }
-        }
-        if (!(gpn_flags & JS_GPN_ENUM_ONLY)) {
-            /* test if the property is enumerable */
-            ret = JS_GetOwnPropertyInternal(ctx, &desc, p, tab_atom[i].atom);
-            if (ret < 0)
-                goto exception;
-            if (!ret)
-                continue;
-            is_enumerable = (desc.flags & JS_PROP_ENUMERABLE) != 0;
-            js_free_desc(ctx, &desc);
-            if (!is_enumerable)
-                continue;
-        }
-        val = JS_GetProperty(ctx, source, tab_atom[i].atom);
-        if (JS_IsException(val))
-            goto exception;
-        if (setprop)
-            ret = JS_SetProperty(ctx, target, tab_atom[i].atom, val);
-        else
-            ret = JS_DefinePropertyValue(ctx, target, tab_atom[i].atom, val,
-                                         JS_PROP_C_W_E);
-        if (ret < 0)
-            goto exception;
-    }
-    js_free_prop_enum(ctx, tab_atom, tab_atom_count);
-    return 0;
- exception:
-    js_free_prop_enum(ctx, tab_atom, tab_atom_count);
-    return -1;
-}
-
-/* only valid inside C functions */
-static JSValueConst JS_GetActiveFunction(JSContext *ctx)
-{
-    return ctx->rt->current_stack_frame->cur_func;
-}
-
-static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf,
-                             int var_idx, BOOL is_arg)
-{
-    JSVarRef *var_ref;
-    struct list_head *el;
-
-    list_for_each(el, &sf->var_ref_list) {
-        var_ref = list_entry(el, JSVarRef, header.link);
-        if (var_ref->var_idx == var_idx && var_ref->is_arg == is_arg) {
-            var_ref->header.ref_count++;
-            return var_ref;
-        }
-    }
-    /* create a new one */
-    var_ref = js_malloc(ctx, sizeof(JSVarRef));
-    if (!var_ref)
-        return NULL;
-    var_ref->header.ref_count = 1;
-    var_ref->is_detached = FALSE;
-    var_ref->is_arg = is_arg;
-    var_ref->var_idx = var_idx;
-    list_add_tail(&var_ref->header.link, &sf->var_ref_list);
-    if (is_arg)
-        var_ref->pvalue = &sf->arg_buf[var_idx];
-    else
-        var_ref->pvalue = &sf->var_buf[var_idx];
-    var_ref->value = JS_UNDEFINED;
-    return var_ref;
-}
-
-static JSValue js_closure2(JSContext *ctx, JSValue func_obj,
-                           JSFunctionBytecode *b,
-                           JSVarRef **cur_var_refs,
-                           JSStackFrame *sf)
-{
-    JSObject *p;
-    JSVarRef **var_refs;
-    int i;
-
-    p = JS_VALUE_GET_OBJ(func_obj);
-    p->u.func.function_bytecode = b;
-    p->u.func.home_object = NULL;
-    p->u.func.var_refs = NULL;
-    if (b->closure_var_count) {
-        var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count);
-        if (!var_refs)
-            goto fail;
-        p->u.func.var_refs = var_refs;
-        for(i = 0; i < b->closure_var_count; i++) {
-            JSClosureVar *cv = &b->closure_var[i];
-            JSVarRef *var_ref;
-            if (cv->is_local) {
-                /* reuse the existing variable reference if it already exists */
-                var_ref = get_var_ref(ctx, sf, cv->var_idx, cv->is_arg);
-                if (!var_ref)
-                    goto fail;
-            } else {
-                var_ref = cur_var_refs[cv->var_idx];
-                var_ref->header.ref_count++;
-            }
-            var_refs[i] = var_ref;
-        }
-    }
-    return func_obj;
- fail:
-    /* bfunc is freed when func_obj is freed */
-    JS_FreeValue(ctx, func_obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque)
-{
-    JSValue obj, this_val;
-    int ret;
-
-    this_val = JS_MKPTR(JS_TAG_OBJECT, p);
-    obj = JS_NewObject(ctx);
-    if (JS_IsException(obj))
-        return JS_EXCEPTION;
-    set_cycle_flag(ctx, obj);
-    set_cycle_flag(ctx, this_val);
-    ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_constructor,
-                                 JS_DupValue(ctx, this_val),
-                                 JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-    if (ret < 0) {
-        JS_FreeValue(ctx, obj);
-        return JS_EXCEPTION;
-    }
-    return obj;
-}
-
-static const uint16_t func_kind_to_class_id[] = {
-    [JS_FUNC_NORMAL] = JS_CLASS_BYTECODE_FUNCTION,
-    [JS_FUNC_GENERATOR] = JS_CLASS_GENERATOR_FUNCTION,
-    [JS_FUNC_ASYNC] = JS_CLASS_ASYNC_FUNCTION,
-    [JS_FUNC_ASYNC_GENERATOR] = JS_CLASS_ASYNC_GENERATOR_FUNCTION,
-};
-
-static JSValue js_closure(JSContext *ctx, JSValue bfunc,
-                          JSVarRef **cur_var_refs,
-                          JSStackFrame *sf)
-{
-    JSFunctionBytecode *b;
-    JSValue func_obj;
-    JSAtom name_atom;
-
-    b = JS_VALUE_GET_PTR(bfunc);
-    func_obj = JS_NewObjectClass(ctx, func_kind_to_class_id[b->func_kind]);
-    if (JS_IsException(func_obj)) {
-        JS_FreeValue(ctx, bfunc);
-        return JS_EXCEPTION;
-    }
-    func_obj = js_closure2(ctx, func_obj, b, cur_var_refs, sf);
-    if (JS_IsException(func_obj)) {
-        /* bfunc has been freed */
-        goto fail;
-    }
-    name_atom = b->func_name;
-    if (name_atom == JS_ATOM_NULL)
-        name_atom = JS_ATOM_empty_string;
-    js_function_set_properties(ctx, func_obj, name_atom,
-                               b->defined_arg_count);
-
-    if (b->func_kind & JS_FUNC_GENERATOR) {
-        JSValue proto;
-        int proto_class_id;
-        /* generators have a prototype field which is used as
-           prototype for the generator object */
-        if (b->func_kind == JS_FUNC_ASYNC_GENERATOR)
-            proto_class_id = JS_CLASS_ASYNC_GENERATOR;
-        else
-            proto_class_id = JS_CLASS_GENERATOR;
-        proto = JS_NewObjectProto(ctx, ctx->class_proto[proto_class_id]);
-        if (JS_IsException(proto))
-            goto fail;
-        JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype, proto,
-                               JS_PROP_WRITABLE);
-    } else if (b->has_prototype) {
-        /* add the 'prototype' property: delay instantiation to avoid
-           creating cycles for every javascript function. The prototype
-           object is created on the fly when first accessed */
-        JS_SetConstructorBit(ctx, func_obj, TRUE);
-        JS_DefineAutoInitProperty(ctx, func_obj, JS_ATOM_prototype,
-                                  JS_AUTOINIT_ID_PROTOTYPE, NULL,
-                                  JS_PROP_WRITABLE);
-    }
-    return func_obj;
- fail:
-    /* bfunc is freed when func_obj is freed */
-    JS_FreeValue(ctx, func_obj);
-    return JS_EXCEPTION;
-}
-
-#define JS_DEFINE_CLASS_HAS_HERITAGE     (1 << 0)
-
-static int js_op_define_class(JSContext *ctx, JSValue *sp,
-                              JSAtom class_name, int class_flags,
-                              JSVarRef **cur_var_refs,
-                              JSStackFrame *sf, BOOL is_computed_name)
-{
-    JSValue bfunc, parent_class, proto = JS_UNDEFINED;
-    JSValue ctor = JS_UNDEFINED, parent_proto = JS_UNDEFINED;
-    JSFunctionBytecode *b;
-
-    parent_class = sp[-2];
-    bfunc = sp[-1];
-
-    if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE) {
-        if (JS_IsNull(parent_class)) {
-            parent_proto = JS_NULL;
-            parent_class = JS_DupValue(ctx, ctx->function_proto);
-        } else {
-            if (!JS_IsConstructor(ctx, parent_class)) {
-                JS_ThrowTypeError(ctx, "parent class must be constructor");
-                goto fail;
-            }
-            parent_proto = JS_GetProperty(ctx, parent_class, JS_ATOM_prototype);
-            if (JS_IsException(parent_proto))
-                goto fail;
-            if (!JS_IsNull(parent_proto) && !JS_IsObject(parent_proto)) {
-                JS_ThrowTypeError(ctx, "parent prototype must be an object or null");
-                goto fail;
-            }
-        }
-    } else {
-        /* parent_class is JS_UNDEFINED in this case */
-        parent_proto = JS_DupValue(ctx, ctx->class_proto[JS_CLASS_OBJECT]);
-        parent_class = JS_DupValue(ctx, ctx->function_proto);
-    }
-    proto = JS_NewObjectProto(ctx, parent_proto);
-    if (JS_IsException(proto))
-        goto fail;
-
-    b = JS_VALUE_GET_PTR(bfunc);
-    assert(b->func_kind == JS_FUNC_NORMAL);
-    ctor = JS_NewObjectProtoClass(ctx, parent_class,
-                                  JS_CLASS_BYTECODE_FUNCTION);
-    if (JS_IsException(ctor))
-        goto fail;
-    ctor = js_closure2(ctx, ctor, b, cur_var_refs, sf);
-    bfunc = JS_UNDEFINED;
-    if (JS_IsException(ctor))
-        goto fail;
-    js_method_set_home_object(ctx, ctor, proto);
-    JS_SetConstructorBit(ctx, ctor, TRUE);
-
-    JS_DefinePropertyValue(ctx, ctor, JS_ATOM_length,
-                           JS_NewInt32(ctx, b->defined_arg_count),
-                           JS_PROP_CONFIGURABLE);
-
-    if (is_computed_name) {
-        if (JS_DefineObjectNameComputed(ctx, ctor, sp[-3],
-                                        JS_PROP_CONFIGURABLE) < 0)
-            goto fail;
-    } else {
-        if (JS_DefineObjectName(ctx, ctor, class_name, JS_PROP_CONFIGURABLE) < 0)
-            goto fail;
-    }
-
-    /* the constructor property must be first. It can be overriden by
-       computed property names */
-    if (JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor,
-                               JS_DupValue(ctx, ctor),
-                               JS_PROP_CONFIGURABLE |
-                               JS_PROP_WRITABLE | JS_PROP_THROW) < 0)
-        goto fail;
-    /* set the prototype property */
-    if (JS_DefinePropertyValue(ctx, ctor, JS_ATOM_prototype,
-                               JS_DupValue(ctx, proto), JS_PROP_THROW) < 0)
-        goto fail;
-    set_cycle_flag(ctx, ctor);
-    set_cycle_flag(ctx, proto);
-
-    JS_FreeValue(ctx, parent_proto);
-    JS_FreeValue(ctx, parent_class);
-
-    sp[-2] = ctor;
-    sp[-1] = proto;
-    return 0;
- fail:
-    JS_FreeValue(ctx, parent_class);
-    JS_FreeValue(ctx, parent_proto);
-    JS_FreeValue(ctx, bfunc);
-    JS_FreeValue(ctx, proto);
-    JS_FreeValue(ctx, ctor);
-    sp[-2] = JS_UNDEFINED;
-    sp[-1] = JS_UNDEFINED;
-    return -1;
-}
-
-static void close_var_refs(JSRuntime *rt, JSStackFrame *sf)
-{
-    struct list_head *el, *el1;
-    JSVarRef *var_ref;
-    int var_idx;
-
-    list_for_each_safe(el, el1, &sf->var_ref_list) {
-        var_ref = list_entry(el, JSVarRef, header.link);
-        var_idx = var_ref->var_idx;
-        if (var_ref->is_arg)
-            var_ref->value = JS_DupValueRT(rt, sf->arg_buf[var_idx]);
-        else
-            var_ref->value = JS_DupValueRT(rt, sf->var_buf[var_idx]);
-        var_ref->pvalue = &var_ref->value;
-        /* the reference is no longer to a local variable */
-        var_ref->is_detached = TRUE;
-        add_gc_object(rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
-    }
-}
-
-static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int idx, int is_arg)
-{
-    struct list_head *el, *el1;
-    JSVarRef *var_ref;
-    int var_idx = idx;
-
-    list_for_each_safe(el, el1, &sf->var_ref_list) {
-        var_ref = list_entry(el, JSVarRef, header.link);
-        if (var_idx == var_ref->var_idx && var_ref->is_arg == is_arg) {
-            var_ref->value = JS_DupValue(ctx, sf->var_buf[var_idx]);
-            var_ref->pvalue = &var_ref->value;
-            list_del(&var_ref->header.link);
-            /* the reference is no longer to a local variable */
-            var_ref->is_detached = TRUE;
-            add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
-        }
-    }
-}
-
-#define JS_CALL_FLAG_COPY_ARGV   (1 << 1)
-#define JS_CALL_FLAG_GENERATOR   (1 << 2)
-
-static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
-                                  JSValueConst this_obj,
-                                  int argc, JSValueConst *argv, int flags)
-{
-    JSRuntime *rt = ctx->rt;
-    JSCFunctionType func;
-    JSObject *p;
-    JSStackFrame sf_s, *sf = &sf_s, *prev_sf;
-    JSValue ret_val;
-    JSValueConst *arg_buf;
-    int arg_count, i;
-    JSCFunctionEnum cproto;
-
-    p = JS_VALUE_GET_OBJ(func_obj);
-    cproto = p->u.cfunc.cproto;
-    arg_count = p->u.cfunc.length;
-
-    /* better to always check stack overflow */
-    if (js_check_stack_overflow(rt, sizeof(arg_buf[0]) * arg_count))
-        return JS_ThrowStackOverflow(ctx);
-
-    prev_sf = rt->current_stack_frame;
-    sf->prev_frame = prev_sf;
-    rt->current_stack_frame = sf;
-    ctx = p->u.cfunc.realm; /* change the current realm */
-    
-#ifdef CONFIG_BIGNUM
-    /* we only propagate the bignum mode as some runtime functions
-       test it */
-    if (prev_sf)
-        sf->js_mode = prev_sf->js_mode & JS_MODE_MATH;
-    else
-        sf->js_mode = 0;
-#else
-    sf->js_mode = 0;
-#endif
-    sf->cur_func = (JSValue)func_obj;
-    sf->arg_count = argc;
-    arg_buf = argv;
-
-    if (unlikely(argc < arg_count)) {
-        /* ensure that at least argc_count arguments are readable */
-        arg_buf = alloca(sizeof(arg_buf[0]) * arg_count);
-        for(i = 0; i < argc; i++)
-            arg_buf[i] = argv[i];
-        for(i = argc; i < arg_count; i++)
-            arg_buf[i] = JS_UNDEFINED;
-        sf->arg_count = arg_count;
-    }
-    sf->arg_buf = (JSValue*)arg_buf;
-
-    func = p->u.cfunc.c_function;
-    switch(cproto) {
-    case JS_CFUNC_constructor:
-    case JS_CFUNC_constructor_or_func:
-        if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) {
-            if (cproto == JS_CFUNC_constructor) {
-            not_a_constructor:
-                ret_val = JS_ThrowTypeError(ctx, "must be called with new");
-                break;
-            } else {
-                this_obj = JS_UNDEFINED;
-            }
-        }
-        /* here this_obj is new_target */
-        /* fall thru */
-    case JS_CFUNC_generic:
-        ret_val = func.generic(ctx, this_obj, argc, arg_buf);
-        break;
-    case JS_CFUNC_constructor_magic:
-    case JS_CFUNC_constructor_or_func_magic:
-        if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) {
-            if (cproto == JS_CFUNC_constructor_magic) {
-                goto not_a_constructor;
-            } else {
-                this_obj = JS_UNDEFINED;
-            }
-        }
-        /* fall thru */
-    case JS_CFUNC_generic_magic:
-        ret_val = func.generic_magic(ctx, this_obj, argc, arg_buf,
-                                     p->u.cfunc.magic);
-        break;
-    case JS_CFUNC_getter:
-        ret_val = func.getter(ctx, this_obj);
-        break;
-    case JS_CFUNC_setter:
-        ret_val = func.setter(ctx, this_obj, arg_buf[0]);
-        break;
-    case JS_CFUNC_getter_magic:
-        ret_val = func.getter_magic(ctx, this_obj, p->u.cfunc.magic);
-        break;
-    case JS_CFUNC_setter_magic:
-        ret_val = func.setter_magic(ctx, this_obj, arg_buf[0], p->u.cfunc.magic);
-        break;
-    case JS_CFUNC_f_f:
-        {
-            double d1;
-
-            if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) {
-                ret_val = JS_EXCEPTION;
-                break;
-            }
-            ret_val = JS_NewFloat64(ctx, func.f_f(d1));
-        }
-        break;
-    case JS_CFUNC_f_f_f:
-        {
-            double d1, d2;
-
-            if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) {
-                ret_val = JS_EXCEPTION;
-                break;
-            }
-            if (unlikely(JS_ToFloat64(ctx, &d2, arg_buf[1]))) {
-                ret_val = JS_EXCEPTION;
-                break;
-            }
-            ret_val = JS_NewFloat64(ctx, func.f_f_f(d1, d2));
-        }
-        break;
-    case JS_CFUNC_iterator_next:
-        {
-            int done;
-            ret_val = func.iterator_next(ctx, this_obj, argc, arg_buf,
-                                         &done, p->u.cfunc.magic);
-            if (!JS_IsException(ret_val) && done != 2) {
-                ret_val = js_create_iterator_result(ctx, ret_val, done);
-            }
-        }
-        break;
-    default:
-        abort();
-    }
-
-    rt->current_stack_frame = sf->prev_frame;
-    return ret_val;
-}
-
-static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj,
-                                      JSValueConst this_obj,
-                                      int argc, JSValueConst *argv, int flags)
-{
-    JSObject *p;
-    JSBoundFunction *bf;
-    JSValueConst *arg_buf, new_target;
-    int arg_count, i;
-
-    p = JS_VALUE_GET_OBJ(func_obj);
-    bf = p->u.bound_function;
-    arg_count = bf->argc + argc;
-    if (js_check_stack_overflow(ctx->rt, sizeof(JSValue) * arg_count))
-        return JS_ThrowStackOverflow(ctx);
-    arg_buf = alloca(sizeof(JSValue) * arg_count);
-    for(i = 0; i < bf->argc; i++) {
-        arg_buf[i] = bf->argv[i];
-    }
-    for(i = 0; i < argc; i++) {
-        arg_buf[bf->argc + i] = argv[i];
-    }
-    if (flags & JS_CALL_FLAG_CONSTRUCTOR) {
-        new_target = this_obj;
-        if (js_same_value(ctx, func_obj, new_target))
-            new_target = bf->func_obj;
-        return JS_CallConstructor2(ctx, bf->func_obj, new_target,
-                                   arg_count, arg_buf);
-    } else {
-        return JS_Call(ctx, bf->func_obj, bf->this_val,
-                       arg_count, arg_buf);
-    }
-}
-
-/* argument of OP_special_object */
-typedef enum {
-    OP_SPECIAL_OBJECT_ARGUMENTS,
-    OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS,
-    OP_SPECIAL_OBJECT_THIS_FUNC,
-    OP_SPECIAL_OBJECT_NEW_TARGET,
-    OP_SPECIAL_OBJECT_HOME_OBJECT,
-    OP_SPECIAL_OBJECT_VAR_OBJECT,
-    OP_SPECIAL_OBJECT_IMPORT_META,
-} OPSpecialObjectEnum;
-
-#define FUNC_RET_AWAIT      0
-#define FUNC_RET_YIELD      1
-#define FUNC_RET_YIELD_STAR 2
-
-/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */
-static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
-                               JSValueConst this_obj, JSValueConst new_target,
-                               int argc, JSValue *argv, int flags)
-{
-    JSRuntime *rt = caller_ctx->rt;
-    JSContext *ctx;
-    JSObject *p;
-    JSFunctionBytecode *b;
-    JSStackFrame sf_s, *sf = &sf_s;
-    const uint8_t *pc;
-    int opcode, arg_allocated_size, i;
-    JSValue *local_buf, *stack_buf, *var_buf, *arg_buf, *sp, ret_val, *pval;
-    JSVarRef **var_refs;
-    size_t alloca_size;
-
-#if !DIRECT_DISPATCH
-#define SWITCH(pc)      switch (opcode = *pc++)
-#define CASE(op)        case op
-#define DEFAULT         default
-#define BREAK           break
-#else
-    static const void * const dispatch_table[256] = {
-#define DEF(id, size, n_pop, n_push, f) && case_OP_ ## id,
-#if SHORT_OPCODES
-#define def(id, size, n_pop, n_push, f)
-#else                                                     
-#define def(id, size, n_pop, n_push, f) && case_default,
-#endif
-#include "quickjs-opcode.h"
-        [ OP_COUNT ... 255 ] = &&case_default
-    };
-#define SWITCH(pc)      goto *dispatch_table[opcode = *pc++];
-#define CASE(op)        case_ ## op
-#define DEFAULT         case_default
-#define BREAK           SWITCH(pc)
-#endif
-
-    if (js_poll_interrupts(caller_ctx))
-        return JS_EXCEPTION;
-    if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)) {
-        if (flags & JS_CALL_FLAG_GENERATOR) {
-            JSAsyncFunctionState *s = JS_VALUE_GET_PTR(func_obj);
-            /* func_obj get contains a pointer to JSFuncAsyncState */
-            /* the stack frame is already allocated */
-            sf = &s->frame;
-            p = JS_VALUE_GET_OBJ(sf->cur_func);
-            b = p->u.func.function_bytecode;
-            ctx = b->realm;
-            var_refs = p->u.func.var_refs;
-            local_buf = arg_buf = sf->arg_buf;
-            var_buf = sf->var_buf;
-            stack_buf = sf->var_buf + b->var_count;
-            sp = sf->cur_sp;
-            sf->cur_sp = NULL; /* cur_sp is NULL if the function is running */
-            pc = sf->cur_pc;
-            sf->prev_frame = rt->current_stack_frame;
-            rt->current_stack_frame = sf;
-            if (s->throw_flag)
-                goto exception;
-            else
-                goto restart;
-        } else {
-            goto not_a_function;
-        }
-    }
-    p = JS_VALUE_GET_OBJ(func_obj);
-    if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {
-        JSClassCall *call_func;
-        call_func = rt->class_array[p->class_id].call;
-        if (!call_func) {
-        not_a_function:
-            return JS_ThrowTypeError(caller_ctx, "not a function");
-        }
-        return call_func(caller_ctx, func_obj, this_obj, argc,
-                         (JSValueConst *)argv, flags);
-    }
-    b = p->u.func.function_bytecode;
-
-    if (unlikely(argc < b->arg_count || (flags & JS_CALL_FLAG_COPY_ARGV))) {
-        arg_allocated_size = b->arg_count;
-    } else {
-        arg_allocated_size = 0;
-    }
-
-    alloca_size = sizeof(JSValue) * (arg_allocated_size + b->var_count +
-                                     b->stack_size);
-    if (js_check_stack_overflow(rt, alloca_size))
-        return JS_ThrowStackOverflow(caller_ctx);
-
-    sf->js_mode = b->js_mode;
-    arg_buf = argv;
-    sf->arg_count = argc;
-    sf->cur_func = (JSValue)func_obj;
-    init_list_head(&sf->var_ref_list);
-    var_refs = p->u.func.var_refs;
-
-    local_buf = alloca(alloca_size);
-    if (unlikely(arg_allocated_size)) {
-        int n = min_int(argc, b->arg_count);
-        arg_buf = local_buf;
-        for(i = 0; i < n; i++)
-            arg_buf[i] = JS_DupValue(caller_ctx, argv[i]);
-        for(; i < b->arg_count; i++)
-            arg_buf[i] = JS_UNDEFINED;
-        sf->arg_count = b->arg_count;
-    }
-    var_buf = local_buf + arg_allocated_size;
-    sf->var_buf = var_buf;
-    sf->arg_buf = arg_buf;
-
-    for(i = 0; i < b->var_count; i++)
-        var_buf[i] = JS_UNDEFINED;
-
-    stack_buf = var_buf + b->var_count;
-    sp = stack_buf;
-    pc = b->byte_code_buf;
-    sf->prev_frame = rt->current_stack_frame;
-    rt->current_stack_frame = sf;
-    ctx = b->realm; /* set the current realm */
-    
- restart:
-    for(;;) {
-        int call_argc;
-        JSValue *call_argv;
-
-        SWITCH(pc) {
-        CASE(OP_push_i32):
-            *sp++ = JS_NewInt32(ctx, get_u32(pc));
-            pc += 4;
-            BREAK;
-        CASE(OP_push_const):
-            *sp++ = JS_DupValue(ctx, b->cpool[get_u32(pc)]);
-            pc += 4;
-            BREAK;
-#if SHORT_OPCODES
-        CASE(OP_push_minus1):
-        CASE(OP_push_0):
-        CASE(OP_push_1):
-        CASE(OP_push_2):
-        CASE(OP_push_3):
-        CASE(OP_push_4):
-        CASE(OP_push_5):
-        CASE(OP_push_6):
-        CASE(OP_push_7):
-            *sp++ = JS_NewInt32(ctx, opcode - OP_push_0);
-            BREAK;
-        CASE(OP_push_i8):
-            *sp++ = JS_NewInt32(ctx, get_i8(pc));
-            pc += 1;
-            BREAK;
-        CASE(OP_push_i16):
-            *sp++ = JS_NewInt32(ctx, get_i16(pc));
-            pc += 2;
-            BREAK;
-        CASE(OP_push_const8):
-            *sp++ = JS_DupValue(ctx, b->cpool[*pc++]);
-            BREAK;
-        CASE(OP_fclosure8):
-            *sp++ = js_closure(ctx, JS_DupValue(ctx, b->cpool[*pc++]), var_refs, sf);
-            if (unlikely(JS_IsException(sp[-1])))
-                goto exception;
-            BREAK;
-        CASE(OP_push_empty_string):
-            *sp++ = JS_AtomToString(ctx, JS_ATOM_empty_string);
-            BREAK;
-        CASE(OP_get_length):
-            {
-                JSValue val;
-
-                val = JS_GetProperty(ctx, sp[-1], JS_ATOM_length);
-                if (unlikely(JS_IsException(val)))
-                    goto exception;
-                JS_FreeValue(ctx, sp[-1]);
-                sp[-1] = val;
-            }
-            BREAK;
-#endif
-        CASE(OP_push_atom_value):
-            *sp++ = JS_AtomToValue(ctx, get_u32(pc));
-            pc += 4;
-            BREAK;
-        CASE(OP_undefined):
-            *sp++ = JS_UNDEFINED;
-            BREAK;
-        CASE(OP_null):
-            *sp++ = JS_NULL;
-            BREAK;
-        CASE(OP_push_this):
-            /* OP_push_this is only called at the start of a function */
-            {
-                JSValue val;
-                if (!(b->js_mode & JS_MODE_STRICT)) {
-                    uint32_t tag = JS_VALUE_GET_TAG(this_obj);
-                    if (likely(tag == JS_TAG_OBJECT))
-                        goto normal_this;
-                    if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) {
-                        val = JS_DupValue(ctx, ctx->global_obj);
-                    } else {
-                        val = JS_ToObject(ctx, this_obj);
-                        if (JS_IsException(val))
-                            goto exception;
-                    }
-                } else {
-                normal_this:
-                    val = JS_DupValue(ctx, this_obj);
-                }
-                *sp++ = val;
-            }
-            BREAK;
-        CASE(OP_push_false):
-            *sp++ = JS_FALSE;
-            BREAK;
-        CASE(OP_push_true):
-            *sp++ = JS_TRUE;
-            BREAK;
-        CASE(OP_object):
-            *sp++ = JS_NewObject(ctx);
-            if (unlikely(JS_IsException(sp[-1])))
-                goto exception;
-            BREAK;
-        CASE(OP_special_object):
-            {
-                int arg = *pc++;
-                switch(arg) {
-                case OP_SPECIAL_OBJECT_ARGUMENTS:
-                    *sp++ = js_build_arguments(ctx, argc, (JSValueConst *)argv);
-                    if (unlikely(JS_IsException(sp[-1])))
-                        goto exception;
-                    break;
-                case OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS:
-                    *sp++ = js_build_mapped_arguments(ctx, argc, (JSValueConst *)argv,
-                                                      sf, min_int(argc, b->arg_count));
-                    if (unlikely(JS_IsException(sp[-1])))
-                        goto exception;
-                    break;
-                case OP_SPECIAL_OBJECT_THIS_FUNC:
-                    *sp++ = JS_DupValue(ctx, sf->cur_func);
-                    break;
-                case OP_SPECIAL_OBJECT_NEW_TARGET:
-                    *sp++ = JS_DupValue(ctx, new_target);
-                    break;
-                case OP_SPECIAL_OBJECT_HOME_OBJECT:
-                    {
-                        JSObject *p1;
-                        p1 = p->u.func.home_object;
-                        if (unlikely(!p1))
-                            *sp++ = JS_UNDEFINED;
-                        else
-                            *sp++ = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
-                    }
-                    break;
-                case OP_SPECIAL_OBJECT_VAR_OBJECT:
-                    *sp++ = JS_NewObjectProto(ctx, JS_NULL);
-                    if (unlikely(JS_IsException(sp[-1])))
-                        goto exception;
-                    break;
-                case OP_SPECIAL_OBJECT_IMPORT_META:
-                    *sp++ = js_import_meta(ctx);
-                    if (unlikely(JS_IsException(sp[-1])))
-                        goto exception;
-                    break;
-                default:
-                    abort();
-                }
-            }
-            BREAK;
-        CASE(OP_rest):
-            {
-                int first = get_u16(pc);
-                pc += 2;
-                *sp++ = js_build_rest(ctx, first, argc, (JSValueConst *)argv);
-                if (unlikely(JS_IsException(sp[-1])))
-                    goto exception;
-            }
-            BREAK;
-
-        CASE(OP_drop):
-            JS_FreeValue(ctx, sp[-1]);
-            sp--;
-            BREAK;
-        CASE(OP_nip):
-            JS_FreeValue(ctx, sp[-2]);
-            sp[-2] = sp[-1];
-            sp--;
-            BREAK;
-        CASE(OP_nip1): /* a b c -> b c */
-            JS_FreeValue(ctx, sp[-3]);
-            sp[-3] = sp[-2];
-            sp[-2] = sp[-1];
-            sp--;
-            BREAK;
-        CASE(OP_dup):
-            sp[0] = JS_DupValue(ctx, sp[-1]);
-            sp++;
-            BREAK;
-        CASE(OP_dup2): /* a b -> a b a b */
-            sp[0] = JS_DupValue(ctx, sp[-2]);
-            sp[1] = JS_DupValue(ctx, sp[-1]);
-            sp += 2;
-            BREAK;
-        CASE(OP_dup3): /* a b c -> a b c a b c */
-            sp[0] = JS_DupValue(ctx, sp[-3]);
-            sp[1] = JS_DupValue(ctx, sp[-2]);
-            sp[2] = JS_DupValue(ctx, sp[-1]);
-            sp += 3;
-            BREAK;
-        CASE(OP_dup1): /* a b -> a a b */
-            sp[0] = sp[-1];
-            sp[-1] = JS_DupValue(ctx, sp[-2]);
-            sp++;
-            BREAK;
-        CASE(OP_insert2): /* obj a -> a obj a (dup_x1) */
-            sp[0] = sp[-1];
-            sp[-1] = sp[-2];
-            sp[-2] = JS_DupValue(ctx, sp[0]);
-            sp++;
-            BREAK;
-        CASE(OP_insert3): /* obj prop a -> a obj prop a (dup_x2) */
-            sp[0] = sp[-1];
-            sp[-1] = sp[-2];
-            sp[-2] = sp[-3];
-            sp[-3] = JS_DupValue(ctx, sp[0]);
-            sp++;
-            BREAK;
-        CASE(OP_insert4): /* this obj prop a -> a this obj prop a */
-            sp[0] = sp[-1];
-            sp[-1] = sp[-2];
-            sp[-2] = sp[-3];
-            sp[-3] = sp[-4];
-            sp[-4] = JS_DupValue(ctx, sp[0]);
-            sp++;
-            BREAK;
-        CASE(OP_perm3): /* obj a b -> a obj b (213) */
-            {
-                JSValue tmp;
-                tmp = sp[-2];
-                sp[-2] = sp[-3];
-                sp[-3] = tmp;
-            }
-            BREAK;
-        CASE(OP_rot3l): /* x a b -> a b x (231) */
-            {
-                JSValue tmp;
-                tmp = sp[-3];
-                sp[-3] = sp[-2];
-                sp[-2] = sp[-1];
-                sp[-1] = tmp;
-            }
-            BREAK;
-        CASE(OP_rot4l): /* x a b c -> a b c x */
-            {
-                JSValue tmp;
-                tmp = sp[-4];
-                sp[-4] = sp[-3];
-                sp[-3] = sp[-2];
-                sp[-2] = sp[-1];
-                sp[-1] = tmp;
-            }
-            BREAK;
-        CASE(OP_rot5l): /* x a b c d -> a b c d x */
-            {
-                JSValue tmp;
-                tmp = sp[-5];
-                sp[-5] = sp[-4];
-                sp[-4] = sp[-3];
-                sp[-3] = sp[-2];
-                sp[-2] = sp[-1];
-                sp[-1] = tmp;
-            }
-            BREAK;
-        CASE(OP_rot3r): /* a b x -> x a b (312) */
-            {
-                JSValue tmp;
-                tmp = sp[-1];
-                sp[-1] = sp[-2];
-                sp[-2] = sp[-3];
-                sp[-3] = tmp;
-            }
-            BREAK;
-        CASE(OP_perm4): /* obj prop a b -> a obj prop b */
-            {
-                JSValue tmp;
-                tmp = sp[-2];
-                sp[-2] = sp[-3];
-                sp[-3] = sp[-4];
-                sp[-4] = tmp;
-            }
-            BREAK;
-        CASE(OP_perm5): /* this obj prop a b -> a this obj prop b */
-            {
-                JSValue tmp;
-                tmp = sp[-2];
-                sp[-2] = sp[-3];
-                sp[-3] = sp[-4];
-                sp[-4] = sp[-5];
-                sp[-5] = tmp;
-            }
-            BREAK;
-        CASE(OP_swap): /* a b -> b a */
-            {
-                JSValue tmp;
-                tmp = sp[-2];
-                sp[-2] = sp[-1];
-                sp[-1] = tmp;
-            }
-            BREAK;
-        CASE(OP_swap2): /* a b c d -> c d a b */
-            {
-                JSValue tmp1, tmp2;
-                tmp1 = sp[-4];
-                tmp2 = sp[-3];
-                sp[-4] = sp[-2];
-                sp[-3] = sp[-1];
-                sp[-2] = tmp1;
-                sp[-1] = tmp2;
-            }
-            BREAK;
-
-        CASE(OP_fclosure):
-            {
-                JSValue bfunc = JS_DupValue(ctx, b->cpool[get_u32(pc)]);
-                pc += 4;
-                *sp++ = js_closure(ctx, bfunc, var_refs, sf);
-                if (unlikely(JS_IsException(sp[-1])))
-                    goto exception;
-            }
-            BREAK;
-#if SHORT_OPCODES
-        CASE(OP_call0):
-        CASE(OP_call1):
-        CASE(OP_call2):
-        CASE(OP_call3):
-            call_argc = opcode - OP_call0;
-            goto has_call_argc;
-#endif
-        CASE(OP_call):
-        CASE(OP_tail_call):
-            {
-                call_argc = get_u16(pc);
-                pc += 2;
-                goto has_call_argc;
-            has_call_argc:
-                call_argv = sp - call_argc;
-                sf->cur_pc = pc;
-                ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED,
-                                          JS_UNDEFINED, call_argc, call_argv, 0);
-                if (unlikely(JS_IsException(ret_val)))
-                    goto exception;
-                if (opcode == OP_tail_call)
-                    goto done;
-                for(i = -1; i < call_argc; i++)
-                    JS_FreeValue(ctx, call_argv[i]);
-                sp -= call_argc + 1;
-                *sp++ = ret_val;
-            }
-            BREAK;
-        CASE(OP_call_constructor):
-            {
-                call_argc = get_u16(pc);
-                pc += 2;
-                call_argv = sp - call_argc;
-                sf->cur_pc = pc;
-                ret_val = JS_CallConstructorInternal(ctx, call_argv[-2],
-                                                     call_argv[-1],
-                                                     call_argc, call_argv, 0);
-                if (unlikely(JS_IsException(ret_val)))
-                    goto exception;
-                for(i = -2; i < call_argc; i++)
-                    JS_FreeValue(ctx, call_argv[i]);
-                sp -= call_argc + 2;
-                *sp++ = ret_val;
-            }
-            BREAK;
-        CASE(OP_call_method):
-        CASE(OP_tail_call_method):
-            {
-                call_argc = get_u16(pc);
-                pc += 2;
-                call_argv = sp - call_argc;
-                sf->cur_pc = pc;
-                ret_val = JS_CallInternal(ctx, call_argv[-1], call_argv[-2],
-                                          JS_UNDEFINED, call_argc, call_argv, 0);
-                if (unlikely(JS_IsException(ret_val)))
-                    goto exception;
-                if (opcode == OP_tail_call_method)
-                    goto done;
-                for(i = -2; i < call_argc; i++)
-                    JS_FreeValue(ctx, call_argv[i]);
-                sp -= call_argc + 2;
-                *sp++ = ret_val;
-            }
-            BREAK;
-        CASE(OP_array_from):
-            {
-                int i, ret;
-
-                call_argc = get_u16(pc);
-                pc += 2;
-                ret_val = JS_NewArray(ctx);
-                if (unlikely(JS_IsException(ret_val)))
-                    goto exception;
-                call_argv = sp - call_argc;
-                for(i = 0; i < call_argc; i++) {
-                    ret = JS_DefinePropertyValue(ctx, ret_val, __JS_AtomFromUInt32(i), call_argv[i],
-                                                 JS_PROP_C_W_E | JS_PROP_THROW);
-                    call_argv[i] = JS_UNDEFINED;
-                    if (ret < 0) {
-                        JS_FreeValue(ctx, ret_val);
-                        goto exception;
-                    }
-                }
-                sp -= call_argc;
-                *sp++ = ret_val;
-            }
-            BREAK;
-
-        CASE(OP_apply):
-            {
-                int magic;
-                magic = get_u16(pc);
-                pc += 2;
-
-                ret_val = js_function_apply(ctx, sp[-3], 2, (JSValueConst *)&sp[-2], magic);
-                if (unlikely(JS_IsException(ret_val)))
-                    goto exception;
-                JS_FreeValue(ctx, sp[-3]);
-                JS_FreeValue(ctx, sp[-2]);
-                JS_FreeValue(ctx, sp[-1]);
-                sp -= 3;
-                *sp++ = ret_val;
-            }
-            BREAK;
-        CASE(OP_return):
-            ret_val = *--sp;
-            goto done;
-        CASE(OP_return_undef):
-            ret_val = JS_UNDEFINED;
-            goto done;
-
-        CASE(OP_check_ctor_return):
-            /* return TRUE if 'this' should be returned */
-            if (!JS_IsObject(sp[-1])) {
-                if (!JS_IsUndefined(sp[-1])) {
-                    JS_ThrowTypeError(caller_ctx, "derived class constructor must return an object or undefined");
-                    goto exception;
-                }
-                sp[0] = JS_TRUE;
-            } else {
-                sp[0] = JS_FALSE;
-            }
-            sp++;
-            BREAK;
-        CASE(OP_check_ctor):
-            if (JS_IsUndefined(new_target)) {
-                JS_ThrowTypeError(ctx, "class constructors must be invoked with 'new'");
-                goto exception;
-            }
-            BREAK;
-        CASE(OP_check_brand):
-            if (JS_CheckBrand(ctx, sp[-2], sp[-1]) < 0)
-                goto exception;
-            BREAK;
-        CASE(OP_add_brand):
-            if (JS_AddBrand(ctx, sp[-2], sp[-1]) < 0)
-                goto exception;
-            JS_FreeValue(ctx, sp[-2]);
-            JS_FreeValue(ctx, sp[-1]);
-            sp -= 2;
-            BREAK;
-            
-        CASE(OP_throw):
-            JS_Throw(ctx, *--sp);
-            goto exception;
-
-        CASE(OP_throw_error):
-#define JS_THROW_VAR_RO             0
-#define JS_THROW_VAR_REDECL         1
-#define JS_THROW_VAR_UNINITIALIZED  2
-#define JS_THROW_ERROR_DELETE_SUPER   3
-#define JS_THROW_ERROR_ITERATOR_THROW 4
-            {
-                JSAtom atom;
-                int type;
-                atom = get_u32(pc);
-                type = pc[4];
-                pc += 5;
-                if (type == JS_THROW_VAR_RO)
-                    JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, atom);
-                else
-                if (type == JS_THROW_VAR_REDECL)
-                    JS_ThrowSyntaxErrorVarRedeclaration(ctx, atom);
-                else
-                if (type == JS_THROW_VAR_UNINITIALIZED)
-                    JS_ThrowReferenceErrorUninitialized(ctx, atom);
-                else
-                if (type == JS_THROW_ERROR_DELETE_SUPER)
-                    JS_ThrowReferenceError(ctx, "unsupported reference to 'super'");
-                else
-                if (type == JS_THROW_ERROR_ITERATOR_THROW)
-                    JS_ThrowTypeError(ctx, "iterator does not have a throw method");
-                else
-                    JS_ThrowInternalError(ctx, "invalid throw var type %d", type);
-            }
-            goto exception;
-
-        CASE(OP_eval):
-            {
-                JSValueConst obj;
-                int scope_idx;
-                call_argc = get_u16(pc);
-                scope_idx = get_u16(pc + 2) - 1;
-                pc += 4;
-                call_argv = sp - call_argc;
-                sf->cur_pc = pc;
-                if (js_same_value(ctx, call_argv[-1], ctx->eval_obj)) {
-                    if (call_argc >= 1)
-                        obj = call_argv[0];
-                    else
-                        obj = JS_UNDEFINED;
-                    ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj,
-                                            JS_EVAL_TYPE_DIRECT, scope_idx);
-                } else {
-                    ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED,
-                                              JS_UNDEFINED, call_argc, call_argv, 0);
-                }
-                if (unlikely(JS_IsException(ret_val)))
-                    goto exception;
-                for(i = -1; i < call_argc; i++)
-                    JS_FreeValue(ctx, call_argv[i]);
-                sp -= call_argc + 1;
-                *sp++ = ret_val;
-            }
-            BREAK;
-            /* could merge with OP_apply */
-        CASE(OP_apply_eval):
-            {
-                int scope_idx;
-                uint32_t len;
-                JSValue *tab;
-                JSValueConst obj;
-
-                scope_idx = get_u16(pc) - 1;
-                pc += 2;
-                tab = build_arg_list(ctx, &len, sp[-1]);
-                if (!tab)
-                    goto exception;
-                if (js_same_value(ctx, sp[-2], ctx->eval_obj)) {
-                    if (len >= 1)
-                        obj = tab[0];
-                    else
-                        obj = JS_UNDEFINED;
-                    ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj,
-                                            JS_EVAL_TYPE_DIRECT, scope_idx);
-                } else {
-                    ret_val = JS_Call(ctx, sp[-2], JS_UNDEFINED, len,
-                                      (JSValueConst *)tab);
-                }
-                free_arg_list(ctx, tab, len);
-                if (unlikely(JS_IsException(ret_val)))
-                    goto exception;
-                JS_FreeValue(ctx, sp[-2]);
-                JS_FreeValue(ctx, sp[-1]);
-                sp -= 2;
-                *sp++ = ret_val;
-            }
-            BREAK;
-
-        CASE(OP_regexp):
-            {
-                sp[-2] = js_regexp_constructor_internal(ctx, JS_UNDEFINED,
-                                                        sp[-2], sp[-1]);
-                sp--;
-            }
-            BREAK;
-
-        CASE(OP_get_super):
-            {
-                JSValue proto;
-                proto = JS_GetPrototype(ctx, sp[-1]);
-                if (JS_IsException(proto))
-                    goto exception;
-                JS_FreeValue(ctx, sp[-1]);
-                sp[-1] = proto;
-            }
-            BREAK;
-
-        CASE(OP_import):
-            {
-                JSValue val;
-                val = js_dynamic_import(ctx, sp[-1]);
-                if (JS_IsException(val))
-                    goto exception;
-                JS_FreeValue(ctx, sp[-1]);
-                sp[-1] = val;
-            }
-            BREAK;
-
-        CASE(OP_check_var):
-            {
-                int ret;
-                JSAtom atom;
-                atom = get_u32(pc);
-                pc += 4;
-
-                ret = JS_CheckGlobalVar(ctx, atom);
-                if (ret < 0)
-                    goto exception;
-                *sp++ = JS_NewBool(ctx, ret);
-            }
-            BREAK;
-
-        CASE(OP_get_var_undef):
-        CASE(OP_get_var):
-            {
-                JSValue val;
-                JSAtom atom;
-                atom = get_u32(pc);
-                pc += 4;
-
-                val = JS_GetGlobalVar(ctx, atom, opcode - OP_get_var_undef);
-                if (unlikely(JS_IsException(val)))
-                    goto exception;
-                *sp++ = val;
-            }
-            BREAK;
-
-        CASE(OP_put_var):
-        CASE(OP_put_var_init):
-            {
-                int ret;
-                JSAtom atom;
-                atom = get_u32(pc);
-                pc += 4;
-
-                ret = JS_SetGlobalVar(ctx, atom, sp[-1], opcode - OP_put_var);
-                sp--;
-                if (unlikely(ret < 0))
-                    goto exception;
-            }
-            BREAK;
-
-        CASE(OP_put_var_strict):
-            {
-                int ret;
-                JSAtom atom;
-                atom = get_u32(pc);
-                pc += 4;
-
-                /* sp[-2] is JS_TRUE or JS_FALSE */
-                if (unlikely(!JS_VALUE_GET_INT(sp[-2]))) {
-                    JS_ThrowReferenceErrorNotDefined(ctx, atom);
-                    goto exception;
-                }
-                ret = JS_SetGlobalVar(ctx, atom, sp[-1], 2);
-                sp -= 2;
-                if (unlikely(ret < 0))
-                    goto exception;
-            }
-            BREAK;
-
-        CASE(OP_check_define_var):
-            {
-                JSAtom atom;
-                int flags;
-                atom = get_u32(pc);
-                flags = pc[4];
-                pc += 5;
-                if (JS_CheckDefineGlobalVar(ctx, atom, flags))
-                    goto exception;
-            }
-            BREAK;
-        CASE(OP_define_var):
-            {
-                JSAtom atom;
-                int flags;
-                atom = get_u32(pc);
-                flags = pc[4];
-                pc += 5;
-                if (JS_DefineGlobalVar(ctx, atom, flags))
-                    goto exception;
-            }
-            BREAK;
-        CASE(OP_define_func):
-            {
-                JSAtom atom;
-                int flags;
-                atom = get_u32(pc);
-                flags = pc[4];
-                pc += 5;
-                if (JS_DefineGlobalFunction(ctx, atom, sp[-1], flags))
-                    goto exception;
-                JS_FreeValue(ctx, sp[-1]);
-                sp--;
-            }
-            BREAK;
-
-        CASE(OP_get_loc):
-            {
-                int idx;
-                idx = get_u16(pc);
-                pc += 2;
-                sp[0] = JS_DupValue(ctx, var_buf[idx]);
-                sp++;
-            }
-            BREAK;
-        CASE(OP_put_loc):
-            {
-                int idx;
-                idx = get_u16(pc);
-                pc += 2;
-                set_value(ctx, &var_buf[idx], sp[-1]);
-                sp--;
-            }
-            BREAK;
-        CASE(OP_set_loc):
-            {
-                int idx;
-                idx = get_u16(pc);
-                pc += 2;
-                set_value(ctx, &var_buf[idx], JS_DupValue(ctx, sp[-1]));
-            }
-            BREAK;
-        CASE(OP_get_arg):
-            {
-                int idx;
-                idx = get_u16(pc);
-                pc += 2;
-                sp[0] = JS_DupValue(ctx, arg_buf[idx]);
-                sp++;
-            }
-            BREAK;
-        CASE(OP_put_arg):
-            {
-                int idx;
-                idx = get_u16(pc);
-                pc += 2;
-                set_value(ctx, &arg_buf[idx], sp[-1]);
-                sp--;
-            }
-            BREAK;
-        CASE(OP_set_arg):
-            {
-                int idx;
-                idx = get_u16(pc);
-                pc += 2;
-                set_value(ctx, &arg_buf[idx], JS_DupValue(ctx, sp[-1]));
-            }
-            BREAK;
-
-#if SHORT_OPCODES
-        CASE(OP_get_loc8): *sp++ = JS_DupValue(ctx, var_buf[*pc++]); BREAK;
-        CASE(OP_put_loc8): set_value(ctx, &var_buf[*pc++], *--sp); BREAK;
-        CASE(OP_set_loc8): set_value(ctx, &var_buf[*pc++], JS_DupValue(ctx, sp[-1])); BREAK;
-
-        CASE(OP_get_loc0): *sp++ = JS_DupValue(ctx, var_buf[0]); BREAK;
-        CASE(OP_get_loc1): *sp++ = JS_DupValue(ctx, var_buf[1]); BREAK;
-        CASE(OP_get_loc2): *sp++ = JS_DupValue(ctx, var_buf[2]); BREAK;
-        CASE(OP_get_loc3): *sp++ = JS_DupValue(ctx, var_buf[3]); BREAK;
-        CASE(OP_put_loc0): set_value(ctx, &var_buf[0], *--sp); BREAK;
-        CASE(OP_put_loc1): set_value(ctx, &var_buf[1], *--sp); BREAK;
-        CASE(OP_put_loc2): set_value(ctx, &var_buf[2], *--sp); BREAK;
-        CASE(OP_put_loc3): set_value(ctx, &var_buf[3], *--sp); BREAK;
-        CASE(OP_set_loc0): set_value(ctx, &var_buf[0], JS_DupValue(ctx, sp[-1])); BREAK;
-        CASE(OP_set_loc1): set_value(ctx, &var_buf[1], JS_DupValue(ctx, sp[-1])); BREAK;
-        CASE(OP_set_loc2): set_value(ctx, &var_buf[2], JS_DupValue(ctx, sp[-1])); BREAK;
-        CASE(OP_set_loc3): set_value(ctx, &var_buf[3], JS_DupValue(ctx, sp[-1])); BREAK;
-        CASE(OP_get_arg0): *sp++ = JS_DupValue(ctx, arg_buf[0]); BREAK;
-        CASE(OP_get_arg1): *sp++ = JS_DupValue(ctx, arg_buf[1]); BREAK;
-        CASE(OP_get_arg2): *sp++ = JS_DupValue(ctx, arg_buf[2]); BREAK;
-        CASE(OP_get_arg3): *sp++ = JS_DupValue(ctx, arg_buf[3]); BREAK;
-        CASE(OP_put_arg0): set_value(ctx, &arg_buf[0], *--sp); BREAK;
-        CASE(OP_put_arg1): set_value(ctx, &arg_buf[1], *--sp); BREAK;
-        CASE(OP_put_arg2): set_value(ctx, &arg_buf[2], *--sp); BREAK;
-        CASE(OP_put_arg3): set_value(ctx, &arg_buf[3], *--sp); BREAK;
-        CASE(OP_set_arg0): set_value(ctx, &arg_buf[0], JS_DupValue(ctx, sp[-1])); BREAK;
-        CASE(OP_set_arg1): set_value(ctx, &arg_buf[1], JS_DupValue(ctx, sp[-1])); BREAK;
-        CASE(OP_set_arg2): set_value(ctx, &arg_buf[2], JS_DupValue(ctx, sp[-1])); BREAK;
-        CASE(OP_set_arg3): set_value(ctx, &arg_buf[3], JS_DupValue(ctx, sp[-1])); BREAK;
-        CASE(OP_get_var_ref0): *sp++ = JS_DupValue(ctx, *var_refs[0]->pvalue); BREAK;
-        CASE(OP_get_var_ref1): *sp++ = JS_DupValue(ctx, *var_refs[1]->pvalue); BREAK;
-        CASE(OP_get_var_ref2): *sp++ = JS_DupValue(ctx, *var_refs[2]->pvalue); BREAK;
-        CASE(OP_get_var_ref3): *sp++ = JS_DupValue(ctx, *var_refs[3]->pvalue); BREAK;
-        CASE(OP_put_var_ref0): set_value(ctx, var_refs[0]->pvalue, *--sp); BREAK;
-        CASE(OP_put_var_ref1): set_value(ctx, var_refs[1]->pvalue, *--sp); BREAK;
-        CASE(OP_put_var_ref2): set_value(ctx, var_refs[2]->pvalue, *--sp); BREAK;
-        CASE(OP_put_var_ref3): set_value(ctx, var_refs[3]->pvalue, *--sp); BREAK;
-        CASE(OP_set_var_ref0): set_value(ctx, var_refs[0]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
-        CASE(OP_set_var_ref1): set_value(ctx, var_refs[1]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
-        CASE(OP_set_var_ref2): set_value(ctx, var_refs[2]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
-        CASE(OP_set_var_ref3): set_value(ctx, var_refs[3]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
-#endif
-
-        CASE(OP_get_var_ref):
-            {
-                int idx;
-                JSValue val;
-                idx = get_u16(pc);
-                pc += 2;
-                val = *var_refs[idx]->pvalue;
-                sp[0] = JS_DupValue(ctx, val);
-                sp++;
-            }
-            BREAK;
-        CASE(OP_put_var_ref):
-            {
-                int idx;
-                idx = get_u16(pc);
-                pc += 2;
-                set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
-                sp--;
-            }
-            BREAK;
-        CASE(OP_set_var_ref):
-            {
-                int idx;
-                idx = get_u16(pc);
-                pc += 2;
-                set_value(ctx, var_refs[idx]->pvalue, JS_DupValue(ctx, sp[-1]));
-            }
-            BREAK;
-        CASE(OP_get_var_ref_check):
-            {
-                int idx;
-                JSValue val;
-                idx = get_u16(pc);
-                pc += 2;
-                val = *var_refs[idx]->pvalue;
-                if (unlikely(JS_IsUninitialized(val))) {
-                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
-                    goto exception;
-                }
-                sp[0] = JS_DupValue(ctx, val);
-                sp++;
-            }
-            BREAK;
-        CASE(OP_put_var_ref_check):
-            {
-                int idx;
-                idx = get_u16(pc);
-                pc += 2;
-                if (unlikely(JS_IsUninitialized(*var_refs[idx]->pvalue))) {
-                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
-                    goto exception;
-                }
-                set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
-                sp--;
-            }
-            BREAK;
-        CASE(OP_put_var_ref_check_init):
-            {
-                int idx;
-                idx = get_u16(pc);
-                pc += 2;
-                if (unlikely(!JS_IsUninitialized(*var_refs[idx]->pvalue))) {
-                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
-                    goto exception;
-                }
-                set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
-                sp--;
-            }
-            BREAK;
-        CASE(OP_set_loc_uninitialized):
-            {
-                int idx;
-                idx = get_u16(pc);
-                pc += 2;
-                set_value(ctx, &var_buf[idx], JS_UNINITIALIZED);
-            }
-            BREAK;
-        CASE(OP_get_loc_check):
-            {
-                int idx;
-                idx = get_u16(pc);
-                pc += 2;
-                if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
-                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);
-                    goto exception;
-                }
-                sp[0] = JS_DupValue(ctx, var_buf[idx]);
-                sp++;
-            }
-            BREAK;
-        CASE(OP_put_loc_check):
-            {
-                int idx;
-                idx = get_u16(pc);
-                pc += 2;
-                if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
-                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);
-                    goto exception;
-                }
-                set_value(ctx, &var_buf[idx], sp[-1]);
-                sp--;
-            }
-            BREAK;
-        CASE(OP_put_loc_check_init):
-            {
-                int idx;
-                idx = get_u16(pc);
-                pc += 2;
-                if (unlikely(!JS_IsUninitialized(var_buf[idx]))) {
-                    JS_ThrowReferenceError(ctx, "'this' can be initialized only once");
-                    goto exception;
-                }
-                set_value(ctx, &var_buf[idx], sp[-1]);
-                sp--;
-            }
-            BREAK;
-        CASE(OP_close_loc):
-            {
-                int idx;
-                idx = get_u16(pc);
-                pc += 2;
-                close_lexical_var(ctx, sf, idx, FALSE);
-            }
-            BREAK;
-
-        CASE(OP_make_loc_ref):
-        CASE(OP_make_arg_ref):
-        CASE(OP_make_var_ref_ref):
-            {
-                JSVarRef *var_ref;
-                JSProperty *pr;
-                JSAtom atom;
-                int idx;
-                atom = get_u32(pc);
-                idx = get_u16(pc + 4);
-                pc += 6;
-                *sp++ = JS_NewObjectProto(ctx, JS_NULL);
-                if (unlikely(JS_IsException(sp[-1])))
-                    goto exception;
-                if (opcode == OP_make_var_ref_ref) {
-                    var_ref = var_refs[idx];
-                    var_ref->header.ref_count++;
-                } else {
-                    var_ref = get_var_ref(ctx, sf, idx, opcode == OP_make_arg_ref);
-                    if (!var_ref)
-                        goto exception;
-                }
-                pr = add_property(ctx, JS_VALUE_GET_OBJ(sp[-1]), atom,
-                                  JS_PROP_WRITABLE | JS_PROP_VARREF);
-                if (!pr) {
-                    free_var_ref(rt, var_ref);
-                    goto exception;
-                }
-                pr->u.var_ref = var_ref;
-                *sp++ = JS_AtomToValue(ctx, atom);
-            }
-            BREAK;
-        CASE(OP_make_var_ref):
-            {
-                JSAtom atom;
-                atom = get_u32(pc);
-                pc += 4;
-
-                if (JS_GetGlobalVarRef(ctx, atom, sp))
-                    goto exception;
-                sp += 2;
-            }
-            BREAK;
-
-        CASE(OP_goto):
-            pc += (int32_t)get_u32(pc);
-            if (unlikely(js_poll_interrupts(ctx)))
-                goto exception;
-            BREAK;
-#if SHORT_OPCODES
-        CASE(OP_goto16):
-            pc += (int16_t)get_u16(pc);
-            if (unlikely(js_poll_interrupts(ctx)))
-                goto exception;
-            BREAK;
-        CASE(OP_goto8):
-            pc += (int8_t)pc[0];
-            if (unlikely(js_poll_interrupts(ctx)))
-                goto exception;
-            BREAK;
-#endif
-        CASE(OP_if_true):
-            {
-                int res;
-                JSValue op1;
-
-                op1 = sp[-1];
-                pc += 4;
-                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
-                    res = JS_VALUE_GET_INT(op1);
-                } else {
-                    res = JS_ToBoolFree(ctx, op1);
-                }
-                sp--;
-                if (res) {
-                    pc += (int32_t)get_u32(pc - 4) - 4;
-                }
-                if (unlikely(js_poll_interrupts(ctx)))
-                    goto exception;
-            }
-            BREAK;
-        CASE(OP_if_false):
-            {
-                int res;
-                JSValue op1;
-
-                op1 = sp[-1];
-                pc += 4;
-                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
-                    res = JS_VALUE_GET_INT(op1);
-                } else {
-                    res = JS_ToBoolFree(ctx, op1);
-                }
-                sp--;
-                if (!res) {
-                    pc += (int32_t)get_u32(pc - 4) - 4;
-                }
-                if (unlikely(js_poll_interrupts(ctx)))
-                    goto exception;
-            }
-            BREAK;
-#if SHORT_OPCODES
-        CASE(OP_if_true8):
-            {
-                int res;
-                JSValue op1;
-
-                op1 = sp[-1];
-                pc += 1;
-                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
-                    res = JS_VALUE_GET_INT(op1);
-                } else {
-                    res = JS_ToBoolFree(ctx, op1);
-                }
-                sp--;
-                if (res) {
-                    pc += (int8_t)pc[-1] - 1;
-                }
-                if (unlikely(js_poll_interrupts(ctx)))
-                    goto exception;
-            }
-            BREAK;
-        CASE(OP_if_false8):
-            {
-                int res;
-                JSValue op1;
-
-                op1 = sp[-1];
-                pc += 1;
-                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
-                    res = JS_VALUE_GET_INT(op1);
-                } else {
-                    res = JS_ToBoolFree(ctx, op1);
-                }
-                sp--;
-                if (!res) {
-                    pc += (int8_t)pc[-1] - 1;
-                }
-                if (unlikely(js_poll_interrupts(ctx)))
-                    goto exception;
-            }
-            BREAK;
-#endif
-        CASE(OP_catch):
-            {
-                int32_t diff;
-                diff = get_u32(pc);
-                sp[0] = JS_NewCatchOffset(ctx, pc + diff - b->byte_code_buf);
-                sp++;
-                pc += 4;
-            }
-            BREAK;
-        CASE(OP_gosub):
-            {
-                int32_t diff;
-                diff = get_u32(pc);
-                /* XXX: should have a different tag to avoid security flaw */
-                sp[0] = JS_NewInt32(ctx, pc + 4 - b->byte_code_buf);
-                sp++;
-                pc += diff;
-            }
-            BREAK;
-        CASE(OP_ret):
-            {
-                JSValue op1;
-                uint32_t pos;
-                op1 = sp[-1];
-                if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_INT))
-                    goto ret_fail;
-                pos = JS_VALUE_GET_INT(op1);
-                if (unlikely(pos >= b->byte_code_len)) {
-                ret_fail:
-                    JS_ThrowInternalError(ctx, "invalid ret value");
-                    goto exception;
-                }
-                sp--;
-                pc = b->byte_code_buf + pos;
-            }
-            BREAK;
-
-        CASE(OP_for_in_start):
-            if (js_for_in_start(ctx, sp))
-                goto exception;
-            BREAK;
-        CASE(OP_for_in_next):
-            if (js_for_in_next(ctx, sp))
-                goto exception;
-            sp += 2;
-            BREAK;
-        CASE(OP_for_of_start):
-            if (js_for_of_start(ctx, sp, FALSE))
-                goto exception;
-            sp += 1;
-            *sp++ = JS_NewCatchOffset(ctx, 0);
-            BREAK;
-        CASE(OP_for_of_next):
-            {
-                int offset = -3 - pc[0];
-                pc += 1;
-                if (js_for_of_next(ctx, sp, offset))
-                    goto exception;
-                sp += 2;
-            }
-            BREAK;
-        CASE(OP_for_await_of_start):
-            if (js_for_of_start(ctx, sp, TRUE))
-                goto exception;
-            sp += 1;
-            *sp++ = JS_NewCatchOffset(ctx, 0);
-            BREAK;
-        CASE(OP_iterator_get_value_done):
-            if (js_iterator_get_value_done(ctx, sp))
-                goto exception;
-            sp += 1;
-            BREAK;
-        CASE(OP_iterator_check_object):
-            if (unlikely(!JS_IsObject(sp[-1]))) {
-                JS_ThrowTypeError(ctx, "iterator must return an object");
-                goto exception;
-            }
-            BREAK;
-
-        CASE(OP_iterator_close):
-            /* iter_obj next catch_offset -> */
-            sp--; /* drop the catch offset to avoid getting caught by exception */
-            JS_FreeValue(ctx, sp[-1]); /* drop the next method */
-            sp--;
-            if (!JS_IsUndefined(sp[-1])) {
-                if (JS_IteratorClose(ctx, sp[-1], FALSE))
-                    goto exception;
-                JS_FreeValue(ctx, sp[-1]);
-            }
-            sp--;
-            BREAK;
-        CASE(OP_iterator_close_return):
-            {
-                JSValue ret_val;
-                /* iter_obj next catch_offset ... ret_val ->
-                   ret_eval iter_obj next catch_offset */
-                ret_val = *--sp;
-                while (sp > stack_buf &&
-                       JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_CATCH_OFFSET) {
-                    JS_FreeValue(ctx, *--sp);
-                }
-                if (unlikely(sp < stack_buf + 3)) {
-                    JS_ThrowInternalError(ctx, "iterator_close_return");
-                    JS_FreeValue(ctx, ret_val);
-                    goto exception;
-                }
-                sp[0] = sp[-1];
-                sp[-1] = sp[-2];
-                sp[-2] = sp[-3];
-                sp[-3] = ret_val;
-                sp++;
-            }
-            BREAK;
-
-        CASE(OP_iterator_next):
-            /* stack: iter_obj next catch_offset val */
-            {
-                JSValue ret;
-                ret = JS_Call(ctx, sp[-3], sp[-4],
-                              1, (JSValueConst *)(sp - 1));
-                if (JS_IsException(ret))
-                    goto exception;
-                JS_FreeValue(ctx, sp[-1]);
-                sp[-1] = ret;
-            }
-            BREAK;
-
-        CASE(OP_iterator_call):
-            /* stack: iter_obj next catch_offset val */
-            {
-                JSValue method, ret;
-                BOOL ret_flag;
-                int flags;
-                flags = *pc++;
-                method = JS_GetProperty(ctx, sp[-4], (flags & 1) ?
-                                        JS_ATOM_throw : JS_ATOM_return);
-                if (JS_IsException(method))
-                    goto exception;
-                if (JS_IsUndefined(method) || JS_IsNull(method)) {
-                    ret_flag = TRUE;
-                } else {
-                    if (flags & 2) {
-                        /* no argument */
-                        ret = JS_CallFree(ctx, method, sp[-4],
-                                          0, NULL);
-                    } else {
-                        ret = JS_CallFree(ctx, method, sp[-4],
-                                          1, (JSValueConst *)(sp - 1));
-                    }
-                    if (JS_IsException(ret))
-                        goto exception;
-                    JS_FreeValue(ctx, sp[-1]);
-                    sp[-1] = ret;
-                    ret_flag = FALSE;
-                }
-                sp[0] = JS_NewBool(ctx, ret_flag);
-                sp += 1;
-            }
-            BREAK;
-
-        CASE(OP_lnot):
-            {
-                int res;
-                JSValue op1;
-
-                op1 = sp[-1];
-                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
-                    res = JS_VALUE_GET_INT(op1) != 0;
-                } else {
-                    res = JS_ToBoolFree(ctx, op1);
-                }
-                sp[-1] = JS_NewBool(ctx, !res);
-            }
-            BREAK;
-
-        CASE(OP_get_field):
-            {
-                JSValue val;
-                JSAtom atom;
-                atom = get_u32(pc);
-                pc += 4;
-
-                val = JS_GetProperty(ctx, sp[-1], atom);
-                if (unlikely(JS_IsException(val)))
-                    goto exception;
-                JS_FreeValue(ctx, sp[-1]);
-                sp[-1] = val;
-            }
-            BREAK;
-
-        CASE(OP_get_field2):
-            {
-                JSValue val;
-                JSAtom atom;
-                atom = get_u32(pc);
-                pc += 4;
-
-                val = JS_GetProperty(ctx, sp[-1], atom);
-                if (unlikely(JS_IsException(val)))
-                    goto exception;
-                *sp++ = val;
-            }
-            BREAK;
-
-        CASE(OP_put_field):
-            {
-                int ret;
-                JSAtom atom;
-                atom = get_u32(pc);
-                pc += 4;
-
-                ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1],
-                                             JS_PROP_THROW_STRICT);
-                JS_FreeValue(ctx, sp[-2]);
-                sp -= 2;
-                if (unlikely(ret < 0))
-                    goto exception;
-            }
-            BREAK;
-
-        CASE(OP_private_symbol):
-            {
-                JSAtom atom;
-                JSValue val;
-                
-                atom = get_u32(pc);
-                pc += 4;
-                val = JS_NewSymbolFromAtom(ctx, atom, JS_ATOM_TYPE_PRIVATE);
-                if (JS_IsException(val))
-                    goto exception;
-                *sp++ = val;
-            }
-            BREAK;
-            
-        CASE(OP_get_private_field):
-            {
-                JSValue val;
-
-                val = JS_GetPrivateField(ctx, sp[-2], sp[-1]);
-                JS_FreeValue(ctx, sp[-1]);
-                JS_FreeValue(ctx, sp[-2]);
-                sp[-2] = val;
-                sp--;
-                if (unlikely(JS_IsException(val)))
-                    goto exception;
-            }
-            BREAK;
-
-        CASE(OP_put_private_field):
-            {
-                int ret;
-                ret = JS_SetPrivateField(ctx, sp[-3], sp[-1], sp[-2]);
-                JS_FreeValue(ctx, sp[-3]);
-                JS_FreeValue(ctx, sp[-1]);
-                sp -= 3;
-                if (unlikely(ret < 0))
-                    goto exception;
-            }
-            BREAK;
-
-        CASE(OP_define_private_field):
-            {
-                int ret;
-                ret = JS_DefinePrivateField(ctx, sp[-3], sp[-2], sp[-1]);
-                JS_FreeValue(ctx, sp[-2]);
-                sp -= 2;
-                if (unlikely(ret < 0))
-                    goto exception;
-            }
-            BREAK;
-
-        CASE(OP_define_field):
-            {
-                int ret;
-                JSAtom atom;
-                atom = get_u32(pc);
-                pc += 4;
-
-                ret = JS_DefinePropertyValue(ctx, sp[-2], atom, sp[-1],
-                                             JS_PROP_C_W_E | JS_PROP_THROW);
-                sp--;
-                if (unlikely(ret < 0))
-                    goto exception;
-            }
-            BREAK;
-
-        CASE(OP_set_name):
-            {
-                int ret;
-                JSAtom atom;
-                atom = get_u32(pc);
-                pc += 4;
-
-                ret = JS_DefineObjectName(ctx, sp[-1], atom, JS_PROP_CONFIGURABLE);
-                if (unlikely(ret < 0))
-                    goto exception;
-            }
-            BREAK;
-        CASE(OP_set_name_computed):
-            {
-                int ret;
-                ret = JS_DefineObjectNameComputed(ctx, sp[-1], sp[-2], JS_PROP_CONFIGURABLE);
-                if (unlikely(ret < 0))
-                    goto exception;
-            }
-            BREAK;
-        CASE(OP_set_proto):
-            {
-                JSValue proto;
-                proto = sp[-1];
-                if (JS_IsObject(proto) || JS_IsNull(proto)) {
-                    if (JS_SetPrototypeInternal(ctx, sp[-2], proto, TRUE) < 0)
-                        goto exception;
-                }
-                JS_FreeValue(ctx, proto);
-                sp--;
-            }
-            BREAK;
-        CASE(OP_set_home_object):
-            js_method_set_home_object(ctx, sp[-1], sp[-2]);
-            BREAK;
-        CASE(OP_define_method):
-        CASE(OP_define_method_computed):
-            {
-                JSValue getter, setter, value;
-                JSValueConst obj;
-                JSAtom atom;
-                int flags, ret, op_flags;
-                BOOL is_computed;
-#define OP_DEFINE_METHOD_METHOD 0
-#define OP_DEFINE_METHOD_GETTER 1
-#define OP_DEFINE_METHOD_SETTER 2
-#define OP_DEFINE_METHOD_ENUMERABLE 4
-
-                is_computed = (opcode == OP_define_method_computed);
-                if (is_computed) {
-                    atom = JS_ValueToAtom(ctx, sp[-2]);
-                    if (unlikely(atom == JS_ATOM_NULL))
-                        goto exception;
-                    opcode += OP_define_method - OP_define_method_computed;
-                } else {
-                    atom = get_u32(pc);
-                    pc += 4;
-                }
-                op_flags = *pc++;
-
-                obj = sp[-2 - is_computed];
-                flags = JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE |
-                    JS_PROP_HAS_ENUMERABLE | JS_PROP_THROW;
-                if (op_flags & OP_DEFINE_METHOD_ENUMERABLE)
-                    flags |= JS_PROP_ENUMERABLE;
-                op_flags &= 3;
-                value = JS_UNDEFINED;
-                getter = JS_UNDEFINED;
-                setter = JS_UNDEFINED;
-                if (op_flags == OP_DEFINE_METHOD_METHOD) {
-                    value = sp[-1];
-                    flags |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE;
-                } else if (op_flags == OP_DEFINE_METHOD_GETTER) {
-                    getter = sp[-1];
-                    flags |= JS_PROP_HAS_GET;
-                } else {
-                    setter = sp[-1];
-                    flags |= JS_PROP_HAS_SET;
-                }
-                ret = js_method_set_properties(ctx, sp[-1], atom, flags, obj);
-                if (ret >= 0) {
-                    ret = JS_DefineProperty(ctx, obj, atom, value,
-                                            getter, setter, flags);
-                }
-                JS_FreeValue(ctx, sp[-1]);
-                if (is_computed) {
-                    JS_FreeAtom(ctx, atom);
-                    JS_FreeValue(ctx, sp[-2]);
-                }
-                sp -= 1 + is_computed;
-                if (unlikely(ret < 0))
-                    goto exception;
-            }
-            BREAK;
-
-        CASE(OP_define_class):
-        CASE(OP_define_class_computed):
-            {
-                int class_flags;
-                JSAtom atom;
-                
-                atom = get_u32(pc);
-                class_flags = pc[4];
-                pc += 5;
-                if (js_op_define_class(ctx, sp, atom, class_flags,
-                                       var_refs, sf,
-                                       (opcode == OP_define_class_computed)) < 0)
-                    goto exception;
-            }
-            BREAK;
-
-        CASE(OP_get_array_el):
-            {
-                JSValue val;
-
-                val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
-                JS_FreeValue(ctx, sp[-2]);
-                sp[-2] = val;
-                sp--;
-                if (unlikely(JS_IsException(val)))
-                    goto exception;
-            }
-            BREAK;
-
-        CASE(OP_get_array_el2):
-            {
-                JSValue val;
-
-                val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
-                sp[-1] = val;
-                if (unlikely(JS_IsException(val)))
-                    goto exception;
-            }
-            BREAK;
-
-        CASE(OP_get_ref_value):
-            {
-                JSValue val;
-                if (unlikely(JS_IsUndefined(sp[-2]))) {
-                    JSAtom atom = JS_ValueToAtom(ctx, sp[-1]);
-                    if (atom != JS_ATOM_NULL) {
-                        JS_ThrowReferenceErrorNotDefined(ctx, atom);
-                        JS_FreeAtom(ctx, atom);
-                    }
-                    goto exception;
-                }
-                val = JS_GetPropertyValue(ctx, sp[-2],
-                                          JS_DupValue(ctx, sp[-1]));
-                if (unlikely(JS_IsException(val)))
-                    goto exception;
-                sp[0] = val;
-                sp++;
-            }
-            BREAK;
-
-        CASE(OP_get_super_value):
-            {
-                JSValue val;
-                JSAtom atom;
-                atom = JS_ValueToAtom(ctx, sp[-1]);
-                if (unlikely(atom == JS_ATOM_NULL))
-                    goto exception;
-                val = JS_GetPropertyInternal(ctx, sp[-2], atom, sp[-3], FALSE);
-                JS_FreeAtom(ctx, atom);
-                if (unlikely(JS_IsException(val)))
-                    goto exception;
-                JS_FreeValue(ctx, sp[-1]);
-                JS_FreeValue(ctx, sp[-2]);
-                JS_FreeValue(ctx, sp[-3]);
-                sp[-3] = val;
-                sp -= 2;
-            }
-            BREAK;
-
-        CASE(OP_put_array_el):
-            {
-                int ret;
-
-                ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT);
-                JS_FreeValue(ctx, sp[-3]);
-                sp -= 3;
-                if (unlikely(ret < 0))
-                    goto exception;
-            }
-            BREAK;
-
-        CASE(OP_put_ref_value):
-            {
-                int ret, flags;
-                flags = JS_PROP_THROW_STRICT;
-                if (unlikely(JS_IsUndefined(sp[-3]))) {
-                    if (is_strict_mode(ctx)) {
-                        JSAtom atom = JS_ValueToAtom(ctx, sp[-2]);
-                        if (atom != JS_ATOM_NULL) {
-                            JS_ThrowReferenceErrorNotDefined(ctx, atom);
-                            JS_FreeAtom(ctx, atom);
-                        }
-                        goto exception;
-                    } else {
-                        sp[-3] = JS_DupValue(ctx, ctx->global_obj);
-                    }
-                } else {
-                    if (is_strict_mode(ctx))
-                        flags |= JS_PROP_NO_ADD;
-                }
-                ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], flags);
-                JS_FreeValue(ctx, sp[-3]);
-                sp -= 3;
-                if (unlikely(ret < 0))
-                    goto exception;
-            }
-            BREAK;
-
-        CASE(OP_put_super_value):
-            {
-                int ret;
-                JSAtom atom;
-                if (JS_VALUE_GET_TAG(sp[-3]) != JS_TAG_OBJECT) {
-                    JS_ThrowTypeErrorNotAnObject(ctx);
-                    goto exception;
-                }
-                atom = JS_ValueToAtom(ctx, sp[-2]);
-                if (unlikely(atom == JS_ATOM_NULL))
-                    goto exception;
-                ret = JS_SetPropertyGeneric(ctx, sp[-3], atom, sp[-1], sp[-4],
-                                            JS_PROP_THROW_STRICT);
-                JS_FreeAtom(ctx, atom);
-                JS_FreeValue(ctx, sp[-4]);
-                JS_FreeValue(ctx, sp[-3]);
-                JS_FreeValue(ctx, sp[-2]);
-                sp -= 4;
-                if (ret < 0)
-                    goto exception;
-            }
-            BREAK;
-
-        CASE(OP_define_array_el):
-            {
-                int ret;
-                ret = JS_DefinePropertyValueValue(ctx, sp[-3], JS_DupValue(ctx, sp[-2]), sp[-1],
-                                                  JS_PROP_C_W_E | JS_PROP_THROW);
-                sp -= 1;
-                if (unlikely(ret < 0))
-                    goto exception;
-            }
-            BREAK;
-
-        CASE(OP_append):    /* array pos enumobj -- array pos */
-            {
-                if (js_append_enumerate(ctx, sp))
-                    goto exception;
-                JS_FreeValue(ctx, *--sp);
-            }
-            BREAK;
-
-        CASE(OP_copy_data_properties):    /* target source excludeList */
-            {
-                /* stack offsets (-1 based):
-                   2 bits for target,
-                   3 bits for source,
-                   2 bits for exclusionList */
-                int mask;
-
-                mask = *pc++;
-                if (JS_CopyDataProperties(ctx, sp[-1 - (mask & 3)],
-                                          sp[-1 - ((mask >> 2) & 7)],
-                                          sp[-1 - ((mask >> 5) & 7)], 0))
-                    goto exception;
-            }
-            BREAK;
-
-        CASE(OP_add):
-            {
-                JSValue op1, op2;
-                op1 = sp[-2];
-                op2 = sp[-1];
-                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
-                    int64_t r;
-                    r = (int64_t)JS_VALUE_GET_INT(op1) + JS_VALUE_GET_INT(op2);
-                    if (unlikely((int)r != r))
-                        goto add_slow;
-                    sp[-2] = JS_NewInt32(ctx, r);
-                    sp--;
-                } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
-                    sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) +
-                                             JS_VALUE_GET_FLOAT64(op2));
-                    sp--;
-                } else {
-                add_slow:
-                    if (js_add_slow(ctx, sp))
-                        goto exception;
-                    sp--;
-                }
-            }
-            BREAK;
-        CASE(OP_add_loc):
-            {
-                JSValue *pv;
-                int idx;
-                idx = *pc;
-                pc += 1;
-
-                pv = &var_buf[idx];
-                if (likely(JS_VALUE_IS_BOTH_INT(*pv, sp[-1]))) {
-                    int64_t r;
-                    r = (int64_t)JS_VALUE_GET_INT(*pv) +
-                        JS_VALUE_GET_INT(sp[-1]);
-                    if (unlikely((int)r != r))
-                        goto add_loc_slow;
-                    *pv = JS_NewInt32(ctx, r);
-                    sp--;
-                } else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING) {
-                    JSValue op1;
-                    op1 = sp[-1];
-                    sp--;
-                    op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
-                    if (JS_IsException(op1))
-                        goto exception;
-                    op1 = JS_ConcatString(ctx, JS_DupValue(ctx, *pv), op1);
-                    if (JS_IsException(op1))
-                        goto exception;
-                    set_value(ctx, pv, op1);
-                } else {
-                    JSValue ops[2];
-                add_loc_slow:
-                    /* In case of exception, js_add_slow frees ops[0]
-                       and ops[1], so we must duplicate *pv */
-                    ops[0] = JS_DupValue(ctx, *pv);
-                    ops[1] = sp[-1];
-                    sp--;
-                    if (js_add_slow(ctx, ops + 2))
-                        goto exception;
-                    set_value(ctx, pv, ops[0]);
-                }
-            }
-            BREAK;
-        CASE(OP_sub):
-            {
-                JSValue op1, op2;
-                op1 = sp[-2];
-                op2 = sp[-1];
-                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
-                    int64_t r;
-                    r = (int64_t)JS_VALUE_GET_INT(op1) - JS_VALUE_GET_INT(op2);
-                    if (unlikely((int)r != r))
-                        goto binary_arith_slow;
-                    sp[-2] = JS_NewInt32(ctx, r);
-                    sp--;
-                } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
-                    sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) -
-                                             JS_VALUE_GET_FLOAT64(op2));
-                    sp--;
-                } else {
-                    goto binary_arith_slow;
-                }
-            }
-            BREAK;
-        CASE(OP_mul):
-            {
-                JSValue op1, op2;
-                double d;
-                op1 = sp[-2];
-                op2 = sp[-1];
-                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
-                    int32_t v1, v2;
-                    int64_t r;
-                    v1 = JS_VALUE_GET_INT(op1);
-                    v2 = JS_VALUE_GET_INT(op2);
-                    r = (int64_t)v1 * v2;
-                    if (unlikely((int)r != r)) {
-#ifdef CONFIG_BIGNUM
-                        if (unlikely(sf->js_mode & JS_MODE_MATH) &&
-                            (r < -MAX_SAFE_INTEGER || r > MAX_SAFE_INTEGER))
-                            goto binary_arith_slow;
-#endif
-                        d = (double)r;
-                        goto mul_fp_res;
-                    }
-                    /* need to test zero case for -0 result */
-                    if (unlikely(r == 0 && (v1 | v2) < 0)) {
-                        d = -0.0;
-                        goto mul_fp_res;
-                    }
-                    sp[-2] = JS_NewInt32(ctx, r);
-                    sp--;
-                } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
-#ifdef CONFIG_BIGNUM
-                    if (unlikely(sf->js_mode & JS_MODE_MATH))
-                        goto binary_arith_slow;
-#endif
-                    d = JS_VALUE_GET_FLOAT64(op1) * JS_VALUE_GET_FLOAT64(op2);
-                mul_fp_res:
-                    sp[-2] = __JS_NewFloat64(ctx, d);
-                    sp--;
-                } else {
-                    goto binary_arith_slow;
-                }
-            }
-            BREAK;
-        CASE(OP_div):
-            {
-                JSValue op1, op2;
-                op1 = sp[-2];
-                op2 = sp[-1];
-                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
-                    int v1, v2;
-                    if (unlikely(sf->js_mode & JS_MODE_MATH))
-                        goto binary_arith_slow;
-                    v1 = JS_VALUE_GET_INT(op1);
-                    v2 = JS_VALUE_GET_INT(op2);
-                    sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2);
-                    sp--;
-                } else {
-                    goto binary_arith_slow;
-                }
-            }
-            BREAK;
-        CASE(OP_mod):
-#ifdef CONFIG_BIGNUM
-        CASE(OP_math_mod):
-#endif
-            {
-                JSValue op1, op2;
-                op1 = sp[-2];
-                op2 = sp[-1];
-                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
-                    int v1, v2, r;
-                    v1 = JS_VALUE_GET_INT(op1);
-                    v2 = JS_VALUE_GET_INT(op2);
-                    /* We must avoid v2 = 0, v1 = INT32_MIN and v2 =
-                       -1 and the cases where the result is -0. */
-                    if (unlikely(v1 < 0 || v2 <= 0))
-                        goto binary_arith_slow;
-                    r = v1 % v2;
-                    sp[-2] = JS_NewInt32(ctx, r);
-                    sp--;
-                } else {
-                    goto binary_arith_slow;
-                }
-            }
-            BREAK;
-        CASE(OP_pow):
-        binary_arith_slow:
-            if (js_binary_arith_slow(ctx, sp, opcode))
-                goto exception;
-            sp--;
-            BREAK;
-
-        CASE(OP_plus):
-            {
-                JSValue op1;
-                uint32_t tag;
-                op1 = sp[-1];
-                tag = JS_VALUE_GET_TAG(op1);
-                if (tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag)) {
-                } else {
-                    if (js_unary_arith_slow(ctx, sp, opcode))
-                        goto exception;
-                }
-            }
-            BREAK;
-        CASE(OP_neg):
-            {
-                JSValue op1;
-                uint32_t tag;
-                int val;
-                double d;
-                op1 = sp[-1];
-                tag = JS_VALUE_GET_TAG(op1);
-                if (tag == JS_TAG_INT) {
-                    val = JS_VALUE_GET_INT(op1);
-                    /* Note: -0 cannot be expressed as integer */
-                    if (unlikely(val == 0)) {
-                        d = -0.0;
-                        goto neg_fp_res;
-                    }
-                    if (unlikely(val == INT32_MIN)) {
-                        d = -(double)val;
-                        goto neg_fp_res;
-                    }
-                    sp[-1] = JS_NewInt32(ctx, -val);
-                } else if (JS_TAG_IS_FLOAT64(tag)) {
-                    d = -JS_VALUE_GET_FLOAT64(op1);
-                neg_fp_res:
-                    sp[-1] = __JS_NewFloat64(ctx, d);
-                } else {
-                    if (js_unary_arith_slow(ctx, sp, opcode))
-                        goto exception;
-                }
-            }
-            BREAK;
-        CASE(OP_inc):
-            {
-                JSValue op1;
-                int val;
-                op1 = sp[-1];
-                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
-                    val = JS_VALUE_GET_INT(op1);
-                    if (unlikely(val == INT32_MAX))
-                        goto inc_slow;
-                    sp[-1] = JS_NewInt32(ctx, val + 1);
-                } else {
-                inc_slow:
-                    if (js_unary_arith_slow(ctx, sp, opcode))
-                        goto exception;
-                }
-            }
-            BREAK;
-        CASE(OP_dec):
-            {
-                JSValue op1;
-                int val;
-                op1 = sp[-1];
-                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
-                    val = JS_VALUE_GET_INT(op1);
-                    if (unlikely(val == INT32_MIN))
-                        goto dec_slow;
-                    sp[-1] = JS_NewInt32(ctx, val - 1);
-                } else {
-                dec_slow:
-                    if (js_unary_arith_slow(ctx, sp, opcode))
-                        goto exception;
-                }
-            }
-            BREAK;
-        CASE(OP_post_inc):
-        CASE(OP_post_dec):
-            if (js_post_inc_slow(ctx, sp, opcode))
-                goto exception;
-            sp++;
-            BREAK;
-        CASE(OP_inc_loc):
-            {
-                JSValue op1;
-                int val;
-                int idx;
-                idx = *pc;
-                pc += 1;
-
-                op1 = var_buf[idx];
-                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
-                    val = JS_VALUE_GET_INT(op1);
-                    if (unlikely(val == INT32_MAX))
-                        goto inc_loc_slow;
-                    var_buf[idx] = JS_NewInt32(ctx, val + 1);
-                } else {
-                inc_loc_slow:
-                    /* must duplicate otherwise the variable value may
-                       be destroyed before JS code accesses it */
-                    op1 = JS_DupValue(ctx, op1);
-                    if (js_unary_arith_slow(ctx, &op1 + 1, OP_inc))
-                        goto exception;
-                    set_value(ctx, &var_buf[idx], op1);
-                }
-            }
-            BREAK;
-        CASE(OP_dec_loc):
-            {
-                JSValue op1;
-                int val;
-                int idx;
-                idx = *pc;
-                pc += 1;
-
-                op1 = var_buf[idx];
-                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
-                    val = JS_VALUE_GET_INT(op1);
-                    if (unlikely(val == INT32_MIN))
-                        goto dec_loc_slow;
-                    var_buf[idx] = JS_NewInt32(ctx, val - 1);
-                } else {
-                dec_loc_slow:
-                    /* must duplicate otherwise the variable value may
-                       be destroyed before JS code accesses it */
-                    op1 = JS_DupValue(ctx, op1);
-                    if (js_unary_arith_slow(ctx, &op1 + 1, OP_dec))
-                        goto exception;
-                    set_value(ctx, &var_buf[idx], op1);
-                }
-            }
-            BREAK;
-        CASE(OP_not):
-            {
-                JSValue op1;
-                op1 = sp[-1];
-                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
-                    sp[-1] = JS_NewInt32(ctx, ~JS_VALUE_GET_INT(op1));
-                } else {
-                    if (js_not_slow(ctx, sp))
-                        goto exception;
-                }
-            }
-            BREAK;
-
-        CASE(OP_shl):
-            {
-                JSValue op1, op2;
-                op1 = sp[-2];
-                op2 = sp[-1];
-                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
-                    uint32_t v1, v2;
-                    v1 = JS_VALUE_GET_INT(op1);
-                    v2 = JS_VALUE_GET_INT(op2);
-#ifdef CONFIG_BIGNUM
-                    {
-                        int64_t r;
-                        if (unlikely(sf->js_mode & JS_MODE_MATH)) {
-                            if (v2 > 0x1f)
-                                goto shl_slow;
-                            r = (int64_t)v1 << v2;
-                            if ((int)r != r)
-                                goto shl_slow;
-                        } else {
-                            v2 &= 0x1f;
-                        }
-                    }
-#else
-                    v2 &= 0x1f;
-#endif
-                    sp[-2] = JS_NewInt32(ctx, v1 << v2);
-                    sp--;
-                } else {
-#ifdef CONFIG_BIGNUM
-                shl_slow:
-#endif
-                    if (js_binary_logic_slow(ctx, sp, opcode))
-                        goto exception;
-                    sp--;
-                }
-            }
-            BREAK;
-        CASE(OP_shr):
-            {
-                JSValue op1, op2;
-                op1 = sp[-2];
-                op2 = sp[-1];
-                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
-                    uint32_t v2;
-                    v2 = JS_VALUE_GET_INT(op2);
-                    /* v1 >>> v2 retains its JS semantics if CONFIG_BIGNUM */
-                    v2 &= 0x1f;
-                    sp[-2] = JS_NewUint32(ctx,
-                                          (uint32_t)JS_VALUE_GET_INT(op1) >>
-                                          v2);
-                    sp--;
-                } else {
-                    if (js_shr_slow(ctx, sp))
-                        goto exception;
-                    sp--;
-                }
-            }
-            BREAK;
-        CASE(OP_sar):
-            {
-                JSValue op1, op2;
-                op1 = sp[-2];
-                op2 = sp[-1];
-                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
-                    uint32_t v2;
-                    v2 = JS_VALUE_GET_INT(op2);
-#ifdef CONFIG_BIGNUM
-                    if (unlikely(v2 > 0x1f)) {
-                        if (unlikely(sf->js_mode & JS_MODE_MATH))
-                            goto sar_slow;
-                        else
-                            v2 &= 0x1f;
-                    }
-#else
-                    v2 &= 0x1f;
-#endif
-                    sp[-2] = JS_NewInt32(ctx,
-                                          (int)JS_VALUE_GET_INT(op1) >> v2);
-                    sp--;
-                } else {
-#ifdef CONFIG_BIGNUM
-                sar_slow:
-#endif
-                    if (js_binary_logic_slow(ctx, sp, opcode))
-                        goto exception;
-                    sp--;
-                }
-            }
-            BREAK;
-        CASE(OP_and):
-            {
-                JSValue op1, op2;
-                op1 = sp[-2];
-                op2 = sp[-1];
-                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
-                    sp[-2] = JS_NewInt32(ctx,
-                                         JS_VALUE_GET_INT(op1) &
-                                         JS_VALUE_GET_INT(op2));
-                    sp--;
-                } else {
-                    if (js_binary_logic_slow(ctx, sp, opcode))
-                        goto exception;
-                    sp--;
-                }
-            }
-            BREAK;
-        CASE(OP_or):
-            {
-                JSValue op1, op2;
-                op1 = sp[-2];
-                op2 = sp[-1];
-                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
-                    sp[-2] = JS_NewInt32(ctx,
-                                         JS_VALUE_GET_INT(op1) |
-                                         JS_VALUE_GET_INT(op2));
-                    sp--;
-                } else {
-                    if (js_binary_logic_slow(ctx, sp, opcode))
-                        goto exception;
-                    sp--;
-                }
-            }
-            BREAK;
-        CASE(OP_xor):
-            {
-                JSValue op1, op2;
-                op1 = sp[-2];
-                op2 = sp[-1];
-                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
-                    sp[-2] = JS_NewInt32(ctx,
-                                         JS_VALUE_GET_INT(op1) ^
-                                         JS_VALUE_GET_INT(op2));
-                    sp--;
-                } else {
-                    if (js_binary_logic_slow(ctx, sp, opcode))
-                        goto exception;
-                    sp--;
-                }
-            }
-            BREAK;
-
-
-#define OP_CMP(opcode, binary_op, slow_call)              \
-            CASE(opcode):                                 \
-                {                                         \
-                JSValue op1, op2;                         \
-                op1 = sp[-2];                             \
-                op2 = sp[-1];                                   \
-                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {           \
-                    sp[-2] = JS_NewBool(ctx, JS_VALUE_GET_INT(op1) binary_op JS_VALUE_GET_INT(op2)); \
-                    sp--;                                               \
-                } else {                                                \
-                    if (slow_call)                                      \
-                        goto exception;                                 \
-                    sp--;                                               \
-                }                                                       \
-                }                                                       \
-            BREAK
-
-            OP_CMP(OP_lt, <, js_relational_slow(ctx, sp, opcode));
-            OP_CMP(OP_lte, <=, js_relational_slow(ctx, sp, opcode));
-            OP_CMP(OP_gt, >, js_relational_slow(ctx, sp, opcode));
-            OP_CMP(OP_gte, >=, js_relational_slow(ctx, sp, opcode));
-            OP_CMP(OP_eq, ==, js_eq_slow(ctx, sp, 0));
-            OP_CMP(OP_neq, !=, js_eq_slow(ctx, sp, 1));
-            OP_CMP(OP_strict_eq, ==, js_strict_eq_slow(ctx, sp, 0));
-            OP_CMP(OP_strict_neq, !=, js_strict_eq_slow(ctx, sp, 1));
-
-#ifdef CONFIG_BIGNUM
-        CASE(OP_mul_pow10):
-            if (rt->bigfloat_ops.mul_pow10(ctx, sp))
-                goto exception;
-            sp--;
-            BREAK;
-#endif
-        CASE(OP_in):
-            if (js_operator_in(ctx, sp))
-                goto exception;
-            sp--;
-            BREAK;
-        CASE(OP_instanceof):
-            if (js_operator_instanceof(ctx, sp))
-                goto exception;
-            sp--;
-            BREAK;
-        CASE(OP_typeof):
-            {
-                JSValue op1;
-                JSAtom atom;
-
-                op1 = sp[-1];
-                atom = js_operator_typeof(ctx, op1);
-                JS_FreeValue(ctx, op1);
-                sp[-1] = JS_AtomToString(ctx, atom);
-            }
-            BREAK;
-        CASE(OP_delete):
-            if (js_operator_delete(ctx, sp))
-                goto exception;
-            sp--;
-            BREAK;
-        CASE(OP_delete_var):
-            {
-                JSAtom atom;
-                int ret;
-
-                atom = get_u32(pc);
-                pc += 4;
-
-                ret = JS_DeleteProperty(ctx, ctx->global_obj, atom, 0);
-                if (unlikely(ret < 0))
-                    goto exception;
-                *sp++ = JS_NewBool(ctx, ret);
-            }
-            BREAK;
-
-        CASE(OP_to_object):
-            if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_OBJECT) {
-                ret_val = JS_ToObject(ctx, sp[-1]);
-                if (JS_IsException(ret_val))
-                    goto exception;
-                JS_FreeValue(ctx, sp[-1]);
-                sp[-1] = ret_val;
-            }
-            BREAK;
-
-        CASE(OP_to_propkey):
-            switch (JS_VALUE_GET_TAG(sp[-1])) {
-            case JS_TAG_INT:
-            case JS_TAG_STRING:
-            case JS_TAG_SYMBOL:
-                break;
-            default:
-                ret_val = JS_ToPropertyKey(ctx, sp[-1]);
-                if (JS_IsException(ret_val))
-                    goto exception;
-                JS_FreeValue(ctx, sp[-1]);
-                sp[-1] = ret_val;
-                break;
-            }
-            BREAK;
-
-        CASE(OP_to_propkey2):
-            /* must be tested first */
-            if (unlikely(JS_IsUndefined(sp[-2]) || JS_IsNull(sp[-2]))) {
-                JS_ThrowTypeError(ctx, "value has no property");
-                goto exception;
-            }
-            switch (JS_VALUE_GET_TAG(sp[-1])) {
-            case JS_TAG_INT:
-            case JS_TAG_STRING:
-            case JS_TAG_SYMBOL:
-                break;
-            default:
-                ret_val = JS_ToPropertyKey(ctx, sp[-1]);
-                if (JS_IsException(ret_val))
-                    goto exception;
-                JS_FreeValue(ctx, sp[-1]);
-                sp[-1] = ret_val;
-                break;
-            }
-            BREAK;
-#if 0
-        CASE(OP_to_string):
-            if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_STRING) {
-                ret_val = JS_ToString(ctx, sp[-1]);
-                if (JS_IsException(ret_val))
-                    goto exception;
-                JS_FreeValue(ctx, sp[-1]);
-                sp[-1] = ret_val;
-            }
-            BREAK;
-#endif
-        CASE(OP_with_get_var):
-        CASE(OP_with_put_var):
-        CASE(OP_with_delete_var):
-        CASE(OP_with_make_ref):
-        CASE(OP_with_get_ref):
-        CASE(OP_with_get_ref_undef):
-            {
-                JSAtom atom;
-                int32_t diff;
-                JSValue obj, val;
-                int ret, is_with;
-                atom = get_u32(pc);
-                diff = get_u32(pc + 4);
-                is_with = pc[8];
-                pc += 9;
-
-                obj = sp[-1];
-                ret = JS_HasProperty(ctx, obj, atom);
-                if (unlikely(ret < 0))
-                    goto exception;
-                if (ret) {
-                    if (is_with) {
-                        ret = js_has_unscopable(ctx, obj, atom);
-                        if (unlikely(ret < 0))
-                            goto exception;
-                        if (ret)
-                            goto no_with;
-                    }
-                    switch (opcode) {
-                    case OP_with_get_var:
-                        val = JS_GetProperty(ctx, obj, atom);
-                        if (unlikely(JS_IsException(val)))
-                            goto exception;
-                        set_value(ctx, &sp[-1], val);
-                        break;
-                    case OP_with_put_var:
-                        /* XXX: check if strict mode */
-                        ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2],
-                                                     JS_PROP_THROW_STRICT);
-                        JS_FreeValue(ctx, sp[-1]);
-                        sp -= 2;
-                        if (unlikely(ret < 0))
-                            goto exception;
-                        break;
-                    case OP_with_delete_var:
-                        ret = JS_DeleteProperty(ctx, obj, atom, 0);
-                        if (unlikely(ret < 0))
-                            goto exception;
-                        JS_FreeValue(ctx, sp[-1]);
-                        sp[-1] = JS_NewBool(ctx, ret);
-                        break;
-                    case OP_with_make_ref:
-                        /* produce a pair object/propname on the stack */
-                        *sp++ = JS_AtomToValue(ctx, atom);
-                        break;
-                    case OP_with_get_ref:
-                        /* produce a pair object/method on the stack */
-                        val = JS_GetProperty(ctx, obj, atom);
-                        if (unlikely(JS_IsException(val)))
-                            goto exception;
-                        *sp++ = val;
-                        break;
-                    case OP_with_get_ref_undef:
-                        /* produce a pair undefined/function on the stack */
-                        val = JS_GetProperty(ctx, obj, atom);
-                        if (unlikely(JS_IsException(val)))
-                            goto exception;
-                        JS_FreeValue(ctx, sp[-1]);
-                        sp[-1] = JS_UNDEFINED;
-                        *sp++ = val;
-                        break;
-                    }
-                    pc += diff - 5;
-                } else {
-                no_with:
-                    /* if not jumping, drop the object argument */
-                    JS_FreeValue(ctx, sp[-1]);
-                    sp--;
-                }
-            }
-            BREAK;
-
-        CASE(OP_await):
-            ret_val = JS_NewInt32(ctx, FUNC_RET_AWAIT);
-            goto done_generator;
-        CASE(OP_yield):
-            ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD);
-            goto done_generator;
-        CASE(OP_yield_star):
-        CASE(OP_async_yield_star):
-            ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD_STAR);
-            goto done_generator;
-        CASE(OP_return_async):
-        CASE(OP_initial_yield):
-            ret_val = JS_UNDEFINED;
-            goto done_generator;
-
-        CASE(OP_nop):
-            BREAK;
-        CASE(OP_is_undefined_or_null):
-            if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED ||
-                JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) {
-                goto set_true;
-            } else {
-                goto free_and_set_false;
-            }
-#if SHORT_OPCODES
-        CASE(OP_is_undefined):
-            if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED) {
-                goto set_true;
-            } else {
-                goto free_and_set_false;
-            }
-        CASE(OP_is_null):
-            if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) {
-                goto set_true;
-            } else {
-                goto free_and_set_false;
-            }
-            /* XXX: could merge to a single opcode */
-        CASE(OP_typeof_is_undefined):
-            /* different from OP_is_undefined because of isHTMLDDA */
-            if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_undefined) {
-                goto free_and_set_true;
-            } else {
-                goto free_and_set_false;
-            }
-        CASE(OP_typeof_is_function):
-            if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_function) {
-                goto free_and_set_true;
-            } else {
-                goto free_and_set_false;
-            }
-        free_and_set_true:
-            JS_FreeValue(ctx, sp[-1]);
-#endif
-        set_true:
-            sp[-1] = JS_TRUE;
-            BREAK;
-        free_and_set_false:
-            JS_FreeValue(ctx, sp[-1]);
-            sp[-1] = JS_FALSE;
-            BREAK;
-        CASE(OP_invalid):
-        DEFAULT:
-            JS_ThrowInternalError(ctx, "invalid opcode: pc=%u opcode=0x%02x",
-                                  (int)(pc - b->byte_code_buf - 1), opcode);
-            goto exception;
-        }
-    }
- exception:
-    if (is_backtrace_needed(ctx, rt->current_exception)) {
-        /* add the backtrace information now (it is not done
-           before if the exception happens in a bytecode
-           operation */
-        sf->cur_pc = pc;
-        build_backtrace(ctx, rt->current_exception, NULL, 0, 0);
-    }
-    if (!JS_IsUncatchableError(ctx, rt->current_exception)) {
-        while (sp > stack_buf) {
-            JSValue val = *--sp;
-            JS_FreeValue(ctx, val);
-            if (JS_VALUE_GET_TAG(val) == JS_TAG_CATCH_OFFSET) {
-                int pos = JS_VALUE_GET_INT(val);
-                if (pos == 0) {
-                    /* enumerator: close it with a throw */
-                    JS_FreeValue(ctx, sp[-1]); /* drop the next method */
-                    sp--;
-                    JS_IteratorClose(ctx, sp[-1], TRUE);
-                } else {
-                    *sp++ = rt->current_exception;
-                    rt->current_exception = JS_NULL;
-                    pc = b->byte_code_buf + pos;
-                    goto restart;
-                }
-            }
-        }
-    }
-    ret_val = JS_EXCEPTION;
-    /* the local variables are freed by the caller in the generator
-       case. Hence the label 'done' should never be reached in a
-       generator function. */
-    if (b->func_kind != JS_FUNC_NORMAL) {
-    done_generator:
-        sf->cur_pc = pc;
-        sf->cur_sp = sp;
-    } else {
-    done:
-        if (unlikely(!list_empty(&sf->var_ref_list))) {
-            /* variable references reference the stack: must close them */
-            close_var_refs(rt, sf);
-        }
-        /* free the local variables and stack */
-        for(pval = local_buf; pval < sp; pval++) {
-            JS_FreeValue(ctx, *pval);
-        }
-    }
-    rt->current_stack_frame = sf->prev_frame;
-    return ret_val;
-}
-
-JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj,
-                int argc, JSValueConst *argv)
-{
-    return JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED,
-                           argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV);
-}
-
-static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj,
-                           int argc, JSValueConst *argv)
-{
-    JSValue res = JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED,
-                                  argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV);
-    JS_FreeValue(ctx, func_obj);
-    return res;
-}
-
-/* warning: the refcount of the context is not incremented. Return
-   NULL in case of exception (case of revoked proxy only) */
-static JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValueConst func_obj)
-{
-    JSObject *p;
-    JSContext *realm;
-    
-    if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
-        return ctx;
-    p = JS_VALUE_GET_OBJ(func_obj);
-    switch(p->class_id) {
-    case JS_CLASS_C_FUNCTION:
-        realm = p->u.cfunc.realm;
-        break;
-    case JS_CLASS_BYTECODE_FUNCTION:
-    case JS_CLASS_GENERATOR_FUNCTION:
-    case JS_CLASS_ASYNC_FUNCTION:
-    case JS_CLASS_ASYNC_GENERATOR_FUNCTION:
-        {
-            JSFunctionBytecode *b;
-            b = p->u.func.function_bytecode;
-            realm = b->realm;
-        }
-        break;
-    case JS_CLASS_PROXY:
-        {
-            JSProxyData *s = p->u.opaque;
-            if (!s)
-                return ctx;
-            if (s->is_revoked) {
-                JS_ThrowTypeErrorRevokedProxy(ctx);
-                return NULL;
-            } else {
-                realm = JS_GetFunctionRealm(ctx, s->target);
-            }
-        }
-        break;
-    case JS_CLASS_BOUND_FUNCTION:
-        {
-            JSBoundFunction *bf = p->u.bound_function;
-            realm = JS_GetFunctionRealm(ctx, bf->func_obj);
-        }
-        break;
-    default:
-        realm = ctx;
-        break;
-    }
-    return realm;
-}
-
-static JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor,
-                                   int class_id)
-{
-    JSValue proto, obj;
-    JSContext *realm;
-    
-    if (JS_IsUndefined(ctor)) {
-        proto = JS_DupValue(ctx, ctx->class_proto[class_id]);
-    } else {
-        proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);
-        if (JS_IsException(proto))
-            return proto;
-        if (!JS_IsObject(proto)) {
-            JS_FreeValue(ctx, proto);
-            realm = JS_GetFunctionRealm(ctx, ctor);
-            if (!realm)
-                return JS_EXCEPTION;
-            proto = JS_DupValue(ctx, realm->class_proto[class_id]);
-        }
-    }
-    obj = JS_NewObjectProtoClass(ctx, proto, class_id);
-    JS_FreeValue(ctx, proto);
-    return obj;
-}
-
-/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */
-static JSValue JS_CallConstructorInternal(JSContext *ctx,
-                                          JSValueConst func_obj,
-                                          JSValueConst new_target,
-                                          int argc, JSValue *argv, int flags)
-{
-    JSObject *p;
-    JSFunctionBytecode *b;
-
-    if (js_poll_interrupts(ctx))
-        return JS_EXCEPTION;
-    flags |= JS_CALL_FLAG_CONSTRUCTOR;
-    if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT))
-        goto not_a_function;
-    p = JS_VALUE_GET_OBJ(func_obj);
-    if (unlikely(!p->is_constructor))
-        return JS_ThrowTypeError(ctx, "not a constructor");
-    if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {
-        JSClassCall *call_func;
-        call_func = ctx->rt->class_array[p->class_id].call;
-        if (!call_func) {
-        not_a_function:
-            return JS_ThrowTypeError(ctx, "not a function");
-        }
-        return call_func(ctx, func_obj, new_target, argc,
-                         (JSValueConst *)argv, flags);
-    }
-
-    b = p->u.func.function_bytecode;
-    if (b->is_derived_class_constructor) {
-        return JS_CallInternal(ctx, func_obj, JS_UNDEFINED, new_target, argc, argv, flags);
-    } else {
-        JSValue obj, ret;
-        /* legacy constructor behavior */
-        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
-        if (JS_IsException(obj))
-            return JS_EXCEPTION;
-        ret = JS_CallInternal(ctx, func_obj, obj, new_target, argc, argv, flags);
-        if (JS_VALUE_GET_TAG(ret) == JS_TAG_OBJECT ||
-            JS_IsException(ret)) {
-            JS_FreeValue(ctx, obj);
-            return ret;
-        } else {
-            JS_FreeValue(ctx, ret);
-            return obj;
-        }
-    }
-}
-
-JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj,
-                            JSValueConst new_target,
-                            int argc, JSValueConst *argv)
-{
-    return JS_CallConstructorInternal(ctx, func_obj, new_target,
-                                      argc, (JSValue *)argv,
-                                      JS_CALL_FLAG_COPY_ARGV);
-}
-
-JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj,
-                           int argc, JSValueConst *argv)
-{
-    return JS_CallConstructorInternal(ctx, func_obj, func_obj,
-                                      argc, (JSValue *)argv,
-                                      JS_CALL_FLAG_COPY_ARGV);
-}
-
-JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom,
-                  int argc, JSValueConst *argv)
-{
-    JSValue func_obj;
-    func_obj = JS_GetProperty(ctx, this_val, atom);
-    if (JS_IsException(func_obj))
-        return func_obj;
-    return JS_CallFree(ctx, func_obj, this_val, argc, argv);
-}
-
-static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
-                             int argc, JSValueConst *argv)
-{
-    JSValue res = JS_Invoke(ctx, this_val, atom, argc, argv);
-    JS_FreeValue(ctx, this_val);
-    return res;
-}
-
-/* JSAsyncFunctionState (used by generator and async functions) */
-static __exception int async_func_init(JSContext *ctx, JSAsyncFunctionState *s,
-                                       JSValueConst func_obj, JSValueConst this_obj,
-                                       int argc, JSValueConst *argv)
-{
-    JSObject *p;
-    JSFunctionBytecode *b;
-    JSStackFrame *sf;
-    int local_count, i, arg_buf_len, n;
-
-    sf = &s->frame;
-    init_list_head(&sf->var_ref_list);
-    p = JS_VALUE_GET_OBJ(func_obj);
-    b = p->u.func.function_bytecode;
-    sf->js_mode = b->js_mode;
-    sf->cur_pc = b->byte_code_buf;
-    arg_buf_len = max_int(b->arg_count, argc);
-    local_count = arg_buf_len + b->var_count + b->stack_size;
-    sf->arg_buf = js_malloc(ctx, sizeof(JSValue) * max_int(local_count, 1));
-    if (!sf->arg_buf)
-        return -1;
-    sf->cur_func = JS_DupValue(ctx, func_obj);
-    s->this_val = JS_DupValue(ctx, this_obj);
-    s->argc = argc;
-    sf->arg_count = arg_buf_len;
-    sf->var_buf = sf->arg_buf + arg_buf_len;
-    sf->cur_sp = sf->var_buf + b->var_count;
-    for(i = 0; i < argc; i++)
-        sf->arg_buf[i] = JS_DupValue(ctx, argv[i]);
-    n = arg_buf_len + b->var_count;
-    for(i = argc; i < n; i++)
-        sf->arg_buf[i] = JS_UNDEFINED;
-    return 0;
-}
-
-static void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s,
-                            JS_MarkFunc *mark_func)
-{
-    JSStackFrame *sf;
-    JSValue *sp;
-
-    sf = &s->frame;
-    JS_MarkValue(rt, sf->cur_func, mark_func);
-    JS_MarkValue(rt, s->this_val, mark_func);
-    if (sf->cur_sp) {
-        /* if the function is running, cur_sp is not known so we
-           cannot mark the stack. Marking the variables is not needed
-           because a running function cannot be part of a removable
-           cycle */
-        for(sp = sf->arg_buf; sp < sf->cur_sp; sp++)
-            JS_MarkValue(rt, *sp, mark_func);
-    }
-}
-
-static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
-{
-    JSStackFrame *sf;
-    JSValue *sp;
-
-    sf = &s->frame;
-
-    /* close the closure variables. */
-    close_var_refs(rt, sf);
-    
-    if (sf->arg_buf) {
-        /* cannot free the function if it is running */
-        assert(sf->cur_sp != NULL);
-        for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) {
-            JS_FreeValueRT(rt, *sp);
-        }
-        js_free_rt(rt, sf->arg_buf);
-    }
-    JS_FreeValueRT(rt, sf->cur_func);
-    JS_FreeValueRT(rt, s->this_val);
-}
-
-static JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s)
-{
-    JSValue func_obj;
-
-    if (js_check_stack_overflow(ctx->rt, 0))
-        return JS_ThrowStackOverflow(ctx);
-
-    /* the tag does not matter provided it is not an object */
-    func_obj = JS_MKPTR(JS_TAG_INT, s);
-    return JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED,
-                           s->argc, s->frame.arg_buf, JS_CALL_FLAG_GENERATOR);
-}
-
-
-/* Generators */
-
-typedef enum JSGeneratorStateEnum {
-    JS_GENERATOR_STATE_SUSPENDED_START,
-    JS_GENERATOR_STATE_SUSPENDED_YIELD,
-    JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR,
-    JS_GENERATOR_STATE_EXECUTING,
-    JS_GENERATOR_STATE_COMPLETED,
-} JSGeneratorStateEnum;
-
-typedef struct JSGeneratorData {
-    JSGeneratorStateEnum state;
-    JSAsyncFunctionState func_state;
-} JSGeneratorData;
-
-static void free_generator_stack_rt(JSRuntime *rt, JSGeneratorData *s)
-{
-    if (s->state == JS_GENERATOR_STATE_COMPLETED)
-        return;
-    async_func_free(rt, &s->func_state);
-    s->state = JS_GENERATOR_STATE_COMPLETED;
-}
-
-static void js_generator_finalizer(JSRuntime *rt, JSValue obj)
-{
-    JSGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_GENERATOR);
-
-    if (s) {
-        free_generator_stack_rt(rt, s);
-        js_free_rt(rt, s);
-    }
-}
-
-static void free_generator_stack(JSContext *ctx, JSGeneratorData *s)
-{
-    free_generator_stack_rt(ctx->rt, s);
-}
-
-static void js_generator_mark(JSRuntime *rt, JSValueConst val,
-                              JS_MarkFunc *mark_func)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    JSGeneratorData *s = p->u.generator_data;
-
-    if (!s || s->state == JS_GENERATOR_STATE_COMPLETED)
-        return;
-    async_func_mark(rt, &s->func_state, mark_func);
-}
-
-/* XXX: use enum */
-#define GEN_MAGIC_NEXT   0
-#define GEN_MAGIC_RETURN 1
-#define GEN_MAGIC_THROW  2
-
-static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv,
-                                 BOOL *pdone, int magic)
-{
-    JSGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_GENERATOR);
-    JSStackFrame *sf;
-    JSValue ret, func_ret;
-
-    *pdone = TRUE;
-    if (!s)
-        return JS_ThrowTypeError(ctx, "not a generator");
-    sf = &s->func_state.frame;
-    switch(s->state) {
-    default:
-    case JS_GENERATOR_STATE_SUSPENDED_START:
-        if (magic == GEN_MAGIC_NEXT) {
-            goto exec_no_arg;
-        } else {
-            free_generator_stack(ctx, s);
-            goto done;
-        }
-        break;
-    case JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
-    case JS_GENERATOR_STATE_SUSPENDED_YIELD:
-        /* cur_sp[-1] was set to JS_UNDEFINED in the previous call */
-        ret = JS_DupValue(ctx, argv[0]);
-        if (magic == GEN_MAGIC_THROW &&
-            s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) {
-            JS_Throw(ctx, ret);
-            s->func_state.throw_flag = TRUE;
-        } else {
-            sf->cur_sp[-1] = ret;
-            sf->cur_sp[0] = JS_NewInt32(ctx, magic);
-            sf->cur_sp++;
-        exec_no_arg:
-            s->func_state.throw_flag = FALSE;
-        }
-        s->state = JS_GENERATOR_STATE_EXECUTING;
-        func_ret = async_func_resume(ctx, &s->func_state);
-        s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD;
-        if (JS_IsException(func_ret)) {
-            /* finalize the execution in case of exception */
-            free_generator_stack(ctx, s);
-            return func_ret;
-        }
-        if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) {
-            /* get the returned yield value at the top of the stack */
-            ret = sf->cur_sp[-1];
-            sf->cur_sp[-1] = JS_UNDEFINED;
-            if (JS_VALUE_GET_INT(func_ret) == FUNC_RET_YIELD_STAR) {
-                s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
-                /* return (value, done) object */
-                *pdone = 2;
-            } else {
-                *pdone = FALSE;
-            }
-        } else {
-            /* end of iterator */
-            ret = sf->cur_sp[-1];
-            sf->cur_sp[-1] = JS_UNDEFINED;
-            JS_FreeValue(ctx, func_ret);
-            free_generator_stack(ctx, s);
-        }
-        break;
-    case JS_GENERATOR_STATE_COMPLETED:
-    done:
-        /* execution is finished */
-        switch(magic) {
-        default:
-        case GEN_MAGIC_NEXT:
-            ret = JS_UNDEFINED;
-            break;
-        case GEN_MAGIC_RETURN:
-            ret = JS_DupValue(ctx, argv[0]);
-            break;
-        case GEN_MAGIC_THROW:
-            ret = JS_Throw(ctx, JS_DupValue(ctx, argv[0]));
-            break;
-        }
-        break;
-    case JS_GENERATOR_STATE_EXECUTING:
-        ret = JS_ThrowTypeError(ctx, "cannot invoke a running generator");
-        break;
-    }
-    return ret;
-}
-
-static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
-                                          JSValueConst this_obj,
-                                          int argc, JSValueConst *argv,
-                                          int flags)
-{
-    JSValue obj, func_ret;
-    JSGeneratorData *s;
-
-    s = js_mallocz(ctx, sizeof(*s));
-    if (!s)
-        return JS_EXCEPTION;
-    s->state = JS_GENERATOR_STATE_SUSPENDED_START;
-    if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
-        s->state = JS_GENERATOR_STATE_COMPLETED;
-        goto fail;
-    }
-
-    /* execute the function up to 'OP_initial_yield' */
-    func_ret = async_func_resume(ctx, &s->func_state);
-    if (JS_IsException(func_ret))
-        goto fail;
-    JS_FreeValue(ctx, func_ret);
-
-    obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_GENERATOR);
-    if (JS_IsException(obj))
-        goto fail;
-    JS_SetOpaque(obj, s);
-    return obj;
- fail:
-    free_generator_stack_rt(ctx->rt, s);
-    js_free(ctx, s);
-    return JS_EXCEPTION;
-}
-
-/* AsyncFunction */
-
-static void js_async_function_terminate(JSRuntime *rt, JSAsyncFunctionData *s)
-{
-    if (s->is_active) {
-        async_func_free(rt, &s->func_state);
-        s->is_active = FALSE;
-    }
-}
-
-static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s)
-{
-    js_async_function_terminate(rt, s);
-    JS_FreeValueRT(rt, s->resolving_funcs[0]);
-    JS_FreeValueRT(rt, s->resolving_funcs[1]);
-    remove_gc_object(&s->header);
-    js_free_rt(rt, s);
-}
-
-static void js_async_function_free(JSRuntime *rt, JSAsyncFunctionData *s)
-{
-    if (--s->header.ref_count == 0) {
-        js_async_function_free0(rt, s);
-    }
-}
-
-static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    JSAsyncFunctionData *s = p->u.async_function_data;
-    if (s) {
-        js_async_function_free(rt, s);
-    }
-}
-
-static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,
-                                           JS_MarkFunc *mark_func)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    JSAsyncFunctionData *s = p->u.async_function_data;
-    if (s) {
-        mark_func(rt, &s->header);
-    }
-}
-
-static int js_async_function_resolve_create(JSContext *ctx,
-                                            JSAsyncFunctionData *s,
-                                            JSValue *resolving_funcs)
-{
-    int i;
-    JSObject *p;
-
-    for(i = 0; i < 2; i++) {
-        resolving_funcs[i] =
-            JS_NewObjectProtoClass(ctx, ctx->function_proto,
-                                   JS_CLASS_ASYNC_FUNCTION_RESOLVE + i);
-        if (JS_IsException(resolving_funcs[i])) {
-            if (i == 1)
-                JS_FreeValue(ctx, resolving_funcs[0]);
-            return -1;
-        }
-        p = JS_VALUE_GET_OBJ(resolving_funcs[i]);
-        s->header.ref_count++;
-        p->u.async_function_data = s;
-    }
-    return 0;
-}
-
-static void js_async_function_resume(JSContext *ctx, JSAsyncFunctionData *s)
-{
-    JSValue func_ret, ret2;
-
-    func_ret = async_func_resume(ctx, &s->func_state);
-    if (JS_IsException(func_ret)) {
-        JSValue error;
-    fail:
-        error = JS_GetException(ctx);
-        ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED,
-                       1, (JSValueConst *)&error);
-        JS_FreeValue(ctx, error);
-        js_async_function_terminate(ctx->rt, s);
-        JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
-    } else {
-        JSValue value;
-        value = s->func_state.frame.cur_sp[-1];
-        s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
-        if (JS_IsUndefined(func_ret)) {
-            /* function returned */
-            ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED,
-                           1, (JSValueConst *)&value);
-            JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
-            JS_FreeValue(ctx, value);
-            js_async_function_terminate(ctx->rt, s);
-        } else {
-            JSValue promise, resolving_funcs[2], resolving_funcs1[2];
-            int i, res;
-
-            /* await */
-            JS_FreeValue(ctx, func_ret); /* not used */
-            promise = js_promise_resolve(ctx, ctx->promise_ctor,
-                                         1, (JSValueConst *)&value, 0);
-            JS_FreeValue(ctx, value);
-            if (JS_IsException(promise))
-                goto fail;
-            if (js_async_function_resolve_create(ctx, s, resolving_funcs)) {
-                JS_FreeValue(ctx, promise);
-                goto fail;
-            }
-
-            /* Note: no need to create 'thrownawayCapability' as in
-               the spec */
-            for(i = 0; i < 2; i++)
-                resolving_funcs1[i] = JS_UNDEFINED;
-            res = perform_promise_then(ctx, promise,
-                                       (JSValueConst *)resolving_funcs,
-                                       (JSValueConst *)resolving_funcs1);
-            JS_FreeValue(ctx, promise);
-            for(i = 0; i < 2; i++)
-                JS_FreeValue(ctx, resolving_funcs[i]);
-            if (res)
-                goto fail;
-        }
-    }
-}
-
-static JSValue js_async_function_resolve_call(JSContext *ctx,
-                                              JSValueConst func_obj,
-                                              JSValueConst this_obj,
-                                              int argc, JSValueConst *argv,
-                                              int flags)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(func_obj);
-    JSAsyncFunctionData *s = p->u.async_function_data;
-    BOOL is_reject = p->class_id - JS_CLASS_ASYNC_FUNCTION_RESOLVE;
-    JSValueConst arg;
-
-    if (argc > 0)
-        arg = argv[0];
-    else
-        arg = JS_UNDEFINED;
-    s->func_state.throw_flag = is_reject;
-    if (is_reject) {
-        JS_Throw(ctx, JS_DupValue(ctx, arg));
-    } else {
-        /* return value of await */
-        s->func_state.frame.cur_sp[-1] = JS_DupValue(ctx, arg);
-    }
-    js_async_function_resume(ctx, s);
-    return JS_UNDEFINED;
-}
-
-static JSValue js_async_function_call(JSContext *ctx, JSValueConst func_obj,
-                                      JSValueConst this_obj,
-                                      int argc, JSValueConst *argv, int flags)
-{
-    JSValue promise;
-    JSAsyncFunctionData *s;
-
-    s = js_mallocz(ctx, sizeof(*s));
-    if (!s)
-        return JS_EXCEPTION;
-    s->header.ref_count = 1;
-    add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION);
-    s->is_active = FALSE;
-    s->resolving_funcs[0] = JS_UNDEFINED;
-    s->resolving_funcs[1] = JS_UNDEFINED;
-
-    promise = JS_NewPromiseCapability(ctx, s->resolving_funcs);
-    if (JS_IsException(promise))
-        goto fail;
-
-    if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
-    fail:
-        JS_FreeValue(ctx, promise);
-        js_async_function_free(ctx->rt, s);
-        return JS_EXCEPTION;
-    }
-    s->is_active = TRUE;
-
-    js_async_function_resume(ctx, s);
-
-    js_async_function_free(ctx->rt, s);
-
-    return promise;
-}
-
-/* AsyncGenerator */
-
-typedef enum JSAsyncGeneratorStateEnum {
-    JS_ASYNC_GENERATOR_STATE_SUSPENDED_START,
-    JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD,
-    JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR,
-    JS_ASYNC_GENERATOR_STATE_EXECUTING,
-    JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN,
-    JS_ASYNC_GENERATOR_STATE_COMPLETED,
-} JSAsyncGeneratorStateEnum;
-
-typedef struct JSAsyncGeneratorRequest {
-    struct list_head link;
-    /* completion */
-    int completion_type; /* GEN_MAGIC_x */
-    JSValue result;
-    /* promise capability */
-    JSValue promise;
-    JSValue resolving_funcs[2];
-} JSAsyncGeneratorRequest;
-
-typedef struct JSAsyncGeneratorData {
-    JSObject *generator; /* back pointer to the object (const) */
-    JSAsyncGeneratorStateEnum state;
-    JSAsyncFunctionState func_state;
-    struct list_head queue; /* list of JSAsyncGeneratorRequest.link */
-} JSAsyncGeneratorData;
-
-static void js_async_generator_free(JSRuntime *rt,
-                                    JSAsyncGeneratorData *s)
-{
-    struct list_head *el, *el1;
-    JSAsyncGeneratorRequest *req;
-
-    list_for_each_safe(el, el1, &s->queue) {
-        req = list_entry(el, JSAsyncGeneratorRequest, link);
-        JS_FreeValueRT(rt, req->result);
-        JS_FreeValueRT(rt, req->promise);
-        JS_FreeValueRT(rt, req->resolving_funcs[0]);
-        JS_FreeValueRT(rt, req->resolving_funcs[1]);
-        js_free_rt(rt, req);
-    }
-    if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED &&
-        s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) {
-        async_func_free(rt, &s->func_state);
-    }
-    js_free_rt(rt, s);
-}
-
-static void js_async_generator_finalizer(JSRuntime *rt, JSValue obj)
-{
-    JSAsyncGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_ASYNC_GENERATOR);
-
-    if (s) {
-        js_async_generator_free(rt, s);
-    }
-}
-
-static void js_async_generator_mark(JSRuntime *rt, JSValueConst val,
-                                    JS_MarkFunc *mark_func)
-{
-    JSAsyncGeneratorData *s = JS_GetOpaque(val, JS_CLASS_ASYNC_GENERATOR);
-    struct list_head *el;
-    JSAsyncGeneratorRequest *req;
-    if (s) {
-        list_for_each(el, &s->queue) {
-            req = list_entry(el, JSAsyncGeneratorRequest, link);
-            JS_MarkValue(rt, req->result, mark_func);
-            JS_MarkValue(rt, req->promise, mark_func);
-            JS_MarkValue(rt, req->resolving_funcs[0], mark_func);
-            JS_MarkValue(rt, req->resolving_funcs[1], mark_func);
-        }
-        if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED &&
-            s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) {
-            async_func_mark(rt, &s->func_state, mark_func);
-        }
-    }
-}
-
-static JSValue js_async_generator_resolve_function(JSContext *ctx,
-                                          JSValueConst this_obj,
-                                          int argc, JSValueConst *argv,
-                                          int magic, JSValue *func_data);
-
-static int js_async_generator_resolve_function_create(JSContext *ctx,
-                                                      JSValueConst generator,
-                                                      JSValue *resolving_funcs,
-                                                      BOOL is_resume_next)
-{
-    int i;
-    JSValue func;
-
-    for(i = 0; i < 2; i++) {
-        func = JS_NewCFunctionData(ctx, js_async_generator_resolve_function, 1,
-                                   i + is_resume_next * 2, 1, &generator);
-        if (JS_IsException(func)) {
-            if (i == 1)
-                JS_FreeValue(ctx, resolving_funcs[0]);
-            return -1;
-        }
-        resolving_funcs[i] = func;
-    }
-    return 0;
-}
-
-static int js_async_generator_await(JSContext *ctx,
-                                    JSAsyncGeneratorData *s,
-                                    JSValueConst value)
-{
-    JSValue promise, resolving_funcs[2], resolving_funcs1[2];
-    int i, res;
-
-    promise = js_promise_resolve(ctx, ctx->promise_ctor,
-                                 1, &value, 0);
-    if (JS_IsException(promise))
-        goto fail;
-
-    if (js_async_generator_resolve_function_create(ctx, JS_MKPTR(JS_TAG_OBJECT, s->generator),
-                                                   resolving_funcs, FALSE)) {
-        JS_FreeValue(ctx, promise);
-        goto fail;
-    }
-
-    /* Note: no need to create 'thrownawayCapability' as in
-       the spec */
-    for(i = 0; i < 2; i++)
-        resolving_funcs1[i] = JS_UNDEFINED;
-    res = perform_promise_then(ctx, promise,
-                               (JSValueConst *)resolving_funcs,
-                               (JSValueConst *)resolving_funcs1);
-    JS_FreeValue(ctx, promise);
-    for(i = 0; i < 2; i++)
-        JS_FreeValue(ctx, resolving_funcs[i]);
-    if (res)
-        goto fail;
-    return 0;
- fail:
-    return -1;
-}
-
-static void js_async_generator_resolve_or_reject(JSContext *ctx,
-                                                 JSAsyncGeneratorData *s,
-                                                 JSValueConst result,
-                                                 int is_reject)
-{
-    JSAsyncGeneratorRequest *next;
-    JSValue ret;
-
-    next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link);
-    list_del(&next->link);
-    ret = JS_Call(ctx, next->resolving_funcs[is_reject], JS_UNDEFINED, 1,
-                  &result);
-    JS_FreeValue(ctx, ret);
-    JS_FreeValue(ctx, next->result);
-    JS_FreeValue(ctx, next->promise);
-    JS_FreeValue(ctx, next->resolving_funcs[0]);
-    JS_FreeValue(ctx, next->resolving_funcs[1]);
-    js_free(ctx, next);
-}
-
-static void js_async_generator_resolve(JSContext *ctx,
-                                       JSAsyncGeneratorData *s,
-                                       JSValueConst value,
-                                       BOOL done)
-{
-    JSValue result;
-    result = js_create_iterator_result(ctx, JS_DupValue(ctx, value), done);
-    /* XXX: better exception handling ? */
-    js_async_generator_resolve_or_reject(ctx, s, result, 0);
-    JS_FreeValue(ctx, result);
- }
-
-static void js_async_generator_reject(JSContext *ctx,
-                                       JSAsyncGeneratorData *s,
-                                       JSValueConst exception)
-{
-    js_async_generator_resolve_or_reject(ctx, s, exception, 1);
-}
-
-static void js_async_generator_complete(JSContext *ctx,
-                                        JSAsyncGeneratorData *s)
-{
-    if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED) {
-        s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
-        async_func_free(ctx->rt, &s->func_state);
-    }
-}
-
-static int js_async_generator_completed_return(JSContext *ctx,
-                                               JSAsyncGeneratorData *s,
-                                               JSValueConst value)
-{
-    JSValue promise, resolving_funcs[2], resolving_funcs1[2];
-    int res;
-
-    promise = js_promise_resolve(ctx, ctx->promise_ctor,
-                                 1, (JSValueConst *)&value, 0);
-    if (JS_IsException(promise))
-        return -1;
-    if (js_async_generator_resolve_function_create(ctx,
-                                                   JS_MKPTR(JS_TAG_OBJECT, s->generator),
-                                                   resolving_funcs1,
-                                                   TRUE)) {
-        JS_FreeValue(ctx, promise);
-        return -1;
-    }
-    resolving_funcs[0] = JS_UNDEFINED;
-    resolving_funcs[1] = JS_UNDEFINED;
-    res = perform_promise_then(ctx, promise,
-                               (JSValueConst *)resolving_funcs1,
-                               (JSValueConst *)resolving_funcs);
-    JS_FreeValue(ctx, resolving_funcs1[0]);
-    JS_FreeValue(ctx, resolving_funcs1[1]);
-    JS_FreeValue(ctx, promise);
-    return res;
-}
-
-static void js_async_generator_resume_next(JSContext *ctx,
-                                           JSAsyncGeneratorData *s)
-{
-    JSAsyncGeneratorRequest *next;
-    JSValue func_ret, value;
-
-    for(;;) {
-        if (list_empty(&s->queue))
-            break;
-        next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link);
-        switch(s->state) {
-        case JS_ASYNC_GENERATOR_STATE_EXECUTING:
-            /* only happens when restarting execution after await() */
-            goto resume_exec;
-        case JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN:
-            goto done;
-        case JS_ASYNC_GENERATOR_STATE_SUSPENDED_START:
-            if (next->completion_type == GEN_MAGIC_NEXT) {
-                goto exec_no_arg;
-            } else {
-                js_async_generator_complete(ctx, s);
-            }
-            break;
-        case JS_ASYNC_GENERATOR_STATE_COMPLETED:
-            if (next->completion_type == GEN_MAGIC_NEXT) {
-                js_async_generator_resolve(ctx, s, JS_UNDEFINED, TRUE);
-            } else if (next->completion_type == GEN_MAGIC_RETURN) {
-                s->state = JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN;
-                js_async_generator_completed_return(ctx, s, next->result);
-                goto done;
-            } else {
-                js_async_generator_reject(ctx, s, next->result);
-            }
-            goto done;
-        case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD:
-        case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
-            value = JS_DupValue(ctx, next->result);
-            if (next->completion_type == GEN_MAGIC_THROW &&
-                s->state == JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD) {
-                JS_Throw(ctx, value);
-                s->func_state.throw_flag = TRUE;
-            } else {
-                /* 'yield' returns a value. 'yield *' also returns a value
-                   in case the 'throw' method is called */
-                s->func_state.frame.cur_sp[-1] = value;
-                s->func_state.frame.cur_sp[0] =
-                    JS_NewInt32(ctx, next->completion_type);
-                s->func_state.frame.cur_sp++;
-            exec_no_arg:
-                s->func_state.throw_flag = FALSE;
-            }
-            s->state = JS_ASYNC_GENERATOR_STATE_EXECUTING;
-        resume_exec:
-            func_ret = async_func_resume(ctx, &s->func_state);
-            if (JS_IsException(func_ret)) {
-                value = JS_GetException(ctx);
-                js_async_generator_complete(ctx, s);
-                js_async_generator_reject(ctx, s, value);
-                JS_FreeValue(ctx, value);
-            } else if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) {
-                int func_ret_code;
-                value = s->func_state.frame.cur_sp[-1];
-                s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
-                func_ret_code = JS_VALUE_GET_INT(func_ret);
-                switch(func_ret_code) {
-                case FUNC_RET_YIELD:
-                case FUNC_RET_YIELD_STAR:
-                    if (func_ret_code == FUNC_RET_YIELD_STAR)
-                        s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
-                    else
-                        s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD;
-                    js_async_generator_resolve(ctx, s, value, FALSE);
-                    JS_FreeValue(ctx, value);
-                    break;
-                case FUNC_RET_AWAIT:
-                    js_async_generator_await(ctx, s, value);
-                    JS_FreeValue(ctx, value);
-                    goto done;
-                default:
-                    abort();
-                }
-            } else {
-                assert(JS_IsUndefined(func_ret));
-                /* end of function */
-                value = s->func_state.frame.cur_sp[-1];
-                s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
-                js_async_generator_complete(ctx, s);
-                js_async_generator_resolve(ctx, s, value, TRUE);
-                JS_FreeValue(ctx, value);
-            }
-            break;
-        default:
-            abort();
-        }
-    }
- done: ;
-}
-
-static JSValue js_async_generator_resolve_function(JSContext *ctx,
-                                                   JSValueConst this_obj,
-                                                   int argc, JSValueConst *argv,
-                                                   int magic, JSValue *func_data)
-{
-    BOOL is_reject = magic & 1;
-    JSAsyncGeneratorData *s = JS_GetOpaque(func_data[0], JS_CLASS_ASYNC_GENERATOR);
-    JSValueConst arg = argv[0];
-
-    /* XXX: what if s == NULL */
-
-    if (magic >= 2) {
-        /* resume next case in AWAITING_RETURN state */
-        assert(s->state == JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN ||
-               s->state == JS_ASYNC_GENERATOR_STATE_COMPLETED);
-        s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
-        if (is_reject) {
-            js_async_generator_reject(ctx, s, arg);
-        } else {
-            js_async_generator_resolve(ctx, s, arg, TRUE);
-        }
-    } else {
-        /* restart function execution after await() */
-        assert(s->state == JS_ASYNC_GENERATOR_STATE_EXECUTING);
-        s->func_state.throw_flag = is_reject;
-        if (is_reject) {
-            JS_Throw(ctx, JS_DupValue(ctx, arg));
-        } else {
-            /* return value of await */
-            s->func_state.frame.cur_sp[-1] = JS_DupValue(ctx, arg);
-        }
-        js_async_generator_resume_next(ctx, s);
-    }
-    return JS_UNDEFINED;
-}
-
-/* magic = GEN_MAGIC_x */
-static JSValue js_async_generator_next(JSContext *ctx, JSValueConst this_val,
-                                       int argc, JSValueConst *argv,
-                                       int magic)
-{
-    JSAsyncGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_GENERATOR);
-    JSValue promise, resolving_funcs[2];
-    JSAsyncGeneratorRequest *req;
-
-    promise = JS_NewPromiseCapability(ctx, resolving_funcs);
-    if (JS_IsException(promise))
-        return JS_EXCEPTION;
-    if (!s) {
-        JSValue err, res2;
-        JS_ThrowTypeError(ctx, "not an AsyncGenerator object");
-        err = JS_GetException(ctx);
-        res2 = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
-                       1, (JSValueConst *)&err);
-        JS_FreeValue(ctx, err);
-        JS_FreeValue(ctx, res2);
-        JS_FreeValue(ctx, resolving_funcs[0]);
-        JS_FreeValue(ctx, resolving_funcs[1]);
-        return promise;
-    }
-    req = js_mallocz(ctx, sizeof(*req));
-    if (!req)
-        goto fail;
-    req->completion_type = magic;
-    req->result = JS_DupValue(ctx, argv[0]);
-    req->promise = JS_DupValue(ctx, promise);
-    req->resolving_funcs[0] = resolving_funcs[0];
-    req->resolving_funcs[1] = resolving_funcs[1];
-    list_add_tail(&req->link, &s->queue);
-    if (s->state != JS_ASYNC_GENERATOR_STATE_EXECUTING) {
-        js_async_generator_resume_next(ctx, s);
-    }
-    return promise;
- fail:
-    JS_FreeValue(ctx, resolving_funcs[0]);
-    JS_FreeValue(ctx, resolving_funcs[1]);
-    JS_FreeValue(ctx, promise);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_async_generator_function_call(JSContext *ctx, JSValueConst func_obj,
-                                                JSValueConst this_obj,
-                                                int argc, JSValueConst *argv,
-                                                int flags)
-{
-    JSValue obj, func_ret;
-    JSAsyncGeneratorData *s;
-
-    s = js_mallocz(ctx, sizeof(*s));
-    if (!s)
-        return JS_EXCEPTION;
-    s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_START;
-    init_list_head(&s->queue);
-    if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
-        s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
-        goto fail;
-    }
-
-    /* execute the function up to 'OP_initial_yield' (no yield nor
-       await are possible) */
-    func_ret = async_func_resume(ctx, &s->func_state);
-    if (JS_IsException(func_ret))
-        goto fail;
-    JS_FreeValue(ctx, func_ret);
-
-    obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_ASYNC_GENERATOR);
-    if (JS_IsException(obj))
-        goto fail;
-    s->generator = JS_VALUE_GET_OBJ(obj);
-    JS_SetOpaque(obj, s);
-    return obj;
- fail:
-    js_async_generator_free(ctx->rt, s);
-    return JS_EXCEPTION;
-}
-
-/* JS parser */
-
-enum {
-    TOK_NUMBER = -128,
-    TOK_STRING,
-    TOK_TEMPLATE,
-    TOK_IDENT,
-    TOK_REGEXP,
-    /* warning: order matters (see js_parse_assign_expr) */
-    TOK_MUL_ASSIGN,
-    TOK_DIV_ASSIGN,
-    TOK_MOD_ASSIGN,
-    TOK_PLUS_ASSIGN,
-    TOK_MINUS_ASSIGN,
-    TOK_SHL_ASSIGN,
-    TOK_SAR_ASSIGN,
-    TOK_SHR_ASSIGN,
-    TOK_AND_ASSIGN,
-    TOK_XOR_ASSIGN,
-    TOK_OR_ASSIGN,
-#ifdef CONFIG_BIGNUM
-    TOK_MATH_POW_ASSIGN,
-#endif
-    TOK_POW_ASSIGN,
-    TOK_LAND_ASSIGN,
-    TOK_LOR_ASSIGN,
-    TOK_DOUBLE_QUESTION_MARK_ASSIGN,
-    TOK_DEC,
-    TOK_INC,
-    TOK_SHL,
-    TOK_SAR,
-    TOK_SHR,
-    TOK_LT,
-    TOK_LTE,
-    TOK_GT,
-    TOK_GTE,
-    TOK_EQ,
-    TOK_STRICT_EQ,
-    TOK_NEQ,
-    TOK_STRICT_NEQ,
-    TOK_LAND,
-    TOK_LOR,
-#ifdef CONFIG_BIGNUM
-    TOK_MATH_POW,
-#endif
-    TOK_POW,
-    TOK_ARROW,
-    TOK_ELLIPSIS,
-    TOK_DOUBLE_QUESTION_MARK,
-    TOK_QUESTION_MARK_DOT,
-    TOK_ERROR,
-    TOK_PRIVATE_NAME,
-    TOK_EOF,
-    /* keywords: WARNING: same order as atoms */
-    TOK_NULL, /* must be first */
-    TOK_FALSE,
-    TOK_TRUE,
-    TOK_IF,
-    TOK_ELSE,
-    TOK_RETURN,
-    TOK_VAR,
-    TOK_THIS,
-    TOK_DELETE,
-    TOK_VOID,
-    TOK_TYPEOF,
-    TOK_NEW,
-    TOK_IN,
-    TOK_INSTANCEOF,
-    TOK_DO,
-    TOK_WHILE,
-    TOK_FOR,
-    TOK_BREAK,
-    TOK_CONTINUE,
-    TOK_SWITCH,
-    TOK_CASE,
-    TOK_DEFAULT,
-    TOK_THROW,
-    TOK_TRY,
-    TOK_CATCH,
-    TOK_FINALLY,
-    TOK_FUNCTION,
-    TOK_DEBUGGER,
-    TOK_WITH,
-    /* FutureReservedWord */
-    TOK_CLASS,
-    TOK_CONST,
-    TOK_ENUM,
-    TOK_EXPORT,
-    TOK_EXTENDS,
-    TOK_IMPORT,
-    TOK_SUPER,
-    /* FutureReservedWords when parsing strict mode code */
-    TOK_IMPLEMENTS,
-    TOK_INTERFACE,
-    TOK_LET,
-    TOK_PACKAGE,
-    TOK_PRIVATE,
-    TOK_PROTECTED,
-    TOK_PUBLIC,
-    TOK_STATIC,
-    TOK_YIELD,
-    TOK_AWAIT, /* must be last */
-    TOK_OF,     /* only used for js_parse_skip_parens_token() */
-};
-
-#define TOK_FIRST_KEYWORD   TOK_NULL
-#define TOK_LAST_KEYWORD    TOK_AWAIT
-
-/* unicode code points */
-#define CP_NBSP 0x00a0
-#define CP_BOM  0xfeff
-
-#define CP_LS   0x2028
-#define CP_PS   0x2029
-
-typedef struct BlockEnv {
-    struct BlockEnv *prev;
-    JSAtom label_name; /* JS_ATOM_NULL if none */
-    int label_break; /* -1 if none */
-    int label_cont; /* -1 if none */
-    int drop_count; /* number of stack elements to drop */
-    int label_finally; /* -1 if none */
-    int scope_level;
-    int has_iterator;
-} BlockEnv;
-
-typedef struct JSGlobalVar {
-    int cpool_idx; /* if >= 0, index in the constant pool for hoisted
-                      function defintion*/
-    uint8_t force_init : 1; /* force initialization to undefined */
-    uint8_t is_lexical : 1; /* global let/const definition */
-    uint8_t is_const   : 1; /* const definition */
-    int scope_level;    /* scope of definition */
-    JSAtom var_name;  /* variable name */
-} JSGlobalVar;
-
-typedef struct RelocEntry {
-    struct RelocEntry *next;
-    uint32_t addr; /* address to patch */
-    int size;   /* address size: 1, 2 or 4 bytes */
-} RelocEntry;
-
-typedef struct JumpSlot {
-    int op;
-    int size;
-    int pos;
-    int label;
-} JumpSlot;
-
-typedef struct LabelSlot {
-    int ref_count;
-    int pos;    /* phase 1 address, -1 means not resolved yet */
-    int pos2;   /* phase 2 address, -1 means not resolved yet */
-    int addr;   /* phase 3 address, -1 means not resolved yet */
-    RelocEntry *first_reloc;
-} LabelSlot;
-
-typedef struct LineNumberSlot {
-    uint32_t pc;
-    int line_num;
-} LineNumberSlot;
-
-typedef enum JSParseFunctionEnum {
-    JS_PARSE_FUNC_STATEMENT,
-    JS_PARSE_FUNC_VAR,
-    JS_PARSE_FUNC_EXPR,
-    JS_PARSE_FUNC_ARROW,
-    JS_PARSE_FUNC_GETTER,
-    JS_PARSE_FUNC_SETTER,
-    JS_PARSE_FUNC_METHOD,
-    JS_PARSE_FUNC_CLASS_CONSTRUCTOR,
-    JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR,
-} JSParseFunctionEnum;
-
-typedef enum JSParseExportEnum {
-    JS_PARSE_EXPORT_NONE,
-    JS_PARSE_EXPORT_NAMED,
-    JS_PARSE_EXPORT_DEFAULT,
-} JSParseExportEnum;
-
-typedef struct JSFunctionDef {
-    JSContext *ctx;
-    struct JSFunctionDef *parent;
-    int parent_cpool_idx; /* index in the constant pool of the parent
-                             or -1 if none */
-    int parent_scope_level; /* scope level in parent at point of definition */
-    struct list_head child_list; /* list of JSFunctionDef.link */
-    struct list_head link;
-
-    BOOL is_eval; /* TRUE if eval code */
-    int eval_type; /* only valid if is_eval = TRUE */
-    BOOL is_global_var; /* TRUE if variables are not defined locally:
-                           eval global, eval module or non strict eval */
-    BOOL is_func_expr; /* TRUE if function expression */
-    BOOL has_home_object; /* TRUE if the home object is available */
-    BOOL has_prototype; /* true if a prototype field is necessary */
-    BOOL has_simple_parameter_list;
-    BOOL has_parameter_expressions; /* if true, an argument scope is created */
-    BOOL has_use_strict; /* to reject directive in special cases */
-    BOOL has_eval_call; /* true if the function contains a call to eval() */
-    BOOL has_arguments_binding; /* true if the 'arguments' binding is
-                                   available in the function */
-    BOOL has_this_binding; /* true if the 'this' and new.target binding are
-                              available in the function */
-    BOOL new_target_allowed; /* true if the 'new.target' does not
-                                throw a syntax error */
-    BOOL super_call_allowed; /* true if super() is allowed */
-    BOOL super_allowed; /* true if super. or super[] is allowed */
-    BOOL arguments_allowed; /* true if the 'arguments' identifier is allowed */
-    BOOL is_derived_class_constructor;
-    BOOL in_function_body;
-    BOOL backtrace_barrier;
-    JSFunctionKindEnum func_kind : 8;
-    JSParseFunctionEnum func_type : 8;
-    uint8_t js_mode; /* bitmap of JS_MODE_x */
-    JSAtom func_name; /* JS_ATOM_NULL if no name */
-
-    JSVarDef *vars;
-    int var_size; /* allocated size for vars[] */
-    int var_count;
-    JSVarDef *args;
-    int arg_size; /* allocated size for args[] */
-    int arg_count; /* number of arguments */
-    int defined_arg_count;
-    int var_object_idx; /* -1 if none */
-    int arg_var_object_idx; /* -1 if none (var object for the argument scope) */
-    int arguments_var_idx; /* -1 if none */
-    int arguments_arg_idx; /* argument variable definition in argument scope, 
-                              -1 if none */
-    int func_var_idx; /* variable containing the current function (-1
-                         if none, only used if is_func_expr is true) */
-    int eval_ret_idx; /* variable containing the return value of the eval, -1 if none */
-    int this_var_idx; /* variable containg the 'this' value, -1 if none */
-    int new_target_var_idx; /* variable containg the 'new.target' value, -1 if none */
-    int this_active_func_var_idx; /* variable containg the 'this.active_func' value, -1 if none */
-    int home_object_var_idx;
-    BOOL need_home_object;
-    
-    int scope_level;    /* index into fd->scopes if the current lexical scope */
-    int scope_first;    /* index into vd->vars of first lexically scoped variable */
-    int scope_size;     /* allocated size of fd->scopes array */
-    int scope_count;    /* number of entries used in the fd->scopes array */
-    JSVarScope *scopes;
-    JSVarScope def_scope_array[4];
-    int body_scope; /* scope of the body of the function or eval */
-
-    int global_var_count;
-    int global_var_size;
-    JSGlobalVar *global_vars;
-
-    DynBuf byte_code;
-    int last_opcode_pos; /* -1 if no last opcode */
-    int last_opcode_line_num;
-    BOOL use_short_opcodes; /* true if short opcodes are used in byte_code */
-    
-    LabelSlot *label_slots;
-    int label_size; /* allocated size for label_slots[] */
-    int label_count;
-    BlockEnv *top_break; /* break/continue label stack */
-
-    /* constant pool (strings, functions, numbers) */
-    JSValue *cpool;
-    int cpool_count;
-    int cpool_size;
-
-    /* list of variables in the closure */
-    int closure_var_count;
-    int closure_var_size;
-    JSClosureVar *closure_var;
-
-    JumpSlot *jump_slots;
-    int jump_size;
-    int jump_count;
-
-    LineNumberSlot *line_number_slots;
-    int line_number_size;
-    int line_number_count;
-    int line_number_last;
-    int line_number_last_pc;
-
-    /* pc2line table */
-    JSAtom filename;
-    int line_num;
-    DynBuf pc2line;
-
-    char *source;  /* raw source, utf-8 encoded */
-    int source_len;
-
-    JSModuleDef *module; /* != NULL when parsing a module */
-} JSFunctionDef;
-
-typedef struct JSToken {
-    int val;
-    int line_num;   /* line number of token start */
-    const uint8_t *ptr;
-    union {
-        struct {
-            JSValue str;
-            int sep;
-        } str;
-        struct {
-            JSValue val;
-#ifdef CONFIG_BIGNUM
-            slimb_t exponent; /* may be != 0 only if val is a float */
-#endif
-        } num;
-        struct {
-            JSAtom atom;
-            BOOL has_escape;
-            BOOL is_reserved;
-        } ident;
-        struct {
-            JSValue body;
-            JSValue flags;
-        } regexp;
-    } u;
-} JSToken;
-
-typedef struct JSParseState {
-    JSContext *ctx;
-    int last_line_num;  /* line number of last token */
-    int line_num;       /* line number of current offset */
-    const char *filename;
-    JSToken token;
-    BOOL got_lf; /* true if got line feed before the current token */
-    const uint8_t *last_ptr;
-    const uint8_t *buf_ptr;
-    const uint8_t *buf_end;
-
-    /* current function code */
-    JSFunctionDef *cur_func;
-    BOOL is_module; /* parsing a module */
-    BOOL allow_html_comments;
-    BOOL ext_json; /* true if accepting JSON superset */
-} JSParseState;
-
-typedef struct JSOpCode {
-#ifdef DUMP_BYTECODE
-    const char *name;
-#endif
-    uint8_t size; /* in bytes */
-    /* the opcodes remove n_pop items from the top of the stack, then
-       pushes n_push items */
-    uint8_t n_pop;
-    uint8_t n_push;
-    uint8_t fmt;
-} JSOpCode;
-
-static const JSOpCode opcode_info[OP_COUNT + (OP_TEMP_END - OP_TEMP_START)] = {
-#define FMT(f)
-#ifdef DUMP_BYTECODE
-#define DEF(id, size, n_pop, n_push, f) { #id, size, n_pop, n_push, OP_FMT_ ## f },
-#else
-#define DEF(id, size, n_pop, n_push, f) { size, n_pop, n_push, OP_FMT_ ## f },
-#endif
-#include "quickjs-opcode.h"
-#undef DEF
-#undef FMT
-};
-
-#if SHORT_OPCODES
-/* After the final compilation pass, short opcodes are used. Their
-   opcodes overlap with the temporary opcodes which cannot appear in
-   the final bytecode. Their description is after the temporary
-   opcodes in opcode_info[]. */
-#define short_opcode_info(op)           \
-    opcode_info[(op) >= OP_TEMP_START ? \
-                (op) + (OP_TEMP_END - OP_TEMP_START) : (op)]
-#else
-#define short_opcode_info(op) opcode_info[op]
-#endif
-
-static __exception int next_token(JSParseState *s);
-
-static void free_token(JSParseState *s, JSToken *token)
-{
-    switch(token->val) {
-#ifdef CONFIG_BIGNUM
-    case TOK_NUMBER:
-        JS_FreeValue(s->ctx, token->u.num.val);
-        break;
-#endif
-    case TOK_STRING:
-    case TOK_TEMPLATE:
-        JS_FreeValue(s->ctx, token->u.str.str);
-        break;
-    case TOK_REGEXP:
-        JS_FreeValue(s->ctx, token->u.regexp.body);
-        JS_FreeValue(s->ctx, token->u.regexp.flags);
-        break;
-    case TOK_IDENT:
-    case TOK_PRIVATE_NAME:
-        JS_FreeAtom(s->ctx, token->u.ident.atom);
-        break;
-    default:
-        if (token->val >= TOK_FIRST_KEYWORD &&
-            token->val <= TOK_LAST_KEYWORD) {
-            JS_FreeAtom(s->ctx, token->u.ident.atom);
-        }
-        break;
-    }
-}
-
-static void __attribute((unused)) dump_token(JSParseState *s,
-                                             const JSToken *token)
-{
-    switch(token->val) {
-    case TOK_NUMBER:
-        {
-            double d;
-            JS_ToFloat64(s->ctx, &d, token->u.num.val);  /* no exception possible */
-            printf("number: %.14g\n", d);
-        }
-        break;
-    case TOK_IDENT:
-    dump_atom:
-        {
-            char buf[ATOM_GET_STR_BUF_SIZE];
-            printf("ident: '%s'\n",
-                   JS_AtomGetStr(s->ctx, buf, sizeof(buf), token->u.ident.atom));
-        }
-        break;
-    case TOK_STRING:
-        {
-            const char *str;
-            /* XXX: quote the string */
-            str = JS_ToCString(s->ctx, token->u.str.str);
-            printf("string: '%s'\n", str);
-            JS_FreeCString(s->ctx, str);
-        }
-        break;
-    case TOK_TEMPLATE:
-        {
-            const char *str;
-            str = JS_ToCString(s->ctx, token->u.str.str);
-            printf("template: `%s`\n", str);
-            JS_FreeCString(s->ctx, str);
-        }
-        break;
-    case TOK_REGEXP:
-        {
-            const char *str, *str2;
-            str = JS_ToCString(s->ctx, token->u.regexp.body);
-            str2 = JS_ToCString(s->ctx, token->u.regexp.flags);
-            printf("regexp: '%s' '%s'\n", str, str2);
-            JS_FreeCString(s->ctx, str);
-            JS_FreeCString(s->ctx, str2);
-        }
-        break;
-    case TOK_EOF:
-        printf("eof\n");
-        break;
-    default:
-        if (s->token.val >= TOK_NULL && s->token.val <= TOK_LAST_KEYWORD) {
-            goto dump_atom;
-        } else if (s->token.val >= 256) {
-            printf("token: %d\n", token->val);
-        } else {
-            printf("token: '%c'\n", token->val);
-        }
-        break;
-    }
-}
-
-int __attribute__((format(printf, 2, 3))) js_parse_error(JSParseState *s, const char *fmt, ...)
-{
-    JSContext *ctx = s->ctx;
-    va_list ap;
-    int backtrace_flags;
-    
-    va_start(ap, fmt);
-    JS_ThrowError2(ctx, JS_SYNTAX_ERROR, fmt, ap, FALSE);
-    va_end(ap);
-    backtrace_flags = 0;
-    if (s->cur_func && s->cur_func->backtrace_barrier)
-        backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL;
-    build_backtrace(ctx, ctx->rt->current_exception, s->filename, s->line_num,
-                    backtrace_flags);
-    return -1;
-}
-
-static int js_parse_expect(JSParseState *s, int tok)
-{
-    if (s->token.val != tok) {
-        /* XXX: dump token correctly in all cases */
-        return js_parse_error(s, "expecting '%c'", tok);
-    }
-    return next_token(s);
-}
-
-static int js_parse_expect_semi(JSParseState *s)
-{
-    if (s->token.val != ';') {
-        /* automatic insertion of ';' */
-        if (s->token.val == TOK_EOF || s->token.val == '}' || s->got_lf) {
-            return 0;
-        }
-        return js_parse_error(s, "expecting '%c'", ';');
-    }
-    return next_token(s);
-}
-
-static int js_parse_error_reserved_identifier(JSParseState *s)
-{
-    char buf1[ATOM_GET_STR_BUF_SIZE];
-    return js_parse_error(s, "'%s' is a reserved identifier",
-                          JS_AtomGetStr(s->ctx, buf1, sizeof(buf1),
-                                        s->token.u.ident.atom));
-}
-
-static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p)
-{
-    uint32_t c;
-    StringBuffer b_s, *b = &b_s;
-
-    /* p points to the first byte of the template part */
-    if (string_buffer_init(s->ctx, b, 32))
-        goto fail;
-    for(;;) {
-        if (p >= s->buf_end)
-            goto unexpected_eof;
-        c = *p++;
-        if (c == '`') {
-            /* template end part */
-            break;
-        }
-        if (c == '$' && *p == '{') {
-            /* template start or middle part */
-            p++;
-            break;
-        }
-        if (c == '\\') {
-            if (string_buffer_putc8(b, c))
-                goto fail;
-            if (p >= s->buf_end)
-                goto unexpected_eof;
-            c = *p++;
-        }
-        /* newline sequences are normalized as single '\n' bytes */
-        if (c == '\r') {
-            if (*p == '\n')
-                p++;
-            c = '\n';
-        }
-        if (c == '\n') {
-            s->line_num++;
-        } else if (c >= 0x80) {
-            const uint8_t *p_next;
-            c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
-            if (c > 0x10FFFF) {
-                js_parse_error(s, "invalid UTF-8 sequence");
-                goto fail;
-            }
-            p = p_next;
-        }
-        if (string_buffer_putc(b, c))
-            goto fail;
-    }
-    s->token.val = TOK_TEMPLATE;
-    s->token.u.str.sep = c;
-    s->token.u.str.str = string_buffer_end(b);
-    s->buf_ptr = p;
-    return 0;
-
- unexpected_eof:
-    js_parse_error(s, "unexpected end of string");
- fail:
-    string_buffer_free(b);
-    return -1;
-}
-
-static __exception int js_parse_string(JSParseState *s, int sep,
-                                       BOOL do_throw, const uint8_t *p,
-                                       JSToken *token, const uint8_t **pp)
-{
-    int ret;
-    uint32_t c;
-    StringBuffer b_s, *b = &b_s;
-
-    /* string */
-    if (string_buffer_init(s->ctx, b, 32))
-        goto fail;
-    for(;;) {
-        if (p >= s->buf_end)
-            goto invalid_char;
-        c = *p;
-        if (c < 0x20) {
-            if (!s->cur_func) {
-                if (do_throw)
-                    js_parse_error(s, "invalid character in a JSON string");
-                goto fail;
-            }
-            if (sep == '`') {
-                if (c == '\r') {
-                    if (p[1] == '\n')
-                        p++;
-                    c = '\n';
-                }
-                /* do not update s->line_num */
-            } else if (c == '\n' || c == '\r')
-                goto invalid_char;
-        }
-        p++;
-        if (c == sep)
-            break;
-        if (c == '$' && *p == '{' && sep == '`') {
-            /* template start or middle part */
-            p++;
-            break;
-        }
-        if (c == '\\') {
-            c = *p;
-            /* XXX: need a specific JSON case to avoid
-               accepting invalid escapes */
-            switch(c) {
-            case '\0':
-                if (p >= s->buf_end)
-                    goto invalid_char;
-                p++;
-                break;
-            case '\'':
-            case '\"':
-            case '\\':
-                p++;
-                break;
-            case '\r':  /* accept DOS and MAC newline sequences */
-                if (p[1] == '\n') {
-                    p++;
-                }
-                /* fall thru */
-            case '\n':
-                /* ignore escaped newline sequence */
-                p++;
-                if (sep != '`')
-                    s->line_num++;
-                continue;
-            default:
-                if (c >= '0' && c <= '9') {
-                    if (!s->cur_func)
-                        goto invalid_escape; /* JSON case */
-                    if (!(s->cur_func->js_mode & JS_MODE_STRICT) && sep != '`')
-                        goto parse_escape;
-                    if (c == '0' && !(p[1] >= '0' && p[1] <= '9')) {
-                        p++;
-                        c = '\0';
-                    } else {
-                        if (c >= '8' || sep == '`') {
-                            /* Note: according to ES2021, \8 and \9 are not
-                               accepted in strict mode or in templates. */
-                            goto invalid_escape;
-                        } else {
-                            if (do_throw)
-                                js_parse_error(s, "octal escape sequences are not allowed in strict mode");
-                        }
-                        goto fail;
-                    }
-                } else if (c >= 0x80) {
-                    const uint8_t *p_next;
-                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
-                    if (c > 0x10FFFF) {
-                        goto invalid_utf8;
-                    }
-                    p = p_next;
-                    /* LS or PS are skipped */
-                    if (c == CP_LS || c == CP_PS)
-                        continue;
-                } else {
-                parse_escape:
-                    ret = lre_parse_escape(&p, TRUE);
-                    if (ret == -1) {
-                    invalid_escape:
-                        if (do_throw)
-                            js_parse_error(s, "malformed escape sequence in string literal");
-                        goto fail;
-                    } else if (ret < 0) {
-                        /* ignore the '\' (could output a warning) */
-                        p++;
-                    } else {
-                        c = ret;
-                    }
-                }
-                break;
-            }
-        } else if (c >= 0x80) {
-            const uint8_t *p_next;
-            c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
-            if (c > 0x10FFFF)
-                goto invalid_utf8;
-            p = p_next;
-        }
-        if (string_buffer_putc(b, c))
-            goto fail;
-    }
-    token->val = TOK_STRING;
-    token->u.str.sep = c;
-    token->u.str.str = string_buffer_end(b);
-    *pp = p;
-    return 0;
-
- invalid_utf8:
-    if (do_throw)
-        js_parse_error(s, "invalid UTF-8 sequence");
-    goto fail;
- invalid_char:
-    if (do_throw)
-        js_parse_error(s, "unexpected end of string");
- fail:
-    string_buffer_free(b);
-    return -1;
-}
-
-static inline BOOL token_is_pseudo_keyword(JSParseState *s, JSAtom atom) {
-    return s->token.val == TOK_IDENT && s->token.u.ident.atom == atom &&
-        !s->token.u.ident.has_escape;
-}
-
-static __exception int js_parse_regexp(JSParseState *s)
-{
-    const uint8_t *p;
-    BOOL in_class;
-    StringBuffer b_s, *b = &b_s;
-    StringBuffer b2_s, *b2 = &b2_s;
-    uint32_t c;
-
-    p = s->buf_ptr;
-    p++;
-    in_class = FALSE;
-    if (string_buffer_init(s->ctx, b, 32))
-        return -1;
-    if (string_buffer_init(s->ctx, b2, 1))
-        goto fail;
-    for(;;) {
-        if (p >= s->buf_end) {
-        eof_error:
-            js_parse_error(s, "unexpected end of regexp");
-            goto fail;
-        }
-        c = *p++;
-        if (c == '\n' || c == '\r') {
-            goto eol_error;
-        } else if (c == '/') {
-            if (!in_class)
-                break;
-        } else if (c == '[') {
-            in_class = TRUE;
-        } else if (c == ']') {
-            /* XXX: incorrect as the first character in a class */
-            in_class = FALSE;
-        } else if (c == '\\') {
-            if (string_buffer_putc8(b, c))
-                goto fail;
-            c = *p++;
-            if (c == '\n' || c == '\r')
-                goto eol_error;
-            else if (c == '\0' && p >= s->buf_end)
-                goto eof_error;
-            else if (c >= 0x80) {
-                const uint8_t *p_next;
-                c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
-                if (c > 0x10FFFF) {
-                    goto invalid_utf8;
-                }
-                p = p_next;
-                if (c == CP_LS || c == CP_PS)
-                    goto eol_error;
-            }
-        } else if (c >= 0x80) {
-            const uint8_t *p_next;
-            c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
-            if (c > 0x10FFFF) {
-            invalid_utf8:
-                js_parse_error(s, "invalid UTF-8 sequence");
-                goto fail;
-            }
-            p = p_next;
-            /* LS or PS are considered as line terminator */
-            if (c == CP_LS || c == CP_PS) {
-            eol_error:
-                js_parse_error(s, "unexpected line terminator in regexp");
-                goto fail;
-            }
-        }
-        if (string_buffer_putc(b, c))
-            goto fail;
-    }
-
-    /* flags */
-    for(;;) {
-        const uint8_t *p_next = p;
-        c = *p_next++;
-        if (c >= 0x80) {
-            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
-            if (c > 0x10FFFF) {
-                goto invalid_utf8;
-            }
-        }
-        if (!lre_js_is_ident_next(c))
-            break;
-        if (string_buffer_putc(b2, c))
-            goto fail;
-        p = p_next;
-    }
-
-    s->token.val = TOK_REGEXP;
-    s->token.u.regexp.body = string_buffer_end(b);
-    s->token.u.regexp.flags = string_buffer_end(b2);
-    s->buf_ptr = p;
-    return 0;
- fail:
-    string_buffer_free(b);
-    string_buffer_free(b2);
-    return -1;
-}
-
-static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize,
-                                     char *static_buf)
-{
-    char *buf, *new_buf;
-    size_t size, new_size;
-    
-    buf = *pbuf;
-    size = *psize;
-    if (size >= (SIZE_MAX / 3) * 2)
-        new_size = SIZE_MAX;
-    else
-        new_size = size + (size >> 1);
-    if (buf == static_buf) {
-        new_buf = js_malloc(ctx, new_size);
-        if (!new_buf)
-            return -1;
-        memcpy(new_buf, buf, size);
-    } else {
-        new_buf = js_realloc(ctx, buf, new_size);
-        if (!new_buf)
-            return -1;
-    }
-    *pbuf = new_buf;
-    *psize = new_size;
-    return 0;
-}
-
-/* 'c' is the first character. Return JS_ATOM_NULL in case of error */
-static JSAtom parse_ident(JSParseState *s, const uint8_t **pp,
-                          BOOL *pident_has_escape, int c, BOOL is_private)
-{
-    const uint8_t *p, *p1;
-    char ident_buf[128], *buf;
-    size_t ident_size, ident_pos;
-    JSAtom atom;
-    
-    p = *pp;
-    buf = ident_buf;
-    ident_size = sizeof(ident_buf);
-    ident_pos = 0;
-    if (is_private)
-        buf[ident_pos++] = '#';
-    for(;;) {
-        p1 = p;
-        
-        if (c < 128) {
-            buf[ident_pos++] = c;
-        } else {
-            ident_pos += unicode_to_utf8((uint8_t*)buf + ident_pos, c);
-        }
-        c = *p1++;
-        if (c == '\\' && *p1 == 'u') {
-            c = lre_parse_escape(&p1, TRUE);
-            *pident_has_escape = TRUE;
-        } else if (c >= 128) {
-            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
-        }
-        if (!lre_js_is_ident_next(c))
-            break;
-        p = p1;
-        if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
-            if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) {
-                atom = JS_ATOM_NULL;
-                goto done;
-            }
-        }
-    }
-    atom = JS_NewAtomLen(s->ctx, buf, ident_pos);
- done:
-    if (unlikely(buf != ident_buf))
-        js_free(s->ctx, buf);
-    *pp = p;
-    return atom;
-}
-
-
-static __exception int next_token(JSParseState *s)
-{
-    const uint8_t *p;
-    int c;
-    BOOL ident_has_escape;
-    JSAtom atom;
-    
-    if (js_check_stack_overflow(s->ctx->rt, 0)) {
-        return js_parse_error(s, "stack overflow");
-    }
-    
-    free_token(s, &s->token);
-
-    p = s->last_ptr = s->buf_ptr;
-    s->got_lf = FALSE;
-    s->last_line_num = s->token.line_num;
- redo:
-    s->token.line_num = s->line_num;
-    s->token.ptr = p;
-    c = *p;
-    switch(c) {
-    case 0:
-        if (p >= s->buf_end) {
-            s->token.val = TOK_EOF;
-        } else {
-            goto def_token;
-        }
-        break;
-    case '`':
-        if (js_parse_template_part(s, p + 1))
-            goto fail;
-        p = s->buf_ptr;
-        break;
-    case '\'':
-    case '\"':
-        if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))
-            goto fail;
-        break;
-    case '\r':  /* accept DOS and MAC newline sequences */
-        if (p[1] == '\n') {
-            p++;
-        }
-        /* fall thru */
-    case '\n':
-        p++;
-    line_terminator:
-        s->got_lf = TRUE;
-        s->line_num++;
-        goto redo;
-    case '\f':
-    case '\v':
-    case ' ':
-    case '\t':
-        p++;
-        goto redo;
-    case '/':
-        if (p[1] == '*') {
-            /* comment */
-            p += 2;
-            for(;;) {
-                if (*p == '\0' && p >= s->buf_end) {
-                    js_parse_error(s, "unexpected end of comment");
-                    goto fail;
-                }
-                if (p[0] == '*' && p[1] == '/') {
-                    p += 2;
-                    break;
-                }
-                if (*p == '\n') {
-                    s->line_num++;
-                    s->got_lf = TRUE; /* considered as LF for ASI */
-                    p++;
-                } else if (*p == '\r') {
-                    s->got_lf = TRUE; /* considered as LF for ASI */
-                    p++;
-                } else if (*p >= 0x80) {
-                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
-                    if (c == CP_LS || c == CP_PS) {
-                        s->got_lf = TRUE; /* considered as LF for ASI */
-                    } else if (c == -1) {
-                        p++; /* skip invalid UTF-8 */
-                    }
-                } else {
-                    p++;
-                }
-            }
-            goto redo;
-        } else if (p[1] == '/') {
-            /* line comment */
-            p += 2;
-        skip_line_comment:
-            for(;;) {
-                if (*p == '\0' && p >= s->buf_end)
-                    break;
-                if (*p == '\r' || *p == '\n')
-                    break;
-                if (*p >= 0x80) {
-                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
-                    /* LS or PS are considered as line terminator */
-                    if (c == CP_LS || c == CP_PS) {
-                        break;
-                    } else if (c == -1) {
-                        p++; /* skip invalid UTF-8 */
-                    }
-                } else {
-                    p++;
-                }
-            }
-            goto redo;
-        } else if (p[1] == '=') {
-            p += 2;
-            s->token.val = TOK_DIV_ASSIGN;
-        } else {
-            p++;
-            s->token.val = c;
-        }
-        break;
-    case '\\':
-        if (p[1] == 'u') {
-            const uint8_t *p1 = p + 1;
-            int c1 = lre_parse_escape(&p1, TRUE);
-            if (c1 >= 0 && lre_js_is_ident_first(c1)) {
-                c = c1;
-                p = p1;
-                ident_has_escape = TRUE;
-                goto has_ident;
-            } else {
-                /* XXX: syntax error? */
-            }
-        }
-        goto def_token;
-    case 'a': case 'b': case 'c': case 'd':
-    case 'e': case 'f': case 'g': case 'h':
-    case 'i': case 'j': case 'k': case 'l':
-    case 'm': case 'n': case 'o': case 'p':
-    case 'q': case 'r': case 's': case 't':
-    case 'u': case 'v': case 'w': case 'x':
-    case 'y': case 'z': 
-    case 'A': case 'B': case 'C': case 'D':
-    case 'E': case 'F': case 'G': case 'H':
-    case 'I': case 'J': case 'K': case 'L':
-    case 'M': case 'N': case 'O': case 'P':
-    case 'Q': case 'R': case 'S': case 'T':
-    case 'U': case 'V': case 'W': case 'X':
-    case 'Y': case 'Z': 
-    case '_':
-    case '$':
-        /* identifier */
-        p++;
-        ident_has_escape = FALSE;
-    has_ident:
-        atom = parse_ident(s, &p, &ident_has_escape, c, FALSE);
-        if (atom == JS_ATOM_NULL)
-            goto fail;
-        s->token.u.ident.atom = atom;
-        s->token.u.ident.has_escape = ident_has_escape;
-        s->token.u.ident.is_reserved = FALSE;
-        if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD ||
-            (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD &&
-             (s->cur_func->js_mode & JS_MODE_STRICT)) ||
-            (s->token.u.ident.atom == JS_ATOM_yield &&
-             ((s->cur_func->func_kind & JS_FUNC_GENERATOR) ||
-              (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
-               !s->cur_func->in_function_body && s->cur_func->parent &&
-               (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) ||
-            (s->token.u.ident.atom == JS_ATOM_await &&
-             (s->is_module ||
-              (((s->cur_func->func_kind & JS_FUNC_ASYNC) ||
-                (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
-                 !s->cur_func->in_function_body && s->cur_func->parent &&
-                 (s->cur_func->parent->func_kind & JS_FUNC_ASYNC))))))) {
-                  if (ident_has_escape) {
-                      s->token.u.ident.is_reserved = TRUE;
-                      s->token.val = TOK_IDENT;
-                  } else {
-                      /* The keywords atoms are pre allocated */
-                      s->token.val = s->token.u.ident.atom - 1 + TOK_FIRST_KEYWORD;
-                  }
-        } else {
-            s->token.val = TOK_IDENT;
-        }
-        break;
-    case '#':
-        /* private name */
-        {
-            const uint8_t *p1;
-            p++;
-            p1 = p;
-            c = *p1++;
-            if (c == '\\' && *p1 == 'u') {
-                c = lre_parse_escape(&p1, TRUE);
-            } else if (c >= 128) {
-                c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
-            }
-            if (!lre_js_is_ident_first(c)) {
-                js_parse_error(s, "invalid first character of private name");
-                goto fail;
-            }
-            p = p1;
-            ident_has_escape = FALSE; /* not used */
-            atom = parse_ident(s, &p, &ident_has_escape, c, TRUE);
-            if (atom == JS_ATOM_NULL)
-                goto fail;
-            s->token.u.ident.atom = atom;
-            s->token.val = TOK_PRIVATE_NAME;
-        }
-        break;
-    case '.':
-        if (p[1] == '.' && p[2] == '.') {
-            p += 3;
-            s->token.val = TOK_ELLIPSIS;
-            break;
-        }
-        if (p[1] >= '0' && p[1] <= '9') {
-            goto parse_number;
-        } else {
-            goto def_token;
-        }
-        break;
-    case '0':
-        /* in strict mode, octal literals are not accepted */
-        if (is_digit(p[1]) && (s->cur_func->js_mode & JS_MODE_STRICT)) {
-            js_parse_error(s, "octal literals are deprecated in strict mode");
-            goto fail;
-        }
-        goto parse_number;
-    case '1': case '2': case '3': case '4':
-    case '5': case '6': case '7': case '8':
-    case '9': 
-        /* number */
-    parse_number:
-        {
-            JSValue ret;
-            const uint8_t *p1;
-            int flags, radix;
-            flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL |
-                ATOD_ACCEPT_UNDERSCORES;
-#ifdef CONFIG_BIGNUM
-            flags |= ATOD_ACCEPT_SUFFIX;
-            if (s->cur_func->js_mode & JS_MODE_MATH) {
-                flags |= ATOD_MODE_BIGINT;
-                if (s->cur_func->js_mode & JS_MODE_MATH)
-                    flags |= ATOD_TYPE_BIG_FLOAT;
-            }
-#endif
-            radix = 0;
-#ifdef CONFIG_BIGNUM
-            s->token.u.num.exponent = 0;
-            ret = js_atof2(s->ctx, (const char *)p, (const char **)&p, radix,
-                           flags, &s->token.u.num.exponent);
-#else
-            ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix,
-                          flags);
-#endif
-            if (JS_IsException(ret))
-                goto fail;
-            /* reject `10instanceof Number` */
-            if (JS_VALUE_IS_NAN(ret) ||
-                lre_js_is_ident_next(unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1))) {
-                JS_FreeValue(s->ctx, ret);
-                js_parse_error(s, "invalid number literal");
-                goto fail;
-            }
-            s->token.val = TOK_NUMBER;
-            s->token.u.num.val = ret;
-        }
-        break;
-    case '*':
-        if (p[1] == '=') {
-            p += 2;
-            s->token.val = TOK_MUL_ASSIGN;
-        } else if (p[1] == '*') {
-            if (p[2] == '=') {
-                p += 3;
-                s->token.val = TOK_POW_ASSIGN;
-            } else {
-                p += 2;
-                s->token.val = TOK_POW;
-            }
-        } else {
-            goto def_token;
-        }
-        break;
-    case '%':
-        if (p[1] == '=') {
-            p += 2;
-            s->token.val = TOK_MOD_ASSIGN;
-        } else {
-            goto def_token;
-        }
-        break;
-    case '+':
-        if (p[1] == '=') {
-            p += 2;
-            s->token.val = TOK_PLUS_ASSIGN;
-        } else if (p[1] == '+') {
-            p += 2;
-            s->token.val = TOK_INC;
-        } else {
-            goto def_token;
-        }
-        break;
-    case '-':
-        if (p[1] == '=') {
-            p += 2;
-            s->token.val = TOK_MINUS_ASSIGN;
-        } else if (p[1] == '-') {
-            if (s->allow_html_comments &&
-                p[2] == '>' && s->last_line_num != s->line_num) {
-                /* Annex B: `-->` at beginning of line is an html comment end.
-                   It extends to the end of the line.
-                 */
-                goto skip_line_comment;
-            }
-            p += 2;
-            s->token.val = TOK_DEC;
-        } else {
-            goto def_token;
-        }
-        break;
-    case '<':
-        if (p[1] == '=') {
-            p += 2;
-            s->token.val = TOK_LTE;
-        } else if (p[1] == '<') {
-            if (p[2] == '=') {
-                p += 3;
-                s->token.val = TOK_SHL_ASSIGN;
-            } else {
-                p += 2;
-                s->token.val = TOK_SHL;
-            }
-        } else if (s->allow_html_comments &&
-                   p[1] == '!' && p[2] == '-' && p[3] == '-') {
-            /* Annex B: handle `<!--` single line html comments */
-            goto skip_line_comment;
-        } 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 if (p[1] == '>') {
-            p += 2;
-            s->token.val = TOK_ARROW;
-        } 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] == '&') {
-            if (p[2] == '=') {
-                p += 3;
-                s->token.val = TOK_LAND_ASSIGN;
-            } else {
-                p += 2;
-                s->token.val = TOK_LAND;
-            }
-        } else {
-            goto def_token;
-        }
-        break;
-#ifdef CONFIG_BIGNUM
-        /* in math mode, '^' is the power operator. '^^' is always the
-           xor operator and '**' is always the power operator */
-    case '^':
-        if (p[1] == '=') {
-            p += 2;
-            if (s->cur_func->js_mode & JS_MODE_MATH)
-                s->token.val = TOK_MATH_POW_ASSIGN;
-            else
-                s->token.val = TOK_XOR_ASSIGN;
-        } else if (p[1] == '^') {
-            if (p[2] == '=') {
-                p += 3;
-                s->token.val = TOK_XOR_ASSIGN;
-            } else {
-                p += 2;
-                s->token.val = '^';
-            }
-        } else {
-            p++;
-            if (s->cur_func->js_mode & JS_MODE_MATH)
-                s->token.val = TOK_MATH_POW;
-            else
-                s->token.val = '^';
-        }
-        break;
-#else
-    case '^':
-        if (p[1] == '=') {
-            p += 2;
-            s->token.val = TOK_XOR_ASSIGN;
-        } else {
-            goto def_token;
-        }
-        break;
-#endif
-    case '|':
-        if (p[1] == '=') {
-            p += 2;
-            s->token.val = TOK_OR_ASSIGN;
-        } else if (p[1] == '|') {
-            if (p[2] == '=') {
-                p += 3;
-                s->token.val = TOK_LOR_ASSIGN;
-            } else {
-                p += 2;
-                s->token.val = TOK_LOR;
-            }
-        } else {
-            goto def_token;
-        }
-        break;
-    case '?':
-        if (p[1] == '?') {
-            if (p[2] == '=') {
-                p += 3;
-                s->token.val = TOK_DOUBLE_QUESTION_MARK_ASSIGN;
-            } else {
-                p += 2;
-                s->token.val = TOK_DOUBLE_QUESTION_MARK;
-            }
-        } else if (p[1] == '.' && !(p[2] >= '0' && p[2] <= '9')) {
-            p += 2;
-            s->token.val = TOK_QUESTION_MARK_DOT;
-        } else {
-            goto def_token;
-        }
-        break;
-    default:
-        if (c >= 128) {
-            /* unicode value */
-            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
-            switch(c) {
-            case CP_PS:
-            case CP_LS:
-                /* XXX: should avoid incrementing line_number, but
-                   needed to handle HTML comments */
-                goto line_terminator; 
-            default:
-                if (lre_is_space(c)) {
-                    goto redo;
-                } else if (lre_js_is_ident_first(c)) {
-                    ident_has_escape = FALSE;
-                    goto has_ident;
-                } else {
-                    js_parse_error(s, "unexpected character");
-                    goto fail;
-                }
-            }
-        }
-    def_token:
-        s->token.val = c;
-        p++;
-        break;
-    }
-    s->buf_ptr = p;
-
-    //    dump_token(s, &s->token);
-    return 0;
-
- fail:
-    s->token.val = TOK_ERROR;
-    return -1;
-}
-
-/* 'c' is the first character. Return JS_ATOM_NULL in case of error */
-static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c)
-{
-    const uint8_t *p;
-    char ident_buf[128], *buf;
-    size_t ident_size, ident_pos;
-    JSAtom atom;
-    
-    p = *pp;
-    buf = ident_buf;
-    ident_size = sizeof(ident_buf);
-    ident_pos = 0;
-    for(;;) {
-        buf[ident_pos++] = c;
-        c = *p;
-        if (c >= 128 ||
-            !((lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1))
-            break;
-        p++;
-        if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
-            if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) {
-                atom = JS_ATOM_NULL;
-                goto done;
-            }
-        }
-    }
-    atom = JS_NewAtomLen(s->ctx, buf, ident_pos);
- done:
-    if (unlikely(buf != ident_buf))
-        js_free(s->ctx, buf);
-    *pp = p;
-    return atom;
-}
-
-static __exception int json_next_token(JSParseState *s)
-{
-    const uint8_t *p;
-    int c;
-    JSAtom atom;
-    
-    if (js_check_stack_overflow(s->ctx->rt, 0)) {
-        return js_parse_error(s, "stack overflow");
-    }
-    
-    free_token(s, &s->token);
-
-    p = s->last_ptr = s->buf_ptr;
-    s->last_line_num = s->token.line_num;
- redo:
-    s->token.line_num = s->line_num;
-    s->token.ptr = p;
-    c = *p;
-    switch(c) {
-    case 0:
-        if (p >= s->buf_end) {
-            s->token.val = TOK_EOF;
-        } else {
-            goto def_token;
-        }
-        break;
-    case '\'':
-        if (!s->ext_json) {
-            /* JSON does not accept single quoted strings */
-            goto def_token;
-        }
-        /* fall through */
-    case '\"':
-        if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))
-            goto fail;
-        break;
-    case '\r':  /* accept DOS and MAC newline sequences */
-        if (p[1] == '\n') {
-            p++;
-        }
-        /* fall thru */
-    case '\n':
-        p++;
-        s->line_num++;
-        goto redo;
-    case '\f':
-    case '\v':
-        if (!s->ext_json) {
-            /* JSONWhitespace does not match <VT>, nor <FF> */
-            goto def_token;
-        }
-        /* fall through */
-    case ' ':
-    case '\t':
-        p++;
-        goto redo;
-    case '/':
-        if (!s->ext_json) {
-            /* JSON does not accept comments */
-            goto def_token;
-        }
-        if (p[1] == '*') {
-            /* comment */
-            p += 2;
-            for(;;) {
-                if (*p == '\0' && p >= s->buf_end) {
-                    js_parse_error(s, "unexpected end of comment");
-                    goto fail;
-                }
-                if (p[0] == '*' && p[1] == '/') {
-                    p += 2;
-                    break;
-                }
-                if (*p == '\n') {
-                    s->line_num++;
-                    p++;
-                } else if (*p == '\r') {
-                    p++;
-                } else if (*p >= 0x80) {
-                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
-                    if (c == -1) {
-                        p++; /* skip invalid UTF-8 */
-                    }
-                } else {
-                    p++;
-                }
-            }
-            goto redo;
-        } else if (p[1] == '/') {
-            /* line comment */
-            p += 2;
-            for(;;) {
-                if (*p == '\0' && p >= s->buf_end)
-                    break;
-                if (*p == '\r' || *p == '\n')
-                    break;
-                if (*p >= 0x80) {
-                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
-                    /* LS or PS are considered as line terminator */
-                    if (c == CP_LS || c == CP_PS) {
-                        break;
-                    } else if (c == -1) {
-                        p++; /* skip invalid UTF-8 */
-                    }
-                } else {
-                    p++;
-                }
-            }
-            goto redo;
-        } else {
-            goto def_token;
-        }
-        break;
-    case 'a': case 'b': case 'c': case 'd':
-    case 'e': case 'f': case 'g': case 'h':
-    case 'i': case 'j': case 'k': case 'l':
-    case 'm': case 'n': case 'o': case 'p':
-    case 'q': case 'r': case 's': case 't':
-    case 'u': case 'v': case 'w': case 'x':
-    case 'y': case 'z': 
-    case 'A': case 'B': case 'C': case 'D':
-    case 'E': case 'F': case 'G': case 'H':
-    case 'I': case 'J': case 'K': case 'L':
-    case 'M': case 'N': case 'O': case 'P':
-    case 'Q': case 'R': case 'S': case 'T':
-    case 'U': case 'V': case 'W': case 'X':
-    case 'Y': case 'Z': 
-    case '_':
-    case '$':
-        /* identifier : only pure ascii characters are accepted */
-        p++;
-        atom = json_parse_ident(s, &p, c);
-        if (atom == JS_ATOM_NULL)
-            goto fail;
-        s->token.u.ident.atom = atom;
-        s->token.u.ident.has_escape = FALSE;
-        s->token.u.ident.is_reserved = FALSE;
-        s->token.val = TOK_IDENT;
-        break;
-    case '+':
-        if (!s->ext_json || !is_digit(p[1]))
-            goto def_token;
-        goto parse_number;
-    case '0':
-        if (is_digit(p[1]))
-            goto def_token;
-        goto parse_number;
-    case '-':
-        if (!is_digit(p[1]))
-            goto def_token;
-        goto parse_number;
-    case '1': case '2': case '3': case '4':
-    case '5': case '6': case '7': case '8':
-    case '9': 
-        /* number */
-    parse_number:
-        {
-            JSValue ret;
-            int flags, radix;
-            if (!s->ext_json) {
-                flags = 0;
-                radix = 10;
-            } else {
-                flags = ATOD_ACCEPT_BIN_OCT;
-                radix = 0;
-            }
-            ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix,
-                          flags);
-            if (JS_IsException(ret))
-                goto fail;
-            s->token.val = TOK_NUMBER;
-            s->token.u.num.val = ret;
-        }
-        break;
-    default:
-        if (c >= 128) {
-            js_parse_error(s, "unexpected character");
-            goto fail;
-        }
-    def_token:
-        s->token.val = c;
-        p++;
-        break;
-    }
-    s->buf_ptr = p;
-
-    //    dump_token(s, &s->token);
-    return 0;
-
- fail:
-    s->token.val = TOK_ERROR;
-    return -1;
-}
-
-/* only used for ':' and '=>', 'let' or 'function' look-ahead. *pp is
-   only set if TOK_IMPORT is returned */
-/* XXX: handle all unicode cases */
-static int simple_next_token(const uint8_t **pp, BOOL no_line_terminator)
-{
-    const uint8_t *p;
-    uint32_t c;
-    
-    /* skip spaces and comments */
-    p = *pp;
-    for (;;) {
-        switch(c = *p++) {
-        case '\r':
-        case '\n':
-            if (no_line_terminator)
-                return '\n';
-            continue;
-        case ' ':
-        case '\t':
-        case '\v':
-        case '\f':
-            continue;
-        case '/':
-            if (*p == '/') {
-                if (no_line_terminator)
-                    return '\n';
-                while (*p && *p != '\r' && *p != '\n')
-                    p++;
-                continue;
-            }
-            if (*p == '*') {
-                while (*++p) {
-                    if ((*p == '\r' || *p == '\n') && no_line_terminator)
-                        return '\n';
-                    if (*p == '*' && p[1] == '/') {
-                        p += 2;
-                        break;
-                    }
-                }
-                continue;
-            }
-            break;
-        case '=':
-            if (*p == '>')
-                return TOK_ARROW;
-            break;
-        default:
-            if (lre_js_is_ident_first(c)) {
-                if (c == 'i') {
-                    if (p[0] == 'n' && !lre_js_is_ident_next(p[1])) {
-                        return TOK_IN;
-                    }
-                    if (p[0] == 'm' && p[1] == 'p' && p[2] == 'o' &&
-                        p[3] == 'r' && p[4] == 't' &&
-                        !lre_js_is_ident_next(p[5])) {
-                        *pp = p + 5;
-                        return TOK_IMPORT;
-                    }
-                } else if (c == 'o' && *p == 'f' && !lre_js_is_ident_next(p[1])) {
-                    return TOK_OF;
-                } else if (c == 'e' &&
-                           p[0] == 'x' && p[1] == 'p' && p[2] == 'o' &&
-                           p[3] == 'r' && p[4] == 't' &&
-                           !lre_js_is_ident_next(p[5])) {
-                    *pp = p + 5;
-                    return TOK_EXPORT;
-                } else if (c == 'f' && p[0] == 'u' && p[1] == 'n' &&
-                         p[2] == 'c' && p[3] == 't' && p[4] == 'i' &&
-                         p[5] == 'o' && p[6] == 'n' && !lre_js_is_ident_next(p[7])) {
-                    return TOK_FUNCTION;
-                }
-                return TOK_IDENT;
-            }
-            break;
-        }
-        return c;
-    }
-}
-
-static int peek_token(JSParseState *s, BOOL no_line_terminator)
-{
-    const uint8_t *p = s->buf_ptr;
-    return simple_next_token(&p, no_line_terminator);
-}
-
-/* return true if 'input' contains the source of a module
-   (heuristic). 'input' must be a zero terminated.
-
-   Heuristic: skip comments and expect 'import' keyword not followed
-   by '(' or '.' or export keyword.
-*/
-BOOL JS_DetectModule(const char *input, size_t input_len)
-{
-    const uint8_t *p = (const uint8_t *)input;
-    int tok;
-    switch(simple_next_token(&p, FALSE)) {
-    case TOK_IMPORT:
-        tok = simple_next_token(&p, FALSE);
-        return (tok != '.' && tok != '(');
-    case TOK_EXPORT:
-        return TRUE;
-    default:
-        return FALSE;
-    }
-}
-
-static inline int get_prev_opcode(JSFunctionDef *fd) {
-    if (fd->last_opcode_pos < 0)
-        return OP_invalid;
-    else
-        return fd->byte_code.buf[fd->last_opcode_pos];
-}
-
-static BOOL js_is_live_code(JSParseState *s) {
-    switch (get_prev_opcode(s->cur_func)) {
-    case OP_tail_call:
-    case OP_tail_call_method:
-    case OP_return:
-    case OP_return_undef:
-    case OP_return_async:
-    case OP_throw:
-    case OP_throw_error:
-    case OP_goto:
-#if SHORT_OPCODES
-    case OP_goto8:
-    case OP_goto16:
-#endif
-    case OP_ret:
-        return FALSE;
-    default:
-        return TRUE;
-    }
-}
-
-static void emit_u8(JSParseState *s, uint8_t val)
-{
-    dbuf_putc(&s->cur_func->byte_code, val);
-}
-
-static void emit_u16(JSParseState *s, uint16_t val)
-{
-    dbuf_put_u16(&s->cur_func->byte_code, val);
-}
-
-static void emit_u32(JSParseState *s, uint32_t val)
-{
-    dbuf_put_u32(&s->cur_func->byte_code, val);
-}
-
-static void emit_op(JSParseState *s, uint8_t val)
-{
-    JSFunctionDef *fd = s->cur_func;
-    DynBuf *bc = &fd->byte_code;
-
-    /* Use the line number of the last token used, not the next token,
-       nor the current offset in the source file.
-     */
-    if (unlikely(fd->last_opcode_line_num != s->last_line_num)) {
-        dbuf_putc(bc, OP_line_num);
-        dbuf_put_u32(bc, s->last_line_num);
-        fd->last_opcode_line_num = s->last_line_num;
-    }
-    fd->last_opcode_pos = bc->size;
-    dbuf_putc(bc, val);
-}
-
-static void emit_atom(JSParseState *s, JSAtom name)
-{
-    emit_u32(s, JS_DupAtom(s->ctx, name));
-}
-
-static int update_label(JSFunctionDef *s, int label, int delta)
-{
-    LabelSlot *ls;
-
-    assert(label >= 0 && label < s->label_count);
-    ls = &s->label_slots[label];
-    ls->ref_count += delta;
-    assert(ls->ref_count >= 0);
-    return ls->ref_count;
-}
-
-static int new_label_fd(JSFunctionDef *fd, int label)
-{
-    LabelSlot *ls;
-
-    if (label < 0) {
-        if (js_resize_array(fd->ctx, (void *)&fd->label_slots,
-                            sizeof(fd->label_slots[0]),
-                            &fd->label_size, fd->label_count + 1))
-            return -1;
-        label = fd->label_count++;
-        ls = &fd->label_slots[label];
-        ls->ref_count = 0;
-        ls->pos = -1;
-        ls->pos2 = -1;
-        ls->addr = -1;
-        ls->first_reloc = NULL;
-    }
-    return label;
-}
-
-static int new_label(JSParseState *s)
-{
-    return new_label_fd(s->cur_func, -1);
-}
-
-/* return the label ID offset */
-static int emit_label(JSParseState *s, int label)
-{
-    if (label >= 0) {
-        emit_op(s, OP_label);
-        emit_u32(s, label);
-        s->cur_func->label_slots[label].pos = s->cur_func->byte_code.size;
-        return s->cur_func->byte_code.size - 4;
-    } else {
-        return -1;
-    }
-}
-
-/* return label or -1 if dead code */
-static int emit_goto(JSParseState *s, int opcode, int label)
-{
-    if (js_is_live_code(s)) {
-        if (label < 0)
-            label = new_label(s);
-        emit_op(s, opcode);
-        emit_u32(s, label);
-        s->cur_func->label_slots[label].ref_count++;
-        return label;
-    }
-    return -1;
-}
-
-/* return the constant pool index. 'val' is not duplicated. */
-static int cpool_add(JSParseState *s, JSValue val)
-{
-    JSFunctionDef *fd = s->cur_func;
-    
-    if (js_resize_array(s->ctx, (void *)&fd->cpool, sizeof(fd->cpool[0]),
-                        &fd->cpool_size, fd->cpool_count + 1))
-        return -1;
-    fd->cpool[fd->cpool_count++] = val;
-    return fd->cpool_count - 1;
-}
-
-static __exception int emit_push_const(JSParseState *s, JSValueConst val,
-                                       BOOL as_atom)
-{
-    int idx;
-
-    if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING && as_atom) {
-        JSAtom atom;
-        /* warning: JS_NewAtomStr frees the string value */
-        JS_DupValue(s->ctx, val);
-        atom = JS_NewAtomStr(s->ctx, JS_VALUE_GET_STRING(val));
-        if (atom != JS_ATOM_NULL && !__JS_AtomIsTaggedInt(atom)) {
-            emit_op(s, OP_push_atom_value);
-            emit_u32(s, atom);
-            return 0;
-        }
-    }
-
-    idx = cpool_add(s, JS_DupValue(s->ctx, val));
-    if (idx < 0)
-        return -1;
-    emit_op(s, OP_push_const);
-    emit_u32(s, idx);
-    return 0;
-}
-
-/* return the variable index or -1 if not found,
-   add ARGUMENT_VAR_OFFSET for argument variables */
-static int find_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
-{
-    int i;
-    for(i = fd->arg_count; i-- > 0;) {
-        if (fd->args[i].var_name == name)
-            return i | ARGUMENT_VAR_OFFSET;
-    }
-    return -1;
-}
-
-static int find_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
-{
-    int i;
-    for(i = fd->var_count; i-- > 0;) {
-        if (fd->vars[i].var_name == name && fd->vars[i].scope_level == 0)
-            return i;
-    }
-    return find_arg(ctx, fd, name);
-}
-
-/* find a variable declaration in a given scope */
-static int find_var_in_scope(JSContext *ctx, JSFunctionDef *fd,
-                             JSAtom name, int scope_level)
-{
-    int scope_idx;
-    for(scope_idx = fd->scopes[scope_level].first; scope_idx >= 0;
-        scope_idx = fd->vars[scope_idx].scope_next) {
-        if (fd->vars[scope_idx].scope_level != scope_level)
-            break;
-        if (fd->vars[scope_idx].var_name == name)
-            return scope_idx;
-    }
-    return -1;
-}
-
-/* return true if scope == parent_scope or if scope is a child of
-   parent_scope */
-static BOOL is_child_scope(JSContext *ctx, JSFunctionDef *fd,
-                           int scope, int parent_scope)
-{
-    while (scope >= 0) {
-        if (scope == parent_scope)
-            return TRUE;
-        scope = fd->scopes[scope].parent;
-    }
-    return FALSE;
-}
-
-/* find a 'var' declaration in the same scope or a child scope */
-static int find_var_in_child_scope(JSContext *ctx, JSFunctionDef *fd,
-                                   JSAtom name, int scope_level)
-{
-    int i;
-    for(i = 0; i < fd->var_count; i++) {
-        JSVarDef *vd = &fd->vars[i];
-        if (vd->var_name == name && vd->scope_level == 0) {
-            if (is_child_scope(ctx, fd, vd->scope_next,
-                               scope_level))
-                return i;
-        }
-    }
-    return -1;
-}
-
-
-static JSGlobalVar *find_global_var(JSFunctionDef *fd, JSAtom name)
-{
-    int i;
-    for(i = 0; i < fd->global_var_count; i++) {
-        JSGlobalVar *hf = &fd->global_vars[i];
-        if (hf->var_name == name)
-            return hf;
-    }
-    return NULL;
-
-}
-
-static JSGlobalVar *find_lexical_global_var(JSFunctionDef *fd, JSAtom name)
-{
-    JSGlobalVar *hf = find_global_var(fd, name);
-    if (hf && hf->is_lexical)
-        return hf;
-    else
-        return NULL;
-}
-
-static int find_lexical_decl(JSContext *ctx, JSFunctionDef *fd, JSAtom name,
-                             int scope_idx, BOOL check_catch_var)
-{
-    while (scope_idx >= 0) {
-        JSVarDef *vd = &fd->vars[scope_idx];
-        if (vd->var_name == name &&
-            (vd->is_lexical || (vd->var_kind == JS_VAR_CATCH &&
-                                check_catch_var)))
-            return scope_idx;
-        scope_idx = vd->scope_next;
-    }
-
-    if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_GLOBAL) {
-        if (find_lexical_global_var(fd, name))
-            return GLOBAL_VAR_OFFSET;
-    }
-    return -1;
-}
-
-static int push_scope(JSParseState *s) {
-    if (s->cur_func) {
-        JSFunctionDef *fd = s->cur_func;
-        int scope = fd->scope_count;
-        /* XXX: should check for scope overflow */
-        if ((fd->scope_count + 1) > fd->scope_size) {
-            int new_size;
-            size_t slack;
-            JSVarScope *new_buf;
-            /* XXX: potential arithmetic overflow */
-            new_size = max_int(fd->scope_count + 1, fd->scope_size * 3 / 2);
-            if (fd->scopes == fd->def_scope_array) {
-                new_buf = js_realloc2(s->ctx, NULL, new_size * sizeof(*fd->scopes), &slack);
-                if (!new_buf)
-                    return -1;
-                memcpy(new_buf, fd->scopes, fd->scope_count * sizeof(*fd->scopes));
-            } else {
-                new_buf = js_realloc2(s->ctx, fd->scopes, new_size * sizeof(*fd->scopes), &slack);
-                if (!new_buf)
-                    return -1;
-            }
-            new_size += slack / sizeof(*new_buf);
-            fd->scopes = new_buf;
-            fd->scope_size = new_size;
-        }
-        fd->scope_count++;
-        fd->scopes[scope].parent = fd->scope_level;
-        fd->scopes[scope].first = fd->scope_first;
-        emit_op(s, OP_enter_scope);
-        emit_u16(s, scope);
-        return fd->scope_level = scope;
-    }
-    return 0;
-}
-
-static int get_first_lexical_var(JSFunctionDef *fd, int scope)
-{
-    while (scope >= 0) {
-        int scope_idx = fd->scopes[scope].first;
-        if (scope_idx >= 0)
-            return scope_idx;
-        scope = fd->scopes[scope].parent;
-    }
-    return -1;
-}
-
-static void pop_scope(JSParseState *s) {
-    if (s->cur_func) {
-        /* disable scoped variables */
-        JSFunctionDef *fd = s->cur_func;
-        int scope = fd->scope_level;
-        emit_op(s, OP_leave_scope);
-        emit_u16(s, scope);
-        fd->scope_level = fd->scopes[scope].parent;
-        fd->scope_first = get_first_lexical_var(fd, fd->scope_level);
-    }
-}
-
-static void close_scopes(JSParseState *s, int scope, int scope_stop)
-{
-    while (scope > scope_stop) {
-        emit_op(s, OP_leave_scope);
-        emit_u16(s, scope);
-        scope = s->cur_func->scopes[scope].parent;
-    }
-}
-
-/* return the variable index or -1 if error */
-static int add_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
-{
-    JSVarDef *vd;
-
-    /* the local variable indexes are currently stored on 16 bits */
-    if (fd->var_count >= JS_MAX_LOCAL_VARS) {
-        JS_ThrowInternalError(ctx, "too many local variables");
-        return -1;
-    }
-    if (js_resize_array(ctx, (void **)&fd->vars, sizeof(fd->vars[0]),
-                        &fd->var_size, fd->var_count + 1))
-        return -1;
-    vd = &fd->vars[fd->var_count++];
-    memset(vd, 0, sizeof(*vd));
-    vd->var_name = JS_DupAtom(ctx, name);
-    vd->func_pool_idx = -1;
-    return fd->var_count - 1;
-}
-
-static int add_scope_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name,
-                         JSVarKindEnum var_kind)
-{
-    int idx = add_var(ctx, fd, name);
-    if (idx >= 0) {
-        JSVarDef *vd = &fd->vars[idx];
-        vd->var_kind = var_kind;
-        vd->scope_level = fd->scope_level;
-        vd->scope_next = fd->scope_first;
-        fd->scopes[fd->scope_level].first = idx;
-        fd->scope_first = idx;
-    }
-    return idx;
-}
-
-static int add_func_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
-{
-    int idx = fd->func_var_idx;
-    if (idx < 0 && (idx = add_var(ctx, fd, name)) >= 0) {
-        fd->func_var_idx = idx;
-        fd->vars[idx].var_kind = JS_VAR_FUNCTION_NAME;
-        if (fd->js_mode & JS_MODE_STRICT)
-            fd->vars[idx].is_const = TRUE;
-    }
-    return idx;
-}
-
-static int add_arguments_var(JSContext *ctx, JSFunctionDef *fd)
-{
-    int idx = fd->arguments_var_idx;
-    if (idx < 0 && (idx = add_var(ctx, fd, JS_ATOM_arguments)) >= 0) {
-        fd->arguments_var_idx = idx;
-    }
-    return idx;
-}
-
-/* add an argument definition in the argument scope. Only needed when
-   "eval()" may be called in the argument scope. Return 0 if OK. */
-static int add_arguments_arg(JSContext *ctx, JSFunctionDef *fd)
-{
-    int idx;
-    if (fd->arguments_arg_idx < 0) {
-        idx = find_var_in_scope(ctx, fd, JS_ATOM_arguments, ARG_SCOPE_INDEX);
-        if (idx < 0) {
-            /* XXX: the scope links are not fully updated. May be an
-               issue if there are child scopes of the argument
-               scope */
-            idx = add_var(ctx, fd, JS_ATOM_arguments);
-            if (idx < 0)
-                return -1;
-            fd->vars[idx].scope_next = fd->scopes[ARG_SCOPE_INDEX].first;
-            fd->scopes[ARG_SCOPE_INDEX].first = idx;
-            fd->vars[idx].scope_level = ARG_SCOPE_INDEX;
-            fd->vars[idx].is_lexical = TRUE;
-
-            fd->arguments_arg_idx = idx;
-        }
-    }
-    return 0;
-}
-
-static int add_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
-{
-    JSVarDef *vd;
-
-    /* the local variable indexes are currently stored on 16 bits */
-    if (fd->arg_count >= JS_MAX_LOCAL_VARS) {
-        JS_ThrowInternalError(ctx, "too many arguments");
-        return -1;
-    }
-    if (js_resize_array(ctx, (void **)&fd->args, sizeof(fd->args[0]),
-                        &fd->arg_size, fd->arg_count + 1))
-        return -1;
-    vd = &fd->args[fd->arg_count++];
-    memset(vd, 0, sizeof(*vd));
-    vd->var_name = JS_DupAtom(ctx, name);
-    vd->func_pool_idx = -1;
-    return fd->arg_count - 1;
-}
-
-/* add a global variable definition */
-static JSGlobalVar *add_global_var(JSContext *ctx, JSFunctionDef *s,
-                                     JSAtom name)
-{
-    JSGlobalVar *hf;
-
-    if (js_resize_array(ctx, (void **)&s->global_vars,
-                        sizeof(s->global_vars[0]),
-                        &s->global_var_size, s->global_var_count + 1))
-        return NULL;
-    hf = &s->global_vars[s->global_var_count++];
-    hf->cpool_idx = -1;
-    hf->force_init = FALSE;
-    hf->is_lexical = FALSE;
-    hf->is_const = FALSE;
-    hf->scope_level = s->scope_level;
-    hf->var_name = JS_DupAtom(ctx, name);
-    return hf;
-}
-
-typedef enum {
-    JS_VAR_DEF_WITH,
-    JS_VAR_DEF_LET,
-    JS_VAR_DEF_CONST,
-    JS_VAR_DEF_FUNCTION_DECL, /* function declaration */
-    JS_VAR_DEF_NEW_FUNCTION_DECL, /* async/generator function declaration */
-    JS_VAR_DEF_CATCH,
-    JS_VAR_DEF_VAR,
-} JSVarDefEnum;
-
-static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
-                      JSVarDefEnum var_def_type)
-{
-    JSContext *ctx = s->ctx;
-    JSVarDef *vd;
-    int idx;
-
-    switch (var_def_type) {
-    case JS_VAR_DEF_WITH:
-        idx = add_scope_var(ctx, fd, name, JS_VAR_NORMAL);
-        break;
-
-    case JS_VAR_DEF_LET:
-    case JS_VAR_DEF_CONST:
-    case JS_VAR_DEF_FUNCTION_DECL:
-    case JS_VAR_DEF_NEW_FUNCTION_DECL:
-        idx = find_lexical_decl(ctx, fd, name, fd->scope_first, TRUE);
-        if (idx >= 0) {
-            if (idx < GLOBAL_VAR_OFFSET) {
-                if (fd->vars[idx].scope_level == fd->scope_level) {
-                    /* same scope: in non strict mode, functions
-                       can be redefined (annex B.3.3.4). */
-                    if (!(!(fd->js_mode & JS_MODE_STRICT) &&
-                          var_def_type == JS_VAR_DEF_FUNCTION_DECL &&
-                          fd->vars[idx].var_kind == JS_VAR_FUNCTION_DECL)) {
-                        goto redef_lex_error;
-                    }
-                } else if (fd->vars[idx].var_kind == JS_VAR_CATCH && (fd->vars[idx].scope_level + 2) == fd->scope_level) {
-                    goto redef_lex_error;
-                }
-            } else {
-                if (fd->scope_level == fd->body_scope) {
-                redef_lex_error:
-                    /* redefining a scoped var in the same scope: error */
-                    return js_parse_error(s, "invalid redefinition of lexical identifier");
-                }
-            }
-        }
-        if (var_def_type != JS_VAR_DEF_FUNCTION_DECL &&
-            var_def_type != JS_VAR_DEF_NEW_FUNCTION_DECL &&
-            fd->scope_level == fd->body_scope &&
-            find_arg(ctx, fd, name) >= 0) {
-            /* lexical variable redefines a parameter name */
-            return js_parse_error(s, "invalid redefinition of parameter name");
-        }
-
-        if (find_var_in_child_scope(ctx, fd, name, fd->scope_level) >= 0) {
-            return js_parse_error(s, "invalid redefinition of a variable");
-        }
-        
-        if (fd->is_global_var) {
-            JSGlobalVar *hf;
-            hf = find_global_var(fd, name);
-            if (hf && is_child_scope(ctx, fd, hf->scope_level,
-                                     fd->scope_level)) {
-                return js_parse_error(s, "invalid redefinition of global identifier");
-            }
-        }
-        
-        if (fd->is_eval &&
-            (fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
-             fd->eval_type == JS_EVAL_TYPE_MODULE) &&
-            fd->scope_level == fd->body_scope) {
-            JSGlobalVar *hf;
-            hf = add_global_var(s->ctx, fd, name);
-            if (!hf)
-                return -1;
-            hf->is_lexical = TRUE;
-            hf->is_const = (var_def_type == JS_VAR_DEF_CONST);
-            idx = GLOBAL_VAR_OFFSET;
-        } else {
-            JSVarKindEnum var_kind;
-            if (var_def_type == JS_VAR_DEF_FUNCTION_DECL)
-                var_kind = JS_VAR_FUNCTION_DECL;
-            else if (var_def_type == JS_VAR_DEF_NEW_FUNCTION_DECL)
-                var_kind = JS_VAR_NEW_FUNCTION_DECL;
-            else
-                var_kind = JS_VAR_NORMAL;
-            idx = add_scope_var(ctx, fd, name, var_kind);
-            if (idx >= 0) {
-                vd = &fd->vars[idx];
-                vd->is_lexical = 1;
-                vd->is_const = (var_def_type == JS_VAR_DEF_CONST);
-            }
-        }
-        break;
-
-    case JS_VAR_DEF_CATCH:
-        idx = add_scope_var(ctx, fd, name, JS_VAR_CATCH);
-        break;
-
-    case JS_VAR_DEF_VAR:
-        if (find_lexical_decl(ctx, fd, name, fd->scope_first,
-                              FALSE) >= 0) {
-       invalid_lexical_redefinition:
-            /* error to redefine a var that inside a lexical scope */
-            return js_parse_error(s, "invalid redefinition of lexical identifier");
-        }
-        if (fd->is_global_var) {
-            JSGlobalVar *hf;
-            hf = find_global_var(fd, name);
-            if (hf && hf->is_lexical && hf->scope_level == fd->scope_level &&
-                fd->eval_type == JS_EVAL_TYPE_MODULE) {
-                goto invalid_lexical_redefinition;
-            }
-            hf = add_global_var(s->ctx, fd, name);
-            if (!hf)
-                return -1;
-            idx = GLOBAL_VAR_OFFSET;
-        } else {
-            /* if the variable already exists, don't add it again  */
-            idx = find_var(ctx, fd, name);
-            if (idx >= 0)
-                break;
-            idx = add_var(ctx, fd, name);
-            if (idx >= 0) {
-                if (name == JS_ATOM_arguments && fd->has_arguments_binding)
-                    fd->arguments_var_idx = idx;
-                fd->vars[idx].scope_next = fd->scope_level;
-            }
-        }
-        break;
-    default:
-        abort();
-    }
-    return idx;
-}
-
-/* add a private field variable in the current scope */
-static int add_private_class_field(JSParseState *s, JSFunctionDef *fd,
-                                   JSAtom name, JSVarKindEnum var_kind)
-{
-    JSContext *ctx = s->ctx;
-    JSVarDef *vd;
-    int idx;
-
-    idx = add_scope_var(ctx, fd, name, var_kind);
-    if (idx < 0)
-        return idx;
-    vd = &fd->vars[idx];
-    vd->is_lexical = 1;
-    vd->is_const = 1;
-    return idx;
-}
-
-static __exception int js_parse_expr(JSParseState *s);
-static __exception int js_parse_function_decl(JSParseState *s,
-                                              JSParseFunctionEnum func_type,
-                                              JSFunctionKindEnum func_kind,
-                                              JSAtom func_name, const uint8_t *ptr,
-                                              int start_line);
-static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s);
-static __exception int js_parse_function_decl2(JSParseState *s,
-                                               JSParseFunctionEnum func_type,
-                                               JSFunctionKindEnum func_kind,
-                                               JSAtom func_name,
-                                               const uint8_t *ptr,
-                                               int function_line_num,
-                                               JSParseExportEnum export_flag,
-                                               JSFunctionDef **pfd);
-static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags);
-static __exception int js_parse_assign_expr(JSParseState *s);
-static __exception int js_parse_unary(JSParseState *s, int parse_flags);
-static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
-                             JSAtom label_name,
-                             int label_break, int label_cont,
-                             int drop_count);
-static void pop_break_entry(JSFunctionDef *fd);
-static JSExportEntry *add_export_entry(JSParseState *s, JSModuleDef *m,
-                                       JSAtom local_name, JSAtom export_name,
-                                       JSExportTypeEnum export_type);
-
-/* Note: all the fields are already sealed except length */
-static int seal_template_obj(JSContext *ctx, JSValueConst obj)
-{
-    JSObject *p;
-    JSShapeProperty *prs;
-
-    p = JS_VALUE_GET_OBJ(obj);
-    prs = find_own_property1(p, JS_ATOM_length);
-    if (prs) {
-        if (js_update_property_flags(ctx, p, &prs,
-                                     prs->flags & ~(JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)))
-            return -1;
-    }
-    p->extensible = FALSE;
-    return 0;
-}
-
-static __exception int js_parse_template(JSParseState *s, int call, int *argc)
-{
-    JSContext *ctx = s->ctx;
-    JSValue raw_array, template_object;
-    JSToken cooked;
-    int depth, ret;
-
-    raw_array = JS_UNDEFINED; /* avoid warning */
-    template_object = JS_UNDEFINED; /* avoid warning */
-    if (call) {
-        /* Create a template object: an array of cooked strings */
-        /* Create an array of raw strings and store it to the raw property */
-        template_object = JS_NewArray(ctx);
-        if (JS_IsException(template_object))
-            return -1;
-        //        pool_idx = s->cur_func->cpool_count;
-        ret = emit_push_const(s, template_object, 0);
-        JS_FreeValue(ctx, template_object);
-        if (ret)
-            return -1;
-        raw_array = JS_NewArray(ctx);
-        if (JS_IsException(raw_array))
-            return -1;
-        if (JS_DefinePropertyValue(ctx, template_object, JS_ATOM_raw,
-                                   raw_array, JS_PROP_THROW) < 0) {
-            return -1;
-        }
-    }
-
-    depth = 0;
-    while (s->token.val == TOK_TEMPLATE) {
-        const uint8_t *p = s->token.ptr + 1;
-        cooked = s->token;
-        if (call) {
-            if (JS_DefinePropertyValueUint32(ctx, raw_array, depth,
-                                             JS_DupValue(ctx, s->token.u.str.str),
-                                             JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) {
-                return -1;
-            }
-            /* re-parse the string with escape sequences but do not throw a
-               syntax error if it contains invalid sequences
-             */
-            if (js_parse_string(s, '`', FALSE, p, &cooked, &p)) {
-                cooked.u.str.str = JS_UNDEFINED;
-            }
-            if (JS_DefinePropertyValueUint32(ctx, template_object, depth,
-                                             cooked.u.str.str,
-                                             JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) {
-                return -1;
-            }
-        } else {
-            JSString *str;
-            /* re-parse the string with escape sequences and throw a
-               syntax error if it contains invalid sequences
-             */
-            JS_FreeValue(ctx, s->token.u.str.str);
-            s->token.u.str.str = JS_UNDEFINED;
-            if (js_parse_string(s, '`', TRUE, p, &cooked, &p))
-                return -1;
-            str = JS_VALUE_GET_STRING(cooked.u.str.str);
-            if (str->len != 0 || depth == 0) {
-                ret = emit_push_const(s, cooked.u.str.str, 1);
-                JS_FreeValue(s->ctx, cooked.u.str.str);
-                if (ret)
-                    return -1;
-                if (depth == 0) {
-                    if (s->token.u.str.sep == '`')
-                        goto done1;
-                    emit_op(s, OP_get_field2);
-                    emit_atom(s, JS_ATOM_concat);
-                }
-                depth++;
-            } else {
-                JS_FreeValue(s->ctx, cooked.u.str.str);
-            }
-        }
-        if (s->token.u.str.sep == '`')
-            goto done;
-        if (next_token(s))
-            return -1;
-        if (js_parse_expr(s))
-            return -1;
-        depth++;
-        if (s->token.val != '}') {
-            return js_parse_error(s, "expected '}' after template expression");
-        }
-        /* XXX: should convert to string at this stage? */
-        free_token(s, &s->token);
-        /* Resume TOK_TEMPLATE parsing (s->token.line_num and
-         * s->token.ptr are OK) */
-        s->got_lf = FALSE;
-        s->last_line_num = s->token.line_num;
-        if (js_parse_template_part(s, s->buf_ptr))
-            return -1;
-    }
-    return js_parse_expect(s, TOK_TEMPLATE);
-
- done:
-    if (call) {
-        /* Seal the objects */
-        seal_template_obj(ctx, raw_array);
-        seal_template_obj(ctx, template_object);
-        *argc = depth + 1;
-    } else {
-        emit_op(s, OP_call_method);
-        emit_u16(s, depth - 1);
-    }
- done1:
-    return next_token(s);
-}
-
-
-#define PROP_TYPE_IDENT 0
-#define PROP_TYPE_VAR   1
-#define PROP_TYPE_GET   2
-#define PROP_TYPE_SET   3
-#define PROP_TYPE_STAR  4
-#define PROP_TYPE_ASYNC 5
-#define PROP_TYPE_ASYNC_STAR 6
-
-#define PROP_TYPE_PRIVATE (1 << 4)
-
-static BOOL token_is_ident(int tok)
-{
-    /* Accept keywords and reserved words as property names */
-    return (tok == TOK_IDENT ||
-            (tok >= TOK_FIRST_KEYWORD &&
-             tok <= TOK_LAST_KEYWORD));
-}
-
-/* if the property is an expression, name = JS_ATOM_NULL */
-static int __exception js_parse_property_name(JSParseState *s,
-                                              JSAtom *pname,
-                                              BOOL allow_method, BOOL allow_var,
-                                              BOOL allow_private)
-{
-    int is_private = 0;
-    BOOL is_non_reserved_ident;
-    JSAtom name;
-    int prop_type;
-    
-    prop_type = PROP_TYPE_IDENT;
-    if (allow_method) {
-        if (token_is_pseudo_keyword(s, JS_ATOM_get)
-        ||  token_is_pseudo_keyword(s, JS_ATOM_set)) {
-            /* get x(), set x() */
-            name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
-            if (next_token(s))
-                goto fail1;
-            if (s->token.val == ':' || s->token.val == ',' ||
-                s->token.val == '}' || s->token.val == '(') {
-                is_non_reserved_ident = TRUE;
-                goto ident_found;
-            }
-            prop_type = PROP_TYPE_GET + (name == JS_ATOM_set);
-            JS_FreeAtom(s->ctx, name);
-        } else if (s->token.val == '*') {
-            if (next_token(s))
-                goto fail;
-            prop_type = PROP_TYPE_STAR;
-        } else if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
-                   peek_token(s, TRUE) != '\n') {
-            name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
-            if (next_token(s))
-                goto fail1;
-            if (s->token.val == ':' || s->token.val == ',' ||
-                s->token.val == '}' || s->token.val == '(') {
-                is_non_reserved_ident = TRUE;
-                goto ident_found;
-            }
-            JS_FreeAtom(s->ctx, name);
-            if (s->token.val == '*') {
-                if (next_token(s))
-                    goto fail;
-                prop_type = PROP_TYPE_ASYNC_STAR;
-            } else {
-                prop_type = PROP_TYPE_ASYNC;
-            }
-        }
-    }
-
-    if (token_is_ident(s->token.val)) {
-        /* variable can only be a non-reserved identifier */
-        is_non_reserved_ident =
-            (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved);
-        /* keywords and reserved words have a valid atom */
-        name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
-        if (next_token(s))
-            goto fail1;
-    ident_found:
-        if (is_non_reserved_ident &&
-            prop_type == PROP_TYPE_IDENT && allow_var) {
-            if (!(s->token.val == ':' ||
-                  (s->token.val == '(' && allow_method))) {
-                prop_type = PROP_TYPE_VAR;
-            }
-        }
-    } else if (s->token.val == TOK_STRING) {
-        name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
-        if (name == JS_ATOM_NULL)
-            goto fail;
-        if (next_token(s))
-            goto fail1;
-    } else if (s->token.val == TOK_NUMBER) {
-        JSValue val;
-        val = s->token.u.num.val;
-#ifdef CONFIG_BIGNUM
-        if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) {
-            JSBigFloat *p = JS_VALUE_GET_PTR(val);
-            val = s->ctx->rt->bigfloat_ops.
-                mul_pow10_to_float64(s->ctx, &p->num,
-                                     s->token.u.num.exponent);
-            if (JS_IsException(val))
-                goto fail;
-            name = JS_ValueToAtom(s->ctx, val);
-            JS_FreeValue(s->ctx, val);
-        } else
-#endif
-        {
-            name = JS_ValueToAtom(s->ctx, val);
-        }
-        if (name == JS_ATOM_NULL)
-            goto fail;
-        if (next_token(s))
-            goto fail1;
-    } else if (s->token.val == '[') {
-        if (next_token(s))
-            goto fail;
-        if (js_parse_expr(s))
-            goto fail;
-        if (js_parse_expect(s, ']'))
-            goto fail;
-        name = JS_ATOM_NULL;
-    } else if (s->token.val == TOK_PRIVATE_NAME && allow_private) {
-        name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
-        if (next_token(s))
-            goto fail1;
-        is_private = PROP_TYPE_PRIVATE;
-    } else {
-        goto invalid_prop;
-    }
-    if (prop_type != PROP_TYPE_IDENT && prop_type != PROP_TYPE_VAR &&
-        s->token.val != '(') {
-        JS_FreeAtom(s->ctx, name);
-    invalid_prop:
-        js_parse_error(s, "invalid property name");
-        goto fail;
-    }
-    *pname = name;
-    return prop_type | is_private;
- fail1:
-    JS_FreeAtom(s->ctx, name);
- fail:
-    *pname = JS_ATOM_NULL;
-    return -1;
-}
-
-typedef struct JSParsePos {
-    int last_line_num;
-    int line_num;
-    BOOL got_lf;
-    const uint8_t *ptr;
-} JSParsePos;
-
-static int js_parse_get_pos(JSParseState *s, JSParsePos *sp)
-{
-    sp->last_line_num = s->last_line_num;
-    sp->line_num = s->token.line_num;
-    sp->ptr = s->token.ptr;
-    sp->got_lf = s->got_lf;
-    return 0;
-}
-
-static __exception int js_parse_seek_token(JSParseState *s, const JSParsePos *sp)
-{
-    s->token.line_num = sp->last_line_num;
-    s->line_num = sp->line_num;
-    s->buf_ptr = sp->ptr;
-    s->got_lf = sp->got_lf;
-    return next_token(s);
-}
-
-/* return TRUE if a regexp literal is allowed after this token */
-static BOOL is_regexp_allowed(int tok)
-{
-    switch (tok) {
-    case TOK_NUMBER:
-    case TOK_STRING:
-    case TOK_REGEXP:
-    case TOK_DEC:
-    case TOK_INC:
-    case TOK_NULL:
-    case TOK_FALSE:
-    case TOK_TRUE:
-    case TOK_THIS:
-    case ')':
-    case ']':
-    case '}': /* XXX: regexp may occur after */
-    case TOK_IDENT:
-        return FALSE;
-    default:
-        return TRUE;
-    }
-}
-
-#define SKIP_HAS_SEMI       (1 << 0)
-#define SKIP_HAS_ELLIPSIS   (1 << 1)
-#define SKIP_HAS_ASSIGNMENT (1 << 2)
-
-/* XXX: improve speed with early bailout */
-/* XXX: no longer works if regexps are present. Could use previous
-   regexp parsing heuristics to handle most cases */
-static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_terminator)
-{
-    char state[256];
-    size_t level = 0;
-    JSParsePos pos;
-    int last_tok, tok = TOK_EOF;
-    int c, tok_len, bits = 0;
-
-    /* protect from underflow */
-    state[level++] = 0;
-
-    js_parse_get_pos(s, &pos);
-    last_tok = 0;
-    for (;;) {
-        switch(s->token.val) {
-        case '(':
-        case '[':
-        case '{':
-            if (level >= sizeof(state))
-                goto done;
-            state[level++] = s->token.val;
-            break;
-        case ')':
-            if (state[--level] != '(')
-                goto done;
-            break;
-        case ']':
-            if (state[--level] != '[')
-                goto done;
-            break;
-        case '}':
-            c = state[--level];
-            if (c == '`') {
-                /* continue the parsing of the template */
-                free_token(s, &s->token);
-                /* Resume TOK_TEMPLATE parsing (s->token.line_num and
-                 * s->token.ptr are OK) */
-                s->got_lf = FALSE;
-                s->last_line_num = s->token.line_num;
-                if (js_parse_template_part(s, s->buf_ptr))
-                    goto done;
-                goto handle_template;
-            } else if (c != '{') {
-                goto done;
-            }
-            break;
-        case TOK_TEMPLATE:
-        handle_template:
-            if (s->token.u.str.sep != '`') {
-                /* '${' inside the template : closing '}' and continue
-                   parsing the template */
-                if (level >= sizeof(state))
-                    goto done;
-                state[level++] = '`';
-            } 
-            break;
-        case TOK_EOF:
-            goto done;
-        case ';':
-            if (level == 2) {
-                bits |= SKIP_HAS_SEMI;
-            }
-            break;
-        case TOK_ELLIPSIS:
-            if (level == 2) {
-                bits |= SKIP_HAS_ELLIPSIS;
-            }
-            break;
-        case '=':
-            bits |= SKIP_HAS_ASSIGNMENT;
-            break;
-            
-        case TOK_DIV_ASSIGN:
-            tok_len = 2;
-            goto parse_regexp;
-        case '/':
-            tok_len = 1;
-        parse_regexp:
-            if (is_regexp_allowed(last_tok)) {
-                s->buf_ptr -= tok_len;
-                if (js_parse_regexp(s)) {
-                    /* XXX: should clear the exception */
-                    goto done;
-                }
-            }
-            break;
-        }
-        /* last_tok is only used to recognize regexps */
-        if (s->token.val == TOK_IDENT &&
-            (token_is_pseudo_keyword(s, JS_ATOM_of) ||
-             token_is_pseudo_keyword(s, JS_ATOM_yield))) {
-            last_tok = TOK_OF;
-        } else {
-            last_tok = s->token.val;
-        }
-        if (next_token(s)) {
-            /* XXX: should clear the exception generated by next_token() */
-            break;
-        }
-        if (level <= 1) {
-            tok = s->token.val;
-            if (token_is_pseudo_keyword(s, JS_ATOM_of))
-                tok = TOK_OF;
-            if (no_line_terminator && s->last_line_num != s->token.line_num)
-                tok = '\n';
-            break;
-        }
-    }
- done:
-    if (pbits) {
-        *pbits = bits;
-    }
-    if (js_parse_seek_token(s, &pos))
-        return -1;
-    return tok;
-}
-
-static void set_object_name(JSParseState *s, JSAtom name)
-{
-    JSFunctionDef *fd = s->cur_func;
-    int opcode;
-
-    opcode = get_prev_opcode(fd);
-    if (opcode == OP_set_name) {
-        /* XXX: should free atom after OP_set_name? */
-        fd->byte_code.size = fd->last_opcode_pos;
-        fd->last_opcode_pos = -1;
-        emit_op(s, OP_set_name);
-        emit_atom(s, name);
-    } else if (opcode == OP_set_class_name) {
-        int define_class_pos;
-        JSAtom atom;
-        define_class_pos = fd->last_opcode_pos + 1 -
-            get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
-        assert(fd->byte_code.buf[define_class_pos] == OP_define_class);
-        /* for consistency we free the previous atom which is
-           JS_ATOM_empty_string */
-        atom = get_u32(fd->byte_code.buf + define_class_pos + 1);
-        JS_FreeAtom(s->ctx, atom);
-        put_u32(fd->byte_code.buf + define_class_pos + 1,
-                JS_DupAtom(s->ctx, name));
-        fd->last_opcode_pos = -1;
-    }
-}
-
-static void set_object_name_computed(JSParseState *s)
-{
-    JSFunctionDef *fd = s->cur_func;
-    int opcode;
-
-    opcode = get_prev_opcode(fd);
-    if (opcode == OP_set_name) {
-        /* XXX: should free atom after OP_set_name? */
-        fd->byte_code.size = fd->last_opcode_pos;
-        fd->last_opcode_pos = -1;
-        emit_op(s, OP_set_name_computed);
-    } else if (opcode == OP_set_class_name) {
-        int define_class_pos;
-        define_class_pos = fd->last_opcode_pos + 1 -
-            get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
-        assert(fd->byte_code.buf[define_class_pos] == OP_define_class);
-        fd->byte_code.buf[define_class_pos] = OP_define_class_computed;
-        fd->last_opcode_pos = -1;
-    }
-}
-
-static __exception int js_parse_object_literal(JSParseState *s)
-{
-    JSAtom name = JS_ATOM_NULL;
-    const uint8_t *start_ptr;
-    int start_line, prop_type;
-    BOOL has_proto;
-
-    if (next_token(s))
-        goto fail;
-    /* XXX: add an initial length that will be patched back */
-    emit_op(s, OP_object);
-    has_proto = FALSE;
-    while (s->token.val != '}') {
-        /* specific case for getter/setter */
-        start_ptr = s->token.ptr;
-        start_line = s->token.line_num;
-
-        if (s->token.val == TOK_ELLIPSIS) {
-            if (next_token(s))
-                return -1;
-            if (js_parse_assign_expr(s))
-                return -1;
-            emit_op(s, OP_null);  /* dummy excludeList */
-            emit_op(s, OP_copy_data_properties);
-            emit_u8(s, 2 | (1 << 2) | (0 << 5));
-            emit_op(s, OP_drop); /* pop excludeList */
-            emit_op(s, OP_drop); /* pop src object */
-            goto next;
-        }
-
-        prop_type = js_parse_property_name(s, &name, TRUE, TRUE, FALSE);
-        if (prop_type < 0)
-            goto fail;
-
-        if (prop_type == PROP_TYPE_VAR) {
-            /* shortcut for x: x */
-            emit_op(s, OP_scope_get_var);
-            emit_atom(s, name);
-            emit_u16(s, s->cur_func->scope_level);
-            emit_op(s, OP_define_field);
-            emit_atom(s, name);
-        } else if (s->token.val == '(') {
-            BOOL is_getset = (prop_type == PROP_TYPE_GET ||
-                              prop_type == PROP_TYPE_SET);
-            JSParseFunctionEnum func_type;
-            JSFunctionKindEnum func_kind;
-            int op_flags;
-
-            func_kind = JS_FUNC_NORMAL;
-            if (is_getset) {
-                func_type = JS_PARSE_FUNC_GETTER + prop_type - PROP_TYPE_GET;
-            } else {
-                func_type = JS_PARSE_FUNC_METHOD;
-                if (prop_type == PROP_TYPE_STAR)
-                    func_kind = JS_FUNC_GENERATOR;
-                else if (prop_type == PROP_TYPE_ASYNC)
-                    func_kind = JS_FUNC_ASYNC;
-                else if (prop_type == PROP_TYPE_ASYNC_STAR)
-                    func_kind = JS_FUNC_ASYNC_GENERATOR;
-            }
-            if (js_parse_function_decl(s, func_type, func_kind, JS_ATOM_NULL,
-                                       start_ptr, start_line))
-                goto fail;
-            if (name == JS_ATOM_NULL) {
-                emit_op(s, OP_define_method_computed);
-            } else {
-                emit_op(s, OP_define_method);
-                emit_atom(s, name);
-            }
-            if (is_getset) {
-                op_flags = OP_DEFINE_METHOD_GETTER +
-                    prop_type - PROP_TYPE_GET;
-            } else {
-                op_flags = OP_DEFINE_METHOD_METHOD;
-            }
-            emit_u8(s, op_flags | OP_DEFINE_METHOD_ENUMERABLE);
-        } else {
-            if (js_parse_expect(s, ':'))
-                goto fail;
-            if (js_parse_assign_expr(s))
-                goto fail;
-            if (name == JS_ATOM_NULL) {
-                set_object_name_computed(s);
-                emit_op(s, OP_define_array_el);
-                emit_op(s, OP_drop);
-            } else if (name == JS_ATOM___proto__) {
-                if (has_proto) {
-                    js_parse_error(s, "duplicate __proto__ property name");
-                    goto fail;
-                }
-                emit_op(s, OP_set_proto);
-                has_proto = TRUE;
-            } else {
-                set_object_name(s, name);
-                emit_op(s, OP_define_field);
-                emit_atom(s, name);
-            }
-        }
-        JS_FreeAtom(s->ctx, name);
-    next:
-        name = JS_ATOM_NULL;
-        if (s->token.val != ',')
-            break;
-        if (next_token(s))
-            goto fail;
-    }
-    if (js_parse_expect(s, '}'))
-        goto fail;
-    return 0;
- fail:
-    JS_FreeAtom(s->ctx, name);
-    return -1;
-}
-
-/* allow the 'in' binary operator */
-#define PF_IN_ACCEPTED  (1 << 0) 
-/* allow function calls parsing in js_parse_postfix_expr() */
-#define PF_POSTFIX_CALL (1 << 1) 
-/* allow arrow functions parsing in js_parse_postfix_expr() */
-#define PF_ARROW_FUNC   (1 << 2) 
-/* allow the exponentiation operator in js_parse_unary() */
-#define PF_POW_ALLOWED  (1 << 3) 
-/* forbid the exponentiation operator in js_parse_unary() */
-#define PF_POW_FORBIDDEN (1 << 4) 
-
-static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags);
-
-static __exception int js_parse_left_hand_side_expr(JSParseState *s)
-{
-    return js_parse_postfix_expr(s, PF_POSTFIX_CALL);
-}
-
-/* XXX: could generate specific bytecode */
-static __exception int js_parse_class_default_ctor(JSParseState *s,
-                                                   BOOL has_super,
-                                                   JSFunctionDef **pfd)
-{
-    JSParsePos pos;
-    const char *str;
-    int ret, line_num;
-    JSParseFunctionEnum func_type;
-    const uint8_t *saved_buf_end;
-    
-    js_parse_get_pos(s, &pos);
-    if (has_super) {
-        /* spec change: no argument evaluation */
-        str = "(){super(...arguments);}";
-        func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR;
-    } else {
-        str = "(){}";
-        func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;
-    }
-    line_num = s->token.line_num;
-    saved_buf_end = s->buf_end;
-    s->buf_ptr = (uint8_t *)str;
-    s->buf_end = (uint8_t *)(str + strlen(str));
-    ret = next_token(s);
-    if (!ret) {
-        ret = js_parse_function_decl2(s, func_type, JS_FUNC_NORMAL,
-                                      JS_ATOM_NULL, (uint8_t *)str,
-                                      line_num, JS_PARSE_EXPORT_NONE, pfd);
-    }
-    s->buf_end = saved_buf_end;
-    ret |= js_parse_seek_token(s, &pos);
-    return ret;
-}
-
-/* find field in the current scope */
-static int find_private_class_field(JSContext *ctx, JSFunctionDef *fd,
-                                    JSAtom name, int scope_level)
-{
-    int idx;
-    idx = fd->scopes[scope_level].first;
-    while (idx != -1) {
-        if (fd->vars[idx].scope_level != scope_level)
-            break;
-        if (fd->vars[idx].var_name == name)
-            return idx;
-        idx = fd->vars[idx].scope_next;
-    }
-    return -1;
-}
-
-/* initialize the class fields, called by the constructor. Note:
-   super() can be called in an arrow function, so <this> and
-   <class_fields_init> can be variable references */
-static void emit_class_field_init(JSParseState *s)
-{
-    int label_next;
-    
-    emit_op(s, OP_scope_get_var);
-    emit_atom(s, JS_ATOM_class_fields_init);
-    emit_u16(s, s->cur_func->scope_level);
-
-    /* no need to call the class field initializer if not defined */
-    emit_op(s, OP_dup);
-    label_next = emit_goto(s, OP_if_false, -1);
-    
-    emit_op(s, OP_scope_get_var);
-    emit_atom(s, JS_ATOM_this);
-    emit_u16(s, 0);
-    
-    emit_op(s, OP_swap);
-    
-    emit_op(s, OP_call_method);
-    emit_u16(s, 0);
-
-    emit_label(s, label_next);
-    emit_op(s, OP_drop);
-}
-
-/* build a private setter function name from the private getter name */
-static JSAtom get_private_setter_name(JSContext *ctx, JSAtom name)
-{
-    return js_atom_concat_str(ctx, name, "<set>");
-}
-
-typedef struct {
-    JSFunctionDef *fields_init_fd;
-    int computed_fields_count;
-    BOOL has_brand;
-    int brand_push_pos;
-} ClassFieldsDef;
-
-static __exception int emit_class_init_start(JSParseState *s,
-                                             ClassFieldsDef *cf)
-{
-    int label_add_brand;
-    
-    cf->fields_init_fd = js_parse_function_class_fields_init(s);
-    if (!cf->fields_init_fd)
-        return -1;
-
-    s->cur_func = cf->fields_init_fd;
-    
-    /* XXX: would be better to add the code only if needed, maybe in a
-       later pass */
-    emit_op(s, OP_push_false); /* will be patched later */
-    cf->brand_push_pos = cf->fields_init_fd->last_opcode_pos;
-    label_add_brand = emit_goto(s, OP_if_false, -1);
-    
-    emit_op(s, OP_scope_get_var);
-    emit_atom(s, JS_ATOM_this);
-    emit_u16(s, 0);
-    
-    emit_op(s, OP_scope_get_var);
-    emit_atom(s, JS_ATOM_home_object);
-    emit_u16(s, 0);
-    
-    emit_op(s, OP_add_brand);
-    
-    emit_label(s, label_add_brand);
-
-    s->cur_func = s->cur_func->parent;
-    return 0;
-}
-
-static __exception int add_brand(JSParseState *s, ClassFieldsDef *cf)
-{
-    if (!cf->has_brand) {
-        /* define the brand field in 'this' of the initializer */
-        if (!cf->fields_init_fd) {
-            if (emit_class_init_start(s, cf))
-                return -1;
-        }
-        /* patch the start of the function to enable the OP_add_brand code */
-        cf->fields_init_fd->byte_code.buf[cf->brand_push_pos] = OP_push_true;
-        
-        cf->has_brand = TRUE;
-    }
-    return 0;
-}
-
-static void emit_class_init_end(JSParseState *s, ClassFieldsDef *cf)
-{
-    int cpool_idx;
-        
-    s->cur_func = cf->fields_init_fd;
-    emit_op(s, OP_return_undef);
-    s->cur_func = s->cur_func->parent;
-    
-    cpool_idx = cpool_add(s, JS_NULL);
-    cf->fields_init_fd->parent_cpool_idx = cpool_idx;
-    emit_op(s, OP_fclosure);
-    emit_u32(s, cpool_idx);
-    emit_op(s, OP_set_home_object);
-}
-
-
-static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
-                                      JSParseExportEnum export_flag)
-{
-    JSContext *ctx = s->ctx;
-    JSFunctionDef *fd = s->cur_func;
-    JSAtom name = JS_ATOM_NULL, class_name = JS_ATOM_NULL, class_name1;
-    JSAtom class_var_name = JS_ATOM_NULL;
-    JSFunctionDef *method_fd, *ctor_fd;
-    int saved_js_mode, class_name_var_idx, prop_type, ctor_cpool_offset;
-    int class_flags = 0, i, define_class_offset;
-    BOOL is_static, is_private;
-    const uint8_t *class_start_ptr = s->token.ptr;
-    const uint8_t *start_ptr;
-    ClassFieldsDef class_fields[2];
-        
-    /* classes are parsed and executed in strict mode */
-    saved_js_mode = fd->js_mode;
-    fd->js_mode |= JS_MODE_STRICT;
-    if (next_token(s))
-        goto fail;
-    if (s->token.val == TOK_IDENT) {
-        if (s->token.u.ident.is_reserved) {
-            js_parse_error_reserved_identifier(s);
-            goto fail;
-        }
-        class_name = JS_DupAtom(ctx, s->token.u.ident.atom);
-        if (next_token(s))
-            goto fail;
-    } else if (!is_class_expr && export_flag != JS_PARSE_EXPORT_DEFAULT) {
-        js_parse_error(s, "class statement requires a name");
-        goto fail;
-    }
-    if (!is_class_expr) {
-        if (class_name == JS_ATOM_NULL)
-            class_var_name = JS_ATOM__default_; /* export default */
-        else
-            class_var_name = class_name;
-        class_var_name = JS_DupAtom(ctx, class_var_name);
-    }
-
-    push_scope(s);
-
-    if (s->token.val == TOK_EXTENDS) {
-        class_flags = JS_DEFINE_CLASS_HAS_HERITAGE;
-        if (next_token(s))
-            goto fail;
-        if (js_parse_left_hand_side_expr(s))
-            goto fail;
-    } else {
-        emit_op(s, OP_undefined);
-    }
-
-    /* add a 'const' definition for the class name */
-    if (class_name != JS_ATOM_NULL) {
-        class_name_var_idx = define_var(s, fd, class_name, JS_VAR_DEF_CONST);
-        if (class_name_var_idx < 0)
-            goto fail;
-    }
-
-    if (js_parse_expect(s, '{'))
-        goto fail;
-
-    /* this scope contains the private fields */
-    push_scope(s);
-
-    emit_op(s, OP_push_const);
-    ctor_cpool_offset = fd->byte_code.size;
-    emit_u32(s, 0); /* will be patched at the end of the class parsing */
-
-    if (class_name == JS_ATOM_NULL) {
-        if (class_var_name != JS_ATOM_NULL)
-            class_name1 = JS_ATOM_default;
-        else
-            class_name1 = JS_ATOM_empty_string;
-    } else {
-        class_name1 = class_name;
-    }
-    
-    emit_op(s, OP_define_class);
-    emit_atom(s, class_name1);
-    emit_u8(s, class_flags);
-    define_class_offset = fd->last_opcode_pos;
-
-    for(i = 0; i < 2; i++) {
-        ClassFieldsDef *cf = &class_fields[i];
-        cf->fields_init_fd = NULL;
-        cf->computed_fields_count = 0;
-        cf->has_brand = FALSE;
-    }
-    
-    ctor_fd = NULL;
-    while (s->token.val != '}') {
-        if (s->token.val == ';') {
-            if (next_token(s))
-                goto fail;
-            continue;
-        }
-        is_static = (s->token.val == TOK_STATIC);
-        prop_type = -1;
-        if (is_static) {
-            if (next_token(s))
-                goto fail;
-            /* allow "static" field name */
-            if (s->token.val == ';' || s->token.val == '=') {
-                is_static = FALSE;
-                name = JS_DupAtom(ctx, JS_ATOM_static);
-                prop_type = PROP_TYPE_IDENT;
-            }
-        }
-        if (is_static)
-            emit_op(s, OP_swap);
-        start_ptr = s->token.ptr;
-        if (prop_type < 0) {
-            prop_type = js_parse_property_name(s, &name, TRUE, FALSE, TRUE);
-            if (prop_type < 0)
-                goto fail;
-        }
-        is_private = prop_type & PROP_TYPE_PRIVATE;
-        prop_type &= ~PROP_TYPE_PRIVATE;
-        
-        if ((name == JS_ATOM_constructor && !is_static &&
-             prop_type != PROP_TYPE_IDENT) ||
-            (name == JS_ATOM_prototype && is_static) ||
-            name == JS_ATOM_hash_constructor) {
-            js_parse_error(s, "invalid method name");
-            goto fail;
-        }
-        if (prop_type == PROP_TYPE_GET || prop_type == PROP_TYPE_SET) {
-            BOOL is_set = prop_type - PROP_TYPE_GET;
-            JSFunctionDef *method_fd;
-
-            if (is_private) {
-                int idx, var_kind;
-                idx = find_private_class_field(ctx, fd, name, fd->scope_level);
-                if (idx >= 0) {
-                    var_kind = fd->vars[idx].var_kind;
-                    if (var_kind == JS_VAR_PRIVATE_FIELD ||
-                        var_kind == JS_VAR_PRIVATE_METHOD ||
-                        var_kind == JS_VAR_PRIVATE_GETTER_SETTER ||
-                        var_kind == (JS_VAR_PRIVATE_GETTER + is_set)) {
-                        goto private_field_already_defined;
-                    }
-                    fd->vars[idx].var_kind = JS_VAR_PRIVATE_GETTER_SETTER;
-                } else {
-                    if (add_private_class_field(s, fd, name,
-                                                JS_VAR_PRIVATE_GETTER + is_set) < 0)
-                        goto fail;
-                }
-                if (add_brand(s, &class_fields[is_static]) < 0)
-                    goto fail;
-            }
-
-            if (js_parse_function_decl2(s, JS_PARSE_FUNC_GETTER + is_set,
-                                        JS_FUNC_NORMAL, JS_ATOM_NULL,
-                                        start_ptr, s->token.line_num,
-                                        JS_PARSE_EXPORT_NONE, &method_fd))
-                goto fail;
-            if (is_private) {
-                method_fd->need_home_object = TRUE; /* needed for brand check */
-                emit_op(s, OP_set_home_object);
-                /* XXX: missing function name */
-                emit_op(s, OP_scope_put_var_init);
-                if (is_set) {
-                    JSAtom setter_name;
-                    int ret;
-                    
-                    setter_name = get_private_setter_name(ctx, name);
-                    if (setter_name == JS_ATOM_NULL)
-                        goto fail;
-                    emit_atom(s, setter_name);
-                    ret = add_private_class_field(s, fd, setter_name,
-                                                  JS_VAR_PRIVATE_SETTER);
-                    JS_FreeAtom(ctx, setter_name);
-                    if (ret < 0)
-                        goto fail;
-                } else {
-                    emit_atom(s, name);
-                }
-                emit_u16(s, s->cur_func->scope_level);
-            } else {
-                if (name == JS_ATOM_NULL) {
-                    emit_op(s, OP_define_method_computed);
-                } else {
-                    emit_op(s, OP_define_method);
-                    emit_atom(s, name);
-                }
-                emit_u8(s, OP_DEFINE_METHOD_GETTER + is_set);
-            }
-        } else if (prop_type == PROP_TYPE_IDENT && s->token.val != '(') {
-            ClassFieldsDef *cf = &class_fields[is_static];
-            JSAtom field_var_name = JS_ATOM_NULL;
-            
-            /* class field */
-
-            /* XXX: spec: not consistent with method name checks */
-            if (name == JS_ATOM_constructor || name == JS_ATOM_prototype) {
-                js_parse_error(s, "invalid field name");
-                goto fail;
-            }
-            
-            if (is_private) {
-                if (find_private_class_field(ctx, fd, name,
-                                             fd->scope_level) >= 0) {
-                    goto private_field_already_defined;
-                }
-                if (add_private_class_field(s, fd, name,
-                                            JS_VAR_PRIVATE_FIELD) < 0)
-                    goto fail;
-                emit_op(s, OP_private_symbol);
-                emit_atom(s, name);
-                emit_op(s, OP_scope_put_var_init);
-                emit_atom(s, name);
-                emit_u16(s, s->cur_func->scope_level);
-            }
-
-            if (!cf->fields_init_fd) {
-                if (emit_class_init_start(s, cf))
-                    goto fail;
-            }
-            if (name == JS_ATOM_NULL ) {
-                /* save the computed field name into a variable */
-                field_var_name = js_atom_concat_num(ctx, JS_ATOM_computed_field + is_static, cf->computed_fields_count);
-                if (field_var_name == JS_ATOM_NULL)
-                    goto fail;
-                if (define_var(s, fd, field_var_name, JS_VAR_DEF_CONST) < 0) {
-                    JS_FreeAtom(ctx, field_var_name);
-                    goto fail;
-                }
-                emit_op(s, OP_to_propkey);
-                emit_op(s, OP_scope_put_var_init);
-                emit_atom(s, field_var_name);
-                emit_u16(s, s->cur_func->scope_level);
-            }
-            s->cur_func = cf->fields_init_fd;
-            emit_op(s, OP_scope_get_var);
-            emit_atom(s, JS_ATOM_this);
-            emit_u16(s, 0);
-
-            if (name == JS_ATOM_NULL) {
-                emit_op(s, OP_scope_get_var);
-                emit_atom(s, field_var_name);
-                emit_u16(s, s->cur_func->scope_level);
-                cf->computed_fields_count++;
-                JS_FreeAtom(ctx, field_var_name);
-            } else if (is_private) {
-                emit_op(s, OP_scope_get_var);
-                emit_atom(s, name);
-                emit_u16(s, s->cur_func->scope_level);
-            }
-            
-            if (s->token.val == '=') {
-                if (next_token(s))
-                    goto fail;
-                if (js_parse_assign_expr(s))
-                    goto fail;
-            } else {
-                emit_op(s, OP_undefined);
-            }
-            if (is_private) {
-                set_object_name_computed(s);
-                emit_op(s, OP_define_private_field);
-            } else if (name == JS_ATOM_NULL) {
-                set_object_name_computed(s);
-                emit_op(s, OP_define_array_el);
-                emit_op(s, OP_drop);
-            } else {
-                set_object_name(s, name);
-                emit_op(s, OP_define_field);
-                emit_atom(s, name);
-            }
-            s->cur_func = s->cur_func->parent;
-            if (js_parse_expect_semi(s))
-                goto fail;
-        } else {
-            JSParseFunctionEnum func_type;
-            JSFunctionKindEnum func_kind;
-            
-            func_type = JS_PARSE_FUNC_METHOD;
-            func_kind = JS_FUNC_NORMAL;
-            if (prop_type == PROP_TYPE_STAR) {
-                func_kind = JS_FUNC_GENERATOR;
-            } else if (prop_type == PROP_TYPE_ASYNC) {
-                func_kind = JS_FUNC_ASYNC;
-            } else if (prop_type == PROP_TYPE_ASYNC_STAR) {
-                func_kind = JS_FUNC_ASYNC_GENERATOR;
-            } else if (name == JS_ATOM_constructor && !is_static) {
-                if (ctor_fd) {
-                    js_parse_error(s, "property constructor appears more than once");
-                    goto fail;
-                }
-                if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE)
-                    func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR;
-                else
-                    func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;
-            }
-            if (is_private) {
-                if (add_brand(s, &class_fields[is_static]) < 0)
-                    goto fail;
-            }
-            if (js_parse_function_decl2(s, func_type, func_kind, JS_ATOM_NULL, start_ptr, s->token.line_num, JS_PARSE_EXPORT_NONE, &method_fd))
-                goto fail;
-            if (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR ||
-                func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) {
-                ctor_fd = method_fd;
-            } else if (is_private) {
-                method_fd->need_home_object = TRUE; /* needed for brand check */
-                if (find_private_class_field(ctx, fd, name,
-                                             fd->scope_level) >= 0) {
-                private_field_already_defined:
-                    js_parse_error(s, "private class field is already defined");
-                    goto fail;
-                }
-                if (add_private_class_field(s, fd, name,
-                                            JS_VAR_PRIVATE_METHOD) < 0)
-                    goto fail;
-                emit_op(s, OP_set_home_object);
-                emit_op(s, OP_set_name);
-                emit_atom(s, name);
-                emit_op(s, OP_scope_put_var_init);
-                emit_atom(s, name);
-                emit_u16(s, s->cur_func->scope_level);
-            } else {
-                if (name == JS_ATOM_NULL) {
-                    emit_op(s, OP_define_method_computed);
-                } else {
-                    emit_op(s, OP_define_method);
-                    emit_atom(s, name);
-                }
-                emit_u8(s, OP_DEFINE_METHOD_METHOD);
-            }
-        }
-        if (is_static)
-            emit_op(s, OP_swap);
-        JS_FreeAtom(ctx, name);
-        name = JS_ATOM_NULL;
-    }
-
-    if (s->token.val != '}') {
-        js_parse_error(s, "expecting '%c'", '}');
-        goto fail;
-    }
-
-    if (!ctor_fd) {
-        if (js_parse_class_default_ctor(s, class_flags & JS_DEFINE_CLASS_HAS_HERITAGE, &ctor_fd))
-            goto fail;
-    }
-    /* patch the constant pool index for the constructor */
-    put_u32(fd->byte_code.buf + ctor_cpool_offset, ctor_fd->parent_cpool_idx);
-
-    /* store the class source code in the constructor. */
-    if (!(fd->js_mode & JS_MODE_STRIP)) {
-        js_free(ctx, ctor_fd->source);
-        ctor_fd->source_len = s->buf_ptr - class_start_ptr;
-        ctor_fd->source = js_strndup(ctx, (const char *)class_start_ptr,
-                                     ctor_fd->source_len);
-        if (!ctor_fd->source)
-            goto fail;
-    }
-
-    /* consume the '}' */
-    if (next_token(s))
-        goto fail;
-
-    /* store the function to initialize the fields to that it can be
-       referenced by the constructor */
-    {
-        ClassFieldsDef *cf = &class_fields[0];
-        int var_idx;
-        
-        var_idx = define_var(s, fd, JS_ATOM_class_fields_init,
-                             JS_VAR_DEF_CONST);
-        if (var_idx < 0)
-            goto fail;
-        if (cf->fields_init_fd) {
-            emit_class_init_end(s, cf);
-        } else {
-            emit_op(s, OP_undefined);
-        }
-        emit_op(s, OP_scope_put_var_init);
-        emit_atom(s, JS_ATOM_class_fields_init);
-        emit_u16(s, s->cur_func->scope_level);
-    }
-
-    /* drop the prototype */
-    emit_op(s, OP_drop);
-
-    /* initialize the static fields */
-    if (class_fields[1].fields_init_fd != NULL) {
-        ClassFieldsDef *cf = &class_fields[1];
-        emit_op(s, OP_dup);
-        emit_class_init_end(s, cf);
-        emit_op(s, OP_call_method);
-        emit_u16(s, 0);
-        emit_op(s, OP_drop);
-    }
-    
-    if (class_name != JS_ATOM_NULL) {
-        /* store the class name in the scoped class name variable (it
-           is independent from the class statement variable
-           definition) */
-        emit_op(s, OP_dup);
-        emit_op(s, OP_scope_put_var_init);
-        emit_atom(s, class_name);
-        emit_u16(s, fd->scope_level);
-    }
-    pop_scope(s);
-    pop_scope(s);
-
-    /* the class statements have a block level scope */
-    if (class_var_name != JS_ATOM_NULL) {
-        if (define_var(s, fd, class_var_name, JS_VAR_DEF_LET) < 0)
-            goto fail;
-        emit_op(s, OP_scope_put_var_init);
-        emit_atom(s, class_var_name);
-        emit_u16(s, fd->scope_level);
-    } else {
-        if (class_name == JS_ATOM_NULL) {
-            /* cannot use OP_set_name because the name of the class
-               must be defined before the static initializers are
-               executed */
-            emit_op(s, OP_set_class_name);
-            emit_u32(s, fd->last_opcode_pos + 1 - define_class_offset);
-        }
-    }
-
-    if (export_flag != JS_PARSE_EXPORT_NONE) {
-        if (!add_export_entry(s, fd->module,
-                              class_var_name,
-                              export_flag == JS_PARSE_EXPORT_NAMED ? class_var_name : JS_ATOM_default,
-                              JS_EXPORT_TYPE_LOCAL))
-            goto fail;
-    }
-
-    JS_FreeAtom(ctx, class_name);
-    JS_FreeAtom(ctx, class_var_name);
-    fd->js_mode = saved_js_mode;
-    return 0;
- fail:
-    JS_FreeAtom(ctx, name);
-    JS_FreeAtom(ctx, class_name);
-    JS_FreeAtom(ctx, class_var_name);
-    fd->js_mode = saved_js_mode;
-    return -1;
-}
-
-static __exception int js_parse_array_literal(JSParseState *s)
-{
-    uint32_t idx;
-    BOOL need_length;
-
-    if (next_token(s))
-        return -1;
-    /* small regular arrays are created on the stack */
-    idx = 0;
-    while (s->token.val != ']' && idx < 32) {
-        if (s->token.val == ',' || s->token.val == TOK_ELLIPSIS)
-            break;
-        if (js_parse_assign_expr(s))
-            return -1;
-        idx++;
-        /* accept trailing comma */
-        if (s->token.val == ',') {
-            if (next_token(s))
-                return -1;
-        } else
-        if (s->token.val != ']')
-            goto done;
-    }
-    emit_op(s, OP_array_from);
-    emit_u16(s, idx);
-
-    /* larger arrays and holes are handled with explicit indices */
-    need_length = FALSE;
-    while (s->token.val != ']' && idx < 0x7fffffff) {
-        if (s->token.val == TOK_ELLIPSIS)
-            break;
-        need_length = TRUE;
-        if (s->token.val != ',') {
-            if (js_parse_assign_expr(s))
-                return -1;
-            emit_op(s, OP_define_field);
-            emit_u32(s, __JS_AtomFromUInt32(idx));
-            need_length = FALSE;
-        }
-        idx++;
-        /* accept trailing comma */
-        if (s->token.val == ',') {
-            if (next_token(s))
-                return -1;
-        }
-    }
-    if (s->token.val == ']') {
-        if (need_length) {
-            /* Set the length: Cannot use OP_define_field because
-               length is not configurable */
-            emit_op(s, OP_dup);
-            emit_op(s, OP_push_i32);
-            emit_u32(s, idx);
-            emit_op(s, OP_put_field);
-            emit_atom(s, JS_ATOM_length);
-        }
-        goto done;
-    }
-
-    /* huge arrays and spread elements require a dynamic index on the stack */
-    emit_op(s, OP_push_i32);
-    emit_u32(s, idx);
-
-    /* stack has array, index */
-    while (s->token.val != ']') {
-        if (s->token.val == TOK_ELLIPSIS) {
-            if (next_token(s))
-                return -1;
-            if (js_parse_assign_expr(s))
-                return -1;
-#if 1
-            emit_op(s, OP_append);
-#else
-            int label_next, label_done;
-            label_next = new_label(s);
-            label_done = new_label(s);
-            /* enumerate object */
-            emit_op(s, OP_for_of_start);
-            emit_op(s, OP_rot5l);
-            emit_op(s, OP_rot5l);
-            emit_label(s, label_next);
-            /* on stack: enum_rec array idx */
-            emit_op(s, OP_for_of_next);
-            emit_u8(s, 2);
-            emit_goto(s, OP_if_true, label_done);
-            /* append element */
-            /* enum_rec array idx val -> enum_rec array new_idx */
-            emit_op(s, OP_define_array_el);
-            emit_op(s, OP_inc);
-            emit_goto(s, OP_goto, label_next);
-            emit_label(s, label_done);
-            /* close enumeration */
-            emit_op(s, OP_drop); /* drop undef val */
-            emit_op(s, OP_nip1); /* drop enum_rec */
-            emit_op(s, OP_nip1);
-            emit_op(s, OP_nip1);
-#endif
-        } else {
-            need_length = TRUE;
-            if (s->token.val != ',') {
-                if (js_parse_assign_expr(s))
-                    return -1;
-                /* a idx val */
-                emit_op(s, OP_define_array_el);
-                need_length = FALSE;
-            }
-            emit_op(s, OP_inc);
-        }
-        if (s->token.val != ',')
-            break;
-        if (next_token(s))
-            return -1;
-    }
-    if (need_length) {
-        /* Set the length: cannot use OP_define_field because
-           length is not configurable */
-        emit_op(s, OP_dup1);    /* array length - array array length */
-        emit_op(s, OP_put_field);
-        emit_atom(s, JS_ATOM_length);
-    } else {
-        emit_op(s, OP_drop);    /* array length - array */
-    }
-done:
-    return js_parse_expect(s, ']');
-}
-
-/* XXX: remove */
-static BOOL has_with_scope(JSFunctionDef *s, int scope_level)
-{
-    /* check if scope chain contains a with statement */
-    while (s) {
-        int scope_idx = s->scopes[scope_level].first;
-        while (scope_idx >= 0) {
-            JSVarDef *vd = &s->vars[scope_idx];
-
-            if (vd->var_name == JS_ATOM__with_)
-                return TRUE;
-            scope_idx = vd->scope_next;
-        }
-        /* check parent scopes */
-        scope_level = s->parent_scope_level;
-        s = s->parent;
-    }
-    return FALSE;
-}
-
-static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
-                                  JSAtom *pname, int *plabel, int *pdepth, BOOL keep,
-                                  int tok)
-{
-    JSFunctionDef *fd;
-    int opcode, scope, label, depth;
-    JSAtom name;
-
-    /* we check the last opcode to get the lvalue type */
-    fd = s->cur_func;
-    scope = 0;
-    name = JS_ATOM_NULL;
-    label = -1;
-    depth = 0;
-    switch(opcode = get_prev_opcode(fd)) {
-    case OP_scope_get_var:
-        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
-        scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
-        if ((name == JS_ATOM_arguments || name == JS_ATOM_eval) &&
-            (fd->js_mode & JS_MODE_STRICT)) {
-            return js_parse_error(s, "invalid lvalue in strict mode");
-        }
-        if (name == JS_ATOM_this || name == JS_ATOM_new_target)
-            goto invalid_lvalue;
-        depth = 2;  /* will generate OP_get_ref_value */
-        break;
-    case OP_get_field:
-        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
-        depth = 1;
-        break;
-    case OP_scope_get_private_field:
-        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
-        scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
-        depth = 1;
-        break;
-    case OP_get_array_el:
-        depth = 2;
-        break;
-    case OP_get_super_value:
-        depth = 3;
-        break;
-    default:
-    invalid_lvalue:
-        if (tok == TOK_FOR) {
-            return js_parse_error(s, "invalid for in/of left hand-side");
-        } else if (tok == TOK_INC || tok == TOK_DEC) {
-            return js_parse_error(s, "invalid increment/decrement operand");
-        } else if (tok == '[' || tok == '{') {
-            return js_parse_error(s, "invalid destructuring target");
-        } else {
-            return js_parse_error(s, "invalid assignment left-hand side");
-        }
-    }
-    /* remove the last opcode */
-    fd->byte_code.size = fd->last_opcode_pos;
-    fd->last_opcode_pos = -1;
-
-    if (keep) {
-        /* get the value but keep the object/fields on the stack */
-        switch(opcode) {
-        case OP_scope_get_var:
-            label = new_label(s);
-            emit_op(s, OP_scope_make_ref);
-            emit_atom(s, name);
-            emit_u32(s, label);
-            emit_u16(s, scope);
-            update_label(fd, label, 1);
-            emit_op(s, OP_get_ref_value);
-            opcode = OP_get_ref_value;
-            break;
-        case OP_get_field:
-            emit_op(s, OP_get_field2);
-            emit_atom(s, name);
-            break;
-        case OP_scope_get_private_field:
-            emit_op(s, OP_scope_get_private_field2);
-            emit_atom(s, name);
-            emit_u16(s, scope);
-            break;
-        case OP_get_array_el:
-            /* XXX: replace by a single opcode ? */
-            emit_op(s, OP_to_propkey2);
-            emit_op(s, OP_dup2);
-            emit_op(s, OP_get_array_el);
-            break;
-        case OP_get_super_value:
-            emit_op(s, OP_to_propkey);
-            emit_op(s, OP_dup3);
-            emit_op(s, OP_get_super_value);
-            break;
-        default:
-            abort();
-        }
-    } else {
-        switch(opcode) {
-        case OP_scope_get_var:
-            label = new_label(s);
-            emit_op(s, OP_scope_make_ref);
-            emit_atom(s, name);
-            emit_u32(s, label);
-            emit_u16(s, scope);
-            update_label(fd, label, 1);
-            opcode = OP_get_ref_value;
-            break;
-        case OP_get_array_el:
-            emit_op(s, OP_to_propkey2);
-            break;
-        case OP_get_super_value:
-            emit_op(s, OP_to_propkey);
-            break;
-        }
-    }
-
-    *popcode = opcode;
-    *pscope = scope;
-    /* name has refcount for OP_get_field and OP_get_ref_value,
-       and JS_ATOM_NULL for other opcodes */
-    *pname = name;
-    *plabel = label;
-    if (pdepth)
-        *pdepth = depth;
-    return 0;
-}
-
-typedef enum {
-    PUT_LVALUE_NOKEEP, /* [depth] v -> */
-    PUT_LVALUE_NOKEEP_DEPTH, /* [depth] v -> , keep depth (currently
-                                just disable optimizations) */
-    PUT_LVALUE_KEEP_TOP,  /* [depth] v -> v */
-    PUT_LVALUE_KEEP_SECOND, /* [depth] v0 v -> v0 */
-    PUT_LVALUE_NOKEEP_BOTTOM, /* v [depth] -> */
-} PutLValueEnum;
-
-/* name has a live reference. 'is_let' is only used with opcode =
-   OP_scope_get_var which is never generated by get_lvalue(). */
-static void put_lvalue(JSParseState *s, int opcode, int scope,
-                       JSAtom name, int label, PutLValueEnum special,
-                       BOOL is_let)
-{
-    switch(opcode) {
-    case OP_get_field:
-    case OP_scope_get_private_field:
-        /* depth = 1 */
-        switch(special) {
-        case PUT_LVALUE_NOKEEP:
-        case PUT_LVALUE_NOKEEP_DEPTH:
-            break;
-        case PUT_LVALUE_KEEP_TOP:
-            emit_op(s, OP_insert2); /* obj v -> v obj v */
-            break;
-        case PUT_LVALUE_KEEP_SECOND:
-            emit_op(s, OP_perm3); /* obj v0 v -> v0 obj v */
-            break;
-        case PUT_LVALUE_NOKEEP_BOTTOM:
-            emit_op(s, OP_swap);
-            break;
-        default:
-            abort();
-        }
-        break;
-    case OP_get_array_el:
-    case OP_get_ref_value:
-        /* depth = 2 */
-        if (opcode == OP_get_ref_value) {
-            JS_FreeAtom(s->ctx, name);
-            emit_label(s, label);
-        }
-        switch(special) {
-        case PUT_LVALUE_NOKEEP:
-            emit_op(s, OP_nop); /* will trigger optimization */
-            break;
-        case PUT_LVALUE_NOKEEP_DEPTH:
-            break;
-        case PUT_LVALUE_KEEP_TOP:
-            emit_op(s, OP_insert3); /* obj prop v -> v obj prop v */
-            break;
-        case PUT_LVALUE_KEEP_SECOND:
-            emit_op(s, OP_perm4); /* obj prop v0 v -> v0 obj prop v */
-            break;
-        case PUT_LVALUE_NOKEEP_BOTTOM:
-            emit_op(s, OP_rot3l);
-            break;
-        default:
-            abort();
-        }
-        break;
-    case OP_get_super_value:
-        /* depth = 3 */
-        switch(special) {
-        case PUT_LVALUE_NOKEEP:
-        case PUT_LVALUE_NOKEEP_DEPTH:
-            break;
-        case PUT_LVALUE_KEEP_TOP:
-            emit_op(s, OP_insert4); /* this obj prop v -> v this obj prop v */
-            break;
-        case PUT_LVALUE_KEEP_SECOND:
-            emit_op(s, OP_perm5); /* this obj prop v0 v -> v0 this obj prop v */
-            break;
-        case PUT_LVALUE_NOKEEP_BOTTOM:
-            emit_op(s, OP_rot4l);
-            break;
-        default:
-            abort();
-        }
-        break;
-    default:
-        break;
-    }
-    
-    switch(opcode) {
-    case OP_scope_get_var:  /* val -- */
-        assert(special == PUT_LVALUE_NOKEEP ||
-               special == PUT_LVALUE_NOKEEP_DEPTH);
-        emit_op(s, is_let ? OP_scope_put_var_init : OP_scope_put_var);
-        emit_u32(s, name);  /* has refcount */
-        emit_u16(s, scope);
-        break;
-    case OP_get_field:
-        emit_op(s, OP_put_field);
-        emit_u32(s, name);  /* name has refcount */
-        break;
-    case OP_scope_get_private_field:
-        emit_op(s, OP_scope_put_private_field);
-        emit_u32(s, name);  /* name has refcount */
-        emit_u16(s, scope);
-        break;
-    case OP_get_array_el:
-        emit_op(s, OP_put_array_el);
-        break;
-    case OP_get_ref_value:
-        emit_op(s, OP_put_ref_value);
-        break;
-    case OP_get_super_value:
-        emit_op(s, OP_put_super_value);
-        break;
-    default:
-        abort();
-    }
-}
-
-static __exception int js_parse_expr_paren(JSParseState *s)
-{
-    if (js_parse_expect(s, '('))
-        return -1;
-    if (js_parse_expr(s))
-        return -1;
-    if (js_parse_expect(s, ')'))
-        return -1;
-    return 0;
-}
-
-static int js_unsupported_keyword(JSParseState *s, JSAtom atom)
-{
-    char buf[ATOM_GET_STR_BUF_SIZE];
-    return js_parse_error(s, "unsupported keyword: %s",
-                          JS_AtomGetStr(s->ctx, buf, sizeof(buf), atom));
-}
-
-static __exception int js_define_var(JSParseState *s, JSAtom name, int tok)
-{
-    JSFunctionDef *fd = s->cur_func;
-    JSVarDefEnum var_def_type;
-    
-    if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) {
-        return js_parse_error(s, "yield is a reserved identifier");
-    }
-    if ((name == JS_ATOM_arguments || name == JS_ATOM_eval)
-    &&  (fd->js_mode & JS_MODE_STRICT)) {
-        return js_parse_error(s, "invalid variable name in strict mode");
-    }
-    if ((name == JS_ATOM_let || name == JS_ATOM_undefined)
-    &&  (tok == TOK_LET || tok == TOK_CONST)) {
-        return js_parse_error(s, "invalid lexical variable name");
-    }
-    switch(tok) {
-    case TOK_LET:
-        var_def_type = JS_VAR_DEF_LET;
-        break;
-    case TOK_CONST:
-        var_def_type = JS_VAR_DEF_CONST;
-        break;
-    case TOK_VAR:
-        var_def_type = JS_VAR_DEF_VAR;
-        break;
-    case TOK_CATCH:
-        var_def_type = JS_VAR_DEF_CATCH;
-        break;
-    default:
-        abort();
-    }
-    if (define_var(s, fd, name, var_def_type) < 0)
-        return -1;
-    return 0;
-}
-
-static void js_emit_spread_code(JSParseState *s, int depth)
-{
-    int label_rest_next, label_rest_done;
-
-    /* XXX: could check if enum object is an actual array and optimize
-       slice extraction. enumeration record and target array are in a
-       different order from OP_append case. */
-    /* enum_rec xxx -- enum_rec xxx array 0 */
-    emit_op(s, OP_array_from);
-    emit_u16(s, 0);
-    emit_op(s, OP_push_i32);
-    emit_u32(s, 0);
-    emit_label(s, label_rest_next = new_label(s));
-    emit_op(s, OP_for_of_next);
-    emit_u8(s, 2 + depth);
-    label_rest_done = emit_goto(s, OP_if_true, -1);
-    /* array idx val -- array idx */
-    emit_op(s, OP_define_array_el);
-    emit_op(s, OP_inc);
-    emit_goto(s, OP_goto, label_rest_next);
-    emit_label(s, label_rest_done);
-    /* enum_rec xxx array idx undef -- enum_rec xxx array */
-    emit_op(s, OP_drop);
-    emit_op(s, OP_drop);
-}
-
-static int js_parse_check_duplicate_parameter(JSParseState *s, JSAtom name)
-{
-    /* Check for duplicate parameter names */
-    JSFunctionDef *fd = s->cur_func;
-    int i;
-    for (i = 0; i < fd->arg_count; i++) {
-        if (fd->args[i].var_name == name)
-            goto duplicate;
-    }
-    for (i = 0; i < fd->var_count; i++) {
-        if (fd->vars[i].var_name == name)
-            goto duplicate;
-    }
-    return 0;
-
-duplicate:
-    return js_parse_error(s, "duplicate parameter names not allowed in this context");
-}
-
-static JSAtom js_parse_destructuring_var(JSParseState *s, int tok, int is_arg)
-{
-    JSAtom name;
-
-    if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)
-    ||  ((s->cur_func->js_mode & JS_MODE_STRICT) &&
-         (s->token.u.ident.atom == JS_ATOM_eval || s->token.u.ident.atom == JS_ATOM_arguments))) {
-        js_parse_error(s, "invalid destructuring target");
-        return JS_ATOM_NULL;
-    }
-    name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
-    if (is_arg && js_parse_check_duplicate_parameter(s, name))
-        goto fail;
-    if (next_token(s))
-        goto fail;
-
-    return name;
-fail:
-    JS_FreeAtom(s->ctx, name);
-    return JS_ATOM_NULL;
-}
-
-/* Return -1 if error, 0 if no initializer, 1 if an initializer is
-   present at the top level. */
-static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
-                                        int hasval, int has_ellipsis,
-                                        BOOL allow_initializer)
-{
-    int label_parse, label_assign, label_done, label_lvalue, depth_lvalue;
-    int start_addr, assign_addr;
-    JSAtom prop_name, var_name;
-    int opcode, scope, tok1, skip_bits;
-    BOOL has_initializer;
-    
-    if (has_ellipsis < 0) {
-        /* pre-parse destructuration target for spread detection */
-        js_parse_skip_parens_token(s, &skip_bits, FALSE);
-        has_ellipsis = skip_bits & SKIP_HAS_ELLIPSIS;
-    }
-
-    label_parse = new_label(s);
-    label_assign = new_label(s);
-
-    start_addr = s->cur_func->byte_code.size;
-    if (hasval) {
-        /* consume value from the stack */
-        emit_op(s, OP_dup);
-        emit_op(s, OP_undefined);
-        emit_op(s, OP_strict_eq);
-        emit_goto(s, OP_if_true, label_parse);
-        emit_label(s, label_assign);
-    } else {
-        emit_goto(s, OP_goto, label_parse);
-        emit_label(s, label_assign);
-        /* leave value on the stack */
-        emit_op(s, OP_dup);
-    }
-    assign_addr = s->cur_func->byte_code.size;
-    if (s->token.val == '{') {
-        if (next_token(s))
-            return -1;
-        /* throw an exception if the value cannot be converted to an object */
-        emit_op(s, OP_to_object);
-        if (has_ellipsis) {
-            /* add excludeList on stack just below src object */
-            emit_op(s, OP_object);
-            emit_op(s, OP_swap);
-        }
-        while (s->token.val != '}') {
-            int prop_type;
-            if (s->token.val == TOK_ELLIPSIS) {
-                if (!has_ellipsis) {
-                    JS_ThrowInternalError(s->ctx, "unexpected ellipsis token");
-                    return -1;
-                }
-                if (next_token(s))
-                    return -1;
-                if (tok) {
-                    var_name = js_parse_destructuring_var(s, tok, is_arg);
-                    if (var_name == JS_ATOM_NULL)
-                        return -1;
-                    opcode = OP_scope_get_var;
-                    scope = s->cur_func->scope_level;
-                    label_lvalue = -1;
-                    depth_lvalue = 0;
-                } else {
-                    if (js_parse_left_hand_side_expr(s))
-                        return -1;
-
-                    if (get_lvalue(s, &opcode, &scope, &var_name,
-                                   &label_lvalue, &depth_lvalue, FALSE, '{'))
-                        return -1;
-                }
-                if (s->token.val != '}') {
-                    js_parse_error(s, "assignment rest property must be last");
-                    goto var_error;
-                }
-                emit_op(s, OP_object);  /* target */
-                emit_op(s, OP_copy_data_properties);
-                emit_u8(s, 0 | ((depth_lvalue + 1) << 2) | ((depth_lvalue + 2) << 5));
-                goto set_val;
-            }
-            prop_type = js_parse_property_name(s, &prop_name, FALSE, TRUE, FALSE);
-            if (prop_type < 0)
-                return -1;
-            var_name = JS_ATOM_NULL;
-            opcode = OP_scope_get_var;
-            scope = s->cur_func->scope_level;
-            label_lvalue = -1;
-            depth_lvalue = 0;
-            if (prop_type == PROP_TYPE_IDENT) {
-                if (next_token(s))
-                    goto prop_error;
-                if ((s->token.val == '[' || s->token.val == '{')
-                    &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' ||
-                         tok1 == '=' || tok1 == '}')) {
-                    if (prop_name == JS_ATOM_NULL) {
-                        /* computed property name on stack */
-                        if (has_ellipsis) {
-                            /* define the property in excludeList */
-                            emit_op(s, OP_to_propkey); /* avoid calling ToString twice */
-                            emit_op(s, OP_perm3); /* TOS: src excludeList prop */
-                            emit_op(s, OP_null); /* TOS: src excludeList prop null */
-                            emit_op(s, OP_define_array_el); /* TOS: src excludeList prop */
-                            emit_op(s, OP_perm3); /* TOS: excludeList src prop */
-                        }
-                        /* get the computed property from the source object */
-                        emit_op(s, OP_get_array_el2);
-                    } else {
-                        /* named property */
-                        if (has_ellipsis) {
-                            /* define the property in excludeList */
-                            emit_op(s, OP_swap); /* TOS: src excludeList */
-                            emit_op(s, OP_null); /* TOS: src excludeList null */
-                            emit_op(s, OP_define_field); /* TOS: src excludeList */
-                            emit_atom(s, prop_name);
-                            emit_op(s, OP_swap); /* TOS: excludeList src */
-                        }
-                        /* get the named property from the source object */
-                        emit_op(s, OP_get_field2);
-                        emit_u32(s, prop_name);
-                    }
-                    if (js_parse_destructuring_element(s, tok, is_arg, TRUE, -1, TRUE) < 0)
-                        return -1;
-                    if (s->token.val == '}')
-                        break;
-                    /* accept a trailing comma before the '}' */
-                    if (js_parse_expect(s, ','))
-                        return -1;
-                    continue;
-                }
-                if (prop_name == JS_ATOM_NULL) {
-                    emit_op(s, OP_to_propkey2);
-                    if (has_ellipsis) {
-                        /* define the property in excludeList */
-                        emit_op(s, OP_perm3);
-                        emit_op(s, OP_null);
-                        emit_op(s, OP_define_array_el);
-                        emit_op(s, OP_perm3);
-                    }
-                    /* source prop -- source source prop */
-                    emit_op(s, OP_dup1);
-                } else {
-                    if (has_ellipsis) {
-                        /* define the property in excludeList */
-                        emit_op(s, OP_swap);
-                        emit_op(s, OP_null);
-                        emit_op(s, OP_define_field);
-                        emit_atom(s, prop_name);
-                        emit_op(s, OP_swap);
-                    }
-                    /* source -- source source */
-                    emit_op(s, OP_dup);
-                }
-                if (tok) {
-                    var_name = js_parse_destructuring_var(s, tok, is_arg);
-                    if (var_name == JS_ATOM_NULL)
-                        goto prop_error;
-                } else {
-                    if (js_parse_left_hand_side_expr(s))
-                        goto prop_error;
-                lvalue:
-                    if (get_lvalue(s, &opcode, &scope, &var_name,
-                                   &label_lvalue, &depth_lvalue, FALSE, '{'))
-                        goto prop_error;
-                    /* swap ref and lvalue object if any */
-                    if (prop_name == JS_ATOM_NULL) {
-                        switch(depth_lvalue) {
-                        case 1:
-                            /* source prop x -> x source prop */
-                            emit_op(s, OP_rot3r);
-                            break;
-                        case 2:
-                            /* source prop x y -> x y source prop */
-                            emit_op(s, OP_swap2);   /* t p2 s p1 */
-                            break;
-                        case 3:
-                            /* source prop x y z -> x y z source prop */
-                            emit_op(s, OP_rot5l);
-                            emit_op(s, OP_rot5l);
-                            break;
-                        }
-                    } else {
-                        switch(depth_lvalue) {
-                        case 1:
-                            /* source x -> x source */
-                            emit_op(s, OP_swap);
-                            break;
-                        case 2:
-                            /* source x y -> x y source */
-                            emit_op(s, OP_rot3l);
-                            break;
-                        case 3:
-                            /* source x y z -> x y z source */
-                            emit_op(s, OP_rot4l);
-                            break;
-                        }
-                    }
-                }
-                if (prop_name == JS_ATOM_NULL) {
-                    /* computed property name on stack */
-                    /* XXX: should have OP_get_array_el2x with depth */
-                    /* source prop -- val */
-                    emit_op(s, OP_get_array_el);
-                } else {
-                    /* named property */
-                    /* XXX: should have OP_get_field2x with depth */
-                    /* source -- val */
-                    emit_op(s, OP_get_field);
-                    emit_u32(s, prop_name);
-                }
-            } else {
-                /* prop_type = PROP_TYPE_VAR, cannot be a computed property */
-                if (is_arg && js_parse_check_duplicate_parameter(s, prop_name))
-                    goto prop_error;
-                if ((s->cur_func->js_mode & JS_MODE_STRICT) &&
-                    (prop_name == JS_ATOM_eval || prop_name == JS_ATOM_arguments)) {
-                    js_parse_error(s, "invalid destructuring target");
-                    goto prop_error;
-                }
-                if (has_ellipsis) {
-                    /* define the property in excludeList */
-                    emit_op(s, OP_swap);
-                    emit_op(s, OP_null);
-                    emit_op(s, OP_define_field);
-                    emit_atom(s, prop_name);
-                    emit_op(s, OP_swap);
-                }
-                if (!tok || tok == TOK_VAR) {
-                    /* generate reference */
-                    /* source -- source source */
-                    emit_op(s, OP_dup);
-                    emit_op(s, OP_scope_get_var);
-                    emit_atom(s, prop_name);
-                    emit_u16(s, s->cur_func->scope_level);
-                    goto lvalue;
-                }
-                var_name = JS_DupAtom(s->ctx, prop_name);
-                /* source -- source val */
-                emit_op(s, OP_get_field2);
-                emit_u32(s, prop_name);
-            }
-        set_val:
-            if (tok) {
-                if (js_define_var(s, var_name, tok))
-                    goto var_error;
-                scope = s->cur_func->scope_level;
-            }
-            if (s->token.val == '=') {  /* handle optional default value */
-                int label_hasval;
-                emit_op(s, OP_dup);
-                emit_op(s, OP_undefined);
-                emit_op(s, OP_strict_eq);
-                label_hasval = emit_goto(s, OP_if_false, -1);
-                if (next_token(s))
-                    goto var_error;
-                emit_op(s, OP_drop);
-                if (js_parse_assign_expr(s))
-                    goto var_error;
-                if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
-                    set_object_name(s, var_name);
-                emit_label(s, label_hasval);
-            }
-            /* store value into lvalue object */
-            put_lvalue(s, opcode, scope, var_name, label_lvalue,
-                       PUT_LVALUE_NOKEEP_DEPTH,
-                       (tok == TOK_CONST || tok == TOK_LET));
-            if (s->token.val == '}')
-                break;
-            /* accept a trailing comma before the '}' */
-            if (js_parse_expect(s, ','))
-                return -1;
-        }
-        /* drop the source object */
-        emit_op(s, OP_drop);
-        if (has_ellipsis) {
-            emit_op(s, OP_drop); /* pop excludeList */
-        }
-        if (next_token(s))
-            return -1;
-    } else if (s->token.val == '[') {
-        BOOL has_spread;
-        int enum_depth;
-        BlockEnv block_env;
-
-        if (next_token(s))
-            return -1;
-        /* the block environment is only needed in generators in case
-           'yield' triggers a 'return' */
-        push_break_entry(s->cur_func, &block_env,
-                         JS_ATOM_NULL, -1, -1, 2);
-        block_env.has_iterator = TRUE;
-        emit_op(s, OP_for_of_start);
-        has_spread = FALSE;
-        while (s->token.val != ']') {
-            /* get the next value */
-            if (s->token.val == TOK_ELLIPSIS) {
-                if (next_token(s))
-                    return -1;
-                if (s->token.val == ',' || s->token.val == ']')
-                    return js_parse_error(s, "missing binding pattern...");
-                has_spread = TRUE;
-            }
-            if (s->token.val == ',') {
-                /* do nothing, skip the value, has_spread is false */
-                emit_op(s, OP_for_of_next);
-                emit_u8(s, 0);
-                emit_op(s, OP_drop);
-                emit_op(s, OP_drop);
-            } else if ((s->token.val == '[' || s->token.val == '{')
-                   &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' ||
-                        tok1 == '=' || tok1 == ']')) {
-                if (has_spread) {
-                    if (tok1 == '=')
-                        return js_parse_error(s, "rest element cannot have a default value");
-                    js_emit_spread_code(s, 0);
-                } else {
-                    emit_op(s, OP_for_of_next);
-                    emit_u8(s, 0);
-                    emit_op(s, OP_drop);
-                }
-                if (js_parse_destructuring_element(s, tok, is_arg, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
-                    return -1;
-            } else {
-                var_name = JS_ATOM_NULL;
-                enum_depth = 0;
-                if (tok) {
-                    var_name = js_parse_destructuring_var(s, tok, is_arg);
-                    if (var_name == JS_ATOM_NULL)
-                        goto var_error;
-                    if (js_define_var(s, var_name, tok))
-                        goto var_error;
-                    opcode = OP_scope_get_var;
-                    scope = s->cur_func->scope_level;
-                } else {
-                    if (js_parse_left_hand_side_expr(s))
-                        return -1;
-                    if (get_lvalue(s, &opcode, &scope, &var_name,
-                                   &label_lvalue, &enum_depth, FALSE, '[')) {
-                        return -1;
-                    }
-                }
-                if (has_spread) {
-                    js_emit_spread_code(s, enum_depth);
-                } else {
-                    emit_op(s, OP_for_of_next);
-                    emit_u8(s, enum_depth);
-                    emit_op(s, OP_drop);
-                }
-                if (s->token.val == '=' && !has_spread) {
-                    /* handle optional default value */
-                    int label_hasval;
-                    emit_op(s, OP_dup);
-                    emit_op(s, OP_undefined);
-                    emit_op(s, OP_strict_eq);
-                    label_hasval = emit_goto(s, OP_if_false, -1);
-                    if (next_token(s))
-                        goto var_error;
-                    emit_op(s, OP_drop);
-                    if (js_parse_assign_expr(s))
-                        goto var_error;
-                    if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
-                        set_object_name(s, var_name);
-                    emit_label(s, label_hasval);
-                }
-                /* store value into lvalue object */
-                put_lvalue(s, opcode, scope, var_name,
-                           label_lvalue, PUT_LVALUE_NOKEEP_DEPTH,
-                           (tok == TOK_CONST || tok == TOK_LET));
-            }
-            if (s->token.val == ']')
-                break;
-            if (has_spread)
-                return js_parse_error(s, "rest element must be the last one");
-            /* accept a trailing comma before the ']' */
-            if (js_parse_expect(s, ','))
-                return -1;
-        }
-        /* close iterator object:
-           if completed, enum_obj has been replaced by undefined */
-        emit_op(s, OP_iterator_close);
-        pop_break_entry(s->cur_func);
-        if (next_token(s))
-            return -1;
-    } else {
-        return js_parse_error(s, "invalid assignment syntax");
-    }
-    if (s->token.val == '=' && allow_initializer) {
-        label_done = emit_goto(s, OP_goto, -1);
-        if (next_token(s))
-            return -1;
-        emit_label(s, label_parse);
-        if (hasval)
-            emit_op(s, OP_drop);
-        if (js_parse_assign_expr(s))
-            return -1;
-        emit_goto(s, OP_goto, label_assign);
-        emit_label(s, label_done);
-        has_initializer = TRUE;
-    } else {
-        /* normally hasval is true except if
-           js_parse_skip_parens_token() was wrong in the parsing */
-        //        assert(hasval);
-        if (!hasval) {
-            js_parse_error(s, "too complicated destructuring expression");
-            return -1;
-        }
-        /* remove test and decrement label ref count */
-        memset(s->cur_func->byte_code.buf + start_addr, OP_nop,
-               assign_addr - start_addr);
-        s->cur_func->label_slots[label_parse].ref_count--;
-        has_initializer = FALSE;
-    }
-    return has_initializer;
-
- prop_error:
-    JS_FreeAtom(s->ctx, prop_name);
- var_error:
-    JS_FreeAtom(s->ctx, var_name);
-    return -1;
-}
-
-typedef enum FuncCallType {
-    FUNC_CALL_NORMAL,
-    FUNC_CALL_NEW,
-    FUNC_CALL_SUPER_CTOR,
-    FUNC_CALL_TEMPLATE,
-} FuncCallType;
-
-static void optional_chain_test(JSParseState *s, int *poptional_chaining_label,
-                                int drop_count)
-{
-    int label_next, i;
-    if (*poptional_chaining_label < 0)
-        *poptional_chaining_label = new_label(s);
-   /* XXX: could be more efficient with a specific opcode */
-    emit_op(s, OP_dup);
-    emit_op(s, OP_is_undefined_or_null);
-    label_next = emit_goto(s, OP_if_false, -1);
-    for(i = 0; i < drop_count; i++)
-        emit_op(s, OP_drop);
-    emit_op(s, OP_undefined);
-    emit_goto(s, OP_goto, *poptional_chaining_label);
-    emit_label(s, label_next);
-}
-
-/* allowed parse_flags: PF_POSTFIX_CALL, PF_ARROW_FUNC */
-static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
-{
-    FuncCallType call_type;
-    int optional_chaining_label;
-    BOOL accept_lparen = (parse_flags & PF_POSTFIX_CALL) != 0;
-    
-    call_type = FUNC_CALL_NORMAL;
-    switch(s->token.val) {
-    case TOK_NUMBER:
-        {
-            JSValue val;
-            val = s->token.u.num.val;
-
-            if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) {
-                emit_op(s, OP_push_i32);
-                emit_u32(s, JS_VALUE_GET_INT(val));
-            } else
-#ifdef CONFIG_BIGNUM
-            if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) {
-                slimb_t e;
-                int ret;
-
-                /* need a runtime conversion */
-                /* XXX: could add a cache and/or do it once at
-                   the start of the function */
-                if (emit_push_const(s, val, 0) < 0)
-                    return -1;
-                e = s->token.u.num.exponent;
-                if (e == (int32_t)e) {
-                    emit_op(s, OP_push_i32);
-                    emit_u32(s, e);
-                } else {
-                    val = JS_NewBigInt64_1(s->ctx, e);
-                    if (JS_IsException(val))
-                        return -1;
-                    ret = emit_push_const(s, val, 0);
-                    JS_FreeValue(s->ctx, val);
-                    if (ret < 0)
-                        return -1;
-                }
-                emit_op(s, OP_mul_pow10);
-            } else
-#endif
-            {
-                if (emit_push_const(s, val, 0) < 0)
-                    return -1;
-            }
-        }
-        if (next_token(s))
-            return -1;
-        break;
-    case TOK_TEMPLATE:
-        if (js_parse_template(s, 0, NULL))
-            return -1;
-        break;
-    case TOK_STRING:
-        if (emit_push_const(s, s->token.u.str.str, 1))
-            return -1;
-        if (next_token(s))
-            return -1;
-        break;
-        
-    case TOK_DIV_ASSIGN:
-        s->buf_ptr -= 2;
-        goto parse_regexp;
-    case '/':
-        s->buf_ptr--;
-    parse_regexp:
-        {
-            JSValue str;
-            int ret, backtrace_flags;
-            if (!s->ctx->compile_regexp)
-                return js_parse_error(s, "RegExp are not supported");
-            /* the previous token is '/' or '/=', so no need to free */
-            if (js_parse_regexp(s))
-                return -1;
-            ret = emit_push_const(s, s->token.u.regexp.body, 0);
-            str = s->ctx->compile_regexp(s->ctx, s->token.u.regexp.body,
-                                         s->token.u.regexp.flags);
-            if (JS_IsException(str)) {
-                /* add the line number info */
-                backtrace_flags = 0;
-                if (s->cur_func && s->cur_func->backtrace_barrier)
-                    backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL;
-                build_backtrace(s->ctx, s->ctx->rt->current_exception,
-                                s->filename, s->token.line_num,
-                                backtrace_flags);
-                return -1;
-            }
-            ret = emit_push_const(s, str, 0);
-            JS_FreeValue(s->ctx, str);
-            if (ret)
-                return -1;
-            /* we use a specific opcode to be sure the correct
-               function is called (otherwise the bytecode would have
-               to be verified by the RegExp constructor) */
-            emit_op(s, OP_regexp);
-            if (next_token(s))
-                return -1;
-        }
-        break;
-    case '(':
-        if ((parse_flags & PF_ARROW_FUNC) &&
-            js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) {
-            if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
-                                       JS_FUNC_NORMAL, JS_ATOM_NULL,
-                                       s->token.ptr, s->token.line_num))
-                return -1;
-        } else {
-            if (js_parse_expr_paren(s))
-                return -1;
-        }
-        break;
-    case TOK_FUNCTION:
-        if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR,
-                                   JS_FUNC_NORMAL, JS_ATOM_NULL,
-                                   s->token.ptr, s->token.line_num))
-            return -1;
-        break;
-    case TOK_CLASS:
-        if (js_parse_class(s, TRUE, JS_PARSE_EXPORT_NONE))
-            return -1;
-        break;
-    case TOK_NULL:
-        if (next_token(s))
-            return -1;
-        emit_op(s, OP_null);
-        break;
-    case TOK_THIS:
-        if (next_token(s))
-            return -1;
-        emit_op(s, OP_scope_get_var);
-        emit_atom(s, JS_ATOM_this);
-        emit_u16(s, 0);
-        break;
-    case TOK_FALSE:
-        if (next_token(s))
-            return -1;
-        emit_op(s, OP_push_false);
-        break;
-    case TOK_TRUE:
-        if (next_token(s))
-            return -1;
-        emit_op(s, OP_push_true);
-        break;
-    case TOK_IDENT:
-        {
-            JSAtom name;
-            if (s->token.u.ident.is_reserved) {
-                return js_parse_error_reserved_identifier(s);
-            }
-            if ((parse_flags & PF_ARROW_FUNC) &&
-                peek_token(s, TRUE) == TOK_ARROW) {
-                if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
-                                           JS_FUNC_NORMAL, JS_ATOM_NULL,
-                                           s->token.ptr, s->token.line_num))
-                    return -1;
-            } else if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
-                       peek_token(s, TRUE) != '\n') {
-                const uint8_t *source_ptr;
-                int source_line_num;
-
-                source_ptr = s->token.ptr;
-                source_line_num = s->token.line_num;
-                if (next_token(s))
-                    return -1;
-                if (s->token.val == TOK_FUNCTION) {
-                    if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR,
-                                               JS_FUNC_ASYNC, JS_ATOM_NULL,
-                                               source_ptr, source_line_num))
-                        return -1;
-                } else if ((parse_flags & PF_ARROW_FUNC) &&
-                           ((s->token.val == '(' &&
-                             js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) ||
-                            (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
-                             peek_token(s, TRUE) == TOK_ARROW))) {
-                    if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
-                                               JS_FUNC_ASYNC, JS_ATOM_NULL,
-                                               source_ptr, source_line_num))
-                        return -1;
-                } else {
-                    name = JS_DupAtom(s->ctx, JS_ATOM_async);
-                    goto do_get_var;
-                }
-            } else {
-                if (s->token.u.ident.atom == JS_ATOM_arguments &&
-                    !s->cur_func->arguments_allowed) {
-                    js_parse_error(s, "'arguments' identifier is not allowed in class field initializer");
-                    return -1;
-                }
-                name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
-                if (next_token(s))  /* update line number before emitting code */
-                    return -1;
-            do_get_var:
-                emit_op(s, OP_scope_get_var);
-                emit_u32(s, name);
-                emit_u16(s, s->cur_func->scope_level);
-            }
-        }
-        break;
-    case '{':
-    case '[':
-        {
-            int skip_bits;
-            if (js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
-                if (js_parse_destructuring_element(s, 0, 0, FALSE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
-                    return -1;
-            } else {
-                if (s->token.val == '{') {
-                    if (js_parse_object_literal(s))
-                        return -1;
-                } else {
-                    if (js_parse_array_literal(s))
-                        return -1;
-                }
-            }
-        }
-        break;
-    case TOK_NEW:
-        if (next_token(s))
-            return -1;
-        if (s->token.val == '.') {
-            if (next_token(s))
-                return -1;
-            if (!token_is_pseudo_keyword(s, JS_ATOM_target))
-                return js_parse_error(s, "expecting target");
-            if (!s->cur_func->new_target_allowed)
-                return js_parse_error(s, "new.target only allowed within functions");
-            if (next_token(s))
-                return -1;
-            emit_op(s, OP_scope_get_var);
-            emit_atom(s, JS_ATOM_new_target);
-            emit_u16(s, 0);
-        } else {
-            if (js_parse_postfix_expr(s, 0))
-                return -1;
-            accept_lparen = TRUE;
-            if (s->token.val != '(') {
-                /* new operator on an object */
-                emit_op(s, OP_dup);
-                emit_op(s, OP_call_constructor);
-                emit_u16(s, 0);
-            } else {
-                call_type = FUNC_CALL_NEW;
-            }
-        }
-        break;
-    case TOK_SUPER:
-        if (next_token(s))
-            return -1;
-        if (s->token.val == '(') {
-            if (!s->cur_func->super_call_allowed)
-                return js_parse_error(s, "super() is only valid in a derived class constructor");
-            call_type = FUNC_CALL_SUPER_CTOR;
-        } else if (s->token.val == '.' || s->token.val == '[') {
-            if (!s->cur_func->super_allowed)
-                return js_parse_error(s, "'super' is only valid in a method");
-            emit_op(s, OP_scope_get_var);
-            emit_atom(s, JS_ATOM_this);
-            emit_u16(s, 0);
-            emit_op(s, OP_scope_get_var);
-            emit_atom(s, JS_ATOM_home_object);
-            emit_u16(s, 0);
-            emit_op(s, OP_get_super);
-        } else {
-            return js_parse_error(s, "invalid use of 'super'");
-        }
-        break;
-    case TOK_IMPORT:
-        if (next_token(s))
-            return -1;
-        if (s->token.val == '.') {
-            if (next_token(s))
-                return -1;
-            if (!token_is_pseudo_keyword(s, JS_ATOM_meta))
-                return js_parse_error(s, "meta expected");
-            if (!s->is_module)
-                return js_parse_error(s, "import.meta only valid in module code");
-            if (next_token(s))
-                return -1;
-            emit_op(s, OP_special_object);
-            emit_u8(s, OP_SPECIAL_OBJECT_IMPORT_META);
-        } else {
-            if (js_parse_expect(s, '('))
-                return -1;
-            if (!accept_lparen)
-                return js_parse_error(s, "invalid use of 'import()'");
-            if (js_parse_assign_expr(s))
-                return -1;
-            if (js_parse_expect(s, ')'))
-                return -1;
-            emit_op(s, OP_import);
-        }
-        break;
-    default:
-        return js_parse_error(s, "unexpected token in expression: '%.*s'",
-                              (int)(s->buf_ptr - s->token.ptr), s->token.ptr);
-    }
-
-    optional_chaining_label = -1;
-    for(;;) {
-        JSFunctionDef *fd = s->cur_func;
-        BOOL has_optional_chain = FALSE;
-        
-        if (s->token.val == TOK_QUESTION_MARK_DOT) {
-            /* optional chaining */
-            if (next_token(s))
-                return -1;
-            has_optional_chain = TRUE;
-            if (s->token.val == '(' && accept_lparen) {
-                goto parse_func_call;
-            } else if (s->token.val == '[') {
-                goto parse_array_access;
-            } else {
-                goto parse_property;
-            }
-        } else if (s->token.val == TOK_TEMPLATE &&
-                   call_type == FUNC_CALL_NORMAL) {
-            if (optional_chaining_label >= 0) {
-                return js_parse_error(s, "template literal cannot appear in an optional chain");
-            }
-            call_type = FUNC_CALL_TEMPLATE;
-            goto parse_func_call2;
-        } else if (s->token.val == '(' && accept_lparen) {
-            int opcode, arg_count, drop_count;
-
-            /* function call */
-        parse_func_call:
-            if (next_token(s))
-                return -1;
-
-            if (call_type == FUNC_CALL_NORMAL) {
-            parse_func_call2:
-                switch(opcode = get_prev_opcode(fd)) {
-                case OP_get_field:
-                    /* keep the object on the stack */
-                    fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;
-                    drop_count = 2;
-                    break;
-                case OP_scope_get_private_field:
-                    /* keep the object on the stack */
-                    fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_private_field2;
-                    drop_count = 2;
-                    break;
-                case OP_get_array_el:
-                    /* keep the object on the stack */
-                    fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;
-                    drop_count = 2;
-                    break;
-                case OP_scope_get_var:
-                    {
-                        JSAtom name;
-                        int scope;
-                        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
-                        scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
-                        if (name == JS_ATOM_eval && call_type == FUNC_CALL_NORMAL && !has_optional_chain) {
-                            /* direct 'eval' */
-                            opcode = OP_eval;
-                        } else {
-                            /* verify if function name resolves to a simple
-                               get_loc/get_arg: a function call inside a `with`
-                               statement can resolve to a method call of the
-                               `with` context object
-                             */
-                            /* XXX: always generate the OP_scope_get_ref
-                               and remove it in variable resolution
-                               pass ? */
-                            if (has_with_scope(fd, scope)) {
-                                opcode = OP_scope_get_ref;
-                                fd->byte_code.buf[fd->last_opcode_pos] = opcode;
-                            }
-                        }
-                        drop_count = 1;
-                    }
-                    break;
-                case OP_get_super_value:
-                    fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el;
-                    /* on stack: this func_obj */
-                    opcode = OP_get_array_el;
-                    drop_count = 2;
-                    break;
-                default:
-                    opcode = OP_invalid;
-                    drop_count = 1;
-                    break;
-                }
-                if (has_optional_chain) {
-                    optional_chain_test(s, &optional_chaining_label,
-                                        drop_count);
-                }
-            } else {
-                opcode = OP_invalid;
-            }
-
-            if (call_type == FUNC_CALL_TEMPLATE) {
-                if (js_parse_template(s, 1, &arg_count))
-                    return -1;
-                goto emit_func_call;
-            } else if (call_type == FUNC_CALL_SUPER_CTOR) {
-                emit_op(s, OP_scope_get_var);
-                emit_atom(s, JS_ATOM_this_active_func);
-                emit_u16(s, 0);
-
-                emit_op(s, OP_get_super);
-
-                emit_op(s, OP_scope_get_var);
-                emit_atom(s, JS_ATOM_new_target);
-                emit_u16(s, 0);
-            } else if (call_type == FUNC_CALL_NEW) {
-                emit_op(s, OP_dup); /* new.target = function */
-            }
-
-            /* parse arguments */
-            arg_count = 0;
-            while (s->token.val != ')') {
-                if (arg_count >= 65535) {
-                    return js_parse_error(s, "Too many call arguments");
-                }
-                if (s->token.val == TOK_ELLIPSIS)
-                    break;
-                if (js_parse_assign_expr(s))
-                    return -1;
-                arg_count++;
-                if (s->token.val == ')')
-                    break;
-                /* accept a trailing comma before the ')' */
-                if (js_parse_expect(s, ','))
-                    return -1;
-            }
-            if (s->token.val == TOK_ELLIPSIS) {
-                emit_op(s, OP_array_from);
-                emit_u16(s, arg_count);
-                emit_op(s, OP_push_i32);
-                emit_u32(s, arg_count);
-
-                /* on stack: array idx */
-                while (s->token.val != ')') {
-                    if (s->token.val == TOK_ELLIPSIS) {
-                        if (next_token(s))
-                            return -1;
-                        if (js_parse_assign_expr(s))
-                            return -1;
-#if 1
-                        /* XXX: could pass is_last indicator? */
-                        emit_op(s, OP_append);
-#else
-                        int label_next, label_done;
-                        label_next = new_label(s);
-                        label_done = new_label(s);
-                        /* push enumerate object below array/idx pair */
-                        emit_op(s, OP_for_of_start);
-                        emit_op(s, OP_rot5l);
-                        emit_op(s, OP_rot5l);
-                        emit_label(s, label_next);
-                        /* on stack: enum_rec array idx */
-                        emit_op(s, OP_for_of_next);
-                        emit_u8(s, 2);
-                        emit_goto(s, OP_if_true, label_done);
-                        /* append element */
-                        /* enum_rec array idx val -> enum_rec array new_idx */
-                        emit_op(s, OP_define_array_el);
-                        emit_op(s, OP_inc);
-                        emit_goto(s, OP_goto, label_next);
-                        emit_label(s, label_done);
-                        /* close enumeration, drop enum_rec and idx */
-                        emit_op(s, OP_drop); /* drop undef */
-                        emit_op(s, OP_nip1); /* drop enum_rec */
-                        emit_op(s, OP_nip1);
-                        emit_op(s, OP_nip1);
-#endif
-                    } else {
-                        if (js_parse_assign_expr(s))
-                            return -1;
-                        /* array idx val */
-                        emit_op(s, OP_define_array_el);
-                        emit_op(s, OP_inc);
-                    }
-                    if (s->token.val == ')')
-                        break;
-                    /* accept a trailing comma before the ')' */
-                    if (js_parse_expect(s, ','))
-                        return -1;
-                }
-                if (next_token(s))
-                    return -1;
-                /* drop the index */
-                emit_op(s, OP_drop);
-
-                /* apply function call */
-                switch(opcode) {
-                case OP_get_field:
-                case OP_scope_get_private_field:
-                case OP_get_array_el:
-                case OP_scope_get_ref:
-                    /* obj func array -> func obj array */
-                    emit_op(s, OP_perm3);
-                    emit_op(s, OP_apply);
-                    emit_u16(s, call_type == FUNC_CALL_NEW);
-                    break;
-                case OP_eval:
-                    emit_op(s, OP_apply_eval);
-                    emit_u16(s, fd->scope_level);
-                    fd->has_eval_call = TRUE;
-                    break;
-                default:
-                    if (call_type == FUNC_CALL_SUPER_CTOR) {
-                        emit_op(s, OP_apply);
-                        emit_u16(s, 1);
-                        /* set the 'this' value */
-                        emit_op(s, OP_dup);
-                        emit_op(s, OP_scope_put_var_init);
-                        emit_atom(s, JS_ATOM_this);
-                        emit_u16(s, 0);
-
-                        emit_class_field_init(s);
-                    } else if (call_type == FUNC_CALL_NEW) {
-                        /* obj func array -> func obj array */
-                        emit_op(s, OP_perm3);
-                        emit_op(s, OP_apply);
-                        emit_u16(s, 1);
-                    } else {
-                        /* func array -> func undef array */
-                        emit_op(s, OP_undefined);
-                        emit_op(s, OP_swap);
-                        emit_op(s, OP_apply);
-                        emit_u16(s, 0);
-                    }
-                    break;
-                }
-            } else {
-                if (next_token(s))
-                    return -1;
-            emit_func_call:
-                switch(opcode) {
-                case OP_get_field:
-                case OP_scope_get_private_field:
-                case OP_get_array_el:
-                case OP_scope_get_ref:
-                    emit_op(s, OP_call_method);
-                    emit_u16(s, arg_count);
-                    break;
-                case OP_eval:
-                    emit_op(s, OP_eval);
-                    emit_u16(s, arg_count);
-                    emit_u16(s, fd->scope_level);
-                    fd->has_eval_call = TRUE;
-                    break;
-                default:
-                    if (call_type == FUNC_CALL_SUPER_CTOR) {
-                        emit_op(s, OP_call_constructor);
-                        emit_u16(s, arg_count);
-
-                        /* set the 'this' value */
-                        emit_op(s, OP_dup);
-                        emit_op(s, OP_scope_put_var_init);
-                        emit_atom(s, JS_ATOM_this);
-                        emit_u16(s, 0);
-
-                        emit_class_field_init(s);
-                    } else if (call_type == FUNC_CALL_NEW) {
-                        emit_op(s, OP_call_constructor);
-                        emit_u16(s, arg_count);
-                    } else {
-                        emit_op(s, OP_call);
-                        emit_u16(s, arg_count);
-                    }
-                    break;
-                }
-            }
-            call_type = FUNC_CALL_NORMAL;
-        } else if (s->token.val == '.') {
-            if (next_token(s))
-                return -1;
-        parse_property:
-            if (s->token.val == TOK_PRIVATE_NAME) {
-                /* private class field */
-                if (get_prev_opcode(fd) == OP_get_super) {
-                    return js_parse_error(s, "private class field forbidden after super");
-                }
-                if (has_optional_chain) {
-                    optional_chain_test(s, &optional_chaining_label, 1);
-                }
-                emit_op(s, OP_scope_get_private_field);
-                emit_atom(s, s->token.u.ident.atom);
-                emit_u16(s, s->cur_func->scope_level);
-            } else {
-                if (!token_is_ident(s->token.val)) {
-                    return js_parse_error(s, "expecting field name");
-                }
-                if (get_prev_opcode(fd) == OP_get_super) {
-                    JSValue val;
-                    int ret;
-                    val = JS_AtomToValue(s->ctx, s->token.u.ident.atom);
-                    ret = emit_push_const(s, val, 1);
-                    JS_FreeValue(s->ctx, val);
-                    if (ret)
-                        return -1;
-                    emit_op(s, OP_get_super_value);
-                } else {
-                    if (has_optional_chain) {
-                        optional_chain_test(s, &optional_chaining_label, 1);
-                    }
-                    emit_op(s, OP_get_field);
-                    emit_atom(s, s->token.u.ident.atom);
-                }
-            }
-            if (next_token(s))
-                return -1;
-        } else if (s->token.val == '[') {
-            int prev_op;
-
-        parse_array_access:
-            prev_op = get_prev_opcode(fd);
-            if (has_optional_chain) {
-                optional_chain_test(s, &optional_chaining_label, 1);
-            }
-            if (next_token(s))
-                return -1;
-            if (js_parse_expr(s))
-                return -1;
-            if (js_parse_expect(s, ']'))
-                return -1;
-            if (prev_op == OP_get_super) {
-                emit_op(s, OP_get_super_value);
-            } else {
-                emit_op(s, OP_get_array_el);
-            }
-        } else {
-            break;
-        }
-    }
-    if (optional_chaining_label >= 0)
-        emit_label(s, optional_chaining_label);
-    return 0;
-}
-
-static __exception int js_parse_delete(JSParseState *s)
-{
-    JSFunctionDef *fd = s->cur_func;
-    JSAtom name;
-    int opcode;
-
-    if (next_token(s))
-        return -1;
-    if (js_parse_unary(s, PF_POW_FORBIDDEN))
-        return -1;
-    switch(opcode = get_prev_opcode(fd)) {
-    case OP_get_field:
-        {
-            JSValue val;
-            int ret;
-
-            name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
-            fd->byte_code.size = fd->last_opcode_pos;
-            fd->last_opcode_pos = -1;
-            val = JS_AtomToValue(s->ctx, name);
-            ret = emit_push_const(s, val, 1);
-            JS_FreeValue(s->ctx, val);
-            JS_FreeAtom(s->ctx, name);
-            if (ret)
-                return ret;
-        }
-        goto do_delete;
-    case OP_get_array_el:
-        fd->byte_code.size = fd->last_opcode_pos;
-        fd->last_opcode_pos = -1;
-    do_delete:
-        emit_op(s, OP_delete);
-        break;
-    case OP_scope_get_var:
-        /* 'delete this': this is not a reference */
-        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
-        if (name == JS_ATOM_this || name == JS_ATOM_new_target)
-            goto ret_true;
-        if (fd->js_mode & JS_MODE_STRICT) {
-            return js_parse_error(s, "cannot delete a direct reference in strict mode");
-        } else {
-            fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_delete_var;
-        }
-        break;
-    case OP_scope_get_private_field:
-        return js_parse_error(s, "cannot delete a private class field");
-    case OP_get_super_value:
-        emit_op(s, OP_throw_error);
-        emit_atom(s, JS_ATOM_NULL);
-        emit_u8(s, JS_THROW_ERROR_DELETE_SUPER);
-        break;
-    default:
-    ret_true:
-        emit_op(s, OP_drop);
-        emit_op(s, OP_push_true);
-        break;
-    }
-    return 0;
-}
-
-/* allowed parse_flags: PF_ARROW_FUNC, PF_POW_ALLOWED, PF_POW_FORBIDDEN */
-static __exception int js_parse_unary(JSParseState *s, int parse_flags)
-{
-    int op;
-
-    switch(s->token.val) {
-    case '+':
-    case '-':
-    case '!':
-    case '~':
-    case TOK_VOID:
-        op = s->token.val;
-        if (next_token(s))
-            return -1;
-        if (js_parse_unary(s, PF_POW_FORBIDDEN))
-            return -1;
-        switch(op) {
-        case '-':
-            emit_op(s, OP_neg);
-            break;
-        case '+':
-            emit_op(s, OP_plus);
-            break;
-        case '!':
-            emit_op(s, OP_lnot);
-            break;
-        case '~':
-            emit_op(s, OP_not);
-            break;
-        case TOK_VOID:
-            emit_op(s, OP_drop);
-            emit_op(s, OP_undefined);
-            break;
-        default:
-            abort();
-        }
-        parse_flags = 0;
-        break;
-    case TOK_DEC:
-    case TOK_INC:
-        {
-            int opcode, op, scope, label;
-            JSAtom name;
-            op = s->token.val;
-            if (next_token(s))
-                return -1;
-            if (js_parse_unary(s, 0))
-                return -1;
-            if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))
-                return -1;
-            emit_op(s, OP_dec + op - TOK_DEC);
-            put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP,
-                       FALSE);
-        }
-        break;
-    case TOK_TYPEOF:
-        {
-            JSFunctionDef *fd;
-            if (next_token(s))
-                return -1;
-            if (js_parse_unary(s, PF_POW_FORBIDDEN))
-                return -1;
-            /* reference access should not return an exception, so we
-               patch the get_var */
-            fd = s->cur_func;
-            if (get_prev_opcode(fd) == OP_scope_get_var) {
-                fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_var_undef;
-            }
-            emit_op(s, OP_typeof);
-            parse_flags = 0;
-        }
-        break;
-    case TOK_DELETE:
-        if (js_parse_delete(s))
-            return -1;
-        parse_flags = 0;
-        break;
-    case TOK_AWAIT:
-        if (!(s->cur_func->func_kind & JS_FUNC_ASYNC))
-            return js_parse_error(s, "unexpected 'await' keyword");
-        if (!s->cur_func->in_function_body)
-            return js_parse_error(s, "await in default expression");
-        if (next_token(s))
-            return -1;
-        if (js_parse_unary(s, PF_POW_FORBIDDEN))
-            return -1;
-        emit_op(s, OP_await);
-        parse_flags = 0;
-        break;
-    default:
-        if (js_parse_postfix_expr(s, (parse_flags & PF_ARROW_FUNC) |
-                                  PF_POSTFIX_CALL))
-            return -1;
-        if (!s->got_lf &&
-            (s->token.val == TOK_DEC || s->token.val == TOK_INC)) {
-            int opcode, op, scope, label;
-            JSAtom name;
-            op = s->token.val;
-            if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))
-                return -1;
-            emit_op(s, OP_post_dec + op - TOK_DEC);
-            put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_SECOND,
-                       FALSE);
-            if (next_token(s))
-                return -1;        
-        }
-        break;
-    }
-    if (parse_flags & (PF_POW_ALLOWED | PF_POW_FORBIDDEN)) {
-#ifdef CONFIG_BIGNUM
-        if (s->token.val == TOK_POW || s->token.val == TOK_MATH_POW) {
-            /* Extended exponentiation syntax rules: we extend the ES7
-               grammar in order to have more intuitive semantics:
-               -2**2 evaluates to -4. */
-            if (!(s->cur_func->js_mode & JS_MODE_MATH)) {
-                if (parse_flags & PF_POW_FORBIDDEN) {
-                    JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'");
-                    return -1;
-                }
-            }
-            if (next_token(s))
-                return -1;
-            if (js_parse_unary(s, PF_POW_ALLOWED))
-                return -1;
-            emit_op(s, OP_pow);
-        }
-#else
-        if (s->token.val == TOK_POW) {
-            /* Strict ES7 exponentiation syntax rules: To solve
-               conficting semantics between different implementations
-               regarding the precedence of prefix operators and the
-               postifx exponential, ES7 specifies that -2**2 is a
-               syntax error. */
-            if (parse_flags & PF_POW_FORBIDDEN) {
-                JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'");
-                return -1;
-            }
-            if (next_token(s))
-                return -1;
-            if (js_parse_unary(s, PF_POW_ALLOWED))
-                return -1;
-            emit_op(s, OP_pow);
-        }
-#endif
-    }
-    return 0;
-}
-
-/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
-static __exception int js_parse_expr_binary(JSParseState *s, int level,
-                                            int parse_flags)
-{
-    int op, opcode;
-
-    if (level == 0) {
-        return js_parse_unary(s, (parse_flags & PF_ARROW_FUNC) |
-                              PF_POW_ALLOWED);
-    }
-    if (js_parse_expr_binary(s, level - 1, parse_flags))
-        return -1;
-    for(;;) {
-        op = s->token.val;
-        switch(level) {
-        case 1:
-            switch(op) {
-            case '*':
-                opcode = OP_mul;
-                break;
-            case '/':
-                opcode = OP_div;
-                break;
-            case '%':
-#ifdef CONFIG_BIGNUM
-                if (s->cur_func->js_mode & JS_MODE_MATH)
-                    opcode = OP_math_mod;
-                else
-#endif
-                    opcode = OP_mod;
-                break;
-            default:
-                return 0;
-            }
-            break;
-        case 2:
-            switch(op) {
-            case '+':
-                opcode = OP_add;
-                break;
-            case '-':
-                opcode = OP_sub;
-                break;
-            default:
-                return 0;
-            }
-            break;
-        case 3:
-            switch(op) {
-            case TOK_SHL:
-                opcode = OP_shl;
-                break;
-            case TOK_SAR:
-                opcode = OP_sar;
-                break;
-            case TOK_SHR:
-                opcode = OP_shr;
-                break;
-            default:
-                return 0;
-            }
-            break;
-        case 4:
-            switch(op) {
-            case '<':
-                opcode = OP_lt;
-                break;
-            case '>':
-                opcode = OP_gt;
-                break;
-            case TOK_LTE:
-                opcode = OP_lte;
-                break;
-            case TOK_GTE:
-                opcode = OP_gte;
-                break;
-            case TOK_INSTANCEOF:
-                opcode = OP_instanceof;
-                break;
-            case TOK_IN:
-                if (parse_flags & PF_IN_ACCEPTED) {
-                    opcode = OP_in;
-                } else {
-                    return 0;
-                }
-                break;
-            default:
-                return 0;
-            }
-            break;
-        case 5:
-            switch(op) {
-            case TOK_EQ:
-                opcode = OP_eq;
-                break;
-            case TOK_NEQ:
-                opcode = OP_neq;
-                break;
-            case TOK_STRICT_EQ:
-                opcode = OP_strict_eq;
-                break;
-            case TOK_STRICT_NEQ:
-                opcode = OP_strict_neq;
-                break;
-            default:
-                return 0;
-            }
-            break;
-        case 6:
-            switch(op) {
-            case '&':
-                opcode = OP_and;
-                break;
-            default:
-                return 0;
-            }
-            break;
-        case 7:
-            switch(op) {
-            case '^':
-                opcode = OP_xor;
-                break;
-            default:
-                return 0;
-            }
-            break;
-        case 8:
-            switch(op) {
-            case '|':
-                opcode = OP_or;
-                break;
-            default:
-                return 0;
-            }
-            break;
-        default:
-            abort();
-        }
-        if (next_token(s))
-            return -1;
-        if (js_parse_expr_binary(s, level - 1, parse_flags & ~PF_ARROW_FUNC))
-            return -1;
-        emit_op(s, opcode);
-    }
-    return 0;
-}
-
-/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
-static __exception int js_parse_logical_and_or(JSParseState *s, int op,
-                                               int parse_flags)
-{
-    int label1;
-
-    if (op == TOK_LAND) {
-        if (js_parse_expr_binary(s, 8, parse_flags))
-            return -1;
-    } else {
-        if (js_parse_logical_and_or(s, TOK_LAND, parse_flags))
-            return -1;
-    }
-    if (s->token.val == op) {
-        label1 = new_label(s);
-
-        for(;;) {
-            if (next_token(s))
-                return -1;
-            emit_op(s, OP_dup);
-            emit_goto(s, op == TOK_LAND ? OP_if_false : OP_if_true, label1);
-            emit_op(s, OP_drop);
-
-            if (op == TOK_LAND) {
-                if (js_parse_expr_binary(s, 8, parse_flags & ~PF_ARROW_FUNC))
-                    return -1;
-            } else {
-                if (js_parse_logical_and_or(s, TOK_LAND,
-                                            parse_flags & ~PF_ARROW_FUNC))
-                    return -1;
-            }
-            if (s->token.val != op) {
-                if (s->token.val == TOK_DOUBLE_QUESTION_MARK)
-                    return js_parse_error(s, "cannot mix ?? with && or ||");
-                break;
-            }
-        }
-
-        emit_label(s, label1);
-    }
-    return 0;
-}
-
-static __exception int js_parse_coalesce_expr(JSParseState *s, int parse_flags)
-{
-    int label1;
-    
-    if (js_parse_logical_and_or(s, TOK_LOR, parse_flags))
-        return -1;
-    if (s->token.val == TOK_DOUBLE_QUESTION_MARK) {
-        label1 = new_label(s);
-        for(;;) {
-            if (next_token(s))
-                return -1;
-            
-            emit_op(s, OP_dup);
-            emit_op(s, OP_is_undefined_or_null);
-            emit_goto(s, OP_if_false, label1);
-            emit_op(s, OP_drop);
-            
-            if (js_parse_expr_binary(s, 8, parse_flags & ~PF_ARROW_FUNC))
-                return -1;
-            if (s->token.val != TOK_DOUBLE_QUESTION_MARK)
-                break;
-        }
-        emit_label(s, label1);
-    }
-    return 0;
-}
-
-/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
-static __exception int js_parse_cond_expr(JSParseState *s, int parse_flags)
-{
-    int label1, label2;
-
-    if (js_parse_coalesce_expr(s, parse_flags))
-        return -1;
-    if (s->token.val == '?') {
-        if (next_token(s))
-            return -1;
-        label1 = emit_goto(s, OP_if_false, -1);
-
-        if (js_parse_assign_expr(s))
-            return -1;
-        if (js_parse_expect(s, ':'))
-            return -1;
-
-        label2 = emit_goto(s, OP_goto, -1);
-
-        emit_label(s, label1);
-
-        if (js_parse_assign_expr2(s, parse_flags & PF_IN_ACCEPTED))
-            return -1;
-
-        emit_label(s, label2);
-    }
-    return 0;
-}
-
-static void emit_return(JSParseState *s, BOOL hasval);
-
-/* allowed parse_flags: PF_IN_ACCEPTED */
-static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
-{
-    int opcode, op, scope;
-    JSAtom name0 = JS_ATOM_NULL;
-    JSAtom name;
-
-    if (s->token.val == TOK_YIELD) {
-        BOOL is_star = FALSE, is_async;
-        
-        if (!(s->cur_func->func_kind & JS_FUNC_GENERATOR))
-            return js_parse_error(s, "unexpected 'yield' keyword");
-        if (!s->cur_func->in_function_body)
-            return js_parse_error(s, "yield in default expression");
-        if (next_token(s))
-            return -1;
-        /* XXX: is there a better method to detect 'yield' without
-           parameters ? */
-        if (s->token.val != ';' && s->token.val != ')' &&
-            s->token.val != ']' && s->token.val != '}' &&
-            s->token.val != ',' && s->token.val != ':' && !s->got_lf) {
-            if (s->token.val == '*') {
-                is_star = TRUE;
-                if (next_token(s))
-                    return -1;
-            }
-            if (js_parse_assign_expr2(s, parse_flags))
-                return -1;
-        } else {
-            emit_op(s, OP_undefined);
-        }
-        is_async = (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR);
-
-        if (is_star) {
-            int label_loop, label_return, label_next;
-            int label_return1, label_yield, label_throw, label_throw1;
-            int label_throw2;
-
-            label_loop = new_label(s);
-            label_yield = new_label(s);
-
-            emit_op(s, is_async ? OP_for_await_of_start : OP_for_of_start);
-
-            /* remove the catch offset (XXX: could avoid pushing back
-               undefined) */
-            emit_op(s, OP_drop);
-            emit_op(s, OP_undefined);
-            
-            emit_op(s, OP_undefined); /* initial value */
-            
-            emit_label(s, label_loop);
-            emit_op(s, OP_iterator_next);
-            if (is_async)
-                emit_op(s, OP_await);
-            emit_op(s, OP_iterator_check_object);
-            emit_op(s, OP_get_field2);
-            emit_atom(s, JS_ATOM_done);
-            label_next = emit_goto(s, OP_if_true, -1); /* end of loop */
-            emit_label(s, label_yield);
-            if (is_async) {
-                /* OP_async_yield_star takes the value as parameter */
-                emit_op(s, OP_get_field);
-                emit_atom(s, JS_ATOM_value);
-                emit_op(s, OP_await);
-                emit_op(s, OP_async_yield_star);
-            } else {
-                /* OP_yield_star takes (value, done) as parameter */
-                emit_op(s, OP_yield_star);
-            }
-            emit_op(s, OP_dup);
-            label_return = emit_goto(s, OP_if_true, -1);
-            emit_op(s, OP_drop);
-            emit_goto(s, OP_goto, label_loop);
-            
-            emit_label(s, label_return);
-            emit_op(s, OP_push_i32);
-            emit_u32(s, 2);
-            emit_op(s, OP_strict_eq);
-            label_throw = emit_goto(s, OP_if_true, -1);
-            
-            /* return handling */
-            if (is_async)
-                emit_op(s, OP_await);
-            emit_op(s, OP_iterator_call);
-            emit_u8(s, 0);
-            label_return1 = emit_goto(s, OP_if_true, -1);
-            if (is_async)
-                emit_op(s, OP_await);
-            emit_op(s, OP_iterator_check_object);
-            emit_op(s, OP_get_field2);
-            emit_atom(s, JS_ATOM_done);
-            emit_goto(s, OP_if_false, label_yield);
-
-            emit_op(s, OP_get_field);
-            emit_atom(s, JS_ATOM_value);
-            
-            emit_label(s, label_return1);
-            emit_op(s, OP_nip);
-            emit_op(s, OP_nip);
-            emit_op(s, OP_nip);
-            emit_return(s, TRUE);
-            
-            /* throw handling */
-            emit_label(s, label_throw);
-            emit_op(s, OP_iterator_call);
-            emit_u8(s, 1);
-            label_throw1 = emit_goto(s, OP_if_true, -1);
-            if (is_async)
-                emit_op(s, OP_await);
-            emit_op(s, OP_iterator_check_object);
-            emit_op(s, OP_get_field2);
-            emit_atom(s, JS_ATOM_done);
-            emit_goto(s, OP_if_false, label_yield);
-            emit_goto(s, OP_goto, label_next);
-            /* close the iterator and throw a type error exception */
-            emit_label(s, label_throw1);
-            emit_op(s, OP_iterator_call);
-            emit_u8(s, 2);
-            label_throw2 = emit_goto(s, OP_if_true, -1);
-            if (is_async)
-                emit_op(s, OP_await);
-            emit_label(s, label_throw2);
-
-            emit_op(s, OP_throw_error);
-            emit_atom(s, JS_ATOM_NULL);
-            emit_u8(s, JS_THROW_ERROR_ITERATOR_THROW);
-            
-            emit_label(s, label_next);
-            emit_op(s, OP_get_field);
-            emit_atom(s, JS_ATOM_value);
-            emit_op(s, OP_nip); /* keep the value associated with
-                                   done = true */
-            emit_op(s, OP_nip);
-            emit_op(s, OP_nip);
-        } else {
-            int label_next;
-            
-            if (is_async)
-                emit_op(s, OP_await);
-            emit_op(s, OP_yield);
-            label_next = emit_goto(s, OP_if_false, -1);
-            emit_return(s, TRUE);
-            emit_label(s, label_next);
-        }
-        return 0;
-    }
-    if (s->token.val == TOK_IDENT) {
-        /* name0 is used to check for OP_set_name pattern, not duplicated */
-        name0 = s->token.u.ident.atom;
-    }
-    if (js_parse_cond_expr(s, parse_flags | PF_ARROW_FUNC))
-        return -1;
-
-    op = s->token.val;
-    if (op == '=' || (op >= TOK_MUL_ASSIGN && op <= TOK_POW_ASSIGN)) {
-        int label;
-        if (next_token(s))
-            return -1;
-        if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, (op != '='), op) < 0)
-            return -1;
-
-        if (js_parse_assign_expr2(s, parse_flags)) {
-            JS_FreeAtom(s->ctx, name);
-            return -1;
-        }
-
-        if (op == '=') {
-            if (opcode == OP_get_ref_value && name == name0) {
-                set_object_name(s, name);
-            }
-        } else {
-            static const uint8_t assign_opcodes[] = {
-                OP_mul, OP_div, OP_mod, OP_add, OP_sub,
-                OP_shl, OP_sar, OP_shr, OP_and, OP_xor, OP_or,
-#ifdef CONFIG_BIGNUM
-                OP_pow,
-#endif
-                OP_pow,
-            };
-            op = assign_opcodes[op - TOK_MUL_ASSIGN];
-#ifdef CONFIG_BIGNUM
-            if (s->cur_func->js_mode & JS_MODE_MATH) {
-                if (op == OP_mod)
-                    op = OP_math_mod;
-            }
-#endif
-            emit_op(s, op);
-        }
-        put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP, FALSE);
-    } else if (op >= TOK_LAND_ASSIGN && op <= TOK_DOUBLE_QUESTION_MARK_ASSIGN) {
-        int label, label1, depth_lvalue, label2;
-        
-        if (next_token(s))
-            return -1;
-        if (get_lvalue(s, &opcode, &scope, &name, &label,
-                       &depth_lvalue, TRUE, op) < 0)
-            return -1;
-
-        emit_op(s, OP_dup);
-        if (op == TOK_DOUBLE_QUESTION_MARK_ASSIGN)
-            emit_op(s, OP_is_undefined_or_null);
-        label1 = emit_goto(s, op == TOK_LOR_ASSIGN ? OP_if_true : OP_if_false,
-                           -1);
-        emit_op(s, OP_drop);
-        
-        if (js_parse_assign_expr2(s, parse_flags)) {
-            JS_FreeAtom(s->ctx, name);
-            return -1;
-        }
-
-        if (opcode == OP_get_ref_value && name == name0) {
-            set_object_name(s, name);
-        }
-        
-        switch(depth_lvalue) {
-        case 1:
-            emit_op(s, OP_insert2);
-            break;
-        case 2:
-            emit_op(s, OP_insert3);
-            break;
-        case 3:
-            emit_op(s, OP_insert4);
-            break;
-        default:
-            abort();
-        }
-
-        /* XXX: we disable the OP_put_ref_value optimization by not
-           using put_lvalue() otherwise depth_lvalue is not correct */
-        put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_NOKEEP_DEPTH,
-                   FALSE);
-        label2 = emit_goto(s, OP_goto, -1);
-        
-        emit_label(s, label1);
-
-        /* remove the lvalue stack entries */
-        while (depth_lvalue != 0) {
-            emit_op(s, OP_nip);
-            depth_lvalue--;
-        }
-
-        emit_label(s, label2);
-    }
-    return 0;
-}
-
-static __exception int js_parse_assign_expr(JSParseState *s)
-{
-    return js_parse_assign_expr2(s, PF_IN_ACCEPTED);
-}
-
-/* allowed parse_flags: PF_IN_ACCEPTED */
-static __exception int js_parse_expr2(JSParseState *s, int parse_flags)
-{
-    BOOL comma = FALSE;
-    for(;;) {
-        if (js_parse_assign_expr2(s, parse_flags))
-            return -1;
-        if (comma) {
-            /* prevent get_lvalue from using the last expression
-               as an lvalue. This also prevents the conversion of
-               of get_var to get_ref for method lookup in function
-               call inside `with` statement.
-             */
-            s->cur_func->last_opcode_pos = -1;
-        }
-        if (s->token.val != ',')
-            break;
-        comma = TRUE;
-        if (next_token(s))
-            return -1;
-        emit_op(s, OP_drop);
-    }
-    return 0;
-}
-
-static __exception int js_parse_expr(JSParseState *s)
-{
-    return js_parse_expr2(s, PF_IN_ACCEPTED);
-}
-
-static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
-                             JSAtom label_name,
-                             int label_break, int label_cont,
-                             int drop_count)
-{
-    be->prev = fd->top_break;
-    fd->top_break = be;
-    be->label_name = label_name;
-    be->label_break = label_break;
-    be->label_cont = label_cont;
-    be->drop_count = drop_count;
-    be->label_finally = -1;
-    be->scope_level = fd->scope_level;
-    be->has_iterator = FALSE;
-}
-
-static void pop_break_entry(JSFunctionDef *fd)
-{
-    BlockEnv *be;
-    be = fd->top_break;
-    fd->top_break = be->prev;
-}
-
-static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont)
-{
-    BlockEnv *top;
-    int i, scope_level;
-
-    scope_level = s->cur_func->scope_level;
-    top = s->cur_func->top_break;
-    while (top != NULL) {
-        close_scopes(s, scope_level, top->scope_level);
-        scope_level = top->scope_level;
-        if (is_cont &&
-            top->label_cont != -1 &&
-            (name == JS_ATOM_NULL || top->label_name == name)) {
-            /* continue stays inside the same block */
-            emit_goto(s, OP_goto, top->label_cont);
-            return 0;
-        }
-        if (!is_cont &&
-            top->label_break != -1 &&
-            (name == JS_ATOM_NULL || top->label_name == name)) {
-            emit_goto(s, OP_goto, top->label_break);
-            return 0;
-        }
-        i = 0;
-        if (top->has_iterator) {
-            emit_op(s, OP_iterator_close);
-            i += 3;
-        }
-        for(; i < top->drop_count; i++)
-            emit_op(s, OP_drop);
-        if (top->label_finally != -1) {
-            /* must push dummy value to keep same stack depth */
-            emit_op(s, OP_undefined);
-            emit_goto(s, OP_gosub, top->label_finally);
-            emit_op(s, OP_drop);
-        }
-        top = top->prev;
-    }
-    if (name == JS_ATOM_NULL) {
-        if (is_cont)
-            return js_parse_error(s, "continue must be inside loop");
-        else
-            return js_parse_error(s, "break must be inside loop or switch");
-    } else {
-        return js_parse_error(s, "break/continue label not found");
-    }
-}
-
-/* execute the finally blocks before return */
-static void emit_return(JSParseState *s, BOOL hasval)
-{
-    BlockEnv *top;
-    int drop_count;
-
-    drop_count = 0;
-    top = s->cur_func->top_break;
-    while (top != NULL) {
-        /* XXX: emit the appropriate OP_leave_scope opcodes? Probably not
-           required as all local variables will be closed upon returning
-           from JS_CallInternal, but not in the same order. */
-        if (top->has_iterator) {
-            /* with 'yield', the exact number of OP_drop to emit is
-               unknown, so we use a specific operation to look for
-               the catch offset */
-            if (!hasval) {
-                emit_op(s, OP_undefined);
-                hasval = TRUE;
-            }
-            emit_op(s, OP_iterator_close_return);
-            if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
-                int label_next, label_next2;
-
-                emit_op(s, OP_drop); /* catch offset */
-                emit_op(s, OP_drop); /* next */
-                emit_op(s, OP_get_field2);
-                emit_atom(s, JS_ATOM_return);
-                /* stack: iter_obj return_func */
-                emit_op(s, OP_dup);
-                emit_op(s, OP_is_undefined_or_null);
-                label_next = emit_goto(s, OP_if_true, -1);
-                emit_op(s, OP_call_method);
-                emit_u16(s, 0);
-                emit_op(s, OP_iterator_check_object);
-                emit_op(s, OP_await);
-                label_next2 = emit_goto(s, OP_goto, -1);
-                emit_label(s, label_next);
-                emit_op(s, OP_drop);
-                emit_label(s, label_next2);
-                emit_op(s, OP_drop);
-            } else {
-                emit_op(s, OP_iterator_close);
-            }
-            drop_count = -3;
-        }
-        drop_count += top->drop_count;
-        if (top->label_finally != -1) {
-            while(drop_count) {
-                /* must keep the stack top if hasval */
-                emit_op(s, hasval ? OP_nip : OP_drop);
-                drop_count--;
-            }
-            if (!hasval) {
-                /* must push return value to keep same stack size */
-                emit_op(s, OP_undefined);
-                hasval = TRUE;
-            }
-            emit_goto(s, OP_gosub, top->label_finally);
-        }
-        top = top->prev;
-    }
-    if (s->cur_func->is_derived_class_constructor) {
-        int label_return;
-
-        /* 'this' can be uninitialized, so it may be accessed only if
-           the derived class constructor does not return an object */
-        if (hasval) {
-            emit_op(s, OP_check_ctor_return);
-            label_return = emit_goto(s, OP_if_false, -1);
-            emit_op(s, OP_drop);
-        } else {
-            label_return = -1;
-        }
-
-        /* XXX: if this is not initialized, should throw the
-           ReferenceError in the caller realm */
-        emit_op(s, OP_scope_get_var);
-        emit_atom(s, JS_ATOM_this);
-        emit_u16(s, 0);
-
-        emit_label(s, label_return);
-        emit_op(s, OP_return);
-    } else if (s->cur_func->func_kind != JS_FUNC_NORMAL) {
-        if (!hasval) {
-            emit_op(s, OP_undefined);
-        } else if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
-            emit_op(s, OP_await);
-        }
-        emit_op(s, OP_return_async);
-    } else {
-        emit_op(s, hasval ? OP_return : OP_return_undef);
-    }
-}
-
-#define DECL_MASK_FUNC  (1 << 0) /* allow normal function declaration */
-/* ored with DECL_MASK_FUNC if function declarations are allowed with a label */
-#define DECL_MASK_FUNC_WITH_LABEL (1 << 1)
-#define DECL_MASK_OTHER (1 << 2) /* all other declarations */
-#define DECL_MASK_ALL   (DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL | DECL_MASK_OTHER)
-
-static __exception int js_parse_statement_or_decl(JSParseState *s,
-                                                  int decl_mask);
-
-static __exception int js_parse_statement(JSParseState *s)
-{
-    return js_parse_statement_or_decl(s, 0);
-}
-
-static __exception int js_parse_block(JSParseState *s)
-{
-    if (js_parse_expect(s, '{'))
-        return -1;
-    if (s->token.val != '}') {
-        push_scope(s);
-        for(;;) {
-            if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
-                return -1;
-            if (s->token.val == '}')
-                break;
-        }
-        pop_scope(s);
-    }
-    if (next_token(s))
-        return -1;
-    return 0;
-}
-
-/* allowed parse_flags: PF_IN_ACCEPTED */
-static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
-                                    BOOL export_flag)
-{
-    JSContext *ctx = s->ctx;
-    JSFunctionDef *fd = s->cur_func;
-    JSAtom name = JS_ATOM_NULL;
-
-    for (;;) {
-        if (s->token.val == TOK_IDENT) {
-            if (s->token.u.ident.is_reserved) {
-                return js_parse_error_reserved_identifier(s);
-            }
-            name = JS_DupAtom(ctx, s->token.u.ident.atom);
-            if (name == JS_ATOM_let && (tok == TOK_LET || tok == TOK_CONST)) {
-                js_parse_error(s, "'let' is not a valid lexical identifier");
-                goto var_error;
-            }
-            if (next_token(s))
-                goto var_error;
-            if (js_define_var(s, name, tok))
-                goto var_error;
-            if (export_flag) {
-                if (!add_export_entry(s, s->cur_func->module, name, name,
-                                      JS_EXPORT_TYPE_LOCAL))
-                    goto var_error;
-            }
-
-            if (s->token.val == '=') {
-                if (next_token(s))
-                    goto var_error;
-                if (tok == TOK_VAR) {
-                    /* Must make a reference for proper `with` semantics */
-                    int opcode, scope, label;
-                    JSAtom name1;
-
-                    emit_op(s, OP_scope_get_var);
-                    emit_atom(s, name);
-                    emit_u16(s, fd->scope_level);
-                    if (get_lvalue(s, &opcode, &scope, &name1, &label, NULL, FALSE, '=') < 0)
-                        goto var_error;
-                    if (js_parse_assign_expr2(s, parse_flags)) {
-                        JS_FreeAtom(ctx, name1);
-                        goto var_error;
-                    }
-                    set_object_name(s, name);
-                    put_lvalue(s, opcode, scope, name1, label,
-                               PUT_LVALUE_NOKEEP, FALSE);
-                } else {
-                    if (js_parse_assign_expr2(s, parse_flags))
-                        goto var_error;
-                    set_object_name(s, name);
-                    emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ?
-                        OP_scope_put_var_init : OP_scope_put_var);
-                    emit_atom(s, name);
-                    emit_u16(s, fd->scope_level);
-                }
-            } else {
-                if (tok == TOK_CONST) {
-                    js_parse_error(s, "missing initializer for const variable");
-                    goto var_error;
-                }
-                if (tok == TOK_LET) {
-                    /* initialize lexical variable upon entering its scope */
-                    emit_op(s, OP_undefined);
-                    emit_op(s, OP_scope_put_var_init);
-                    emit_atom(s, name);
-                    emit_u16(s, fd->scope_level);
-                }
-            }
-            JS_FreeAtom(ctx, name);
-        } else {
-            int skip_bits;
-            if ((s->token.val == '[' || s->token.val == '{')
-            &&  js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
-                emit_op(s, OP_undefined);
-                if (js_parse_destructuring_element(s, tok, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
-                    return -1;
-            } else {
-                return js_parse_error(s, "variable name expected");
-            }
-        }
-        if (s->token.val != ',')
-            break;
-        if (next_token(s))
-            return -1;
-    }
-    return 0;
-
- var_error:
-    JS_FreeAtom(ctx, name);
-    return -1;
-}
-
-/* test if the current token is a label. Use simplistic look-ahead scanner */
-static BOOL is_label(JSParseState *s)
-{
-    return (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
-            peek_token(s, FALSE) == ':');
-}
-
-/* test if the current token is a let keyword. Use simplistic look-ahead scanner */
-static int is_let(JSParseState *s, int decl_mask)
-{
-    int res = FALSE;
-
-    if (token_is_pseudo_keyword(s, JS_ATOM_let)) {
-#if 1
-        JSParsePos pos;
-        js_parse_get_pos(s, &pos);
-        for (;;) {
-            if (next_token(s)) {
-                res = -1;
-                break;
-            }
-            if (s->token.val == '[') {
-                /* let [ is a syntax restriction:
-                   it never introduces an ExpressionStatement */
-                res = TRUE;
-                break;
-            }
-            if (s->token.val == '{' ||
-                (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved) ||
-                s->token.val == TOK_LET ||
-                s->token.val == TOK_YIELD ||
-                s->token.val == TOK_AWAIT) {
-                /* Check for possible ASI if not scanning for Declaration */
-                /* XXX: should also check that `{` introduces a BindingPattern,
-                   but Firefox does not and rejects eval("let=1;let\n{if(1)2;}") */
-                if (s->last_line_num == s->token.line_num || (decl_mask & DECL_MASK_OTHER)) {
-                    res = TRUE;
-                    break;
-                }
-                break;
-            }
-            break;
-        }
-        if (js_parse_seek_token(s, &pos)) {
-            res = -1;
-        }
-#else
-        int tok = peek_token(s, TRUE);
-        if (tok == '{' || tok == TOK_IDENT || peek_token(s, FALSE) == '[') {
-            res = TRUE;
-        }
-#endif
-    }
-    return res;
-}
-
-/* XXX: handle IteratorClose when exiting the loop before the
-   enumeration is done */
-static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
-                                          BOOL is_async)
-{
-    JSContext *ctx = s->ctx;
-    JSFunctionDef *fd = s->cur_func;
-    JSAtom var_name;
-    BOOL has_initializer, is_for_of, has_destructuring;
-    int tok, tok1, opcode, scope, block_scope_level;
-    int label_next, label_expr, label_cont, label_body, label_break;
-    int pos_next, pos_expr;
-    BlockEnv break_entry;
-
-    has_initializer = FALSE;
-    has_destructuring = FALSE;
-    is_for_of = FALSE;
-    block_scope_level = fd->scope_level;
-    label_cont = new_label(s);
-    label_body = new_label(s);
-    label_break = new_label(s);
-    label_next = new_label(s);
-
-    /* create scope for the lexical variables declared in the enumeration
-       expressions. XXX: Not completely correct because of weird capturing
-       semantics in `for (i of o) a.push(function(){return i})` */
-    push_scope(s);
-
-    /* local for_in scope starts here so individual elements
-       can be closed in statement. */
-    push_break_entry(s->cur_func, &break_entry,
-                     label_name, label_break, label_cont, 1);
-    break_entry.scope_level = block_scope_level;
-
-    label_expr = emit_goto(s, OP_goto, -1);
-
-    pos_next = s->cur_func->byte_code.size;
-    emit_label(s, label_next);
-
-    tok = s->token.val;
-    switch (is_let(s, DECL_MASK_OTHER)) {
-    case TRUE:
-        tok = TOK_LET;
-        break;
-    case FALSE:
-        break;
-    default:
-        return -1;
-    }
-    if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) {
-        if (next_token(s))
-            return -1;
-
-        if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
-            if (s->token.val == '[' || s->token.val == '{') {
-                if (js_parse_destructuring_element(s, tok, 0, TRUE, -1, FALSE) < 0)
-                    return -1;
-                has_destructuring = TRUE;
-            } else {
-                return js_parse_error(s, "variable name expected");
-            }
-            var_name = JS_ATOM_NULL;
-        } else {
-            var_name = JS_DupAtom(ctx, s->token.u.ident.atom);
-            if (next_token(s)) {
-                JS_FreeAtom(s->ctx, var_name);
-                return -1;
-            }
-            if (js_define_var(s, var_name, tok)) {
-                JS_FreeAtom(s->ctx, var_name);
-                return -1;
-            }
-            emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ?
-                    OP_scope_put_var_init : OP_scope_put_var);
-            emit_atom(s, var_name);
-            emit_u16(s, fd->scope_level);
-        }
-    } else {
-        int skip_bits;
-        if ((s->token.val == '[' || s->token.val == '{')
-        &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == TOK_IN || tok1 == TOK_OF)) {
-            if (js_parse_destructuring_element(s, 0, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
-                return -1;
-        } else {
-            int lvalue_label;
-            if (js_parse_left_hand_side_expr(s))
-                return -1;
-            if (get_lvalue(s, &opcode, &scope, &var_name, &lvalue_label,
-                           NULL, FALSE, TOK_FOR))
-                return -1;
-            put_lvalue(s, opcode, scope, var_name, lvalue_label,
-                       PUT_LVALUE_NOKEEP_BOTTOM, FALSE);
-        }
-        var_name = JS_ATOM_NULL;
-    }
-    emit_goto(s, OP_goto, label_body);
-
-    pos_expr = s->cur_func->byte_code.size;
-    emit_label(s, label_expr);
-    if (s->token.val == '=') {
-        /* XXX: potential scoping issue if inside `with` statement */
-        has_initializer = TRUE;
-        /* parse and evaluate initializer prior to evaluating the
-           object (only used with "for in" with a non lexical variable
-           in non strict mode */
-        if (next_token(s) || js_parse_assign_expr2(s, 0)) {
-            JS_FreeAtom(ctx, var_name);
-            return -1;
-        }
-        if (var_name != JS_ATOM_NULL) {
-            emit_op(s, OP_scope_put_var);
-            emit_atom(s, var_name);
-            emit_u16(s, fd->scope_level);
-        }
-    }
-    JS_FreeAtom(ctx, var_name);
-
-    if (token_is_pseudo_keyword(s, JS_ATOM_of)) {
-        break_entry.has_iterator = is_for_of = TRUE;
-        break_entry.drop_count += 2;
-        if (has_initializer)
-            goto initializer_error;
-    } else if (s->token.val == TOK_IN) {
-        if (is_async)
-            return js_parse_error(s, "'for await' loop should be used with 'of'");
-        if (has_initializer &&
-            (tok != TOK_VAR || (fd->js_mode & JS_MODE_STRICT) ||
-             has_destructuring)) {
-        initializer_error:
-            return js_parse_error(s, "a declaration in the head of a for-%s loop can't have an initializer",
-                                  is_for_of ? "of" : "in");
-        }
-    } else {
-        return js_parse_error(s, "expected 'of' or 'in' in for control expression");
-    }
-    if (next_token(s))
-        return -1;
-    if (is_for_of) {
-        if (js_parse_assign_expr(s))
-            return -1;
-    } else {
-        if (js_parse_expr(s))
-            return -1;
-    }
-    /* close the scope after having evaluated the expression so that
-       the TDZ values are in the closures */
-    close_scopes(s, s->cur_func->scope_level, block_scope_level);
-    if (is_for_of) {
-        if (is_async)
-            emit_op(s, OP_for_await_of_start);
-        else
-            emit_op(s, OP_for_of_start);
-        /* on stack: enum_rec */
-    } else {
-        emit_op(s, OP_for_in_start);
-        /* on stack: enum_obj */
-    }
-    emit_goto(s, OP_goto, label_cont);
-
-    if (js_parse_expect(s, ')'))
-        return -1;
-
-    if (OPTIMIZE) {
-        /* move the `next` code here */
-        DynBuf *bc = &s->cur_func->byte_code;
-        int chunk_size = pos_expr - pos_next;
-        int offset = bc->size - pos_next;
-        int i;
-        dbuf_realloc(bc, bc->size + chunk_size);
-        dbuf_put(bc, bc->buf + pos_next, chunk_size);
-        memset(bc->buf + pos_next, OP_nop, chunk_size);
-        /* `next` part ends with a goto */
-        s->cur_func->last_opcode_pos = bc->size - 5;
-        /* relocate labels */
-        for (i = label_cont; i < s->cur_func->label_count; i++) {
-            LabelSlot *ls = &s->cur_func->label_slots[i];
-            if (ls->pos >= pos_next && ls->pos < pos_expr)
-                ls->pos += offset;
-        }
-    }
-
-    emit_label(s, label_body);
-    if (js_parse_statement(s))
-        return -1;
-
-    close_scopes(s, s->cur_func->scope_level, block_scope_level);
-
-    emit_label(s, label_cont);
-    if (is_for_of) {
-        if (is_async) {
-            /* call the next method */
-            /* stack: iter_obj next catch_offset */
-            emit_op(s, OP_dup3);
-            emit_op(s, OP_drop);
-            emit_op(s, OP_call_method);
-            emit_u16(s, 0);
-            /* get the result of the promise */
-            emit_op(s, OP_await);
-            /* unwrap the value and done values */
-            emit_op(s, OP_iterator_get_value_done);
-        } else {
-            emit_op(s, OP_for_of_next);
-            emit_u8(s, 0);
-        }
-    } else {
-        emit_op(s, OP_for_in_next);
-    }
-    /* on stack: enum_rec / enum_obj value bool */
-    emit_goto(s, OP_if_false, label_next);
-    /* drop the undefined value from for_xx_next */
-    emit_op(s, OP_drop);
-
-    emit_label(s, label_break);
-    if (is_for_of) {
-        /* close and drop enum_rec */
-        emit_op(s, OP_iterator_close);
-    } else {
-        emit_op(s, OP_drop);
-    }
-    pop_break_entry(s->cur_func);
-    pop_scope(s);
-    return 0;
-}
-
-static void set_eval_ret_undefined(JSParseState *s)
-{
-    if (s->cur_func->eval_ret_idx >= 0) {
-        emit_op(s, OP_undefined);
-        emit_op(s, OP_put_loc);
-        emit_u16(s, s->cur_func->eval_ret_idx);
-    }
-}
-
-static __exception int js_parse_statement_or_decl(JSParseState *s,
-                                                  int decl_mask)
-{
-    JSContext *ctx = s->ctx;
-    JSAtom label_name;
-    int tok;
-
-    /* specific label handling */
-    /* XXX: support multiple labels on loop statements */
-    label_name = JS_ATOM_NULL;
-    if (is_label(s)) {
-        BlockEnv *be;
-
-        label_name = JS_DupAtom(ctx, s->token.u.ident.atom);
-
-        for (be = s->cur_func->top_break; be; be = be->prev) {
-            if (be->label_name == label_name) {
-                js_parse_error(s, "duplicate label name");
-                goto fail;
-            }
-        }
-
-        if (next_token(s))
-            goto fail;
-        if (js_parse_expect(s, ':'))
-            goto fail;
-        if (s->token.val != TOK_FOR
-        &&  s->token.val != TOK_DO
-        &&  s->token.val != TOK_WHILE) {
-            /* labelled regular statement */
-            int label_break, mask;
-            BlockEnv break_entry;
-
-            label_break = new_label(s);
-            push_break_entry(s->cur_func, &break_entry,
-                             label_name, label_break, -1, 0);
-            if (!(s->cur_func->js_mode & JS_MODE_STRICT) &&
-                (decl_mask & DECL_MASK_FUNC_WITH_LABEL)) {
-                mask = DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL;
-            } else {
-                mask = 0;
-            }
-            if (js_parse_statement_or_decl(s, mask))
-                goto fail;
-            emit_label(s, label_break);
-            pop_break_entry(s->cur_func);
-            goto done;
-        }
-    }
-
-    switch(tok = s->token.val) {
-    case '{':
-        if (js_parse_block(s))
-            goto fail;
-        break;
-    case TOK_RETURN:
-        if (s->cur_func->is_eval) {
-            js_parse_error(s, "return not in a function");
-            goto fail;
-        }
-        if (next_token(s))
-            goto fail;
-        if (s->token.val != ';' && s->token.val != '}' && !s->got_lf) {
-            if (js_parse_expr(s))
-                goto fail;
-            emit_return(s, TRUE);
-        } else {
-            emit_return(s, FALSE);
-        }
-        if (js_parse_expect_semi(s))
-            goto fail;
-        break;
-    case TOK_THROW:
-        if (next_token(s))
-            goto fail;
-        if (s->got_lf) {
-            js_parse_error(s, "line terminator not allowed after throw");
-            goto fail;
-        }
-        if (js_parse_expr(s))
-            goto fail;
-        emit_op(s, OP_throw);
-        if (js_parse_expect_semi(s))
-            goto fail;
-        break;
-    case TOK_LET:
-    case TOK_CONST:
-    haslet:
-        if (!(decl_mask & DECL_MASK_OTHER)) {
-            js_parse_error(s, "lexical declarations can't appear in single-statement context");
-            goto fail;
-        }
-        /* fall thru */
-    case TOK_VAR:
-        if (next_token(s))
-            goto fail;
-        if (js_parse_var(s, TRUE, tok, FALSE))
-            goto fail;
-        if (js_parse_expect_semi(s))
-            goto fail;
-        break;
-    case TOK_IF:
-        {
-            int label1, label2, mask;
-            if (next_token(s))
-                goto fail;
-            /* create a new scope for `let f;if(1) function f(){}` */
-            push_scope(s);
-            set_eval_ret_undefined(s);
-            if (js_parse_expr_paren(s))
-                goto fail;
-            label1 = emit_goto(s, OP_if_false, -1);
-            if (s->cur_func->js_mode & JS_MODE_STRICT)
-                mask = 0;
-            else
-                mask = DECL_MASK_FUNC; /* Annex B.3.4 */
-
-            if (js_parse_statement_or_decl(s, mask))
-                goto fail;
-
-            if (s->token.val == TOK_ELSE) {
-                label2 = emit_goto(s, OP_goto, -1);
-                if (next_token(s))
-                    goto fail;
-
-                emit_label(s, label1);
-                if (js_parse_statement_or_decl(s, mask))
-                    goto fail;
-
-                label1 = label2;
-            }
-            emit_label(s, label1);
-            pop_scope(s);
-        }
-        break;
-    case TOK_WHILE:
-        {
-            int label_cont, label_break;
-            BlockEnv break_entry;
-
-            label_cont = new_label(s);
-            label_break = new_label(s);
-
-            push_break_entry(s->cur_func, &break_entry,
-                             label_name, label_break, label_cont, 0);
-
-            if (next_token(s))
-                goto fail;
-
-            set_eval_ret_undefined(s);
-
-            emit_label(s, label_cont);
-            if (js_parse_expr_paren(s))
-                goto fail;
-            emit_goto(s, OP_if_false, label_break);
-
-            if (js_parse_statement(s))
-                goto fail;
-            emit_goto(s, OP_goto, label_cont);
-
-            emit_label(s, label_break);
-
-            pop_break_entry(s->cur_func);
-        }
-        break;
-    case TOK_DO:
-        {
-            int label_cont, label_break, label1;
-            BlockEnv break_entry;
-
-            label_cont = new_label(s);
-            label_break = new_label(s);
-            label1 = new_label(s);
-
-            push_break_entry(s->cur_func, &break_entry,
-                             label_name, label_break, label_cont, 0);
-
-            if (next_token(s))
-                goto fail;
-
-            emit_label(s, label1);
-
-            set_eval_ret_undefined(s);
-
-            if (js_parse_statement(s))
-                goto fail;
-
-            emit_label(s, label_cont);
-            if (js_parse_expect(s, TOK_WHILE))
-                goto fail;
-            if (js_parse_expr_paren(s))
-                goto fail;
-            /* Insert semicolon if missing */
-            if (s->token.val == ';') {
-                if (next_token(s))
-                    goto fail;
-            }
-            emit_goto(s, OP_if_true, label1);
-
-            emit_label(s, label_break);
-
-            pop_break_entry(s->cur_func);
-        }
-        break;
-    case TOK_FOR:
-        {
-            int label_cont, label_break, label_body, label_test;
-            int pos_cont, pos_body, block_scope_level;
-            BlockEnv break_entry;
-            int tok, bits;
-            BOOL is_async;
-
-            if (next_token(s))
-                goto fail;
-
-            set_eval_ret_undefined(s);
-            bits = 0;
-            is_async = FALSE;
-            if (s->token.val == '(') {
-                js_parse_skip_parens_token(s, &bits, FALSE);
-            } else if (s->token.val == TOK_AWAIT) {
-                if (!(s->cur_func->func_kind & JS_FUNC_ASYNC)) {
-                    js_parse_error(s, "for await is only valid in asynchronous functions");
-                    goto fail;
-                }
-                is_async = TRUE;
-                if (next_token(s))
-                    goto fail;
-            }
-            if (js_parse_expect(s, '('))
-                goto fail;
-
-            if (!(bits & SKIP_HAS_SEMI)) {
-                /* parse for/in or for/of */
-                if (js_parse_for_in_of(s, label_name, is_async))
-                    goto fail;
-                break;
-            }
-            block_scope_level = s->cur_func->scope_level;
-
-            /* create scope for the lexical variables declared in the initial,
-               test and increment expressions */
-            push_scope(s);
-            /* initial expression */
-            tok = s->token.val;
-            if (tok != ';') {
-                switch (is_let(s, DECL_MASK_OTHER)) {
-                case TRUE:
-                    tok = TOK_LET;
-                    break;
-                case FALSE:
-                    break;
-                default:
-                    goto fail;
-                }
-                if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) {
-                    if (next_token(s))
-                        goto fail;
-                    if (js_parse_var(s, FALSE, tok, FALSE))
-                        goto fail;
-                } else {
-                    if (js_parse_expr2(s, FALSE))
-                        goto fail;
-                    emit_op(s, OP_drop);
-                }
-
-                /* close the closures before the first iteration */
-                close_scopes(s, s->cur_func->scope_level, block_scope_level);
-            }
-            if (js_parse_expect(s, ';'))
-                goto fail;
-
-            label_test = new_label(s);
-            label_cont = new_label(s);
-            label_body = new_label(s);
-            label_break = new_label(s);
-
-            push_break_entry(s->cur_func, &break_entry,
-                             label_name, label_break, label_cont, 0);
-
-            /* test expression */
-            if (s->token.val == ';') {
-                /* no test expression */
-                label_test = label_body;
-            } else {
-                emit_label(s, label_test);
-                if (js_parse_expr(s))
-                    goto fail;
-                emit_goto(s, OP_if_false, label_break);
-            }
-            if (js_parse_expect(s, ';'))
-                goto fail;
-
-            if (s->token.val == ')') {
-                /* no end expression */
-                break_entry.label_cont = label_cont = label_test;
-                pos_cont = 0; /* avoid warning */
-            } else {
-                /* skip the end expression */
-                emit_goto(s, OP_goto, label_body);
-
-                pos_cont = s->cur_func->byte_code.size;
-                emit_label(s, label_cont);
-                if (js_parse_expr(s))
-                    goto fail;
-                emit_op(s, OP_drop);
-                if (label_test != label_body)
-                    emit_goto(s, OP_goto, label_test);
-            }
-            if (js_parse_expect(s, ')'))
-                goto fail;
-
-            pos_body = s->cur_func->byte_code.size;
-            emit_label(s, label_body);
-            if (js_parse_statement(s))
-                goto fail;
-
-            /* close the closures before the next iteration */
-            /* XXX: check continue case */
-            close_scopes(s, s->cur_func->scope_level, block_scope_level);
-
-            if (OPTIMIZE && label_test != label_body && label_cont != label_test) {
-                /* move the increment code here */
-                DynBuf *bc = &s->cur_func->byte_code;
-                int chunk_size = pos_body - pos_cont;
-                int offset = bc->size - pos_cont;
-                int i;
-                dbuf_realloc(bc, bc->size + chunk_size);
-                dbuf_put(bc, bc->buf + pos_cont, chunk_size);
-                memset(bc->buf + pos_cont, OP_nop, chunk_size);
-                /* increment part ends with a goto */
-                s->cur_func->last_opcode_pos = bc->size - 5;
-                /* relocate labels */
-                for (i = label_cont; i < s->cur_func->label_count; i++) {
-                    LabelSlot *ls = &s->cur_func->label_slots[i];
-                    if (ls->pos >= pos_cont && ls->pos < pos_body)
-                        ls->pos += offset;
-                }
-            } else {
-                emit_goto(s, OP_goto, label_cont);
-            }
-
-            emit_label(s, label_break);
-
-            pop_break_entry(s->cur_func);
-            pop_scope(s);
-        }
-        break;
-    case TOK_BREAK:
-    case TOK_CONTINUE:
-        {
-            int is_cont = s->token.val - TOK_BREAK;
-            int label;
-
-            if (next_token(s))
-                goto fail;
-            if (!s->got_lf && s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)
-                label = s->token.u.ident.atom;
-            else
-                label = JS_ATOM_NULL;
-            if (emit_break(s, label, is_cont))
-                goto fail;
-            if (label != JS_ATOM_NULL) {
-                if (next_token(s))
-                    goto fail;
-            }
-            if (js_parse_expect_semi(s))
-                goto fail;
-        }
-        break;
-    case TOK_SWITCH:
-        {
-            int label_case, label_break, label1;
-            int default_label_pos;
-            BlockEnv break_entry;
-
-            if (next_token(s))
-                goto fail;
-
-            set_eval_ret_undefined(s);
-            if (js_parse_expr_paren(s))
-                goto fail;
-
-            push_scope(s);
-            label_break = new_label(s);
-            push_break_entry(s->cur_func, &break_entry,
-                             label_name, label_break, -1, 1);
-
-            if (js_parse_expect(s, '{'))
-                goto fail;
-
-            default_label_pos = -1;
-            label_case = -1;
-            while (s->token.val != '}') {
-                if (s->token.val == TOK_CASE) {
-                    label1 = -1;
-                    if (label_case >= 0) {
-                        /* skip the case if needed */
-                        label1 = emit_goto(s, OP_goto, -1);
-                    }
-                    emit_label(s, label_case);
-                    label_case = -1;
-                    for (;;) {
-                        /* parse a sequence of case clauses */
-                        if (next_token(s))
-                            goto fail;
-                        emit_op(s, OP_dup);
-                        if (js_parse_expr(s))
-                            goto fail;
-                        if (js_parse_expect(s, ':'))
-                            goto fail;
-                        emit_op(s, OP_strict_eq);
-                        if (s->token.val == TOK_CASE) {
-                            label1 = emit_goto(s, OP_if_true, label1);
-                        } else {
-                            label_case = emit_goto(s, OP_if_false, -1);
-                            emit_label(s, label1);
-                            break;
-                        }
-                    }
-                } else if (s->token.val == TOK_DEFAULT) {
-                    if (next_token(s))
-                        goto fail;
-                    if (js_parse_expect(s, ':'))
-                        goto fail;
-                    if (default_label_pos >= 0) {
-                        js_parse_error(s, "duplicate default");
-                        goto fail;
-                    }
-                    if (label_case < 0) {
-                        /* falling thru direct from switch expression */
-                        label_case = emit_goto(s, OP_goto, -1);
-                    }
-                    /* Emit a dummy label opcode. Label will be patched after
-                       the end of the switch body. Do not use emit_label(s, 0)
-                       because it would clobber label 0 address, preventing
-                       proper optimizer operation.
-                     */
-                    emit_op(s, OP_label);
-                    emit_u32(s, 0);
-                    default_label_pos = s->cur_func->byte_code.size - 4;
-                } else {
-                    if (label_case < 0) {
-                        /* falling thru direct from switch expression */
-                        js_parse_error(s, "invalid switch statement");
-                        goto fail;
-                    }
-                    if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
-                        goto fail;
-                }
-            }
-            if (js_parse_expect(s, '}'))
-                goto fail;
-            if (default_label_pos >= 0) {
-                /* Ugly patch for the the `default` label, shameful and risky */
-                put_u32(s->cur_func->byte_code.buf + default_label_pos,
-                        label_case);
-                s->cur_func->label_slots[label_case].pos = default_label_pos + 4;
-            } else {
-                emit_label(s, label_case);
-            }
-            emit_label(s, label_break);
-            emit_op(s, OP_drop); /* drop the switch expression */
-
-            pop_break_entry(s->cur_func);
-            pop_scope(s);
-        }
-        break;
-    case TOK_TRY:
-        {
-            int label_catch, label_catch2, label_finally, label_end;
-            JSAtom name;
-            BlockEnv block_env;
-
-            set_eval_ret_undefined(s);
-            if (next_token(s))
-                goto fail;
-            label_catch = new_label(s);
-            label_catch2 = new_label(s);
-            label_finally = new_label(s);
-            label_end = new_label(s);
-
-            emit_goto(s, OP_catch, label_catch);
-
-            push_break_entry(s->cur_func, &block_env,
-                             JS_ATOM_NULL, -1, -1, 1);
-            block_env.label_finally = label_finally;
-
-            if (js_parse_block(s))
-                goto fail;
-
-            pop_break_entry(s->cur_func);
-
-            if (js_is_live_code(s)) {
-                /* drop the catch offset */
-                emit_op(s, OP_drop);
-                /* must push dummy value to keep same stack size */
-                emit_op(s, OP_undefined);
-                emit_goto(s, OP_gosub, label_finally);
-                emit_op(s, OP_drop);
-
-                emit_goto(s, OP_goto, label_end);
-            }
-
-            if (s->token.val == TOK_CATCH) {
-                if (next_token(s))
-                    goto fail;
-
-                push_scope(s);  /* catch variable */
-                emit_label(s, label_catch);
-
-                if (s->token.val == '{') {
-                    /* support optional-catch-binding feature */
-                    emit_op(s, OP_drop);    /* pop the exception object */
-                } else {
-                    if (js_parse_expect(s, '('))
-                        goto fail;
-                    if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
-                        if (s->token.val == '[' || s->token.val == '{') {
-                            /* XXX: TOK_LET is not completely correct */
-                            if (js_parse_destructuring_element(s, TOK_LET, 0, TRUE, -1, TRUE) < 0)
-                                goto fail;
-                        } else {
-                            js_parse_error(s, "identifier expected");
-                            goto fail;
-                        }
-                    } else {
-                        name = JS_DupAtom(ctx, s->token.u.ident.atom);
-                        if (next_token(s)
-                        ||  js_define_var(s, name, TOK_CATCH) < 0) {
-                            JS_FreeAtom(ctx, name);
-                            goto fail;
-                        }
-                        /* store the exception value in the catch variable */
-                        emit_op(s, OP_scope_put_var);
-                        emit_u32(s, name);
-                        emit_u16(s, s->cur_func->scope_level);
-                    }
-                    if (js_parse_expect(s, ')'))
-                        goto fail;
-                }
-                /* XXX: should keep the address to nop it out if there is no finally block */
-                emit_goto(s, OP_catch, label_catch2);
-
-                push_scope(s);  /* catch block */
-                push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL,
-                                 -1, -1, 1);
-                block_env.label_finally = label_finally;
-
-                if (js_parse_block(s))
-                    goto fail;
-
-                pop_break_entry(s->cur_func);
-                pop_scope(s);  /* catch block */
-                pop_scope(s);  /* catch variable */
-
-                if (js_is_live_code(s)) {
-                    /* drop the catch2 offset */
-                    emit_op(s, OP_drop);
-                    /* XXX: should keep the address to nop it out if there is no finally block */
-                    /* must push dummy value to keep same stack size */
-                    emit_op(s, OP_undefined);
-                    emit_goto(s, OP_gosub, label_finally);
-                    emit_op(s, OP_drop);
-                    emit_goto(s, OP_goto, label_end);
-                }
-                /* catch exceptions thrown in the catch block to execute the
-                 * finally clause and rethrow the exception */
-                emit_label(s, label_catch2);
-                /* catch value is at TOS, no need to push undefined */
-                emit_goto(s, OP_gosub, label_finally);
-                emit_op(s, OP_throw);
-
-            } else if (s->token.val == TOK_FINALLY) {
-                /* finally without catch : execute the finally clause
-                 * and rethrow the exception */
-                emit_label(s, label_catch);
-                /* catch value is at TOS, no need to push undefined */
-                emit_goto(s, OP_gosub, label_finally);
-                emit_op(s, OP_throw);
-            } else {
-                js_parse_error(s, "expecting catch or finally");
-                goto fail;
-            }
-            emit_label(s, label_finally);
-            if (s->token.val == TOK_FINALLY) {
-                int saved_eval_ret_idx = 0; /* avoid warning */
-                
-                if (next_token(s))
-                    goto fail;
-                /* on the stack: ret_value gosub_ret_value */
-                push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL,
-                                 -1, -1, 2);
-
-                if (s->cur_func->eval_ret_idx >= 0) {
-                    /* 'finally' updates eval_ret only if not a normal
-                       termination */
-                    saved_eval_ret_idx =
-                        add_var(s->ctx, s->cur_func, JS_ATOM__ret_);
-                    if (saved_eval_ret_idx < 0)
-                        goto fail;
-                    emit_op(s, OP_get_loc);
-                    emit_u16(s, s->cur_func->eval_ret_idx);
-                    emit_op(s, OP_put_loc);
-                    emit_u16(s, saved_eval_ret_idx);
-                    set_eval_ret_undefined(s);
-                }
-                
-                if (js_parse_block(s))
-                    goto fail;
-
-                if (s->cur_func->eval_ret_idx >= 0) {
-                    emit_op(s, OP_get_loc);
-                    emit_u16(s, saved_eval_ret_idx);
-                    emit_op(s, OP_put_loc);
-                    emit_u16(s, s->cur_func->eval_ret_idx);
-                }
-                pop_break_entry(s->cur_func);
-            }
-            emit_op(s, OP_ret);
-            emit_label(s, label_end);
-        }
-        break;
-    case ';':
-        /* empty statement */
-        if (next_token(s))
-            goto fail;
-        break;
-    case TOK_WITH:
-        if (s->cur_func->js_mode & JS_MODE_STRICT) {
-            js_parse_error(s, "invalid keyword: with");
-            goto fail;
-        } else {
-            int with_idx;
-
-            if (next_token(s))
-                goto fail;
-
-            if (js_parse_expr_paren(s))
-                goto fail;
-
-            push_scope(s);
-            with_idx = define_var(s, s->cur_func, JS_ATOM__with_,
-                                  JS_VAR_DEF_WITH);
-            if (with_idx < 0)
-                goto fail;
-            emit_op(s, OP_to_object);
-            emit_op(s, OP_put_loc);
-            emit_u16(s, with_idx);
-
-            set_eval_ret_undefined(s);
-            if (js_parse_statement(s))
-                goto fail;
-
-            /* Popping scope drops lexical context for the with object variable */
-            pop_scope(s);
-        }
-        break;
-    case TOK_FUNCTION:
-        /* ES6 Annex B.3.2 and B.3.3 semantics */
-        if (!(decl_mask & DECL_MASK_FUNC))
-            goto func_decl_error;
-        if (!(decl_mask & DECL_MASK_OTHER) && peek_token(s, FALSE) == '*')
-            goto func_decl_error;
-        goto parse_func_var;
-    case TOK_IDENT:
-        if (s->token.u.ident.is_reserved) {
-            js_parse_error_reserved_identifier(s);
-            goto fail;
-        }
-        /* Determine if `let` introduces a Declaration or an ExpressionStatement */
-        switch (is_let(s, decl_mask)) {
-        case TRUE:
-            tok = TOK_LET;
-            goto haslet;
-        case FALSE:
-            break;
-        default:
-            goto fail;
-        }
-        if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
-            peek_token(s, TRUE) == TOK_FUNCTION) {
-            if (!(decl_mask & DECL_MASK_OTHER)) {
-            func_decl_error:
-                js_parse_error(s, "function declarations can't appear in single-statement context");
-                goto fail;
-            }
-        parse_func_var:
-            if (js_parse_function_decl(s, JS_PARSE_FUNC_VAR,
-                                       JS_FUNC_NORMAL, JS_ATOM_NULL,
-                                       s->token.ptr, s->token.line_num))
-                goto fail;
-            break;
-        }
-        goto hasexpr;
-
-    case TOK_CLASS:
-        if (!(decl_mask & DECL_MASK_OTHER)) {
-            js_parse_error(s, "class declarations can't appear in single-statement context");
-            goto fail;
-        }
-        if (js_parse_class(s, FALSE, JS_PARSE_EXPORT_NONE))
-            return -1;
-        break;
-
-    case TOK_DEBUGGER:
-        /* currently no debugger, so just skip the keyword */
-        if (next_token(s))
-            goto fail;
-        if (js_parse_expect_semi(s))
-            goto fail;
-        break;
-        
-    case TOK_ENUM:
-    case TOK_EXPORT:
-    case TOK_EXTENDS:
-        js_unsupported_keyword(s, s->token.u.ident.atom);
-        goto fail;
-
-    default:
-    hasexpr:
-        if (js_parse_expr(s))
-            goto fail;
-        if (s->cur_func->eval_ret_idx >= 0) {
-            /* store the expression value so that it can be returned
-               by eval() */
-            emit_op(s, OP_put_loc);
-            emit_u16(s, s->cur_func->eval_ret_idx);
-        } else {
-            emit_op(s, OP_drop); /* drop the result */
-        }
-        if (js_parse_expect_semi(s))
-            goto fail;
-        break;
-    }
-done:
-    JS_FreeAtom(ctx, label_name);
-    return 0;
-fail:
-    JS_FreeAtom(ctx, label_name);
-    return -1;
-}
-
-/* 'name' is freed */
-static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name)
-{
-    JSModuleDef *m;
-    m = js_mallocz(ctx, sizeof(*m));
-    if (!m) {
-        JS_FreeAtom(ctx, name);
-        return NULL;
-    }
-    m->header.ref_count = 1;
-    m->module_name = name;
-    m->module_ns = JS_UNDEFINED;
-    m->func_obj = JS_UNDEFINED;
-    m->eval_exception = JS_UNDEFINED;
-    m->meta_obj = JS_UNDEFINED;
-    list_add_tail(&m->link, &ctx->loaded_modules);
-    return m;
-}
-
-static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
-                               JS_MarkFunc *mark_func)
-{
-    int i;
-
-    for(i = 0; i < m->export_entries_count; i++) {
-        JSExportEntry *me = &m->export_entries[i];
-        if (me->export_type == JS_EXPORT_TYPE_LOCAL &&
-            me->u.local.var_ref) {
-            mark_func(rt, &me->u.local.var_ref->header);
-        }
-    }
-
-    JS_MarkValue(rt, m->module_ns, mark_func);
-    JS_MarkValue(rt, m->func_obj, mark_func);
-    JS_MarkValue(rt, m->eval_exception, mark_func);
-    JS_MarkValue(rt, m->meta_obj, mark_func);
-}
-
-static void js_free_module_def(JSContext *ctx, JSModuleDef *m)
-{
-    int i;
-
-    JS_FreeAtom(ctx, m->module_name);
-
-    for(i = 0; i < m->req_module_entries_count; i++) {
-        JSReqModuleEntry *rme = &m->req_module_entries[i];
-        JS_FreeAtom(ctx, rme->module_name);
-    }
-    js_free(ctx, m->req_module_entries);
-
-    for(i = 0; i < m->export_entries_count; i++) {
-        JSExportEntry *me = &m->export_entries[i];
-        if (me->export_type == JS_EXPORT_TYPE_LOCAL)
-            free_var_ref(ctx->rt, me->u.local.var_ref);
-        JS_FreeAtom(ctx, me->export_name);
-        JS_FreeAtom(ctx, me->local_name);
-    }
-    js_free(ctx, m->export_entries);
-
-    js_free(ctx, m->star_export_entries);
-
-    for(i = 0; i < m->import_entries_count; i++) {
-        JSImportEntry *mi = &m->import_entries[i];
-        JS_FreeAtom(ctx, mi->import_name);
-    }
-    js_free(ctx, m->import_entries);
-
-    JS_FreeValue(ctx, m->module_ns);
-    JS_FreeValue(ctx, m->func_obj);
-    JS_FreeValue(ctx, m->eval_exception);
-    JS_FreeValue(ctx, m->meta_obj);
-    list_del(&m->link);
-    js_free(ctx, m);
-}
-
-static int add_req_module_entry(JSContext *ctx, JSModuleDef *m,
-                                JSAtom module_name)
-{
-    JSReqModuleEntry *rme;
-    int i;
-
-    /* no need to add the module request if it is already present */
-    for(i = 0; i < m->req_module_entries_count; i++) {
-        rme = &m->req_module_entries[i];
-        if (rme->module_name == module_name)
-            return i;
-    }
-
-    if (js_resize_array(ctx, (void **)&m->req_module_entries,
-                        sizeof(JSReqModuleEntry),
-                        &m->req_module_entries_size,
-                        m->req_module_entries_count + 1))
-        return -1;
-    rme = &m->req_module_entries[m->req_module_entries_count++];
-    rme->module_name = JS_DupAtom(ctx, module_name);
-    rme->module = NULL;
-    return i;
-}
-
-static JSExportEntry *find_export_entry(JSContext *ctx, JSModuleDef *m,
-                                        JSAtom export_name)
-{
-    JSExportEntry *me;
-    int i;
-    for(i = 0; i < m->export_entries_count; i++) {
-        me = &m->export_entries[i];
-        if (me->export_name == export_name)
-            return me;
-    }
-    return NULL;
-}
-
-static JSExportEntry *add_export_entry2(JSContext *ctx,
-                                        JSParseState *s, JSModuleDef *m,
-                                       JSAtom local_name, JSAtom export_name,
-                                       JSExportTypeEnum export_type)
-{
-    JSExportEntry *me;
-
-    if (find_export_entry(ctx, m, export_name)) {
-        char buf1[ATOM_GET_STR_BUF_SIZE];
-        if (s) {
-            js_parse_error(s, "duplicate exported name '%s'",
-                           JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name));
-        } else {
-            JS_ThrowSyntaxErrorAtom(ctx, "duplicate exported name '%s'", export_name);
-        }
-        return NULL;
-    }
-
-    if (js_resize_array(ctx, (void **)&m->export_entries,
-                        sizeof(JSExportEntry),
-                        &m->export_entries_size,
-                        m->export_entries_count + 1))
-        return NULL;
-    me = &m->export_entries[m->export_entries_count++];
-    memset(me, 0, sizeof(*me));
-    me->local_name = JS_DupAtom(ctx, local_name);
-    me->export_name = JS_DupAtom(ctx, export_name);
-    me->export_type = export_type;
-    return me;
-}
-
-static JSExportEntry *add_export_entry(JSParseState *s, JSModuleDef *m,
-                                       JSAtom local_name, JSAtom export_name,
-                                       JSExportTypeEnum export_type)
-{
-    return add_export_entry2(s->ctx, s, m, local_name, export_name,
-                             export_type);
-}
-
-static int add_star_export_entry(JSContext *ctx, JSModuleDef *m,
-                                 int req_module_idx)
-{
-    JSStarExportEntry *se;
-
-    if (js_resize_array(ctx, (void **)&m->star_export_entries,
-                        sizeof(JSStarExportEntry),
-                        &m->star_export_entries_size,
-                        m->star_export_entries_count + 1))
-        return -1;
-    se = &m->star_export_entries[m->star_export_entries_count++];
-    se->req_module_idx = req_module_idx;
-    return 0;
-}
-
-/* create a C module */
-JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str,
-                           JSModuleInitFunc *func)
-{
-    JSModuleDef *m;
-    JSAtom name;
-    name = JS_NewAtom(ctx, name_str);
-    if (name == JS_ATOM_NULL)
-        return NULL;
-    m = js_new_module_def(ctx, name);
-    m->init_func = func;
-    return m;
-}
-
-int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name)
-{
-    JSExportEntry *me;
-    JSAtom name;
-    name = JS_NewAtom(ctx, export_name);
-    if (name == JS_ATOM_NULL)
-        return -1;
-    me = add_export_entry2(ctx, NULL, m, JS_ATOM_NULL, name,
-                           JS_EXPORT_TYPE_LOCAL);
-    JS_FreeAtom(ctx, name);
-    if (!me)
-        return -1;
-    else
-        return 0;
-}
-
-int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name,
-                       JSValue val)
-{
-    JSExportEntry *me;
-    JSAtom name;
-    name = JS_NewAtom(ctx, export_name);
-    if (name == JS_ATOM_NULL)
-        goto fail;
-    me = find_export_entry(ctx, m, name);
-    JS_FreeAtom(ctx, name);
-    if (!me)
-        goto fail;
-    set_value(ctx, me->u.local.var_ref->pvalue, val);
-    return 0;
- fail:
-    JS_FreeValue(ctx, val);
-    return -1;
-}
-
-void JS_SetModuleLoaderFunc(JSRuntime *rt,
-                            JSModuleNormalizeFunc *module_normalize,
-                            JSModuleLoaderFunc *module_loader, void *opaque)
-{
-    rt->module_normalize_func = module_normalize;
-    rt->module_loader_func = module_loader;
-    rt->module_loader_opaque = opaque;
-}
-
-/* default module filename normalizer */
-static char *js_default_module_normalize_name(JSContext *ctx,
-                                              const char *base_name,
-                                              const char *name)
-{
-    char *filename, *p;
-    const char *r;
-    int len;
-
-    if (name[0] != '.') {
-        /* if no initial dot, the module name is not modified */
-        return js_strdup(ctx, name);
-    }
-
-    p = strrchr(base_name, '/');
-    if (p)
-        len = p - base_name;
-    else
-        len = 0;
-
-    filename = js_malloc(ctx, len + strlen(name) + 1 + 1);
-    if (!filename)
-        return NULL;
-    memcpy(filename, base_name, len);
-    filename[len] = '\0';
-
-    /* we only normalize the leading '..' or '.' */
-    r = name;
-    for(;;) {
-        if (r[0] == '.' && r[1] == '/') {
-            r += 2;
-        } else if (r[0] == '.' && r[1] == '.' && r[2] == '/') {
-            /* remove the last path element of filename, except if "."
-               or ".." */
-            if (filename[0] == '\0')
-                break;
-            p = strrchr(filename, '/');
-            if (!p)
-                p = filename;
-            else
-                p++;
-            if (!strcmp(p, ".") || !strcmp(p, ".."))
-                break;
-            if (p > filename)
-                p--;
-            *p = '\0';
-            r += 3;
-        } else {
-            break;
-        }
-    }
-    if (filename[0] != '\0')
-        strcat(filename, "/");
-    strcat(filename, r);
-    //    printf("normalize: %s %s -> %s\n", base_name, name, filename);
-    return filename;
-}
-
-static JSModuleDef *js_find_loaded_module(JSContext *ctx, JSAtom name)
-{
-    struct list_head *el;
-    JSModuleDef *m;
-    
-    /* first look at the loaded modules */
-    list_for_each(el, &ctx->loaded_modules) {
-        m = list_entry(el, JSModuleDef, link);
-        if (m->module_name == name)
-            return m;
-    }
-    return NULL;
-}
-
-/* return NULL in case of exception (e.g. module could not be loaded) */
-static JSModuleDef *js_host_resolve_imported_module(JSContext *ctx,
-                                                    const char *base_cname,
-                                                    const char *cname1)
-{
-    JSRuntime *rt = ctx->rt;
-    JSModuleDef *m;
-    char *cname;
-    JSAtom module_name;
-
-    if (!rt->module_normalize_func) {
-        cname = js_default_module_normalize_name(ctx, base_cname, cname1);
-    } else {
-        cname = rt->module_normalize_func(ctx, base_cname, cname1,
-                                          rt->module_loader_opaque);
-    }
-    if (!cname)
-        return NULL;
-
-    module_name = JS_NewAtom(ctx, cname);
-    if (module_name == JS_ATOM_NULL) {
-        js_free(ctx, cname);
-        return NULL;
-    }
-
-    /* first look at the loaded modules */
-    m = js_find_loaded_module(ctx, module_name);
-    if (m) {
-        js_free(ctx, cname);
-        JS_FreeAtom(ctx, module_name);
-        return m;
-    }
-
-    JS_FreeAtom(ctx, module_name);
-
-    /* load the module */
-    if (!rt->module_loader_func) {
-        /* XXX: use a syntax error ? */
-        JS_ThrowReferenceError(ctx, "could not load module '%s'",
-                               cname);
-        js_free(ctx, cname);
-        return NULL;
-    }
-
-    m = rt->module_loader_func(ctx, cname, rt->module_loader_opaque);
-    js_free(ctx, cname);
-    return m;
-}
-
-static JSModuleDef *js_host_resolve_imported_module_atom(JSContext *ctx,
-                                                    JSAtom base_module_name,
-                                                    JSAtom module_name1)
-{
-    const char *base_cname, *cname;
-    JSModuleDef *m;
-    
-    base_cname = JS_AtomToCString(ctx, base_module_name);
-    if (!base_cname)
-        return NULL;
-    cname = JS_AtomToCString(ctx, module_name1);
-    if (!cname) {
-        JS_FreeCString(ctx, base_cname);
-        return NULL;
-    }
-    m = js_host_resolve_imported_module(ctx, base_cname, cname);
-    JS_FreeCString(ctx, base_cname);
-    JS_FreeCString(ctx, cname);
-    return m;
-}
-
-typedef struct JSResolveEntry {
-    JSModuleDef *module;
-    JSAtom name;
-} JSResolveEntry;
-
-typedef struct JSResolveState {
-    JSResolveEntry *array;
-    int size;
-    int count;
-} JSResolveState;
-
-static int find_resolve_entry(JSResolveState *s,
-                              JSModuleDef *m, JSAtom name)
-{
-    int i;
-    for(i = 0; i < s->count; i++) {
-        JSResolveEntry *re = &s->array[i];
-        if (re->module == m && re->name == name)
-            return i;
-    }
-    return -1;
-}
-
-static int add_resolve_entry(JSContext *ctx, JSResolveState *s,
-                             JSModuleDef *m, JSAtom name)
-{
-    JSResolveEntry *re;
-
-    if (js_resize_array(ctx, (void **)&s->array,
-                        sizeof(JSResolveEntry),
-                        &s->size, s->count + 1))
-        return -1;
-    re = &s->array[s->count++];
-    re->module = m;
-    re->name = JS_DupAtom(ctx, name);
-    return 0;
-}
-
-typedef enum JSResolveResultEnum {
-    JS_RESOLVE_RES_EXCEPTION = -1, /* memory alloc error */
-    JS_RESOLVE_RES_FOUND = 0,
-    JS_RESOLVE_RES_NOT_FOUND,
-    JS_RESOLVE_RES_CIRCULAR,
-    JS_RESOLVE_RES_AMBIGUOUS,
-} JSResolveResultEnum;
-
-static JSResolveResultEnum js_resolve_export1(JSContext *ctx,
-                                              JSModuleDef **pmodule,
-                                              JSExportEntry **pme,
-                                              JSModuleDef *m,
-                                              JSAtom export_name,
-                                              JSResolveState *s)
-{
-    JSExportEntry *me;
-
-    *pmodule = NULL;
-    *pme = NULL;
-    if (find_resolve_entry(s, m, export_name) >= 0)
-        return JS_RESOLVE_RES_CIRCULAR;
-    if (add_resolve_entry(ctx, s, m, export_name) < 0)
-        return JS_RESOLVE_RES_EXCEPTION;
-    me = find_export_entry(ctx, m, export_name);
-    if (me) {
-        if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
-            /* local export */
-            *pmodule = m;
-            *pme = me;
-            return JS_RESOLVE_RES_FOUND;
-        } else {
-            /* indirect export */
-            JSModuleDef *m1;
-            m1 = m->req_module_entries[me->u.req_module_idx].module;
-            if (me->local_name == JS_ATOM__star_) {
-                /* export ns from */
-                *pmodule = m;
-                *pme = me;
-                return JS_RESOLVE_RES_FOUND;
-            } else {
-                return js_resolve_export1(ctx, pmodule, pme, m1,
-                                          me->local_name, s);
-            }
-        }
-    } else {
-        if (export_name != JS_ATOM_default) {
-            /* not found in direct or indirect exports: try star exports */
-            int i;
-
-            for(i = 0; i < m->star_export_entries_count; i++) {
-                JSStarExportEntry *se = &m->star_export_entries[i];
-                JSModuleDef *m1, *res_m;
-                JSExportEntry *res_me;
-                JSResolveResultEnum ret;
-
-                m1 = m->req_module_entries[se->req_module_idx].module;
-                ret = js_resolve_export1(ctx, &res_m, &res_me, m1,
-                                         export_name, s);
-                if (ret == JS_RESOLVE_RES_AMBIGUOUS ||
-                    ret == JS_RESOLVE_RES_EXCEPTION) {
-                    return ret;
-                } else if (ret == JS_RESOLVE_RES_FOUND) {
-                    if (*pme != NULL) {
-                        if (*pmodule != res_m ||
-                            res_me->local_name != (*pme)->local_name) {
-                            *pmodule = NULL;
-                            *pme = NULL;
-                            return JS_RESOLVE_RES_AMBIGUOUS;
-                        }
-                    } else {
-                        *pmodule = res_m;
-                        *pme = res_me;
-                    }
-                }
-            }
-            if (*pme != NULL)
-                return JS_RESOLVE_RES_FOUND;
-        }
-        return JS_RESOLVE_RES_NOT_FOUND;
-    }
-}
-
-/* If the return value is JS_RESOLVE_RES_FOUND, return the module
-  (*pmodule) and the corresponding local export entry
-  (*pme). Otherwise return (NULL, NULL) */
-static JSResolveResultEnum js_resolve_export(JSContext *ctx,
-                                             JSModuleDef **pmodule,
-                                             JSExportEntry **pme,
-                                             JSModuleDef *m,
-                                             JSAtom export_name)
-{
-    JSResolveState ss, *s = &ss;
-    int i;
-    JSResolveResultEnum ret;
-
-    s->array = NULL;
-    s->size = 0;
-    s->count = 0;
-
-    ret = js_resolve_export1(ctx, pmodule, pme, m, export_name, s);
-
-    for(i = 0; i < s->count; i++)
-        JS_FreeAtom(ctx, s->array[i].name);
-    js_free(ctx, s->array);
-
-    return ret;
-}
-
-static void js_resolve_export_throw_error(JSContext *ctx,
-                                          JSResolveResultEnum res,
-                                          JSModuleDef *m, JSAtom export_name)
-{
-    char buf1[ATOM_GET_STR_BUF_SIZE];
-    char buf2[ATOM_GET_STR_BUF_SIZE];
-    switch(res) {
-    case JS_RESOLVE_RES_EXCEPTION:
-        break;
-    default:
-    case JS_RESOLVE_RES_NOT_FOUND:
-        JS_ThrowSyntaxError(ctx, "Could not find export '%s' in module '%s'",
-                            JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
-                            JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
-        break;
-    case JS_RESOLVE_RES_CIRCULAR:
-        JS_ThrowSyntaxError(ctx, "circular reference when looking for export '%s' in module '%s'",
-                            JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
-                            JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
-        break;
-    case JS_RESOLVE_RES_AMBIGUOUS:
-        JS_ThrowSyntaxError(ctx, "export '%s' in module '%s' is ambiguous",
-                            JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
-                            JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
-        break;
-    }
-}
-
-
-typedef enum {
-    EXPORTED_NAME_AMBIGUOUS,
-    EXPORTED_NAME_NORMAL,
-    EXPORTED_NAME_NS,
-} ExportedNameEntryEnum;
-
-typedef struct ExportedNameEntry {
-    JSAtom export_name;
-    ExportedNameEntryEnum export_type;
-    union {
-        JSExportEntry *me; /* using when the list is built */
-        JSVarRef *var_ref; /* EXPORTED_NAME_NORMAL */
-        JSModuleDef *module; /* for EXPORTED_NAME_NS */
-    } u;
-} ExportedNameEntry;
-
-typedef struct GetExportNamesState {
-    JSModuleDef **modules;
-    int modules_size;
-    int modules_count;
-
-    ExportedNameEntry *exported_names;
-    int exported_names_size;
-    int exported_names_count;
-} GetExportNamesState;
-
-static int find_exported_name(GetExportNamesState *s, JSAtom name)
-{
-    int i;
-    for(i = 0; i < s->exported_names_count; i++) {
-        if (s->exported_names[i].export_name == name)
-            return i;
-    }
-    return -1;
-}
-
-static __exception int get_exported_names(JSContext *ctx,
-                                          GetExportNamesState *s,
-                                          JSModuleDef *m, BOOL from_star)
-{
-    ExportedNameEntry *en;
-    int i, j;
-
-    /* check circular reference */
-    for(i = 0; i < s->modules_count; i++) {
-        if (s->modules[i] == m)
-            return 0;
-    }
-    if (js_resize_array(ctx, (void **)&s->modules, sizeof(s->modules[0]),
-                        &s->modules_size, s->modules_count + 1))
-        return -1;
-    s->modules[s->modules_count++] = m;
-
-    for(i = 0; i < m->export_entries_count; i++) {
-        JSExportEntry *me = &m->export_entries[i];
-        if (from_star && me->export_name == JS_ATOM_default)
-            continue;
-        j = find_exported_name(s, me->export_name);
-        if (j < 0) {
-            if (js_resize_array(ctx, (void **)&s->exported_names, sizeof(s->exported_names[0]),
-                                &s->exported_names_size,
-                                s->exported_names_count + 1))
-                return -1;
-            en = &s->exported_names[s->exported_names_count++];
-            en->export_name = me->export_name;
-            /* avoid a second lookup for simple module exports */
-            if (from_star || me->export_type != JS_EXPORT_TYPE_LOCAL)
-                en->u.me = NULL;
-            else
-                en->u.me = me;
-        } else {
-            en = &s->exported_names[j];
-            en->u.me = NULL;
-        }
-    }
-    for(i = 0; i < m->star_export_entries_count; i++) {
-        JSStarExportEntry *se = &m->star_export_entries[i];
-        JSModuleDef *m1;
-        m1 = m->req_module_entries[se->req_module_idx].module;
-        if (get_exported_names(ctx, s, m1, TRUE))
-            return -1;
-    }
-    return 0;
-}
-
-/* Unfortunately, the spec gives a different behavior from GetOwnProperty ! */
-static int js_module_ns_has(JSContext *ctx, JSValueConst obj, JSAtom atom)
-{
-    return (find_own_property1(JS_VALUE_GET_OBJ(obj), atom) != NULL);
-}
-
-static const JSClassExoticMethods js_module_ns_exotic_methods = {
-    .has_property = js_module_ns_has,
-};
-
-static int exported_names_cmp(const void *p1, const void *p2, void *opaque)
-{
-    JSContext *ctx = opaque;
-    const ExportedNameEntry *me1 = p1;
-    const ExportedNameEntry *me2 = p2;
-    JSValue str1, str2;
-    int ret;
-
-    /* XXX: should avoid allocation memory in atom comparison */
-    str1 = JS_AtomToString(ctx, me1->export_name);
-    str2 = JS_AtomToString(ctx, me2->export_name);
-    if (JS_IsException(str1) || JS_IsException(str2)) {
-        /* XXX: raise an error ? */
-        ret = 0;
-    } else {
-        ret = js_string_compare(ctx, JS_VALUE_GET_STRING(str1),
-                                JS_VALUE_GET_STRING(str2));
-    }
-    JS_FreeValue(ctx, str1);
-    JS_FreeValue(ctx, str2);
-    return ret;
-}
-
-static JSValue js_get_module_ns(JSContext *ctx, JSModuleDef *m);
-
-static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
-                                     void *opaque)
-{
-    JSModuleDef *m = opaque;
-    return js_get_module_ns(ctx, m);
-}
-
-static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m)
-{
-    JSValue obj;
-    JSObject *p;
-    GetExportNamesState s_s, *s = &s_s;
-    int i, ret;
-    JSProperty *pr;
-
-    obj = JS_NewObjectClass(ctx, JS_CLASS_MODULE_NS);
-    if (JS_IsException(obj))
-        return obj;
-    p = JS_VALUE_GET_OBJ(obj);
-
-    memset(s, 0, sizeof(*s));
-    ret = get_exported_names(ctx, s, m, FALSE);
-    js_free(ctx, s->modules);
-    if (ret)
-        goto fail;
-
-    /* Resolve the exported names. The ambiguous exports are removed */
-    for(i = 0; i < s->exported_names_count; i++) {
-        ExportedNameEntry *en = &s->exported_names[i];
-        JSResolveResultEnum res;
-        JSExportEntry *res_me;
-        JSModuleDef *res_m;
-
-        if (en->u.me) {
-            res_me = en->u.me; /* fast case: no resolution needed */
-            res_m = m;
-            res = JS_RESOLVE_RES_FOUND;
-        } else {
-            res = js_resolve_export(ctx, &res_m, &res_me, m,
-                                    en->export_name);
-        }
-        if (res != JS_RESOLVE_RES_FOUND) {
-            if (res != JS_RESOLVE_RES_AMBIGUOUS) {
-                js_resolve_export_throw_error(ctx, res, m, en->export_name);
-                goto fail;
-            }
-            en->export_type = EXPORTED_NAME_AMBIGUOUS;
-        } else {
-            if (res_me->local_name == JS_ATOM__star_) {
-                en->export_type = EXPORTED_NAME_NS;
-                en->u.module = res_m->req_module_entries[res_me->u.req_module_idx].module;
-            } else {
-                en->export_type = EXPORTED_NAME_NORMAL;
-                if (res_me->u.local.var_ref) {
-                    en->u.var_ref = res_me->u.local.var_ref;
-                } else {
-                    JSObject *p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
-                    p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
-                    en->u.var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];
-                }
-            }
-        }
-    }
-
-    /* sort the exported names */
-    rqsort(s->exported_names, s->exported_names_count,
-           sizeof(s->exported_names[0]), exported_names_cmp, ctx);
-
-    for(i = 0; i < s->exported_names_count; i++) {
-        ExportedNameEntry *en = &s->exported_names[i];
-        switch(en->export_type) {
-        case EXPORTED_NAME_NORMAL:
-            {
-                JSVarRef *var_ref = en->u.var_ref;
-                pr = add_property(ctx, p, en->export_name,
-                                  JS_PROP_ENUMERABLE | JS_PROP_WRITABLE |
-                                  JS_PROP_VARREF);
-                if (!pr)
-                    goto fail;
-                var_ref->header.ref_count++;
-                pr->u.var_ref = var_ref;
-            }
-            break;
-        case EXPORTED_NAME_NS:
-            /* the exported namespace must be created on demand */
-            if (JS_DefineAutoInitProperty(ctx, obj,
-                                          en->export_name,
-                                          JS_AUTOINIT_ID_MODULE_NS,
-                                          en->u.module, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
-                goto fail;
-            break;
-        default:
-            break;
-        }
-    }
-
-    js_free(ctx, s->exported_names);
-
-    JS_DefinePropertyValue(ctx, obj, JS_ATOM_Symbol_toStringTag,
-                           JS_AtomToString(ctx, JS_ATOM_Module),
-                           0);
-
-    p->extensible = FALSE;
-    return obj;
- fail:
-    js_free(ctx, s->exported_names);
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_get_module_ns(JSContext *ctx, JSModuleDef *m)
-{
-    if (JS_IsUndefined(m->module_ns)) {
-        JSValue val;
-        val = js_build_module_ns(ctx, m);
-        if (JS_IsException(val))
-            return JS_EXCEPTION;
-        m->module_ns = val;
-    }
-    return JS_DupValue(ctx, m->module_ns);
-}
-
-/* Load all the required modules for module 'm' */
-static int js_resolve_module(JSContext *ctx, JSModuleDef *m)
-{
-    int i;
-    JSModuleDef *m1;
-
-    if (m->resolved)
-        return 0;
-#ifdef DUMP_MODULE_RESOLVE
-    {
-        char buf1[ATOM_GET_STR_BUF_SIZE];
-        printf("resolving module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
-    }
-#endif
-    m->resolved = TRUE;
-    /* resolve each requested module */
-    for(i = 0; i < m->req_module_entries_count; i++) {
-        JSReqModuleEntry *rme = &m->req_module_entries[i];
-        m1 = js_host_resolve_imported_module_atom(ctx, m->module_name,
-                                                  rme->module_name);
-        if (!m1)
-            return -1;
-        rme->module = m1;
-        /* already done in js_host_resolve_imported_module() except if
-           the module was loaded with JS_EvalBinary() */
-        if (js_resolve_module(ctx, m1) < 0)
-            return -1;
-    }
-    return 0;
-}
-
-static JSVarRef *js_create_module_var(JSContext *ctx, BOOL is_lexical)
-{
-    JSVarRef *var_ref;
-    var_ref = js_malloc(ctx, sizeof(JSVarRef));
-    if (!var_ref)
-        return NULL;
-    var_ref->header.ref_count = 1;
-    if (is_lexical)
-        var_ref->value = JS_UNINITIALIZED;
-    else
-        var_ref->value = JS_UNDEFINED;
-    var_ref->pvalue = &var_ref->value;
-    var_ref->is_detached = TRUE;
-    add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
-    return var_ref;
-}
-
-/* Create the <eval> function associated with the module */
-static int js_create_module_bytecode_function(JSContext *ctx, JSModuleDef *m)
-{
-    JSFunctionBytecode *b;
-    int i;
-    JSVarRef **var_refs;
-    JSValue func_obj, bfunc;
-    JSObject *p;
-
-    bfunc = m->func_obj;
-    func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
-                                      JS_CLASS_BYTECODE_FUNCTION);
-
-    if (JS_IsException(func_obj))
-        return -1;
-    b = JS_VALUE_GET_PTR(bfunc);
-
-    p = JS_VALUE_GET_OBJ(func_obj);
-    p->u.func.function_bytecode = b;
-    b->header.ref_count++;
-    p->u.func.home_object = NULL;
-    p->u.func.var_refs = NULL;
-    if (b->closure_var_count) {
-        var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count);
-        if (!var_refs)
-            goto fail;
-        p->u.func.var_refs = var_refs;
-
-        /* create the global variables. The other variables are
-           imported from other modules */
-        for(i = 0; i < b->closure_var_count; i++) {
-            JSClosureVar *cv = &b->closure_var[i];
-            JSVarRef *var_ref;
-            if (cv->is_local) {
-                var_ref = js_create_module_var(ctx, cv->is_lexical);
-                if (!var_ref)
-                    goto fail;
-#ifdef DUMP_MODULE_RESOLVE
-                printf("local %d: %p\n", i, var_ref);
-#endif
-                var_refs[i] = var_ref;
-            }
-        }
-    }
-    m->func_obj = func_obj;
-    JS_FreeValue(ctx, bfunc);
-    return 0;
- fail:
-    JS_FreeValue(ctx, func_obj);
-    return -1;
-}
-
-/* must be done before js_link_module() because of cyclic references */
-static int js_create_module_function(JSContext *ctx, JSModuleDef *m)
-{
-    BOOL is_c_module;
-    int i;
-    JSVarRef *var_ref;
-    
-    if (m->func_created)
-        return 0;
-
-    is_c_module = (m->init_func != NULL);
-
-    if (is_c_module) {
-        /* initialize the exported variables */
-        for(i = 0; i < m->export_entries_count; i++) {
-            JSExportEntry *me = &m->export_entries[i];
-            if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
-                var_ref = js_create_module_var(ctx, FALSE);
-                if (!var_ref)
-                    return -1;
-                me->u.local.var_ref = var_ref;
-            }
-        }
-    } else {
-        if (js_create_module_bytecode_function(ctx, m))
-            return -1;
-    }
-    m->func_created = TRUE;
-
-    /* do it on the dependencies */
-    
-    for(i = 0; i < m->req_module_entries_count; i++) {
-        JSReqModuleEntry *rme = &m->req_module_entries[i];
-        if (js_create_module_function(ctx, rme->module) < 0)
-            return -1;
-    }
-
-    return 0;
-}    
-
-    
-/* Prepare a module to be executed by resolving all the imported
-   variables. */
-static int js_link_module(JSContext *ctx, JSModuleDef *m)
-{
-    int i;
-    JSImportEntry *mi;
-    JSModuleDef *m1;
-    JSVarRef **var_refs, *var_ref;
-    JSObject *p;
-    BOOL is_c_module;
-    JSValue ret_val;
-    
-    if (m->instantiated)
-        return 0;
-    m->instantiated = TRUE;
-
-#ifdef DUMP_MODULE_RESOLVE
-    {
-        char buf1[ATOM_GET_STR_BUF_SIZE];
-        printf("start instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
-    }
-#endif
-
-    for(i = 0; i < m->req_module_entries_count; i++) {
-        JSReqModuleEntry *rme = &m->req_module_entries[i];
-        if (js_link_module(ctx, rme->module) < 0)
-            goto fail;
-    }
-
-#ifdef DUMP_MODULE_RESOLVE
-    {
-        char buf1[ATOM_GET_STR_BUF_SIZE];
-        printf("instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
-    }
-#endif
-    /* check the indirect exports */
-    for(i = 0; i < m->export_entries_count; i++) {
-        JSExportEntry *me = &m->export_entries[i];
-        if (me->export_type == JS_EXPORT_TYPE_INDIRECT &&
-            me->local_name != JS_ATOM__star_) {
-            JSResolveResultEnum ret;
-            JSExportEntry *res_me;
-            JSModuleDef *res_m, *m1;
-            m1 = m->req_module_entries[me->u.req_module_idx].module;
-            ret = js_resolve_export(ctx, &res_m, &res_me, m1, me->local_name);
-            if (ret != JS_RESOLVE_RES_FOUND) {
-                js_resolve_export_throw_error(ctx, ret, m, me->export_name);
-                goto fail;
-            }
-        }
-    }
-
-#ifdef DUMP_MODULE_RESOLVE
-    {
-        printf("exported bindings:\n");
-        for(i = 0; i < m->export_entries_count; i++) {
-            JSExportEntry *me = &m->export_entries[i];
-            printf(" name="); print_atom(ctx, me->export_name);
-            printf(" local="); print_atom(ctx, me->local_name);
-            printf(" type=%d idx=%d\n", me->export_type, me->u.local.var_idx);
-        }
-    }
-#endif
-
-    is_c_module = (m->init_func != NULL);
-
-    if (!is_c_module) {
-        p = JS_VALUE_GET_OBJ(m->func_obj);
-        var_refs = p->u.func.var_refs;
-
-        for(i = 0; i < m->import_entries_count; i++) {
-            mi = &m->import_entries[i];
-#ifdef DUMP_MODULE_RESOLVE
-            printf("import var_idx=%d name=", mi->var_idx);
-            print_atom(ctx, mi->import_name);
-            printf(": ");
-#endif
-            m1 = m->req_module_entries[mi->req_module_idx].module;
-            if (mi->import_name == JS_ATOM__star_) {
-                JSValue val;
-                /* name space import */
-                val = js_get_module_ns(ctx, m1);
-                if (JS_IsException(val))
-                    goto fail;
-                set_value(ctx, &var_refs[mi->var_idx]->value, val);
-#ifdef DUMP_MODULE_RESOLVE
-                printf("namespace\n");
-#endif
-            } else {
-                JSResolveResultEnum ret;
-                JSExportEntry *res_me;
-                JSModuleDef *res_m;
-                JSObject *p1;
-
-                ret = js_resolve_export(ctx, &res_m,
-                                        &res_me, m1, mi->import_name);
-                if (ret != JS_RESOLVE_RES_FOUND) {
-                    js_resolve_export_throw_error(ctx, ret, m1, mi->import_name);
-                    goto fail;
-                }
-                if (res_me->local_name == JS_ATOM__star_) {
-                    JSValue val;
-                    JSModuleDef *m2;
-                    /* name space import from */
-                    m2 = res_m->req_module_entries[res_me->u.req_module_idx].module;
-                    val = js_get_module_ns(ctx, m2);
-                    if (JS_IsException(val))
-                        goto fail;
-                    var_ref = js_create_module_var(ctx, TRUE);
-                    if (!var_ref) {
-                        JS_FreeValue(ctx, val);
-                        goto fail;
-                    }
-                    set_value(ctx, &var_ref->value, val);
-                    var_refs[mi->var_idx] = var_ref;
-#ifdef DUMP_MODULE_RESOLVE
-                    printf("namespace from\n");
-#endif
-                } else {
-                    var_ref = res_me->u.local.var_ref;
-                    if (!var_ref) {
-                        p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
-                        var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];
-                    }
-                    var_ref->header.ref_count++;
-                    var_refs[mi->var_idx] = var_ref;
-#ifdef DUMP_MODULE_RESOLVE
-                    printf("local export (var_ref=%p)\n", var_ref);
-#endif
-                }
-            }
-        }
-
-        /* keep the exported variables in the module export entries (they
-           are used when the eval function is deleted and cannot be
-           initialized before in case imports are exported) */
-        for(i = 0; i < m->export_entries_count; i++) {
-            JSExportEntry *me = &m->export_entries[i];
-            if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
-                var_ref = var_refs[me->u.local.var_idx];
-                var_ref->header.ref_count++;
-                me->u.local.var_ref = var_ref;
-            }
-        }
-
-        /* initialize the global variables */
-        ret_val = JS_Call(ctx, m->func_obj, JS_TRUE, 0, NULL);
-        if (JS_IsException(ret_val))
-            goto fail;
-        JS_FreeValue(ctx, ret_val);
-    }
-
-#ifdef DUMP_MODULE_RESOLVE
-    printf("done instantiate\n");
-#endif
-    return 0;
- fail:
-    return -1;
-}
-
-/* return JS_ATOM_NULL if the name cannot be found. Only works with
-   not striped bytecode functions. */
-JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels)
-{
-    JSStackFrame *sf;
-    JSFunctionBytecode *b;
-    JSObject *p;
-    /* XXX: currently we just use the filename of the englobing
-       function. It does not work for eval(). Need to add a
-       ScriptOrModule info in JSFunctionBytecode */
-    sf = ctx->rt->current_stack_frame;
-    if (!sf)
-        return JS_ATOM_NULL;
-    while (n_stack_levels-- > 0) {
-        sf = sf->prev_frame;
-        if (!sf)
-            return JS_ATOM_NULL;
-    }
-    if (JS_VALUE_GET_TAG(sf->cur_func) != JS_TAG_OBJECT)
-        return JS_ATOM_NULL;
-    p = JS_VALUE_GET_OBJ(sf->cur_func);
-    if (!js_class_has_bytecode(p->class_id))
-        return JS_ATOM_NULL;
-    b = p->u.func.function_bytecode;
-    if (!b->has_debug)
-        return JS_ATOM_NULL;
-    return JS_DupAtom(ctx, b->debug.filename);
-}
-
-JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m)
-{
-    return JS_DupAtom(ctx, m->module_name);
-}
-
-JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m)
-{
-    JSValue obj;
-    /* allocate meta_obj only if requested to save memory */
-    obj = m->meta_obj;
-    if (JS_IsUndefined(obj)) {
-        obj = JS_NewObjectProto(ctx, JS_NULL);
-        if (JS_IsException(obj))
-            return JS_EXCEPTION;
-        m->meta_obj = obj;
-    }
-    return JS_DupValue(ctx, obj);
-}
-
-static JSValue js_import_meta(JSContext *ctx)
-{
-    JSAtom filename;
-    JSModuleDef *m;
-    
-    filename = JS_GetScriptOrModuleName(ctx, 0);
-    if (filename == JS_ATOM_NULL)
-        goto fail;
-
-    /* XXX: inefficient, need to add a module or script pointer in
-       JSFunctionBytecode */
-    m = js_find_loaded_module(ctx, filename);
-    JS_FreeAtom(ctx, filename);
-    if (!m) {
-    fail:
-        JS_ThrowTypeError(ctx, "import.meta not supported in this context");
-        return JS_EXCEPTION;
-    }
-    return JS_GetImportMeta(ctx, m);
-}
-
-/* used by os.Worker() and import() */
-JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename,
-                          const char *filename)
-{
-    JSModuleDef *m;
-    JSValue ret, func_obj;
-    
-    m = js_host_resolve_imported_module(ctx, basename, filename);
-    if (!m)
-        return NULL;
-    
-    if (js_resolve_module(ctx, m) < 0) {
-        js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);
-        return NULL;
-    }
-
-    /* Evaluate the module code */
-    func_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
-    ret = JS_EvalFunction(ctx, func_obj);
-    if (JS_IsException(ret))
-        return NULL;
-    JS_FreeValue(ctx, ret);
-    return m;
-}
-
-static JSValue js_dynamic_import_job(JSContext *ctx,
-                                     int argc, JSValueConst *argv)
-{
-    JSValueConst *resolving_funcs = argv;
-    JSValueConst basename_val = argv[2];
-    JSValueConst specifier = argv[3];
-    JSModuleDef *m;
-    const char *basename = NULL, *filename;
-    JSValue ret, err, ns;
-
-    if (!JS_IsString(basename_val)) {
-        JS_ThrowTypeError(ctx, "no function filename for import()");
-        goto exception;
-    }
-    basename = JS_ToCString(ctx, basename_val);
-    if (!basename)
-        goto exception;
-
-    filename = JS_ToCString(ctx, specifier);
-    if (!filename)
-        goto exception;
-                     
-    m = JS_RunModule(ctx, basename, filename);
-    JS_FreeCString(ctx, filename);
-    if (!m)
-        goto exception;
-
-    /* return the module namespace */
-    ns = js_get_module_ns(ctx, m);
-    if (JS_IsException(ns))
-        goto exception;
-
-    ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED,
-                   1, (JSValueConst *)&ns);
-    JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
-    JS_FreeValue(ctx, ns);
-    JS_FreeCString(ctx, basename);
-    return JS_UNDEFINED;
- exception:
-
-    err = JS_GetException(ctx);
-    ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
-                   1, (JSValueConst *)&err);
-    JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
-    JS_FreeValue(ctx, err);
-    JS_FreeCString(ctx, basename);
-    return JS_UNDEFINED;
-}
-
-static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier)
-{
-    JSAtom basename;
-    JSValue promise, resolving_funcs[2], basename_val;
-    JSValueConst args[4];
-
-    basename = JS_GetScriptOrModuleName(ctx, 0);
-    if (basename == JS_ATOM_NULL)
-        basename_val = JS_NULL;
-    else
-        basename_val = JS_AtomToValue(ctx, basename);
-    JS_FreeAtom(ctx, basename);
-    if (JS_IsException(basename_val))
-        return basename_val;
-    
-    promise = JS_NewPromiseCapability(ctx, resolving_funcs);
-    if (JS_IsException(promise)) {
-        JS_FreeValue(ctx, basename_val);
-        return promise;
-    }
-
-    args[0] = resolving_funcs[0];
-    args[1] = resolving_funcs[1];
-    args[2] = basename_val;
-    args[3] = specifier;
-    
-    JS_EnqueueJob(ctx, js_dynamic_import_job, 4, args);
-
-    JS_FreeValue(ctx, basename_val);
-    JS_FreeValue(ctx, resolving_funcs[0]);
-    JS_FreeValue(ctx, resolving_funcs[1]);
-    return promise;
-}
-
-/* Run the <eval> function of the module and of all its requested
-   modules. */
-static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m)
-{
-    JSModuleDef *m1;
-    int i;
-    JSValue ret_val;
-
-    if (m->eval_mark)
-        return JS_UNDEFINED; /* avoid cycles */
-
-    if (m->evaluated) {
-        /* if the module was already evaluated, rethrow the exception
-           it raised */
-        if (m->eval_has_exception) {
-            return JS_Throw(ctx, JS_DupValue(ctx, m->eval_exception));
-        } else {
-            return JS_UNDEFINED;
-        }
-    }
-
-    m->eval_mark = TRUE;
-
-    for(i = 0; i < m->req_module_entries_count; i++) {
-        JSReqModuleEntry *rme = &m->req_module_entries[i];
-        m1 = rme->module;
-        if (!m1->eval_mark) {
-            ret_val = js_evaluate_module(ctx, m1);
-            if (JS_IsException(ret_val)) {
-                m->eval_mark = FALSE;
-                return ret_val;
-            }
-            JS_FreeValue(ctx, ret_val);
-        }
-    }
-
-    if (m->init_func) {
-        /* C module init */
-        if (m->init_func(ctx, m) < 0)
-            ret_val = JS_EXCEPTION;
-        else
-            ret_val = JS_UNDEFINED;
-    } else {
-        ret_val = JS_CallFree(ctx, m->func_obj, JS_UNDEFINED, 0, NULL);
-        m->func_obj = JS_UNDEFINED;
-    }
-    if (JS_IsException(ret_val)) {
-        /* save the thrown exception value */
-        m->eval_has_exception = TRUE;
-        m->eval_exception = JS_DupValue(ctx, ctx->rt->current_exception);
-    }
-    m->eval_mark = FALSE;
-    m->evaluated = TRUE;
-    return ret_val;
-}
-
-static __exception JSAtom js_parse_from_clause(JSParseState *s)
-{
-    JSAtom module_name;
-    if (!token_is_pseudo_keyword(s, JS_ATOM_from)) {
-        js_parse_error(s, "from clause expected");
-        return JS_ATOM_NULL;
-    }
-    if (next_token(s))
-        return JS_ATOM_NULL;
-    if (s->token.val != TOK_STRING) {
-        js_parse_error(s, "string expected");
-        return JS_ATOM_NULL;
-    }
-    module_name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
-    if (module_name == JS_ATOM_NULL)
-        return JS_ATOM_NULL;
-    if (next_token(s)) {
-        JS_FreeAtom(s->ctx, module_name);
-        return JS_ATOM_NULL;
-    }
-    return module_name;
-}
-
-static __exception int js_parse_export(JSParseState *s)
-{
-    JSContext *ctx = s->ctx;
-    JSModuleDef *m = s->cur_func->module;
-    JSAtom local_name, export_name;
-    int first_export, idx, i, tok;
-    JSAtom module_name;
-    JSExportEntry *me;
-
-    if (next_token(s))
-        return -1;
-
-    tok = s->token.val;
-    if (tok == TOK_CLASS) {
-        return js_parse_class(s, FALSE, JS_PARSE_EXPORT_NAMED);
-    } else if (tok == TOK_FUNCTION ||
-               (token_is_pseudo_keyword(s, JS_ATOM_async) &&
-                peek_token(s, TRUE) == TOK_FUNCTION)) {
-        return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT,
-                                       JS_FUNC_NORMAL, JS_ATOM_NULL,
-                                       s->token.ptr, s->token.line_num,
-                                       JS_PARSE_EXPORT_NAMED, NULL);
-    }
-
-    if (next_token(s))
-        return -1;
-
-    switch(tok) {
-    case '{':
-        first_export = m->export_entries_count;
-        while (s->token.val != '}') {
-            if (!token_is_ident(s->token.val)) {
-                js_parse_error(s, "identifier expected");
-                return -1;
-            }
-            local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
-            export_name = JS_ATOM_NULL;
-            if (next_token(s))
-                goto fail;
-            if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
-                if (next_token(s))
-                    goto fail;
-                if (!token_is_ident(s->token.val)) {
-                    js_parse_error(s, "identifier expected");
-                    goto fail;
-                }
-                export_name = JS_DupAtom(ctx, s->token.u.ident.atom);
-                if (next_token(s)) {
-                fail:
-                    JS_FreeAtom(ctx, local_name);
-                fail1:
-                    JS_FreeAtom(ctx, export_name);
-                    return -1;
-                }
-            } else {
-                export_name = JS_DupAtom(ctx, local_name);
-            }
-            me = add_export_entry(s, m, local_name, export_name,
-                                  JS_EXPORT_TYPE_LOCAL);
-            JS_FreeAtom(ctx, local_name);
-            JS_FreeAtom(ctx, export_name);
-            if (!me)
-                return -1;
-            if (s->token.val != ',')
-                break;
-            if (next_token(s))
-                return -1;
-        }
-        if (js_parse_expect(s, '}'))
-            return -1;
-        if (token_is_pseudo_keyword(s, JS_ATOM_from)) {
-            module_name = js_parse_from_clause(s);
-            if (module_name == JS_ATOM_NULL)
-                return -1;
-            idx = add_req_module_entry(ctx, m, module_name);
-            JS_FreeAtom(ctx, module_name);
-            if (idx < 0)
-                return -1;
-            for(i = first_export; i < m->export_entries_count; i++) {
-                me = &m->export_entries[i];
-                me->export_type = JS_EXPORT_TYPE_INDIRECT;
-                me->u.req_module_idx = idx;
-            }
-        }
-        break;
-    case '*':
-        if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
-            /* export ns from */
-            if (next_token(s))
-                return -1;
-            if (!token_is_ident(s->token.val)) {
-                js_parse_error(s, "identifier expected");
-                return -1;
-            }
-            export_name = JS_DupAtom(ctx, s->token.u.ident.atom);
-            if (next_token(s))
-                goto fail1;
-            module_name = js_parse_from_clause(s);
-            if (module_name == JS_ATOM_NULL)
-                goto fail1;
-            idx = add_req_module_entry(ctx, m, module_name);
-            JS_FreeAtom(ctx, module_name);
-            if (idx < 0)
-                goto fail1;
-            me = add_export_entry(s, m, JS_ATOM__star_, export_name,
-                                  JS_EXPORT_TYPE_INDIRECT);
-            JS_FreeAtom(ctx, export_name);
-            if (!me)
-                return -1;
-            me->u.req_module_idx = idx;
-        } else {
-            module_name = js_parse_from_clause(s);
-            if (module_name == JS_ATOM_NULL)
-                return -1;
-            idx = add_req_module_entry(ctx, m, module_name);
-            JS_FreeAtom(ctx, module_name);
-            if (idx < 0)
-                return -1;
-            if (add_star_export_entry(ctx, m, idx) < 0)
-                return -1;
-        }
-        break;
-    case TOK_DEFAULT:
-        if (s->token.val == TOK_CLASS) {
-            return js_parse_class(s, FALSE, JS_PARSE_EXPORT_DEFAULT);
-        } else if (s->token.val == TOK_FUNCTION ||
-                   (token_is_pseudo_keyword(s, JS_ATOM_async) &&
-                    peek_token(s, TRUE) == TOK_FUNCTION)) {
-            return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT,
-                                           JS_FUNC_NORMAL, JS_ATOM_NULL,
-                                           s->token.ptr, s->token.line_num,
-                                           JS_PARSE_EXPORT_DEFAULT, NULL);
-        } else {
-            if (js_parse_assign_expr(s))
-                return -1;
-        }
-        /* set the name of anonymous functions */
-        set_object_name(s, JS_ATOM_default);
-
-        /* store the value in the _default_ global variable and export
-           it */
-        local_name = JS_ATOM__default_;
-        if (define_var(s, s->cur_func, local_name, JS_VAR_DEF_LET) < 0)
-            return -1;
-        emit_op(s, OP_scope_put_var_init);
-        emit_atom(s, local_name);
-        emit_u16(s, 0);
-
-        if (!add_export_entry(s, m, local_name, JS_ATOM_default,
-                              JS_EXPORT_TYPE_LOCAL))
-            return -1;
-        break;
-    case TOK_VAR:
-    case TOK_LET:
-    case TOK_CONST:
-        return js_parse_var(s, TRUE, tok, TRUE);
-    default:
-        return js_parse_error(s, "invalid export syntax");
-    }
-    return js_parse_expect_semi(s);
-}
-
-static int add_closure_var(JSContext *ctx, JSFunctionDef *s,
-                           BOOL is_local, BOOL is_arg,
-                           int var_idx, JSAtom var_name,
-                           BOOL is_const, BOOL is_lexical,
-                           JSVarKindEnum var_kind);
-
-static int add_import(JSParseState *s, JSModuleDef *m,
-                      JSAtom local_name, JSAtom import_name)
-{
-    JSContext *ctx = s->ctx;
-    int i, var_idx;
-    JSImportEntry *mi;
-    BOOL is_local;
-
-    if (local_name == JS_ATOM_arguments || local_name == JS_ATOM_eval)
-        return js_parse_error(s, "invalid import binding");
-
-    if (local_name != JS_ATOM_default) {
-        for (i = 0; i < s->cur_func->closure_var_count; i++) {
-            if (s->cur_func->closure_var[i].var_name == local_name)
-                return js_parse_error(s, "duplicate import binding");
-        }
-    }
-
-    is_local = (import_name == JS_ATOM__star_);
-    var_idx = add_closure_var(ctx, s->cur_func, is_local, FALSE,
-                              m->import_entries_count,
-                              local_name, TRUE, TRUE, FALSE);
-    if (var_idx < 0)
-        return -1;
-    if (js_resize_array(ctx, (void **)&m->import_entries,
-                        sizeof(JSImportEntry),
-                        &m->import_entries_size,
-                        m->import_entries_count + 1))
-        return -1;
-    mi = &m->import_entries[m->import_entries_count++];
-    mi->import_name = JS_DupAtom(ctx, import_name);
-    mi->var_idx = var_idx;
-    return 0;
-}
-
-static __exception int js_parse_import(JSParseState *s)
-{
-    JSContext *ctx = s->ctx;
-    JSModuleDef *m = s->cur_func->module;
-    JSAtom local_name, import_name, module_name;
-    int first_import, i, idx;
-
-    if (next_token(s))
-        return -1;
-
-    first_import = m->import_entries_count;
-    if (s->token.val == TOK_STRING) {
-        module_name = JS_ValueToAtom(ctx, s->token.u.str.str);
-        if (module_name == JS_ATOM_NULL)
-            return -1;
-        if (next_token(s)) {
-            JS_FreeAtom(ctx, module_name);
-            return -1;
-        }
-    } else {
-        if (s->token.val == TOK_IDENT) {
-            if (s->token.u.ident.is_reserved) {
-                return js_parse_error_reserved_identifier(s);
-            }
-            /* "default" import */
-            local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
-            import_name = JS_ATOM_default;
-            if (next_token(s))
-                goto fail;
-            if (add_import(s, m, local_name, import_name))
-                goto fail;
-            JS_FreeAtom(ctx, local_name);
-
-            if (s->token.val != ',')
-                goto end_import_clause;
-            if (next_token(s))
-                return -1;
-        }
-
-        if (s->token.val == '*') {
-            /* name space import */
-            if (next_token(s))
-                return -1;
-            if (!token_is_pseudo_keyword(s, JS_ATOM_as))
-                return js_parse_error(s, "expecting 'as'");
-            if (next_token(s))
-                return -1;
-            if (!token_is_ident(s->token.val)) {
-                js_parse_error(s, "identifier expected");
-                return -1;
-            }
-            local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
-            import_name = JS_ATOM__star_;
-            if (next_token(s))
-                goto fail;
-            if (add_import(s, m, local_name, import_name))
-                goto fail;
-            JS_FreeAtom(ctx, local_name);
-        } else if (s->token.val == '{') {
-            if (next_token(s))
-                return -1;
-
-            while (s->token.val != '}') {
-                if (!token_is_ident(s->token.val)) {
-                    js_parse_error(s, "identifier expected");
-                    return -1;
-                }
-                import_name = JS_DupAtom(ctx, s->token.u.ident.atom);
-                local_name = JS_ATOM_NULL;
-                if (next_token(s))
-                    goto fail;
-                if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
-                    if (next_token(s))
-                        goto fail;
-                    if (!token_is_ident(s->token.val)) {
-                        js_parse_error(s, "identifier expected");
-                        goto fail;
-                    }
-                    local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
-                    if (next_token(s)) {
-                    fail:
-                        JS_FreeAtom(ctx, local_name);
-                        JS_FreeAtom(ctx, import_name);
-                        return -1;
-                    }
-                } else {
-                    local_name = JS_DupAtom(ctx, import_name);
-                }
-                if (add_import(s, m, local_name, import_name))
-                    goto fail;
-                JS_FreeAtom(ctx, local_name);
-                JS_FreeAtom(ctx, import_name);
-                if (s->token.val != ',')
-                    break;
-                if (next_token(s))
-                    return -1;
-            }
-            if (js_parse_expect(s, '}'))
-                return -1;
-        }
-    end_import_clause:
-        module_name = js_parse_from_clause(s);
-        if (module_name == JS_ATOM_NULL)
-            return -1;
-    }
-    idx = add_req_module_entry(ctx, m, module_name);
-    JS_FreeAtom(ctx, module_name);
-    if (idx < 0)
-        return -1;
-    for(i = first_import; i < m->import_entries_count; i++)
-        m->import_entries[i].req_module_idx = idx;
-
-    return js_parse_expect_semi(s);
-}
-
-static __exception int js_parse_source_element(JSParseState *s)
-{
-    JSFunctionDef *fd = s->cur_func;
-    int tok;
-    
-    if (s->token.val == TOK_FUNCTION ||
-        (token_is_pseudo_keyword(s, JS_ATOM_async) &&
-         peek_token(s, TRUE) == TOK_FUNCTION)) {
-        if (js_parse_function_decl(s, JS_PARSE_FUNC_STATEMENT,
-                                   JS_FUNC_NORMAL, JS_ATOM_NULL,
-                                   s->token.ptr, s->token.line_num))
-            return -1;
-    } else if (s->token.val == TOK_EXPORT && fd->module) {
-        if (js_parse_export(s))
-            return -1;
-    } else if (s->token.val == TOK_IMPORT && fd->module &&
-               ((tok = peek_token(s, FALSE)) != '(' && tok != '.'))  {
-        /* the peek_token is needed to avoid confusion with ImportCall
-           (dynamic import) or import.meta */
-        if (js_parse_import(s))
-            return -1;
-    } else {
-        if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
-            return -1;
-    }
-    return 0;
-}
-
-static JSFunctionDef *js_new_function_def(JSContext *ctx,
-                                          JSFunctionDef *parent,
-                                          BOOL is_eval,
-                                          BOOL is_func_expr,
-                                          const char *filename, int line_num)
-{
-    JSFunctionDef *fd;
-
-    fd = js_mallocz(ctx, sizeof(*fd));
-    if (!fd)
-        return NULL;
-
-    fd->ctx = ctx;
-    init_list_head(&fd->child_list);
-
-    /* insert in parent list */
-    fd->parent = parent;
-    fd->parent_cpool_idx = -1;
-    if (parent) {
-        list_add_tail(&fd->link, &parent->child_list);
-        fd->js_mode = parent->js_mode;
-        fd->parent_scope_level = parent->scope_level;
-    }
-
-    fd->is_eval = is_eval;
-    fd->is_func_expr = is_func_expr;
-    js_dbuf_init(ctx, &fd->byte_code);
-    fd->last_opcode_pos = -1;
-    fd->func_name = JS_ATOM_NULL;
-    fd->var_object_idx = -1;
-    fd->arg_var_object_idx = -1;
-    fd->arguments_var_idx = -1;
-    fd->arguments_arg_idx = -1;
-    fd->func_var_idx = -1;
-    fd->eval_ret_idx = -1;
-    fd->this_var_idx = -1;
-    fd->new_target_var_idx = -1;
-    fd->this_active_func_var_idx = -1;
-    fd->home_object_var_idx = -1;
-
-    /* XXX: should distinguish arg, var and var object and body scopes */
-    fd->scopes = fd->def_scope_array;
-    fd->scope_size = countof(fd->def_scope_array);
-    fd->scope_count = 1;
-    fd->scopes[0].first = -1;
-    fd->scopes[0].parent = -1;
-    fd->scope_level = 0;  /* 0: var/arg scope */
-    fd->scope_first = -1;
-    fd->body_scope = -1;
-
-    fd->filename = JS_NewAtom(ctx, filename);
-    fd->line_num = line_num;
-
-    js_dbuf_init(ctx, &fd->pc2line);
-    //fd->pc2line_last_line_num = line_num;
-    //fd->pc2line_last_pc = 0;
-    fd->last_opcode_line_num = line_num;
-
-    return fd;
-}
-
-static void free_bytecode_atoms(JSRuntime *rt,
-                                const uint8_t *bc_buf, int bc_len,
-                                BOOL use_short_opcodes)
-{
-    int pos, len, op;
-    JSAtom atom;
-    const JSOpCode *oi;
-    
-    pos = 0;
-    while (pos < bc_len) {
-        op = bc_buf[pos];
-        if (use_short_opcodes)
-            oi = &short_opcode_info(op);
-        else
-            oi = &opcode_info[op];
-            
-        len = oi->size;
-        switch(oi->fmt) {
-        case OP_FMT_atom:
-        case OP_FMT_atom_u8:
-        case OP_FMT_atom_u16:
-        case OP_FMT_atom_label_u8:
-        case OP_FMT_atom_label_u16:
-            atom = get_u32(bc_buf + pos + 1);
-            JS_FreeAtomRT(rt, atom);
-            break;
-        default:
-            break;
-        }
-        pos += len;
-    }
-}
-
-static void js_free_function_def(JSContext *ctx, JSFunctionDef *fd)
-{
-    int i;
-    struct list_head *el, *el1;
-
-    /* free the child functions */
-    list_for_each_safe(el, el1, &fd->child_list) {
-        JSFunctionDef *fd1;
-        fd1 = list_entry(el, JSFunctionDef, link);
-        js_free_function_def(ctx, fd1);
-    }
-
-    free_bytecode_atoms(ctx->rt, fd->byte_code.buf, fd->byte_code.size,
-                        fd->use_short_opcodes);
-    dbuf_free(&fd->byte_code);
-    js_free(ctx, fd->jump_slots);
-    js_free(ctx, fd->label_slots);
-    js_free(ctx, fd->line_number_slots);
-
-    for(i = 0; i < fd->cpool_count; i++) {
-        JS_FreeValue(ctx, fd->cpool[i]);
-    }
-    js_free(ctx, fd->cpool);
-
-    JS_FreeAtom(ctx, fd->func_name);
-
-    for(i = 0; i < fd->var_count; i++) {
-        JS_FreeAtom(ctx, fd->vars[i].var_name);
-    }
-    js_free(ctx, fd->vars);
-    for(i = 0; i < fd->arg_count; i++) {
-        JS_FreeAtom(ctx, fd->args[i].var_name);
-    }
-    js_free(ctx, fd->args);
-
-    for(i = 0; i < fd->global_var_count; i++) {
-        JS_FreeAtom(ctx, fd->global_vars[i].var_name);
-    }
-    js_free(ctx, fd->global_vars);
-
-    for(i = 0; i < fd->closure_var_count; i++) {
-        JSClosureVar *cv = &fd->closure_var[i];
-        JS_FreeAtom(ctx, cv->var_name);
-    }
-    js_free(ctx, fd->closure_var);
-
-    if (fd->scopes != fd->def_scope_array)
-        js_free(ctx, fd->scopes);
-
-    JS_FreeAtom(ctx, fd->filename);
-    dbuf_free(&fd->pc2line);
-
-    js_free(ctx, fd->source);
-
-    if (fd->parent) {
-        /* remove in parent list */
-        list_del(&fd->link);
-    }
-    js_free(ctx, fd);
-}
-
-#ifdef DUMP_BYTECODE
-static const char *skip_lines(const char *p, int n) {
-    while (n-- > 0 && *p) {
-        while (*p && *p++ != '\n')
-            continue;
-    }
-    return p;
-}
-
-static void print_lines(const char *source, int line, int line1) {
-    const char *s = source;
-    const char *p = skip_lines(s, line);
-    if (*p) {
-        while (line++ < line1) {
-            p = skip_lines(s = p, 1);
-            printf(";; %.*s", (int)(p - s), s);
-            if (!*p) {
-                if (p[-1] != '\n')
-                    printf("\n");
-                break;
-            }
-        }
-    }
-}
-
-static void dump_byte_code(JSContext *ctx, int pass,
-                           const uint8_t *tab, int len,
-                           const JSVarDef *args, int arg_count,
-                           const JSVarDef *vars, int var_count,
-                           const JSClosureVar *closure_var, int closure_var_count,
-                           const JSValue *cpool, uint32_t cpool_count,
-                           const char *source, int line_num,
-                           const LabelSlot *label_slots, JSFunctionBytecode *b)
-{
-    const JSOpCode *oi;
-    int pos, pos_next, op, size, idx, addr, line, line1, in_source;
-    uint8_t *bits = js_mallocz(ctx, len * sizeof(*bits));
-    BOOL use_short_opcodes = (b != NULL);
-
-    /* scan for jump targets */
-    for (pos = 0; pos < len; pos = pos_next) {
-        op = tab[pos];
-        if (use_short_opcodes)
-            oi = &short_opcode_info(op);
-        else
-            oi = &opcode_info[op];
-        pos_next = pos + oi->size;
-        if (op < OP_COUNT) {
-            switch (oi->fmt) {
-#if SHORT_OPCODES
-            case OP_FMT_label8:
-                pos++;
-                addr = (int8_t)tab[pos];
-                goto has_addr;
-            case OP_FMT_label16:
-                pos++;
-                addr = (int16_t)get_u16(tab + pos);
-                goto has_addr;
-#endif
-            case OP_FMT_atom_label_u8:
-            case OP_FMT_atom_label_u16:
-                pos += 4;
-                /* fall thru */
-            case OP_FMT_label:
-            case OP_FMT_label_u16:
-                pos++;
-                addr = get_u32(tab + pos);
-                goto has_addr;
-            has_addr:
-                if (pass == 1)
-                    addr = label_slots[addr].pos;
-                if (pass == 2)
-                    addr = label_slots[addr].pos2;
-                if (pass == 3)
-                    addr += pos;
-                if (addr >= 0 && addr < len)
-                    bits[addr] |= 1;
-                break;
-            }
-        }
-    }
-    in_source = 0;
-    if (source) {
-        /* Always print first line: needed if single line */
-        print_lines(source, 0, 1);
-        in_source = 1;
-    }
-    line1 = line = 1;
-    pos = 0;
-    while (pos < len) {
-        op = tab[pos];
-        if (source) {
-            if (b) {
-                line1 = find_line_num(ctx, b, pos) - line_num + 1;
-            } else if (op == OP_line_num) {
-                line1 = get_u32(tab + pos + 1) - line_num + 1;
-            }
-            if (line1 > line) {
-                if (!in_source)
-                    printf("\n");
-                in_source = 1;
-                print_lines(source, line, line1);
-                line = line1;
-                //bits[pos] |= 2;
-            }
-        }
-        if (in_source)
-            printf("\n");
-        in_source = 0;
-        if (op >= OP_COUNT) {
-            printf("invalid opcode (0x%02x)\n", op);
-            pos++;
-            continue;
-        }
-        if (use_short_opcodes)
-            oi = &short_opcode_info(op);
-        else
-            oi = &opcode_info[op];
-        size = oi->size;
-        if (pos + size > len) {
-            printf("truncated opcode (0x%02x)\n", op);
-            break;
-        }
-#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 16)
-        {
-            int i, x, x0;
-            x = x0 = printf("%5d ", pos);
-            for (i = 0; i < size; i++) {
-                if (i == 6) {
-                    printf("\n%*s", x = x0, "");
-                }
-                x += printf(" %02X", tab[pos + i]);
-            }
-            printf("%*s", x0 + 20 - x, "");
-        }
-#endif
-        if (bits[pos]) {
-            printf("%5d:  ", pos);
-        } else {
-            printf("        ");
-        }
-        printf("%s", oi->name);
-        pos++;
-        switch(oi->fmt) {
-        case OP_FMT_none_int:
-            printf(" %d", op - OP_push_0);
-            break;
-        case OP_FMT_npopx:
-            printf(" %d", op - OP_call0);
-            break;
-        case OP_FMT_u8:
-            printf(" %u", get_u8(tab + pos));
-            break;
-        case OP_FMT_i8:
-            printf(" %d", get_i8(tab + pos));
-            break;
-        case OP_FMT_u16:
-        case OP_FMT_npop:
-            printf(" %u", get_u16(tab + pos));
-            break;
-        case OP_FMT_npop_u16:
-            printf(" %u,%u", get_u16(tab + pos), get_u16(tab + pos + 2));
-            break;
-        case OP_FMT_i16:
-            printf(" %d", get_i16(tab + pos));
-            break;
-        case OP_FMT_i32:
-            printf(" %d", get_i32(tab + pos));
-            break;
-        case OP_FMT_u32:
-            printf(" %u", get_u32(tab + pos));
-            break;
-#if SHORT_OPCODES
-        case OP_FMT_label8:
-            addr = get_i8(tab + pos);
-            goto has_addr1;
-        case OP_FMT_label16:
-            addr = get_i16(tab + pos);
-            goto has_addr1;
-#endif
-        case OP_FMT_label:
-            addr = get_u32(tab + pos);
-            goto has_addr1;
-        has_addr1:
-            if (pass == 1)
-                printf(" %u:%u", addr, label_slots[addr].pos);
-            if (pass == 2)
-                printf(" %u:%u", addr, label_slots[addr].pos2);
-            if (pass == 3)
-                printf(" %u", addr + pos);
-            break;
-        case OP_FMT_label_u16:
-            addr = get_u32(tab + pos);
-            if (pass == 1)
-                printf(" %u:%u", addr, label_slots[addr].pos);
-            if (pass == 2)
-                printf(" %u:%u", addr, label_slots[addr].pos2);
-            if (pass == 3)
-                printf(" %u", addr + pos);
-            printf(",%u", get_u16(tab + pos + 4));
-            break;
-#if SHORT_OPCODES
-        case OP_FMT_const8:
-            idx = get_u8(tab + pos);
-            goto has_pool_idx;
-#endif
-        case OP_FMT_const:
-            idx = get_u32(tab + pos);
-            goto has_pool_idx;
-        has_pool_idx:
-            printf(" %u: ", idx);
-            if (idx < cpool_count) {
-                JS_DumpValue(ctx, cpool[idx]);
-            }
-            break;
-        case OP_FMT_atom:
-            printf(" ");
-            print_atom(ctx, get_u32(tab + pos));
-            break;
-        case OP_FMT_atom_u8:
-            printf(" ");
-            print_atom(ctx, get_u32(tab + pos));
-            printf(",%d", get_u8(tab + pos + 4));
-            break;
-        case OP_FMT_atom_u16:
-            printf(" ");
-            print_atom(ctx, get_u32(tab + pos));
-            printf(",%d", get_u16(tab + pos + 4));
-            break;
-        case OP_FMT_atom_label_u8:
-        case OP_FMT_atom_label_u16:
-            printf(" ");
-            print_atom(ctx, get_u32(tab + pos));
-            addr = get_u32(tab + pos + 4);
-            if (pass == 1)
-                printf(",%u:%u", addr, label_slots[addr].pos);
-            if (pass == 2)
-                printf(",%u:%u", addr, label_slots[addr].pos2);
-            if (pass == 3)
-                printf(",%u", addr + pos + 4);
-            if (oi->fmt == OP_FMT_atom_label_u8)
-                printf(",%u", get_u8(tab + pos + 8));
-            else
-                printf(",%u", get_u16(tab + pos + 8));
-            break;
-        case OP_FMT_none_loc:
-            idx = (op - OP_get_loc0) % 4;
-            goto has_loc;
-        case OP_FMT_loc8:
-            idx = get_u8(tab + pos);
-            goto has_loc;
-        case OP_FMT_loc:
-            idx = get_u16(tab + pos);
-        has_loc:
-            printf(" %d: ", idx);
-            if (idx < var_count) {
-                print_atom(ctx, vars[idx].var_name);
-            }
-            break;
-        case OP_FMT_none_arg:
-            idx = (op - OP_get_arg0) % 4;
-            goto has_arg;
-        case OP_FMT_arg:
-            idx = get_u16(tab + pos);
-        has_arg:
-            printf(" %d: ", idx);
-            if (idx < arg_count) {
-                print_atom(ctx, args[idx].var_name);
-            }
-            break;
-        case OP_FMT_none_var_ref:
-            idx = (op - OP_get_var_ref0) % 4;
-            goto has_var_ref;
-        case OP_FMT_var_ref:
-            idx = get_u16(tab + pos);
-        has_var_ref:
-            printf(" %d: ", idx);
-            if (idx < closure_var_count) {
-                print_atom(ctx, closure_var[idx].var_name);
-            }
-            break;
-        default:
-            break;
-        }
-        printf("\n");
-        pos += oi->size - 1;
-    }
-    if (source) {
-        if (!in_source)
-            printf("\n");
-        print_lines(source, line, INT32_MAX);
-    }
-    js_free(ctx, bits);
-}
-
-static __maybe_unused void dump_pc2line(JSContext *ctx, const uint8_t *buf, int len,
-                                                 int line_num)
-{
-    const uint8_t *p_end, *p_next, *p;
-    int pc, v;
-    unsigned int op;
-
-    if (len <= 0)
-        return;
-
-    printf("%5s %5s\n", "PC", "LINE");
-
-    p = buf;
-    p_end = buf + len;
-    pc = 0;
-    while (p < p_end) {
-        op = *p++;
-        if (op == 0) {
-            v = unicode_from_utf8(p, p_end - p, &p_next);
-            if (v < 0)
-                goto fail;
-            pc += v;
-            p = p_next;
-            v = unicode_from_utf8(p, p_end - p, &p_next);
-            if (v < 0) {
-            fail:
-                printf("invalid pc2line encode pos=%d\n", (int)(p - buf));
-                return;
-            }
-            if (!(v & 1)) {
-                v = v >> 1;
-            } else {
-                v = -(v >> 1) - 1;
-            }
-            line_num += v;
-            p = p_next;
-        } else {
-            op -= PC2LINE_OP_FIRST;
-            pc += (op / PC2LINE_RANGE);
-            line_num += (op % PC2LINE_RANGE) + PC2LINE_BASE;
-        }
-        printf("%5d %5d\n", pc, line_num);
-    }
-}
-
-static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionBytecode *b)
-{
-    int i;
-    char atom_buf[ATOM_GET_STR_BUF_SIZE];
-    const char *str;
-
-    if (b->has_debug && b->debug.filename != JS_ATOM_NULL) {
-        str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->debug.filename);
-        printf("%s:%d: ", str, b->debug.line_num);
-    }
-
-    str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->func_name);
-    printf("function: %s%s\n", &"*"[b->func_kind != JS_FUNC_GENERATOR], str);
-    if (b->js_mode) {
-        printf("  mode:");
-        if (b->js_mode & JS_MODE_STRICT)
-            printf(" strict");
-#ifdef CONFIG_BIGNUM
-        if (b->js_mode & JS_MODE_MATH)
-            printf(" math");
-#endif
-        printf("\n");
-    }
-    if (b->arg_count && b->vardefs) {
-        printf("  args:");
-        for(i = 0; i < b->arg_count; i++) {
-            printf(" %s", JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf),
-                                        b->vardefs[i].var_name));
-        }
-        printf("\n");
-    }
-    if (b->var_count && b->vardefs) {
-        printf("  locals:\n");
-        for(i = 0; i < b->var_count; i++) {
-            JSVarDef *vd = &b->vardefs[b->arg_count + i];
-            printf("%5d: %s %s", i,
-                   vd->var_kind == JS_VAR_CATCH ? "catch" :
-                   (vd->var_kind == JS_VAR_FUNCTION_DECL ||
-                    vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) ? "function" :
-                   vd->is_const ? "const" :
-                   vd->is_lexical ? "let" : "var",
-                   JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), vd->var_name));
-            if (vd->scope_level)
-                printf(" [level:%d next:%d]", vd->scope_level, vd->scope_next);
-            printf("\n");
-        }
-    }
-    if (b->closure_var_count) {
-        printf("  closure vars:\n");
-        for(i = 0; i < b->closure_var_count; i++) {
-            JSClosureVar *cv = &b->closure_var[i];
-            printf("%5d: %s %s:%s%d %s\n", i,
-                   JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), cv->var_name),
-                   cv->is_local ? "local" : "parent",
-                   cv->is_arg ? "arg" : "loc", cv->var_idx,
-                   cv->is_const ? "const" :
-                   cv->is_lexical ? "let" : "var");
-        }
-    }
-    printf("  stack_size: %d\n", b->stack_size);
-    printf("  opcodes:\n");
-    dump_byte_code(ctx, 3, b->byte_code_buf, b->byte_code_len,
-                   b->vardefs, b->arg_count,
-                   b->vardefs ? b->vardefs + b->arg_count : NULL, b->var_count,
-                   b->closure_var, b->closure_var_count,
-                   b->cpool, b->cpool_count,
-                   b->has_debug ? b->debug.source : NULL,
-                   b->has_debug ? b->debug.line_num : -1, NULL, b);
-#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 32)
-    if (b->has_debug)
-        dump_pc2line(ctx, b->debug.pc2line_buf, b->debug.pc2line_len, b->debug.line_num);
-#endif
-    printf("\n");
-}
-#endif
-
-static int add_closure_var(JSContext *ctx, JSFunctionDef *s,
-                           BOOL is_local, BOOL is_arg,
-                           int var_idx, JSAtom var_name,
-                           BOOL is_const, BOOL is_lexical,
-                           JSVarKindEnum var_kind)
-{
-    JSClosureVar *cv;
-
-    /* the closure variable indexes are currently stored on 16 bits */
-    if (s->closure_var_count >= JS_MAX_LOCAL_VARS) {
-        JS_ThrowInternalError(ctx, "too many closure variables");
-        return -1;
-    }
-
-    if (js_resize_array(ctx, (void **)&s->closure_var,
-                        sizeof(s->closure_var[0]),
-                        &s->closure_var_size, s->closure_var_count + 1))
-        return -1;
-    cv = &s->closure_var[s->closure_var_count++];
-    cv->is_local = is_local;
-    cv->is_arg = is_arg;
-    cv->is_const = is_const;
-    cv->is_lexical = is_lexical;
-    cv->var_kind = var_kind;
-    cv->var_idx = var_idx;
-    cv->var_name = JS_DupAtom(ctx, var_name);
-    return s->closure_var_count - 1;
-}
-
-static int find_closure_var(JSContext *ctx, JSFunctionDef *s,
-                            JSAtom var_name)
-{
-    int i;
-    for(i = 0; i < s->closure_var_count; i++) {
-        JSClosureVar *cv = &s->closure_var[i];
-        if (cv->var_name == var_name)
-            return i;
-    }
-    return -1;
-}
-
-/* 'fd' must be a parent of 's'. Create in 's' a closure referencing a
-   local variable (is_local = TRUE) or a closure (is_local = FALSE) in
-   'fd' */
-static int get_closure_var2(JSContext *ctx, JSFunctionDef *s,
-                            JSFunctionDef *fd, BOOL is_local,
-                            BOOL is_arg, int var_idx, JSAtom var_name,
-                            BOOL is_const, BOOL is_lexical,
-                            JSVarKindEnum var_kind)
-{
-    int i;
-
-    if (fd != s->parent) {
-        var_idx = get_closure_var2(ctx, s->parent, fd, is_local,
-                                   is_arg, var_idx, var_name,
-                                   is_const, is_lexical, var_kind);
-        if (var_idx < 0)
-            return -1;
-        is_local = FALSE;
-    }
-    for(i = 0; i < s->closure_var_count; i++) {
-        JSClosureVar *cv = &s->closure_var[i];
-        if (cv->var_idx == var_idx && cv->is_arg == is_arg &&
-            cv->is_local == is_local)
-            return i;
-    }
-    return add_closure_var(ctx, s, is_local, is_arg, var_idx, var_name,
-                           is_const, is_lexical, var_kind);
-}
-
-static int get_closure_var(JSContext *ctx, JSFunctionDef *s,
-                           JSFunctionDef *fd, BOOL is_arg,
-                           int var_idx, JSAtom var_name,
-                           BOOL is_const, BOOL is_lexical,
-                           JSVarKindEnum var_kind)
-{
-    return get_closure_var2(ctx, s, fd, TRUE, is_arg,
-                            var_idx, var_name, is_const, is_lexical,
-                            var_kind);
-}
-
-static int get_with_scope_opcode(int op)
-{
-    if (op == OP_scope_get_var_undef)
-        return OP_with_get_var;
-    else
-        return OP_with_get_var + (op - OP_scope_get_var);
-}
-
-static BOOL can_opt_put_ref_value(const uint8_t *bc_buf, int pos)
-{
-    int opcode = bc_buf[pos];
-    return (bc_buf[pos + 1] == OP_put_ref_value &&
-            (opcode == OP_insert3 ||
-             opcode == OP_perm4 ||
-             opcode == OP_nop ||
-             opcode == OP_rot3l));
-}
-
-static BOOL can_opt_put_global_ref_value(const uint8_t *bc_buf, int pos)
-{
-    int opcode = bc_buf[pos];
-    return (bc_buf[pos + 1] == OP_put_ref_value &&
-            (opcode == OP_insert3 ||
-             opcode == OP_perm4 ||
-             opcode == OP_nop ||
-             opcode == OP_rot3l));
-}
-
-static int optimize_scope_make_ref(JSContext *ctx, JSFunctionDef *s,
-                                   DynBuf *bc, uint8_t *bc_buf,
-                                   LabelSlot *ls, int pos_next,
-                                   int get_op, int var_idx)
-{
-    int label_pos, end_pos, pos;
-
-    /* XXX: should optimize `loc(a) += expr` as `expr add_loc(a)`
-       but only if expr does not modify `a`.
-       should scan the code between pos_next and label_pos
-       for operations that can potentially change `a`:
-       OP_scope_make_ref(a), function calls, jumps and gosub.
-     */
-    /* replace the reference get/put with normal variable
-       accesses */
-    if (bc_buf[pos_next] == OP_get_ref_value) {
-        dbuf_putc(bc, get_op);
-        dbuf_put_u16(bc, var_idx);
-        pos_next++;
-    }
-    /* remove the OP_label to make room for replacement */
-    /* label should have a refcount of 0 anyway */
-    /* XXX: should avoid this patch by inserting nops in phase 1 */
-    label_pos = ls->pos;
-    pos = label_pos - 5;
-    assert(bc_buf[pos] == OP_label);
-    /* label points to an instruction pair:
-       - insert3 / put_ref_value
-       - perm4 / put_ref_value
-       - rot3l / put_ref_value
-       - nop / put_ref_value
-     */
-    end_pos = label_pos + 2;
-    if (bc_buf[label_pos] == OP_insert3)
-        bc_buf[pos++] = OP_dup;
-    bc_buf[pos] = get_op + 1;
-    put_u16(bc_buf + pos + 1, var_idx);
-    pos += 3;
-    /* pad with OP_nop */
-    while (pos < end_pos)
-        bc_buf[pos++] = OP_nop;
-    return pos_next;
-}
-
-static int optimize_scope_make_global_ref(JSContext *ctx, JSFunctionDef *s,
-                                          DynBuf *bc, uint8_t *bc_buf,
-                                          LabelSlot *ls, int pos_next,
-                                          JSAtom var_name)
-{
-    int label_pos, end_pos, pos, op;
-    BOOL is_strict;
-    is_strict = ((s->js_mode & JS_MODE_STRICT) != 0);
-
-    /* replace the reference get/put with normal variable
-       accesses */
-    if (is_strict) {
-        /* need to check if the variable exists before evaluating the right
-           expression */
-        /* XXX: need an extra OP_true if destructuring an array */
-        dbuf_putc(bc, OP_check_var);
-        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-    } else {
-        /* XXX: need 2 extra OP_true if destructuring an array */
-    }
-    if (bc_buf[pos_next] == OP_get_ref_value) {
-        dbuf_putc(bc, OP_get_var);
-        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-        pos_next++;
-    }
-    /* remove the OP_label to make room for replacement */
-    /* label should have a refcount of 0 anyway */
-    /* XXX: should have emitted several OP_nop to avoid this kludge */
-    label_pos = ls->pos;
-    pos = label_pos - 5;
-    assert(bc_buf[pos] == OP_label);
-    end_pos = label_pos + 2;
-    op = bc_buf[label_pos];
-    if (is_strict) {
-        if (op != OP_nop) {
-            switch(op) {
-            case OP_insert3:
-                op = OP_insert2;
-                break;
-            case OP_perm4:
-                op = OP_perm3;
-                break;
-            case OP_rot3l:
-                op = OP_swap;
-                break;
-            default:
-                abort();
-            }
-            bc_buf[pos++] = op;
-        }
-    } else {
-        if (op == OP_insert3)
-            bc_buf[pos++] = OP_dup;
-    }
-    if (is_strict) {
-        bc_buf[pos] = OP_put_var_strict;
-        /* XXX: need 1 extra OP_drop if destructuring an array */
-    } else {
-        bc_buf[pos] = OP_put_var;
-        /* XXX: need 2 extra OP_drop if destructuring an array */
-    }
-    put_u32(bc_buf + pos + 1, JS_DupAtom(ctx, var_name));
-    pos += 5;
-    /* pad with OP_nop */
-    while (pos < end_pos)
-        bc_buf[pos++] = OP_nop;
-    return pos_next;
-}
-
-static int add_var_this(JSContext *ctx, JSFunctionDef *fd)
-{
-    int idx;
-    idx = add_var(ctx, fd, JS_ATOM_this);
-    if (idx >= 0 && fd->is_derived_class_constructor) {
-        JSVarDef *vd = &fd->vars[idx];
-        /* XXX: should have is_this flag or var type */
-        vd->is_lexical = 1; /* used to trigger 'uninitialized' checks
-                               in a derived class constructor */
-    }
-    return idx;
-}
-
-static int resolve_pseudo_var(JSContext *ctx, JSFunctionDef *s,
-                               JSAtom var_name)
-{
-    int var_idx;
-
-    if (!s->has_this_binding)
-        return -1;
-    switch(var_name) {
-    case JS_ATOM_home_object:
-        /* 'home_object' pseudo variable */
-        if (s->home_object_var_idx < 0)
-            s->home_object_var_idx = add_var(ctx, s, var_name);
-        var_idx = s->home_object_var_idx;
-        break;
-    case JS_ATOM_this_active_func:
-        /* 'this.active_func' pseudo variable */
-        if (s->this_active_func_var_idx < 0)
-            s->this_active_func_var_idx = add_var(ctx, s, var_name);
-        var_idx = s->this_active_func_var_idx;
-        break;
-    case JS_ATOM_new_target:
-        /* 'new.target' pseudo variable */
-        if (s->new_target_var_idx < 0)
-            s->new_target_var_idx = add_var(ctx, s, var_name);
-        var_idx = s->new_target_var_idx;
-        break;
-    case JS_ATOM_this:
-        /* 'this' pseudo variable */
-        if (s->this_var_idx < 0)
-            s->this_var_idx = add_var_this(ctx, s);
-        var_idx = s->this_var_idx;
-        break;
-    default:
-        var_idx = -1;
-        break;
-    }
-    return var_idx;
-}
-
-/* test if 'var_name' is in the variable object on the stack. If is it
-   the case, handle it and jump to 'label_done' */
-static void var_object_test(JSContext *ctx, JSFunctionDef *s,
-                            JSAtom var_name, int op, DynBuf *bc,
-                            int *plabel_done, BOOL is_with)
-{
-    dbuf_putc(bc, get_with_scope_opcode(op));
-    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-    *plabel_done = new_label_fd(s, *plabel_done);
-    dbuf_put_u32(bc, *plabel_done);
-    dbuf_putc(bc, is_with);
-    update_label(s, *plabel_done, 1);
-    s->jump_size++;
-}
-    
-/* return the position of the next opcode */
-static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
-                             JSAtom var_name, int scope_level, int op,
-                             DynBuf *bc, uint8_t *bc_buf,
-                             LabelSlot *ls, int pos_next)
-{
-    int idx, var_idx, is_put;
-    int label_done;
-    JSFunctionDef *fd;
-    JSVarDef *vd;
-    BOOL is_pseudo_var, is_arg_scope;
-
-    label_done = -1;
-
-    /* XXX: could be simpler to use a specific function to
-       resolve the pseudo variables */
-    is_pseudo_var = (var_name == JS_ATOM_home_object ||
-                     var_name == JS_ATOM_this_active_func ||
-                     var_name == JS_ATOM_new_target ||
-                     var_name == JS_ATOM_this);
-
-    /* resolve local scoped variables */
-    var_idx = -1;
-    for (idx = s->scopes[scope_level].first; idx >= 0;) {
-        vd = &s->vars[idx];
-        if (vd->var_name == var_name) {
-            if (op == OP_scope_put_var || op == OP_scope_make_ref) {
-                if (vd->is_const) {
-                    dbuf_putc(bc, OP_throw_error);
-                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-                    dbuf_putc(bc, JS_THROW_VAR_RO);
-                    goto done;
-                }
-            }
-            var_idx = idx;
-            break;
-        } else
-        if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
-            dbuf_putc(bc, OP_get_loc);
-            dbuf_put_u16(bc, idx);
-            var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
-        }
-        idx = vd->scope_next;
-    }
-    is_arg_scope = (idx == ARG_SCOPE_END);
-    if (var_idx < 0) {
-        /* argument scope: variables are not visible but pseudo
-           variables are visible */
-        if (!is_arg_scope) {
-            var_idx = find_var(ctx, s, var_name);
-        }
-
-        if (var_idx < 0 && is_pseudo_var)
-            var_idx = resolve_pseudo_var(ctx, s, var_name);
-
-        if (var_idx < 0 && var_name == JS_ATOM_arguments &&
-            s->has_arguments_binding) {
-            /* 'arguments' pseudo variable */
-            var_idx = add_arguments_var(ctx, s);
-        }
-        if (var_idx < 0 && s->is_func_expr && var_name == s->func_name) {
-            /* add a new variable with the function name */
-            var_idx = add_func_var(ctx, s, var_name);
-        }
-    }
-    if (var_idx >= 0) {
-        if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&
-            !(var_idx & ARGUMENT_VAR_OFFSET) &&
-            s->vars[var_idx].is_const) {
-            /* only happens when assigning a function expression name
-               in strict mode */
-            dbuf_putc(bc, OP_throw_error);
-            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-            dbuf_putc(bc, JS_THROW_VAR_RO);
-            goto done;
-        }
-        /* OP_scope_put_var_init is only used to initialize a
-           lexical variable, so it is never used in a with or var object. It
-           can be used with a closure (module global variable case). */
-        switch (op) {
-        case OP_scope_make_ref:
-            if (!(var_idx & ARGUMENT_VAR_OFFSET) &&
-                s->vars[var_idx].var_kind == JS_VAR_FUNCTION_NAME) {
-                /* Create a dummy object reference for the func_var */
-                dbuf_putc(bc, OP_object);
-                dbuf_putc(bc, OP_get_loc);
-                dbuf_put_u16(bc, var_idx);
-                dbuf_putc(bc, OP_define_field);
-                dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-                dbuf_putc(bc, OP_push_atom_value);
-                dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-            } else
-            if (label_done == -1 && can_opt_put_ref_value(bc_buf, ls->pos)) {
-                int get_op;
-                if (var_idx & ARGUMENT_VAR_OFFSET) {
-                    get_op = OP_get_arg;
-                    var_idx -= ARGUMENT_VAR_OFFSET;
-                } else {
-                    if (s->vars[var_idx].is_lexical)
-                        get_op = OP_get_loc_check;
-                    else
-                        get_op = OP_get_loc;
-                }
-                pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,
-                                                   pos_next, get_op, var_idx);
-            } else {
-                /* Create a dummy object with a named slot that is
-                   a reference to the local variable */
-                if (var_idx & ARGUMENT_VAR_OFFSET) {
-                    dbuf_putc(bc, OP_make_arg_ref);
-                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-                    dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
-                } else {
-                    dbuf_putc(bc, OP_make_loc_ref);
-                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-                    dbuf_put_u16(bc, var_idx);
-                }
-            }
-            break;
-        case OP_scope_get_ref:
-            dbuf_putc(bc, OP_undefined);
-            /* fall thru */
-        case OP_scope_get_var_undef:
-        case OP_scope_get_var:
-        case OP_scope_put_var:
-        case OP_scope_put_var_init:
-            is_put = (op == OP_scope_put_var || op == OP_scope_put_var_init);
-            if (var_idx & ARGUMENT_VAR_OFFSET) {
-                dbuf_putc(bc, OP_get_arg + is_put);
-                dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
-            } else {
-                if (is_put) {
-                    if (s->vars[var_idx].is_lexical) {
-                        if (op == OP_scope_put_var_init) {
-                            /* 'this' can only be initialized once */
-                            if (var_name == JS_ATOM_this)
-                                dbuf_putc(bc, OP_put_loc_check_init);
-                            else
-                                dbuf_putc(bc, OP_put_loc);
-                        } else {
-                            dbuf_putc(bc, OP_put_loc_check);
-                        }
-                    } else {
-                        dbuf_putc(bc, OP_put_loc);
-                    }
-                } else {
-                    if (s->vars[var_idx].is_lexical) {
-                        dbuf_putc(bc, OP_get_loc_check);
-                    } else {
-                        dbuf_putc(bc, OP_get_loc);
-                    }
-                }
-                dbuf_put_u16(bc, var_idx);
-            }
-            break;
-        case OP_scope_delete_var:
-            dbuf_putc(bc, OP_push_false);
-            break;
-        }
-        goto done;
-    }
-    /* check eval object */
-    if (!is_arg_scope && s->var_object_idx >= 0 && !is_pseudo_var) {
-        dbuf_putc(bc, OP_get_loc);
-        dbuf_put_u16(bc, s->var_object_idx);
-        var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
-    }
-    /* check eval object in argument scope */
-    if (s->arg_var_object_idx >= 0 && !is_pseudo_var) {
-        dbuf_putc(bc, OP_get_loc);
-        dbuf_put_u16(bc, s->arg_var_object_idx);
-        var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
-    }
-
-    /* check parent scopes */
-    for (fd = s; fd->parent;) {
-        scope_level = fd->parent_scope_level;
-        fd = fd->parent;
-        for (idx = fd->scopes[scope_level].first; idx >= 0;) {
-            vd = &fd->vars[idx];
-            if (vd->var_name == var_name) {
-                if (op == OP_scope_put_var || op == OP_scope_make_ref) {
-                    if (vd->is_const) {
-                        dbuf_putc(bc, OP_throw_error);
-                        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-                        dbuf_putc(bc, JS_THROW_VAR_RO);
-                        goto done;
-                    }
-                }
-                var_idx = idx;
-                break;
-            } else if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
-                vd->is_captured = 1;
-                idx = get_closure_var(ctx, s, fd, FALSE, idx, vd->var_name, FALSE, FALSE, JS_VAR_NORMAL);
-                if (idx >= 0) {
-                    dbuf_putc(bc, OP_get_var_ref);
-                    dbuf_put_u16(bc, idx);
-                    var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
-                }
-            }
-            idx = vd->scope_next;
-        }
-        is_arg_scope = (idx == ARG_SCOPE_END);
-        if (var_idx >= 0)
-            break;
-        
-        if (!is_arg_scope) {
-            var_idx = find_var(ctx, fd, var_name);
-            if (var_idx >= 0)
-                break;
-        }
-        if (is_pseudo_var) {
-            var_idx = resolve_pseudo_var(ctx, fd, var_name);
-            if (var_idx >= 0)
-                break;
-        }
-        if (var_name == JS_ATOM_arguments && fd->has_arguments_binding) {
-            var_idx = add_arguments_var(ctx, fd);
-            break;
-        }
-        if (fd->is_func_expr && fd->func_name == var_name) {
-            /* add a new variable with the function name */
-            var_idx = add_func_var(ctx, fd, var_name);
-            break;
-        }
-
-        /* check eval object */
-        if (!is_arg_scope && fd->var_object_idx >= 0 && !is_pseudo_var) {
-            vd = &fd->vars[fd->var_object_idx];
-            vd->is_captured = 1;
-            idx = get_closure_var(ctx, s, fd, FALSE,
-                                  fd->var_object_idx, vd->var_name,
-                                  FALSE, FALSE, JS_VAR_NORMAL);
-            dbuf_putc(bc, OP_get_var_ref);
-            dbuf_put_u16(bc, idx);
-            var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
-        }
-
-        /* check eval object in argument scope */
-        if (fd->arg_var_object_idx >= 0 && !is_pseudo_var) {
-            vd = &fd->vars[fd->arg_var_object_idx];
-            vd->is_captured = 1;
-            idx = get_closure_var(ctx, s, fd, FALSE,
-                                  fd->arg_var_object_idx, vd->var_name,
-                                  FALSE, FALSE, JS_VAR_NORMAL);
-            dbuf_putc(bc, OP_get_var_ref);
-            dbuf_put_u16(bc, idx);
-            var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
-        }
-        
-        if (fd->is_eval)
-            break; /* it it necessarily the top level function */
-    }
-
-    /* check direct eval scope (in the closure of the eval function
-       which is necessarily at the top level) */
-    if (!fd)
-        fd = s;
-    if (var_idx < 0 && fd->is_eval) {
-        int idx1;
-        for (idx1 = 0; idx1 < fd->closure_var_count; idx1++) {
-            JSClosureVar *cv = &fd->closure_var[idx1];
-            if (var_name == cv->var_name) {
-                if (fd != s) {
-                    idx = get_closure_var2(ctx, s, fd,
-                                           FALSE,
-                                           cv->is_arg, idx1,
-                                           cv->var_name, cv->is_const,
-                                           cv->is_lexical, cv->var_kind);
-                } else {
-                    idx = idx1;
-                }
-                goto has_idx;
-            } else if ((cv->var_name == JS_ATOM__var_ ||
-                        cv->var_name == JS_ATOM__arg_var_ ||
-                        cv->var_name == JS_ATOM__with_) && !is_pseudo_var) {
-                int is_with = (cv->var_name == JS_ATOM__with_);
-                if (fd != s) {
-                    idx = get_closure_var2(ctx, s, fd,
-                                           FALSE,
-                                           cv->is_arg, idx1,
-                                           cv->var_name, FALSE, FALSE,
-                                           JS_VAR_NORMAL);
-                } else {
-                    idx = idx1;
-                }
-                dbuf_putc(bc, OP_get_var_ref);
-                dbuf_put_u16(bc, idx);
-                var_object_test(ctx, s, var_name, op, bc, &label_done, is_with);
-            }
-        }
-    }
-
-    if (var_idx >= 0) {
-        /* find the corresponding closure variable */
-        if (var_idx & ARGUMENT_VAR_OFFSET) {
-            fd->args[var_idx - ARGUMENT_VAR_OFFSET].is_captured = 1;
-            idx = get_closure_var(ctx, s, fd,
-                                  TRUE, var_idx - ARGUMENT_VAR_OFFSET,
-                                  var_name, FALSE, FALSE, JS_VAR_NORMAL);
-        } else {
-            fd->vars[var_idx].is_captured = 1;
-            idx = get_closure_var(ctx, s, fd,
-                                  FALSE, var_idx,
-                                  var_name,
-                                  fd->vars[var_idx].is_const,
-                                  fd->vars[var_idx].is_lexical,
-                                  fd->vars[var_idx].var_kind);
-        }
-        if (idx >= 0) {
-        has_idx:
-            if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&
-                s->closure_var[idx].is_const) {
-                dbuf_putc(bc, OP_throw_error);
-                dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-                dbuf_putc(bc, JS_THROW_VAR_RO);
-                goto done;
-            }
-            switch (op) {
-            case OP_scope_make_ref:
-                if (s->closure_var[idx].var_kind == JS_VAR_FUNCTION_NAME) {
-                    /* Create a dummy object reference for the func_var */
-                    dbuf_putc(bc, OP_object);
-                    dbuf_putc(bc, OP_get_var_ref);
-                    dbuf_put_u16(bc, idx);
-                    dbuf_putc(bc, OP_define_field);
-                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-                    dbuf_putc(bc, OP_push_atom_value);
-                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-                } else
-                if (label_done == -1 &&
-                    can_opt_put_ref_value(bc_buf, ls->pos)) {
-                    int get_op;
-                    if (s->closure_var[idx].is_lexical)
-                        get_op = OP_get_var_ref_check;
-                    else
-                        get_op = OP_get_var_ref;
-                    pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,
-                                                       pos_next,
-                                                       get_op, idx);
-                } else {
-                    /* Create a dummy object with a named slot that is
-                       a reference to the closure variable */
-                    dbuf_putc(bc, OP_make_var_ref_ref);
-                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-                    dbuf_put_u16(bc, idx);
-                }
-                break;
-            case OP_scope_get_ref:
-                /* XXX: should create a dummy object with a named slot that is
-                   a reference to the closure variable */
-                dbuf_putc(bc, OP_undefined);
-                /* fall thru */
-            case OP_scope_get_var_undef:
-            case OP_scope_get_var:
-            case OP_scope_put_var:
-            case OP_scope_put_var_init:
-                is_put = (op == OP_scope_put_var ||
-                          op == OP_scope_put_var_init);
-                if (is_put) {
-                    if (s->closure_var[idx].is_lexical) {
-                        if (op == OP_scope_put_var_init) {
-                            /* 'this' can only be initialized once */
-                            if (var_name == JS_ATOM_this)
-                                dbuf_putc(bc, OP_put_var_ref_check_init);
-                            else
-                                dbuf_putc(bc, OP_put_var_ref);
-                        } else {
-                            dbuf_putc(bc, OP_put_var_ref_check);
-                        }
-                    } else {
-                        dbuf_putc(bc, OP_put_var_ref);
-                    }
-                } else {
-                    if (s->closure_var[idx].is_lexical) {
-                        dbuf_putc(bc, OP_get_var_ref_check);
-                    } else {
-                        dbuf_putc(bc, OP_get_var_ref);
-                    }
-                }
-                dbuf_put_u16(bc, idx);
-                break;
-            case OP_scope_delete_var:
-                dbuf_putc(bc, OP_push_false);
-                break;
-            }
-            goto done;
-        }
-    }
-
-    /* global variable access */
-
-    switch (op) {
-    case OP_scope_make_ref:
-        if (label_done == -1 && can_opt_put_global_ref_value(bc_buf, ls->pos)) {
-            pos_next = optimize_scope_make_global_ref(ctx, s, bc, bc_buf, ls,
-                                                      pos_next, var_name);
-        } else {
-            dbuf_putc(bc, OP_make_var_ref);
-            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-        }
-        break;
-    case OP_scope_get_ref:
-        /* XXX: should create a dummy object with a named slot that is
-           a reference to the global variable */
-        dbuf_putc(bc, OP_undefined);
-        dbuf_putc(bc, OP_get_var);
-        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-        break;
-    case OP_scope_get_var_undef:
-    case OP_scope_get_var:
-    case OP_scope_put_var:
-        dbuf_putc(bc, OP_get_var_undef + (op - OP_scope_get_var_undef));
-        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-        break;
-    case OP_scope_put_var_init:
-        dbuf_putc(bc, OP_put_var_init);
-        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-        break;
-    case OP_scope_delete_var:
-        dbuf_putc(bc, OP_delete_var);
-        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-        break;
-    }
-done:
-    if (label_done >= 0) {
-        dbuf_putc(bc, OP_label);
-        dbuf_put_u32(bc, label_done);
-        s->label_slots[label_done].pos2 = bc->size;
-    }
-    return pos_next;
-}
-
-/* search in all scopes */
-static int find_private_class_field_all(JSContext *ctx, JSFunctionDef *fd,
-                                        JSAtom name, int scope_level)
-{
-    int idx;
-
-    idx = fd->scopes[scope_level].first;
-    while (idx >= 0) {
-        if (fd->vars[idx].var_name == name)
-            return idx;
-        idx = fd->vars[idx].scope_next;
-    }
-    return -1;
-}
-
-static void get_loc_or_ref(DynBuf *bc, BOOL is_ref, int idx)
-{
-    /* if the field is not initialized, the error is catched when
-       accessing it */
-    if (is_ref) 
-        dbuf_putc(bc, OP_get_var_ref);
-    else
-        dbuf_putc(bc, OP_get_loc);
-    dbuf_put_u16(bc, idx);
-}
-
-static int resolve_scope_private_field1(JSContext *ctx,
-                                        BOOL *pis_ref, int *pvar_kind,
-                                        JSFunctionDef *s,
-                                        JSAtom var_name, int scope_level)
-{
-    int idx, var_kind;
-    JSFunctionDef *fd;
-    BOOL is_ref;
-    
-    fd = s;
-    is_ref = FALSE;
-    for(;;) {
-        idx = find_private_class_field_all(ctx, fd, var_name, scope_level);
-        if (idx >= 0) {
-            var_kind = fd->vars[idx].var_kind;
-            if (is_ref) {
-                idx = get_closure_var(ctx, s, fd, FALSE, idx, var_name,
-                                      TRUE, TRUE, JS_VAR_NORMAL);
-                if (idx < 0)
-                    return -1;
-            }
-            break;
-        }
-        scope_level = fd->parent_scope_level;
-        if (!fd->parent) {
-            if (fd->is_eval) {
-                /* closure of the eval function (top level) */
-                for (idx = 0; idx < fd->closure_var_count; idx++) {
-                    JSClosureVar *cv = &fd->closure_var[idx];
-                    if (cv->var_name == var_name) {
-                        var_kind = cv->var_kind;
-                        is_ref = TRUE;
-                        if (fd != s) {
-                            idx = get_closure_var2(ctx, s, fd,
-                                                   FALSE,
-                                                   cv->is_arg, idx,
-                                                   cv->var_name, cv->is_const,
-                                                   cv->is_lexical,
-                                                   cv->var_kind);
-                            if (idx < 0)
-                                return -1;
-                        }
-                        goto done;
-                    }
-                }
-            }
-            /* XXX: no line number info */
-            JS_ThrowSyntaxErrorAtom(ctx, "undefined private field '%s'",
-                                    var_name);
-            return -1;
-        } else {
-            fd = fd->parent;
-        }
-        is_ref = TRUE;
-    }
- done:
-    *pis_ref = is_ref;
-    *pvar_kind = var_kind;
-    return idx;
-}
-
-/* return 0 if OK or -1 if the private field could not be resolved */
-static int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s,
-                                       JSAtom var_name, int scope_level, int op,
-                                       DynBuf *bc)
-{
-    int idx, var_kind;
-    BOOL is_ref;
-
-    idx = resolve_scope_private_field1(ctx, &is_ref, &var_kind, s,
-                                       var_name, scope_level);
-    if (idx < 0)
-        return -1;
-    assert(var_kind != JS_VAR_NORMAL);
-    switch (op) {
-    case OP_scope_get_private_field:
-    case OP_scope_get_private_field2:
-        switch(var_kind) {
-        case JS_VAR_PRIVATE_FIELD:
-            if (op == OP_scope_get_private_field2)
-                dbuf_putc(bc, OP_dup);
-            get_loc_or_ref(bc, is_ref, idx);
-            dbuf_putc(bc, OP_get_private_field);
-            break;
-        case JS_VAR_PRIVATE_METHOD:
-            get_loc_or_ref(bc, is_ref, idx);
-            dbuf_putc(bc, OP_check_brand);
-            if (op != OP_scope_get_private_field2)
-                dbuf_putc(bc, OP_nip);
-            break;
-        case JS_VAR_PRIVATE_GETTER:
-        case JS_VAR_PRIVATE_GETTER_SETTER:
-            if (op == OP_scope_get_private_field2)
-                dbuf_putc(bc, OP_dup);
-            get_loc_or_ref(bc, is_ref, idx);
-            dbuf_putc(bc, OP_check_brand);
-            dbuf_putc(bc, OP_call_method);
-            dbuf_put_u16(bc, 0);
-            break;
-        case JS_VAR_PRIVATE_SETTER:
-            /* XXX: add clearer error message */
-            dbuf_putc(bc, OP_throw_error);
-            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-            dbuf_putc(bc, JS_THROW_VAR_RO);
-            break;
-        default:
-            abort();
-        }
-        break;
-    case OP_scope_put_private_field:
-        switch(var_kind) {
-        case JS_VAR_PRIVATE_FIELD:
-            get_loc_or_ref(bc, is_ref, idx);
-            dbuf_putc(bc, OP_put_private_field);
-            break;
-        case JS_VAR_PRIVATE_METHOD:
-        case JS_VAR_PRIVATE_GETTER:
-            /* XXX: add clearer error message */
-            dbuf_putc(bc, OP_throw_error);
-            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
-            dbuf_putc(bc, JS_THROW_VAR_RO);
-            break;
-        case JS_VAR_PRIVATE_SETTER:
-        case JS_VAR_PRIVATE_GETTER_SETTER:
-            {
-                JSAtom setter_name = get_private_setter_name(ctx, var_name);
-                if (setter_name == JS_ATOM_NULL)
-                    return -1;
-                idx = resolve_scope_private_field1(ctx, &is_ref,
-                                                   &var_kind, s,
-                                                   setter_name, scope_level);
-                JS_FreeAtom(ctx, setter_name);
-                if (idx < 0)
-                    return -1;
-                assert(var_kind == JS_VAR_PRIVATE_SETTER);
-                get_loc_or_ref(bc, is_ref, idx);
-                dbuf_putc(bc, OP_swap);
-                /* obj func value */
-                dbuf_putc(bc, OP_rot3r);
-                /* value obj func */
-                dbuf_putc(bc, OP_check_brand);
-                dbuf_putc(bc, OP_rot3l);
-                /* obj func value */
-                dbuf_putc(bc, OP_call_method);
-                dbuf_put_u16(bc, 1);
-            }
-            break;
-        default:
-            abort();
-        }
-        break;
-    default:
-        abort();
-    }
-    return 0;
-}
-
-static void mark_eval_captured_variables(JSContext *ctx, JSFunctionDef *s,
-                                         int scope_level)
-{
-    int idx;
-    JSVarDef *vd;
-
-    for (idx = s->scopes[scope_level].first; idx >= 0;) {
-        vd = &s->vars[idx];
-        vd->is_captured = 1;
-        idx = vd->scope_next;
-    }
-}
-
-/* XXX: should handle the argument scope generically */
-static BOOL is_var_in_arg_scope(const JSVarDef *vd)
-{
-    return (vd->var_name == JS_ATOM_home_object ||
-            vd->var_name == JS_ATOM_this_active_func ||
-            vd->var_name == JS_ATOM_new_target ||
-            vd->var_name == JS_ATOM_this ||
-            vd->var_name == JS_ATOM__arg_var_ ||
-            vd->var_kind == JS_VAR_FUNCTION_NAME);
-}
-
-static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
-{
-    JSFunctionDef *fd;
-    JSVarDef *vd;
-    int i, scope_level, scope_idx;
-    BOOL has_arguments_binding, has_this_binding, is_arg_scope;
-
-    /* in non strict mode, variables are created in the caller's
-       environment object */
-    if (!s->is_eval && !(s->js_mode & JS_MODE_STRICT)) {
-        s->var_object_idx = add_var(ctx, s, JS_ATOM__var_);
-        if (s->has_parameter_expressions) {
-            /* an additional variable object is needed for the
-               argument scope */
-            s->arg_var_object_idx = add_var(ctx, s, JS_ATOM__arg_var_);
-        }
-    }
-
-    /* eval can potentially use 'arguments' so we must define it */
-    has_this_binding = s->has_this_binding;
-    if (has_this_binding) {
-        if (s->this_var_idx < 0)
-            s->this_var_idx = add_var_this(ctx, s);
-        if (s->new_target_var_idx < 0)
-            s->new_target_var_idx = add_var(ctx, s, JS_ATOM_new_target);
-        if (s->is_derived_class_constructor && s->this_active_func_var_idx < 0)
-            s->this_active_func_var_idx = add_var(ctx, s, JS_ATOM_this_active_func);
-        if (s->has_home_object && s->home_object_var_idx < 0)
-            s->home_object_var_idx = add_var(ctx, s, JS_ATOM_home_object);
-    }
-    has_arguments_binding = s->has_arguments_binding;
-    if (has_arguments_binding) {
-        add_arguments_var(ctx, s);
-        /* also add an arguments binding in the argument scope to
-           raise an error if a direct eval in the argument scope tries
-           to redefine it */
-        if (s->has_parameter_expressions && !(s->js_mode & JS_MODE_STRICT))
-            add_arguments_arg(ctx, s);
-    }
-    if (s->is_func_expr && s->func_name != JS_ATOM_NULL)
-        add_func_var(ctx, s, s->func_name);
-
-    /* eval can use all the variables of the enclosing functions, so
-       they must be all put in the closure. The closure variables are
-       ordered by scope. It works only because no closure are created
-       before. */
-    assert(s->is_eval || s->closure_var_count == 0);
-
-    /* XXX: inefficient, but eval performance is less critical */
-    fd = s;
-    for(;;) {
-        scope_level = fd->parent_scope_level;
-        fd = fd->parent;
-        if (!fd)
-            break;
-        /* add 'this' if it was not previously added */
-        if (!has_this_binding && fd->has_this_binding) {
-            if (fd->this_var_idx < 0)
-                fd->this_var_idx = add_var_this(ctx, fd);
-            if (fd->new_target_var_idx < 0)
-                fd->new_target_var_idx = add_var(ctx, fd, JS_ATOM_new_target);
-            if (fd->is_derived_class_constructor && fd->this_active_func_var_idx < 0)
-                fd->this_active_func_var_idx = add_var(ctx, fd, JS_ATOM_this_active_func);
-            if (fd->has_home_object && fd->home_object_var_idx < 0)
-                fd->home_object_var_idx = add_var(ctx, fd, JS_ATOM_home_object);
-            has_this_binding = TRUE;
-        }
-        /* add 'arguments' if it was not previously added */
-        if (!has_arguments_binding && fd->has_arguments_binding) {
-            add_arguments_var(ctx, fd);
-            has_arguments_binding = TRUE;
-        }
-        /* add function name */
-        if (fd->is_func_expr && fd->func_name != JS_ATOM_NULL)
-            add_func_var(ctx, fd, fd->func_name);
-
-        /* add lexical variables */
-        scope_idx = fd->scopes[scope_level].first;
-        while (scope_idx >= 0) {
-            vd = &fd->vars[scope_idx];
-            vd->is_captured = 1;
-            get_closure_var(ctx, s, fd, FALSE, scope_idx,
-                            vd->var_name, vd->is_const, vd->is_lexical, vd->var_kind);
-            scope_idx = vd->scope_next;
-        }
-        is_arg_scope = (scope_idx == ARG_SCOPE_END);
-        if (!is_arg_scope) {
-            /* add unscoped variables */
-            for(i = 0; i < fd->arg_count; i++) {
-                vd = &fd->args[i];
-                if (vd->var_name != JS_ATOM_NULL) {
-                    get_closure_var(ctx, s, fd,
-                                    TRUE, i, vd->var_name, FALSE, FALSE,
-                                    JS_VAR_NORMAL);
-                }
-            }
-            for(i = 0; i < fd->var_count; i++) {
-                vd = &fd->vars[i];
-                /* do not close top level last result */
-                if (vd->scope_level == 0 &&
-                    vd->var_name != JS_ATOM__ret_ &&
-                    vd->var_name != JS_ATOM_NULL) {
-                    get_closure_var(ctx, s, fd,
-                                    FALSE, i, vd->var_name, FALSE, FALSE,
-                                    JS_VAR_NORMAL);
-                }
-            }
-        } else {
-            for(i = 0; i < fd->var_count; i++) {
-                vd = &fd->vars[i];
-                /* do not close top level last result */
-                if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
-                    get_closure_var(ctx, s, fd,
-                                    FALSE, i, vd->var_name, FALSE, FALSE,
-                                    JS_VAR_NORMAL);
-                }
-            }
-        }
-        if (fd->is_eval) {
-            int idx;
-            /* add direct eval variables (we are necessarily at the
-               top level) */
-            for (idx = 0; idx < fd->closure_var_count; idx++) {
-                JSClosureVar *cv = &fd->closure_var[idx];
-                get_closure_var2(ctx, s, fd,
-                                 FALSE, cv->is_arg,
-                                 idx, cv->var_name, cv->is_const,
-                                 cv->is_lexical, cv->var_kind);
-            }
-        }
-    }
-}
-
-static void set_closure_from_var(JSContext *ctx, JSClosureVar *cv,
-                                 JSVarDef *vd, int var_idx)
-{
-    cv->is_local = TRUE;
-    cv->is_arg = FALSE;
-    cv->is_const = vd->is_const;
-    cv->is_lexical = vd->is_lexical;
-    cv->var_kind = vd->var_kind;
-    cv->var_idx = var_idx;
-    cv->var_name = JS_DupAtom(ctx, vd->var_name);
-}
-
-/* for direct eval compilation: add references to the variables of the
-   calling function */
-static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
-                                             JSFunctionBytecode *b, int scope_idx)
-{
-    int i, count;
-    JSVarDef *vd;
-    BOOL is_arg_scope;
-    
-    count = b->arg_count + b->var_count + b->closure_var_count;
-    s->closure_var = NULL;
-    s->closure_var_count = 0;
-    s->closure_var_size = count;
-    if (count == 0)
-        return 0;
-    s->closure_var = js_malloc(ctx, sizeof(s->closure_var[0]) * count);
-    if (!s->closure_var)
-        return -1;
-    /* Add lexical variables in scope at the point of evaluation */
-    for (i = scope_idx; i >= 0;) {
-        vd = &b->vardefs[b->arg_count + i];
-        if (vd->scope_level > 0) {
-            JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
-            set_closure_from_var(ctx, cv, vd, i);
-        }
-        i = vd->scope_next;
-    }
-    is_arg_scope = (i == ARG_SCOPE_END);
-    if (!is_arg_scope) {
-        /* Add argument variables */
-        for(i = 0; i < b->arg_count; i++) {
-            JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
-            vd = &b->vardefs[i];
-            cv->is_local = TRUE;
-            cv->is_arg = TRUE;
-            cv->is_const = FALSE;
-            cv->is_lexical = FALSE;
-            cv->var_kind = JS_VAR_NORMAL;
-            cv->var_idx = i;
-            cv->var_name = JS_DupAtom(ctx, vd->var_name);
-        }
-        /* Add local non lexical variables */
-        for(i = 0; i < b->var_count; i++) {
-            vd = &b->vardefs[b->arg_count + i];
-            if (vd->scope_level == 0 && vd->var_name != JS_ATOM__ret_) {
-                JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
-                set_closure_from_var(ctx, cv, vd, i);
-            }
-        }
-    } else {
-        /* only add pseudo variables */
-        for(i = 0; i < b->var_count; i++) {
-            vd = &b->vardefs[b->arg_count + i];
-            if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
-                JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
-                set_closure_from_var(ctx, cv, vd, i);
-            }
-        }
-    }
-    for(i = 0; i < b->closure_var_count; i++) {
-        JSClosureVar *cv0 = &b->closure_var[i];
-        JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
-        cv->is_local = FALSE;
-        cv->is_arg = cv0->is_arg;
-        cv->is_const = cv0->is_const;
-        cv->is_lexical = cv0->is_lexical;
-        cv->var_kind = cv0->var_kind;
-        cv->var_idx = i;
-        cv->var_name = JS_DupAtom(ctx, cv0->var_name);
-    }
-    return 0;
-}
-
-typedef struct CodeContext {
-    const uint8_t *bc_buf; /* code buffer */
-    int bc_len;   /* length of the code buffer */
-    int pos;      /* position past the matched code pattern */
-    int line_num; /* last visited OP_line_num parameter or -1 */
-    int op;
-    int idx;
-    int label;
-    int val;
-    JSAtom atom;
-} CodeContext;
-
-#define M2(op1, op2)            ((op1) | ((op2) << 8))
-#define M3(op1, op2, op3)       ((op1) | ((op2) << 8) | ((op3) << 16))
-#define M4(op1, op2, op3, op4)  ((op1) | ((op2) << 8) | ((op3) << 16) | ((op4) << 24))
-
-static BOOL code_match(CodeContext *s, int pos, ...)
-{
-    const uint8_t *tab = s->bc_buf;
-    int op, len, op1, line_num, pos_next;
-    va_list ap;
-    BOOL ret = FALSE;
-
-    line_num = -1;
-    va_start(ap, pos);
-
-    for(;;) {
-        op1 = va_arg(ap, int);
-        if (op1 == -1) {
-            s->pos = pos;
-            s->line_num = line_num;
-            ret = TRUE;
-            break;
-        }
-        for (;;) {
-            if (pos >= s->bc_len)
-                goto done;
-            op = tab[pos];
-            len = opcode_info[op].size;
-            pos_next = pos + len;
-            if (pos_next > s->bc_len)
-                goto done;
-            if (op == OP_line_num) {
-                line_num = get_u32(tab + pos + 1);
-                pos = pos_next;
-            } else {
-                break;
-            }
-        }
-        if (op != op1) {
-            if (op1 == (uint8_t)op1 || !op)
-                break;
-            if (op != (uint8_t)op1
-            &&  op != (uint8_t)(op1 >> 8)
-            &&  op != (uint8_t)(op1 >> 16)
-            &&  op != (uint8_t)(op1 >> 24)) {
-                break;
-            }
-            s->op = op;
-        }
-
-        pos++;
-        switch(opcode_info[op].fmt) {
-        case OP_FMT_loc8:
-        case OP_FMT_u8:
-            {
-                int idx = tab[pos];
-                int arg = va_arg(ap, int);
-                if (arg == -1) {
-                    s->idx = idx;
-                } else {
-                    if (arg != idx)
-                        goto done;
-                }
-                break;
-            }
-        case OP_FMT_u16:
-        case OP_FMT_npop:
-        case OP_FMT_loc:
-        case OP_FMT_arg:
-        case OP_FMT_var_ref:
-            {
-                int idx = get_u16(tab + pos);
-                int arg = va_arg(ap, int);
-                if (arg == -1) {
-                    s->idx = idx;
-                } else {
-                    if (arg != idx)
-                        goto done;
-                }
-                break;
-            }
-        case OP_FMT_i32:
-        case OP_FMT_u32:
-        case OP_FMT_label:
-        case OP_FMT_const:
-            {
-                s->label = get_u32(tab + pos);
-                break;
-            }
-        case OP_FMT_label_u16:
-            {
-                s->label = get_u32(tab + pos);
-                s->val = get_u16(tab + pos + 4);
-                break;
-            }
-        case OP_FMT_atom:
-            {
-                s->atom = get_u32(tab + pos);
-                break;
-            }
-        case OP_FMT_atom_u8:
-            {
-                s->atom = get_u32(tab + pos);
-                s->val = get_u8(tab + pos + 4);
-                break;
-            }
-        case OP_FMT_atom_u16:
-            {
-                s->atom = get_u32(tab + pos);
-                s->val = get_u16(tab + pos + 4);
-                break;
-            }
-        case OP_FMT_atom_label_u8:
-            {
-                s->atom = get_u32(tab + pos);
-                s->label = get_u32(tab + pos + 4);
-                s->val = get_u8(tab + pos + 8);
-                break;
-            }
-        default:
-            break;
-        }
-        pos = pos_next;
-    }
- done:
-    va_end(ap);
-    return ret;
-}
-
-static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, DynBuf *bc)
-{
-    int i, idx, label_next = -1;
-
-    /* add the hoisted functions in arguments and local variables */
-    for(i = 0; i < s->arg_count; i++) {
-        JSVarDef *vd = &s->args[i];
-        if (vd->func_pool_idx >= 0) {
-            dbuf_putc(bc, OP_fclosure);
-            dbuf_put_u32(bc, vd->func_pool_idx);
-            dbuf_putc(bc, OP_put_arg);
-            dbuf_put_u16(bc, i);
-        }
-    }
-    for(i = 0; i < s->var_count; i++) {
-        JSVarDef *vd = &s->vars[i];
-        if (vd->scope_level == 0 && vd->func_pool_idx >= 0) {
-            dbuf_putc(bc, OP_fclosure);
-            dbuf_put_u32(bc, vd->func_pool_idx);
-            dbuf_putc(bc, OP_put_loc);
-            dbuf_put_u16(bc, i);
-        }
-    }
-
-    /* the module global variables must be initialized before
-       evaluating the module so that the exported functions are
-       visible if there are cyclic module references */
-    if (s->module) {
-        label_next = new_label_fd(s, -1);
-        
-        /* if 'this' is true, initialize the global variables and return */
-        dbuf_putc(bc, OP_push_this);
-        dbuf_putc(bc, OP_if_false);
-        dbuf_put_u32(bc, label_next);
-        update_label(s, label_next, 1);
-        s->jump_size++;
-    }
-    
-    /* add the global variables (only happens if s->is_global_var is
-       true) */
-    for(i = 0; i < s->global_var_count; i++) {
-        JSGlobalVar *hf = &s->global_vars[i];
-        int has_closure = 0;
-        BOOL force_init = hf->force_init;
-        /* we are in an eval, so the closure contains all the
-           enclosing variables */
-        /* If the outer function has a variable environment,
-           create a property for the variable there */
-        for(idx = 0; idx < s->closure_var_count; idx++) {
-            JSClosureVar *cv = &s->closure_var[idx];
-            if (cv->var_name == hf->var_name) {
-                has_closure = 2;
-                force_init = FALSE;
-                break;
-            }
-            if (cv->var_name == JS_ATOM__var_ ||
-                cv->var_name == JS_ATOM__arg_var_) {
-                dbuf_putc(bc, OP_get_var_ref);
-                dbuf_put_u16(bc, idx);
-                has_closure = 1;
-                force_init = TRUE;
-                break;
-            }
-        }
-        if (!has_closure) {
-            int flags;
-            
-            flags = 0;
-            if (s->eval_type != JS_EVAL_TYPE_GLOBAL)
-                flags |= JS_PROP_CONFIGURABLE;
-            if (hf->cpool_idx >= 0 && !hf->is_lexical) {
-                /* global function definitions need a specific handling */
-                dbuf_putc(bc, OP_fclosure);
-                dbuf_put_u32(bc, hf->cpool_idx);
-                
-                dbuf_putc(bc, OP_define_func);
-                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
-                dbuf_putc(bc, flags);
-                
-                goto done_global_var;
-            } else {
-                if (hf->is_lexical) {
-                    flags |= DEFINE_GLOBAL_LEX_VAR;
-                    if (!hf->is_const)
-                        flags |= JS_PROP_WRITABLE;
-                }
-                dbuf_putc(bc, OP_define_var);
-                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
-                dbuf_putc(bc, flags);
-            }
-        }
-        if (hf->cpool_idx >= 0 || force_init) {
-            if (hf->cpool_idx >= 0) {
-                dbuf_putc(bc, OP_fclosure);
-                dbuf_put_u32(bc, hf->cpool_idx);
-                if (hf->var_name == JS_ATOM__default_) {
-                    /* set default export function name */
-                    dbuf_putc(bc, OP_set_name);
-                    dbuf_put_u32(bc, JS_DupAtom(ctx, JS_ATOM_default));
-                }
-            } else {
-                dbuf_putc(bc, OP_undefined);
-            }
-            if (has_closure == 2) {
-                dbuf_putc(bc, OP_put_var_ref);
-                dbuf_put_u16(bc, idx);
-            } else if (has_closure == 1) {
-                dbuf_putc(bc, OP_define_field);
-                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
-                dbuf_putc(bc, OP_drop);
-            } else {
-                /* XXX: Check if variable is writable and enumerable */
-                dbuf_putc(bc, OP_put_var);
-                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
-            }
-        }
-    done_global_var:
-        JS_FreeAtom(ctx, hf->var_name);
-    }
-
-    if (s->module) {
-        dbuf_putc(bc, OP_return_undef);
-        
-        dbuf_putc(bc, OP_label);
-        dbuf_put_u32(bc, label_next);
-        s->label_slots[label_next].pos2 = bc->size;
-    }
-
-    js_free(ctx, s->global_vars);
-    s->global_vars = NULL;
-    s->global_var_count = 0;
-    s->global_var_size = 0;
-}
-
-static int skip_dead_code(JSFunctionDef *s, const uint8_t *bc_buf, int bc_len,
-                          int pos, int *linep)
-{
-    int op, len, label;
-
-    for (; pos < bc_len; pos += len) {
-        op = bc_buf[pos];
-        len = opcode_info[op].size;
-        if (op == OP_line_num) {
-            *linep = get_u32(bc_buf + pos + 1);
-        } else
-        if (op == OP_label) {
-            label = get_u32(bc_buf + pos + 1);
-            if (update_label(s, label, 0) > 0)
-                break;
-#if 0
-            if (s->label_slots[label].first_reloc) {
-                printf("line %d: unreferenced label %d:%d has relocations\n",
-                       *linep, label, s->label_slots[label].pos2);
-            }
-#endif
-            assert(s->label_slots[label].first_reloc == NULL);
-        } else {
-            /* XXX: output a warning for unreachable code? */
-            JSAtom atom;
-            switch(opcode_info[op].fmt) {
-            case OP_FMT_label:
-            case OP_FMT_label_u16:
-                label = get_u32(bc_buf + pos + 1);
-                update_label(s, label, -1);
-                break;
-            case OP_FMT_atom_label_u8:
-            case OP_FMT_atom_label_u16:
-                label = get_u32(bc_buf + pos + 5);
-                update_label(s, label, -1);
-                /* fall thru */
-            case OP_FMT_atom:
-            case OP_FMT_atom_u8:
-            case OP_FMT_atom_u16:
-                atom = get_u32(bc_buf + pos + 1);
-                JS_FreeAtom(s->ctx, atom);
-                break;
-            default:
-                break;
-            }
-        }
-    }
-    return pos;
-}
-
-static int get_label_pos(JSFunctionDef *s, int label)
-{
-    int i, pos;
-    for (i = 0; i < 20; i++) {
-        pos = s->label_slots[label].pos;
-        for (;;) {
-            switch (s->byte_code.buf[pos]) {
-            case OP_line_num:
-            case OP_label:
-                pos += 5;
-                continue;
-            case OP_goto:
-                label = get_u32(s->byte_code.buf + pos + 1);
-                break;
-            default:
-                return pos;
-            }
-            break;
-        }
-    }
-    return pos;
-}
-
-/* convert global variable accesses to local variables or closure
-   variables when necessary */
-static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
-{
-    int pos, pos_next, bc_len, op, len, i, idx, line_num;
-    uint8_t *bc_buf;
-    JSAtom var_name;
-    DynBuf bc_out;
-    CodeContext cc;
-    int scope;
-
-    cc.bc_buf = bc_buf = s->byte_code.buf;
-    cc.bc_len = bc_len = s->byte_code.size;
-    js_dbuf_init(ctx, &bc_out);
-
-    /* first pass for runtime checks (must be done before the
-       variables are created) */
-    for(i = 0; i < s->global_var_count; i++) {
-        JSGlobalVar *hf = &s->global_vars[i];
-        int flags;
-        
-        /* check if global variable (XXX: simplify) */
-        for(idx = 0; idx < s->closure_var_count; idx++) {
-            JSClosureVar *cv = &s->closure_var[idx];
-            if (cv->var_name == hf->var_name) {
-                if (s->eval_type == JS_EVAL_TYPE_DIRECT &&
-                    cv->is_lexical) {
-                    /* Check if a lexical variable is
-                       redefined as 'var'. XXX: Could abort
-                       compilation here, but for consistency
-                       with the other checks, we delay the
-                       error generation. */
-                    dbuf_putc(&bc_out, OP_throw_error);
-                    dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
-                    dbuf_putc(&bc_out, JS_THROW_VAR_REDECL);
-                }
-                goto next;
-            }
-            if (cv->var_name == JS_ATOM__var_ ||
-                cv->var_name == JS_ATOM__arg_var_)
-                goto next;
-        }
-        
-        dbuf_putc(&bc_out, OP_check_define_var);
-        dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
-        flags = 0;
-        if (hf->is_lexical)
-            flags |= DEFINE_GLOBAL_LEX_VAR;
-        if (hf->cpool_idx >= 0)
-            flags |= DEFINE_GLOBAL_FUNC_VAR;
-        dbuf_putc(&bc_out, flags);
-    next: ;
-    }
-
-    line_num = 0; /* avoid warning */
-    for (pos = 0; pos < bc_len; pos = pos_next) {
-        op = bc_buf[pos];
-        len = opcode_info[op].size;
-        pos_next = pos + len;
-        switch(op) {
-        case OP_line_num:
-            line_num = get_u32(bc_buf + pos + 1);
-            s->line_number_size++;
-            goto no_change;
-
-        case OP_eval: /* convert scope index to adjusted variable index */
-            {
-                int call_argc = get_u16(bc_buf + pos + 1);
-                scope = get_u16(bc_buf + pos + 1 + 2);
-                mark_eval_captured_variables(ctx, s, scope);
-                dbuf_putc(&bc_out, op);
-                dbuf_put_u16(&bc_out, call_argc);
-                dbuf_put_u16(&bc_out, s->scopes[scope].first + 1);
-            }
-            break;
-        case OP_apply_eval: /* convert scope index to adjusted variable index */
-            scope = get_u16(bc_buf + pos + 1);
-            mark_eval_captured_variables(ctx, s, scope);
-            dbuf_putc(&bc_out, op);
-            dbuf_put_u16(&bc_out, s->scopes[scope].first + 1);
-            break;
-        case OP_scope_get_var_undef:
-        case OP_scope_get_var:
-        case OP_scope_put_var:
-        case OP_scope_delete_var:
-        case OP_scope_get_ref:
-        case OP_scope_put_var_init:
-            var_name = get_u32(bc_buf + pos + 1);
-            scope = get_u16(bc_buf + pos + 5);
-            pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
-                                         NULL, NULL, pos_next);
-            JS_FreeAtom(ctx, var_name);
-            break;
-        case OP_scope_make_ref:
-            {
-                int label;
-                LabelSlot *ls;
-                var_name = get_u32(bc_buf + pos + 1);
-                label = get_u32(bc_buf + pos + 5);
-                scope = get_u16(bc_buf + pos + 9);
-                ls = &s->label_slots[label];
-                ls->ref_count--;  /* always remove label reference */
-                pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
-                                             bc_buf, ls, pos_next);
-                JS_FreeAtom(ctx, var_name);
-            }
-            break;
-        case OP_scope_get_private_field:
-        case OP_scope_get_private_field2:
-        case OP_scope_put_private_field:
-            {
-                int ret;
-                var_name = get_u32(bc_buf + pos + 1);
-                scope = get_u16(bc_buf + pos + 5);
-                ret = resolve_scope_private_field(ctx, s, var_name, scope, op, &bc_out);
-                if (ret < 0)
-                    goto fail;
-                JS_FreeAtom(ctx, var_name);
-            }
-            break;
-        case OP_gosub:
-            s->jump_size++;
-            if (OPTIMIZE) {
-                /* remove calls to empty finalizers  */
-                int label;
-                LabelSlot *ls;
-
-                label = get_u32(bc_buf + pos + 1);
-                assert(label >= 0 && label < s->label_count);
-                ls = &s->label_slots[label];
-                if (code_match(&cc, ls->pos, OP_ret, -1)) {
-                    ls->ref_count--;
-                    break;
-                }
-            }
-            goto no_change;
-        case OP_drop:
-            if (0) {
-                /* remove drops before return_undef */
-                /* do not perform this optimization in pass2 because
-                   it breaks patterns recognised in resolve_labels */
-                int pos1 = pos_next;
-                int line1 = line_num;
-                while (code_match(&cc, pos1, OP_drop, -1)) {
-                    if (cc.line_num >= 0) line1 = cc.line_num;
-                    pos1 = cc.pos;
-                }
-                if (code_match(&cc, pos1, OP_return_undef, -1)) {
-                    pos_next = pos1;
-                    if (line1 != -1 && line1 != line_num) {
-                        line_num = line1;
-                        s->line_number_size++;
-                        dbuf_putc(&bc_out, OP_line_num);
-                        dbuf_put_u32(&bc_out, line_num);
-                    }
-                    break;
-                }
-            }
-            goto no_change;
-        case OP_insert3:
-            if (OPTIMIZE) {
-                /* Transformation: insert3 put_array_el|put_ref_value drop -> put_array_el|put_ref_value */
-                if (code_match(&cc, pos_next, M2(OP_put_array_el, OP_put_ref_value), OP_drop, -1)) {
-                    dbuf_putc(&bc_out, cc.op);
-                    pos_next = cc.pos;
-                    if (cc.line_num != -1 && cc.line_num != line_num) {
-                        line_num = cc.line_num;
-                        s->line_number_size++;
-                        dbuf_putc(&bc_out, OP_line_num);
-                        dbuf_put_u32(&bc_out, line_num);
-                    }
-                    break;
-                }
-            }
-            goto no_change;
-
-        case OP_goto:
-            s->jump_size++;
-            /* fall thru */
-        case OP_tail_call:
-        case OP_tail_call_method:
-        case OP_return:
-        case OP_return_undef:
-        case OP_throw:
-        case OP_throw_error:
-        case OP_ret:
-            if (OPTIMIZE) {
-                /* remove dead code */
-                int line = -1;
-                dbuf_put(&bc_out, bc_buf + pos, len);
-                pos = skip_dead_code(s, bc_buf, bc_len, pos + len, &line);
-                pos_next = pos;
-                if (pos < bc_len && line >= 0 && line_num != line) {
-                    line_num = line;
-                    s->line_number_size++;
-                    dbuf_putc(&bc_out, OP_line_num);
-                    dbuf_put_u32(&bc_out, line_num);
-                }
-                break;
-            }
-            goto no_change;
-
-        case OP_label:
-            {
-                int label;
-                LabelSlot *ls;
-
-                label = get_u32(bc_buf + pos + 1);
-                assert(label >= 0 && label < s->label_count);
-                ls = &s->label_slots[label];
-                ls->pos2 = bc_out.size + opcode_info[op].size;
-            }
-            goto no_change;
-
-        case OP_enter_scope:
-            {
-                int scope_idx, scope = get_u16(bc_buf + pos + 1);
-
-                if (scope == s->body_scope) {
-                    instantiate_hoisted_definitions(ctx, s, &bc_out);
-                }
-
-                for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {
-                    JSVarDef *vd = &s->vars[scope_idx];
-                    if (vd->scope_level == scope) {
-                        if (scope_idx != s->arguments_arg_idx) {
-                            if (vd->var_kind == JS_VAR_FUNCTION_DECL ||
-                                vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) {
-                                /* Initialize lexical variable upon entering scope */
-                                dbuf_putc(&bc_out, OP_fclosure);
-                                dbuf_put_u32(&bc_out, vd->func_pool_idx);
-                                dbuf_putc(&bc_out, OP_put_loc);
-                                dbuf_put_u16(&bc_out, scope_idx);
-                            } else {
-                                /* XXX: should check if variable can be used
-                                   before initialization */
-                                dbuf_putc(&bc_out, OP_set_loc_uninitialized);
-                                dbuf_put_u16(&bc_out, scope_idx);
-                            }
-                        }
-                        scope_idx = vd->scope_next;
-                    } else {
-                        break;
-                    }
-                }
-            }
-            break;
-
-        case OP_leave_scope:
-            {
-                int scope_idx, scope = get_u16(bc_buf + pos + 1);
-
-                for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {
-                    JSVarDef *vd = &s->vars[scope_idx];
-                    if (vd->scope_level == scope) {
-                        if (vd->is_captured) {
-                            dbuf_putc(&bc_out, OP_close_loc);
-                            dbuf_put_u16(&bc_out, scope_idx);
-                        }
-                        scope_idx = vd->scope_next;
-                    } else {
-                        break;
-                    }
-                }
-            }
-            break;
-
-        case OP_set_name:
-            {
-                /* remove dummy set_name opcodes */
-                JSAtom name = get_u32(bc_buf + pos + 1);
-                if (name == JS_ATOM_NULL)
-                    break;
-            }
-            goto no_change;
-
-        case OP_if_false:
-        case OP_if_true:
-        case OP_catch:
-            s->jump_size++;
-            goto no_change;
-
-        case OP_dup:
-            if (OPTIMIZE) {
-                /* Transformation: dup if_false(l1) drop, l1: if_false(l2) -> if_false(l2) */
-                /* Transformation: dup if_true(l1) drop, l1: if_true(l2) -> if_true(l2) */
-                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), OP_drop, -1)) {
-                    int lab0, lab1, op1, pos1, line1, pos2;
-                    lab0 = lab1 = cc.label;
-                    assert(lab1 >= 0 && lab1 < s->label_count);
-                    op1 = cc.op;
-                    pos1 = cc.pos;
-                    line1 = cc.line_num;
-                    while (code_match(&cc, (pos2 = get_label_pos(s, lab1)), OP_dup, op1, OP_drop, -1)) {
-                        lab1 = cc.label;
-                    }
-                    if (code_match(&cc, pos2, op1, -1)) {
-                        s->jump_size++;
-                        update_label(s, lab0, -1);
-                        update_label(s, cc.label, +1);
-                        dbuf_putc(&bc_out, op1);
-                        dbuf_put_u32(&bc_out, cc.label);
-                        pos_next = pos1;
-                        if (line1 != -1 && line1 != line_num) {
-                            line_num = line1;
-                            s->line_number_size++;
-                            dbuf_putc(&bc_out, OP_line_num);
-                            dbuf_put_u32(&bc_out, line_num);
-                        }
-                        break;
-                    }
-                }
-            }
-            goto no_change;
-
-        case OP_nop:
-            /* remove erased code */
-            break;
-        case OP_set_class_name:
-            /* only used during parsing */
-            break;
-            
-        default:
-        no_change:
-            dbuf_put(&bc_out, bc_buf + pos, len);
-            break;
-        }
-    }
-
-    /* set the new byte code */
-    dbuf_free(&s->byte_code);
-    s->byte_code = bc_out;
-    if (dbuf_error(&s->byte_code)) {
-        JS_ThrowOutOfMemory(ctx);
-        return -1;
-    }
-    return 0;
- fail:
-    /* continue the copy to keep the atom refcounts consistent */
-    /* XXX: find a better solution ? */
-    for (; pos < bc_len; pos = pos_next) {
-        op = bc_buf[pos];
-        len = opcode_info[op].size;
-        pos_next = pos + len;
-        dbuf_put(&bc_out, bc_buf + pos, len);
-    }
-    dbuf_free(&s->byte_code);
-    s->byte_code = bc_out;
-    return -1;
-}
-
-/* the pc2line table gives a line number for each PC value */
-static void add_pc2line_info(JSFunctionDef *s, uint32_t pc, int line_num)
-{
-    if (s->line_number_slots != NULL
-    &&  s->line_number_count < s->line_number_size
-    &&  pc >= s->line_number_last_pc
-    &&  line_num != s->line_number_last) {
-        s->line_number_slots[s->line_number_count].pc = pc;
-        s->line_number_slots[s->line_number_count].line_num = line_num;
-        s->line_number_count++;
-        s->line_number_last_pc = pc;
-        s->line_number_last = line_num;
-    }
-}
-
-static void compute_pc2line_info(JSFunctionDef *s)
-{
-    if (!(s->js_mode & JS_MODE_STRIP) && s->line_number_slots) {
-        int last_line_num = s->line_num;
-        uint32_t last_pc = 0;
-        int i;
-
-        js_dbuf_init(s->ctx, &s->pc2line);
-        for (i = 0; i < s->line_number_count; i++) {
-            uint32_t pc = s->line_number_slots[i].pc;
-            int line_num = s->line_number_slots[i].line_num;
-            int diff_pc, diff_line;
-
-            if (line_num < 0)
-                continue;
-
-            diff_pc = pc - last_pc;
-            diff_line = line_num - last_line_num;
-            if (diff_line == 0 || diff_pc < 0)
-                continue;
-
-            if (diff_line >= PC2LINE_BASE &&
-                diff_line < PC2LINE_BASE + PC2LINE_RANGE &&
-                diff_pc <= PC2LINE_DIFF_PC_MAX) {
-                dbuf_putc(&s->pc2line, (diff_line - PC2LINE_BASE) +
-                          diff_pc * PC2LINE_RANGE + PC2LINE_OP_FIRST);
-            } else {
-                /* longer encoding */
-                dbuf_putc(&s->pc2line, 0);
-                dbuf_put_leb128(&s->pc2line, diff_pc);
-                dbuf_put_sleb128(&s->pc2line, diff_line);
-            }
-            last_pc = pc;
-            last_line_num = line_num;
-        }
-    }
-}
-
-static RelocEntry *add_reloc(JSContext *ctx, LabelSlot *ls, uint32_t addr, int size)
-{
-    RelocEntry *re;
-    re = js_malloc(ctx, sizeof(*re));
-    if (!re)
-        return NULL;
-    re->addr = addr;
-    re->size = size;
-    re->next = ls->first_reloc;
-    ls->first_reloc = re;
-    return re;
-}
-
-static BOOL code_has_label(CodeContext *s, int pos, int label)
-{
-    while (pos < s->bc_len) {
-        int op = s->bc_buf[pos];
-        if (op == OP_line_num) {
-            pos += 5;
-            continue;
-        }
-        if (op == OP_label) {
-            int lab = get_u32(s->bc_buf + pos + 1);
-            if (lab == label)
-                return TRUE;
-            pos += 5;
-            continue;
-        }
-        if (op == OP_goto) {
-            int lab = get_u32(s->bc_buf + pos + 1);
-            if (lab == label)
-                return TRUE;
-        }
-        break;
-    }
-    return FALSE;
-}
-
-/* return the target label, following the OP_goto jumps
-   the first opcode at destination is stored in *pop
- */
-static int find_jump_target(JSFunctionDef *s, int label, int *pop, int *pline)
-{
-    int i, pos, op;
-
-    update_label(s, label, -1);
-    for (i = 0; i < 10; i++) {
-        assert(label >= 0 && label < s->label_count);
-        pos = s->label_slots[label].pos2;
-        for (;;) {
-            switch(op = s->byte_code.buf[pos]) {
-            case OP_line_num:
-                if (pline)
-                    *pline = get_u32(s->byte_code.buf + pos + 1);
-                /* fall thru */
-            case OP_label:
-                pos += opcode_info[op].size;
-                continue;
-            case OP_goto:
-                label = get_u32(s->byte_code.buf + pos + 1);
-                break;
-            case OP_drop:
-                /* ignore drop opcodes if followed by OP_return_undef */
-                while (s->byte_code.buf[++pos] == OP_drop)
-                    continue;
-                if (s->byte_code.buf[pos] == OP_return_undef)
-                    op = OP_return_undef;
-                /* fall thru */
-            default:
-                goto done;
-            }
-            break;
-        }
-    }
-    /* cycle detected, could issue a warning */
- done:
-    *pop = op;
-    update_label(s, label, +1);
-    return label;
-}
-
-static void push_short_int(DynBuf *bc_out, int val)
-{
-#if SHORT_OPCODES
-    if (val >= -1 && val <= 7) {
-        dbuf_putc(bc_out, OP_push_0 + val);
-        return;
-    }
-    if (val == (int8_t)val) {
-        dbuf_putc(bc_out, OP_push_i8);
-        dbuf_putc(bc_out, val);
-        return;
-    }
-    if (val == (int16_t)val) {
-        dbuf_putc(bc_out, OP_push_i16);
-        dbuf_put_u16(bc_out, val);
-        return;
-    }
-#endif
-    dbuf_putc(bc_out, OP_push_i32);
-    dbuf_put_u32(bc_out, val);
-}
-
-static void put_short_code(DynBuf *bc_out, int op, int idx)
-{
-#if SHORT_OPCODES
-    if (idx < 4) {
-        switch (op) {
-        case OP_get_loc:
-            dbuf_putc(bc_out, OP_get_loc0 + idx);
-            return;
-        case OP_put_loc:
-            dbuf_putc(bc_out, OP_put_loc0 + idx);
-            return;
-        case OP_set_loc:
-            dbuf_putc(bc_out, OP_set_loc0 + idx);
-            return;
-        case OP_get_arg:
-            dbuf_putc(bc_out, OP_get_arg0 + idx);
-            return;
-        case OP_put_arg:
-            dbuf_putc(bc_out, OP_put_arg0 + idx);
-            return;
-        case OP_set_arg:
-            dbuf_putc(bc_out, OP_set_arg0 + idx);
-            return;
-        case OP_get_var_ref:
-            dbuf_putc(bc_out, OP_get_var_ref0 + idx);
-            return;
-        case OP_put_var_ref:
-            dbuf_putc(bc_out, OP_put_var_ref0 + idx);
-            return;
-        case OP_set_var_ref:
-            dbuf_putc(bc_out, OP_set_var_ref0 + idx);
-            return;
-        case OP_call:
-            dbuf_putc(bc_out, OP_call0 + idx);
-            return;
-        }
-    }
-    if (idx < 256) {
-        switch (op) {
-        case OP_get_loc:
-            dbuf_putc(bc_out, OP_get_loc8);
-            dbuf_putc(bc_out, idx);
-            return;
-        case OP_put_loc:
-            dbuf_putc(bc_out, OP_put_loc8);
-            dbuf_putc(bc_out, idx);
-            return;
-        case OP_set_loc:
-            dbuf_putc(bc_out, OP_set_loc8);
-            dbuf_putc(bc_out, idx);
-            return;
-        }
-    }
-#endif
-    dbuf_putc(bc_out, op);
-    dbuf_put_u16(bc_out, idx);
-}
-
-/* peephole optimizations and resolve goto/labels */
-static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
-{
-    int pos, pos_next, bc_len, op, op1, len, i, line_num;
-    const uint8_t *bc_buf;
-    DynBuf bc_out;
-    LabelSlot *label_slots, *ls;
-    RelocEntry *re, *re_next;
-    CodeContext cc;
-    int label;
-#if SHORT_OPCODES
-    JumpSlot *jp;
-#endif
-
-    label_slots = s->label_slots;
-
-    line_num = s->line_num;
-
-    cc.bc_buf = bc_buf = s->byte_code.buf;
-    cc.bc_len = bc_len = s->byte_code.size;
-    js_dbuf_init(ctx, &bc_out);
-
-#if SHORT_OPCODES
-    if (s->jump_size) {
-        s->jump_slots = js_mallocz(s->ctx, sizeof(*s->jump_slots) * s->jump_size);
-        if (s->jump_slots == NULL)
-            return -1;
-    }
-#endif
-    /* XXX: Should skip this phase if not generating SHORT_OPCODES */
-    if (s->line_number_size && !(s->js_mode & JS_MODE_STRIP)) {
-        s->line_number_slots = js_mallocz(s->ctx, sizeof(*s->line_number_slots) * s->line_number_size);
-        if (s->line_number_slots == NULL)
-            return -1;
-        s->line_number_last = s->line_num;
-        s->line_number_last_pc = 0;
-    }
-
-    /* initialize the 'home_object' variable if needed */
-    if (s->home_object_var_idx >= 0) {
-        dbuf_putc(&bc_out, OP_special_object);
-        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_HOME_OBJECT);
-        put_short_code(&bc_out, OP_put_loc, s->home_object_var_idx);
-    }
-    /* initialize the 'this.active_func' variable if needed */
-    if (s->this_active_func_var_idx >= 0) {
-        dbuf_putc(&bc_out, OP_special_object);
-        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_THIS_FUNC);
-        put_short_code(&bc_out, OP_put_loc, s->this_active_func_var_idx);
-    }
-    /* initialize the 'new.target' variable if needed */
-    if (s->new_target_var_idx >= 0) {
-        dbuf_putc(&bc_out, OP_special_object);
-        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_NEW_TARGET);
-        put_short_code(&bc_out, OP_put_loc, s->new_target_var_idx);
-    }
-    /* initialize the 'this' variable if needed. In a derived class
-       constructor, this is initially uninitialized. */
-    if (s->this_var_idx >= 0) {
-        if (s->is_derived_class_constructor) {
-            dbuf_putc(&bc_out, OP_set_loc_uninitialized);
-            dbuf_put_u16(&bc_out, s->this_var_idx);
-        } else {
-            dbuf_putc(&bc_out, OP_push_this);
-            put_short_code(&bc_out, OP_put_loc, s->this_var_idx);
-        }
-    }
-    /* initialize the 'arguments' variable if needed */
-    if (s->arguments_var_idx >= 0) {
-        if ((s->js_mode & JS_MODE_STRICT) || !s->has_simple_parameter_list) {
-            dbuf_putc(&bc_out, OP_special_object);
-            dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_ARGUMENTS);
-        } else {
-            dbuf_putc(&bc_out, OP_special_object);
-            dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS);
-        }
-        if (s->arguments_arg_idx >= 0)
-            put_short_code(&bc_out, OP_set_loc, s->arguments_arg_idx);
-        put_short_code(&bc_out, OP_put_loc, s->arguments_var_idx);
-    }
-    /* initialize a reference to the current function if needed */
-    if (s->func_var_idx >= 0) {
-        dbuf_putc(&bc_out, OP_special_object);
-        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_THIS_FUNC);
-        put_short_code(&bc_out, OP_put_loc, s->func_var_idx);
-    }
-    /* initialize the variable environment object if needed */
-    if (s->var_object_idx >= 0) {
-        dbuf_putc(&bc_out, OP_special_object);
-        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
-        put_short_code(&bc_out, OP_put_loc, s->var_object_idx);
-    }
-    if (s->arg_var_object_idx >= 0) {
-        dbuf_putc(&bc_out, OP_special_object);
-        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
-        put_short_code(&bc_out, OP_put_loc, s->arg_var_object_idx);
-    }
-
-    for (pos = 0; pos < bc_len; pos = pos_next) {
-        int val;
-        op = bc_buf[pos];
-        len = opcode_info[op].size;
-        pos_next = pos + len;
-        switch(op) {
-        case OP_line_num:
-            /* line number info (for debug). We put it in a separate
-               compressed table to reduce memory usage and get better
-               performance */
-            line_num = get_u32(bc_buf + pos + 1);
-            break;
-
-        case OP_label:
-            {
-                label = get_u32(bc_buf + pos + 1);
-                assert(label >= 0 && label < s->label_count);
-                ls = &label_slots[label];
-                assert(ls->addr == -1);
-                ls->addr = bc_out.size;
-                /* resolve the relocation entries */
-                for(re = ls->first_reloc; re != NULL; re = re_next) {
-                    int diff = ls->addr - re->addr;
-                    re_next = re->next;
-                    switch (re->size) {
-                    case 4:
-                        put_u32(bc_out.buf + re->addr, diff);
-                        break;
-                    case 2:
-                        assert(diff == (int16_t)diff);
-                        put_u16(bc_out.buf + re->addr, diff);
-                        break;
-                    case 1:
-                        assert(diff == (int8_t)diff);
-                        put_u8(bc_out.buf + re->addr, diff);
-                        break;
-                    }
-                    js_free(ctx, re);
-                }
-                ls->first_reloc = NULL;
-            }
-            break;
-
-        case OP_call:
-        case OP_call_method:
-            {
-                /* detect and transform tail calls */
-                int argc;
-                argc = get_u16(bc_buf + pos + 1);
-                if (code_match(&cc, pos_next, OP_return, -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    add_pc2line_info(s, bc_out.size, line_num);
-                    put_short_code(&bc_out, op + 1, argc);
-                    pos_next = skip_dead_code(s, bc_buf, bc_len, cc.pos, &line_num);
-                    break;
-                }
-                add_pc2line_info(s, bc_out.size, line_num);
-                put_short_code(&bc_out, op, argc);
-                break;
-            }
-            goto no_change;
-
-        case OP_return:
-        case OP_return_undef:
-        case OP_return_async:
-        case OP_throw:
-        case OP_throw_error:
-            pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
-            goto no_change;
-
-        case OP_goto:
-            label = get_u32(bc_buf + pos + 1);
-        has_goto:
-            if (OPTIMIZE) {
-                int line1 = -1;
-                /* Use custom matcher because multiple labels can follow */
-                label = find_jump_target(s, label, &op1, &line1);
-                if (code_has_label(&cc, pos_next, label)) {
-                    /* jump to next instruction: remove jump */
-                    update_label(s, label, -1);
-                    break;
-                }
-                if (op1 == OP_return || op1 == OP_return_undef || op1 == OP_throw) {
-                    /* jump to return/throw: remove jump, append return/throw */
-                    /* updating the line number obfuscates assembly listing */
-                    //if (line1 >= 0) line_num = line1;
-                    update_label(s, label, -1);
-                    add_pc2line_info(s, bc_out.size, line_num);
-                    dbuf_putc(&bc_out, op1);
-                    pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
-                    break;
-                }
-                /* XXX: should duplicate single instructions followed by goto or return */
-                /* For example, can match one of these followed by return:
-                   push_i32 / push_const / push_atom_value / get_var /
-                   undefined / null / push_false / push_true / get_ref_value /
-                   get_loc / get_arg / get_var_ref
-                 */
-            }
-            goto has_label;
-
-        case OP_gosub:
-            label = get_u32(bc_buf + pos + 1);
-            if (0 && OPTIMIZE) {
-                label = find_jump_target(s, label, &op1, NULL);
-                if (op1 == OP_ret) {
-                    update_label(s, label, -1);
-                    /* empty finally clause: remove gosub */
-                    break;
-                }
-            }
-            goto has_label;
-
-        case OP_catch:
-            label = get_u32(bc_buf + pos + 1);
-            goto has_label;
-
-        case OP_if_true:
-        case OP_if_false:
-            label = get_u32(bc_buf + pos + 1);
-            if (OPTIMIZE) {
-                label = find_jump_target(s, label, &op1, NULL);
-                /* transform if_false/if_true(l1) label(l1) -> drop label(l1) */
-                if (code_has_label(&cc, pos_next, label)) {
-                    update_label(s, label, -1);
-                    dbuf_putc(&bc_out, OP_drop);
-                    break;
-                }
-                /* transform if_false(l1) goto(l2) label(l1) -> if_false(l2) label(l1) */
-                if (code_match(&cc, pos_next, OP_goto, -1)) {
-                    int pos1 = cc.pos;
-                    int line1 = cc.line_num;
-                    if (code_has_label(&cc, pos1, label)) {
-                        if (line1 >= 0) line_num = line1;
-                        pos_next = pos1;
-                        update_label(s, label, -1);
-                        label = cc.label;
-                        op ^= OP_if_true ^ OP_if_false;
-                    }
-                }
-            }
-        has_label:
-            add_pc2line_info(s, bc_out.size, line_num);
-            if (op == OP_goto) {
-                pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
-            }
-            assert(label >= 0 && label < s->label_count);
-            ls = &label_slots[label];
-#if SHORT_OPCODES
-            jp = &s->jump_slots[s->jump_count++];
-            jp->op = op;
-            jp->size = 4;
-            jp->pos = bc_out.size + 1;
-            jp->label = label;
-
-            if (ls->addr == -1) {
-                int diff = ls->pos2 - pos - 1;
-                if (diff < 128 && (op == OP_if_false || op == OP_if_true || op == OP_goto)) {
-                    jp->size = 1;
-                    jp->op = OP_if_false8 + (op - OP_if_false);
-                    dbuf_putc(&bc_out, OP_if_false8 + (op - OP_if_false));
-                    dbuf_putc(&bc_out, 0);
-                    if (!add_reloc(ctx, ls, bc_out.size - 1, 1))
-                        goto fail;
-                    break;
-                }
-                if (diff < 32768 && op == OP_goto) {
-                    jp->size = 2;
-                    jp->op = OP_goto16;
-                    dbuf_putc(&bc_out, OP_goto16);
-                    dbuf_put_u16(&bc_out, 0);
-                    if (!add_reloc(ctx, ls, bc_out.size - 2, 2))
-                        goto fail;
-                    break;
-                }
-            } else {
-                int diff = ls->addr - bc_out.size - 1;
-                if (diff == (int8_t)diff && (op == OP_if_false || op == OP_if_true || op == OP_goto)) {
-                    jp->size = 1;
-                    jp->op = OP_if_false8 + (op - OP_if_false);
-                    dbuf_putc(&bc_out, OP_if_false8 + (op - OP_if_false));
-                    dbuf_putc(&bc_out, diff);
-                    break;
-                }
-                if (diff == (int16_t)diff && op == OP_goto) {
-                    jp->size = 2;
-                    jp->op = OP_goto16;
-                    dbuf_putc(&bc_out, OP_goto16);
-                    dbuf_put_u16(&bc_out, diff);
-                    break;
-                }
-            }
-#endif
-            dbuf_putc(&bc_out, op);
-            dbuf_put_u32(&bc_out, ls->addr - bc_out.size);
-            if (ls->addr == -1) {
-                /* unresolved yet: create a new relocation entry */
-                if (!add_reloc(ctx, ls, bc_out.size - 4, 4))
-                    goto fail;
-            }
-            break;
-        case OP_with_get_var:
-        case OP_with_put_var:
-        case OP_with_delete_var:
-        case OP_with_make_ref:
-        case OP_with_get_ref:
-        case OP_with_get_ref_undef:
-            {
-                JSAtom atom;
-                int is_with;
-
-                atom = get_u32(bc_buf + pos + 1);
-                label = get_u32(bc_buf + pos + 5);
-                is_with = bc_buf[pos + 9];
-                if (OPTIMIZE) {
-                    label = find_jump_target(s, label, &op1, NULL);
-                }
-                assert(label >= 0 && label < s->label_count);
-                ls = &label_slots[label];
-                add_pc2line_info(s, bc_out.size, line_num);
-#if SHORT_OPCODES
-                jp = &s->jump_slots[s->jump_count++];
-                jp->op = op;
-                jp->size = 4;
-                jp->pos = bc_out.size + 5;
-                jp->label = label;
-#endif
-                dbuf_putc(&bc_out, op);
-                dbuf_put_u32(&bc_out, atom);
-                dbuf_put_u32(&bc_out, ls->addr - bc_out.size);
-                if (ls->addr == -1) {
-                    /* unresolved yet: create a new relocation entry */
-                    if (!add_reloc(ctx, ls, bc_out.size - 4, 4))
-                        goto fail;
-                }
-                dbuf_putc(&bc_out, is_with);
-            }
-            break;
-
-        case OP_drop:
-            if (OPTIMIZE) {
-                /* remove useless drops before return */
-                if (code_match(&cc, pos_next, OP_return_undef, -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    break;
-                }
-            }
-            goto no_change;
-
-        case OP_null:
-#if SHORT_OPCODES
-            if (OPTIMIZE) {
-                /* transform null strict_eq into is_null */
-                if (code_match(&cc, pos_next, OP_strict_eq, -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    add_pc2line_info(s, bc_out.size, line_num);
-                    dbuf_putc(&bc_out, OP_is_null);
-                    pos_next = cc.pos;
-                    break;
-                }
-                /* transform null strict_neq if_false/if_true -> is_null if_true/if_false */
-                if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    add_pc2line_info(s, bc_out.size, line_num);
-                    dbuf_putc(&bc_out, OP_is_null);
-                    pos_next = cc.pos;
-                    label = cc.label;
-                    op = cc.op ^ OP_if_false ^ OP_if_true;
-                    goto has_label;
-                }
-            }
-#endif
-            /* fall thru */
-        case OP_push_false:
-        case OP_push_true:
-            if (OPTIMIZE) {
-                val = (op == OP_push_true);
-                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
-                has_constant_test:
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    if (val == cc.op - OP_if_false) {
-                        /* transform null if_false(l1) -> goto l1 */
-                        /* transform false if_false(l1) -> goto l1 */
-                        /* transform true if_true(l1) -> goto l1 */
-                        pos_next = cc.pos;
-                        op = OP_goto;
-                        label = cc.label;
-                        goto has_goto;
-                    } else {
-                        /* transform null if_true(l1) -> nop */
-                        /* transform false if_true(l1) -> nop */
-                        /* transform true if_false(l1) -> nop */
-                        pos_next = cc.pos;
-                        update_label(s, cc.label, -1);
-                        break;
-                    }
-                }
-            }
-            goto no_change;
-
-        case OP_push_i32:
-            if (OPTIMIZE) {
-                /* transform i32(val) neg -> i32(-val) */
-                val = get_i32(bc_buf + pos + 1);
-                if ((val != INT32_MIN && val != 0)
-                &&  code_match(&cc, pos_next, OP_neg, -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    if (code_match(&cc, cc.pos, OP_drop, -1)) {
-                        if (cc.line_num >= 0) line_num = cc.line_num;
-                    } else {
-                        add_pc2line_info(s, bc_out.size, line_num);
-                        push_short_int(&bc_out, -val);
-                    }
-                    pos_next = cc.pos;
-                    break;
-                }
-                /* remove push/drop pairs generated by the parser */
-                if (code_match(&cc, pos_next, OP_drop, -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    pos_next = cc.pos;
-                    break;
-                }
-                /* Optimize constant tests: `if (0)`, `if (1)`, `if (!0)`... */
-                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
-                    val = (val != 0);
-                    goto has_constant_test;
-                }
-                add_pc2line_info(s, bc_out.size, line_num);
-                push_short_int(&bc_out, val);
-                break;
-            }
-            goto no_change;
-
-#if SHORT_OPCODES
-        case OP_push_const:
-        case OP_fclosure:
-            if (OPTIMIZE) {
-                int idx = get_u32(bc_buf + pos + 1);
-                if (idx < 256) {
-                    add_pc2line_info(s, bc_out.size, line_num);
-                    dbuf_putc(&bc_out, OP_push_const8 + op - OP_push_const);
-                    dbuf_putc(&bc_out, idx);
-                    break;
-                }
-            }
-            goto no_change;
-
-        case OP_get_field:
-            if (OPTIMIZE) {
-                JSAtom atom = get_u32(bc_buf + pos + 1);
-                if (atom == JS_ATOM_length) {
-                    JS_FreeAtom(ctx, atom);
-                    add_pc2line_info(s, bc_out.size, line_num);
-                    dbuf_putc(&bc_out, OP_get_length);
-                    break;
-                }
-            }
-            goto no_change;
-#endif
-        case OP_push_atom_value:
-            if (OPTIMIZE) {
-                JSAtom atom = get_u32(bc_buf + pos + 1);
-                /* remove push/drop pairs generated by the parser */
-                if (code_match(&cc, pos_next, OP_drop, -1)) {
-                    JS_FreeAtom(ctx, atom);
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    pos_next = cc.pos;
-                    break;
-                }
-#if SHORT_OPCODES
-                if (atom == JS_ATOM_empty_string) {
-                    JS_FreeAtom(ctx, atom);
-                    add_pc2line_info(s, bc_out.size, line_num);
-                    dbuf_putc(&bc_out, OP_push_empty_string);
-                    break;
-                }
-#endif
-            }
-            goto no_change;
-
-        case OP_to_propkey:
-        case OP_to_propkey2:
-            if (OPTIMIZE) {
-                /* remove redundant to_propkey/to_propkey2 opcodes when storing simple data */
-                if (code_match(&cc, pos_next, M3(OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_put_array_el, -1)
-                ||  code_match(&cc, pos_next, M3(OP_push_i32, OP_push_const, OP_push_atom_value), OP_put_array_el, -1)
-                ||  code_match(&cc, pos_next, M4(OP_undefined, OP_null, OP_push_true, OP_push_false), OP_put_array_el, -1)) {
-                    break;
-                }
-            }
-            goto no_change;
-
-        case OP_undefined:
-            if (OPTIMIZE) {
-                /* remove push/drop pairs generated by the parser */
-                if (code_match(&cc, pos_next, OP_drop, -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    pos_next = cc.pos;
-                    break;
-                }
-                /* transform undefined return -> return_undefined */
-                if (code_match(&cc, pos_next, OP_return, -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    add_pc2line_info(s, bc_out.size, line_num);
-                    dbuf_putc(&bc_out, OP_return_undef);
-                    pos_next = cc.pos;
-                    break;
-                }
-                /* transform undefined if_true(l1)/if_false(l1) -> nop/goto(l1) */
-                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
-                    val = 0;
-                    goto has_constant_test;
-                }
-#if SHORT_OPCODES
-                /* transform undefined strict_eq -> is_undefined */
-                if (code_match(&cc, pos_next, OP_strict_eq, -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    add_pc2line_info(s, bc_out.size, line_num);
-                    dbuf_putc(&bc_out, OP_is_undefined);
-                    pos_next = cc.pos;
-                    break;
-                }
-                /* transform undefined strict_neq if_false/if_true -> is_undefined if_true/if_false */
-                if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    add_pc2line_info(s, bc_out.size, line_num);
-                    dbuf_putc(&bc_out, OP_is_undefined);
-                    pos_next = cc.pos;
-                    label = cc.label;
-                    op = cc.op ^ OP_if_false ^ OP_if_true;
-                    goto has_label;
-                }
-#endif
-            }
-            goto no_change;
-
-        case OP_insert2:
-            if (OPTIMIZE) {
-                /* Transformation:
-                   insert2 put_field(a) drop -> put_field(a)
-                   insert2 put_var_strict(a) drop -> put_var_strict(a)
-                */
-                if (code_match(&cc, pos_next, M2(OP_put_field, OP_put_var_strict), OP_drop, -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    add_pc2line_info(s, bc_out.size, line_num);
-                    dbuf_putc(&bc_out, cc.op);
-                    dbuf_put_u32(&bc_out, cc.atom);
-                    pos_next = cc.pos;
-                    break;
-                }
-            }
-            goto no_change;
-
-        case OP_dup:
-            if (OPTIMIZE) {
-                /* Transformation: dup put_x(n) drop -> put_x(n) */
-                int op1, line2 = -1;
-                /* Transformation: dup put_x(n) -> set_x(n) */
-                if (code_match(&cc, pos_next, M3(OP_put_loc, OP_put_arg, OP_put_var_ref), -1, -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    op1 = cc.op + 1;  /* put_x -> set_x */
-                    pos_next = cc.pos;
-                    if (code_match(&cc, cc.pos, OP_drop, -1)) {
-                        if (cc.line_num >= 0) line_num = cc.line_num;
-                        op1 -= 1; /* set_x drop -> put_x */
-                        pos_next = cc.pos;
-                        if (code_match(&cc, cc.pos, op1 - 1, cc.idx, -1)) {
-                            line2 = cc.line_num; /* delay line number update */
-                            op1 += 1;   /* put_x(n) get_x(n) -> set_x(n) */
-                            pos_next = cc.pos;
-                        }
-                    }
-                    add_pc2line_info(s, bc_out.size, line_num);
-                    put_short_code(&bc_out, op1, cc.idx);
-                    if (line2 >= 0) line_num = line2;
-                    break;
-                }
-            }
-            goto no_change;
-
-        case OP_get_loc:
-            if (OPTIMIZE) {
-                /* transformation:
-                   get_loc(n) post_dec put_loc(n) drop -> dec_loc(n)
-                   get_loc(n) post_inc put_loc(n) drop -> inc_loc(n)
-                   get_loc(n) dec dup put_loc(n) drop -> dec_loc(n)
-                   get_loc(n) inc dup put_loc(n) drop -> inc_loc(n)
-                 */
-                int idx;
-                idx = get_u16(bc_buf + pos + 1);
-                if (idx >= 256)
-                    goto no_change;
-                if (code_match(&cc, pos_next, M2(OP_post_dec, OP_post_inc), OP_put_loc, idx, OP_drop, -1) ||
-                    code_match(&cc, pos_next, M2(OP_dec, OP_inc), OP_dup, OP_put_loc, idx, OP_drop, -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    add_pc2line_info(s, bc_out.size, line_num);
-                    dbuf_putc(&bc_out, (cc.op == OP_inc || cc.op == OP_post_inc) ? OP_inc_loc : OP_dec_loc);
-                    dbuf_putc(&bc_out, idx);
-                    pos_next = cc.pos;
-                    break;
-                }
-                /* transformation:
-                   get_loc(n) push_atom_value(x) add dup put_loc(n) drop -> push_atom_value(x) add_loc(n)
-                 */
-                if (code_match(&cc, pos_next, OP_push_atom_value, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    add_pc2line_info(s, bc_out.size, line_num);
-#if SHORT_OPCODES
-                    if (cc.atom == JS_ATOM_empty_string) {
-                        JS_FreeAtom(ctx, cc.atom);
-                        dbuf_putc(&bc_out, OP_push_empty_string);
-                    } else
-#endif
-                    {
-                        dbuf_putc(&bc_out, OP_push_atom_value);
-                        dbuf_put_u32(&bc_out, cc.atom);
-                    }
-                    dbuf_putc(&bc_out, OP_add_loc);
-                    dbuf_putc(&bc_out, idx);
-                    pos_next = cc.pos;
-                    break;
-                }
-                /* transformation:
-                   get_loc(n) push_i32(x) add dup put_loc(n) drop -> push_i32(x) add_loc(n)
-                 */
-                if (code_match(&cc, pos_next, OP_push_i32, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    add_pc2line_info(s, bc_out.size, line_num);
-                    push_short_int(&bc_out, cc.label);
-                    dbuf_putc(&bc_out, OP_add_loc);
-                    dbuf_putc(&bc_out, idx);
-                    pos_next = cc.pos;
-                    break;
-                }
-                /* transformation: XXX: also do these:
-                   get_loc(n) get_loc(x) add dup put_loc(n) drop -> get_loc(x) add_loc(n)
-                   get_loc(n) get_arg(x) add dup put_loc(n) drop -> get_arg(x) add_loc(n)
-                   get_loc(n) get_var_ref(x) add dup put_loc(n) drop -> get_var_ref(x) add_loc(n)
-                 */
-                if (code_match(&cc, pos_next, M3(OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    add_pc2line_info(s, bc_out.size, line_num);
-                    put_short_code(&bc_out, cc.op, cc.idx);
-                    dbuf_putc(&bc_out, OP_add_loc);
-                    dbuf_putc(&bc_out, idx);
-                    pos_next = cc.pos;
-                    break;
-                }
-                add_pc2line_info(s, bc_out.size, line_num);
-                put_short_code(&bc_out, op, idx);
-                break;
-            }
-            goto no_change;
-#if SHORT_OPCODES
-        case OP_get_arg:
-        case OP_get_var_ref:
-            if (OPTIMIZE) {
-                int idx;
-                idx = get_u16(bc_buf + pos + 1);
-                add_pc2line_info(s, bc_out.size, line_num);
-                put_short_code(&bc_out, op, idx);
-                break;
-            }
-            goto no_change;
-#endif
-        case OP_put_loc:
-        case OP_put_arg:
-        case OP_put_var_ref:
-            if (OPTIMIZE) {
-                /* transformation: put_x(n) get_x(n) -> set_x(n) */
-                int idx;
-                idx = get_u16(bc_buf + pos + 1);
-                if (code_match(&cc, pos_next, op - 1, idx, -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    add_pc2line_info(s, bc_out.size, line_num);
-                    put_short_code(&bc_out, op + 1, idx);
-                    pos_next = cc.pos;
-                    break;
-                }
-                add_pc2line_info(s, bc_out.size, line_num);
-                put_short_code(&bc_out, op, idx);
-                break;
-            }
-            goto no_change;
-
-        case OP_post_inc:
-        case OP_post_dec:
-            if (OPTIMIZE) {
-                /* transformation:
-                   post_inc put_x drop -> inc put_x
-                   post_inc perm3 put_field drop -> inc put_field
-                   post_inc perm3 put_var_strict drop -> inc put_var_strict
-                   post_inc perm4 put_array_el drop -> inc put_array_el
-                 */
-                int op1, idx;
-                if (code_match(&cc, pos_next, M3(OP_put_loc, OP_put_arg, OP_put_var_ref), -1, OP_drop, -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    op1 = cc.op;
-                    idx = cc.idx;
-                    pos_next = cc.pos;
-                    if (code_match(&cc, cc.pos, op1 - 1, idx, -1)) {
-                        if (cc.line_num >= 0) line_num = cc.line_num;
-                        op1 += 1;   /* put_x(n) get_x(n) -> set_x(n) */
-                        pos_next = cc.pos;
-                    }
-                    add_pc2line_info(s, bc_out.size, line_num);
-                    dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
-                    put_short_code(&bc_out, op1, idx);
-                    break;
-                }
-                if (code_match(&cc, pos_next, OP_perm3, M2(OP_put_field, OP_put_var_strict), OP_drop, -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    add_pc2line_info(s, bc_out.size, line_num);
-                    dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
-                    dbuf_putc(&bc_out, cc.op);
-                    dbuf_put_u32(&bc_out, cc.atom);
-                    pos_next = cc.pos;
-                    break;
-                }
-                if (code_match(&cc, pos_next, OP_perm4, OP_put_array_el, OP_drop, -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    add_pc2line_info(s, bc_out.size, line_num);
-                    dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
-                    dbuf_putc(&bc_out, OP_put_array_el);
-                    pos_next = cc.pos;
-                    break;
-                }
-            }
-            goto no_change;
-
-#if SHORT_OPCODES
-        case OP_typeof:
-            if (OPTIMIZE) {
-                /* simplify typeof tests */
-                if (code_match(&cc, pos_next, OP_push_atom_value, M4(OP_strict_eq, OP_strict_neq, OP_eq, OP_neq), -1)) {
-                    if (cc.line_num >= 0) line_num = cc.line_num;
-                    int op1 = (cc.op == OP_strict_eq || cc.op == OP_eq) ? OP_strict_eq : OP_strict_neq;
-                    int op2 = -1;
-                    switch (cc.atom) {
-                    case JS_ATOM_undefined:
-                        op2 = OP_typeof_is_undefined;
-                        break;
-                    case JS_ATOM_function:
-                        op2 = OP_typeof_is_function;
-                        break;
-                    }
-                    if (op2 >= 0) {
-                        /* transform typeof(s) == "<type>" into is_<type> */
-                        if (op1 == OP_strict_eq) {
-                            add_pc2line_info(s, bc_out.size, line_num);
-                            dbuf_putc(&bc_out, op2);
-                            JS_FreeAtom(ctx, cc.atom);
-                            pos_next = cc.pos;
-                            break;
-                        }
-                        if (op1 == OP_strict_neq && code_match(&cc, cc.pos, OP_if_false, -1)) {
-                            /* transform typeof(s) != "<type>" if_false into is_<type> if_true */
-                            if (cc.line_num >= 0) line_num = cc.line_num;
-                            add_pc2line_info(s, bc_out.size, line_num);
-                            dbuf_putc(&bc_out, op2);
-                            JS_FreeAtom(ctx, cc.atom);
-                            pos_next = cc.pos;
-                            label = cc.label;
-                            op = OP_if_true;
-                            goto has_label;
-                        }
-                    }
-                }
-            }
-            goto no_change;
-#endif
-
-        default:
-        no_change:
-            add_pc2line_info(s, bc_out.size, line_num);
-            dbuf_put(&bc_out, bc_buf + pos, len);
-            break;
-        }
-    }
-
-    /* check that there were no missing labels */
-    for(i = 0; i < s->label_count; i++) {
-        assert(label_slots[i].first_reloc == NULL);
-    }
-#if SHORT_OPCODES
-    if (OPTIMIZE) {
-        /* more jump optimizations */
-        int patch_offsets = 0;
-        for (i = 0, jp = s->jump_slots; i < s->jump_count; i++, jp++) {
-            LabelSlot *ls;
-            JumpSlot *jp1;
-            int j, pos, diff, delta;
-
-            delta = 3;
-            switch (op = jp->op) {
-            case OP_goto16:
-                delta = 1;
-                /* fall thru */
-            case OP_if_false:
-            case OP_if_true:
-            case OP_goto:
-                pos = jp->pos;
-                diff = s->label_slots[jp->label].addr - pos;
-                if (diff >= -128 && diff <= 127 + delta) {
-                    //put_u8(bc_out.buf + pos, diff);
-                    jp->size = 1;
-                    if (op == OP_goto16) {
-                        bc_out.buf[pos - 1] = jp->op = OP_goto8;
-                    } else {
-                        bc_out.buf[pos - 1] = jp->op = OP_if_false8 + (op - OP_if_false);
-                    }
-                    goto shrink;
-                } else
-                if (diff == (int16_t)diff && op == OP_goto) {
-                    //put_u16(bc_out.buf + pos, diff);
-                    jp->size = 2;
-                    delta = 2;
-                    bc_out.buf[pos - 1] = jp->op = OP_goto16;
-                shrink:
-                    /* XXX: should reduce complexity, using 2 finger copy scheme */
-                    memmove(bc_out.buf + pos + jp->size, bc_out.buf + pos + jp->size + delta,
-                            bc_out.size - pos - jp->size - delta);
-                    bc_out.size -= delta;
-                    patch_offsets++;
-                    for (j = 0, ls = s->label_slots; j < s->label_count; j++, ls++) {
-                        if (ls->addr > pos)
-                            ls->addr -= delta;
-                    }
-                    for (j = i + 1, jp1 = jp + 1; j < s->jump_count; j++, jp1++) {
-                        if (jp1->pos > pos)
-                            jp1->pos -= delta;
-                    }
-                    for (j = 0; j < s->line_number_count; j++) {
-                        if (s->line_number_slots[j].pc > pos)
-                            s->line_number_slots[j].pc -= delta;
-                    }
-                    continue;
-                }
-                break;
-            }
-        }
-        if (patch_offsets) {
-            JumpSlot *jp1;
-            int j;
-            for (j = 0, jp1 = s->jump_slots; j < s->jump_count; j++, jp1++) {
-                int diff1 = s->label_slots[jp1->label].addr - jp1->pos;
-                switch (jp1->size) {
-                case 1:
-                    put_u8(bc_out.buf + jp1->pos, diff1);
-                    break;
-                case 2:
-                    put_u16(bc_out.buf + jp1->pos, diff1);
-                    break;
-                case 4:
-                    put_u32(bc_out.buf + jp1->pos, diff1);
-                    break;
-                }
-            }
-        }
-    }
-    js_free(ctx, s->jump_slots);
-    s->jump_slots = NULL;
-#endif
-    js_free(ctx, s->label_slots);
-    s->label_slots = NULL;
-    /* XXX: should delay until copying to runtime bytecode function */
-    compute_pc2line_info(s);
-    js_free(ctx, s->line_number_slots);
-    s->line_number_slots = NULL;
-    /* set the new byte code */
-    dbuf_free(&s->byte_code);
-    s->byte_code = bc_out;
-    s->use_short_opcodes = TRUE;
-    if (dbuf_error(&s->byte_code)) {
-        JS_ThrowOutOfMemory(ctx);
-        return -1;
-    }
-    return 0;
- fail:
-    /* XXX: not safe */
-    dbuf_free(&bc_out);
-    return -1;
-}
-
-/* compute the maximum stack size needed by the function */
-
-typedef struct StackSizeState {
-    int bc_len;
-    int stack_len_max;
-    uint16_t *stack_level_tab;
-    int *pc_stack;
-    int pc_stack_len;
-    int pc_stack_size;
-} StackSizeState;
-
-/* 'op' is only used for error indication */
-static __exception int ss_check(JSContext *ctx, StackSizeState *s,
-                                int pos, int op, int stack_len)
-{
-    if ((unsigned)pos >= s->bc_len) {
-        JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
-        return -1;
-    }
-    if (stack_len > s->stack_len_max) {
-        s->stack_len_max = stack_len;
-        if (s->stack_len_max > JS_STACK_SIZE_MAX) {
-            JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
-            return -1;
-        }
-    }
-    if (s->stack_level_tab[pos] != 0xffff) {
-        /* already explored: check that the stack size is consistent */
-        if (s->stack_level_tab[pos] != stack_len) {
-            JS_ThrowInternalError(ctx, "unconsistent stack size: %d %d (pc=%d)",
-                                  s->stack_level_tab[pos], stack_len, pos);
-            return -1;
-        } else {
-            return 0;
-        }
-    }
-
-    /* mark as explored and store the stack size */
-    s->stack_level_tab[pos] = stack_len;
-
-    /* queue the new PC to explore */
-    if (js_resize_array(ctx, (void **)&s->pc_stack, sizeof(s->pc_stack[0]),
-                        &s->pc_stack_size, s->pc_stack_len + 1))
-        return -1;
-    s->pc_stack[s->pc_stack_len++] = pos;
-    return 0;
-}
-
-static __exception int compute_stack_size(JSContext *ctx,
-                                          JSFunctionDef *fd,
-                                          int *pstack_size)
-{
-    StackSizeState s_s, *s = &s_s;
-    int i, diff, n_pop, pos_next, stack_len, pos, op;
-    const JSOpCode *oi;
-    const uint8_t *bc_buf;
-
-    bc_buf = fd->byte_code.buf;
-    s->bc_len = fd->byte_code.size;
-    /* bc_len > 0 */
-    s->stack_level_tab = js_malloc(ctx, sizeof(s->stack_level_tab[0]) *
-                                   s->bc_len);
-    if (!s->stack_level_tab)
-        return -1;
-    for(i = 0; i < s->bc_len; i++)
-        s->stack_level_tab[i] = 0xffff;
-    s->stack_len_max = 0;
-    s->pc_stack = NULL;
-    s->pc_stack_len = 0;
-    s->pc_stack_size = 0;
-
-    /* breadth-first graph exploration */
-    if (ss_check(ctx, s, 0, OP_invalid, 0))
-        goto fail;
-
-    while (s->pc_stack_len > 0) {
-        pos = s->pc_stack[--s->pc_stack_len];
-        stack_len = s->stack_level_tab[pos];
-        op = bc_buf[pos];
-        if (op == 0 || op >= OP_COUNT) {
-            JS_ThrowInternalError(ctx, "invalid opcode (op=%d, pc=%d)", op, pos);
-            goto fail;
-        }
-        oi = &short_opcode_info(op);
-        pos_next = pos + oi->size;
-        if (pos_next > s->bc_len) {
-            JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
-            goto fail;
-        }
-        n_pop = oi->n_pop;
-        /* call pops a variable number of arguments */
-        if (oi->fmt == OP_FMT_npop || oi->fmt == OP_FMT_npop_u16) {
-            n_pop += get_u16(bc_buf + pos + 1);
-        } else {
-#if SHORT_OPCODES
-            if (oi->fmt == OP_FMT_npopx) {
-                n_pop += op - OP_call0;
-            }
-#endif
-        }
-
-        if (stack_len < n_pop) {
-            JS_ThrowInternalError(ctx, "stack underflow (op=%d, pc=%d)", op, pos);
-            goto fail;
-        }
-        stack_len += oi->n_push - n_pop;
-        if (stack_len > s->stack_len_max) {
-            s->stack_len_max = stack_len;
-            if (s->stack_len_max > JS_STACK_SIZE_MAX) {
-                JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
-                goto fail;
-            }
-        }
-        switch(op) {
-        case OP_tail_call:
-        case OP_tail_call_method:
-        case OP_return:
-        case OP_return_undef:
-        case OP_return_async:
-        case OP_throw:
-        case OP_throw_error:
-        case OP_ret:
-            goto done_insn;
-        case OP_goto:
-            diff = get_u32(bc_buf + pos + 1);
-            pos_next = pos + 1 + diff;
-            break;
-#if SHORT_OPCODES
-        case OP_goto16:
-            diff = (int16_t)get_u16(bc_buf + pos + 1);
-            pos_next = pos + 1 + diff;
-            break;
-        case OP_goto8:
-            diff = (int8_t)bc_buf[pos + 1];
-            pos_next = pos + 1 + diff;
-            break;
-        case OP_if_true8:
-        case OP_if_false8:
-            diff = (int8_t)bc_buf[pos + 1];
-            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len))
-                goto fail;
-            break;
-#endif
-        case OP_if_true:
-        case OP_if_false:
-        case OP_catch:
-            diff = get_u32(bc_buf + pos + 1);
-            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len))
-                goto fail;
-            break;
-        case OP_gosub:
-            diff = get_u32(bc_buf + pos + 1);
-            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1))
-                goto fail;
-            break;
-        case OP_with_get_var:
-        case OP_with_delete_var:
-            diff = get_u32(bc_buf + pos + 5);
-            if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1))
-                goto fail;
-            break;
-        case OP_with_make_ref:
-        case OP_with_get_ref:
-        case OP_with_get_ref_undef:
-            diff = get_u32(bc_buf + pos + 5);
-            if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2))
-                goto fail;
-            break;
-        case OP_with_put_var:
-            diff = get_u32(bc_buf + pos + 5);
-            if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1))
-                goto fail;
-            break;
-
-        default:
-            break;
-        }
-        if (ss_check(ctx, s, pos_next, op, stack_len))
-            goto fail;
-    done_insn: ;
-    }
-    js_free(ctx, s->stack_level_tab);
-    js_free(ctx, s->pc_stack);
-    *pstack_size = s->stack_len_max;
-    return 0;
- fail:
-    js_free(ctx, s->stack_level_tab);
-    js_free(ctx, s->pc_stack);
-    *pstack_size = 0;
-    return -1;
-}
-
-static int add_module_variables(JSContext *ctx, JSFunctionDef *fd)
-{
-    int i, idx;
-    JSModuleDef *m = fd->module;
-    JSExportEntry *me;
-    JSGlobalVar *hf;
-
-    /* The imported global variables were added as closure variables
-       in js_parse_import(). We add here the module global
-       variables. */
-
-    for(i = 0; i < fd->global_var_count; i++) {
-        hf = &fd->global_vars[i];
-        if (add_closure_var(ctx, fd, TRUE, FALSE, i, hf->var_name, hf->is_const,
-                            hf->is_lexical, FALSE) < 0)
-            return -1;
-    }
-
-    /* resolve the variable names of the local exports */
-    for(i = 0; i < m->export_entries_count; i++) {
-        me = &m->export_entries[i];
-        if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
-            idx = find_closure_var(ctx, fd, me->local_name);
-            if (idx < 0) {
-                JS_ThrowSyntaxErrorAtom(ctx, "exported variable '%s' does not exist",
-                                        me->local_name);
-                return -1;
-            }
-            me->u.local.var_idx = idx;
-        }
-    }
-    return 0;
-}
-
-/* create a function object from a function definition. The function
-   definition is freed. All the child functions are also created. It
-   must be done this way to resolve all the variables. */
-static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
-{
-    JSValue func_obj;
-    JSFunctionBytecode *b;
-    struct list_head *el, *el1;
-    int stack_size, scope, idx;
-    int function_size, byte_code_offset, cpool_offset;
-    int closure_var_offset, vardefs_offset;
-
-    /* recompute scope linkage */
-    for (scope = 0; scope < fd->scope_count; scope++) {
-        fd->scopes[scope].first = -1;
-    }
-    if (fd->has_parameter_expressions) {
-        /* special end of variable list marker for the argument scope */
-        fd->scopes[ARG_SCOPE_INDEX].first = ARG_SCOPE_END;
-    }
-    for (idx = 0; idx < fd->var_count; idx++) {
-        JSVarDef *vd = &fd->vars[idx];
-        vd->scope_next = fd->scopes[vd->scope_level].first;
-        fd->scopes[vd->scope_level].first = idx;
-    }
-    for (scope = 2; scope < fd->scope_count; scope++) {
-        JSVarScope *sd = &fd->scopes[scope];
-        if (sd->first < 0)
-            sd->first = fd->scopes[sd->parent].first;
-    }
-    for (idx = 0; idx < fd->var_count; idx++) {
-        JSVarDef *vd = &fd->vars[idx];
-        if (vd->scope_next < 0 && vd->scope_level > 1) {
-            scope = fd->scopes[vd->scope_level].parent;
-            vd->scope_next = fd->scopes[scope].first;
-        }
-    }
-
-    /* if the function contains an eval call, the closure variables
-       are used to compile the eval and they must be ordered by scope,
-       so it is necessary to create the closure variables before any
-       other variable lookup is done. */
-    if (fd->has_eval_call)
-        add_eval_variables(ctx, fd);
-
-    /* add the module global variables in the closure */
-    if (fd->module) {
-        if (add_module_variables(ctx, fd))
-            goto fail;
-    }
-
-    /* first create all the child functions */
-    list_for_each_safe(el, el1, &fd->child_list) {
-        JSFunctionDef *fd1;
-        int cpool_idx;
-
-        fd1 = list_entry(el, JSFunctionDef, link);
-        cpool_idx = fd1->parent_cpool_idx;
-        func_obj = js_create_function(ctx, fd1);
-        if (JS_IsException(func_obj))
-            goto fail;
-        /* save it in the constant pool */
-        assert(cpool_idx >= 0);
-        fd->cpool[cpool_idx] = func_obj;
-    }
-
-#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 4)
-    if (!(fd->js_mode & JS_MODE_STRIP)) {
-        printf("pass 1\n");
-        dump_byte_code(ctx, 1, fd->byte_code.buf, fd->byte_code.size,
-                       fd->args, fd->arg_count, fd->vars, fd->var_count,
-                       fd->closure_var, fd->closure_var_count,
-                       fd->cpool, fd->cpool_count, fd->source, fd->line_num,
-                       fd->label_slots, NULL);
-        printf("\n");
-    }
-#endif
-
-    if (resolve_variables(ctx, fd))
-        goto fail;
-
-#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 2)
-    if (!(fd->js_mode & JS_MODE_STRIP)) {
-        printf("pass 2\n");
-        dump_byte_code(ctx, 2, fd->byte_code.buf, fd->byte_code.size,
-                       fd->args, fd->arg_count, fd->vars, fd->var_count,
-                       fd->closure_var, fd->closure_var_count,
-                       fd->cpool, fd->cpool_count, fd->source, fd->line_num,
-                       fd->label_slots, NULL);
-        printf("\n");
-    }
-#endif
-
-    if (resolve_labels(ctx, fd))
-        goto fail;
-
-    if (compute_stack_size(ctx, fd, &stack_size) < 0)
-        goto fail;
-
-    if (fd->js_mode & JS_MODE_STRIP) {
-        function_size = offsetof(JSFunctionBytecode, debug);
-    } else {
-        function_size = sizeof(*b);
-    }
-    cpool_offset = function_size;
-    function_size += fd->cpool_count * sizeof(*fd->cpool);
-    vardefs_offset = function_size;
-    if (!(fd->js_mode & JS_MODE_STRIP) || fd->has_eval_call) {
-        function_size += (fd->arg_count + fd->var_count) * sizeof(*b->vardefs);
-    }
-    closure_var_offset = function_size;
-    function_size += fd->closure_var_count * sizeof(*fd->closure_var);
-    byte_code_offset = function_size;
-    function_size += fd->byte_code.size;
-
-    b = js_mallocz(ctx, function_size);
-    if (!b)
-        goto fail;
-    b->header.ref_count = 1;
-
-    b->byte_code_buf = (void *)((uint8_t*)b + byte_code_offset);
-    b->byte_code_len = fd->byte_code.size;
-    memcpy(b->byte_code_buf, fd->byte_code.buf, fd->byte_code.size);
-    js_free(ctx, fd->byte_code.buf);
-    fd->byte_code.buf = NULL;
-
-    b->func_name = fd->func_name;
-    if (fd->arg_count + fd->var_count > 0) {
-        if ((fd->js_mode & JS_MODE_STRIP) && !fd->has_eval_call) {
-            /* Strip variable definitions not needed at runtime */
-            int i;
-            for(i = 0; i < fd->var_count; i++) {
-                JS_FreeAtom(ctx, fd->vars[i].var_name);
-            }
-            for(i = 0; i < fd->arg_count; i++) {
-                JS_FreeAtom(ctx, fd->args[i].var_name);
-            }
-            for(i = 0; i < fd->closure_var_count; i++) {
-                JS_FreeAtom(ctx, fd->closure_var[i].var_name);
-                fd->closure_var[i].var_name = JS_ATOM_NULL;
-            }
-        } else {
-            b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
-            memcpy(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0]));
-            memcpy(b->vardefs + fd->arg_count, fd->vars, fd->var_count * sizeof(fd->vars[0]));
-        }
-        b->var_count = fd->var_count;
-        b->arg_count = fd->arg_count;
-        b->defined_arg_count = fd->defined_arg_count;
-        js_free(ctx, fd->args);
-        js_free(ctx, fd->vars);
-    }
-    b->cpool_count = fd->cpool_count;
-    if (b->cpool_count) {
-        b->cpool = (void *)((uint8_t*)b + cpool_offset);
-        memcpy(b->cpool, fd->cpool, b->cpool_count * sizeof(*b->cpool));
-    }
-    js_free(ctx, fd->cpool);
-    fd->cpool = NULL;
-
-    b->stack_size = stack_size;
-
-    if (fd->js_mode & JS_MODE_STRIP) {
-        JS_FreeAtom(ctx, fd->filename);
-        dbuf_free(&fd->pc2line);    // probably useless
-    } else {
-        /* XXX: source and pc2line info should be packed at the end of the
-           JSFunctionBytecode structure, avoiding allocation overhead
-         */
-        b->has_debug = 1;
-        b->debug.filename = fd->filename;
-        b->debug.line_num = fd->line_num;
-
-        //DynBuf pc2line;
-        //compute_pc2line_info(fd, &pc2line);
-        //js_free(ctx, fd->line_number_slots)
-        b->debug.pc2line_buf = js_realloc(ctx, fd->pc2line.buf, fd->pc2line.size);
-        if (!b->debug.pc2line_buf)
-            b->debug.pc2line_buf = fd->pc2line.buf;
-        b->debug.pc2line_len = fd->pc2line.size;
-        b->debug.source = fd->source;
-        b->debug.source_len = fd->source_len;
-    }
-    if (fd->scopes != fd->def_scope_array)
-        js_free(ctx, fd->scopes);
-
-    b->closure_var_count = fd->closure_var_count;
-    if (b->closure_var_count) {
-        b->closure_var = (void *)((uint8_t*)b + closure_var_offset);
-        memcpy(b->closure_var, fd->closure_var, b->closure_var_count * sizeof(*b->closure_var));
-    }
-    js_free(ctx, fd->closure_var);
-    fd->closure_var = NULL;
-
-    b->has_prototype = fd->has_prototype;
-    b->has_simple_parameter_list = fd->has_simple_parameter_list;
-    b->js_mode = fd->js_mode;
-    b->is_derived_class_constructor = fd->is_derived_class_constructor;
-    b->func_kind = fd->func_kind;
-    b->need_home_object = (fd->home_object_var_idx >= 0 ||
-                           fd->need_home_object);
-    b->new_target_allowed = fd->new_target_allowed;
-    b->super_call_allowed = fd->super_call_allowed;
-    b->super_allowed = fd->super_allowed;
-    b->arguments_allowed = fd->arguments_allowed;
-    b->backtrace_barrier = fd->backtrace_barrier;
-    b->realm = JS_DupContext(ctx);
-
-    add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
-    
-#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 1)
-    if (!(fd->js_mode & JS_MODE_STRIP)) {
-        js_dump_function_bytecode(ctx, b);
-    }
-#endif
-
-    if (fd->parent) {
-        /* remove from parent list */
-        list_del(&fd->link);
-    }
-
-    js_free(ctx, fd);
-    return JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);
- fail:
-    js_free_function_def(ctx, fd);
-    return JS_EXCEPTION;
-}
-
-static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b)
-{
-    int i;
-
-#if 0
-    {
-        char buf[ATOM_GET_STR_BUF_SIZE];
-        printf("freeing %s\n",
-               JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
-    }
-#endif
-    free_bytecode_atoms(rt, b->byte_code_buf, b->byte_code_len, TRUE);
-
-    if (b->vardefs) {
-        for(i = 0; i < b->arg_count + b->var_count; i++) {
-            JS_FreeAtomRT(rt, b->vardefs[i].var_name);
-        }
-    }
-    for(i = 0; i < b->cpool_count; i++)
-        JS_FreeValueRT(rt, b->cpool[i]);
-
-    for(i = 0; i < b->closure_var_count; i++) {
-        JSClosureVar *cv = &b->closure_var[i];
-        JS_FreeAtomRT(rt, cv->var_name);
-    }
-    if (b->realm)
-        JS_FreeContext(b->realm);
-
-    JS_FreeAtomRT(rt, b->func_name);
-    if (b->has_debug) {
-        JS_FreeAtomRT(rt, b->debug.filename);
-        js_free_rt(rt, b->debug.pc2line_buf);
-        js_free_rt(rt, b->debug.source);
-    }
-
-    remove_gc_object(&b->header);
-    if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && b->header.ref_count != 0) {
-        list_add_tail(&b->header.link, &rt->gc_zero_ref_count_list);
-    } else {
-        js_free_rt(rt, b);
-    }
-}
-
-static __exception int js_parse_directives(JSParseState *s)
-{
-    char str[20];
-    JSParsePos pos;
-    BOOL has_semi;
-
-    if (s->token.val != TOK_STRING)
-        return 0;
-
-    js_parse_get_pos(s, &pos);
-
-    while(s->token.val == TOK_STRING) {
-        /* Copy actual source string representation */
-        snprintf(str, sizeof str, "%.*s",
-                 (int)(s->buf_ptr - s->token.ptr - 2), s->token.ptr + 1);
-
-        if (next_token(s))
-            return -1;
-
-        has_semi = FALSE;
-        switch (s->token.val) {
-        case ';':
-            if (next_token(s))
-                return -1;
-            has_semi = TRUE;
-            break;
-        case '}':
-        case TOK_EOF:
-            has_semi = TRUE;
-            break;
-        case TOK_NUMBER:
-        case TOK_STRING:
-        case TOK_TEMPLATE:
-        case TOK_IDENT:
-        case TOK_REGEXP:
-        case TOK_DEC:
-        case TOK_INC:
-        case TOK_NULL:
-        case TOK_FALSE:
-        case TOK_TRUE:
-        case TOK_IF:
-        case TOK_RETURN:
-        case TOK_VAR:
-        case TOK_THIS:
-        case TOK_DELETE:
-        case TOK_TYPEOF:
-        case TOK_NEW:
-        case TOK_DO:
-        case TOK_WHILE:
-        case TOK_FOR:
-        case TOK_SWITCH:
-        case TOK_THROW:
-        case TOK_TRY:
-        case TOK_FUNCTION:
-        case TOK_DEBUGGER:
-        case TOK_WITH:
-        case TOK_CLASS:
-        case TOK_CONST:
-        case TOK_ENUM:
-        case TOK_EXPORT:
-        case TOK_IMPORT:
-        case TOK_SUPER:
-        case TOK_INTERFACE:
-        case TOK_LET:
-        case TOK_PACKAGE:
-        case TOK_PRIVATE:
-        case TOK_PROTECTED:
-        case TOK_PUBLIC:
-        case TOK_STATIC:
-            /* automatic insertion of ';' */
-            if (s->got_lf)
-                has_semi = TRUE;
-            break;
-        default:
-            break;
-        }
-        if (!has_semi)
-            break;
-        if (!strcmp(str, "use strict")) {
-            s->cur_func->has_use_strict = TRUE;
-            s->cur_func->js_mode |= JS_MODE_STRICT;
-        }
-#if !defined(DUMP_BYTECODE) || !(DUMP_BYTECODE & 8)
-        else if (!strcmp(str, "use strip")) {
-            s->cur_func->js_mode |= JS_MODE_STRIP;
-        }
-#endif
-#ifdef CONFIG_BIGNUM
-        else if (s->ctx->bignum_ext && !strcmp(str, "use math")) {
-            s->cur_func->js_mode |= JS_MODE_MATH;
-        }
-#endif
-    }
-    return js_parse_seek_token(s, &pos);
-}
-
-static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd,
-                                         JSAtom func_name)
-{
-    JSAtom name;
-    int i, idx;
-
-    if (fd->js_mode & JS_MODE_STRICT) {
-        if (!fd->has_simple_parameter_list && fd->has_use_strict) {
-            return js_parse_error(s, "\"use strict\" not allowed in function with default or destructuring parameter");
-        }
-        if (func_name == JS_ATOM_eval || func_name == JS_ATOM_arguments) {
-            return js_parse_error(s, "invalid function name in strict code");
-        }
-        for (idx = 0; idx < fd->arg_count; idx++) {
-            name = fd->args[idx].var_name;
-
-            if (name == JS_ATOM_eval || name == JS_ATOM_arguments) {
-                return js_parse_error(s, "invalid argument name in strict code");
-            }
-        }
-    }
-    /* check async_generator case */
-    if ((fd->js_mode & JS_MODE_STRICT)
-    ||  !fd->has_simple_parameter_list
-    ||  (fd->func_type == JS_PARSE_FUNC_METHOD && fd->func_kind == JS_FUNC_ASYNC)
-    ||  fd->func_type == JS_PARSE_FUNC_ARROW
-    ||  fd->func_type == JS_PARSE_FUNC_METHOD) {
-        for (idx = 0; idx < fd->arg_count; idx++) {
-            name = fd->args[idx].var_name;
-            if (name != JS_ATOM_NULL) {
-                for (i = 0; i < idx; i++) {
-                    if (fd->args[i].var_name == name)
-                        goto duplicate;
-                }
-                /* Check if argument name duplicates a destructuring parameter */
-                /* XXX: should have a flag for such variables */
-                for (i = 0; i < fd->var_count; i++) {
-                    if (fd->vars[i].var_name == name &&
-                        fd->vars[i].scope_level == 0)
-                        goto duplicate;
-                }
-            }
-        }
-    }
-    return 0;
-
-duplicate:
-    return js_parse_error(s, "duplicate argument names not allowed in this context");
-}
-
-/* create a function to initialize class fields */
-static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s)
-{
-    JSFunctionDef *fd;
-    
-    fd = js_new_function_def(s->ctx, s->cur_func, FALSE, FALSE,
-                             s->filename, 0);
-    if (!fd)
-        return NULL;
-    fd->func_name = JS_ATOM_NULL;
-    fd->has_prototype = FALSE;
-    fd->has_home_object = TRUE;
-    
-    fd->has_arguments_binding = FALSE;
-    fd->has_this_binding = TRUE;
-    fd->is_derived_class_constructor = FALSE;
-    fd->new_target_allowed = TRUE;
-    fd->super_call_allowed = FALSE;
-    fd->super_allowed = fd->has_home_object;
-    fd->arguments_allowed = FALSE;
-    
-    fd->func_kind = JS_FUNC_NORMAL;
-    fd->func_type = JS_PARSE_FUNC_METHOD;
-    return fd;
-}
-
-/* func_name must be JS_ATOM_NULL for JS_PARSE_FUNC_STATEMENT and
-   JS_PARSE_FUNC_EXPR, JS_PARSE_FUNC_ARROW and JS_PARSE_FUNC_VAR */
-static __exception int js_parse_function_decl2(JSParseState *s,
-                                               JSParseFunctionEnum func_type,
-                                               JSFunctionKindEnum func_kind,
-                                               JSAtom func_name,
-                                               const uint8_t *ptr,
-                                               int function_line_num,
-                                               JSParseExportEnum export_flag,
-                                               JSFunctionDef **pfd)
-{
-    JSContext *ctx = s->ctx;
-    JSFunctionDef *fd = s->cur_func;
-    BOOL is_expr;
-    int func_idx, lexical_func_idx = -1;
-    BOOL has_opt_arg;
-    BOOL create_func_var = FALSE;
-
-    is_expr = (func_type != JS_PARSE_FUNC_STATEMENT &&
-               func_type != JS_PARSE_FUNC_VAR);
-
-    if (func_type == JS_PARSE_FUNC_STATEMENT ||
-        func_type == JS_PARSE_FUNC_VAR ||
-        func_type == JS_PARSE_FUNC_EXPR) {
-        if (func_kind == JS_FUNC_NORMAL &&
-            token_is_pseudo_keyword(s, JS_ATOM_async) &&
-            peek_token(s, TRUE) != '\n') {
-            if (next_token(s))
-                return -1;
-            func_kind = JS_FUNC_ASYNC;
-        }
-        if (next_token(s))
-            return -1;
-        if (s->token.val == '*') {
-            if (next_token(s))
-                return -1;
-            func_kind |= JS_FUNC_GENERATOR;
-        }
-
-        if (s->token.val == TOK_IDENT) {
-            if (s->token.u.ident.is_reserved ||
-                (s->token.u.ident.atom == JS_ATOM_yield &&
-                 func_type == JS_PARSE_FUNC_EXPR &&
-                 (func_kind & JS_FUNC_GENERATOR)) ||
-                (s->token.u.ident.atom == JS_ATOM_await &&
-                 func_type == JS_PARSE_FUNC_EXPR &&
-                 (func_kind & JS_FUNC_ASYNC))) {
-                return js_parse_error_reserved_identifier(s);
-            }
-        }
-        if (s->token.val == TOK_IDENT ||
-            (((s->token.val == TOK_YIELD && !(fd->js_mode & JS_MODE_STRICT)) ||
-             (s->token.val == TOK_AWAIT && !s->is_module)) &&
-             func_type == JS_PARSE_FUNC_EXPR)) {
-            func_name = JS_DupAtom(ctx, s->token.u.ident.atom);
-            if (next_token(s)) {
-                JS_FreeAtom(ctx, func_name);
-                return -1;
-            }
-        } else {
-            if (func_type != JS_PARSE_FUNC_EXPR &&
-                export_flag != JS_PARSE_EXPORT_DEFAULT) {
-                return js_parse_error(s, "function name expected");
-            }
-        }
-    } else if (func_type != JS_PARSE_FUNC_ARROW) {
-        func_name = JS_DupAtom(ctx, func_name);
-    }
-
-    if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_MODULE &&
-        (func_type == JS_PARSE_FUNC_STATEMENT || func_type == JS_PARSE_FUNC_VAR)) {
-        JSGlobalVar *hf;
-        hf = find_global_var(fd, func_name);
-        /* XXX: should check scope chain */
-        if (hf && hf->scope_level == fd->scope_level) {
-            js_parse_error(s, "invalid redefinition of global identifier in module code");
-            JS_FreeAtom(ctx, func_name);
-            return -1;
-        }
-    }
-
-    if (func_type == JS_PARSE_FUNC_VAR) {
-        if (!(fd->js_mode & JS_MODE_STRICT)
-        && func_kind == JS_FUNC_NORMAL
-        &&  find_lexical_decl(ctx, fd, func_name, fd->scope_first, FALSE) < 0
-        &&  !((func_idx = find_var(ctx, fd, func_name)) >= 0 && (func_idx & ARGUMENT_VAR_OFFSET))
-        &&  !(func_name == JS_ATOM_arguments && fd->has_arguments_binding)) {
-            create_func_var = TRUE;
-        }
-        /* Create the lexical name here so that the function closure
-           contains it */
-        if (fd->is_eval &&
-            (fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
-             fd->eval_type == JS_EVAL_TYPE_MODULE) &&
-            fd->scope_level == fd->body_scope) {
-            /* avoid creating a lexical variable in the global
-               scope. XXX: check annex B */
-            JSGlobalVar *hf;
-            hf = find_global_var(fd, func_name);
-            /* XXX: should check scope chain */
-            if (hf && hf->scope_level == fd->scope_level) {
-                js_parse_error(s, "invalid redefinition of global identifier");
-                JS_FreeAtom(ctx, func_name);
-                return -1;
-            }
-        } else {
-            /* Always create a lexical name, fail if at the same scope as
-               existing name */
-            /* Lexical variable will be initialized upon entering scope */
-            lexical_func_idx = define_var(s, fd, func_name,
-                                          func_kind != JS_FUNC_NORMAL ?
-                                          JS_VAR_DEF_NEW_FUNCTION_DECL :
-                                          JS_VAR_DEF_FUNCTION_DECL);
-            if (lexical_func_idx < 0) {
-                JS_FreeAtom(ctx, func_name);
-                return -1;
-            }
-        }
-    }
-
-    fd = js_new_function_def(ctx, fd, FALSE, is_expr,
-                             s->filename, function_line_num);
-    if (!fd) {
-        JS_FreeAtom(ctx, func_name);
-        return -1;
-    }
-    if (pfd)
-        *pfd = fd;
-    s->cur_func = fd;
-    fd->func_name = func_name;
-    /* XXX: test !fd->is_generator is always false */
-    fd->has_prototype = (func_type == JS_PARSE_FUNC_STATEMENT ||
-                         func_type == JS_PARSE_FUNC_VAR ||
-                         func_type == JS_PARSE_FUNC_EXPR) &&
-                        func_kind == JS_FUNC_NORMAL;
-    fd->has_home_object = (func_type == JS_PARSE_FUNC_METHOD ||
-                           func_type == JS_PARSE_FUNC_GETTER ||
-                           func_type == JS_PARSE_FUNC_SETTER ||
-                           func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR ||
-                           func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);
-    fd->has_arguments_binding = (func_type != JS_PARSE_FUNC_ARROW);
-    fd->has_this_binding = fd->has_arguments_binding;
-    fd->is_derived_class_constructor = (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);
-    if (func_type == JS_PARSE_FUNC_ARROW) {
-        fd->new_target_allowed = fd->parent->new_target_allowed;
-        fd->super_call_allowed = fd->parent->super_call_allowed;
-        fd->super_allowed = fd->parent->super_allowed;
-        fd->arguments_allowed = fd->parent->arguments_allowed;
-    } else {
-        fd->new_target_allowed = TRUE;
-        fd->super_call_allowed = fd->is_derived_class_constructor;
-        fd->super_allowed = fd->has_home_object;
-        fd->arguments_allowed = TRUE;
-    }
-
-    /* fd->in_function_body == FALSE prevents yield/await during the parsing
-       of the arguments in generator/async functions. They are parsed as
-       regular identifiers for other function kinds. */
-    fd->func_kind = func_kind;
-    fd->func_type = func_type;
-
-    if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR ||
-        func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR) {
-        /* error if not invoked as a constructor */
-        emit_op(s, OP_check_ctor);
-    }
-
-    if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) {
-        emit_class_field_init(s);
-    }
-    
-    /* parse arguments */
-    fd->has_simple_parameter_list = TRUE;
-    fd->has_parameter_expressions = FALSE;
-    has_opt_arg = FALSE;
-    if (func_type == JS_PARSE_FUNC_ARROW && s->token.val == TOK_IDENT) {
-        JSAtom name;
-        if (s->token.u.ident.is_reserved) {
-            js_parse_error_reserved_identifier(s);
-            goto fail;
-        }
-        name = s->token.u.ident.atom;
-        if (add_arg(ctx, fd, name) < 0)
-            goto fail;
-        fd->defined_arg_count = 1;
-    } else {
-        if (s->token.val == '(') {
-            int skip_bits;
-            /* if there is an '=' inside the parameter list, we
-               consider there is a parameter expression inside */
-            js_parse_skip_parens_token(s, &skip_bits, FALSE);
-            if (skip_bits & SKIP_HAS_ASSIGNMENT)
-                fd->has_parameter_expressions = TRUE;
-            if (next_token(s))
-                goto fail;
-        } else {
-            if (js_parse_expect(s, '('))
-                goto fail;
-        }
-
-        if (fd->has_parameter_expressions) {
-            fd->scope_level = -1; /* force no parent scope */
-            if (push_scope(s) < 0)
-                return -1;
-        }
-        
-        while (s->token.val != ')') {
-            JSAtom name;
-            BOOL rest = FALSE;
-            int idx, has_initializer;
-
-            if (s->token.val == TOK_ELLIPSIS) {
-                fd->has_simple_parameter_list = FALSE;
-                rest = TRUE;
-                if (next_token(s))
-                    goto fail;
-            }
-            if (s->token.val == '[' || s->token.val == '{') {
-                fd->has_simple_parameter_list = FALSE;
-                if (rest) {
-                    emit_op(s, OP_rest);
-                    emit_u16(s, fd->arg_count);
-                } else {
-                    /* unnamed arg for destructuring */
-                    idx = add_arg(ctx, fd, JS_ATOM_NULL);
-                    emit_op(s, OP_get_arg);
-                    emit_u16(s, idx);
-                }
-                has_initializer = js_parse_destructuring_element(s, fd->has_parameter_expressions ? TOK_LET : TOK_VAR, 1, TRUE, -1, TRUE);
-                if (has_initializer < 0)
-                    goto fail;
-                if (has_initializer)
-                    has_opt_arg = TRUE;
-                if (!has_opt_arg)
-                    fd->defined_arg_count++;
-            } else if (s->token.val == TOK_IDENT) {
-                if (s->token.u.ident.is_reserved) {
-                    js_parse_error_reserved_identifier(s);
-                    goto fail;
-                }
-                name = s->token.u.ident.atom;
-                if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) {
-                    js_parse_error_reserved_identifier(s);
-                    goto fail;
-                }
-                if (fd->has_parameter_expressions) {
-                    if (define_var(s, fd, name, JS_VAR_DEF_LET) < 0)
-                        goto fail;
-                }
-                /* XXX: could avoid allocating an argument if rest is true */
-                idx = add_arg(ctx, fd, name);
-                if (idx < 0)
-                    goto fail;
-                if (next_token(s))
-                    goto fail;
-                if (rest) {
-                    emit_op(s, OP_rest);
-                    emit_u16(s, idx);
-                    if (fd->has_parameter_expressions) {
-                        emit_op(s, OP_dup);
-                        emit_op(s, OP_scope_put_var_init);
-                        emit_atom(s, name);
-                        emit_u16(s, fd->scope_level);
-                    }
-                    emit_op(s, OP_put_arg);
-                    emit_u16(s, idx);
-                    fd->has_simple_parameter_list = FALSE;
-                    has_opt_arg = TRUE;
-                } else if (s->token.val == '=') {
-                    int label;
-                    
-                    fd->has_simple_parameter_list = FALSE;
-                    has_opt_arg = TRUE;
-
-                    if (next_token(s))
-                        goto fail;
-
-                    label = new_label(s);
-                    emit_op(s, OP_get_arg);
-                    emit_u16(s, idx);
-                    emit_op(s, OP_dup);
-                    emit_op(s, OP_undefined);
-                    emit_op(s, OP_strict_eq);
-                    emit_goto(s, OP_if_false, label);
-                    emit_op(s, OP_drop);
-                    if (js_parse_assign_expr(s))
-                        goto fail;
-                    set_object_name(s, name);
-                    emit_op(s, OP_dup);
-                    emit_op(s, OP_put_arg);
-                    emit_u16(s, idx);
-                    emit_label(s, label);
-                    emit_op(s, OP_scope_put_var_init);
-                    emit_atom(s, name);
-                    emit_u16(s, fd->scope_level);
-                } else {
-                    if (!has_opt_arg) {
-                        fd->defined_arg_count++;
-                    }
-                    if (fd->has_parameter_expressions) {
-                        /* copy the argument to the argument scope */
-                        emit_op(s, OP_get_arg);
-                        emit_u16(s, idx);
-                        emit_op(s, OP_scope_put_var_init);
-                        emit_atom(s, name);
-                        emit_u16(s, fd->scope_level);
-                    }
-                }
-            } else {
-                js_parse_error(s, "missing formal parameter");
-                goto fail;
-            }
-            if (rest && s->token.val != ')') {
-                js_parse_expect(s, ')');
-                goto fail;
-            }
-            if (s->token.val == ')')
-                break;
-            if (js_parse_expect(s, ','))
-                goto fail;
-        }
-        if ((func_type == JS_PARSE_FUNC_GETTER && fd->arg_count != 0) ||
-            (func_type == JS_PARSE_FUNC_SETTER && fd->arg_count != 1)) {
-            js_parse_error(s, "invalid number of arguments for getter or setter");
-            goto fail;
-        }
-    }
-
-    if (fd->has_parameter_expressions) {
-        int idx;
-
-        /* Copy the variables in the argument scope to the variable
-           scope (see FunctionDeclarationInstantiation() in spec). The
-           normal arguments are already present, so no need to copy
-           them. */
-        idx = fd->scopes[fd->scope_level].first;
-        while (idx >= 0) {
-            JSVarDef *vd = &fd->vars[idx];
-            if (vd->scope_level != fd->scope_level)
-                break;
-            if (find_var(ctx, fd, vd->var_name) < 0) {
-                if (add_var(ctx, fd, vd->var_name) < 0)
-                    goto fail;
-                vd = &fd->vars[idx]; /* fd->vars may have been reallocated */
-                emit_op(s, OP_scope_get_var);
-                emit_atom(s, vd->var_name);
-                emit_u16(s, fd->scope_level);
-                emit_op(s, OP_scope_put_var);
-                emit_atom(s, vd->var_name);
-                emit_u16(s, 0);
-            }
-            idx = vd->scope_next;
-        }
-        
-        /* the argument scope has no parent, hence we don't use pop_scope(s) */
-        emit_op(s, OP_leave_scope);
-        emit_u16(s, fd->scope_level);
-
-        /* set the variable scope as the current scope */
-        fd->scope_level = 0;
-        fd->scope_first = fd->scopes[fd->scope_level].first;
-    }
-    
-    if (next_token(s))
-        goto fail;
-
-    /* generator function: yield after the parameters are evaluated */
-    if (func_kind == JS_FUNC_GENERATOR ||
-        func_kind == JS_FUNC_ASYNC_GENERATOR)
-        emit_op(s, OP_initial_yield);
-
-    /* in generators, yield expression is forbidden during the parsing
-       of the arguments */
-    fd->in_function_body = TRUE;
-    push_scope(s);  /* enter body scope */
-    fd->body_scope = fd->scope_level;
-
-    if (s->token.val == TOK_ARROW) {
-        if (next_token(s))
-            goto fail;
-
-        if (s->token.val != '{') {
-            if (js_parse_function_check_names(s, fd, func_name))
-                goto fail;
-
-            if (js_parse_assign_expr(s))
-                goto fail;
-
-            if (func_kind != JS_FUNC_NORMAL)
-                emit_op(s, OP_return_async);
-            else
-                emit_op(s, OP_return);
-
-            if (!(fd->js_mode & JS_MODE_STRIP)) {
-                /* save the function source code */
-                /* the end of the function source code is after the last
-                   token of the function source stored into s->last_ptr */
-                fd->source_len = s->last_ptr - ptr;
-                fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len);
-                if (!fd->source)
-                    goto fail;
-            }
-            goto done;
-        }
-    }
-
-    if (js_parse_expect(s, '{'))
-        goto fail;
-
-    if (js_parse_directives(s))
-        goto fail;
-
-    /* in strict_mode, check function and argument names */
-    if (js_parse_function_check_names(s, fd, func_name))
-        goto fail;
-
-    while (s->token.val != '}') {
-        if (js_parse_source_element(s))
-            goto fail;
-    }
-    if (!(fd->js_mode & JS_MODE_STRIP)) {
-        /* save the function source code */
-        fd->source_len = s->buf_ptr - ptr;
-        fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len);
-        if (!fd->source)
-            goto fail;
-    }
-
-    if (next_token(s)) {
-        /* consume the '}' */
-        goto fail;
-    }
-
-    /* in case there is no return, add one */
-    if (js_is_live_code(s)) {
-        emit_return(s, FALSE);
-    }
-done:
-    s->cur_func = fd->parent;
-
-    /* create the function object */
-    {
-        int idx;
-        JSAtom func_name = fd->func_name;
-
-        /* the real object will be set at the end of the compilation */
-        idx = cpool_add(s, JS_NULL);
-        fd->parent_cpool_idx = idx;
-
-        if (is_expr) {
-            /* for constructors, no code needs to be generated here */
-            if (func_type != JS_PARSE_FUNC_CLASS_CONSTRUCTOR &&
-                func_type != JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR) {
-                /* OP_fclosure creates the function object from the bytecode
-                   and adds the scope information */
-                emit_op(s, OP_fclosure);
-                emit_u32(s, idx);
-                if (func_name == JS_ATOM_NULL) {
-                    emit_op(s, OP_set_name);
-                    emit_u32(s, JS_ATOM_NULL);
-                }
-            }
-        } else if (func_type == JS_PARSE_FUNC_VAR) {
-            emit_op(s, OP_fclosure);
-            emit_u32(s, idx);
-            if (create_func_var) {
-                if (s->cur_func->is_global_var) {
-                    JSGlobalVar *hf;
-                    /* the global variable must be defined at the start of the
-                       function */
-                    hf = add_global_var(ctx, s->cur_func, func_name);
-                    if (!hf)
-                        goto fail;
-                    /* it is considered as defined at the top level
-                       (needed for annex B.3.3.4 and B.3.3.5
-                       checks) */
-                    hf->scope_level = 0; 
-                    hf->force_init = ((s->cur_func->js_mode & JS_MODE_STRICT) != 0);
-                    /* store directly into global var, bypass lexical scope */
-                    emit_op(s, OP_dup);
-                    emit_op(s, OP_scope_put_var);
-                    emit_atom(s, func_name);
-                    emit_u16(s, 0);
-                } else {
-                    /* do not call define_var to bypass lexical scope check */
-                    func_idx = find_var(ctx, s->cur_func, func_name);
-                    if (func_idx < 0) {
-                        func_idx = add_var(ctx, s->cur_func, func_name);
-                        if (func_idx < 0)
-                            goto fail;
-                    }
-                    /* store directly into local var, bypass lexical catch scope */
-                    emit_op(s, OP_dup);
-                    emit_op(s, OP_scope_put_var);
-                    emit_atom(s, func_name);
-                    emit_u16(s, 0);
-                }
-            }
-            if (lexical_func_idx >= 0) {
-                /* lexical variable will be initialized upon entering scope */
-                s->cur_func->vars[lexical_func_idx].func_pool_idx = idx;
-                emit_op(s, OP_drop);
-            } else {
-                /* store function object into its lexical name */
-                /* XXX: could use OP_put_loc directly */
-                emit_op(s, OP_scope_put_var_init);
-                emit_atom(s, func_name);
-                emit_u16(s, s->cur_func->scope_level);
-            }
-        } else {
-            if (!s->cur_func->is_global_var) {
-                int var_idx = define_var(s, s->cur_func, func_name, JS_VAR_DEF_VAR);
-
-                if (var_idx < 0)
-                    goto fail;
-                /* the variable will be assigned at the top of the function */
-                if (var_idx & ARGUMENT_VAR_OFFSET) {
-                    s->cur_func->args[var_idx - ARGUMENT_VAR_OFFSET].func_pool_idx = idx;
-                } else {
-                    s->cur_func->vars[var_idx].func_pool_idx = idx;
-                }
-            } else {
-                JSAtom func_var_name;
-                JSGlobalVar *hf;
-                if (func_name == JS_ATOM_NULL)
-                    func_var_name = JS_ATOM__default_; /* export default */
-                else
-                    func_var_name = func_name;
-                /* the variable will be assigned at the top of the function */
-                hf = add_global_var(ctx, s->cur_func, func_var_name);
-                if (!hf)
-                    goto fail;
-                hf->cpool_idx = idx;
-                if (export_flag != JS_PARSE_EXPORT_NONE) {
-                    if (!add_export_entry(s, s->cur_func->module, func_var_name,
-                                          export_flag == JS_PARSE_EXPORT_NAMED ? func_var_name : JS_ATOM_default, JS_EXPORT_TYPE_LOCAL))
-                        goto fail;
-                }
-            }
-        }
-    }
-    return 0;
- fail:
-    s->cur_func = fd->parent;
-    js_free_function_def(ctx, fd);
-    if (pfd)
-        *pfd = NULL;
-    return -1;
-}
-
-static __exception int js_parse_function_decl(JSParseState *s,
-                                              JSParseFunctionEnum func_type,
-                                              JSFunctionKindEnum func_kind,
-                                              JSAtom func_name,
-                                              const uint8_t *ptr,
-                                              int function_line_num)
-{
-    return js_parse_function_decl2(s, func_type, func_kind, func_name, ptr,
-                                   function_line_num, JS_PARSE_EXPORT_NONE,
-                                   NULL);
-}
-
-static __exception int js_parse_program(JSParseState *s)
-{
-    JSFunctionDef *fd = s->cur_func;
-    int idx;
-
-    if (next_token(s))
-        return -1;
-
-    if (js_parse_directives(s))
-        return -1;
-
-    fd->is_global_var = (fd->eval_type == JS_EVAL_TYPE_GLOBAL) ||
-        (fd->eval_type == JS_EVAL_TYPE_MODULE) ||
-        !(fd->js_mode & JS_MODE_STRICT);
-
-    if (!s->is_module) {
-        /* hidden variable for the return value */
-        fd->eval_ret_idx = idx = add_var(s->ctx, fd, JS_ATOM__ret_);
-        if (idx < 0)
-            return -1;
-    }
-
-    while (s->token.val != TOK_EOF) {
-        if (js_parse_source_element(s))
-            return -1;
-    }
-
-    if (!s->is_module) {
-        /* return the value of the hidden variable eval_ret_idx  */
-        emit_op(s, OP_get_loc);
-        emit_u16(s, fd->eval_ret_idx);
-
-        emit_op(s, OP_return);
-    } else {
-        emit_op(s, OP_return_undef);
-    }
-
-    return 0;
-}
-
-static void js_parse_init(JSContext *ctx, JSParseState *s,
-                          const char *input, size_t input_len,
-                          const char *filename)
-{
-    memset(s, 0, sizeof(*s));
-    s->ctx = ctx;
-    s->filename = filename;
-    s->line_num = 1;
-    s->buf_ptr = (const uint8_t *)input;
-    s->buf_end = s->buf_ptr + input_len;
-    s->token.val = ' ';
-    s->token.line_num = 1;
-}
-
-static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj,
-                                       JSValueConst this_obj,
-                                       JSVarRef **var_refs, JSStackFrame *sf)
-{
-    JSValue ret_val;
-    uint32_t tag;
-
-    tag = JS_VALUE_GET_TAG(fun_obj);
-    if (tag == JS_TAG_FUNCTION_BYTECODE) {
-        fun_obj = js_closure(ctx, fun_obj, var_refs, sf);
-        ret_val = JS_CallFree(ctx, fun_obj, this_obj, 0, NULL);
-    } else if (tag == JS_TAG_MODULE) {
-        JSModuleDef *m;
-        m = JS_VALUE_GET_PTR(fun_obj);
-        /* the module refcount should be >= 2 */
-        JS_FreeValue(ctx, fun_obj);
-        if (js_create_module_function(ctx, m) < 0)
-            goto fail;
-        if (js_link_module(ctx, m) < 0)
-            goto fail;
-        ret_val = js_evaluate_module(ctx, m);
-        if (JS_IsException(ret_val)) {
-        fail:
-            js_free_modules(ctx, JS_FREE_MODULE_NOT_EVALUATED);
-            return JS_EXCEPTION;
-        }
-    } else {
-        JS_FreeValue(ctx, fun_obj);
-        ret_val = JS_ThrowTypeError(ctx, "bytecode function expected");
-    }
-    return ret_val;
-}
-
-JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj)
-{
-    return JS_EvalFunctionInternal(ctx, fun_obj, ctx->global_obj, NULL, NULL);
-}
-
-static void skip_shebang(JSParseState *s)
-{
-    const uint8_t *p = s->buf_ptr;
-    int c;
-
-    if (p[0] == '#' && p[1] == '!') {
-        p += 2;
-        while (p < s->buf_end) {
-            if (*p == '\n' || *p == '\r') {
-                break;
-            } else if (*p >= 0x80) {
-                c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
-                if (c == CP_LS || c == CP_PS) {
-                    break;
-                } else if (c == -1) {
-                    p++; /* skip invalid UTF-8 */
-                }
-            } else {
-                p++;
-            }
-        }
-        s->buf_ptr = p;
-    }
-}
-
-/* 'input' must be zero terminated i.e. input[input_len] = '\0'. */
-static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
-                                 const char *input, size_t input_len,
-                                 const char *filename, int flags, int scope_idx)
-{
-    JSParseState s1, *s = &s1;
-    int err, js_mode, eval_type;
-    JSValue fun_obj, ret_val;
-    JSStackFrame *sf;
-    JSVarRef **var_refs;
-    JSFunctionBytecode *b;
-    JSFunctionDef *fd;
-    JSModuleDef *m;
-
-    js_parse_init(ctx, s, input, input_len, filename);
-    skip_shebang(s);
-
-    eval_type = flags & JS_EVAL_TYPE_MASK;
-    m = NULL;
-    if (eval_type == JS_EVAL_TYPE_DIRECT) {
-        JSObject *p;
-        sf = ctx->rt->current_stack_frame;
-        assert(sf != NULL);
-        assert(JS_VALUE_GET_TAG(sf->cur_func) == JS_TAG_OBJECT);
-        p = JS_VALUE_GET_OBJ(sf->cur_func);
-        assert(js_class_has_bytecode(p->class_id));
-        b = p->u.func.function_bytecode;
-        var_refs = p->u.func.var_refs;
-        js_mode = b->js_mode;
-    } else {
-        sf = NULL;
-        b = NULL;
-        var_refs = NULL;
-        js_mode = 0;
-        if (flags & JS_EVAL_FLAG_STRICT)
-            js_mode |= JS_MODE_STRICT;
-        if (flags & JS_EVAL_FLAG_STRIP)
-            js_mode |= JS_MODE_STRIP;
-        if (eval_type == JS_EVAL_TYPE_MODULE) {
-            JSAtom module_name = JS_NewAtom(ctx, filename);
-            if (module_name == JS_ATOM_NULL)
-                return JS_EXCEPTION;
-            m = js_new_module_def(ctx, module_name);
-            if (!m)
-                return JS_EXCEPTION;
-            js_mode |= JS_MODE_STRICT;
-        }
-    }
-    fd = js_new_function_def(ctx, NULL, TRUE, FALSE, filename, 1);
-    if (!fd)
-        goto fail1;
-    s->cur_func = fd;
-    fd->eval_type = eval_type;
-    fd->has_this_binding = (eval_type != JS_EVAL_TYPE_DIRECT);
-    fd->backtrace_barrier = ((flags & JS_EVAL_FLAG_BACKTRACE_BARRIER) != 0);
-    if (eval_type == JS_EVAL_TYPE_DIRECT) {
-        fd->new_target_allowed = b->new_target_allowed;
-        fd->super_call_allowed = b->super_call_allowed;
-        fd->super_allowed = b->super_allowed;
-        fd->arguments_allowed = b->arguments_allowed;
-    } else {
-        fd->new_target_allowed = FALSE;
-        fd->super_call_allowed = FALSE;
-        fd->super_allowed = FALSE;
-        fd->arguments_allowed = TRUE;
-    }
-    fd->js_mode = js_mode;
-    fd->func_name = JS_DupAtom(ctx, JS_ATOM__eval_);
-    if (b) {
-        if (add_closure_variables(ctx, fd, b, scope_idx))
-            goto fail;
-    }
-    fd->module = m;
-    s->is_module = (m != NULL);
-    s->allow_html_comments = !s->is_module;
-
-    push_scope(s); /* body scope */
-    fd->body_scope = fd->scope_level;
-    
-    err = js_parse_program(s);
-    if (err) {
-    fail:
-        free_token(s, &s->token);
-        js_free_function_def(ctx, fd);
-        goto fail1;
-    }
-
-    /* create the function object and all the enclosed functions */
-    fun_obj = js_create_function(ctx, fd);
-    if (JS_IsException(fun_obj))
-        goto fail1;
-    /* Could add a flag to avoid resolution if necessary */
-    if (m) {
-        m->func_obj = fun_obj;
-        if (js_resolve_module(ctx, m) < 0)
-            goto fail1;
-        fun_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
-    }
-    if (flags & JS_EVAL_FLAG_COMPILE_ONLY) {
-        ret_val = fun_obj;
-    } else {
-        ret_val = JS_EvalFunctionInternal(ctx, fun_obj, this_obj, var_refs, sf);
-    }
-    return ret_val;
- fail1:
-    /* XXX: should free all the unresolved dependencies */
-    if (m)
-        js_free_module_def(ctx, m);
-    return JS_EXCEPTION;
-}
-
-/* the indirection is needed to make 'eval' optional */
-static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
-                               const char *input, size_t input_len,
-                               const char *filename, int flags, int scope_idx)
-{
-    if (unlikely(!ctx->eval_internal)) {
-        return JS_ThrowTypeError(ctx, "eval is not supported");
-    }
-    return ctx->eval_internal(ctx, this_obj, input, input_len, filename,
-                              flags, scope_idx);
-}
-
-static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
-                             JSValueConst val, int flags, int scope_idx)
-{
-    JSValue ret;
-    const char *str;
-    size_t len;
-
-    if (!JS_IsString(val))
-        return JS_DupValue(ctx, val);
-    str = JS_ToCStringLen(ctx, &len, val);
-    if (!str)
-        return JS_EXCEPTION;
-    ret = JS_EvalInternal(ctx, this_obj, str, len, "<input>", flags, scope_idx);
-    JS_FreeCString(ctx, str);
-    return ret;
-
-}
-
-JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj,
-                    const char *input, size_t input_len,
-                    const char *filename, int eval_flags)
-{
-    int eval_type = eval_flags & JS_EVAL_TYPE_MASK;
-    JSValue ret;
-
-    assert(eval_type == JS_EVAL_TYPE_GLOBAL ||
-           eval_type == JS_EVAL_TYPE_MODULE);
-    ret = JS_EvalInternal(ctx, this_obj, input, input_len, filename,
-                          eval_flags, -1);
-    return ret;
-}
-
-JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
-                const char *filename, int eval_flags)
-{
-    return JS_EvalThis(ctx, ctx->global_obj, input, input_len, filename,
-                       eval_flags);
-}
-
-int JS_ResolveModule(JSContext *ctx, JSValueConst obj)
-{
-    if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
-        JSModuleDef *m = JS_VALUE_GET_PTR(obj);
-        if (js_resolve_module(ctx, m) < 0) {
-            js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);
-            return -1;
-        }
-    }
-    return 0;
-}
-
-/*******************************************************************/
-/* object list */
-
-typedef struct {
-    JSObject *obj;
-    uint32_t hash_next; /* -1 if no next entry */
-} JSObjectListEntry;
-
-/* XXX: reuse it to optimize weak references */
-typedef struct {
-    JSObjectListEntry *object_tab;
-    int object_count;
-    int object_size;
-    uint32_t *hash_table;
-    uint32_t hash_size;
-} JSObjectList;
-
-static void js_object_list_init(JSObjectList *s)
-{
-    memset(s, 0, sizeof(*s));
-}
-
-static uint32_t js_object_list_get_hash(JSObject *p, uint32_t hash_size)
-{
-    return ((uintptr_t)p * 3163) & (hash_size - 1);
-}
-
-static int js_object_list_resize_hash(JSContext *ctx, JSObjectList *s,
-                                 uint32_t new_hash_size)
-{
-    JSObjectListEntry *e;
-    uint32_t i, h, *new_hash_table;
-
-    new_hash_table = js_malloc(ctx, sizeof(new_hash_table[0]) * new_hash_size);
-    if (!new_hash_table)
-        return -1;
-    js_free(ctx, s->hash_table);
-    s->hash_table = new_hash_table;
-    s->hash_size = new_hash_size;
-    
-    for(i = 0; i < s->hash_size; i++) {
-        s->hash_table[i] = -1;
-    }
-    for(i = 0; i < s->object_count; i++) {
-        e = &s->object_tab[i];
-        h = js_object_list_get_hash(e->obj, s->hash_size); 
-        e->hash_next = s->hash_table[h];
-        s->hash_table[h] = i;
-    }
-    return 0;
-}
-
-/* the reference count of 'obj' is not modified. Return 0 if OK, -1 if
-   memory error */
-static int js_object_list_add(JSContext *ctx, JSObjectList *s, JSObject *obj)
-{
-    JSObjectListEntry *e;
-    uint32_t h, new_hash_size;
-    
-    if (js_resize_array(ctx, (void *)&s->object_tab,
-                        sizeof(s->object_tab[0]),
-                        &s->object_size, s->object_count + 1))
-        return -1;
-    if (unlikely((s->object_count + 1) >= s->hash_size)) {
-        new_hash_size = max_uint32(s->hash_size, 4);
-        while (new_hash_size <= s->object_count)
-            new_hash_size *= 2;
-        if (js_object_list_resize_hash(ctx, s, new_hash_size))
-            return -1;
-    }
-    e = &s->object_tab[s->object_count++];
-    h = js_object_list_get_hash(obj, s->hash_size); 
-    e->obj = obj;
-    e->hash_next = s->hash_table[h];
-    s->hash_table[h] = s->object_count - 1;
-    return 0;
-}
-
-/* return -1 if not present or the object index */
-static int js_object_list_find(JSContext *ctx, JSObjectList *s, JSObject *obj)
-{
-    JSObjectListEntry *e;
-    uint32_t h, p;
-
-    /* must test empty size because there is no hash table */
-    if (s->object_count == 0)
-        return -1;
-    h = js_object_list_get_hash(obj, s->hash_size); 
-    p = s->hash_table[h];
-    while (p != -1) {
-        e = &s->object_tab[p];
-        if (e->obj == obj)
-            return p;
-        p = e->hash_next;
-    }
-    return -1;
-}
-
-static void js_object_list_end(JSContext *ctx, JSObjectList *s)
-{
-    js_free(ctx, s->object_tab);
-    js_free(ctx, s->hash_table);
-}
-
-/*******************************************************************/
-/* binary object writer & reader */
-
-typedef enum BCTagEnum {
-    BC_TAG_NULL = 1,
-    BC_TAG_UNDEFINED,
-    BC_TAG_BOOL_FALSE,
-    BC_TAG_BOOL_TRUE,
-    BC_TAG_INT32,
-    BC_TAG_FLOAT64,
-    BC_TAG_STRING,
-    BC_TAG_OBJECT,
-    BC_TAG_ARRAY,
-    BC_TAG_BIG_INT,
-    BC_TAG_BIG_FLOAT,
-    BC_TAG_BIG_DECIMAL,
-    BC_TAG_TEMPLATE_OBJECT,
-    BC_TAG_FUNCTION_BYTECODE,
-    BC_TAG_MODULE,
-    BC_TAG_TYPED_ARRAY,
-    BC_TAG_ARRAY_BUFFER,
-    BC_TAG_SHARED_ARRAY_BUFFER,
-    BC_TAG_DATE,
-    BC_TAG_OBJECT_VALUE,
-    BC_TAG_OBJECT_REFERENCE,
-} BCTagEnum;
-
-#ifdef CONFIG_BIGNUM
-#define BC_BASE_VERSION 2
-#else
-#define BC_BASE_VERSION 1
-#endif
-#define BC_BE_VERSION 0x40
-#ifdef WORDS_BIGENDIAN
-#define BC_VERSION (BC_BASE_VERSION | BC_BE_VERSION)
-#else
-#define BC_VERSION BC_BASE_VERSION
-#endif
-
-typedef struct BCWriterState {
-    JSContext *ctx;
-    DynBuf dbuf;
-    BOOL byte_swap : 8;
-    BOOL allow_bytecode : 8;
-    BOOL allow_sab : 8;
-    BOOL allow_reference : 8;
-    uint32_t first_atom;
-    uint32_t *atom_to_idx;
-    int atom_to_idx_size;
-    JSAtom *idx_to_atom;
-    int idx_to_atom_count;
-    int idx_to_atom_size;
-    uint8_t **sab_tab;
-    int sab_tab_len;
-    int sab_tab_size;
-    /* list of referenced objects (used if allow_reference = TRUE) */
-    JSObjectList object_list;
-} BCWriterState;
-
-#ifdef DUMP_READ_OBJECT
-static const char * const bc_tag_str[] = {
-    "invalid",
-    "null",
-    "undefined",
-    "false",
-    "true",
-    "int32",
-    "float64",
-    "string",
-    "object",
-    "array",
-    "bigint",
-    "bigfloat",
-    "bigdecimal",
-    "template",
-    "function",
-    "module",
-    "TypedArray",
-    "ArrayBuffer",
-    "SharedArrayBuffer",
-    "Date",
-    "ObjectValue",
-    "ObjectReference",
-};
-#endif
-
-static void bc_put_u8(BCWriterState *s, uint8_t v)
-{
-    dbuf_putc(&s->dbuf, v);
-}
-
-static void bc_put_u16(BCWriterState *s, uint16_t v)
-{
-    if (s->byte_swap)
-        v = bswap16(v);
-    dbuf_put_u16(&s->dbuf, v);
-}
-
-static __maybe_unused void bc_put_u32(BCWriterState *s, uint32_t v)
-{
-    if (s->byte_swap)
-        v = bswap32(v);
-    dbuf_put_u32(&s->dbuf, v);
-}
-
-static void bc_put_u64(BCWriterState *s, uint64_t v)
-{
-    if (s->byte_swap)
-        v = bswap64(v);
-    dbuf_put(&s->dbuf, (uint8_t *)&v, sizeof(v));
-}
-
-static void bc_put_leb128(BCWriterState *s, uint32_t v)
-{
-    dbuf_put_leb128(&s->dbuf, v);
-}
-
-static void bc_put_sleb128(BCWriterState *s, int32_t v)
-{
-    dbuf_put_sleb128(&s->dbuf, v);
-}
-
-static void bc_set_flags(uint32_t *pflags, int *pidx, uint32_t val, int n)
-{
-    *pflags = *pflags | (val << *pidx);
-    *pidx += n;
-}
-
-static int bc_atom_to_idx(BCWriterState *s, uint32_t *pres, JSAtom atom)
-{
-    uint32_t v;
-
-    if (atom < s->first_atom || __JS_AtomIsTaggedInt(atom)) {
-        *pres = atom;
-        return 0;
-    }
-    atom -= s->first_atom;
-    if (atom < s->atom_to_idx_size && s->atom_to_idx[atom] != 0) {
-        *pres = s->atom_to_idx[atom];
-        return 0;
-    }
-    if (atom >= s->atom_to_idx_size) {
-        int old_size, i;
-        old_size = s->atom_to_idx_size;
-        if (js_resize_array(s->ctx, (void **)&s->atom_to_idx,
-                            sizeof(s->atom_to_idx[0]), &s->atom_to_idx_size,
-                            atom + 1))
-            return -1;
-        /* XXX: could add a specific js_resize_array() function to do it */
-        for(i = old_size; i < s->atom_to_idx_size; i++)
-            s->atom_to_idx[i] = 0;
-    }
-    if (js_resize_array(s->ctx, (void **)&s->idx_to_atom,
-                        sizeof(s->idx_to_atom[0]),
-                        &s->idx_to_atom_size, s->idx_to_atom_count + 1))
-        goto fail;
-
-    v = s->idx_to_atom_count++;
-    s->idx_to_atom[v] = atom + s->first_atom;
-    v += s->first_atom;
-    s->atom_to_idx[atom] = v;
-    *pres = v;
-    return 0;
- fail:
-    *pres = 0;
-    return -1;
-}
-
-static int bc_put_atom(BCWriterState *s, JSAtom atom)
-{
-    uint32_t v;
-
-    if (__JS_AtomIsTaggedInt(atom)) {
-        v = (__JS_AtomToUInt32(atom) << 1) | 1;
-    } else {
-        if (bc_atom_to_idx(s, &v, atom))
-            return -1;
-        v <<= 1;
-    }
-    bc_put_leb128(s, v);
-    return 0;
-}
-
-static void bc_byte_swap(uint8_t *bc_buf, int bc_len)
-{
-    int pos, len, op, fmt;
-
-    pos = 0;
-    while (pos < bc_len) {
-        op = bc_buf[pos];
-        len = short_opcode_info(op).size;
-        fmt = short_opcode_info(op).fmt;
-        switch(fmt) {
-        case OP_FMT_u16:
-        case OP_FMT_i16:
-        case OP_FMT_label16:
-        case OP_FMT_npop:
-        case OP_FMT_loc:
-        case OP_FMT_arg:
-        case OP_FMT_var_ref:
-            put_u16(bc_buf + pos + 1,
-                    bswap16(get_u16(bc_buf + pos + 1)));
-            break;
-        case OP_FMT_i32:
-        case OP_FMT_u32:
-        case OP_FMT_const:
-        case OP_FMT_label:
-        case OP_FMT_atom:
-        case OP_FMT_atom_u8:
-            put_u32(bc_buf + pos + 1,
-                    bswap32(get_u32(bc_buf + pos + 1)));
-            break;
-        case OP_FMT_atom_u16:
-        case OP_FMT_label_u16:
-            put_u32(bc_buf + pos + 1,
-                    bswap32(get_u32(bc_buf + pos + 1)));
-            put_u16(bc_buf + pos + 1 + 4,
-                    bswap16(get_u16(bc_buf + pos + 1 + 4)));
-            break;
-        case OP_FMT_atom_label_u8:
-        case OP_FMT_atom_label_u16:
-            put_u32(bc_buf + pos + 1,
-                    bswap32(get_u32(bc_buf + pos + 1)));
-            put_u32(bc_buf + pos + 1 + 4,
-                    bswap32(get_u32(bc_buf + pos + 1 + 4)));
-            if (fmt == OP_FMT_atom_label_u16) {
-                put_u16(bc_buf + pos + 1 + 4 + 4,
-                        bswap16(get_u16(bc_buf + pos + 1 + 4 + 4)));
-            }
-            break;
-        case OP_FMT_npop_u16:
-            put_u16(bc_buf + pos + 1,
-                    bswap16(get_u16(bc_buf + pos + 1)));
-            put_u16(bc_buf + pos + 1 + 2,
-                    bswap16(get_u16(bc_buf + pos + 1 + 2)));
-            break;
-        default:
-            break;
-        }
-        pos += len;
-    }
-}
-
-static int JS_WriteFunctionBytecode(BCWriterState *s,
-                                    const uint8_t *bc_buf1, int bc_len)
-{
-    int pos, len, op;
-    JSAtom atom;
-    uint8_t *bc_buf;
-    uint32_t val;
-
-    bc_buf = js_malloc(s->ctx, bc_len);
-    if (!bc_buf)
-        return -1;
-    memcpy(bc_buf, bc_buf1, bc_len);
-
-    pos = 0;
-    while (pos < bc_len) {
-        op = bc_buf[pos];
-        len = short_opcode_info(op).size;
-        switch(short_opcode_info(op).fmt) {
-        case OP_FMT_atom:
-        case OP_FMT_atom_u8:
-        case OP_FMT_atom_u16:
-        case OP_FMT_atom_label_u8:
-        case OP_FMT_atom_label_u16:
-            atom = get_u32(bc_buf + pos + 1);
-            if (bc_atom_to_idx(s, &val, atom))
-                goto fail;
-            put_u32(bc_buf + pos + 1, val);
-            break;
-        default:
-            break;
-        }
-        pos += len;
-    }
-
-    if (s->byte_swap)
-        bc_byte_swap(bc_buf, bc_len);
-
-    dbuf_put(&s->dbuf, bc_buf, bc_len);
-
-    js_free(s->ctx, bc_buf);
-    return 0;
- fail:
-    js_free(s->ctx, bc_buf);
-    return -1;
-}
-
-static void JS_WriteString(BCWriterState *s, JSString *p)
-{
-    int i;
-    bc_put_leb128(s, ((uint32_t)p->len << 1) | p->is_wide_char);
-    if (p->is_wide_char) {
-        for(i = 0; i < p->len; i++)
-            bc_put_u16(s, p->u.str16[i]);
-    } else {
-        dbuf_put(&s->dbuf, p->u.str8, p->len);
-    }
-}
-
-#ifdef CONFIG_BIGNUM
-static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj)
-{
-    uint32_t tag, tag1;
-    int64_t e;
-    JSBigFloat *bf = JS_VALUE_GET_PTR(obj);
-    bf_t *a = &bf->num;
-    size_t len, i, n1, j;
-    limb_t v;
-
-    tag = JS_VALUE_GET_TAG(obj);
-    switch(tag) {
-    case JS_TAG_BIG_INT:
-        tag1 = BC_TAG_BIG_INT;
-        break;
-    case JS_TAG_BIG_FLOAT:
-        tag1 = BC_TAG_BIG_FLOAT;
-        break;
-    case JS_TAG_BIG_DECIMAL:
-        tag1 = BC_TAG_BIG_DECIMAL;
-        break;
-    default:
-        abort();
-    }
-    bc_put_u8(s, tag1);
-
-    /* sign + exponent */
-    if (a->expn == BF_EXP_ZERO)
-        e = 0;
-    else if (a->expn == BF_EXP_INF)
-        e = 1;
-    else if (a->expn == BF_EXP_NAN)
-        e = 2;
-    else if (a->expn >= 0)
-        e = a->expn + 3;
-    else
-        e = a->expn;
-    e = (e << 1) | a->sign;
-    if (e < INT32_MIN || e > INT32_MAX) {
-        JS_ThrowInternalError(s->ctx, "bignum exponent is too large");
-        return -1;
-    }
-    bc_put_sleb128(s, e);
-
-    /* mantissa */
-    if (a->len != 0) {
-        if (tag != JS_TAG_BIG_DECIMAL) {
-            i = 0;
-            while (i < a->len && a->tab[i] == 0)
-                i++;
-            assert(i < a->len);
-            v = a->tab[i];
-            n1 = sizeof(limb_t);
-            while ((v & 0xff) == 0) {
-                n1--;
-                v >>= 8;
-            }
-            i++;
-            len = (a->len - i) * sizeof(limb_t) + n1;
-            if (len > INT32_MAX) {
-                JS_ThrowInternalError(s->ctx, "bignum is too large");
-                return -1;
-            }
-            bc_put_leb128(s, len);
-            /* always saved in byte based little endian representation */
-            for(j = 0; j < n1; j++) {
-                dbuf_putc(&s->dbuf, v >> (j * 8));
-            }
-            for(; i < a->len; i++) {
-                limb_t v = a->tab[i];
-#if LIMB_BITS == 32
-#ifdef WORDS_BIGENDIAN
-                v = bswap32(v);
-#endif
-                dbuf_put_u32(&s->dbuf, v);
-#else
-#ifdef WORDS_BIGENDIAN
-                v = bswap64(v);
-#endif
-                dbuf_put_u64(&s->dbuf, v);
-#endif
-            }
-        } else {
-            int bpos, d;
-            uint8_t v8;
-            size_t i0;
-            
-            /* little endian BCD */
-            i = 0;
-            while (i < a->len && a->tab[i] == 0)
-                i++;
-            assert(i < a->len);
-            len = a->len * LIMB_DIGITS;
-            v = a->tab[i];
-            j = 0;
-            while ((v % 10) == 0) {
-                j++;
-                v /= 10;
-            }
-            len -= j;
-            assert(len > 0);
-            if (len > INT32_MAX) {
-                JS_ThrowInternalError(s->ctx, "bignum is too large");
-                return -1;
-            }
-            bc_put_leb128(s, len);
-            
-            bpos = 0;
-            v8 = 0;
-            i0 = i;
-            for(; i < a->len; i++) {
-                if (i != i0) {
-                    v = a->tab[i];
-                    j = 0;
-                }
-                for(; j < LIMB_DIGITS; j++) {
-                    d = v % 10;
-                    v /= 10;
-                    if (bpos == 0) {
-                        v8 = d;
-                        bpos = 1;
-                    } else {
-                        dbuf_putc(&s->dbuf, v8 | (d << 4));
-                        bpos = 0;
-                    }
-                }
-            }
-            /* flush the last digit */
-            if (bpos) {
-                dbuf_putc(&s->dbuf, v8);
-            }
-        }
-    }
-    return 0;
-}
-#endif /* CONFIG_BIGNUM */
-
-static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj);
-
-static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj)
-{
-    JSFunctionBytecode *b = JS_VALUE_GET_PTR(obj);
-    uint32_t flags;
-    int idx, i;
-    
-    bc_put_u8(s, BC_TAG_FUNCTION_BYTECODE);
-    flags = idx = 0;
-    bc_set_flags(&flags, &idx, b->has_prototype, 1);
-    bc_set_flags(&flags, &idx, b->has_simple_parameter_list, 1);
-    bc_set_flags(&flags, &idx, b->is_derived_class_constructor, 1);
-    bc_set_flags(&flags, &idx, b->need_home_object, 1);
-    bc_set_flags(&flags, &idx, b->func_kind, 2);
-    bc_set_flags(&flags, &idx, b->new_target_allowed, 1);
-    bc_set_flags(&flags, &idx, b->super_call_allowed, 1);
-    bc_set_flags(&flags, &idx, b->super_allowed, 1);
-    bc_set_flags(&flags, &idx, b->arguments_allowed, 1);
-    bc_set_flags(&flags, &idx, b->has_debug, 1);
-    bc_set_flags(&flags, &idx, b->backtrace_barrier, 1);
-    assert(idx <= 16);
-    bc_put_u16(s, flags);
-    bc_put_u8(s, b->js_mode);
-    bc_put_atom(s, b->func_name);
-    
-    bc_put_leb128(s, b->arg_count);
-    bc_put_leb128(s, b->var_count);
-    bc_put_leb128(s, b->defined_arg_count);
-    bc_put_leb128(s, b->stack_size);
-    bc_put_leb128(s, b->closure_var_count);
-    bc_put_leb128(s, b->cpool_count);
-    bc_put_leb128(s, b->byte_code_len);
-    if (b->vardefs) {
-        /* XXX: this field is redundant */
-        bc_put_leb128(s, b->arg_count + b->var_count);
-        for(i = 0; i < b->arg_count + b->var_count; i++) {
-            JSVarDef *vd = &b->vardefs[i];
-            bc_put_atom(s, vd->var_name);
-            bc_put_leb128(s, vd->scope_level);
-            bc_put_leb128(s, vd->scope_next + 1);
-            flags = idx = 0;
-            bc_set_flags(&flags, &idx, vd->var_kind, 4);
-            bc_set_flags(&flags, &idx, vd->is_const, 1);
-            bc_set_flags(&flags, &idx, vd->is_lexical, 1);
-            bc_set_flags(&flags, &idx, vd->is_captured, 1);
-            assert(idx <= 8);
-            bc_put_u8(s, flags);
-        }
-    } else {
-        bc_put_leb128(s, 0);
-    }
-    
-    for(i = 0; i < b->closure_var_count; i++) {
-        JSClosureVar *cv = &b->closure_var[i];
-        bc_put_atom(s, cv->var_name);
-        bc_put_leb128(s, cv->var_idx);
-        flags = idx = 0;
-        bc_set_flags(&flags, &idx, cv->is_local, 1);
-        bc_set_flags(&flags, &idx, cv->is_arg, 1);
-        bc_set_flags(&flags, &idx, cv->is_const, 1);
-        bc_set_flags(&flags, &idx, cv->is_lexical, 1);
-        bc_set_flags(&flags, &idx, cv->var_kind, 4);
-        assert(idx <= 8);
-        bc_put_u8(s, flags);
-    }
-    
-    if (JS_WriteFunctionBytecode(s, b->byte_code_buf, b->byte_code_len))
-        goto fail;
-    
-    if (b->has_debug) {
-        bc_put_atom(s, b->debug.filename);
-        bc_put_leb128(s, b->debug.line_num);
-        bc_put_leb128(s, b->debug.pc2line_len);
-        dbuf_put(&s->dbuf, b->debug.pc2line_buf, b->debug.pc2line_len);
-    }
-    
-    for(i = 0; i < b->cpool_count; i++) {
-        if (JS_WriteObjectRec(s, b->cpool[i]))
-            goto fail;
-    }
-    return 0;
- fail:
-    return -1;
-}
-
-static int JS_WriteModule(BCWriterState *s, JSValueConst obj)
-{
-    JSModuleDef *m = JS_VALUE_GET_PTR(obj);
-    int i;
-    
-    bc_put_u8(s, BC_TAG_MODULE);
-    bc_put_atom(s, m->module_name);
-    
-    bc_put_leb128(s, m->req_module_entries_count);
-    for(i = 0; i < m->req_module_entries_count; i++) {
-        JSReqModuleEntry *rme = &m->req_module_entries[i];
-        bc_put_atom(s, rme->module_name);
-    }
-    
-    bc_put_leb128(s, m->export_entries_count);
-    for(i = 0; i < m->export_entries_count; i++) {
-        JSExportEntry *me = &m->export_entries[i];
-        bc_put_u8(s, me->export_type);
-        if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
-            bc_put_leb128(s, me->u.local.var_idx);
-        } else {
-            bc_put_leb128(s, me->u.req_module_idx);
-            bc_put_atom(s, me->local_name);
-        }
-        bc_put_atom(s, me->export_name);
-    }
-    
-    bc_put_leb128(s, m->star_export_entries_count);
-    for(i = 0; i < m->star_export_entries_count; i++) {
-        JSStarExportEntry *se = &m->star_export_entries[i];
-        bc_put_leb128(s, se->req_module_idx);
-    }
-    
-    bc_put_leb128(s, m->import_entries_count);
-    for(i = 0; i < m->import_entries_count; i++) {
-        JSImportEntry *mi = &m->import_entries[i];
-        bc_put_leb128(s, mi->var_idx);
-        bc_put_atom(s, mi->import_name);
-        bc_put_leb128(s, mi->req_module_idx);
-    }
-    
-    if (JS_WriteObjectRec(s, m->func_obj))
-        goto fail;
-    return 0;
- fail:
-    return -1;
-}
-
-static int JS_WriteArray(BCWriterState *s, JSValueConst obj)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(obj);
-    uint32_t i, len;
-    JSValue val;
-    int ret;
-    BOOL is_template;
-    
-    if (s->allow_bytecode && !p->extensible) {
-        /* not extensible array: we consider it is a
-           template when we are saving bytecode */
-        bc_put_u8(s, BC_TAG_TEMPLATE_OBJECT);
-        is_template = TRUE;
-    } else {
-        bc_put_u8(s, BC_TAG_ARRAY);
-        is_template = FALSE;
-    }
-    if (js_get_length32(s->ctx, &len, obj))
-        goto fail1;
-    bc_put_leb128(s, len);
-    for(i = 0; i < len; i++) {
-        val = JS_GetPropertyUint32(s->ctx, obj, i);
-        if (JS_IsException(val))
-            goto fail1;
-        ret = JS_WriteObjectRec(s, val);
-        JS_FreeValue(s->ctx, val);
-        if (ret)
-            goto fail1;
-    }
-    if (is_template) {
-        val = JS_GetProperty(s->ctx, obj, JS_ATOM_raw);
-        if (JS_IsException(val))
-            goto fail1;
-        ret = JS_WriteObjectRec(s, val);
-        JS_FreeValue(s->ctx, val);
-        if (ret)
-            goto fail1;
-    }
-    return 0;
- fail1:
-    return -1;
-}
-
-static int JS_WriteObjectTag(BCWriterState *s, JSValueConst obj)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(obj);
-    uint32_t i, prop_count;
-    JSShape *sh;
-    JSShapeProperty *pr;
-    int pass;
-    JSAtom atom;
-
-    bc_put_u8(s, BC_TAG_OBJECT);
-    prop_count = 0;
-    sh = p->shape;
-    for(pass = 0; pass < 2; pass++) {
-        if (pass == 1)
-            bc_put_leb128(s, prop_count);
-        for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {
-            atom = pr->atom;
-            if (atom != JS_ATOM_NULL &&
-                JS_AtomIsString(s->ctx, atom) &&
-                (pr->flags & JS_PROP_ENUMERABLE)) {
-                if (pr->flags & JS_PROP_TMASK) {
-                    JS_ThrowTypeError(s->ctx, "only value properties are supported");
-                    goto fail;
-                }
-                if (pass == 0) {
-                    prop_count++;
-                } else {
-                    bc_put_atom(s, atom);
-                    if (JS_WriteObjectRec(s, p->prop[i].u.value))
-                        goto fail;
-                }
-            }
-        }
-    }
-    return 0;
- fail:
-    return -1;
-}
-
-static int JS_WriteTypedArray(BCWriterState *s, JSValueConst obj)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(obj);
-    JSTypedArray *ta = p->u.typed_array;
-
-    bc_put_u8(s, BC_TAG_TYPED_ARRAY);
-    bc_put_u8(s, p->class_id - JS_CLASS_UINT8C_ARRAY);
-    bc_put_leb128(s, p->u.array.count);
-    bc_put_leb128(s, ta->offset);
-    if (JS_WriteObjectRec(s, JS_MKPTR(JS_TAG_OBJECT, ta->buffer)))
-        return -1;
-    return 0;
-}
-
-static int JS_WriteArrayBuffer(BCWriterState *s, JSValueConst obj)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(obj);
-    JSArrayBuffer *abuf = p->u.array_buffer;
-    if (abuf->detached) {
-        JS_ThrowTypeErrorDetachedArrayBuffer(s->ctx);
-        return -1;
-    }
-    bc_put_u8(s, BC_TAG_ARRAY_BUFFER);
-    bc_put_leb128(s, abuf->byte_length);
-    dbuf_put(&s->dbuf, abuf->data, abuf->byte_length);
-    return 0;
-}
-
-static int JS_WriteSharedArrayBuffer(BCWriterState *s, JSValueConst obj)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(obj);
-    JSArrayBuffer *abuf = p->u.array_buffer;
-    assert(!abuf->detached); /* SharedArrayBuffer are never detached */
-    bc_put_u8(s, BC_TAG_SHARED_ARRAY_BUFFER);
-    bc_put_leb128(s, abuf->byte_length);
-    bc_put_u64(s, (uintptr_t)abuf->data);
-    if (js_resize_array(s->ctx, (void **)&s->sab_tab, sizeof(s->sab_tab[0]),
-                        &s->sab_tab_size, s->sab_tab_len + 1))
-        return -1;
-    /* keep the SAB pointer so that the user can clone it or free it */
-    s->sab_tab[s->sab_tab_len++] = abuf->data;
-    return 0;
-}
-
-static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj)
-{
-    uint32_t tag;
-
-    if (js_check_stack_overflow(s->ctx->rt, 0)) {
-        JS_ThrowStackOverflow(s->ctx);
-        return -1;
-    }
-
-    tag = JS_VALUE_GET_NORM_TAG(obj);
-    switch(tag) {
-    case JS_TAG_NULL:
-        bc_put_u8(s, BC_TAG_NULL);
-        break;
-    case JS_TAG_UNDEFINED:
-        bc_put_u8(s, BC_TAG_UNDEFINED);
-        break;
-    case JS_TAG_BOOL:
-        bc_put_u8(s, BC_TAG_BOOL_FALSE + JS_VALUE_GET_INT(obj));
-        break;
-    case JS_TAG_INT:
-        bc_put_u8(s, BC_TAG_INT32);
-        bc_put_sleb128(s, JS_VALUE_GET_INT(obj));
-        break;
-    case JS_TAG_FLOAT64:
-        {
-            JSFloat64Union u;
-            bc_put_u8(s, BC_TAG_FLOAT64);
-            u.d = JS_VALUE_GET_FLOAT64(obj);
-            bc_put_u64(s, u.u64);
-        }
-        break;
-    case JS_TAG_STRING:
-        {
-            JSString *p = JS_VALUE_GET_STRING(obj);
-            bc_put_u8(s, BC_TAG_STRING);
-            JS_WriteString(s, p);
-        }
-        break;
-    case JS_TAG_FUNCTION_BYTECODE:
-        if (!s->allow_bytecode)
-            goto invalid_tag;
-        if (JS_WriteFunctionTag(s, obj))
-            goto fail;
-        break;
-    case JS_TAG_MODULE:
-        if (!s->allow_bytecode)
-            goto invalid_tag;
-        if (JS_WriteModule(s, obj))
-            goto fail;
-        break;
-    case JS_TAG_OBJECT:
-        {
-            JSObject *p = JS_VALUE_GET_OBJ(obj);
-            int ret, idx;
-            
-            if (s->allow_reference) {
-                idx = js_object_list_find(s->ctx, &s->object_list, p);
-                if (idx >= 0) {
-                    bc_put_u8(s, BC_TAG_OBJECT_REFERENCE);
-                    bc_put_leb128(s, idx);
-                    break;
-                } else {
-                    if (js_object_list_add(s->ctx, &s->object_list, p))
-                        goto fail;
-                }
-            } else {
-                if (p->tmp_mark) {
-                    JS_ThrowTypeError(s->ctx, "circular reference");
-                    goto fail;
-                }
-                p->tmp_mark = 1;
-            }
-            switch(p->class_id) {
-            case JS_CLASS_ARRAY:
-                ret = JS_WriteArray(s, obj);
-                break;
-            case JS_CLASS_OBJECT:
-                ret = JS_WriteObjectTag(s, obj);
-                break;
-            case JS_CLASS_ARRAY_BUFFER:
-                ret = JS_WriteArrayBuffer(s, obj);
-                break;
-            case JS_CLASS_SHARED_ARRAY_BUFFER:
-                if (!s->allow_sab)
-                    goto invalid_tag;
-                ret = JS_WriteSharedArrayBuffer(s, obj);
-                break;
-            case JS_CLASS_DATE:
-                bc_put_u8(s, BC_TAG_DATE);
-                ret = JS_WriteObjectRec(s, p->u.object_data);
-                break;
-            case JS_CLASS_NUMBER:
-            case JS_CLASS_STRING:
-            case JS_CLASS_BOOLEAN:
-#ifdef CONFIG_BIGNUM
-            case JS_CLASS_BIG_INT:
-            case JS_CLASS_BIG_FLOAT:
-            case JS_CLASS_BIG_DECIMAL:
-#endif
-                bc_put_u8(s, BC_TAG_OBJECT_VALUE);
-                ret = JS_WriteObjectRec(s, p->u.object_data);
-                break;
-            default:
-                if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
-                    p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
-                    ret = JS_WriteTypedArray(s, obj);
-                } else {
-                    JS_ThrowTypeError(s->ctx, "unsupported object class");
-                    ret = -1;
-                }
-                break;
-            }
-            p->tmp_mark = 0;
-            if (ret)
-                goto fail;
-        }
-        break;
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_INT:
-    case JS_TAG_BIG_FLOAT:
-    case JS_TAG_BIG_DECIMAL:
-        if (JS_WriteBigNum(s, obj))
-            goto fail;
-        break;
-#endif
-    default:
-    invalid_tag:
-        JS_ThrowInternalError(s->ctx, "unsupported tag (%d)", tag);
-        goto fail;
-    }
-    return 0;
-
- fail:
-    return -1;
-}
-
-/* create the atom table */
-static int JS_WriteObjectAtoms(BCWriterState *s)
-{
-    JSRuntime *rt = s->ctx->rt;
-    DynBuf dbuf1;
-    int i, atoms_size;
-    uint8_t version;
-
-    dbuf1 = s->dbuf;
-    js_dbuf_init(s->ctx, &s->dbuf);
-
-    version = BC_VERSION;
-    if (s->byte_swap)
-        version ^= BC_BE_VERSION;
-    bc_put_u8(s, version);
-
-    bc_put_leb128(s, s->idx_to_atom_count);
-    for(i = 0; i < s->idx_to_atom_count; i++) {
-        JSAtomStruct *p = rt->atom_array[s->idx_to_atom[i]];
-        JS_WriteString(s, p);
-    }
-    /* XXX: should check for OOM in above phase */
-
-    /* move the atoms at the start */
-    /* XXX: could just append dbuf1 data, but it uses more memory if
-       dbuf1 is larger than dbuf */
-    atoms_size = s->dbuf.size;
-    if (dbuf_realloc(&dbuf1, dbuf1.size + atoms_size))
-        goto fail;
-    memmove(dbuf1.buf + atoms_size, dbuf1.buf, dbuf1.size);
-    memcpy(dbuf1.buf, s->dbuf.buf, atoms_size);
-    dbuf1.size += atoms_size;
-    dbuf_free(&s->dbuf);
-    s->dbuf = dbuf1;
-    return 0;
- fail:
-    dbuf_free(&dbuf1);
-    return -1;
-}
-
-uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj,
-                         int flags, uint8_t ***psab_tab, size_t *psab_tab_len)
-{
-    BCWriterState ss, *s = &ss;
-
-    memset(s, 0, sizeof(*s));
-    s->ctx = ctx;
-    /* XXX: byte swapped output is untested */
-    s->byte_swap = ((flags & JS_WRITE_OBJ_BSWAP) != 0);
-    s->allow_bytecode = ((flags & JS_WRITE_OBJ_BYTECODE) != 0);
-    s->allow_sab = ((flags & JS_WRITE_OBJ_SAB) != 0);
-    s->allow_reference = ((flags & JS_WRITE_OBJ_REFERENCE) != 0);
-    /* XXX: could use a different version when bytecode is included */
-    if (s->allow_bytecode)
-        s->first_atom = JS_ATOM_END;
-    else
-        s->first_atom = 1;
-    js_dbuf_init(ctx, &s->dbuf);
-    js_object_list_init(&s->object_list);
-    
-    if (JS_WriteObjectRec(s, obj))
-        goto fail;
-    if (JS_WriteObjectAtoms(s))
-        goto fail;
-    js_object_list_end(ctx, &s->object_list);
-    js_free(ctx, s->atom_to_idx);
-    js_free(ctx, s->idx_to_atom);
-    *psize = s->dbuf.size;
-    if (psab_tab)
-        *psab_tab = s->sab_tab;
-    if (psab_tab_len)
-        *psab_tab_len = s->sab_tab_len;
-    return s->dbuf.buf;
- fail:
-    js_object_list_end(ctx, &s->object_list);
-    js_free(ctx, s->atom_to_idx);
-    js_free(ctx, s->idx_to_atom);
-    dbuf_free(&s->dbuf);
-    *psize = 0;
-    if (psab_tab)
-        *psab_tab = NULL;
-    if (psab_tab_len)
-        *psab_tab_len = 0;
-    return NULL;
-}
-
-uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj,
-                        int flags)
-{
-    return JS_WriteObject2(ctx, psize, obj, flags, NULL, NULL);
-}
-
-typedef struct BCReaderState {
-    JSContext *ctx;
-    const uint8_t *buf_start, *ptr, *buf_end;
-    uint32_t first_atom;
-    uint32_t idx_to_atom_count;
-    JSAtom *idx_to_atom;
-    int error_state;
-    BOOL allow_sab : 8;
-    BOOL allow_bytecode : 8;
-    BOOL is_rom_data : 8;
-    BOOL allow_reference : 8;
-    /* object references */
-    JSObject **objects;
-    int objects_count;
-    int objects_size;
-    
-#ifdef DUMP_READ_OBJECT
-    const uint8_t *ptr_last;
-    int level;
-#endif
-} BCReaderState;
-
-#ifdef DUMP_READ_OBJECT
-static void __attribute__((format(printf, 2, 3))) bc_read_trace(BCReaderState *s, const char *fmt, ...) {
-    va_list ap;
-    int i, n, n0;
-
-    if (!s->ptr_last)
-        s->ptr_last = s->buf_start;
-
-    n = n0 = 0;
-    if (s->ptr > s->ptr_last || s->ptr == s->buf_start) {
-        n0 = printf("%04x: ", (int)(s->ptr_last - s->buf_start));
-        n += n0;
-    }
-    for (i = 0; s->ptr_last < s->ptr; i++) {
-        if ((i & 7) == 0 && i > 0) {
-            printf("\n%*s", n0, "");
-            n = n0;
-        }
-        n += printf(" %02x", *s->ptr_last++);
-    }
-    if (*fmt == '}')
-        s->level--;
-    if (n < 32 + s->level * 2) {
-        printf("%*s", 32 + s->level * 2 - n, "");
-    }
-    va_start(ap, fmt);
-    vfprintf(stdout, fmt, ap);
-    va_end(ap);
-    if (strchr(fmt, '{'))
-        s->level++;
-}
-#else
-#define bc_read_trace(...)
-#endif
-
-static int bc_read_error_end(BCReaderState *s)
-{
-    if (!s->error_state) {
-        JS_ThrowSyntaxError(s->ctx, "read after the end of the buffer");
-    }
-    return s->error_state = -1;
-}
-
-static int bc_get_u8(BCReaderState *s, uint8_t *pval)
-{
-    if (unlikely(s->buf_end - s->ptr < 1)) {
-        *pval = 0; /* avoid warning */
-        return bc_read_error_end(s);
-    }
-    *pval = *s->ptr++;
-    return 0;
-}
-
-static int bc_get_u16(BCReaderState *s, uint16_t *pval)
-{
-    if (unlikely(s->buf_end - s->ptr < 2)) {
-        *pval = 0; /* avoid warning */
-        return bc_read_error_end(s);
-    }
-    *pval = get_u16(s->ptr);
-    s->ptr += 2;
-    return 0;
-}
-
-static __maybe_unused int bc_get_u32(BCReaderState *s, uint32_t *pval)
-{
-    if (unlikely(s->buf_end - s->ptr < 4)) {
-        *pval = 0; /* avoid warning */
-        return bc_read_error_end(s);
-    }
-    *pval = get_u32(s->ptr);
-    s->ptr += 4;
-    return 0;
-}
-
-static int bc_get_u64(BCReaderState *s, uint64_t *pval)
-{
-    if (unlikely(s->buf_end - s->ptr < 8)) {
-        *pval = 0; /* avoid warning */
-        return bc_read_error_end(s);
-    }
-    *pval = get_u64(s->ptr);
-    s->ptr += 8;
-    return 0;
-}
-
-static int bc_get_leb128(BCReaderState *s, uint32_t *pval)
-{
-    int ret;
-    ret = get_leb128(pval, s->ptr, s->buf_end);
-    if (unlikely(ret < 0))
-        return bc_read_error_end(s);
-    s->ptr += ret;
-    return 0;
-}
-
-static int bc_get_sleb128(BCReaderState *s, int32_t *pval)
-{
-    int ret;
-    ret = get_sleb128(pval, s->ptr, s->buf_end);
-    if (unlikely(ret < 0))
-        return bc_read_error_end(s);
-    s->ptr += ret;
-    return 0;
-}
-
-/* XXX: used to read an `int` with a positive value */
-static int bc_get_leb128_int(BCReaderState *s, int *pval)
-{
-    return bc_get_leb128(s, (uint32_t *)pval);
-}
-
-static int bc_get_leb128_u16(BCReaderState *s, uint16_t *pval)
-{
-    uint32_t val;
-    if (bc_get_leb128(s, &val)) {
-        *pval = 0;
-        return -1;
-    }
-    *pval = val;
-    return 0;
-}
-
-static int bc_get_buf(BCReaderState *s, uint8_t *buf, uint32_t buf_len)
-{
-    if (buf_len != 0) {
-        if (unlikely(!buf || s->buf_end - s->ptr < buf_len))
-            return bc_read_error_end(s);
-        memcpy(buf, s->ptr, buf_len);
-        s->ptr += buf_len;
-    }
-    return 0;
-}
-
-static int bc_idx_to_atom(BCReaderState *s, JSAtom *patom, uint32_t idx)
-{
-    JSAtom atom;
-
-    if (__JS_AtomIsTaggedInt(idx)) {
-        atom = idx;
-    } else if (idx < s->first_atom) {
-        atom = JS_DupAtom(s->ctx, idx);
-    } else {
-        idx -= s->first_atom;
-        if (idx >= s->idx_to_atom_count) {
-            JS_ThrowSyntaxError(s->ctx, "invalid atom index (pos=%u)",
-                                (unsigned int)(s->ptr - s->buf_start));
-            *patom = JS_ATOM_NULL;
-            return s->error_state = -1;
-        }
-        atom = JS_DupAtom(s->ctx, s->idx_to_atom[idx]);
-    }
-    *patom = atom;
-    return 0;
-}
-
-static int bc_get_atom(BCReaderState *s, JSAtom *patom)
-{
-    uint32_t v;
-    if (bc_get_leb128(s, &v))
-        return -1;
-    if (v & 1) {
-        *patom = __JS_AtomFromUInt32(v >> 1);
-        return 0;
-    } else {
-        return bc_idx_to_atom(s, patom, v >> 1);
-    }
-}
-
-static JSString *JS_ReadString(BCReaderState *s)
-{
-    uint32_t len;
-    size_t size;
-    BOOL is_wide_char;
-    JSString *p;
-
-    if (bc_get_leb128(s, &len))
-        return NULL;
-    is_wide_char = len & 1;
-    len >>= 1;
-    p = js_alloc_string(s->ctx, len, is_wide_char);
-    if (!p) {
-        s->error_state = -1;
-        return NULL;
-    }
-    size = (size_t)len << is_wide_char;
-    if ((s->buf_end - s->ptr) < size) {
-        bc_read_error_end(s);
-        js_free_string(s->ctx->rt, p);
-        return NULL;
-    }
-    memcpy(p->u.str8, s->ptr, size);
-    s->ptr += size;
-    if (!is_wide_char) {
-        p->u.str8[size] = '\0'; /* add the trailing zero for 8 bit strings */
-    }
-#ifdef DUMP_READ_OBJECT
-    JS_DumpString(s->ctx->rt, p); printf("\n");
-#endif
-    return p;
-}
-
-static uint32_t bc_get_flags(uint32_t flags, int *pidx, int n)
-{
-    uint32_t val;
-    /* XXX: this does not work for n == 32 */
-    val = (flags >> *pidx) & ((1U << n) - 1);
-    *pidx += n;
-    return val;
-}
-
-static int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b,
-                                   int byte_code_offset, uint32_t bc_len)
-{
-    uint8_t *bc_buf;
-    int pos, len, op;
-    JSAtom atom;
-    uint32_t idx;
-
-    if (s->is_rom_data) {
-        /* directly use the input buffer */
-        if (unlikely(s->buf_end - s->ptr < bc_len))
-            return bc_read_error_end(s);
-        bc_buf = (uint8_t *)s->ptr;
-        s->ptr += bc_len;
-    } else {
-        bc_buf = (void *)((uint8_t*)b + byte_code_offset);
-        if (bc_get_buf(s, bc_buf, bc_len))
-            return -1;
-    }
-    b->byte_code_buf = bc_buf;
-
-    pos = 0;
-    while (pos < bc_len) {
-        op = bc_buf[pos];
-        len = short_opcode_info(op).size;
-        switch(short_opcode_info(op).fmt) {
-        case OP_FMT_atom:
-        case OP_FMT_atom_u8:
-        case OP_FMT_atom_u16:
-        case OP_FMT_atom_label_u8:
-        case OP_FMT_atom_label_u16:
-            idx = get_u32(bc_buf + pos + 1);
-            if (s->is_rom_data) {
-                /* just increment the reference count of the atom */
-                JS_DupAtom(s->ctx, (JSAtom)idx);
-            } else {
-                if (bc_idx_to_atom(s, &atom, idx)) {
-                    /* Note: the atoms will be freed up to this position */
-                    b->byte_code_len = pos;
-                    return -1;
-                }
-                put_u32(bc_buf + pos + 1, atom);
-#ifdef DUMP_READ_OBJECT
-                bc_read_trace(s, "at %d, fixup atom: ", pos + 1); print_atom(s->ctx, atom); printf("\n");
-#endif
-            }
-            break;
-        default:
-            break;
-        }
-        pos += len;
-    }
-    return 0;
-}
-
-#ifdef CONFIG_BIGNUM
-static JSValue JS_ReadBigNum(BCReaderState *s, int tag)
-{
-    JSValue obj = JS_UNDEFINED;
-    uint8_t v8;
-    int32_t e;
-    uint32_t len;
-    limb_t l, i, n, j;
-    JSBigFloat *p;
-    limb_t v;
-    bf_t *a;
-    int bpos, d;
-    
-    p = js_new_bf(s->ctx);
-    if (!p)
-        goto fail;
-    switch(tag) {
-    case BC_TAG_BIG_INT:
-        obj = JS_MKPTR(JS_TAG_BIG_INT, p);
-        break;
-    case BC_TAG_BIG_FLOAT:
-        obj = JS_MKPTR(JS_TAG_BIG_FLOAT, p);
-        break;
-    case BC_TAG_BIG_DECIMAL:
-        obj = JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
-        break;
-    default:
-        abort();
-    }
-
-    /* sign + exponent */
-    if (bc_get_sleb128(s, &e))
-        goto fail;
-
-    a = &p->num;
-    a->sign = e & 1;
-    e >>= 1;
-    if (e == 0)
-        a->expn = BF_EXP_ZERO;
-    else if (e == 1)
-        a->expn = BF_EXP_INF;
-    else if (e == 2)
-        a->expn = BF_EXP_NAN;
-    else if (e >= 3)
-        a->expn = e - 3;
-    else
-        a->expn = e;
-
-    /* mantissa */
-    if (a->expn != BF_EXP_ZERO &&
-        a->expn != BF_EXP_INF &&
-        a->expn != BF_EXP_NAN) {
-        if (bc_get_leb128(s, &len))
-            goto fail;
-        bc_read_trace(s, "len=%" PRId64 "\n", (int64_t)len);
-        if (len == 0) {
-            JS_ThrowInternalError(s->ctx, "invalid bignum length");
-            goto fail;
-        }
-        if (tag != BC_TAG_BIG_DECIMAL)
-            l = (len + sizeof(limb_t) - 1) / sizeof(limb_t);
-        else
-            l = (len + LIMB_DIGITS - 1) / LIMB_DIGITS;
-        if (bf_resize(a, l)) {
-            JS_ThrowOutOfMemory(s->ctx);
-            goto fail;
-        }
-        if (tag != BC_TAG_BIG_DECIMAL) {
-            n = len & (sizeof(limb_t) - 1);
-            if (n != 0) {
-                v = 0;
-                for(i = 0; i < n; i++) {
-                    if (bc_get_u8(s, &v8))
-                        goto fail;
-                    v |= (limb_t)v8 << ((sizeof(limb_t) - n + i) * 8);
-                }
-                a->tab[0] = v;
-                i = 1;
-            } else {
-                i = 0;
-            }
-            for(; i < l; i++) {
-#if LIMB_BITS == 32
-                if (bc_get_u32(s, &v))
-                    goto fail;
-#ifdef WORDS_BIGENDIAN
-                v = bswap32(v);
-#endif
-#else
-                if (bc_get_u64(s, &v))
-                    goto fail;
-#ifdef WORDS_BIGENDIAN
-                v = bswap64(v);
-#endif
-#endif
-                a->tab[i] = v;
-            }
-        } else {
-            bpos = 0;
-            for(i = 0; i < l; i++) {
-                if (i == 0 && (n = len % LIMB_DIGITS) != 0) {
-                    j = LIMB_DIGITS - n;
-                } else {
-                    j = 0;
-                }
-                v = 0;
-                for(; j < LIMB_DIGITS; j++) {
-                    if (bpos == 0) {
-                        if (bc_get_u8(s, &v8))
-                            goto fail;
-                        d = v8 & 0xf;
-                        bpos = 1;
-                    } else {
-                        d = v8 >> 4;
-                        bpos = 0;
-                    }
-                    if (d >= 10) {
-                        JS_ThrowInternalError(s->ctx, "invalid digit");
-                        goto fail;
-                    }
-                    v += mp_pow_dec[j] * d;
-                }
-                a->tab[i] = v;
-            }
-        }
-    }
-    bc_read_trace(s, "}\n");
-    return obj;
- fail:
-    JS_FreeValue(s->ctx, obj);
-    return JS_EXCEPTION;
-}
-#endif /* CONFIG_BIGNUM */
-
-static JSValue JS_ReadObjectRec(BCReaderState *s);
-
-static int BC_add_object_ref1(BCReaderState *s, JSObject *p)
-{
-    if (s->allow_reference) {
-        if (js_resize_array(s->ctx, (void *)&s->objects,
-                            sizeof(s->objects[0]),
-                            &s->objects_size, s->objects_count + 1))
-            return -1;
-        s->objects[s->objects_count++] = p;
-    }
-    return 0;
-}
-
-static int BC_add_object_ref(BCReaderState *s, JSValueConst obj)
-{
-    return BC_add_object_ref1(s, JS_VALUE_GET_OBJ(obj));
-}
-
-static JSValue JS_ReadFunctionTag(BCReaderState *s)
-{
-    JSContext *ctx = s->ctx;
-    JSFunctionBytecode bc, *b;
-    JSValue obj = JS_UNDEFINED;
-    uint16_t v16;
-    uint8_t v8;
-    int idx, i, local_count;
-    int function_size, cpool_offset, byte_code_offset;
-    int closure_var_offset, vardefs_offset;
-
-    memset(&bc, 0, sizeof(bc));
-    bc.header.ref_count = 1;
-    //bc.gc_header.mark = 0;
-
-    if (bc_get_u16(s, &v16))
-        goto fail;
-    idx = 0;
-    bc.has_prototype = bc_get_flags(v16, &idx, 1);
-    bc.has_simple_parameter_list = bc_get_flags(v16, &idx, 1);
-    bc.is_derived_class_constructor = bc_get_flags(v16, &idx, 1);
-    bc.need_home_object = bc_get_flags(v16, &idx, 1);
-    bc.func_kind = bc_get_flags(v16, &idx, 2);
-    bc.new_target_allowed = bc_get_flags(v16, &idx, 1);
-    bc.super_call_allowed = bc_get_flags(v16, &idx, 1);
-    bc.super_allowed = bc_get_flags(v16, &idx, 1);
-    bc.arguments_allowed = bc_get_flags(v16, &idx, 1);
-    bc.has_debug = bc_get_flags(v16, &idx, 1);
-    bc.backtrace_barrier = bc_get_flags(v16, &idx, 1);
-    bc.read_only_bytecode = s->is_rom_data;
-    if (bc_get_u8(s, &v8))
-        goto fail;
-    bc.js_mode = v8;
-    if (bc_get_atom(s, &bc.func_name))  //@ atom leak if failure
-        goto fail;
-    if (bc_get_leb128_u16(s, &bc.arg_count))
-        goto fail;
-    if (bc_get_leb128_u16(s, &bc.var_count))
-        goto fail;
-    if (bc_get_leb128_u16(s, &bc.defined_arg_count))
-        goto fail;
-    if (bc_get_leb128_u16(s, &bc.stack_size))
-        goto fail;
-    if (bc_get_leb128_int(s, &bc.closure_var_count))
-        goto fail;
-    if (bc_get_leb128_int(s, &bc.cpool_count))
-        goto fail;
-    if (bc_get_leb128_int(s, &bc.byte_code_len))
-        goto fail;
-    if (bc_get_leb128_int(s, &local_count))
-        goto fail;
-
-    if (bc.has_debug) {
-        function_size = sizeof(*b);
-    } else {
-        function_size = offsetof(JSFunctionBytecode, debug);
-    }
-    cpool_offset = function_size;
-    function_size += bc.cpool_count * sizeof(*bc.cpool);
-    vardefs_offset = function_size;
-    function_size += local_count * sizeof(*bc.vardefs);
-    closure_var_offset = function_size;
-    function_size += bc.closure_var_count * sizeof(*bc.closure_var);
-    byte_code_offset = function_size;
-    if (!bc.read_only_bytecode) {
-        function_size += bc.byte_code_len;
-    }
-
-    b = js_mallocz(ctx, function_size);
-    if (!b)
-        return JS_EXCEPTION;
-            
-    memcpy(b, &bc, offsetof(JSFunctionBytecode, debug));
-    b->header.ref_count = 1;
-    if (local_count != 0) {
-        b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
-    }
-    if (b->closure_var_count != 0) {
-        b->closure_var = (void *)((uint8_t*)b + closure_var_offset);
-    }
-    if (b->cpool_count != 0) {
-        b->cpool = (void *)((uint8_t*)b + cpool_offset);
-    }
-    
-    add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
-            
-    obj = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);
-
-#ifdef DUMP_READ_OBJECT
-    bc_read_trace(s, "name: "); print_atom(s->ctx, b->func_name); printf("\n");
-#endif
-    bc_read_trace(s, "args=%d vars=%d defargs=%d closures=%d cpool=%d\n",
-                  b->arg_count, b->var_count, b->defined_arg_count,
-                  b->closure_var_count, b->cpool_count);
-    bc_read_trace(s, "stack=%d bclen=%d locals=%d\n",
-                  b->stack_size, b->byte_code_len, local_count);
-
-    if (local_count != 0) {
-        bc_read_trace(s, "vars {\n");
-        for(i = 0; i < local_count; i++) {
-            JSVarDef *vd = &b->vardefs[i];
-            if (bc_get_atom(s, &vd->var_name))
-                goto fail;
-            if (bc_get_leb128_int(s, &vd->scope_level))
-                goto fail;
-            if (bc_get_leb128_int(s, &vd->scope_next))
-                goto fail;
-            vd->scope_next--;
-            if (bc_get_u8(s, &v8))
-                goto fail;
-            idx = 0;
-            vd->var_kind = bc_get_flags(v8, &idx, 4);
-            vd->is_const = bc_get_flags(v8, &idx, 1);
-            vd->is_lexical = bc_get_flags(v8, &idx, 1);
-            vd->is_captured = bc_get_flags(v8, &idx, 1);
-#ifdef DUMP_READ_OBJECT
-            bc_read_trace(s, "name: "); print_atom(s->ctx, vd->var_name); printf("\n");
-#endif
-        }
-        bc_read_trace(s, "}\n");
-    }
-    if (b->closure_var_count != 0) {
-        bc_read_trace(s, "closure vars {\n");
-        for(i = 0; i < b->closure_var_count; i++) {
-            JSClosureVar *cv = &b->closure_var[i];
-            int var_idx;
-            if (bc_get_atom(s, &cv->var_name))
-                goto fail;
-            if (bc_get_leb128_int(s, &var_idx))
-                goto fail;
-            cv->var_idx = var_idx;
-            if (bc_get_u8(s, &v8))
-                goto fail;
-            idx = 0;
-            cv->is_local = bc_get_flags(v8, &idx, 1);
-            cv->is_arg = bc_get_flags(v8, &idx, 1);
-            cv->is_const = bc_get_flags(v8, &idx, 1);
-            cv->is_lexical = bc_get_flags(v8, &idx, 1);
-            cv->var_kind = bc_get_flags(v8, &idx, 4);
-#ifdef DUMP_READ_OBJECT
-            bc_read_trace(s, "name: "); print_atom(s->ctx, cv->var_name); printf("\n");
-#endif
-        }
-        bc_read_trace(s, "}\n");
-    }
-    {
-        bc_read_trace(s, "bytecode {\n");
-        if (JS_ReadFunctionBytecode(s, b, byte_code_offset, b->byte_code_len))
-            goto fail;
-        bc_read_trace(s, "}\n");
-    }
-    if (b->has_debug) {
-        /* read optional debug information */
-        bc_read_trace(s, "debug {\n");
-        if (bc_get_atom(s, &b->debug.filename))
-            goto fail;
-        if (bc_get_leb128_int(s, &b->debug.line_num))
-            goto fail;
-        if (bc_get_leb128_int(s, &b->debug.pc2line_len))
-            goto fail;
-        if (b->debug.pc2line_len) {
-            b->debug.pc2line_buf = js_mallocz(ctx, b->debug.pc2line_len);
-            if (!b->debug.pc2line_buf)
-                goto fail;
-            if (bc_get_buf(s, b->debug.pc2line_buf, b->debug.pc2line_len))
-                goto fail;
-        }
-#ifdef DUMP_READ_OBJECT
-        bc_read_trace(s, "filename: "); print_atom(s->ctx, b->debug.filename); printf("\n");
-#endif
-        bc_read_trace(s, "}\n");
-    }
-    if (b->cpool_count != 0) {
-        bc_read_trace(s, "cpool {\n");
-        for(i = 0; i < b->cpool_count; i++) {
-            JSValue val;
-            val = JS_ReadObjectRec(s);
-            if (JS_IsException(val))
-                goto fail;
-            b->cpool[i] = val;
-        }
-        bc_read_trace(s, "}\n");
-    }
-    b->realm = JS_DupContext(ctx);
-    return obj;
- fail:
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue JS_ReadModule(BCReaderState *s)
-{
-    JSContext *ctx = s->ctx;
-    JSValue obj;
-    JSModuleDef *m = NULL;
-    JSAtom module_name;
-    int i;
-    uint8_t v8;
-    
-    if (bc_get_atom(s, &module_name))
-        goto fail;
-#ifdef DUMP_READ_OBJECT
-    bc_read_trace(s, "name: "); print_atom(s->ctx, module_name); printf("\n");
-#endif
-    m = js_new_module_def(ctx, module_name);
-    if (!m)
-        goto fail;
-    obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
-    if (bc_get_leb128_int(s, &m->req_module_entries_count))
-        goto fail;
-    if (m->req_module_entries_count != 0) {
-        m->req_module_entries_size = m->req_module_entries_count;
-        m->req_module_entries = js_mallocz(ctx, sizeof(m->req_module_entries[0]) * m->req_module_entries_size);
-        if (!m->req_module_entries)
-            goto fail;
-        for(i = 0; i < m->req_module_entries_count; i++) {
-            JSReqModuleEntry *rme = &m->req_module_entries[i];
-            if (bc_get_atom(s, &rme->module_name))
-                goto fail;
-        }
-    }
-
-    if (bc_get_leb128_int(s, &m->export_entries_count))
-        goto fail;
-    if (m->export_entries_count != 0) {
-        m->export_entries_size = m->export_entries_count;
-        m->export_entries = js_mallocz(ctx, sizeof(m->export_entries[0]) * m->export_entries_size);
-        if (!m->export_entries)
-            goto fail;
-        for(i = 0; i < m->export_entries_count; i++) {
-            JSExportEntry *me = &m->export_entries[i];
-            if (bc_get_u8(s, &v8))
-                goto fail;
-            me->export_type = v8;
-            if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
-                if (bc_get_leb128_int(s, &me->u.local.var_idx))
-                    goto fail;
-            } else {
-                if (bc_get_leb128_int(s, &me->u.req_module_idx))
-                    goto fail;
-                if (bc_get_atom(s, &me->local_name))
-                    goto fail;
-            }
-            if (bc_get_atom(s, &me->export_name))
-                goto fail;
-        }
-    }
-
-    if (bc_get_leb128_int(s, &m->star_export_entries_count))
-        goto fail;
-    if (m->star_export_entries_count != 0) {
-        m->star_export_entries_size = m->star_export_entries_count;
-        m->star_export_entries = js_mallocz(ctx, sizeof(m->star_export_entries[0]) * m->star_export_entries_size);
-        if (!m->star_export_entries)
-            goto fail;
-        for(i = 0; i < m->star_export_entries_count; i++) {
-            JSStarExportEntry *se = &m->star_export_entries[i];
-            if (bc_get_leb128_int(s, &se->req_module_idx))
-                goto fail;
-        }
-    }
-
-    if (bc_get_leb128_int(s, &m->import_entries_count))
-        goto fail;
-    if (m->import_entries_count != 0) {
-        m->import_entries_size = m->import_entries_count;
-        m->import_entries = js_mallocz(ctx, sizeof(m->import_entries[0]) * m->import_entries_size);
-        if (!m->import_entries)
-            goto fail;
-        for(i = 0; i < m->import_entries_count; i++) {
-            JSImportEntry *mi = &m->import_entries[i];
-            if (bc_get_leb128_int(s, &mi->var_idx))
-                goto fail;
-            if (bc_get_atom(s, &mi->import_name))
-                goto fail;
-            if (bc_get_leb128_int(s, &mi->req_module_idx))
-                goto fail;
-        }
-    }
-
-    m->func_obj = JS_ReadObjectRec(s);
-    if (JS_IsException(m->func_obj))
-        goto fail;
-    return obj;
- fail:
-    if (m) {
-        js_free_module_def(ctx, m);
-    }
-    return JS_EXCEPTION;
-}
-
-static JSValue JS_ReadObjectTag(BCReaderState *s)
-{
-    JSContext *ctx = s->ctx;
-    JSValue obj;
-    uint32_t prop_count, i;
-    JSAtom atom;
-    JSValue val;
-    int ret;
-    
-    obj = JS_NewObject(ctx);
-    if (BC_add_object_ref(s, obj))
-        goto fail;
-    if (bc_get_leb128(s, &prop_count))
-        goto fail;
-    for(i = 0; i < prop_count; i++) {
-        if (bc_get_atom(s, &atom))
-            goto fail;
-#ifdef DUMP_READ_OBJECT
-        bc_read_trace(s, "propname: "); print_atom(s->ctx, atom); printf("\n");
-#endif
-        val = JS_ReadObjectRec(s);
-        if (JS_IsException(val)) {
-            JS_FreeAtom(ctx, atom);
-            goto fail;
-        }
-        ret = JS_DefinePropertyValue(ctx, obj, atom, val, JS_PROP_C_W_E);
-        JS_FreeAtom(ctx, atom);
-        if (ret < 0)
-            goto fail;
-    }
-    return obj;
- fail:
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue JS_ReadArray(BCReaderState *s, int tag)
-{
-    JSContext *ctx = s->ctx;
-    JSValue obj;
-    uint32_t len, i;
-    JSValue val;
-    int ret, prop_flags;
-    BOOL is_template;
-
-    obj = JS_NewArray(ctx);
-    if (BC_add_object_ref(s, obj))
-        goto fail;
-    is_template = (tag == BC_TAG_TEMPLATE_OBJECT);
-    if (bc_get_leb128(s, &len))
-        goto fail;
-    for(i = 0; i < len; i++) {
-        val = JS_ReadObjectRec(s);
-        if (JS_IsException(val))
-            goto fail;
-        if (is_template)
-            prop_flags = JS_PROP_ENUMERABLE;
-        else
-            prop_flags = JS_PROP_C_W_E;
-        ret = JS_DefinePropertyValueUint32(ctx, obj, i, val,
-                                           prop_flags);
-        if (ret < 0)
-            goto fail;
-    }
-    if (is_template) {
-        val = JS_ReadObjectRec(s);
-        if (JS_IsException(val))
-            goto fail;
-        if (!JS_IsUndefined(val)) {
-            ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_raw, val, 0);
-            if (ret < 0)
-                goto fail;
-        }
-        JS_PreventExtensions(ctx, obj);
-    }
-    return obj;
- fail:
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue JS_ReadTypedArray(BCReaderState *s)
-{
-    JSContext *ctx = s->ctx;
-    JSValue obj = JS_UNDEFINED, array_buffer = JS_UNDEFINED;
-    uint8_t array_tag;
-    JSValueConst args[3];
-    uint32_t offset, len, idx;
-    
-    if (bc_get_u8(s, &array_tag))
-        return JS_EXCEPTION;
-    if (array_tag >= JS_TYPED_ARRAY_COUNT)
-        return JS_ThrowTypeError(ctx, "invalid typed array");
-    if (bc_get_leb128(s, &len))
-        return JS_EXCEPTION;
-    if (bc_get_leb128(s, &offset))
-        return JS_EXCEPTION;
-    /* XXX: this hack could be avoided if the typed array could be
-       created before the array buffer */
-    idx = s->objects_count;
-    if (BC_add_object_ref1(s, NULL))
-        goto fail;
-    array_buffer = JS_ReadObjectRec(s);
-    if (JS_IsException(array_buffer))
-        return JS_EXCEPTION;
-    if (!js_get_array_buffer(ctx, array_buffer)) {
-        JS_FreeValue(ctx, array_buffer);
-        return JS_EXCEPTION;
-    }
-    args[0] = array_buffer;
-    args[1] = JS_NewInt64(ctx, offset);
-    args[2] = JS_NewInt64(ctx, len);
-    obj = js_typed_array_constructor(ctx, JS_UNDEFINED,
-                                     3, args,
-                                     JS_CLASS_UINT8C_ARRAY + array_tag);
-    if (JS_IsException(obj))
-        goto fail;
-    if (s->allow_reference) {
-        s->objects[idx] = JS_VALUE_GET_OBJ(obj);
-    }
-    JS_FreeValue(ctx, array_buffer);
-    return obj;
- fail:
-    JS_FreeValue(ctx, array_buffer);
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue JS_ReadArrayBuffer(BCReaderState *s)
-{
-    JSContext *ctx = s->ctx;
-    uint32_t byte_length;
-    JSValue obj;
-    
-    if (bc_get_leb128(s, &byte_length))
-        return JS_EXCEPTION;
-    if (unlikely(s->buf_end - s->ptr < byte_length)) {
-        bc_read_error_end(s);
-        return JS_EXCEPTION;
-    }
-    obj = JS_NewArrayBufferCopy(ctx, s->ptr, byte_length);
-    if (JS_IsException(obj))
-        goto fail;
-    if (BC_add_object_ref(s, obj))
-        goto fail;
-    s->ptr += byte_length;
-    return obj;
- fail:
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue JS_ReadSharedArrayBuffer(BCReaderState *s)
-{
-    JSContext *ctx = s->ctx;
-    uint32_t byte_length;
-    uint8_t *data_ptr;
-    JSValue obj;
-    uint64_t u64;
-    
-    if (bc_get_leb128(s, &byte_length))
-        return JS_EXCEPTION;
-    if (bc_get_u64(s, &u64))
-        return JS_EXCEPTION;
-    data_ptr = (uint8_t *)(uintptr_t)u64;
-    /* the SharedArrayBuffer is cloned */
-    obj = js_array_buffer_constructor3(ctx, JS_UNDEFINED, byte_length,
-                                       JS_CLASS_SHARED_ARRAY_BUFFER,
-                                       data_ptr,
-                                       NULL, NULL, FALSE);
-    if (JS_IsException(obj))
-        goto fail;
-    if (BC_add_object_ref(s, obj))
-        goto fail;
-    return obj;
- fail:
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue JS_ReadDate(BCReaderState *s)
-{
-    JSContext *ctx = s->ctx;
-    JSValue val, obj = JS_UNDEFINED;
-
-    val = JS_ReadObjectRec(s);
-    if (JS_IsException(val))
-        goto fail;
-    if (!JS_IsNumber(val)) {
-        JS_ThrowTypeError(ctx, "Number tag expected for date");
-        goto fail;
-    }
-    obj = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_DATE],
-                                 JS_CLASS_DATE);
-    if (JS_IsException(obj))
-        goto fail;
-    if (BC_add_object_ref(s, obj))
-        goto fail;
-    JS_SetObjectData(ctx, obj, val);
-    return obj;
- fail:
-    JS_FreeValue(ctx, val);
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue JS_ReadObjectValue(BCReaderState *s)
-{
-    JSContext *ctx = s->ctx;
-    JSValue val, obj = JS_UNDEFINED;
-
-    val = JS_ReadObjectRec(s);
-    if (JS_IsException(val))
-        goto fail;
-    obj = JS_ToObject(ctx, val);
-    if (JS_IsException(obj))
-        goto fail;
-    if (BC_add_object_ref(s, obj))
-        goto fail;
-    JS_FreeValue(ctx, val);
-    return obj;
- fail:
-    JS_FreeValue(ctx, val);
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue JS_ReadObjectRec(BCReaderState *s)
-{
-    JSContext *ctx = s->ctx;
-    uint8_t tag;
-    JSValue obj = JS_UNDEFINED;
-
-    if (js_check_stack_overflow(ctx->rt, 0))
-        return JS_ThrowStackOverflow(ctx);
-
-    if (bc_get_u8(s, &tag))
-        return JS_EXCEPTION;
-
-    bc_read_trace(s, "%s {\n", bc_tag_str[tag]);
-
-    switch(tag) {
-    case BC_TAG_NULL:
-        obj = JS_NULL;
-        break;
-    case BC_TAG_UNDEFINED:
-        obj = JS_UNDEFINED;
-        break;
-    case BC_TAG_BOOL_FALSE:
-    case BC_TAG_BOOL_TRUE:
-        obj = JS_NewBool(ctx, tag - BC_TAG_BOOL_FALSE);
-        break;
-    case BC_TAG_INT32:
-        {
-            int32_t val;
-            if (bc_get_sleb128(s, &val))
-                return JS_EXCEPTION;
-            bc_read_trace(s, "%d\n", val);
-            obj = JS_NewInt32(ctx, val);
-        }
-        break;
-    case BC_TAG_FLOAT64:
-        {
-            JSFloat64Union u;
-            if (bc_get_u64(s, &u.u64))
-                return JS_EXCEPTION;
-            bc_read_trace(s, "%g\n", u.d);
-            obj = __JS_NewFloat64(ctx, u.d);
-        }
-        break;
-    case BC_TAG_STRING:
-        {
-            JSString *p;
-            p = JS_ReadString(s);
-            if (!p)
-                return JS_EXCEPTION;
-            obj = JS_MKPTR(JS_TAG_STRING, p);
-        }
-        break;
-    case BC_TAG_FUNCTION_BYTECODE:
-        if (!s->allow_bytecode)
-            goto invalid_tag;
-        obj = JS_ReadFunctionTag(s);
-        break;
-    case BC_TAG_MODULE:
-        if (!s->allow_bytecode)
-            goto invalid_tag;
-        obj = JS_ReadModule(s);
-        break;
-    case BC_TAG_OBJECT:
-        obj = JS_ReadObjectTag(s);
-        break;
-    case BC_TAG_ARRAY:
-    case BC_TAG_TEMPLATE_OBJECT:
-        obj = JS_ReadArray(s, tag);
-        break;
-    case BC_TAG_TYPED_ARRAY:
-        obj = JS_ReadTypedArray(s);
-        break;
-    case BC_TAG_ARRAY_BUFFER:
-        obj = JS_ReadArrayBuffer(s);
-        break;
-    case BC_TAG_SHARED_ARRAY_BUFFER:
-        if (!s->allow_sab || !ctx->rt->sab_funcs.sab_dup)
-            goto invalid_tag;
-        obj = JS_ReadSharedArrayBuffer(s);
-        break;
-    case BC_TAG_DATE:
-        obj = JS_ReadDate(s);
-        break;
-    case BC_TAG_OBJECT_VALUE:
-        obj = JS_ReadObjectValue(s);
-        break;
-#ifdef CONFIG_BIGNUM
-    case BC_TAG_BIG_INT:
-    case BC_TAG_BIG_FLOAT:
-    case BC_TAG_BIG_DECIMAL:
-        obj = JS_ReadBigNum(s, tag);
-        break;
-#endif
-    case BC_TAG_OBJECT_REFERENCE:
-        {
-            uint32_t val;
-            if (!s->allow_reference)
-                return JS_ThrowSyntaxError(ctx, "object references are not allowed");
-            if (bc_get_leb128(s, &val))
-                return JS_EXCEPTION;
-            bc_read_trace(s, "%u\n", val);
-            if (val >= s->objects_count) {
-                return JS_ThrowSyntaxError(ctx, "invalid object reference (%u >= %u)",
-                                           val, s->objects_count);
-            }
-            obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, s->objects[val]));
-        }
-        break;
-    default:
-    invalid_tag:
-        return JS_ThrowSyntaxError(ctx, "invalid tag (tag=%d pos=%u)",
-                                   tag, (unsigned int)(s->ptr - s->buf_start));
-    }
-    bc_read_trace(s, "}\n");
-    return obj;
-}
-
-static int JS_ReadObjectAtoms(BCReaderState *s)
-{
-    uint8_t v8;
-    JSString *p;
-    int i;
-    JSAtom atom;
-
-    if (bc_get_u8(s, &v8))
-        return -1;
-    /* XXX: could support byte swapped input */
-    if (v8 != BC_VERSION) {
-        JS_ThrowSyntaxError(s->ctx, "invalid version (%d expected=%d)",
-                            v8, BC_VERSION);
-        return -1;
-    }
-    if (bc_get_leb128(s, &s->idx_to_atom_count))
-        return -1;
-
-    bc_read_trace(s, "%d atom indexes {\n", s->idx_to_atom_count);
-
-    if (s->idx_to_atom_count != 0) {
-        s->idx_to_atom = js_mallocz(s->ctx, s->idx_to_atom_count *
-                                    sizeof(s->idx_to_atom[0]));
-        if (!s->idx_to_atom)
-            return s->error_state = -1;
-    }
-    for(i = 0; i < s->idx_to_atom_count; i++) {
-        p = JS_ReadString(s);
-        if (!p)
-            return -1;
-        atom = JS_NewAtomStr(s->ctx, p);
-        if (atom == JS_ATOM_NULL)
-            return s->error_state = -1;
-        s->idx_to_atom[i] = atom;
-        if (s->is_rom_data && (atom != (i + s->first_atom)))
-            s->is_rom_data = FALSE; /* atoms must be relocated */
-    }
-    bc_read_trace(s, "}\n");
-    return 0;
-}
-
-static void bc_reader_free(BCReaderState *s)
-{
-    int i;
-    if (s->idx_to_atom) {
-        for(i = 0; i < s->idx_to_atom_count; i++) {
-            JS_FreeAtom(s->ctx, s->idx_to_atom[i]);
-        }
-        js_free(s->ctx, s->idx_to_atom);
-    }
-    js_free(s->ctx, s->objects);
-}
-
-JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len,
-                       int flags)
-{
-    BCReaderState ss, *s = &ss;
-    JSValue obj;
-
-    ctx->binary_object_count += 1;
-    ctx->binary_object_size += buf_len;
-
-    memset(s, 0, sizeof(*s));
-    s->ctx = ctx;
-    s->buf_start = buf;
-    s->buf_end = buf + buf_len;
-    s->ptr = buf;
-    s->allow_bytecode = ((flags & JS_READ_OBJ_BYTECODE) != 0);
-    s->is_rom_data = ((flags & JS_READ_OBJ_ROM_DATA) != 0);
-    s->allow_sab = ((flags & JS_READ_OBJ_SAB) != 0);
-    s->allow_reference = ((flags & JS_READ_OBJ_REFERENCE) != 0);
-    if (s->allow_bytecode)
-        s->first_atom = JS_ATOM_END;
-    else
-        s->first_atom = 1;
-    if (JS_ReadObjectAtoms(s)) {
-        obj = JS_EXCEPTION;
-    } else {
-        obj = JS_ReadObjectRec(s);
-    }
-    bc_reader_free(s);
-    return obj;
-}
-
-/*******************************************************************/
-/* runtime functions & objects */
-
-static JSValue js_string_constructor(JSContext *ctx, JSValueConst this_val,
-                                     int argc, JSValueConst *argv);
-static JSValue js_boolean_constructor(JSContext *ctx, JSValueConst this_val,
-                                      int argc, JSValueConst *argv);
-static JSValue js_number_constructor(JSContext *ctx, JSValueConst this_val,
-                                     int argc, JSValueConst *argv);
-
-static int check_function(JSContext *ctx, JSValueConst obj)
-{
-    if (likely(JS_IsFunction(ctx, obj)))
-        return 0;
-    JS_ThrowTypeError(ctx, "not a function");
-    return -1;
-}
-
-static int check_exception_free(JSContext *ctx, JSValue obj)
-{
-    JS_FreeValue(ctx, obj);
-    return JS_IsException(obj);
-}
-
-static JSAtom find_atom(JSContext *ctx, const char *name)
-{
-    JSAtom atom;
-    int len;
-
-    if (*name == '[') {
-        name++;
-        len = strlen(name) - 1;
-        /* We assume 8 bit non null strings, which is the case for these
-           symbols */
-        for(atom = JS_ATOM_Symbol_toPrimitive; atom < JS_ATOM_END; atom++) {
-            JSAtomStruct *p = ctx->rt->atom_array[atom];
-            JSString *str = p;
-            if (str->len == len && !memcmp(str->u.str8, name, len))
-                return JS_DupAtom(ctx, atom);
-        }
-        abort();
-    } else {
-        atom = JS_NewAtom(ctx, name);
-    }
-    return atom;
-}
-
-static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,
-                                               JSAtom atom, void *opaque)
-{
-    const JSCFunctionListEntry *e = opaque;
-    JSValue val;
-
-    switch(e->def_type) {
-    case JS_DEF_CFUNC:
-        val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic,
-                               e->name, e->u.func.length, e->u.func.cproto, e->magic);
-        break;
-    case JS_DEF_PROP_STRING:
-        val = JS_NewAtomString(ctx, e->u.str);
-        break;
-    case JS_DEF_OBJECT:
-        val = JS_NewObject(ctx);
-        JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len);
-        break;
-    default:
-        abort();
-    }
-    return val;
-}
-
-static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj,
-                                          JSAtom atom,
-                                          const JSCFunctionListEntry *e)
-{
-    JSValue val;
-    int prop_flags = e->prop_flags;
-
-    switch(e->def_type) {
-    case JS_DEF_ALIAS: /* using autoinit for aliases is not safe */
-        {
-            JSAtom atom1 = find_atom(ctx, e->u.alias.name);
-            switch (e->u.alias.base) {
-            case -1:
-                val = JS_GetProperty(ctx, obj, atom1);
-                break;
-            case 0:
-                val = JS_GetProperty(ctx, ctx->global_obj, atom1);
-                break;
-            case 1:
-                val = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], atom1);
-                break;
-            default:
-                abort();
-            }
-            JS_FreeAtom(ctx, atom1);
-            if (atom == JS_ATOM_Symbol_toPrimitive) {
-                /* Symbol.toPrimitive functions are not writable */
-                prop_flags = JS_PROP_CONFIGURABLE;
-            } else if (atom == JS_ATOM_Symbol_hasInstance) {
-                /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */
-                prop_flags = 0;
-            }
-        }
-        break;
-    case JS_DEF_CFUNC:
-        if (atom == JS_ATOM_Symbol_toPrimitive) {
-            /* Symbol.toPrimitive functions are not writable */
-            prop_flags = JS_PROP_CONFIGURABLE;
-        } else if (atom == JS_ATOM_Symbol_hasInstance) {
-            /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */
-            prop_flags = 0;
-        }
-        JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP,
-                                  (void *)e, prop_flags);
-        return 0;
-    case JS_DEF_CGETSET: /* XXX: use autoinit again ? */
-    case JS_DEF_CGETSET_MAGIC:
-        {
-            JSValue getter, setter;
-            char buf[64];
-
-            getter = JS_UNDEFINED;
-            if (e->u.getset.get.generic) {
-                snprintf(buf, sizeof(buf), "get %s", e->name);
-                getter = JS_NewCFunction2(ctx, e->u.getset.get.generic,
-                                          buf, 0, e->def_type == JS_DEF_CGETSET_MAGIC ? JS_CFUNC_getter_magic : JS_CFUNC_getter,
-                                          e->magic);
-            }
-            setter = JS_UNDEFINED;
-            if (e->u.getset.set.generic) {
-                snprintf(buf, sizeof(buf), "set %s", e->name);
-                setter = JS_NewCFunction2(ctx, e->u.getset.set.generic,
-                                          buf, 1, e->def_type == JS_DEF_CGETSET_MAGIC ? JS_CFUNC_setter_magic : JS_CFUNC_setter,
-                                          e->magic);
-            }
-            JS_DefinePropertyGetSet(ctx, obj, atom, getter, setter, prop_flags);
-            return 0;
-        }
-        break;
-    case JS_DEF_PROP_INT32:
-        val = JS_NewInt32(ctx, e->u.i32);
-        break;
-    case JS_DEF_PROP_INT64:
-        val = JS_NewInt64(ctx, e->u.i64);
-        break;
-    case JS_DEF_PROP_DOUBLE:
-        val = __JS_NewFloat64(ctx, e->u.f64);
-        break;
-    case JS_DEF_PROP_UNDEFINED:
-        val = JS_UNDEFINED;
-        break;
-    case JS_DEF_PROP_STRING:
-    case JS_DEF_OBJECT:
-        JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP,
-                                  (void *)e, prop_flags);
-        return 0;
-    default:
-        abort();
-    }
-    JS_DefinePropertyValue(ctx, obj, atom, val, prop_flags);
-    return 0;
-}
-
-void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
-                                const JSCFunctionListEntry *tab, int len)
-{
-    int i;
-
-    for (i = 0; i < len; i++) {
-        const JSCFunctionListEntry *e = &tab[i];
-        JSAtom atom = find_atom(ctx, e->name);
-        JS_InstantiateFunctionListItem(ctx, obj, atom, e);
-        JS_FreeAtom(ctx, atom);
-    }
-}
-
-int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m,
-                           const JSCFunctionListEntry *tab, int len)
-{
-    int i;
-    for(i = 0; i < len; i++) {
-        if (JS_AddModuleExport(ctx, m, tab[i].name))
-            return -1;
-    }
-    return 0;
-}
-
-int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,
-                           const JSCFunctionListEntry *tab, int len)
-{
-    int i;
-    JSValue val;
-
-    for(i = 0; i < len; i++) {
-        const JSCFunctionListEntry *e = &tab[i];
-        switch(e->def_type) {
-        case JS_DEF_CFUNC:
-            val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic,
-                                   e->name, e->u.func.length, e->u.func.cproto, e->magic);
-            break;
-        case JS_DEF_PROP_STRING:
-            val = JS_NewString(ctx, e->u.str);
-            break;
-        case JS_DEF_PROP_INT32:
-            val = JS_NewInt32(ctx, e->u.i32);
-            break;
-        case JS_DEF_PROP_INT64:
-            val = JS_NewInt64(ctx, e->u.i64);
-            break;
-        case JS_DEF_PROP_DOUBLE:
-            val = __JS_NewFloat64(ctx, e->u.f64);
-            break;
-        case JS_DEF_OBJECT:
-            val = JS_NewObject(ctx);
-            JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len);
-            break;
-        default:
-            abort();
-        }
-        if (JS_SetModuleExport(ctx, m, e->name, val))
-            return -1;
-    }
-    return 0;
-}
-
-/* Note: 'func_obj' is not necessarily a constructor */
-static void JS_SetConstructor2(JSContext *ctx,
-                               JSValueConst func_obj,
-                               JSValueConst proto,
-                               int proto_flags, int ctor_flags)
-{
-    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype,
-                           JS_DupValue(ctx, proto), proto_flags);
-    JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor,
-                           JS_DupValue(ctx, func_obj),
-                           ctor_flags);
-    set_cycle_flag(ctx, func_obj);
-    set_cycle_flag(ctx, proto);
-}
-
-void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, 
-                       JSValueConst proto)
-{
-    JS_SetConstructor2(ctx, func_obj, proto,
-                       0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-}
-
-static void JS_NewGlobalCConstructor2(JSContext *ctx,
-                                      JSValue func_obj,
-                                      const char *name,
-                                      JSValueConst proto)
-{
-    JS_DefinePropertyValueStr(ctx, ctx->global_obj, name,
-                           JS_DupValue(ctx, func_obj),
-                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-    JS_SetConstructor(ctx, func_obj, proto);
-    JS_FreeValue(ctx, func_obj);
-}
-
-static JSValueConst JS_NewGlobalCConstructor(JSContext *ctx, const char *name,
-                                             JSCFunction *func, int length,
-                                             JSValueConst proto)
-{
-    JSValue func_obj;
-    func_obj = JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_constructor_or_func, 0);
-    JS_NewGlobalCConstructor2(ctx, func_obj, name, proto);
-    return func_obj;
-}
-
-static JSValueConst JS_NewGlobalCConstructorOnly(JSContext *ctx, const char *name,
-                                                 JSCFunction *func, int length,
-                                                 JSValueConst proto)
-{
-    JSValue func_obj;
-    func_obj = JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_constructor, 0);
-    JS_NewGlobalCConstructor2(ctx, func_obj, name, proto);
-    return func_obj;
-}
-
-static JSValue js_global_eval(JSContext *ctx, JSValueConst this_val,
-                              int argc, JSValueConst *argv)
-{
-    return JS_EvalObject(ctx, ctx->global_obj, argv[0], JS_EVAL_TYPE_INDIRECT, -1);
-}
-
-static JSValue js_global_isNaN(JSContext *ctx, JSValueConst this_val,
-                               int argc, JSValueConst *argv)
-{
-    double d;
-
-    /* XXX: does this work for bigfloat? */
-    if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
-        return JS_EXCEPTION;
-    return JS_NewBool(ctx, isnan(d));
-}
-
-static JSValue js_global_isFinite(JSContext *ctx, JSValueConst this_val,
-                                  int argc, JSValueConst *argv)
-{
-    BOOL res;
-    double d;
-    if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
-        return JS_EXCEPTION;
-    res = isfinite(d);
-    return JS_NewBool(ctx, res);
-}
-
-/* Object class */
-
-static JSValue JS_ToObject(JSContext *ctx, JSValueConst val)
-{
-    int tag = JS_VALUE_GET_NORM_TAG(val);
-    JSValue obj;
-
-    switch(tag) {
-    default:
-    case JS_TAG_NULL:
-    case JS_TAG_UNDEFINED:
-        return JS_ThrowTypeError(ctx, "cannot convert to object");
-    case JS_TAG_OBJECT:
-    case JS_TAG_EXCEPTION:
-        return JS_DupValue(ctx, val);
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_INT:
-        obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT);
-        goto set_value;
-    case JS_TAG_BIG_FLOAT:
-        obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_FLOAT);
-        goto set_value;
-    case JS_TAG_BIG_DECIMAL:
-        obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_DECIMAL);
-        goto set_value;
-#endif
-    case JS_TAG_INT:
-    case JS_TAG_FLOAT64:
-        obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER);
-        goto set_value;
-    case JS_TAG_STRING:
-        /* XXX: should call the string constructor */
-        {
-            JSString *p1 = JS_VALUE_GET_STRING(val);
-            obj = JS_NewObjectClass(ctx, JS_CLASS_STRING);
-            JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, JS_NewInt32(ctx, p1->len), 0);
-        }
-        goto set_value;
-    case JS_TAG_BOOL:
-        obj = JS_NewObjectClass(ctx, JS_CLASS_BOOLEAN);
-        goto set_value;
-    case JS_TAG_SYMBOL:
-        obj = JS_NewObjectClass(ctx, JS_CLASS_SYMBOL);
-    set_value:
-        if (!JS_IsException(obj))
-            JS_SetObjectData(ctx, obj, JS_DupValue(ctx, val));
-        return obj;
-    }
-}
-
-static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val)
-{
-    JSValue obj = JS_ToObject(ctx, val);
-    JS_FreeValue(ctx, val);
-    return obj;
-}
-
-static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
-                          JSValueConst desc)
-{
-    JSValue val, getter, setter;
-    int flags;
-
-    if (!JS_IsObject(desc)) {
-        JS_ThrowTypeErrorNotAnObject(ctx);
-        return -1;
-    }
-    flags = 0;
-    val = JS_UNDEFINED;
-    getter = JS_UNDEFINED;
-    setter = JS_UNDEFINED;
-    if (JS_HasProperty(ctx, desc, JS_ATOM_configurable)) {
-        JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_configurable);
-        if (JS_IsException(prop))
-            goto fail;
-        flags |= JS_PROP_HAS_CONFIGURABLE;
-        if (JS_ToBoolFree(ctx, prop))
-            flags |= JS_PROP_CONFIGURABLE;
-    }
-    if (JS_HasProperty(ctx, desc, JS_ATOM_writable)) {
-        JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_writable);
-        if (JS_IsException(prop))
-            goto fail;
-        flags |= JS_PROP_HAS_WRITABLE;
-        if (JS_ToBoolFree(ctx, prop))
-            flags |= JS_PROP_WRITABLE;
-    }
-    if (JS_HasProperty(ctx, desc, JS_ATOM_enumerable)) {
-        JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_enumerable);
-        if (JS_IsException(prop))
-            goto fail;
-        flags |= JS_PROP_HAS_ENUMERABLE;
-        if (JS_ToBoolFree(ctx, prop))
-            flags |= JS_PROP_ENUMERABLE;
-    }
-    if (JS_HasProperty(ctx, desc, JS_ATOM_value)) {
-        flags |= JS_PROP_HAS_VALUE;
-        val = JS_GetProperty(ctx, desc, JS_ATOM_value);
-        if (JS_IsException(val))
-            goto fail;
-    }
-    if (JS_HasProperty(ctx, desc, JS_ATOM_get)) {
-        flags |= JS_PROP_HAS_GET;
-        getter = JS_GetProperty(ctx, desc, JS_ATOM_get);
-        if (JS_IsException(getter) ||
-            !(JS_IsUndefined(getter) || JS_IsFunction(ctx, getter))) {
-            JS_ThrowTypeError(ctx, "invalid getter");
-            goto fail;
-        }
-    }
-    if (JS_HasProperty(ctx, desc, JS_ATOM_set)) {
-        flags |= JS_PROP_HAS_SET;
-        setter = JS_GetProperty(ctx, desc, JS_ATOM_set);
-        if (JS_IsException(setter) ||
-            !(JS_IsUndefined(setter) || JS_IsFunction(ctx, setter))) {
-            JS_ThrowTypeError(ctx, "invalid setter");
-            goto fail;
-        }
-    }
-    if ((flags & (JS_PROP_HAS_SET | JS_PROP_HAS_GET)) &&
-        (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE))) {
-        JS_ThrowTypeError(ctx, "cannot have setter/getter and value or writable");
-        goto fail;
-    }
-    d->flags = flags;
-    d->value = val;
-    d->getter = getter;
-    d->setter = setter;
-    return 0;
- fail:
-    JS_FreeValue(ctx, val);
-    JS_FreeValue(ctx, getter);
-    JS_FreeValue(ctx, setter);
-    return -1;
-}
-
-static __exception int JS_DefinePropertyDesc(JSContext *ctx, JSValueConst obj,
-                                             JSAtom prop, JSValueConst desc,
-                                             int flags)
-{
-    JSPropertyDescriptor d;
-    int ret;
-
-    if (js_obj_to_desc(ctx, &d, desc) < 0)
-        return -1;
-
-    ret = JS_DefineProperty(ctx, obj, prop,
-                            d.value, d.getter, d.setter, d.flags | flags);
-    js_free_desc(ctx, &d);
-    return ret;
-}
-
-static __exception int JS_ObjectDefineProperties(JSContext *ctx,
-                                                 JSValueConst obj,
-                                                 JSValueConst properties)
-{
-    JSValue props, desc;
-    JSObject *p;
-    JSPropertyEnum *atoms;
-    uint32_t len, i;
-    int ret = -1;
-
-    if (!JS_IsObject(obj)) {
-        JS_ThrowTypeErrorNotAnObject(ctx);
-        return -1;
-    }
-    desc = JS_UNDEFINED;
-    props = JS_ToObject(ctx, properties);
-    if (JS_IsException(props))
-        return -1;
-    p = JS_VALUE_GET_OBJ(props);
-    if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK) < 0)
-        goto exception;
-    for(i = 0; i < len; i++) {
-        JS_FreeValue(ctx, desc);
-        desc = JS_GetProperty(ctx, props, atoms[i].atom);
-        if (JS_IsException(desc))
-            goto exception;
-        if (JS_DefinePropertyDesc(ctx, obj, atoms[i].atom, desc, JS_PROP_THROW) < 0)
-            goto exception;
-    }
-    ret = 0;
-
-exception:
-    js_free_prop_enum(ctx, atoms, len);
-    JS_FreeValue(ctx, props);
-    JS_FreeValue(ctx, desc);
-    return ret;
-}
-
-static JSValue js_object_constructor(JSContext *ctx, JSValueConst new_target,
-                                     int argc, JSValueConst *argv)
-{
-    JSValue ret;
-    if (!JS_IsUndefined(new_target) &&
-        JS_VALUE_GET_OBJ(new_target) !=
-        JS_VALUE_GET_OBJ(JS_GetActiveFunction(ctx))) {
-        ret = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
-    } else {
-        int tag = JS_VALUE_GET_NORM_TAG(argv[0]);
-        switch(tag) {
-        case JS_TAG_NULL:
-        case JS_TAG_UNDEFINED:
-            ret = JS_NewObject(ctx);
-            break;
-        default:
-            ret = JS_ToObject(ctx, argv[0]);
-            break;
-        }
-    }
-    return ret;
-}
-
-static JSValue js_object_create(JSContext *ctx, JSValueConst this_val,
-                                int argc, JSValueConst *argv)
-{
-    JSValueConst proto, props;
-    JSValue obj;
-
-    proto = argv[0];
-    if (!JS_IsObject(proto) && !JS_IsNull(proto))
-        return JS_ThrowTypeError(ctx, "not a prototype");
-    obj = JS_NewObjectProto(ctx, proto);
-    if (JS_IsException(obj))
-        return JS_EXCEPTION;
-    props = argv[1];
-    if (!JS_IsUndefined(props)) {
-        if (JS_ObjectDefineProperties(ctx, obj, props)) {
-            JS_FreeValue(ctx, obj);
-            return JS_EXCEPTION;
-        }
-    }
-    return obj;
-}
-
-static JSValue js_object_getPrototypeOf(JSContext *ctx, JSValueConst this_val,
-                                        int argc, JSValueConst *argv, int magic)
-{
-    JSValueConst val;
-
-    val = argv[0];
-    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) {
-        /* ES6 feature non compatible with ES5.1: primitive types are
-           accepted */
-        if (magic || JS_VALUE_GET_TAG(val) == JS_TAG_NULL ||
-            JS_VALUE_GET_TAG(val) == JS_TAG_UNDEFINED)
-            return JS_ThrowTypeErrorNotAnObject(ctx);
-    }
-    return JS_GetPrototype(ctx, val);
-}
-
-static JSValue js_object_setPrototypeOf(JSContext *ctx, JSValueConst this_val,
-                                        int argc, JSValueConst *argv)
-{
-    JSValueConst obj;
-    obj = argv[0];
-    if (JS_SetPrototypeInternal(ctx, obj, argv[1], TRUE) < 0)
-        return JS_EXCEPTION;
-    return JS_DupValue(ctx, obj);
-}
-
-/* magic = 1 if called as Reflect.defineProperty */
-static JSValue js_object_defineProperty(JSContext *ctx, JSValueConst this_val,
-                                        int argc, JSValueConst *argv, int magic)
-{
-    JSValueConst obj, prop, desc;
-    int ret, flags;
-    JSAtom atom;
-
-    obj = argv[0];
-    prop = argv[1];
-    desc = argv[2];
-
-    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-    atom = JS_ValueToAtom(ctx, prop);
-    if (unlikely(atom == JS_ATOM_NULL))
-        return JS_EXCEPTION;
-    flags = 0;
-    if (!magic)
-        flags |= JS_PROP_THROW;
-    ret = JS_DefinePropertyDesc(ctx, obj, atom, desc, flags);
-    JS_FreeAtom(ctx, atom);
-    if (ret < 0) {
-        return JS_EXCEPTION;
-    } else if (magic) {
-        return JS_NewBool(ctx, ret);
-    } else {
-        return JS_DupValue(ctx, obj);
-    }
-}
-
-static JSValue js_object_defineProperties(JSContext *ctx, JSValueConst this_val,
-                                          int argc, JSValueConst *argv)
-{
-    // defineProperties(obj, properties)
-    JSValueConst obj = argv[0];
-
-    if (JS_ObjectDefineProperties(ctx, obj, argv[1]))
-        return JS_EXCEPTION;
-    else
-        return JS_DupValue(ctx, obj);
-}
-
-/* magic = 1 if called as __defineSetter__ */
-static JSValue js_object___defineGetter__(JSContext *ctx, JSValueConst this_val,
-                                          int argc, JSValueConst *argv, int magic)
-{
-    JSValue obj;
-    JSValueConst prop, value, get, set;
-    int ret, flags;
-    JSAtom atom;
-
-    prop = argv[0];
-    value = argv[1];
-
-    obj = JS_ToObject(ctx, this_val);
-    if (JS_IsException(obj))
-        return JS_EXCEPTION;
-
-    if (check_function(ctx, value)) {
-        JS_FreeValue(ctx, obj);
-        return JS_EXCEPTION;
-    }
-    atom = JS_ValueToAtom(ctx, prop);
-    if (unlikely(atom == JS_ATOM_NULL)) {
-        JS_FreeValue(ctx, obj);
-        return JS_EXCEPTION;
-    }
-    flags = JS_PROP_THROW |
-        JS_PROP_HAS_ENUMERABLE | JS_PROP_ENUMERABLE |
-        JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE;
-    if (magic) {
-        get = JS_UNDEFINED;
-        set = value;
-        flags |= JS_PROP_HAS_SET;
-    } else {
-        get = value;
-        set = JS_UNDEFINED;
-        flags |= JS_PROP_HAS_GET;
-    }
-    ret = JS_DefineProperty(ctx, obj, atom, JS_UNDEFINED, get, set, flags);
-    JS_FreeValue(ctx, obj);
-    JS_FreeAtom(ctx, atom);
-    if (ret < 0) {
-        return JS_EXCEPTION;
-    } else {
-        return JS_UNDEFINED;
-    }
-}
-
-static JSValue js_object_getOwnPropertyDescriptor(JSContext *ctx, JSValueConst this_val,
-                                                  int argc, JSValueConst *argv, int magic)
-{
-    JSValueConst prop;
-    JSAtom atom;
-    JSValue ret, obj;
-    JSPropertyDescriptor desc;
-    int res, flags;
-
-    if (magic) {
-        /* Reflect.getOwnPropertyDescriptor case */
-        if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT)
-            return JS_ThrowTypeErrorNotAnObject(ctx);
-        obj = JS_DupValue(ctx, argv[0]);
-    } else {
-        obj = JS_ToObject(ctx, argv[0]);
-        if (JS_IsException(obj))
-            return obj;
-    }
-    prop = argv[1];
-    atom = JS_ValueToAtom(ctx, prop);
-    if (unlikely(atom == JS_ATOM_NULL))
-        goto exception;
-    ret = JS_UNDEFINED;
-    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
-        res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), atom);
-        if (res < 0)
-            goto exception;
-        if (res) {
-            ret = JS_NewObject(ctx);
-            if (JS_IsException(ret))
-                goto exception1;
-            flags = JS_PROP_C_W_E | JS_PROP_THROW;
-            if (desc.flags & JS_PROP_GETSET) {
-                if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, desc.getter), flags) < 0
-                ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, desc.setter), flags) < 0)
-                    goto exception1;
-            } else {
-                if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, desc.value), flags) < 0
-                ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,
-                                           JS_NewBool(ctx, (desc.flags & JS_PROP_WRITABLE) != 0), flags) < 0)
-                    goto exception1;
-            }
-            if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,
-                                       JS_NewBool(ctx, (desc.flags & JS_PROP_ENUMERABLE) != 0), flags) < 0
-            ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
-                                       JS_NewBool(ctx, (desc.flags & JS_PROP_CONFIGURABLE) != 0), flags) < 0)
-                goto exception1;
-            js_free_desc(ctx, &desc);
-        }
-    }
-    JS_FreeAtom(ctx, atom);
-    JS_FreeValue(ctx, obj);
-    return ret;
-
-exception1:
-    js_free_desc(ctx, &desc);
-    JS_FreeValue(ctx, ret);
-exception:
-    JS_FreeAtom(ctx, atom);
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_object_getOwnPropertyDescriptors(JSContext *ctx, JSValueConst this_val,
-                                                   int argc, JSValueConst *argv)
-{
-    //getOwnPropertyDescriptors(obj)
-    JSValue obj, r;
-    JSObject *p;
-    JSPropertyEnum *props;
-    uint32_t len, i;
-
-    r = JS_UNDEFINED;
-    obj = JS_ToObject(ctx, argv[0]);
-    if (JS_IsException(obj))
-        return JS_EXCEPTION;
-
-    p = JS_VALUE_GET_OBJ(obj);
-    if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p,
-                               JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK))
-        goto exception;
-    r = JS_NewObject(ctx);
-    if (JS_IsException(r))
-        goto exception;
-    for(i = 0; i < len; i++) {
-        JSValue atomValue, desc;
-        JSValueConst args[2];
-
-        atomValue = JS_AtomToValue(ctx, props[i].atom);
-        if (JS_IsException(atomValue))
-            goto exception;
-        args[0] = obj;
-        args[1] = atomValue;
-        desc = js_object_getOwnPropertyDescriptor(ctx, JS_UNDEFINED, 2, args, 0);
-        JS_FreeValue(ctx, atomValue);
-        if (JS_IsException(desc))
-            goto exception;
-        if (!JS_IsUndefined(desc)) {
-            if (JS_DefinePropertyValue(ctx, r, props[i].atom, desc,
-                                       JS_PROP_C_W_E | JS_PROP_THROW) < 0)
-                goto exception;
-        }
-    }
-    js_free_prop_enum(ctx, props, len);
-    JS_FreeValue(ctx, obj);
-    return r;
-
-exception:
-    js_free_prop_enum(ctx, props, len);
-    JS_FreeValue(ctx, obj);
-    JS_FreeValue(ctx, r);
-    return JS_EXCEPTION;
-}
-
-static JSValue JS_GetOwnPropertyNames2(JSContext *ctx, JSValueConst obj1,
-                                       int flags, int kind)
-{
-    JSValue obj, r, val, key, value;
-    JSObject *p;
-    JSPropertyEnum *atoms;
-    uint32_t len, i, j;
-
-    r = JS_UNDEFINED;
-    val = JS_UNDEFINED;
-    obj = JS_ToObject(ctx, obj1);
-    if (JS_IsException(obj))
-        return JS_EXCEPTION;
-    p = JS_VALUE_GET_OBJ(obj);
-    if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, flags & ~JS_GPN_ENUM_ONLY))
-        goto exception;
-    r = JS_NewArray(ctx);
-    if (JS_IsException(r))
-        goto exception;
-    for(j = i = 0; i < len; i++) {
-        JSAtom atom = atoms[i].atom;
-        if (flags & JS_GPN_ENUM_ONLY) {
-            JSPropertyDescriptor desc;
-            int res;
-
-            /* Check if property is still enumerable */
-            res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
-            if (res < 0)
-                goto exception;
-            if (!res)
-                continue;
-            js_free_desc(ctx, &desc);
-            if (!(desc.flags & JS_PROP_ENUMERABLE))
-                continue;
-        }
-        switch(kind) {
-        default:
-        case JS_ITERATOR_KIND_KEY:
-            val = JS_AtomToValue(ctx, atom);
-            if (JS_IsException(val))
-                goto exception;
-            break;
-        case JS_ITERATOR_KIND_VALUE:
-            val = JS_GetProperty(ctx, obj, atom);
-            if (JS_IsException(val))
-                goto exception;
-            break;
-        case JS_ITERATOR_KIND_KEY_AND_VALUE:
-            val = JS_NewArray(ctx);
-            if (JS_IsException(val))
-                goto exception;
-            key = JS_AtomToValue(ctx, atom);
-            if (JS_IsException(key))
-                goto exception1;
-            if (JS_CreateDataPropertyUint32(ctx, val, 0, key, JS_PROP_THROW) < 0)
-                goto exception1;
-            value = JS_GetProperty(ctx, obj, atom);
-            if (JS_IsException(value))
-                goto exception1;
-            if (JS_CreateDataPropertyUint32(ctx, val, 1, value, JS_PROP_THROW) < 0)
-                goto exception1;
-            break;
-        }
-        if (JS_CreateDataPropertyUint32(ctx, r, j++, val, 0) < 0)
-            goto exception;
-    }
-    goto done;
-
-exception1:
-    JS_FreeValue(ctx, val);
-exception:
-    JS_FreeValue(ctx, r);
-    r = JS_EXCEPTION;
-done:
-    js_free_prop_enum(ctx, atoms, len);
-    JS_FreeValue(ctx, obj);
-    return r;
-}
-
-static JSValue js_object_getOwnPropertyNames(JSContext *ctx, JSValueConst this_val,
-                                             int argc, JSValueConst *argv)
-{
-    return JS_GetOwnPropertyNames2(ctx, argv[0],
-                                   JS_GPN_STRING_MASK, JS_ITERATOR_KIND_KEY);
-}
-
-static JSValue js_object_getOwnPropertySymbols(JSContext *ctx, JSValueConst this_val,
-                                             int argc, JSValueConst *argv)
-{
-    return JS_GetOwnPropertyNames2(ctx, argv[0],
-                                   JS_GPN_SYMBOL_MASK, JS_ITERATOR_KIND_KEY);
-}
-
-static JSValue js_object_keys(JSContext *ctx, JSValueConst this_val,
-                              int argc, JSValueConst *argv, int kind)
-{
-    return JS_GetOwnPropertyNames2(ctx, argv[0],
-                                   JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK, kind);
-}
-
-static JSValue js_object_isExtensible(JSContext *ctx, JSValueConst this_val,
-                                      int argc, JSValueConst *argv, int reflect)
-{
-    JSValueConst obj;
-    int ret;
-
-    obj = argv[0];
-    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
-        if (reflect)
-            return JS_ThrowTypeErrorNotAnObject(ctx);
-        else
-            return JS_FALSE;
-    }
-    ret = JS_IsExtensible(ctx, obj);
-    if (ret < 0)
-        return JS_EXCEPTION;
-    else
-        return JS_NewBool(ctx, ret);
-}
-
-static JSValue js_object_preventExtensions(JSContext *ctx, JSValueConst this_val,
-                                           int argc, JSValueConst *argv, int reflect)
-{
-    JSValueConst obj;
-    int ret;
-
-    obj = argv[0];
-    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
-        if (reflect)
-            return JS_ThrowTypeErrorNotAnObject(ctx);
-        else
-            return JS_DupValue(ctx, obj);
-    }
-    ret = JS_PreventExtensions(ctx, obj);
-    if (ret < 0)
-        return JS_EXCEPTION;
-    if (reflect) {
-        return JS_NewBool(ctx, ret);
-    } else {
-        if (!ret)
-            return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
-        return JS_DupValue(ctx, obj);
-    }
-}
-
-static JSValue js_object_hasOwnProperty(JSContext *ctx, JSValueConst this_val,
-                                        int argc, JSValueConst *argv)
-{
-    JSValue obj;
-    JSAtom atom;
-    JSObject *p;
-    BOOL ret;
-
-    atom = JS_ValueToAtom(ctx, argv[0]); /* must be done first */
-    if (unlikely(atom == JS_ATOM_NULL))
-        return JS_EXCEPTION;
-    obj = JS_ToObject(ctx, this_val);
-    if (JS_IsException(obj)) {
-        JS_FreeAtom(ctx, atom);
-        return obj;
-    }
-    p = JS_VALUE_GET_OBJ(obj);
-    ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);
-    JS_FreeAtom(ctx, atom);
-    JS_FreeValue(ctx, obj);
-    if (ret < 0)
-        return JS_EXCEPTION;
-    else
-        return JS_NewBool(ctx, ret);
-}
-
-static JSValue js_object_hasOwn(JSContext *ctx, JSValueConst this_val,
-                                int argc, JSValueConst *argv)
-{
-    JSValue obj;
-    JSAtom atom;
-    JSObject *p;
-    BOOL ret;
-
-    obj = JS_ToObject(ctx, argv[0]);
-    if (JS_IsException(obj))
-        return obj;
-    atom = JS_ValueToAtom(ctx, argv[1]);
-    if (unlikely(atom == JS_ATOM_NULL)) {
-        JS_FreeValue(ctx, obj);
-        return JS_EXCEPTION;
-    }
-    p = JS_VALUE_GET_OBJ(obj);
-    ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);
-    JS_FreeAtom(ctx, atom);
-    JS_FreeValue(ctx, obj);
-    if (ret < 0)
-        return JS_EXCEPTION;
-    else
-        return JS_NewBool(ctx, ret);
-}
-
-static JSValue js_object_valueOf(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv)
-{
-    return JS_ToObject(ctx, this_val);
-}
-
-static JSValue js_object_toString(JSContext *ctx, JSValueConst this_val,
-                                  int argc, JSValueConst *argv)
-{
-    JSValue obj, tag;
-    int is_array;
-    JSAtom atom;
-    JSObject *p;
-
-    if (JS_IsNull(this_val)) {
-        tag = JS_NewString(ctx, "Null");
-    } else if (JS_IsUndefined(this_val)) {
-        tag = JS_NewString(ctx, "Undefined");
-    } else {
-        obj = JS_ToObject(ctx, this_val);
-        if (JS_IsException(obj))
-            return obj;
-        is_array = JS_IsArray(ctx, obj);
-        if (is_array < 0) {
-            JS_FreeValue(ctx, obj);
-            return JS_EXCEPTION;
-        }
-        if (is_array) {
-            atom = JS_ATOM_Array;
-        } else if (JS_IsFunction(ctx, obj)) {
-            atom = JS_ATOM_Function;
-        } else {
-            p = JS_VALUE_GET_OBJ(obj);
-            switch(p->class_id) {
-            case JS_CLASS_STRING:
-            case JS_CLASS_ARGUMENTS:
-            case JS_CLASS_MAPPED_ARGUMENTS:
-            case JS_CLASS_ERROR:
-            case JS_CLASS_BOOLEAN:
-            case JS_CLASS_NUMBER:
-            case JS_CLASS_DATE:
-            case JS_CLASS_REGEXP:
-                atom = ctx->rt->class_array[p->class_id].class_name;
-                break;
-            default:
-                atom = JS_ATOM_Object;
-                break;
-            }
-        }
-        tag = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_toStringTag);
-        JS_FreeValue(ctx, obj);
-        if (JS_IsException(tag))
-            return JS_EXCEPTION;
-        if (!JS_IsString(tag)) {
-            JS_FreeValue(ctx, tag);
-            tag = JS_AtomToString(ctx, atom);
-        }
-    }
-    return JS_ConcatString3(ctx, "[object ", tag, "]");
-}
-
-static JSValue js_object_toLocaleString(JSContext *ctx, JSValueConst this_val,
-                                        int argc, JSValueConst *argv)
-{
-    return JS_Invoke(ctx, this_val, JS_ATOM_toString, 0, NULL);
-}
-
-static JSValue js_object_assign(JSContext *ctx, JSValueConst this_val,
-                                int argc, JSValueConst *argv)
-{
-    // Object.assign(obj, source1)
-    JSValue obj, s;
-    int i;
-
-    s = JS_UNDEFINED;
-    obj = JS_ToObject(ctx, argv[0]);
-    if (JS_IsException(obj))
-        goto exception;
-    for (i = 1; i < argc; i++) {
-        if (!JS_IsNull(argv[i]) && !JS_IsUndefined(argv[i])) {
-            s = JS_ToObject(ctx, argv[i]);
-            if (JS_IsException(s))
-                goto exception;
-            if (JS_CopyDataProperties(ctx, obj, s, JS_UNDEFINED, TRUE))
-                goto exception;
-            JS_FreeValue(ctx, s);
-        }
-    }
-    return obj;
-exception:
-    JS_FreeValue(ctx, obj);
-    JS_FreeValue(ctx, s);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_object_seal(JSContext *ctx, JSValueConst this_val,
-                              int argc, JSValueConst *argv, int freeze_flag)
-{
-    JSValueConst obj = argv[0];
-    JSObject *p;
-    JSPropertyEnum *props;
-    uint32_t len, i;
-    int flags, desc_flags, res;
-
-    if (!JS_IsObject(obj))
-        return JS_DupValue(ctx, obj);
-
-    res = JS_PreventExtensions(ctx, obj);
-    if (res < 0)
-        return JS_EXCEPTION;
-    if (!res) {
-        return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
-    }
-    
-    p = JS_VALUE_GET_OBJ(obj);
-    flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK;
-    if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags))
-        return JS_EXCEPTION;
-
-    for(i = 0; i < len; i++) {
-        JSPropertyDescriptor desc;
-        JSAtom prop = props[i].atom;
-
-        desc_flags = JS_PROP_THROW | JS_PROP_HAS_CONFIGURABLE;
-        if (freeze_flag) {
-            res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
-            if (res < 0)
-                goto exception;
-            if (res) {
-                if (desc.flags & JS_PROP_WRITABLE)
-                    desc_flags |= JS_PROP_HAS_WRITABLE;
-                js_free_desc(ctx, &desc);
-            }
-        }
-        if (JS_DefineProperty(ctx, obj, prop, JS_UNDEFINED,
-                              JS_UNDEFINED, JS_UNDEFINED, desc_flags) < 0)
-            goto exception;
-    }
-    js_free_prop_enum(ctx, props, len);
-    return JS_DupValue(ctx, obj);
-
- exception:
-    js_free_prop_enum(ctx, props, len);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val,
-                                  int argc, JSValueConst *argv, int is_frozen)
-{
-    JSValueConst obj = argv[0];
-    JSObject *p;
-    JSPropertyEnum *props;
-    uint32_t len, i;
-    int flags, res;
-    
-    if (!JS_IsObject(obj))
-        return JS_TRUE;
-
-    p = JS_VALUE_GET_OBJ(obj);
-    flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK;
-    if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags))
-        return JS_EXCEPTION;
-
-    for(i = 0; i < len; i++) {
-        JSPropertyDescriptor desc;
-        JSAtom prop = props[i].atom;
-
-        res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
-        if (res < 0)
-            goto exception;
-        if (res) {
-            js_free_desc(ctx, &desc);
-            if ((desc.flags & JS_PROP_CONFIGURABLE)
-            ||  (is_frozen && (desc.flags & JS_PROP_WRITABLE))) {
-                res = FALSE;
-                goto done;
-            }
-        }
-    }
-    res = JS_IsExtensible(ctx, obj);
-    if (res < 0)
-        return JS_EXCEPTION;
-    res ^= 1;
-done:        
-    js_free_prop_enum(ctx, props, len);
-    return JS_NewBool(ctx, res);
-
-exception:
-    js_free_prop_enum(ctx, props, len);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val,
-                                     int argc, JSValueConst *argv)
-{
-    JSValue obj, iter, next_method = JS_UNDEFINED;
-    JSValueConst iterable;
-    BOOL done;
-
-    /*  RequireObjectCoercible() not necessary because it is tested in
-        JS_GetIterator() by JS_GetProperty() */
-    iterable = argv[0];
-
-    obj = JS_NewObject(ctx);
-    if (JS_IsException(obj))
-        return obj;
-    
-    iter = JS_GetIterator(ctx, iterable, FALSE);
-    if (JS_IsException(iter))
-        goto fail;
-    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
-    if (JS_IsException(next_method))
-        goto fail;
-    
-    for(;;) {
-        JSValue key, value, item;
-        item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
-        if (JS_IsException(item))
-            goto fail;
-        if (done) {
-            JS_FreeValue(ctx, item);
-            break;
-        }
-        
-        key = JS_UNDEFINED;
-        value = JS_UNDEFINED;
-        if (!JS_IsObject(item)) {
-            JS_ThrowTypeErrorNotAnObject(ctx);
-            goto fail1;
-        }
-        key = JS_GetPropertyUint32(ctx, item, 0);
-        if (JS_IsException(key))
-            goto fail1;
-        value = JS_GetPropertyUint32(ctx, item, 1);
-        if (JS_IsException(value)) {
-            JS_FreeValue(ctx, key);
-            goto fail1;
-        }
-        if (JS_DefinePropertyValueValue(ctx, obj, key, value,
-                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0) {
-        fail1:
-            JS_FreeValue(ctx, item);
-            goto fail;
-        }
-        JS_FreeValue(ctx, item);
-    }
-    JS_FreeValue(ctx, next_method);
-    JS_FreeValue(ctx, iter);
-    return obj;
- fail:
-    if (JS_IsObject(iter)) {
-        /* close the iterator object, preserving pending exception */
-        JS_IteratorClose(ctx, iter, TRUE);
-    }
-    JS_FreeValue(ctx, next_method);
-    JS_FreeValue(ctx, iter);
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-#if 0
-/* Note: corresponds to ECMA spec: CreateDataPropertyOrThrow() */
-static JSValue js_object___setOwnProperty(JSContext *ctx, JSValueConst this_val,
-                                          int argc, JSValueConst *argv)
-{
-    int ret;
-    ret = JS_DefinePropertyValueValue(ctx, argv[0], JS_DupValue(ctx, argv[1]),
-                                      JS_DupValue(ctx, argv[2]),
-                                      JS_PROP_C_W_E | JS_PROP_THROW);
-    if (ret < 0)
-        return JS_EXCEPTION;
-    else
-        return JS_NewBool(ctx, ret);
-}
-
-static JSValue js_object___toObject(JSContext *ctx, JSValueConst this_val,
-                                    int argc, JSValueConst *argv)
-{
-    return JS_ToObject(ctx, argv[0]);
-}
-
-static JSValue js_object___toPrimitive(JSContext *ctx, JSValueConst this_val,
-                                       int argc, JSValueConst *argv)
-{
-    int hint = HINT_NONE;
-
-    if (JS_VALUE_GET_TAG(argv[1]) == JS_TAG_INT)
-        hint = JS_VALUE_GET_INT(argv[1]);
-
-    return JS_ToPrimitive(ctx, argv[0], hint);
-}
-#endif
-
-/* return an empty string if not an object */
-static JSValue js_object___getClass(JSContext *ctx, JSValueConst this_val,
-                                    int argc, JSValueConst *argv)
-{
-    JSAtom atom;
-    JSObject *p;
-    uint32_t tag;
-    int class_id;
-
-    tag = JS_VALUE_GET_NORM_TAG(argv[0]);
-    if (tag == JS_TAG_OBJECT) {
-        p = JS_VALUE_GET_OBJ(argv[0]);
-        class_id = p->class_id;
-        if (class_id == JS_CLASS_PROXY && JS_IsFunction(ctx, argv[0]))
-            class_id = JS_CLASS_BYTECODE_FUNCTION;
-        atom = ctx->rt->class_array[class_id].class_name;
-    } else {
-        atom = JS_ATOM_empty_string;
-    }
-    return JS_AtomToString(ctx, atom);
-}
-
-static JSValue js_object_is(JSContext *ctx, JSValueConst this_val,
-                            int argc, JSValueConst *argv)
-{
-    return JS_NewBool(ctx, js_same_value(ctx, argv[0], argv[1]));
-}
-
-#if 0
-static JSValue js_object___getObjectData(JSContext *ctx, JSValueConst this_val,
-                                         int argc, JSValueConst *argv)
-{
-    return JS_GetObjectData(ctx, argv[0]);
-}
-
-static JSValue js_object___setObjectData(JSContext *ctx, JSValueConst this_val,
-                                         int argc, JSValueConst *argv)
-{
-    if (JS_SetObjectData(ctx, argv[0], JS_DupValue(ctx, argv[1])))
-        return JS_EXCEPTION;
-    return JS_DupValue(ctx, argv[1]);
-}
-
-static JSValue js_object___toPropertyKey(JSContext *ctx, JSValueConst this_val,
-                                         int argc, JSValueConst *argv)
-{
-    return JS_ToPropertyKey(ctx, argv[0]);
-}
-
-static JSValue js_object___isObject(JSContext *ctx, JSValueConst this_val,
-                                    int argc, JSValueConst *argv)
-{
-    return JS_NewBool(ctx, JS_IsObject(argv[0]));
-}
-
-static JSValue js_object___isSameValueZero(JSContext *ctx, JSValueConst this_val,
-                                           int argc, JSValueConst *argv)
-{
-    return JS_NewBool(ctx, js_same_value_zero(ctx, argv[0], argv[1]));
-}
-
-static JSValue js_object___isConstructor(JSContext *ctx, JSValueConst this_val,
-                                         int argc, JSValueConst *argv)
-{
-    return JS_NewBool(ctx, JS_IsConstructor(ctx, argv[0]));
-}
-#endif
-
-static JSValue JS_SpeciesConstructor(JSContext *ctx, JSValueConst obj,
-                                     JSValueConst defaultConstructor)
-{
-    JSValue ctor, species;
-
-    if (!JS_IsObject(obj))
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-    ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);
-    if (JS_IsException(ctor))
-        return ctor;
-    if (JS_IsUndefined(ctor))
-        return JS_DupValue(ctx, defaultConstructor);
-    if (!JS_IsObject(ctor)) {
-        JS_FreeValue(ctx, ctor);
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-    }
-    species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species);
-    JS_FreeValue(ctx, ctor);
-    if (JS_IsException(species))
-        return species;
-    if (JS_IsUndefined(species) || JS_IsNull(species))
-        return JS_DupValue(ctx, defaultConstructor);
-    if (!JS_IsConstructor(ctx, species)) {
-        JS_FreeValue(ctx, species);
-        return JS_ThrowTypeError(ctx, "not a constructor");
-    }
-    return species;
-}
-
-#if 0
-static JSValue js_object___speciesConstructor(JSContext *ctx, JSValueConst this_val,
-                                              int argc, JSValueConst *argv)
-{
-    return JS_SpeciesConstructor(ctx, argv[0], argv[1]);
-}
-#endif
-
-static JSValue js_object_get___proto__(JSContext *ctx, JSValueConst this_val)
-{
-    JSValue val, ret;
-
-    val = JS_ToObject(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    ret = JS_GetPrototype(ctx, val);
-    JS_FreeValue(ctx, val);
-    return ret;
-}
-
-static JSValue js_object_set___proto__(JSContext *ctx, JSValueConst this_val,
-                                       JSValueConst proto)
-{
-    if (JS_IsUndefined(this_val) || JS_IsNull(this_val))
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-    if (!JS_IsObject(proto) && !JS_IsNull(proto))
-        return JS_UNDEFINED;
-    if (JS_SetPrototypeInternal(ctx, this_val, proto, TRUE) < 0)
-        return JS_EXCEPTION;
-    else
-        return JS_UNDEFINED;
-}
-
-static JSValue js_object_isPrototypeOf(JSContext *ctx, JSValueConst this_val,
-                                       int argc, JSValueConst *argv)
-{
-    JSValue obj, v1;
-    JSValueConst v;
-    int res;
-
-    v = argv[0];
-    if (!JS_IsObject(v))
-        return JS_FALSE;
-    obj = JS_ToObject(ctx, this_val);
-    if (JS_IsException(obj))
-        return JS_EXCEPTION;
-    v1 = JS_DupValue(ctx, v);
-    for(;;) {
-        v1 = JS_GetPrototypeFree(ctx, v1);
-        if (JS_IsException(v1))
-            goto exception;
-        if (JS_IsNull(v1)) {
-            res = FALSE;
-            break;
-        }
-        if (JS_VALUE_GET_OBJ(obj) == JS_VALUE_GET_OBJ(v1)) {
-            res = TRUE;
-            break;
-        }
-        /* avoid infinite loop (possible with proxies) */
-        if (js_poll_interrupts(ctx))
-            goto exception;
-    }
-    JS_FreeValue(ctx, v1);
-    JS_FreeValue(ctx, obj);
-    return JS_NewBool(ctx, res);
-
-exception:
-    JS_FreeValue(ctx, v1);
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_object_propertyIsEnumerable(JSContext *ctx, JSValueConst this_val,
-                                              int argc, JSValueConst *argv)
-{
-    JSValue obj, res = JS_EXCEPTION;
-    JSAtom prop = JS_ATOM_NULL;
-    JSPropertyDescriptor desc;
-    int has_prop;
-
-    obj = JS_ToObject(ctx, this_val);
-    if (JS_IsException(obj))
-        goto exception;
-    prop = JS_ValueToAtom(ctx, argv[0]);
-    if (unlikely(prop == JS_ATOM_NULL))
-        goto exception;
-
-    has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);
-    if (has_prop < 0)
-        goto exception;
-    if (has_prop) {
-        res = JS_NewBool(ctx, (desc.flags & JS_PROP_ENUMERABLE) != 0);
-        js_free_desc(ctx, &desc);
-    } else {
-        res = JS_FALSE;
-    }
-
-exception:
-    JS_FreeAtom(ctx, prop);
-    JS_FreeValue(ctx, obj);
-    return res;
-}
-
-static JSValue js_object___lookupGetter__(JSContext *ctx, JSValueConst this_val,
-                                          int argc, JSValueConst *argv, int setter)
-{
-    JSValue obj, res = JS_EXCEPTION;
-    JSAtom prop = JS_ATOM_NULL;
-    JSPropertyDescriptor desc;
-    int has_prop;
-
-    obj = JS_ToObject(ctx, this_val);
-    if (JS_IsException(obj))
-        goto exception;
-    prop = JS_ValueToAtom(ctx, argv[0]);
-    if (unlikely(prop == JS_ATOM_NULL))
-        goto exception;
-
-    for (;;) {
-        has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);
-        if (has_prop < 0)
-            goto exception;
-        if (has_prop) {
-            if (desc.flags & JS_PROP_GETSET)
-                res = JS_DupValue(ctx, setter ? desc.setter : desc.getter);
-            else
-                res = JS_UNDEFINED;
-            js_free_desc(ctx, &desc);
-            break;
-        }
-        obj = JS_GetPrototypeFree(ctx, obj);
-        if (JS_IsException(obj))
-            goto exception;
-        if (JS_IsNull(obj)) {
-            res = JS_UNDEFINED;
-            break;
-        }
-        /* avoid infinite loop (possible with proxies) */
-        if (js_poll_interrupts(ctx))
-            goto exception;
-    }
-
-exception:
-    JS_FreeAtom(ctx, prop);
-    JS_FreeValue(ctx, obj);
-    return res;
-}
-
-static const JSCFunctionListEntry js_object_funcs[] = {
-    JS_CFUNC_DEF("create", 2, js_object_create ),
-    JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 0 ),
-    JS_CFUNC_DEF("setPrototypeOf", 2, js_object_setPrototypeOf ),
-    JS_CFUNC_MAGIC_DEF("defineProperty", 3, js_object_defineProperty, 0 ),
-    JS_CFUNC_DEF("defineProperties", 2, js_object_defineProperties ),
-    JS_CFUNC_DEF("getOwnPropertyNames", 1, js_object_getOwnPropertyNames ),
-    JS_CFUNC_DEF("getOwnPropertySymbols", 1, js_object_getOwnPropertySymbols ),
-    JS_CFUNC_MAGIC_DEF("keys", 1, js_object_keys, JS_ITERATOR_KIND_KEY ),
-    JS_CFUNC_MAGIC_DEF("values", 1, js_object_keys, JS_ITERATOR_KIND_VALUE ),
-    JS_CFUNC_MAGIC_DEF("entries", 1, js_object_keys, JS_ITERATOR_KIND_KEY_AND_VALUE ),
-    JS_CFUNC_MAGIC_DEF("isExtensible", 1, js_object_isExtensible, 0 ),
-    JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 0 ),
-    JS_CFUNC_MAGIC_DEF("getOwnPropertyDescriptor", 2, js_object_getOwnPropertyDescriptor, 0 ),
-    JS_CFUNC_DEF("getOwnPropertyDescriptors", 1, js_object_getOwnPropertyDescriptors ),
-    JS_CFUNC_DEF("is", 2, js_object_is ),
-    JS_CFUNC_DEF("assign", 2, js_object_assign ),
-    JS_CFUNC_MAGIC_DEF("seal", 1, js_object_seal, 0 ),
-    JS_CFUNC_MAGIC_DEF("freeze", 1, js_object_seal, 1 ),
-    JS_CFUNC_MAGIC_DEF("isSealed", 1, js_object_isSealed, 0 ),
-    JS_CFUNC_MAGIC_DEF("isFrozen", 1, js_object_isSealed, 1 ),
-    JS_CFUNC_DEF("__getClass", 1, js_object___getClass ),
-    //JS_CFUNC_DEF("__isObject", 1, js_object___isObject ),
-    //JS_CFUNC_DEF("__isConstructor", 1, js_object___isConstructor ),
-    //JS_CFUNC_DEF("__toObject", 1, js_object___toObject ),
-    //JS_CFUNC_DEF("__setOwnProperty", 3, js_object___setOwnProperty ),
-    //JS_CFUNC_DEF("__toPrimitive", 2, js_object___toPrimitive ),
-    //JS_CFUNC_DEF("__toPropertyKey", 1, js_object___toPropertyKey ),
-    //JS_CFUNC_DEF("__speciesConstructor", 2, js_object___speciesConstructor ),
-    //JS_CFUNC_DEF("__isSameValueZero", 2, js_object___isSameValueZero ),
-    //JS_CFUNC_DEF("__getObjectData", 1, js_object___getObjectData ),
-    //JS_CFUNC_DEF("__setObjectData", 2, js_object___setObjectData ),
-    JS_CFUNC_DEF("fromEntries", 1, js_object_fromEntries ),
-    JS_CFUNC_DEF("hasOwn", 2, js_object_hasOwn ),
-};
-
-static const JSCFunctionListEntry js_object_proto_funcs[] = {
-    JS_CFUNC_DEF("toString", 0, js_object_toString ),
-    JS_CFUNC_DEF("toLocaleString", 0, js_object_toLocaleString ),
-    JS_CFUNC_DEF("valueOf", 0, js_object_valueOf ),
-    JS_CFUNC_DEF("hasOwnProperty", 1, js_object_hasOwnProperty ),
-    JS_CFUNC_DEF("isPrototypeOf", 1, js_object_isPrototypeOf ),
-    JS_CFUNC_DEF("propertyIsEnumerable", 1, js_object_propertyIsEnumerable ),
-    JS_CGETSET_DEF("__proto__", js_object_get___proto__, js_object_set___proto__ ),
-    JS_CFUNC_MAGIC_DEF("__defineGetter__", 2, js_object___defineGetter__, 0 ),
-    JS_CFUNC_MAGIC_DEF("__defineSetter__", 2, js_object___defineGetter__, 1 ),
-    JS_CFUNC_MAGIC_DEF("__lookupGetter__", 1, js_object___lookupGetter__, 0 ),
-    JS_CFUNC_MAGIC_DEF("__lookupSetter__", 1, js_object___lookupGetter__, 1 ),
-};
-
-/* Function class */
-
-static JSValue js_function_proto(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv)
-{
-    return JS_UNDEFINED;
-}
-
-/* XXX: add a specific eval mode so that Function("}), ({") is rejected */
-static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target,
-                                       int argc, JSValueConst *argv, int magic)
-{
-    JSFunctionKindEnum func_kind = magic;
-    int i, n, ret;
-    JSValue s, proto, obj = JS_UNDEFINED;
-    StringBuffer b_s, *b = &b_s;
-
-    string_buffer_init(ctx, b, 0);
-    string_buffer_putc8(b, '(');
-    
-    if (func_kind == JS_FUNC_ASYNC || func_kind == JS_FUNC_ASYNC_GENERATOR) {
-        string_buffer_puts8(b, "async ");
-    }
-    string_buffer_puts8(b, "function");
-
-    if (func_kind == JS_FUNC_GENERATOR || func_kind == JS_FUNC_ASYNC_GENERATOR) {
-        string_buffer_putc8(b, '*');
-    }
-    string_buffer_puts8(b, " anonymous(");
-
-    n = argc - 1;
-    for(i = 0; i < n; i++) {
-        if (i != 0) {
-            string_buffer_putc8(b, ',');
-        }
-        if (string_buffer_concat_value(b, argv[i]))
-            goto fail;
-    }
-    string_buffer_puts8(b, "\n) {\n");
-    if (n >= 0) {
-        if (string_buffer_concat_value(b, argv[n]))
-            goto fail;
-    }
-    string_buffer_puts8(b, "\n})");
-    s = string_buffer_end(b);
-    if (JS_IsException(s))
-        goto fail1;
-
-    obj = JS_EvalObject(ctx, ctx->global_obj, s, JS_EVAL_TYPE_INDIRECT, -1);
-    JS_FreeValue(ctx, s);
-    if (JS_IsException(obj))
-        goto fail1;
-    if (!JS_IsUndefined(new_target)) {
-        /* set the prototype */
-        proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);
-        if (JS_IsException(proto))
-            goto fail1;
-        if (!JS_IsObject(proto)) {
-            JSContext *realm;
-            JS_FreeValue(ctx, proto);
-            realm = JS_GetFunctionRealm(ctx, new_target);
-            if (!realm)
-                goto fail1;
-            proto = JS_DupValue(ctx, realm->class_proto[func_kind_to_class_id[func_kind]]);
-        }
-        ret = JS_SetPrototypeInternal(ctx, obj, proto, TRUE);
-        JS_FreeValue(ctx, proto);
-        if (ret < 0)
-            goto fail1;
-    }
-    return obj;
-
- fail:
-    string_buffer_free(b);
- fail1:
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static __exception int js_get_length32(JSContext *ctx, uint32_t *pres,
-                                       JSValueConst obj)
-{
-    JSValue len_val;
-    len_val = JS_GetProperty(ctx, obj, JS_ATOM_length);
-    if (JS_IsException(len_val)) {
-        *pres = 0;
-        return -1;
-    }
-    return JS_ToUint32Free(ctx, pres, len_val);
-}
-
-static __exception int js_get_length64(JSContext *ctx, int64_t *pres,
-                                       JSValueConst obj)
-{
-    JSValue len_val;
-    len_val = JS_GetProperty(ctx, obj, JS_ATOM_length);
-    if (JS_IsException(len_val)) {
-        *pres = 0;
-        return -1;
-    }
-    return JS_ToLengthFree(ctx, pres, len_val);
-}
-
-static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len)
-{
-    uint32_t i;
-    for(i = 0; i < len; i++) {
-        JS_FreeValue(ctx, tab[i]);
-    }
-    js_free(ctx, tab);
-}
-
-/* XXX: should use ValueArray */
-static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
-                               JSValueConst array_arg)
-{
-    uint32_t len, i;
-    JSValue *tab, ret;
-    JSObject *p;
-
-    if (JS_VALUE_GET_TAG(array_arg) != JS_TAG_OBJECT) {
-        JS_ThrowTypeError(ctx, "not a object");
-        return NULL;
-    }
-    if (js_get_length32(ctx, &len, array_arg))
-        return NULL;
-    if (len > JS_MAX_LOCAL_VARS) {
-        JS_ThrowInternalError(ctx, "too many arguments");
-        return NULL;
-    }
-    /* avoid allocating 0 bytes */
-    tab = js_mallocz(ctx, sizeof(tab[0]) * max_uint32(1, len));
-    if (!tab)
-        return NULL;
-    p = JS_VALUE_GET_OBJ(array_arg);
-    if ((p->class_id == JS_CLASS_ARRAY || p->class_id == JS_CLASS_ARGUMENTS) &&
-        p->fast_array &&
-        len == p->u.array.count) {
-        for(i = 0; i < len; i++) {
-            tab[i] = JS_DupValue(ctx, p->u.array.u.values[i]);
-        }
-    } else {
-        for(i = 0; i < len; i++) {
-            ret = JS_GetPropertyUint32(ctx, array_arg, i);
-            if (JS_IsException(ret)) {
-                free_arg_list(ctx, tab, i);
-                return NULL;
-            }
-            tab[i] = ret;
-        }
-    }
-    *plen = len;
-    return tab;
-}
-
-/* magic value: 0 = normal apply, 1 = apply for constructor, 2 =
-   Reflect.apply */
-static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv, int magic)
-{
-    JSValueConst this_arg, array_arg;
-    uint32_t len;
-    JSValue *tab, ret;
-
-    if (check_function(ctx, this_val))
-        return JS_EXCEPTION;
-    this_arg = argv[0];
-    array_arg = argv[1];
-    if ((JS_VALUE_GET_TAG(array_arg) == JS_TAG_UNDEFINED ||
-         JS_VALUE_GET_TAG(array_arg) == JS_TAG_NULL) && magic != 2) {
-        return JS_Call(ctx, this_val, this_arg, 0, NULL);
-    }
-    tab = build_arg_list(ctx, &len, array_arg);
-    if (!tab)
-        return JS_EXCEPTION;
-    if (magic & 1) {
-        ret = JS_CallConstructor2(ctx, this_val, this_arg, len, (JSValueConst *)tab);
-    } else {
-        ret = JS_Call(ctx, this_val, this_arg, len, (JSValueConst *)tab);
-    }
-    free_arg_list(ctx, tab, len);
-    return ret;
-}
-
-static JSValue js_function_call(JSContext *ctx, JSValueConst this_val,
-                                int argc, JSValueConst *argv)
-{
-    if (argc <= 0) {
-        return JS_Call(ctx, this_val, JS_UNDEFINED, 0, NULL);
-    } else {
-        return JS_Call(ctx, this_val, argv[0], argc - 1, argv + 1);
-    }
-}
-
-static JSValue js_function_bind(JSContext *ctx, JSValueConst this_val,
-                                int argc, JSValueConst *argv)
-{
-    JSBoundFunction *bf;
-    JSValue func_obj, name1, len_val;
-    JSObject *p;
-    int arg_count, i, ret;
-
-    if (check_function(ctx, this_val))
-        return JS_EXCEPTION;
-
-    func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
-                                 JS_CLASS_BOUND_FUNCTION);
-    if (JS_IsException(func_obj))
-        return JS_EXCEPTION;
-    p = JS_VALUE_GET_OBJ(func_obj);
-    p->is_constructor = JS_IsConstructor(ctx, this_val);
-    arg_count = max_int(0, argc - 1);
-    bf = js_malloc(ctx, sizeof(*bf) + arg_count * sizeof(JSValue));
-    if (!bf)
-        goto exception;
-    bf->func_obj = JS_DupValue(ctx, this_val);
-    bf->this_val = JS_DupValue(ctx, argv[0]);
-    bf->argc = arg_count;
-    for(i = 0; i < arg_count; i++) {
-        bf->argv[i] = JS_DupValue(ctx, argv[i + 1]);
-    }
-    p->u.bound_function = bf;
-
-    /* XXX: the spec could be simpler by only using GetOwnProperty */
-    ret = JS_GetOwnProperty(ctx, NULL, this_val, JS_ATOM_length);
-    if (ret < 0)
-        goto exception;
-    if (!ret) {
-        len_val = JS_NewInt32(ctx, 0);
-    } else {
-        len_val = JS_GetProperty(ctx, this_val, JS_ATOM_length);
-        if (JS_IsException(len_val))
-            goto exception;
-        if (JS_VALUE_GET_TAG(len_val) == JS_TAG_INT) {
-            /* most common case */
-            int len1 = JS_VALUE_GET_INT(len_val);
-            if (len1 <= arg_count)
-                len1 = 0;
-            else
-                len1 -= arg_count;
-            len_val = JS_NewInt32(ctx, len1);
-        } else if (JS_VALUE_GET_NORM_TAG(len_val) == JS_TAG_FLOAT64) {
-            double d = JS_VALUE_GET_FLOAT64(len_val);
-            if (isnan(d)) {
-                d = 0.0;
-            } else {
-                d = trunc(d);
-                if (d <= (double)arg_count)
-                    d = 0.0;
-                else
-                    d -= (double)arg_count; /* also converts -0 to +0 */
-            }
-            len_val = JS_NewFloat64(ctx, d);
-        } else {
-            JS_FreeValue(ctx, len_val);
-            len_val = JS_NewInt32(ctx, 0);
-        }
-    }
-    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length,
-                           len_val, JS_PROP_CONFIGURABLE);
-
-    name1 = JS_GetProperty(ctx, this_val, JS_ATOM_name);
-    if (JS_IsException(name1))
-        goto exception;
-    if (!JS_IsString(name1)) {
-        JS_FreeValue(ctx, name1);
-        name1 = JS_AtomToString(ctx, JS_ATOM_empty_string);
-    }
-    name1 = JS_ConcatString3(ctx, "bound ", name1, "");
-    if (JS_IsException(name1))
-        goto exception;
-    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name1,
-                           JS_PROP_CONFIGURABLE);
-    return func_obj;
- exception:
-    JS_FreeValue(ctx, func_obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_function_toString(JSContext *ctx, JSValueConst this_val,
-                                    int argc, JSValueConst *argv)
-{
-    JSObject *p;
-    JSFunctionKindEnum func_kind = JS_FUNC_NORMAL;
-
-    if (check_function(ctx, this_val))
-        return JS_EXCEPTION;
-
-    p = JS_VALUE_GET_OBJ(this_val);
-    if (js_class_has_bytecode(p->class_id)) {
-        JSFunctionBytecode *b = p->u.func.function_bytecode;
-        if (b->has_debug && b->debug.source) {
-            return JS_NewStringLen(ctx, b->debug.source, b->debug.source_len);
-        }
-        func_kind = b->func_kind;
-    }
-    {
-        JSValue name;
-        const char *pref, *suff;
-
-        switch(func_kind) {
-        default:
-        case JS_FUNC_NORMAL:
-            pref = "function ";
-            break;
-        case JS_FUNC_GENERATOR:
-            pref = "function *";
-            break;
-        case JS_FUNC_ASYNC:
-            pref = "async function ";
-            break;
-        case JS_FUNC_ASYNC_GENERATOR:
-            pref = "async function *";
-            break;
-        }
-        suff = "() {\n    [native code]\n}";
-        name = JS_GetProperty(ctx, this_val, JS_ATOM_name);
-        if (JS_IsUndefined(name))
-            name = JS_AtomToString(ctx, JS_ATOM_empty_string);
-        return JS_ConcatString3(ctx, pref, name, suff);
-    }
-}
-
-static JSValue js_function_hasInstance(JSContext *ctx, JSValueConst this_val,
-                                       int argc, JSValueConst *argv)
-{
-    int ret;
-    ret = JS_OrdinaryIsInstanceOf(ctx, argv[0], this_val);
-    if (ret < 0)
-        return JS_EXCEPTION;
-    else
-        return JS_NewBool(ctx, ret);
-}
-
-static const JSCFunctionListEntry js_function_proto_funcs[] = {
-    JS_CFUNC_DEF("call", 1, js_function_call ),
-    JS_CFUNC_MAGIC_DEF("apply", 2, js_function_apply, 0 ),
-    JS_CFUNC_DEF("bind", 1, js_function_bind ),
-    JS_CFUNC_DEF("toString", 0, js_function_toString ),
-    JS_CFUNC_DEF("[Symbol.hasInstance]", 1, js_function_hasInstance ),
-    JS_CGETSET_DEF("fileName", js_function_proto_fileName, NULL ),
-    JS_CGETSET_DEF("lineNumber", js_function_proto_lineNumber, NULL ),
-};
-
-/* Error class */
-
-static JSValue iterator_to_array(JSContext *ctx, JSValueConst items)
-{
-    JSValue iter, next_method = JS_UNDEFINED;
-    JSValue v, r = JS_UNDEFINED;
-    int64_t k;
-    BOOL done;
-    
-    iter = JS_GetIterator(ctx, items, FALSE);
-    if (JS_IsException(iter))
-        goto exception;
-    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
-    if (JS_IsException(next_method))
-        goto exception;
-    r = JS_NewArray(ctx);
-    if (JS_IsException(r))
-        goto exception;
-    for (k = 0;; k++) {
-        v = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
-        if (JS_IsException(v))
-            goto exception_close;
-        if (done)
-            break;
-        if (JS_DefinePropertyValueInt64(ctx, r, k, v,
-                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)
-            goto exception_close;
-    }
- done:
-    JS_FreeValue(ctx, next_method);
-    JS_FreeValue(ctx, iter);
-    return r;
- exception_close:
-    JS_IteratorClose(ctx, iter, TRUE);
- exception:
-    JS_FreeValue(ctx, r);
-    r = JS_EXCEPTION;
-    goto done;
-}
-
-static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target,
-                                    int argc, JSValueConst *argv, int magic)
-{
-    JSValue obj, msg, proto;
-    JSValueConst message;
-
-    if (JS_IsUndefined(new_target))
-        new_target = JS_GetActiveFunction(ctx);
-    proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);
-    if (JS_IsException(proto))
-        return proto;
-    if (!JS_IsObject(proto)) {
-        JSContext *realm;
-        JSValueConst proto1;
-        
-        JS_FreeValue(ctx, proto);
-        realm = JS_GetFunctionRealm(ctx, new_target);
-        if (!realm)
-            return JS_EXCEPTION;
-        if (magic < 0) {
-            proto1 = realm->class_proto[JS_CLASS_ERROR];
-        } else {
-            proto1 = realm->native_error_proto[magic];
-        }
-        proto = JS_DupValue(ctx, proto1);
-    }
-    obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_ERROR);
-    JS_FreeValue(ctx, proto);
-    if (JS_IsException(obj))
-        return obj;
-    if (magic == JS_AGGREGATE_ERROR) {
-        message = argv[1];
-    } else {
-        message = argv[0];
-    }
-
-    if (!JS_IsUndefined(message)) {
-        msg = JS_ToString(ctx, message);
-        if (unlikely(JS_IsException(msg)))
-            goto exception;
-        JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, msg,
-                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-    }
-
-    if (magic == JS_AGGREGATE_ERROR) {
-        JSValue error_list = iterator_to_array(ctx, argv[0]);
-        if (JS_IsException(error_list))
-            goto exception;
-        JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, error_list,
-                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-    }
-
-    /* skip the Error() function in the backtrace */
-    build_backtrace(ctx, obj, NULL, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL);
-    return obj;
- exception:
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_error_toString(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv)
-{
-    JSValue name, msg;
-
-    if (!JS_IsObject(this_val))
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-    name = JS_GetProperty(ctx, this_val, JS_ATOM_name);
-    if (JS_IsUndefined(name))
-        name = JS_AtomToString(ctx, JS_ATOM_Error);
-    else
-        name = JS_ToStringFree(ctx, name);
-    if (JS_IsException(name))
-        return JS_EXCEPTION;
-
-    msg = JS_GetProperty(ctx, this_val, JS_ATOM_message);
-    if (JS_IsUndefined(msg))
-        msg = JS_AtomToString(ctx, JS_ATOM_empty_string);
-    else
-        msg = JS_ToStringFree(ctx, msg);
-    if (JS_IsException(msg)) {
-        JS_FreeValue(ctx, name);
-        return JS_EXCEPTION;
-    }
-    if (!JS_IsEmptyString(name) && !JS_IsEmptyString(msg))
-        name = JS_ConcatString3(ctx, "", name, ": ");
-    return JS_ConcatString(ctx, name, msg);
-}
-
-static const JSCFunctionListEntry js_error_proto_funcs[] = {
-    JS_CFUNC_DEF("toString", 0, js_error_toString ),
-    JS_PROP_STRING_DEF("name", "Error", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
-    JS_PROP_STRING_DEF("message", "", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
-};
-
-/* AggregateError */
-
-/* used by C code. */
-static JSValue js_aggregate_error_constructor(JSContext *ctx,
-                                              JSValueConst errors)
-{
-    JSValue obj;
-    
-    obj = JS_NewObjectProtoClass(ctx,
-                                 ctx->native_error_proto[JS_AGGREGATE_ERROR],
-                                 JS_CLASS_ERROR);
-    if (JS_IsException(obj))
-        return obj;
-    JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, JS_DupValue(ctx, errors),
-                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-    return obj;
-}
-
-/* Array */
-
-static int JS_CopySubArray(JSContext *ctx,
-                           JSValueConst obj, int64_t to_pos,
-                           int64_t from_pos, int64_t count, int dir)
-{
-    JSObject *p;
-    int64_t i, from, to, len;
-    JSValue val;
-    int fromPresent;
-
-    p = NULL;
-    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
-        p = JS_VALUE_GET_OBJ(obj);
-        if (p->class_id != JS_CLASS_ARRAY || !p->fast_array) {
-            p = NULL;
-        }
-    }
-
-    for (i = 0; i < count; ) {
-        if (dir < 0) {
-            from = from_pos + count - i - 1;
-            to = to_pos + count - i - 1;
-        } else {
-            from = from_pos + i;
-            to = to_pos + i;
-        }
-        if (p && p->fast_array &&
-            from >= 0 && from < (len = p->u.array.count)  &&
-            to >= 0 && to < len) {
-            int64_t l, j;
-            /* Fast path for fast arrays. Since we don't look at the
-               prototype chain, we can optimize only the cases where
-               all the elements are present in the array. */
-            l = count - i;
-            if (dir < 0) {
-                l = min_int64(l, from + 1);
-                l = min_int64(l, to + 1);
-                for(j = 0; j < l; j++) {
-                    set_value(ctx, &p->u.array.u.values[to - j],
-                              JS_DupValue(ctx, p->u.array.u.values[from - j]));
-                }
-            } else {
-                l = min_int64(l, len - from);
-                l = min_int64(l, len - to);
-                for(j = 0; j < l; j++) {
-                    set_value(ctx, &p->u.array.u.values[to + j],
-                              JS_DupValue(ctx, p->u.array.u.values[from + j]));
-                }
-            }
-            i += l;
-        } else {
-            fromPresent = JS_TryGetPropertyInt64(ctx, obj, from, &val);
-            if (fromPresent < 0)
-                goto exception;
-            
-            if (fromPresent) {
-                if (JS_SetPropertyInt64(ctx, obj, to, val) < 0)
-                    goto exception;
-            } else {
-                if (JS_DeletePropertyInt64(ctx, obj, to, JS_PROP_THROW) < 0)
-                    goto exception;
-            }
-            i++;
-        }
-    }
-    return 0;
-
- exception:
-    return -1;
-}
-
-static JSValue js_array_constructor(JSContext *ctx, JSValueConst new_target,
-                                    int argc, JSValueConst *argv)
-{
-    JSValue obj;
-    int i;
-
-    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_ARRAY);
-    if (JS_IsException(obj))
-        return obj;
-    if (argc == 1 && JS_IsNumber(argv[0])) {
-        uint32_t len;
-        if (JS_ToArrayLengthFree(ctx, &len, JS_DupValue(ctx, argv[0]), TRUE))
-            goto fail;
-        if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, len)) < 0)
-            goto fail;
-    } else {
-        for(i = 0; i < argc; i++) {
-            if (JS_SetPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i])) < 0)
-                goto fail;
-        }
-    }
-    return obj;
-fail:
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_array_from(JSContext *ctx, JSValueConst this_val,
-                             int argc, JSValueConst *argv)
-{
-    // from(items, mapfn = void 0, this_arg = void 0)
-    JSValueConst items = argv[0], mapfn, this_arg;
-    JSValueConst args[2];
-    JSValue stack[2];
-    JSValue iter, r, v, v2, arrayLike;
-    int64_t k, len;
-    int done, mapping;
-
-    mapping = FALSE;
-    mapfn = JS_UNDEFINED;
-    this_arg = JS_UNDEFINED;
-    r = JS_UNDEFINED;
-    arrayLike = JS_UNDEFINED;
-    stack[0] = JS_UNDEFINED;
-    stack[1] = JS_UNDEFINED;
-
-    if (argc > 1) {
-        mapfn = argv[1];
-        if (!JS_IsUndefined(mapfn)) {
-            if (check_function(ctx, mapfn))
-                goto exception;
-            mapping = 1;
-            if (argc > 2)
-                this_arg = argv[2];
-        }
-    }
-    iter = JS_GetProperty(ctx, items, JS_ATOM_Symbol_iterator);
-    if (JS_IsException(iter))
-        goto exception;
-    if (!JS_IsUndefined(iter)) {
-        JS_FreeValue(ctx, iter);
-        if (JS_IsConstructor(ctx, this_val))
-            r = JS_CallConstructor(ctx, this_val, 0, NULL);
-        else
-            r = JS_NewArray(ctx);
-        if (JS_IsException(r))
-            goto exception;
-        stack[0] = JS_DupValue(ctx, items);
-        if (js_for_of_start(ctx, &stack[1], FALSE))
-            goto exception;
-        for (k = 0;; k++) {
-            v = JS_IteratorNext(ctx, stack[0], stack[1], 0, NULL, &done);
-            if (JS_IsException(v))
-                goto exception_close;
-            if (done)
-                break;
-            if (mapping) {
-                args[0] = v;
-                args[1] = JS_NewInt32(ctx, k);
-                v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
-                JS_FreeValue(ctx, v);
-                v = v2;
-                if (JS_IsException(v))
-                    goto exception_close;
-            }
-            if (JS_DefinePropertyValueInt64(ctx, r, k, v,
-                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)
-                goto exception_close;
-        }
-    } else {
-        arrayLike = JS_ToObject(ctx, items);
-        if (JS_IsException(arrayLike))
-            goto exception;
-        if (js_get_length64(ctx, &len, arrayLike) < 0)
-            goto exception;
-        v = JS_NewInt64(ctx, len);
-        args[0] = v;
-        if (JS_IsConstructor(ctx, this_val)) {
-            r = JS_CallConstructor(ctx, this_val, 1, args);
-        } else {
-            r = js_array_constructor(ctx, JS_UNDEFINED, 1, args);
-        }
-        JS_FreeValue(ctx, v);
-        if (JS_IsException(r))
-            goto exception;
-        for(k = 0; k < len; k++) {
-            v = JS_GetPropertyInt64(ctx, arrayLike, k);
-            if (JS_IsException(v))
-                goto exception;
-            if (mapping) {
-                args[0] = v;
-                args[1] = JS_NewInt32(ctx, k);
-                v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
-                JS_FreeValue(ctx, v);
-                v = v2;
-                if (JS_IsException(v))
-                    goto exception;
-            }
-            if (JS_DefinePropertyValueInt64(ctx, r, k, v,
-                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)
-                goto exception;
-        }
-    }
-    if (JS_SetProperty(ctx, r, JS_ATOM_length, JS_NewUint32(ctx, k)) < 0)
-        goto exception;
-    goto done;
-
- exception_close:
-    if (!JS_IsUndefined(stack[0]))
-        JS_IteratorClose(ctx, stack[0], TRUE);
- exception:
-    JS_FreeValue(ctx, r);
-    r = JS_EXCEPTION;
- done:
-    JS_FreeValue(ctx, arrayLike);
-    JS_FreeValue(ctx, stack[0]);
-    JS_FreeValue(ctx, stack[1]);
-    return r;
-}
-
-static JSValue js_array_of(JSContext *ctx, JSValueConst this_val,
-                           int argc, JSValueConst *argv)
-{
-    JSValue obj, args[1];
-    int i;
-
-    if (JS_IsConstructor(ctx, this_val)) {
-        args[0] = JS_NewInt32(ctx, argc);
-        obj = JS_CallConstructor(ctx, this_val, 1, (JSValueConst *)args);
-    } else {
-        obj = JS_NewArray(ctx);
-    }
-    if (JS_IsException(obj))
-        return JS_EXCEPTION;
-    for(i = 0; i < argc; i++) {
-        if (JS_CreateDataPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i]),
-                                        JS_PROP_THROW) < 0) {
-            goto fail;
-        }
-    }
-    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, argc)) < 0) {
-    fail:
-        JS_FreeValue(ctx, obj);
-        return JS_EXCEPTION;
-    }
-    return obj;
-}
-
-static JSValue js_array_isArray(JSContext *ctx, JSValueConst this_val,
-                                int argc, JSValueConst *argv)
-{
-    int ret;
-    ret = JS_IsArray(ctx, argv[0]);
-    if (ret < 0)
-        return JS_EXCEPTION;
-    else
-        return JS_NewBool(ctx, ret);
-}
-
-static JSValue js_get_this(JSContext *ctx,
-                           JSValueConst this_val)
-{
-    return JS_DupValue(ctx, this_val);
-}
-
-static JSValue JS_ArraySpeciesCreate(JSContext *ctx, JSValueConst obj,
-                                     JSValueConst len_val)
-{
-    JSValue ctor, ret, species;
-    int res;
-    JSContext *realm;
-    
-    res = JS_IsArray(ctx, obj);
-    if (res < 0)
-        return JS_EXCEPTION;
-    if (!res)
-        return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);
-    ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);
-    if (JS_IsException(ctor))
-        return ctor;
-    if (JS_IsConstructor(ctx, ctor)) {
-        /* legacy web compatibility */
-        realm = JS_GetFunctionRealm(ctx, ctor);
-        if (!realm) {
-            JS_FreeValue(ctx, ctor);
-            return JS_EXCEPTION;
-        }
-        if (realm != ctx &&
-            js_same_value(ctx, ctor, realm->array_ctor)) {
-            JS_FreeValue(ctx, ctor);
-            ctor = JS_UNDEFINED;
-        }
-    }
-    if (JS_IsObject(ctor)) {
-        species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species);
-        JS_FreeValue(ctx, ctor);
-        if (JS_IsException(species))
-            return species;
-        ctor = species;
-        if (JS_IsNull(ctor))
-            ctor = JS_UNDEFINED;
-    }
-    if (JS_IsUndefined(ctor)) {
-        return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);
-    } else {
-        ret = JS_CallConstructor(ctx, ctor, 1, &len_val);
-        JS_FreeValue(ctx, ctor);
-        return ret;
-    }
-}
-
-static const JSCFunctionListEntry js_array_funcs[] = {
-    JS_CFUNC_DEF("isArray", 1, js_array_isArray ),
-    JS_CFUNC_DEF("from", 1, js_array_from ),
-    JS_CFUNC_DEF("of", 0, js_array_of ),
-    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
-};
-
-static int JS_isConcatSpreadable(JSContext *ctx, JSValueConst obj)
-{
-    JSValue val;
-
-    if (!JS_IsObject(obj))
-        return FALSE;
-    val = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_isConcatSpreadable);
-    if (JS_IsException(val))
-        return -1;
-    if (!JS_IsUndefined(val))
-        return JS_ToBoolFree(ctx, val);
-    return JS_IsArray(ctx, obj);
-}
-
-static JSValue js_array_concat(JSContext *ctx, JSValueConst this_val,
-                               int argc, JSValueConst *argv)
-{
-    JSValue obj, arr, val;
-    JSValueConst e;
-    int64_t len, k, n;
-    int i, res;
-
-    arr = JS_UNDEFINED;
-    obj = JS_ToObject(ctx, this_val);
-    if (JS_IsException(obj))
-        goto exception;
-
-    arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
-    if (JS_IsException(arr))
-        goto exception;
-    n = 0;
-    for (i = -1; i < argc; i++) {
-        if (i < 0)
-            e = obj;
-        else
-            e = argv[i];
-
-        res = JS_isConcatSpreadable(ctx, e);
-        if (res < 0)
-            goto exception;
-        if (res) {
-            if (js_get_length64(ctx, &len, e))
-                goto exception;
-            if (n + len > MAX_SAFE_INTEGER) {
-                JS_ThrowTypeError(ctx, "Array loo long");
-                goto exception;
-            }
-            for (k = 0; k < len; k++, n++) {
-                res = JS_TryGetPropertyInt64(ctx, e, k, &val);
-                if (res < 0)
-                    goto exception;
-                if (res) {
-                    if (JS_DefinePropertyValueInt64(ctx, arr, n, val,
-                                                    JS_PROP_C_W_E | JS_PROP_THROW) < 0)
-                        goto exception;
-                }
-            }
-        } else {
-            if (n >= MAX_SAFE_INTEGER) {
-                JS_ThrowTypeError(ctx, "Array loo long");
-                goto exception;
-            }
-            if (JS_DefinePropertyValueInt64(ctx, arr, n, JS_DupValue(ctx, e),
-                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)
-                goto exception;
-            n++;
-        }
-    }
-    if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0)
-        goto exception;
-
-    JS_FreeValue(ctx, obj);
-    return arr;
-
-exception:
-    JS_FreeValue(ctx, arr);
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-#define special_every    0
-#define special_some     1
-#define special_forEach  2
-#define special_map      3
-#define special_filter   4
-#define special_TA       8
-
-static int js_typed_array_get_length_internal(JSContext *ctx, JSValueConst obj);
-
-static JSValue js_typed_array___speciesCreate(JSContext *ctx,
-                                              JSValueConst this_val,
-                                              int argc, JSValueConst *argv);
-
-static JSValue js_array_every(JSContext *ctx, JSValueConst this_val,
-                              int argc, JSValueConst *argv, int special)
-{
-    JSValue obj, val, index_val, res, ret;
-    JSValueConst args[3];
-    JSValueConst func, this_arg;
-    int64_t len, k, n;
-    int present;
-
-    ret = JS_UNDEFINED;
-    val = JS_UNDEFINED;
-    if (special & special_TA) {
-        obj = JS_DupValue(ctx, this_val);
-        len = js_typed_array_get_length_internal(ctx, obj);
-        if (len < 0)
-            goto exception;
-    } else {
-        obj = JS_ToObject(ctx, this_val);
-        if (js_get_length64(ctx, &len, obj))
-            goto exception;
-    }
-    func = argv[0];
-    this_arg = JS_UNDEFINED;
-    if (argc > 1)
-        this_arg = argv[1];
-        
-    if (check_function(ctx, func))
-        goto exception;
-
-    switch (special) {
-    case special_every:
-    case special_every | special_TA:
-        ret = JS_TRUE;
-        break;
-    case special_some:
-    case special_some | special_TA:
-        ret = JS_FALSE;
-        break;
-    case special_map:
-        /* XXX: JS_ArraySpeciesCreate should take int64_t */
-        ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt64(ctx, len));
-        if (JS_IsException(ret))
-            goto exception;
-        break;
-    case special_filter:
-        ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
-        if (JS_IsException(ret))
-            goto exception;
-        break;
-    case special_map | special_TA:
-        args[0] = obj;
-        args[1] = JS_NewInt32(ctx, len);
-        ret = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
-        if (JS_IsException(ret))
-            goto exception;
-        break;
-    case special_filter | special_TA:
-        ret = JS_NewArray(ctx);
-        if (JS_IsException(ret))
-            goto exception;
-        break;
-    }
-    n = 0;
-
-    for(k = 0; k < len; k++) {
-        if (special & special_TA) {
-            val = JS_GetPropertyInt64(ctx, obj, k);
-            if (JS_IsException(val))
-                goto exception;
-            present = TRUE;
-        } else {
-            present = JS_TryGetPropertyInt64(ctx, obj, k, &val);
-            if (present < 0)
-                goto exception;
-        }
-        if (present) {
-            index_val = JS_NewInt64(ctx, k);
-            if (JS_IsException(index_val))
-                goto exception;
-            args[0] = val;
-            args[1] = index_val;
-            args[2] = obj;
-            res = JS_Call(ctx, func, this_arg, 3, args);
-            JS_FreeValue(ctx, index_val);
-            if (JS_IsException(res))
-                goto exception;
-            switch (special) {
-            case special_every:
-            case special_every | special_TA:
-                if (!JS_ToBoolFree(ctx, res)) {
-                    ret = JS_FALSE;
-                    goto done;
-                }
-                break;
-            case special_some:
-            case special_some | special_TA:
-                if (JS_ToBoolFree(ctx, res)) {
-                    ret = JS_TRUE;
-                    goto done;
-                }
-                break;
-            case special_map:
-                if (JS_DefinePropertyValueInt64(ctx, ret, k, res,
-                                                JS_PROP_C_W_E | JS_PROP_THROW) < 0)
-                    goto exception;
-                break;
-            case special_map | special_TA:
-                if (JS_SetPropertyValue(ctx, ret, JS_NewInt32(ctx, k), res, JS_PROP_THROW) < 0)
-                    goto exception;
-                break;
-            case special_filter:
-            case special_filter | special_TA:
-                if (JS_ToBoolFree(ctx, res)) {
-                    if (JS_DefinePropertyValueInt64(ctx, ret, n++, JS_DupValue(ctx, val),
-                                                    JS_PROP_C_W_E | JS_PROP_THROW) < 0)
-                        goto exception;
-                }
-                break;
-            default:
-                JS_FreeValue(ctx, res);
-                break;
-            }
-            JS_FreeValue(ctx, val);
-            val = JS_UNDEFINED;
-        }
-    }
-done:
-    if (special == (special_filter | special_TA)) {
-        JSValue arr;
-        args[0] = obj;
-        args[1] = JS_NewInt32(ctx, n);
-        arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
-        if (JS_IsException(arr))
-            goto exception;
-        args[0] = ret;
-        res = JS_Invoke(ctx, arr, JS_ATOM_set, 1, args);
-        if (check_exception_free(ctx, res))
-            goto exception;
-        JS_FreeValue(ctx, ret);
-        ret = arr;
-    }
-    JS_FreeValue(ctx, val);
-    JS_FreeValue(ctx, obj);
-    return ret;
-
-exception:
-    JS_FreeValue(ctx, ret);
-    JS_FreeValue(ctx, val);
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-#define special_reduce       0
-#define special_reduceRight  1
-
-static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val,
-                               int argc, JSValueConst *argv, int special)
-{
-    JSValue obj, val, index_val, acc, acc1;
-    JSValueConst args[4];
-    JSValueConst func;
-    int64_t len, k, k1;
-    int present;
-
-    acc = JS_UNDEFINED;
-    val = JS_UNDEFINED;
-    if (special & special_TA) {
-        obj = JS_DupValue(ctx, this_val);
-        len = js_typed_array_get_length_internal(ctx, obj);
-        if (len < 0)
-            goto exception;
-    } else {
-        obj = JS_ToObject(ctx, this_val);
-        if (js_get_length64(ctx, &len, obj))
-            goto exception;
-    }
-    func = argv[0];
-
-    if (check_function(ctx, func))
-        goto exception;
-
-    k = 0;
-    if (argc > 1) {
-        acc = JS_DupValue(ctx, argv[1]);
-    } else {
-        for(;;) {
-            if (k >= len) {
-                JS_ThrowTypeError(ctx, "empty array");
-                goto exception;
-            }
-            k1 = (special & special_reduceRight) ? len - k - 1 : k;
-            k++;
-            if (special & special_TA) {
-                acc = JS_GetPropertyInt64(ctx, obj, k1);
-                if (JS_IsException(acc))
-                    goto exception;
-                break;
-            } else {
-                present = JS_TryGetPropertyInt64(ctx, obj, k1, &acc);
-                if (present < 0)
-                    goto exception;
-                if (present)
-                    break;
-            }
-        }
-    }
-    for (; k < len; k++) {
-        k1 = (special & special_reduceRight) ? len - k - 1 : k;
-        if (special & special_TA) {
-            val = JS_GetPropertyInt64(ctx, obj, k1);
-            if (JS_IsException(val))
-                goto exception;
-            present = TRUE;
-        } else {
-            present = JS_TryGetPropertyInt64(ctx, obj, k1, &val);
-            if (present < 0)
-                goto exception;
-        }
-        if (present) {
-            index_val = JS_NewInt64(ctx, k1);
-            if (JS_IsException(index_val))
-                goto exception;
-            args[0] = acc;
-            args[1] = val;
-            args[2] = index_val;
-            args[3] = obj;
-            acc1 = JS_Call(ctx, func, JS_UNDEFINED, 4, args);
-            JS_FreeValue(ctx, index_val);
-            JS_FreeValue(ctx, val);
-            val = JS_UNDEFINED;
-            if (JS_IsException(acc1))
-                goto exception;
-            JS_FreeValue(ctx, acc);
-            acc = acc1;
-        }
-    }
-    JS_FreeValue(ctx, obj);
-    return acc;
-
-exception:
-    JS_FreeValue(ctx, acc);
-    JS_FreeValue(ctx, val);
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_array_fill(JSContext *ctx, JSValueConst this_val,
-                             int argc, JSValueConst *argv)
-{
-    JSValue obj;
-    int64_t len, start, end;
-
-    obj = JS_ToObject(ctx, this_val);
-    if (js_get_length64(ctx, &len, obj))
-        goto exception;
-
-    start = 0;
-    if (argc > 1 && !JS_IsUndefined(argv[1])) {
-        if (JS_ToInt64Clamp(ctx, &start, argv[1], 0, len, len))
-            goto exception;
-    }
-
-    end = len;
-    if (argc > 2 && !JS_IsUndefined(argv[2])) {
-        if (JS_ToInt64Clamp(ctx, &end, argv[2], 0, len, len))
-            goto exception;
-    }
-
-    /* XXX: should special case fast arrays */
-    while (start < end) {
-        if (JS_SetPropertyInt64(ctx, obj, start,
-                                JS_DupValue(ctx, argv[0])) < 0)
-            goto exception;
-        start++;
-    }
-    return obj;
-
- exception:
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_array_includes(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv)
-{
-    JSValue obj, val;
-    int64_t len, n, res;
-    JSValue *arrp;
-    uint32_t count;
-
-    obj = JS_ToObject(ctx, this_val);
-    if (js_get_length64(ctx, &len, obj))
-        goto exception;
-
-    res = FALSE;
-    if (len > 0) {
-        n = 0;
-        if (argc > 1) {
-            if (JS_ToInt64Clamp(ctx, &n, argv[1], 0, len, len))
-                goto exception;
-        }
-        if (js_get_fast_array(ctx, obj, &arrp, &count)) {
-            for (; n < count; n++) {
-                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]),
-                                  JS_DupValue(ctx, arrp[n]),
-                                  JS_EQ_SAME_VALUE_ZERO)) {
-                    res = TRUE;
-                    goto done;
-                }
-            }
-        }
-        for (; n < len; n++) {
-            val = JS_GetPropertyInt64(ctx, obj, n);
-            if (JS_IsException(val))
-                goto exception;
-            if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val,
-                              JS_EQ_SAME_VALUE_ZERO)) {
-                res = TRUE;
-                break;
-            }
-        }
-    }
- done:
-    JS_FreeValue(ctx, obj);
-    return JS_NewBool(ctx, res);
-
- exception:
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_array_indexOf(JSContext *ctx, JSValueConst this_val,
-                                int argc, JSValueConst *argv)
-{
-    JSValue obj, val;
-    int64_t len, n, res;
-    JSValue *arrp;
-    uint32_t count;
-
-    obj = JS_ToObject(ctx, this_val);
-    if (js_get_length64(ctx, &len, obj))
-        goto exception;
-
-    res = -1;
-    if (len > 0) {
-        n = 0;
-        if (argc > 1) {
-            if (JS_ToInt64Clamp(ctx, &n, argv[1], 0, len, len))
-                goto exception;
-        }
-        if (js_get_fast_array(ctx, obj, &arrp, &count)) {
-            for (; n < count; n++) {
-                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]),
-                                  JS_DupValue(ctx, arrp[n]), JS_EQ_STRICT)) {
-                    res = n;
-                    goto done;
-                }
-            }
-        }
-        for (; n < len; n++) {
-            int present = JS_TryGetPropertyInt64(ctx, obj, n, &val);
-            if (present < 0)
-                goto exception;
-            if (present) {
-                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_STRICT)) {
-                    res = n;
-                    break;
-                }
-            }
-        }
-    }
- done:
-    JS_FreeValue(ctx, obj);
-    return JS_NewInt64(ctx, res);
-
- exception:
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_array_lastIndexOf(JSContext *ctx, JSValueConst this_val,
-                                    int argc, JSValueConst *argv)
-{
-    JSValue obj, val;
-    int64_t len, n, res;
-    int present;
-
-    obj = JS_ToObject(ctx, this_val);
-    if (js_get_length64(ctx, &len, obj))
-        goto exception;
-
-    res = -1;
-    if (len > 0) {
-        n = len - 1;
-        if (argc > 1) {
-            if (JS_ToInt64Clamp(ctx, &n, argv[1], -1, len - 1, len))
-                goto exception;
-        }
-        /* XXX: should special case fast arrays */
-        for (; n >= 0; n--) {
-            present = JS_TryGetPropertyInt64(ctx, obj, n, &val);
-            if (present < 0)
-                goto exception;
-            if (present) {
-                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_STRICT)) {
-                    res = n;
-                    break;
-                }
-            }
-        }
-    }
-    JS_FreeValue(ctx, obj);
-    return JS_NewInt64(ctx, res);
-
- exception:
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_array_find(JSContext *ctx, JSValueConst this_val,
-                             int argc, JSValueConst *argv, int findIndex)
-{
-    JSValueConst func, this_arg;
-    JSValueConst args[3];
-    JSValue obj, val, index_val, res;
-    int64_t len, k;
-
-    index_val = JS_UNDEFINED;
-    val = JS_UNDEFINED;
-    obj = JS_ToObject(ctx, this_val);
-    if (js_get_length64(ctx, &len, obj))
-        goto exception;
-
-    func = argv[0];
-    if (check_function(ctx, func))
-        goto exception;
-
-    this_arg = JS_UNDEFINED;
-    if (argc > 1)
-        this_arg = argv[1];
-
-    for(k = 0; k < len; k++) {
-        index_val = JS_NewInt64(ctx, k);
-        if (JS_IsException(index_val))
-            goto exception;
-        val = JS_GetPropertyValue(ctx, obj, index_val);
-        if (JS_IsException(val))
-            goto exception;
-        args[0] = val;
-        args[1] = index_val;
-        args[2] = this_val;
-        res = JS_Call(ctx, func, this_arg, 3, args);
-        if (JS_IsException(res))
-            goto exception;
-        if (JS_ToBoolFree(ctx, res)) {
-            if (findIndex) {
-                JS_FreeValue(ctx, val);
-                JS_FreeValue(ctx, obj);
-                return index_val;
-            } else {
-                JS_FreeValue(ctx, index_val);
-                JS_FreeValue(ctx, obj);
-                return val;
-            }
-        }
-        JS_FreeValue(ctx, val);
-        JS_FreeValue(ctx, index_val);
-    }
-    JS_FreeValue(ctx, obj);
-    if (findIndex)
-        return JS_NewInt32(ctx, -1);
-    else
-        return JS_UNDEFINED;
-
-exception:
-    JS_FreeValue(ctx, index_val);
-    JS_FreeValue(ctx, val);
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_array_toString(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv)
-{
-    JSValue obj, method, ret;
-
-    obj = JS_ToObject(ctx, this_val);
-    if (JS_IsException(obj))
-        return JS_EXCEPTION;
-    method = JS_GetProperty(ctx, obj, JS_ATOM_join);
-    if (JS_IsException(method)) {
-        ret = JS_EXCEPTION;
-    } else
-    if (!JS_IsFunction(ctx, method)) {
-        /* Use intrinsic Object.prototype.toString */
-        JS_FreeValue(ctx, method);
-        ret = js_object_toString(ctx, obj, 0, NULL);
-    } else {
-        ret = JS_CallFree(ctx, method, obj, 0, NULL);
-    }
-    JS_FreeValue(ctx, obj);
-    return ret;
-}
-
-static JSValue js_array_join(JSContext *ctx, JSValueConst this_val,
-                             int argc, JSValueConst *argv, int toLocaleString)
-{
-    JSValue obj, sep = JS_UNDEFINED, el;
-    StringBuffer b_s, *b = &b_s;
-    JSString *p = NULL;
-    int64_t i, n;
-    int c;
-
-    obj = JS_ToObject(ctx, this_val);
-    if (js_get_length64(ctx, &n, obj))
-        goto exception;
-
-    c = ',';    /* default separator */
-    if (!toLocaleString && argc > 0 && !JS_IsUndefined(argv[0])) {
-        sep = JS_ToString(ctx, argv[0]);
-        if (JS_IsException(sep))
-            goto exception;
-        p = JS_VALUE_GET_STRING(sep);
-        if (p->len == 1 && !p->is_wide_char)
-            c = p->u.str8[0];
-        else
-            c = -1;
-    }
-    string_buffer_init(ctx, b, 0);
-
-    for(i = 0; i < n; i++) {
-        if (i > 0) {
-            if (c >= 0) {
-                string_buffer_putc8(b, c);
-            } else {
-                string_buffer_concat(b, p, 0, p->len);
-            }
-        }
-        el = JS_GetPropertyUint32(ctx, obj, i);
-        if (JS_IsException(el))
-            goto fail;
-        if (!JS_IsNull(el) && !JS_IsUndefined(el)) {
-            if (toLocaleString) {
-                el = JS_ToLocaleStringFree(ctx, el);
-            }
-            if (string_buffer_concat_value_free(b, el))
-                goto fail;
-        }
-    }
-    JS_FreeValue(ctx, sep);
-    JS_FreeValue(ctx, obj);
-    return string_buffer_end(b);
-
-fail:
-    string_buffer_free(b);
-    JS_FreeValue(ctx, sep);
-exception:
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_array_pop(JSContext *ctx, JSValueConst this_val,
-                            int argc, JSValueConst *argv, int shift)
-{
-    JSValue obj, res = JS_UNDEFINED;
-    int64_t len, newLen;
-    JSValue *arrp;
-    uint32_t count32;
-
-    obj = JS_ToObject(ctx, this_val);
-    if (js_get_length64(ctx, &len, obj))
-        goto exception;
-    newLen = 0;
-    if (len > 0) {
-        newLen = len - 1;
-        /* Special case fast arrays */
-        if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
-            JSObject *p = JS_VALUE_GET_OBJ(obj);
-            if (shift) {
-                res = arrp[0];
-                memmove(arrp, arrp + 1, (count32 - 1) * sizeof(*arrp));
-                p->u.array.count--;
-            } else {
-                res = arrp[count32 - 1];
-                p->u.array.count--;
-            }
-        } else {
-            if (shift) {
-                res = JS_GetPropertyInt64(ctx, obj, 0);
-                if (JS_IsException(res))
-                    goto exception;
-                if (JS_CopySubArray(ctx, obj, 0, 1, len - 1, +1))
-                    goto exception;
-            } else {
-                res = JS_GetPropertyInt64(ctx, obj, newLen);
-                if (JS_IsException(res))
-                    goto exception;
-            }
-            if (JS_DeletePropertyInt64(ctx, obj, newLen, JS_PROP_THROW) < 0)
-                goto exception;
-        }
-    }
-    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
-        goto exception;
-
-    JS_FreeValue(ctx, obj);
-    return res;
-
- exception:
-    JS_FreeValue(ctx, res);
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_array_push(JSContext *ctx, JSValueConst this_val,
-                             int argc, JSValueConst *argv, int unshift)
-{
-    JSValue obj;
-    int i;
-    int64_t len, from, newLen;
-
-    obj = JS_ToObject(ctx, this_val);
-    if (js_get_length64(ctx, &len, obj))
-        goto exception;
-    newLen = len + argc;
-    if (newLen > MAX_SAFE_INTEGER) {
-        JS_ThrowTypeError(ctx, "Array loo long");
-        goto exception;
-    }
-    from = len;
-    if (unshift && argc > 0) {
-        if (JS_CopySubArray(ctx, obj, argc, 0, len, -1))
-            goto exception;
-        from = 0;
-    }
-    for(i = 0; i < argc; i++) {
-        if (JS_SetPropertyInt64(ctx, obj, from + i,
-                                JS_DupValue(ctx, argv[i])) < 0)
-            goto exception;
-    }
-    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
-        goto exception;
-
-    JS_FreeValue(ctx, obj);
-    return JS_NewInt64(ctx, newLen);
-
- exception:
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_array_reverse(JSContext *ctx, JSValueConst this_val,
-                                int argc, JSValueConst *argv)
-{
-    JSValue obj, lval, hval;
-    JSValue *arrp;
-    int64_t len, l, h;
-    int l_present, h_present;
-    uint32_t count32;
-
-    lval = JS_UNDEFINED;
-    obj = JS_ToObject(ctx, this_val);
-    if (js_get_length64(ctx, &len, obj))
-        goto exception;
-
-    /* Special case fast arrays */
-    if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
-        uint32_t ll, hh;
-
-        if (count32 > 1) {
-            for (ll = 0, hh = count32 - 1; ll < hh; ll++, hh--) {
-                lval = arrp[ll];
-                arrp[ll] = arrp[hh];
-                arrp[hh] = lval;
-            }
-        }
-        return obj;
-    }
-
-    for (l = 0, h = len - 1; l < h; l++, h--) {
-        l_present = JS_TryGetPropertyInt64(ctx, obj, l, &lval);
-        if (l_present < 0)
-            goto exception;
-        h_present = JS_TryGetPropertyInt64(ctx, obj, h, &hval);
-        if (h_present < 0)
-            goto exception;
-        if (h_present) {
-            if (JS_SetPropertyInt64(ctx, obj, l, hval) < 0)
-                goto exception;
-
-            if (l_present) {
-                if (JS_SetPropertyInt64(ctx, obj, h, lval) < 0) {
-                    lval = JS_UNDEFINED;
-                    goto exception;
-                }
-                lval = JS_UNDEFINED;
-            } else {
-                if (JS_DeletePropertyInt64(ctx, obj, h, JS_PROP_THROW) < 0)
-                    goto exception;
-            }
-        } else {
-            if (l_present) {
-                if (JS_DeletePropertyInt64(ctx, obj, l, JS_PROP_THROW) < 0)
-                    goto exception;
-                if (JS_SetPropertyInt64(ctx, obj, h, lval) < 0) {
-                    lval = JS_UNDEFINED;
-                    goto exception;
-                }
-                lval = JS_UNDEFINED;
-            }
-        }
-    }
-    return obj;
-
- exception:
-    JS_FreeValue(ctx, lval);
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val,
-                              int argc, JSValueConst *argv, int splice)
-{
-    JSValue obj, arr, val, len_val;
-    int64_t len, start, k, final, n, count, del_count, new_len;
-    int kPresent;
-    JSValue *arrp;
-    uint32_t count32, i, item_count;
-
-    arr = JS_UNDEFINED;
-    obj = JS_ToObject(ctx, this_val);
-    if (js_get_length64(ctx, &len, obj))
-        goto exception;
-
-    if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
-        goto exception;
-
-    if (splice) {
-        if (argc == 0) {
-            item_count = 0;
-            del_count = 0;
-        } else
-        if (argc == 1) {
-            item_count = 0;
-            del_count = len - start;
-        } else {
-            item_count = argc - 2;
-            if (JS_ToInt64Clamp(ctx, &del_count, argv[1], 0, len - start, 0))
-                goto exception;
-        }
-        if (len + item_count - del_count > MAX_SAFE_INTEGER) {
-            JS_ThrowTypeError(ctx, "Array loo long");
-            goto exception;
-        }
-        count = del_count;
-    } else {
-        item_count = 0; /* avoid warning */
-        final = len;
-        if (!JS_IsUndefined(argv[1])) {
-            if (JS_ToInt64Clamp(ctx, &final, argv[1], 0, len, len))
-                goto exception;
-        }
-        count = max_int64(final - start, 0);
-    }
-    len_val = JS_NewInt64(ctx, count);
-    arr = JS_ArraySpeciesCreate(ctx, obj, len_val);
-    JS_FreeValue(ctx, len_val);
-    if (JS_IsException(arr))
-        goto exception;
-
-    k = start;
-    final = start + count;
-    n = 0;
-    /* The fast array test on arr ensures that
-       JS_CreateDataPropertyUint32() won't modify obj in case arr is
-       an exotic object */
-    /* Special case fast arrays */
-    if (js_get_fast_array(ctx, obj, &arrp, &count32) &&
-        js_is_fast_array(ctx, arr)) {
-        /* XXX: should share code with fast array constructor */
-        for (; k < final && k < count32; k++, n++) {
-            if (JS_CreateDataPropertyUint32(ctx, arr, n, JS_DupValue(ctx, arrp[k]), JS_PROP_THROW) < 0)
-                goto exception;
-        }
-    }
-    /* Copy the remaining elements if any (handle case of inherited properties) */
-    for (; k < final; k++, n++) {
-        kPresent = JS_TryGetPropertyInt64(ctx, obj, k, &val);
-        if (kPresent < 0)
-            goto exception;
-        if (kPresent) {
-            if (JS_CreateDataPropertyUint32(ctx, arr, n, val, JS_PROP_THROW) < 0)
-                goto exception;
-        }
-    }
-    if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0)
-        goto exception;
-
-    if (splice) {
-        new_len = len + item_count - del_count;
-        if (item_count != del_count) {
-            if (JS_CopySubArray(ctx, obj, start + item_count,
-                                start + del_count, len - (start + del_count),
-                                item_count <= del_count ? +1 : -1) < 0)
-                goto exception;
-
-            for (k = len; k-- > new_len; ) {
-                if (JS_DeletePropertyInt64(ctx, obj, k, JS_PROP_THROW) < 0)
-                    goto exception;
-            }
-        }
-        for (i = 0; i < item_count; i++) {
-            if (JS_SetPropertyInt64(ctx, obj, start + i, JS_DupValue(ctx, argv[i + 2])) < 0)
-                goto exception;
-        }
-        if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, new_len)) < 0)
-            goto exception;
-    }
-    JS_FreeValue(ctx, obj);
-    return arr;
-
- exception:
-    JS_FreeValue(ctx, obj);
-    JS_FreeValue(ctx, arr);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_array_copyWithin(JSContext *ctx, JSValueConst this_val,
-                                   int argc, JSValueConst *argv)
-{
-    JSValue obj;
-    int64_t len, from, to, final, count;
-
-    obj = JS_ToObject(ctx, this_val);
-    if (js_get_length64(ctx, &len, obj))
-        goto exception;
-
-    if (JS_ToInt64Clamp(ctx, &to, argv[0], 0, len, len))
-        goto exception;
-
-    if (JS_ToInt64Clamp(ctx, &from, argv[1], 0, len, len))
-        goto exception;
-
-    final = len;
-    if (argc > 2 && !JS_IsUndefined(argv[2])) {
-        if (JS_ToInt64Clamp(ctx, &final, argv[2], 0, len, len))
-            goto exception;
-    }
-
-    count = min_int64(final - from, len - to);
-
-    if (JS_CopySubArray(ctx, obj, to, from, count,
-                        (from < to && to < from + count) ? -1 : +1))
-        goto exception;
-
-    return obj;
-
- exception:
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static int64_t JS_FlattenIntoArray(JSContext *ctx, JSValueConst target,
-                                   JSValueConst source, int64_t sourceLen,
-                                   int64_t targetIndex, int depth,
-                                   JSValueConst mapperFunction,
-                                   JSValueConst thisArg)
-{
-    JSValue element;
-    int64_t sourceIndex, elementLen;
-    int present, is_array;
-
-    if (js_check_stack_overflow(ctx->rt, 0)) {
-        JS_ThrowStackOverflow(ctx);
-        return -1;
-    }
-
-    for (sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) {
-        present = JS_TryGetPropertyInt64(ctx, source, sourceIndex, &element);
-        if (present < 0)
-            return -1;
-        if (!present)
-            continue;
-        if (!JS_IsUndefined(mapperFunction)) {
-            JSValueConst args[3] = { element, JS_NewInt64(ctx, sourceIndex), source };
-            element = JS_Call(ctx, mapperFunction, thisArg, 3, args);
-            JS_FreeValue(ctx, (JSValue)args[0]);
-            JS_FreeValue(ctx, (JSValue)args[1]);
-            if (JS_IsException(element))
-                return -1;
-        }
-        if (depth > 0) {
-            is_array = JS_IsArray(ctx, element);
-            if (is_array < 0)
-                goto fail;
-            if (is_array) {
-                if (js_get_length64(ctx, &elementLen, element) < 0)
-                    goto fail;
-                targetIndex = JS_FlattenIntoArray(ctx, target, element,
-                                                  elementLen, targetIndex,
-                                                  depth - 1,
-                                                  JS_UNDEFINED, JS_UNDEFINED);
-                if (targetIndex < 0)
-                    goto fail;
-                JS_FreeValue(ctx, element);
-                continue;
-            }
-        }
-        if (targetIndex >= MAX_SAFE_INTEGER) {
-            JS_ThrowTypeError(ctx, "Array too long");
-            goto fail;
-        }
-        if (JS_DefinePropertyValueInt64(ctx, target, targetIndex, element,
-                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)
-            return -1;
-        targetIndex++;
-    }
-    return targetIndex;
-
-fail:
-    JS_FreeValue(ctx, element);
-    return -1;
-}
-
-static JSValue js_array_flatten(JSContext *ctx, JSValueConst this_val,
-                                int argc, JSValueConst *argv, int map)
-{
-    JSValue obj, arr;
-    JSValueConst mapperFunction, thisArg;
-    int64_t sourceLen;
-    int depthNum;
-
-    arr = JS_UNDEFINED;
-    obj = JS_ToObject(ctx, this_val);
-    if (js_get_length64(ctx, &sourceLen, obj))
-        goto exception;
-
-    depthNum = 1;
-    mapperFunction = JS_UNDEFINED;
-    thisArg = JS_UNDEFINED;
-    if (map) {
-        mapperFunction = argv[0];
-        if (argc > 1) {
-            thisArg = argv[1];
-        }
-        if (check_function(ctx, mapperFunction))
-            goto exception;
-    } else {
-        if (argc > 0 && !JS_IsUndefined(argv[0])) {
-            if (JS_ToInt32Sat(ctx, &depthNum, argv[0]) < 0)
-                goto exception;
-        }
-    }
-    arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
-    if (JS_IsException(arr))
-        goto exception;
-    if (JS_FlattenIntoArray(ctx, arr, obj, sourceLen, 0, depthNum,
-                            mapperFunction, thisArg) < 0)
-        goto exception;
-    JS_FreeValue(ctx, obj);
-    return arr;
-
-exception:
-    JS_FreeValue(ctx, obj);
-    JS_FreeValue(ctx, arr);
-    return JS_EXCEPTION;
-}
-
-/* Array sort */
-
-typedef struct ValueSlot {
-    JSValue val;
-    JSString *str;
-    int64_t pos;
-} ValueSlot;
-
-struct array_sort_context {
-    JSContext *ctx;
-    int exception;
-    int has_method;
-    JSValueConst method;
-};
-
-static int js_array_cmp_generic(const void *a, const void *b, void *opaque) {
-    struct array_sort_context *psc = opaque;
-    JSContext *ctx = psc->ctx;
-    JSValueConst argv[2];
-    JSValue res;
-    ValueSlot *ap = (ValueSlot *)(void *)a;
-    ValueSlot *bp = (ValueSlot *)(void *)b;
-    int cmp;
-
-    if (psc->exception)
-        return 0;
-
-    if (psc->has_method) {
-        /* custom sort function is specified as returning 0 for identical
-         * objects: avoid method call overhead.
-         */
-        if (!memcmp(&ap->val, &bp->val, sizeof(ap->val)))
-            goto cmp_same;
-        argv[0] = ap->val;
-        argv[1] = bp->val;
-        res = JS_Call(ctx, psc->method, JS_UNDEFINED, 2, argv);
-        if (JS_IsException(res))
-            goto exception;
-        if (JS_VALUE_GET_TAG(res) == JS_TAG_INT) {
-            int val = JS_VALUE_GET_INT(res);
-            cmp = (val > 0) - (val < 0);
-        } else {
-            double val;
-            if (JS_ToFloat64Free(ctx, &val, res) < 0)
-                goto exception;
-            cmp = (val > 0) - (val < 0);
-        }
-    } else {
-        /* Not supposed to bypass ToString even for identical objects as
-         * tested in test262/test/built-ins/Array/prototype/sort/bug_596_1.js
-         */
-        if (!ap->str) {
-            JSValue str = JS_ToString(ctx, ap->val);
-            if (JS_IsException(str))
-                goto exception;
-            ap->str = JS_VALUE_GET_STRING(str);
-        }
-        if (!bp->str) {
-            JSValue str = JS_ToString(ctx, bp->val);
-            if (JS_IsException(str))
-                goto exception;
-            bp->str = JS_VALUE_GET_STRING(str);
-        }
-        cmp = js_string_compare(ctx, ap->str, bp->str);
-    }
-    if (cmp != 0)
-        return cmp;
-cmp_same:
-    /* make sort stable: compare array offsets */
-    return (ap->pos > bp->pos) - (ap->pos < bp->pos);
-
-exception:
-    psc->exception = 1;
-    return 0;
-}
-
-static JSValue js_array_sort(JSContext *ctx, JSValueConst this_val,
-                             int argc, JSValueConst *argv)
-{
-    struct array_sort_context asc = { ctx, 0, 0, argv[0] };
-    JSValue obj = JS_UNDEFINED;
-    ValueSlot *array = NULL;
-    size_t array_size = 0, pos = 0, n = 0;
-    int64_t i, len, undefined_count = 0;
-    int present;
-
-    if (!JS_IsUndefined(asc.method)) {
-        if (check_function(ctx, asc.method))
-            goto exception;
-        asc.has_method = 1;
-    }
-    obj = JS_ToObject(ctx, this_val);
-    if (js_get_length64(ctx, &len, obj))
-        goto exception;
-
-    /* XXX: should special case fast arrays */
-    for (i = 0; i < len; i++) {
-        if (pos >= array_size) {
-            size_t new_size, slack;
-            ValueSlot *new_array;
-            new_size = (array_size + (array_size >> 1) + 31) & ~15;
-            new_array = js_realloc2(ctx, array, new_size * sizeof(*array), &slack);
-            if (new_array == NULL)
-                goto exception;
-            new_size += slack / sizeof(*new_array);
-            array = new_array;
-            array_size = new_size;
-        }
-        present = JS_TryGetPropertyInt64(ctx, obj, i, &array[pos].val);
-        if (present < 0)
-            goto exception;
-        if (present == 0)
-            continue;
-        if (JS_IsUndefined(array[pos].val)) {
-            undefined_count++;
-            continue;
-        }
-        array[pos].str = NULL;
-        array[pos].pos = i;
-        pos++;
-    }
-    rqsort(array, pos, sizeof(*array), js_array_cmp_generic, &asc);
-    if (asc.exception)
-        goto exception;
-
-    /* XXX: should special case fast arrays */
-    while (n < pos) {
-        if (array[n].str)
-            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, array[n].str));
-        if (array[n].pos == n) {
-            JS_FreeValue(ctx, array[n].val);
-        } else {
-            if (JS_SetPropertyInt64(ctx, obj, n, array[n].val) < 0) {
-                n++;
-                goto exception;
-            }
-        }
-        n++;
-    }
-    js_free(ctx, array);
-    for (i = n; undefined_count-- > 0; i++) {
-        if (JS_SetPropertyInt64(ctx, obj, i, JS_UNDEFINED) < 0)
-            goto fail;
-    }
-    for (; i < len; i++) {
-        if (JS_DeletePropertyInt64(ctx, obj, i, JS_PROP_THROW) < 0)
-            goto fail;
-    }
-    return obj;
-
-exception:
-    for (; n < pos; n++) {
-        JS_FreeValue(ctx, array[n].val);
-        if (array[n].str)
-            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, array[n].str));
-    }
-    js_free(ctx, array);
-fail:
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-typedef struct JSArrayIteratorData {
-    JSValue obj;
-    JSIteratorKindEnum kind;
-    uint32_t idx;
-} JSArrayIteratorData;
-
-static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    JSArrayIteratorData *it = p->u.array_iterator_data;
-    if (it) {
-        JS_FreeValueRT(rt, it->obj);
-        js_free_rt(rt, it);
-    }
-}
-
-static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val,
-                                   JS_MarkFunc *mark_func)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    JSArrayIteratorData *it = p->u.array_iterator_data;
-    if (it) {
-        JS_MarkValue(rt, it->obj, mark_func);
-    }
-}
-
-static JSValue js_create_array(JSContext *ctx, int len, JSValueConst *tab)
-{
-    JSValue obj;
-    int i;
-
-    obj = JS_NewArray(ctx);
-    if (JS_IsException(obj))
-        return JS_EXCEPTION;
-    for(i = 0; i < len; i++) {
-        if (JS_CreateDataPropertyUint32(ctx, obj, i, JS_DupValue(ctx, tab[i]), 0) < 0) {
-            JS_FreeValue(ctx, obj);
-            return JS_EXCEPTION;
-        }
-    }
-    return obj;
-}
-
-static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val,
-                                        int argc, JSValueConst *argv, int magic)
-{
-    JSValue enum_obj, arr;
-    JSArrayIteratorData *it;
-    JSIteratorKindEnum kind;
-    int class_id;
-
-    kind = magic & 3;
-    if (magic & 4) {
-        /* string iterator case */
-        arr = JS_ToStringCheckObject(ctx, this_val);
-        class_id = JS_CLASS_STRING_ITERATOR;
-    } else {
-        arr = JS_ToObject(ctx, this_val);
-        class_id = JS_CLASS_ARRAY_ITERATOR;
-    }
-    if (JS_IsException(arr))
-        goto fail;
-    enum_obj = JS_NewObjectClass(ctx, class_id);
-    if (JS_IsException(enum_obj))
-        goto fail;
-    it = js_malloc(ctx, sizeof(*it));
-    if (!it)
-        goto fail1;
-    it->obj = arr;
-    it->kind = kind;
-    it->idx = 0;
-    JS_SetOpaque(enum_obj, it);
-    return enum_obj;
- fail1:
-    JS_FreeValue(ctx, enum_obj);
- fail:
-    JS_FreeValue(ctx, arr);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val,
-                                      int argc, JSValueConst *argv,
-                                      BOOL *pdone, int magic)
-{
-    JSArrayIteratorData *it;
-    uint32_t len, idx;
-    JSValue val, obj;
-    JSObject *p;
-
-    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_ITERATOR);
-    if (!it)
-        goto fail1;
-    if (JS_IsUndefined(it->obj))
-        goto done;
-    p = JS_VALUE_GET_OBJ(it->obj);
-    if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
-        p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
-        if (typed_array_is_detached(ctx, p)) {
-            JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-            goto fail1;
-        }
-        len = p->u.array.count;
-    } else {
-        if (js_get_length32(ctx, &len, it->obj)) {
-        fail1:
-            *pdone = FALSE;
-            return JS_EXCEPTION;
-        }
-    }
-    idx = it->idx;
-    if (idx >= len) {
-        JS_FreeValue(ctx, it->obj);
-        it->obj = JS_UNDEFINED;
-    done:
-        *pdone = TRUE;
-        return JS_UNDEFINED;
-    }
-    it->idx = idx + 1;
-    *pdone = FALSE;
-    if (it->kind == JS_ITERATOR_KIND_KEY) {
-        return JS_NewUint32(ctx, idx);
-    } else {
-        val = JS_GetPropertyUint32(ctx, it->obj, idx);
-        if (JS_IsException(val))
-            return JS_EXCEPTION;
-        if (it->kind == JS_ITERATOR_KIND_VALUE) {
-            return val;
-        } else {
-            JSValueConst args[2];
-            JSValue num;
-            num = JS_NewUint32(ctx, idx);
-            args[0] = num;
-            args[1] = val;
-            obj = js_create_array(ctx, 2, args);
-            JS_FreeValue(ctx, val);
-            JS_FreeValue(ctx, num);
-            return obj;
-        }
-    }
-}
-
-static JSValue js_iterator_proto_iterator(JSContext *ctx, JSValueConst this_val,
-                                          int argc, JSValueConst *argv)
-{
-    return JS_DupValue(ctx, this_val);
-}
-
-static const JSCFunctionListEntry js_iterator_proto_funcs[] = {
-    JS_CFUNC_DEF("[Symbol.iterator]", 0, js_iterator_proto_iterator ),
-};
-
-static const JSCFunctionListEntry js_array_proto_funcs[] = {
-    JS_CFUNC_DEF("concat", 1, js_array_concat ),
-    JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every ),
-    JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some ),
-    JS_CFUNC_MAGIC_DEF("forEach", 1, js_array_every, special_forEach ),
-    JS_CFUNC_MAGIC_DEF("map", 1, js_array_every, special_map ),
-    JS_CFUNC_MAGIC_DEF("filter", 1, js_array_every, special_filter ),
-    JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce ),
-    JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight ),
-    JS_CFUNC_DEF("fill", 1, js_array_fill ),
-    JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, 0 ),
-    JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, 1 ),
-    JS_CFUNC_DEF("indexOf", 1, js_array_indexOf ),
-    JS_CFUNC_DEF("lastIndexOf", 1, js_array_lastIndexOf ),
-    JS_CFUNC_DEF("includes", 1, js_array_includes ),
-    JS_CFUNC_MAGIC_DEF("join", 1, js_array_join, 0 ),
-    JS_CFUNC_DEF("toString", 0, js_array_toString ),
-    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_array_join, 1 ),
-    JS_CFUNC_MAGIC_DEF("pop", 0, js_array_pop, 0 ),
-    JS_CFUNC_MAGIC_DEF("push", 1, js_array_push, 0 ),
-    JS_CFUNC_MAGIC_DEF("shift", 0, js_array_pop, 1 ),
-    JS_CFUNC_MAGIC_DEF("unshift", 1, js_array_push, 1 ),
-    JS_CFUNC_DEF("reverse", 0, js_array_reverse ),
-    JS_CFUNC_DEF("sort", 1, js_array_sort ),
-    JS_CFUNC_MAGIC_DEF("slice", 2, js_array_slice, 0 ),
-    JS_CFUNC_MAGIC_DEF("splice", 2, js_array_slice, 1 ),
-    JS_CFUNC_DEF("copyWithin", 2, js_array_copyWithin ),
-    JS_CFUNC_MAGIC_DEF("flatMap", 1, js_array_flatten, 1 ),
-    JS_CFUNC_MAGIC_DEF("flat", 0, js_array_flatten, 0 ),
-    JS_CFUNC_MAGIC_DEF("values", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE ),
-    JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
-    JS_CFUNC_MAGIC_DEF("keys", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY ),
-    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE ),
-};
-
-static const JSCFunctionListEntry js_array_iterator_proto_funcs[] = {
-    JS_ITERATOR_NEXT_DEF("next", 0, js_array_iterator_next, 0 ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Array Iterator", JS_PROP_CONFIGURABLE ),
-};
-
-/* Number */
-
-static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target,
-                                     int argc, JSValueConst *argv)
-{
-    JSValue val, obj;
-    if (argc == 0) {
-        val = JS_NewInt32(ctx, 0);
-    } else {
-        val = JS_ToNumeric(ctx, argv[0]);
-        if (JS_IsException(val))
-            return val;
-        switch(JS_VALUE_GET_TAG(val)) {
-#ifdef CONFIG_BIGNUM
-        case JS_TAG_BIG_INT:
-        case JS_TAG_BIG_FLOAT:
-            {
-                JSBigFloat *p = JS_VALUE_GET_PTR(val);
-                double d;
-                bf_get_float64(&p->num, &d, BF_RNDN);
-                JS_FreeValue(ctx, val);
-                val = __JS_NewFloat64(ctx, d);
-            }
-            break;
-        case JS_TAG_BIG_DECIMAL:
-            val = JS_ToStringFree(ctx, val);
-            if (JS_IsException(val))
-                return val;
-            val = JS_ToNumberFree(ctx, val);
-            if (JS_IsException(val))
-                return val;
-            break;
-#endif
-        default:
-            break;
-        }
-    }
-    if (!JS_IsUndefined(new_target)) {
-        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_NUMBER);
-        if (!JS_IsException(obj))
-            JS_SetObjectData(ctx, obj, val);
-        return obj;
-    } else {
-        return val;
-    }
-}
-
-#if 0
-static JSValue js_number___toInteger(JSContext *ctx, JSValueConst this_val,
-                                     int argc, JSValueConst *argv)
-{
-    return JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[0]));
-}
-
-static JSValue js_number___toLength(JSContext *ctx, JSValueConst this_val,
-                                    int argc, JSValueConst *argv)
-{
-    int64_t v;
-    if (JS_ToLengthFree(ctx, &v, JS_DupValue(ctx, argv[0])))
-        return JS_EXCEPTION;
-    return JS_NewInt64(ctx, v);
-}
-#endif
-
-static JSValue js_number_isNaN(JSContext *ctx, JSValueConst this_val,
-                               int argc, JSValueConst *argv)
-{
-    if (!JS_IsNumber(argv[0]))
-        return JS_FALSE;
-    return js_global_isNaN(ctx, this_val, argc, argv);
-}
-
-static JSValue js_number_isFinite(JSContext *ctx, JSValueConst this_val,
-                                  int argc, JSValueConst *argv)
-{
-    if (!JS_IsNumber(argv[0]))
-        return JS_FALSE;
-    return js_global_isFinite(ctx, this_val, argc, argv);
-}
-
-static JSValue js_number_isInteger(JSContext *ctx, JSValueConst this_val,
-                                   int argc, JSValueConst *argv)
-{
-    int ret;
-    ret = JS_NumberIsInteger(ctx, argv[0]);
-    if (ret < 0)
-        return JS_EXCEPTION;
-    else
-        return JS_NewBool(ctx, ret);
-}
-
-static JSValue js_number_isSafeInteger(JSContext *ctx, JSValueConst this_val,
-                                       int argc, JSValueConst *argv)
-{
-    double d;
-    if (!JS_IsNumber(argv[0]))
-        return JS_FALSE;
-    if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
-        return JS_EXCEPTION;
-    return JS_NewBool(ctx, is_safe_integer(d));
-}
-
-static const JSCFunctionListEntry js_number_funcs[] = {
-    /* global ParseInt and parseFloat should be defined already or delayed */
-    JS_ALIAS_BASE_DEF("parseInt", "parseInt", 0 ),
-    JS_ALIAS_BASE_DEF("parseFloat", "parseFloat", 0 ),
-    JS_CFUNC_DEF("isNaN", 1, js_number_isNaN ),
-    JS_CFUNC_DEF("isFinite", 1, js_number_isFinite ),
-    JS_CFUNC_DEF("isInteger", 1, js_number_isInteger ),
-    JS_CFUNC_DEF("isSafeInteger", 1, js_number_isSafeInteger ),
-    JS_PROP_DOUBLE_DEF("MAX_VALUE", 1.7976931348623157e+308, 0 ),
-    JS_PROP_DOUBLE_DEF("MIN_VALUE", 5e-324, 0 ),
-    JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ),
-    JS_PROP_DOUBLE_DEF("NEGATIVE_INFINITY", -INFINITY, 0 ),
-    JS_PROP_DOUBLE_DEF("POSITIVE_INFINITY", INFINITY, 0 ),
-    JS_PROP_DOUBLE_DEF("EPSILON", 2.220446049250313e-16, 0 ), /* ES6 */
-    JS_PROP_DOUBLE_DEF("MAX_SAFE_INTEGER", 9007199254740991.0, 0 ), /* ES6 */
-    JS_PROP_DOUBLE_DEF("MIN_SAFE_INTEGER", -9007199254740991.0, 0 ), /* ES6 */
-    //JS_CFUNC_DEF("__toInteger", 1, js_number___toInteger ),
-    //JS_CFUNC_DEF("__toLength", 1, js_number___toLength ),
-};
-
-static JSValue js_thisNumberValue(JSContext *ctx, JSValueConst this_val)
-{
-    if (JS_IsNumber(this_val))
-        return JS_DupValue(ctx, this_val);
-
-    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
-        JSObject *p = JS_VALUE_GET_OBJ(this_val);
-        if (p->class_id == JS_CLASS_NUMBER) {
-            if (JS_IsNumber(p->u.object_data))
-                return JS_DupValue(ctx, p->u.object_data);
-        }
-    }
-    return JS_ThrowTypeError(ctx, "not a number");
-}
-
-static JSValue js_number_valueOf(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv)
-{
-    return js_thisNumberValue(ctx, this_val);
-}
-
-static int js_get_radix(JSContext *ctx, JSValueConst val)
-{
-    int radix;
-    if (JS_ToInt32Sat(ctx, &radix, val))
-        return -1;
-    if (radix < 2 || radix > 36) {
-        JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
-        return -1;
-    }
-    return radix;
-}
-
-static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val,
-                                  int argc, JSValueConst *argv, int magic)
-{
-    JSValue val;
-    int base;
-    double d;
-
-    val = js_thisNumberValue(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    if (magic || JS_IsUndefined(argv[0])) {
-        base = 10;
-    } else {
-        base = js_get_radix(ctx, argv[0]);
-        if (base < 0)
-            goto fail;
-    }
-    if (JS_ToFloat64Free(ctx, &d, val))
-        return JS_EXCEPTION;
-    return js_dtoa(ctx, d, base, 0, JS_DTOA_VAR_FORMAT);
- fail:
-    JS_FreeValue(ctx, val);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_number_toFixed(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv)
-{
-    JSValue val;
-    int f;
-    double d;
-
-    val = js_thisNumberValue(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    if (JS_ToFloat64Free(ctx, &d, val))
-        return JS_EXCEPTION;
-    if (JS_ToInt32Sat(ctx, &f, argv[0]))
-        return JS_EXCEPTION;
-    if (f < 0 || f > 100)
-        return JS_ThrowRangeError(ctx, "invalid number of digits");
-    if (fabs(d) >= 1e21) {
-        return JS_ToStringFree(ctx, __JS_NewFloat64(ctx, d));
-    } else {
-        return js_dtoa(ctx, d, 10, f, JS_DTOA_FRAC_FORMAT);
-    }
-}
-
-static JSValue js_number_toExponential(JSContext *ctx, JSValueConst this_val,
-                                       int argc, JSValueConst *argv)
-{
-    JSValue val;
-    int f, flags;
-    double d;
-
-    val = js_thisNumberValue(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    if (JS_ToFloat64Free(ctx, &d, val))
-        return JS_EXCEPTION;
-    if (JS_ToInt32Sat(ctx, &f, argv[0]))
-        return JS_EXCEPTION;
-    if (!isfinite(d)) {
-        return JS_ToStringFree(ctx,  __JS_NewFloat64(ctx, d));
-    }
-    if (JS_IsUndefined(argv[0])) {
-        flags = 0;
-        f = 0;
-    } else {
-        if (f < 0 || f > 100)
-            return JS_ThrowRangeError(ctx, "invalid number of digits");
-        f++;
-        flags = JS_DTOA_FIXED_FORMAT;
-    }
-    return js_dtoa(ctx, d, 10, f, flags | JS_DTOA_FORCE_EXP);
-}
-
-static JSValue js_number_toPrecision(JSContext *ctx, JSValueConst this_val,
-                                     int argc, JSValueConst *argv)
-{
-    JSValue val;
-    int p;
-    double d;
-
-    val = js_thisNumberValue(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    if (JS_ToFloat64Free(ctx, &d, val))
-        return JS_EXCEPTION;
-    if (JS_IsUndefined(argv[0]))
-        goto to_string;
-    if (JS_ToInt32Sat(ctx, &p, argv[0]))
-        return JS_EXCEPTION;
-    if (!isfinite(d)) {
-    to_string:
-        return JS_ToStringFree(ctx,  __JS_NewFloat64(ctx, d));
-    }
-    if (p < 1 || p > 100)
-        return JS_ThrowRangeError(ctx, "invalid number of digits");
-    return js_dtoa(ctx, d, 10, p, JS_DTOA_FIXED_FORMAT);
-}
-
-static const JSCFunctionListEntry js_number_proto_funcs[] = {
-    JS_CFUNC_DEF("toExponential", 1, js_number_toExponential ),
-    JS_CFUNC_DEF("toFixed", 1, js_number_toFixed ),
-    JS_CFUNC_DEF("toPrecision", 1, js_number_toPrecision ),
-    JS_CFUNC_MAGIC_DEF("toString", 1, js_number_toString, 0 ),
-    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_number_toString, 1 ),
-    JS_CFUNC_DEF("valueOf", 0, js_number_valueOf ),
-};
-
-static JSValue js_parseInt(JSContext *ctx, JSValueConst this_val,
-                           int argc, JSValueConst *argv)
-{
-    const char *str, *p;
-    int radix, flags;
-    JSValue ret;
-
-    str = JS_ToCString(ctx, argv[0]);
-    if (!str)
-        return JS_EXCEPTION;
-    if (JS_ToInt32(ctx, &radix, argv[1])) {
-        JS_FreeCString(ctx, str);
-        return JS_EXCEPTION;
-    }
-    if (radix != 0 && (radix < 2 || radix > 36)) {
-        ret = JS_NAN;
-    } else {
-        p = str;
-        p += skip_spaces(p);
-        flags = ATOD_INT_ONLY | ATOD_ACCEPT_PREFIX_AFTER_SIGN;
-        ret = js_atof(ctx, p, NULL, radix, flags);
-    }
-    JS_FreeCString(ctx, str);
-    return ret;
-}
-
-static JSValue js_parseFloat(JSContext *ctx, JSValueConst this_val,
-                             int argc, JSValueConst *argv)
-{
-    const char *str, *p;
-    JSValue ret;
-
-    str = JS_ToCString(ctx, argv[0]);
-    if (!str)
-        return JS_EXCEPTION;
-    p = str;
-    p += skip_spaces(p);
-    ret = js_atof(ctx, p, NULL, 10, 0);
-    JS_FreeCString(ctx, str);
-    return ret;
-}
-
-/* Boolean */
-static JSValue js_boolean_constructor(JSContext *ctx, JSValueConst new_target,
-                                     int argc, JSValueConst *argv)
-{
-    JSValue val, obj;
-    val = JS_NewBool(ctx, JS_ToBool(ctx, argv[0]));
-    if (!JS_IsUndefined(new_target)) {
-        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_BOOLEAN);
-        if (!JS_IsException(obj))
-            JS_SetObjectData(ctx, obj, val);
-        return obj;
-    } else {
-        return val;
-    }
-}
-
-static JSValue js_thisBooleanValue(JSContext *ctx, JSValueConst this_val)
-{
-    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_BOOL)
-        return JS_DupValue(ctx, this_val);
-
-    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
-        JSObject *p = JS_VALUE_GET_OBJ(this_val);
-        if (p->class_id == JS_CLASS_BOOLEAN) {
-            if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_BOOL)
-                return p->u.object_data;
-        }
-    }
-    return JS_ThrowTypeError(ctx, "not a boolean");
-}
-
-static JSValue js_boolean_toString(JSContext *ctx, JSValueConst this_val,
-                                   int argc, JSValueConst *argv)
-{
-    JSValue val = js_thisBooleanValue(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ?
-                       JS_ATOM_true : JS_ATOM_false);
-}
-
-static JSValue js_boolean_valueOf(JSContext *ctx, JSValueConst this_val,
-                                  int argc, JSValueConst *argv)
-{
-    return js_thisBooleanValue(ctx, this_val);
-}
-
-static const JSCFunctionListEntry js_boolean_proto_funcs[] = {
-    JS_CFUNC_DEF("toString", 0, js_boolean_toString ),
-    JS_CFUNC_DEF("valueOf", 0, js_boolean_valueOf ),
-};
-
-/* String */
-
-static int js_string_get_own_property(JSContext *ctx,
-                                      JSPropertyDescriptor *desc,
-                                      JSValueConst obj, JSAtom prop)
-{
-    JSObject *p;
-    JSString *p1;
-    uint32_t idx, ch;
-
-    /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
-    if (__JS_AtomIsTaggedInt(prop)) {
-        p = JS_VALUE_GET_OBJ(obj);
-        if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
-            p1 = JS_VALUE_GET_STRING(p->u.object_data);
-            idx = __JS_AtomToUInt32(prop);
-            if (idx < p1->len) {
-                if (desc) {
-                    if (p1->is_wide_char)
-                        ch = p1->u.str16[idx];
-                    else
-                        ch = p1->u.str8[idx];
-                    desc->flags = JS_PROP_ENUMERABLE;
-                    desc->value = js_new_string_char(ctx, ch);
-                    desc->getter = JS_UNDEFINED;
-                    desc->setter = JS_UNDEFINED;
-                }
-                return TRUE;
-            }
-        }
-    }
-    return FALSE;
-}
-
-static int js_string_define_own_property(JSContext *ctx,
-                                         JSValueConst this_obj,
-                                         JSAtom prop, JSValueConst val,
-                                         JSValueConst getter,
-                                         JSValueConst setter, int flags)
-{
-    uint32_t idx;
-    JSObject *p;
-    JSString *p1, *p2;
-    
-    if (__JS_AtomIsTaggedInt(prop)) {
-        idx = __JS_AtomToUInt32(prop);
-        p = JS_VALUE_GET_OBJ(this_obj);
-        if (JS_VALUE_GET_TAG(p->u.object_data) != JS_TAG_STRING)
-            goto def;
-        p1 = JS_VALUE_GET_STRING(p->u.object_data);
-        if (idx >= p1->len)
-            goto def;
-        if (!check_define_prop_flags(JS_PROP_ENUMERABLE, flags))
-            goto fail;
-        /* check that the same value is configured */
-        if (flags & JS_PROP_HAS_VALUE) {
-            if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
-                goto fail;
-            p2 = JS_VALUE_GET_STRING(val);
-            if (p2->len != 1)
-                goto fail;
-            if (string_get(p1, idx) != string_get(p2, 0)) {
-            fail:
-                return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
-            }
-        }
-        return TRUE;
-    } else {
-    def:
-        return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter,
-                                 flags | JS_PROP_NO_EXOTIC);
-    }
-}
-
-static int js_string_delete_property(JSContext *ctx,
-                                     JSValueConst obj, JSAtom prop)
-{
-    uint32_t idx;
-
-    if (__JS_AtomIsTaggedInt(prop)) {
-        idx = __JS_AtomToUInt32(prop);
-        if (idx < js_string_obj_get_length(ctx, obj)) {
-            return FALSE;
-        }
-    }
-    return TRUE;
-}
-
-static const JSClassExoticMethods js_string_exotic_methods = {
-    .get_own_property = js_string_get_own_property,
-    .define_own_property = js_string_define_own_property,
-    .delete_property = js_string_delete_property,
-};
-
-static JSValue js_string_constructor(JSContext *ctx, JSValueConst new_target,
-                                     int argc, JSValueConst *argv)
-{
-    JSValue val, obj;
-    if (argc == 0) {
-        val = JS_AtomToString(ctx, JS_ATOM_empty_string);
-    } else {
-        if (JS_IsUndefined(new_target) && JS_IsSymbol(argv[0])) {
-            JSAtomStruct *p = JS_VALUE_GET_PTR(argv[0]);
-            val = JS_ConcatString3(ctx, "Symbol(", JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p)), ")");
-        } else {
-            val = JS_ToString(ctx, argv[0]);
-        }
-        if (JS_IsException(val))
-            return val;
-    }
-    if (!JS_IsUndefined(new_target)) {
-        JSString *p1 = JS_VALUE_GET_STRING(val);
-
-        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_STRING);
-        if (!JS_IsException(obj)) {
-            JS_SetObjectData(ctx, obj, val);
-            JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, JS_NewInt32(ctx, p1->len), 0);
-        }
-        return obj;
-    } else {
-        return val;
-    }
-}
-
-static JSValue js_thisStringValue(JSContext *ctx, JSValueConst this_val)
-{
-    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_STRING)
-        return JS_DupValue(ctx, this_val);
-
-    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
-        JSObject *p = JS_VALUE_GET_OBJ(this_val);
-        if (p->class_id == JS_CLASS_STRING) {
-            if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING)
-                return JS_DupValue(ctx, p->u.object_data);
-        }
-    }
-    return JS_ThrowTypeError(ctx, "not a string");
-}
-
-static JSValue js_string_fromCharCode(JSContext *ctx, JSValueConst this_val,
-                                      int argc, JSValueConst *argv)
-{
-    int i;
-    StringBuffer b_s, *b = &b_s;
-
-    string_buffer_init(ctx, b, argc);
-
-    for(i = 0; i < argc; i++) {
-        int32_t c;
-        if (JS_ToInt32(ctx, &c, argv[i]) || string_buffer_putc16(b, c & 0xffff)) {
-            string_buffer_free(b);
-            return JS_EXCEPTION;
-        }
-    }
-    return string_buffer_end(b);
-}
-
-static JSValue js_string_fromCodePoint(JSContext *ctx, JSValueConst this_val,
-                                       int argc, JSValueConst *argv)
-{
-    double d;
-    int i, c;
-    StringBuffer b_s, *b = &b_s;
-
-    /* XXX: could pre-compute string length if all arguments are JS_TAG_INT */
-
-    if (string_buffer_init(ctx, b, argc))
-        goto fail;
-    for(i = 0; i < argc; i++) {
-        if (JS_VALUE_GET_TAG(argv[i]) == JS_TAG_INT) {
-            c = JS_VALUE_GET_INT(argv[i]);
-            if (c < 0 || c > 0x10ffff)
-                goto range_error;
-        } else {
-            if (JS_ToFloat64(ctx, &d, argv[i]))
-                goto fail;
-            if (d < 0 || d > 0x10ffff || (c = (int)d) != d)
-                goto range_error;
-        }
-        if (string_buffer_putc(b, c))
-            goto fail;
-    }
-    return string_buffer_end(b);
-
- range_error:
-    JS_ThrowRangeError(ctx, "invalid code point");
- fail:
-    string_buffer_free(b);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_string_raw(JSContext *ctx, JSValueConst this_val,
-                             int argc, JSValueConst *argv)
-{
-    // raw(temp,...a)
-    JSValue cooked, val, raw;
-    StringBuffer b_s, *b = &b_s;
-    int64_t i, n;
-
-    string_buffer_init(ctx, b, 0);
-    raw = JS_UNDEFINED;
-    cooked = JS_ToObject(ctx, argv[0]);
-    if (JS_IsException(cooked))
-        goto exception;
-    raw = JS_ToObjectFree(ctx, JS_GetProperty(ctx, cooked, JS_ATOM_raw));
-    if (JS_IsException(raw))
-        goto exception;
-    if (js_get_length64(ctx, &n, raw) < 0)
-        goto exception;
-        
-    for (i = 0; i < n; i++) {
-        val = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, raw, i));
-        if (JS_IsException(val))
-            goto exception;
-        string_buffer_concat_value_free(b, val);
-        if (i < n - 1 && i + 1 < argc) {
-            if (string_buffer_concat_value(b, argv[i + 1]))
-                goto exception;
-        }
-    }
-    JS_FreeValue(ctx, cooked);
-    JS_FreeValue(ctx, raw);
-    return string_buffer_end(b);
-
-exception:
-    JS_FreeValue(ctx, cooked);
-    JS_FreeValue(ctx, raw);
-    string_buffer_free(b);
-    return JS_EXCEPTION;
-}
-
-/* only used in test262 */
-JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv)
-{
-    uint32_t start, end, i, n;
-    StringBuffer b_s, *b = &b_s;
-
-    if (JS_ToUint32(ctx, &start, argv[0]) ||
-        JS_ToUint32(ctx, &end, argv[1]))
-        return JS_EXCEPTION;
-    end = min_uint32(end, 0x10ffff + 1);
-
-    if (start > end) {
-        start = end;
-    }
-    n = end - start;
-    if (end > 0x10000) {
-        n += end - max_uint32(start, 0x10000);
-    }
-    if (string_buffer_init2(ctx, b, n, end >= 0x100))
-        return JS_EXCEPTION;
-    for(i = start; i < end; i++) {
-        string_buffer_putc(b, i);
-    }
-    return string_buffer_end(b);
-}
-
-#if 0
-static JSValue js_string___isSpace(JSContext *ctx, JSValueConst this_val,
-                                   int argc, JSValueConst *argv)
-{
-    int c;
-    if (JS_ToInt32(ctx, &c, argv[0]))
-        return JS_EXCEPTION;
-    return JS_NewBool(ctx, lre_is_space(c));
-}
-#endif
-
-static JSValue js_string_charCodeAt(JSContext *ctx, JSValueConst this_val,
-                                     int argc, JSValueConst *argv)
-{
-    JSValue val, ret;
-    JSString *p;
-    int idx, c;
-
-    val = JS_ToStringCheckObject(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    p = JS_VALUE_GET_STRING(val);
-    if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
-        JS_FreeValue(ctx, val);
-        return JS_EXCEPTION;
-    }
-    if (idx < 0 || idx >= p->len) {
-        ret = JS_NAN;
-    } else {
-        if (p->is_wide_char)
-            c = p->u.str16[idx];
-        else
-            c = p->u.str8[idx];
-        ret = JS_NewInt32(ctx, c);
-    }
-    JS_FreeValue(ctx, val);
-    return ret;
-}
-
-static JSValue js_string_charAt(JSContext *ctx, JSValueConst this_val,
-                                int argc, JSValueConst *argv)
-{
-    JSValue val, ret;
-    JSString *p;
-    int idx, c;
-
-    val = JS_ToStringCheckObject(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    p = JS_VALUE_GET_STRING(val);
-    if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
-        JS_FreeValue(ctx, val);
-        return JS_EXCEPTION;
-    }
-    if (idx < 0 || idx >= p->len) {
-        ret = js_new_string8(ctx, NULL, 0);
-    } else {
-        if (p->is_wide_char)
-            c = p->u.str16[idx];
-        else
-            c = p->u.str8[idx];
-        ret = js_new_string_char(ctx, c);
-    }
-    JS_FreeValue(ctx, val);
-    return ret;
-}
-
-static JSValue js_string_codePointAt(JSContext *ctx, JSValueConst this_val,
-                                     int argc, JSValueConst *argv)
-{
-    JSValue val, ret;
-    JSString *p;
-    int idx, c;
-
-    val = JS_ToStringCheckObject(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    p = JS_VALUE_GET_STRING(val);
-    if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
-        JS_FreeValue(ctx, val);
-        return JS_EXCEPTION;
-    }
-    if (idx < 0 || idx >= p->len) {
-        ret = JS_UNDEFINED;
-    } else {
-        c = string_getc(p, &idx);
-        ret = JS_NewInt32(ctx, c);
-    }
-    JS_FreeValue(ctx, val);
-    return ret;
-}
-
-static JSValue js_string_concat(JSContext *ctx, JSValueConst this_val,
-                                int argc, JSValueConst *argv)
-{
-    JSValue r;
-    int i;
-
-    /* XXX: Use more efficient method */
-    /* XXX: This method is OK if r has a single refcount */
-    /* XXX: should use string_buffer? */
-    r = JS_ToStringCheckObject(ctx, this_val);
-    for (i = 0; i < argc; i++) {
-        if (JS_IsException(r))
-            break;
-        r = JS_ConcatString(ctx, r, JS_DupValue(ctx, argv[i]));
-    }
-    return r;
-}
-
-static int string_cmp(JSString *p1, JSString *p2, int x1, int x2, int len)
-{
-    int i, c1, c2;
-    for (i = 0; i < len; i++) {
-        if ((c1 = string_get(p1, x1 + i)) != (c2 = string_get(p2, x2 + i)))
-            return c1 - c2;
-    }
-    return 0;
-}
-
-static int string_indexof_char(JSString *p, int c, int from)
-{
-    /* assuming 0 <= from <= p->len */
-    int i, len = p->len;
-    if (p->is_wide_char) {
-        for (i = from; i < len; i++) {
-            if (p->u.str16[i] == c)
-                return i;
-        }
-    } else {
-        if ((c & ~0xff) == 0) {
-            for (i = from; i < len; i++) {
-                if (p->u.str8[i] == (uint8_t)c)
-                    return i;
-            }
-        }
-    }
-    return -1;
-}
-
-static int string_indexof(JSString *p1, JSString *p2, int from)
-{
-    /* assuming 0 <= from <= p1->len */
-    int c, i, j, len1 = p1->len, len2 = p2->len;
-    if (len2 == 0)
-        return from;
-    for (i = from, c = string_get(p2, 0); i + len2 <= len1; i = j + 1) {
-        j = string_indexof_char(p1, c, i);
-        if (j < 0 || j + len2 > len1)
-            break;
-        if (!string_cmp(p1, p2, j + 1, 1, len2 - 1))
-            return j;
-    }
-    return -1;
-}
-
-static int64_t string_advance_index(JSString *p, int64_t index, BOOL unicode)
-{
-    if (!unicode || index >= p->len || !p->is_wide_char) {
-        index++;
-    } else {
-        int index32 = (int)index;
-        string_getc(p, &index32);
-        index = index32;
-    }
-    return index;
-}
-
-static JSValue js_string_indexOf(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv, int lastIndexOf)
-{
-    JSValue str, v;
-    int i, len, v_len, pos, start, stop, ret, inc;
-    JSString *p;
-    JSString *p1;
-
-    str = JS_ToStringCheckObject(ctx, this_val);
-    if (JS_IsException(str))
-        return str;
-    v = JS_ToString(ctx, argv[0]);
-    if (JS_IsException(v))
-        goto fail;
-    p = JS_VALUE_GET_STRING(str);
-    p1 = JS_VALUE_GET_STRING(v);
-    len = p->len;
-    v_len = p1->len;
-    if (lastIndexOf) {
-        pos = len - v_len;
-        if (argc > 1) {
-            double d;
-            if (JS_ToFloat64(ctx, &d, argv[1]))
-                goto fail;
-            if (!isnan(d)) {
-                if (d <= 0)
-                    pos = 0;
-                else if (d < pos)
-                    pos = d;
-            }
-        }
-        start = pos;
-        stop = 0;
-        inc = -1;
-    } else {
-        pos = 0;
-        if (argc > 1) {
-            if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0))
-                goto fail;
-        }
-        start = pos;
-        stop = len - v_len;
-        inc = 1;
-    }
-    ret = -1;
-    if (len >= v_len && inc * (stop - start) >= 0) {
-        for (i = start;; i += inc) {
-            if (!string_cmp(p, p1, i, 0, v_len)) {
-                ret = i;
-                break;
-            }
-            if (i == stop)
-                break;
-        }
-    }
-    JS_FreeValue(ctx, str);
-    JS_FreeValue(ctx, v);
-    return JS_NewInt32(ctx, ret);
-
-fail:
-    JS_FreeValue(ctx, str);
-    JS_FreeValue(ctx, v);
-    return JS_EXCEPTION;
-}
-
-/* return < 0 if exception or TRUE/FALSE */
-static int js_is_regexp(JSContext *ctx, JSValueConst obj);
-
-static JSValue js_string_includes(JSContext *ctx, JSValueConst this_val,
-                                  int argc, JSValueConst *argv, int magic)
-{
-    JSValue str, v = JS_UNDEFINED;
-    int i, len, v_len, pos, start, stop, ret;
-    JSString *p;
-    JSString *p1;
-
-    str = JS_ToStringCheckObject(ctx, this_val);
-    if (JS_IsException(str))
-        return str;
-    ret = js_is_regexp(ctx, argv[0]);
-    if (ret) {
-        if (ret > 0)
-            JS_ThrowTypeError(ctx, "regex not supported");
-        goto fail;
-    }
-    v = JS_ToString(ctx, argv[0]);
-    if (JS_IsException(v))
-        goto fail;
-    p = JS_VALUE_GET_STRING(str);
-    p1 = JS_VALUE_GET_STRING(v);
-    len = p->len;
-    v_len = p1->len;
-    pos = (magic == 2) ? len : 0;
-    if (argc > 1 && !JS_IsUndefined(argv[1])) {
-        if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0))
-            goto fail;
-    }
-    len -= v_len;
-    ret = 0;
-    if (magic == 0) {
-        start = pos;
-        stop = len;
-    } else {
-        if (magic == 1) {
-            if (pos > len)
-                goto done;
-        } else {
-            pos -= v_len;
-        }
-        start = stop = pos;
-    }
-    if (start >= 0 && start <= stop) {
-        for (i = start;; i++) {
-            if (!string_cmp(p, p1, i, 0, v_len)) {
-                ret = 1;
-                break;
-            }
-            if (i == stop)
-                break;
-        }
-    }
- done:
-    JS_FreeValue(ctx, str);
-    JS_FreeValue(ctx, v);
-    return JS_NewBool(ctx, ret);
-
-fail:
-    JS_FreeValue(ctx, str);
-    JS_FreeValue(ctx, v);
-    return JS_EXCEPTION;
-}
-
-static int check_regexp_g_flag(JSContext *ctx, JSValueConst regexp)
-{
-    int ret;
-    JSValue flags;
-    
-    ret = js_is_regexp(ctx, regexp);
-    if (ret < 0)
-        return -1;
-    if (ret) {
-        flags = JS_GetProperty(ctx, regexp, JS_ATOM_flags);
-        if (JS_IsException(flags))
-            return -1;
-        if (JS_IsUndefined(flags) || JS_IsNull(flags)) {
-            JS_ThrowTypeError(ctx, "cannot convert to object");
-            return -1;
-        }
-        flags = JS_ToStringFree(ctx, flags);
-        if (JS_IsException(flags))
-            return -1;
-        ret = string_indexof_char(JS_VALUE_GET_STRING(flags), 'g', 0);
-        JS_FreeValue(ctx, flags);
-        if (ret < 0) {
-            JS_ThrowTypeError(ctx, "regexp must have the 'g' flag");
-            return -1;
-        }
-    }
-    return 0;
-}
-
-static JSValue js_string_match(JSContext *ctx, JSValueConst this_val,
-                               int argc, JSValueConst *argv, int atom)
-{
-    // match(rx), search(rx), matchAll(rx)
-    // atom is JS_ATOM_Symbol_match, JS_ATOM_Symbol_search, or JS_ATOM_Symbol_matchAll
-    JSValueConst O = this_val, regexp = argv[0], args[2];
-    JSValue matcher, S, rx, result, str;
-    int args_len;
-
-    if (JS_IsUndefined(O) || JS_IsNull(O))
-        return JS_ThrowTypeError(ctx, "cannot convert to object");
-
-    if (!JS_IsUndefined(regexp) && !JS_IsNull(regexp)) {
-        matcher = JS_GetProperty(ctx, regexp, atom);
-        if (JS_IsException(matcher))
-            return JS_EXCEPTION;
-        if (atom == JS_ATOM_Symbol_matchAll) {
-            if (check_regexp_g_flag(ctx, regexp) < 0) {
-                JS_FreeValue(ctx, matcher);
-                return JS_EXCEPTION;
-            }
-        }
-        if (!JS_IsUndefined(matcher) && !JS_IsNull(matcher)) {
-            return JS_CallFree(ctx, matcher, regexp, 1, &O);
-        }
-    }
-    S = JS_ToString(ctx, O);
-    if (JS_IsException(S))
-        return JS_EXCEPTION;
-    args_len = 1;
-    args[0] = regexp;
-    str = JS_UNDEFINED;
-    if (atom == JS_ATOM_Symbol_matchAll) {
-        str = JS_NewString(ctx, "g");
-        if (JS_IsException(str))
-            goto fail;
-        args[args_len++] = (JSValueConst)str;
-    }
-    rx = JS_CallConstructor(ctx, ctx->regexp_ctor, args_len, args);
-    JS_FreeValue(ctx, str);
-    if (JS_IsException(rx)) {
-    fail:
-        JS_FreeValue(ctx, S);
-        return JS_EXCEPTION;
-    }
-    result = JS_InvokeFree(ctx, rx, atom, 1, (JSValueConst *)&S);
-    JS_FreeValue(ctx, S);
-    return result;
-}
-
-static JSValue js_string___GetSubstitution(JSContext *ctx, JSValueConst this_val,
-                                           int argc, JSValueConst *argv)
-{
-    // GetSubstitution(matched, str, position, captures, namedCaptures, rep)
-    JSValueConst matched, str, captures, namedCaptures, rep;
-    JSValue capture, name, s;
-    uint32_t position, len, matched_len, captures_len;
-    int i, j, j0, k, k1;
-    int c, c1;
-    StringBuffer b_s, *b = &b_s;
-    JSString *sp, *rp;
-
-    matched = argv[0];
-    str = argv[1];
-    captures = argv[3];
-    namedCaptures = argv[4];
-    rep = argv[5];
-
-    if (!JS_IsString(rep) || !JS_IsString(str))
-        return JS_ThrowTypeError(ctx, "not a string");
-
-    sp = JS_VALUE_GET_STRING(str);
-    rp = JS_VALUE_GET_STRING(rep);
-
-    string_buffer_init(ctx, b, 0);
-
-    captures_len = 0;
-    if (!JS_IsUndefined(captures)) {
-        if (js_get_length32(ctx, &captures_len, captures))
-            goto exception;
-    }
-    if (js_get_length32(ctx, &matched_len, matched))
-        goto exception;
-    if (JS_ToUint32(ctx, &position, argv[2]) < 0)
-        goto exception;
-
-    len = rp->len;
-    i = 0;
-    for(;;) {
-        j = string_indexof_char(rp, '$', i);
-        if (j < 0 || j + 1 >= len)
-            break;
-        string_buffer_concat(b, rp, i, j);
-        j0 = j++;
-        c = string_get(rp, j++);
-        if (c == '$') {
-            string_buffer_putc8(b, '$');
-        } else if (c == '&') {
-            if (string_buffer_concat_value(b, matched))
-                goto exception;
-        } else if (c == '`') {
-            string_buffer_concat(b, sp, 0, position);
-        } else if (c == '\'') {
-            string_buffer_concat(b, sp, position + matched_len, sp->len);
-        } else if (c >= '0' && c <= '9') {
-            k = c - '0';
-            if (j < len) {
-                c1 = string_get(rp, j);
-                if (c1 >= '0' && c1 <= '9') {
-                    /* This behavior is specified in ES6 and refined in ECMA 2019 */
-                    /* ECMA 2019 does not have the extra test, but
-                       Test262 S15.5.4.11_A3_T1..3 require this behavior */
-                    k1 = k * 10 + c1 - '0';
-                    if (k1 >= 1 && k1 < captures_len) {
-                        k = k1;
-                        j++;
-                    }
-                }
-            }
-            if (k >= 1 && k < captures_len) {
-                s = JS_GetPropertyInt64(ctx, captures, k);
-                if (JS_IsException(s))
-                    goto exception;
-                if (!JS_IsUndefined(s)) {
-                    if (string_buffer_concat_value_free(b, s))
-                        goto exception;
-                }
-            } else {
-                goto norep;
-            }
-        } else if (c == '<' && !JS_IsUndefined(namedCaptures)) {
-            k = string_indexof_char(rp, '>', j);
-            if (k < 0)
-                goto norep;
-            name = js_sub_string(ctx, rp, j, k);
-            if (JS_IsException(name))
-                goto exception;
-            capture = JS_GetPropertyValue(ctx, namedCaptures, name);
-            if (JS_IsException(capture))
-                goto exception;
-            if (!JS_IsUndefined(capture)) {
-                if (string_buffer_concat_value_free(b, capture))
-                    goto exception;
-            }
-            j = k + 1;
-        } else {
-        norep:
-            string_buffer_concat(b, rp, j0, j);
-        }
-        i = j;
-    }
-    string_buffer_concat(b, rp, i, rp->len);
-    return string_buffer_end(b);
-exception:
-    string_buffer_free(b);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_string_replace(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv,
-                                 int is_replaceAll)
-{
-    // replace(rx, rep)
-    JSValueConst O = this_val, searchValue = argv[0], replaceValue = argv[1];
-    JSValueConst args[6];
-    JSValue str, search_str, replaceValue_str, repl_str;
-    JSString *sp, *searchp;
-    StringBuffer b_s, *b = &b_s;
-    int pos, functionalReplace, endOfLastMatch;
-    BOOL is_first;
-
-    if (JS_IsUndefined(O) || JS_IsNull(O))
-        return JS_ThrowTypeError(ctx, "cannot convert to object");
-
-    search_str = JS_UNDEFINED;
-    replaceValue_str = JS_UNDEFINED;
-    repl_str = JS_UNDEFINED;
-
-    if (!JS_IsUndefined(searchValue) && !JS_IsNull(searchValue)) {
-        JSValue replacer;
-        if (is_replaceAll) {
-            if (check_regexp_g_flag(ctx, searchValue) < 0)
-                return JS_EXCEPTION;
-        }
-        replacer = JS_GetProperty(ctx, searchValue, JS_ATOM_Symbol_replace);
-        if (JS_IsException(replacer))
-            return JS_EXCEPTION;
-        if (!JS_IsUndefined(replacer) && !JS_IsNull(replacer)) {
-            args[0] = O;
-            args[1] = replaceValue;
-            return JS_CallFree(ctx, replacer, searchValue, 2, args);
-        }
-    }
-    string_buffer_init(ctx, b, 0);
-
-    str = JS_ToString(ctx, O);
-    if (JS_IsException(str))
-        goto exception;
-    search_str = JS_ToString(ctx, searchValue);
-    if (JS_IsException(search_str))
-        goto exception;
-    functionalReplace = JS_IsFunction(ctx, replaceValue);
-    if (!functionalReplace) {
-        replaceValue_str = JS_ToString(ctx, replaceValue);
-        if (JS_IsException(replaceValue_str))
-            goto exception;
-    }
-
-    sp = JS_VALUE_GET_STRING(str);
-    searchp = JS_VALUE_GET_STRING(search_str);
-    endOfLastMatch = 0;
-    is_first = TRUE;
-    for(;;) {
-        if (unlikely(searchp->len == 0)) {
-            if (is_first)
-                pos = 0;
-            else if (endOfLastMatch >= sp->len)
-                pos = -1;
-            else
-                pos = endOfLastMatch + 1;
-        } else {
-            pos = string_indexof(sp, searchp, endOfLastMatch);
-        }
-        if (pos < 0) {
-            if (is_first) {
-                string_buffer_free(b);
-                JS_FreeValue(ctx, search_str);
-                JS_FreeValue(ctx, replaceValue_str);
-                return str;
-            } else {
-                break;
-            }
-        }
-        if (functionalReplace) {
-            args[0] = search_str;
-            args[1] = JS_NewInt32(ctx, pos);
-            args[2] = str;
-            repl_str = JS_ToStringFree(ctx, JS_Call(ctx, replaceValue, JS_UNDEFINED, 3, args));
-        } else {
-            args[0] = search_str;
-            args[1] = str;
-            args[2] = JS_NewInt32(ctx, pos);
-            args[3] = JS_UNDEFINED;
-            args[4] = JS_UNDEFINED;
-            args[5] = replaceValue_str;
-            repl_str = js_string___GetSubstitution(ctx, JS_UNDEFINED, 6, args);
-        }
-        if (JS_IsException(repl_str))
-            goto exception;
-        
-        string_buffer_concat(b, sp, endOfLastMatch, pos);
-        string_buffer_concat_value_free(b, repl_str);
-        endOfLastMatch = pos + searchp->len;
-        is_first = FALSE;
-        if (!is_replaceAll)
-            break;
-    }
-    string_buffer_concat(b, sp, endOfLastMatch, sp->len);
-    JS_FreeValue(ctx, search_str);
-    JS_FreeValue(ctx, replaceValue_str);
-    JS_FreeValue(ctx, str);
-    return string_buffer_end(b);
-
-exception:
-    string_buffer_free(b);
-    JS_FreeValue(ctx, search_str);
-    JS_FreeValue(ctx, replaceValue_str);
-    JS_FreeValue(ctx, str);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_string_split(JSContext *ctx, JSValueConst this_val,
-                               int argc, JSValueConst *argv)
-{
-    // split(sep, limit)
-    JSValueConst O = this_val, separator = argv[0], limit = argv[1];
-    JSValueConst args[2];
-    JSValue S, A, R, T;
-    uint32_t lim, lengthA;
-    int64_t p, q, s, r, e;
-    JSString *sp, *rp;
-
-    if (JS_IsUndefined(O) || JS_IsNull(O))
-        return JS_ThrowTypeError(ctx, "cannot convert to object");
-
-    S = JS_UNDEFINED;
-    A = JS_UNDEFINED;
-    R = JS_UNDEFINED;
-
-    if (!JS_IsUndefined(separator) && !JS_IsNull(separator)) {
-        JSValue splitter;
-        splitter = JS_GetProperty(ctx, separator, JS_ATOM_Symbol_split);
-        if (JS_IsException(splitter))
-            return JS_EXCEPTION;
-        if (!JS_IsUndefined(splitter) && !JS_IsNull(splitter)) {
-            args[0] = O;
-            args[1] = limit;
-            return JS_CallFree(ctx, splitter, separator, 2, args);
-        }
-    }
-    S = JS_ToString(ctx, O);
-    if (JS_IsException(S))
-        goto exception;
-    A = JS_NewArray(ctx);
-    if (JS_IsException(A))
-        goto exception;
-    lengthA = 0;
-    if (JS_IsUndefined(limit)) {
-        lim = 0xffffffff;
-    } else {
-        if (JS_ToUint32(ctx, &lim, limit) < 0)
-            goto exception;
-    }
-    sp = JS_VALUE_GET_STRING(S);
-    s = sp->len;
-    R = JS_ToString(ctx, separator);
-    if (JS_IsException(R))
-        goto exception;
-    rp = JS_VALUE_GET_STRING(R);
-    r = rp->len;
-    p = 0;
-    if (lim == 0)
-        goto done;
-    if (JS_IsUndefined(separator))
-        goto add_tail;
-    if (s == 0) {
-        if (r != 0)
-            goto add_tail;
-        goto done;
-    }
-    q = p;
-    for (q = p; (q += !r) <= s - r - !r; q = p = e + r) {
-        e = string_indexof(sp, rp, q);
-        if (e < 0)
-            break;
-        T = js_sub_string(ctx, sp, p, e);
-        if (JS_IsException(T))
-            goto exception;
-        if (JS_CreateDataPropertyUint32(ctx, A, lengthA++, T, 0) < 0)
-            goto exception;
-        if (lengthA == lim)
-            goto done;
-    }
-add_tail:
-    T = js_sub_string(ctx, sp, p, s);
-    if (JS_IsException(T))
-        goto exception;
-    if (JS_CreateDataPropertyUint32(ctx, A, lengthA++, T,0 ) < 0)
-        goto exception;
-done:
-    JS_FreeValue(ctx, S);
-    JS_FreeValue(ctx, R);
-    return A;
-
-exception:
-    JS_FreeValue(ctx, A);
-    JS_FreeValue(ctx, S);
-    JS_FreeValue(ctx, R);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_string_substring(JSContext *ctx, JSValueConst this_val,
-                                   int argc, JSValueConst *argv)
-{
-    JSValue str, ret;
-    int a, b, start, end;
-    JSString *p;
-
-    str = JS_ToStringCheckObject(ctx, this_val);
-    if (JS_IsException(str))
-        return str;
-    p = JS_VALUE_GET_STRING(str);
-    if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, p->len, 0)) {
-        JS_FreeValue(ctx, str);
-        return JS_EXCEPTION;
-    }
-    b = p->len;
-    if (!JS_IsUndefined(argv[1])) {
-        if (JS_ToInt32Clamp(ctx, &b, argv[1], 0, p->len, 0)) {
-            JS_FreeValue(ctx, str);
-            return JS_EXCEPTION;
-        }
-    }
-    if (a < b) {
-        start = a;
-        end = b;
-    } else {
-        start = b;
-        end = a;
-    }
-    ret = js_sub_string(ctx, p, start, end);
-    JS_FreeValue(ctx, str);
-    return ret;
-}
-
-static JSValue js_string_substr(JSContext *ctx, JSValueConst this_val,
-                                int argc, JSValueConst *argv)
-{
-    JSValue str, ret;
-    int a, len, n;
-    JSString *p;
-
-    str = JS_ToStringCheckObject(ctx, this_val);
-    if (JS_IsException(str))
-        return str;
-    p = JS_VALUE_GET_STRING(str);
-    len = p->len;
-    if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, len, len)) {
-        JS_FreeValue(ctx, str);
-        return JS_EXCEPTION;
-    }
-    n = len - a;
-    if (!JS_IsUndefined(argv[1])) {
-        if (JS_ToInt32Clamp(ctx, &n, argv[1], 0, len - a, 0)) {
-            JS_FreeValue(ctx, str);
-            return JS_EXCEPTION;
-        }
-    }
-    ret = js_sub_string(ctx, p, a, a + n);
-    JS_FreeValue(ctx, str);
-    return ret;
-}
-
-static JSValue js_string_slice(JSContext *ctx, JSValueConst this_val,
-                               int argc, JSValueConst *argv)
-{
-    JSValue str, ret;
-    int len, start, end;
-    JSString *p;
-
-    str = JS_ToStringCheckObject(ctx, this_val);
-    if (JS_IsException(str))
-        return str;
-    p = JS_VALUE_GET_STRING(str);
-    len = p->len;
-    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len)) {
-        JS_FreeValue(ctx, str);
-        return JS_EXCEPTION;
-    }
-    end = len;
-    if (!JS_IsUndefined(argv[1])) {
-        if (JS_ToInt32Clamp(ctx, &end, argv[1], 0, len, len)) {
-            JS_FreeValue(ctx, str);
-            return JS_EXCEPTION;
-        }
-    }
-    ret = js_sub_string(ctx, p, start, max_int(end, start));
-    JS_FreeValue(ctx, str);
-    return ret;
-}
-
-static JSValue js_string_pad(JSContext *ctx, JSValueConst this_val,
-                             int argc, JSValueConst *argv, int padEnd)
-{
-    JSValue str, v = JS_UNDEFINED;
-    StringBuffer b_s, *b = &b_s;
-    JSString *p, *p1 = NULL;
-    int n, len, c = ' ';
-
-    str = JS_ToStringCheckObject(ctx, this_val);
-    if (JS_IsException(str))
-        goto fail1;
-    if (JS_ToInt32Sat(ctx, &n, argv[0]))
-        goto fail2;
-    p = JS_VALUE_GET_STRING(str);
-    len = p->len;
-    if (len >= n)
-        return str;
-    if (argc > 1 && !JS_IsUndefined(argv[1])) {
-        v = JS_ToString(ctx, argv[1]);
-        if (JS_IsException(v))
-            goto fail2;
-        p1 = JS_VALUE_GET_STRING(v);
-        if (p1->len == 0) {
-            JS_FreeValue(ctx, v);
-            return str;
-        }
-        if (p1->len == 1) {
-            c = string_get(p1, 0);
-            p1 = NULL;
-        }
-    }
-    if (n > JS_STRING_LEN_MAX) {
-        JS_ThrowInternalError(ctx, "string too long");
-        goto fail2;
-    }
-    if (string_buffer_init(ctx, b, n))
-        goto fail3;
-    n -= len;
-    if (padEnd) {
-        if (string_buffer_concat(b, p, 0, len))
-            goto fail;
-    }
-    if (p1) {
-        while (n > 0) {
-            int chunk = min_int(n, p1->len);
-            if (string_buffer_concat(b, p1, 0, chunk))
-                goto fail;
-            n -= chunk;
-        }
-    } else {
-        if (string_buffer_fill(b, c, n))
-            goto fail;
-    }
-    if (!padEnd) {
-        if (string_buffer_concat(b, p, 0, len))
-            goto fail;
-    }
-    JS_FreeValue(ctx, v);
-    JS_FreeValue(ctx, str);
-    return string_buffer_end(b);
-
-fail:
-    string_buffer_free(b);
-fail3:
-    JS_FreeValue(ctx, v);
-fail2:
-    JS_FreeValue(ctx, str);
-fail1:
-    return JS_EXCEPTION;
-}
-
-static JSValue js_string_repeat(JSContext *ctx, JSValueConst this_val,
-                                int argc, JSValueConst *argv)
-{
-    JSValue str;
-    StringBuffer b_s, *b = &b_s;
-    JSString *p;
-    int64_t val;
-    int n, len;
-
-    str = JS_ToStringCheckObject(ctx, this_val);
-    if (JS_IsException(str))
-        goto fail;
-    if (JS_ToInt64Sat(ctx, &val, argv[0]))
-        goto fail;
-    if (val < 0 || val > 2147483647) {
-        JS_ThrowRangeError(ctx, "invalid repeat count");
-        goto fail;
-    }
-    n = val;
-    p = JS_VALUE_GET_STRING(str);
-    len = p->len;
-    if (len == 0 || n == 1)
-        return str;
-    if (val * len > JS_STRING_LEN_MAX) {
-        JS_ThrowInternalError(ctx, "string too long");
-        goto fail;
-    }
-    if (string_buffer_init2(ctx, b, n * len, p->is_wide_char))
-        goto fail;
-    if (len == 1) {
-        string_buffer_fill(b, string_get(p, 0), n);
-    } else {
-        while (n-- > 0) {
-            string_buffer_concat(b, p, 0, len);
-        }
-    }
-    JS_FreeValue(ctx, str);
-    return string_buffer_end(b);
-
-fail:
-    JS_FreeValue(ctx, str);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_string_trim(JSContext *ctx, JSValueConst this_val,
-                              int argc, JSValueConst *argv, int magic)
-{
-    JSValue str, ret;
-    int a, b, len;
-    JSString *p;
-
-    str = JS_ToStringCheckObject(ctx, this_val);
-    if (JS_IsException(str))
-        return str;
-    p = JS_VALUE_GET_STRING(str);
-    a = 0;
-    b = len = p->len;
-    if (magic & 1) {
-        while (a < len && lre_is_space(string_get(p, a)))
-            a++;
-    }
-    if (magic & 2) {
-        while (b > a && lre_is_space(string_get(p, b - 1)))
-            b--;
-    }
-    ret = js_sub_string(ctx, p, a, b);
-    JS_FreeValue(ctx, str);
-    return ret;
-}
-
-static JSValue js_string___quote(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv)
-{
-    return JS_ToQuotedString(ctx, this_val);
-}
-
-/* return 0 if before the first char */
-static int string_prevc(JSString *p, int *pidx)
-{
-    int idx, c, c1;
-
-    idx = *pidx;
-    if (idx <= 0)
-        return 0;
-    idx--;
-    if (p->is_wide_char) {
-        c = p->u.str16[idx];
-        if (c >= 0xdc00 && c < 0xe000 && idx > 0) {
-            c1 = p->u.str16[idx - 1];
-            if (c1 >= 0xd800 && c1 <= 0xdc00) {
-                c = (((c1 & 0x3ff) << 10) | (c & 0x3ff)) + 0x10000;
-                idx--;
-            }
-        }
-    } else {
-        c = p->u.str8[idx];
-    }
-    *pidx = idx;
-    return c;
-}
-
-static BOOL test_final_sigma(JSString *p, int sigma_pos)
-{
-    int k, c1;
-
-    /* before C: skip case ignorable chars and check there is
-       a cased letter */
-    k = sigma_pos;
-    for(;;) {
-        c1 = string_prevc(p, &k);
-        if (!lre_is_case_ignorable(c1))
-            break;
-    }
-    if (!lre_is_cased(c1))
-        return FALSE;
-
-    /* after C: skip case ignorable chars and check there is
-       no cased letter */
-    k = sigma_pos + 1;
-    for(;;) {
-        if (k >= p->len)
-            return TRUE;
-        c1 = string_getc(p, &k);
-        if (!lre_is_case_ignorable(c1))
-            break;
-    }
-    return !lre_is_cased(c1);
-}
-
-static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val,
-                                       int argc, JSValueConst *argv)
-{
-    JSValue a, b;
-    int cmp;
-
-    a = JS_ToStringCheckObject(ctx, this_val);
-    if (JS_IsException(a))
-        return JS_EXCEPTION;
-    b = JS_ToString(ctx, argv[0]);
-    if (JS_IsException(b)) {
-        JS_FreeValue(ctx, a);
-        return JS_EXCEPTION;
-    }
-    cmp = js_string_compare(ctx, JS_VALUE_GET_STRING(a), JS_VALUE_GET_STRING(b));
-    JS_FreeValue(ctx, a);
-    JS_FreeValue(ctx, b);
-    return JS_NewInt32(ctx, cmp);
-}
-
-static JSValue js_string_toLowerCase(JSContext *ctx, JSValueConst this_val,
-                                     int argc, JSValueConst *argv, int to_lower)
-{
-    JSValue val;
-    StringBuffer b_s, *b = &b_s;
-    JSString *p;
-    int i, c, j, l;
-    uint32_t res[LRE_CC_RES_LEN_MAX];
-
-    val = JS_ToStringCheckObject(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    p = JS_VALUE_GET_STRING(val);
-    if (p->len == 0)
-        return val;
-    if (string_buffer_init(ctx, b, p->len))
-        goto fail;
-    for(i = 0; i < p->len;) {
-        c = string_getc(p, &i);
-        if (c == 0x3a3 && to_lower && test_final_sigma(p, i - 1)) {
-            res[0] = 0x3c2; /* final sigma */
-            l = 1;
-        } else {
-            l = lre_case_conv(res, c, to_lower);
-        }
-        for(j = 0; j < l; j++) {
-            if (string_buffer_putc(b, res[j]))
-                goto fail;
-        }
-    }
-    JS_FreeValue(ctx, val);
-    return string_buffer_end(b);
- fail:
-    JS_FreeValue(ctx, val);
-    string_buffer_free(b);
-    return JS_EXCEPTION;
-}
-
-#ifdef CONFIG_ALL_UNICODE
-
-/* return (-1, NULL) if exception, otherwise (len, buf) */
-static int JS_ToUTF32String(JSContext *ctx, uint32_t **pbuf, JSValueConst val1)
-{
-    JSValue val;
-    JSString *p;
-    uint32_t *buf;
-    int i, j, len;
-
-    val = JS_ToString(ctx, val1);
-    if (JS_IsException(val))
-        return -1;
-    p = JS_VALUE_GET_STRING(val);
-    len = p->len;
-    /* UTF32 buffer length is len minus the number of correct surrogates pairs */
-    buf = js_malloc(ctx, sizeof(buf[0]) * max_int(len, 1));
-    if (!buf) {
-        JS_FreeValue(ctx, val);
-        goto fail;
-    }
-    for(i = j = 0; i < len;)
-        buf[j++] = string_getc(p, &i);
-    JS_FreeValue(ctx, val);
-    *pbuf = buf;
-    return j;
- fail:
-    *pbuf = NULL;
-    return -1;
-}
-
-static JSValue JS_NewUTF32String(JSContext *ctx, const uint32_t *buf, int len)
-{
-    int i;
-    StringBuffer b_s, *b = &b_s;
-    if (string_buffer_init(ctx, b, len))
-        return JS_EXCEPTION;
-    for(i = 0; i < len; i++) {
-        if (string_buffer_putc(b, buf[i]))
-            goto fail;
-    }
-    return string_buffer_end(b);
- fail:
-    string_buffer_free(b);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_string_normalize(JSContext *ctx, JSValueConst this_val,
-                                   int argc, JSValueConst *argv)
-{
-    const char *form, *p;
-    size_t form_len;
-    int is_compat, buf_len, out_len;
-    UnicodeNormalizationEnum n_type;
-    JSValue val;
-    uint32_t *buf, *out_buf;
-
-    val = JS_ToStringCheckObject(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    buf_len = JS_ToUTF32String(ctx, &buf, val);
-    JS_FreeValue(ctx, val);
-    if (buf_len < 0)
-        return JS_EXCEPTION;
-
-    if (argc == 0 || JS_IsUndefined(argv[0])) {
-        n_type = UNICODE_NFC;
-    } else {
-        form = JS_ToCStringLen(ctx, &form_len, argv[0]);
-        if (!form)
-            goto fail1;
-        p = form;
-        if (p[0] != 'N' || p[1] != 'F')
-            goto bad_form;
-        p += 2;
-        is_compat = FALSE;
-        if (*p == 'K') {
-            is_compat = TRUE;
-            p++;
-        }
-        if (*p == 'C' || *p == 'D') {
-            n_type = UNICODE_NFC + is_compat * 2 + (*p - 'C');
-            if ((p + 1 - form) != form_len)
-                goto bad_form;
-        } else {
-        bad_form:
-            JS_FreeCString(ctx, form);
-            JS_ThrowRangeError(ctx, "bad normalization form");
-        fail1:
-            js_free(ctx, buf);
-            return JS_EXCEPTION;
-        }
-        JS_FreeCString(ctx, form);
-    }
-
-    out_len = unicode_normalize(&out_buf, buf, buf_len, n_type,
-                                ctx->rt, (DynBufReallocFunc *)js_realloc_rt);
-    js_free(ctx, buf);
-    if (out_len < 0)
-        return JS_EXCEPTION;
-    val = JS_NewUTF32String(ctx, out_buf, out_len);
-    js_free(ctx, out_buf);
-    return val;
-}
-#endif /* CONFIG_ALL_UNICODE */
-
-/* also used for String.prototype.valueOf */
-static JSValue js_string_toString(JSContext *ctx, JSValueConst this_val,
-                                  int argc, JSValueConst *argv)
-{
-    return js_thisStringValue(ctx, this_val);
-}
-
-#if 0
-static JSValue js_string___toStringCheckObject(JSContext *ctx, JSValueConst this_val,
-                                               int argc, JSValueConst *argv)
-{
-    return JS_ToStringCheckObject(ctx, argv[0]);
-}
-
-static JSValue js_string___toString(JSContext *ctx, JSValueConst this_val,
-                                    int argc, JSValueConst *argv)
-{
-    return JS_ToString(ctx, argv[0]);
-}
-
-static JSValue js_string___advanceStringIndex(JSContext *ctx, JSValueConst
-                                              this_val,
-                                              int argc, JSValueConst *argv)
-{
-    JSValue str;
-    int idx;
-    BOOL is_unicode;
-    JSString *p;
-
-    str = JS_ToString(ctx, argv[0]);
-    if (JS_IsException(str))
-        return str;
-    if (JS_ToInt32Sat(ctx, &idx, argv[1])) {
-        JS_FreeValue(ctx, str);
-        return JS_EXCEPTION;
-    }
-    is_unicode = JS_ToBool(ctx, argv[2]);
-    p = JS_VALUE_GET_STRING(str);
-    if (!is_unicode || (unsigned)idx >= p->len || !p->is_wide_char) {
-        idx++;
-    } else {
-        string_getc(p, &idx);
-    }
-    JS_FreeValue(ctx, str);
-    return JS_NewInt32(ctx, idx);
-}
-#endif
-
-/* String Iterator */
-
-static JSValue js_string_iterator_next(JSContext *ctx, JSValueConst this_val,
-                                       int argc, JSValueConst *argv,
-                                       BOOL *pdone, int magic)
-{
-    JSArrayIteratorData *it;
-    uint32_t idx, c, start;
-    JSString *p;
-
-    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_STRING_ITERATOR);
-    if (!it) {
-        *pdone = FALSE;
-        return JS_EXCEPTION;
-    }
-    if (JS_IsUndefined(it->obj))
-        goto done;
-    p = JS_VALUE_GET_STRING(it->obj);
-    idx = it->idx;
-    if (idx >= p->len) {
-        JS_FreeValue(ctx, it->obj);
-        it->obj = JS_UNDEFINED;
-    done:
-        *pdone = TRUE;
-        return JS_UNDEFINED;
-    }
-
-    start = idx;
-    c = string_getc(p, (int *)&idx);
-    it->idx = idx;
-    *pdone = FALSE;
-    if (c <= 0xffff) {
-        return js_new_string_char(ctx, c);
-    } else {
-        return js_new_string16(ctx, p->u.str16 + start, 2);
-    }
-}
-
-/* ES6 Annex B 2.3.2 etc. */
-enum {
-    magic_string_anchor,
-    magic_string_big,
-    magic_string_blink,
-    magic_string_bold,
-    magic_string_fixed,
-    magic_string_fontcolor,
-    magic_string_fontsize,
-    magic_string_italics,
-    magic_string_link,
-    magic_string_small,
-    magic_string_strike,
-    magic_string_sub,
-    magic_string_sup,
-};
-
-static JSValue js_string_CreateHTML(JSContext *ctx, JSValueConst this_val,
-                                    int argc, JSValueConst *argv, int magic)
-{
-    JSValue str;
-    const JSString *p;
-    StringBuffer b_s, *b = &b_s;
-    static struct { const char *tag, *attr; } const defs[] = {
-        { "a", "name" }, { "big", NULL }, { "blink", NULL }, { "b", NULL },
-        { "tt", NULL }, { "font", "color" }, { "font", "size" }, { "i", NULL },
-        { "a", "href" }, { "small", NULL }, { "strike", NULL }, 
-        { "sub", NULL }, { "sup", NULL },
-    };
-
-    str = JS_ToStringCheckObject(ctx, this_val);
-    if (JS_IsException(str))
-        return JS_EXCEPTION;
-    string_buffer_init(ctx, b, 7);
-    string_buffer_putc8(b, '<');
-    string_buffer_puts8(b, defs[magic].tag);
-    if (defs[magic].attr) {
-        // r += " " + attr + "=\"" + value + "\"";
-        JSValue value;
-        int i;
-
-        string_buffer_putc8(b, ' ');
-        string_buffer_puts8(b, defs[magic].attr);
-        string_buffer_puts8(b, "=\"");
-        value = JS_ToStringCheckObject(ctx, argv[0]);
-        if (JS_IsException(value)) {
-            JS_FreeValue(ctx, str);
-            string_buffer_free(b);
-            return JS_EXCEPTION;
-        }
-        p = JS_VALUE_GET_STRING(value);
-        for (i = 0; i < p->len; i++) {
-            int c = string_get(p, i);
-            if (c == '"') {
-                string_buffer_puts8(b, "&quot;");
-            } else {
-                string_buffer_putc16(b, c);
-            }
-        }
-        JS_FreeValue(ctx, value);
-        string_buffer_putc8(b, '\"');
-    }
-    // return r + ">" + str + "</" + tag + ">";
-    string_buffer_putc8(b, '>');
-    string_buffer_concat_value_free(b, str);
-    string_buffer_puts8(b, "</");
-    string_buffer_puts8(b, defs[magic].tag);
-    string_buffer_putc8(b, '>');
-    return string_buffer_end(b);
-}
-
-static const JSCFunctionListEntry js_string_funcs[] = {
-    JS_CFUNC_DEF("fromCharCode", 1, js_string_fromCharCode ),
-    JS_CFUNC_DEF("fromCodePoint", 1, js_string_fromCodePoint ),
-    JS_CFUNC_DEF("raw", 1, js_string_raw ),
-    //JS_CFUNC_DEF("__toString", 1, js_string___toString ),
-    //JS_CFUNC_DEF("__isSpace", 1, js_string___isSpace ),
-    //JS_CFUNC_DEF("__toStringCheckObject", 1, js_string___toStringCheckObject ),
-    //JS_CFUNC_DEF("__advanceStringIndex", 3, js_string___advanceStringIndex ),
-    //JS_CFUNC_DEF("__GetSubstitution", 6, js_string___GetSubstitution ),
-};
-
-static const JSCFunctionListEntry js_string_proto_funcs[] = {
-    JS_PROP_INT32_DEF("length", 0, JS_PROP_CONFIGURABLE ),
-    JS_CFUNC_DEF("charCodeAt", 1, js_string_charCodeAt ),
-    JS_CFUNC_DEF("charAt", 1, js_string_charAt ),
-    JS_CFUNC_DEF("concat", 1, js_string_concat ),
-    JS_CFUNC_DEF("codePointAt", 1, js_string_codePointAt ),
-    JS_CFUNC_MAGIC_DEF("indexOf", 1, js_string_indexOf, 0 ),
-    JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_string_indexOf, 1 ),
-    JS_CFUNC_MAGIC_DEF("includes", 1, js_string_includes, 0 ),
-    JS_CFUNC_MAGIC_DEF("endsWith", 1, js_string_includes, 2 ),
-    JS_CFUNC_MAGIC_DEF("startsWith", 1, js_string_includes, 1 ),
-    JS_CFUNC_MAGIC_DEF("match", 1, js_string_match, JS_ATOM_Symbol_match ),
-    JS_CFUNC_MAGIC_DEF("matchAll", 1, js_string_match, JS_ATOM_Symbol_matchAll ),
-    JS_CFUNC_MAGIC_DEF("search", 1, js_string_match, JS_ATOM_Symbol_search ),
-    JS_CFUNC_DEF("split", 2, js_string_split ),
-    JS_CFUNC_DEF("substring", 2, js_string_substring ),
-    JS_CFUNC_DEF("substr", 2, js_string_substr ),
-    JS_CFUNC_DEF("slice", 2, js_string_slice ),
-    JS_CFUNC_DEF("repeat", 1, js_string_repeat ),
-    JS_CFUNC_MAGIC_DEF("replace", 2, js_string_replace, 0 ),
-    JS_CFUNC_MAGIC_DEF("replaceAll", 2, js_string_replace, 1 ),
-    JS_CFUNC_MAGIC_DEF("padEnd", 1, js_string_pad, 1 ),
-    JS_CFUNC_MAGIC_DEF("padStart", 1, js_string_pad, 0 ),
-    JS_CFUNC_MAGIC_DEF("trim", 0, js_string_trim, 3 ),
-    JS_CFUNC_MAGIC_DEF("trimEnd", 0, js_string_trim, 2 ),
-    JS_ALIAS_DEF("trimRight", "trimEnd" ),
-    JS_CFUNC_MAGIC_DEF("trimStart", 0, js_string_trim, 1 ),
-    JS_ALIAS_DEF("trimLeft", "trimStart" ),
-    JS_CFUNC_DEF("toString", 0, js_string_toString ),
-    JS_CFUNC_DEF("valueOf", 0, js_string_toString ),
-    JS_CFUNC_DEF("__quote", 1, js_string___quote ),
-    JS_CFUNC_DEF("localeCompare", 1, js_string_localeCompare ),
-    JS_CFUNC_MAGIC_DEF("toLowerCase", 0, js_string_toLowerCase, 1 ),
-    JS_CFUNC_MAGIC_DEF("toUpperCase", 0, js_string_toLowerCase, 0 ),
-    JS_CFUNC_MAGIC_DEF("toLocaleLowerCase", 0, js_string_toLowerCase, 1 ),
-    JS_CFUNC_MAGIC_DEF("toLocaleUpperCase", 0, js_string_toLowerCase, 0 ),
-    JS_CFUNC_MAGIC_DEF("[Symbol.iterator]", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE | 4 ),
-    /* ES6 Annex B 2.3.2 etc. */
-    JS_CFUNC_MAGIC_DEF("anchor", 1, js_string_CreateHTML, magic_string_anchor ),
-    JS_CFUNC_MAGIC_DEF("big", 0, js_string_CreateHTML, magic_string_big ),
-    JS_CFUNC_MAGIC_DEF("blink", 0, js_string_CreateHTML, magic_string_blink ),
-    JS_CFUNC_MAGIC_DEF("bold", 0, js_string_CreateHTML, magic_string_bold ),
-    JS_CFUNC_MAGIC_DEF("fixed", 0, js_string_CreateHTML, magic_string_fixed ),
-    JS_CFUNC_MAGIC_DEF("fontcolor", 1, js_string_CreateHTML, magic_string_fontcolor ),
-    JS_CFUNC_MAGIC_DEF("fontsize", 1, js_string_CreateHTML, magic_string_fontsize ),
-    JS_CFUNC_MAGIC_DEF("italics", 0, js_string_CreateHTML, magic_string_italics ),
-    JS_CFUNC_MAGIC_DEF("link", 1, js_string_CreateHTML, magic_string_link ),
-    JS_CFUNC_MAGIC_DEF("small", 0, js_string_CreateHTML, magic_string_small ),
-    JS_CFUNC_MAGIC_DEF("strike", 0, js_string_CreateHTML, magic_string_strike ),
-    JS_CFUNC_MAGIC_DEF("sub", 0, js_string_CreateHTML, magic_string_sub ),
-    JS_CFUNC_MAGIC_DEF("sup", 0, js_string_CreateHTML, magic_string_sup ),
-};
-
-static const JSCFunctionListEntry js_string_iterator_proto_funcs[] = {
-    JS_ITERATOR_NEXT_DEF("next", 0, js_string_iterator_next, 0 ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "String Iterator", JS_PROP_CONFIGURABLE ),
-};
-
-#ifdef CONFIG_ALL_UNICODE
-static const JSCFunctionListEntry js_string_proto_normalize[] = {
-    JS_CFUNC_DEF("normalize", 0, js_string_normalize ),
-};
-#endif
-
-void JS_AddIntrinsicStringNormalize(JSContext *ctx)
-{
-#ifdef CONFIG_ALL_UNICODE
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING], js_string_proto_normalize,
-                               countof(js_string_proto_normalize));
-#endif
-}
-
-/* Math */
-
-/* precondition: a and b are not NaN */
-static double js_fmin(double a, double b)
-{
-    if (a == 0 && b == 0) {
-        JSFloat64Union a1, b1;
-        a1.d = a;
-        b1.d = b;
-        a1.u64 |= b1.u64;
-        return a1.d;
-    } else {
-        return fmin(a, b);
-    }
-}
-
-/* precondition: a and b are not NaN */
-static double js_fmax(double a, double b)
-{
-    if (a == 0 && b == 0) {
-        JSFloat64Union a1, b1;
-        a1.d = a;
-        b1.d = b;
-        a1.u64 &= b1.u64;
-        return a1.d;
-    } else {
-        return fmax(a, b);
-    }
-}
-
-static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,
-                               int argc, JSValueConst *argv, int magic)
-{
-    BOOL is_max = magic;
-    double r, a;
-    int i;
-    uint32_t tag;
-
-    if (unlikely(argc == 0)) {
-        return __JS_NewFloat64(ctx, is_max ? -1.0 / 0.0 : 1.0 / 0.0);
-    }
-
-    tag = JS_VALUE_GET_TAG(argv[0]);
-    if (tag == JS_TAG_INT) {
-        int a1, r1 = JS_VALUE_GET_INT(argv[0]);
-        for(i = 1; i < argc; i++) {
-            tag = JS_VALUE_GET_TAG(argv[i]);
-            if (tag != JS_TAG_INT) {
-                r = r1;
-                goto generic_case;
-            }
-            a1 = JS_VALUE_GET_INT(argv[i]);
-            if (is_max)
-                r1 = max_int(r1, a1);
-            else
-                r1 = min_int(r1, a1);
-
-        }
-        return JS_NewInt32(ctx, r1);
-    } else {
-        if (JS_ToFloat64(ctx, &r, argv[0]))
-            return JS_EXCEPTION;
-        i = 1;
-    generic_case:
-        while (i < argc) {
-            if (JS_ToFloat64(ctx, &a, argv[i]))
-                return JS_EXCEPTION;
-            if (!isnan(r)) {
-                if (isnan(a)) {
-                    r = a;
-                } else {
-                    if (is_max)
-                        r = js_fmax(r, a);
-                    else
-                        r = js_fmin(r, a);
-                }
-            }
-            i++;
-        }
-        return JS_NewFloat64(ctx, r);
-    }
-}
-
-static double js_math_sign(double a)
-{
-    if (isnan(a) || a == 0.0)
-        return a;
-    if (a < 0)
-        return -1;
-    else
-        return 1;
-}
-
-static double js_math_round(double a)
-{
-    JSFloat64Union u;
-    uint64_t frac_mask, one;
-    unsigned int e, s;
-
-    u.d = a;
-    e = (u.u64 >> 52) & 0x7ff;
-    if (e < 1023) {
-        /* abs(a) < 1 */
-        if (e == (1023 - 1) && u.u64 != 0xbfe0000000000000) {
-            /* abs(a) > 0.5 or a = 0.5: return +/-1.0 */
-            u.u64 = (u.u64 & ((uint64_t)1 << 63)) | ((uint64_t)1023 << 52);
-        } else {
-            /* return +/-0.0 */
-            u.u64 &= (uint64_t)1 << 63;
-        }
-    } else if (e < (1023 + 52)) {
-        s = u.u64 >> 63;
-        one = (uint64_t)1 << (52 - (e - 1023));
-        frac_mask = one - 1;
-        u.u64 += (one >> 1) - s;
-        u.u64 &= ~frac_mask; /* truncate to an integer */
-    }
-    /* otherwise: abs(a) >= 2^52, or NaN, +/-Infinity: no change */
-    return u.d;
-}
-
-static JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val,
-                             int argc, JSValueConst *argv)
-{
-    double r, a;
-    int i;
-
-    r = 0;
-    if (argc > 0) {
-        if (JS_ToFloat64(ctx, &r, argv[0]))
-            return JS_EXCEPTION;
-        if (argc == 1) {
-            r = fabs(r);
-        } else {
-            /* use the built-in function to minimize precision loss */
-            for (i = 1; i < argc; i++) {
-                if (JS_ToFloat64(ctx, &a, argv[i]))
-                    return JS_EXCEPTION;
-                r = hypot(r, a);
-            }
-        }
-    }
-    return JS_NewFloat64(ctx, r);
-}
-
-static double js_math_fround(double a)
-{
-    return (float)a;
-}
-
-static JSValue js_math_imul(JSContext *ctx, JSValueConst this_val,
-                            int argc, JSValueConst *argv)
-{
-    int a, b;
-
-    if (JS_ToInt32(ctx, &a, argv[0]))
-        return JS_EXCEPTION;
-    if (JS_ToInt32(ctx, &b, argv[1]))
-        return JS_EXCEPTION;
-    /* purposely ignoring overflow */
-    return JS_NewInt32(ctx, a * b);
-}
-
-static JSValue js_math_clz32(JSContext *ctx, JSValueConst this_val,
-                             int argc, JSValueConst *argv)
-{
-    uint32_t a, r;
-
-    if (JS_ToUint32(ctx, &a, argv[0]))
-        return JS_EXCEPTION;
-    if (a == 0)
-        r = 32;
-    else
-        r = clz32(a);
-    return JS_NewInt32(ctx, r);
-}
-
-/* xorshift* random number generator by Marsaglia */
-static uint64_t xorshift64star(uint64_t *pstate)
-{
-    uint64_t x;
-    x = *pstate;
-    x ^= x >> 12;
-    x ^= x << 25;
-    x ^= x >> 27;
-    *pstate = x;
-    return x * 0x2545F4914F6CDD1D;
-}
-
-static void js_random_init(JSContext *ctx)
-{
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    ctx->random_state = ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec;
-    /* the state must be non zero */
-    if (ctx->random_state == 0)
-        ctx->random_state = 1;
-}
-
-static JSValue js_math_random(JSContext *ctx, JSValueConst this_val,
-                              int argc, JSValueConst *argv)
-{
-    JSFloat64Union u;
-    uint64_t v;
-
-    v = xorshift64star(&ctx->random_state);
-    /* 1.0 <= u.d < 2 */
-    u.u64 = ((uint64_t)0x3ff << 52) | (v >> 12);
-    return __JS_NewFloat64(ctx, u.d - 1.0);
-}
-
-static const JSCFunctionListEntry js_math_funcs[] = {
-    JS_CFUNC_MAGIC_DEF("min", 2, js_math_min_max, 0 ),
-    JS_CFUNC_MAGIC_DEF("max", 2, js_math_min_max, 1 ),
-    JS_CFUNC_SPECIAL_DEF("abs", 1, f_f, fabs ),
-    JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, floor ),
-    JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, ceil ),
-    JS_CFUNC_SPECIAL_DEF("round", 1, f_f, js_math_round ),
-    JS_CFUNC_SPECIAL_DEF("sqrt", 1, f_f, sqrt ),
-
-    JS_CFUNC_SPECIAL_DEF("acos", 1, f_f, acos ),
-    JS_CFUNC_SPECIAL_DEF("asin", 1, f_f, asin ),
-    JS_CFUNC_SPECIAL_DEF("atan", 1, f_f, atan ),
-    JS_CFUNC_SPECIAL_DEF("atan2", 2, f_f_f, atan2 ),
-    JS_CFUNC_SPECIAL_DEF("cos", 1, f_f, cos ),
-    JS_CFUNC_SPECIAL_DEF("exp", 1, f_f, exp ),
-    JS_CFUNC_SPECIAL_DEF("log", 1, f_f, log ),
-    JS_CFUNC_SPECIAL_DEF("pow", 2, f_f_f, js_pow ),
-    JS_CFUNC_SPECIAL_DEF("sin", 1, f_f, sin ),
-    JS_CFUNC_SPECIAL_DEF("tan", 1, f_f, tan ),
-    /* ES6 */
-    JS_CFUNC_SPECIAL_DEF("trunc", 1, f_f, trunc ),
-    JS_CFUNC_SPECIAL_DEF("sign", 1, f_f, js_math_sign ),
-    JS_CFUNC_SPECIAL_DEF("cosh", 1, f_f, cosh ),
-    JS_CFUNC_SPECIAL_DEF("sinh", 1, f_f, sinh ),
-    JS_CFUNC_SPECIAL_DEF("tanh", 1, f_f, tanh ),
-    JS_CFUNC_SPECIAL_DEF("acosh", 1, f_f, acosh ),
-    JS_CFUNC_SPECIAL_DEF("asinh", 1, f_f, asinh ),
-    JS_CFUNC_SPECIAL_DEF("atanh", 1, f_f, atanh ),
-    JS_CFUNC_SPECIAL_DEF("expm1", 1, f_f, expm1 ),
-    JS_CFUNC_SPECIAL_DEF("log1p", 1, f_f, log1p ),
-    JS_CFUNC_SPECIAL_DEF("log2", 1, f_f, log2 ),
-    JS_CFUNC_SPECIAL_DEF("log10", 1, f_f, log10 ),
-    JS_CFUNC_SPECIAL_DEF("cbrt", 1, f_f, cbrt ),
-    JS_CFUNC_DEF("hypot", 2, js_math_hypot ),
-    JS_CFUNC_DEF("random", 0, js_math_random ),
-    JS_CFUNC_SPECIAL_DEF("fround", 1, f_f, js_math_fround ),
-    JS_CFUNC_DEF("imul", 2, js_math_imul ),
-    JS_CFUNC_DEF("clz32", 1, js_math_clz32 ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Math", JS_PROP_CONFIGURABLE ),
-    JS_PROP_DOUBLE_DEF("E", 2.718281828459045, 0 ),
-    JS_PROP_DOUBLE_DEF("LN10", 2.302585092994046, 0 ),
-    JS_PROP_DOUBLE_DEF("LN2", 0.6931471805599453, 0 ),
-    JS_PROP_DOUBLE_DEF("LOG2E", 1.4426950408889634, 0 ),
-    JS_PROP_DOUBLE_DEF("LOG10E", 0.4342944819032518, 0 ),
-    JS_PROP_DOUBLE_DEF("PI", 3.141592653589793, 0 ),
-    JS_PROP_DOUBLE_DEF("SQRT1_2", 0.7071067811865476, 0 ),
-    JS_PROP_DOUBLE_DEF("SQRT2", 1.4142135623730951, 0 ),
-};
-
-static const JSCFunctionListEntry js_math_obj[] = {
-    JS_OBJECT_DEF("Math", js_math_funcs, countof(js_math_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
-};
-
-/* Date */
-
-#if 0
-/* OS dependent: return the UTC time in ms since 1970. */
-static JSValue js___date_now(JSContext *ctx, JSValueConst this_val,
-                             int argc, JSValueConst *argv)
-{
-    int64_t d;
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    d = (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
-    return JS_NewInt64(ctx, d);
-}
-#endif
-
-/* OS dependent: return the UTC time in microseconds since 1970. */
-static JSValue js___date_clock(JSContext *ctx, JSValueConst this_val,
-                               int argc, JSValueConst *argv)
-{
-    int64_t d;
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    d = (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
-    return JS_NewInt64(ctx, d);
-}
-
-/* OS dependent. d = argv[0] is in ms from 1970. Return the difference
-   between UTC time and local time 'd' in minutes */
-static int getTimezoneOffset(int64_t time) {
-#if defined(_WIN32)
-    /* XXX: TODO */
-    return 0;
-#else
-    time_t ti;
-    struct tm tm;
-
-    time /= 1000; /* convert to seconds */
-    if (sizeof(time_t) == 4) {
-        /* on 32-bit systems, we need to clamp the time value to the
-           range of `time_t`. This is better than truncating values to
-           32 bits and hopefully provides the same result as 64-bit
-           implementation of localtime_r.
-         */
-        if ((time_t)-1 < 0) {
-            if (time < INT32_MIN) {
-                time = INT32_MIN;
-            } else if (time > INT32_MAX) {
-                time = INT32_MAX;
-            }
-        } else {
-            if (time < 0) {
-                time = 0;
-            } else if (time > UINT32_MAX) {
-                time = UINT32_MAX;
-            }
-        }
-    }
-    ti = time;
-    localtime_r(&ti, &tm);
-    return -tm.tm_gmtoff / 60;
-#endif
-}
-
-#if 0
-static JSValue js___date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val,
-                                           int argc, JSValueConst *argv)
-{
-    double dd;
-
-    if (JS_ToFloat64(ctx, &dd, argv[0]))
-        return JS_EXCEPTION;
-    if (isnan(dd))
-        return __JS_NewFloat64(ctx, dd);
-    else
-        return JS_NewInt32(ctx, getTimezoneOffset((int64_t)dd));
-}
-
-static JSValue js_get_prototype_from_ctor(JSContext *ctx, JSValueConst ctor,
-                                          JSValueConst def_proto)
-{
-    JSValue proto;
-    proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);
-    if (JS_IsException(proto))
-        return proto;
-    if (!JS_IsObject(proto)) {
-        JS_FreeValue(ctx, proto);
-        proto = JS_DupValue(ctx, def_proto);
-    }
-    return proto;
-}
-
-/* create a new date object */
-static JSValue js___date_create(JSContext *ctx, JSValueConst this_val,
-                                int argc, JSValueConst *argv)
-{
-    JSValue obj, proto;
-    proto = js_get_prototype_from_ctor(ctx, argv[0], argv[1]);
-    if (JS_IsException(proto))
-        return proto;
-    obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_DATE);
-    JS_FreeValue(ctx, proto);
-    if (!JS_IsException(obj))
-        JS_SetObjectData(ctx, obj, JS_DupValue(ctx, argv[2]));
-    return obj;
-}
-#endif
-
-/* RegExp */
-
-static void js_regexp_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    JSRegExp *re = &p->u.regexp;
-    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, re->bytecode));
-    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, re->pattern));
-}
-
-/* create a string containing the RegExp bytecode */
-static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
-                                 JSValueConst flags)
-{
-    const char *str;
-    int re_flags, mask;
-    uint8_t *re_bytecode_buf;
-    size_t i, len;
-    int re_bytecode_len;
-    JSValue ret;
-    char error_msg[64];
-
-    re_flags = 0;
-    if (!JS_IsUndefined(flags)) {
-        str = JS_ToCStringLen(ctx, &len, flags);
-        if (!str)
-            return JS_EXCEPTION;
-        /* XXX: re_flags = LRE_FLAG_OCTAL unless strict mode? */
-        for (i = 0; i < len; i++) {
-            switch(str[i]) {
-            case 'g':
-                mask = LRE_FLAG_GLOBAL;
-                break;
-            case 'i':
-                mask = LRE_FLAG_IGNORECASE;
-                break;
-            case 'm':
-                mask = LRE_FLAG_MULTILINE;
-                break;
-            case 's':
-                mask = LRE_FLAG_DOTALL;
-                break;
-            case 'u':
-                mask = LRE_FLAG_UTF16;
-                break;
-            case 'y':
-                mask = LRE_FLAG_STICKY;
-                break;
-            default:
-                goto bad_flags;
-            }
-            if ((re_flags & mask) != 0) {
-            bad_flags:
-                JS_FreeCString(ctx, str);
-                return JS_ThrowSyntaxError(ctx, "invalid regular expression flags");
-            }
-            re_flags |= mask;
-        }
-        JS_FreeCString(ctx, str);
-    }
-
-    str = JS_ToCStringLen2(ctx, &len, pattern, !(re_flags & LRE_FLAG_UTF16));
-    if (!str)
-        return JS_EXCEPTION;
-    re_bytecode_buf = lre_compile(&re_bytecode_len, error_msg,
-                                  sizeof(error_msg), str, len, re_flags, ctx);
-    JS_FreeCString(ctx, str);
-    if (!re_bytecode_buf) {
-        JS_ThrowSyntaxError(ctx, "%s", error_msg);
-        return JS_EXCEPTION;
-    }
-
-    ret = js_new_string8(ctx, re_bytecode_buf, re_bytecode_len);
-    js_free(ctx, re_bytecode_buf);
-    return ret;
-}
-
-/* create a RegExp object from a string containing the RegExp bytecode
-   and the source pattern */
-static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor,
-                                              JSValue pattern, JSValue bc)
-{
-    JSValue obj;
-    JSObject *p;
-    JSRegExp *re;
-
-    /* sanity check */
-    if (JS_VALUE_GET_TAG(bc) != JS_TAG_STRING ||
-        JS_VALUE_GET_TAG(pattern) != JS_TAG_STRING) {
-        JS_ThrowTypeError(ctx, "string expected");
-    fail:
-        JS_FreeValue(ctx, bc);
-        JS_FreeValue(ctx, pattern);
-        return JS_EXCEPTION;
-    }
-
-    obj = js_create_from_ctor(ctx, ctor, JS_CLASS_REGEXP);
-    if (JS_IsException(obj))
-        goto fail;
-    p = JS_VALUE_GET_OBJ(obj);
-    re = &p->u.regexp;
-    re->pattern = JS_VALUE_GET_STRING(pattern);
-    re->bytecode = JS_VALUE_GET_STRING(bc);
-    JS_DefinePropertyValue(ctx, obj, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0),
-                           JS_PROP_WRITABLE);
-    return obj;
-}
-
-static JSRegExp *js_get_regexp(JSContext *ctx, JSValueConst obj, BOOL throw_error)
-{
-    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
-        JSObject *p = JS_VALUE_GET_OBJ(obj);
-        if (p->class_id == JS_CLASS_REGEXP)
-            return &p->u.regexp;
-    }
-    if (throw_error) {
-        JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP);
-    }
-    return NULL;
-}
-
-/* return < 0 if exception or TRUE/FALSE */
-static int js_is_regexp(JSContext *ctx, JSValueConst obj)
-{
-    JSValue m;
-
-    if (!JS_IsObject(obj))
-        return FALSE;
-    m = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_match);
-    if (JS_IsException(m))
-        return -1;
-    if (!JS_IsUndefined(m))
-        return JS_ToBoolFree(ctx, m);
-    return js_get_regexp(ctx, obj, FALSE) != NULL;
-}
-
-static JSValue js_regexp_constructor(JSContext *ctx, JSValueConst new_target,
-                                     int argc, JSValueConst *argv)
-{
-    JSValue pattern, flags, bc, val;
-    JSValueConst pat, flags1;
-    JSRegExp *re;
-    int pat_is_regexp;
-
-    pat = argv[0];
-    flags1 = argv[1];
-    pat_is_regexp = js_is_regexp(ctx, pat);
-    if (pat_is_regexp < 0)
-        return JS_EXCEPTION;
-    if (JS_IsUndefined(new_target)) {
-        /* called as a function */
-        new_target = JS_GetActiveFunction(ctx);
-        if (pat_is_regexp && JS_IsUndefined(flags1)) {
-            JSValue ctor;
-            BOOL res;
-            ctor = JS_GetProperty(ctx, pat, JS_ATOM_constructor);
-            if (JS_IsException(ctor))
-                return ctor;
-            res = js_same_value(ctx, ctor, new_target);
-            JS_FreeValue(ctx, ctor);
-            if (res)
-                return JS_DupValue(ctx, pat);
-        }
-    }
-    re = js_get_regexp(ctx, pat, FALSE);
-    if (re) {
-        pattern = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
-        if (JS_IsUndefined(flags1)) {
-            bc = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->bytecode));
-            goto no_compilation;
-        } else {
-            flags = JS_ToString(ctx, flags1);
-            if (JS_IsException(flags))
-                goto fail;
-        }
-    } else {
-        flags = JS_UNDEFINED;
-        if (pat_is_regexp) {
-            pattern = JS_GetProperty(ctx, pat, JS_ATOM_source);
-            if (JS_IsException(pattern))
-                goto fail;
-            if (JS_IsUndefined(flags1)) {
-                flags = JS_GetProperty(ctx, pat, JS_ATOM_flags);
-                if (JS_IsException(flags))
-                    goto fail;
-            } else {
-                flags = JS_DupValue(ctx, flags1);
-            }
-        } else {
-            pattern = JS_DupValue(ctx, pat);
-            flags = JS_DupValue(ctx, flags1);
-        }
-        if (JS_IsUndefined(pattern)) {
-            pattern = JS_AtomToString(ctx, JS_ATOM_empty_string);
-        } else {
-            val = pattern;
-            pattern = JS_ToString(ctx, val);
-            JS_FreeValue(ctx, val);
-            if (JS_IsException(pattern))
-                goto fail;
-        }
-    }
-    bc = js_compile_regexp(ctx, pattern, flags);
-    if (JS_IsException(bc))
-        goto fail;
-    JS_FreeValue(ctx, flags);
- no_compilation:
-    return js_regexp_constructor_internal(ctx, new_target, pattern, bc);
- fail:
-    JS_FreeValue(ctx, pattern);
-    JS_FreeValue(ctx, flags);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_regexp_compile(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv)
-{
-    JSRegExp *re1, *re;
-    JSValueConst pattern1, flags1;
-    JSValue bc, pattern;
-
-    re = js_get_regexp(ctx, this_val, TRUE);
-    if (!re)
-        return JS_EXCEPTION;
-    pattern1 = argv[0];
-    flags1 = argv[1];
-    re1 = js_get_regexp(ctx, pattern1, FALSE);
-    if (re1) {
-        if (!JS_IsUndefined(flags1))
-            return JS_ThrowTypeError(ctx, "flags must be undefined");
-        pattern = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re1->pattern));
-        bc = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re1->bytecode));
-    } else {
-        bc = JS_UNDEFINED;
-        if (JS_IsUndefined(pattern1))
-            pattern = JS_AtomToString(ctx, JS_ATOM_empty_string);
-        else
-            pattern = JS_ToString(ctx, pattern1);
-        if (JS_IsException(pattern))
-            goto fail;
-        bc = js_compile_regexp(ctx, pattern, flags1);
-        if (JS_IsException(bc))
-            goto fail;
-    }
-    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
-    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, re->bytecode));
-    re->pattern = JS_VALUE_GET_STRING(pattern);
-    re->bytecode = JS_VALUE_GET_STRING(bc);
-    if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
-                       JS_NewInt32(ctx, 0)) < 0)
-        return JS_EXCEPTION;
-    return JS_DupValue(ctx, this_val);
- fail:
-    JS_FreeValue(ctx, pattern);
-    JS_FreeValue(ctx, bc);
-    return JS_EXCEPTION;
-}
-
-#if 0
-static JSValue js_regexp_get___source(JSContext *ctx, JSValueConst this_val)
-{
-    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
-    if (!re)
-        return JS_EXCEPTION;
-    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
-}
-
-static JSValue js_regexp_get___flags(JSContext *ctx, JSValueConst this_val)
-{
-    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
-    int flags;
-
-    if (!re)
-        return JS_EXCEPTION;
-    flags = lre_get_flags(re->bytecode->u.str8);
-    return JS_NewInt32(ctx, flags);
-}
-#endif
-
-static JSValue js_regexp_get_source(JSContext *ctx, JSValueConst this_val)
-{
-    JSRegExp *re;
-    JSString *p;
-    StringBuffer b_s, *b = &b_s;
-    int i, n, c, c2, bra;
-
-    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-
-    if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP]))
-        goto empty_regex;
-
-    re = js_get_regexp(ctx, this_val, TRUE);
-    if (!re)
-        return JS_EXCEPTION;
-
-    p = re->pattern;
-
-    if (p->len == 0) {
-    empty_regex:
-        return JS_NewString(ctx, "(?:)");
-    }    
-    string_buffer_init2(ctx, b, p->len, p->is_wide_char);
-
-    /* Escape '/' and newline sequences as needed */
-    bra = 0;
-    for (i = 0, n = p->len; i < n;) {
-        c2 = -1;
-        switch (c = string_get(p, i++)) {
-        case '\\':
-            if (i < n)
-                c2 = string_get(p, i++);
-            break;
-        case ']':
-            bra = 0;
-            break;
-        case '[':
-            if (!bra) {
-                if (i < n && string_get(p, i) == ']')
-                    c2 = string_get(p, i++);
-                bra = 1;
-            }
-            break;
-        case '\n':
-            c = '\\';
-            c2 = 'n';
-            break;
-        case '\r':
-            c = '\\';
-            c2 = 'r';
-            break;
-        case '/':
-            if (!bra) {
-                c = '\\';
-                c2 = '/';
-            }
-            break;
-        }
-        string_buffer_putc16(b, c);
-        if (c2 >= 0)
-            string_buffer_putc16(b, c2);
-    }
-    return string_buffer_end(b);
-}
-
-static JSValue js_regexp_get_flag(JSContext *ctx, JSValueConst this_val, int mask)
-{
-    JSRegExp *re;
-    int flags;
-
-    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-
-    re = js_get_regexp(ctx, this_val, FALSE);
-    if (!re) {
-        if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP]))
-            return JS_UNDEFINED;
-        else
-            return JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP);
-    }
-    
-    flags = lre_get_flags(re->bytecode->u.str8);
-    return JS_NewBool(ctx, (flags & mask) != 0);
-}
-
-static JSValue js_regexp_get_flags(JSContext *ctx, JSValueConst this_val)
-{
-    char str[8], *p = str;
-    int res;
-
-    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-
-    res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, JS_ATOM_global));
-    if (res < 0)
-        goto exception;
-    if (res)
-        *p++ = 'g';
-    res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "ignoreCase"));
-    if (res < 0)
-        goto exception;
-    if (res)
-        *p++ = 'i';
-    res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "multiline"));
-    if (res < 0)
-        goto exception;
-    if (res)
-        *p++ = 'm';
-    res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "dotAll"));
-    if (res < 0)
-        goto exception;
-    if (res)
-        *p++ = 's';
-    res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, JS_ATOM_unicode));
-    if (res < 0)
-        goto exception;
-    if (res)
-        *p++ = 'u';
-    res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "sticky"));
-    if (res < 0)
-        goto exception;
-    if (res)
-        *p++ = 'y';
-    return JS_NewStringLen(ctx, str, p - str);
-
-exception:
-    return JS_EXCEPTION;
-}
-
-static JSValue js_regexp_toString(JSContext *ctx, JSValueConst this_val,
-                                  int argc, JSValueConst *argv)
-{
-    JSValue pattern, flags;
-    StringBuffer b_s, *b = &b_s;
-
-    if (!JS_IsObject(this_val))
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-
-    string_buffer_init(ctx, b, 0);
-    string_buffer_putc8(b, '/');
-    pattern = JS_GetProperty(ctx, this_val, JS_ATOM_source);
-    if (string_buffer_concat_value_free(b, pattern))
-        goto fail;
-    string_buffer_putc8(b, '/');
-    flags = JS_GetProperty(ctx, this_val, JS_ATOM_flags);
-    if (string_buffer_concat_value_free(b, flags))
-        goto fail;
-    return string_buffer_end(b);
-
-fail:
-    string_buffer_free(b);
-    return JS_EXCEPTION;
-}
-
-BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size)
-{
-    JSContext *ctx = opaque;
-    return js_check_stack_overflow(ctx->rt, alloca_size);
-}
-
-void *lre_realloc(void *opaque, void *ptr, size_t size)
-{
-    JSContext *ctx = opaque;
-    /* No JS exception is raised here */
-    return js_realloc_rt(ctx->rt, ptr, size);
-}
-
-static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val,
-                              int argc, JSValueConst *argv)
-{
-    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
-    JSString *str;
-    JSValue str_val, obj, val, groups = JS_UNDEFINED;
-    uint8_t *re_bytecode;
-    int ret;
-    uint8_t **capture, *str_buf;
-    int capture_count, shift, i, re_flags;
-    int64_t last_index;
-    const char *group_name_ptr;
-
-    if (!re)
-        return JS_EXCEPTION;
-    str_val = JS_ToString(ctx, argv[0]);
-    if (JS_IsException(str_val))
-        return str_val;
-    val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex);
-    if (JS_IsException(val) ||
-        JS_ToLengthFree(ctx, &last_index, val)) {
-        JS_FreeValue(ctx, str_val);
-        return JS_EXCEPTION;
-    }
-    re_bytecode = re->bytecode->u.str8;
-    re_flags = lre_get_flags(re_bytecode);
-    if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {
-        last_index = 0;
-    }
-    str = JS_VALUE_GET_STRING(str_val);
-    capture_count = lre_get_capture_count(re_bytecode);
-    capture = NULL;
-    if (capture_count > 0) {
-        capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2);
-        if (!capture) {
-            JS_FreeValue(ctx, str_val);
-            return JS_EXCEPTION;
-        }
-    }
-    shift = str->is_wide_char;
-    str_buf = str->u.str8;
-    if (last_index > str->len) {
-        ret = 2;
-    } else {
-        ret = lre_exec(capture, re_bytecode,
-                       str_buf, last_index, str->len,
-                       shift, ctx);
-    }
-    obj = JS_NULL;
-    if (ret != 1) {
-        if (ret >= 0) {
-            if (ret == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
-                if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
-                                   JS_NewInt32(ctx, 0)) < 0)
-                    goto fail;
-            }
-        } else {
-            JS_ThrowInternalError(ctx, "out of memory in regexp execution");
-            goto fail;
-        }
-        JS_FreeValue(ctx, str_val);
-    } else {
-        int prop_flags;
-        if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) {
-            if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
-                               JS_NewInt32(ctx, (capture[1] - str_buf) >> shift)) < 0)
-                goto fail;
-        }
-        obj = JS_NewArray(ctx);
-        if (JS_IsException(obj))
-            goto fail;
-        prop_flags = JS_PROP_C_W_E | JS_PROP_THROW;
-        group_name_ptr = lre_get_groupnames(re_bytecode);
-        if (group_name_ptr) {
-            groups = JS_NewObjectProto(ctx, JS_NULL);
-            if (JS_IsException(groups))
-                goto fail;
-        }
-
-        for(i = 0; i < capture_count; i++) {
-            int start, end;
-            JSValue val;
-            if (capture[2 * i] == NULL ||
-                capture[2 * i + 1] == NULL) {
-                val = JS_UNDEFINED;
-            } else {
-                start = (capture[2 * i] - str_buf) >> shift;
-                end = (capture[2 * i + 1] - str_buf) >> shift;
-                val = js_sub_string(ctx, str, start, end);
-                if (JS_IsException(val))
-                    goto fail;
-            }
-            if (group_name_ptr && i > 0) {
-                if (*group_name_ptr) {
-                    if (JS_DefinePropertyValueStr(ctx, groups, group_name_ptr,
-                                                  JS_DupValue(ctx, val),
-                                                  prop_flags) < 0) {
-                        JS_FreeValue(ctx, val);
-                        goto fail;
-                    }
-                }
-                group_name_ptr += strlen(group_name_ptr) + 1;
-            }
-            if (JS_DefinePropertyValueUint32(ctx, obj, i, val, prop_flags) < 0)
-                goto fail;
-        }
-        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_groups,
-                                   groups, prop_flags) < 0)
-            goto fail;
-        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_index,
-                                   JS_NewInt32(ctx, (capture[0] - str_buf) >> shift), prop_flags) < 0)
-            goto fail;
-        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_input, str_val, prop_flags) < 0)
-            goto fail1;
-    }
-    js_free(ctx, capture);
-    return obj;
-fail:
-    JS_FreeValue(ctx, groups);
-    JS_FreeValue(ctx, str_val);
-fail1:
-    JS_FreeValue(ctx, obj);
-    js_free(ctx, capture);
-    return JS_EXCEPTION;
-}
-
-/* delete portions of a string that match a given regex */
-static JSValue JS_RegExpDelete(JSContext *ctx, JSValueConst this_val, JSValueConst arg)
-{
-    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
-    JSString *str;
-    JSValue str_val, val;
-    uint8_t *re_bytecode;
-    int ret;
-    uint8_t **capture, *str_buf;
-    int capture_count, shift, re_flags;
-    int next_src_pos, start, end;
-    int64_t last_index;
-    StringBuffer b_s, *b = &b_s;
-
-    if (!re)
-        return JS_EXCEPTION;
-
-    string_buffer_init(ctx, b, 0);
-
-    capture = NULL;
-    str_val = JS_ToString(ctx, arg);
-    if (JS_IsException(str_val))
-        goto fail;
-    str = JS_VALUE_GET_STRING(str_val);
-    re_bytecode = re->bytecode->u.str8;
-    re_flags = lre_get_flags(re_bytecode);
-    if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {
-        last_index = 0;
-    } else {
-        val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex);
-        if (JS_IsException(val) || JS_ToLengthFree(ctx, &last_index, val))
-            goto fail;
-    }
-    capture_count = lre_get_capture_count(re_bytecode);
-    if (capture_count > 0) {
-        capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2);
-        if (!capture)
-            goto fail;
-    }
-    shift = str->is_wide_char;
-    str_buf = str->u.str8;
-    next_src_pos = 0;
-    for (;;) {
-        if (last_index > str->len)
-            break;
-
-        ret = lre_exec(capture, re_bytecode,
-                       str_buf, last_index, str->len, shift, ctx);
-        if (ret != 1) {
-            if (ret >= 0) {
-                if (ret == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
-                    if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
-                                       JS_NewInt32(ctx, 0)) < 0)
-                        goto fail;
-                }
-            } else {
-                JS_ThrowInternalError(ctx, "out of memory in regexp execution");
-                goto fail;
-            }
-            break;
-        }
-        start = (capture[0] - str_buf) >> shift;
-        end = (capture[1] - str_buf) >> shift;
-        last_index = end;
-        if (next_src_pos < start) {
-            if (string_buffer_concat(b, str, next_src_pos, start))
-                goto fail;
-        }
-        next_src_pos = end;
-        if (!(re_flags & LRE_FLAG_GLOBAL)) {
-            if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
-                               JS_NewInt32(ctx, end)) < 0)
-                goto fail;
-            break;
-        }
-        if (end == start) {
-            if (!(re_flags & LRE_FLAG_UTF16) || (unsigned)end >= str->len || !str->is_wide_char) {
-                end++;
-            } else {
-                string_getc(str, &end);
-            }
-        }
-        last_index = end;
-    }
-    if (string_buffer_concat(b, str, next_src_pos, str->len))
-        goto fail;
-    JS_FreeValue(ctx, str_val);
-    js_free(ctx, capture);
-    return string_buffer_end(b);
-fail:
-    JS_FreeValue(ctx, str_val);
-    js_free(ctx, capture);
-    string_buffer_free(b);
-    return JS_EXCEPTION;
-}
-
-static JSValue JS_RegExpExec(JSContext *ctx, JSValueConst r, JSValueConst s)
-{
-    JSValue method, ret;
-
-    method = JS_GetProperty(ctx, r, JS_ATOM_exec);
-    if (JS_IsException(method))
-        return method;
-    if (JS_IsFunction(ctx, method)) {
-        ret = JS_CallFree(ctx, method, r, 1, &s);
-        if (JS_IsException(ret))
-            return ret;
-        if (!JS_IsObject(ret) && !JS_IsNull(ret)) {
-            JS_FreeValue(ctx, ret);
-            return JS_ThrowTypeError(ctx, "RegExp exec method must return an object or null");
-        }
-        return ret;
-    }
-    JS_FreeValue(ctx, method);
-    return js_regexp_exec(ctx, r, 1, &s);
-}
-
-#if 0
-static JSValue js_regexp___RegExpExec(JSContext *ctx, JSValueConst this_val,
-                                      int argc, JSValueConst *argv)
-{
-    return JS_RegExpExec(ctx, argv[0], argv[1]);
-}
-static JSValue js_regexp___RegExpDelete(JSContext *ctx, JSValueConst this_val,
-                                        int argc, JSValueConst *argv)
-{
-    return JS_RegExpDelete(ctx, argv[0], argv[1]);
-}
-#endif
-
-static JSValue js_regexp_test(JSContext *ctx, JSValueConst this_val,
-                              int argc, JSValueConst *argv)
-{
-    JSValue val;
-    BOOL ret;
-
-    val = JS_RegExpExec(ctx, this_val, argv[0]);
-    if (JS_IsException(val))
-        return JS_EXCEPTION;
-    ret = !JS_IsNull(val);
-    JS_FreeValue(ctx, val);
-    return JS_NewBool(ctx, ret);
-}
-
-static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val,
-                                      int argc, JSValueConst *argv)
-{
-    // [Symbol.match](str)
-    JSValueConst rx = this_val;
-    JSValue A, S, result, matchStr;
-    int global, n, fullUnicode, isEmpty;
-    JSString *p;
-
-    if (!JS_IsObject(rx))
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-
-    A = JS_UNDEFINED;
-    result = JS_UNDEFINED;
-    matchStr = JS_UNDEFINED;
-    S = JS_ToString(ctx, argv[0]);
-    if (JS_IsException(S))
-        goto exception;
-
-    global = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_global));
-    if (global < 0)
-        goto exception;
-
-    if (!global) {
-        A = JS_RegExpExec(ctx, rx, S);
-    } else {
-        fullUnicode = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_unicode));
-        if (fullUnicode < 0)
-            goto exception;
-
-        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0)
-            goto exception;
-        A = JS_NewArray(ctx);
-        if (JS_IsException(A))
-            goto exception;
-        n = 0;
-        for(;;) {
-            JS_FreeValue(ctx, result);
-            result = JS_RegExpExec(ctx, rx, S);
-            if (JS_IsException(result))
-                goto exception;
-            if (JS_IsNull(result))
-                break;
-            matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
-            if (JS_IsException(matchStr))
-                goto exception;
-            isEmpty = JS_IsEmptyString(matchStr);
-            if (JS_SetPropertyInt64(ctx, A, n++, matchStr) < 0)
-                goto exception;
-            if (isEmpty) {
-                int64_t thisIndex, nextIndex;
-                if (JS_ToLengthFree(ctx, &thisIndex,
-                                    JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0)
-                    goto exception;
-                p = JS_VALUE_GET_STRING(S);
-                nextIndex = string_advance_index(p, thisIndex, fullUnicode);
-                if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0)
-                    goto exception;
-            }
-        }
-        if (n == 0) {
-            JS_FreeValue(ctx, A);
-            A = JS_NULL;
-        }
-    }
-    JS_FreeValue(ctx, result);
-    JS_FreeValue(ctx, S);
-    return A;
-
-exception:
-    JS_FreeValue(ctx, A);
-    JS_FreeValue(ctx, result);
-    JS_FreeValue(ctx, S);
-    return JS_EXCEPTION;
-}
-
-typedef struct JSRegExpStringIteratorData {
-    JSValue iterating_regexp;
-    JSValue iterated_string;
-    BOOL global;
-    BOOL unicode;
-    BOOL done;
-} JSRegExpStringIteratorData;
-
-static void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data;
-    if (it) {
-        JS_FreeValueRT(rt, it->iterating_regexp);
-        JS_FreeValueRT(rt, it->iterated_string);
-        js_free_rt(rt, it);
-    }
-}
-
-static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val,
-                                           JS_MarkFunc *mark_func)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data;
-    if (it) {
-        JS_MarkValue(rt, it->iterating_regexp, mark_func);
-        JS_MarkValue(rt, it->iterated_string, mark_func);
-    }
-}
-
-static JSValue js_regexp_string_iterator_next(JSContext *ctx,
-                                              JSValueConst this_val,
-                                              int argc, JSValueConst *argv,
-                                              BOOL *pdone, int magic)
-{
-    JSRegExpStringIteratorData *it;
-    JSValueConst R, S;
-    JSValue matchStr = JS_UNDEFINED, match = JS_UNDEFINED;
-    JSString *sp;
-
-    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_REGEXP_STRING_ITERATOR);
-    if (!it)
-        goto exception;
-    if (it->done) {
-        *pdone = TRUE;
-        return JS_UNDEFINED;
-    }
-    R = it->iterating_regexp;
-    S = it->iterated_string;
-    match = JS_RegExpExec(ctx, R, S);
-    if (JS_IsException(match))
-        goto exception;
-    if (JS_IsNull(match)) {
-        it->done = TRUE;
-        *pdone = TRUE;
-        return JS_UNDEFINED;
-    } else if (it->global) {
-        matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, match, 0));
-        if (JS_IsException(matchStr))
-            goto exception;
-        if (JS_IsEmptyString(matchStr)) {
-            int64_t thisIndex, nextIndex;
-            if (JS_ToLengthFree(ctx, &thisIndex,
-                                JS_GetProperty(ctx, R, JS_ATOM_lastIndex)) < 0)
-                goto exception;
-            sp = JS_VALUE_GET_STRING(S);
-            nextIndex = string_advance_index(sp, thisIndex, it->unicode);
-            if (JS_SetProperty(ctx, R, JS_ATOM_lastIndex,
-                               JS_NewInt64(ctx, nextIndex)) < 0)
-                goto exception;
-        }
-        JS_FreeValue(ctx, matchStr);
-    } else {
-        it->done = TRUE;
-    }
-    *pdone = FALSE;
-    return match;
- exception:
-    JS_FreeValue(ctx, match);
-    JS_FreeValue(ctx, matchStr);
-    *pdone = FALSE;
-    return JS_EXCEPTION;
-}
-
-static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val,
-                                         int argc, JSValueConst *argv)
-{
-    // [Symbol.matchAll](str)
-    JSValueConst R = this_val;
-    JSValue S, C, flags, matcher, iter;
-    JSValueConst args[2];
-    JSString *strp;
-    int64_t lastIndex;
-    JSRegExpStringIteratorData *it;
-    
-    if (!JS_IsObject(R))
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-
-    C = JS_UNDEFINED;
-    flags = JS_UNDEFINED;
-    matcher = JS_UNDEFINED;
-    iter = JS_UNDEFINED;
-    
-    S = JS_ToString(ctx, argv[0]);
-    if (JS_IsException(S))
-        goto exception;
-    C = JS_SpeciesConstructor(ctx, R, ctx->regexp_ctor);
-    if (JS_IsException(C))
-        goto exception;
-    flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, R, JS_ATOM_flags));
-    if (JS_IsException(flags))
-        goto exception;
-    args[0] = R;
-    args[1] = flags;
-    matcher = JS_CallConstructor(ctx, C, 2, args);
-    if (JS_IsException(matcher))
-        goto exception;
-    if (JS_ToLengthFree(ctx, &lastIndex,
-                        JS_GetProperty(ctx, R, JS_ATOM_lastIndex)))
-        goto exception;
-    if (JS_SetProperty(ctx, matcher, JS_ATOM_lastIndex,
-                       JS_NewInt64(ctx, lastIndex)) < 0)
-        goto exception;
-    
-    iter = JS_NewObjectClass(ctx, JS_CLASS_REGEXP_STRING_ITERATOR);
-    if (JS_IsException(iter))
-        goto exception;
-    it = js_malloc(ctx, sizeof(*it));
-    if (!it)
-        goto exception;
-    it->iterating_regexp = matcher;
-    it->iterated_string = S;
-    strp = JS_VALUE_GET_STRING(flags);
-    it->global = string_indexof_char(strp, 'g', 0) >= 0;
-    it->unicode = string_indexof_char(strp, 'u', 0) >= 0;
-    it->done = FALSE;
-    JS_SetOpaque(iter, it);
-
-    JS_FreeValue(ctx, C);
-    JS_FreeValue(ctx, flags);
-    return iter;
- exception:
-    JS_FreeValue(ctx, S);
-    JS_FreeValue(ctx, C);
-    JS_FreeValue(ctx, flags);
-    JS_FreeValue(ctx, matcher);
-    JS_FreeValue(ctx, iter);
-    return JS_EXCEPTION;
-}
-
-typedef struct ValueBuffer {
-    JSContext *ctx;
-    JSValue *arr;
-    JSValue def[4];
-    int len;
-    int size;
-    int error_status;
-} ValueBuffer;
-
-static int value_buffer_init(JSContext *ctx, ValueBuffer *b)
-{
-    b->ctx = ctx;
-    b->len = 0;
-    b->size = 4;
-    b->error_status = 0;
-    b->arr = b->def;
-    return 0;
-}
-
-static void value_buffer_free(ValueBuffer *b)
-{
-    while (b->len > 0)
-        JS_FreeValue(b->ctx, b->arr[--b->len]);
-    if (b->arr != b->def)
-        js_free(b->ctx, b->arr);
-    b->arr = b->def;
-    b->size = 4;
-}
-
-static int value_buffer_append(ValueBuffer *b, JSValue val)
-{
-    if (b->error_status)
-        return -1;
-
-    if (b->len >= b->size) {
-        int new_size = (b->len + (b->len >> 1) + 31) & ~16;
-        size_t slack;
-        JSValue *new_arr;
-
-        if (b->arr == b->def) {
-            new_arr = js_realloc2(b->ctx, NULL, sizeof(*b->arr) * new_size, &slack);
-            if (new_arr)
-                memcpy(new_arr, b->def, sizeof b->def);
-        } else {
-            new_arr = js_realloc2(b->ctx, b->arr, sizeof(*b->arr) * new_size, &slack);
-        }
-        if (!new_arr) {
-            value_buffer_free(b);
-            JS_FreeValue(b->ctx, val);
-            b->error_status = -1;
-            return -1;
-        }
-        new_size += slack / sizeof(*new_arr);
-        b->arr = new_arr;
-        b->size = new_size;
-    }
-    b->arr[b->len++] = val;
-    return 0;
-}
-
-static int js_is_standard_regexp(JSContext *ctx, JSValueConst rx)
-{
-    JSValue val;
-    int res;
-
-    val = JS_GetProperty(ctx, rx, JS_ATOM_constructor);
-    if (JS_IsException(val))
-        return -1;
-    // rx.constructor === RegExp
-    res = js_same_value(ctx, val, ctx->regexp_ctor);
-    JS_FreeValue(ctx, val);
-    if (res) {
-        val = JS_GetProperty(ctx, rx, JS_ATOM_exec);
-        if (JS_IsException(val))
-            return -1;
-        // rx.exec === RE_exec
-        res = JS_IsCFunction(ctx, val, js_regexp_exec, 0);
-        JS_FreeValue(ctx, val);
-    }
-    return res;
-}
-
-static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
-                                        int argc, JSValueConst *argv)
-{
-    // [Symbol.replace](str, rep)
-    JSValueConst rx = this_val, rep = argv[1];
-    JSValueConst args[6];
-    JSValue str, rep_val, matched, tab, rep_str, namedCaptures, res;
-    JSString *sp, *rp;
-    StringBuffer b_s, *b = &b_s;
-    ValueBuffer v_b, *results = &v_b;
-    int nextSourcePosition, n, j, functionalReplace, is_global, fullUnicode;
-    uint32_t nCaptures;
-    int64_t position;
-
-    if (!JS_IsObject(rx))
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-
-    string_buffer_init(ctx, b, 0);
-    value_buffer_init(ctx, results);
-
-    rep_val = JS_UNDEFINED;
-    matched = JS_UNDEFINED;
-    tab = JS_UNDEFINED;
-    rep_str = JS_UNDEFINED;
-    namedCaptures = JS_UNDEFINED;
-
-    str = JS_ToString(ctx, argv[0]);
-    if (JS_IsException(str))
-        goto exception;
-        
-    sp = JS_VALUE_GET_STRING(str);
-    rp = NULL;
-    functionalReplace = JS_IsFunction(ctx, rep);
-    if (!functionalReplace) {
-        rep_val = JS_ToString(ctx, rep);
-        if (JS_IsException(rep_val))
-            goto exception;
-        rp = JS_VALUE_GET_STRING(rep_val);
-    }
-    fullUnicode = 0;
-    is_global = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_global));
-    if (is_global < 0)
-        goto exception;
-    if (is_global) {
-        fullUnicode = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_unicode));
-        if (fullUnicode < 0)
-            goto exception;
-        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0)
-            goto exception;
-    }
-
-    if (rp && rp->len == 0 && is_global && js_is_standard_regexp(ctx, rx)) {
-        /* use faster version for simple cases */
-        res = JS_RegExpDelete(ctx, rx, str);
-        goto done;
-    }
-    for(;;) {
-        JSValue result;
-        result = JS_RegExpExec(ctx, rx, str);
-        if (JS_IsException(result))
-            goto exception;
-        if (JS_IsNull(result))
-            break;
-        if (value_buffer_append(results, result) < 0)
-            goto exception;
-        if (!is_global)
-            break;
-        JS_FreeValue(ctx, matched);
-        matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
-        if (JS_IsException(matched))
-            goto exception;
-        if (JS_IsEmptyString(matched)) {
-            /* always advance of at least one char */
-            int64_t thisIndex, nextIndex;
-            if (JS_ToLengthFree(ctx, &thisIndex, JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0)
-                goto exception;
-            nextIndex = string_advance_index(sp, thisIndex, fullUnicode);
-            if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0)
-                goto exception;
-        }
-    }
-    nextSourcePosition = 0;
-    for(j = 0; j < results->len; j++) {
-        JSValueConst result;
-        result = results->arr[j];
-        if (js_get_length32(ctx, &nCaptures, result) < 0)
-            goto exception;
-        JS_FreeValue(ctx, matched);
-        matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
-        if (JS_IsException(matched))
-            goto exception;
-        if (JS_ToLengthFree(ctx, &position, JS_GetProperty(ctx, result, JS_ATOM_index)))
-            goto exception;
-        if (position > sp->len)
-            position = sp->len;
-        else if (position < 0)
-            position = 0;
-        /* ignore substition if going backward (can happen
-           with custom regexp object) */
-        JS_FreeValue(ctx, tab);
-        tab = JS_NewArray(ctx);
-        if (JS_IsException(tab))
-            goto exception;
-        if (JS_DefinePropertyValueInt64(ctx, tab, 0, JS_DupValue(ctx, matched),
-                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)
-            goto exception;
-        for(n = 1; n < nCaptures; n++) {
-            JSValue capN;
-            capN = JS_GetPropertyInt64(ctx, result, n);
-            if (JS_IsException(capN))
-                goto exception;
-            if (!JS_IsUndefined(capN)) {
-                capN = JS_ToStringFree(ctx, capN);
-                if (JS_IsException(capN))
-                    goto exception;
-            }
-            if (JS_DefinePropertyValueInt64(ctx, tab, n, capN,
-                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)
-                goto exception;
-        }
-        JS_FreeValue(ctx, namedCaptures);
-        namedCaptures = JS_GetProperty(ctx, result, JS_ATOM_groups);
-        if (JS_IsException(namedCaptures))
-            goto exception;
-        if (functionalReplace) {
-            if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_NewInt32(ctx, position), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
-                goto exception;
-            if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, str), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
-                goto exception;
-            if (!JS_IsUndefined(namedCaptures)) {
-                if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, namedCaptures), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
-                    goto exception;
-            }
-            args[0] = JS_UNDEFINED;
-            args[1] = tab;
-            JS_FreeValue(ctx, rep_str);
-            rep_str = JS_ToStringFree(ctx, js_function_apply(ctx, rep, 2, args, 0));
-        } else {
-            JSValue namedCaptures1;
-            if (!JS_IsUndefined(namedCaptures)) {
-                namedCaptures1 = JS_ToObject(ctx, namedCaptures);
-                if (JS_IsException(namedCaptures1))
-                    goto exception;
-            } else {
-                namedCaptures1 = JS_UNDEFINED;
-            }
-            args[0] = matched;
-            args[1] = str;
-            args[2] = JS_NewInt32(ctx, position);
-            args[3] = tab;
-            args[4] = namedCaptures1;
-            args[5] = rep_val;
-            JS_FreeValue(ctx, rep_str);
-            rep_str = js_string___GetSubstitution(ctx, JS_UNDEFINED, 6, args);
-            JS_FreeValue(ctx, namedCaptures1);
-        }
-        if (JS_IsException(rep_str))
-            goto exception;
-        if (position >= nextSourcePosition) {
-            string_buffer_concat(b, sp, nextSourcePosition, position);
-            string_buffer_concat_value(b, rep_str);
-            nextSourcePosition = position + JS_VALUE_GET_STRING(matched)->len;
-        }
-    }
-    string_buffer_concat(b, sp, nextSourcePosition, sp->len);
-    res = string_buffer_end(b);
-    goto done1;
-
-exception:
-    res = JS_EXCEPTION;
-done:
-    string_buffer_free(b);
-done1:
-    value_buffer_free(results);
-    JS_FreeValue(ctx, rep_val);
-    JS_FreeValue(ctx, matched);
-    JS_FreeValue(ctx, tab);
-    JS_FreeValue(ctx, rep_str);
-    JS_FreeValue(ctx, namedCaptures);
-    JS_FreeValue(ctx, str);
-    return res;
-}
-
-static JSValue js_regexp_Symbol_search(JSContext *ctx, JSValueConst this_val,
-                                       int argc, JSValueConst *argv)
-{
-    JSValueConst rx = this_val;
-    JSValue str, previousLastIndex, currentLastIndex, result, index;
-
-    if (!JS_IsObject(rx))
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-
-    result = JS_UNDEFINED;
-    currentLastIndex = JS_UNDEFINED;
-    previousLastIndex = JS_UNDEFINED;
-    str = JS_ToString(ctx, argv[0]);
-    if (JS_IsException(str))
-        goto exception;
-
-    previousLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex);
-    if (JS_IsException(previousLastIndex))
-        goto exception;
-
-    if (!js_same_value(ctx, previousLastIndex, JS_NewInt32(ctx, 0))) {
-        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0) {
-            goto exception;
-        }
-    }
-    result = JS_RegExpExec(ctx, rx, str);
-    if (JS_IsException(result))
-        goto exception;
-    currentLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex);
-    if (JS_IsException(currentLastIndex))
-        goto exception;
-    if (js_same_value(ctx, currentLastIndex, previousLastIndex)) {
-        JS_FreeValue(ctx, previousLastIndex);
-    } else {
-        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, previousLastIndex) < 0) {
-            previousLastIndex = JS_UNDEFINED;
-            goto exception;
-        }
-    }
-    JS_FreeValue(ctx, str);
-    JS_FreeValue(ctx, currentLastIndex);
-
-    if (JS_IsNull(result)) {
-        return JS_NewInt32(ctx, -1);
-    } else {
-        index = JS_GetProperty(ctx, result, JS_ATOM_index);
-        JS_FreeValue(ctx, result);
-        return index;
-    }
-
-exception:
-    JS_FreeValue(ctx, result);
-    JS_FreeValue(ctx, str);
-    JS_FreeValue(ctx, currentLastIndex);
-    JS_FreeValue(ctx, previousLastIndex);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val,
-                                       int argc, JSValueConst *argv)
-{
-    // [Symbol.split](str, limit)
-    JSValueConst rx = this_val;
-    JSValueConst args[2];
-    JSValue str, ctor, splitter, A, flags, z, sub;
-    JSString *strp;
-    uint32_t lim, size, p, q;
-    int unicodeMatching;
-    int64_t lengthA, e, numberOfCaptures, i;
-
-    if (!JS_IsObject(rx))
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-
-    ctor = JS_UNDEFINED;
-    splitter = JS_UNDEFINED;
-    A = JS_UNDEFINED;
-    flags = JS_UNDEFINED;
-    z = JS_UNDEFINED;
-    str = JS_ToString(ctx, argv[0]);
-    if (JS_IsException(str))
-        goto exception;
-    ctor = JS_SpeciesConstructor(ctx, rx, ctx->regexp_ctor);
-    if (JS_IsException(ctor))
-        goto exception;
-    flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_flags));
-    if (JS_IsException(flags))
-        goto exception;
-    strp = JS_VALUE_GET_STRING(flags);
-    unicodeMatching = string_indexof_char(strp, 'u', 0) >= 0;
-    if (string_indexof_char(strp, 'y', 0) < 0) {
-        flags = JS_ConcatString3(ctx, "", flags, "y");
-        if (JS_IsException(flags))
-            goto exception;
-    }
-    args[0] = rx;
-    args[1] = flags;
-    splitter = JS_CallConstructor(ctx, ctor, 2, args);
-    if (JS_IsException(splitter))
-        goto exception;
-    A = JS_NewArray(ctx);
-    if (JS_IsException(A))
-        goto exception;
-    lengthA = 0;
-    if (JS_IsUndefined(argv[1])) {
-        lim = 0xffffffff;
-    } else {
-        if (JS_ToUint32(ctx, &lim, argv[1]) < 0)
-            goto exception;
-        if (lim == 0)
-            goto done;
-    }
-    strp = JS_VALUE_GET_STRING(str);
-    p = q = 0;
-    size = strp->len;
-    if (size == 0) {
-        z = JS_RegExpExec(ctx, splitter, str);
-        if (JS_IsException(z))
-            goto exception;
-        if (JS_IsNull(z))
-            goto add_tail;
-        goto done;
-    }
-    while (q < size) {
-        if (JS_SetProperty(ctx, splitter, JS_ATOM_lastIndex, JS_NewInt32(ctx, q)) < 0)
-            goto exception;
-        JS_FreeValue(ctx, z);    
-        z = JS_RegExpExec(ctx, splitter, str);
-        if (JS_IsException(z))
-            goto exception;
-        if (JS_IsNull(z)) {
-            q = string_advance_index(strp, q, unicodeMatching);
-        } else {
-            if (JS_ToLengthFree(ctx, &e, JS_GetProperty(ctx, splitter, JS_ATOM_lastIndex)))
-                goto exception;
-            if (e > size)
-                e = size;
-            if (e == p) {
-                q = string_advance_index(strp, q, unicodeMatching);
-            } else {
-                sub = js_sub_string(ctx, strp, p, q);
-                if (JS_IsException(sub))
-                    goto exception;
-                if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub,
-                                                JS_PROP_C_W_E | JS_PROP_THROW) < 0)
-                    goto exception;
-                if (lengthA == lim)
-                    goto done;
-                p = e;
-                if (js_get_length64(ctx, &numberOfCaptures, z))
-                    goto exception;
-                for(i = 1; i < numberOfCaptures; i++) {
-                    sub = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, z, i));
-                    if (JS_IsException(sub))
-                        goto exception;
-                    if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
-                        goto exception;
-                    if (lengthA == lim)
-                        goto done;
-                }
-                q = p;
-            }
-        }
-    }
-add_tail:
-    if (p > size)
-        p = size;
-    sub = js_sub_string(ctx, strp, p, size);
-    if (JS_IsException(sub))
-        goto exception;
-    if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
-        goto exception;
-    goto done;
-exception:
-    JS_FreeValue(ctx, A);
-    A = JS_EXCEPTION;
-done:
-    JS_FreeValue(ctx, str);
-    JS_FreeValue(ctx, ctor);
-    JS_FreeValue(ctx, splitter);
-    JS_FreeValue(ctx, flags);
-    JS_FreeValue(ctx, z);    
-    return A;
-}
-
-static const JSCFunctionListEntry js_regexp_funcs[] = {
-    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
-    //JS_CFUNC_DEF("__RegExpExec", 2, js_regexp___RegExpExec ),
-    //JS_CFUNC_DEF("__RegExpDelete", 2, js_regexp___RegExpDelete ),
-};
-
-static const JSCFunctionListEntry js_regexp_proto_funcs[] = {
-    JS_CGETSET_DEF("flags", js_regexp_get_flags, NULL ),
-    JS_CGETSET_DEF("source", js_regexp_get_source, NULL ),
-    JS_CGETSET_MAGIC_DEF("global", js_regexp_get_flag, NULL, 1 ),
-    JS_CGETSET_MAGIC_DEF("ignoreCase", js_regexp_get_flag, NULL, 2 ),
-    JS_CGETSET_MAGIC_DEF("multiline", js_regexp_get_flag, NULL, 4 ),
-    JS_CGETSET_MAGIC_DEF("dotAll", js_regexp_get_flag, NULL, 8 ),
-    JS_CGETSET_MAGIC_DEF("unicode", js_regexp_get_flag, NULL, 16 ),
-    JS_CGETSET_MAGIC_DEF("sticky", js_regexp_get_flag, NULL, 32 ),
-    JS_CFUNC_DEF("exec", 1, js_regexp_exec ),
-    JS_CFUNC_DEF("compile", 2, js_regexp_compile ),
-    JS_CFUNC_DEF("test", 1, js_regexp_test ),
-    JS_CFUNC_DEF("toString", 0, js_regexp_toString ),
-    JS_CFUNC_DEF("[Symbol.replace]", 2, js_regexp_Symbol_replace ),
-    JS_CFUNC_DEF("[Symbol.match]", 1, js_regexp_Symbol_match ),
-    JS_CFUNC_DEF("[Symbol.matchAll]", 1, js_regexp_Symbol_matchAll ),
-    JS_CFUNC_DEF("[Symbol.search]", 1, js_regexp_Symbol_search ),
-    JS_CFUNC_DEF("[Symbol.split]", 2, js_regexp_Symbol_split ),
-    //JS_CGETSET_DEF("__source", js_regexp_get___source, NULL ),
-    //JS_CGETSET_DEF("__flags", js_regexp_get___flags, NULL ),
-};
-
-static const JSCFunctionListEntry js_regexp_string_iterator_proto_funcs[] = {
-    JS_ITERATOR_NEXT_DEF("next", 0, js_regexp_string_iterator_next, 0 ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "RegExp String Iterator", JS_PROP_CONFIGURABLE ),
-};
-
-void JS_AddIntrinsicRegExpCompiler(JSContext *ctx)
-{
-    ctx->compile_regexp = js_compile_regexp;
-}
-
-void JS_AddIntrinsicRegExp(JSContext *ctx)
-{
-    JSValueConst obj;
-
-    JS_AddIntrinsicRegExpCompiler(ctx);
-
-    ctx->class_proto[JS_CLASS_REGEXP] = JS_NewObject(ctx);
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_REGEXP], js_regexp_proto_funcs,
-                               countof(js_regexp_proto_funcs));
-    obj = JS_NewGlobalCConstructor(ctx, "RegExp", js_regexp_constructor, 2,
-                                   ctx->class_proto[JS_CLASS_REGEXP]);
-    ctx->regexp_ctor = JS_DupValue(ctx, obj);
-    JS_SetPropertyFunctionList(ctx, obj, js_regexp_funcs, countof(js_regexp_funcs));
-
-    ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR] =
-        JS_NewObjectProto(ctx, ctx->iterator_proto);
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR],
-                               js_regexp_string_iterator_proto_funcs,
-                               countof(js_regexp_string_iterator_proto_funcs));
-}
-
-/* JSON */
-
-static int json_parse_expect(JSParseState *s, int tok)
-{
-    if (s->token.val != tok) {
-        /* XXX: dump token correctly in all cases */
-        return js_parse_error(s, "expecting '%c'", tok);
-    }
-    return json_next_token(s);
-}
-
-static JSValue json_parse_value(JSParseState *s)
-{
-    JSContext *ctx = s->ctx;
-    JSValue val = JS_NULL;
-    int ret;
-
-    switch(s->token.val) {
-    case '{':
-        {
-            JSValue prop_val;
-            JSAtom prop_name;
-            
-            if (json_next_token(s))
-                goto fail;
-            val = JS_NewObject(ctx);
-            if (JS_IsException(val))
-                goto fail;
-            if (s->token.val != '}') {
-                for(;;) {
-                    if (s->token.val == TOK_STRING) {
-                        prop_name = JS_ValueToAtom(ctx, s->token.u.str.str);
-                        if (prop_name == JS_ATOM_NULL)
-                            goto fail;
-                    } else if (s->ext_json && s->token.val == TOK_IDENT) {
-                        prop_name = JS_DupAtom(ctx, s->token.u.ident.atom);
-                    } else {
-                        js_parse_error(s, "expecting property name");
-                        goto fail;
-                    }
-                    if (json_next_token(s))
-                        goto fail1;
-                    if (json_parse_expect(s, ':'))
-                        goto fail1;
-                    prop_val = json_parse_value(s);
-                    if (JS_IsException(prop_val)) {
-                    fail1:
-                        JS_FreeAtom(ctx, prop_name);
-                        goto fail;
-                    }
-                    ret = JS_DefinePropertyValue(ctx, val, prop_name,
-                                                 prop_val, JS_PROP_C_W_E);
-                    JS_FreeAtom(ctx, prop_name);
-                    if (ret < 0)
-                        goto fail;
-
-                    if (s->token.val != ',')
-                        break;
-                    if (json_next_token(s))
-                        goto fail;
-                    if (s->ext_json && s->token.val == '}')
-                        break;
-                }
-            }
-            if (json_parse_expect(s, '}'))
-                goto fail;
-        }
-        break;
-    case '[':
-        {
-            JSValue el;
-            uint32_t idx;
-
-            if (json_next_token(s))
-                goto fail;
-            val = JS_NewArray(ctx);
-            if (JS_IsException(val))
-                goto fail;
-            if (s->token.val != ']') {
-                idx = 0;
-                for(;;) {
-                    el = json_parse_value(s);
-                    if (JS_IsException(el))
-                        goto fail;
-                    ret = JS_DefinePropertyValueUint32(ctx, val, idx, el, JS_PROP_C_W_E);
-                    if (ret < 0)
-                        goto fail;
-                    if (s->token.val != ',')
-                        break;
-                    if (json_next_token(s))
-                        goto fail;
-                    idx++;
-                    if (s->ext_json && s->token.val == ']')
-                        break;
-                }
-            }
-            if (json_parse_expect(s, ']'))
-                goto fail;
-        }
-        break;
-    case TOK_STRING:
-        val = JS_DupValue(ctx, s->token.u.str.str);
-        if (json_next_token(s))
-            goto fail;
-        break;
-    case TOK_NUMBER:
-        val = s->token.u.num.val;
-        if (json_next_token(s))
-            goto fail;
-        break;
-    case TOK_IDENT:
-        if (s->token.u.ident.atom == JS_ATOM_false ||
-            s->token.u.ident.atom == JS_ATOM_true) {
-            val = JS_NewBool(ctx, (s->token.u.ident.atom == JS_ATOM_true));
-        } else if (s->token.u.ident.atom == JS_ATOM_null) {
-            val = JS_NULL;
-        } else {
-            goto def_token;
-        }
-        if (json_next_token(s))
-            goto fail;
-        break;
-    default:
-    def_token:
-        if (s->token.val == TOK_EOF) {
-            js_parse_error(s, "unexpected end of input");
-        } else {
-            js_parse_error(s, "unexpected token: '%.*s'",
-                           (int)(s->buf_ptr - s->token.ptr), s->token.ptr);
-        }
-        goto fail;
-    }
-    return val;
- fail:
-    JS_FreeValue(ctx, val);
-    return JS_EXCEPTION;
-}
-
-JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
-                      const char *filename, int flags)
-{
-    JSParseState s1, *s = &s1;
-    JSValue val = JS_UNDEFINED;
-
-    js_parse_init(ctx, s, buf, buf_len, filename);
-    s->ext_json = ((flags & JS_PARSE_JSON_EXT) != 0);
-    if (json_next_token(s))
-        goto fail;
-    val = json_parse_value(s);
-    if (JS_IsException(val))
-        goto fail;
-    if (s->token.val != TOK_EOF) {
-        if (js_parse_error(s, "unexpected data at the end"))
-            goto fail;
-    }
-    return val;
- fail:
-    JS_FreeValue(ctx, val);
-    free_token(s, &s->token);
-    return JS_EXCEPTION;
-}
-
-JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
-                     const char *filename)
-{
-    return JS_ParseJSON2(ctx, buf, buf_len, filename, 0); 
-}
-
-static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
-                                         JSAtom name, JSValueConst reviver)
-{
-    JSValue val, new_el, name_val, res;
-    JSValueConst args[2];
-    int ret, is_array;
-    uint32_t i, len = 0;
-    JSAtom prop;
-    JSPropertyEnum *atoms = NULL;
-
-    if (js_check_stack_overflow(ctx->rt, 0)) {
-        return JS_ThrowStackOverflow(ctx);
-    }
-
-    val = JS_GetProperty(ctx, holder, name);
-    if (JS_IsException(val))
-        return val;
-    if (JS_IsObject(val)) {
-        is_array = JS_IsArray(ctx, val);
-        if (is_array < 0)
-            goto fail;
-        if (is_array) {
-            if (js_get_length32(ctx, &len, val))
-                goto fail;
-        } else {
-            ret = JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, JS_VALUE_GET_OBJ(val), JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK);
-            if (ret < 0)
-                goto fail;
-        }
-        for(i = 0; i < len; i++) {
-            if (is_array) {
-                prop = JS_NewAtomUInt32(ctx, i);
-                if (prop == JS_ATOM_NULL)
-                    goto fail;
-            } else {
-                prop = JS_DupAtom(ctx, atoms[i].atom);
-            }
-            new_el = internalize_json_property(ctx, val, prop, reviver);
-            if (JS_IsException(new_el)) {
-                JS_FreeAtom(ctx, prop);
-                goto fail;
-            }
-            if (JS_IsUndefined(new_el)) {
-                ret = JS_DeleteProperty(ctx, val, prop, 0);
-            } else {
-                ret = JS_DefinePropertyValue(ctx, val, prop, new_el, JS_PROP_C_W_E);
-            }
-            JS_FreeAtom(ctx, prop);
-            if (ret < 0)
-                goto fail;
-        }
-    }
-    js_free_prop_enum(ctx, atoms, len);
-    atoms = NULL;
-    name_val = JS_AtomToValue(ctx, name);
-    if (JS_IsException(name_val))
-        goto fail;
-    args[0] = name_val;
-    args[1] = val;
-    res = JS_Call(ctx, reviver, holder, 2, args);
-    JS_FreeValue(ctx, name_val);
-    JS_FreeValue(ctx, val);
-    return res;
- fail:
-    js_free_prop_enum(ctx, atoms, len);
-    JS_FreeValue(ctx, val);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_json_parse(JSContext *ctx, JSValueConst this_val,
-                             int argc, JSValueConst *argv)
-{
-    JSValue obj, root;
-    JSValueConst reviver;
-    const char *str;
-    size_t len;
-
-    str = JS_ToCStringLen(ctx, &len, argv[0]);
-    if (!str)
-        return JS_EXCEPTION;
-    obj = JS_ParseJSON(ctx, str, len, "<input>");
-    JS_FreeCString(ctx, str);
-    if (JS_IsException(obj))
-        return obj;
-    if (argc > 1 && JS_IsFunction(ctx, argv[1])) {
-        reviver = argv[1];
-        root = JS_NewObject(ctx);
-        if (JS_IsException(root)) {
-            JS_FreeValue(ctx, obj);
-            return JS_EXCEPTION;
-        }
-        if (JS_DefinePropertyValue(ctx, root, JS_ATOM_empty_string, obj,
-                                   JS_PROP_C_W_E) < 0) {
-            JS_FreeValue(ctx, root);
-            return JS_EXCEPTION;
-        }
-        obj = internalize_json_property(ctx, root, JS_ATOM_empty_string,
-                                        reviver);
-        JS_FreeValue(ctx, root);
-    }
-    return obj;
-}
-
-typedef struct JSONStringifyContext {
-    JSValueConst replacer_func;
-    JSValue stack;
-    JSValue property_list;
-    JSValue gap;
-    JSValue empty;
-    StringBuffer *b;
-} JSONStringifyContext;
-
-static JSValue JS_ToQuotedStringFree(JSContext *ctx, JSValue val) {
-    JSValue r = JS_ToQuotedString(ctx, val);
-    JS_FreeValue(ctx, val);
-    return r;
-}
-
-static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,
-                             JSValueConst holder, JSValue val, JSValueConst key)
-{
-    JSValue v;
-    JSValueConst args[2];
-
-    if (JS_IsObject(val)
-#ifdef CONFIG_BIGNUM
-    ||  JS_IsBigInt(ctx, val)   /* XXX: probably useless */
-#endif
-        ) {
-            JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON);
-            if (JS_IsException(f))
-                goto exception;
-            if (JS_IsFunction(ctx, f)) {
-                v = JS_CallFree(ctx, f, val, 1, &key);
-                JS_FreeValue(ctx, val);
-                val = v;
-                if (JS_IsException(val))
-                    goto exception;
-            } else {
-                JS_FreeValue(ctx, f);
-            }
-        }
-
-    if (!JS_IsUndefined(jsc->replacer_func)) {
-        args[0] = key;
-        args[1] = val;
-        v = JS_Call(ctx, jsc->replacer_func, holder, 2, args);
-        JS_FreeValue(ctx, val);
-        val = v;
-        if (JS_IsException(val))
-            goto exception;
-    }
-
-    switch (JS_VALUE_GET_NORM_TAG(val)) {
-    case JS_TAG_OBJECT:
-        if (JS_IsFunction(ctx, val))
-            break;
-    case JS_TAG_STRING:
-    case JS_TAG_INT:
-    case JS_TAG_FLOAT64:
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_FLOAT:
-#endif
-    case JS_TAG_BOOL:
-    case JS_TAG_NULL:
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_INT:
-#endif
-    case JS_TAG_EXCEPTION:
-        return val;
-    default:
-        break;
-    }
-    JS_FreeValue(ctx, val);
-    return JS_UNDEFINED;
-
-exception:
-    JS_FreeValue(ctx, val);
-    return JS_EXCEPTION;
-}
-
-static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
-                          JSValueConst holder, JSValue val,
-                          JSValueConst indent)
-{
-    JSValue indent1, sep, sep1, tab, v, prop;
-    JSObject *p;
-    int64_t i, len;
-    int cl, ret;
-    BOOL has_content;
-    
-    indent1 = JS_UNDEFINED;
-    sep = JS_UNDEFINED;
-    sep1 = JS_UNDEFINED;
-    tab = JS_UNDEFINED;
-    prop = JS_UNDEFINED;
-
-    switch (JS_VALUE_GET_NORM_TAG(val)) {
-    case JS_TAG_OBJECT:
-        p = JS_VALUE_GET_OBJ(val);
-        cl = p->class_id;
-        if (cl == JS_CLASS_STRING) {
-            val = JS_ToStringFree(ctx, val);
-            if (JS_IsException(val))
-                goto exception;
-            val = JS_ToQuotedStringFree(ctx, val);
-            if (JS_IsException(val))
-                goto exception;
-            return string_buffer_concat_value_free(jsc->b, val);
-        } else if (cl == JS_CLASS_NUMBER) {
-            val = JS_ToNumberFree(ctx, val);
-            if (JS_IsException(val))
-                goto exception;
-            return string_buffer_concat_value_free(jsc->b, val);
-        } else if (cl == JS_CLASS_BOOLEAN) {
-            ret = string_buffer_concat_value(jsc->b, p->u.object_data);
-            JS_FreeValue(ctx, val);
-            return ret;
-        }
-#ifdef CONFIG_BIGNUM
-        else if (cl == JS_CLASS_BIG_FLOAT) {
-            return string_buffer_concat_value_free(jsc->b, val);
-        } else if (cl == JS_CLASS_BIG_INT) {
-            JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify");
-            goto exception;
-        }
-#endif
-        v = js_array_includes(ctx, jsc->stack, 1, (JSValueConst *)&val);
-        if (JS_IsException(v))
-            goto exception;
-        if (JS_ToBoolFree(ctx, v)) {
-            JS_ThrowTypeError(ctx, "circular reference");
-            goto exception;
-        }
-        indent1 = JS_ConcatString(ctx, JS_DupValue(ctx, indent), JS_DupValue(ctx, jsc->gap));
-        if (JS_IsException(indent1))
-            goto exception;
-        if (!JS_IsEmptyString(jsc->gap)) {
-            sep = JS_ConcatString3(ctx, "\n", JS_DupValue(ctx, indent1), "");
-            if (JS_IsException(sep))
-                goto exception;
-            sep1 = JS_NewString(ctx, " ");
-            if (JS_IsException(sep1))
-                goto exception;
-        } else {
-            sep = JS_DupValue(ctx, jsc->empty);
-            sep1 = JS_DupValue(ctx, jsc->empty);
-        }
-        v = js_array_push(ctx, jsc->stack, 1, (JSValueConst *)&val, 0);
-        if (check_exception_free(ctx, v))
-            goto exception;
-        ret = JS_IsArray(ctx, val);
-        if (ret < 0)
-            goto exception;
-        if (ret) {
-            if (js_get_length64(ctx, &len, val))
-                goto exception;
-            string_buffer_putc8(jsc->b, '[');
-            for(i = 0; i < len; i++) {
-                if (i > 0)
-                    string_buffer_putc8(jsc->b, ',');
-                string_buffer_concat_value(jsc->b, sep);
-                v = JS_GetPropertyInt64(ctx, val, i);
-                if (JS_IsException(v))
-                    goto exception;
-                /* XXX: could do this string conversion only when needed */
-                prop = JS_ToStringFree(ctx, JS_NewInt64(ctx, i));
-                if (JS_IsException(prop))
-                    goto exception;
-                v = js_json_check(ctx, jsc, val, v, prop);
-                JS_FreeValue(ctx, prop);
-                prop = JS_UNDEFINED;
-                if (JS_IsException(v))
-                    goto exception;
-                if (JS_IsUndefined(v))
-                    v = JS_NULL;
-                if (js_json_to_str(ctx, jsc, val, v, indent1))
-                    goto exception;
-            }
-            if (len > 0 && !JS_IsEmptyString(jsc->gap)) {
-                string_buffer_putc8(jsc->b, '\n');
-                string_buffer_concat_value(jsc->b, indent);
-            }
-            string_buffer_putc8(jsc->b, ']');
-        } else {
-            if (!JS_IsUndefined(jsc->property_list))
-                tab = JS_DupValue(ctx, jsc->property_list);
-            else
-                tab = js_object_keys(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val, JS_ITERATOR_KIND_KEY);
-            if (JS_IsException(tab))
-                goto exception;
-            if (js_get_length64(ctx, &len, tab))
-                goto exception;
-            string_buffer_putc8(jsc->b, '{');
-            has_content = FALSE;
-            for(i = 0; i < len; i++) {
-                JS_FreeValue(ctx, prop);
-                prop = JS_GetPropertyInt64(ctx, tab, i);
-                if (JS_IsException(prop))
-                    goto exception;
-                v = JS_GetPropertyValue(ctx, val, JS_DupValue(ctx, prop));
-                if (JS_IsException(v))
-                    goto exception;
-                v = js_json_check(ctx, jsc, val, v, prop);
-                if (JS_IsException(v))
-                    goto exception;
-                if (!JS_IsUndefined(v)) {
-                    if (has_content)
-                        string_buffer_putc8(jsc->b, ',');
-                    prop = JS_ToQuotedStringFree(ctx, prop);
-                    if (JS_IsException(prop)) {
-                        JS_FreeValue(ctx, v);
-                        goto exception;
-                    }
-                    string_buffer_concat_value(jsc->b, sep);
-                    string_buffer_concat_value(jsc->b, prop);
-                    string_buffer_putc8(jsc->b, ':');
-                    string_buffer_concat_value(jsc->b, sep1);
-                    if (js_json_to_str(ctx, jsc, val, v, indent1))
-                        goto exception;
-                    has_content = TRUE;
-                }
-            }
-            if (has_content && JS_VALUE_GET_STRING(jsc->gap)->len != 0) {
-                string_buffer_putc8(jsc->b, '\n');
-                string_buffer_concat_value(jsc->b, indent);
-            }
-            string_buffer_putc8(jsc->b, '}');
-        }
-        if (check_exception_free(ctx, js_array_pop(ctx, jsc->stack, 0, NULL, 0)))
-            goto exception;
-        JS_FreeValue(ctx, val);
-        JS_FreeValue(ctx, tab);
-        JS_FreeValue(ctx, sep);
-        JS_FreeValue(ctx, sep1);
-        JS_FreeValue(ctx, indent1);
-        JS_FreeValue(ctx, prop);
-        return 0;
-    case JS_TAG_STRING:
-        val = JS_ToQuotedStringFree(ctx, val);
-        if (JS_IsException(val))
-            goto exception;
-        goto concat_value;
-    case JS_TAG_FLOAT64:
-        if (!isfinite(JS_VALUE_GET_FLOAT64(val))) {
-            val = JS_NULL;
-        }
-        goto concat_value;
-    case JS_TAG_INT:
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_FLOAT:
-#endif
-    case JS_TAG_BOOL:
-    case JS_TAG_NULL:
-    concat_value:
-        return string_buffer_concat_value_free(jsc->b, val);
-#ifdef CONFIG_BIGNUM
-    case JS_TAG_BIG_INT:
-        JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify");
-        goto exception;
-#endif
-    default:
-        JS_FreeValue(ctx, val);
-        return 0;
-    }
-    
-exception:
-    JS_FreeValue(ctx, val);
-    JS_FreeValue(ctx, tab);
-    JS_FreeValue(ctx, sep);
-    JS_FreeValue(ctx, sep1);
-    JS_FreeValue(ctx, indent1);
-    JS_FreeValue(ctx, prop);
-    return -1;
-}
-
-JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
-                         JSValueConst replacer, JSValueConst space0)
-{
-    StringBuffer b_s;
-    JSONStringifyContext jsc_s, *jsc = &jsc_s;
-    JSValue val, v, space, ret, wrapper;
-    int res;
-    int64_t i, j, n;
-
-    jsc->replacer_func = JS_UNDEFINED;
-    jsc->stack = JS_UNDEFINED;
-    jsc->property_list = JS_UNDEFINED;
-    jsc->gap = JS_UNDEFINED;
-    jsc->b = &b_s;
-    jsc->empty = JS_AtomToString(ctx, JS_ATOM_empty_string);
-    ret = JS_UNDEFINED;
-    wrapper = JS_UNDEFINED;
-
-    string_buffer_init(ctx, jsc->b, 0);
-    jsc->stack = JS_NewArray(ctx);
-    if (JS_IsException(jsc->stack))
-        goto exception;
-    if (JS_IsFunction(ctx, replacer)) {
-        jsc->replacer_func = replacer;
-    } else {
-        res = JS_IsArray(ctx, replacer);
-        if (res < 0)
-            goto exception;
-        if (res) {
-            /* XXX: enumeration is not fully correct */
-            jsc->property_list = JS_NewArray(ctx);
-            if (JS_IsException(jsc->property_list))
-                goto exception;
-            if (js_get_length64(ctx, &n, replacer))
-                goto exception;
-            for (i = j = 0; i < n; i++) {
-                JSValue present;
-                v = JS_GetPropertyInt64(ctx, replacer, i);
-                if (JS_IsException(v))
-                    goto exception;
-                if (JS_IsObject(v)) {
-                    JSObject *p = JS_VALUE_GET_OBJ(v);
-                    if (p->class_id == JS_CLASS_STRING ||
-                        p->class_id == JS_CLASS_NUMBER) {
-                        v = JS_ToStringFree(ctx, v);
-                        if (JS_IsException(v))
-                            goto exception;
-                    } else {
-                        JS_FreeValue(ctx, v);
-                        continue;
-                    }
-                } else if (JS_IsNumber(v)) {
-                    v = JS_ToStringFree(ctx, v);
-                    if (JS_IsException(v))
-                        goto exception;
-                } else if (!JS_IsString(v)) {
-                    JS_FreeValue(ctx, v);
-                    continue;
-                }
-                present = js_array_includes(ctx, jsc->property_list,
-                                            1, (JSValueConst *)&v);
-                if (JS_IsException(present)) {
-                    JS_FreeValue(ctx, v);
-                    goto exception;
-                }
-                if (!JS_ToBoolFree(ctx, present)) {
-                    JS_SetPropertyInt64(ctx, jsc->property_list, j++, v);
-                } else {
-                    JS_FreeValue(ctx, v);
-                }
-            }
-        }
-    }
-    space = JS_DupValue(ctx, space0);
-    if (JS_IsObject(space)) {
-        JSObject *p = JS_VALUE_GET_OBJ(space);
-        if (p->class_id == JS_CLASS_NUMBER) {
-            space = JS_ToNumberFree(ctx, space);
-        } else if (p->class_id == JS_CLASS_STRING) {
-            space = JS_ToStringFree(ctx, space);
-        }
-        if (JS_IsException(space)) {
-            JS_FreeValue(ctx, space);
-            goto exception;
-        }
-    }
-    if (JS_IsNumber(space)) {
-        int n;
-        if (JS_ToInt32Clamp(ctx, &n, space, 0, 10, 0))
-            goto exception;
-        jsc->gap = JS_NewStringLen(ctx, "          ", n);
-    } else if (JS_IsString(space)) {
-        JSString *p = JS_VALUE_GET_STRING(space);
-        jsc->gap = js_sub_string(ctx, p, 0, min_int(p->len, 10));
-    } else {
-        jsc->gap = JS_DupValue(ctx, jsc->empty);
-    }
-    JS_FreeValue(ctx, space);
-    if (JS_IsException(jsc->gap))
-        goto exception;
-    wrapper = JS_NewObject(ctx);
-    if (JS_IsException(wrapper))
-        goto exception;
-    if (JS_DefinePropertyValue(ctx, wrapper, JS_ATOM_empty_string,
-                               JS_DupValue(ctx, obj), JS_PROP_C_W_E) < 0)
-        goto exception;
-    val = JS_DupValue(ctx, obj);
-                           
-    val = js_json_check(ctx, jsc, wrapper, val, jsc->empty);
-    if (JS_IsException(val))
-        goto exception;
-    if (JS_IsUndefined(val)) {
-        ret = JS_UNDEFINED;
-        goto done1;
-    }
-    if (js_json_to_str(ctx, jsc, wrapper, val, jsc->empty))
-        goto exception;
-
-    ret = string_buffer_end(jsc->b);
-    goto done;
-
-exception:
-    ret = JS_EXCEPTION;
-done1:
-    string_buffer_free(jsc->b);
-done:
-    JS_FreeValue(ctx, wrapper);
-    JS_FreeValue(ctx, jsc->empty);
-    JS_FreeValue(ctx, jsc->gap);
-    JS_FreeValue(ctx, jsc->property_list);
-    JS_FreeValue(ctx, jsc->stack);
-    return ret;
-}
-
-static JSValue js_json_stringify(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv)
-{
-    // stringify(val, replacer, space)
-    return JS_JSONStringify(ctx, argv[0], argv[1], argv[2]);
-}
-
-static const JSCFunctionListEntry js_json_funcs[] = {
-    JS_CFUNC_DEF("parse", 2, js_json_parse ),
-    JS_CFUNC_DEF("stringify", 3, js_json_stringify ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "JSON", JS_PROP_CONFIGURABLE ),
-};
-
-static const JSCFunctionListEntry js_json_obj[] = {
-    JS_OBJECT_DEF("JSON", js_json_funcs, countof(js_json_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
-};
-
-void JS_AddIntrinsicJSON(JSContext *ctx)
-{
-    /* add JSON as autoinit object */
-    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_json_obj, countof(js_json_obj));
-}
-
-/* Reflect */
-
-static JSValue js_reflect_apply(JSContext *ctx, JSValueConst this_val,
-                                int argc, JSValueConst *argv)
-{
-    return js_function_apply(ctx, argv[0], max_int(0, argc - 1), argv + 1, 2);
-}
-
-static JSValue js_reflect_construct(JSContext *ctx, JSValueConst this_val,
-                                    int argc, JSValueConst *argv)
-{
-    JSValueConst func, array_arg, new_target;
-    JSValue *tab, ret;
-    uint32_t len;
-
-    func = argv[0];
-    array_arg = argv[1];
-    if (argc > 2) {
-        new_target = argv[2];
-        if (!JS_IsConstructor(ctx, new_target))
-            return JS_ThrowTypeError(ctx, "not a constructor");
-    } else {
-        new_target = func;
-    }
-    tab = build_arg_list(ctx, &len, array_arg);
-    if (!tab)
-        return JS_EXCEPTION;
-    ret = JS_CallConstructor2(ctx, func, new_target, len, (JSValueConst *)tab);
-    free_arg_list(ctx, tab, len);
-    return ret;
-}
-
-static JSValue js_reflect_deleteProperty(JSContext *ctx, JSValueConst this_val,
-                                         int argc, JSValueConst *argv)
-{
-    JSValueConst obj;
-    JSAtom atom;
-    int ret;
-
-    obj = argv[0];
-    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-    atom = JS_ValueToAtom(ctx, argv[1]);
-    if (unlikely(atom == JS_ATOM_NULL))
-        return JS_EXCEPTION;
-    ret = JS_DeleteProperty(ctx, obj, atom, 0);
-    JS_FreeAtom(ctx, atom);
-    if (ret < 0)
-        return JS_EXCEPTION;
-    else
-        return JS_NewBool(ctx, ret);
-}
-
-static JSValue js_reflect_get(JSContext *ctx, JSValueConst this_val,
-                              int argc, JSValueConst *argv)
-{
-    JSValueConst obj, prop, receiver;
-    JSAtom atom;
-    JSValue ret;
-
-    obj = argv[0];
-    prop = argv[1];
-    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-    if (argc > 2)
-        receiver = argv[2];
-    else
-        receiver = obj;
-    atom = JS_ValueToAtom(ctx, prop);
-    if (unlikely(atom == JS_ATOM_NULL))
-        return JS_EXCEPTION;
-    ret = JS_GetPropertyInternal(ctx, obj, atom, receiver, FALSE);
-    JS_FreeAtom(ctx, atom);
-    return ret;
-}
-
-static JSValue js_reflect_has(JSContext *ctx, JSValueConst this_val,
-                              int argc, JSValueConst *argv)
-{
-    JSValueConst obj, prop;
-    JSAtom atom;
-    int ret;
-
-    obj = argv[0];
-    prop = argv[1];
-    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-    atom = JS_ValueToAtom(ctx, prop);
-    if (unlikely(atom == JS_ATOM_NULL))
-        return JS_EXCEPTION;
-    ret = JS_HasProperty(ctx, obj, atom);
-    JS_FreeAtom(ctx, atom);
-    if (ret < 0)
-        return JS_EXCEPTION;
-    else
-        return JS_NewBool(ctx, ret);
-}
-
-static JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val,
-                              int argc, JSValueConst *argv)
-{
-    JSValueConst obj, prop, val, receiver;
-    int ret;
-    JSAtom atom;
-
-    obj = argv[0];
-    prop = argv[1];
-    val = argv[2];
-    if (argc > 3)
-        receiver = argv[3];
-    else
-        receiver = obj;
-    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-    atom = JS_ValueToAtom(ctx, prop);
-    if (unlikely(atom == JS_ATOM_NULL))
-        return JS_EXCEPTION;
-    ret = JS_SetPropertyGeneric(ctx, obj, atom,
-                                JS_DupValue(ctx, val), receiver, 0);
-    JS_FreeAtom(ctx, atom);
-    if (ret < 0)
-        return JS_EXCEPTION;
-    else
-        return JS_NewBool(ctx, ret);
-}
-
-static JSValue js_reflect_setPrototypeOf(JSContext *ctx, JSValueConst this_val,
-                                         int argc, JSValueConst *argv)
-{
-    int ret;
-    ret = JS_SetPrototypeInternal(ctx, argv[0], argv[1], FALSE);
-    if (ret < 0)
-        return JS_EXCEPTION;
-    else
-        return JS_NewBool(ctx, ret);
-}
-
-static JSValue js_reflect_ownKeys(JSContext *ctx, JSValueConst this_val,
-                                  int argc, JSValueConst *argv)
-{
-    if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT)
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-    return JS_GetOwnPropertyNames2(ctx, argv[0],
-                                   JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK,
-                                   JS_ITERATOR_KIND_KEY);
-}
-
-static const JSCFunctionListEntry js_reflect_funcs[] = {
-    JS_CFUNC_DEF("apply", 3, js_reflect_apply ),
-    JS_CFUNC_DEF("construct", 2, js_reflect_construct ),
-    JS_CFUNC_MAGIC_DEF("defineProperty", 3, js_object_defineProperty, 1 ),
-    JS_CFUNC_DEF("deleteProperty", 2, js_reflect_deleteProperty ),
-    JS_CFUNC_DEF("get", 2, js_reflect_get ),
-    JS_CFUNC_MAGIC_DEF("getOwnPropertyDescriptor", 2, js_object_getOwnPropertyDescriptor, 1 ),
-    JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 1 ),
-    JS_CFUNC_DEF("has", 2, js_reflect_has ),
-    JS_CFUNC_MAGIC_DEF("isExtensible", 1, js_object_isExtensible, 1 ),
-    JS_CFUNC_DEF("ownKeys", 1, js_reflect_ownKeys ),
-    JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 1 ),
-    JS_CFUNC_DEF("set", 3, js_reflect_set ),
-    JS_CFUNC_DEF("setPrototypeOf", 2, js_reflect_setPrototypeOf ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Reflect", JS_PROP_CONFIGURABLE ),
-};
-
-static const JSCFunctionListEntry js_reflect_obj[] = {
-    JS_OBJECT_DEF("Reflect", js_reflect_funcs, countof(js_reflect_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
-};
-
-/* Proxy */
-
-static void js_proxy_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY);
-    if (s) {
-        JS_FreeValueRT(rt, s->target);
-        JS_FreeValueRT(rt, s->handler);
-        js_free_rt(rt, s);
-    }
-}
-
-static void js_proxy_mark(JSRuntime *rt, JSValueConst val,
-                          JS_MarkFunc *mark_func)
-{
-    JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY);
-    if (s) {
-        JS_MarkValue(rt, s->target, mark_func);
-        JS_MarkValue(rt, s->handler, mark_func);
-    }
-}
-
-static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx)
-{
-    return JS_ThrowTypeError(ctx, "revoked proxy");
-}
-
-static JSProxyData *get_proxy_method(JSContext *ctx, JSValue *pmethod,
-                                     JSValueConst obj, JSAtom name)
-{
-    JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY);
-    JSValue method;
-
-    /* safer to test recursion in all proxy methods */
-    if (js_check_stack_overflow(ctx->rt, 0)) {
-        JS_ThrowStackOverflow(ctx);
-        return NULL;
-    }
-    
-    /* 's' should never be NULL */
-    if (s->is_revoked) {
-        JS_ThrowTypeErrorRevokedProxy(ctx);
-        return NULL;
-    }
-    method = JS_GetProperty(ctx, s->handler, name);
-    if (JS_IsException(method))
-        return NULL;
-    if (JS_IsNull(method))
-        method = JS_UNDEFINED;
-    *pmethod = method;
-    return s;
-}
-
-static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj)
-{
-    JSProxyData *s;
-    JSValue method, ret, proto1;
-    int res;
-
-    s = get_proxy_method(ctx, &method, obj, JS_ATOM_getPrototypeOf);
-    if (!s)
-        return JS_EXCEPTION;
-    if (JS_IsUndefined(method))
-        return JS_GetPrototype(ctx, s->target);
-    ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
-    if (JS_IsException(ret))
-        return ret;
-    if (JS_VALUE_GET_TAG(ret) != JS_TAG_NULL &&
-        JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
-        goto fail;
-    }
-    res = JS_IsExtensible(ctx, s->target);
-    if (res < 0) {
-        JS_FreeValue(ctx, ret);
-        return JS_EXCEPTION;
-    }
-    if (!res) {
-        /* check invariant */
-        proto1 = JS_GetPrototype(ctx, s->target);
-        if (JS_IsException(proto1)) {
-            JS_FreeValue(ctx, ret);
-            return JS_EXCEPTION;
-        }
-        if (JS_VALUE_GET_OBJ(proto1) != JS_VALUE_GET_OBJ(ret)) {
-            JS_FreeValue(ctx, proto1);
-        fail:
-            JS_FreeValue(ctx, ret);
-            return JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
-        }
-        JS_FreeValue(ctx, proto1);
-    }
-    return ret;
-}
-
-static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
-                                   JSValueConst proto_val, BOOL throw_flag)
-{
-    JSProxyData *s;
-    JSValue method, ret, proto1;
-    JSValueConst args[2];
-    BOOL res;
-    int res2;
-
-    s = get_proxy_method(ctx, &method, obj, JS_ATOM_setPrototypeOf);
-    if (!s)
-        return -1;
-    if (JS_IsUndefined(method))
-        return JS_SetPrototypeInternal(ctx, s->target, proto_val, throw_flag);
-    args[0] = s->target;
-    args[1] = proto_val;
-    ret = JS_CallFree(ctx, method, s->handler, 2, args);
-    if (JS_IsException(ret))
-        return -1;
-    res = JS_ToBoolFree(ctx, ret);
-    if (!res) {
-        if (throw_flag) {
-            JS_ThrowTypeError(ctx, "proxy: bad prototype");
-            return -1;
-        } else {
-            return FALSE;
-        }
-    }
-    res2 = JS_IsExtensible(ctx, s->target);
-    if (res2 < 0)
-        return -1;
-    if (!res2) {
-        proto1 = JS_GetPrototype(ctx, s->target);
-        if (JS_IsException(proto1))
-            return -1;
-        if (JS_VALUE_GET_OBJ(proto_val) != JS_VALUE_GET_OBJ(proto1)) {
-            JS_FreeValue(ctx, proto1);
-            JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
-            return -1;
-        }
-        JS_FreeValue(ctx, proto1);
-    }
-    return TRUE;
-}
-
-static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj)
-{
-    JSProxyData *s;
-    JSValue method, ret;
-    BOOL res;
-    int res2;
-
-    s = get_proxy_method(ctx, &method, obj, JS_ATOM_isExtensible);
-    if (!s)
-        return -1;
-    if (JS_IsUndefined(method))
-        return JS_IsExtensible(ctx, s->target);
-    ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
-    if (JS_IsException(ret))
-        return -1;
-    res = JS_ToBoolFree(ctx, ret);
-    res2 = JS_IsExtensible(ctx, s->target);
-    if (res2 < 0)
-        return res2;
-    if (res != res2) {
-        JS_ThrowTypeError(ctx, "proxy: inconsistent isExtensible");
-        return -1;
-    }
-    return res;
-}
-
-static int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj)
-{
-    JSProxyData *s;
-    JSValue method, ret;
-    BOOL res;
-    int res2;
-
-    s = get_proxy_method(ctx, &method, obj, JS_ATOM_preventExtensions);
-    if (!s)
-        return -1;
-    if (JS_IsUndefined(method))
-        return JS_PreventExtensions(ctx, s->target);
-    ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
-    if (JS_IsException(ret))
-        return -1;
-    res = JS_ToBoolFree(ctx, ret);
-    if (res) {
-        res2 = JS_IsExtensible(ctx, s->target);
-        if (res2 < 0)
-            return res2;
-        if (res2) {
-            JS_ThrowTypeError(ctx, "proxy: inconsistent preventExtensions");
-            return -1;
-        }
-    }
-    return res;
-}
-
-static int js_proxy_has(JSContext *ctx, JSValueConst obj, JSAtom atom)
-{
-    JSProxyData *s;
-    JSValue method, ret1, atom_val;
-    int ret, res;
-    JSObject *p;
-    JSValueConst args[2];
-    BOOL res2;
-
-    s = get_proxy_method(ctx, &method, obj, JS_ATOM_has);
-    if (!s)
-        return -1;
-    if (JS_IsUndefined(method))
-        return JS_HasProperty(ctx, s->target, atom);
-    atom_val = JS_AtomToValue(ctx, atom);
-    if (JS_IsException(atom_val)) {
-        JS_FreeValue(ctx, method);
-        return -1;
-    }
-    args[0] = s->target;
-    args[1] = atom_val;
-    ret1 = JS_CallFree(ctx, method, s->handler, 2, args);
-    JS_FreeValue(ctx, atom_val);
-    if (JS_IsException(ret1))
-        return -1;
-    ret = JS_ToBoolFree(ctx, ret1);
-    if (!ret) {
-        JSPropertyDescriptor desc;
-        p = JS_VALUE_GET_OBJ(s->target);
-        res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
-        if (res < 0)
-            return -1;
-        if (res) {
-            res2 = !(desc.flags & JS_PROP_CONFIGURABLE);
-            js_free_desc(ctx, &desc);
-            if (res2 || !p->extensible) {
-                JS_ThrowTypeError(ctx, "proxy: inconsistent has");
-                return -1;
-            }
-        }
-    }
-    return ret;
-}
-
-static JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom,
-                            JSValueConst receiver)
-{
-    JSProxyData *s;
-    JSValue method, ret, atom_val;
-    int res;
-    JSValueConst args[3];
-    JSPropertyDescriptor desc;
-
-    s = get_proxy_method(ctx, &method, obj, JS_ATOM_get);
-    if (!s)
-        return JS_EXCEPTION;
-    /* Note: recursion is possible thru the prototype of s->target */
-    if (JS_IsUndefined(method))
-        return JS_GetPropertyInternal(ctx, s->target, atom, receiver, FALSE);
-    atom_val = JS_AtomToValue(ctx, atom);
-    if (JS_IsException(atom_val)) {
-        JS_FreeValue(ctx, method);
-        return JS_EXCEPTION;
-    }
-    args[0] = s->target;
-    args[1] = atom_val;
-    args[2] = receiver;
-    ret = JS_CallFree(ctx, method, s->handler, 3, args);
-    JS_FreeValue(ctx, atom_val);
-    if (JS_IsException(ret))
-        return JS_EXCEPTION;
-    res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
-    if (res < 0)
-        return JS_EXCEPTION;
-    if (res) {
-        if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {
-            if (!js_same_value(ctx, desc.value, ret)) {
-                goto fail;
-            }
-        } else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET) {
-            if (JS_IsUndefined(desc.getter) && !JS_IsUndefined(ret)) {
-            fail:
-                js_free_desc(ctx, &desc);
-                JS_FreeValue(ctx, ret);
-                return JS_ThrowTypeError(ctx, "proxy: inconsistent get");
-            }
-        }
-        js_free_desc(ctx, &desc);
-    }
-    return ret;
-}
-
-static int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom,
-                        JSValueConst value, JSValueConst receiver, int flags)
-{
-    JSProxyData *s;
-    JSValue method, ret1, atom_val;
-    int ret, res;
-    JSValueConst args[4];
-
-    s = get_proxy_method(ctx, &method, obj, JS_ATOM_set);
-    if (!s)
-        return -1;
-    if (JS_IsUndefined(method)) {
-        return JS_SetPropertyGeneric(ctx, s->target, atom,
-                                     JS_DupValue(ctx, value), receiver,
-                                     flags);
-    }
-    atom_val = JS_AtomToValue(ctx, atom);
-    if (JS_IsException(atom_val)) {
-        JS_FreeValue(ctx, method);
-        return -1;
-    }
-    args[0] = s->target;
-    args[1] = atom_val;
-    args[2] = value;
-    args[3] = receiver;
-    ret1 = JS_CallFree(ctx, method, s->handler, 4, args);
-    JS_FreeValue(ctx, atom_val);
-    if (JS_IsException(ret1))
-        return -1;
-    ret = JS_ToBoolFree(ctx, ret1);
-    if (ret) {
-        JSPropertyDescriptor desc;
-        res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
-        if (res < 0)
-            return -1;
-        if (res) {
-            if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {
-                if (!js_same_value(ctx, desc.value, value)) {
-                    goto fail;
-                }
-            } else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET && JS_IsUndefined(desc.setter)) {
-                fail:
-                    js_free_desc(ctx, &desc);
-                    JS_ThrowTypeError(ctx, "proxy: inconsistent set");
-                    return -1;
-            }
-            js_free_desc(ctx, &desc);
-        }
-    } else {
-        if ((flags & JS_PROP_THROW) ||
-            ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
-            JS_ThrowTypeError(ctx, "proxy: cannot set property");
-            return -1;
-        }
-    }
-    return ret;
-}
-
-static JSValue js_create_desc(JSContext *ctx, JSValueConst val,
-                              JSValueConst getter, JSValueConst setter,
-                              int flags)
-{
-    JSValue ret;
-    ret = JS_NewObject(ctx);
-    if (JS_IsException(ret))
-        return ret;
-    if (flags & JS_PROP_HAS_GET) {
-        JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, getter),
-                               JS_PROP_C_W_E);
-    }
-    if (flags & JS_PROP_HAS_SET) {
-        JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, setter),
-                               JS_PROP_C_W_E);
-    }
-    if (flags & JS_PROP_HAS_VALUE) {
-        JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, val),
-                               JS_PROP_C_W_E);
-    }
-    if (flags & JS_PROP_HAS_WRITABLE) {
-        JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,
-                               JS_NewBool(ctx, (flags & JS_PROP_WRITABLE) != 0),
-                               JS_PROP_C_W_E);
-    }
-    if (flags & JS_PROP_HAS_ENUMERABLE) {
-        JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,
-                               JS_NewBool(ctx, (flags & JS_PROP_ENUMERABLE) != 0),
-                               JS_PROP_C_W_E);
-    }
-    if (flags & JS_PROP_HAS_CONFIGURABLE) {
-        JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
-                               JS_NewBool(ctx, (flags & JS_PROP_CONFIGURABLE) != 0),
-                               JS_PROP_C_W_E);
-    }
-    return ret;
-}
-
-static int js_proxy_get_own_property(JSContext *ctx, JSPropertyDescriptor *pdesc,
-                                     JSValueConst obj, JSAtom prop)
-{
-    JSProxyData *s;
-    JSValue method, trap_result_obj, prop_val;
-    int res, target_desc_ret, ret;
-    JSObject *p;
-    JSValueConst args[2];
-    JSPropertyDescriptor result_desc, target_desc;
-
-    s = get_proxy_method(ctx, &method, obj, JS_ATOM_getOwnPropertyDescriptor);
-    if (!s)
-        return -1;
-    p = JS_VALUE_GET_OBJ(s->target);
-    if (JS_IsUndefined(method)) {
-        return JS_GetOwnPropertyInternal(ctx, pdesc, p, prop);
-    }
-    prop_val = JS_AtomToValue(ctx, prop);
-    if (JS_IsException(prop_val)) {
-        JS_FreeValue(ctx, method);
-        return -1;
-    }
-    args[0] = s->target;
-    args[1] = prop_val;
-    trap_result_obj = JS_CallFree(ctx, method, s->handler, 2, args);
-    JS_FreeValue(ctx, prop_val);
-    if (JS_IsException(trap_result_obj))
-        return -1;
-    if (!JS_IsObject(trap_result_obj) && !JS_IsUndefined(trap_result_obj)) {
-        JS_FreeValue(ctx, trap_result_obj);
-        goto fail;
-    }
-    target_desc_ret = JS_GetOwnPropertyInternal(ctx, &target_desc, p, prop);
-    if (target_desc_ret < 0) {
-        JS_FreeValue(ctx, trap_result_obj);
-        return -1;
-    }
-    if (target_desc_ret)
-        js_free_desc(ctx, &target_desc);
-    if (JS_IsUndefined(trap_result_obj)) {
-        if (target_desc_ret) {
-            if (!(target_desc.flags & JS_PROP_CONFIGURABLE) || !p->extensible)
-                goto fail;
-        }
-        ret = FALSE;
-    } else {
-        int flags1, extensible_target;
-        extensible_target = JS_IsExtensible(ctx, s->target);
-        if (extensible_target < 0) {
-            JS_FreeValue(ctx, trap_result_obj);
-            return -1;
-        }
-        res = js_obj_to_desc(ctx, &result_desc, trap_result_obj);
-        JS_FreeValue(ctx, trap_result_obj);
-        if (res < 0)
-            return -1;
-        
-        if (target_desc_ret) {
-            /* convert result_desc.flags to defineProperty flags */
-            flags1 = result_desc.flags | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE;
-            if (result_desc.flags & JS_PROP_GETSET)
-                flags1 |= JS_PROP_HAS_GET | JS_PROP_HAS_SET;
-            else
-                flags1 |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE;
-            /* XXX: not complete check: need to compare value &
-               getter/setter as in defineproperty */
-            if (!check_define_prop_flags(target_desc.flags, flags1))
-                goto fail1;
-        } else {
-            if (!extensible_target)
-                goto fail1;
-        }
-        if (!(result_desc.flags & JS_PROP_CONFIGURABLE)) {
-            if (!target_desc_ret || (target_desc.flags & JS_PROP_CONFIGURABLE))
-                goto fail1;
-            if ((result_desc.flags &
-                 (JS_PROP_GETSET | JS_PROP_WRITABLE)) == 0 &&
-                target_desc_ret &&
-                (target_desc.flags & JS_PROP_WRITABLE) != 0) {
-                /* proxy-missing-checks */
-            fail1:
-                js_free_desc(ctx, &result_desc);
-            fail:
-                JS_ThrowTypeError(ctx, "proxy: inconsistent getOwnPropertyDescriptor");
-                return -1;
-            }
-        }
-        ret = TRUE;
-        if (pdesc) {
-            *pdesc = result_desc;
-        } else {
-            js_free_desc(ctx, &result_desc);
-        }
-    }
-    return ret;
-}
-
-static int js_proxy_define_own_property(JSContext *ctx, JSValueConst obj,
-                                        JSAtom prop, JSValueConst val,
-                                        JSValueConst getter, JSValueConst setter,
-                                        int flags)
-{
-    JSProxyData *s;
-    JSValue method, ret1, prop_val, desc_val;
-    int res, ret;
-    JSObject *p;
-    JSValueConst args[3];
-    JSPropertyDescriptor desc;
-    BOOL setting_not_configurable;
-
-    s = get_proxy_method(ctx, &method, obj, JS_ATOM_defineProperty);
-    if (!s)
-        return -1;
-    if (JS_IsUndefined(method)) {
-        return JS_DefineProperty(ctx, s->target, prop, val, getter, setter, flags);
-    }
-    prop_val = JS_AtomToValue(ctx, prop);
-    if (JS_IsException(prop_val)) {
-        JS_FreeValue(ctx, method);
-        return -1;
-    }
-    desc_val = js_create_desc(ctx, val, getter, setter, flags);
-    if (JS_IsException(desc_val)) {
-        JS_FreeValue(ctx, prop_val);
-        JS_FreeValue(ctx, method);
-        return -1;
-    }
-    args[0] = s->target;
-    args[1] = prop_val;
-    args[2] = desc_val;
-    ret1 = JS_CallFree(ctx, method, s->handler, 3, args);
-    JS_FreeValue(ctx, prop_val);
-    JS_FreeValue(ctx, desc_val);
-    if (JS_IsException(ret1))
-        return -1;
-    ret = JS_ToBoolFree(ctx, ret1);
-    if (!ret) {
-        if (flags & JS_PROP_THROW) {
-            JS_ThrowTypeError(ctx, "proxy: defineProperty exception");
-            return -1;
-        } else {
-            return 0;
-        }
-    }
-    p = JS_VALUE_GET_OBJ(s->target);
-    res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
-    if (res < 0)
-        return -1;
-    setting_not_configurable = ((flags & (JS_PROP_HAS_CONFIGURABLE |
-                                          JS_PROP_CONFIGURABLE)) ==
-                                JS_PROP_HAS_CONFIGURABLE);
-    if (!res) {
-        if (!p->extensible || setting_not_configurable)
-            goto fail;
-    } else {
-        if (!check_define_prop_flags(desc.flags, flags) ||
-            ((desc.flags & JS_PROP_CONFIGURABLE) && setting_not_configurable)) {
-            goto fail1;
-        }
-        if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
-            if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) ==
-                JS_PROP_GETSET) {
-                if ((flags & JS_PROP_HAS_GET) &&
-                    !js_same_value(ctx, getter, desc.getter)) {
-                    goto fail1;
-                }
-                if ((flags & JS_PROP_HAS_SET) &&
-                    !js_same_value(ctx, setter, desc.setter)) {
-                    goto fail1;
-                }
-            }
-        } else if (flags & JS_PROP_HAS_VALUE) {
-            if ((desc.flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) ==
-                JS_PROP_WRITABLE && !(flags & JS_PROP_WRITABLE)) {
-                /* missing-proxy-check feature */
-                goto fail1;
-            } else if ((desc.flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 &&
-                !js_same_value(ctx, val, desc.value)) {
-                goto fail1;
-            }
-        }
-        if (flags & JS_PROP_HAS_WRITABLE) {
-            if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE |
-                               JS_PROP_WRITABLE)) == JS_PROP_WRITABLE) {
-                /* proxy-missing-checks */
-            fail1:
-                js_free_desc(ctx, &desc);
-            fail:
-                JS_ThrowTypeError(ctx, "proxy: inconsistent defineProperty");
-                return -1;
-            }
-        }
-        js_free_desc(ctx, &desc);
-    }
-    return 1;
-}
-
-static int js_proxy_delete_property(JSContext *ctx, JSValueConst obj,
-                                    JSAtom atom)
-{
-    JSProxyData *s;
-    JSValue method, ret, atom_val;
-    int res, res2, is_extensible;
-    JSValueConst args[2];
-
-    s = get_proxy_method(ctx, &method, obj, JS_ATOM_deleteProperty);
-    if (!s)
-        return -1;
-    if (JS_IsUndefined(method)) {
-        return JS_DeleteProperty(ctx, s->target, atom, 0);
-    }
-    atom_val = JS_AtomToValue(ctx, atom);;
-    if (JS_IsException(atom_val)) {
-        JS_FreeValue(ctx, method);
-        return -1;
-    }
-    args[0] = s->target;
-    args[1] = atom_val;
-    ret = JS_CallFree(ctx, method, s->handler, 2, args);
-    JS_FreeValue(ctx, atom_val);
-    if (JS_IsException(ret))
-        return -1;
-    res = JS_ToBoolFree(ctx, ret);
-    if (res) {
-        JSPropertyDescriptor desc;
-        res2 = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
-        if (res2 < 0)
-            return -1;
-        if (res2) {
-            if (!(desc.flags & JS_PROP_CONFIGURABLE))
-                goto fail;
-            is_extensible = JS_IsExtensible(ctx, s->target);
-            if (is_extensible < 0)
-                goto fail1;
-            if (!is_extensible) {
-                /* proxy-missing-checks */
-            fail:
-                JS_ThrowTypeError(ctx, "proxy: inconsistent deleteProperty");
-            fail1:
-                js_free_desc(ctx, &desc);
-                return -1;
-            }
-            js_free_desc(ctx, &desc);
-        }
-    }
-    return res;
-}
-
-/* return the index of the property or -1 if not found */
-static int find_prop_key(const JSPropertyEnum *tab, int n, JSAtom atom)
-{
-    int i;
-    for(i = 0; i < n; i++) {
-        if (tab[i].atom == atom)
-            return i;
-    }
-    return -1;
-}
-
-static int js_proxy_get_own_property_names(JSContext *ctx,
-                                           JSPropertyEnum **ptab,
-                                           uint32_t *plen,
-                                           JSValueConst obj)
-{
-    JSProxyData *s;
-    JSValue method, prop_array, val;
-    uint32_t len, i, len2;
-    JSPropertyEnum *tab, *tab2;
-    JSAtom atom;
-    JSPropertyDescriptor desc;
-    int res, is_extensible, idx;
-
-    s = get_proxy_method(ctx, &method, obj, JS_ATOM_ownKeys);
-    if (!s)
-        return -1;
-    if (JS_IsUndefined(method)) {
-        return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen,
-                                      JS_VALUE_GET_OBJ(s->target),
-                                      JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK);
-    }
-    prop_array = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
-    if (JS_IsException(prop_array))
-        return -1;
-    tab = NULL;
-    len = 0;
-    tab2 = NULL;
-    len2 = 0;
-    if (js_get_length32(ctx, &len, prop_array))
-        goto fail;
-    if (len > 0) {
-        tab = js_mallocz(ctx, sizeof(tab[0]) * len);
-        if (!tab)
-            goto fail;
-    }
-    for(i = 0; i < len; i++) {
-        val = JS_GetPropertyUint32(ctx, prop_array, i);
-        if (JS_IsException(val))
-            goto fail;
-        if (!JS_IsString(val) && !JS_IsSymbol(val)) {
-            JS_FreeValue(ctx, val);
-            JS_ThrowTypeError(ctx, "proxy: properties must be strings or symbols");
-            goto fail;
-        }
-        atom = JS_ValueToAtom(ctx, val);
-        JS_FreeValue(ctx, val);
-        if (atom == JS_ATOM_NULL)
-            goto fail;
-        tab[i].atom = atom;
-        tab[i].is_enumerable = FALSE; /* XXX: redundant? */
-    }
-
-    /* check duplicate properties (XXX: inefficient, could store the
-     * properties an a temporary object to use the hash) */
-    for(i = 1; i < len; i++) {
-        if (find_prop_key(tab, i, tab[i].atom) >= 0) {
-            JS_ThrowTypeError(ctx, "proxy: duplicate property");
-            goto fail;
-        }
-    }
-
-    is_extensible = JS_IsExtensible(ctx, s->target);
-    if (is_extensible < 0)
-        goto fail;
-
-    /* check if there are non configurable properties */
-    if (s->is_revoked) {
-        JS_ThrowTypeErrorRevokedProxy(ctx);
-        goto fail;
-    }
-    if (JS_GetOwnPropertyNamesInternal(ctx, &tab2, &len2, JS_VALUE_GET_OBJ(s->target),
-                               JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK))
-        goto fail;
-    for(i = 0; i < len2; i++) {
-        if (s->is_revoked) {
-            JS_ThrowTypeErrorRevokedProxy(ctx);
-            goto fail;
-        }
-        res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target),
-                                tab2[i].atom);
-        if (res < 0)
-            goto fail;
-        if (res) {  /* safety, property should be found */
-            js_free_desc(ctx, &desc);
-            if (!(desc.flags & JS_PROP_CONFIGURABLE) || !is_extensible) {
-                idx = find_prop_key(tab, len, tab2[i].atom);
-                if (idx < 0) {
-                    JS_ThrowTypeError(ctx, "proxy: target property must be present in proxy ownKeys");
-                    goto fail;
-                }
-                /* mark the property as found */
-                if (!is_extensible)
-                    tab[idx].is_enumerable = TRUE;
-            }
-        }
-    }
-    if (!is_extensible) {
-        /* check that all property in 'tab' were checked */
-        for(i = 0; i < len; i++) {
-            if (!tab[i].is_enumerable) {
-                JS_ThrowTypeError(ctx, "proxy: property not present in target were returned by non extensible proxy");
-                goto fail;
-            }
-        }
-    }
-
-    js_free_prop_enum(ctx, tab2, len2);
-    JS_FreeValue(ctx, prop_array);
-    *ptab = tab;
-    *plen = len;
-    return 0;
- fail:
-    js_free_prop_enum(ctx, tab2, len2);
-    js_free_prop_enum(ctx, tab, len);
-    JS_FreeValue(ctx, prop_array);
-    return -1;
-}
-
-static JSValue js_proxy_call_constructor(JSContext *ctx, JSValueConst func_obj,
-                                         JSValueConst new_target,
-                                         int argc, JSValueConst *argv)
-{
-    JSProxyData *s;
-    JSValue method, arg_array, ret;
-    JSValueConst args[3];
-
-    s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_construct);
-    if (!s)
-        return JS_EXCEPTION;
-    if (!JS_IsConstructor(ctx, s->target))
-        return JS_ThrowTypeError(ctx, "not a constructor");
-    if (JS_IsUndefined(method))
-        return JS_CallConstructor2(ctx, s->target, new_target, argc, argv);
-    arg_array = js_create_array(ctx, argc, argv);
-    if (JS_IsException(arg_array)) {
-        ret = JS_EXCEPTION;
-        goto fail;
-    }
-    args[0] = s->target;
-    args[1] = arg_array;
-    args[2] = new_target;
-    ret = JS_Call(ctx, method, s->handler, 3, args);
-    if (!JS_IsException(ret) && JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
-        JS_FreeValue(ctx, ret);
-        ret = JS_ThrowTypeErrorNotAnObject(ctx);
-    }
- fail:
-    JS_FreeValue(ctx, method);
-    JS_FreeValue(ctx, arg_array);
-    return ret;
-}
-
-static JSValue js_proxy_call(JSContext *ctx, JSValueConst func_obj,
-                             JSValueConst this_obj,
-                             int argc, JSValueConst *argv, int flags)
-{
-    JSProxyData *s;
-    JSValue method, arg_array, ret;
-    JSValueConst args[3];
-
-    if (flags & JS_CALL_FLAG_CONSTRUCTOR)
-        return js_proxy_call_constructor(ctx, func_obj, this_obj, argc, argv);
-    
-    s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_apply);
-    if (!s)
-        return JS_EXCEPTION;
-    if (!s->is_func) {
-        JS_FreeValue(ctx, method);
-        return JS_ThrowTypeError(ctx, "not a function");
-    }
-    if (JS_IsUndefined(method))
-        return JS_Call(ctx, s->target, this_obj, argc, argv);
-    arg_array = js_create_array(ctx, argc, argv);
-    if (JS_IsException(arg_array)) {
-        ret = JS_EXCEPTION;
-        goto fail;
-    }
-    args[0] = s->target;
-    args[1] = this_obj;
-    args[2] = arg_array;
-    ret = JS_Call(ctx, method, s->handler, 3, args);
- fail:
-    JS_FreeValue(ctx, method);
-    JS_FreeValue(ctx, arg_array);
-    return ret;
-}
-
-static int js_proxy_isArray(JSContext *ctx, JSValueConst obj)
-{
-    JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY);
-    if (!s)
-        return FALSE;
-    if (s->is_revoked) {
-        JS_ThrowTypeErrorRevokedProxy(ctx);
-        return -1;
-    }
-    return JS_IsArray(ctx, s->target);
-}
-
-static const JSClassExoticMethods js_proxy_exotic_methods = {
-    .get_own_property = js_proxy_get_own_property,
-    .define_own_property = js_proxy_define_own_property,
-    .delete_property = js_proxy_delete_property,
-    .get_own_property_names = js_proxy_get_own_property_names,
-    .has_property = js_proxy_has,
-    .get_property = js_proxy_get,
-    .set_property = js_proxy_set,
-};
-
-static JSValue js_proxy_constructor(JSContext *ctx, JSValueConst this_val,
-                                    int argc, JSValueConst *argv)
-{
-    JSValueConst target, handler;
-    JSValue obj;
-    JSProxyData *s;
-
-    target = argv[0];
-    handler = argv[1];
-    if (JS_VALUE_GET_TAG(target) != JS_TAG_OBJECT ||
-        JS_VALUE_GET_TAG(handler) != JS_TAG_OBJECT)
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-
-    obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_PROXY);
-    if (JS_IsException(obj))
-        return obj;
-    s = js_malloc(ctx, sizeof(JSProxyData));
-    if (!s) {
-        JS_FreeValue(ctx, obj);
-        return JS_EXCEPTION;
-    }
-    s->target = JS_DupValue(ctx, target);
-    s->handler = JS_DupValue(ctx, handler);
-    s->is_func = JS_IsFunction(ctx, target);
-    s->is_revoked = FALSE;
-    JS_SetOpaque(obj, s);
-    JS_SetConstructorBit(ctx, obj, JS_IsConstructor(ctx, target));
-    return obj;
-}
-
-static JSValue js_proxy_revoke(JSContext *ctx, JSValueConst this_val,
-                               int argc, JSValueConst *argv, int magic,
-                               JSValue *func_data)
-{
-    JSProxyData *s = JS_GetOpaque(func_data[0], JS_CLASS_PROXY);
-    if (s) {
-        /* We do not free the handler and target in case they are
-           referenced as constants in the C call stack */
-        s->is_revoked = TRUE;
-        JS_FreeValue(ctx, func_data[0]);
-        func_data[0] = JS_NULL;
-    }
-    return JS_UNDEFINED;
-}
-
-static JSValue js_proxy_revoke_constructor(JSContext *ctx,
-                                           JSValueConst proxy_obj)
-{
-    return JS_NewCFunctionData(ctx, js_proxy_revoke, 0, 0, 1, &proxy_obj);
-}
-
-static JSValue js_proxy_revocable(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv)
-{
-    JSValue proxy_obj, revoke_obj = JS_UNDEFINED, obj;
-
-    proxy_obj = js_proxy_constructor(ctx, JS_UNDEFINED, argc, argv);
-    if (JS_IsException(proxy_obj))
-        goto fail;
-    revoke_obj = js_proxy_revoke_constructor(ctx, proxy_obj);
-    if (JS_IsException(revoke_obj))
-        goto fail;
-    obj = JS_NewObject(ctx);
-    if (JS_IsException(obj))
-        goto fail;
-    // XXX: exceptions?
-    JS_DefinePropertyValue(ctx, obj, JS_ATOM_proxy, proxy_obj, JS_PROP_C_W_E);
-    JS_DefinePropertyValue(ctx, obj, JS_ATOM_revoke, revoke_obj, JS_PROP_C_W_E);
-    return obj;
- fail:
-    JS_FreeValue(ctx, proxy_obj);
-    JS_FreeValue(ctx, revoke_obj);
-    return JS_EXCEPTION;
-}
-
-static const JSCFunctionListEntry js_proxy_funcs[] = {
-    JS_CFUNC_DEF("revocable", 2, js_proxy_revocable ),
-};
-
-static const JSClassShortDef js_proxy_class_def[] = {
-    { JS_ATOM_Object, js_proxy_finalizer, js_proxy_mark }, /* JS_CLASS_PROXY */
-};
-
-void JS_AddIntrinsicProxy(JSContext *ctx)
-{
-    JSRuntime *rt = ctx->rt;
-    JSValue obj1;
-
-    if (!JS_IsRegisteredClass(rt, JS_CLASS_PROXY)) {
-        init_class_range(rt, js_proxy_class_def, JS_CLASS_PROXY,
-                         countof(js_proxy_class_def));
-        rt->class_array[JS_CLASS_PROXY].exotic = &js_proxy_exotic_methods;
-        rt->class_array[JS_CLASS_PROXY].call = js_proxy_call;
-    }
-
-    obj1 = JS_NewCFunction2(ctx, js_proxy_constructor, "Proxy", 2,
-                            JS_CFUNC_constructor, 0);
-    JS_SetConstructorBit(ctx, obj1, TRUE);
-    JS_SetPropertyFunctionList(ctx, obj1, js_proxy_funcs,
-                               countof(js_proxy_funcs));
-    JS_DefinePropertyValueStr(ctx, ctx->global_obj, "Proxy",
-                              obj1, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-}
-
-/* Symbol */
-
-static JSValue js_symbol_constructor(JSContext *ctx, JSValueConst new_target,
-                                     int argc, JSValueConst *argv)
-{
-    JSValue str;
-    JSString *p;
-
-    if (!JS_IsUndefined(new_target))
-        return JS_ThrowTypeError(ctx, "not a constructor");
-    if (argc == 0 || JS_IsUndefined(argv[0])) {
-        p = NULL;
-    } else {
-        str = JS_ToString(ctx, argv[0]);
-        if (JS_IsException(str))
-            return JS_EXCEPTION;
-        p = JS_VALUE_GET_STRING(str);
-    }
-    return JS_NewSymbol(ctx, p, JS_ATOM_TYPE_SYMBOL);
-}
-
-static JSValue js_thisSymbolValue(JSContext *ctx, JSValueConst this_val)
-{
-    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_SYMBOL)
-        return JS_DupValue(ctx, this_val);
-
-    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
-        JSObject *p = JS_VALUE_GET_OBJ(this_val);
-        if (p->class_id == JS_CLASS_SYMBOL) {
-            if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_SYMBOL)
-                return JS_DupValue(ctx, p->u.object_data);
-        }
-    }
-    return JS_ThrowTypeError(ctx, "not a symbol");
-}
-
-static JSValue js_symbol_toString(JSContext *ctx, JSValueConst this_val,
-                                  int argc, JSValueConst *argv)
-{
-    JSValue val, ret;
-    val = js_thisSymbolValue(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    /* XXX: use JS_ToStringInternal() with a flags */
-    ret = js_string_constructor(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val);
-    JS_FreeValue(ctx, val);
-    return ret;
-}
-
-static JSValue js_symbol_valueOf(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv)
-{
-    return js_thisSymbolValue(ctx, this_val);
-}
-
-static JSValue js_symbol_get_description(JSContext *ctx, JSValueConst this_val)
-{
-    JSValue val, ret;
-    JSAtomStruct *p;
-
-    val = js_thisSymbolValue(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    p = JS_VALUE_GET_PTR(val);
-    if (p->len == 0 && p->is_wide_char != 0) {
-        ret = JS_UNDEFINED;
-    } else {
-        ret = JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p));
-    }
-    JS_FreeValue(ctx, val);
-    return ret;
-}
-
-static const JSCFunctionListEntry js_symbol_proto_funcs[] = {
-    JS_CFUNC_DEF("toString", 0, js_symbol_toString ),
-    JS_CFUNC_DEF("valueOf", 0, js_symbol_valueOf ),
-    // XXX: should have writable: false
-    JS_CFUNC_DEF("[Symbol.toPrimitive]", 1, js_symbol_valueOf ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Symbol", JS_PROP_CONFIGURABLE ),
-    JS_CGETSET_DEF("description", js_symbol_get_description, NULL ),
-};
-
-static JSValue js_symbol_for(JSContext *ctx, JSValueConst this_val,
-                             int argc, JSValueConst *argv)
-{
-    JSValue str;
-
-    str = JS_ToString(ctx, argv[0]);
-    if (JS_IsException(str))
-        return JS_EXCEPTION;
-    return JS_NewSymbol(ctx, JS_VALUE_GET_STRING(str), JS_ATOM_TYPE_GLOBAL_SYMBOL);
-}
-
-static JSValue js_symbol_keyFor(JSContext *ctx, JSValueConst this_val,
-                                int argc, JSValueConst *argv)
-{
-    JSAtomStruct *p;
-
-    if (!JS_IsSymbol(argv[0]))
-        return JS_ThrowTypeError(ctx, "not a symbol");
-    p = JS_VALUE_GET_PTR(argv[0]);
-    if (p->atom_type != JS_ATOM_TYPE_GLOBAL_SYMBOL)
-        return JS_UNDEFINED;
-    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
-}
-
-static const JSCFunctionListEntry js_symbol_funcs[] = {
-    JS_CFUNC_DEF("for", 1, js_symbol_for ),
-    JS_CFUNC_DEF("keyFor", 1, js_symbol_keyFor ),
-};
-
-/* Set/Map/WeakSet/WeakMap */
-
-typedef struct JSMapRecord {
-    int ref_count; /* used during enumeration to avoid freeing the record */
-    BOOL empty; /* TRUE if the record is deleted */
-    struct JSMapState *map;
-    struct JSMapRecord *next_weak_ref;
-    struct list_head link;
-    struct list_head hash_link;
-    JSValue key;
-    JSValue value;
-} JSMapRecord;
-
-typedef struct JSMapState {
-    BOOL is_weak; /* TRUE if WeakSet/WeakMap */
-    struct list_head records; /* list of JSMapRecord.link */
-    uint32_t record_count;
-    struct list_head *hash_table;
-    uint32_t hash_size; /* must be a power of two */
-    uint32_t record_count_threshold; /* count at which a hash table
-                                        resize is needed */
-} JSMapState;
-
-#define MAGIC_SET (1 << 0)
-#define MAGIC_WEAK (1 << 1)
-
-static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target,
-                                  int argc, JSValueConst *argv, int magic)
-{
-    JSMapState *s;
-    JSValue obj, adder = JS_UNDEFINED, iter = JS_UNDEFINED, next_method = JS_UNDEFINED;
-    JSValueConst arr;
-    BOOL is_set, is_weak;
-
-    is_set = magic & MAGIC_SET;
-    is_weak = ((magic & MAGIC_WEAK) != 0);
-    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_MAP + magic);
-    if (JS_IsException(obj))
-        return JS_EXCEPTION;
-    s = js_mallocz(ctx, sizeof(*s));
-    if (!s)
-        goto fail;
-    init_list_head(&s->records);
-    s->is_weak = is_weak;
-    JS_SetOpaque(obj, s);
-    s->hash_size = 1;
-    s->hash_table = js_malloc(ctx, sizeof(s->hash_table[0]) * s->hash_size);
-    if (!s->hash_table)
-        goto fail;
-    init_list_head(&s->hash_table[0]);
-    s->record_count_threshold = 4;
-
-    arr = JS_UNDEFINED;
-    if (argc > 0)
-        arr = argv[0];
-    if (!JS_IsUndefined(arr) && !JS_IsNull(arr)) {
-        JSValue item, ret;
-        BOOL done;
-
-        adder = JS_GetProperty(ctx, obj, is_set ? JS_ATOM_add : JS_ATOM_set);
-        if (JS_IsException(adder))
-            goto fail;
-        if (!JS_IsFunction(ctx, adder)) {
-            JS_ThrowTypeError(ctx, "set/add is not a function");
-            goto fail;
-        }
-
-        iter = JS_GetIterator(ctx, arr, FALSE);
-        if (JS_IsException(iter))
-            goto fail;
-        next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
-        if (JS_IsException(next_method))
-            goto fail;
-
-        for(;;) {
-            item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
-            if (JS_IsException(item))
-                goto fail;
-            if (done) {
-                JS_FreeValue(ctx, item);
-                break;
-            }
-            if (is_set) {
-                ret = JS_Call(ctx, adder, obj, 1, (JSValueConst *)&item);
-                if (JS_IsException(ret)) {
-                    JS_FreeValue(ctx, item);
-                    goto fail;
-                }
-            } else {
-                JSValue key, value;
-                JSValueConst args[2];
-                key = JS_UNDEFINED;
-                value = JS_UNDEFINED;
-                if (!JS_IsObject(item)) {
-                    JS_ThrowTypeErrorNotAnObject(ctx);
-                    goto fail1;
-                }
-                key = JS_GetPropertyUint32(ctx, item, 0);
-                if (JS_IsException(key))
-                    goto fail1;
-                value = JS_GetPropertyUint32(ctx, item, 1);
-                if (JS_IsException(value))
-                    goto fail1;
-                args[0] = key;
-                args[1] = value;
-                ret = JS_Call(ctx, adder, obj, 2, args);
-                if (JS_IsException(ret)) {
-                fail1:
-                    JS_FreeValue(ctx, item);
-                    JS_FreeValue(ctx, key);
-                    JS_FreeValue(ctx, value);
-                    goto fail;
-                }
-                JS_FreeValue(ctx, key);
-                JS_FreeValue(ctx, value);
-            }
-            JS_FreeValue(ctx, ret);
-            JS_FreeValue(ctx, item);
-        }
-        JS_FreeValue(ctx, next_method);
-        JS_FreeValue(ctx, iter);
-        JS_FreeValue(ctx, adder);
-    }
-    return obj;
- fail:
-    if (JS_IsObject(iter)) {
-        /* close the iterator object, preserving pending exception */
-        JS_IteratorClose(ctx, iter, TRUE);
-    }
-    JS_FreeValue(ctx, next_method);
-    JS_FreeValue(ctx, iter);
-    JS_FreeValue(ctx, adder);
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-/* XXX: could normalize strings to speed up comparison */
-static JSValueConst map_normalize_key(JSContext *ctx, JSValueConst key)
-{
-    uint32_t tag = JS_VALUE_GET_TAG(key);
-    /* convert -0.0 to +0.0 */
-    if (JS_TAG_IS_FLOAT64(tag) && JS_VALUE_GET_FLOAT64(key) == 0.0) {
-        key = JS_NewInt32(ctx, 0);
-    }
-    return key;
-}
-
-/* XXX: better hash ? */
-static uint32_t map_hash_key(JSContext *ctx, JSValueConst key)
-{
-    uint32_t tag = JS_VALUE_GET_NORM_TAG(key);
-    uint32_t h;
-    double d;
-    JSFloat64Union u;
-
-    switch(tag) {
-    case JS_TAG_BOOL:
-        h = JS_VALUE_GET_INT(key);
-        break;
-    case JS_TAG_STRING:
-        h = hash_string(JS_VALUE_GET_STRING(key), 0);
-        break;
-    case JS_TAG_OBJECT:
-    case JS_TAG_SYMBOL:
-        h = (uintptr_t)JS_VALUE_GET_PTR(key) * 3163;
-        break;
-    case JS_TAG_INT:
-        d = JS_VALUE_GET_INT(key) * 3163;
-        goto hash_float64;
-    case JS_TAG_FLOAT64:
-        d = JS_VALUE_GET_FLOAT64(key);
-        /* normalize the NaN */
-        if (isnan(d))
-            d = JS_FLOAT64_NAN;
-    hash_float64:
-        u.d = d;
-        h = (u.u32[0] ^ u.u32[1]) * 3163;
-        break;
-    default:
-        h = 0; /* XXX: bignum support */
-        break;
-    }
-    h ^= tag;
-    return h;
-}
-
-static JSMapRecord *map_find_record(JSContext *ctx, JSMapState *s,
-                                    JSValueConst key)
-{
-    struct list_head *el;
-    JSMapRecord *mr;
-    uint32_t h;
-    h = map_hash_key(ctx, key) & (s->hash_size - 1);
-    list_for_each(el, &s->hash_table[h]) {
-        mr = list_entry(el, JSMapRecord, hash_link);
-        if (js_same_value_zero(ctx, mr->key, key))
-            return mr;
-    }
-    return NULL;
-}
-
-static void map_hash_resize(JSContext *ctx, JSMapState *s)
-{
-    uint32_t new_hash_size, i, h;
-    size_t slack;
-    struct list_head *new_hash_table, *el;
-    JSMapRecord *mr;
-
-    /* XXX: no reporting of memory allocation failure */
-    if (s->hash_size == 1)
-        new_hash_size = 4;
-    else
-        new_hash_size = s->hash_size * 2;
-    new_hash_table = js_realloc2(ctx, s->hash_table,
-                                 sizeof(new_hash_table[0]) * new_hash_size, &slack);
-    if (!new_hash_table)
-        return;
-    new_hash_size += slack / sizeof(*new_hash_table);
-
-    for(i = 0; i < new_hash_size; i++)
-        init_list_head(&new_hash_table[i]);
-
-    list_for_each(el, &s->records) {
-        mr = list_entry(el, JSMapRecord, link);
-        if (!mr->empty) {
-            h = map_hash_key(ctx, mr->key) & (new_hash_size - 1);
-            list_add_tail(&mr->hash_link, &new_hash_table[h]);
-        }
-    }
-    s->hash_table = new_hash_table;
-    s->hash_size = new_hash_size;
-    s->record_count_threshold = new_hash_size * 2;
-}
-
-static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s,
-                                   JSValueConst key)
-{
-    uint32_t h;
-    JSMapRecord *mr;
-
-    mr = js_malloc(ctx, sizeof(*mr));
-    if (!mr)
-        return NULL;
-    mr->ref_count = 1;
-    mr->map = s;
-    mr->empty = FALSE;
-    if (s->is_weak) {
-        JSObject *p = JS_VALUE_GET_OBJ(key);
-        /* Add the weak reference */
-        mr->next_weak_ref = p->first_weak_ref;
-        p->first_weak_ref = mr;
-    } else {
-        JS_DupValue(ctx, key);
-    }
-    mr->key = (JSValue)key;
-    h = map_hash_key(ctx, key) & (s->hash_size - 1);
-    list_add_tail(&mr->hash_link, &s->hash_table[h]);
-    list_add_tail(&mr->link, &s->records);
-    s->record_count++;
-    if (s->record_count >= s->record_count_threshold) {
-        map_hash_resize(ctx, s);
-    }
-    return mr;
-}
-
-/* Remove the weak reference from the object weak
-   reference list. we don't use a doubly linked list to
-   save space, assuming a given object has few weak
-       references to it */
-static void delete_weak_ref(JSRuntime *rt, JSMapRecord *mr)
-{
-    JSMapRecord **pmr, *mr1;
-    JSObject *p;
-
-    p = JS_VALUE_GET_OBJ(mr->key);
-    pmr = &p->first_weak_ref;
-    for(;;) {
-        mr1 = *pmr;
-        assert(mr1 != NULL);
-        if (mr1 == mr)
-            break;
-        pmr = &mr1->next_weak_ref;
-    }
-    *pmr = mr1->next_weak_ref;
-}
-
-static void map_delete_record(JSRuntime *rt, JSMapState *s, JSMapRecord *mr)
-{
-    if (mr->empty)
-        return;
-    list_del(&mr->hash_link);
-    if (s->is_weak) {
-        delete_weak_ref(rt, mr);
-    } else {
-        JS_FreeValueRT(rt, mr->key);
-    }
-    JS_FreeValueRT(rt, mr->value);
-    if (--mr->ref_count == 0) {
-        list_del(&mr->link);
-        js_free_rt(rt, mr);
-    } else {
-        /* keep a zombie record for iterators */
-        mr->empty = TRUE;
-        mr->key = JS_UNDEFINED;
-        mr->value = JS_UNDEFINED;
-    }
-    s->record_count--;
-}
-
-static void map_decref_record(JSRuntime *rt, JSMapRecord *mr)
-{
-    if (--mr->ref_count == 0) {
-        /* the record can be safely removed */
-        assert(mr->empty);
-        list_del(&mr->link);
-        js_free_rt(rt, mr);
-    }
-}
-
-static void reset_weak_ref(JSRuntime *rt, JSObject *p)
-{
-    JSMapRecord *mr, *mr_next;
-    JSMapState *s;
-    
-    /* first pass to remove the records from the WeakMap/WeakSet
-       lists */
-    for(mr = p->first_weak_ref; mr != NULL; mr = mr->next_weak_ref) {
-        s = mr->map;
-        assert(s->is_weak);
-        assert(!mr->empty); /* no iterator on WeakMap/WeakSet */
-        list_del(&mr->hash_link);
-        list_del(&mr->link);
-    }
-    
-    /* second pass to free the values to avoid modifying the weak
-       reference list while traversing it. */
-    for(mr = p->first_weak_ref; mr != NULL; mr = mr_next) {
-        mr_next = mr->next_weak_ref;
-        JS_FreeValueRT(rt, mr->value);
-        js_free_rt(rt, mr);
-    }
-
-    p->first_weak_ref = NULL; /* fail safe */
-}
-
-static JSValue js_map_set(JSContext *ctx, JSValueConst this_val,
-                          int argc, JSValueConst *argv, int magic)
-{
-    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
-    JSMapRecord *mr;
-    JSValueConst key, value;
-
-    if (!s)
-        return JS_EXCEPTION;
-    key = map_normalize_key(ctx, argv[0]);
-    if (s->is_weak && !JS_IsObject(key))
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-    if (magic & MAGIC_SET)
-        value = JS_UNDEFINED;
-    else
-        value = argv[1];
-    mr = map_find_record(ctx, s, key);
-    if (mr) {
-        JS_FreeValue(ctx, mr->value);
-    } else {
-        mr = map_add_record(ctx, s, key);
-        if (!mr)
-            return JS_EXCEPTION;
-    }
-    mr->value = JS_DupValue(ctx, value);
-    return JS_DupValue(ctx, this_val);
-}
-
-static JSValue js_map_get(JSContext *ctx, JSValueConst this_val,
-                          int argc, JSValueConst *argv, int magic)
-{
-    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
-    JSMapRecord *mr;
-    JSValueConst key;
-
-    if (!s)
-        return JS_EXCEPTION;
-    key = map_normalize_key(ctx, argv[0]);
-    mr = map_find_record(ctx, s, key);
-    if (!mr)
-        return JS_UNDEFINED;
-    else
-        return JS_DupValue(ctx, mr->value);
-}
-
-static JSValue js_map_has(JSContext *ctx, JSValueConst this_val,
-                          int argc, JSValueConst *argv, int magic)
-{
-    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
-    JSMapRecord *mr;
-    JSValueConst key;
-
-    if (!s)
-        return JS_EXCEPTION;
-    key = map_normalize_key(ctx, argv[0]);
-    mr = map_find_record(ctx, s, key);
-    return JS_NewBool(ctx, (mr != NULL));
-}
-
-static JSValue js_map_delete(JSContext *ctx, JSValueConst this_val,
-                             int argc, JSValueConst *argv, int magic)
-{
-    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
-    JSMapRecord *mr;
-    JSValueConst key;
-
-    if (!s)
-        return JS_EXCEPTION;
-    key = map_normalize_key(ctx, argv[0]);
-    mr = map_find_record(ctx, s, key);
-    if (!mr)
-        return JS_FALSE;
-    map_delete_record(ctx->rt, s, mr);
-    return JS_TRUE;
-}
-
-static JSValue js_map_clear(JSContext *ctx, JSValueConst this_val,
-                            int argc, JSValueConst *argv, int magic)
-{
-    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
-    struct list_head *el, *el1;
-    JSMapRecord *mr;
-
-    if (!s)
-        return JS_EXCEPTION;
-    list_for_each_safe(el, el1, &s->records) {
-        mr = list_entry(el, JSMapRecord, link);
-        map_delete_record(ctx->rt, s, mr);
-    }
-    return JS_UNDEFINED;
-}
-
-static JSValue js_map_get_size(JSContext *ctx, JSValueConst this_val, int magic)
-{
-    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
-    if (!s)
-        return JS_EXCEPTION;
-    return JS_NewUint32(ctx, s->record_count);
-}
-
-static JSValue js_map_forEach(JSContext *ctx, JSValueConst this_val,
-                              int argc, JSValueConst *argv, int magic)
-{
-    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
-    JSValueConst func, this_arg;
-    JSValue ret, args[3];
-    struct list_head *el;
-    JSMapRecord *mr;
-
-    if (!s)
-        return JS_EXCEPTION;
-    func = argv[0];
-    if (argc > 1)
-        this_arg = argv[1];
-    else
-        this_arg = JS_UNDEFINED;
-    if (check_function(ctx, func))
-        return JS_EXCEPTION;
-    /* Note: the list can be modified while traversing it, but the
-       current element is locked */
-    el = s->records.next;
-    while (el != &s->records) {
-        mr = list_entry(el, JSMapRecord, link);
-        if (!mr->empty) {
-            mr->ref_count++;
-            /* must duplicate in case the record is deleted */
-            args[1] = JS_DupValue(ctx, mr->key);
-            if (magic)
-                args[0] = args[1];
-            else
-                args[0] = JS_DupValue(ctx, mr->value);
-            args[2] = (JSValue)this_val;
-            ret = JS_Call(ctx, func, this_arg, 3, (JSValueConst *)args);
-            JS_FreeValue(ctx, args[0]);
-            if (!magic)
-                JS_FreeValue(ctx, args[1]);
-            el = el->next;
-            map_decref_record(ctx->rt, mr);
-            if (JS_IsException(ret))
-                return ret;
-            JS_FreeValue(ctx, ret);
-        } else {
-            el = el->next;
-        }
-    }
-    return JS_UNDEFINED;
-}
-
-static void js_map_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSObject *p;
-    JSMapState *s;
-    struct list_head *el, *el1;
-    JSMapRecord *mr;
-
-    p = JS_VALUE_GET_OBJ(val);
-    s = p->u.map_state;
-    if (s) {
-        /* if the object is deleted we are sure that no iterator is
-           using it */
-        list_for_each_safe(el, el1, &s->records) {
-            mr = list_entry(el, JSMapRecord, link);
-            if (!mr->empty) {
-                if (s->is_weak)
-                    delete_weak_ref(rt, mr);
-                else
-                    JS_FreeValueRT(rt, mr->key);
-                JS_FreeValueRT(rt, mr->value);
-            }
-            js_free_rt(rt, mr);
-        }
-        js_free_rt(rt, s->hash_table);
-        js_free_rt(rt, s);
-    }
-}
-
-static void js_map_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    JSMapState *s;
-    struct list_head *el;
-    JSMapRecord *mr;
-
-    s = p->u.map_state;
-    if (s) {
-        list_for_each(el, &s->records) {
-            mr = list_entry(el, JSMapRecord, link);
-            if (!s->is_weak)
-                JS_MarkValue(rt, mr->key, mark_func);
-            JS_MarkValue(rt, mr->value, mark_func);
-        }
-    }
-}
-
-/* Map Iterator */
-
-typedef struct JSMapIteratorData {
-    JSValue obj;
-    JSIteratorKindEnum kind;
-    JSMapRecord *cur_record;
-} JSMapIteratorData;
-
-static void js_map_iterator_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSObject *p;
-    JSMapIteratorData *it;
-
-    p = JS_VALUE_GET_OBJ(val);
-    it = p->u.map_iterator_data;
-    if (it) {
-        /* During the GC sweep phase the Map finalizer may be
-           called before the Map iterator finalizer */
-        if (JS_IsLiveObject(rt, it->obj) && it->cur_record) {
-            map_decref_record(rt, it->cur_record);
-        }
-        JS_FreeValueRT(rt, it->obj);
-        js_free_rt(rt, it);
-    }
-}
-
-static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val,
-                                 JS_MarkFunc *mark_func)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    JSMapIteratorData *it;
-    it = p->u.map_iterator_data;
-    if (it) {
-        /* the record is already marked by the object */
-        JS_MarkValue(rt, it->obj, mark_func);
-    }
-}
-
-static JSValue js_create_map_iterator(JSContext *ctx, JSValueConst this_val,
-                                      int argc, JSValueConst *argv, int magic)
-{
-    JSIteratorKindEnum kind;
-    JSMapState *s;
-    JSMapIteratorData *it;
-    JSValue enum_obj;
-
-    kind = magic >> 2;
-    magic &= 3;
-    s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
-    if (!s)
-        return JS_EXCEPTION;
-    enum_obj = JS_NewObjectClass(ctx, JS_CLASS_MAP_ITERATOR + magic);
-    if (JS_IsException(enum_obj))
-        goto fail;
-    it = js_malloc(ctx, sizeof(*it));
-    if (!it) {
-        JS_FreeValue(ctx, enum_obj);
-        goto fail;
-    }
-    it->obj = JS_DupValue(ctx, this_val);
-    it->kind = kind;
-    it->cur_record = NULL;
-    JS_SetOpaque(enum_obj, it);
-    return enum_obj;
- fail:
-    return JS_EXCEPTION;
-}
-
-static JSValue js_map_iterator_next(JSContext *ctx, JSValueConst this_val,
-                                    int argc, JSValueConst *argv,
-                                    BOOL *pdone, int magic)
-{
-    JSMapIteratorData *it;
-    JSMapState *s;
-    JSMapRecord *mr;
-    struct list_head *el;
-
-    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP_ITERATOR + magic);
-    if (!it) {
-        *pdone = FALSE;
-        return JS_EXCEPTION;
-    }
-    if (JS_IsUndefined(it->obj))
-        goto done;
-    s = JS_GetOpaque(it->obj, JS_CLASS_MAP + magic);
-    assert(s != NULL);
-    if (!it->cur_record) {
-        el = s->records.next;
-    } else {
-        mr = it->cur_record;
-        el = mr->link.next;
-        map_decref_record(ctx->rt, mr); /* the record can be freed here */
-    }
-    for(;;) {
-        if (el == &s->records) {
-            /* no more record  */
-            it->cur_record = NULL;
-            JS_FreeValue(ctx, it->obj);
-            it->obj = JS_UNDEFINED;
-        done:
-            /* end of enumeration */
-            *pdone = TRUE;
-            return JS_UNDEFINED;
-        }
-        mr = list_entry(el, JSMapRecord, link);
-        if (!mr->empty)
-            break;
-        /* get the next record */
-        el = mr->link.next;
-    }
-
-    /* lock the record so that it won't be freed */
-    mr->ref_count++;
-    it->cur_record = mr;
-    *pdone = FALSE;
-
-    if (it->kind == JS_ITERATOR_KIND_KEY) {
-        return JS_DupValue(ctx, mr->key);
-    } else {
-        JSValueConst args[2];
-        args[0] = mr->key;
-        if (magic)
-            args[1] = mr->key;
-        else
-            args[1] = mr->value;
-        if (it->kind == JS_ITERATOR_KIND_VALUE) {
-            return JS_DupValue(ctx, args[1]);
-        } else {
-            return js_create_array(ctx, 2, args);
-        }
-    }
-}
-
-static const JSCFunctionListEntry js_map_funcs[] = {
-    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
-};
-
-static const JSCFunctionListEntry js_map_proto_funcs[] = {
-    JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, 0 ),
-    JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, 0 ),
-    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, 0 ),
-    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, 0 ),
-    JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, 0 ),
-    JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, 0),
-    JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, 0 ),
-    JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_VALUE << 2) | 0 ),
-    JS_CFUNC_MAGIC_DEF("keys", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | 0 ),
-    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | 0 ),
-    JS_ALIAS_DEF("[Symbol.iterator]", "entries" ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Map", JS_PROP_CONFIGURABLE ),
-};
-
-static const JSCFunctionListEntry js_map_iterator_proto_funcs[] = {
-    JS_ITERATOR_NEXT_DEF("next", 0, js_map_iterator_next, 0 ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Map Iterator", JS_PROP_CONFIGURABLE ),
-};
-
-static const JSCFunctionListEntry js_set_proto_funcs[] = {
-    JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET ),
-    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET ),
-    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET ),
-    JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, MAGIC_SET ),
-    JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, MAGIC_SET ),
-    JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, MAGIC_SET ),
-    JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | MAGIC_SET ),
-    JS_ALIAS_DEF("keys", "values" ),
-    JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
-    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | MAGIC_SET ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set", JS_PROP_CONFIGURABLE ),
-};
-
-static const JSCFunctionListEntry js_set_iterator_proto_funcs[] = {
-    JS_ITERATOR_NEXT_DEF("next", 0, js_map_iterator_next, MAGIC_SET ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set Iterator", JS_PROP_CONFIGURABLE ),
-};
-
-static const JSCFunctionListEntry js_weak_map_proto_funcs[] = {
-    JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, MAGIC_WEAK ),
-    JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, MAGIC_WEAK ),
-    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_WEAK ),
-    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_WEAK ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakMap", JS_PROP_CONFIGURABLE ),
-};
-
-static const JSCFunctionListEntry js_weak_set_proto_funcs[] = {
-    JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET | MAGIC_WEAK ),
-    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET | MAGIC_WEAK ),
-    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET | MAGIC_WEAK ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakSet", JS_PROP_CONFIGURABLE ),
-};
-
-static const JSCFunctionListEntry * const js_map_proto_funcs_ptr[6] = {
-    js_map_proto_funcs,
-    js_set_proto_funcs,
-    js_weak_map_proto_funcs,
-    js_weak_set_proto_funcs,
-    js_map_iterator_proto_funcs,
-    js_set_iterator_proto_funcs,
-};
-
-static const uint8_t js_map_proto_funcs_count[6] = {
-    countof(js_map_proto_funcs),
-    countof(js_set_proto_funcs),
-    countof(js_weak_map_proto_funcs),
-    countof(js_weak_set_proto_funcs),
-    countof(js_map_iterator_proto_funcs),
-    countof(js_set_iterator_proto_funcs),
-};
-
-void JS_AddIntrinsicMapSet(JSContext *ctx)
-{
-    int i;
-    JSValue obj1;
-    char buf[ATOM_GET_STR_BUF_SIZE];
-
-    for(i = 0; i < 4; i++) {
-        const char *name = JS_AtomGetStr(ctx, buf, sizeof(buf),
-                                         JS_ATOM_Map + i);
-        ctx->class_proto[JS_CLASS_MAP + i] = JS_NewObject(ctx);
-        JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP + i],
-                                   js_map_proto_funcs_ptr[i],
-                                   js_map_proto_funcs_count[i]);
-        obj1 = JS_NewCFunctionMagic(ctx, js_map_constructor, name, 0,
-                                    JS_CFUNC_constructor_magic, i);
-        if (i < 2) {
-            JS_SetPropertyFunctionList(ctx, obj1, js_map_funcs,
-                                       countof(js_map_funcs));
-        }
-        JS_NewGlobalCConstructor2(ctx, obj1, name, ctx->class_proto[JS_CLASS_MAP + i]);
-    }
-
-    for(i = 0; i < 2; i++) {
-        ctx->class_proto[JS_CLASS_MAP_ITERATOR + i] =
-            JS_NewObjectProto(ctx, ctx->iterator_proto);
-        JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP_ITERATOR + i],
-                                   js_map_proto_funcs_ptr[i + 4],
-                                   js_map_proto_funcs_count[i + 4]);
-    }
-}
-
-/* Generator */
-static const JSCFunctionListEntry js_generator_function_proto_funcs[] = {
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "GeneratorFunction", JS_PROP_CONFIGURABLE),
-};
-
-static const JSCFunctionListEntry js_generator_proto_funcs[] = {
-    JS_ITERATOR_NEXT_DEF("next", 1, js_generator_next, GEN_MAGIC_NEXT ),
-    JS_ITERATOR_NEXT_DEF("return", 1, js_generator_next, GEN_MAGIC_RETURN ),
-    JS_ITERATOR_NEXT_DEF("throw", 1, js_generator_next, GEN_MAGIC_THROW ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Generator", JS_PROP_CONFIGURABLE),
-};
-
-/* Promise */
-
-typedef enum JSPromiseStateEnum {
-    JS_PROMISE_PENDING,
-    JS_PROMISE_FULFILLED,
-    JS_PROMISE_REJECTED,
-} JSPromiseStateEnum;
-
-typedef struct JSPromiseData {
-    JSPromiseStateEnum promise_state;
-    /* 0=fulfill, 1=reject, list of JSPromiseReactionData.link */
-    struct list_head promise_reactions[2];
-    BOOL is_handled; /* Note: only useful to debug */
-    JSValue promise_result;
-} JSPromiseData;
-
-typedef struct JSPromiseFunctionDataResolved {
-    int ref_count;
-    BOOL already_resolved;
-} JSPromiseFunctionDataResolved;
-
-typedef struct JSPromiseFunctionData {
-    JSValue promise;
-    JSPromiseFunctionDataResolved *presolved;
-} JSPromiseFunctionData;
-
-typedef struct JSPromiseReactionData {
-    struct list_head link; /* not used in promise_reaction_job */
-    JSValue resolving_funcs[2];
-    JSValue handler;
-} JSPromiseReactionData;
-
-static int js_create_resolving_functions(JSContext *ctx, JSValue *args,
-                                         JSValueConst promise);
-
-static void promise_reaction_data_free(JSRuntime *rt,
-                                       JSPromiseReactionData *rd)
-{
-    JS_FreeValueRT(rt, rd->resolving_funcs[0]);
-    JS_FreeValueRT(rt, rd->resolving_funcs[1]);
-    JS_FreeValueRT(rt, rd->handler);
-    js_free_rt(rt, rd);
-}
-
-static JSValue promise_reaction_job(JSContext *ctx, int argc,
-                                    JSValueConst *argv)
-{
-    JSValueConst handler, arg, func;
-    JSValue res, res2;
-    BOOL is_reject;
-
-    assert(argc == 5);
-    handler = argv[2];
-    is_reject = JS_ToBool(ctx, argv[3]);
-    arg = argv[4];
-#ifdef DUMP_PROMISE
-    printf("promise_reaction_job: is_reject=%d\n", is_reject);
-#endif
-
-    if (JS_IsUndefined(handler)) {
-        if (is_reject) {
-            res = JS_Throw(ctx, JS_DupValue(ctx, arg));
-        } else {
-            res = JS_DupValue(ctx, arg);
-        }
-    } else {
-        res = JS_Call(ctx, handler, JS_UNDEFINED, 1, &arg);
-    }
-    is_reject = JS_IsException(res);
-    if (is_reject)
-        res = JS_GetException(ctx);
-    func = argv[is_reject];
-    /* as an extension, we support undefined as value to avoid
-       creating a dummy promise in the 'await' implementation of async
-       functions */
-    if (!JS_IsUndefined(func)) {
-        res2 = JS_Call(ctx, func, JS_UNDEFINED,
-                       1, (JSValueConst *)&res);
-    } else {
-        res2 = JS_UNDEFINED;
-    }
-    JS_FreeValue(ctx, res);
-
-    return res2;
-}
-
-void JS_SetHostPromiseRejectionTracker(JSRuntime *rt,
-                                       JSHostPromiseRejectionTracker *cb,
-                                       void *opaque)
-{
-    rt->host_promise_rejection_tracker = cb;
-    rt->host_promise_rejection_tracker_opaque = opaque;
-}
-
-static void fulfill_or_reject_promise(JSContext *ctx, JSValueConst promise,
-                                      JSValueConst value, BOOL is_reject)
-{
-    JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
-    struct list_head *el, *el1;
-    JSPromiseReactionData *rd;
-    JSValueConst args[5];
-
-    if (!s || s->promise_state != JS_PROMISE_PENDING)
-        return; /* should never happen */
-    set_value(ctx, &s->promise_result, JS_DupValue(ctx, value));
-    s->promise_state = JS_PROMISE_FULFILLED + is_reject;
-#ifdef DUMP_PROMISE
-    printf("fulfill_or_reject_promise: is_reject=%d\n", is_reject);
-#endif
-    if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {
-        JSRuntime *rt = ctx->rt;
-        if (rt->host_promise_rejection_tracker) {
-            rt->host_promise_rejection_tracker(ctx, promise, value, FALSE,
-                                               rt->host_promise_rejection_tracker_opaque);
-        }
-    }
-
-    list_for_each_safe(el, el1, &s->promise_reactions[is_reject]) {
-        rd = list_entry(el, JSPromiseReactionData, link);
-        args[0] = rd->resolving_funcs[0];
-        args[1] = rd->resolving_funcs[1];
-        args[2] = rd->handler;
-        args[3] = JS_NewBool(ctx, is_reject);
-        args[4] = value;
-        JS_EnqueueJob(ctx, promise_reaction_job, 5, args);
-        list_del(&rd->link);
-        promise_reaction_data_free(ctx->rt, rd);
-    }
-
-    list_for_each_safe(el, el1, &s->promise_reactions[1 - is_reject]) {
-        rd = list_entry(el, JSPromiseReactionData, link);
-        list_del(&rd->link);
-        promise_reaction_data_free(ctx->rt, rd);
-    }
-}
-
-static void reject_promise(JSContext *ctx, JSValueConst promise,
-                           JSValueConst value)
-{
-    fulfill_or_reject_promise(ctx, promise, value, TRUE);
-}
-
-static JSValue js_promise_resolve_thenable_job(JSContext *ctx,
-                                               int argc, JSValueConst *argv)
-{
-    JSValueConst promise, thenable, then;
-    JSValue args[2], res;
-
-#ifdef DUMP_PROMISE
-    printf("js_promise_resolve_thenable_job\n");
-#endif
-    assert(argc == 3);
-    promise = argv[0];
-    thenable = argv[1];
-    then = argv[2];
-    if (js_create_resolving_functions(ctx, args, promise) < 0)
-        return JS_EXCEPTION;
-    res = JS_Call(ctx, then, thenable, 2, (JSValueConst *)args);
-    if (JS_IsException(res)) {
-        JSValue error = JS_GetException(ctx);
-        res = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error);
-        JS_FreeValue(ctx, error);
-    }
-    JS_FreeValue(ctx, args[0]);
-    JS_FreeValue(ctx, args[1]);
-    return res;
-}
-
-static void js_promise_resolve_function_free_resolved(JSRuntime *rt,
-                                                      JSPromiseFunctionDataResolved *sr)
-{
-    if (--sr->ref_count == 0) {
-        js_free_rt(rt, sr);
-    }
-}
-
-static int js_create_resolving_functions(JSContext *ctx,
-                                         JSValue *resolving_funcs,
-                                         JSValueConst promise)
-
-{
-    JSValue obj;
-    JSPromiseFunctionData *s;
-    JSPromiseFunctionDataResolved *sr;
-    int i, ret;
-
-    sr = js_malloc(ctx, sizeof(*sr));
-    if (!sr)
-        return -1;
-    sr->ref_count = 1;
-    sr->already_resolved = FALSE; /* must be shared between the two functions */
-    ret = 0;
-    for(i = 0; i < 2; i++) {
-        obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
-                                     JS_CLASS_PROMISE_RESOLVE_FUNCTION + i);
-        if (JS_IsException(obj))
-            goto fail;
-        s = js_malloc(ctx, sizeof(*s));
-        if (!s) {
-            JS_FreeValue(ctx, obj);
-        fail:
-
-            if (i != 0)
-                JS_FreeValue(ctx, resolving_funcs[0]);
-            ret = -1;
-            break;
-        }
-        sr->ref_count++;
-        s->presolved = sr;
-        s->promise = JS_DupValue(ctx, promise);
-        JS_SetOpaque(obj, s);
-        js_function_set_properties(ctx, obj, JS_ATOM_empty_string, 1);
-        resolving_funcs[i] = obj;
-    }
-    js_promise_resolve_function_free_resolved(ctx->rt, sr);
-    return ret;
-}
-
-static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data;
-    if (s) {
-        js_promise_resolve_function_free_resolved(rt, s->presolved);
-        JS_FreeValueRT(rt, s->promise);
-        js_free_rt(rt, s);
-    }
-}
-
-static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
-                                             JS_MarkFunc *mark_func)
-{
-    JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data;
-    if (s) {
-        JS_MarkValue(rt, s->promise, mark_func);
-    }
-}
-
-static JSValue js_promise_resolve_function_call(JSContext *ctx,
-                                                JSValueConst func_obj,
-                                                JSValueConst this_val,
-                                                int argc, JSValueConst *argv,
-                                                int flags)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(func_obj);
-    JSPromiseFunctionData *s;
-    JSValueConst resolution, args[3];
-    JSValue then;
-    BOOL is_reject;
-
-    s = p->u.promise_function_data;
-    if (!s || s->presolved->already_resolved)
-        return JS_UNDEFINED;
-    s->presolved->already_resolved = TRUE;
-    is_reject = p->class_id - JS_CLASS_PROMISE_RESOLVE_FUNCTION;
-    if (argc > 0)
-        resolution = argv[0];
-    else
-        resolution = JS_UNDEFINED;
-#ifdef DUMP_PROMISE
-    printf("js_promise_resolving_function_call: is_reject=%d resolution=", is_reject);
-    JS_DumpValue(ctx, resolution);
-    printf("\n");
-#endif
-    if (is_reject || !JS_IsObject(resolution)) {
-        goto done;
-    } else if (js_same_value(ctx, resolution, s->promise)) {
-        JS_ThrowTypeError(ctx, "promise self resolution");
-        goto fail_reject;
-    }
-    then = JS_GetProperty(ctx, resolution, JS_ATOM_then);
-    if (JS_IsException(then)) {
-        JSValue error;
-    fail_reject:
-        error = JS_GetException(ctx);
-        reject_promise(ctx, s->promise, error);
-        JS_FreeValue(ctx, error);
-    } else if (!JS_IsFunction(ctx, then)) {
-        JS_FreeValue(ctx, then);
-    done:
-        fulfill_or_reject_promise(ctx, s->promise, resolution, is_reject);
-    } else {
-        args[0] = s->promise;
-        args[1] = resolution;
-        args[2] = then;
-        JS_EnqueueJob(ctx, js_promise_resolve_thenable_job, 3, args);
-        JS_FreeValue(ctx, then);
-    }
-    return JS_UNDEFINED;
-}
-
-static void js_promise_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE);
-    struct list_head *el, *el1;
-    int i;
-
-    if (!s)
-        return;
-    for(i = 0; i < 2; i++) {
-        list_for_each_safe(el, el1, &s->promise_reactions[i]) {
-            JSPromiseReactionData *rd =
-                list_entry(el, JSPromiseReactionData, link);
-            promise_reaction_data_free(rt, rd);
-        }
-    }
-    JS_FreeValueRT(rt, s->promise_result);
-    js_free_rt(rt, s);
-}
-
-static void js_promise_mark(JSRuntime *rt, JSValueConst val,
-                            JS_MarkFunc *mark_func)
-{
-    JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE);
-    struct list_head *el;
-    int i;
-
-    if (!s)
-        return;
-    for(i = 0; i < 2; i++) {
-        list_for_each(el, &s->promise_reactions[i]) {
-            JSPromiseReactionData *rd =
-                list_entry(el, JSPromiseReactionData, link);
-            JS_MarkValue(rt, rd->resolving_funcs[0], mark_func);
-            JS_MarkValue(rt, rd->resolving_funcs[1], mark_func);
-            JS_MarkValue(rt, rd->handler, mark_func);
-        }
-    }
-    JS_MarkValue(rt, s->promise_result, mark_func);
-}
-
-static JSValue js_promise_constructor(JSContext *ctx, JSValueConst new_target,
-                                      int argc, JSValueConst *argv)
-{
-    JSValueConst executor;
-    JSValue obj;
-    JSPromiseData *s;
-    JSValue args[2], ret;
-    int i;
-
-    executor = argv[0];
-    if (check_function(ctx, executor))
-        return JS_EXCEPTION;
-    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_PROMISE);
-    if (JS_IsException(obj))
-        return JS_EXCEPTION;
-    s = js_mallocz(ctx, sizeof(*s));
-    if (!s)
-        goto fail;
-    s->promise_state = JS_PROMISE_PENDING;
-    s->is_handled = FALSE;
-    for(i = 0; i < 2; i++)
-        init_list_head(&s->promise_reactions[i]);
-    s->promise_result = JS_UNDEFINED;
-    JS_SetOpaque(obj, s);
-    if (js_create_resolving_functions(ctx, args, obj))
-        goto fail;
-    ret = JS_Call(ctx, executor, JS_UNDEFINED, 2, (JSValueConst *)args);
-    if (JS_IsException(ret)) {
-        JSValue ret2, error;
-        error = JS_GetException(ctx);
-        ret2 = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error);
-        JS_FreeValue(ctx, error);
-        if (JS_IsException(ret2))
-            goto fail1;
-        JS_FreeValue(ctx, ret2);
-    }
-    JS_FreeValue(ctx, ret);
-    JS_FreeValue(ctx, args[0]);
-    JS_FreeValue(ctx, args[1]);
-    return obj;
- fail1:
-    JS_FreeValue(ctx, args[0]);
-    JS_FreeValue(ctx, args[1]);
- fail:
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_promise_executor(JSContext *ctx,
-                                   JSValueConst this_val,
-                                   int argc, JSValueConst *argv,
-                                   int magic, JSValue *func_data)
-{
-    int i;
-
-    for(i = 0; i < 2; i++) {
-        if (!JS_IsUndefined(func_data[i]))
-            return JS_ThrowTypeError(ctx, "resolving function already set");
-        func_data[i] = JS_DupValue(ctx, argv[i]);
-    }
-    return JS_UNDEFINED;
-}
-
-static JSValue js_promise_executor_new(JSContext *ctx)
-{
-    JSValueConst func_data[2];
-
-    func_data[0] = JS_UNDEFINED;
-    func_data[1] = JS_UNDEFINED;
-    return JS_NewCFunctionData(ctx, js_promise_executor, 2,
-                               0, 2, func_data);
-}
-
-static JSValue js_new_promise_capability(JSContext *ctx,
-                                         JSValue *resolving_funcs,
-                                         JSValueConst ctor)
-{
-    JSValue executor, result_promise;
-    JSCFunctionDataRecord *s;
-    int i;
-
-    executor = js_promise_executor_new(ctx);
-    if (JS_IsException(executor))
-        return executor;
-
-    if (JS_IsUndefined(ctor)) {
-        result_promise = js_promise_constructor(ctx, ctor, 1,
-                                                (JSValueConst *)&executor);
-    } else {
-        result_promise = JS_CallConstructor(ctx, ctor, 1,
-                                            (JSValueConst *)&executor);
-    }
-    if (JS_IsException(result_promise))
-        goto fail;
-    s = JS_GetOpaque(executor, JS_CLASS_C_FUNCTION_DATA);
-    for(i = 0; i < 2; i++) {
-        if (check_function(ctx, s->data[i]))
-            goto fail;
-    }
-    for(i = 0; i < 2; i++)
-        resolving_funcs[i] = JS_DupValue(ctx, s->data[i]);
-    JS_FreeValue(ctx, executor);
-    return result_promise;
- fail:
-    JS_FreeValue(ctx, executor);
-    JS_FreeValue(ctx, result_promise);
-    return JS_EXCEPTION;
-}
-
-JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs)
-{
-    return js_new_promise_capability(ctx, resolving_funcs, JS_UNDEFINED);
-}
-
-static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
-                                  int argc, JSValueConst *argv, int magic)
-{
-    JSValue result_promise, resolving_funcs[2], ret;
-    BOOL is_reject = magic;
-
-    if (!JS_IsObject(this_val))
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-    if (!is_reject && JS_GetOpaque(argv[0], JS_CLASS_PROMISE)) {
-        JSValue ctor;
-        BOOL is_same;
-        ctor = JS_GetProperty(ctx, argv[0], JS_ATOM_constructor);
-        if (JS_IsException(ctor))
-            return ctor;
-        is_same = js_same_value(ctx, ctor, this_val);
-        JS_FreeValue(ctx, ctor);
-        if (is_same)
-            return JS_DupValue(ctx, argv[0]);
-    }
-    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
-    if (JS_IsException(result_promise))
-        return result_promise;
-    ret = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED, 1, argv);
-    JS_FreeValue(ctx, resolving_funcs[0]);
-    JS_FreeValue(ctx, resolving_funcs[1]);
-    if (JS_IsException(ret)) {
-        JS_FreeValue(ctx, result_promise);
-        return ret;
-    }
-    JS_FreeValue(ctx, ret);
-    return result_promise;
-}
-
-#if 0
-static JSValue js_promise___newPromiseCapability(JSContext *ctx,
-                                                 JSValueConst this_val,
-                                                 int argc, JSValueConst *argv)
-{
-    JSValue result_promise, resolving_funcs[2], obj;
-    JSValueConst ctor;
-    ctor = argv[0];
-    if (!JS_IsObject(ctor))
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-    result_promise = js_new_promise_capability(ctx, resolving_funcs, ctor);
-    if (JS_IsException(result_promise))
-        return result_promise;
-    obj = JS_NewObject(ctx);
-    if (JS_IsException(obj)) {
-        JS_FreeValue(ctx, resolving_funcs[0]);
-        JS_FreeValue(ctx, resolving_funcs[1]);
-        JS_FreeValue(ctx, result_promise);
-        return JS_EXCEPTION;
-    }
-    JS_DefinePropertyValue(ctx, obj, JS_ATOM_promise, result_promise, JS_PROP_C_W_E);
-    JS_DefinePropertyValue(ctx, obj, JS_ATOM_resolve, resolving_funcs[0], JS_PROP_C_W_E);
-    JS_DefinePropertyValue(ctx, obj, JS_ATOM_reject, resolving_funcs[1], JS_PROP_C_W_E);
-    return obj;
-}
-#endif
-
-static __exception int remainingElementsCount_add(JSContext *ctx,
-                                                  JSValueConst resolve_element_env,
-                                                  int addend)
-{
-    JSValue val;
-    int remainingElementsCount;
-
-    val = JS_GetPropertyUint32(ctx, resolve_element_env, 0);
-    if (JS_IsException(val))
-        return -1;
-    if (JS_ToInt32Free(ctx, &remainingElementsCount, val))
-        return -1;
-    remainingElementsCount += addend;
-    if (JS_SetPropertyUint32(ctx, resolve_element_env, 0,
-                             JS_NewInt32(ctx, remainingElementsCount)) < 0)
-        return -1;
-    return (remainingElementsCount == 0);
-}
-
-#define PROMISE_MAGIC_all        0
-#define PROMISE_MAGIC_allSettled 1
-#define PROMISE_MAGIC_any        2
-
-static JSValue js_promise_all_resolve_element(JSContext *ctx,
-                                              JSValueConst this_val,
-                                              int argc, JSValueConst *argv,
-                                              int magic,
-                                              JSValue *func_data)
-{
-    int resolve_type = magic & 3;
-    int is_reject = magic & 4;
-    BOOL alreadyCalled = JS_ToBool(ctx, func_data[0]);
-    JSValueConst values = func_data[2];
-    JSValueConst resolve = func_data[3];
-    JSValueConst resolve_element_env = func_data[4];
-    JSValue ret, obj;
-    int is_zero, index;
-    
-    if (JS_ToInt32(ctx, &index, func_data[1]))
-        return JS_EXCEPTION;
-    if (alreadyCalled)
-        return JS_UNDEFINED;
-    func_data[0] = JS_NewBool(ctx, TRUE);
-
-    if (resolve_type == PROMISE_MAGIC_allSettled) {
-        JSValue str;
-        
-        obj = JS_NewObject(ctx);
-        if (JS_IsException(obj))
-            return JS_EXCEPTION;
-        str = JS_NewString(ctx, is_reject ? "rejected" : "fulfilled");
-        if (JS_IsException(str))
-            goto fail1;
-        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_status,
-                                   str,
-                                   JS_PROP_C_W_E) < 0)
-            goto fail1;
-        if (JS_DefinePropertyValue(ctx, obj,
-                                   is_reject ? JS_ATOM_reason : JS_ATOM_value,
-                                   JS_DupValue(ctx, argv[0]),
-                                   JS_PROP_C_W_E) < 0) {
-        fail1:
-            JS_FreeValue(ctx, obj);
-            return JS_EXCEPTION;
-        }
-    } else {
-        obj = JS_DupValue(ctx, argv[0]);
-    }
-    if (JS_DefinePropertyValueUint32(ctx, values, index,
-                                     obj, JS_PROP_C_W_E) < 0)
-        return JS_EXCEPTION;
-    
-    is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1);
-    if (is_zero < 0)
-        return JS_EXCEPTION;
-    if (is_zero) {
-        if (resolve_type == PROMISE_MAGIC_any) {
-            JSValue error;
-            error = js_aggregate_error_constructor(ctx, values);
-            if (JS_IsException(error))
-                return JS_EXCEPTION;
-            ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&error);
-            JS_FreeValue(ctx, error);
-        } else {
-            ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&values);
-        }
-        if (JS_IsException(ret))
-            return ret;
-        JS_FreeValue(ctx, ret);
-    }
-    return JS_UNDEFINED;
-}
-
-/* magic = 0: Promise.all 1: Promise.allSettled */
-static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
-                              int argc, JSValueConst *argv, int magic)
-{
-    JSValue result_promise, resolving_funcs[2], item, next_promise, ret;
-    JSValue next_method = JS_UNDEFINED, values = JS_UNDEFINED;
-    JSValue resolve_element_env = JS_UNDEFINED, resolve_element, reject_element;
-    JSValue promise_resolve = JS_UNDEFINED, iter = JS_UNDEFINED;
-    JSValueConst then_args[2], resolve_element_data[5];
-    BOOL done;
-    int index, is_zero, is_promise_any = (magic == PROMISE_MAGIC_any);
-    
-    if (!JS_IsObject(this_val))
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
-    if (JS_IsException(result_promise))
-        return result_promise;
-    promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);
-    if (JS_IsException(promise_resolve) ||
-        check_function(ctx, promise_resolve))
-        goto fail_reject;
-    iter = JS_GetIterator(ctx, argv[0], FALSE);
-    if (JS_IsException(iter)) {
-        JSValue error;
-    fail_reject:
-        error = JS_GetException(ctx);
-        ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
-                       (JSValueConst *)&error);
-        JS_FreeValue(ctx, error);
-        if (JS_IsException(ret))
-            goto fail;
-        JS_FreeValue(ctx, ret);
-    } else {
-        next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
-        if (JS_IsException(next_method))
-            goto fail_reject;
-        values = JS_NewArray(ctx);
-        if (JS_IsException(values))
-            goto fail_reject;
-        resolve_element_env = JS_NewArray(ctx);
-        if (JS_IsException(resolve_element_env))
-            goto fail_reject;
-        /* remainingElementsCount field */
-        if (JS_DefinePropertyValueUint32(ctx, resolve_element_env, 0,
-                                         JS_NewInt32(ctx, 1),
-                                         JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
-            goto fail_reject;
-        
-        index = 0;
-        for(;;) {
-            /* XXX: conformance: should close the iterator if error on 'done'
-               access, but not on 'value' access */
-            item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
-            if (JS_IsException(item))
-                goto fail_reject;
-            if (done)
-                break;
-            next_promise = JS_Call(ctx, promise_resolve, 
-                                   this_val, 1, (JSValueConst *)&item);
-            JS_FreeValue(ctx, item);
-            if (JS_IsException(next_promise)) {
-            fail_reject1:
-                JS_IteratorClose(ctx, iter, TRUE);
-                goto fail_reject;
-            }
-            resolve_element_data[0] = JS_NewBool(ctx, FALSE);
-            resolve_element_data[1] = (JSValueConst)JS_NewInt32(ctx, index);
-            resolve_element_data[2] = values;
-            resolve_element_data[3] = resolving_funcs[is_promise_any];
-            resolve_element_data[4] = resolve_element_env;
-            resolve_element =
-                JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,
-                                    magic, 5, resolve_element_data);
-            if (JS_IsException(resolve_element)) {
-                JS_FreeValue(ctx, next_promise);
-                goto fail_reject1;
-            }
-            
-            if (magic == PROMISE_MAGIC_allSettled) {
-                reject_element =
-                    JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,
-                                        magic | 4, 5, resolve_element_data);
-                if (JS_IsException(reject_element)) {
-                    JS_FreeValue(ctx, next_promise);
-                    goto fail_reject1;
-                }
-            } else if (magic == PROMISE_MAGIC_any) {
-                if (JS_DefinePropertyValueUint32(ctx, values, index,
-                                                 JS_UNDEFINED, JS_PROP_C_W_E) < 0)
-                    goto fail_reject1;
-                reject_element = resolve_element;
-                resolve_element = JS_DupValue(ctx, resolving_funcs[0]);
-            } else {
-                reject_element = JS_DupValue(ctx, resolving_funcs[1]);
-            }
-
-            if (remainingElementsCount_add(ctx, resolve_element_env, 1) < 0) {
-                JS_FreeValue(ctx, next_promise);
-                JS_FreeValue(ctx, resolve_element);
-                JS_FreeValue(ctx, reject_element);
-                goto fail_reject1;
-            }
-
-            then_args[0] = resolve_element;
-            then_args[1] = reject_element;
-            ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2, then_args);
-            JS_FreeValue(ctx, resolve_element);
-            JS_FreeValue(ctx, reject_element);
-            if (check_exception_free(ctx, ret))
-                goto fail_reject1;
-            index++;
-        }
-
-        is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1);
-        if (is_zero < 0)
-            goto fail_reject;
-        if (is_zero) {
-            if (magic == PROMISE_MAGIC_any) {
-                JSValue error;
-                error = js_aggregate_error_constructor(ctx, values);
-                if (JS_IsException(error))
-                    goto fail_reject;
-                JS_FreeValue(ctx, values);
-                values = error;
-            }
-            ret = JS_Call(ctx, resolving_funcs[is_promise_any], JS_UNDEFINED,
-                          1, (JSValueConst *)&values);
-            if (check_exception_free(ctx, ret))
-                goto fail_reject;
-        }
-    }
- done:
-    JS_FreeValue(ctx, promise_resolve);
-    JS_FreeValue(ctx, resolve_element_env);
-    JS_FreeValue(ctx, values);
-    JS_FreeValue(ctx, next_method);
-    JS_FreeValue(ctx, iter);
-    JS_FreeValue(ctx, resolving_funcs[0]);
-    JS_FreeValue(ctx, resolving_funcs[1]);
-    return result_promise;
- fail:
-    JS_FreeValue(ctx, result_promise);
-    result_promise = JS_EXCEPTION;
-    goto done;
-}
-
-static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val,
-                               int argc, JSValueConst *argv)
-{
-    JSValue result_promise, resolving_funcs[2], item, next_promise, ret;
-    JSValue next_method = JS_UNDEFINED, iter = JS_UNDEFINED;
-    JSValue promise_resolve = JS_UNDEFINED;
-    BOOL done;
-
-    if (!JS_IsObject(this_val))
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
-    if (JS_IsException(result_promise))
-        return result_promise;
-    promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);
-    if (JS_IsException(promise_resolve) ||
-        check_function(ctx, promise_resolve))
-        goto fail_reject;
-    iter = JS_GetIterator(ctx, argv[0], FALSE);
-    if (JS_IsException(iter)) {
-        JSValue error;
-    fail_reject:
-        error = JS_GetException(ctx);
-        ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
-                       (JSValueConst *)&error);
-        JS_FreeValue(ctx, error);
-        if (JS_IsException(ret))
-            goto fail;
-        JS_FreeValue(ctx, ret);
-    } else {
-        next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
-        if (JS_IsException(next_method))
-            goto fail_reject;
-
-        for(;;) {
-            /* XXX: conformance: should close the iterator if error on 'done'
-               access, but not on 'value' access */
-            item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
-            if (JS_IsException(item))
-                goto fail_reject;
-            if (done)
-                break;
-            next_promise = JS_Call(ctx, promise_resolve,
-                                   this_val, 1, (JSValueConst *)&item);
-            JS_FreeValue(ctx, item);
-            if (JS_IsException(next_promise)) {
-            fail_reject1:
-                JS_IteratorClose(ctx, iter, TRUE);
-                goto fail_reject;
-            }
-            ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2,
-                                (JSValueConst *)resolving_funcs);
-            if (check_exception_free(ctx, ret))
-                goto fail_reject1;
-        }
-    }
- done:
-    JS_FreeValue(ctx, promise_resolve);
-    JS_FreeValue(ctx, next_method);
-    JS_FreeValue(ctx, iter);
-    JS_FreeValue(ctx, resolving_funcs[0]);
-    JS_FreeValue(ctx, resolving_funcs[1]);
-    return result_promise;
- fail:
-    //JS_FreeValue(ctx, next_method); // why not???
-    JS_FreeValue(ctx, result_promise);
-    result_promise = JS_EXCEPTION;
-    goto done;
-}
-
-static __exception int perform_promise_then(JSContext *ctx,
-                                            JSValueConst promise,
-                                            JSValueConst *resolve_reject,
-                                            JSValueConst *cap_resolving_funcs)
-{
-    JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
-    JSPromiseReactionData *rd_array[2], *rd;
-    int i, j;
-
-    rd_array[0] = NULL;
-    rd_array[1] = NULL;
-    for(i = 0; i < 2; i++) {
-        JSValueConst handler;
-        rd = js_mallocz(ctx, sizeof(*rd));
-        if (!rd) {
-            if (i == 1)
-                promise_reaction_data_free(ctx->rt, rd_array[0]);
-            return -1;
-        }
-        for(j = 0; j < 2; j++)
-            rd->resolving_funcs[j] = JS_DupValue(ctx, cap_resolving_funcs[j]);
-        handler = resolve_reject[i];
-        if (!JS_IsFunction(ctx, handler))
-            handler = JS_UNDEFINED;
-        rd->handler = JS_DupValue(ctx, handler);
-        rd_array[i] = rd;
-    }
-
-    if (s->promise_state == JS_PROMISE_PENDING) {
-        for(i = 0; i < 2; i++)
-            list_add_tail(&rd_array[i]->link, &s->promise_reactions[i]);
-    } else {
-        JSValueConst args[5];
-        if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {
-            JSRuntime *rt = ctx->rt;
-            if (rt->host_promise_rejection_tracker) {
-                rt->host_promise_rejection_tracker(ctx, promise, s->promise_result,
-                                                   TRUE, rt->host_promise_rejection_tracker_opaque);
-            }
-        }
-        i = s->promise_state - JS_PROMISE_FULFILLED;
-        rd = rd_array[i];
-        args[0] = rd->resolving_funcs[0];
-        args[1] = rd->resolving_funcs[1];
-        args[2] = rd->handler;
-        args[3] = JS_NewBool(ctx, i);
-        args[4] = s->promise_result;
-        JS_EnqueueJob(ctx, promise_reaction_job, 5, args);
-        for(i = 0; i < 2; i++)
-            promise_reaction_data_free(ctx->rt, rd_array[i]);
-    }
-    s->is_handled = TRUE;
-    return 0;
-}
-
-static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val,
-                               int argc, JSValueConst *argv)
-{
-    JSValue ctor, result_promise, resolving_funcs[2];
-    JSPromiseData *s;
-    int i, ret;
-
-    s = JS_GetOpaque2(ctx, this_val, JS_CLASS_PROMISE);
-    if (!s)
-        return JS_EXCEPTION;
-
-    ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
-    if (JS_IsException(ctor))
-        return ctor;
-    result_promise = js_new_promise_capability(ctx, resolving_funcs, ctor);
-    JS_FreeValue(ctx, ctor);
-    if (JS_IsException(result_promise))
-        return result_promise;
-    ret = perform_promise_then(ctx, this_val, argv,
-                               (JSValueConst *)resolving_funcs);
-    for(i = 0; i < 2; i++)
-        JS_FreeValue(ctx, resolving_funcs[i]);
-    if (ret) {
-        JS_FreeValue(ctx, result_promise);
-        return JS_EXCEPTION;
-    }
-    return result_promise;
-}
-
-static JSValue js_promise_catch(JSContext *ctx, JSValueConst this_val,
-                                int argc, JSValueConst *argv)
-{
-    JSValueConst args[2];
-    args[0] = JS_UNDEFINED;
-    args[1] = argv[0];
-    return JS_Invoke(ctx, this_val, JS_ATOM_then, 2, args);
-}
-
-static JSValue js_promise_finally_value_thunk(JSContext *ctx, JSValueConst this_val,
-                                              int argc, JSValueConst *argv,
-                                              int magic, JSValue *func_data)
-{
-    return JS_DupValue(ctx, func_data[0]);
-}
-
-static JSValue js_promise_finally_thrower(JSContext *ctx, JSValueConst this_val,
-                                          int argc, JSValueConst *argv,
-                                          int magic, JSValue *func_data)
-{
-    return JS_Throw(ctx, JS_DupValue(ctx, func_data[0]));
-}
-
-static JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_val,
-                                            int argc, JSValueConst *argv,
-                                            int magic, JSValue *func_data)
-{
-    JSValueConst ctor = func_data[0];
-    JSValueConst onFinally = func_data[1];
-    JSValue res, promise, ret, then_func;
-
-    res = JS_Call(ctx, onFinally, JS_UNDEFINED, 0, NULL);
-    if (JS_IsException(res))
-        return res;
-    promise = js_promise_resolve(ctx, ctor, 1, (JSValueConst *)&res, 0);
-    JS_FreeValue(ctx, res);
-    if (JS_IsException(promise))
-        return promise;
-    if (magic == 0) {
-        then_func = JS_NewCFunctionData(ctx, js_promise_finally_value_thunk, 0,
-                                        0, 1, argv);
-    } else {
-        then_func = JS_NewCFunctionData(ctx, js_promise_finally_thrower, 0,
-                                        0, 1, argv);
-    }
-    if (JS_IsException(then_func)) {
-        JS_FreeValue(ctx, promise);
-        return then_func;
-    }
-    ret = JS_InvokeFree(ctx, promise, JS_ATOM_then, 1, (JSValueConst *)&then_func);
-    JS_FreeValue(ctx, then_func);
-    return ret;
-}
-
-static JSValue js_promise_finally(JSContext *ctx, JSValueConst this_val,
-                                  int argc, JSValueConst *argv)
-{
-    JSValueConst onFinally = argv[0];
-    JSValue ctor, ret;
-    JSValue then_funcs[2];
-    JSValueConst func_data[2];
-    int i;
-
-    ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
-    if (JS_IsException(ctor))
-        return ctor;
-    if (!JS_IsFunction(ctx, onFinally)) {
-        then_funcs[0] = JS_DupValue(ctx, onFinally);
-        then_funcs[1] = JS_DupValue(ctx, onFinally);
-    } else {
-        func_data[0] = ctor;
-        func_data[1] = onFinally;
-        for(i = 0; i < 2; i++) {
-            then_funcs[i] = JS_NewCFunctionData(ctx, js_promise_then_finally_func, 1, i, 2, func_data);
-            if (JS_IsException(then_funcs[i])) {
-                if (i == 1)
-                    JS_FreeValue(ctx, then_funcs[0]);
-                JS_FreeValue(ctx, ctor);
-                return JS_EXCEPTION;
-            }
-        }
-    }
-    JS_FreeValue(ctx, ctor);
-    ret = JS_Invoke(ctx, this_val, JS_ATOM_then, 2, (JSValueConst *)then_funcs);
-    JS_FreeValue(ctx, then_funcs[0]);
-    JS_FreeValue(ctx, then_funcs[1]);
-    return ret;
-}
-
-static const JSCFunctionListEntry js_promise_funcs[] = {
-    JS_CFUNC_MAGIC_DEF("resolve", 1, js_promise_resolve, 0 ),
-    JS_CFUNC_MAGIC_DEF("reject", 1, js_promise_resolve, 1 ),
-    JS_CFUNC_MAGIC_DEF("all", 1, js_promise_all, PROMISE_MAGIC_all ),
-    JS_CFUNC_MAGIC_DEF("allSettled", 1, js_promise_all, PROMISE_MAGIC_allSettled ),
-    JS_CFUNC_MAGIC_DEF("any", 1, js_promise_all, PROMISE_MAGIC_any ),
-    JS_CFUNC_DEF("race", 1, js_promise_race ),
-    //JS_CFUNC_DEF("__newPromiseCapability", 1, js_promise___newPromiseCapability ),
-    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL),
-};
-
-static const JSCFunctionListEntry js_promise_proto_funcs[] = {
-    JS_CFUNC_DEF("then", 2, js_promise_then ),
-    JS_CFUNC_DEF("catch", 1, js_promise_catch ),
-    JS_CFUNC_DEF("finally", 1, js_promise_finally ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Promise", JS_PROP_CONFIGURABLE ),
-};
-
-/* AsyncFunction */
-static const JSCFunctionListEntry js_async_function_proto_funcs[] = {
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncFunction", JS_PROP_CONFIGURABLE ),
-};
-
-static JSValue js_async_from_sync_iterator_unwrap(JSContext *ctx,
-                                                  JSValueConst this_val,
-                                                  int argc, JSValueConst *argv,
-                                                  int magic, JSValue *func_data)
-{
-    return js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]),
-                                     JS_ToBool(ctx, func_data[0]));
-}
-
-static JSValue js_async_from_sync_iterator_unwrap_func_create(JSContext *ctx,
-                                                              BOOL done)
-{
-    JSValueConst func_data[1];
-
-    func_data[0] = (JSValueConst)JS_NewBool(ctx, done);
-    return JS_NewCFunctionData(ctx, js_async_from_sync_iterator_unwrap,
-                               1, 0, 1, func_data);
-}
-
-/* AsyncIteratorPrototype */
-
-static const JSCFunctionListEntry js_async_iterator_proto_funcs[] = {
-    JS_CFUNC_DEF("[Symbol.asyncIterator]", 0, js_iterator_proto_iterator ),
-};
-
-/* AsyncFromSyncIteratorPrototype */
-
-typedef struct JSAsyncFromSyncIteratorData {
-    JSValue sync_iter;
-    JSValue next_method;
-} JSAsyncFromSyncIteratorData;
-
-static void js_async_from_sync_iterator_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSAsyncFromSyncIteratorData *s =
-        JS_GetOpaque(val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
-    if (s) {
-        JS_FreeValueRT(rt, s->sync_iter);
-        JS_FreeValueRT(rt, s->next_method);
-        js_free_rt(rt, s);
-    }
-}
-
-static void js_async_from_sync_iterator_mark(JSRuntime *rt, JSValueConst val,
-                                             JS_MarkFunc *mark_func)
-{
-    JSAsyncFromSyncIteratorData *s =
-        JS_GetOpaque(val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
-    if (s) {
-        JS_MarkValue(rt, s->sync_iter, mark_func);
-        JS_MarkValue(rt, s->next_method, mark_func);
-    }
-}
-
-static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx,
-                                              JSValueConst sync_iter)
-{
-    JSValue async_iter, next_method;
-    JSAsyncFromSyncIteratorData *s;
-
-    next_method = JS_GetProperty(ctx, sync_iter, JS_ATOM_next);
-    if (JS_IsException(next_method))
-        return JS_EXCEPTION;
-    async_iter = JS_NewObjectClass(ctx, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
-    if (JS_IsException(async_iter)) {
-        JS_FreeValue(ctx, next_method);
-        return async_iter;
-    }
-    s = js_mallocz(ctx, sizeof(*s));
-    if (!s) {
-        JS_FreeValue(ctx, async_iter);
-        JS_FreeValue(ctx, next_method);
-        return JS_EXCEPTION;
-    }
-    s->sync_iter = JS_DupValue(ctx, sync_iter);
-    s->next_method = next_method;
-    JS_SetOpaque(async_iter, s);
-    return async_iter;
-}
-
-static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst this_val,
-                                                int argc, JSValueConst *argv,
-                                                int magic)
-{
-    JSValue promise, resolving_funcs[2], value, err, method;
-    JSAsyncFromSyncIteratorData *s;
-    int done;
-    int is_reject;
-
-    promise = JS_NewPromiseCapability(ctx, resolving_funcs);
-    if (JS_IsException(promise))
-        return JS_EXCEPTION;
-    s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
-    if (!s) {
-        JS_ThrowTypeError(ctx, "not an Async-from-Sync Iterator");
-        goto reject;
-    }
-
-    if (magic == GEN_MAGIC_NEXT) {
-        method = JS_DupValue(ctx, s->next_method);
-    } else {
-        method = JS_GetProperty(ctx, s->sync_iter,
-                                magic == GEN_MAGIC_RETURN ? JS_ATOM_return :
-                                JS_ATOM_throw);
-        if (JS_IsException(method))
-            goto reject;
-        if (JS_IsUndefined(method) || JS_IsNull(method)) {
-            if (magic == GEN_MAGIC_RETURN) {
-                err = js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]), TRUE);
-                is_reject = 0;
-            } else {
-                err = JS_DupValue(ctx, argv[0]);
-                is_reject = 1;
-            }
-            goto done_resolve;
-        }
-    }
-    value = JS_IteratorNext2(ctx, s->sync_iter, method,
-                             argc >= 1 ? 1 : 0, argv, &done);
-    JS_FreeValue(ctx, method);
-    if (JS_IsException(value))
-        goto reject;
-    if (done == 2) {
-        JSValue obj = value;
-        value = JS_IteratorGetCompleteValue(ctx, obj, &done);
-        JS_FreeValue(ctx, obj);
-        if (JS_IsException(value))
-            goto reject;
-    }
-
-    if (JS_IsException(value)) {
-        JSValue res2;
-    reject:
-        err = JS_GetException(ctx);
-        is_reject = 1;
-    done_resolve:
-        res2 = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED,
-                       1, (JSValueConst *)&err);
-        JS_FreeValue(ctx, err);
-        JS_FreeValue(ctx, res2);
-        JS_FreeValue(ctx, resolving_funcs[0]);
-        JS_FreeValue(ctx, resolving_funcs[1]);
-        return promise;
-    }
-    {
-        JSValue value_wrapper_promise, resolve_reject[2];
-        int res;
-
-        value_wrapper_promise = js_promise_resolve(ctx, ctx->promise_ctor,
-                                                   1, (JSValueConst *)&value, 0);
-        if (JS_IsException(value_wrapper_promise)) {
-            JS_FreeValue(ctx, value);
-            goto reject;
-        }
-
-        resolve_reject[0] =
-            js_async_from_sync_iterator_unwrap_func_create(ctx, done);
-        if (JS_IsException(resolve_reject[0])) {
-            JS_FreeValue(ctx, value_wrapper_promise);
-            goto fail;
-        }
-        JS_FreeValue(ctx, value);
-        resolve_reject[1] = JS_UNDEFINED;
-
-        res = perform_promise_then(ctx, value_wrapper_promise,
-                                   (JSValueConst *)resolve_reject,
-                                   (JSValueConst *)resolving_funcs);
-        JS_FreeValue(ctx, resolve_reject[0]);
-        JS_FreeValue(ctx, value_wrapper_promise);
-        JS_FreeValue(ctx, resolving_funcs[0]);
-        JS_FreeValue(ctx, resolving_funcs[1]);
-        if (res) {
-            JS_FreeValue(ctx, promise);
-            return JS_EXCEPTION;
-        }
-    }
-    return promise;
- fail:
-    JS_FreeValue(ctx, value);
-    JS_FreeValue(ctx, resolving_funcs[0]);
-    JS_FreeValue(ctx, resolving_funcs[1]);
-    JS_FreeValue(ctx, promise);
-    return JS_EXCEPTION;
-}
-
-static const JSCFunctionListEntry js_async_from_sync_iterator_proto_funcs[] = {
-    JS_CFUNC_MAGIC_DEF("next", 1, js_async_from_sync_iterator_next, GEN_MAGIC_NEXT ),
-    JS_CFUNC_MAGIC_DEF("return", 1, js_async_from_sync_iterator_next, GEN_MAGIC_RETURN ),
-    JS_CFUNC_MAGIC_DEF("throw", 1, js_async_from_sync_iterator_next, GEN_MAGIC_THROW ),
-};
-
-/* AsyncGeneratorFunction */
-
-static const JSCFunctionListEntry js_async_generator_function_proto_funcs[] = {
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncGeneratorFunction", JS_PROP_CONFIGURABLE ),
-};
-
-/* AsyncGenerator prototype */
-
-static const JSCFunctionListEntry js_async_generator_proto_funcs[] = {
-    JS_CFUNC_MAGIC_DEF("next", 1, js_async_generator_next, GEN_MAGIC_NEXT ),
-    JS_CFUNC_MAGIC_DEF("return", 1, js_async_generator_next, GEN_MAGIC_RETURN ),
-    JS_CFUNC_MAGIC_DEF("throw", 1, js_async_generator_next, GEN_MAGIC_THROW ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncGenerator", JS_PROP_CONFIGURABLE ),
-};
-
-static JSClassShortDef const js_async_class_def[] = {
-    { JS_ATOM_Promise, js_promise_finalizer, js_promise_mark },                      /* JS_CLASS_PROMISE */
-    { JS_ATOM_PromiseResolveFunction, js_promise_resolve_function_finalizer, js_promise_resolve_function_mark }, /* JS_CLASS_PROMISE_RESOLVE_FUNCTION */
-    { JS_ATOM_PromiseRejectFunction, js_promise_resolve_function_finalizer, js_promise_resolve_function_mark }, /* JS_CLASS_PROMISE_REJECT_FUNCTION */
-    { JS_ATOM_AsyncFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_ASYNC_FUNCTION */
-    { JS_ATOM_AsyncFunctionResolve, js_async_function_resolve_finalizer, js_async_function_resolve_mark }, /* JS_CLASS_ASYNC_FUNCTION_RESOLVE */
-    { JS_ATOM_AsyncFunctionReject, js_async_function_resolve_finalizer, js_async_function_resolve_mark }, /* JS_CLASS_ASYNC_FUNCTION_REJECT */
-    { JS_ATOM_empty_string, js_async_from_sync_iterator_finalizer, js_async_from_sync_iterator_mark }, /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */
-    { JS_ATOM_AsyncGeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_ASYNC_GENERATOR_FUNCTION */
-    { JS_ATOM_AsyncGenerator, js_async_generator_finalizer, js_async_generator_mark },  /* JS_CLASS_ASYNC_GENERATOR */
-};
-
-void JS_AddIntrinsicPromise(JSContext *ctx)
-{
-    JSRuntime *rt = ctx->rt;
-    JSValue obj1;
-
-    if (!JS_IsRegisteredClass(rt, JS_CLASS_PROMISE)) {
-        init_class_range(rt, js_async_class_def, JS_CLASS_PROMISE,
-                         countof(js_async_class_def));
-        rt->class_array[JS_CLASS_PROMISE_RESOLVE_FUNCTION].call = js_promise_resolve_function_call;
-        rt->class_array[JS_CLASS_PROMISE_REJECT_FUNCTION].call = js_promise_resolve_function_call;
-        rt->class_array[JS_CLASS_ASYNC_FUNCTION].call = js_async_function_call;
-        rt->class_array[JS_CLASS_ASYNC_FUNCTION_RESOLVE].call = js_async_function_resolve_call;
-        rt->class_array[JS_CLASS_ASYNC_FUNCTION_REJECT].call = js_async_function_resolve_call;
-        rt->class_array[JS_CLASS_ASYNC_GENERATOR_FUNCTION].call = js_async_generator_function_call;
-    }
-
-    /* Promise */
-    ctx->class_proto[JS_CLASS_PROMISE] = JS_NewObject(ctx);
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_PROMISE],
-                               js_promise_proto_funcs,
-                               countof(js_promise_proto_funcs));
-    obj1 = JS_NewCFunction2(ctx, js_promise_constructor, "Promise", 1,
-                            JS_CFUNC_constructor, 0);
-    ctx->promise_ctor = JS_DupValue(ctx, obj1);
-    JS_SetPropertyFunctionList(ctx, obj1,
-                               js_promise_funcs,
-                               countof(js_promise_funcs));
-    JS_NewGlobalCConstructor2(ctx, obj1, "Promise",
-                              ctx->class_proto[JS_CLASS_PROMISE]);
-
-    /* AsyncFunction */
-    ctx->class_proto[JS_CLASS_ASYNC_FUNCTION] = JS_NewObjectProto(ctx, ctx->function_proto);
-    obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor,
-                            "AsyncFunction", 1,
-                            JS_CFUNC_constructor_or_func_magic, JS_FUNC_ASYNC,
-                            ctx->function_ctor);
-    JS_SetPropertyFunctionList(ctx,
-                               ctx->class_proto[JS_CLASS_ASYNC_FUNCTION],
-                               js_async_function_proto_funcs,
-                               countof(js_async_function_proto_funcs));
-    JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_ASYNC_FUNCTION],
-                       0, JS_PROP_CONFIGURABLE);
-    JS_FreeValue(ctx, obj1);
-
-    /* AsyncIteratorPrototype */
-    ctx->async_iterator_proto = JS_NewObject(ctx);
-    JS_SetPropertyFunctionList(ctx, ctx->async_iterator_proto,
-                               js_async_iterator_proto_funcs,
-                               countof(js_async_iterator_proto_funcs));
-
-    /* AsyncFromSyncIteratorPrototype */
-    ctx->class_proto[JS_CLASS_ASYNC_FROM_SYNC_ITERATOR] =
-        JS_NewObjectProto(ctx, ctx->async_iterator_proto);
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ASYNC_FROM_SYNC_ITERATOR],
-                               js_async_from_sync_iterator_proto_funcs,
-                               countof(js_async_from_sync_iterator_proto_funcs));
-
-    /* AsyncGeneratorPrototype */
-    ctx->class_proto[JS_CLASS_ASYNC_GENERATOR] =
-        JS_NewObjectProto(ctx, ctx->async_iterator_proto);
-    JS_SetPropertyFunctionList(ctx,
-                               ctx->class_proto[JS_CLASS_ASYNC_GENERATOR],
-                               js_async_generator_proto_funcs,
-                               countof(js_async_generator_proto_funcs));
-
-    /* AsyncGeneratorFunction */
-    ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION] =
-        JS_NewObjectProto(ctx, ctx->function_proto);
-    obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor,
-                            "AsyncGeneratorFunction", 1,
-                            JS_CFUNC_constructor_or_func_magic,
-                            JS_FUNC_ASYNC_GENERATOR,
-                            ctx->function_ctor);
-    JS_SetPropertyFunctionList(ctx,
-                               ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
-                               js_async_generator_function_proto_funcs,
-                               countof(js_async_generator_function_proto_funcs));
-    JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
-                       ctx->class_proto[JS_CLASS_ASYNC_GENERATOR],
-                       JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE);
-    JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
-                       0, JS_PROP_CONFIGURABLE);
-    JS_FreeValue(ctx, obj1);
-}
-
-/* URI handling */
-
-static int string_get_hex(JSString *p, int k, int n) {
-    int c = 0, h;
-    while (n-- > 0) {
-        if ((h = from_hex(string_get(p, k++))) < 0)
-            return -1;
-        c = (c << 4) | h;
-    }
-    return c;
-}
-
-static int isURIReserved(int c) {
-    return c < 0x100 && memchr(";/?:@&=+$,#", c, sizeof(";/?:@&=+$,#") - 1) != NULL;
-}
-
-static int __attribute__((format(printf, 2, 3))) js_throw_URIError(JSContext *ctx, const char *fmt, ...)
-{
-    va_list ap;
-
-    va_start(ap, fmt);
-    JS_ThrowError(ctx, JS_URI_ERROR, fmt, ap);
-    va_end(ap);
-    return -1;
-}
-
-static int hex_decode(JSContext *ctx, JSString *p, int k) {
-    int c;
-
-    if (k >= p->len || string_get(p, k) != '%')
-        return js_throw_URIError(ctx, "expecting %%");
-    if (k + 2 >= p->len || (c = string_get_hex(p, k + 1, 2)) < 0)
-        return js_throw_URIError(ctx, "expecting hex digit");
-
-    return c;
-}
-
-static JSValue js_global_decodeURI(JSContext *ctx, JSValueConst this_val,
-                                   int argc, JSValueConst *argv, int isComponent)
-{
-    JSValue str;
-    StringBuffer b_s, *b = &b_s;
-    JSString *p;
-    int k, c, c1, n, c_min;
-
-    str = JS_ToString(ctx, argv[0]);
-    if (JS_IsException(str))
-        return str;
-
-    string_buffer_init(ctx, b, 0);
-
-    p = JS_VALUE_GET_STRING(str);
-    for (k = 0; k < p->len;) {
-        c = string_get(p, k);
-        if (c == '%') {
-            c = hex_decode(ctx, p, k);
-            if (c < 0)
-                goto fail;
-            k += 3;
-            if (c < 0x80) {
-                if (!isComponent && isURIReserved(c)) {
-                    c = '%';
-                    k -= 2;
-                }
-            } else {
-                /* Decode URI-encoded UTF-8 sequence */
-                if (c >= 0xc0 && c <= 0xdf) {
-                    n = 1;
-                    c_min = 0x80;
-                    c &= 0x1f;
-                } else if (c >= 0xe0 && c <= 0xef) {
-                    n = 2;
-                    c_min = 0x800;
-                    c &= 0xf;
-                } else if (c >= 0xf0 && c <= 0xf7) {
-                    n = 3;
-                    c_min = 0x10000;
-                    c &= 0x7;
-                } else {
-                    n = 0;
-                    c_min = 1;
-                    c = 0;
-                }
-                while (n-- > 0) {
-                    c1 = hex_decode(ctx, p, k);
-                    if (c1 < 0)
-                        goto fail;
-                    k += 3;
-                    if ((c1 & 0xc0) != 0x80) {
-                        c = 0;
-                        break;
-                    }
-                    c = (c << 6) | (c1 & 0x3f);
-                }
-                if (c < c_min || c > 0x10FFFF ||
-                    (c >= 0xd800 && c < 0xe000)) {
-                    js_throw_URIError(ctx, "malformed UTF-8");
-                    goto fail;
-                }
-            }
-        } else {
-            k++;
-        }
-        string_buffer_putc(b, c);
-    }
-    JS_FreeValue(ctx, str);
-    return string_buffer_end(b);
-
-fail:
-    JS_FreeValue(ctx, str);
-    string_buffer_free(b);
-    return JS_EXCEPTION;
-}
-
-static int isUnescaped(int c) {
-    static char const unescaped_chars[] =
-        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-        "abcdefghijklmnopqrstuvwxyz"
-        "0123456789"
-        "@*_+-./";
-    return c < 0x100 &&
-        memchr(unescaped_chars, c, sizeof(unescaped_chars) - 1);
-}
-
-static int isURIUnescaped(int c, int isComponent) {
-    return c < 0x100 &&
-        ((c >= 0x61 && c <= 0x7a) ||
-         (c >= 0x41 && c <= 0x5a) ||
-         (c >= 0x30 && c <= 0x39) ||
-         memchr("-_.!~*'()", c, sizeof("-_.!~*'()") - 1) != NULL ||
-         (!isComponent && isURIReserved(c)));
-}
-
-static int encodeURI_hex(StringBuffer *b, int c) {
-    uint8_t buf[6];
-    int n = 0;
-    const char *hex = "0123456789ABCDEF";
-
-    buf[n++] = '%';
-    if (c >= 256) {
-        buf[n++] = 'u';
-        buf[n++] = hex[(c >> 12) & 15];
-        buf[n++] = hex[(c >>  8) & 15];
-    }
-    buf[n++] = hex[(c >> 4) & 15];
-    buf[n++] = hex[(c >> 0) & 15];
-    return string_buffer_write8(b, buf, n);
-}
-
-static JSValue js_global_encodeURI(JSContext *ctx, JSValueConst this_val,
-                                   int argc, JSValueConst *argv,
-                                   int isComponent)
-{
-    JSValue str;
-    StringBuffer b_s, *b = &b_s;
-    JSString *p;
-    int k, c, c1;
-
-    str = JS_ToString(ctx, argv[0]);
-    if (JS_IsException(str))
-        return str;
-
-    p = JS_VALUE_GET_STRING(str);
-    string_buffer_init(ctx, b, p->len);
-    for (k = 0; k < p->len;) {
-        c = string_get(p, k);
-        k++;
-        if (isURIUnescaped(c, isComponent)) {
-            string_buffer_putc16(b, c);
-        } else {
-            if (c >= 0xdc00 && c <= 0xdfff) {
-                js_throw_URIError(ctx, "invalid character");
-                goto fail;
-            } else if (c >= 0xd800 && c <= 0xdbff) {
-                if (k >= p->len) {
-                    js_throw_URIError(ctx, "expecting surrogate pair");
-                    goto fail;
-                }
-                c1 = string_get(p, k);
-                k++;
-                if (c1 < 0xdc00 || c1 > 0xdfff) {
-                    js_throw_URIError(ctx, "expecting surrogate pair");
-                    goto fail;
-                }
-                c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
-            }
-            if (c < 0x80) {
-                encodeURI_hex(b, c);
-            } else {
-                /* XXX: use C UTF-8 conversion ? */
-                if (c < 0x800) {
-                    encodeURI_hex(b, (c >> 6) | 0xc0);
-                } else {
-                    if (c < 0x10000) {
-                        encodeURI_hex(b, (c >> 12) | 0xe0);
-                    } else {
-                        encodeURI_hex(b, (c >> 18) | 0xf0);
-                        encodeURI_hex(b, ((c >> 12) & 0x3f) | 0x80);
-                    }
-                    encodeURI_hex(b, ((c >> 6) & 0x3f) | 0x80);
-                }
-                encodeURI_hex(b, (c & 0x3f) | 0x80);
-            }
-        }
-    }
-    JS_FreeValue(ctx, str);
-    return string_buffer_end(b);
-
-fail:
-    JS_FreeValue(ctx, str);
-    string_buffer_free(b);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_global_escape(JSContext *ctx, JSValueConst this_val,
-                                int argc, JSValueConst *argv)
-{
-    JSValue str;
-    StringBuffer b_s, *b = &b_s;
-    JSString *p;
-    int i, len, c;
-
-    str = JS_ToString(ctx, argv[0]);
-    if (JS_IsException(str))
-        return str;
-
-    p = JS_VALUE_GET_STRING(str);
-    string_buffer_init(ctx, b, p->len);
-    for (i = 0, len = p->len; i < len; i++) {
-        c = string_get(p, i);
-        if (isUnescaped(c)) {
-            string_buffer_putc16(b, c);
-        } else {
-            encodeURI_hex(b, c);
-        }
-    }
-    JS_FreeValue(ctx, str);
-    return string_buffer_end(b);
-}
-
-static JSValue js_global_unescape(JSContext *ctx, JSValueConst this_val,
-                                  int argc, JSValueConst *argv)
-{
-    JSValue str;
-    StringBuffer b_s, *b = &b_s;
-    JSString *p;
-    int i, len, c, n;
-
-    str = JS_ToString(ctx, argv[0]);
-    if (JS_IsException(str))
-        return str;
-
-    string_buffer_init(ctx, b, 0);
-    p = JS_VALUE_GET_STRING(str);
-    for (i = 0, len = p->len; i < len; i++) {
-        c = string_get(p, i);
-        if (c == '%') {
-            if (i + 6 <= len
-            &&  string_get(p, i + 1) == 'u'
-            &&  (n = string_get_hex(p, i + 2, 4)) >= 0) {
-                c = n;
-                i += 6 - 1;
-            } else
-            if (i + 3 <= len
-            &&  (n = string_get_hex(p, i + 1, 2)) >= 0) {
-                c = n;
-                i += 3 - 1;
-            }
-        }
-        string_buffer_putc16(b, c);
-    }
-    JS_FreeValue(ctx, str);
-    return string_buffer_end(b);
-}
-
-/* global object */
-
-static const JSCFunctionListEntry js_global_funcs[] = {
-    JS_CFUNC_DEF("parseInt", 2, js_parseInt ),
-    JS_CFUNC_DEF("parseFloat", 1, js_parseFloat ),
-    JS_CFUNC_DEF("isNaN", 1, js_global_isNaN ),
-    JS_CFUNC_DEF("isFinite", 1, js_global_isFinite ),
-
-    JS_CFUNC_MAGIC_DEF("decodeURI", 1, js_global_decodeURI, 0 ),
-    JS_CFUNC_MAGIC_DEF("decodeURIComponent", 1, js_global_decodeURI, 1 ),
-    JS_CFUNC_MAGIC_DEF("encodeURI", 1, js_global_encodeURI, 0 ),
-    JS_CFUNC_MAGIC_DEF("encodeURIComponent", 1, js_global_encodeURI, 1 ),
-    JS_CFUNC_DEF("escape", 1, js_global_escape ),
-    JS_CFUNC_DEF("unescape", 1, js_global_unescape ),
-    JS_PROP_DOUBLE_DEF("Infinity", 1.0 / 0.0, 0 ),
-    JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ),
-    JS_PROP_UNDEFINED_DEF("undefined", 0 ),
-
-    /* for the 'Date' implementation */
-    JS_CFUNC_DEF("__date_clock", 0, js___date_clock ),
-    //JS_CFUNC_DEF("__date_now", 0, js___date_now ),
-    //JS_CFUNC_DEF("__date_getTimezoneOffset", 1, js___date_getTimezoneOffset ),
-    //JS_CFUNC_DEF("__date_create", 3, js___date_create ),
-};
-
-/* Date */
-
-static int64_t math_mod(int64_t a, int64_t b) {
-    /* return positive modulo */
-    int64_t m = a % b;
-    return m + (m < 0) * b;
-}
-
-static int64_t floor_div(int64_t a, int64_t b) {
-    /* integer division rounding toward -Infinity */
-    int64_t m = a % b;
-    return (a - (m + (m < 0) * b)) / b;
-}
-
-static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
-                             int argc, JSValueConst *argv);
-
-static __exception int JS_ThisTimeValue(JSContext *ctx, double *valp, JSValueConst this_val)
-{
-    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
-        JSObject *p = JS_VALUE_GET_OBJ(this_val);
-        if (p->class_id == JS_CLASS_DATE && JS_IsNumber(p->u.object_data))
-            return JS_ToFloat64(ctx, valp, p->u.object_data);
-    }
-    JS_ThrowTypeError(ctx, "not a Date object");
-    return -1;
-}
-
-static JSValue JS_SetThisTimeValue(JSContext *ctx, JSValueConst this_val, double v)
-{
-    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
-        JSObject *p = JS_VALUE_GET_OBJ(this_val);
-        if (p->class_id == JS_CLASS_DATE) {
-            JS_FreeValue(ctx, p->u.object_data);
-            p->u.object_data = JS_NewFloat64(ctx, v);
-            return JS_DupValue(ctx, p->u.object_data);
-        }
-    }
-    return JS_ThrowTypeError(ctx, "not a Date object");
-}
-
-static int64_t days_from_year(int64_t y) {
-    return 365 * (y - 1970) + floor_div(y - 1969, 4) -
-        floor_div(y - 1901, 100) + floor_div(y - 1601, 400);
-}
-
-static int64_t days_in_year(int64_t y) {
-    return 365 + !(y % 4) - !(y % 100) + !(y % 400);
-}
-
-/* return the year, update days */
-static int64_t year_from_days(int64_t *days) {
-    int64_t y, d1, nd, d = *days;
-    y = floor_div(d * 10000, 3652425) + 1970;
-    /* the initial approximation is very good, so only a few
-       iterations are necessary */
-    for(;;) {
-        d1 = d - days_from_year(y);
-        if (d1 < 0) {
-            y--;
-            d1 += days_in_year(y);
-        } else {
-            nd = days_in_year(y);
-            if (d1 < nd)
-                break;
-            d1 -= nd;
-            y++;
-        }
-    }
-    *days = d1;
-    return y;
-}
-
-static int const month_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-static char const month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
-static char const day_names[] = "SunMonTueWedThuFriSat";
-
-static __exception int get_date_fields(JSContext *ctx, JSValueConst obj,
-                                       double fields[9], int is_local, int force)
-{
-    double dval;
-    int64_t d, days, wd, y, i, md, h, m, s, ms, tz = 0;
-
-    if (JS_ThisTimeValue(ctx, &dval, obj))
-        return -1;
-
-    if (isnan(dval)) {
-        if (!force)
-            return FALSE; /* NaN */
-        d = 0;        /* initialize all fields to 0 */
-    } else {
-        d = dval;
-        if (is_local) {
-            tz = -getTimezoneOffset(d);
-            d += tz * 60000;
-        }
-    }
-
-    /* result is >= 0, we can use % */
-    h = math_mod(d, 86400000);
-    days = (d - h) / 86400000;
-    ms = h % 1000;
-    h = (h - ms) / 1000;
-    s = h % 60;
-    h = (h - s) / 60;
-    m = h % 60;
-    h = (h - m) / 60;
-    wd = math_mod(days + 4, 7); /* week day */
-    y = year_from_days(&days);
-
-    for(i = 0; i < 11; i++) {
-        md = month_days[i];
-        if (i == 1)
-            md += days_in_year(y) - 365;
-        if (days < md)
-            break;
-        days -= md;
-    }
-    fields[0] = y;
-    fields[1] = i;
-    fields[2] = days + 1;
-    fields[3] = h;
-    fields[4] = m;
-    fields[5] = s;
-    fields[6] = ms;
-    fields[7] = wd;
-    fields[8] = tz;
-    return TRUE;
-}
-
-static double time_clip(double t) {
-    if (t >= -8.64e15 && t <= 8.64e15)
-        return trunc(t) + 0.0;  /* convert -0 to +0 */
-    else
-        return NAN;
-}
-
-/* The spec mandates the use of 'double' and it fixes the order
-   of the operations */
-static double set_date_fields(double fields[], int is_local) {
-    int64_t y;
-    double days, d, h, m1;
-    int i, m, md;
-    
-    m1 = fields[1];
-    m = fmod(m1, 12);
-    if (m < 0)
-        m += 12;
-    y = (int64_t)(fields[0] + floor(m1 / 12));
-    days = days_from_year(y);
-
-    for(i = 0; i < m; i++) {
-        md = month_days[i];
-        if (i == 1)
-            md += days_in_year(y) - 365;
-        days += md;
-    }
-    days += fields[2] - 1;
-    h = fields[3] * 3600000 + fields[4] * 60000 + 
-        fields[5] * 1000 + fields[6];
-    d = days * 86400000 + h;
-    if (is_local)
-        d += getTimezoneOffset(d) * 60000;
-    return time_clip(d);
-}
-
-static JSValue get_date_field(JSContext *ctx, JSValueConst this_val,
-                              int argc, JSValueConst *argv, int magic)
-{
-    // get_date_field(obj, n, is_local)
-    double fields[9];
-    int res, n, is_local;
-
-    is_local = magic & 0x0F;
-    n = (magic >> 4) & 0x0F;
-    res = get_date_fields(ctx, this_val, fields, is_local, 0);
-    if (res < 0)
-        return JS_EXCEPTION;
-    if (!res)
-        return JS_NAN;
-
-    if (magic & 0x100) {    // getYear
-        fields[0] -= 1900;
-    }
-    return JS_NewFloat64(ctx, fields[n]);
-}
-
-static JSValue set_date_field(JSContext *ctx, JSValueConst this_val,
-                              int argc, JSValueConst *argv, int magic)
-{
-    // _field(obj, first_field, end_field, args, is_local)
-    double fields[9];
-    int res, first_field, end_field, is_local, i, n;
-    double d, a;
-
-    d = NAN;
-    first_field = (magic >> 8) & 0x0F;
-    end_field = (magic >> 4) & 0x0F;
-    is_local = magic & 0x0F;
-
-    res = get_date_fields(ctx, this_val, fields, is_local, first_field == 0);
-    if (res < 0)
-        return JS_EXCEPTION;
-    if (res && argc > 0) {
-        n = end_field - first_field;
-        if (argc < n)
-            n = argc;
-        for(i = 0; i < n; i++) {
-            if (JS_ToFloat64(ctx, &a, argv[i]))
-                return JS_EXCEPTION;
-            if (!isfinite(a))
-                goto done;
-            fields[first_field + i] = trunc(a);
-        }
-        d = set_date_fields(fields, is_local);
-    }
-done:
-    return JS_SetThisTimeValue(ctx, this_val, d);
-}
-
-/* fmt:
-   0: toUTCString: "Tue, 02 Jan 2018 23:04:46 GMT"
-   1: toString: "Wed Jan 03 2018 00:05:22 GMT+0100 (CET)"
-   2: toISOString: "2018-01-02T23:02:56.927Z"
-   3: toLocaleString: "1/2/2018, 11:40:40 PM"
-   part: 1=date, 2=time 3=all
-   XXX: should use a variant of strftime().
- */
-static JSValue get_date_string(JSContext *ctx, JSValueConst this_val,
-                               int argc, JSValueConst *argv, int magic)
-{
-    // _string(obj, fmt, part)
-    char buf[64];
-    double fields[9];
-    int res, fmt, part, pos;
-    int y, mon, d, h, m, s, ms, wd, tz;
-
-    fmt = (magic >> 4) & 0x0F;
-    part = magic & 0x0F;
-
-    res = get_date_fields(ctx, this_val, fields, fmt & 1, 0);
-    if (res < 0)
-        return JS_EXCEPTION;
-    if (!res) {
-        if (fmt == 2)
-            return JS_ThrowRangeError(ctx, "Date value is NaN");
-        else
-            return JS_NewString(ctx, "Invalid Date");
-    }
-
-    y = fields[0];
-    mon = fields[1];
-    d = fields[2];
-    h = fields[3];
-    m = fields[4];
-    s = fields[5];
-    ms = fields[6];
-    wd = fields[7];
-    tz = fields[8];
-
-    pos = 0;
-
-    if (part & 1) { /* date part */
-        switch(fmt) {
-        case 0:
-            pos += snprintf(buf + pos, sizeof(buf) - pos,
-                            "%.3s, %02d %.3s %0*d ",
-                            day_names + wd * 3, d,
-                            month_names + mon * 3, 4 + (y < 0), y);
-            break;
-        case 1:
-            pos += snprintf(buf + pos, sizeof(buf) - pos,
-                            "%.3s %.3s %02d %0*d",
-                            day_names + wd * 3,
-                            month_names + mon * 3, d, 4 + (y < 0), y);
-            if (part == 3) {
-                buf[pos++] = ' ';
-            }
-            break;
-        case 2:
-            if (y >= 0 && y <= 9999) {
-                pos += snprintf(buf + pos, sizeof(buf) - pos,
-                                "%04d", y);
-            } else {
-                pos += snprintf(buf + pos, sizeof(buf) - pos,
-                                "%+07d", y);
-            }
-            pos += snprintf(buf + pos, sizeof(buf) - pos,
-                            "-%02d-%02dT", mon + 1, d);
-            break;
-        case 3:
-            pos += snprintf(buf + pos, sizeof(buf) - pos,
-                            "%02d/%02d/%0*d", mon + 1, d, 4 + (y < 0), y);
-            if (part == 3) {
-                buf[pos++] = ',';
-                buf[pos++] = ' ';
-            }
-            break;
-        }
-    }
-    if (part & 2) { /* time part */
-        switch(fmt) {
-        case 0:
-            pos += snprintf(buf + pos, sizeof(buf) - pos,
-                            "%02d:%02d:%02d GMT", h, m, s);
-            break;
-        case 1:
-            pos += snprintf(buf + pos, sizeof(buf) - pos,
-                            "%02d:%02d:%02d GMT", h, m, s);
-            if (tz < 0) {
-                buf[pos++] = '-';
-                tz = -tz;
-            } else {
-                buf[pos++] = '+';
-            }
-            /* tz is >= 0, can use % */
-            pos += snprintf(buf + pos, sizeof(buf) - pos,
-                            "%02d%02d", tz / 60, tz % 60);
-            /* XXX: tack the time zone code? */
-            break;
-        case 2:
-            pos += snprintf(buf + pos, sizeof(buf) - pos,
-                            "%02d:%02d:%02d.%03dZ", h, m, s, ms);
-            break;
-        case 3:
-            pos += snprintf(buf + pos, sizeof(buf) - pos,
-                            "%02d:%02d:%02d %cM", (h + 1) % 12 - 1, m, s,
-                            (h < 12) ? 'A' : 'P');
-            break;
-        }
-    }
-    return JS_NewStringLen(ctx, buf, pos);
-}
-
-/* OS dependent: return the UTC time in ms since 1970. */
-static int64_t date_now(void) {
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
-}
-
-static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target,
-                                   int argc, JSValueConst *argv)
-{
-    // Date(y, mon, d, h, m, s, ms)
-    JSValue rv;
-    int i, n;
-    double a, val;
-
-    if (JS_IsUndefined(new_target)) {
-        /* invoked as function */
-        argc = 0;
-    }
-    n = argc;
-    if (n == 0) {
-        val = date_now();
-    } else if (n == 1) {
-        JSValue v, dv;
-        if (JS_VALUE_GET_TAG(argv[0]) == JS_TAG_OBJECT) {
-            JSObject *p = JS_VALUE_GET_OBJ(argv[0]);
-            if (p->class_id == JS_CLASS_DATE && JS_IsNumber(p->u.object_data)) {
-                if (JS_ToFloat64(ctx, &val, p->u.object_data))
-                    return JS_EXCEPTION;
-                val = time_clip(val);
-                goto has_val;
-            }
-        }
-        v = JS_ToPrimitive(ctx, argv[0], HINT_NONE);
-        if (JS_IsString(v)) {
-            dv = js_Date_parse(ctx, JS_UNDEFINED, 1, (JSValueConst *)&v);
-            JS_FreeValue(ctx, v);
-            if (JS_IsException(dv))
-                return JS_EXCEPTION;
-            if (JS_ToFloat64Free(ctx, &val, dv))
-                return JS_EXCEPTION;
-        } else {
-            if (JS_ToFloat64Free(ctx, &val, v))
-                return JS_EXCEPTION;
-        }
-        val = time_clip(val);
-    } else {
-        double fields[] = { 0, 0, 1, 0, 0, 0, 0 };
-        if (n > 7)
-            n = 7;
-        for(i = 0; i < n; i++) {
-            if (JS_ToFloat64(ctx, &a, argv[i]))
-                return JS_EXCEPTION;
-            if (!isfinite(a))
-                break;
-            fields[i] = trunc(a);
-            if (i == 0 && fields[0] >= 0 && fields[0] < 100)
-                fields[0] += 1900;
-        }
-        val = (i == n) ? set_date_fields(fields, 1) : NAN;
-    }
-has_val:
-#if 0
-    JSValueConst args[3];
-    args[0] = new_target;
-    args[1] = ctx->class_proto[JS_CLASS_DATE];
-    args[2] = JS_NewFloat64(ctx, val);
-    rv = js___date_create(ctx, JS_UNDEFINED, 3, args);
-#else
-    rv = js_create_from_ctor(ctx, new_target, JS_CLASS_DATE);
-    if (!JS_IsException(rv))
-        JS_SetObjectData(ctx, rv, JS_NewFloat64(ctx, val));
-#endif
-    if (!JS_IsException(rv) && JS_IsUndefined(new_target)) {
-        /* invoked as a function, return (new Date()).toString(); */
-        JSValue s;
-        s = get_date_string(ctx, rv, 0, NULL, 0x13);
-        JS_FreeValue(ctx, rv);
-        rv = s;
-    }
-    return rv;
-}
-
-static JSValue js_Date_UTC(JSContext *ctx, JSValueConst this_val,
-                           int argc, JSValueConst *argv)
-{
-    // UTC(y, mon, d, h, m, s, ms)
-    double fields[] = { 0, 0, 1, 0, 0, 0, 0 };
-    int i, n;
-    double a;
-
-    n = argc;
-    if (n == 0)
-        return JS_NAN;
-    if (n > 7)
-        n = 7;
-    for(i = 0; i < n; i++) {
-        if (JS_ToFloat64(ctx, &a, argv[i]))
-            return JS_EXCEPTION;
-        if (!isfinite(a))
-            return JS_NAN;
-        fields[i] = trunc(a);
-        if (i == 0 && fields[0] >= 0 && fields[0] < 100)
-            fields[0] += 1900;
-    }
-    return JS_NewFloat64(ctx, set_date_fields(fields, 0));
-}
-
-static void string_skip_spaces(JSString *sp, int *pp) {
-    while (*pp < sp->len && string_get(sp, *pp) == ' ')
-        *pp += 1;
-}
-
-static void string_skip_non_spaces(JSString *sp, int *pp) {
-    while (*pp < sp->len && string_get(sp, *pp) != ' ')
-        *pp += 1;
-}
-
-/* parse a numeric field with an optional sign if accept_sign is TRUE */
-static int string_get_digits(JSString *sp, int *pp, int64_t *pval) {
-    int64_t v = 0;
-    int c, p = *pp, p_start;
-    
-    if (p >= sp->len)
-        return -1;
-    p_start = p;
-    while (p < sp->len) {
-        c = string_get(sp, p);
-        if (!(c >= '0' && c <= '9')) {
-            if (p == p_start)
-                return -1;
-            else
-                break;
-        }
-        v = v * 10 + c - '0';
-        p++;
-    }
-    *pval = v;
-    *pp = p;
-    return 0;
-}
-
-static int string_get_signed_digits(JSString *sp, int *pp, int64_t *pval) {
-    int res, sgn, p = *pp;
-    
-    if (p >= sp->len)
-        return -1;
-
-    sgn = string_get(sp, p);
-    if (sgn == '-' || sgn == '+')
-        p++;
- 
-    res = string_get_digits(sp, &p, pval);
-    if (res == 0 && sgn == '-')
-        *pval = -*pval;
-    *pp = p;
-    return res;
-}
-
-/* parse a fixed width numeric field */
-static int string_get_fixed_width_digits(JSString *sp, int *pp, int n, int64_t *pval) {
-    int64_t v = 0;
-    int i, c, p = *pp;
-
-    for(i = 0; i < n; i++) {
-        if (p >= sp->len)
-            return -1;
-        c = string_get(sp, p);
-        if (!(c >= '0' && c <= '9'))
-            return -1;
-        v = v * 10 + c - '0';
-        p++;
-    }
-    *pval = v;
-    *pp = p;
-    return 0;
-}
-
-static int string_get_milliseconds(JSString *sp, int *pp, int64_t *pval) {
-    /* parse milliseconds as a fractional part, round to nearest */
-    /* XXX: the spec does not indicate which rounding should be used */
-    int mul = 1000, ms = 0, p = *pp, c, p_start;
-    if (p >= sp->len)
-        return -1;
-    p_start = p;
-    while (p < sp->len) {
-        c = string_get(sp, p);
-        if (!(c >= '0' && c <= '9')) {
-            if (p == p_start)
-                return -1;
-            else
-                break;
-        }
-        if (mul == 1 && c >= '5')
-            ms += 1;
-        ms += (c - '0') * (mul /= 10);
-        p++;
-    }
-    *pval = ms;
-    *pp = p;
-    return 0;
-}
-
-
-static int find_abbrev(JSString *sp, int p, const char *list, int count) {
-    int n, i;
-
-    if (p + 3 <= sp->len) {
-        for (n = 0; n < count; n++) {
-            for (i = 0; i < 3; i++) {
-                if (string_get(sp, p + i) != month_names[n * 3 + i])
-                    goto next;
-            }
-            return n;
-        next:;
-        }
-    }
-    return -1;
-}
-
-static int string_get_month(JSString *sp, int *pp, int64_t *pval) {
-    int n;
-
-    string_skip_spaces(sp, pp);
-    n = find_abbrev(sp, *pp, month_names, 12);
-    if (n < 0)
-        return -1;
-
-    *pval = n;
-    *pp += 3;
-    return 0;
-}
-
-static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
-                             int argc, JSValueConst *argv)
-{
-    // parse(s)
-    JSValue s, rv;
-    int64_t fields[] = { 0, 1, 1, 0, 0, 0, 0 };
-    double fields1[7];
-    int64_t tz, hh, mm;
-    double d;
-    int p, i, c, sgn, l;
-    JSString *sp;
-    BOOL is_local;
-    
-    rv = JS_NAN;
-
-    s = JS_ToString(ctx, argv[0]);
-    if (JS_IsException(s))
-        return JS_EXCEPTION;
-    
-    sp = JS_VALUE_GET_STRING(s);
-    p = 0;
-    if (p < sp->len && (((c = string_get(sp, p)) >= '0' && c <= '9') || c == '+' || c == '-')) {
-        /* ISO format */
-        /* year field can be negative */
-        if (string_get_signed_digits(sp, &p, &fields[0]))
-            goto done;
-
-        for (i = 1; i < 7; i++) {
-            if (p >= sp->len)
-                break;
-            switch(i) {
-            case 1:
-            case 2:
-                c = '-';
-                break;
-            case 3:
-                c = 'T';
-                break;
-            case 4:
-            case 5:
-                c = ':';
-                break;
-            case 6:
-                c = '.';
-                break;
-            }
-            if (string_get(sp, p) != c)
-                break;
-            p++;
-            if (i == 6) {
-                if (string_get_milliseconds(sp, &p, &fields[i]))
-                    goto done;
-            } else {
-                if (string_get_digits(sp, &p, &fields[i]))
-                    goto done;
-            }
-        }
-        /* no time: UTC by default */
-        is_local = (i > 3);
-        fields[1] -= 1;
-
-        /* parse the time zone offset if present: [+-]HH:mm or [+-]HHmm */
-        tz = 0;
-        if (p < sp->len) {
-            sgn = string_get(sp, p);
-            if (sgn == '+' || sgn == '-') {
-                p++;
-                l = sp->len - p;
-                if (l != 4 && l != 5)
-                    goto done;
-                if (string_get_fixed_width_digits(sp, &p, 2, &hh))
-                    goto done;
-                if (l == 5) {
-                    if (string_get(sp, p) != ':')
-                        goto done;
-                    p++;
-                }
-                if (string_get_fixed_width_digits(sp, &p, 2, &mm))
-                    goto done;
-                tz = hh * 60 + mm;
-                if (sgn == '-')
-                    tz = -tz;
-                is_local = FALSE;
-            } else if (sgn == 'Z') {
-                p++;
-                is_local = FALSE;
-            } else {
-                goto done;
-            }
-            /* error if extraneous characters */
-            if (p != sp->len)
-                goto done;
-        }
-    } else {
-        /* toString or toUTCString format */
-        /* skip the day of the week */
-        string_skip_non_spaces(sp, &p);
-        string_skip_spaces(sp, &p);
-        if (p >= sp->len)
-            goto done;
-        c = string_get(sp, p);
-        if (c >= '0' && c <= '9') {
-            /* day of month first */
-            if (string_get_digits(sp, &p, &fields[2]))
-                goto done;
-            if (string_get_month(sp, &p, &fields[1]))
-                goto done;
-        } else {
-            /* month first */
-            if (string_get_month(sp, &p, &fields[1]))
-                goto done;
-            string_skip_spaces(sp, &p);
-            if (string_get_digits(sp, &p, &fields[2]))
-                goto done;
-        }
-        /* year */
-        string_skip_spaces(sp, &p);
-        if (string_get_signed_digits(sp, &p, &fields[0]))
-            goto done;
-
-        /* hour, min, seconds */
-        string_skip_spaces(sp, &p);
-        for(i = 0; i < 3; i++) {
-            if (i == 1 || i == 2) {
-                if (p >= sp->len)
-                    goto done;
-                if (string_get(sp, p) != ':')
-                    goto done;
-                p++;
-            }
-            if (string_get_digits(sp, &p, &fields[3 + i]))
-                goto done;
-        }
-        // XXX: parse optional milliseconds?
-
-        /* parse the time zone offset if present: [+-]HHmm */
-        is_local = FALSE;
-        tz = 0;
-        for (tz = 0; p < sp->len; p++) {
-            sgn = string_get(sp, p);
-            if (sgn == '+' || sgn == '-') {
-                p++;
-                if (string_get_fixed_width_digits(sp, &p, 2, &hh))
-                    goto done;
-                if (string_get_fixed_width_digits(sp, &p, 2, &mm))
-                    goto done;
-                tz = hh * 60 + mm;
-                if (sgn == '-')
-                    tz = -tz;
-                break;
-            }
-        }
-    }
-    for(i = 0; i < 7; i++)
-        fields1[i] = fields[i];
-    d = set_date_fields(fields1, is_local) - tz * 60000;
-    rv = JS_NewFloat64(ctx, d);
-
-done:
-    JS_FreeValue(ctx, s);
-    return rv;
-}
-
-static JSValue js_Date_now(JSContext *ctx, JSValueConst this_val,
-                           int argc, JSValueConst *argv)
-{
-    // now()
-    return JS_NewInt64(ctx, date_now());
-}
-
-static JSValue js_date_Symbol_toPrimitive(JSContext *ctx, JSValueConst this_val,
-                                          int argc, JSValueConst *argv)
-{
-    // Symbol_toPrimitive(hint)
-    JSValueConst obj = this_val;
-    JSAtom hint = JS_ATOM_NULL;
-    int hint_num;
-
-    if (!JS_IsObject(obj))
-        return JS_ThrowTypeErrorNotAnObject(ctx);
-
-    if (JS_IsString(argv[0])) {
-        hint = JS_ValueToAtom(ctx, argv[0]);
-        if (hint == JS_ATOM_NULL)
-            return JS_EXCEPTION;
-        JS_FreeAtom(ctx, hint);
-    }
-    switch (hint) {
-    case JS_ATOM_number:
-#ifdef CONFIG_BIGNUM
-    case JS_ATOM_integer:
-#endif
-        hint_num = HINT_NUMBER;
-        break;
-    case JS_ATOM_string:
-    case JS_ATOM_default:
-        hint_num = HINT_STRING;
-        break;
-    default:
-        return JS_ThrowTypeError(ctx, "invalid hint");
-    }
-    return JS_ToPrimitive(ctx, obj, hint_num | HINT_FORCE_ORDINARY);
-}
-
-static JSValue js_date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val,
-                                         int argc, JSValueConst *argv)
-{
-    // getTimezoneOffset()
-    double v;
-
-    if (JS_ThisTimeValue(ctx, &v, this_val))
-        return JS_EXCEPTION;
-    if (isnan(v))
-        return JS_NAN;
-    else
-        return JS_NewInt64(ctx, getTimezoneOffset((int64_t)trunc(v)));
-}
-
-static JSValue js_date_getTime(JSContext *ctx, JSValueConst this_val,
-                               int argc, JSValueConst *argv)
-{
-    // getTime()
-    double v;
-
-    if (JS_ThisTimeValue(ctx, &v, this_val))
-        return JS_EXCEPTION;
-    return JS_NewFloat64(ctx, v);
-}
-
-static JSValue js_date_setTime(JSContext *ctx, JSValueConst this_val,
-                               int argc, JSValueConst *argv)
-{
-    // setTime(v)
-    double v;
-
-    if (JS_ThisTimeValue(ctx, &v, this_val) || JS_ToFloat64(ctx, &v, argv[0]))
-        return JS_EXCEPTION;
-    return JS_SetThisTimeValue(ctx, this_val, time_clip(v));
-}
-
-static JSValue js_date_setYear(JSContext *ctx, JSValueConst this_val,
-                               int argc, JSValueConst *argv)
-{
-    // setYear(y)
-    double y;
-    JSValueConst args[1];
-
-    if (JS_ThisTimeValue(ctx, &y, this_val) || JS_ToFloat64(ctx, &y, argv[0]))
-        return JS_EXCEPTION;
-    y = +y;
-    if (isfinite(y)) {
-        y = trunc(y);
-        if (y >= 0 && y < 100)
-            y += 1900;
-    }
-    args[0] = JS_NewFloat64(ctx, y);
-    return set_date_field(ctx, this_val, 1, args, 0x011);
-}
-
-static JSValue js_date_toJSON(JSContext *ctx, JSValueConst this_val,
-                              int argc, JSValueConst *argv)
-{
-    // toJSON(key)
-    JSValue obj, tv, method, rv;
-    double d;
-
-    rv = JS_EXCEPTION;
-    tv = JS_UNDEFINED;
-
-    obj = JS_ToObject(ctx, this_val);
-    tv = JS_ToPrimitive(ctx, obj, HINT_NUMBER);
-    if (JS_IsException(tv))
-        goto exception;
-    if (JS_IsNumber(tv)) {
-        if (JS_ToFloat64(ctx, &d, tv) < 0)
-            goto exception;
-        if (!isfinite(d)) {
-            rv = JS_NULL;
-            goto done;
-        }
-    }
-    method = JS_GetPropertyStr(ctx, obj, "toISOString");
-    if (JS_IsException(method))
-        goto exception;
-    if (!JS_IsFunction(ctx, method)) {
-        JS_ThrowTypeError(ctx, "object needs toISOString method");
-        JS_FreeValue(ctx, method);
-        goto exception;
-    }
-    rv = JS_CallFree(ctx, method, obj, 0, NULL);
-exception:
-done:
-    JS_FreeValue(ctx, obj);
-    JS_FreeValue(ctx, tv);
-    return rv;
-}
-
-static const JSCFunctionListEntry js_date_funcs[] = {
-    JS_CFUNC_DEF("now", 0, js_Date_now ),
-    JS_CFUNC_DEF("parse", 1, js_Date_parse ),
-    JS_CFUNC_DEF("UTC", 7, js_Date_UTC ),
-};
-
-static const JSCFunctionListEntry js_date_proto_funcs[] = {
-    JS_CFUNC_DEF("valueOf", 0, js_date_getTime ),
-    JS_CFUNC_MAGIC_DEF("toString", 0, get_date_string, 0x13 ),
-    JS_CFUNC_DEF("[Symbol.toPrimitive]", 1, js_date_Symbol_toPrimitive ),
-    JS_CFUNC_MAGIC_DEF("toUTCString", 0, get_date_string, 0x03 ),
-    JS_ALIAS_DEF("toGMTString", "toUTCString" ),
-    JS_CFUNC_MAGIC_DEF("toISOString", 0, get_date_string, 0x23 ),
-    JS_CFUNC_MAGIC_DEF("toDateString", 0, get_date_string, 0x11 ),
-    JS_CFUNC_MAGIC_DEF("toTimeString", 0, get_date_string, 0x12 ),
-    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, get_date_string, 0x33 ),
-    JS_CFUNC_MAGIC_DEF("toLocaleDateString", 0, get_date_string, 0x31 ),
-    JS_CFUNC_MAGIC_DEF("toLocaleTimeString", 0, get_date_string, 0x32 ),
-    JS_CFUNC_DEF("getTimezoneOffset", 0, js_date_getTimezoneOffset ),
-    JS_CFUNC_DEF("getTime", 0, js_date_getTime ),
-    JS_CFUNC_MAGIC_DEF("getYear", 0, get_date_field, 0x101 ),
-    JS_CFUNC_MAGIC_DEF("getFullYear", 0, get_date_field, 0x01 ),
-    JS_CFUNC_MAGIC_DEF("getUTCFullYear", 0, get_date_field, 0x00 ),
-    JS_CFUNC_MAGIC_DEF("getMonth", 0, get_date_field, 0x11 ),
-    JS_CFUNC_MAGIC_DEF("getUTCMonth", 0, get_date_field, 0x10 ),
-    JS_CFUNC_MAGIC_DEF("getDate", 0, get_date_field, 0x21 ),
-    JS_CFUNC_MAGIC_DEF("getUTCDate", 0, get_date_field, 0x20 ),
-    JS_CFUNC_MAGIC_DEF("getHours", 0, get_date_field, 0x31 ),
-    JS_CFUNC_MAGIC_DEF("getUTCHours", 0, get_date_field, 0x30 ),
-    JS_CFUNC_MAGIC_DEF("getMinutes", 0, get_date_field, 0x41 ),
-    JS_CFUNC_MAGIC_DEF("getUTCMinutes", 0, get_date_field, 0x40 ),
-    JS_CFUNC_MAGIC_DEF("getSeconds", 0, get_date_field, 0x51 ),
-    JS_CFUNC_MAGIC_DEF("getUTCSeconds", 0, get_date_field, 0x50 ),
-    JS_CFUNC_MAGIC_DEF("getMilliseconds", 0, get_date_field, 0x61 ),
-    JS_CFUNC_MAGIC_DEF("getUTCMilliseconds", 0, get_date_field, 0x60 ),
-    JS_CFUNC_MAGIC_DEF("getDay", 0, get_date_field, 0x71 ),
-    JS_CFUNC_MAGIC_DEF("getUTCDay", 0, get_date_field, 0x70 ),
-    JS_CFUNC_DEF("setTime", 1, js_date_setTime ),
-    JS_CFUNC_MAGIC_DEF("setMilliseconds", 1, set_date_field, 0x671 ),
-    JS_CFUNC_MAGIC_DEF("setUTCMilliseconds", 1, set_date_field, 0x670 ),
-    JS_CFUNC_MAGIC_DEF("setSeconds", 2, set_date_field, 0x571 ),
-    JS_CFUNC_MAGIC_DEF("setUTCSeconds", 2, set_date_field, 0x570 ),
-    JS_CFUNC_MAGIC_DEF("setMinutes", 3, set_date_field, 0x471 ),
-    JS_CFUNC_MAGIC_DEF("setUTCMinutes", 3, set_date_field, 0x470 ),
-    JS_CFUNC_MAGIC_DEF("setHours", 4, set_date_field, 0x371 ),
-    JS_CFUNC_MAGIC_DEF("setUTCHours", 4, set_date_field, 0x370 ),
-    JS_CFUNC_MAGIC_DEF("setDate", 1, set_date_field, 0x231 ),
-    JS_CFUNC_MAGIC_DEF("setUTCDate", 1, set_date_field, 0x230 ),
-    JS_CFUNC_MAGIC_DEF("setMonth", 2, set_date_field, 0x131 ),
-    JS_CFUNC_MAGIC_DEF("setUTCMonth", 2, set_date_field, 0x130 ),
-    JS_CFUNC_DEF("setYear", 1, js_date_setYear ),
-    JS_CFUNC_MAGIC_DEF("setFullYear", 3, set_date_field, 0x031 ),
-    JS_CFUNC_MAGIC_DEF("setUTCFullYear", 3, set_date_field, 0x030 ),
-    JS_CFUNC_DEF("toJSON", 1, js_date_toJSON ),
-};
-
-void JS_AddIntrinsicDate(JSContext *ctx)
-{
-    JSValueConst obj;
-
-    /* Date */
-    ctx->class_proto[JS_CLASS_DATE] = JS_NewObject(ctx);
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_DATE], js_date_proto_funcs,
-                               countof(js_date_proto_funcs));
-    obj = JS_NewGlobalCConstructor(ctx, "Date", js_date_constructor, 7,
-                                   ctx->class_proto[JS_CLASS_DATE]);
-    JS_SetPropertyFunctionList(ctx, obj, js_date_funcs, countof(js_date_funcs));
-}
-
-/* eval */
-
-void JS_AddIntrinsicEval(JSContext *ctx)
-{
-    ctx->eval_internal = __JS_EvalInternal;
-}
-
-#ifdef CONFIG_BIGNUM
-
-/* Operators */
-
-static void js_operator_set_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET);
-    int i, j;
-    JSBinaryOperatorDefEntry *ent;
-    
-    if (opset) {
-        for(i = 0; i < JS_OVOP_COUNT; i++) {
-            if (opset->self_ops[i])
-                JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[i]));
-        }
-        for(j = 0; j < opset->left.count; j++) {
-            ent = &opset->left.tab[j];
-            for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
-                if (ent->ops[i])
-                    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]));
-            }
-        }
-        js_free_rt(rt, opset->left.tab);
-        for(j = 0; j < opset->right.count; j++) {
-            ent = &opset->right.tab[j];
-            for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
-                if (ent->ops[i])
-                    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]));
-            }
-        }
-        js_free_rt(rt, opset->right.tab);
-        js_free_rt(rt, opset);
-    }
-}
-
-static void js_operator_set_mark(JSRuntime *rt, JSValueConst val,
-                                 JS_MarkFunc *mark_func)
-{
-    JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET);
-    int i, j;
-    JSBinaryOperatorDefEntry *ent;
-    
-    if (opset) {
-        for(i = 0; i < JS_OVOP_COUNT; i++) {
-            if (opset->self_ops[i])
-                JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[i]),
-                             mark_func);
-        }
-        for(j = 0; j < opset->left.count; j++) {
-            ent = &opset->left.tab[j];
-            for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
-                if (ent->ops[i])
-                    JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]),
-                                 mark_func);
-            }
-        }
-        for(j = 0; j < opset->right.count; j++) {
-            ent = &opset->right.tab[j];
-            for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
-                if (ent->ops[i])
-                    JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]),
-                                 mark_func);
-            }
-        }
-    }
-}
-
-
-/* create an OperatorSet object */
-static JSValue js_operators_create_internal(JSContext *ctx,
-                                            int argc, JSValueConst *argv,
-                                            BOOL is_primitive)
-{
-    JSValue opset_obj, prop, obj;
-    JSOperatorSetData *opset, *opset1;
-    JSBinaryOperatorDef *def;
-    JSValueConst arg;
-    int i, j;
-    JSBinaryOperatorDefEntry *new_tab;
-    JSBinaryOperatorDefEntry *ent;
-    uint32_t op_count;
-
-    if (ctx->rt->operator_count == UINT32_MAX) {
-        return JS_ThrowTypeError(ctx, "too many operators");
-    }
-    opset_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_OPERATOR_SET);
-    if (JS_IsException(opset_obj))
-        goto fail;
-    opset = js_mallocz(ctx, sizeof(*opset));
-    if (!opset)
-        goto fail;
-    JS_SetOpaque(opset_obj, opset);
-    if (argc >= 1) {
-        arg = argv[0];
-        /* self operators */
-        for(i = 0; i < JS_OVOP_COUNT; i++) {
-            prop = JS_GetPropertyStr(ctx, arg, js_overloadable_operator_names[i]);
-            if (JS_IsException(prop))
-                goto fail;
-            if (!JS_IsUndefined(prop)) {
-                if (check_function(ctx, prop)) {
-                    JS_FreeValue(ctx, prop);
-                    goto fail;
-                }
-                opset->self_ops[i] = JS_VALUE_GET_OBJ(prop);
-            }
-        }
-    }
-    /* left & right operators */
-    for(j = 1; j < argc; j++) {
-        arg = argv[j];
-        prop = JS_GetPropertyStr(ctx, arg, "left");
-        if (JS_IsException(prop))
-            goto fail;
-        def = &opset->right;
-        if (JS_IsUndefined(prop)) {
-            prop = JS_GetPropertyStr(ctx, arg, "right");
-            if (JS_IsException(prop))
-                goto fail;
-            if (JS_IsUndefined(prop)) {
-                JS_ThrowTypeError(ctx, "left or right property must be present");
-                goto fail;
-            }
-            def = &opset->left;
-        }
-        /* get the operator set */
-        obj = JS_GetProperty(ctx, prop, JS_ATOM_prototype);
-        JS_FreeValue(ctx, prop);
-        if (JS_IsException(obj))
-            goto fail;
-        prop = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet);
-        JS_FreeValue(ctx, obj);
-        if (JS_IsException(prop))
-            goto fail;
-        opset1 = JS_GetOpaque2(ctx, prop, JS_CLASS_OPERATOR_SET);
-        if (!opset1) {
-            JS_FreeValue(ctx, prop);
-            goto fail;
-        }
-        op_count = opset1->operator_counter;
-        JS_FreeValue(ctx, prop);
-        
-        /* we assume there are few entries */
-        new_tab = js_realloc(ctx, def->tab,
-                             (def->count + 1) * sizeof(def->tab[0]));
-        if (!new_tab)
-            goto fail;
-        def->tab = new_tab;
-        def->count++;
-        ent = def->tab + def->count - 1;
-        memset(ent, 0, sizeof(def->tab[0]));
-        ent->operator_index = op_count;
-        
-        for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
-            prop = JS_GetPropertyStr(ctx, arg,
-                                     js_overloadable_operator_names[i]);
-            if (JS_IsException(prop))
-                goto fail;
-            if (!JS_IsUndefined(prop)) {
-                if (check_function(ctx, prop)) {
-                    JS_FreeValue(ctx, prop);
-                    goto fail;
-                }
-                ent->ops[i] = JS_VALUE_GET_OBJ(prop);
-            }
-        }
-    }
-    opset->is_primitive = is_primitive;
-    opset->operator_counter = ctx->rt->operator_count++;
-    return opset_obj;
- fail:
-    JS_FreeValue(ctx, opset_obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_operators_create(JSContext *ctx, JSValueConst this_val,
-                                int argc, JSValueConst *argv)
-{
-    return js_operators_create_internal(ctx, argc, argv, FALSE);
-}
-
-static JSValue js_operators_updateBigIntOperators(JSContext *ctx, JSValueConst this_val,
-                                                  int argc, JSValueConst *argv)
-{
-    JSValue opset_obj, prop;
-    JSOperatorSetData *opset;
-    const JSOverloadableOperatorEnum ops[2] = { JS_OVOP_DIV, JS_OVOP_POW };
-    JSOverloadableOperatorEnum op;
-    int i;
-    
-    opset_obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_BIG_INT],
-                               JS_ATOM_Symbol_operatorSet);
-    if (JS_IsException(opset_obj))
-        goto fail;
-    opset = JS_GetOpaque2(ctx, opset_obj, JS_CLASS_OPERATOR_SET);
-    if (!opset)
-        goto fail;
-    for(i = 0; i < countof(ops); i++) {
-        op = ops[i];
-        prop = JS_GetPropertyStr(ctx, argv[0],
-                                 js_overloadable_operator_names[op]);
-        if (JS_IsException(prop))
-            goto fail;
-        if (!JS_IsUndefined(prop)) {
-            if (!JS_IsNull(prop) && check_function(ctx, prop)) {
-                JS_FreeValue(ctx, prop);
-                goto fail;
-            }
-            if (opset->self_ops[op])
-                JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[op]));
-            if (JS_IsNull(prop)) {
-                opset->self_ops[op] = NULL;
-            } else {
-                opset->self_ops[op] = JS_VALUE_GET_PTR(prop);
-            }
-        }
-    }
-    JS_FreeValue(ctx, opset_obj);
-    return JS_UNDEFINED;
- fail:
-    JS_FreeValue(ctx, opset_obj);
-    return JS_EXCEPTION;
-}
-
-static int js_operators_set_default(JSContext *ctx, JSValueConst obj)
-{
-    JSValue opset_obj;
-
-    if (!JS_IsObject(obj)) /* in case the prototype is not defined */
-        return 0;
-    opset_obj = js_operators_create_internal(ctx, 0, NULL, TRUE);
-    if (JS_IsException(opset_obj))
-        return -1;
-    /* cannot be modified by the user */
-    JS_DefinePropertyValue(ctx, obj, JS_ATOM_Symbol_operatorSet,
-                           opset_obj, 0);
-    return 0;
-}
-
-static JSValue js_dummy_operators_ctor(JSContext *ctx, JSValueConst new_target,
-                                       int argc, JSValueConst *argv)
-{
-    return js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
-}
-
-static JSValue js_global_operators(JSContext *ctx, JSValueConst this_val,
-                                   int argc, JSValueConst *argv)
-{
-    JSValue func_obj, proto, opset_obj;
-
-    func_obj = JS_UNDEFINED;
-    proto = JS_NewObject(ctx);
-    if (JS_IsException(proto))
-        return JS_EXCEPTION;
-    opset_obj = js_operators_create_internal(ctx, argc, argv, FALSE);
-    if (JS_IsException(opset_obj))
-        goto fail;
-    JS_DefinePropertyValue(ctx, proto, JS_ATOM_Symbol_operatorSet,
-                           opset_obj, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-    func_obj = JS_NewCFunction2(ctx, js_dummy_operators_ctor, "Operators",
-                                0, JS_CFUNC_constructor, 0);
-    if (JS_IsException(func_obj))
-        goto fail;
-    JS_SetConstructor2(ctx, func_obj, proto,
-                       0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-    JS_FreeValue(ctx, proto);
-    return func_obj;
- fail:
-    JS_FreeValue(ctx, proto);
-    JS_FreeValue(ctx, func_obj);
-    return JS_EXCEPTION;
-}
-
-static const JSCFunctionListEntry js_operators_funcs[] = {
-    JS_CFUNC_DEF("create", 1, js_operators_create ),
-    JS_CFUNC_DEF("updateBigIntOperators", 2, js_operators_updateBigIntOperators ),
-};
-
-/* must be called after all overloadable base types are initialized */
-void JS_AddIntrinsicOperators(JSContext *ctx)
-{
-    JSValue obj;
-
-    ctx->allow_operator_overloading = TRUE;
-    obj = JS_NewCFunction(ctx, js_global_operators, "Operators", 1);
-    JS_SetPropertyFunctionList(ctx, obj,
-                               js_operators_funcs,
-                               countof(js_operators_funcs));
-    JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_Operators,
-                           obj,
-                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-    /* add default operatorSets */
-    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BOOLEAN]);
-    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_NUMBER]);
-    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_STRING]);
-    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_INT]);
-    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT]);
-    js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL]);
-}
-
-/* BigInt */
-
-static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)
-{
-    uint32_t tag;
-
- redo:
-    tag = JS_VALUE_GET_NORM_TAG(val);
-    switch(tag) {
-    case JS_TAG_INT:
-    case JS_TAG_BOOL:
-        val = JS_NewBigInt64(ctx, JS_VALUE_GET_INT(val));
-        break;
-    case JS_TAG_BIG_INT:
-        break;
-    case JS_TAG_FLOAT64:
-    case JS_TAG_BIG_FLOAT:
-        {
-            bf_t *a, a_s;
-            
-            a = JS_ToBigFloat(ctx, &a_s, val);
-            if (!bf_is_finite(a)) {
-                JS_FreeValue(ctx, val);
-                val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to bigint");
-            } else {
-                JSValue val1 = JS_NewBigInt(ctx);
-                bf_t *r;
-                int ret;
-                if (JS_IsException(val1)) {
-                    JS_FreeValue(ctx, val);
-                    return JS_EXCEPTION;
-                }
-                r = JS_GetBigInt(val1);
-                ret = bf_set(r, a);
-                ret |= bf_rint(r, BF_RNDZ);
-                JS_FreeValue(ctx, val);
-                if (ret & BF_ST_MEM_ERROR) {
-                    JS_FreeValue(ctx, val1);
-                    val = JS_ThrowOutOfMemory(ctx);
-                } else if (ret & BF_ST_INEXACT) {
-                    JS_FreeValue(ctx, val1);
-                    val = JS_ThrowRangeError(ctx, "cannot convert to bigint: not an integer");
-                } else {
-                    val = JS_CompactBigInt(ctx, val1);
-                }
-            }
-            if (a == &a_s)
-                bf_delete(a);
-        }
-        break;
-    case JS_TAG_BIG_DECIMAL:
-        val = JS_ToStringFree(ctx, val);
-         if (JS_IsException(val))
-            break;
-        goto redo;
-    case JS_TAG_STRING:
-        val = JS_StringToBigIntErr(ctx, val);
-        break;
-    case JS_TAG_OBJECT:
-        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
-        if (JS_IsException(val))
-            break;
-        goto redo;
-    case JS_TAG_NULL:
-    case JS_TAG_UNDEFINED:
-    default:
-        JS_FreeValue(ctx, val);
-        return JS_ThrowTypeError(ctx, "cannot convert to bigint");
-    }
-    return val;
-}
-
-static JSValue js_bigint_constructor(JSContext *ctx,
-                                     JSValueConst new_target,
-                                     int argc, JSValueConst *argv)
-{
-    if (!JS_IsUndefined(new_target))
-        return JS_ThrowTypeError(ctx, "not a constructor");
-    return JS_ToBigIntCtorFree(ctx, JS_DupValue(ctx, argv[0]));
-}
-
-static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val)
-{
-    if (JS_IsBigInt(ctx, this_val))
-        return JS_DupValue(ctx, this_val);
-
-    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
-        JSObject *p = JS_VALUE_GET_OBJ(this_val);
-        if (p->class_id == JS_CLASS_BIG_INT) {
-            if (JS_IsBigInt(ctx, p->u.object_data))
-                return JS_DupValue(ctx, p->u.object_data);
-        }
-    }
-    return JS_ThrowTypeError(ctx, "not a bigint");
-}
-
-static JSValue js_bigint_toString(JSContext *ctx, JSValueConst this_val,
-                                  int argc, JSValueConst *argv)
-{
-    JSValue val;
-    int base;
-    JSValue ret;
-
-    val = js_thisBigIntValue(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    if (argc == 0 || JS_IsUndefined(argv[0])) {
-        base = 10;
-    } else {
-        base = js_get_radix(ctx, argv[0]);
-        if (base < 0)
-            goto fail;
-    }
-    ret = js_bigint_to_string1(ctx, val, base);
-    JS_FreeValue(ctx, val);
-    return ret;
- fail:
-    JS_FreeValue(ctx, val);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_bigint_valueOf(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv)
-{
-    return js_thisBigIntValue(ctx, this_val);
-}
-
-static JSValue js_bigint_div(JSContext *ctx,
-                              JSValueConst this_val,
-                              int argc, JSValueConst *argv, int magic)
-{
-    bf_t a_s, b_s, *a, *b, *r, *q;
-    int status;
-    JSValue q_val, r_val;
-    
-    q_val = JS_NewBigInt(ctx);
-    if (JS_IsException(q_val))
-        return JS_EXCEPTION;
-    r_val = JS_NewBigInt(ctx);
-    if (JS_IsException(r_val))
-        goto fail;
-    b = NULL;
-    a = JS_ToBigInt(ctx, &a_s, argv[0]);
-    if (!a)
-        goto fail;
-    b = JS_ToBigInt(ctx, &b_s, argv[1]);
-    if (!b) {
-        JS_FreeBigInt(ctx, a, &a_s);
-        goto fail;
-    }
-    q = JS_GetBigInt(q_val);
-    r = JS_GetBigInt(r_val);
-    status = bf_divrem(q, r, a, b, BF_PREC_INF, BF_RNDZ, magic & 0xf);
-    JS_FreeBigInt(ctx, a, &a_s);
-    JS_FreeBigInt(ctx, b, &b_s);
-    if (unlikely(status)) {
-        throw_bf_exception(ctx, status);
-        goto fail;
-    }
-    q_val = JS_CompactBigInt(ctx, q_val);
-    if (magic & 0x10) {
-        JSValue ret;
-        ret = JS_NewArray(ctx);
-        if (JS_IsException(ret))
-            goto fail;
-        JS_SetPropertyUint32(ctx, ret, 0, q_val);
-        JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, r_val));
-        return ret;
-    } else {
-        JS_FreeValue(ctx, r_val);
-        return q_val;
-    }
- fail:
-    JS_FreeValue(ctx, q_val);
-    JS_FreeValue(ctx, r_val);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_bigint_sqrt(JSContext *ctx,
-                               JSValueConst this_val,
-                               int argc, JSValueConst *argv, int magic)
-{
-    bf_t a_s, *a, *r, *rem;
-    int status;
-    JSValue r_val, rem_val;
-    
-    r_val = JS_NewBigInt(ctx);
-    if (JS_IsException(r_val))
-        return JS_EXCEPTION;
-    rem_val = JS_NewBigInt(ctx);
-    if (JS_IsException(rem_val))
-        return JS_EXCEPTION;
-    r = JS_GetBigInt(r_val);
-    rem = JS_GetBigInt(rem_val);
-
-    a = JS_ToBigInt(ctx, &a_s, argv[0]);
-    if (!a)
-        goto fail;
-    status = bf_sqrtrem(r, rem, a);
-    JS_FreeBigInt(ctx, a, &a_s);
-    if (unlikely(status & ~BF_ST_INEXACT)) {
-        throw_bf_exception(ctx, status);
-        goto fail;
-    }
-    r_val = JS_CompactBigInt(ctx, r_val);
-    if (magic) {
-        JSValue ret;
-        ret = JS_NewArray(ctx);
-        if (JS_IsException(ret))
-            goto fail;
-        JS_SetPropertyUint32(ctx, ret, 0, r_val);
-        JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, rem_val));
-        return ret;
-    } else {
-        JS_FreeValue(ctx, rem_val);
-        return r_val;
-    }
- fail:
-    JS_FreeValue(ctx, r_val);
-    JS_FreeValue(ctx, rem_val);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_bigint_op1(JSContext *ctx,
-                              JSValueConst this_val,
-                              int argc, JSValueConst *argv,
-                              int magic)
-{
-    bf_t a_s, *a;
-    int64_t res;
-
-    a = JS_ToBigInt(ctx, &a_s, argv[0]);
-    if (!a)
-        return JS_EXCEPTION;
-    switch(magic) {
-    case 0: /* floorLog2 */
-        if (a->sign || a->expn <= 0) {
-            res = -1;
-        } else {
-            res = a->expn - 1;
-        }
-        break;
-    case 1: /* ctz */
-        if (bf_is_zero(a)) {
-            res = -1;
-        } else {
-            res = bf_get_exp_min(a);
-        }
-        break;
-    default:
-        abort();
-    }
-    JS_FreeBigInt(ctx, a, &a_s);
-    return JS_NewBigInt64(ctx, res);
-}
-
-static JSValue js_bigint_asUintN(JSContext *ctx,
-                                  JSValueConst this_val,
-                                  int argc, JSValueConst *argv, int asIntN)
-{
-    uint64_t bits;
-    bf_t a_s, *a = &a_s, *r, mask_s, *mask = &mask_s;
-    JSValue res;
-    
-    if (JS_ToIndex(ctx, &bits, argv[0]))
-        return JS_EXCEPTION;
-    res = JS_NewBigInt(ctx);
-    if (JS_IsException(res))
-        return JS_EXCEPTION;
-    r = JS_GetBigInt(res);
-    a = JS_ToBigInt(ctx, &a_s, argv[1]);
-    if (!a) {
-        JS_FreeValue(ctx, res);
-        return JS_EXCEPTION;
-    }
-    /* XXX: optimize */
-    r = JS_GetBigInt(res);
-    bf_init(ctx->bf_ctx, mask);
-    bf_set_ui(mask, 1);
-    bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ);
-    bf_add_si(mask, mask, -1, BF_PREC_INF, BF_RNDZ);
-    bf_logic_and(r, a, mask);
-    if (asIntN && bits != 0) {
-        bf_set_ui(mask, 1);
-        bf_mul_2exp(mask, bits - 1, BF_PREC_INF, BF_RNDZ);
-        if (bf_cmpu(r, mask) >= 0) {
-            bf_set_ui(mask, 1);
-            bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ);
-            bf_sub(r, r, mask, BF_PREC_INF, BF_RNDZ);
-        }
-    }
-    bf_delete(mask);
-    JS_FreeBigInt(ctx, a, &a_s);
-    return JS_CompactBigInt(ctx, res);
-}
-
-static const JSCFunctionListEntry js_bigint_funcs[] = {
-    JS_CFUNC_MAGIC_DEF("asUintN", 2, js_bigint_asUintN, 0 ),
-    JS_CFUNC_MAGIC_DEF("asIntN", 2, js_bigint_asUintN, 1 ),
-    /* QuickJS extensions */
-    JS_CFUNC_MAGIC_DEF("tdiv", 2, js_bigint_div, BF_RNDZ ),
-    JS_CFUNC_MAGIC_DEF("fdiv", 2, js_bigint_div, BF_RNDD ),
-    JS_CFUNC_MAGIC_DEF("cdiv", 2, js_bigint_div, BF_RNDU ),
-    JS_CFUNC_MAGIC_DEF("ediv", 2, js_bigint_div, BF_DIVREM_EUCLIDIAN ),
-    JS_CFUNC_MAGIC_DEF("tdivrem", 2, js_bigint_div, BF_RNDZ | 0x10 ),
-    JS_CFUNC_MAGIC_DEF("fdivrem", 2, js_bigint_div, BF_RNDD | 0x10 ),
-    JS_CFUNC_MAGIC_DEF("cdivrem", 2, js_bigint_div, BF_RNDU | 0x10 ),
-    JS_CFUNC_MAGIC_DEF("edivrem", 2, js_bigint_div, BF_DIVREM_EUCLIDIAN | 0x10 ),
-    JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigint_sqrt, 0 ),
-    JS_CFUNC_MAGIC_DEF("sqrtrem", 1, js_bigint_sqrt, 1 ),
-    JS_CFUNC_MAGIC_DEF("floorLog2", 1, js_bigint_op1, 0 ),
-    JS_CFUNC_MAGIC_DEF("ctz", 1, js_bigint_op1, 1 ),
-};
-
-static const JSCFunctionListEntry js_bigint_proto_funcs[] = {
-    JS_CFUNC_DEF("toString", 0, js_bigint_toString ),
-    JS_CFUNC_DEF("valueOf", 0, js_bigint_valueOf ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "BigInt", JS_PROP_CONFIGURABLE ),
-};
-
-void JS_AddIntrinsicBigInt(JSContext *ctx)
-{
-    JSRuntime *rt = ctx->rt;
-    JSValueConst obj1;
-
-    rt->bigint_ops.to_string = js_bigint_to_string;
-    rt->bigint_ops.from_string = js_string_to_bigint;
-    rt->bigint_ops.unary_arith = js_unary_arith_bigint;
-    rt->bigint_ops.binary_arith = js_binary_arith_bigint;
-    rt->bigint_ops.compare = js_compare_bigfloat;
-    
-    ctx->class_proto[JS_CLASS_BIG_INT] = JS_NewObject(ctx);
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_INT],
-                               js_bigint_proto_funcs,
-                               countof(js_bigint_proto_funcs));
-    obj1 = JS_NewGlobalCConstructor(ctx, "BigInt", js_bigint_constructor, 1,
-                                    ctx->class_proto[JS_CLASS_BIG_INT]);
-    JS_SetPropertyFunctionList(ctx, obj1, js_bigint_funcs,
-                               countof(js_bigint_funcs));
-}
-
-/* BigFloat */
-
-static JSValue js_thisBigFloatValue(JSContext *ctx, JSValueConst this_val)
-{
-    if (JS_IsBigFloat(this_val))
-        return JS_DupValue(ctx, this_val);
-
-    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
-        JSObject *p = JS_VALUE_GET_OBJ(this_val);
-        if (p->class_id == JS_CLASS_BIG_FLOAT) {
-            if (JS_IsBigFloat(p->u.object_data))
-                return JS_DupValue(ctx, p->u.object_data);
-        }
-    }
-    return JS_ThrowTypeError(ctx, "not a bigfloat");
-}
-
-static JSValue js_bigfloat_toString(JSContext *ctx, JSValueConst this_val,
-                                    int argc, JSValueConst *argv)
-{
-    JSValue val;
-    int base;
-    JSValue ret;
-
-    val = js_thisBigFloatValue(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    if (argc == 0 || JS_IsUndefined(argv[0])) {
-        base = 10;
-    } else {
-        base = js_get_radix(ctx, argv[0]);
-        if (base < 0)
-            goto fail;
-    }
-    ret = js_ftoa(ctx, val, base, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN);
-    JS_FreeValue(ctx, val);
-    return ret;
- fail:
-    JS_FreeValue(ctx, val);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_bigfloat_valueOf(JSContext *ctx, JSValueConst this_val,
-                                   int argc, JSValueConst *argv)
-{
-    return js_thisBigFloatValue(ctx, this_val);
-}
-
-static int bigfloat_get_rnd_mode(JSContext *ctx, JSValueConst val)
-{
-    int rnd_mode;
-    if (JS_ToInt32Sat(ctx, &rnd_mode, val))
-        return -1;
-    if (rnd_mode < BF_RNDN || rnd_mode > BF_RNDF) {
-        JS_ThrowRangeError(ctx, "invalid rounding mode");
-        return -1;
-    }
-    return rnd_mode;
-}
-
-static JSValue js_bigfloat_toFixed(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv)
-{
-    JSValue val, ret;
-    int64_t f;
-    int rnd_mode, radix;
-
-    val = js_thisBigFloatValue(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    if (JS_ToInt64Sat(ctx, &f, argv[0]))
-        goto fail;
-    if (f < 0 || f > BF_PREC_MAX) {
-        JS_ThrowRangeError(ctx, "invalid number of digits");
-        goto fail;
-    }
-    rnd_mode = BF_RNDNA;
-    radix = 10;
-    /* XXX: swap parameter order for rounding mode and radix */
-    if (argc > 1) {
-        rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
-        if (rnd_mode < 0)
-            goto fail;
-    }
-    if (argc > 2) {
-        radix = js_get_radix(ctx, argv[2]);
-        if (radix < 0)
-            goto fail;
-    }
-    ret = js_ftoa(ctx, val, radix, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
-    JS_FreeValue(ctx, val);
-    return ret;
- fail:
-    JS_FreeValue(ctx, val);
-    return JS_EXCEPTION;
-}
-
-static BOOL js_bigfloat_is_finite(JSContext *ctx, JSValueConst val)
-{
-    BOOL res;
-    uint32_t tag;
-
-    tag = JS_VALUE_GET_NORM_TAG(val);
-    switch(tag) {
-    case JS_TAG_BIG_FLOAT:
-        {
-            JSBigFloat *p = JS_VALUE_GET_PTR(val);
-            res = bf_is_finite(&p->num);
-        }
-        break;
-    default:
-        res = FALSE;
-        break;
-    }
-    return res;
-}
-
-static JSValue js_bigfloat_toExponential(JSContext *ctx, JSValueConst this_val,
-                                       int argc, JSValueConst *argv)
-{
-    JSValue val, ret;
-    int64_t f;
-    int rnd_mode, radix;
-
-    val = js_thisBigFloatValue(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    if (JS_ToInt64Sat(ctx, &f, argv[0]))
-        goto fail;
-    if (!js_bigfloat_is_finite(ctx, val)) {
-        ret = JS_ToString(ctx, val);
-    } else if (JS_IsUndefined(argv[0])) {
-        ret = js_ftoa(ctx, val, 10, 0,
-                      BF_RNDN | BF_FTOA_FORMAT_FREE_MIN | BF_FTOA_FORCE_EXP);
-    } else {
-        if (f < 0 || f > BF_PREC_MAX) {
-            JS_ThrowRangeError(ctx, "invalid number of digits");
-            goto fail;
-        }
-        rnd_mode = BF_RNDNA;
-        radix = 10;
-        if (argc > 1) {
-            rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
-            if (rnd_mode < 0)
-                goto fail;
-        }
-        if (argc > 2) {
-            radix = js_get_radix(ctx, argv[2]);
-            if (radix < 0)
-                goto fail;
-        }
-        ret = js_ftoa(ctx, val, radix, f + 1,
-                      rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP);
-    }
-    JS_FreeValue(ctx, val);
-    return ret;
- fail:
-    JS_FreeValue(ctx, val);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_bigfloat_toPrecision(JSContext *ctx, JSValueConst this_val,
-                                     int argc, JSValueConst *argv)
-{
-    JSValue val, ret;
-    int64_t p;
-    int rnd_mode, radix;
-
-    val = js_thisBigFloatValue(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    if (JS_IsUndefined(argv[0]))
-        goto to_string;
-    if (JS_ToInt64Sat(ctx, &p, argv[0]))
-        goto fail;
-    if (!js_bigfloat_is_finite(ctx, val)) {
-    to_string:
-        ret = JS_ToString(ctx, this_val);
-    } else {
-        if (p < 1 || p > BF_PREC_MAX) {
-            JS_ThrowRangeError(ctx, "invalid number of digits");
-            goto fail;
-        }
-        rnd_mode = BF_RNDNA;
-        radix = 10;
-        if (argc > 1) {
-            rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
-            if (rnd_mode < 0)
-                goto fail;
-        }
-        if (argc > 2) {
-            radix = js_get_radix(ctx, argv[2]);
-            if (radix < 0)
-                goto fail;
-        }
-        ret = js_ftoa(ctx, val, radix, p, rnd_mode | BF_FTOA_FORMAT_FIXED);
-    }
-    JS_FreeValue(ctx, val);
-    return ret;
- fail:
-    JS_FreeValue(ctx, val);
-    return JS_EXCEPTION;
-}
-
-static const JSCFunctionListEntry js_bigfloat_proto_funcs[] = {
-    JS_CFUNC_DEF("toString", 0, js_bigfloat_toString ),
-    JS_CFUNC_DEF("valueOf", 0, js_bigfloat_valueOf ),
-    JS_CFUNC_DEF("toPrecision", 1, js_bigfloat_toPrecision ),
-    JS_CFUNC_DEF("toFixed", 1, js_bigfloat_toFixed ),
-    JS_CFUNC_DEF("toExponential", 1, js_bigfloat_toExponential ),
-};
-
-static JSValue js_bigfloat_constructor(JSContext *ctx,
-                                       JSValueConst new_target,
-                                       int argc, JSValueConst *argv)
-{
-    JSValue val;
-    if (!JS_IsUndefined(new_target))
-        return JS_ThrowTypeError(ctx, "not a constructor");
-    if (argc == 0) {
-        bf_t *r;
-        val = JS_NewBigFloat(ctx);
-        if (JS_IsException(val))
-            return val;
-        r = JS_GetBigFloat(val);
-        bf_set_zero(r, 0);
-    } else {
-        val = JS_DupValue(ctx, argv[0]);
-    redo:
-        switch(JS_VALUE_GET_NORM_TAG(val)) {
-        case JS_TAG_BIG_FLOAT:
-            break;
-        case JS_TAG_FLOAT64:
-            {
-                bf_t *r;
-                double d = JS_VALUE_GET_FLOAT64(val);
-                val = JS_NewBigFloat(ctx);
-                if (JS_IsException(val))
-                    break;
-                r = JS_GetBigFloat(val);
-                if (bf_set_float64(r, d))
-                    goto fail;
-            }
-            break;
-        case JS_TAG_INT:
-            {
-                bf_t *r;
-                int32_t v = JS_VALUE_GET_INT(val);
-                val = JS_NewBigFloat(ctx);
-                if (JS_IsException(val))
-                    break;
-                r = JS_GetBigFloat(val);
-                if (bf_set_si(r, v))
-                    goto fail;
-            }
-            break;
-        case JS_TAG_BIG_INT:
-            /* We keep the full precision of the integer */
-            {
-                JSBigFloat *p = JS_VALUE_GET_PTR(val);
-                val = JS_MKPTR(JS_TAG_BIG_FLOAT, p);
-            }
-            break;
-        case JS_TAG_BIG_DECIMAL:
-            val = JS_ToStringFree(ctx, val);
-            if (JS_IsException(val))
-                break;
-            goto redo;
-        case JS_TAG_STRING:
-            {
-                const char *str, *p;
-                size_t len;
-                int err;
-
-                str = JS_ToCStringLen(ctx, &len, val);
-                JS_FreeValue(ctx, val);
-                if (!str)
-                    return JS_EXCEPTION;
-                p = str;
-                p += skip_spaces(p);
-                if ((p - str) == len) {
-                    bf_t *r;
-                    val = JS_NewBigFloat(ctx);
-                    if (JS_IsException(val))
-                        break;
-                    r = JS_GetBigFloat(val);
-                    bf_set_zero(r, 0);
-                    err = 0;
-                } else {
-                    val = js_atof(ctx, p, &p, 0, ATOD_ACCEPT_BIN_OCT |
-                                  ATOD_TYPE_BIG_FLOAT |
-                                  ATOD_ACCEPT_PREFIX_AFTER_SIGN);
-                    if (JS_IsException(val)) {
-                        JS_FreeCString(ctx, str);
-                        return JS_EXCEPTION;
-                    }
-                    p += skip_spaces(p);
-                    err = ((p - str) != len);
-                }
-                JS_FreeCString(ctx, str);
-                if (err) {
-                    JS_FreeValue(ctx, val);
-                    return JS_ThrowSyntaxError(ctx, "invalid bigfloat literal");
-                }
-            }
-            break;
-        case JS_TAG_OBJECT:
-            val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
-            if (JS_IsException(val))
-                break;
-            goto redo;
-        case JS_TAG_NULL:
-        case JS_TAG_UNDEFINED:
-        default:
-            JS_FreeValue(ctx, val);
-            return JS_ThrowTypeError(ctx, "cannot convert to bigfloat");
-        }
-    }
-    return val;
- fail:
-    JS_FreeValue(ctx, val);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_bigfloat_get_const(JSContext *ctx,
-                                     JSValueConst this_val, int magic)
-{
-    bf_t *r;
-    JSValue val;
-    val = JS_NewBigFloat(ctx);
-    if (JS_IsException(val))
-        return val;
-    r = JS_GetBigFloat(val);
-    switch(magic) {
-    case 0: /* PI */
-        bf_const_pi(r, ctx->fp_env.prec, ctx->fp_env.flags);
-        break;
-    case 1: /* LN2 */
-        bf_const_log2(r, ctx->fp_env.prec, ctx->fp_env.flags);
-        break;
-    case 2: /* MIN_VALUE */
-    case 3: /* MAX_VALUE */
-        {
-            slimb_t e_range, e;
-            e_range = (limb_t)1 << (bf_get_exp_bits(ctx->fp_env.flags) - 1);
-            bf_set_ui(r, 1);
-            if (magic == 2) {
-                e = -e_range + 2;
-                if (ctx->fp_env.flags & BF_FLAG_SUBNORMAL)
-                    e -= ctx->fp_env.prec - 1;
-                bf_mul_2exp(r, e, ctx->fp_env.prec, ctx->fp_env.flags);
-            } else {
-                bf_mul_2exp(r, ctx->fp_env.prec, ctx->fp_env.prec,
-                            ctx->fp_env.flags);
-                bf_add_si(r, r, -1, ctx->fp_env.prec, ctx->fp_env.flags);
-                bf_mul_2exp(r, e_range - ctx->fp_env.prec, ctx->fp_env.prec,
-                            ctx->fp_env.flags);
-            }
-        }
-        break;
-    case 4: /* EPSILON */
-        bf_set_ui(r, 1);
-        bf_mul_2exp(r, 1 - ctx->fp_env.prec,
-                    ctx->fp_env.prec, ctx->fp_env.flags);
-        break;
-    default:
-        abort();
-    }
-    return val;
-}
-
-static JSValue js_bigfloat_parseFloat(JSContext *ctx, JSValueConst this_val,
-                                      int argc, JSValueConst *argv)
-{
-    bf_t *a;
-    const char *str;
-    JSValue ret;
-    int radix;
-    JSFloatEnv *fe;
-
-    str = JS_ToCString(ctx, argv[0]);
-    if (!str)
-        return JS_EXCEPTION;
-    if (JS_ToInt32(ctx, &radix, argv[1])) {
-    fail:
-        JS_FreeCString(ctx, str);
-        return JS_EXCEPTION;
-    }
-    if (radix != 0 && (radix < 2 || radix > 36)) {
-        JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
-        goto fail;
-    }
-    fe = &ctx->fp_env;
-    if (argc > 2) {
-        fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV);
-        if (!fe)
-            goto fail;
-    }
-    ret = JS_NewBigFloat(ctx);
-    if (JS_IsException(ret))
-        goto done;
-    a = JS_GetBigFloat(ret);
-    /* XXX: use js_atof() */
-    bf_atof(a, str, NULL, radix, fe->prec, fe->flags);
- done:
-    JS_FreeCString(ctx, str);
-    return ret;
-}
-
-static JSValue js_bigfloat_isFinite(JSContext *ctx, JSValueConst this_val,
-                                    int argc, JSValueConst *argv)
-{
-    JSValueConst val = argv[0];
-    JSBigFloat *p;
-    
-    if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT)
-        return JS_FALSE;
-    p = JS_VALUE_GET_PTR(val);
-    return JS_NewBool(ctx, bf_is_finite(&p->num));
-}
-
-static JSValue js_bigfloat_isNaN(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv)
-{
-    JSValueConst val = argv[0];
-    JSBigFloat *p;
-    
-    if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT)
-        return JS_FALSE;
-    p = JS_VALUE_GET_PTR(val);
-    return JS_NewBool(ctx, bf_is_nan(&p->num));
-}
-
-enum {
-    MATH_OP_ABS,
-    MATH_OP_FLOOR,
-    MATH_OP_CEIL,
-    MATH_OP_ROUND,
-    MATH_OP_TRUNC,
-    MATH_OP_SQRT,
-    MATH_OP_FPROUND,
-    MATH_OP_ACOS,
-    MATH_OP_ASIN,
-    MATH_OP_ATAN,
-    MATH_OP_ATAN2,
-    MATH_OP_COS,
-    MATH_OP_EXP,
-    MATH_OP_LOG,
-    MATH_OP_POW,
-    MATH_OP_SIN,
-    MATH_OP_TAN,
-    MATH_OP_FMOD,
-    MATH_OP_REM,
-    MATH_OP_SIGN,
-
-    MATH_OP_ADD,
-    MATH_OP_SUB,
-    MATH_OP_MUL,
-    MATH_OP_DIV,
-};
-
-static JSValue js_bigfloat_fop(JSContext *ctx, JSValueConst this_val,
-                           int argc, JSValueConst *argv, int magic)
-{
-    bf_t a_s, *a, *r;
-    JSFloatEnv *fe;
-    int rnd_mode;
-    JSValue op1, res;
-
-    op1 = JS_ToNumeric(ctx, argv[0]);
-    if (JS_IsException(op1))
-        return op1;
-    a = JS_ToBigFloat(ctx, &a_s, op1);
-    fe = &ctx->fp_env;
-    if (argc > 1) {
-        fe = JS_GetOpaque2(ctx, argv[1], JS_CLASS_FLOAT_ENV);
-        if (!fe)
-            goto fail;
-    }
-    res = JS_NewBigFloat(ctx);
-    if (JS_IsException(res)) {
-    fail:
-        if (a == &a_s)
-            bf_delete(a);
-        JS_FreeValue(ctx, op1);
-        return JS_EXCEPTION;
-    }
-    r = JS_GetBigFloat(res);
-    switch (magic) {
-    case MATH_OP_ABS:
-        bf_set(r, a);
-        r->sign = 0;
-        break;
-    case MATH_OP_FLOOR:
-        rnd_mode = BF_RNDD;
-        goto rint;
-    case MATH_OP_CEIL:
-        rnd_mode = BF_RNDU;
-        goto rint;
-    case MATH_OP_ROUND:
-        rnd_mode = BF_RNDNA;
-        goto rint;
-    case MATH_OP_TRUNC:
-        rnd_mode = BF_RNDZ;
-    rint:
-        bf_set(r, a);
-        fe->status |= bf_rint(r, rnd_mode);
-        break;
-    case MATH_OP_SQRT:
-        fe->status |= bf_sqrt(r, a, fe->prec, fe->flags);
-        break;
-    case MATH_OP_FPROUND:
-        bf_set(r, a);
-        fe->status |= bf_round(r, fe->prec, fe->flags);
-        break;
-    case MATH_OP_ACOS:
-        fe->status |= bf_acos(r, a, fe->prec, fe->flags);
-        break;
-    case MATH_OP_ASIN:
-        fe->status |= bf_asin(r, a, fe->prec, fe->flags);
-        break;
-    case MATH_OP_ATAN:
-        fe->status |= bf_atan(r, a, fe->prec, fe->flags);
-        break;
-    case MATH_OP_COS:
-        fe->status |= bf_cos(r, a, fe->prec, fe->flags);
-        break;
-    case MATH_OP_EXP:
-        fe->status |= bf_exp(r, a, fe->prec, fe->flags);
-        break;
-    case MATH_OP_LOG:
-        fe->status |= bf_log(r, a, fe->prec, fe->flags);
-        break;
-    case MATH_OP_SIN:
-        fe->status |= bf_sin(r, a, fe->prec, fe->flags);
-        break;
-    case MATH_OP_TAN:
-        fe->status |= bf_tan(r, a, fe->prec, fe->flags);
-        break;
-    case MATH_OP_SIGN:
-        if (bf_is_nan(a) || bf_is_zero(a)) {
-            bf_set(r, a);
-        } else {
-            bf_set_si(r, 1 - 2 * a->sign);
-        }
-        break;
-    default:
-        abort();
-    }
-    if (a == &a_s)
-        bf_delete(a);
-    JS_FreeValue(ctx, op1);
-    return res;
-}
-
-static JSValue js_bigfloat_fop2(JSContext *ctx, JSValueConst this_val,
-                            int argc, JSValueConst *argv, int magic)
-{
-    bf_t a_s, *a, b_s, *b, r_s, *r = &r_s;
-    JSFloatEnv *fe;
-    JSValue op1, op2, res;
-
-    op1 = JS_ToNumeric(ctx, argv[0]);
-    if (JS_IsException(op1))
-        return op1;
-    op2 = JS_ToNumeric(ctx, argv[1]);
-    if (JS_IsException(op2)) {
-        JS_FreeValue(ctx, op1);
-        return op2;
-    }
-    a = JS_ToBigFloat(ctx, &a_s, op1);
-    b = JS_ToBigFloat(ctx, &b_s, op2);
-    fe = &ctx->fp_env;
-    if (argc > 2) {
-        fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV);
-        if (!fe)
-            goto fail;
-    }
-    res = JS_NewBigFloat(ctx);
-    if (JS_IsException(res)) {
-    fail:
-        if (a == &a_s)
-            bf_delete(a);
-        if (b == &b_s)
-            bf_delete(b);
-        JS_FreeValue(ctx, op1);
-        JS_FreeValue(ctx, op2);
-        return JS_EXCEPTION;
-    }
-    r = JS_GetBigFloat(res);
-    switch (magic) {
-    case MATH_OP_ATAN2:
-        fe->status |= bf_atan2(r, a, b, fe->prec, fe->flags);
-        break;
-    case MATH_OP_POW:
-        fe->status |= bf_pow(r, a, b, fe->prec, fe->flags | BF_POW_JS_QUIRKS);
-        break;
-    case MATH_OP_FMOD:
-        fe->status |= bf_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ);
-        break;
-    case MATH_OP_REM:
-        fe->status |= bf_rem(r, a, b, fe->prec, fe->flags, BF_RNDN);
-        break;
-    case MATH_OP_ADD:
-        fe->status |= bf_add(r, a, b, fe->prec, fe->flags);
-        break;
-    case MATH_OP_SUB:
-        fe->status |= bf_sub(r, a, b, fe->prec, fe->flags);
-        break;
-    case MATH_OP_MUL:
-        fe->status |= bf_mul(r, a, b, fe->prec, fe->flags);
-        break;
-    case MATH_OP_DIV:
-        fe->status |= bf_div(r, a, b, fe->prec, fe->flags);
-        break;
-    default:
-        abort();
-    }
-    if (a == &a_s)
-        bf_delete(a);
-    if (b == &b_s)
-        bf_delete(b);
-    JS_FreeValue(ctx, op1);
-    JS_FreeValue(ctx, op2);
-    return res;
-}
-
-static const JSCFunctionListEntry js_bigfloat_funcs[] = {
-    JS_CGETSET_MAGIC_DEF("PI", js_bigfloat_get_const, NULL, 0 ),
-    JS_CGETSET_MAGIC_DEF("LN2", js_bigfloat_get_const, NULL, 1 ),
-    JS_CGETSET_MAGIC_DEF("MIN_VALUE", js_bigfloat_get_const, NULL, 2 ),
-    JS_CGETSET_MAGIC_DEF("MAX_VALUE", js_bigfloat_get_const, NULL, 3 ),
-    JS_CGETSET_MAGIC_DEF("EPSILON", js_bigfloat_get_const, NULL, 4 ),
-    JS_CFUNC_DEF("parseFloat", 1, js_bigfloat_parseFloat ),
-    JS_CFUNC_DEF("isFinite", 1, js_bigfloat_isFinite ),
-    JS_CFUNC_DEF("isNaN", 1, js_bigfloat_isNaN ),
-    JS_CFUNC_MAGIC_DEF("abs", 1, js_bigfloat_fop, MATH_OP_ABS ),
-    JS_CFUNC_MAGIC_DEF("fpRound", 1, js_bigfloat_fop, MATH_OP_FPROUND ),
-    JS_CFUNC_MAGIC_DEF("floor", 1, js_bigfloat_fop, MATH_OP_FLOOR ),
-    JS_CFUNC_MAGIC_DEF("ceil", 1, js_bigfloat_fop, MATH_OP_CEIL ),
-    JS_CFUNC_MAGIC_DEF("round", 1, js_bigfloat_fop, MATH_OP_ROUND ),
-    JS_CFUNC_MAGIC_DEF("trunc", 1, js_bigfloat_fop, MATH_OP_TRUNC ),
-    JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigfloat_fop, MATH_OP_SQRT ),
-    JS_CFUNC_MAGIC_DEF("acos", 1, js_bigfloat_fop, MATH_OP_ACOS ),
-    JS_CFUNC_MAGIC_DEF("asin", 1, js_bigfloat_fop, MATH_OP_ASIN ),
-    JS_CFUNC_MAGIC_DEF("atan", 1, js_bigfloat_fop, MATH_OP_ATAN ),
-    JS_CFUNC_MAGIC_DEF("atan2", 2, js_bigfloat_fop2, MATH_OP_ATAN2 ),
-    JS_CFUNC_MAGIC_DEF("cos", 1, js_bigfloat_fop, MATH_OP_COS ),
-    JS_CFUNC_MAGIC_DEF("exp", 1, js_bigfloat_fop, MATH_OP_EXP ),
-    JS_CFUNC_MAGIC_DEF("log", 1, js_bigfloat_fop, MATH_OP_LOG ),
-    JS_CFUNC_MAGIC_DEF("pow", 2, js_bigfloat_fop2, MATH_OP_POW ),
-    JS_CFUNC_MAGIC_DEF("sin", 1, js_bigfloat_fop, MATH_OP_SIN ),
-    JS_CFUNC_MAGIC_DEF("tan", 1, js_bigfloat_fop, MATH_OP_TAN ),
-    JS_CFUNC_MAGIC_DEF("sign", 1, js_bigfloat_fop, MATH_OP_SIGN ),
-    JS_CFUNC_MAGIC_DEF("add", 2, js_bigfloat_fop2, MATH_OP_ADD ),
-    JS_CFUNC_MAGIC_DEF("sub", 2, js_bigfloat_fop2, MATH_OP_SUB ),
-    JS_CFUNC_MAGIC_DEF("mul", 2, js_bigfloat_fop2, MATH_OP_MUL ),
-    JS_CFUNC_MAGIC_DEF("div", 2, js_bigfloat_fop2, MATH_OP_DIV ),
-    JS_CFUNC_MAGIC_DEF("fmod", 2, js_bigfloat_fop2, MATH_OP_FMOD ),
-    JS_CFUNC_MAGIC_DEF("remainder", 2, js_bigfloat_fop2, MATH_OP_REM ),
-};
-
-/* FloatEnv */
-
-static JSValue js_float_env_constructor(JSContext *ctx,
-                                        JSValueConst new_target,
-                                        int argc, JSValueConst *argv)
-{
-    JSValue obj;
-    JSFloatEnv *fe;
-    int64_t prec;
-    int flags, rndmode;
-
-    prec = ctx->fp_env.prec;
-    flags = ctx->fp_env.flags;
-    if (!JS_IsUndefined(argv[0])) {
-        if (JS_ToInt64Sat(ctx, &prec, argv[0]))
-            return JS_EXCEPTION;
-        if (prec < BF_PREC_MIN || prec > BF_PREC_MAX)
-            return JS_ThrowRangeError(ctx, "invalid precision");
-        flags = BF_RNDN; /* RNDN, max exponent size, no subnormal */
-        if (argc > 1 && !JS_IsUndefined(argv[1])) {
-            if (JS_ToInt32Sat(ctx, &rndmode, argv[1]))
-                return JS_EXCEPTION;
-            if (rndmode < BF_RNDN || rndmode > BF_RNDF)
-                return JS_ThrowRangeError(ctx, "invalid rounding mode");
-            flags = rndmode;
-        }
-    }
-
-    obj = JS_NewObjectClass(ctx, JS_CLASS_FLOAT_ENV);
-    if (JS_IsException(obj))
-        return JS_EXCEPTION;
-    fe = js_malloc(ctx, sizeof(*fe));
-    if (!fe)
-        return JS_EXCEPTION;
-    fe->prec = prec;
-    fe->flags = flags;
-    fe->status = 0;
-    JS_SetOpaque(obj, fe);
-    return obj;
-}
-
-static void js_float_env_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSFloatEnv *fe = JS_GetOpaque(val, JS_CLASS_FLOAT_ENV);
-    js_free_rt(rt, fe);
-}
-
-static JSValue js_float_env_get_prec(JSContext *ctx, JSValueConst this_val)
-{
-    return JS_NewInt64(ctx, ctx->fp_env.prec);
-}
-
-static JSValue js_float_env_get_expBits(JSContext *ctx, JSValueConst this_val)
-{
-    return JS_NewInt32(ctx, bf_get_exp_bits(ctx->fp_env.flags));
-}
-
-static JSValue js_float_env_setPrec(JSContext *ctx,
-                                    JSValueConst this_val,
-                                    int argc, JSValueConst *argv)
-{
-    JSValueConst func;
-    int exp_bits, flags, saved_flags;
-    JSValue ret;
-    limb_t saved_prec;
-    int64_t prec;
-
-    func = argv[0];
-    if (JS_ToInt64Sat(ctx, &prec, argv[1]))
-        return JS_EXCEPTION;
-    if (prec < BF_PREC_MIN || prec > BF_PREC_MAX)
-        return JS_ThrowRangeError(ctx, "invalid precision");
-    exp_bits = BF_EXP_BITS_MAX;
-
-    if (argc > 2 && !JS_IsUndefined(argv[2])) {
-        if (JS_ToInt32Sat(ctx, &exp_bits, argv[2]))
-            return JS_EXCEPTION;
-        if (exp_bits < BF_EXP_BITS_MIN || exp_bits > BF_EXP_BITS_MAX)
-            return JS_ThrowRangeError(ctx, "invalid number of exponent bits");
-    }
-
-    flags = BF_RNDN | BF_FLAG_SUBNORMAL | bf_set_exp_bits(exp_bits);
-
-    saved_prec = ctx->fp_env.prec;
-    saved_flags = ctx->fp_env.flags;
-
-    ctx->fp_env.prec = prec;
-    ctx->fp_env.flags = flags;
-
-    ret = JS_Call(ctx, func, JS_UNDEFINED, 0, NULL);
-    /* always restore the floating point precision */
-    ctx->fp_env.prec = saved_prec;
-    ctx->fp_env.flags = saved_flags;
-    return ret;
-}
-
-#define FE_PREC      (-1)
-#define FE_EXP       (-2)
-#define FE_RNDMODE   (-3)
-#define FE_SUBNORMAL (-4)
-
-static JSValue js_float_env_proto_get_status(JSContext *ctx, JSValueConst this_val, int magic)
-{
-    JSFloatEnv *fe;
-    fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV);
-    if (!fe)
-        return JS_EXCEPTION;
-    switch(magic) {
-    case FE_PREC:
-        return JS_NewInt64(ctx, fe->prec);
-    case FE_EXP:
-        return JS_NewInt32(ctx, bf_get_exp_bits(fe->flags));
-    case FE_RNDMODE:
-        return JS_NewInt32(ctx, fe->flags & BF_RND_MASK);
-    case FE_SUBNORMAL:
-        return JS_NewBool(ctx, (fe->flags & BF_FLAG_SUBNORMAL) != 0);
-    default:
-        return JS_NewBool(ctx, (fe->status & magic) != 0);
-    }
-}
-
-static JSValue js_float_env_proto_set_status(JSContext *ctx, JSValueConst this_val, JSValueConst val, int magic)
-{
-    JSFloatEnv *fe;
-    int b;
-    int64_t prec;
-
-    fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV);
-    if (!fe)
-        return JS_EXCEPTION;
-    switch(magic) {
-    case FE_PREC:
-        if (JS_ToInt64Sat(ctx, &prec, val))
-            return JS_EXCEPTION;
-        if (prec < BF_PREC_MIN || prec > BF_PREC_MAX)
-            return JS_ThrowRangeError(ctx, "invalid precision");
-        fe->prec = prec;
-        break;
-    case FE_EXP:
-        if (JS_ToInt32Sat(ctx, &b, val))
-            return JS_EXCEPTION;
-        if (b < BF_EXP_BITS_MIN || b > BF_EXP_BITS_MAX)
-            return JS_ThrowRangeError(ctx, "invalid number of exponent bits");
-        fe->flags = (fe->flags & ~(BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)) |
-            bf_set_exp_bits(b);
-        break;
-    case FE_RNDMODE:
-        b = bigfloat_get_rnd_mode(ctx, val);
-        if (b < 0)
-            return JS_EXCEPTION;
-        fe->flags = (fe->flags & ~BF_RND_MASK) | b;
-        break;
-    case FE_SUBNORMAL:
-        b = JS_ToBool(ctx, val);
-        fe->flags = (fe->flags & ~BF_FLAG_SUBNORMAL) | (b ? BF_FLAG_SUBNORMAL: 0);
-        break;
-    default:
-        b = JS_ToBool(ctx, val);
-        fe->status = (fe->status & ~magic) & ((-b) & magic);
-        break;
-    }
-    return JS_UNDEFINED;
-}
-
-static JSValue js_float_env_clearStatus(JSContext *ctx,
-                                        JSValueConst this_val,
-                                        int argc, JSValueConst *argv)
-{
-    JSFloatEnv *fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV);
-    if (!fe)
-        return JS_EXCEPTION;
-    fe->status = 0;
-    return JS_UNDEFINED;
-}
-
-static const JSCFunctionListEntry js_float_env_funcs[] = {
-    JS_CGETSET_DEF("prec", js_float_env_get_prec, NULL ),
-    JS_CGETSET_DEF("expBits", js_float_env_get_expBits, NULL ),
-    JS_CFUNC_DEF("setPrec", 2, js_float_env_setPrec ),
-    JS_PROP_INT32_DEF("RNDN", BF_RNDN, 0 ),
-    JS_PROP_INT32_DEF("RNDZ", BF_RNDZ, 0 ),
-    JS_PROP_INT32_DEF("RNDU", BF_RNDU, 0 ),
-    JS_PROP_INT32_DEF("RNDD", BF_RNDD, 0 ),
-    JS_PROP_INT32_DEF("RNDNA", BF_RNDNA, 0 ),
-    JS_PROP_INT32_DEF("RNDA", BF_RNDA, 0 ),
-    JS_PROP_INT32_DEF("RNDF", BF_RNDF, 0 ),
-    JS_PROP_INT32_DEF("precMin", BF_PREC_MIN, 0 ),
-    JS_PROP_INT64_DEF("precMax", BF_PREC_MAX, 0 ),
-    JS_PROP_INT32_DEF("expBitsMin", BF_EXP_BITS_MIN, 0 ),
-    JS_PROP_INT32_DEF("expBitsMax", BF_EXP_BITS_MAX, 0 ),
-};
-
-static const JSCFunctionListEntry js_float_env_proto_funcs[] = {
-    JS_CGETSET_MAGIC_DEF("prec", js_float_env_proto_get_status,
-                         js_float_env_proto_set_status, FE_PREC ),
-    JS_CGETSET_MAGIC_DEF("expBits", js_float_env_proto_get_status,
-                         js_float_env_proto_set_status, FE_EXP ),
-    JS_CGETSET_MAGIC_DEF("rndMode", js_float_env_proto_get_status,
-                         js_float_env_proto_set_status, FE_RNDMODE ),
-    JS_CGETSET_MAGIC_DEF("subnormal", js_float_env_proto_get_status,
-                         js_float_env_proto_set_status, FE_SUBNORMAL ),
-    JS_CGETSET_MAGIC_DEF("invalidOperation", js_float_env_proto_get_status,
-                         js_float_env_proto_set_status, BF_ST_INVALID_OP ),
-    JS_CGETSET_MAGIC_DEF("divideByZero", js_float_env_proto_get_status,
-                         js_float_env_proto_set_status, BF_ST_DIVIDE_ZERO ),
-    JS_CGETSET_MAGIC_DEF("overflow", js_float_env_proto_get_status,
-                         js_float_env_proto_set_status, BF_ST_OVERFLOW ),
-    JS_CGETSET_MAGIC_DEF("underflow", js_float_env_proto_get_status,
-                         js_float_env_proto_set_status, BF_ST_UNDERFLOW ),
-    JS_CGETSET_MAGIC_DEF("inexact", js_float_env_proto_get_status,
-                         js_float_env_proto_set_status, BF_ST_INEXACT ),
-    JS_CFUNC_DEF("clearStatus", 0, js_float_env_clearStatus ),
-};
-
-void JS_AddIntrinsicBigFloat(JSContext *ctx)
-{
-    JSRuntime *rt = ctx->rt;
-    JSValueConst obj1;
-    
-    rt->bigfloat_ops.to_string = js_bigfloat_to_string;
-    rt->bigfloat_ops.from_string = js_string_to_bigfloat;
-    rt->bigfloat_ops.unary_arith = js_unary_arith_bigfloat;
-    rt->bigfloat_ops.binary_arith = js_binary_arith_bigfloat;
-    rt->bigfloat_ops.compare = js_compare_bigfloat;
-    rt->bigfloat_ops.mul_pow10_to_float64 = js_mul_pow10_to_float64;
-    rt->bigfloat_ops.mul_pow10 = js_mul_pow10;
-    
-    ctx->class_proto[JS_CLASS_BIG_FLOAT] = JS_NewObject(ctx);
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT],
-                               js_bigfloat_proto_funcs,
-                               countof(js_bigfloat_proto_funcs));
-    obj1 = JS_NewGlobalCConstructor(ctx, "BigFloat", js_bigfloat_constructor, 1,
-                                    ctx->class_proto[JS_CLASS_BIG_FLOAT]);
-    JS_SetPropertyFunctionList(ctx, obj1, js_bigfloat_funcs,
-                               countof(js_bigfloat_funcs));
-
-    ctx->class_proto[JS_CLASS_FLOAT_ENV] = JS_NewObject(ctx);
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_FLOAT_ENV],
-                               js_float_env_proto_funcs,
-                               countof(js_float_env_proto_funcs));
-    obj1 = JS_NewGlobalCConstructorOnly(ctx, "BigFloatEnv",
-                                        js_float_env_constructor, 1,
-                                        ctx->class_proto[JS_CLASS_FLOAT_ENV]);
-    JS_SetPropertyFunctionList(ctx, obj1, js_float_env_funcs,
-                               countof(js_float_env_funcs));
-}
-
-/* BigDecimal */
-
-static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
-                                   BOOL allow_null_or_undefined)
-{
- redo:
-    switch(JS_VALUE_GET_NORM_TAG(val)) {
-    case JS_TAG_BIG_DECIMAL:
-        break;
-    case JS_TAG_NULL:
-        if (!allow_null_or_undefined)
-            goto fail;
-        /* fall thru */
-    case JS_TAG_BOOL:
-    case JS_TAG_INT:
-        {
-            bfdec_t *r;
-            int32_t v = JS_VALUE_GET_INT(val);
-
-            val = JS_NewBigDecimal(ctx);
-            if (JS_IsException(val))
-                break;
-            r = JS_GetBigDecimal(val);
-            if (bfdec_set_si(r, v)) {
-                JS_FreeValue(ctx, val);
-                val = JS_EXCEPTION;
-                break;
-            }
-        }
-        break;
-    case JS_TAG_FLOAT64:
-    case JS_TAG_BIG_INT:
-    case JS_TAG_BIG_FLOAT:
-        val = JS_ToStringFree(ctx, val);
-        if (JS_IsException(val))
-            break;
-        goto redo;
-    case JS_TAG_STRING:
-        {
-            const char *str, *p;
-            size_t len;
-            int err;
-
-            str = JS_ToCStringLen(ctx, &len, val);
-            JS_FreeValue(ctx, val);
-            if (!str)
-                return JS_EXCEPTION;
-            p = str;
-            p += skip_spaces(p);
-            if ((p - str) == len) {
-                bfdec_t *r;
-                val = JS_NewBigDecimal(ctx);
-                if (JS_IsException(val))
-                    break;
-                r = JS_GetBigDecimal(val);
-                bfdec_set_zero(r, 0);
-                err = 0;
-            } else {
-                val = js_atof(ctx, p, &p, 0, ATOD_TYPE_BIG_DECIMAL);
-                if (JS_IsException(val)) {
-                    JS_FreeCString(ctx, str);
-                    return JS_EXCEPTION;
-                }
-                p += skip_spaces(p);
-                err = ((p - str) != len);
-            }
-            JS_FreeCString(ctx, str);
-            if (err) {
-                JS_FreeValue(ctx, val);
-                return JS_ThrowSyntaxError(ctx, "invalid bigdecimal literal");
-            }
-        }
-        break;
-    case JS_TAG_OBJECT:
-        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
-        if (JS_IsException(val))
-            break;
-        goto redo;
-    case JS_TAG_UNDEFINED:
-        {
-            bfdec_t *r;
-            if (!allow_null_or_undefined)
-                goto fail;
-            val = JS_NewBigDecimal(ctx);
-            if (JS_IsException(val))
-                break;
-            r = JS_GetBigDecimal(val);
-            bfdec_set_nan(r);
-        }
-        break;
-    default:
-    fail:
-        JS_FreeValue(ctx, val);
-        return JS_ThrowTypeError(ctx, "cannot convert to bigdecimal");
-    }
-    return val;
-}
-
-static JSValue js_bigdecimal_constructor(JSContext *ctx,
-                                         JSValueConst new_target,
-                                         int argc, JSValueConst *argv)
-{
-    JSValue val;
-    if (!JS_IsUndefined(new_target))
-        return JS_ThrowTypeError(ctx, "not a constructor");
-    if (argc == 0) {
-        bfdec_t *r;
-        val = JS_NewBigDecimal(ctx);
-        if (JS_IsException(val))
-            return val;
-        r = JS_GetBigDecimal(val);
-        bfdec_set_zero(r, 0);
-    } else {
-        val = JS_ToBigDecimalFree(ctx, JS_DupValue(ctx, argv[0]), FALSE);
-    }
-    return val;
-}
-
-static JSValue js_thisBigDecimalValue(JSContext *ctx, JSValueConst this_val)
-{
-    if (JS_IsBigDecimal(this_val))
-        return JS_DupValue(ctx, this_val);
-
-    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
-        JSObject *p = JS_VALUE_GET_OBJ(this_val);
-        if (p->class_id == JS_CLASS_BIG_DECIMAL) {
-            if (JS_IsBigDecimal(p->u.object_data))
-                return JS_DupValue(ctx, p->u.object_data);
-        }
-    }
-    return JS_ThrowTypeError(ctx, "not a bigdecimal");
-}
-
-static JSValue js_bigdecimal_toString(JSContext *ctx, JSValueConst this_val,
-                                      int argc, JSValueConst *argv)
-{
-    JSValue val;
-
-    val = js_thisBigDecimalValue(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    return JS_ToStringFree(ctx, val);
-}
-
-static JSValue js_bigdecimal_valueOf(JSContext *ctx, JSValueConst this_val,
-                                   int argc, JSValueConst *argv)
-{
-    return js_thisBigDecimalValue(ctx, this_val);
-}
-
-static int js_bigdecimal_get_rnd_mode(JSContext *ctx, JSValueConst obj)
-{
-    const char *str;
-    size_t size;
-    int rnd_mode;
-    
-    str = JS_ToCStringLen(ctx, &size, obj);
-    if (!str)
-        return -1;
-    if (strlen(str) != size)
-        goto invalid_rounding_mode;
-    if (!strcmp(str, "floor")) {
-        rnd_mode = BF_RNDD;
-    } else if (!strcmp(str, "ceiling")) {
-        rnd_mode = BF_RNDU;
-    } else if (!strcmp(str, "down")) {
-        rnd_mode = BF_RNDZ;
-    } else if (!strcmp(str, "up")) {
-        rnd_mode = BF_RNDA;
-    } else if (!strcmp(str, "half-even")) {
-        rnd_mode = BF_RNDN;
-    } else if (!strcmp(str, "half-up")) {
-        rnd_mode = BF_RNDNA;
-    } else {
-    invalid_rounding_mode:
-        JS_FreeCString(ctx, str);
-        JS_ThrowTypeError(ctx, "invalid rounding mode");
-        return -1;
-    }
-    JS_FreeCString(ctx, str);
-    return rnd_mode;
-}
-
-typedef struct {
-    int64_t prec;
-    bf_flags_t flags;
-} BigDecimalEnv;
-
-static int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe,
-                                 JSValueConst obj)
-{
-    JSValue prop;
-    int64_t val;
-    BOOL has_prec;
-    int rnd_mode;
-    
-    if (!JS_IsObject(obj)) {
-        JS_ThrowTypeErrorNotAnObject(ctx);
-        return -1;
-    }
-    prop = JS_GetProperty(ctx, obj, JS_ATOM_roundingMode);
-    if (JS_IsException(prop))
-        return -1;
-    rnd_mode = js_bigdecimal_get_rnd_mode(ctx, prop);
-    JS_FreeValue(ctx, prop);
-    if (rnd_mode < 0)
-        return -1;
-    fe->flags = rnd_mode;
-    
-    prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumSignificantDigits);
-    if (JS_IsException(prop))
-        return -1;
-    has_prec = FALSE;
-    if (!JS_IsUndefined(prop)) {
-        if (JS_ToInt64SatFree(ctx, &val, prop))
-            return -1;
-        if (val < 1 || val > BF_PREC_MAX)
-            goto invalid_precision;
-        fe->prec = val;
-        has_prec = TRUE;
-    }
-
-    prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumFractionDigits);
-    if (JS_IsException(prop))
-        return -1;
-    if (!JS_IsUndefined(prop)) {
-        if (has_prec) {
-            JS_FreeValue(ctx, prop);
-            JS_ThrowTypeError(ctx, "cannot provide both maximumSignificantDigits and maximumFractionDigits");
-            return -1;
-        }
-        if (JS_ToInt64SatFree(ctx, &val, prop))
-            return -1;
-        if (val < 0 || val > BF_PREC_MAX) {
-        invalid_precision:
-            JS_ThrowTypeError(ctx, "invalid precision");
-            return -1;
-        }
-        fe->prec = val;
-        fe->flags |= BF_FLAG_RADPNT_PREC;
-        has_prec = TRUE;
-    }
-    if (!has_prec) {
-        JS_ThrowTypeError(ctx, "precision must be present");
-        return -1;
-    }
-    return 0;
-}
-
-
-static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv, int magic)
-{
-    bfdec_t *a, *b, r_s, *r = &r_s;
-    JSValue op1, op2, res;
-    BigDecimalEnv fe_s, *fe = &fe_s;
-    int op_count, ret;
-
-    if (magic == MATH_OP_SQRT ||
-        magic == MATH_OP_ROUND)
-        op_count = 1;
-    else
-        op_count = 2;
-    
-    op1 = JS_ToNumeric(ctx, argv[0]);
-    if (JS_IsException(op1))
-        return op1;
-    a = JS_ToBigDecimal(ctx, op1);
-    if (!a) {
-        JS_FreeValue(ctx, op1);
-        return JS_EXCEPTION;
-    }
-    if (op_count >= 2) {
-        op2 = JS_ToNumeric(ctx, argv[1]);
-        if (JS_IsException(op2)) {
-            JS_FreeValue(ctx, op1);
-            return op2;
-        }
-        b = JS_ToBigDecimal(ctx, op2);
-        if (!b)
-            goto fail;
-    } else {
-        op2 = JS_UNDEFINED;
-        b = NULL;
-    }
-    fe->flags = BF_RNDZ;
-    fe->prec = BF_PREC_INF;
-    if (op_count < argc) {
-        if (js_bigdecimal_get_env(ctx, fe, argv[op_count]))
-            goto fail;
-    }
-
-    res = JS_NewBigDecimal(ctx);
-    if (JS_IsException(res)) {
-    fail:
-        JS_FreeValue(ctx, op1);
-        JS_FreeValue(ctx, op2);
-        return JS_EXCEPTION;
-    }
-    r = JS_GetBigDecimal(res);
-    switch (magic) {
-    case MATH_OP_ADD:
-        ret = bfdec_add(r, a, b, fe->prec, fe->flags);
-        break;
-    case MATH_OP_SUB:
-        ret = bfdec_sub(r, a, b, fe->prec, fe->flags);
-        break;
-    case MATH_OP_MUL:
-        ret = bfdec_mul(r, a, b, fe->prec, fe->flags);
-        break;
-    case MATH_OP_DIV:
-        ret = bfdec_div(r, a, b, fe->prec, fe->flags);
-        break;
-    case MATH_OP_FMOD:
-        ret = bfdec_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ);
-        break;
-    case MATH_OP_SQRT:
-        ret = bfdec_sqrt(r, a, fe->prec, fe->flags);
-        break;
-    case MATH_OP_ROUND:
-        ret = bfdec_set(r, a);
-        if (!(ret & BF_ST_MEM_ERROR))
-            ret = bfdec_round(r, fe->prec, fe->flags);
-        break;
-    default:
-        abort();
-    }
-    JS_FreeValue(ctx, op1);
-    JS_FreeValue(ctx, op2);
-    ret &= BF_ST_MEM_ERROR | BF_ST_DIVIDE_ZERO | BF_ST_INVALID_OP |
-        BF_ST_OVERFLOW;
-    if (ret != 0) {
-        JS_FreeValue(ctx, res);
-        return throw_bf_exception(ctx, ret);
-    } else {
-        return res;
-    }
-}
-
-static JSValue js_bigdecimal_toFixed(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv)
-{
-    JSValue val, ret;
-    int64_t f;
-    int rnd_mode;
-
-    val = js_thisBigDecimalValue(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    if (JS_ToInt64Sat(ctx, &f, argv[0]))
-        goto fail;
-    if (f < 0 || f > BF_PREC_MAX) {
-        JS_ThrowRangeError(ctx, "invalid number of digits");
-        goto fail;
-    }
-    rnd_mode = BF_RNDNA;
-    if (argc > 1) {
-        rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
-        if (rnd_mode < 0)
-            goto fail;
-    }
-    ret = js_bigdecimal_to_string1(ctx, val, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
-    JS_FreeValue(ctx, val);
-    return ret;
- fail:
-    JS_FreeValue(ctx, val);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_bigdecimal_toExponential(JSContext *ctx, JSValueConst this_val,
-                                       int argc, JSValueConst *argv)
-{
-    JSValue val, ret;
-    int64_t f;
-    int rnd_mode;
-
-    val = js_thisBigDecimalValue(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    if (JS_ToInt64Sat(ctx, &f, argv[0]))
-        goto fail;
-    if (JS_IsUndefined(argv[0])) {
-        ret = js_bigdecimal_to_string1(ctx, val, 0,
-                  BF_RNDN | BF_FTOA_FORMAT_FREE_MIN | BF_FTOA_FORCE_EXP);
-    } else {
-        if (f < 0 || f > BF_PREC_MAX) {
-            JS_ThrowRangeError(ctx, "invalid number of digits");
-            goto fail;
-        }
-        rnd_mode = BF_RNDNA;
-        if (argc > 1) {
-            rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
-            if (rnd_mode < 0)
-                goto fail;
-        }
-        ret = js_bigdecimal_to_string1(ctx, val, f + 1,
-                      rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP);
-    }
-    JS_FreeValue(ctx, val);
-    return ret;
- fail:
-    JS_FreeValue(ctx, val);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_bigdecimal_toPrecision(JSContext *ctx, JSValueConst this_val,
-                                     int argc, JSValueConst *argv)
-{
-    JSValue val, ret;
-    int64_t p;
-    int rnd_mode;
-
-    val = js_thisBigDecimalValue(ctx, this_val);
-    if (JS_IsException(val))
-        return val;
-    if (JS_IsUndefined(argv[0])) {
-        return JS_ToStringFree(ctx, val);
-    }
-    if (JS_ToInt64Sat(ctx, &p, argv[0]))
-        goto fail;
-    if (p < 1 || p > BF_PREC_MAX) {
-        JS_ThrowRangeError(ctx, "invalid number of digits");
-        goto fail;
-    }
-    rnd_mode = BF_RNDNA;
-    if (argc > 1) {
-        rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
-        if (rnd_mode < 0)
-            goto fail;
-    }
-    ret = js_bigdecimal_to_string1(ctx, val, p,
-                                   rnd_mode | BF_FTOA_FORMAT_FIXED);
-    JS_FreeValue(ctx, val);
-    return ret;
- fail:
-    JS_FreeValue(ctx, val);
-    return JS_EXCEPTION;
-}
-
-static const JSCFunctionListEntry js_bigdecimal_proto_funcs[] = {
-    JS_CFUNC_DEF("toString", 0, js_bigdecimal_toString ),
-    JS_CFUNC_DEF("valueOf", 0, js_bigdecimal_valueOf ),
-    JS_CFUNC_DEF("toPrecision", 1, js_bigdecimal_toPrecision ),
-    JS_CFUNC_DEF("toFixed", 1, js_bigdecimal_toFixed ),
-    JS_CFUNC_DEF("toExponential", 1, js_bigdecimal_toExponential ),
-};
-
-static const JSCFunctionListEntry js_bigdecimal_funcs[] = {
-    JS_CFUNC_MAGIC_DEF("add", 2, js_bigdecimal_fop, MATH_OP_ADD ),
-    JS_CFUNC_MAGIC_DEF("sub", 2, js_bigdecimal_fop, MATH_OP_SUB ),
-    JS_CFUNC_MAGIC_DEF("mul", 2, js_bigdecimal_fop, MATH_OP_MUL ),
-    JS_CFUNC_MAGIC_DEF("div", 2, js_bigdecimal_fop, MATH_OP_DIV ),
-    JS_CFUNC_MAGIC_DEF("mod", 2, js_bigdecimal_fop, MATH_OP_FMOD ),
-    JS_CFUNC_MAGIC_DEF("round", 1, js_bigdecimal_fop, MATH_OP_ROUND ),
-    JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigdecimal_fop, MATH_OP_SQRT ),
-};
-
-void JS_AddIntrinsicBigDecimal(JSContext *ctx)
-{
-    JSRuntime *rt = ctx->rt;
-    JSValueConst obj1;
-
-    rt->bigdecimal_ops.to_string = js_bigdecimal_to_string;
-    rt->bigdecimal_ops.from_string = js_string_to_bigdecimal;
-    rt->bigdecimal_ops.unary_arith = js_unary_arith_bigdecimal;
-    rt->bigdecimal_ops.binary_arith = js_binary_arith_bigdecimal;
-    rt->bigdecimal_ops.compare = js_compare_bigdecimal;
-
-    ctx->class_proto[JS_CLASS_BIG_DECIMAL] = JS_NewObject(ctx);
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL],
-                               js_bigdecimal_proto_funcs,
-                               countof(js_bigdecimal_proto_funcs));
-    obj1 = JS_NewGlobalCConstructor(ctx, "BigDecimal",
-                                    js_bigdecimal_constructor, 1,
-                                    ctx->class_proto[JS_CLASS_BIG_DECIMAL]);
-    JS_SetPropertyFunctionList(ctx, obj1, js_bigdecimal_funcs,
-                               countof(js_bigdecimal_funcs));
-}
-
-void JS_EnableBignumExt(JSContext *ctx, BOOL enable)
-{
-    ctx->bignum_ext = enable;
-}
-
-#endif /* CONFIG_BIGNUM */
-
-static const char * const native_error_name[JS_NATIVE_ERROR_COUNT] = {
-    "EvalError", "RangeError", "ReferenceError",
-    "SyntaxError", "TypeError", "URIError",
-    "InternalError", "AggregateError",
-};
-
-/* Minimum amount of objects to be able to compile code and display
-   error messages. No JSAtom should be allocated by this function. */
-static void JS_AddIntrinsicBasicObjects(JSContext *ctx)
-{
-    JSValue proto;
-    int i;
-
-    ctx->class_proto[JS_CLASS_OBJECT] = JS_NewObjectProto(ctx, JS_NULL);
-    ctx->function_proto = JS_NewCFunction3(ctx, js_function_proto, "", 0,
-                                           JS_CFUNC_generic, 0,
-                                           ctx->class_proto[JS_CLASS_OBJECT]);
-    ctx->class_proto[JS_CLASS_BYTECODE_FUNCTION] = JS_DupValue(ctx, ctx->function_proto);
-    ctx->class_proto[JS_CLASS_ERROR] = JS_NewObject(ctx);
-#if 0
-    /* these are auto-initialized from js_error_proto_funcs,
-       but delaying might be a problem */
-    JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ERROR], JS_ATOM_name,
-                           JS_AtomToString(ctx, JS_ATOM_Error),
-                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-    JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ERROR], JS_ATOM_message,
-                           JS_AtomToString(ctx, JS_ATOM_empty_string),
-                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-#endif
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ERROR],
-                               js_error_proto_funcs,
-                               countof(js_error_proto_funcs));
-
-    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
-        proto = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ERROR]);
-        JS_DefinePropertyValue(ctx, proto, JS_ATOM_name,
-                               JS_NewAtomString(ctx, native_error_name[i]),
-                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-        JS_DefinePropertyValue(ctx, proto, JS_ATOM_message,
-                               JS_AtomToString(ctx, JS_ATOM_empty_string),
-                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-        ctx->native_error_proto[i] = proto;
-    }
-
-    /* the array prototype is an array */
-    ctx->class_proto[JS_CLASS_ARRAY] =
-        JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
-                               JS_CLASS_ARRAY);
-
-    ctx->array_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_ARRAY]),
-                                     JS_PROP_INITIAL_HASH_SIZE, 1);
-    add_shape_property(ctx, &ctx->array_shape, NULL,
-                       JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_LENGTH);
-
-    /* XXX: could test it on first context creation to ensure that no
-       new atoms are created in JS_AddIntrinsicBasicObjects(). It is
-       necessary to avoid useless renumbering of atoms after
-       JS_EvalBinary() if it is done just after
-       JS_AddIntrinsicBasicObjects(). */
-    //    assert(ctx->rt->atom_count == JS_ATOM_END);
-}
-
-void JS_AddIntrinsicBaseObjects(JSContext *ctx)
-{
-    int i;
-    JSValueConst obj, number_obj;
-    JSValue obj1;
-
-    ctx->throw_type_error = JS_NewCFunction(ctx, js_throw_type_error, NULL, 0);
-
-    /* add caller and arguments properties to throw a TypeError */
-    obj1 = JS_NewCFunction(ctx, js_function_proto_caller, NULL, 0);
-    JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_caller, JS_UNDEFINED,
-                      obj1, ctx->throw_type_error,
-                      JS_PROP_HAS_GET | JS_PROP_HAS_SET |
-                      JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE);
-    JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_arguments, JS_UNDEFINED,
-                      obj1, ctx->throw_type_error,
-                      JS_PROP_HAS_GET | JS_PROP_HAS_SET |
-                      JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE);
-    JS_FreeValue(ctx, obj1);
-    JS_FreeValue(ctx, js_object_seal(ctx, JS_UNDEFINED, 1, (JSValueConst *)&ctx->throw_type_error, 1));
-
-    ctx->global_obj = JS_NewObject(ctx);
-    ctx->global_var_obj = JS_NewObjectProto(ctx, JS_NULL);
-
-    /* Object */
-    obj = JS_NewGlobalCConstructor(ctx, "Object", js_object_constructor, 1,
-                                   ctx->class_proto[JS_CLASS_OBJECT]);
-    JS_SetPropertyFunctionList(ctx, obj, js_object_funcs, countof(js_object_funcs));
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_OBJECT],
-                               js_object_proto_funcs, countof(js_object_proto_funcs));
-
-    /* Function */
-    JS_SetPropertyFunctionList(ctx, ctx->function_proto, js_function_proto_funcs, countof(js_function_proto_funcs));
-    ctx->function_ctor = JS_NewCFunctionMagic(ctx, js_function_constructor,
-                                              "Function", 1, JS_CFUNC_constructor_or_func_magic,
-                                              JS_FUNC_NORMAL);
-    JS_NewGlobalCConstructor2(ctx, JS_DupValue(ctx, ctx->function_ctor), "Function",
-                              ctx->function_proto);
-
-    /* Error */
-    obj1 = JS_NewCFunctionMagic(ctx, js_error_constructor,
-                                "Error", 1, JS_CFUNC_constructor_or_func_magic, -1);
-    JS_NewGlobalCConstructor2(ctx, obj1,
-                              "Error", ctx->class_proto[JS_CLASS_ERROR]);
-
-    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
-        JSValue func_obj;
-        int n_args;
-        n_args = 1 + (i == JS_AGGREGATE_ERROR);
-        func_obj = JS_NewCFunction3(ctx, (JSCFunction *)js_error_constructor,
-                                    native_error_name[i], n_args,
-                                    JS_CFUNC_constructor_or_func_magic, i, obj1);
-        JS_NewGlobalCConstructor2(ctx, func_obj, native_error_name[i],
-                                  ctx->native_error_proto[i]);
-    }
-
-    /* Iterator prototype */
-    ctx->iterator_proto = JS_NewObject(ctx);
-    JS_SetPropertyFunctionList(ctx, ctx->iterator_proto,
-                               js_iterator_proto_funcs,
-                               countof(js_iterator_proto_funcs));
-
-    /* Array */
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY],
-                               js_array_proto_funcs,
-                               countof(js_array_proto_funcs));
-
-    obj = JS_NewGlobalCConstructor(ctx, "Array", js_array_constructor, 1,
-                                   ctx->class_proto[JS_CLASS_ARRAY]);
-    ctx->array_ctor = JS_DupValue(ctx, obj);
-    JS_SetPropertyFunctionList(ctx, obj, js_array_funcs,
-                               countof(js_array_funcs));
-
-    /* XXX: create auto_initializer */
-    {
-        /* initialize Array.prototype[Symbol.unscopables] */
-        char const unscopables[] = "copyWithin" "\0" "entries" "\0" "fill" "\0" "find" "\0"
-            "findIndex" "\0" "flat" "\0" "flatMap" "\0" "includes" "\0" "keys" "\0" "values" "\0";
-        const char *p = unscopables;
-        obj1 = JS_NewObjectProto(ctx, JS_NULL);
-        for(p = unscopables; *p; p += strlen(p) + 1) {
-            JS_DefinePropertyValueStr(ctx, obj1, p, JS_TRUE, JS_PROP_C_W_E);
-        }
-        JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ARRAY],
-                               JS_ATOM_Symbol_unscopables, obj1,
-                               JS_PROP_CONFIGURABLE);
-    }
-
-    /* needed to initialize arguments[Symbol.iterator] */
-    ctx->array_proto_values =
-        JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_values);
-
-    ctx->class_proto[JS_CLASS_ARRAY_ITERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto);
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY_ITERATOR],
-                               js_array_iterator_proto_funcs,
-                               countof(js_array_iterator_proto_funcs));
-
-    /* parseFloat and parseInteger must be defined before Number
-       because of the Number.parseFloat and Number.parseInteger
-       aliases */
-    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_global_funcs,
-                               countof(js_global_funcs));
-
-    /* Number */
-    ctx->class_proto[JS_CLASS_NUMBER] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
-                                                               JS_CLASS_NUMBER);
-    JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_NUMBER], JS_NewInt32(ctx, 0));
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_NUMBER],
-                               js_number_proto_funcs,
-                               countof(js_number_proto_funcs));
-    number_obj = JS_NewGlobalCConstructor(ctx, "Number", js_number_constructor, 1,
-                                          ctx->class_proto[JS_CLASS_NUMBER]);
-    JS_SetPropertyFunctionList(ctx, number_obj, js_number_funcs, countof(js_number_funcs));
-
-    /* Boolean */
-    ctx->class_proto[JS_CLASS_BOOLEAN] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
-                                                                JS_CLASS_BOOLEAN);
-    JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], JS_NewBool(ctx, FALSE));
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], js_boolean_proto_funcs,
-                               countof(js_boolean_proto_funcs));
-    JS_NewGlobalCConstructor(ctx, "Boolean", js_boolean_constructor, 1,
-                             ctx->class_proto[JS_CLASS_BOOLEAN]);
-
-    /* String */
-    ctx->class_proto[JS_CLASS_STRING] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
-                                                               JS_CLASS_STRING);
-    JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_STRING], JS_AtomToString(ctx, JS_ATOM_empty_string));
-    obj = JS_NewGlobalCConstructor(ctx, "String", js_string_constructor, 1,
-                                   ctx->class_proto[JS_CLASS_STRING]);
-    JS_SetPropertyFunctionList(ctx, obj, js_string_funcs,
-                               countof(js_string_funcs));
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING], js_string_proto_funcs,
-                               countof(js_string_proto_funcs));
-
-    ctx->class_proto[JS_CLASS_STRING_ITERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto);
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING_ITERATOR],
-                               js_string_iterator_proto_funcs,
-                               countof(js_string_iterator_proto_funcs));
-
-    /* Math: create as autoinit object */
-    js_random_init(ctx);
-    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_math_obj, countof(js_math_obj));
-
-    /* ES6 Reflect: create as autoinit object */
-    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_reflect_obj, countof(js_reflect_obj));
-
-    /* ES6 Symbol */
-    ctx->class_proto[JS_CLASS_SYMBOL] = JS_NewObject(ctx);
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_SYMBOL], js_symbol_proto_funcs,
-                               countof(js_symbol_proto_funcs));
-    obj = JS_NewGlobalCConstructor(ctx, "Symbol", js_symbol_constructor, 0,
-                                   ctx->class_proto[JS_CLASS_SYMBOL]);
-    JS_SetPropertyFunctionList(ctx, obj, js_symbol_funcs,
-                               countof(js_symbol_funcs));
-    for(i = JS_ATOM_Symbol_toPrimitive; i < JS_ATOM_END; i++) {
-        char buf[ATOM_GET_STR_BUF_SIZE];
-        const char *str, *p;
-        str = JS_AtomGetStr(ctx, buf, sizeof(buf), i);
-        /* skip "Symbol." */
-        p = strchr(str, '.');
-        if (p)
-            str = p + 1;
-        JS_DefinePropertyValueStr(ctx, obj, str, JS_AtomToValue(ctx, i), 0);
-    }
-
-    /* ES6 Generator */
-    ctx->class_proto[JS_CLASS_GENERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto);
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_GENERATOR],
-                               js_generator_proto_funcs,
-                               countof(js_generator_proto_funcs));
-
-    ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION] = JS_NewObjectProto(ctx, ctx->function_proto);
-    obj1 = JS_NewCFunctionMagic(ctx, js_function_constructor,
-                                "GeneratorFunction", 1,
-                                JS_CFUNC_constructor_or_func_magic, JS_FUNC_GENERATOR);
-    JS_SetPropertyFunctionList(ctx,
-                               ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
-                               js_generator_function_proto_funcs,
-                               countof(js_generator_function_proto_funcs));
-    JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
-                       ctx->class_proto[JS_CLASS_GENERATOR],
-                       JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE);
-    JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
-                       0, JS_PROP_CONFIGURABLE);
-    JS_FreeValue(ctx, obj1);
-
-    /* global properties */
-    ctx->eval_obj = JS_NewCFunction(ctx, js_global_eval, "eval", 1);
-    JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_eval,
-                           JS_DupValue(ctx, ctx->eval_obj),
-                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-
-    JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_globalThis,
-                           JS_DupValue(ctx, ctx->global_obj),
-                           JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
-}
-
-/* Typed Arrays */
-
-static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT] = {
-    0, 0, 0, 1, 1, 2, 2,
-#ifdef CONFIG_BIGNUM
-    3, 3, /* BigInt64Array, BigUint64Array */
-#endif
-    2, 3
-};
-
-static JSValue js_array_buffer_constructor3(JSContext *ctx,
-                                            JSValueConst new_target,
-                                            uint64_t len, JSClassID class_id,
-                                            uint8_t *buf,
-                                            JSFreeArrayBufferDataFunc *free_func,
-                                            void *opaque, BOOL alloc_flag)
-{
-    JSRuntime *rt = ctx->rt;
-    JSValue obj;
-    JSArrayBuffer *abuf = NULL;
-
-    obj = js_create_from_ctor(ctx, new_target, class_id);
-    if (JS_IsException(obj))
-        return obj;
-    /* XXX: we are currently limited to 2 GB */
-    if (len > INT32_MAX) {
-        JS_ThrowRangeError(ctx, "invalid array buffer length");
-        goto fail;
-    }
-    abuf = js_malloc(ctx, sizeof(*abuf));
-    if (!abuf)
-        goto fail;
-    abuf->byte_length = len;
-    if (alloc_flag) {
-        if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER &&
-            rt->sab_funcs.sab_alloc) {
-            abuf->data = rt->sab_funcs.sab_alloc(rt->sab_funcs.sab_opaque,
-                                                 max_int(len, 1));
-            if (!abuf->data)
-                goto fail;
-            memset(abuf->data, 0, len);
-        } else {
-            /* the allocation must be done after the object creation */
-            abuf->data = js_mallocz(ctx, max_int(len, 1));
-            if (!abuf->data)
-                goto fail;
-        }
-    } else {
-        if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER &&
-            rt->sab_funcs.sab_dup) {
-            rt->sab_funcs.sab_dup(rt->sab_funcs.sab_opaque, buf);
-        }
-        abuf->data = buf;
-    }
-    init_list_head(&abuf->array_list);
-    abuf->detached = FALSE;
-    abuf->shared = (class_id == JS_CLASS_SHARED_ARRAY_BUFFER);
-    abuf->opaque = opaque;
-    abuf->free_func = free_func;
-    if (alloc_flag && buf)
-        memcpy(abuf->data, buf, len);
-    JS_SetOpaque(obj, abuf);
-    return obj;
- fail:
-    JS_FreeValue(ctx, obj);
-    js_free(ctx, abuf);
-    return JS_EXCEPTION;
-}
-
-static void js_array_buffer_free(JSRuntime *rt, void *opaque, void *ptr)
-{
-    js_free_rt(rt, ptr);
-}
-
-static JSValue js_array_buffer_constructor2(JSContext *ctx,
-                                            JSValueConst new_target,
-                                            uint64_t len, JSClassID class_id)
-{
-    return js_array_buffer_constructor3(ctx, new_target, len, class_id,
-                                        NULL, js_array_buffer_free, NULL,
-                                        TRUE);
-}
-
-static JSValue js_array_buffer_constructor1(JSContext *ctx,
-                                            JSValueConst new_target,
-                                            uint64_t len)
-{
-    return js_array_buffer_constructor2(ctx, new_target, len,
-                                        JS_CLASS_ARRAY_BUFFER);
-}
-
-JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len,
-                          JSFreeArrayBufferDataFunc *free_func, void *opaque,
-                          BOOL is_shared)
-{
-    return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len,
-                                        is_shared ? JS_CLASS_SHARED_ARRAY_BUFFER : JS_CLASS_ARRAY_BUFFER,
-                                        buf, free_func, opaque, FALSE);
-}
-
-/* create a new ArrayBuffer of length 'len' and copy 'buf' to it */
-JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len)
-{
-    return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len,
-                                        JS_CLASS_ARRAY_BUFFER,
-                                        (uint8_t *)buf,
-                                        js_array_buffer_free, NULL,
-                                        TRUE);
-}
-
-static JSValue js_array_buffer_constructor(JSContext *ctx,
-                                           JSValueConst new_target,
-                                           int argc, JSValueConst *argv)
-{
-    uint64_t len;
-    if (JS_ToIndex(ctx, &len, argv[0]))
-        return JS_EXCEPTION;
-    return js_array_buffer_constructor1(ctx, new_target, len);
-}
-
-static JSValue js_shared_array_buffer_constructor(JSContext *ctx,
-                                                  JSValueConst new_target,
-                                                  int argc, JSValueConst *argv)
-{
-    uint64_t len;
-    if (JS_ToIndex(ctx, &len, argv[0]))
-        return JS_EXCEPTION;
-    return js_array_buffer_constructor2(ctx, new_target, len,
-                                        JS_CLASS_SHARED_ARRAY_BUFFER);
-}
-
-/* also used for SharedArrayBuffer */
-static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    JSArrayBuffer *abuf = p->u.array_buffer;
-    if (abuf) {
-        /* The ArrayBuffer finalizer may be called before the typed
-           array finalizers using it, so abuf->array_list is not
-           necessarily empty. */
-        // assert(list_empty(&abuf->array_list));
-        if (abuf->shared && rt->sab_funcs.sab_free) {
-            rt->sab_funcs.sab_free(rt->sab_funcs.sab_opaque, abuf->data);
-        } else {
-            if (abuf->free_func)
-                abuf->free_func(rt, abuf->opaque, abuf->data);
-        }
-        js_free_rt(rt, abuf);
-    }
-}
-
-static JSValue js_array_buffer_isView(JSContext *ctx,
-                                      JSValueConst this_val,
-                                      int argc, JSValueConst *argv)
-{
-    JSObject *p;
-    BOOL res;
-    res = FALSE;
-    if (JS_VALUE_GET_TAG(argv[0]) == JS_TAG_OBJECT) {
-        p = JS_VALUE_GET_OBJ(argv[0]);
-        if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
-            p->class_id <= JS_CLASS_DATAVIEW) {
-            res = TRUE;
-        }
-    }
-    return JS_NewBool(ctx, res);
-}
-
-static const JSCFunctionListEntry js_array_buffer_funcs[] = {
-    JS_CFUNC_DEF("isView", 1, js_array_buffer_isView ),
-    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
-};
-
-static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx)
-{
-    return JS_ThrowTypeError(ctx, "ArrayBuffer is detached");
-}
-
-static JSValue js_array_buffer_get_byteLength(JSContext *ctx,
-                                              JSValueConst this_val,
-                                              int class_id)
-{
-    JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, class_id);
-    if (!abuf)
-        return JS_EXCEPTION;
-    /* return 0 if detached */
-    return JS_NewUint32(ctx, abuf->byte_length);
-}
-
-void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj)
-{
-    JSArrayBuffer *abuf = JS_GetOpaque(obj, JS_CLASS_ARRAY_BUFFER);
-    struct list_head *el;
-
-    if (!abuf || abuf->detached)
-        return;
-    if (abuf->free_func)
-        abuf->free_func(ctx->rt, abuf->opaque, abuf->data);
-    abuf->data = NULL;
-    abuf->byte_length = 0;
-    abuf->detached = TRUE;
-
-    list_for_each(el, &abuf->array_list) {
-        JSTypedArray *ta;
-        JSObject *p;
-
-        ta = list_entry(el, JSTypedArray, link);
-        p = ta->obj;
-        /* Note: the typed array length and offset fields are not modified */
-        if (p->class_id != JS_CLASS_DATAVIEW) {
-            p->u.array.count = 0;
-            p->u.array.u.ptr = NULL;
-        }
-    }
-}
-
-/* get an ArrayBuffer or SharedArrayBuffer */
-static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj)
-{
-    JSObject *p;
-    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
-        goto fail;
-    p = JS_VALUE_GET_OBJ(obj);
-    if (p->class_id != JS_CLASS_ARRAY_BUFFER &&
-        p->class_id != JS_CLASS_SHARED_ARRAY_BUFFER) {
-    fail:
-        JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_ARRAY_BUFFER);
-        return NULL;
-    }
-    return p->u.array_buffer;
-}
-
-/* return NULL if exception. WARNING: any JS call can detach the
-   buffer and render the returned pointer invalid */
-uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj)
-{
-    JSArrayBuffer *abuf = js_get_array_buffer(ctx, obj);
-    if (!abuf)
-        goto fail;
-    if (abuf->detached) {
-        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-        goto fail;
-    }
-    *psize = abuf->byte_length;
-    return abuf->data;
- fail:
-    *psize = 0;
-    return NULL;
-}
-
-static JSValue js_array_buffer_slice(JSContext *ctx,
-                                     JSValueConst this_val,
-                                     int argc, JSValueConst *argv, int class_id)
-{
-    JSArrayBuffer *abuf, *new_abuf;
-    int64_t len, start, end, new_len;
-    JSValue ctor, new_obj;
-
-    abuf = JS_GetOpaque2(ctx, this_val, class_id);
-    if (!abuf)
-        return JS_EXCEPTION;
-    if (abuf->detached)
-        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-    len = abuf->byte_length;
-
-    if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
-        return JS_EXCEPTION;
-
-    end = len;
-    if (!JS_IsUndefined(argv[1])) {
-        if (JS_ToInt64Clamp(ctx, &end, argv[1], 0, len, len))
-            return JS_EXCEPTION;
-    }
-    new_len = max_int64(end - start, 0);
-    ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
-    if (JS_IsException(ctor))
-        return ctor;
-    if (JS_IsUndefined(ctor)) {
-        new_obj = js_array_buffer_constructor2(ctx, JS_UNDEFINED, new_len,
-                                               class_id);
-    } else {
-        JSValue args[1];
-        args[0] = JS_NewInt64(ctx, new_len);
-        new_obj = JS_CallConstructor(ctx, ctor, 1, (JSValueConst *)args);
-        JS_FreeValue(ctx, ctor);
-        JS_FreeValue(ctx, args[0]);
-    }
-    if (JS_IsException(new_obj))
-        return new_obj;
-    new_abuf = JS_GetOpaque2(ctx, new_obj, class_id);
-    if (!new_abuf)
-        goto fail;
-    if (js_same_value(ctx, new_obj, this_val)) {
-        JS_ThrowTypeError(ctx, "cannot use identical ArrayBuffer");
-        goto fail;
-    }
-    if (new_abuf->detached) {
-        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-        goto fail;
-    }
-    if (new_abuf->byte_length < new_len) {
-        JS_ThrowTypeError(ctx, "new ArrayBuffer is too small");
-        goto fail;
-    }
-    /* must test again because of side effects */
-    if (abuf->detached) {
-        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-        goto fail;
-    }
-    memcpy(new_abuf->data, abuf->data + start, new_len);
-    return new_obj;
- fail:
-    JS_FreeValue(ctx, new_obj);
-    return JS_EXCEPTION;
-}
-
-static const JSCFunctionListEntry js_array_buffer_proto_funcs[] = {
-    JS_CGETSET_MAGIC_DEF("byteLength", js_array_buffer_get_byteLength, NULL, JS_CLASS_ARRAY_BUFFER ),
-    JS_CFUNC_MAGIC_DEF("slice", 2, js_array_buffer_slice, JS_CLASS_ARRAY_BUFFER ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "ArrayBuffer", JS_PROP_CONFIGURABLE ),
-};
-
-/* SharedArrayBuffer */
-
-static const JSCFunctionListEntry js_shared_array_buffer_funcs[] = {
-    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
-};
-
-static const JSCFunctionListEntry js_shared_array_buffer_proto_funcs[] = {
-    JS_CGETSET_MAGIC_DEF("byteLength", js_array_buffer_get_byteLength, NULL, JS_CLASS_SHARED_ARRAY_BUFFER ),
-    JS_CFUNC_MAGIC_DEF("slice", 2, js_array_buffer_slice, JS_CLASS_SHARED_ARRAY_BUFFER ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "SharedArrayBuffer", JS_PROP_CONFIGURABLE ),
-};
-
-static JSObject *get_typed_array(JSContext *ctx,
-                                 JSValueConst this_val,
-                                 int is_dataview)
-{
-    JSObject *p;
-    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
-        goto fail;
-    p = JS_VALUE_GET_OBJ(this_val);
-    if (is_dataview) {
-        if (p->class_id != JS_CLASS_DATAVIEW)
-            goto fail;
-    } else {
-        if (!(p->class_id >= JS_CLASS_UINT8C_ARRAY &&
-              p->class_id <= JS_CLASS_FLOAT64_ARRAY)) {
-        fail:
-            JS_ThrowTypeError(ctx, "not a %s", is_dataview ? "DataView" : "TypedArray");
-            return NULL;
-        }
-    }
-    return p;
-}
-
-/* WARNING: 'p' must be a typed array */
-static BOOL typed_array_is_detached(JSContext *ctx, JSObject *p)
-{
-    JSTypedArray *ta = p->u.typed_array;
-    JSArrayBuffer *abuf = ta->buffer->u.array_buffer;
-    /* XXX: could simplify test by ensuring that
-       p->u.array.u.ptr is NULL iff it is detached */
-    return abuf->detached;
-}
-
-/* WARNING: 'p' must be a typed array. Works even if the array buffer
-   is detached */
-static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p)
-{
-    JSTypedArray *ta = p->u.typed_array;
-    int size_log2 = typed_array_size_log2(p->class_id);
-    return ta->length >> size_log2;
-}
-
-static int validate_typed_array(JSContext *ctx, JSValueConst this_val)
-{
-    JSObject *p;
-    p = get_typed_array(ctx, this_val, 0);
-    if (!p)
-        return -1;
-    if (typed_array_is_detached(ctx, p)) {
-        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-        return -1;
-    }
-    return 0;
-}
-
-static JSValue js_typed_array_get_length(JSContext *ctx,
-                                         JSValueConst this_val)
-{
-    JSObject *p;
-    p = get_typed_array(ctx, this_val, 0);
-    if (!p)
-        return JS_EXCEPTION;
-    return JS_NewInt32(ctx, p->u.array.count);
-}
-
-static JSValue js_typed_array_get_buffer(JSContext *ctx,
-                                         JSValueConst this_val, int is_dataview)
-{
-    JSObject *p;
-    JSTypedArray *ta;
-    p = get_typed_array(ctx, this_val, is_dataview);
-    if (!p)
-        return JS_EXCEPTION;
-    ta = p->u.typed_array;
-    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
-}
-
-static JSValue js_typed_array_get_byteLength(JSContext *ctx,
-                                             JSValueConst this_val,
-                                             int is_dataview)
-{
-    JSObject *p;
-    JSTypedArray *ta;
-    p = get_typed_array(ctx, this_val, is_dataview);
-    if (!p)
-        return JS_EXCEPTION;
-    if (typed_array_is_detached(ctx, p)) {
-        if (is_dataview) {
-            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-        } else {
-            return JS_NewInt32(ctx, 0);
-        }
-    }
-    ta = p->u.typed_array;
-    return JS_NewInt32(ctx, ta->length);
-}
-
-static JSValue js_typed_array_get_byteOffset(JSContext *ctx,
-                                             JSValueConst this_val,
-                                             int is_dataview)
-{
-    JSObject *p;
-    JSTypedArray *ta;
-    p = get_typed_array(ctx, this_val, is_dataview);
-    if (!p)
-        return JS_EXCEPTION;
-    if (typed_array_is_detached(ctx, p)) {
-        if (is_dataview) {
-            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-        } else {
-            return JS_NewInt32(ctx, 0);
-        }
-    }
-    ta = p->u.typed_array;
-    return JS_NewInt32(ctx, ta->offset);
-}
-
-/* Return the buffer associated to the typed array or an exception if
-   it is not a typed array or if the buffer is detached. pbyte_offset,
-   pbyte_length or pbytes_per_element can be NULL. */
-JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj,
-                               size_t *pbyte_offset,
-                               size_t *pbyte_length,
-                               size_t *pbytes_per_element)
-{
-    JSObject *p;
-    JSTypedArray *ta;
-    p = get_typed_array(ctx, obj, FALSE);
-    if (!p)
-        return JS_EXCEPTION;
-    if (typed_array_is_detached(ctx, p))
-        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-    ta = p->u.typed_array;
-    if (pbyte_offset)
-        *pbyte_offset = ta->offset;
-    if (pbyte_length)
-        *pbyte_length = ta->length;
-    if (pbytes_per_element) {
-        *pbytes_per_element = 1 << typed_array_size_log2(p->class_id);
-    }
-    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
-}
-                               
-static JSValue js_typed_array_get_toStringTag(JSContext *ctx,
-                                              JSValueConst this_val)
-{
-    JSObject *p;
-    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
-        return JS_UNDEFINED;
-    p = JS_VALUE_GET_OBJ(this_val);
-    if (!(p->class_id >= JS_CLASS_UINT8C_ARRAY &&
-          p->class_id <= JS_CLASS_FLOAT64_ARRAY))
-        return JS_UNDEFINED;
-    return JS_AtomToString(ctx, ctx->rt->class_array[p->class_id].class_name);
-}
-
-static JSValue js_typed_array_set_internal(JSContext *ctx,
-                                           JSValueConst dst,
-                                           JSValueConst src,
-                                           JSValueConst off)
-{
-    JSObject *p;
-    JSObject *src_p;
-    uint32_t i;
-    int64_t src_len, offset;
-    JSValue val, src_obj = JS_UNDEFINED;
-
-    p = get_typed_array(ctx, dst, 0);
-    if (!p)
-        goto fail;
-    if (JS_ToInt64Sat(ctx, &offset, off))
-        goto fail;
-    if (offset < 0)
-        goto range_error;
-    if (typed_array_is_detached(ctx, p)) {
-    detached:
-        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-        goto fail;
-    }
-    src_obj = JS_ToObject(ctx, src);
-    if (JS_IsException(src_obj))
-        goto fail;
-    src_p = JS_VALUE_GET_OBJ(src_obj);
-    if (src_p->class_id >= JS_CLASS_UINT8C_ARRAY &&
-        src_p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
-        JSTypedArray *dest_ta = p->u.typed_array;
-        JSArrayBuffer *dest_abuf = dest_ta->buffer->u.array_buffer;
-        JSTypedArray *src_ta = src_p->u.typed_array;
-        JSArrayBuffer *src_abuf = src_ta->buffer->u.array_buffer;
-        int shift = typed_array_size_log2(p->class_id);
-
-        if (src_abuf->detached)
-            goto detached;
-
-        src_len = src_p->u.array.count;
-        if (offset > (int64_t)(p->u.array.count - src_len))
-            goto range_error;
-
-        /* copying between typed objects */
-        if (src_p->class_id == p->class_id) {
-            /* same type, use memmove */
-            memmove(dest_abuf->data + dest_ta->offset + (offset << shift),
-                    src_abuf->data + src_ta->offset, src_len << shift);
-            goto done;
-        }
-        if (dest_abuf->data == src_abuf->data) {
-            /* copying between the same buffer using different types of mappings
-               would require a temporary buffer */
-        }
-        /* otherwise, default behavior is slow but correct */
-    } else {
-        if (js_get_length64(ctx, &src_len, src_obj))
-            goto fail;
-        if (offset > (int64_t)(p->u.array.count - src_len)) {
-        range_error:
-            JS_ThrowRangeError(ctx, "invalid array length");
-            goto fail;
-        }
-    }
-    for(i = 0; i < src_len; i++) {
-        val = JS_GetPropertyUint32(ctx, src_obj, i);
-        if (JS_IsException(val))
-            goto fail;
-        if (JS_SetPropertyUint32(ctx, dst, offset + i, val) < 0)
-            goto fail;
-    }
-done:
-    JS_FreeValue(ctx, src_obj);
-    return JS_UNDEFINED;
-fail:
-    JS_FreeValue(ctx, src_obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_typed_array_set(JSContext *ctx,
-                                  JSValueConst this_val,
-                                  int argc, JSValueConst *argv)
-{
-    JSValueConst offset = JS_UNDEFINED;
-    if (argc > 1) {
-        offset = argv[1];
-    }
-    return js_typed_array_set_internal(ctx, this_val, argv[0], offset);
-}
-
-static JSValue js_create_typed_array_iterator(JSContext *ctx, JSValueConst this_val,
-                                              int argc, JSValueConst *argv, int magic)
-{
-    if (validate_typed_array(ctx, this_val))
-        return JS_EXCEPTION;
-    return js_create_array_iterator(ctx, this_val, argc, argv, magic);
-}
-
-/* return < 0 if exception */
-static int js_typed_array_get_length_internal(JSContext *ctx,
-                                              JSValueConst obj)
-{
-    JSObject *p;
-    p = get_typed_array(ctx, obj, 0);
-    if (!p)
-        return -1;
-    if (typed_array_is_detached(ctx, p)) {
-        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-        return -1;
-    }
-    return p->u.array.count;
-}
-
-#if 0
-/* validate a typed array and return its length */
-static JSValue js_typed_array___getLength(JSContext *ctx,
-                                          JSValueConst this_val,
-                                          int argc, JSValueConst *argv)
-{
-    BOOL ignore_detached = JS_ToBool(ctx, argv[1]);
-
-    if (ignore_detached) {
-        return js_typed_array_get_length(ctx, argv[0]);
-    } else {
-        int len;
-        len = js_typed_array_get_length_internal(ctx, argv[0]);
-        if (len < 0)
-            return JS_EXCEPTION;
-        return JS_NewInt32(ctx, len);
-    }
-}
-#endif
-
-static JSValue js_typed_array_create(JSContext *ctx, JSValueConst ctor,
-                                     int argc, JSValueConst *argv)
-{
-    JSValue ret;
-    int new_len;
-    int64_t len;
-
-    ret = JS_CallConstructor(ctx, ctor, argc, argv);
-    if (JS_IsException(ret))
-        return ret;
-    /* validate the typed array */
-    new_len = js_typed_array_get_length_internal(ctx, ret);
-    if (new_len < 0)
-        goto fail;
-    if (argc == 1) {
-        /* ensure that it is large enough */
-        if (JS_ToLengthFree(ctx, &len, JS_DupValue(ctx, argv[0])))
-            goto fail;
-        if (new_len < len) {
-            JS_ThrowTypeError(ctx, "TypedArray length is too small");
-        fail:
-            JS_FreeValue(ctx, ret);
-            return JS_EXCEPTION;
-        }
-    }
-    return ret;
-}
-
-#if 0
-static JSValue js_typed_array___create(JSContext *ctx,
-                                       JSValueConst this_val,
-                                       int argc, JSValueConst *argv)
-{
-    return js_typed_array_create(ctx, argv[0], max_int(argc - 1, 0), argv + 1);
-}
-#endif
-
-static JSValue js_typed_array___speciesCreate(JSContext *ctx,
-                                              JSValueConst this_val,
-                                              int argc, JSValueConst *argv)
-{
-    JSValueConst obj;
-    JSObject *p;
-    JSValue ctor, ret;
-    int argc1;
-
-    obj = argv[0];
-    p = get_typed_array(ctx, obj, 0);
-    if (!p)
-        return JS_EXCEPTION;
-    ctor = JS_SpeciesConstructor(ctx, obj, JS_UNDEFINED);
-    if (JS_IsException(ctor))
-        return ctor;
-    argc1 = max_int(argc - 1, 0);
-    if (JS_IsUndefined(ctor)) {
-        ret = js_typed_array_constructor(ctx, JS_UNDEFINED, argc1, argv + 1,
-                                         p->class_id);
-    } else {
-        ret = js_typed_array_create(ctx, ctor, argc1, argv + 1);
-        JS_FreeValue(ctx, ctor);
-    }
-    return ret;
-}
-
-static JSValue js_typed_array_from(JSContext *ctx, JSValueConst this_val,
-                                   int argc, JSValueConst *argv)
-{
-    // from(items, mapfn = void 0, this_arg = void 0)
-    JSValueConst items = argv[0], mapfn, this_arg;
-    JSValueConst args[2];
-    JSValue stack[2];
-    JSValue iter, arr, r, v, v2;
-    int64_t k, len;
-    int done, mapping;
-
-    mapping = FALSE;
-    mapfn = JS_UNDEFINED;
-    this_arg = JS_UNDEFINED;
-    r = JS_UNDEFINED;
-    arr = JS_UNDEFINED;
-    stack[0] = JS_UNDEFINED;
-    stack[1] = JS_UNDEFINED;
-
-    if (argc > 1) {
-        mapfn = argv[1];
-        if (!JS_IsUndefined(mapfn)) {
-            if (check_function(ctx, mapfn))
-                goto exception;
-            mapping = 1;
-            if (argc > 2)
-                this_arg = argv[2];
-        }
-    }
-    iter = JS_GetProperty(ctx, items, JS_ATOM_Symbol_iterator);
-    if (JS_IsException(iter))
-        goto exception;
-    if (!JS_IsUndefined(iter)) {
-        JS_FreeValue(ctx, iter);
-        arr = JS_NewArray(ctx);
-        if (JS_IsException(arr))
-            goto exception;
-        stack[0] = JS_DupValue(ctx, items);
-        if (js_for_of_start(ctx, &stack[1], FALSE))
-            goto exception;
-        for (k = 0;; k++) {
-            v = JS_IteratorNext(ctx, stack[0], stack[1], 0, NULL, &done);
-            if (JS_IsException(v))
-                goto exception_close;
-            if (done)
-                break;
-            if (JS_DefinePropertyValueInt64(ctx, arr, k, v, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
-                goto exception_close;
-        }
-    } else {
-        arr = JS_ToObject(ctx, items);
-        if (JS_IsException(arr))
-            goto exception;
-    }
-    if (js_get_length64(ctx, &len, arr) < 0)
-        goto exception;
-    v = JS_NewInt64(ctx, len);
-    args[0] = v;
-    r = js_typed_array_create(ctx, this_val, 1, args);
-    JS_FreeValue(ctx, v);
-    if (JS_IsException(r))
-        goto exception;
-    for(k = 0; k < len; k++) {
-        v = JS_GetPropertyInt64(ctx, arr, k);
-        if (JS_IsException(v))
-            goto exception;
-        if (mapping) {
-            args[0] = v;
-            args[1] = JS_NewInt32(ctx, k);
-            v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
-            JS_FreeValue(ctx, v);
-            v = v2;
-            if (JS_IsException(v))
-                goto exception;
-        }
-        if (JS_SetPropertyInt64(ctx, r, k, v) < 0)
-            goto exception;
-    }
-    goto done;
-
- exception_close:
-    if (!JS_IsUndefined(stack[0]))
-        JS_IteratorClose(ctx, stack[0], TRUE);
- exception:
-    JS_FreeValue(ctx, r);
-    r = JS_EXCEPTION;
- done:
-    JS_FreeValue(ctx, arr);
-    JS_FreeValue(ctx, stack[0]);
-    JS_FreeValue(ctx, stack[1]);
-    return r;
-}
-
-static JSValue js_typed_array_of(JSContext *ctx, JSValueConst this_val,
-                                 int argc, JSValueConst *argv)
-{
-    JSValue obj;
-    JSValueConst args[1];
-    int i;
-
-    args[0] = JS_NewInt32(ctx, argc);
-    obj = js_typed_array_create(ctx, this_val, 1, args);
-    if (JS_IsException(obj))
-        return obj;
-
-    for(i = 0; i < argc; i++) {
-        if (JS_SetPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i])) < 0) {
-            JS_FreeValue(ctx, obj);
-            return JS_EXCEPTION;
-        }
-    }
-    return obj;
-}
-
-static JSValue js_typed_array_copyWithin(JSContext *ctx, JSValueConst this_val,
-                                         int argc, JSValueConst *argv)
-{
-    JSObject *p;
-    int len, to, from, final, count, shift;
-
-    len = js_typed_array_get_length_internal(ctx, this_val);
-    if (len < 0)
-        return JS_EXCEPTION;
-
-    if (JS_ToInt32Clamp(ctx, &to, argv[0], 0, len, len))
-        return JS_EXCEPTION;
-
-    if (JS_ToInt32Clamp(ctx, &from, argv[1], 0, len, len))
-        return JS_EXCEPTION;
-
-    final = len;
-    if (argc > 2 && !JS_IsUndefined(argv[2])) {
-        if (JS_ToInt32Clamp(ctx, &final, argv[2], 0, len, len))
-            return JS_EXCEPTION;
-    }
-
-    count = min_int(final - from, len - to);
-    if (count > 0) {
-        p = JS_VALUE_GET_OBJ(this_val);
-        if (typed_array_is_detached(ctx, p))
-            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-        shift = typed_array_size_log2(p->class_id);
-        memmove(p->u.array.u.uint8_ptr + (to << shift),
-                p->u.array.u.uint8_ptr + (from << shift),
-                count << shift);
-    }
-    return JS_DupValue(ctx, this_val);
-}
-
-static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val,
-                                   int argc, JSValueConst *argv)
-{
-    JSObject *p;
-    int len, k, final, shift;
-    uint64_t v64;
-
-    len = js_typed_array_get_length_internal(ctx, this_val);
-    if (len < 0)
-        return JS_EXCEPTION;
-    p = JS_VALUE_GET_OBJ(this_val);
-
-    if (p->class_id == JS_CLASS_UINT8C_ARRAY) {
-        int32_t v;
-        if (JS_ToUint8ClampFree(ctx, &v, JS_DupValue(ctx, argv[0])))
-            return JS_EXCEPTION;
-        v64 = v;
-    } else if (p->class_id <= JS_CLASS_UINT32_ARRAY) {
-        uint32_t v;
-        if (JS_ToUint32(ctx, &v, argv[0]))
-            return JS_EXCEPTION;
-        v64 = v;
-    } else
-#ifdef CONFIG_BIGNUM
-    if (p->class_id <= JS_CLASS_BIG_UINT64_ARRAY) {
-        if (JS_ToBigInt64(ctx, (int64_t *)&v64, argv[0]))
-            return JS_EXCEPTION;
-    } else
-#endif
-    {
-        double d;
-        if (JS_ToFloat64(ctx, &d, argv[0]))
-            return JS_EXCEPTION;
-        if (p->class_id == JS_CLASS_FLOAT32_ARRAY) {
-            union {
-                float f;
-                uint32_t u32;
-            } u;
-            u.f = d;
-            v64 = u.u32;
-        } else {
-            JSFloat64Union u;
-            u.d = d;
-            v64 = u.u64;
-        }
-    }
-
-    k = 0;
-    if (argc > 1) {
-        if (JS_ToInt32Clamp(ctx, &k, argv[1], 0, len, len))
-            return JS_EXCEPTION;
-    }
-
-    final = len;
-    if (argc > 2 && !JS_IsUndefined(argv[2])) {
-        if (JS_ToInt32Clamp(ctx, &final, argv[2], 0, len, len))
-            return JS_EXCEPTION;
-    }
-
-    if (typed_array_is_detached(ctx, p))
-        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-    
-    shift = typed_array_size_log2(p->class_id);
-    switch(shift) {
-    case 0:
-        if (k < final) {
-            memset(p->u.array.u.uint8_ptr + k, v64, final - k);
-        }
-        break;
-    case 1:
-        for(; k < final; k++) {
-            p->u.array.u.uint16_ptr[k] = v64;
-        }
-        break;
-    case 2:
-        for(; k < final; k++) {
-            p->u.array.u.uint32_ptr[k] = v64;
-        }
-        break;
-    case 3:
-        for(; k < final; k++) {
-            p->u.array.u.uint64_ptr[k] = v64;
-        }
-        break;
-    default:
-        abort();
-    }
-    return JS_DupValue(ctx, this_val);
-}
-
-static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val,
-                                   int argc, JSValueConst *argv, int findIndex)
-{
-    JSValueConst func, this_arg;
-    JSValueConst args[3];
-    JSValue val, index_val, res;
-    int len, k;
-
-    val = JS_UNDEFINED;
-    len = js_typed_array_get_length_internal(ctx, this_val);
-    if (len < 0)
-        goto exception;
-
-    func = argv[0];
-    if (check_function(ctx, func))
-        goto exception;
-
-    this_arg = JS_UNDEFINED;
-    if (argc > 1)
-        this_arg = argv[1];
-
-    for(k = 0; k < len; k++) {
-        index_val = JS_NewInt32(ctx, k);
-        val = JS_GetPropertyValue(ctx, this_val, index_val);
-        if (JS_IsException(val))
-            goto exception;
-        args[0] = val;
-        args[1] = index_val;
-        args[2] = this_val;
-        res = JS_Call(ctx, func, this_arg, 3, args);
-        if (JS_IsException(res))
-            goto exception;
-        if (JS_ToBoolFree(ctx, res)) {
-            if (findIndex) {
-                JS_FreeValue(ctx, val);
-                return index_val;
-            } else {
-                return val;
-            }
-        }
-        JS_FreeValue(ctx, val);
-    }
-    if (findIndex)
-        return JS_NewInt32(ctx, -1);
-    else
-        return JS_UNDEFINED;
-
-exception:
-    JS_FreeValue(ctx, val);
-    return JS_EXCEPTION;
-}
-
-#define special_indexOf 0
-#define special_lastIndexOf 1
-#define special_includes -1
-
-static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
-                                      int argc, JSValueConst *argv, int special)
-{
-    JSObject *p;
-    int len, tag, is_int, is_bigint, k, stop, inc, res = -1;
-    int64_t v64;
-    double d;
-    float f;
-
-    len = js_typed_array_get_length_internal(ctx, this_val);
-    if (len < 0)
-        goto exception;
-    if (len == 0)
-        goto done;
-
-    if (special == special_lastIndexOf) {
-        k = len - 1;
-        if (argc > 1) {
-            if (JS_ToFloat64(ctx, &d, argv[1]))
-                goto exception;
-            if (isnan(d)) {
-                k = 0;
-            } else {
-                if (d >= 0) {
-                    if (d < k) {
-                        k = d;
-                    }
-                } else {
-                    d += len;
-                    if (d < 0)
-                        goto done;
-                    k = d;
-                }
-            }
-        }
-        stop = -1;
-        inc = -1;
-    } else {
-        k = 0;
-        if (argc > 1) {
-            if (JS_ToInt32Clamp(ctx, &k, argv[1], 0, len, len))
-                goto exception;
-        }
-        stop = len;
-        inc = 1;
-    }
-
-    p = JS_VALUE_GET_OBJ(this_val);
-    /* if the array was detached, no need to go further (but no
-       exception is raised) */
-    if (typed_array_is_detached(ctx, p)) {
-        /* "includes" scans all the properties, so "undefined" can match */
-        if (special == special_includes && JS_IsUndefined(argv[0]) && len > 0)
-            res = 0;
-        goto done;
-    }
-    
-    is_bigint = 0;
-    is_int = 0; /* avoid warning */
-    v64 = 0; /* avoid warning */
-    tag = JS_VALUE_GET_NORM_TAG(argv[0]);
-    if (tag == JS_TAG_INT) {
-        is_int = 1;
-        v64 = JS_VALUE_GET_INT(argv[0]);
-        d = v64;
-    } else
-    if (tag == JS_TAG_FLOAT64) {
-        d = JS_VALUE_GET_FLOAT64(argv[0]);
-        v64 = d;
-        is_int = (v64 == d);
-    } else
-#ifdef CONFIG_BIGNUM
-    if (tag == JS_TAG_BIG_INT) {
-        JSBigFloat *p1 = JS_VALUE_GET_PTR(argv[0]);
-        
-        if (p->class_id == JS_CLASS_BIG_INT64_ARRAY) {
-            if (bf_get_int64(&v64, &p1->num, 0) != 0)
-                goto done;
-        } else if (p->class_id == JS_CLASS_BIG_UINT64_ARRAY) {
-            if (bf_get_uint64((uint64_t *)&v64, &p1->num) != 0)
-                goto done;
-        } else {
-            goto done;
-        }
-        d = 0;
-        is_bigint = 1;
-    } else
-#endif
-    {
-        goto done;
-    }
-
-    switch (p->class_id) {
-    case JS_CLASS_INT8_ARRAY:
-        if (is_int && (int8_t)v64 == v64)
-            goto scan8;
-        break;
-    case JS_CLASS_UINT8C_ARRAY:
-    case JS_CLASS_UINT8_ARRAY:
-        if (is_int && (uint8_t)v64 == v64) {
-            const uint8_t *pv, *pp;
-            uint16_t v;
-        scan8:
-            pv = p->u.array.u.uint8_ptr;
-            v = v64;
-            if (inc > 0) {
-                pp = memchr(pv + k, v, len - k);
-                if (pp)
-                    res = pp - pv;
-            } else {
-                for (; k != stop; k += inc) {
-                    if (pv[k] == v) {
-                        res = k;
-                        break;
-                    }
-                }
-            }
-        }
-        break;
-    case JS_CLASS_INT16_ARRAY:
-        if (is_int && (int16_t)v64 == v64)
-            goto scan16;
-        break;
-    case JS_CLASS_UINT16_ARRAY:
-        if (is_int && (uint16_t)v64 == v64) {
-            const uint16_t *pv;
-            uint16_t v;
-        scan16:
-            pv = p->u.array.u.uint16_ptr;
-            v = v64;
-            for (; k != stop; k += inc) {
-                if (pv[k] == v) {
-                    res = k;
-                    break;
-                }
-            }
-        }
-        break;
-    case JS_CLASS_INT32_ARRAY:
-        if (is_int && (int32_t)v64 == v64)
-            goto scan32;
-        break;
-    case JS_CLASS_UINT32_ARRAY:
-        if (is_int && (uint32_t)v64 == v64) {
-            const uint32_t *pv;
-            uint32_t v;
-        scan32:
-            pv = p->u.array.u.uint32_ptr;
-            v = v64;
-            for (; k != stop; k += inc) {
-                if (pv[k] == v) {
-                    res = k;
-                    break;
-                }
-            }
-        }
-        break;
-    case JS_CLASS_FLOAT32_ARRAY:
-        if (is_bigint)
-            break;
-        if (isnan(d)) {
-            const float *pv = p->u.array.u.float_ptr;
-            /* special case: indexOf returns -1, includes finds NaN */
-            if (special != special_includes)
-                goto done;
-            for (; k != stop; k += inc) {
-                if (isnan(pv[k])) {
-                    res = k;
-                    break;
-                }
-            }
-        } else if ((f = (float)d) == d) {
-            const float *pv = p->u.array.u.float_ptr;
-            for (; k != stop; k += inc) {
-                if (pv[k] == f) {
-                    res = k;
-                    break;
-                }
-            }
-        }
-        break;
-    case JS_CLASS_FLOAT64_ARRAY:
-        if (is_bigint)
-            break;
-        if (isnan(d)) {
-            const double *pv = p->u.array.u.double_ptr;
-            /* special case: indexOf returns -1, includes finds NaN */
-            if (special != special_includes)
-                goto done;
-            for (; k != stop; k += inc) {
-                if (isnan(pv[k])) {
-                    res = k;
-                    break;
-                }
-            }
-        } else {
-            const double *pv = p->u.array.u.double_ptr;
-            for (; k != stop; k += inc) {
-                if (pv[k] == d) {
-                    res = k;
-                    break;
-                }
-            }
-        }
-        break;
-#ifdef CONFIG_BIGNUM
-    case JS_CLASS_BIG_INT64_ARRAY:
-        if (is_bigint || (is_math_mode(ctx) && is_int &&
-                          v64 >= -MAX_SAFE_INTEGER &&
-                          v64 <= MAX_SAFE_INTEGER)) {
-            goto scan64;
-        }
-        break;
-    case JS_CLASS_BIG_UINT64_ARRAY:
-        if (is_bigint || (is_math_mode(ctx) && is_int &&
-                          v64 >= 0 && v64 <= MAX_SAFE_INTEGER)) {
-            const uint64_t *pv;
-            uint64_t v;
-        scan64:
-            pv = p->u.array.u.uint64_ptr;
-            v = v64;
-            for (; k != stop; k += inc) {
-                if (pv[k] == v) {
-                    res = k;
-                    break;
-                }
-            }
-        }
-        break;
-#endif
-    }
-
-done:
-    if (special == special_includes)
-        return JS_NewBool(ctx, res >= 0);
-    else
-        return JS_NewInt32(ctx, res);
-
-exception:
-    return JS_EXCEPTION;
-}
-
-static JSValue js_typed_array_join(JSContext *ctx, JSValueConst this_val,
-                                   int argc, JSValueConst *argv, int toLocaleString)
-{
-    JSValue sep = JS_UNDEFINED, el;
-    StringBuffer b_s, *b = &b_s;
-    JSString *p = NULL;
-    int i, n;
-    int c;
-
-    n = js_typed_array_get_length_internal(ctx, this_val);
-    if (n < 0)
-        goto exception;
-
-    c = ',';    /* default separator */
-    if (!toLocaleString && argc > 0 && !JS_IsUndefined(argv[0])) {
-        sep = JS_ToString(ctx, argv[0]);
-        if (JS_IsException(sep))
-            goto exception;
-        p = JS_VALUE_GET_STRING(sep);
-        if (p->len == 1 && !p->is_wide_char)
-            c = p->u.str8[0];
-        else
-            c = -1;
-    }
-    string_buffer_init(ctx, b, 0);
-
-    /* XXX: optimize with direct access */
-    for(i = 0; i < n; i++) {
-        if (i > 0) {
-            if (c >= 0) {
-                if (string_buffer_putc8(b, c))
-                    goto fail;
-            } else {
-                if (string_buffer_concat(b, p, 0, p->len))
-                    goto fail;
-            }
-        }
-        el = JS_GetPropertyUint32(ctx, this_val, i);
-        /* Can return undefined for example if the typed array is detached */
-        if (!JS_IsNull(el) && !JS_IsUndefined(el)) {
-            if (JS_IsException(el))
-                goto fail;
-            if (toLocaleString) {
-                el = JS_ToLocaleStringFree(ctx, el);
-            }
-            if (string_buffer_concat_value_free(b, el))
-                goto fail;
-        }
-    }
-    JS_FreeValue(ctx, sep);
-    return string_buffer_end(b);
-
-fail:
-    string_buffer_free(b);
-    JS_FreeValue(ctx, sep);
-exception:
-    return JS_EXCEPTION;
-}
-
-static JSValue js_typed_array_reverse(JSContext *ctx, JSValueConst this_val,
-                                      int argc, JSValueConst *argv)
-{
-    JSObject *p;
-    int len;
-
-    len = js_typed_array_get_length_internal(ctx, this_val);
-    if (len < 0)
-        return JS_EXCEPTION;
-    if (len > 0) {
-        p = JS_VALUE_GET_OBJ(this_val);
-        switch (typed_array_size_log2(p->class_id)) {
-        case 0:
-            {
-                uint8_t *p1 = p->u.array.u.uint8_ptr;
-                uint8_t *p2 = p1 + len - 1;
-                while (p1 < p2) {
-                    uint8_t v = *p1;
-                    *p1++ = *p2;
-                    *p2-- = v;
-                }
-            }
-            break;
-        case 1:
-            {
-                uint16_t *p1 = p->u.array.u.uint16_ptr;
-                uint16_t *p2 = p1 + len - 1;
-                while (p1 < p2) {
-                    uint16_t v = *p1;
-                    *p1++ = *p2;
-                    *p2-- = v;
-                }
-            }
-            break;
-        case 2:
-            {
-                uint32_t *p1 = p->u.array.u.uint32_ptr;
-                uint32_t *p2 = p1 + len - 1;
-                while (p1 < p2) {
-                    uint32_t v = *p1;
-                    *p1++ = *p2;
-                    *p2-- = v;
-                }
-            }
-            break;
-        case 3:
-            {
-                uint64_t *p1 = p->u.array.u.uint64_ptr;
-                uint64_t *p2 = p1 + len - 1;
-                while (p1 < p2) {
-                    uint64_t v = *p1;
-                    *p1++ = *p2;
-                    *p2-- = v;
-                }
-            }
-            break;
-        default:
-            abort();
-        }
-    }
-    return JS_DupValue(ctx, this_val);
-}
-
-static JSValue js_typed_array_slice(JSContext *ctx, JSValueConst this_val,
-                                    int argc, JSValueConst *argv)
-{
-    JSValueConst args[2];
-    JSValue arr, val;
-    JSObject *p, *p1;
-    int n, len, start, final, count, shift;
-
-    arr = JS_UNDEFINED;
-    len = js_typed_array_get_length_internal(ctx, this_val);
-    if (len < 0)
-        goto exception;
-
-    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))
-        goto exception;
-    final = len;
-    if (!JS_IsUndefined(argv[1])) {
-        if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len))
-            goto exception;
-    }
-    count = max_int(final - start, 0);
-
-    p = get_typed_array(ctx, this_val, 0);
-    if (p == NULL)
-        goto exception;
-    shift = typed_array_size_log2(p->class_id);
-
-    args[0] = this_val;
-    args[1] = JS_NewInt32(ctx, count);
-    arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
-    if (JS_IsException(arr))
-        goto exception;
-
-    if (count > 0) {
-        if (validate_typed_array(ctx, this_val)
-        ||  validate_typed_array(ctx, arr))
-            goto exception;
-
-        p1 = get_typed_array(ctx, arr, 0);
-        if (p1 != NULL && p->class_id == p1->class_id &&
-            typed_array_get_length(ctx, p1) >= count &&
-            typed_array_get_length(ctx, p) >= start + count) {
-            memcpy(p1->u.array.u.uint8_ptr,
-                   p->u.array.u.uint8_ptr + (start << shift),
-                   count << shift);
-        } else {
-            for (n = 0; n < count; n++) {
-                val = JS_GetPropertyValue(ctx, this_val, JS_NewInt32(ctx, start + n));
-                if (JS_IsException(val))
-                    goto exception;
-                if (JS_SetPropertyValue(ctx, arr, JS_NewInt32(ctx, n), val,
-                                        JS_PROP_THROW) < 0)
-                    goto exception;
-            }
-        }
-    }
-    return arr;
-
- exception:
-    JS_FreeValue(ctx, arr);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_typed_array_subarray(JSContext *ctx, JSValueConst this_val,
-                                       int argc, JSValueConst *argv)
-{
-    JSValueConst args[4];
-    JSValue arr, byteOffset, ta_buffer;
-    JSObject *p;
-    int len, start, final, count, shift, offset;
-
-    p = get_typed_array(ctx, this_val, 0);
-    if (!p)
-        goto exception;
-    len = p->u.array.count;
-    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))
-        goto exception;
-
-    final = len;
-    if (!JS_IsUndefined(argv[1])) {
-        if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len))
-            goto exception;
-    }
-    count = max_int(final - start, 0);
-    byteOffset = js_typed_array_get_byteOffset(ctx, this_val, 0);
-    if (JS_IsException(byteOffset))
-        goto exception;
-    shift = typed_array_size_log2(p->class_id);
-    offset = JS_VALUE_GET_INT(byteOffset) + (start << shift);
-    JS_FreeValue(ctx, byteOffset);
-    ta_buffer = js_typed_array_get_buffer(ctx, this_val, 0);
-    if (JS_IsException(ta_buffer))
-        goto exception;
-    args[0] = this_val;
-    args[1] = ta_buffer;
-    args[2] = JS_NewInt32(ctx, offset);
-    args[3] = JS_NewInt32(ctx, count);
-    arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 4, args);
-    JS_FreeValue(ctx, ta_buffer);
-    return arr;
-
- exception:
-    return JS_EXCEPTION;
-}
-
-/* TypedArray.prototype.sort */
-
-static int js_cmp_doubles(double x, double y)
-{
-    if (isnan(x))    return isnan(y) ? 0 : +1;
-    if (isnan(y))    return -1;
-    if (x < y)       return -1;
-    if (x > y)       return 1;
-    if (x != 0)      return 0;
-    if (signbit(x))  return signbit(y) ? 0 : -1;
-    else             return signbit(y) ? 1 : 0;
-}
-
-static int js_TA_cmp_int8(const void *a, const void *b, void *opaque) {
-    return *(const int8_t *)a - *(const int8_t *)b;
-}
-
-static int js_TA_cmp_uint8(const void *a, const void *b, void *opaque) {
-    return *(const uint8_t *)a - *(const uint8_t *)b;
-}
-
-static int js_TA_cmp_int16(const void *a, const void *b, void *opaque) {
-    return *(const int16_t *)a - *(const int16_t *)b;
-}
-
-static int js_TA_cmp_uint16(const void *a, const void *b, void *opaque) {
-    return *(const uint16_t *)a - *(const uint16_t *)b;
-}
-
-static int js_TA_cmp_int32(const void *a, const void *b, void *opaque) {
-    int32_t x = *(const int32_t *)a;
-    int32_t y = *(const int32_t *)b;
-    return (y < x) - (y > x);
-}
-
-static int js_TA_cmp_uint32(const void *a, const void *b, void *opaque) {
-    uint32_t x = *(const uint32_t *)a;
-    uint32_t y = *(const uint32_t *)b;
-    return (y < x) - (y > x);
-}
-
-#ifdef CONFIG_BIGNUM
-static int js_TA_cmp_int64(const void *a, const void *b, void *opaque) {
-    int64_t x = *(const int64_t *)a;
-    int64_t y = *(const int64_t *)b;
-    return (y < x) - (y > x);
-}
-
-static int js_TA_cmp_uint64(const void *a, const void *b, void *opaque) {
-    uint64_t x = *(const uint64_t *)a;
-    uint64_t y = *(const uint64_t *)b;
-    return (y < x) - (y > x);
-}
-#endif
-
-static int js_TA_cmp_float32(const void *a, const void *b, void *opaque) {
-    return js_cmp_doubles(*(const float *)a, *(const float *)b);
-}
-
-static int js_TA_cmp_float64(const void *a, const void *b, void *opaque) {
-    return js_cmp_doubles(*(const double *)a, *(const double *)b);
-}
-
-static JSValue js_TA_get_int8(JSContext *ctx, const void *a) {
-    return JS_NewInt32(ctx, *(const int8_t *)a);
-}
-
-static JSValue js_TA_get_uint8(JSContext *ctx, const void *a) {
-    return JS_NewInt32(ctx, *(const uint8_t *)a);
-}
-
-static JSValue js_TA_get_int16(JSContext *ctx, const void *a) {
-    return JS_NewInt32(ctx, *(const int16_t *)a);
-}
-
-static JSValue js_TA_get_uint16(JSContext *ctx, const void *a) {
-    return JS_NewInt32(ctx, *(const uint16_t *)a);
-}
-
-static JSValue js_TA_get_int32(JSContext *ctx, const void *a) {
-    return JS_NewInt32(ctx, *(const int32_t *)a);
-}
-
-static JSValue js_TA_get_uint32(JSContext *ctx, const void *a) {
-    return JS_NewUint32(ctx, *(const uint32_t *)a);
-}
-
-#ifdef CONFIG_BIGNUM
-static JSValue js_TA_get_int64(JSContext *ctx, const void *a) {
-    return JS_NewBigInt64(ctx, *(int64_t *)a);
-}
-
-static JSValue js_TA_get_uint64(JSContext *ctx, const void *a) {
-    return JS_NewBigUint64(ctx, *(uint64_t *)a);
-}
-#endif
-
-static JSValue js_TA_get_float32(JSContext *ctx, const void *a) {
-    return __JS_NewFloat64(ctx, *(const float *)a);
-}
-
-static JSValue js_TA_get_float64(JSContext *ctx, const void *a) {
-    return __JS_NewFloat64(ctx, *(const double *)a);
-}
-
-struct TA_sort_context {
-    JSContext *ctx;
-    int exception;
-    JSValueConst arr;
-    JSValueConst cmp;
-    JSValue (*getfun)(JSContext *ctx, const void *a);
-    uint8_t *array_ptr; /* cannot change unless the array is detached */
-    int elt_size;
-};
-
-static int js_TA_cmp_generic(const void *a, const void *b, void *opaque) {
-    struct TA_sort_context *psc = opaque;
-    JSContext *ctx = psc->ctx;
-    uint32_t a_idx, b_idx;
-    JSValueConst argv[2];
-    JSValue res;
-    int cmp;
-
-    cmp = 0;
-    if (!psc->exception) {
-        a_idx = *(uint32_t *)a;
-        b_idx = *(uint32_t *)b;
-        argv[0] = psc->getfun(ctx, psc->array_ptr +
-                              a_idx * (size_t)psc->elt_size);
-        argv[1] = psc->getfun(ctx, psc->array_ptr +
-                              b_idx * (size_t)(psc->elt_size));
-        res = JS_Call(ctx, psc->cmp, JS_UNDEFINED, 2, argv);
-        if (JS_IsException(res)) {
-            psc->exception = 1;
-            goto done;
-        }
-        if (JS_VALUE_GET_TAG(res) == JS_TAG_INT) {
-            int val = JS_VALUE_GET_INT(res);
-            cmp = (val > 0) - (val < 0);
-        } else {
-            double val;
-            if (JS_ToFloat64Free(ctx, &val, res) < 0) {
-                psc->exception = 1;
-                goto done;
-            } else {
-                cmp = (val > 0) - (val < 0);
-            }
-        }
-        if (cmp == 0) {
-            /* make sort stable: compare array offsets */
-            cmp = (a_idx > b_idx) - (a_idx < b_idx);
-        }
-        if (validate_typed_array(ctx, psc->arr) < 0) {
-            psc->exception = 1;
-        }
-    done:
-        JS_FreeValue(ctx, (JSValue)argv[0]);
-        JS_FreeValue(ctx, (JSValue)argv[1]);
-    }
-    return cmp;
-}
-
-static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val,
-                                   int argc, JSValueConst *argv)
-{
-    JSObject *p;
-    int len;
-    size_t elt_size;
-    struct TA_sort_context tsc;
-    void *array_ptr;
-    int (*cmpfun)(const void *a, const void *b, void *opaque);
-
-    tsc.ctx = ctx;
-    tsc.exception = 0;
-    tsc.arr = this_val;
-    tsc.cmp = argv[0];
-
-    len = js_typed_array_get_length_internal(ctx, this_val);
-    if (len < 0)
-        return JS_EXCEPTION;
-    if (!JS_IsUndefined(tsc.cmp) && check_function(ctx, tsc.cmp))
-        return JS_EXCEPTION;
-
-    if (len > 1) {
-        p = JS_VALUE_GET_OBJ(this_val);
-        switch (p->class_id) {
-        case JS_CLASS_INT8_ARRAY:
-            tsc.getfun = js_TA_get_int8;
-            cmpfun = js_TA_cmp_int8;
-            break;
-        case JS_CLASS_UINT8C_ARRAY:
-        case JS_CLASS_UINT8_ARRAY:
-            tsc.getfun = js_TA_get_uint8;
-            cmpfun = js_TA_cmp_uint8;
-            break;
-        case JS_CLASS_INT16_ARRAY:
-            tsc.getfun = js_TA_get_int16;
-            cmpfun = js_TA_cmp_int16;
-            break;
-        case JS_CLASS_UINT16_ARRAY:
-            tsc.getfun = js_TA_get_uint16;
-            cmpfun = js_TA_cmp_uint16;
-            break;
-        case JS_CLASS_INT32_ARRAY:
-            tsc.getfun = js_TA_get_int32;
-            cmpfun = js_TA_cmp_int32;
-            break;
-        case JS_CLASS_UINT32_ARRAY:
-            tsc.getfun = js_TA_get_uint32;
-            cmpfun = js_TA_cmp_uint32;
-            break;
-#ifdef CONFIG_BIGNUM
-        case JS_CLASS_BIG_INT64_ARRAY:
-            tsc.getfun = js_TA_get_int64;
-            cmpfun = js_TA_cmp_int64;
-            break;
-        case JS_CLASS_BIG_UINT64_ARRAY:
-            tsc.getfun = js_TA_get_uint64;
-            cmpfun = js_TA_cmp_uint64;
-            break;
-#endif
-        case JS_CLASS_FLOAT32_ARRAY:
-            tsc.getfun = js_TA_get_float32;
-            cmpfun = js_TA_cmp_float32;
-            break;
-        case JS_CLASS_FLOAT64_ARRAY:
-            tsc.getfun = js_TA_get_float64;
-            cmpfun = js_TA_cmp_float64;
-            break;
-        default:
-            abort();
-        }
-        array_ptr = p->u.array.u.ptr;
-        elt_size = 1 << typed_array_size_log2(p->class_id);
-        if (!JS_IsUndefined(tsc.cmp)) {
-            uint32_t *array_idx;
-            void *array_tmp;
-            size_t i, j;
-            
-            /* XXX: a stable sort would use less memory */
-            array_idx = js_malloc(ctx, len * sizeof(array_idx[0]));
-            if (!array_idx)
-                return JS_EXCEPTION;
-            for(i = 0; i < len; i++)
-                array_idx[i] = i;
-            tsc.array_ptr = array_ptr;
-            tsc.elt_size = elt_size;
-            rqsort(array_idx, len, sizeof(array_idx[0]),
-                   js_TA_cmp_generic, &tsc);
-            if (tsc.exception)
-                goto fail;
-            array_tmp = js_malloc(ctx, len * elt_size);
-            if (!array_tmp) {
-            fail:
-                js_free(ctx, array_idx);
-                return JS_EXCEPTION;
-            }
-            memcpy(array_tmp, array_ptr, len * elt_size);
-            switch(elt_size) {
-            case 1:
-                for(i = 0; i < len; i++) {
-                    j = array_idx[i];
-                    ((uint8_t *)array_ptr)[i] = ((uint8_t *)array_tmp)[j];
-                }
-                break;
-            case 2:
-                for(i = 0; i < len; i++) {
-                    j = array_idx[i];
-                    ((uint16_t *)array_ptr)[i] = ((uint16_t *)array_tmp)[j];
-                }
-                break;
-            case 4:
-                for(i = 0; i < len; i++) {
-                    j = array_idx[i];
-                    ((uint32_t *)array_ptr)[i] = ((uint32_t *)array_tmp)[j];
-                }
-                break;
-            case 8:
-                for(i = 0; i < len; i++) {
-                    j = array_idx[i];
-                    ((uint64_t *)array_ptr)[i] = ((uint64_t *)array_tmp)[j];
-                }
-                break;
-            default:
-                abort();
-            }
-            js_free(ctx, array_tmp);
-            js_free(ctx, array_idx);
-        } else {
-            rqsort(array_ptr, len, elt_size, cmpfun, &tsc);
-            if (tsc.exception)
-                return JS_EXCEPTION;
-        }
-    }
-    return JS_DupValue(ctx, this_val);
-}
-
-static const JSCFunctionListEntry js_typed_array_base_funcs[] = {
-    JS_CFUNC_DEF("from", 1, js_typed_array_from ),
-    JS_CFUNC_DEF("of", 0, js_typed_array_of ),
-    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
-    //JS_CFUNC_DEF("__getLength", 2, js_typed_array___getLength ),
-    //JS_CFUNC_DEF("__create", 2, js_typed_array___create ),
-    //JS_CFUNC_DEF("__speciesCreate", 2, js_typed_array___speciesCreate ),
-};
-
-static const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = {
-    JS_CGETSET_DEF("length", js_typed_array_get_length, NULL ),
-    JS_CGETSET_MAGIC_DEF("buffer", js_typed_array_get_buffer, NULL, 0 ),
-    JS_CGETSET_MAGIC_DEF("byteLength", js_typed_array_get_byteLength, NULL, 0 ),
-    JS_CGETSET_MAGIC_DEF("byteOffset", js_typed_array_get_byteOffset, NULL, 0 ),
-    JS_CFUNC_DEF("set", 1, js_typed_array_set ),
-    JS_CFUNC_MAGIC_DEF("values", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_VALUE ),
-    JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
-    JS_CFUNC_MAGIC_DEF("keys", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_KEY ),
-    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE ),
-    JS_CGETSET_DEF("[Symbol.toStringTag]", js_typed_array_get_toStringTag, NULL ),
-    JS_CFUNC_DEF("copyWithin", 2, js_typed_array_copyWithin ),
-    JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every | special_TA ),
-    JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some | special_TA ),
-    JS_CFUNC_MAGIC_DEF("forEach", 1, js_array_every, special_forEach | special_TA ),
-    JS_CFUNC_MAGIC_DEF("map", 1, js_array_every, special_map | special_TA ),
-    JS_CFUNC_MAGIC_DEF("filter", 1, js_array_every, special_filter | special_TA ),
-    JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce | special_TA ),
-    JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight | special_TA ),
-    JS_CFUNC_DEF("fill", 1, js_typed_array_fill ),
-    JS_CFUNC_MAGIC_DEF("find", 1, js_typed_array_find, 0 ),
-    JS_CFUNC_MAGIC_DEF("findIndex", 1, js_typed_array_find, 1 ),
-    JS_CFUNC_DEF("reverse", 0, js_typed_array_reverse ),
-    JS_CFUNC_DEF("slice", 2, js_typed_array_slice ),
-    JS_CFUNC_DEF("subarray", 2, js_typed_array_subarray ),
-    JS_CFUNC_DEF("sort", 1, js_typed_array_sort ),
-    JS_CFUNC_MAGIC_DEF("join", 1, js_typed_array_join, 0 ),
-    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_typed_array_join, 1 ),
-    JS_CFUNC_MAGIC_DEF("indexOf", 1, js_typed_array_indexOf, special_indexOf ),
-    JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_typed_array_indexOf, special_lastIndexOf ),
-    JS_CFUNC_MAGIC_DEF("includes", 1, js_typed_array_indexOf, special_includes ),
-    //JS_ALIAS_BASE_DEF("toString", "toString", 2 /* Array.prototype. */), @@@
-};
-
-static JSValue js_typed_array_base_constructor(JSContext *ctx,
-                                               JSValueConst this_val,
-                                               int argc, JSValueConst *argv)
-{
-    return JS_ThrowTypeError(ctx, "cannot be called");
-}
-
-/* 'obj' must be an allocated typed array object */
-static int typed_array_init(JSContext *ctx, JSValueConst obj,
-                            JSValue buffer, uint64_t offset, uint64_t len)
-{
-    JSTypedArray *ta;
-    JSObject *p, *pbuffer;
-    JSArrayBuffer *abuf;
-    int size_log2;
-
-    p = JS_VALUE_GET_OBJ(obj);
-    size_log2 = typed_array_size_log2(p->class_id);
-    ta = js_malloc(ctx, sizeof(*ta));
-    if (!ta) {
-        JS_FreeValue(ctx, buffer);
-        return -1;
-    }
-    pbuffer = JS_VALUE_GET_OBJ(buffer);
-    abuf = pbuffer->u.array_buffer;
-    ta->obj = p;
-    ta->buffer = pbuffer;
-    ta->offset = offset;
-    ta->length = len << size_log2;
-    list_add_tail(&ta->link, &abuf->array_list);
-    p->u.typed_array = ta;
-    p->u.array.count = len;
-    p->u.array.u.ptr = abuf->data + offset;
-    return 0;
-}
-
-
-static JSValue js_array_from_iterator(JSContext *ctx, uint32_t *plen,
-                                      JSValueConst obj, JSValueConst method)
-{
-    JSValue arr, iter, next_method = JS_UNDEFINED, val;
-    BOOL done;
-    uint32_t k;
-
-    *plen = 0;
-    arr = JS_NewArray(ctx);
-    if (JS_IsException(arr))
-        return arr;
-    iter = JS_GetIterator2(ctx, obj, method);
-    if (JS_IsException(iter))
-        goto fail;
-    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
-    if (JS_IsException(next_method))
-        goto fail;
-    k = 0;
-    for(;;) {
-        val = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
-        if (JS_IsException(val))
-            goto fail;
-        if (done) {
-            JS_FreeValue(ctx, val);
-            break;
-        }
-        if (JS_CreateDataPropertyUint32(ctx, arr, k, val, JS_PROP_THROW) < 0)
-            goto fail;
-        k++;
-    }
-    JS_FreeValue(ctx, next_method);
-    JS_FreeValue(ctx, iter);
-    *plen = k;
-    return arr;
- fail:
-    JS_FreeValue(ctx, next_method);
-    JS_FreeValue(ctx, iter);
-    JS_FreeValue(ctx, arr);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_typed_array_constructor_obj(JSContext *ctx,
-                                              JSValueConst new_target,
-                                              JSValueConst obj,
-                                              int classid)
-{
-    JSValue iter, ret, arr = JS_UNDEFINED, val, buffer;
-    uint32_t i;
-    int size_log2;
-    int64_t len;
-
-    size_log2 = typed_array_size_log2(classid);
-    ret = js_create_from_ctor(ctx, new_target, classid);
-    if (JS_IsException(ret))
-        return JS_EXCEPTION;
-
-    iter = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
-    if (JS_IsException(iter))
-        goto fail;
-    if (!JS_IsUndefined(iter) && !JS_IsNull(iter)) {
-        uint32_t len1;
-        arr = js_array_from_iterator(ctx, &len1, obj, iter);
-        JS_FreeValue(ctx, iter);
-        if (JS_IsException(arr))
-            goto fail;
-        len = len1;
-    } else {
-        if (js_get_length64(ctx, &len, obj))
-            goto fail;
-        arr = JS_DupValue(ctx, obj);
-    }
-
-    buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,
-                                          len << size_log2);
-    if (JS_IsException(buffer))
-        goto fail;
-    if (typed_array_init(ctx, ret, buffer, 0, len))
-        goto fail;
-
-    for(i = 0; i < len; i++) {
-        val = JS_GetPropertyUint32(ctx, arr, i);
-        if (JS_IsException(val))
-            goto fail;
-        if (JS_SetPropertyUint32(ctx, ret, i, val) < 0)
-            goto fail;
-    }
-    JS_FreeValue(ctx, arr);
-    return ret;
- fail:
-    JS_FreeValue(ctx, arr);
-    JS_FreeValue(ctx, ret);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_typed_array_constructor_ta(JSContext *ctx,
-                                             JSValueConst new_target,
-                                             JSValueConst src_obj,
-                                             int classid)
-{
-    JSObject *p, *src_buffer;
-    JSTypedArray *ta;
-    JSValue ctor, obj, buffer;
-    uint32_t len, i;
-    int size_log2;
-    JSArrayBuffer *src_abuf, *abuf;
-
-    obj = js_create_from_ctor(ctx, new_target, classid);
-    if (JS_IsException(obj))
-        return obj;
-    p = JS_VALUE_GET_OBJ(src_obj);
-    if (typed_array_is_detached(ctx, p)) {
-        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-        goto fail;
-    }
-    ta = p->u.typed_array;
-    len = p->u.array.count;
-    src_buffer = ta->buffer;
-    src_abuf = src_buffer->u.array_buffer;
-    if (!src_abuf->shared) {
-        ctor = JS_SpeciesConstructor(ctx, JS_MKPTR(JS_TAG_OBJECT, src_buffer),
-                                     JS_UNDEFINED);
-        if (JS_IsException(ctor))
-            goto fail;
-    } else {
-        /* force ArrayBuffer default constructor */
-        ctor = JS_UNDEFINED;
-    }
-    size_log2 = typed_array_size_log2(classid);
-    buffer = js_array_buffer_constructor1(ctx, ctor,
-                                          (uint64_t)len << size_log2);
-    JS_FreeValue(ctx, ctor);
-    if (JS_IsException(buffer))
-        goto fail;
-    /* necessary because it could have been detached */
-    if (typed_array_is_detached(ctx, p)) {
-        JS_FreeValue(ctx, buffer);
-        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-        goto fail;
-    }
-    abuf = JS_GetOpaque(buffer, JS_CLASS_ARRAY_BUFFER);
-    if (typed_array_init(ctx, obj, buffer, 0, len))
-        goto fail;
-    if (p->class_id == classid) {
-        /* same type: copy the content */
-        memcpy(abuf->data, src_abuf->data + ta->offset, abuf->byte_length);
-    } else {
-        for(i = 0; i < len; i++) {
-            JSValue val;
-            val = JS_GetPropertyUint32(ctx, src_obj, i);
-            if (JS_IsException(val))
-                goto fail;
-            if (JS_SetPropertyUint32(ctx, obj, i, val) < 0)
-                goto fail;
-        }
-    }
-    return obj;
- fail:
-    JS_FreeValue(ctx, obj);
-    return JS_EXCEPTION;
-}
-
-static JSValue js_typed_array_constructor(JSContext *ctx,
-                                          JSValueConst new_target,
-                                          int argc, JSValueConst *argv,
-                                          int classid)
-{
-    JSValue buffer, obj;
-    JSArrayBuffer *abuf;
-    int size_log2;
-    uint64_t len, offset;
-
-    size_log2 = typed_array_size_log2(classid);
-    if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT) {
-        if (JS_ToIndex(ctx, &len, argv[0]))
-            return JS_EXCEPTION;
-        buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,
-                                              len << size_log2);
-        if (JS_IsException(buffer))
-            return JS_EXCEPTION;
-        offset = 0;
-    } else {
-        JSObject *p = JS_VALUE_GET_OBJ(argv[0]);
-        if (p->class_id == JS_CLASS_ARRAY_BUFFER ||
-            p->class_id == JS_CLASS_SHARED_ARRAY_BUFFER) {
-            abuf = p->u.array_buffer;
-            if (JS_ToIndex(ctx, &offset, argv[1]))
-                return JS_EXCEPTION;
-            if (abuf->detached)
-                return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-            if ((offset & ((1 << size_log2) - 1)) != 0 ||
-                offset > abuf->byte_length)
-                return JS_ThrowRangeError(ctx, "invalid offset");
-            if (JS_IsUndefined(argv[2])) {
-                if ((abuf->byte_length & ((1 << size_log2) - 1)) != 0)
-                    goto invalid_length;
-                len = (abuf->byte_length - offset) >> size_log2;
-            } else {
-                if (JS_ToIndex(ctx, &len, argv[2]))
-                    return JS_EXCEPTION;
-                if (abuf->detached)
-                    return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-                if ((offset + (len << size_log2)) > abuf->byte_length) {
-                invalid_length:
-                    return JS_ThrowRangeError(ctx, "invalid length");
-                }
-            }
-            buffer = JS_DupValue(ctx, argv[0]);
-        } else {
-            if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
-                p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
-                return js_typed_array_constructor_ta(ctx, new_target, argv[0], classid);
-            } else {
-                return js_typed_array_constructor_obj(ctx, new_target, argv[0], classid);
-            }
-        }
-    }
-
-    obj = js_create_from_ctor(ctx, new_target, classid);
-    if (JS_IsException(obj)) {
-        JS_FreeValue(ctx, buffer);
-        return JS_EXCEPTION;
-    }
-    if (typed_array_init(ctx, obj, buffer, offset, len)) {
-        JS_FreeValue(ctx, obj);
-        return JS_EXCEPTION;
-    }
-    return obj;
-}
-
-static void js_typed_array_finalizer(JSRuntime *rt, JSValue val)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    JSTypedArray *ta = p->u.typed_array;
-    if (ta) {
-        /* during the GC the finalizers are called in an arbitrary
-           order so the ArrayBuffer finalizer may have been called */
-        if (JS_IsLiveObject(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer))) {
-            list_del(&ta->link);
-        }
-        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
-        js_free_rt(rt, ta);
-    }
-}
-
-static void js_typed_array_mark(JSRuntime *rt, JSValueConst val,
-                                JS_MarkFunc *mark_func)
-{
-    JSObject *p = JS_VALUE_GET_OBJ(val);
-    JSTypedArray *ta = p->u.typed_array;
-    if (ta) {
-        JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer), mark_func);
-    }
-}
-
-static JSValue js_dataview_constructor(JSContext *ctx,
-                                       JSValueConst new_target,
-                                       int argc, JSValueConst *argv)
-{
-    JSArrayBuffer *abuf;
-    uint64_t offset;
-    uint32_t len;
-    JSValueConst buffer;
-    JSValue obj;
-    JSTypedArray *ta;
-    JSObject *p;
-
-    buffer = argv[0];
-    abuf = js_get_array_buffer(ctx, buffer);
-    if (!abuf)
-        return JS_EXCEPTION;
-    offset = 0;
-    if (argc > 1) {
-        if (JS_ToIndex(ctx, &offset, argv[1]))
-            return JS_EXCEPTION;
-    }
-    if (abuf->detached)
-        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-    if (offset > abuf->byte_length)
-        return JS_ThrowRangeError(ctx, "invalid byteOffset");
-    len = abuf->byte_length - offset;
-    if (argc > 2 && !JS_IsUndefined(argv[2])) {
-        uint64_t l;
-        if (JS_ToIndex(ctx, &l, argv[2]))
-            return JS_EXCEPTION;
-        if (l > len)
-            return JS_ThrowRangeError(ctx, "invalid byteLength");
-        len = l;
-    }
-
-    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_DATAVIEW);
-    if (JS_IsException(obj))
-        return JS_EXCEPTION;
-    if (abuf->detached) {
-        /* could have been detached in js_create_from_ctor() */
-        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-        goto fail;
-    }
-    ta = js_malloc(ctx, sizeof(*ta));
-    if (!ta) {
-    fail:
-        JS_FreeValue(ctx, obj);
-        return JS_EXCEPTION;
-    }
-    p = JS_VALUE_GET_OBJ(obj);
-    ta->obj = p;
-    ta->buffer = JS_VALUE_GET_OBJ(JS_DupValue(ctx, buffer));
-    ta->offset = offset;
-    ta->length = len;
-    list_add_tail(&ta->link, &abuf->array_list);
-    p->u.typed_array = ta;
-    return obj;
-}
-
-static JSValue js_dataview_getValue(JSContext *ctx,
-                                    JSValueConst this_obj,
-                                    int argc, JSValueConst *argv, int class_id)
-{
-    JSTypedArray *ta;
-    JSArrayBuffer *abuf;
-    int is_swap, size;
-    uint8_t *ptr;
-    uint32_t v;
-    uint64_t pos;
-
-    ta = JS_GetOpaque2(ctx, this_obj, JS_CLASS_DATAVIEW);
-    if (!ta)
-        return JS_EXCEPTION;
-    size = 1 << typed_array_size_log2(class_id);
-    if (JS_ToIndex(ctx, &pos, argv[0]))
-        return JS_EXCEPTION;
-    is_swap = FALSE;
-    if (argc > 1)
-        is_swap = JS_ToBool(ctx, argv[1]);
-#ifndef WORDS_BIGENDIAN
-    is_swap ^= 1;
-#endif
-    abuf = ta->buffer->u.array_buffer;
-    if (abuf->detached)
-        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-    if ((pos + size) > ta->length)
-        return JS_ThrowRangeError(ctx, "out of bound");
-    ptr = abuf->data + ta->offset + pos;
-
-    switch(class_id) {
-    case JS_CLASS_INT8_ARRAY:
-        return JS_NewInt32(ctx, *(int8_t *)ptr);
-    case JS_CLASS_UINT8_ARRAY:
-        return JS_NewInt32(ctx, *(uint8_t *)ptr);
-    case JS_CLASS_INT16_ARRAY:
-        v = get_u16(ptr);
-        if (is_swap)
-            v = bswap16(v);
-        return JS_NewInt32(ctx, (int16_t)v);
-    case JS_CLASS_UINT16_ARRAY:
-        v = get_u16(ptr);
-        if (is_swap)
-            v = bswap16(v);
-        return JS_NewInt32(ctx, v);
-    case JS_CLASS_INT32_ARRAY:
-        v = get_u32(ptr);
-        if (is_swap)
-            v = bswap32(v);
-        return JS_NewInt32(ctx, v);
-    case JS_CLASS_UINT32_ARRAY:
-        v = get_u32(ptr);
-        if (is_swap)
-            v = bswap32(v);
-        return JS_NewUint32(ctx, v);
-#ifdef CONFIG_BIGNUM
-    case JS_CLASS_BIG_INT64_ARRAY:
-        {
-            uint64_t v;
-            v = get_u64(ptr);
-            if (is_swap)
-                v = bswap64(v);
-            return JS_NewBigInt64(ctx, v);
-        }
-        break;
-    case JS_CLASS_BIG_UINT64_ARRAY:
-        {
-            uint64_t v;
-            v = get_u64(ptr);
-            if (is_swap)
-                v = bswap64(v);
-            return JS_NewBigUint64(ctx, v);
-        }
-        break;
-#endif
-    case JS_CLASS_FLOAT32_ARRAY:
-        {
-            union {
-                float f;
-                uint32_t i;
-            } u;
-            v = get_u32(ptr);
-            if (is_swap)
-                v = bswap32(v);
-            u.i = v;
-            return __JS_NewFloat64(ctx, u.f);
-        }
-    case JS_CLASS_FLOAT64_ARRAY:
-        {
-            union {
-                double f;
-                uint64_t i;
-            } u;
-            u.i = get_u64(ptr);
-            if (is_swap)
-                u.i = bswap64(u.i);
-            return __JS_NewFloat64(ctx, u.f);
-        }
-    default:
-        abort();
-    }
-}
-
-static JSValue js_dataview_setValue(JSContext *ctx,
-                                    JSValueConst this_obj,
-                                    int argc, JSValueConst *argv, int class_id)
-{
-    JSTypedArray *ta;
-    JSArrayBuffer *abuf;
-    int is_swap, size;
-    uint8_t *ptr;
-    uint64_t v64;
-    uint32_t v;
-    uint64_t pos;
-    JSValueConst val;
-
-    ta = JS_GetOpaque2(ctx, this_obj, JS_CLASS_DATAVIEW);
-    if (!ta)
-        return JS_EXCEPTION;
-    size = 1 << typed_array_size_log2(class_id);
-    if (JS_ToIndex(ctx, &pos, argv[0]))
-        return JS_EXCEPTION;
-    val = argv[1];
-    v = 0; /* avoid warning */
-    v64 = 0; /* avoid warning */
-    if (class_id <= JS_CLASS_UINT32_ARRAY) {
-        if (JS_ToUint32(ctx, &v, val))
-            return JS_EXCEPTION;
-    } else
-#ifdef CONFIG_BIGNUM
-    if (class_id <= JS_CLASS_BIG_UINT64_ARRAY) {
-        if (JS_ToBigInt64(ctx, (int64_t *)&v64, val))
-            return JS_EXCEPTION;
-    } else
-#endif
-    {
-        double d;
-        if (JS_ToFloat64(ctx, &d, val))
-            return JS_EXCEPTION;
-        if (class_id == JS_CLASS_FLOAT32_ARRAY) {
-            union {
-                float f;
-                uint32_t i;
-            } u;
-            u.f = d;
-            v = u.i;
-        } else {
-            JSFloat64Union u;
-            u.d = d;
-            v64 = u.u64;
-        }
-    }
-    is_swap = FALSE;
-    if (argc > 2)
-        is_swap = JS_ToBool(ctx, argv[2]);
-#ifndef WORDS_BIGENDIAN
-    is_swap ^= 1;
-#endif
-    abuf = ta->buffer->u.array_buffer;
-    if (abuf->detached)
-        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-    if ((pos + size) > ta->length)
-        return JS_ThrowRangeError(ctx, "out of bound");
-    ptr = abuf->data + ta->offset + pos;
-
-    switch(class_id) {
-    case JS_CLASS_INT8_ARRAY:
-    case JS_CLASS_UINT8_ARRAY:
-        *ptr = v;
-        break;
-    case JS_CLASS_INT16_ARRAY:
-    case JS_CLASS_UINT16_ARRAY:
-        if (is_swap)
-            v = bswap16(v);
-        put_u16(ptr, v);
-        break;
-    case JS_CLASS_INT32_ARRAY:
-    case JS_CLASS_UINT32_ARRAY:
-    case JS_CLASS_FLOAT32_ARRAY:
-        if (is_swap)
-            v = bswap32(v);
-        put_u32(ptr, v);
-        break;
-#ifdef CONFIG_BIGNUM
-    case JS_CLASS_BIG_INT64_ARRAY:
-    case JS_CLASS_BIG_UINT64_ARRAY:
-#endif
-    case JS_CLASS_FLOAT64_ARRAY:
-        if (is_swap)
-            v64 = bswap64(v64);
-        put_u64(ptr, v64);
-        break;
-    default:
-        abort();
-    }
-    return JS_UNDEFINED;
-}
-
-static const JSCFunctionListEntry js_dataview_proto_funcs[] = {
-    JS_CGETSET_MAGIC_DEF("buffer", js_typed_array_get_buffer, NULL, 1 ),
-    JS_CGETSET_MAGIC_DEF("byteLength", js_typed_array_get_byteLength, NULL, 1 ),
-    JS_CGETSET_MAGIC_DEF("byteOffset", js_typed_array_get_byteOffset, NULL, 1 ),
-    JS_CFUNC_MAGIC_DEF("getInt8", 1, js_dataview_getValue, JS_CLASS_INT8_ARRAY ),
-    JS_CFUNC_MAGIC_DEF("getUint8", 1, js_dataview_getValue, JS_CLASS_UINT8_ARRAY ),
-    JS_CFUNC_MAGIC_DEF("getInt16", 1, js_dataview_getValue, JS_CLASS_INT16_ARRAY ),
-    JS_CFUNC_MAGIC_DEF("getUint16", 1, js_dataview_getValue, JS_CLASS_UINT16_ARRAY ),
-    JS_CFUNC_MAGIC_DEF("getInt32", 1, js_dataview_getValue, JS_CLASS_INT32_ARRAY ),
-    JS_CFUNC_MAGIC_DEF("getUint32", 1, js_dataview_getValue, JS_CLASS_UINT32_ARRAY ),
-#ifdef CONFIG_BIGNUM
-    JS_CFUNC_MAGIC_DEF("getBigInt64", 1, js_dataview_getValue, JS_CLASS_BIG_INT64_ARRAY ),
-    JS_CFUNC_MAGIC_DEF("getBigUint64", 1, js_dataview_getValue, JS_CLASS_BIG_UINT64_ARRAY ),
-#endif
-    JS_CFUNC_MAGIC_DEF("getFloat32", 1, js_dataview_getValue, JS_CLASS_FLOAT32_ARRAY ),
-    JS_CFUNC_MAGIC_DEF("getFloat64", 1, js_dataview_getValue, JS_CLASS_FLOAT64_ARRAY ),
-    JS_CFUNC_MAGIC_DEF("setInt8", 2, js_dataview_setValue, JS_CLASS_INT8_ARRAY ),
-    JS_CFUNC_MAGIC_DEF("setUint8", 2, js_dataview_setValue, JS_CLASS_UINT8_ARRAY ),
-    JS_CFUNC_MAGIC_DEF("setInt16", 2, js_dataview_setValue, JS_CLASS_INT16_ARRAY ),
-    JS_CFUNC_MAGIC_DEF("setUint16", 2, js_dataview_setValue, JS_CLASS_UINT16_ARRAY ),
-    JS_CFUNC_MAGIC_DEF("setInt32", 2, js_dataview_setValue, JS_CLASS_INT32_ARRAY ),
-    JS_CFUNC_MAGIC_DEF("setUint32", 2, js_dataview_setValue, JS_CLASS_UINT32_ARRAY ),
-#ifdef CONFIG_BIGNUM
-    JS_CFUNC_MAGIC_DEF("setBigInt64", 2, js_dataview_setValue, JS_CLASS_BIG_INT64_ARRAY ),
-    JS_CFUNC_MAGIC_DEF("setBigUint64", 2, js_dataview_setValue, JS_CLASS_BIG_UINT64_ARRAY ),
-#endif
-    JS_CFUNC_MAGIC_DEF("setFloat32", 2, js_dataview_setValue, JS_CLASS_FLOAT32_ARRAY ),
-    JS_CFUNC_MAGIC_DEF("setFloat64", 2, js_dataview_setValue, JS_CLASS_FLOAT64_ARRAY ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "DataView", JS_PROP_CONFIGURABLE ),
-};
-
-/* Atomics */
-#ifdef CONFIG_ATOMICS
-
-typedef enum AtomicsOpEnum {
-    ATOMICS_OP_ADD,
-    ATOMICS_OP_AND,
-    ATOMICS_OP_OR,
-    ATOMICS_OP_SUB,
-    ATOMICS_OP_XOR,
-    ATOMICS_OP_EXCHANGE,
-    ATOMICS_OP_COMPARE_EXCHANGE,
-    ATOMICS_OP_LOAD,
-} AtomicsOpEnum;
-
-static void *js_atomics_get_ptr(JSContext *ctx,
-                                JSArrayBuffer **pabuf,
-                                int *psize_log2, JSClassID *pclass_id,
-                                JSValueConst obj, JSValueConst idx_val,
-                                int is_waitable)
-{
-    JSObject *p;
-    JSTypedArray *ta;
-    JSArrayBuffer *abuf;
-    void *ptr;
-    uint64_t idx;
-    BOOL err;
-    int size_log2;
-
-    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
-        goto fail;
-    p = JS_VALUE_GET_OBJ(obj);
-#ifdef CONFIG_BIGNUM
-    if (is_waitable)
-        err = (p->class_id != JS_CLASS_INT32_ARRAY &&
-               p->class_id != JS_CLASS_BIG_INT64_ARRAY);
-    else
-        err = !(p->class_id >= JS_CLASS_INT8_ARRAY &&
-                p->class_id <= JS_CLASS_BIG_UINT64_ARRAY);
-#else
-    if (is_waitable)
-        err = (p->class_id != JS_CLASS_INT32_ARRAY);
-    else
-        err = !(p->class_id >= JS_CLASS_INT8_ARRAY &&
-                p->class_id <= JS_CLASS_UINT32_ARRAY);
-#endif
-    if (err) {
-    fail:
-        JS_ThrowTypeError(ctx, "integer TypedArray expected");
-        return NULL;
-    }
-    ta = p->u.typed_array;
-    abuf = ta->buffer->u.array_buffer;
-    if (!abuf->shared) {
-        if (is_waitable == 2) {
-            JS_ThrowTypeError(ctx, "not a SharedArrayBuffer TypedArray");
-            return NULL;
-        }
-        if (abuf->detached) {
-            JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-            return NULL;
-        }
-    }
-    if (JS_ToIndex(ctx, &idx, idx_val)) {
-        return NULL;
-    }
-    /* if the array buffer is detached, p->u.array.count = 0 */
-    if (idx >= p->u.array.count) {
-        JS_ThrowRangeError(ctx, "out-of-bound access");
-        return NULL;
-    }
-    size_log2 = typed_array_size_log2(p->class_id);
-    ptr = p->u.array.u.uint8_ptr + ((uintptr_t)idx << size_log2);
-    if (pabuf)
-        *pabuf = abuf;
-    if (psize_log2)
-        *psize_log2 = size_log2;
-    if (pclass_id)
-        *pclass_id = p->class_id;
-    return ptr;
-}
-
-static JSValue js_atomics_op(JSContext *ctx,
-                             JSValueConst this_obj,
-                             int argc, JSValueConst *argv, int op)
-{
-    int size_log2;
-#ifdef CONFIG_BIGNUM
-    uint64_t v, a, rep_val;
-#else
-    uint32_t v, a, rep_val;
-#endif
-    void *ptr;
-    JSValue ret;
-    JSClassID class_id;
-    JSArrayBuffer *abuf;
-
-    ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, &class_id,
-                             argv[0], argv[1], 0);
-    if (!ptr)
-        return JS_EXCEPTION;
-    rep_val = 0;
-    if (op == ATOMICS_OP_LOAD) {
-        v = 0;
-    } else {
-#ifdef CONFIG_BIGNUM
-        if (size_log2 == 3) {
-            int64_t v64;
-            if (JS_ToBigInt64(ctx, &v64, argv[2]))
-                return JS_EXCEPTION;
-            v = v64;
-            if (op == ATOMICS_OP_COMPARE_EXCHANGE) {
-                if (JS_ToBigInt64(ctx, &v64, argv[3]))
-                    return JS_EXCEPTION;
-                rep_val = v64;
-            }
-        } else
-#endif
-        {
-                uint32_t v32;
-                if (JS_ToUint32(ctx, &v32, argv[2]))
-                    return JS_EXCEPTION;
-                v = v32;
-                if (op == ATOMICS_OP_COMPARE_EXCHANGE) {
-                    if (JS_ToUint32(ctx, &v32, argv[3]))
-                        return JS_EXCEPTION;
-                    rep_val = v32;
-                }
-        }
-        if (abuf->detached)
-            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-   }
-
-   switch(op | (size_log2 << 3)) {
-            
-#ifdef CONFIG_BIGNUM
-#define OP(op_name, func_name)                          \
-    case ATOMICS_OP_ ## op_name | (0 << 3):             \
-       a = func_name((_Atomic(uint8_t) *)ptr, v);       \
-       break;                                           \
-    case ATOMICS_OP_ ## op_name | (1 << 3):             \
-        a = func_name((_Atomic(uint16_t) *)ptr, v);     \
-        break;                                          \
-    case ATOMICS_OP_ ## op_name | (2 << 3):             \
-        a = func_name((_Atomic(uint32_t) *)ptr, v);     \
-        break;                                          \
-    case ATOMICS_OP_ ## op_name | (3 << 3):             \
-        a = func_name((_Atomic(uint64_t) *)ptr, v);     \
-        break;
-#else
-#define OP(op_name, func_name)                          \
-    case ATOMICS_OP_ ## op_name | (0 << 3):             \
-       a = func_name((_Atomic(uint8_t) *)ptr, v);       \
-       break;                                           \
-    case ATOMICS_OP_ ## op_name | (1 << 3):             \
-        a = func_name((_Atomic(uint16_t) *)ptr, v);     \
-        break;                                          \
-    case ATOMICS_OP_ ## op_name | (2 << 3):             \
-        a = func_name((_Atomic(uint32_t) *)ptr, v);     \
-        break;
-#endif
-        OP(ADD, atomic_fetch_add)
-        OP(AND, atomic_fetch_and)
-        OP(OR, atomic_fetch_or)
-        OP(SUB, atomic_fetch_sub)
-        OP(XOR, atomic_fetch_xor)
-        OP(EXCHANGE, atomic_exchange)
-#undef OP
-
-    case ATOMICS_OP_LOAD | (0 << 3):
-        a = atomic_load((_Atomic(uint8_t) *)ptr);
-        break;
-    case ATOMICS_OP_LOAD | (1 << 3):
-        a = atomic_load((_Atomic(uint16_t) *)ptr);
-        break;
-    case ATOMICS_OP_LOAD | (2 << 3):
-        a = atomic_load((_Atomic(uint32_t) *)ptr);
-        break;
-#ifdef CONFIG_BIGNUM
-    case ATOMICS_OP_LOAD | (3 << 3):
-        a = atomic_load((_Atomic(uint64_t) *)ptr);
-        break;
-#endif
-        
-    case ATOMICS_OP_COMPARE_EXCHANGE | (0 << 3):
-        {
-            uint8_t v1 = v;
-            atomic_compare_exchange_strong((_Atomic(uint8_t) *)ptr, &v1, rep_val);
-            a = v1;
-        }
-        break;
-    case ATOMICS_OP_COMPARE_EXCHANGE | (1 << 3):
-        {
-            uint16_t v1 = v;
-            atomic_compare_exchange_strong((_Atomic(uint16_t) *)ptr, &v1, rep_val);
-            a = v1;
-        }
-        break;
-    case ATOMICS_OP_COMPARE_EXCHANGE | (2 << 3):
-        {
-            uint32_t v1 = v;
-            atomic_compare_exchange_strong((_Atomic(uint32_t) *)ptr, &v1, rep_val);
-            a = v1;
-        }
-        break;
-#ifdef CONFIG_BIGNUM
-    case ATOMICS_OP_COMPARE_EXCHANGE | (3 << 3):
-        {
-            uint64_t v1 = v;
-            atomic_compare_exchange_strong((_Atomic(uint64_t) *)ptr, &v1, rep_val);
-            a = v1;
-        }
-        break;
-#endif
-    default:
-        abort();
-    }
-
-    switch(class_id) {
-    case JS_CLASS_INT8_ARRAY:
-        a = (int8_t)a;
-        goto done;
-    case JS_CLASS_UINT8_ARRAY:
-        a = (uint8_t)a;
-        goto done;
-    case JS_CLASS_INT16_ARRAY:
-        a = (int16_t)a;
-        goto done;
-    case JS_CLASS_UINT16_ARRAY:
-        a = (uint16_t)a;
-        goto done;
-    case JS_CLASS_INT32_ARRAY:
-    done:
-        ret = JS_NewInt32(ctx, a);
-        break;
-    case JS_CLASS_UINT32_ARRAY:
-        ret = JS_NewUint32(ctx, a);
-        break;
-#ifdef CONFIG_BIGNUM
-    case JS_CLASS_BIG_INT64_ARRAY:
-        ret = JS_NewBigInt64(ctx, a);
-        break;
-    case JS_CLASS_BIG_UINT64_ARRAY:
-        ret = JS_NewBigUint64(ctx, a);
-        break;
-#endif
-    default:
-        abort();
-    }
-    return ret;
-}
-
-static JSValue js_atomics_store(JSContext *ctx,
-                                JSValueConst this_obj,
-                                int argc, JSValueConst *argv)
-{
-    int size_log2;
-    void *ptr;
-    JSValue ret;
-    JSArrayBuffer *abuf;
-
-    ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, NULL,
-                             argv[0], argv[1], 0);
-    if (!ptr)
-        return JS_EXCEPTION;
-#ifdef CONFIG_BIGNUM
-    if (size_log2 == 3) {
-        int64_t v64;
-        ret = JS_ToBigIntValueFree(ctx, JS_DupValue(ctx, argv[2]));
-        if (JS_IsException(ret))
-            return ret;
-        if (JS_ToBigInt64(ctx, &v64, ret)) {
-            JS_FreeValue(ctx, ret);
-            return JS_EXCEPTION;
-        }
-        if (abuf->detached)
-            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-        atomic_store((_Atomic(uint64_t) *)ptr, v64);
-    } else
-#endif
-    {
-        uint32_t v;
-        /* XXX: spec, would be simpler to return the written value */
-        ret = JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[2]));
-        if (JS_IsException(ret))
-            return ret;
-        if (JS_ToUint32(ctx, &v, ret)) {
-            JS_FreeValue(ctx, ret);
-            return JS_EXCEPTION;
-        }
-        if (abuf->detached)
-            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-        switch(size_log2) {
-        case 0:
-            atomic_store((_Atomic(uint8_t) *)ptr, v);
-            break;
-        case 1:
-            atomic_store((_Atomic(uint16_t) *)ptr, v);
-            break;
-        case 2:
-            atomic_store((_Atomic(uint32_t) *)ptr, v);
-            break;
-        default:
-            abort();
-        }
-    }
-    return ret;
-}
-
-static JSValue js_atomics_isLockFree(JSContext *ctx,
-                                     JSValueConst this_obj,
-                                     int argc, JSValueConst *argv)
-{
-    int v, ret;
-    if (JS_ToInt32Sat(ctx, &v, argv[0]))
-        return JS_EXCEPTION;
-    ret = (v == 1 || v == 2 || v == 4
-#ifdef CONFIG_BIGNUM
-           || v == 8
-#endif
-           );
-    return JS_NewBool(ctx, ret);
-}
-
-typedef struct JSAtomicsWaiter {
-    struct list_head link;
-    BOOL linked;
-    pthread_cond_t cond;
-    int32_t *ptr;
-} JSAtomicsWaiter;
-
-static pthread_mutex_t js_atomics_mutex = PTHREAD_MUTEX_INITIALIZER;
-static struct list_head js_atomics_waiter_list =
-    LIST_HEAD_INIT(js_atomics_waiter_list);
-
-static JSValue js_atomics_wait(JSContext *ctx,
-                               JSValueConst this_obj,
-                               int argc, JSValueConst *argv)
-{
-    int64_t v;
-    int32_t v32;
-    void *ptr;
-    int64_t timeout;
-    struct timespec ts;
-    JSAtomicsWaiter waiter_s, *waiter;
-    int ret, size_log2, res;
-    double d;
-
-    ptr = js_atomics_get_ptr(ctx, NULL, &size_log2, NULL,
-                             argv[0], argv[1], 2);
-    if (!ptr)
-        return JS_EXCEPTION;
-#ifdef CONFIG_BIGNUM
-    if (size_log2 == 3) {
-        if (JS_ToBigInt64(ctx, &v, argv[2]))
-            return JS_EXCEPTION;
-    } else
-#endif
-    {        
-        if (JS_ToInt32(ctx, &v32, argv[2]))
-            return JS_EXCEPTION;
-        v = v32;
-    }
-    if (JS_ToFloat64(ctx, &d, argv[3]))
-        return JS_EXCEPTION;
-    if (isnan(d) || d > INT64_MAX)
-        timeout = INT64_MAX;
-    else if (d < 0)
-        timeout = 0;
-    else
-        timeout = (int64_t)d;
-    if (!ctx->rt->can_block)
-        return JS_ThrowTypeError(ctx, "cannot block in this thread");
-
-    /* XXX: inefficient if large number of waiters, should hash on
-       'ptr' value */
-    /* XXX: use Linux futexes when available ? */
-    pthread_mutex_lock(&js_atomics_mutex);
-    if (size_log2 == 3) {
-        res = *(int64_t *)ptr != v;
-    } else {
-        res = *(int32_t *)ptr != v;
-    }
-    if (res) {
-        pthread_mutex_unlock(&js_atomics_mutex);
-        return JS_AtomToString(ctx, JS_ATOM_not_equal);
-    }
-
-    waiter = &waiter_s;
-    waiter->ptr = ptr;
-    pthread_cond_init(&waiter->cond, NULL);
-    waiter->linked = TRUE;
-    list_add_tail(&waiter->link, &js_atomics_waiter_list);
-
-    if (timeout == INT64_MAX) {
-        pthread_cond_wait(&waiter->cond, &js_atomics_mutex);
-        ret = 0;
-    } else {
-        /* XXX: use clock monotonic */
-        clock_gettime(CLOCK_REALTIME, &ts);
-        ts.tv_sec += timeout / 1000;
-        ts.tv_nsec += (timeout % 1000) * 1000000;
-        if (ts.tv_nsec >= 1000000000) {
-            ts.tv_nsec -= 1000000000;
-            ts.tv_sec++;
-        }
-        ret = pthread_cond_timedwait(&waiter->cond, &js_atomics_mutex,
-                                     &ts);
-    }
-    if (waiter->linked)
-        list_del(&waiter->link);
-    pthread_mutex_unlock(&js_atomics_mutex);
-    pthread_cond_destroy(&waiter->cond);
-    if (ret == ETIMEDOUT) {
-        return JS_AtomToString(ctx, JS_ATOM_timed_out);
-    } else {
-        return JS_AtomToString(ctx, JS_ATOM_ok);
-    }
-}
-
-static JSValue js_atomics_notify(JSContext *ctx,
-                                 JSValueConst this_obj,
-                                 int argc, JSValueConst *argv)
-{
-    struct list_head *el, *el1, waiter_list;
-    int32_t count, n;
-    void *ptr;
-    JSAtomicsWaiter *waiter;
-    JSArrayBuffer *abuf;
-
-    ptr = js_atomics_get_ptr(ctx, &abuf, NULL, NULL, argv[0], argv[1], 1);
-    if (!ptr)
-        return JS_EXCEPTION;
-
-    if (JS_IsUndefined(argv[2])) {
-        count = INT32_MAX;
-    } else {
-        if (JS_ToInt32Clamp(ctx, &count, argv[2], 0, INT32_MAX, 0))
-            return JS_EXCEPTION;
-    }
-    if (abuf->detached)
-        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
-
-    n = 0;
-    if (abuf->shared && count > 0) {
-        pthread_mutex_lock(&js_atomics_mutex);
-        init_list_head(&waiter_list);
-        list_for_each_safe(el, el1, &js_atomics_waiter_list) {
-            waiter = list_entry(el, JSAtomicsWaiter, link);
-            if (waiter->ptr == ptr) {
-                list_del(&waiter->link);
-                waiter->linked = FALSE;
-                list_add_tail(&waiter->link, &waiter_list);
-                n++;
-                if (n >= count)
-                    break;
-            }
-        }
-        list_for_each(el, &waiter_list) {
-            waiter = list_entry(el, JSAtomicsWaiter, link);
-            pthread_cond_signal(&waiter->cond);
-        }
-        pthread_mutex_unlock(&js_atomics_mutex);
-    }
-    return JS_NewInt32(ctx, n);
-}
-
-static const JSCFunctionListEntry js_atomics_funcs[] = {
-    JS_CFUNC_MAGIC_DEF("add", 3, js_atomics_op, ATOMICS_OP_ADD ),
-    JS_CFUNC_MAGIC_DEF("and", 3, js_atomics_op, ATOMICS_OP_AND ),
-    JS_CFUNC_MAGIC_DEF("or", 3, js_atomics_op, ATOMICS_OP_OR ),
-    JS_CFUNC_MAGIC_DEF("sub", 3, js_atomics_op, ATOMICS_OP_SUB ),
-    JS_CFUNC_MAGIC_DEF("xor", 3, js_atomics_op, ATOMICS_OP_XOR ),
-    JS_CFUNC_MAGIC_DEF("exchange", 3, js_atomics_op, ATOMICS_OP_EXCHANGE ),
-    JS_CFUNC_MAGIC_DEF("compareExchange", 4, js_atomics_op, ATOMICS_OP_COMPARE_EXCHANGE ),
-    JS_CFUNC_MAGIC_DEF("load", 2, js_atomics_op, ATOMICS_OP_LOAD ),
-    JS_CFUNC_DEF("store", 3, js_atomics_store ),
-    JS_CFUNC_DEF("isLockFree", 1, js_atomics_isLockFree ),
-    JS_CFUNC_DEF("wait", 4, js_atomics_wait ),
-    JS_CFUNC_DEF("notify", 3, js_atomics_notify ),
-    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Atomics", JS_PROP_CONFIGURABLE ),
-};
-
-static const JSCFunctionListEntry js_atomics_obj[] = {
-    JS_OBJECT_DEF("Atomics", js_atomics_funcs, countof(js_atomics_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
-};
-
-void JS_AddIntrinsicAtomics(JSContext *ctx)
-{
-    /* add Atomics as autoinit object */
-    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_atomics_obj, countof(js_atomics_obj));
-}
-
-#endif /* CONFIG_ATOMICS */
-
-void JS_AddIntrinsicTypedArrays(JSContext *ctx)
-{
-    JSValue typed_array_base_proto, typed_array_base_func;
-    JSValueConst array_buffer_func, shared_array_buffer_func;
-    int i;
-
-    ctx->class_proto[JS_CLASS_ARRAY_BUFFER] = JS_NewObject(ctx);
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY_BUFFER],
-                               js_array_buffer_proto_funcs,
-                               countof(js_array_buffer_proto_funcs));
-
-    array_buffer_func = JS_NewGlobalCConstructorOnly(ctx, "ArrayBuffer",
-                                                 js_array_buffer_constructor, 1,
-                                                 ctx->class_proto[JS_CLASS_ARRAY_BUFFER]);
-    JS_SetPropertyFunctionList(ctx, array_buffer_func,
-                               js_array_buffer_funcs,
-                               countof(js_array_buffer_funcs));
-
-    ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER] = JS_NewObject(ctx);
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER],
-                               js_shared_array_buffer_proto_funcs,
-                               countof(js_shared_array_buffer_proto_funcs));
-
-    shared_array_buffer_func = JS_NewGlobalCConstructorOnly(ctx, "SharedArrayBuffer",
-                                                 js_shared_array_buffer_constructor, 1,
-                                                 ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER]);
-    JS_SetPropertyFunctionList(ctx, shared_array_buffer_func,
-                               js_shared_array_buffer_funcs,
-                               countof(js_shared_array_buffer_funcs));
-
-    typed_array_base_proto = JS_NewObject(ctx);
-    JS_SetPropertyFunctionList(ctx, typed_array_base_proto,
-                               js_typed_array_base_proto_funcs,
-                               countof(js_typed_array_base_proto_funcs));
-
-    /* TypedArray.prototype.toString must be the same object as Array.prototype.toString */
-    JSValue obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_toString);
-    /* XXX: should use alias method in JSCFunctionListEntry */ //@@@
-    JS_DefinePropertyValue(ctx, typed_array_base_proto, JS_ATOM_toString, obj,
-                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
-
-    typed_array_base_func = JS_NewCFunction(ctx, js_typed_array_base_constructor,
-                                            "TypedArray", 0);
-    JS_SetPropertyFunctionList(ctx, typed_array_base_func,
-                               js_typed_array_base_funcs,
-                               countof(js_typed_array_base_funcs));
-    JS_SetConstructor(ctx, typed_array_base_func, typed_array_base_proto);
-
-    for(i = JS_CLASS_UINT8C_ARRAY; i < JS_CLASS_UINT8C_ARRAY + JS_TYPED_ARRAY_COUNT; i++) {
-        JSValue func_obj;
-        char buf[ATOM_GET_STR_BUF_SIZE];
-        const char *name;
-
-        ctx->class_proto[i] = JS_NewObjectProto(ctx, typed_array_base_proto);
-        JS_DefinePropertyValueStr(ctx, ctx->class_proto[i],
-                                  "BYTES_PER_ELEMENT",
-                                  JS_NewInt32(ctx, 1 << typed_array_size_log2(i)),
-                                  0);
-        name = JS_AtomGetStr(ctx, buf, sizeof(buf),
-                             JS_ATOM_Uint8ClampedArray + i - JS_CLASS_UINT8C_ARRAY);
-        func_obj = JS_NewCFunction3(ctx, (JSCFunction *)js_typed_array_constructor,
-                                    name, 3, JS_CFUNC_constructor_magic, i,
-                                    typed_array_base_func);
-        JS_NewGlobalCConstructor2(ctx, func_obj, name, ctx->class_proto[i]);
-        JS_DefinePropertyValueStr(ctx, func_obj,
-                                  "BYTES_PER_ELEMENT",
-                                  JS_NewInt32(ctx, 1 << typed_array_size_log2(i)),
-                                  0);
-    }
-    JS_FreeValue(ctx, typed_array_base_proto);
-    JS_FreeValue(ctx, typed_array_base_func);
-
-    /* DataView */
-    ctx->class_proto[JS_CLASS_DATAVIEW] = JS_NewObject(ctx);
-    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_DATAVIEW],
-                               js_dataview_proto_funcs,
-                               countof(js_dataview_proto_funcs));
-    JS_NewGlobalCConstructorOnly(ctx, "DataView",
-                                 js_dataview_constructor, 1,
-                                 ctx->class_proto[JS_CLASS_DATAVIEW]);
-    /* Atomics */
-#ifdef CONFIG_ATOMICS
-    JS_AddIntrinsicAtomics(ctx);
-#endif
-}
diff --git a/src/core/base.h b/src/core/base.h
new file mode 100644
index 000000000..f02747fc8
--- /dev/null
+++ b/src/core/base.h
@@ -0,0 +1,119 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+*/
+
+#ifndef QUICKJS_BASE_H
+#define QUICKJS_BASE_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <time.h>
+#include <fenv.h>
+#include <math.h>
+#if defined(__APPLE__)
+#include <malloc/malloc.h>
+#elif defined(__linux__)
+#include <malloc.h>
+#elif defined(__FreeBSD__)
+#include <malloc_np.h>
+#endif
+
+#ifdef CONFIG_BIGNUM
+#include "quickjs/libbf.h"
+#endif
+
+#define OPTIMIZE         1
+#define SHORT_OPCODES    1
+#if defined(EMSCRIPTEN)
+#define DIRECT_DISPATCH  0
+#else
+#define DIRECT_DISPATCH  1
+#endif
+
+#if defined(__APPLE__)
+#define MALLOC_OVERHEAD  0
+#else
+#define MALLOC_OVERHEAD  8
+#endif
+
+#if !defined(_WIN32)
+/* define it if printf uses the RNDN rounding mode instead of RNDNA */
+#define CONFIG_PRINTF_RNDN
+#endif
+
+/* define to include Atomics.* operations which depend on the OS
+   threads */
+#if !defined(EMSCRIPTEN)
+#define CONFIG_ATOMICS
+#endif
+
+#if !defined(EMSCRIPTEN)
+/* enable stack limitation */
+#define CONFIG_STACK_CHECK
+#endif
+
+
+/* dump object free */
+//#define DUMP_FREE
+//#define DUMP_CLOSURE
+/* dump the bytecode of the compiled functions: combination of bits
+   1: dump pass 3 final byte code
+   2: dump pass 2 code
+   4: dump pass 1 code
+   8: dump stdlib functions
+  16: dump bytecode in hex
+  32: dump line number table
+ */
+//#define DUMP_BYTECODE  (1)
+/* dump the occurence of the automatic GC */
+//#define DUMP_GC
+/* dump objects freed by the garbage collector */
+//#define DUMP_GC_FREE
+/* dump objects leaking when freeing the runtime */
+//#define DUMP_LEAKS  1
+/* dump memory usage before running the garbage collector */
+//#define DUMP_MEM
+//#define DUMP_OBJECTS    /* dump objects in JS_FreeContext */
+//#define DUMP_ATOMS      /* dump atoms in JS_FreeContext */
+//#define DUMP_SHAPES     /* dump shapes in JS_FreeContext */
+//#define DUMP_MODULE_RESOLVE
+//#define DUMP_PROMISE
+//#define DUMP_READ_OBJECT
+
+/* test the GC by forcing it before each object allocation */
+//#define FORCE_GC_AT_MALLOC
+
+#ifdef CONFIG_ATOMICS
+#include <pthread.h>
+#include <stdatomic.h>
+#include <errno.h>
+#endif
+
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-array.c b/src/core/builtins/js-array.c
new file mode 100644
index 000000000..87304d034
--- /dev/null
+++ b/src/core/builtins/js-array.c
@@ -0,0 +1,1753 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-array.h"
+#include "../convertion.h"
+#include "../exception.h"
+#include "../function.h"
+#include "../object.h"
+#include "../runtime.h"
+#include "../string.h"
+#include "js-function.h"
+#include "js-object.h"
+#include "js-operator.h"
+#include "js-typed-array.h"
+
+void js_array_finalizer(JSRuntime* rt, JSValue val) {
+  JSObject* p = JS_VALUE_GET_OBJ(val);
+  int i;
+
+  for (i = 0; i < p->u.array.count; i++) {
+    JS_FreeValueRT(rt, p->u.array.u.values[i]);
+  }
+  js_free_rt(rt, p->u.array.u.values);
+}
+
+void js_array_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func) {
+  JSObject* p = JS_VALUE_GET_OBJ(val);
+  int i;
+
+  for (i = 0; i < p->u.array.count; i++) {
+    JS_MarkValue(rt, p->u.array.u.values[i], mark_func);
+  }
+}
+
+JSValue js_create_iterator_result(JSContext* ctx, JSValue val, BOOL done) {
+  JSValue obj;
+  obj = JS_NewObject(ctx);
+  if (JS_IsException(obj)) {
+    JS_FreeValue(ctx, val);
+    return obj;
+  }
+  if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_value, val, JS_PROP_C_W_E) < 0) {
+    goto fail;
+  }
+  if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_done, JS_NewBool(ctx, done), JS_PROP_C_W_E) < 0) {
+  fail:
+    JS_FreeValue(ctx, obj);
+    return JS_EXCEPTION;
+  }
+  return obj;
+}
+
+BOOL js_is_fast_array(JSContext* ctx, JSValueConst obj) {
+  /* Try and handle fast arrays explicitly */
+  if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
+    JSObject* p = JS_VALUE_GET_OBJ(obj);
+    if (p->class_id == JS_CLASS_ARRAY && p->fast_array) {
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+/* Access an Array's internal JSValue array if available */
+BOOL js_get_fast_array(JSContext* ctx, JSValueConst obj, JSValue** arrpp, uint32_t* countp) {
+  /* Try and handle fast arrays explicitly */
+  if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
+    JSObject* p = JS_VALUE_GET_OBJ(obj);
+    if (p->class_id == JS_CLASS_ARRAY && p->fast_array) {
+      *countp = p->u.array.count;
+      *arrpp = p->u.array.u.values;
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+
+/* return -1 if exception */
+int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len)
+{
+  uint32_t new_size;
+  size_t slack;
+  JSValue *new_array_prop;
+  /* XXX: potential arithmetic overflow */
+  new_size = max_int(new_len, p->u.array.u1.size * 3 / 2);
+  new_array_prop = js_realloc2(ctx, p->u.array.u.values, sizeof(JSValue) * new_size, &slack);
+  if (!new_array_prop)
+    return -1;
+  new_size += slack / sizeof(*new_array_prop);
+  p->u.array.u.values = new_array_prop;
+  p->u.array.u1.size = new_size;
+  return 0;
+}
+
+__exception int js_append_enumerate(JSContext* ctx, JSValue* sp) {
+  JSValue iterator, enumobj, method, value;
+  int is_array_iterator;
+  JSValue* arrp;
+  uint32_t i, count32, pos;
+
+  if (JS_VALUE_GET_TAG(sp[-2]) != JS_TAG_INT) {
+    JS_ThrowInternalError(ctx, "invalid index for append");
+    return -1;
+  }
+
+  pos = JS_VALUE_GET_INT(sp[-2]);
+
+  /* XXX: further optimisations:
+     - use ctx->array_proto_values?
+     - check if array_iterator_prototype next method is built-in and
+       avoid constructing actual iterator object?
+     - build this into js_for_of_start and use in all `for (x of o)` loops
+   */
+  iterator = JS_GetProperty(ctx, sp[-1], JS_ATOM_Symbol_iterator);
+  if (JS_IsException(iterator))
+    return -1;
+  is_array_iterator = JS_IsCFunction(ctx, iterator, (JSCFunction*)js_create_array_iterator, JS_ITERATOR_KIND_VALUE);
+  JS_FreeValue(ctx, iterator);
+
+  enumobj = JS_GetIterator(ctx, sp[-1], FALSE);
+  if (JS_IsException(enumobj))
+    return -1;
+  method = JS_GetProperty(ctx, enumobj, JS_ATOM_next);
+  if (JS_IsException(method)) {
+    JS_FreeValue(ctx, enumobj);
+    return -1;
+  }
+  if (is_array_iterator && JS_IsCFunction(ctx, method, (JSCFunction*)js_array_iterator_next, 0) && js_get_fast_array(ctx, sp[-1], &arrp, &count32)) {
+    uint32_t len;
+    if (js_get_length32(ctx, &len, sp[-1]))
+      goto exception;
+    /* if len > count32, the elements >= count32 might be read in
+       the prototypes and might have side effects */
+    if (len != count32)
+      goto general_case;
+    /* Handle fast arrays explicitly */
+    for (i = 0; i < count32; i++) {
+      if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, JS_DupValue(ctx, arrp[i]), JS_PROP_C_W_E) < 0)
+        goto exception;
+    }
+  } else {
+  general_case:
+    for (;;) {
+      BOOL done;
+      value = JS_IteratorNext(ctx, enumobj, method, 0, NULL, &done);
+      if (JS_IsException(value))
+        goto exception;
+      if (done) {
+        /* value is JS_UNDEFINED */
+        break;
+      }
+      if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, value, JS_PROP_C_W_E) < 0)
+        goto exception;
+    }
+  }
+  /* Note: could raise an error if too many elements */
+  sp[-2] = JS_NewInt32(ctx, pos);
+  JS_FreeValue(ctx, enumobj);
+  JS_FreeValue(ctx, method);
+  return 0;
+
+exception:
+  JS_IteratorClose(ctx, enumobj, TRUE);
+  JS_FreeValue(ctx, enumobj);
+  JS_FreeValue(ctx, method);
+  return -1;
+}
+
+/* Array */
+
+int JS_CopySubArray(JSContext* ctx, JSValueConst obj, int64_t to_pos, int64_t from_pos, int64_t count, int dir) {
+  int64_t i, from, to;
+  JSValue val;
+  int fromPresent;
+
+  /* XXX: should special case fast arrays */
+  for (i = 0; i < count; i++) {
+    if (dir < 0) {
+      from = from_pos + count - i - 1;
+      to = to_pos + count - i - 1;
+    } else {
+      from = from_pos + i;
+      to = to_pos + i;
+    }
+    fromPresent = JS_TryGetPropertyInt64(ctx, obj, from, &val);
+    if (fromPresent < 0)
+      goto exception;
+
+    if (fromPresent) {
+      if (JS_SetPropertyInt64(ctx, obj, to, val) < 0)
+        goto exception;
+    } else {
+      if (JS_DeletePropertyInt64(ctx, obj, to, JS_PROP_THROW) < 0)
+        goto exception;
+    }
+  }
+  return 0;
+
+exception:
+  return -1;
+}
+
+JSValue js_array_constructor(JSContext* ctx, JSValueConst new_target, int argc, JSValueConst* argv) {
+  JSValue obj;
+  int i;
+
+  obj = js_create_from_ctor(ctx, new_target, JS_CLASS_ARRAY);
+  if (JS_IsException(obj))
+    return obj;
+  if (argc == 1 && JS_IsNumber(argv[0])) {
+    uint32_t len;
+    if (JS_ToArrayLengthFree(ctx, &len, JS_DupValue(ctx, argv[0]), TRUE))
+      goto fail;
+    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, len)) < 0)
+      goto fail;
+  } else {
+    for (i = 0; i < argc; i++) {
+      if (JS_SetPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i])) < 0)
+        goto fail;
+    }
+  }
+  return obj;
+fail:
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+JSValue js_array_from(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  // from(items, mapfn = void 0, this_arg = void 0)
+  JSValueConst items = argv[0], mapfn, this_arg;
+  JSValueConst args[2];
+  JSValue stack[2];
+  JSValue iter, r, v, v2, arrayLike;
+  int64_t k, len;
+  int done, mapping;
+
+  mapping = FALSE;
+  mapfn = JS_UNDEFINED;
+  this_arg = JS_UNDEFINED;
+  r = JS_UNDEFINED;
+  arrayLike = JS_UNDEFINED;
+  stack[0] = JS_UNDEFINED;
+  stack[1] = JS_UNDEFINED;
+
+  if (argc > 1) {
+    mapfn = argv[1];
+    if (!JS_IsUndefined(mapfn)) {
+      if (check_function(ctx, mapfn))
+        goto exception;
+      mapping = 1;
+      if (argc > 2)
+        this_arg = argv[2];
+    }
+  }
+  iter = JS_GetProperty(ctx, items, JS_ATOM_Symbol_iterator);
+  if (JS_IsException(iter))
+    goto exception;
+  if (!JS_IsUndefined(iter)) {
+    JS_FreeValue(ctx, iter);
+    if (JS_IsConstructor(ctx, this_val))
+      r = JS_CallConstructor(ctx, this_val, 0, NULL);
+    else
+      r = JS_NewArray(ctx);
+    if (JS_IsException(r))
+      goto exception;
+    stack[0] = JS_DupValue(ctx, items);
+    if (js_for_of_start(ctx, &stack[1], FALSE))
+      goto exception;
+    for (k = 0;; k++) {
+      v = JS_IteratorNext(ctx, stack[0], stack[1], 0, NULL, &done);
+      if (JS_IsException(v))
+        goto exception_close;
+      if (done)
+        break;
+      if (mapping) {
+        args[0] = v;
+        args[1] = JS_NewInt32(ctx, k);
+        v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
+        JS_FreeValue(ctx, v);
+        v = v2;
+        if (JS_IsException(v))
+          goto exception_close;
+      }
+      if (JS_DefinePropertyValueInt64(ctx, r, k, v, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+        goto exception_close;
+    }
+  } else {
+    arrayLike = JS_ToObject(ctx, items);
+    if (JS_IsException(arrayLike))
+      goto exception;
+    if (js_get_length64(ctx, &len, arrayLike) < 0)
+      goto exception;
+    v = JS_NewInt64(ctx, len);
+    args[0] = v;
+    if (JS_IsConstructor(ctx, this_val)) {
+      r = JS_CallConstructor(ctx, this_val, 1, args);
+    } else {
+      r = js_array_constructor(ctx, JS_UNDEFINED, 1, args);
+    }
+    JS_FreeValue(ctx, v);
+    if (JS_IsException(r))
+      goto exception;
+    for (k = 0; k < len; k++) {
+      v = JS_GetPropertyInt64(ctx, arrayLike, k);
+      if (JS_IsException(v))
+        goto exception;
+      if (mapping) {
+        args[0] = v;
+        args[1] = JS_NewInt32(ctx, k);
+        v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
+        JS_FreeValue(ctx, v);
+        v = v2;
+        if (JS_IsException(v))
+          goto exception;
+      }
+      if (JS_DefinePropertyValueInt64(ctx, r, k, v, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+        goto exception;
+    }
+  }
+  if (JS_SetProperty(ctx, r, JS_ATOM_length, JS_NewUint32(ctx, k)) < 0)
+    goto exception;
+  goto done;
+
+exception_close:
+  if (!JS_IsUndefined(stack[0]))
+    JS_IteratorClose(ctx, stack[0], TRUE);
+exception:
+  JS_FreeValue(ctx, r);
+  r = JS_EXCEPTION;
+done:
+  JS_FreeValue(ctx, arrayLike);
+  JS_FreeValue(ctx, stack[0]);
+  JS_FreeValue(ctx, stack[1]);
+  return r;
+}
+
+JSValue js_array_of(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue obj, args[1];
+  int i;
+
+  if (JS_IsConstructor(ctx, this_val)) {
+    args[0] = JS_NewInt32(ctx, argc);
+    obj = JS_CallConstructor(ctx, this_val, 1, (JSValueConst*)args);
+  } else {
+    obj = JS_NewArray(ctx);
+  }
+  if (JS_IsException(obj))
+    return JS_EXCEPTION;
+  for (i = 0; i < argc; i++) {
+    if (JS_CreateDataPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i]), JS_PROP_THROW) < 0) {
+      goto fail;
+    }
+  }
+  if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, argc)) < 0) {
+  fail:
+    JS_FreeValue(ctx, obj);
+    return JS_EXCEPTION;
+  }
+  return obj;
+}
+
+JSValue js_array_isArray(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  int ret;
+  ret = JS_IsArray(ctx, argv[0]);
+  if (ret < 0)
+    return JS_EXCEPTION;
+  else
+    return JS_NewBool(ctx, ret);
+}
+
+JSValue js_get_this(JSContext* ctx, JSValueConst this_val) {
+  return JS_DupValue(ctx, this_val);
+}
+
+JSValue JS_ArraySpeciesCreate(JSContext* ctx, JSValueConst obj, JSValueConst len_val) {
+  JSValue ctor, ret, species;
+  int res;
+  JSContext* realm;
+
+  res = JS_IsArray(ctx, obj);
+  if (res < 0)
+    return JS_EXCEPTION;
+  if (!res)
+    return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);
+  ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);
+  if (JS_IsException(ctor))
+    return ctor;
+  if (JS_IsConstructor(ctx, ctor)) {
+    /* legacy web compatibility */
+    realm = JS_GetFunctionRealm(ctx, ctor);
+    if (!realm) {
+      JS_FreeValue(ctx, ctor);
+      return JS_EXCEPTION;
+    }
+    if (realm != ctx && js_same_value(ctx, ctor, realm->array_ctor)) {
+      JS_FreeValue(ctx, ctor);
+      ctor = JS_UNDEFINED;
+    }
+  }
+  if (JS_IsObject(ctor)) {
+    species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species);
+    JS_FreeValue(ctx, ctor);
+    if (JS_IsException(species))
+      return species;
+    ctor = species;
+    if (JS_IsNull(ctor))
+      ctor = JS_UNDEFINED;
+  }
+  if (JS_IsUndefined(ctor)) {
+    return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);
+  } else {
+    ret = JS_CallConstructor(ctx, ctor, 1, &len_val);
+    JS_FreeValue(ctx, ctor);
+    return ret;
+  }
+}
+
+int JS_isConcatSpreadable(JSContext* ctx, JSValueConst obj) {
+  JSValue val;
+
+  if (!JS_IsObject(obj))
+    return FALSE;
+  val = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_isConcatSpreadable);
+  if (JS_IsException(val))
+    return -1;
+  if (!JS_IsUndefined(val))
+    return JS_ToBoolFree(ctx, val);
+  return JS_IsArray(ctx, obj);
+}
+
+JSValue js_array_concat(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue obj, arr, val;
+  JSValueConst e;
+  int64_t len, k, n;
+  int i, res;
+
+  arr = JS_UNDEFINED;
+  obj = JS_ToObject(ctx, this_val);
+  if (JS_IsException(obj))
+    goto exception;
+
+  arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
+  if (JS_IsException(arr))
+    goto exception;
+  n = 0;
+  for (i = -1; i < argc; i++) {
+    if (i < 0)
+      e = obj;
+    else
+      e = argv[i];
+
+    res = JS_isConcatSpreadable(ctx, e);
+    if (res < 0)
+      goto exception;
+    if (res) {
+      if (js_get_length64(ctx, &len, e))
+        goto exception;
+      if (n + len > MAX_SAFE_INTEGER) {
+        JS_ThrowTypeError(ctx, "Array loo long");
+        goto exception;
+      }
+      for (k = 0; k < len; k++, n++) {
+        res = JS_TryGetPropertyInt64(ctx, e, k, &val);
+        if (res < 0)
+          goto exception;
+        if (res) {
+          if (JS_DefinePropertyValueInt64(ctx, arr, n, val, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+            goto exception;
+        }
+      }
+    } else {
+      if (n >= MAX_SAFE_INTEGER) {
+        JS_ThrowTypeError(ctx, "Array loo long");
+        goto exception;
+      }
+      if (JS_DefinePropertyValueInt64(ctx, arr, n, JS_DupValue(ctx, e), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+        goto exception;
+      n++;
+    }
+  }
+  if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0)
+    goto exception;
+
+  JS_FreeValue(ctx, obj);
+  return arr;
+
+exception:
+  JS_FreeValue(ctx, arr);
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+int js_typed_array_get_length_internal(JSContext* ctx, JSValueConst obj);
+
+JSValue js_typed_array___speciesCreate(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+
+JSValue js_array_every(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int special) {
+  JSValue obj, val, index_val, res, ret;
+  JSValueConst args[3];
+  JSValueConst func, this_arg;
+  int64_t len, k, n;
+  int present;
+
+  ret = JS_UNDEFINED;
+  val = JS_UNDEFINED;
+  if (special & special_TA) {
+    obj = JS_DupValue(ctx, this_val);
+    len = js_typed_array_get_length_internal(ctx, obj);
+    if (len < 0)
+      goto exception;
+  } else {
+    obj = JS_ToObject(ctx, this_val);
+    if (js_get_length64(ctx, &len, obj))
+      goto exception;
+  }
+  func = argv[0];
+  this_arg = JS_UNDEFINED;
+  if (argc > 1)
+    this_arg = argv[1];
+
+  if (check_function(ctx, func))
+    goto exception;
+
+  switch (special) {
+    case special_every:
+    case special_every | special_TA:
+      ret = JS_TRUE;
+      break;
+    case special_some:
+    case special_some | special_TA:
+      ret = JS_FALSE;
+      break;
+    case special_map:
+      /* XXX: JS_ArraySpeciesCreate should take int64_t */
+      ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt64(ctx, len));
+      if (JS_IsException(ret))
+        goto exception;
+      break;
+    case special_filter:
+      ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
+      if (JS_IsException(ret))
+        goto exception;
+      break;
+    case special_map | special_TA:
+      args[0] = obj;
+      args[1] = JS_NewInt32(ctx, len);
+      ret = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
+      if (JS_IsException(ret))
+        goto exception;
+      break;
+    case special_filter | special_TA:
+      ret = JS_NewArray(ctx);
+      if (JS_IsException(ret))
+        goto exception;
+      break;
+  }
+  n = 0;
+
+  for (k = 0; k < len; k++) {
+    if (special & special_TA) {
+      val = JS_GetPropertyInt64(ctx, obj, k);
+      if (JS_IsException(val))
+        goto exception;
+      present = TRUE;
+    } else {
+      present = JS_TryGetPropertyInt64(ctx, obj, k, &val);
+      if (present < 0)
+        goto exception;
+    }
+    if (present) {
+      index_val = JS_NewInt64(ctx, k);
+      if (JS_IsException(index_val))
+        goto exception;
+      args[0] = val;
+      args[1] = index_val;
+      args[2] = obj;
+      res = JS_Call(ctx, func, this_arg, 3, args);
+      JS_FreeValue(ctx, index_val);
+      if (JS_IsException(res))
+        goto exception;
+      switch (special) {
+        case special_every:
+        case special_every | special_TA:
+          if (!JS_ToBoolFree(ctx, res)) {
+            ret = JS_FALSE;
+            goto done;
+          }
+          break;
+        case special_some:
+        case special_some | special_TA:
+          if (JS_ToBoolFree(ctx, res)) {
+            ret = JS_TRUE;
+            goto done;
+          }
+          break;
+        case special_map:
+          if (JS_DefinePropertyValueInt64(ctx, ret, k, res, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+            goto exception;
+          break;
+        case special_map | special_TA:
+          if (JS_SetPropertyValue(ctx, ret, JS_NewInt32(ctx, k), res, JS_PROP_THROW) < 0)
+            goto exception;
+          break;
+        case special_filter:
+        case special_filter | special_TA:
+          if (JS_ToBoolFree(ctx, res)) {
+            if (JS_DefinePropertyValueInt64(ctx, ret, n++, JS_DupValue(ctx, val), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+              goto exception;
+          }
+          break;
+        default:
+          JS_FreeValue(ctx, res);
+          break;
+      }
+      JS_FreeValue(ctx, val);
+      val = JS_UNDEFINED;
+    }
+  }
+done:
+  if (special == (special_filter | special_TA)) {
+    JSValue arr;
+    args[0] = obj;
+    args[1] = JS_NewInt32(ctx, n);
+    arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
+    if (JS_IsException(arr))
+      goto exception;
+    args[0] = ret;
+    res = JS_Invoke(ctx, arr, JS_ATOM_set, 1, args);
+    if (check_exception_free(ctx, res))
+      goto exception;
+    JS_FreeValue(ctx, ret);
+    ret = arr;
+  }
+  JS_FreeValue(ctx, val);
+  JS_FreeValue(ctx, obj);
+  return ret;
+
+exception:
+  JS_FreeValue(ctx, ret);
+  JS_FreeValue(ctx, val);
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+JSValue js_array_reduce(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int special) {
+  JSValue obj, val, index_val, acc, acc1;
+  JSValueConst args[4];
+  JSValueConst func;
+  int64_t len, k, k1;
+  int present;
+
+  acc = JS_UNDEFINED;
+  val = JS_UNDEFINED;
+  if (special & special_TA) {
+    obj = JS_DupValue(ctx, this_val);
+    len = js_typed_array_get_length_internal(ctx, obj);
+    if (len < 0)
+      goto exception;
+  } else {
+    obj = JS_ToObject(ctx, this_val);
+    if (js_get_length64(ctx, &len, obj))
+      goto exception;
+  }
+  func = argv[0];
+
+  if (check_function(ctx, func))
+    goto exception;
+
+  k = 0;
+  if (argc > 1) {
+    acc = JS_DupValue(ctx, argv[1]);
+  } else {
+    for (;;) {
+      if (k >= len) {
+        JS_ThrowTypeError(ctx, "empty array");
+        goto exception;
+      }
+      k1 = (special & special_reduceRight) ? len - k - 1 : k;
+      k++;
+      if (special & special_TA) {
+        acc = JS_GetPropertyInt64(ctx, obj, k1);
+        if (JS_IsException(acc))
+          goto exception;
+        break;
+      } else {
+        present = JS_TryGetPropertyInt64(ctx, obj, k1, &acc);
+        if (present < 0)
+          goto exception;
+        if (present)
+          break;
+      }
+    }
+  }
+  for (; k < len; k++) {
+    k1 = (special & special_reduceRight) ? len - k - 1 : k;
+    if (special & special_TA) {
+      val = JS_GetPropertyInt64(ctx, obj, k1);
+      if (JS_IsException(val))
+        goto exception;
+      present = TRUE;
+    } else {
+      present = JS_TryGetPropertyInt64(ctx, obj, k1, &val);
+      if (present < 0)
+        goto exception;
+    }
+    if (present) {
+      index_val = JS_NewInt64(ctx, k1);
+      if (JS_IsException(index_val))
+        goto exception;
+      args[0] = acc;
+      args[1] = val;
+      args[2] = index_val;
+      args[3] = obj;
+      acc1 = JS_Call(ctx, func, JS_UNDEFINED, 4, args);
+      JS_FreeValue(ctx, index_val);
+      JS_FreeValue(ctx, val);
+      val = JS_UNDEFINED;
+      if (JS_IsException(acc1))
+        goto exception;
+      JS_FreeValue(ctx, acc);
+      acc = acc1;
+    }
+  }
+  JS_FreeValue(ctx, obj);
+  return acc;
+
+exception:
+  JS_FreeValue(ctx, acc);
+  JS_FreeValue(ctx, val);
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+JSValue js_array_fill(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue obj;
+  int64_t len, start, end;
+
+  obj = JS_ToObject(ctx, this_val);
+  if (js_get_length64(ctx, &len, obj))
+    goto exception;
+
+  start = 0;
+  if (argc > 1 && !JS_IsUndefined(argv[1])) {
+    if (JS_ToInt64Clamp(ctx, &start, argv[1], 0, len, len))
+      goto exception;
+  }
+
+  end = len;
+  if (argc > 2 && !JS_IsUndefined(argv[2])) {
+    if (JS_ToInt64Clamp(ctx, &end, argv[2], 0, len, len))
+      goto exception;
+  }
+
+  /* XXX: should special case fast arrays */
+  while (start < end) {
+    if (JS_SetPropertyInt64(ctx, obj, start, JS_DupValue(ctx, argv[0])) < 0)
+      goto exception;
+    start++;
+  }
+  return obj;
+
+exception:
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+JSValue js_array_includes(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue obj, val;
+  int64_t len, n, res;
+  JSValue* arrp;
+  uint32_t count;
+
+  obj = JS_ToObject(ctx, this_val);
+  if (js_get_length64(ctx, &len, obj))
+    goto exception;
+
+  res = FALSE;
+  if (len > 0) {
+    n = 0;
+    if (argc > 1) {
+      if (JS_ToInt64Clamp(ctx, &n, argv[1], 0, len, len))
+        goto exception;
+    }
+    if (js_get_fast_array(ctx, obj, &arrp, &count)) {
+      for (; n < count; n++) {
+        if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), JS_DupValue(ctx, arrp[n]), JS_EQ_SAME_VALUE_ZERO)) {
+          res = TRUE;
+          goto done;
+        }
+      }
+    }
+    for (; n < len; n++) {
+      val = JS_GetPropertyInt64(ctx, obj, n);
+      if (JS_IsException(val))
+        goto exception;
+      if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_SAME_VALUE_ZERO)) {
+        res = TRUE;
+        break;
+      }
+    }
+  }
+done:
+  JS_FreeValue(ctx, obj);
+  return JS_NewBool(ctx, res);
+
+exception:
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+JSValue js_array_indexOf(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue obj, val;
+  int64_t len, n, res;
+  JSValue* arrp;
+  uint32_t count;
+
+  obj = JS_ToObject(ctx, this_val);
+  if (js_get_length64(ctx, &len, obj))
+    goto exception;
+
+  res = -1;
+  if (len > 0) {
+    n = 0;
+    if (argc > 1) {
+      if (JS_ToInt64Clamp(ctx, &n, argv[1], 0, len, len))
+        goto exception;
+    }
+    if (js_get_fast_array(ctx, obj, &arrp, &count)) {
+      for (; n < count; n++) {
+        if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), JS_DupValue(ctx, arrp[n]), JS_EQ_STRICT)) {
+          res = n;
+          goto done;
+        }
+      }
+    }
+    for (; n < len; n++) {
+      int present = JS_TryGetPropertyInt64(ctx, obj, n, &val);
+      if (present < 0)
+        goto exception;
+      if (present) {
+        if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_STRICT)) {
+          res = n;
+          break;
+        }
+      }
+    }
+  }
+done:
+  JS_FreeValue(ctx, obj);
+  return JS_NewInt64(ctx, res);
+
+exception:
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+JSValue js_array_lastIndexOf(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue obj, val;
+  int64_t len, n, res;
+  int present;
+
+  obj = JS_ToObject(ctx, this_val);
+  if (js_get_length64(ctx, &len, obj))
+    goto exception;
+
+  res = -1;
+  if (len > 0) {
+    n = len - 1;
+    if (argc > 1) {
+      if (JS_ToInt64Clamp(ctx, &n, argv[1], -1, len - 1, len))
+        goto exception;
+    }
+    /* XXX: should special case fast arrays */
+    for (; n >= 0; n--) {
+      present = JS_TryGetPropertyInt64(ctx, obj, n, &val);
+      if (present < 0)
+        goto exception;
+      if (present) {
+        if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_STRICT)) {
+          res = n;
+          break;
+        }
+      }
+    }
+  }
+  JS_FreeValue(ctx, obj);
+  return JS_NewInt64(ctx, res);
+
+exception:
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+JSValue js_array_find(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int findIndex) {
+  JSValueConst func, this_arg;
+  JSValueConst args[3];
+  JSValue obj, val, index_val, res;
+  int64_t len, k;
+
+  index_val = JS_UNDEFINED;
+  val = JS_UNDEFINED;
+  obj = JS_ToObject(ctx, this_val);
+  if (js_get_length64(ctx, &len, obj))
+    goto exception;
+
+  func = argv[0];
+  if (check_function(ctx, func))
+    goto exception;
+
+  this_arg = JS_UNDEFINED;
+  if (argc > 1)
+    this_arg = argv[1];
+
+  for (k = 0; k < len; k++) {
+    index_val = JS_NewInt64(ctx, k);
+    if (JS_IsException(index_val))
+      goto exception;
+    val = JS_GetPropertyValue(ctx, obj, index_val);
+    if (JS_IsException(val))
+      goto exception;
+    args[0] = val;
+    args[1] = index_val;
+    args[2] = this_val;
+    res = JS_Call(ctx, func, this_arg, 3, args);
+    if (JS_IsException(res))
+      goto exception;
+    if (JS_ToBoolFree(ctx, res)) {
+      if (findIndex) {
+        JS_FreeValue(ctx, val);
+        JS_FreeValue(ctx, obj);
+        return index_val;
+      } else {
+        JS_FreeValue(ctx, index_val);
+        JS_FreeValue(ctx, obj);
+        return val;
+      }
+    }
+    JS_FreeValue(ctx, val);
+    JS_FreeValue(ctx, index_val);
+  }
+  JS_FreeValue(ctx, obj);
+  if (findIndex)
+    return JS_NewInt32(ctx, -1);
+  else
+    return JS_UNDEFINED;
+
+exception:
+  JS_FreeValue(ctx, index_val);
+  JS_FreeValue(ctx, val);
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+JSValue js_array_toString(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue obj, method, ret;
+
+  obj = JS_ToObject(ctx, this_val);
+  if (JS_IsException(obj))
+    return JS_EXCEPTION;
+  method = JS_GetProperty(ctx, obj, JS_ATOM_join);
+  if (JS_IsException(method)) {
+    ret = JS_EXCEPTION;
+  } else if (!JS_IsFunction(ctx, method)) {
+    /* Use intrinsic Object.prototype.toString */
+    JS_FreeValue(ctx, method);
+    ret = js_object_toString(ctx, obj, 0, NULL);
+  } else {
+    ret = JS_CallFree(ctx, method, obj, 0, NULL);
+  }
+  JS_FreeValue(ctx, obj);
+  return ret;
+}
+
+JSValue js_array_join(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int toLocaleString) {
+  JSValue obj, sep = JS_UNDEFINED, el;
+  StringBuffer b_s, *b = &b_s;
+  JSString* p = NULL;
+  int64_t i, n;
+  int c;
+
+  obj = JS_ToObject(ctx, this_val);
+  if (js_get_length64(ctx, &n, obj))
+    goto exception;
+
+  c = ','; /* default separator */
+  if (!toLocaleString && argc > 0 && !JS_IsUndefined(argv[0])) {
+    sep = JS_ToString(ctx, argv[0]);
+    if (JS_IsException(sep))
+      goto exception;
+    p = JS_VALUE_GET_STRING(sep);
+    if (p->len == 1 && !p->is_wide_char)
+      c = p->u.str8[0];
+    else
+      c = -1;
+  }
+  string_buffer_init(ctx, b, 0);
+
+  for (i = 0; i < n; i++) {
+    if (i > 0) {
+      if (c >= 0) {
+        string_buffer_putc8(b, c);
+      } else {
+        string_buffer_concat(b, p, 0, p->len);
+      }
+    }
+    el = JS_GetPropertyUint32(ctx, obj, i);
+    if (JS_IsException(el))
+      goto fail;
+    if (!JS_IsNull(el) && !JS_IsUndefined(el)) {
+      if (toLocaleString) {
+        el = JS_ToLocaleStringFree(ctx, el);
+      }
+      if (string_buffer_concat_value_free(b, el))
+        goto fail;
+    }
+  }
+  JS_FreeValue(ctx, sep);
+  JS_FreeValue(ctx, obj);
+  return string_buffer_end(b);
+
+fail:
+  string_buffer_free(b);
+  JS_FreeValue(ctx, sep);
+exception:
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+JSValue js_array_pop(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int shift) {
+  JSValue obj, res = JS_UNDEFINED;
+  int64_t len, newLen;
+  JSValue* arrp;
+  uint32_t count32;
+
+  obj = JS_ToObject(ctx, this_val);
+  if (js_get_length64(ctx, &len, obj))
+    goto exception;
+  newLen = 0;
+  if (len > 0) {
+    newLen = len - 1;
+    /* Special case fast arrays */
+    if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
+      JSObject* p = JS_VALUE_GET_OBJ(obj);
+      if (shift) {
+        res = arrp[0];
+        memmove(arrp, arrp + 1, (count32 - 1) * sizeof(*arrp));
+        p->u.array.count--;
+      } else {
+        res = arrp[count32 - 1];
+        p->u.array.count--;
+      }
+    } else {
+      if (shift) {
+        res = JS_GetPropertyInt64(ctx, obj, 0);
+        if (JS_IsException(res))
+          goto exception;
+        if (JS_CopySubArray(ctx, obj, 0, 1, len - 1, +1))
+          goto exception;
+      } else {
+        res = JS_GetPropertyInt64(ctx, obj, newLen);
+        if (JS_IsException(res))
+          goto exception;
+      }
+      if (JS_DeletePropertyInt64(ctx, obj, newLen, JS_PROP_THROW) < 0)
+        goto exception;
+    }
+  }
+  if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
+    goto exception;
+
+  JS_FreeValue(ctx, obj);
+  return res;
+
+exception:
+  JS_FreeValue(ctx, res);
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+JSValue js_array_push(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int unshift) {
+  JSValue obj;
+  int i;
+  int64_t len, from, newLen;
+
+  obj = JS_ToObject(ctx, this_val);
+
+  if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
+    JSObject* p = JS_VALUE_GET_OBJ(obj);
+    if (p->class_id != JS_CLASS_ARRAY || !p->fast_array || !p->extensible)
+      goto generic_case;
+    /* length must be writable */
+    if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE)))
+      goto generic_case;
+    /* check the length */
+    if (unlikely(JS_VALUE_GET_TAG(p->prop[0].u.value) != JS_TAG_INT))
+      goto generic_case;
+    len = JS_VALUE_GET_INT(p->prop[0].u.value);
+    /* we don't support holes */
+    if (unlikely(len != p->u.array.count))
+      goto generic_case;
+    newLen = len + argc;
+    if (unlikely(newLen > INT32_MAX))
+      goto generic_case;
+    if (newLen > p->u.array.u1.size) {
+      if (expand_fast_array(ctx, p, newLen))
+        goto exception;
+    }
+    if (unshift && argc > 0) {
+      memmove(p->u.array.u.values + argc, p->u.array.u.values, len * sizeof(p->u.array.u.values[0]));
+      from = 0;
+    } else {
+      from = len;
+    }
+    for (i = 0; i < argc; i++) {
+      p->u.array.u.values[from + i] = JS_DupValue(ctx, argv[i]);
+    }
+    p->u.array.count = newLen;
+    p->prop[0].u.value = JS_NewInt32(ctx, newLen);
+  } else {
+  generic_case:
+    if (js_get_length64(ctx, &len, obj))
+      goto exception;
+    newLen = len + argc;
+    if (newLen > MAX_SAFE_INTEGER) {
+      JS_ThrowTypeError(ctx, "Array loo long");
+      goto exception;
+    }
+    from = len;
+    if (unshift && argc > 0) {
+      if (JS_CopySubArray(ctx, obj, argc, 0, len, -1))
+        goto exception;
+      from = 0;
+    }
+    for (i = 0; i < argc; i++) {
+      if (JS_SetPropertyInt64(ctx, obj, from + i, JS_DupValue(ctx, argv[i])) < 0)
+        goto exception;
+    }
+    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
+      goto exception;
+  }
+  JS_FreeValue(ctx, obj);
+  return JS_NewInt64(ctx, newLen);
+
+exception:
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+JSValue js_array_reverse(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue obj, lval, hval;
+  JSValue* arrp;
+  int64_t len, l, h;
+  int l_present, h_present;
+  uint32_t count32;
+
+  lval = JS_UNDEFINED;
+  obj = JS_ToObject(ctx, this_val);
+  if (js_get_length64(ctx, &len, obj))
+    goto exception;
+
+  /* Special case fast arrays */
+  if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
+    uint32_t ll, hh;
+
+    if (count32 > 1) {
+      for (ll = 0, hh = count32 - 1; ll < hh; ll++, hh--) {
+        lval = arrp[ll];
+        arrp[ll] = arrp[hh];
+        arrp[hh] = lval;
+      }
+    }
+    return obj;
+  }
+
+  for (l = 0, h = len - 1; l < h; l++, h--) {
+    l_present = JS_TryGetPropertyInt64(ctx, obj, l, &lval);
+    if (l_present < 0)
+      goto exception;
+    h_present = JS_TryGetPropertyInt64(ctx, obj, h, &hval);
+    if (h_present < 0)
+      goto exception;
+    if (h_present) {
+      if (JS_SetPropertyInt64(ctx, obj, l, hval) < 0)
+        goto exception;
+
+      if (l_present) {
+        if (JS_SetPropertyInt64(ctx, obj, h, lval) < 0) {
+          lval = JS_UNDEFINED;
+          goto exception;
+        }
+        lval = JS_UNDEFINED;
+      } else {
+        if (JS_DeletePropertyInt64(ctx, obj, h, JS_PROP_THROW) < 0)
+          goto exception;
+      }
+    } else {
+      if (l_present) {
+        if (JS_DeletePropertyInt64(ctx, obj, l, JS_PROP_THROW) < 0)
+          goto exception;
+        if (JS_SetPropertyInt64(ctx, obj, h, lval) < 0) {
+          lval = JS_UNDEFINED;
+          goto exception;
+        }
+        lval = JS_UNDEFINED;
+      }
+    }
+  }
+  return obj;
+
+exception:
+  JS_FreeValue(ctx, lval);
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+JSValue js_array_slice(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int splice) {
+  JSValue obj, arr, val, len_val;
+  int64_t len, start, k, final, n, count, del_count, new_len;
+  int kPresent;
+  JSValue* arrp;
+  uint32_t count32, i, item_count;
+
+  arr = JS_UNDEFINED;
+  obj = JS_ToObject(ctx, this_val);
+  if (js_get_length64(ctx, &len, obj))
+    goto exception;
+
+  if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
+    goto exception;
+
+  if (splice) {
+    if (argc == 0) {
+      item_count = 0;
+      del_count = 0;
+    } else if (argc == 1) {
+      item_count = 0;
+      del_count = len - start;
+    } else {
+      item_count = argc - 2;
+      if (JS_ToInt64Clamp(ctx, &del_count, argv[1], 0, len - start, 0))
+        goto exception;
+    }
+    if (len + item_count - del_count > MAX_SAFE_INTEGER) {
+      JS_ThrowTypeError(ctx, "Array loo long");
+      goto exception;
+    }
+    count = del_count;
+  } else {
+    item_count = 0; /* avoid warning */
+    final = len;
+    if (!JS_IsUndefined(argv[1])) {
+      if (JS_ToInt64Clamp(ctx, &final, argv[1], 0, len, len))
+        goto exception;
+    }
+    count = max_int64(final - start, 0);
+  }
+  len_val = JS_NewInt64(ctx, count);
+  arr = JS_ArraySpeciesCreate(ctx, obj, len_val);
+  JS_FreeValue(ctx, len_val);
+  if (JS_IsException(arr))
+    goto exception;
+
+  k = start;
+  final = start + count;
+  n = 0;
+  /* The fast array test on arr ensures that
+     JS_CreateDataPropertyUint32() won't modify obj in case arr is
+     an exotic object */
+  /* Special case fast arrays */
+  if (js_get_fast_array(ctx, obj, &arrp, &count32) && js_is_fast_array(ctx, arr)) {
+    /* XXX: should share code with fast array constructor */
+    for (; k < final && k < count32; k++, n++) {
+      if (JS_CreateDataPropertyUint32(ctx, arr, n, JS_DupValue(ctx, arrp[k]), JS_PROP_THROW) < 0)
+        goto exception;
+    }
+  }
+  /* Copy the remaining elements if any (handle case of inherited properties) */
+  for (; k < final; k++, n++) {
+    kPresent = JS_TryGetPropertyInt64(ctx, obj, k, &val);
+    if (kPresent < 0)
+      goto exception;
+    if (kPresent) {
+      if (JS_CreateDataPropertyUint32(ctx, arr, n, val, JS_PROP_THROW) < 0)
+        goto exception;
+    }
+  }
+  if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0)
+    goto exception;
+
+  if (splice) {
+    new_len = len + item_count - del_count;
+    if (item_count != del_count) {
+      if (JS_CopySubArray(ctx, obj, start + item_count, start + del_count, len - (start + del_count), item_count <= del_count ? +1 : -1) < 0)
+        goto exception;
+
+      for (k = len; k-- > new_len;) {
+        if (JS_DeletePropertyInt64(ctx, obj, k, JS_PROP_THROW) < 0)
+          goto exception;
+      }
+    }
+    for (i = 0; i < item_count; i++) {
+      if (JS_SetPropertyInt64(ctx, obj, start + i, JS_DupValue(ctx, argv[i + 2])) < 0)
+        goto exception;
+    }
+    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, new_len)) < 0)
+      goto exception;
+  }
+  JS_FreeValue(ctx, obj);
+  return arr;
+
+exception:
+  JS_FreeValue(ctx, obj);
+  JS_FreeValue(ctx, arr);
+  return JS_EXCEPTION;
+}
+
+JSValue js_array_copyWithin(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue obj;
+  int64_t len, from, to, final, count;
+
+  obj = JS_ToObject(ctx, this_val);
+  if (js_get_length64(ctx, &len, obj))
+    goto exception;
+
+  if (JS_ToInt64Clamp(ctx, &to, argv[0], 0, len, len))
+    goto exception;
+
+  if (JS_ToInt64Clamp(ctx, &from, argv[1], 0, len, len))
+    goto exception;
+
+  final = len;
+  if (argc > 2 && !JS_IsUndefined(argv[2])) {
+    if (JS_ToInt64Clamp(ctx, &final, argv[2], 0, len, len))
+      goto exception;
+  }
+
+  count = min_int64(final - from, len - to);
+
+  if (JS_CopySubArray(ctx, obj, to, from, count, (from < to && to < from + count) ? -1 : +1))
+    goto exception;
+
+  return obj;
+
+exception:
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+int64_t JS_FlattenIntoArray(JSContext* ctx, JSValueConst target, JSValueConst source, int64_t sourceLen, int64_t targetIndex, int depth, JSValueConst mapperFunction, JSValueConst thisArg) {
+  JSValue element;
+  int64_t sourceIndex, elementLen;
+  int present, is_array;
+
+  if (js_check_stack_overflow(ctx->rt, 0)) {
+    JS_ThrowStackOverflow(ctx);
+    return -1;
+  }
+
+  for (sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) {
+    present = JS_TryGetPropertyInt64(ctx, source, sourceIndex, &element);
+    if (present < 0)
+      return -1;
+    if (!present)
+      continue;
+    if (!JS_IsUndefined(mapperFunction)) {
+      JSValueConst args[3] = {element, JS_NewInt64(ctx, sourceIndex), source};
+      element = JS_Call(ctx, mapperFunction, thisArg, 3, args);
+      JS_FreeValue(ctx, (JSValue)args[0]);
+      JS_FreeValue(ctx, (JSValue)args[1]);
+      if (JS_IsException(element))
+        return -1;
+    }
+    if (depth > 0) {
+      is_array = JS_IsArray(ctx, element);
+      if (is_array < 0)
+        goto fail;
+      if (is_array) {
+        if (js_get_length64(ctx, &elementLen, element) < 0)
+          goto fail;
+        targetIndex = JS_FlattenIntoArray(ctx, target, element, elementLen, targetIndex, depth - 1, JS_UNDEFINED, JS_UNDEFINED);
+        if (targetIndex < 0)
+          goto fail;
+        JS_FreeValue(ctx, element);
+        continue;
+      }
+    }
+    if (targetIndex >= MAX_SAFE_INTEGER) {
+      JS_ThrowTypeError(ctx, "Array too long");
+      goto fail;
+    }
+    if (JS_DefinePropertyValueInt64(ctx, target, targetIndex, element, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+      return -1;
+    targetIndex++;
+  }
+  return targetIndex;
+
+fail:
+  JS_FreeValue(ctx, element);
+  return -1;
+}
+
+JSValue js_array_flatten(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int map) {
+  JSValue obj, arr;
+  JSValueConst mapperFunction, thisArg;
+  int64_t sourceLen;
+  int depthNum;
+
+  arr = JS_UNDEFINED;
+  obj = JS_ToObject(ctx, this_val);
+  if (js_get_length64(ctx, &sourceLen, obj))
+    goto exception;
+
+  depthNum = 1;
+  mapperFunction = JS_UNDEFINED;
+  thisArg = JS_UNDEFINED;
+  if (map) {
+    mapperFunction = argv[0];
+    if (argc > 1) {
+      thisArg = argv[1];
+    }
+    if (check_function(ctx, mapperFunction))
+      goto exception;
+  } else {
+    if (argc > 0 && !JS_IsUndefined(argv[0])) {
+      if (JS_ToInt32Sat(ctx, &depthNum, argv[0]) < 0)
+        goto exception;
+    }
+  }
+  arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
+  if (JS_IsException(arr))
+    goto exception;
+  if (JS_FlattenIntoArray(ctx, arr, obj, sourceLen, 0, depthNum, mapperFunction, thisArg) < 0)
+    goto exception;
+  JS_FreeValue(ctx, obj);
+  return arr;
+
+exception:
+  JS_FreeValue(ctx, obj);
+  JS_FreeValue(ctx, arr);
+  return JS_EXCEPTION;
+}
+
+/* Array sort */
+typedef struct ValueSlot {
+  JSValue val;
+  JSString* str;
+  int64_t pos;
+} ValueSlot;
+
+struct array_sort_context {
+  JSContext* ctx;
+  int exception;
+  int has_method;
+  JSValueConst method;
+};
+
+int js_array_cmp_generic(const void* a, const void* b, void* opaque) {
+  struct array_sort_context* psc = opaque;
+  JSContext* ctx = psc->ctx;
+  JSValueConst argv[2];
+  JSValue res;
+  ValueSlot* ap = (ValueSlot*)(void*)a;
+  ValueSlot* bp = (ValueSlot*)(void*)b;
+  int cmp;
+
+  if (psc->exception)
+    return 0;
+
+  if (psc->has_method) {
+    /* custom sort function is specified as returning 0 for identical
+     * objects: avoid method call overhead.
+     */
+    if (!memcmp(&ap->val, &bp->val, sizeof(ap->val)))
+      goto cmp_same;
+    argv[0] = ap->val;
+    argv[1] = bp->val;
+    res = JS_Call(ctx, psc->method, JS_UNDEFINED, 2, argv);
+    if (JS_IsException(res))
+      goto exception;
+    if (JS_VALUE_GET_TAG(res) == JS_TAG_INT) {
+      int val = JS_VALUE_GET_INT(res);
+      cmp = (val > 0) - (val < 0);
+    } else {
+      double val;
+      if (JS_ToFloat64Free(ctx, &val, res) < 0)
+        goto exception;
+      cmp = (val > 0) - (val < 0);
+    }
+  } else {
+    /* Not supposed to bypass ToString even for identical objects as
+     * tested in test262/test/built-ins/Array/prototype/sort/bug_596_1.js
+     */
+    if (!ap->str) {
+      JSValue str = JS_ToString(ctx, ap->val);
+      if (JS_IsException(str))
+        goto exception;
+      ap->str = JS_VALUE_GET_STRING(str);
+    }
+    if (!bp->str) {
+      JSValue str = JS_ToString(ctx, bp->val);
+      if (JS_IsException(str))
+        goto exception;
+      bp->str = JS_VALUE_GET_STRING(str);
+    }
+    cmp = js_string_compare(ctx, ap->str, bp->str);
+  }
+  if (cmp != 0)
+    return cmp;
+cmp_same:
+  /* make sort stable: compare array offsets */
+  return (ap->pos > bp->pos) - (ap->pos < bp->pos);
+
+exception:
+  psc->exception = 1;
+  return 0;
+}
+
+JSValue js_array_sort(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  struct array_sort_context asc = {ctx, 0, 0, argv[0]};
+  JSValue obj = JS_UNDEFINED;
+  ValueSlot* array = NULL;
+  size_t array_size = 0, pos = 0, n = 0;
+  int64_t i, len, undefined_count = 0;
+  int present;
+
+  if (!JS_IsUndefined(asc.method)) {
+    if (check_function(ctx, asc.method))
+      goto exception;
+    asc.has_method = 1;
+  }
+  obj = JS_ToObject(ctx, this_val);
+  if (js_get_length64(ctx, &len, obj))
+    goto exception;
+
+  /* XXX: should special case fast arrays */
+  for (i = 0; i < len; i++) {
+    if (pos >= array_size) {
+      size_t new_size, slack;
+      ValueSlot* new_array;
+      new_size = (array_size + (array_size >> 1) + 31) & ~15;
+      new_array = js_realloc2(ctx, array, new_size * sizeof(*array), &slack);
+      if (new_array == NULL)
+        goto exception;
+      new_size += slack / sizeof(*new_array);
+      array = new_array;
+      array_size = new_size;
+    }
+    present = JS_TryGetPropertyInt64(ctx, obj, i, &array[pos].val);
+    if (present < 0)
+      goto exception;
+    if (present == 0)
+      continue;
+    if (JS_IsUndefined(array[pos].val)) {
+      undefined_count++;
+      continue;
+    }
+    array[pos].str = NULL;
+    array[pos].pos = i;
+    pos++;
+  }
+  rqsort(array, pos, sizeof(*array), js_array_cmp_generic, &asc);
+  if (asc.exception)
+    goto exception;
+
+  /* XXX: should special case fast arrays */
+  while (n < pos) {
+    if (array[n].str)
+      JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, array[n].str));
+    if (array[n].pos == n) {
+      JS_FreeValue(ctx, array[n].val);
+    } else {
+      if (JS_SetPropertyInt64(ctx, obj, n, array[n].val) < 0) {
+        n++;
+        goto exception;
+      }
+    }
+    n++;
+  }
+  js_free(ctx, array);
+  for (i = n; undefined_count-- > 0; i++) {
+    if (JS_SetPropertyInt64(ctx, obj, i, JS_UNDEFINED) < 0)
+      goto fail;
+  }
+  for (; i < len; i++) {
+    if (JS_DeletePropertyInt64(ctx, obj, i, JS_PROP_THROW) < 0)
+      goto fail;
+  }
+  return obj;
+
+exception:
+  for (; n < pos; n++) {
+    JS_FreeValue(ctx, array[n].val);
+    if (array[n].str)
+      JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, array[n].str));
+  }
+  js_free(ctx, array);
+fail:
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+void js_array_iterator_finalizer(JSRuntime* rt, JSValue val) {
+  JSObject* p = JS_VALUE_GET_OBJ(val);
+  JSArrayIteratorData* it = p->u.array_iterator_data;
+  if (it) {
+    JS_FreeValueRT(rt, it->obj);
+    js_free_rt(rt, it);
+  }
+}
+
+void js_array_iterator_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func) {
+  JSObject* p = JS_VALUE_GET_OBJ(val);
+  JSArrayIteratorData* it = p->u.array_iterator_data;
+  if (it) {
+    JS_MarkValue(rt, it->obj, mark_func);
+  }
+}
+
+JSValue js_create_array(JSContext* ctx, int len, JSValueConst* tab) {
+  JSValue obj;
+  int i;
+
+  obj = JS_NewArray(ctx);
+  if (JS_IsException(obj))
+    return JS_EXCEPTION;
+  for (i = 0; i < len; i++) {
+    if (JS_CreateDataPropertyUint32(ctx, obj, i, JS_DupValue(ctx, tab[i]), 0) < 0) {
+      JS_FreeValue(ctx, obj);
+      return JS_EXCEPTION;
+    }
+  }
+  return obj;
+}
+
+JSValue js_create_array_iterator(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic) {
+  JSValue enum_obj, arr;
+  JSArrayIteratorData* it;
+  JSIteratorKindEnum kind;
+  int class_id;
+
+  kind = magic & 3;
+  if (magic & 4) {
+    /* string iterator case */
+    arr = JS_ToStringCheckObject(ctx, this_val);
+    class_id = JS_CLASS_STRING_ITERATOR;
+  } else {
+    arr = JS_ToObject(ctx, this_val);
+    class_id = JS_CLASS_ARRAY_ITERATOR;
+  }
+  if (JS_IsException(arr))
+    goto fail;
+  enum_obj = JS_NewObjectClass(ctx, class_id);
+  if (JS_IsException(enum_obj))
+    goto fail;
+  it = js_malloc(ctx, sizeof(*it));
+  if (!it)
+    goto fail1;
+  it->obj = arr;
+  it->kind = kind;
+  it->idx = 0;
+  JS_SetOpaque(enum_obj, it);
+  return enum_obj;
+fail1:
+  JS_FreeValue(ctx, enum_obj);
+fail:
+  JS_FreeValue(ctx, arr);
+  return JS_EXCEPTION;
+}
+
+JSValue js_array_iterator_next(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, BOOL* pdone, int magic) {
+  JSArrayIteratorData* it;
+  uint32_t len, idx;
+  JSValue val, obj;
+  JSObject* p;
+
+  it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_ITERATOR);
+  if (!it)
+    goto fail1;
+  if (JS_IsUndefined(it->obj))
+    goto done;
+  p = JS_VALUE_GET_OBJ(it->obj);
+  if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
+    if (typed_array_is_detached(ctx, p)) {
+      JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+      goto fail1;
+    }
+    len = p->u.array.count;
+  } else {
+    if (js_get_length32(ctx, &len, it->obj)) {
+    fail1:
+      *pdone = FALSE;
+      return JS_EXCEPTION;
+    }
+  }
+  idx = it->idx;
+  if (idx >= len) {
+    JS_FreeValue(ctx, it->obj);
+    it->obj = JS_UNDEFINED;
+  done:
+    *pdone = TRUE;
+    return JS_UNDEFINED;
+  }
+  it->idx = idx + 1;
+  *pdone = FALSE;
+  if (it->kind == JS_ITERATOR_KIND_KEY) {
+    return JS_NewUint32(ctx, idx);
+  } else {
+    val = JS_GetPropertyUint32(ctx, it->obj, idx);
+    if (JS_IsException(val))
+      return JS_EXCEPTION;
+    if (it->kind == JS_ITERATOR_KIND_VALUE) {
+      return val;
+    } else {
+      JSValueConst args[2];
+      JSValue num;
+      num = JS_NewUint32(ctx, idx);
+      args[0] = num;
+      args[1] = val;
+      obj = js_create_array(ctx, 2, args);
+      JS_FreeValue(ctx, val);
+      JS_FreeValue(ctx, num);
+      return obj;
+    }
+  }
+}
+
+JSValue js_iterator_proto_iterator(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  return JS_DupValue(ctx, this_val);
+}
+
diff --git a/src/core/builtins/js-array.h b/src/core/builtins/js-array.h
new file mode 100644
index 000000000..a986ac5fe
--- /dev/null
+++ b/src/core/builtins/js-array.h
@@ -0,0 +1,100 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_ARRAY_H
+#define QUICKJS_JS_ARRAY_H
+
+#include "../types.h"
+#include "quickjs/cutils.h"
+#include "quickjs/quickjs.h"
+
+#define special_every 0
+#define special_some 1
+#define special_forEach 2
+#define special_map 3
+#define special_filter 4
+#define special_TA 8
+
+#define special_reduce 0
+#define special_reduceRight 1
+
+typedef struct JSArrayIteratorData {
+  JSValue obj;
+  JSIteratorKindEnum kind;
+  uint32_t idx;
+} JSArrayIteratorData;
+
+JSValue js_create_iterator_result(JSContext* ctx, JSValue val, BOOL done);
+JSValue js_array_iterator_next(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, BOOL* pdone, int magic);
+
+JSValue js_create_array_iterator(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic);
+BOOL js_is_fast_array(JSContext* ctx, JSValueConst obj);
+/* Access an Array's internal JSValue array if available */
+BOOL js_get_fast_array(JSContext* ctx, JSValueConst obj, JSValue** arrpp, uint32_t* countp);
+
+int expand_fast_array(JSContext* ctx, JSObject* p, uint32_t new_len);
+
+int JS_CopySubArray(JSContext* ctx, JSValueConst obj, int64_t to_pos, int64_t from_pos, int64_t count, int dir);
+JSValue js_array_constructor(JSContext* ctx, JSValueConst new_target, int argc, JSValueConst* argv);
+JSValue js_array_from(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_array_of(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_array_isArray(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_get_this(JSContext* ctx, JSValueConst this_val);
+JSValue JS_ArraySpeciesCreate(JSContext* ctx, JSValueConst obj, JSValueConst len_val);
+int JS_isConcatSpreadable(JSContext* ctx, JSValueConst obj);
+JSValue js_array_concat(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+int js_typed_array_get_length_internal(JSContext* ctx, JSValueConst obj);
+JSValue js_typed_array___speciesCreate(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_array_every(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int special);
+JSValue js_array_reduce(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int special);
+JSValue js_array_fill(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_array_includes(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_array_indexOf(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_array_lastIndexOf(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_array_find(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int findIndex);
+JSValue js_array_toString(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_array_join(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int toLocaleString);
+JSValue js_array_pop(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int shift);
+JSValue js_array_push(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int unshift);
+JSValue js_array_reverse(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_array_slice(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int splice);
+JSValue js_array_copyWithin(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+int64_t JS_FlattenIntoArray(JSContext* ctx, JSValueConst target, JSValueConst source, int64_t sourceLen, int64_t targetIndex, int depth, JSValueConst mapperFunction, JSValueConst thisArg);
+JSValue js_array_flatten(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int map);
+int js_array_cmp_generic(const void* a, const void* b, void* opaque);
+JSValue js_array_sort(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+
+void js_array_iterator_finalizer(JSRuntime* rt, JSValue val);
+void js_array_iterator_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func);
+JSValue js_create_array(JSContext* ctx, int len, JSValueConst* tab);
+
+__exception int js_append_enumerate(JSContext* ctx, JSValue* sp);
+
+void js_array_finalizer(JSRuntime* rt, JSValue val);
+void js_array_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func);
+
+JSValue js_iterator_proto_iterator(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-async-function.c b/src/core/builtins/js-async-function.c
new file mode 100644
index 000000000..f3d49287b
--- /dev/null
+++ b/src/core/builtins/js-async-function.c
@@ -0,0 +1,310 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-async-function.h"
+#include "../exception.h"
+#include "../function.h"
+#include "../gc.h"
+#include "js-closures.h"
+#include "js-promise.h"
+#include "quickjs/cutils.h"
+#include "quickjs/list.h"
+
+/* JSAsyncFunctionState (used by generator and async functions) */
+__exception int async_func_init(JSContext *ctx, JSAsyncFunctionState *s,
+                                       JSValueConst func_obj, JSValueConst this_obj,
+                                       int argc, JSValueConst *argv)
+{
+  JSObject *p;
+  JSFunctionBytecode *b;
+  JSStackFrame *sf;
+  int local_count, i, arg_buf_len, n;
+
+  sf = &s->frame;
+  init_list_head(&sf->var_ref_list);
+  p = JS_VALUE_GET_OBJ(func_obj);
+  b = p->u.func.function_bytecode;
+  sf->js_mode = b->js_mode;
+  sf->cur_pc = b->byte_code_buf;
+  arg_buf_len = max_int(b->arg_count, argc);
+  local_count = arg_buf_len + b->var_count + b->stack_size;
+  sf->arg_buf = js_malloc(ctx, sizeof(JSValue) * max_int(local_count, 1));
+  if (!sf->arg_buf)
+    return -1;
+  sf->cur_func = JS_DupValue(ctx, func_obj);
+  s->this_val = JS_DupValue(ctx, this_obj);
+  s->argc = argc;
+  sf->arg_count = arg_buf_len;
+  sf->var_buf = sf->arg_buf + arg_buf_len;
+  sf->cur_sp = sf->var_buf + b->var_count;
+  for(i = 0; i < argc; i++)
+    sf->arg_buf[i] = JS_DupValue(ctx, argv[i]);
+  n = arg_buf_len + b->var_count;
+  for(i = argc; i < n; i++)
+    sf->arg_buf[i] = JS_UNDEFINED;
+  return 0;
+}
+
+void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s,
+                            JS_MarkFunc *mark_func)
+{
+  JSStackFrame *sf;
+  JSValue *sp;
+
+  sf = &s->frame;
+  JS_MarkValue(rt, sf->cur_func, mark_func);
+  JS_MarkValue(rt, s->this_val, mark_func);
+  if (sf->cur_sp) {
+    /* if the function is running, cur_sp is not known so we
+       cannot mark the stack. Marking the variables is not needed
+       because a running function cannot be part of a removable
+       cycle */
+    for(sp = sf->arg_buf; sp < sf->cur_sp; sp++)
+      JS_MarkValue(rt, *sp, mark_func);
+  }
+}
+
+void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
+{
+  JSStackFrame *sf;
+  JSValue *sp;
+
+  sf = &s->frame;
+
+  /* close the closure variables. */
+  close_var_refs(rt, sf);
+
+  if (sf->arg_buf) {
+    /* cannot free the function if it is running */
+    assert(sf->cur_sp != NULL);
+    for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) {
+      JS_FreeValueRT(rt, *sp);
+    }
+    js_free_rt(rt, sf->arg_buf);
+  }
+  JS_FreeValueRT(rt, sf->cur_func);
+  JS_FreeValueRT(rt, s->this_val);
+}
+
+JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s)
+{
+  JSValue func_obj;
+
+  if (js_check_stack_overflow(ctx->rt, 0))
+    return JS_ThrowStackOverflow(ctx);
+
+  /* the tag does not matter provided it is not an object */
+  func_obj = JS_MKPTR(JS_TAG_INT, s);
+  return JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED,
+                         s->argc, s->frame.arg_buf, JS_CALL_FLAG_GENERATOR);
+}
+
+
+
+/* AsyncFunction */
+
+void js_async_function_terminate(JSRuntime *rt, JSAsyncFunctionData *s)
+{
+  if (s->is_active) {
+    async_func_free(rt, &s->func_state);
+    s->is_active = FALSE;
+  }
+}
+
+void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s)
+{
+  js_async_function_terminate(rt, s);
+  JS_FreeValueRT(rt, s->resolving_funcs[0]);
+  JS_FreeValueRT(rt, s->resolving_funcs[1]);
+  remove_gc_object(&s->header);
+  js_free_rt(rt, s);
+}
+
+void js_async_function_free(JSRuntime *rt, JSAsyncFunctionData *s)
+{
+  if (--s->header.ref_count == 0) {
+    js_async_function_free0(rt, s);
+  }
+}
+
+void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val)
+{
+  JSObject *p = JS_VALUE_GET_OBJ(val);
+  JSAsyncFunctionData *s = p->u.async_function_data;
+  if (s) {
+    js_async_function_free(rt, s);
+  }
+}
+
+void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,
+                                           JS_MarkFunc *mark_func)
+{
+  JSObject *p = JS_VALUE_GET_OBJ(val);
+  JSAsyncFunctionData *s = p->u.async_function_data;
+  if (s) {
+    mark_func(rt, &s->header);
+  }
+}
+
+int js_async_function_resolve_create(JSContext *ctx,
+                                            JSAsyncFunctionData *s,
+                                            JSValue *resolving_funcs)
+{
+  int i;
+  JSObject *p;
+
+  for(i = 0; i < 2; i++) {
+    resolving_funcs[i] =
+        JS_NewObjectProtoClass(ctx, ctx->function_proto,
+                               JS_CLASS_ASYNC_FUNCTION_RESOLVE + i);
+    if (JS_IsException(resolving_funcs[i])) {
+      if (i == 1)
+        JS_FreeValue(ctx, resolving_funcs[0]);
+      return -1;
+    }
+    p = JS_VALUE_GET_OBJ(resolving_funcs[i]);
+    s->header.ref_count++;
+    p->u.async_function_data = s;
+  }
+  return 0;
+}
+
+void js_async_function_resume(JSContext *ctx, JSAsyncFunctionData *s)
+{
+  JSValue func_ret, ret2;
+
+  func_ret = async_func_resume(ctx, &s->func_state);
+  if (JS_IsException(func_ret)) {
+    JSValue error;
+  fail:
+    error = JS_GetException(ctx);
+    ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED,
+                   1, (JSValueConst *)&error);
+    JS_FreeValue(ctx, error);
+    js_async_function_terminate(ctx->rt, s);
+    JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
+  } else {
+    JSValue value;
+    value = s->func_state.frame.cur_sp[-1];
+    s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
+    if (JS_IsUndefined(func_ret)) {
+      /* function returned */
+      ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED,
+                     1, (JSValueConst *)&value);
+      JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
+      JS_FreeValue(ctx, value);
+      js_async_function_terminate(ctx->rt, s);
+    } else {
+      JSValue promise, resolving_funcs[2], resolving_funcs1[2];
+      int i, res;
+
+      /* await */
+      JS_FreeValue(ctx, func_ret); /* not used */
+      promise = js_promise_resolve(ctx, ctx->promise_ctor,
+                                   1, (JSValueConst *)&value, 0);
+      JS_FreeValue(ctx, value);
+      if (JS_IsException(promise))
+        goto fail;
+      if (js_async_function_resolve_create(ctx, s, resolving_funcs)) {
+        JS_FreeValue(ctx, promise);
+        goto fail;
+      }
+
+      /* Note: no need to create 'thrownawayCapability' as in
+         the spec */
+      for(i = 0; i < 2; i++)
+        resolving_funcs1[i] = JS_UNDEFINED;
+      res = perform_promise_then(ctx, promise,
+                                 (JSValueConst *)resolving_funcs,
+                                 (JSValueConst *)resolving_funcs1);
+      JS_FreeValue(ctx, promise);
+      for(i = 0; i < 2; i++)
+        JS_FreeValue(ctx, resolving_funcs[i]);
+      if (res)
+        goto fail;
+    }
+  }
+}
+
+JSValue js_async_function_resolve_call(JSContext *ctx,
+                                              JSValueConst func_obj,
+                                              JSValueConst this_obj,
+                                              int argc, JSValueConst *argv,
+                                              int flags)
+{
+  JSObject *p = JS_VALUE_GET_OBJ(func_obj);
+  JSAsyncFunctionData *s = p->u.async_function_data;
+  BOOL is_reject = p->class_id - JS_CLASS_ASYNC_FUNCTION_RESOLVE;
+  JSValueConst arg;
+
+  if (argc > 0)
+    arg = argv[0];
+  else
+    arg = JS_UNDEFINED;
+  s->func_state.throw_flag = is_reject;
+  if (is_reject) {
+    JS_Throw(ctx, JS_DupValue(ctx, arg));
+  } else {
+    /* return value of await */
+    s->func_state.frame.cur_sp[-1] = JS_DupValue(ctx, arg);
+  }
+  js_async_function_resume(ctx, s);
+  return JS_UNDEFINED;
+}
+
+JSValue js_async_function_call(JSContext *ctx, JSValueConst func_obj,
+                                      JSValueConst this_obj,
+                                      int argc, JSValueConst *argv, int flags)
+{
+  JSValue promise;
+  JSAsyncFunctionData *s;
+
+  s = js_mallocz(ctx, sizeof(*s));
+  if (!s)
+    return JS_EXCEPTION;
+  s->header.ref_count = 1;
+  add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION);
+  s->is_active = FALSE;
+  s->resolving_funcs[0] = JS_UNDEFINED;
+  s->resolving_funcs[1] = JS_UNDEFINED;
+
+  promise = JS_NewPromiseCapability(ctx, s->resolving_funcs);
+  if (JS_IsException(promise))
+    goto fail;
+
+  if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
+  fail:
+    JS_FreeValue(ctx, promise);
+    js_async_function_free(ctx->rt, s);
+    return JS_EXCEPTION;
+  }
+  s->is_active = TRUE;
+
+  js_async_function_resume(ctx, s);
+
+  js_async_function_free(ctx->rt, s);
+
+  return promise;
+}
diff --git a/src/core/builtins/js-async-function.h b/src/core/builtins/js-async-function.h
new file mode 100644
index 000000000..33efca855
--- /dev/null
+++ b/src/core/builtins/js-async-function.h
@@ -0,0 +1,59 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_ASYNC_FUNCTION_H
+#define QUICKJS_JS_ASYNC_FUNCTION_H
+
+#include "quickjs/quickjs.h"
+#include "../types.h"
+
+JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s);
+__exception int async_func_init(JSContext *ctx, JSAsyncFunctionState *s,
+                                       JSValueConst func_obj, JSValueConst this_obj,
+                                       int argc, JSValueConst *argv);
+void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s);
+void async_func_mark(JSRuntime *rt, JSAsyncFunctionState *s,
+                            JS_MarkFunc *mark_func);
+
+void js_async_function_terminate(JSRuntime *rt, JSAsyncFunctionData *s);
+void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s);
+void js_async_function_free(JSRuntime *rt, JSAsyncFunctionData *s);
+void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val);
+void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,
+                                           JS_MarkFunc *mark_func);
+int js_async_function_resolve_create(JSContext *ctx,
+                                            JSAsyncFunctionData *s,
+                                            JSValue *resolving_funcs);
+void js_async_function_resume(JSContext *ctx, JSAsyncFunctionData *s);
+JSValue js_async_function_resolve_call(JSContext *ctx,
+                                              JSValueConst func_obj,
+                                              JSValueConst this_obj,
+                                              int argc, JSValueConst *argv,
+                                              int flags);
+JSValue js_async_function_call(JSContext *ctx, JSValueConst func_obj,
+                                      JSValueConst this_obj,
+                                      int argc, JSValueConst *argv, int flags);
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-async-generator.c b/src/core/builtins/js-async-generator.c
new file mode 100644
index 000000000..d5b75d9b0
--- /dev/null
+++ b/src/core/builtins/js-async-generator.c
@@ -0,0 +1,440 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-async-generator.h"
+#include "../exception.h"
+#include "../function.h"
+#include "../object.h"
+#include "js-array.h"
+#include "js-async-function.h"
+#include "js-generator.h"
+#include "js-promise.h"
+#include "quickjs/cutils.h"
+#include "quickjs/list.h"
+
+/* AsyncGenerator */
+
+void js_async_generator_free(JSRuntime *rt,
+                                    JSAsyncGeneratorData *s)
+{
+  struct list_head *el, *el1;
+  JSAsyncGeneratorRequest *req;
+
+  list_for_each_safe(el, el1, &s->queue) {
+    req = list_entry(el, JSAsyncGeneratorRequest, link);
+    JS_FreeValueRT(rt, req->result);
+    JS_FreeValueRT(rt, req->promise);
+    JS_FreeValueRT(rt, req->resolving_funcs[0]);
+    JS_FreeValueRT(rt, req->resolving_funcs[1]);
+    js_free_rt(rt, req);
+  }
+  if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED &&
+      s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) {
+    async_func_free(rt, &s->func_state);
+  }
+  js_free_rt(rt, s);
+}
+
+void js_async_generator_finalizer(JSRuntime *rt, JSValue obj)
+{
+  JSAsyncGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_ASYNC_GENERATOR);
+
+  if (s) {
+    js_async_generator_free(rt, s);
+  }
+}
+
+void js_async_generator_mark(JSRuntime *rt, JSValueConst val,
+                                    JS_MarkFunc *mark_func)
+{
+  JSAsyncGeneratorData *s = JS_GetOpaque(val, JS_CLASS_ASYNC_GENERATOR);
+  struct list_head *el;
+  JSAsyncGeneratorRequest *req;
+  if (s) {
+    list_for_each(el, &s->queue) {
+      req = list_entry(el, JSAsyncGeneratorRequest, link);
+      JS_MarkValue(rt, req->result, mark_func);
+      JS_MarkValue(rt, req->promise, mark_func);
+      JS_MarkValue(rt, req->resolving_funcs[0], mark_func);
+      JS_MarkValue(rt, req->resolving_funcs[1], mark_func);
+    }
+    if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED &&
+        s->state != JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN) {
+      async_func_mark(rt, &s->func_state, mark_func);
+    }
+  }
+}
+
+JSValue js_async_generator_resolve_function(JSContext *ctx,
+                                                   JSValueConst this_obj,
+                                                   int argc, JSValueConst *argv,
+                                                   int magic, JSValue *func_data);
+
+int js_async_generator_resolve_function_create(JSContext *ctx,
+                                                      JSValueConst generator,
+                                                      JSValue *resolving_funcs,
+                                                      BOOL is_resume_next)
+{
+  int i;
+  JSValue func;
+
+  for(i = 0; i < 2; i++) {
+    func = JS_NewCFunctionData(ctx, js_async_generator_resolve_function, 1,
+                               i + is_resume_next * 2, 1, &generator);
+    if (JS_IsException(func)) {
+      if (i == 1)
+        JS_FreeValue(ctx, resolving_funcs[0]);
+      return -1;
+    }
+    resolving_funcs[i] = func;
+  }
+  return 0;
+}
+
+int js_async_generator_await(JSContext *ctx,
+                                    JSAsyncGeneratorData *s,
+                                    JSValueConst value)
+{
+  JSValue promise, resolving_funcs[2], resolving_funcs1[2];
+  int i, res;
+
+  promise = js_promise_resolve(ctx, ctx->promise_ctor,
+                               1, &value, 0);
+  if (JS_IsException(promise))
+    goto fail;
+
+  if (js_async_generator_resolve_function_create(ctx, JS_MKPTR(JS_TAG_OBJECT, s->generator),
+                                                 resolving_funcs, FALSE)) {
+    JS_FreeValue(ctx, promise);
+    goto fail;
+  }
+
+  /* Note: no need to create 'thrownawayCapability' as in
+     the spec */
+  for(i = 0; i < 2; i++)
+    resolving_funcs1[i] = JS_UNDEFINED;
+  res = perform_promise_then(ctx, promise,
+                             (JSValueConst *)resolving_funcs,
+                             (JSValueConst *)resolving_funcs1);
+  JS_FreeValue(ctx, promise);
+  for(i = 0; i < 2; i++)
+    JS_FreeValue(ctx, resolving_funcs[i]);
+  if (res)
+    goto fail;
+  return 0;
+fail:
+  return -1;
+}
+
+void js_async_generator_resolve_or_reject(JSContext *ctx,
+                                                 JSAsyncGeneratorData *s,
+                                                 JSValueConst result,
+                                                 int is_reject)
+{
+  JSAsyncGeneratorRequest *next;
+  JSValue ret;
+
+  next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link);
+  list_del(&next->link);
+  ret = JS_Call(ctx, next->resolving_funcs[is_reject], JS_UNDEFINED, 1,
+                &result);
+  JS_FreeValue(ctx, ret);
+  JS_FreeValue(ctx, next->result);
+  JS_FreeValue(ctx, next->promise);
+  JS_FreeValue(ctx, next->resolving_funcs[0]);
+  JS_FreeValue(ctx, next->resolving_funcs[1]);
+  js_free(ctx, next);
+}
+
+void js_async_generator_resolve(JSContext *ctx,
+                                       JSAsyncGeneratorData *s,
+                                       JSValueConst value,
+                                       BOOL done)
+{
+  JSValue result;
+  result = js_create_iterator_result(ctx, JS_DupValue(ctx, value), done);
+  /* XXX: better exception handling ? */
+  js_async_generator_resolve_or_reject(ctx, s, result, 0);
+  JS_FreeValue(ctx, result);
+}
+
+void js_async_generator_reject(JSContext *ctx,
+                                      JSAsyncGeneratorData *s,
+                                      JSValueConst exception)
+{
+  js_async_generator_resolve_or_reject(ctx, s, exception, 1);
+}
+
+void js_async_generator_complete(JSContext *ctx,
+                                        JSAsyncGeneratorData *s)
+{
+  if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED) {
+    s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
+    async_func_free(ctx->rt, &s->func_state);
+  }
+}
+
+int js_async_generator_completed_return(JSContext *ctx,
+                                               JSAsyncGeneratorData *s,
+                                               JSValueConst value)
+{
+  JSValue promise, resolving_funcs[2], resolving_funcs1[2];
+  int res;
+
+  promise = js_promise_resolve(ctx, ctx->promise_ctor,
+                               1, (JSValueConst *)&value, 0);
+  if (JS_IsException(promise))
+    return -1;
+  if (js_async_generator_resolve_function_create(ctx,
+                                                 JS_MKPTR(JS_TAG_OBJECT, s->generator),
+                                                 resolving_funcs1,
+                                                 TRUE)) {
+    JS_FreeValue(ctx, promise);
+    return -1;
+  }
+  resolving_funcs[0] = JS_UNDEFINED;
+  resolving_funcs[1] = JS_UNDEFINED;
+  res = perform_promise_then(ctx, promise,
+                             (JSValueConst *)resolving_funcs1,
+                             (JSValueConst *)resolving_funcs);
+  JS_FreeValue(ctx, resolving_funcs1[0]);
+  JS_FreeValue(ctx, resolving_funcs1[1]);
+  JS_FreeValue(ctx, promise);
+  return res;
+}
+
+void js_async_generator_resume_next(JSContext *ctx,
+                                           JSAsyncGeneratorData *s)
+{
+  JSAsyncGeneratorRequest *next;
+  JSValue func_ret, value;
+
+  for(;;) {
+    if (list_empty(&s->queue))
+      break;
+    next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link);
+    switch(s->state) {
+      case JS_ASYNC_GENERATOR_STATE_EXECUTING:
+        /* only happens when restarting execution after await() */
+        goto resume_exec;
+      case JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN:
+        goto done;
+      case JS_ASYNC_GENERATOR_STATE_SUSPENDED_START:
+        if (next->completion_type == GEN_MAGIC_NEXT) {
+          goto exec_no_arg;
+        } else {
+          js_async_generator_complete(ctx, s);
+        }
+        break;
+      case JS_ASYNC_GENERATOR_STATE_COMPLETED:
+        if (next->completion_type == GEN_MAGIC_NEXT) {
+          js_async_generator_resolve(ctx, s, JS_UNDEFINED, TRUE);
+        } else if (next->completion_type == GEN_MAGIC_RETURN) {
+          s->state = JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN;
+          js_async_generator_completed_return(ctx, s, next->result);
+          goto done;
+        } else {
+          js_async_generator_reject(ctx, s, next->result);
+        }
+        goto done;
+      case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD:
+      case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
+        value = JS_DupValue(ctx, next->result);
+        if (next->completion_type == GEN_MAGIC_THROW &&
+            s->state == JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD) {
+          JS_Throw(ctx, value);
+          s->func_state.throw_flag = TRUE;
+        } else {
+          /* 'yield' returns a value. 'yield *' also returns a value
+             in case the 'throw' method is called */
+          s->func_state.frame.cur_sp[-1] = value;
+          s->func_state.frame.cur_sp[0] =
+              JS_NewInt32(ctx, next->completion_type);
+          s->func_state.frame.cur_sp++;
+        exec_no_arg:
+          s->func_state.throw_flag = FALSE;
+        }
+        s->state = JS_ASYNC_GENERATOR_STATE_EXECUTING;
+      resume_exec:
+        func_ret = async_func_resume(ctx, &s->func_state);
+        if (JS_IsException(func_ret)) {
+          value = JS_GetException(ctx);
+          js_async_generator_complete(ctx, s);
+          js_async_generator_reject(ctx, s, value);
+          JS_FreeValue(ctx, value);
+        } else if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) {
+          int func_ret_code;
+          value = s->func_state.frame.cur_sp[-1];
+          s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
+          func_ret_code = JS_VALUE_GET_INT(func_ret);
+          switch(func_ret_code) {
+            case FUNC_RET_YIELD:
+            case FUNC_RET_YIELD_STAR:
+              if (func_ret_code == FUNC_RET_YIELD_STAR)
+                s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
+              else
+                s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD;
+              js_async_generator_resolve(ctx, s, value, FALSE);
+              JS_FreeValue(ctx, value);
+              break;
+            case FUNC_RET_AWAIT:
+              js_async_generator_await(ctx, s, value);
+              JS_FreeValue(ctx, value);
+              goto done;
+            default:
+              abort();
+          }
+        } else {
+          assert(JS_IsUndefined(func_ret));
+          /* end of function */
+          value = s->func_state.frame.cur_sp[-1];
+          s->func_state.frame.cur_sp[-1] = JS_UNDEFINED;
+          js_async_generator_complete(ctx, s);
+          js_async_generator_resolve(ctx, s, value, TRUE);
+          JS_FreeValue(ctx, value);
+        }
+        break;
+      default:
+        abort();
+    }
+  }
+done: ;
+}
+
+JSValue js_async_generator_resolve_function(JSContext *ctx,
+                                                   JSValueConst this_obj,
+                                                   int argc, JSValueConst *argv,
+                                                   int magic, JSValue *func_data)
+{
+  BOOL is_reject = magic & 1;
+  JSAsyncGeneratorData *s = JS_GetOpaque(func_data[0], JS_CLASS_ASYNC_GENERATOR);
+  JSValueConst arg = argv[0];
+
+  /* XXX: what if s == NULL */
+
+  if (magic >= 2) {
+    /* resume next case in AWAITING_RETURN state */
+    assert(s->state == JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN ||
+           s->state == JS_ASYNC_GENERATOR_STATE_COMPLETED);
+    s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
+    if (is_reject) {
+      js_async_generator_reject(ctx, s, arg);
+    } else {
+      js_async_generator_resolve(ctx, s, arg, TRUE);
+    }
+  } else {
+    /* restart function execution after await() */
+    assert(s->state == JS_ASYNC_GENERATOR_STATE_EXECUTING);
+    s->func_state.throw_flag = is_reject;
+    if (is_reject) {
+      JS_Throw(ctx, JS_DupValue(ctx, arg));
+    } else {
+      /* return value of await */
+      s->func_state.frame.cur_sp[-1] = JS_DupValue(ctx, arg);
+    }
+    js_async_generator_resume_next(ctx, s);
+  }
+  return JS_UNDEFINED;
+}
+
+/* magic = GEN_MAGIC_x */
+JSValue js_async_generator_next(JSContext *ctx, JSValueConst this_val,
+                                       int argc, JSValueConst *argv,
+                                       int magic)
+{
+  JSAsyncGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_GENERATOR);
+  JSValue promise, resolving_funcs[2];
+  JSAsyncGeneratorRequest *req;
+
+  promise = JS_NewPromiseCapability(ctx, resolving_funcs);
+  if (JS_IsException(promise))
+    return JS_EXCEPTION;
+  if (!s) {
+    JSValue err, res2;
+    JS_ThrowTypeError(ctx, "not an AsyncGenerator object");
+    err = JS_GetException(ctx);
+    res2 = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
+                   1, (JSValueConst *)&err);
+    JS_FreeValue(ctx, err);
+    JS_FreeValue(ctx, res2);
+    JS_FreeValue(ctx, resolving_funcs[0]);
+    JS_FreeValue(ctx, resolving_funcs[1]);
+    return promise;
+  }
+  req = js_mallocz(ctx, sizeof(*req));
+  if (!req)
+    goto fail;
+  req->completion_type = magic;
+  req->result = JS_DupValue(ctx, argv[0]);
+  req->promise = JS_DupValue(ctx, promise);
+  req->resolving_funcs[0] = resolving_funcs[0];
+  req->resolving_funcs[1] = resolving_funcs[1];
+  list_add_tail(&req->link, &s->queue);
+  if (s->state != JS_ASYNC_GENERATOR_STATE_EXECUTING) {
+    js_async_generator_resume_next(ctx, s);
+  }
+  return promise;
+fail:
+  JS_FreeValue(ctx, resolving_funcs[0]);
+  JS_FreeValue(ctx, resolving_funcs[1]);
+  JS_FreeValue(ctx, promise);
+  return JS_EXCEPTION;
+}
+
+JSValue js_async_generator_function_call(JSContext *ctx, JSValueConst func_obj,
+                                                JSValueConst this_obj,
+                                                int argc, JSValueConst *argv,
+                                                int flags)
+{
+  JSValue obj, func_ret;
+  JSAsyncGeneratorData *s;
+
+  s = js_mallocz(ctx, sizeof(*s));
+  if (!s)
+    return JS_EXCEPTION;
+  s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_START;
+  init_list_head(&s->queue);
+  if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
+    s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
+    goto fail;
+  }
+
+  /* execute the function up to 'OP_initial_yield' (no yield nor
+     await are possible) */
+  func_ret = async_func_resume(ctx, &s->func_state);
+  if (JS_IsException(func_ret))
+    goto fail;
+  JS_FreeValue(ctx, func_ret);
+
+  obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_ASYNC_GENERATOR);
+  if (JS_IsException(obj))
+    goto fail;
+  s->generator = JS_VALUE_GET_OBJ(obj);
+  JS_SetOpaque(obj, s);
+  return obj;
+fail:
+  js_async_generator_free(ctx->rt, s);
+  return JS_EXCEPTION;
+}
diff --git a/src/core/builtins/js-async-generator.h b/src/core/builtins/js-async-generator.h
new file mode 100644
index 000000000..a10edcfc9
--- /dev/null
+++ b/src/core/builtins/js-async-generator.h
@@ -0,0 +1,107 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_ASYNC_GENERATOR_H
+#define QUICKJS_JS_ASYNC_GENERATOR_H
+
+#include "quickjs/quickjs.h"
+#include "quickjs/cutils.h"
+#include "../types.h"
+
+
+typedef enum JSAsyncGeneratorStateEnum {
+  JS_ASYNC_GENERATOR_STATE_SUSPENDED_START,
+  JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD,
+  JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR,
+  JS_ASYNC_GENERATOR_STATE_EXECUTING,
+  JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN,
+  JS_ASYNC_GENERATOR_STATE_COMPLETED,
+} JSAsyncGeneratorStateEnum;
+
+typedef struct JSAsyncGeneratorRequest {
+  struct list_head link;
+  /* completion */
+  int completion_type; /* GEN_MAGIC_x */
+  JSValue result;
+  /* promise capability */
+  JSValue promise;
+  JSValue resolving_funcs[2];
+} JSAsyncGeneratorRequest;
+
+typedef struct JSAsyncGeneratorData {
+  JSObject *generator; /* back pointer to the object (const) */
+  JSAsyncGeneratorStateEnum state;
+  JSAsyncFunctionState func_state;
+  struct list_head queue; /* list of JSAsyncGeneratorRequest.link */
+} JSAsyncGeneratorData;
+
+void js_async_generator_free(JSRuntime *rt,
+                                    JSAsyncGeneratorData *s);
+void js_async_generator_finalizer(JSRuntime *rt, JSValue obj);
+void js_async_generator_mark(JSRuntime *rt, JSValueConst val,
+                                    JS_MarkFunc *mark_func);
+
+int js_async_generator_resolve_function_create(JSContext *ctx,
+                                                      JSValueConst generator,
+                                                      JSValue *resolving_funcs,
+                                                      BOOL is_resume_next);
+int js_async_generator_await(JSContext *ctx,
+                                    JSAsyncGeneratorData *s,
+                                    JSValueConst value);
+void js_async_generator_resolve_or_reject(JSContext *ctx,
+                                                 JSAsyncGeneratorData *s,
+                                                 JSValueConst result,
+                                                 int is_reject);
+
+void js_async_generator_resolve(JSContext *ctx,
+                                       JSAsyncGeneratorData *s,
+                                       JSValueConst value,
+                                       BOOL done);
+
+void js_async_generator_reject(JSContext *ctx,
+                                      JSAsyncGeneratorData *s,
+                                      JSValueConst exception);
+
+void js_async_generator_complete(JSContext *ctx,
+                                        JSAsyncGeneratorData *s);
+
+int js_async_generator_completed_return(JSContext *ctx,
+                                               JSAsyncGeneratorData *s,
+                                               JSValueConst value);
+
+void js_async_generator_resume_next(JSContext *ctx,
+                                           JSAsyncGeneratorData *s);
+/* magic = GEN_MAGIC_x */
+JSValue js_async_generator_next(JSContext *ctx, JSValueConst this_val,
+                                       int argc, JSValueConst *argv,
+                                       int magic);
+
+JSValue js_async_generator_function_call(JSContext *ctx, JSValueConst func_obj,
+                                                JSValueConst this_obj,
+                                                int argc, JSValueConst *argv,
+                                                int flags);
+
+
+#endif
diff --git a/src/core/builtins/js-atomics.c b/src/core/builtins/js-atomics.c
new file mode 100644
index 000000000..d024346bf
--- /dev/null
+++ b/src/core/builtins/js-atomics.c
@@ -0,0 +1,527 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-atomics.h"
+#include "../convertion.h"
+#include "../exception.h"
+#include "js-typed-array.h"
+
+#if CONFIG_BIGNUM
+#include "js-big-num.h"
+#endif
+
+/* Atomics */
+#ifdef CONFIG_ATOMICS
+
+typedef enum AtomicsOpEnum {
+  ATOMICS_OP_ADD,
+  ATOMICS_OP_AND,
+  ATOMICS_OP_OR,
+  ATOMICS_OP_SUB,
+  ATOMICS_OP_XOR,
+  ATOMICS_OP_EXCHANGE,
+  ATOMICS_OP_COMPARE_EXCHANGE,
+  ATOMICS_OP_LOAD,
+} AtomicsOpEnum;
+
+void *js_atomics_get_ptr(JSContext *ctx,
+                                JSArrayBuffer **pabuf,
+                                int *psize_log2, JSClassID *pclass_id,
+                                JSValueConst obj, JSValueConst idx_val,
+                                int is_waitable)
+{
+  JSObject *p;
+  JSTypedArray *ta;
+  JSArrayBuffer *abuf;
+  void *ptr;
+  uint64_t idx;
+  BOOL err;
+  int size_log2;
+
+  if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
+    goto fail;
+  p = JS_VALUE_GET_OBJ(obj);
+#ifdef CONFIG_BIGNUM
+  if (is_waitable)
+    err = (p->class_id != JS_CLASS_INT32_ARRAY &&
+           p->class_id != JS_CLASS_BIG_INT64_ARRAY);
+  else
+    err = !(p->class_id >= JS_CLASS_INT8_ARRAY &&
+            p->class_id <= JS_CLASS_BIG_UINT64_ARRAY);
+#else
+  if (is_waitable)
+    err = (p->class_id != JS_CLASS_INT32_ARRAY);
+  else
+    err = !(p->class_id >= JS_CLASS_INT8_ARRAY &&
+            p->class_id <= JS_CLASS_UINT32_ARRAY);
+#endif
+  if (err) {
+  fail:
+    JS_ThrowTypeError(ctx, "integer TypedArray expected");
+    return NULL;
+  }
+  ta = p->u.typed_array;
+  abuf = ta->buffer->u.array_buffer;
+  if (!abuf->shared) {
+    if (is_waitable == 2) {
+      JS_ThrowTypeError(ctx, "not a SharedArrayBuffer TypedArray");
+      return NULL;
+    }
+    if (abuf->detached) {
+      JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+      return NULL;
+    }
+  }
+  if (JS_ToIndex(ctx, &idx, idx_val)) {
+    return NULL;
+  }
+  /* if the array buffer is detached, p->u.array.count = 0 */
+  if (idx >= p->u.array.count) {
+    JS_ThrowRangeError(ctx, "out-of-bound access");
+    return NULL;
+  }
+  size_log2 = typed_array_size_log2(p->class_id);
+  ptr = p->u.array.u.uint8_ptr + ((uintptr_t)idx << size_log2);
+  if (pabuf)
+    *pabuf = abuf;
+  if (psize_log2)
+    *psize_log2 = size_log2;
+  if (pclass_id)
+    *pclass_id = p->class_id;
+  return ptr;
+}
+
+JSValue js_atomics_op(JSContext *ctx,
+                             JSValueConst this_obj,
+                             int argc, JSValueConst *argv, int op)
+{
+  int size_log2;
+#ifdef CONFIG_BIGNUM
+  uint64_t v, a, rep_val;
+#else
+  uint32_t v, a, rep_val;
+#endif
+  void *ptr;
+  JSValue ret;
+  JSClassID class_id;
+  JSArrayBuffer *abuf;
+
+  ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, &class_id,
+                           argv[0], argv[1], 0);
+  if (!ptr)
+    return JS_EXCEPTION;
+  rep_val = 0;
+  if (op == ATOMICS_OP_LOAD) {
+    v = 0;
+  } else {
+#ifdef CONFIG_BIGNUM
+    if (size_log2 == 3) {
+      int64_t v64;
+      if (JS_ToBigInt64(ctx, &v64, argv[2]))
+        return JS_EXCEPTION;
+      v = v64;
+      if (op == ATOMICS_OP_COMPARE_EXCHANGE) {
+        if (JS_ToBigInt64(ctx, &v64, argv[3]))
+          return JS_EXCEPTION;
+        rep_val = v64;
+      }
+    } else
+#endif
+    {
+      uint32_t v32;
+      if (JS_ToUint32(ctx, &v32, argv[2]))
+        return JS_EXCEPTION;
+      v = v32;
+      if (op == ATOMICS_OP_COMPARE_EXCHANGE) {
+        if (JS_ToUint32(ctx, &v32, argv[3]))
+          return JS_EXCEPTION;
+        rep_val = v32;
+      }
+    }
+    if (abuf->detached)
+      return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+  }
+
+  switch(op | (size_log2 << 3)) {
+
+#ifdef CONFIG_BIGNUM
+#define OP(op_name, func_name)                          \
+    case ATOMICS_OP_ ## op_name | (0 << 3):             \
+       a = func_name((_Atomic(uint8_t) *)ptr, v);       \
+       break;                                           \
+    case ATOMICS_OP_ ## op_name | (1 << 3):             \
+        a = func_name((_Atomic(uint16_t) *)ptr, v);     \
+        break;                                          \
+    case ATOMICS_OP_ ## op_name | (2 << 3):             \
+        a = func_name((_Atomic(uint32_t) *)ptr, v);     \
+        break;                                          \
+    case ATOMICS_OP_ ## op_name | (3 << 3):             \
+        a = func_name((_Atomic(uint64_t) *)ptr, v);     \
+        break;
+#else
+#define OP(op_name, func_name)                          \
+    case ATOMICS_OP_ ## op_name | (0 << 3):             \
+       a = func_name((_Atomic(uint8_t) *)ptr, v);       \
+       break;                                           \
+    case ATOMICS_OP_ ## op_name | (1 << 3):             \
+        a = func_name((_Atomic(uint16_t) *)ptr, v);     \
+        break;                                          \
+    case ATOMICS_OP_ ## op_name | (2 << 3):             \
+        a = func_name((_Atomic(uint32_t) *)ptr, v);     \
+        break;
+#endif
+    OP(ADD, atomic_fetch_add)
+    OP(AND, atomic_fetch_and)
+    OP(OR, atomic_fetch_or)
+    OP(SUB, atomic_fetch_sub)
+    OP(XOR, atomic_fetch_xor)
+    OP(EXCHANGE, atomic_exchange)
+#undef OP
+
+    case ATOMICS_OP_LOAD | (0 << 3):
+      a = atomic_load((_Atomic(uint8_t) *)ptr);
+      break;
+    case ATOMICS_OP_LOAD | (1 << 3):
+      a = atomic_load((_Atomic(uint16_t) *)ptr);
+      break;
+    case ATOMICS_OP_LOAD | (2 << 3):
+      a = atomic_load((_Atomic(uint32_t) *)ptr);
+      break;
+#ifdef CONFIG_BIGNUM
+    case ATOMICS_OP_LOAD | (3 << 3):
+      a = atomic_load((_Atomic(uint64_t) *)ptr);
+      break;
+#endif
+
+    case ATOMICS_OP_COMPARE_EXCHANGE | (0 << 3):
+    {
+      uint8_t v1 = v;
+      atomic_compare_exchange_strong((_Atomic(uint8_t) *)ptr, &v1, rep_val);
+      a = v1;
+    }
+    break;
+    case ATOMICS_OP_COMPARE_EXCHANGE | (1 << 3):
+    {
+      uint16_t v1 = v;
+      atomic_compare_exchange_strong((_Atomic(uint16_t) *)ptr, &v1, rep_val);
+      a = v1;
+    }
+    break;
+    case ATOMICS_OP_COMPARE_EXCHANGE | (2 << 3):
+    {
+      uint32_t v1 = v;
+      atomic_compare_exchange_strong((_Atomic(uint32_t) *)ptr, &v1, rep_val);
+      a = v1;
+    }
+    break;
+#ifdef CONFIG_BIGNUM
+    case ATOMICS_OP_COMPARE_EXCHANGE | (3 << 3):
+    {
+      uint64_t v1 = v;
+      atomic_compare_exchange_strong((_Atomic(uint64_t) *)ptr, &v1, rep_val);
+      a = v1;
+    }
+    break;
+#endif
+    default:
+      abort();
+  }
+
+  switch(class_id) {
+    case JS_CLASS_INT8_ARRAY:
+      a = (int8_t)a;
+      goto done;
+    case JS_CLASS_UINT8_ARRAY:
+      a = (uint8_t)a;
+      goto done;
+    case JS_CLASS_INT16_ARRAY:
+      a = (int16_t)a;
+      goto done;
+    case JS_CLASS_UINT16_ARRAY:
+      a = (uint16_t)a;
+      goto done;
+    case JS_CLASS_INT32_ARRAY:
+    done:
+      ret = JS_NewInt32(ctx, a);
+      break;
+    case JS_CLASS_UINT32_ARRAY:
+      ret = JS_NewUint32(ctx, a);
+      break;
+#ifdef CONFIG_BIGNUM
+    case JS_CLASS_BIG_INT64_ARRAY:
+      ret = JS_NewBigInt64(ctx, a);
+      break;
+    case JS_CLASS_BIG_UINT64_ARRAY:
+      ret = JS_NewBigUint64(ctx, a);
+      break;
+#endif
+    default:
+      abort();
+  }
+  return ret;
+}
+
+JSValue js_atomics_store(JSContext *ctx,
+                                JSValueConst this_obj,
+                                int argc, JSValueConst *argv)
+{
+  int size_log2;
+  void *ptr;
+  JSValue ret;
+  JSArrayBuffer *abuf;
+
+  ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, NULL,
+                           argv[0], argv[1], 0);
+  if (!ptr)
+    return JS_EXCEPTION;
+#ifdef CONFIG_BIGNUM
+  if (size_log2 == 3) {
+    int64_t v64;
+    ret = JS_ToBigIntValueFree(ctx, JS_DupValue(ctx, argv[2]));
+    if (JS_IsException(ret))
+      return ret;
+    if (JS_ToBigInt64(ctx, &v64, ret)) {
+      JS_FreeValue(ctx, ret);
+      return JS_EXCEPTION;
+    }
+    if (abuf->detached)
+      return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+    atomic_store((_Atomic(uint64_t) *)ptr, v64);
+  } else
+#endif
+  {
+    uint32_t v;
+    /* XXX: spec, would be simpler to return the written value */
+    ret = JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[2]));
+    if (JS_IsException(ret))
+      return ret;
+    if (JS_ToUint32(ctx, &v, ret)) {
+      JS_FreeValue(ctx, ret);
+      return JS_EXCEPTION;
+    }
+    if (abuf->detached)
+      return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+    switch(size_log2) {
+      case 0:
+        atomic_store((_Atomic(uint8_t) *)ptr, v);
+        break;
+      case 1:
+        atomic_store((_Atomic(uint16_t) *)ptr, v);
+        break;
+      case 2:
+        atomic_store((_Atomic(uint32_t) *)ptr, v);
+        break;
+      default:
+        abort();
+    }
+  }
+  return ret;
+}
+
+JSValue js_atomics_isLockFree(JSContext *ctx,
+                                     JSValueConst this_obj,
+                                     int argc, JSValueConst *argv)
+{
+  int v, ret;
+  if (JS_ToInt32Sat(ctx, &v, argv[0]))
+    return JS_EXCEPTION;
+  ret = (v == 1 || v == 2 || v == 4
+#ifdef CONFIG_BIGNUM
+         || v == 8
+#endif
+  );
+  return JS_NewBool(ctx, ret);
+}
+
+typedef struct JSAtomicsWaiter {
+  struct list_head link;
+  BOOL linked;
+  pthread_cond_t cond;
+  int32_t *ptr;
+} JSAtomicsWaiter;
+
+pthread_mutex_t js_atomics_mutex = PTHREAD_MUTEX_INITIALIZER;
+struct list_head js_atomics_waiter_list =
+    LIST_HEAD_INIT(js_atomics_waiter_list);
+
+JSValue js_atomics_wait(JSContext *ctx,
+                               JSValueConst this_obj,
+                               int argc, JSValueConst *argv)
+{
+  int64_t v;
+  int32_t v32;
+  void *ptr;
+  int64_t timeout;
+  struct timespec ts;
+  JSAtomicsWaiter waiter_s, *waiter;
+  int ret, size_log2, res;
+  double d;
+
+  ptr = js_atomics_get_ptr(ctx, NULL, &size_log2, NULL,
+                           argv[0], argv[1], 2);
+  if (!ptr)
+    return JS_EXCEPTION;
+#ifdef CONFIG_BIGNUM
+  if (size_log2 == 3) {
+    if (JS_ToBigInt64(ctx, &v, argv[2]))
+      return JS_EXCEPTION;
+  } else
+#endif
+  {
+    if (JS_ToInt32(ctx, &v32, argv[2]))
+      return JS_EXCEPTION;
+    v = v32;
+  }
+  if (JS_ToFloat64(ctx, &d, argv[3]))
+    return JS_EXCEPTION;
+  if (isnan(d) || d > INT64_MAX)
+    timeout = INT64_MAX;
+  else if (d < 0)
+    timeout = 0;
+  else
+    timeout = (int64_t)d;
+  if (!ctx->rt->can_block)
+    return JS_ThrowTypeError(ctx, "cannot block in this thread");
+
+  /* XXX: inefficient if large number of waiters, should hash on
+     'ptr' value */
+  /* XXX: use Linux futexes when available ? */
+  pthread_mutex_lock(&js_atomics_mutex);
+  if (size_log2 == 3) {
+    res = *(int64_t *)ptr != v;
+  } else {
+    res = *(int32_t *)ptr != v;
+  }
+  if (res) {
+    pthread_mutex_unlock(&js_atomics_mutex);
+    return JS_AtomToString(ctx, JS_ATOM_not_equal);
+  }
+
+  waiter = &waiter_s;
+  waiter->ptr = ptr;
+  pthread_cond_init(&waiter->cond, NULL);
+  waiter->linked = TRUE;
+  list_add_tail(&waiter->link, &js_atomics_waiter_list);
+
+  if (timeout == INT64_MAX) {
+    pthread_cond_wait(&waiter->cond, &js_atomics_mutex);
+    ret = 0;
+  } else {
+    /* XXX: use clock monotonic */
+    clock_gettime(CLOCK_REALTIME, &ts);
+    ts.tv_sec += timeout / 1000;
+    ts.tv_nsec += (timeout % 1000) * 1000000;
+    if (ts.tv_nsec >= 1000000000) {
+      ts.tv_nsec -= 1000000000;
+      ts.tv_sec++;
+    }
+    ret = pthread_cond_timedwait(&waiter->cond, &js_atomics_mutex,
+                                 &ts);
+  }
+  if (waiter->linked)
+    list_del(&waiter->link);
+  pthread_mutex_unlock(&js_atomics_mutex);
+  pthread_cond_destroy(&waiter->cond);
+  if (ret == ETIMEDOUT) {
+    return JS_AtomToString(ctx, JS_ATOM_timed_out);
+  } else {
+    return JS_AtomToString(ctx, JS_ATOM_ok);
+  }
+}
+
+JSValue js_atomics_notify(JSContext *ctx,
+                                 JSValueConst this_obj,
+                                 int argc, JSValueConst *argv)
+{
+  struct list_head *el, *el1, waiter_list;
+  int32_t count, n;
+  void *ptr;
+  JSAtomicsWaiter *waiter;
+  JSArrayBuffer *abuf;
+
+  ptr = js_atomics_get_ptr(ctx, &abuf, NULL, NULL, argv[0], argv[1], 1);
+  if (!ptr)
+    return JS_EXCEPTION;
+
+  if (JS_IsUndefined(argv[2])) {
+    count = INT32_MAX;
+  } else {
+    if (JS_ToInt32Clamp(ctx, &count, argv[2], 0, INT32_MAX, 0))
+      return JS_EXCEPTION;
+  }
+  if (abuf->detached)
+    return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+
+  n = 0;
+  if (abuf->shared && count > 0) {
+    pthread_mutex_lock(&js_atomics_mutex);
+    init_list_head(&waiter_list);
+    list_for_each_safe(el, el1, &js_atomics_waiter_list) {
+      waiter = list_entry(el, JSAtomicsWaiter, link);
+      if (waiter->ptr == ptr) {
+        list_del(&waiter->link);
+        waiter->linked = FALSE;
+        list_add_tail(&waiter->link, &waiter_list);
+        n++;
+        if (n >= count)
+          break;
+      }
+    }
+    list_for_each(el, &waiter_list) {
+      waiter = list_entry(el, JSAtomicsWaiter, link);
+      pthread_cond_signal(&waiter->cond);
+    }
+    pthread_mutex_unlock(&js_atomics_mutex);
+  }
+  return JS_NewInt32(ctx, n);
+}
+
+const JSCFunctionListEntry js_atomics_funcs[] = {
+    JS_CFUNC_MAGIC_DEF("add", 3, js_atomics_op, ATOMICS_OP_ADD ),
+    JS_CFUNC_MAGIC_DEF("and", 3, js_atomics_op, ATOMICS_OP_AND ),
+    JS_CFUNC_MAGIC_DEF("or", 3, js_atomics_op, ATOMICS_OP_OR ),
+    JS_CFUNC_MAGIC_DEF("sub", 3, js_atomics_op, ATOMICS_OP_SUB ),
+    JS_CFUNC_MAGIC_DEF("xor", 3, js_atomics_op, ATOMICS_OP_XOR ),
+    JS_CFUNC_MAGIC_DEF("exchange", 3, js_atomics_op, ATOMICS_OP_EXCHANGE ),
+    JS_CFUNC_MAGIC_DEF("compareExchange", 4, js_atomics_op, ATOMICS_OP_COMPARE_EXCHANGE ),
+    JS_CFUNC_MAGIC_DEF("load", 2, js_atomics_op, ATOMICS_OP_LOAD ),
+    JS_CFUNC_DEF("store", 3, js_atomics_store ),
+    JS_CFUNC_DEF("isLockFree", 1, js_atomics_isLockFree ),
+    JS_CFUNC_DEF("wait", 4, js_atomics_wait ),
+    JS_CFUNC_DEF("notify", 3, js_atomics_notify ),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Atomics", JS_PROP_CONFIGURABLE ),
+};
+
+const JSCFunctionListEntry js_atomics_obj[] = {
+    JS_OBJECT_DEF("Atomics", js_atomics_funcs, countof(js_atomics_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
+};
+
+void JS_AddIntrinsicAtomics(JSContext *ctx)
+{
+  /* add Atomics as autoinit object */
+  JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_atomics_obj, countof(js_atomics_obj));
+}
+
+#endif /* CONFIG_ATOMICS */
\ No newline at end of file
diff --git a/src/core/builtins/js-atomics.h b/src/core/builtins/js-atomics.h
new file mode 100644
index 000000000..cb5c3e265
--- /dev/null
+++ b/src/core/builtins/js-atomics.h
@@ -0,0 +1,36 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_ATOMICS_H
+#define QUICKJS_JS_ATOMICS_H
+
+#include "quickjs/quickjs.h"
+
+#ifdef CONFIG_ATOMICS
+void JS_AddIntrinsicAtomics(JSContext *ctx);
+#endif
+
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-big-num.c b/src/core/builtins/js-big-num.c
new file mode 100644
index 000000000..1f96b6bc4
--- /dev/null
+++ b/src/core/builtins/js-big-num.c
@@ -0,0 +1,4637 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-big-num.h"
+#include "../convertion.h"
+#include "../exception.h"
+#include "../function.h"
+#include "../object.h"
+#include "../runtime.h"
+#include "../string.h"
+#include "js-number.h"
+#include "js-operator.h"
+
+#ifdef CONFIG_BIGNUM
+
+JSValue JS_NewBigInt64_1(JSContext *ctx, int64_t v)
+{
+  JSValue val;
+  bf_t *a;
+  val = JS_NewBigInt(ctx);
+  if (JS_IsException(val))
+    return val;
+  a = JS_GetBigInt(val);
+  if (bf_set_si(a, v)) {
+    JS_FreeValue(ctx, val);
+    return JS_ThrowOutOfMemory(ctx);
+  }
+  return val;
+}
+
+JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)
+{
+  if (is_math_mode(ctx) &&
+      v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) {
+    return JS_NewInt64(ctx, v);
+  } else {
+    return JS_NewBigInt64_1(ctx, v);
+  }
+}
+
+JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
+{
+  JSValue val;
+  if (is_math_mode(ctx) && v <= MAX_SAFE_INTEGER) {
+    val = JS_NewInt64(ctx, v);
+  } else {
+    bf_t *a;
+    val = JS_NewBigInt(ctx);
+    if (JS_IsException(val))
+      return val;
+    a = JS_GetBigInt(val);
+    if (bf_set_ui(a, v)) {
+      JS_FreeValue(ctx, val);
+      return JS_ThrowOutOfMemory(ctx);
+    }
+  }
+  return val;
+}
+
+/* if the returned bigfloat is allocated it is equal to
+   'buf'. Otherwise it is a pointer to the bigfloat in 'val'. Return
+   NULL in case of error. */
+bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val)
+{
+  uint32_t tag;
+  bf_t *r;
+  JSBigFloat *p;
+
+  tag = JS_VALUE_GET_NORM_TAG(val);
+  switch(tag) {
+    case JS_TAG_INT:
+    case JS_TAG_BOOL:
+    case JS_TAG_NULL:
+      r = buf;
+      bf_init(ctx->bf_ctx, r);
+      if (bf_set_si(r, JS_VALUE_GET_INT(val)))
+        goto fail;
+      break;
+    case JS_TAG_FLOAT64:
+      r = buf;
+      bf_init(ctx->bf_ctx, r);
+      if (bf_set_float64(r, JS_VALUE_GET_FLOAT64(val))) {
+      fail:
+        bf_delete(r);
+        return NULL;
+      }
+      break;
+    case JS_TAG_BIG_INT:
+    case JS_TAG_BIG_FLOAT:
+      p = JS_VALUE_GET_PTR(val);
+      r = &p->num;
+      break;
+    case JS_TAG_UNDEFINED:
+    default:
+      r = buf;
+      bf_init(ctx->bf_ctx, r);
+      bf_set_nan(r);
+      break;
+  }
+  return r;
+}
+
+/* return NULL if invalid type */
+bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val)
+{
+  uint32_t tag;
+  JSBigDecimal *p;
+  bfdec_t *r;
+
+  tag = JS_VALUE_GET_NORM_TAG(val);
+  switch(tag) {
+    case JS_TAG_BIG_DECIMAL:
+      p = JS_VALUE_GET_PTR(val);
+      r = &p->num;
+      break;
+    default:
+      JS_ThrowTypeError(ctx, "bigdecimal expected");
+      r = NULL;
+      break;
+  }
+  return r;
+}
+
+/* return NaN if bad bigint literal */
+JSValue JS_StringToBigInt(JSContext *ctx, JSValue val)
+{
+  const char *str, *p;
+  size_t len;
+  int flags;
+
+  str = JS_ToCStringLen(ctx, &len, val);
+  JS_FreeValue(ctx, val);
+  if (!str)
+    return JS_EXCEPTION;
+  p = str;
+  p += skip_spaces(p);
+  if ((p - str) == len) {
+    val = JS_NewBigInt64(ctx, 0);
+  } else {
+    flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT;
+    if (is_math_mode(ctx))
+      flags |= ATOD_MODE_BIGINT;
+    val = js_atof(ctx, p, &p, 0, flags);
+    p += skip_spaces(p);
+    if (!JS_IsException(val)) {
+      if ((p - str) != len) {
+        JS_FreeValue(ctx, val);
+        val = JS_NAN;
+      }
+    }
+  }
+  JS_FreeCString(ctx, str);
+  return val;
+}
+
+JSValue JS_StringToBigIntErr(JSContext *ctx, JSValue val)
+{
+  val = JS_StringToBigInt(ctx, val);
+  if (JS_VALUE_IS_NAN(val))
+    return JS_ThrowSyntaxError(ctx, "invalid bigint literal");
+  return val;
+}
+
+/* if the returned bigfloat is allocated it is equal to
+   'buf'. Otherwise it is a pointer to the bigfloat in 'val'. */
+bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val)
+{
+  uint32_t tag;
+  bf_t *r;
+  JSBigFloat *p;
+
+redo:
+  tag = JS_VALUE_GET_NORM_TAG(val);
+  switch(tag) {
+    case JS_TAG_INT:
+    case JS_TAG_NULL:
+    case JS_TAG_UNDEFINED:
+      if (!is_math_mode(ctx))
+        goto fail;
+      /* fall tru */
+    case JS_TAG_BOOL:
+      r = buf;
+      bf_init(ctx->bf_ctx, r);
+      bf_set_si(r, JS_VALUE_GET_INT(val));
+      break;
+    case JS_TAG_FLOAT64:
+    {
+      double d = JS_VALUE_GET_FLOAT64(val);
+      if (!is_math_mode(ctx))
+        goto fail;
+      if (!isfinite(d))
+        goto fail;
+      r = buf;
+      bf_init(ctx->bf_ctx, r);
+      d = trunc(d);
+      bf_set_float64(r, d);
+    }
+    break;
+    case JS_TAG_BIG_INT:
+      p = JS_VALUE_GET_PTR(val);
+      r = &p->num;
+      break;
+    case JS_TAG_BIG_FLOAT:
+      if (!is_math_mode(ctx))
+        goto fail;
+      p = JS_VALUE_GET_PTR(val);
+      if (!bf_is_finite(&p->num))
+        goto fail;
+      r = buf;
+      bf_init(ctx->bf_ctx, r);
+      bf_set(r, &p->num);
+      bf_rint(r, BF_RNDZ);
+      JS_FreeValue(ctx, val);
+      break;
+    case JS_TAG_STRING:
+      val = JS_StringToBigIntErr(ctx, val);
+      if (JS_IsException(val))
+        return NULL;
+      goto redo;
+    case JS_TAG_OBJECT:
+      val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
+      if (JS_IsException(val))
+        return NULL;
+      goto redo;
+    default:
+    fail:
+      JS_FreeValue(ctx, val);
+      JS_ThrowTypeError(ctx, "cannot convert to bigint");
+      return NULL;
+  }
+  return r;
+}
+
+bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val)
+{
+  return JS_ToBigIntFree(ctx, buf, JS_DupValue(ctx, val));
+}
+
+__maybe_unused JSValue JS_ToBigIntValueFree(JSContext *ctx, JSValue val)
+{
+  if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT) {
+    return val;
+  } else {
+    bf_t a_s, *a, *r;
+    int ret;
+    JSValue res;
+
+    res = JS_NewBigInt(ctx);
+    if (JS_IsException(res))
+      return JS_EXCEPTION;
+    a = JS_ToBigIntFree(ctx, &a_s, val);
+    if (!a) {
+      JS_FreeValue(ctx, res);
+      return JS_EXCEPTION;
+    }
+    r = JS_GetBigInt(res);
+    ret = bf_set(r, a);
+    JS_FreeBigInt(ctx, a, &a_s);
+    if (ret) {
+      JS_FreeValue(ctx, res);
+      return JS_ThrowOutOfMemory(ctx);
+    }
+    return JS_CompactBigInt(ctx, res);
+  }
+}
+
+/* free the bf_t allocated by JS_ToBigInt */
+void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf)
+{
+  if (a == buf) {
+    bf_delete(a);
+  } else {
+    JSBigFloat *p = (JSBigFloat *)((uint8_t *)a -
+                                  offsetof(JSBigFloat, num));
+    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_BIG_FLOAT, p));
+  }
+}
+
+/* XXX: merge with JS_ToInt64Free with a specific flag */
+int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
+{
+  bf_t a_s, *a;
+
+  a = JS_ToBigIntFree(ctx, &a_s, val);
+  if (!a) {
+    *pres = 0;
+    return -1;
+  }
+  bf_get_int64(pres, a, BF_GET_INT_MOD);
+  JS_FreeBigInt(ctx, a, &a_s);
+  return 0;
+}
+
+int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
+{
+  return JS_ToBigInt64Free(ctx, pres, JS_DupValue(ctx, val));
+}
+
+JSBigFloat *js_new_bf(JSContext *ctx)
+{
+  JSBigFloat *p;
+  p = js_malloc(ctx, sizeof(*p));
+  if (!p)
+    return NULL;
+  p->header.ref_count = 1;
+  bf_init(ctx->bf_ctx, &p->num);
+  return p;
+}
+
+JSValue JS_NewBigFloat(JSContext *ctx)
+{
+  JSBigFloat *p;
+  p = js_malloc(ctx, sizeof(*p));
+  if (!p)
+    return JS_EXCEPTION;
+  p->header.ref_count = 1;
+  bf_init(ctx->bf_ctx, &p->num);
+  return JS_MKPTR(JS_TAG_BIG_FLOAT, p);
+}
+
+JSValue JS_NewBigDecimal(JSContext *ctx)
+{
+  JSBigDecimal *p;
+  p = js_malloc(ctx, sizeof(*p));
+  if (!p)
+    return JS_EXCEPTION;
+  p->header.ref_count = 1;
+  bfdec_init(ctx->bf_ctx, &p->num);
+  return JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
+}
+
+JSValue JS_NewBigInt(JSContext *ctx)
+{
+  JSBigFloat *p;
+  p = js_malloc(ctx, sizeof(*p));
+  if (!p)
+    return JS_EXCEPTION;
+  p->header.ref_count = 1;
+  bf_init(ctx->bf_ctx, &p->num);
+  return JS_MKPTR(JS_TAG_BIG_INT, p);
+}
+
+JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
+                                 BOOL convert_to_safe_integer)
+{
+  int64_t v;
+  bf_t *a;
+
+  if (JS_VALUE_GET_TAG(val) != JS_TAG_BIG_INT)
+    return val; /* fail safe */
+  a = JS_GetBigInt(val);
+  if (convert_to_safe_integer && bf_get_int64(&v, a, 0) == 0 &&
+      v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) {
+    JS_FreeValue(ctx, val);
+    return JS_NewInt64(ctx, v);
+  } else if (a->expn == BF_EXP_ZERO && a->sign) {
+    JSBigFloat *p = JS_VALUE_GET_PTR(val);
+    assert(p->header.ref_count == 1);
+    a->sign = 0;
+  }
+  return val;
+}
+
+/* Convert the big int to a safe integer if in math mode. normalize
+   the zero representation. Could also be used to convert the bigint
+   to a short bigint value. The reference count of the value must be
+   1. Cannot fail */
+JSValue JS_CompactBigInt(JSContext *ctx, JSValue val)
+{
+  return JS_CompactBigInt1(ctx, val, is_math_mode(ctx));
+}
+
+/* must be kept in sync with JSOverloadableOperatorEnum */
+/* XXX: use atoms ? */
+const char js_overloadable_operator_names[JS_OVOP_COUNT][4] = {
+    "+",
+    "-",
+    "*",
+    "/",
+    "%",
+    "**",
+    "|",
+    "&",
+    "^",
+    "<<",
+    ">>",
+    ">>>",
+    "==",
+    "<",
+    "pos",
+    "neg",
+    "++",
+    "--",
+    "~",
+};
+
+int get_ovop_from_opcode(OPCodeEnum op)
+{
+  switch(op) {
+    case OP_add:
+      return JS_OVOP_ADD;
+    case OP_sub:
+      return JS_OVOP_SUB;
+    case OP_mul:
+      return JS_OVOP_MUL;
+    case OP_div:
+      return JS_OVOP_DIV;
+    case OP_mod:
+    case OP_math_mod:
+      return JS_OVOP_MOD;
+    case OP_pow:
+      return JS_OVOP_POW;
+    case OP_or:
+      return JS_OVOP_OR;
+    case OP_and:
+      return JS_OVOP_AND;
+    case OP_xor:
+      return JS_OVOP_XOR;
+    case OP_shl:
+      return JS_OVOP_SHL;
+    case OP_sar:
+      return JS_OVOP_SAR;
+    case OP_shr:
+      return JS_OVOP_SHR;
+    case OP_eq:
+    case OP_neq:
+      return JS_OVOP_EQ;
+    case OP_lt:
+    case OP_lte:
+    case OP_gt:
+    case OP_gte:
+      return JS_OVOP_LESS;
+    case OP_plus:
+      return JS_OVOP_POS;
+    case OP_neg:
+      return JS_OVOP_NEG;
+    case OP_inc:
+      return JS_OVOP_INC;
+    case OP_dec:
+      return JS_OVOP_DEC;
+    default:
+      abort();
+  }
+}
+
+/* return NULL if not present */
+JSObject *find_binary_op(JSBinaryOperatorDef *def,
+                                uint32_t operator_index,
+                                JSOverloadableOperatorEnum op)
+{
+  JSBinaryOperatorDefEntry *ent;
+  int i;
+  for(i = 0; i < def->count; i++) {
+    ent = &def->tab[i];
+    if (ent->operator_index == operator_index)
+      return ent->ops[op];
+  }
+  return NULL;
+}
+
+/* return -1 if exception, 0 if no operator overloading, 1 if
+   overloaded operator called */
+__exception int js_call_binary_op_fallback(JSContext *ctx,
+                                                  JSValue *pret,
+                                                  JSValueConst op1,
+                                                  JSValueConst op2,
+                                                  OPCodeEnum op,
+                                                  BOOL is_numeric,
+                                                  int hint)
+{
+  JSValue opset1_obj, opset2_obj, method, ret, new_op1, new_op2;
+  JSOperatorSetData *opset1, *opset2;
+  JSOverloadableOperatorEnum ovop;
+  JSObject *p;
+  JSValueConst args[2];
+
+  if (!ctx->allow_operator_overloading)
+    return 0;
+
+  opset2_obj = JS_UNDEFINED;
+  opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet);
+  if (JS_IsException(opset1_obj))
+    goto exception;
+  if (JS_IsUndefined(opset1_obj))
+    return 0;
+  opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
+  if (!opset1)
+    goto exception;
+
+  opset2_obj = JS_GetProperty(ctx, op2, JS_ATOM_Symbol_operatorSet);
+  if (JS_IsException(opset2_obj))
+    goto exception;
+  if (JS_IsUndefined(opset2_obj)) {
+    JS_FreeValue(ctx, opset1_obj);
+    return 0;
+  }
+  opset2 = JS_GetOpaque2(ctx, opset2_obj, JS_CLASS_OPERATOR_SET);
+  if (!opset2)
+    goto exception;
+
+  if (opset1->is_primitive && opset2->is_primitive) {
+    JS_FreeValue(ctx, opset1_obj);
+    JS_FreeValue(ctx, opset2_obj);
+    return 0;
+  }
+
+  ovop = get_ovop_from_opcode(op);
+
+  if (opset1->operator_counter == opset2->operator_counter) {
+    p = opset1->self_ops[ovop];
+  } else if (opset1->operator_counter > opset2->operator_counter) {
+    p = find_binary_op(&opset1->left, opset2->operator_counter, ovop);
+  } else {
+    p = find_binary_op(&opset2->right, opset1->operator_counter, ovop);
+  }
+  if (!p) {
+    JS_ThrowTypeError(ctx, "operator %s: no function defined",
+                      js_overloadable_operator_names[ovop]);
+    goto exception;
+  }
+
+  if (opset1->is_primitive) {
+    if (is_numeric) {
+      new_op1 = JS_ToNumeric(ctx, op1);
+    } else {
+      new_op1 = JS_ToPrimitive(ctx, op1, hint);
+    }
+    if (JS_IsException(new_op1))
+      goto exception;
+  } else {
+    new_op1 = JS_DupValue(ctx, op1);
+  }
+
+  if (opset2->is_primitive) {
+    if (is_numeric) {
+      new_op2 = JS_ToNumeric(ctx, op2);
+    } else {
+      new_op2 = JS_ToPrimitive(ctx, op2, hint);
+    }
+    if (JS_IsException(new_op2)) {
+      JS_FreeValue(ctx, new_op1);
+      goto exception;
+    }
+  } else {
+    new_op2 = JS_DupValue(ctx, op2);
+  }
+
+  /* XXX: could apply JS_ToPrimitive() if primitive type so that the
+     operator function does not get a value object */
+
+  method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+  if (ovop == JS_OVOP_LESS && (op == OP_lte || op == OP_gt)) {
+    args[0] = new_op2;
+    args[1] = new_op1;
+  } else {
+    args[0] = new_op1;
+    args[1] = new_op2;
+  }
+  ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
+  JS_FreeValue(ctx, new_op1);
+  JS_FreeValue(ctx, new_op2);
+  if (JS_IsException(ret))
+    goto exception;
+  if (ovop == JS_OVOP_EQ) {
+    BOOL res = JS_ToBoolFree(ctx, ret);
+    if (op == OP_neq)
+      res ^= 1;
+    ret = JS_NewBool(ctx, res);
+  } else if (ovop == JS_OVOP_LESS) {
+    if (JS_IsUndefined(ret)) {
+      ret = JS_FALSE;
+    } else {
+      BOOL res = JS_ToBoolFree(ctx, ret);
+      if (op == OP_lte || op == OP_gte)
+        res ^= 1;
+      ret = JS_NewBool(ctx, res);
+    }
+  }
+  JS_FreeValue(ctx, opset1_obj);
+  JS_FreeValue(ctx, opset2_obj);
+  *pret = ret;
+  return 1;
+exception:
+  JS_FreeValue(ctx, opset1_obj);
+  JS_FreeValue(ctx, opset2_obj);
+  *pret = JS_UNDEFINED;
+  return -1;
+}
+
+/* try to call the operation on the operatorSet field of 'obj'. Only
+   used for "/" and "**" on the BigInt prototype in math mode */
+__exception int js_call_binary_op_simple(JSContext *ctx,
+                                                JSValue *pret,
+                                                JSValueConst obj,
+                                                JSValueConst op1,
+                                                JSValueConst op2,
+                                                OPCodeEnum op)
+{
+  JSValue opset1_obj, method, ret, new_op1, new_op2;
+  JSOperatorSetData *opset1;
+  JSOverloadableOperatorEnum ovop;
+  JSObject *p;
+  JSValueConst args[2];
+
+  opset1_obj = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet);
+  if (JS_IsException(opset1_obj))
+    goto exception;
+  if (JS_IsUndefined(opset1_obj))
+    return 0;
+  opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
+  if (!opset1)
+    goto exception;
+  ovop = get_ovop_from_opcode(op);
+
+  p = opset1->self_ops[ovop];
+  if (!p) {
+    JS_FreeValue(ctx, opset1_obj);
+    return 0;
+  }
+
+  new_op1 = JS_ToNumeric(ctx, op1);
+  if (JS_IsException(new_op1))
+    goto exception;
+  new_op2 = JS_ToNumeric(ctx, op2);
+  if (JS_IsException(new_op2)) {
+    JS_FreeValue(ctx, new_op1);
+    goto exception;
+  }
+
+  method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+  args[0] = new_op1;
+  args[1] = new_op2;
+  ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
+  JS_FreeValue(ctx, new_op1);
+  JS_FreeValue(ctx, new_op2);
+  if (JS_IsException(ret))
+    goto exception;
+  JS_FreeValue(ctx, opset1_obj);
+  *pret = ret;
+  return 1;
+exception:
+  JS_FreeValue(ctx, opset1_obj);
+  *pret = JS_UNDEFINED;
+  return -1;
+}
+
+/* return -1 if exception, 0 if no operator overloading, 1 if
+   overloaded operator called */
+__exception int js_call_unary_op_fallback(JSContext *ctx,
+                                                 JSValue *pret,
+                                                 JSValueConst op1,
+                                                 OPCodeEnum op)
+{
+  JSValue opset1_obj, method, ret;
+  JSOperatorSetData *opset1;
+  JSOverloadableOperatorEnum ovop;
+  JSObject *p;
+
+  if (!ctx->allow_operator_overloading)
+    return 0;
+
+  opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet);
+  if (JS_IsException(opset1_obj))
+    goto exception;
+  if (JS_IsUndefined(opset1_obj))
+    return 0;
+  opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
+  if (!opset1)
+    goto exception;
+  if (opset1->is_primitive) {
+    JS_FreeValue(ctx, opset1_obj);
+    return 0;
+  }
+
+  ovop = get_ovop_from_opcode(op);
+
+  p = opset1->self_ops[ovop];
+  if (!p) {
+    JS_ThrowTypeError(ctx, "no overloaded operator %s",
+                      js_overloadable_operator_names[ovop]);
+    goto exception;
+  }
+  method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+  ret = JS_CallFree(ctx, method, JS_UNDEFINED, 1, &op1);
+  if (JS_IsException(ret))
+    goto exception;
+  JS_FreeValue(ctx, opset1_obj);
+  *pret = ret;
+  return 1;
+exception:
+  JS_FreeValue(ctx, opset1_obj);
+  *pret = JS_UNDEFINED;
+  return -1;
+}
+
+JSValue throw_bf_exception(JSContext *ctx, int status)
+{
+  const char *str;
+  if (status & BF_ST_MEM_ERROR)
+    return JS_ThrowOutOfMemory(ctx);
+  if (status & BF_ST_DIVIDE_ZERO) {
+    str = "division by zero";
+  } else if (status & BF_ST_INVALID_OP) {
+    str = "invalid operation";
+  } else {
+    str = "integer overflow";
+  }
+  return JS_ThrowRangeError(ctx, "%s", str);
+}
+
+int js_unary_arith_bigint(JSContext *ctx,
+                                 JSValue *pres, OPCodeEnum op, JSValue op1)
+{
+  bf_t a_s, *r, *a;
+  int ret, v;
+  JSValue res;
+
+  if (op == OP_plus && !is_math_mode(ctx)) {
+    JS_ThrowTypeError(ctx, "bigint argument with unary +");
+    JS_FreeValue(ctx, op1);
+    return -1;
+  }
+  res = JS_NewBigInt(ctx);
+  if (JS_IsException(res)) {
+    JS_FreeValue(ctx, op1);
+    return -1;
+  }
+  r = JS_GetBigInt(res);
+  a = JS_ToBigInt(ctx, &a_s, op1);
+  ret = 0;
+  switch(op) {
+    case OP_inc:
+    case OP_dec:
+      v = 2 * (op - OP_dec) - 1;
+      ret = bf_add_si(r, a, v, BF_PREC_INF, BF_RNDZ);
+      break;
+    case OP_plus:
+      ret = bf_set(r, a);
+      break;
+    case OP_neg:
+      ret = bf_set(r, a);
+      bf_neg(r);
+      break;
+    case OP_not:
+      ret = bf_add_si(r, a, 1, BF_PREC_INF, BF_RNDZ);
+      bf_neg(r);
+      break;
+    default:
+      abort();
+  }
+  JS_FreeBigInt(ctx, a, &a_s);
+  JS_FreeValue(ctx, op1);
+  if (unlikely(ret)) {
+    JS_FreeValue(ctx, res);
+    throw_bf_exception(ctx, ret);
+    return -1;
+  }
+  res = JS_CompactBigInt(ctx, res);
+  *pres = res;
+  return 0;
+}
+
+int js_unary_arith_bigfloat(JSContext *ctx,
+                                   JSValue *pres, OPCodeEnum op, JSValue op1)
+{
+  bf_t a_s, *r, *a;
+  int ret, v;
+  JSValue res;
+
+  if (op == OP_plus && !is_math_mode(ctx)) {
+    JS_ThrowTypeError(ctx, "bigfloat argument with unary +");
+    JS_FreeValue(ctx, op1);
+    return -1;
+  }
+
+  res = JS_NewBigFloat(ctx);
+  if (JS_IsException(res)) {
+    JS_FreeValue(ctx, op1);
+    return -1;
+  }
+  r = JS_GetBigFloat(res);
+  a = JS_ToBigFloat(ctx, &a_s, op1);
+  ret = 0;
+  switch(op) {
+    case OP_inc:
+    case OP_dec:
+      v = 2 * (op - OP_dec) - 1;
+      ret = bf_add_si(r, a, v, ctx->fp_env.prec, ctx->fp_env.flags);
+      break;
+    case OP_plus:
+      ret = bf_set(r, a);
+      break;
+    case OP_neg:
+      ret = bf_set(r, a);
+      bf_neg(r);
+      break;
+    default:
+      abort();
+  }
+  if (a == &a_s)
+    bf_delete(a);
+  JS_FreeValue(ctx, op1);
+  if (unlikely(ret & BF_ST_MEM_ERROR)) {
+    JS_FreeValue(ctx, res);
+    throw_bf_exception(ctx, ret);
+    return -1;
+  }
+  *pres = res;
+  return 0;
+}
+
+int js_unary_arith_bigdecimal(JSContext *ctx,
+                                     JSValue *pres, OPCodeEnum op, JSValue op1)
+{
+  bfdec_t *r, *a;
+  int ret, v;
+  JSValue res;
+
+  if (op == OP_plus && !is_math_mode(ctx)) {
+    JS_ThrowTypeError(ctx, "bigdecimal argument with unary +");
+    JS_FreeValue(ctx, op1);
+    return -1;
+  }
+
+  res = JS_NewBigDecimal(ctx);
+  if (JS_IsException(res)) {
+    JS_FreeValue(ctx, op1);
+    return -1;
+  }
+  r = JS_GetBigDecimal(res);
+  a = JS_ToBigDecimal(ctx, op1);
+  ret = 0;
+  switch(op) {
+    case OP_inc:
+    case OP_dec:
+      v = 2 * (op - OP_dec) - 1;
+      ret = bfdec_add_si(r, a, v, BF_PREC_INF, BF_RNDZ);
+      break;
+    case OP_plus:
+      ret = bfdec_set(r, a);
+      break;
+    case OP_neg:
+      ret = bfdec_set(r, a);
+      bfdec_neg(r);
+      break;
+    default:
+      abort();
+  }
+  JS_FreeValue(ctx, op1);
+  if (unlikely(ret)) {
+    JS_FreeValue(ctx, res);
+    throw_bf_exception(ctx, ret);
+    return -1;
+  }
+  *pres = res;
+  return 0;
+}
+
+no_inline __exception int js_unary_arith_slow(JSContext *ctx,
+                                                     JSValue *sp,
+                                                     OPCodeEnum op)
+{
+  JSValue op1, val;
+  int v, ret;
+  uint32_t tag;
+
+  op1 = sp[-1];
+  /* fast path for float64 */
+  if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)))
+    goto handle_float64;
+  if (JS_IsObject(op1)) {
+    ret = js_call_unary_op_fallback(ctx, &val, op1, op);
+    if (ret < 0)
+      return -1;
+    if (ret) {
+      JS_FreeValue(ctx, op1);
+      sp[-1] = val;
+      return 0;
+    }
+  }
+
+  op1 = JS_ToNumericFree(ctx, op1);
+  if (JS_IsException(op1))
+    goto exception;
+  tag = JS_VALUE_GET_TAG(op1);
+  switch(tag) {
+    case JS_TAG_INT:
+    {
+      int64_t v64;
+      v64 = JS_VALUE_GET_INT(op1);
+      switch(op) {
+        case OP_inc:
+        case OP_dec:
+          v = 2 * (op - OP_dec) - 1;
+          v64 += v;
+          break;
+        case OP_plus:
+          break;
+        case OP_neg:
+          if (v64 == 0) {
+            sp[-1] = __JS_NewFloat64(ctx, -0.0);
+            return 0;
+          } else {
+            v64 = -v64;
+          }
+          break;
+        default:
+          abort();
+      }
+      sp[-1] = JS_NewInt64(ctx, v64);
+    }
+    break;
+    case JS_TAG_BIG_INT:
+    handle_bigint:
+      if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, op, op1))
+        goto exception;
+      break;
+    case JS_TAG_BIG_FLOAT:
+      if (ctx->rt->bigfloat_ops.unary_arith(ctx, sp - 1, op, op1))
+        goto exception;
+      break;
+    case JS_TAG_BIG_DECIMAL:
+      if (ctx->rt->bigdecimal_ops.unary_arith(ctx, sp - 1, op, op1))
+        goto exception;
+      break;
+    default:
+    handle_float64:
+    {
+      double d;
+      if (is_math_mode(ctx))
+        goto handle_bigint;
+      d = JS_VALUE_GET_FLOAT64(op1);
+      switch(op) {
+        case OP_inc:
+        case OP_dec:
+          v = 2 * (op - OP_dec) - 1;
+          d += v;
+          break;
+        case OP_plus:
+          break;
+        case OP_neg:
+          d = -d;
+          break;
+        default:
+          abort();
+      }
+      sp[-1] = __JS_NewFloat64(ctx, d);
+    }
+    break;
+  }
+  return 0;
+exception:
+  sp[-1] = JS_UNDEFINED;
+  return -1;
+}
+
+__exception int js_post_inc_slow(JSContext *ctx,
+                                        JSValue *sp, OPCodeEnum op)
+{
+  JSValue op1;
+
+  /* XXX: allow custom operators */
+  op1 = sp[-1];
+  op1 = JS_ToNumericFree(ctx, op1);
+  if (JS_IsException(op1)) {
+    sp[-1] = JS_UNDEFINED;
+    return -1;
+  }
+  sp[-1] = op1;
+  sp[0] = JS_DupValue(ctx, op1);
+  return js_unary_arith_slow(ctx, sp + 1, op - OP_post_dec + OP_dec);
+}
+
+no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
+{
+  JSValue op1, val;
+  int ret;
+
+  op1 = sp[-1];
+  if (JS_IsObject(op1)) {
+    ret = js_call_unary_op_fallback(ctx, &val, op1, OP_not);
+    if (ret < 0)
+      return -1;
+    if (ret) {
+      JS_FreeValue(ctx, op1);
+      sp[-1] = val;
+      return 0;
+    }
+  }
+
+  op1 = JS_ToNumericFree(ctx, op1);
+  if (JS_IsException(op1))
+    goto exception;
+  if (is_math_mode(ctx) || JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) {
+    if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, OP_not, op1))
+      goto exception;
+  } else {
+    int32_t v1;
+    if (unlikely(JS_ToInt32Free(ctx, &v1, op1)))
+      goto exception;
+    sp[-1] = JS_NewInt32(ctx, ~v1);
+  }
+  return 0;
+exception:
+  sp[-1] = JS_UNDEFINED;
+  return -1;
+}
+
+int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op,
+                                    JSValue *pres, JSValue op1, JSValue op2)
+{
+  bf_t a_s, b_s, *r, *a, *b;
+  int ret;
+  JSValue res;
+
+  res = JS_NewBigFloat(ctx);
+  if (JS_IsException(res)) {
+    JS_FreeValue(ctx, op1);
+    JS_FreeValue(ctx, op2);
+    return -1;
+  }
+  r = JS_GetBigFloat(res);
+  a = JS_ToBigFloat(ctx, &a_s, op1);
+  b = JS_ToBigFloat(ctx, &b_s, op2);
+  bf_init(ctx->bf_ctx, r);
+  switch(op) {
+    case OP_add:
+      ret = bf_add(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
+      break;
+    case OP_sub:
+      ret = bf_sub(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
+      break;
+    case OP_mul:
+      ret = bf_mul(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
+      break;
+    case OP_div:
+      ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
+      break;
+    case OP_math_mod:
+      /* Euclidian remainder */
+      ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
+                   BF_DIVREM_EUCLIDIAN);
+      break;
+    case OP_mod:
+      ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
+                   BF_RNDZ);
+      break;
+    case OP_pow:
+      ret = bf_pow(r, a, b, ctx->fp_env.prec,
+                   ctx->fp_env.flags | BF_POW_JS_QUIRKS);
+      break;
+    default:
+      abort();
+  }
+  if (a == &a_s)
+    bf_delete(a);
+  if (b == &b_s)
+    bf_delete(b);
+  JS_FreeValue(ctx, op1);
+  JS_FreeValue(ctx, op2);
+  if (unlikely(ret & BF_ST_MEM_ERROR)) {
+    JS_FreeValue(ctx, res);
+    throw_bf_exception(ctx, ret);
+    return -1;
+  }
+  *pres = res;
+  return 0;
+}
+
+int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,
+                                  JSValue *pres, JSValue op1, JSValue op2)
+{
+  bf_t a_s, b_s, *r, *a, *b;
+  int ret;
+  JSValue res;
+
+  res = JS_NewBigInt(ctx);
+  if (JS_IsException(res))
+    goto fail;
+  a = JS_ToBigInt(ctx, &a_s, op1);
+  if (!a)
+    goto fail;
+  b = JS_ToBigInt(ctx, &b_s, op2);
+  if (!b) {
+    JS_FreeBigInt(ctx, a, &a_s);
+    goto fail;
+  }
+  r = JS_GetBigInt(res);
+  ret = 0;
+  switch(op) {
+    case OP_add:
+      ret = bf_add(r, a, b, BF_PREC_INF, BF_RNDZ);
+      break;
+    case OP_sub:
+      ret = bf_sub(r, a, b, BF_PREC_INF, BF_RNDZ);
+      break;
+    case OP_mul:
+      ret = bf_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
+      break;
+    case OP_div:
+      if (!is_math_mode(ctx)) {
+        bf_t rem_s, *rem = &rem_s;
+        bf_init(ctx->bf_ctx, rem);
+        ret = bf_divrem(r, rem, a, b, BF_PREC_INF, BF_RNDZ,
+                        BF_RNDZ);
+        bf_delete(rem);
+      } else {
+        goto math_mode_div_pow;
+      }
+      break;
+    case OP_math_mod:
+      /* Euclidian remainder */
+      ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
+                   BF_DIVREM_EUCLIDIAN) & BF_ST_INVALID_OP;
+      break;
+    case OP_mod:
+      ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
+                   BF_RNDZ) & BF_ST_INVALID_OP;
+      break;
+    case OP_pow:
+      if (b->sign) {
+        if (!is_math_mode(ctx)) {
+          ret = BF_ST_INVALID_OP;
+        } else {
+        math_mode_div_pow:
+          JS_FreeValue(ctx, res);
+          ret = js_call_binary_op_simple(ctx, &res, ctx->class_proto[JS_CLASS_BIG_INT], op1, op2, op);
+          if (ret != 0) {
+            JS_FreeBigInt(ctx, a, &a_s);
+            JS_FreeBigInt(ctx, b, &b_s);
+            JS_FreeValue(ctx, op1);
+            JS_FreeValue(ctx, op2);
+            if (ret < 0) {
+              return -1;
+            } else {
+              *pres = res;
+              return 0;
+            }
+          }
+          /* if no BigInt power operator defined, return a
+             bigfloat */
+          res = JS_NewBigFloat(ctx);
+          if (JS_IsException(res)) {
+            JS_FreeBigInt(ctx, a, &a_s);
+            JS_FreeBigInt(ctx, b, &b_s);
+            goto fail;
+          }
+          r = JS_GetBigFloat(res);
+          if (op == OP_div) {
+            ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags) & BF_ST_MEM_ERROR;
+          } else {
+            ret = bf_pow(r, a, b, ctx->fp_env.prec,
+                         ctx->fp_env.flags | BF_POW_JS_QUIRKS) & BF_ST_MEM_ERROR;
+          }
+          JS_FreeBigInt(ctx, a, &a_s);
+          JS_FreeBigInt(ctx, b, &b_s);
+          JS_FreeValue(ctx, op1);
+          JS_FreeValue(ctx, op2);
+          if (unlikely(ret)) {
+            JS_FreeValue(ctx, res);
+            throw_bf_exception(ctx, ret);
+            return -1;
+          }
+          *pres = res;
+          return 0;
+        }
+      } else {
+        ret = bf_pow(r, a, b, BF_PREC_INF, BF_RNDZ | BF_POW_JS_QUIRKS);
+      }
+      break;
+
+      /* logical operations */
+    case OP_shl:
+    case OP_sar:
+    {
+      slimb_t v2;
+#if LIMB_BITS == 32
+      bf_get_int32(&v2, b, 0);
+      if (v2 == INT32_MIN)
+        v2 = INT32_MIN + 1;
+#else
+      bf_get_int64(&v2, b, 0);
+      if (v2 == INT64_MIN)
+        v2 = INT64_MIN + 1;
+#endif
+      if (op == OP_sar)
+        v2 = -v2;
+      ret = bf_set(r, a);
+      ret |= bf_mul_2exp(r, v2, BF_PREC_INF, BF_RNDZ);
+      if (v2 < 0) {
+        ret |= bf_rint(r, BF_RNDD) & (BF_ST_OVERFLOW | BF_ST_MEM_ERROR);
+      }
+    }
+    break;
+    case OP_and:
+      ret = bf_logic_and(r, a, b);
+      break;
+    case OP_or:
+      ret = bf_logic_or(r, a, b);
+      break;
+    case OP_xor:
+      ret = bf_logic_xor(r, a, b);
+      break;
+    default:
+      abort();
+  }
+  JS_FreeBigInt(ctx, a, &a_s);
+  JS_FreeBigInt(ctx, b, &b_s);
+  JS_FreeValue(ctx, op1);
+  JS_FreeValue(ctx, op2);
+  if (unlikely(ret)) {
+    JS_FreeValue(ctx, res);
+    throw_bf_exception(ctx, ret);
+    return -1;
+  }
+  *pres = JS_CompactBigInt(ctx, res);
+  return 0;
+fail:
+  JS_FreeValue(ctx, res);
+  JS_FreeValue(ctx, op1);
+  JS_FreeValue(ctx, op2);
+  return -1;
+}
+
+/* b must be a positive integer */
+int js_bfdec_pow(bfdec_t *r, const bfdec_t *a, const bfdec_t *b)
+{
+  bfdec_t b1;
+  int32_t b2;
+  int ret;
+
+  bfdec_init(b->ctx, &b1);
+  ret = bfdec_set(&b1, b);
+  if (ret) {
+    bfdec_delete(&b1);
+    return ret;
+  }
+  ret = bfdec_rint(&b1, BF_RNDZ);
+  if (ret) {
+    bfdec_delete(&b1);
+    return BF_ST_INVALID_OP; /* must be an integer */
+  }
+  ret = bfdec_get_int32(&b2, &b1);
+  bfdec_delete(&b1);
+  if (ret)
+    return ret; /* overflow */
+  if (b2 < 0)
+    return BF_ST_INVALID_OP; /* must be positive */
+  return bfdec_pow_ui(r, a, b2);
+}
+
+int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op,
+                                      JSValue *pres, JSValue op1, JSValue op2)
+{
+  bfdec_t *r, *a, *b;
+  int ret;
+  JSValue res;
+
+  res = JS_NewBigDecimal(ctx);
+  if (JS_IsException(res))
+    goto fail;
+  r = JS_GetBigDecimal(res);
+
+  a = JS_ToBigDecimal(ctx, op1);
+  if (!a)
+    goto fail;
+  b = JS_ToBigDecimal(ctx, op2);
+  if (!b)
+    goto fail;
+  switch(op) {
+    case OP_add:
+      ret = bfdec_add(r, a, b, BF_PREC_INF, BF_RNDZ);
+      break;
+    case OP_sub:
+      ret = bfdec_sub(r, a, b, BF_PREC_INF, BF_RNDZ);
+      break;
+    case OP_mul:
+      ret = bfdec_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
+      break;
+    case OP_div:
+      ret = bfdec_div(r, a, b, BF_PREC_INF, BF_RNDZ);
+      break;
+    case OP_math_mod:
+      /* Euclidian remainder */
+      ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_DIVREM_EUCLIDIAN);
+      break;
+    case OP_mod:
+      ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_RNDZ);
+      break;
+    case OP_pow:
+      ret = js_bfdec_pow(r, a, b);
+      break;
+    default:
+      abort();
+  }
+  JS_FreeValue(ctx, op1);
+  JS_FreeValue(ctx, op2);
+  if (unlikely(ret)) {
+    JS_FreeValue(ctx, res);
+    throw_bf_exception(ctx, ret);
+    return -1;
+  }
+  *pres = res;
+  return 0;
+fail:
+  JS_FreeValue(ctx, res);
+  JS_FreeValue(ctx, op1);
+  JS_FreeValue(ctx, op2);
+  return -1;
+}
+
+no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
+                                                      OPCodeEnum op)
+{
+  JSValue op1, op2, res;
+  uint32_t tag1, tag2;
+  int ret;
+  double d1, d2;
+
+  op1 = sp[-2];
+  op2 = sp[-1];
+  tag1 = JS_VALUE_GET_NORM_TAG(op1);
+  tag2 = JS_VALUE_GET_NORM_TAG(op2);
+  /* fast path for float operations */
+  if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) {
+    d1 = JS_VALUE_GET_FLOAT64(op1);
+    d2 = JS_VALUE_GET_FLOAT64(op2);
+    goto handle_float64;
+  }
+
+  /* try to call an overloaded operator */
+  if ((tag1 == JS_TAG_OBJECT &&
+       (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
+      (tag2 == JS_TAG_OBJECT &&
+       (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
+    ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
+    if (ret != 0) {
+      JS_FreeValue(ctx, op1);
+      JS_FreeValue(ctx, op2);
+      if (ret < 0) {
+        goto exception;
+      } else {
+        sp[-2] = res;
+        return 0;
+      }
+    }
+  }
+
+  op1 = JS_ToNumericFree(ctx, op1);
+  if (JS_IsException(op1)) {
+    JS_FreeValue(ctx, op2);
+    goto exception;
+  }
+  op2 = JS_ToNumericFree(ctx, op2);
+  if (JS_IsException(op2)) {
+    JS_FreeValue(ctx, op1);
+    goto exception;
+  }
+  tag1 = JS_VALUE_GET_NORM_TAG(op1);
+  tag2 = JS_VALUE_GET_NORM_TAG(op2);
+
+  if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
+    int32_t v1, v2;
+    int64_t v;
+    v1 = JS_VALUE_GET_INT(op1);
+    v2 = JS_VALUE_GET_INT(op2);
+    switch(op) {
+      case OP_sub:
+        v = (int64_t)v1 - (int64_t)v2;
+        break;
+      case OP_mul:
+        v = (int64_t)v1 * (int64_t)v2;
+        if (is_math_mode(ctx) &&
+            (v < -MAX_SAFE_INTEGER || v > MAX_SAFE_INTEGER))
+          goto handle_bigint;
+        if (v == 0 && (v1 | v2) < 0) {
+          sp[-2] = __JS_NewFloat64(ctx, -0.0);
+          return 0;
+        }
+        break;
+      case OP_div:
+        if (is_math_mode(ctx))
+          goto handle_bigint;
+        sp[-2] = __JS_NewFloat64(ctx, (double)v1 / (double)v2);
+        return 0;
+      case OP_math_mod:
+        if (unlikely(v2 == 0)) {
+          throw_bf_exception(ctx, BF_ST_DIVIDE_ZERO);
+          goto exception;
+        }
+        v = (int64_t)v1 % (int64_t)v2;
+        if (v < 0) {
+          if (v2 < 0)
+            v -= v2;
+          else
+            v += v2;
+        }
+        break;
+      case OP_mod:
+        if (v1 < 0 || v2 <= 0) {
+          sp[-2] = JS_NewFloat64(ctx, fmod(v1, v2));
+          return 0;
+        } else {
+          v = (int64_t)v1 % (int64_t)v2;
+        }
+        break;
+      case OP_pow:
+        if (!is_math_mode(ctx)) {
+          sp[-2] = JS_NewFloat64(ctx, js_pow(v1, v2));
+          return 0;
+        } else {
+          goto handle_bigint;
+        }
+        break;
+      default:
+        abort();
+    }
+    sp[-2] = JS_NewInt64(ctx, v);
+  } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
+    if (ctx->rt->bigdecimal_ops.binary_arith(ctx, op, sp - 2, op1, op2))
+      goto exception;
+  } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
+    if (ctx->rt->bigfloat_ops.binary_arith(ctx, op, sp - 2, op1, op2))
+      goto exception;
+  } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
+  handle_bigint:
+    if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
+      goto exception;
+  } else {
+    double dr;
+    /* float64 result */
+    if (JS_ToFloat64Free(ctx, &d1, op1)) {
+      JS_FreeValue(ctx, op2);
+      goto exception;
+    }
+    if (JS_ToFloat64Free(ctx, &d2, op2))
+      goto exception;
+  handle_float64:
+    if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2))
+      goto handle_bigint;
+    switch(op) {
+      case OP_sub:
+        dr = d1 - d2;
+        break;
+      case OP_mul:
+        dr = d1 * d2;
+        break;
+      case OP_div:
+        dr = d1 / d2;
+        break;
+      case OP_mod:
+        dr = fmod(d1, d2);
+        break;
+      case OP_math_mod:
+        d2 = fabs(d2);
+        dr = fmod(d1, d2);
+        /* XXX: loss of accuracy if dr < 0 */
+        if (dr < 0)
+          dr += d2;
+        break;
+      case OP_pow:
+        dr = js_pow(d1, d2);
+        break;
+      default:
+        abort();
+    }
+    sp[-2] = __JS_NewFloat64(ctx, dr);
+  }
+  return 0;
+exception:
+  sp[-2] = JS_UNDEFINED;
+  sp[-1] = JS_UNDEFINED;
+  return -1;
+}
+
+no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
+{
+  JSValue op1, op2, res;
+  uint32_t tag1, tag2;
+  int ret;
+
+  op1 = sp[-2];
+  op2 = sp[-1];
+
+  tag1 = JS_VALUE_GET_NORM_TAG(op1);
+  tag2 = JS_VALUE_GET_NORM_TAG(op2);
+  /* fast path for float64 */
+  if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) {
+    double d1, d2;
+    d1 = JS_VALUE_GET_FLOAT64(op1);
+    d2 = JS_VALUE_GET_FLOAT64(op2);
+    sp[-2] = __JS_NewFloat64(ctx, d1 + d2);
+    return 0;
+  }
+
+  if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) {
+    /* try to call an overloaded operator */
+    if ((tag1 == JS_TAG_OBJECT &&
+         (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED &&
+          tag2 != JS_TAG_STRING)) ||
+        (tag2 == JS_TAG_OBJECT &&
+         (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED &&
+          tag1 != JS_TAG_STRING))) {
+      ret = js_call_binary_op_fallback(ctx, &res, op1, op2, OP_add,
+                                       FALSE, HINT_NONE);
+      if (ret != 0) {
+        JS_FreeValue(ctx, op1);
+        JS_FreeValue(ctx, op2);
+        if (ret < 0) {
+          goto exception;
+        } else {
+          sp[-2] = res;
+          return 0;
+        }
+      }
+    }
+
+    op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
+    if (JS_IsException(op1)) {
+      JS_FreeValue(ctx, op2);
+      goto exception;
+    }
+
+    op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
+    if (JS_IsException(op2)) {
+      JS_FreeValue(ctx, op1);
+      goto exception;
+    }
+    tag1 = JS_VALUE_GET_NORM_TAG(op1);
+    tag2 = JS_VALUE_GET_NORM_TAG(op2);
+  }
+
+  if (tag1 == JS_TAG_STRING || tag2 == JS_TAG_STRING) {
+    sp[-2] = JS_ConcatString(ctx, op1, op2);
+    if (JS_IsException(sp[-2]))
+      goto exception;
+    return 0;
+  }
+
+  op1 = JS_ToNumericFree(ctx, op1);
+  if (JS_IsException(op1)) {
+    JS_FreeValue(ctx, op2);
+    goto exception;
+  }
+  op2 = JS_ToNumericFree(ctx, op2);
+  if (JS_IsException(op2)) {
+    JS_FreeValue(ctx, op1);
+    goto exception;
+  }
+  tag1 = JS_VALUE_GET_NORM_TAG(op1);
+  tag2 = JS_VALUE_GET_NORM_TAG(op2);
+
+  if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
+    int32_t v1, v2;
+    int64_t v;
+    v1 = JS_VALUE_GET_INT(op1);
+    v2 = JS_VALUE_GET_INT(op2);
+    v = (int64_t)v1 + (int64_t)v2;
+    sp[-2] = JS_NewInt64(ctx, v);
+  } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
+    if (ctx->rt->bigdecimal_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
+      goto exception;
+  } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
+    if (ctx->rt->bigfloat_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
+      goto exception;
+  } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
+  handle_bigint:
+    if (ctx->rt->bigint_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
+      goto exception;
+  } else {
+    double d1, d2;
+    /* float64 result */
+    if (JS_ToFloat64Free(ctx, &d1, op1)) {
+      JS_FreeValue(ctx, op2);
+      goto exception;
+    }
+    if (JS_ToFloat64Free(ctx, &d2, op2))
+      goto exception;
+    if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2))
+      goto handle_bigint;
+    sp[-2] = __JS_NewFloat64(ctx, d1 + d2);
+  }
+  return 0;
+exception:
+  sp[-2] = JS_UNDEFINED;
+  sp[-1] = JS_UNDEFINED;
+  return -1;
+}
+
+no_inline __exception int js_binary_logic_slow(JSContext *ctx,
+                                                      JSValue *sp,
+                                                      OPCodeEnum op)
+{
+  JSValue op1, op2, res;
+  int ret;
+  uint32_t tag1, tag2;
+  uint32_t v1, v2, r;
+
+  op1 = sp[-2];
+  op2 = sp[-1];
+  tag1 = JS_VALUE_GET_NORM_TAG(op1);
+  tag2 = JS_VALUE_GET_NORM_TAG(op2);
+
+  /* try to call an overloaded operator */
+  if ((tag1 == JS_TAG_OBJECT &&
+       (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
+      (tag2 == JS_TAG_OBJECT &&
+       (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
+    ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
+    if (ret != 0) {
+      JS_FreeValue(ctx, op1);
+      JS_FreeValue(ctx, op2);
+      if (ret < 0) {
+        goto exception;
+      } else {
+        sp[-2] = res;
+        return 0;
+      }
+    }
+  }
+
+  op1 = JS_ToNumericFree(ctx, op1);
+  if (JS_IsException(op1)) {
+    JS_FreeValue(ctx, op2);
+    goto exception;
+  }
+  op2 = JS_ToNumericFree(ctx, op2);
+  if (JS_IsException(op2)) {
+    JS_FreeValue(ctx, op1);
+    goto exception;
+  }
+
+  if (is_math_mode(ctx))
+    goto bigint_op;
+
+  tag1 = JS_VALUE_GET_TAG(op1);
+  tag2 = JS_VALUE_GET_TAG(op2);
+  if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
+    if (tag1 != tag2) {
+      JS_FreeValue(ctx, op1);
+      JS_FreeValue(ctx, op2);
+      JS_ThrowTypeError(ctx, "both operands must be bigint");
+      goto exception;
+    } else {
+    bigint_op:
+      if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
+        goto exception;
+    }
+  } else {
+    if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {
+      JS_FreeValue(ctx, op2);
+      goto exception;
+    }
+    if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2)))
+      goto exception;
+    switch(op) {
+      case OP_shl:
+        r = v1 << (v2 & 0x1f);
+        break;
+      case OP_sar:
+        r = (int)v1 >> (v2 & 0x1f);
+        break;
+      case OP_and:
+        r = v1 & v2;
+        break;
+      case OP_or:
+        r = v1 | v2;
+        break;
+      case OP_xor:
+        r = v1 ^ v2;
+        break;
+      default:
+        abort();
+    }
+    sp[-2] = JS_NewInt32(ctx, r);
+  }
+  return 0;
+exception:
+  sp[-2] = JS_UNDEFINED;
+  sp[-1] = JS_UNDEFINED;
+  return -1;
+}
+
+/* Note: also used for bigint */
+int js_compare_bigfloat(JSContext *ctx, OPCodeEnum op,
+                               JSValue op1, JSValue op2)
+{
+  bf_t a_s, b_s, *a, *b;
+  int res;
+
+  a = JS_ToBigFloat(ctx, &a_s, op1);
+  if (!a) {
+    JS_FreeValue(ctx, op2);
+    return -1;
+  }
+  b = JS_ToBigFloat(ctx, &b_s, op2);
+  if (!b) {
+    if (a == &a_s)
+      bf_delete(a);
+    JS_FreeValue(ctx, op1);
+    return -1;
+  }
+  switch(op) {
+    case OP_lt:
+      res = bf_cmp_lt(a, b); /* if NaN return false */
+      break;
+    case OP_lte:
+      res = bf_cmp_le(a, b); /* if NaN return false */
+      break;
+    case OP_gt:
+      res = bf_cmp_lt(b, a); /* if NaN return false */
+      break;
+    case OP_gte:
+      res = bf_cmp_le(b, a); /* if NaN return false */
+      break;
+    case OP_eq:
+      res = bf_cmp_eq(a, b); /* if NaN return false */
+      break;
+    default:
+      abort();
+  }
+  if (a == &a_s)
+    bf_delete(a);
+  if (b == &b_s)
+    bf_delete(b);
+  JS_FreeValue(ctx, op1);
+  JS_FreeValue(ctx, op2);
+  return res;
+}
+
+int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op,
+                                 JSValue op1, JSValue op2)
+{
+  bfdec_t *a, *b;
+  int res;
+
+  /* Note: binary floats are converted to bigdecimal with
+     toString(). It is not mathematically correct but is consistent
+     with the BigDecimal() constructor behavior */
+  op1 = JS_ToBigDecimalFree(ctx, op1, TRUE);
+  if (JS_IsException(op1)) {
+    JS_FreeValue(ctx, op2);
+    return -1;
+  }
+  op2 = JS_ToBigDecimalFree(ctx, op2, TRUE);
+  if (JS_IsException(op2)) {
+    JS_FreeValue(ctx, op1);
+    return -1;
+  }
+  a = JS_ToBigDecimal(ctx, op1);
+  b = JS_ToBigDecimal(ctx, op2);
+
+  switch(op) {
+    case OP_lt:
+      res = bfdec_cmp_lt(a, b); /* if NaN return false */
+      break;
+    case OP_lte:
+      res = bfdec_cmp_le(a, b); /* if NaN return false */
+      break;
+    case OP_gt:
+      res = bfdec_cmp_lt(b, a); /* if NaN return false */
+      break;
+    case OP_gte:
+      res = bfdec_cmp_le(b, a); /* if NaN return false */
+      break;
+    case OP_eq:
+      res = bfdec_cmp_eq(a, b); /* if NaN return false */
+      break;
+    default:
+      abort();
+  }
+  JS_FreeValue(ctx, op1);
+  JS_FreeValue(ctx, op2);
+  return res;
+}
+
+no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
+                                        OPCodeEnum op)
+{
+  JSValue op1, op2, ret;
+  int res;
+  uint32_t tag1, tag2;
+
+  op1 = sp[-2];
+  op2 = sp[-1];
+  tag1 = JS_VALUE_GET_NORM_TAG(op1);
+  tag2 = JS_VALUE_GET_NORM_TAG(op2);
+  /* try to call an overloaded operator */
+  if ((tag1 == JS_TAG_OBJECT &&
+       (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
+      (tag2 == JS_TAG_OBJECT &&
+       (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
+    res = js_call_binary_op_fallback(ctx, &ret, op1, op2, op,
+                                     FALSE, HINT_NUMBER);
+    if (res != 0) {
+      JS_FreeValue(ctx, op1);
+      JS_FreeValue(ctx, op2);
+      if (res < 0) {
+        goto exception;
+      } else {
+        sp[-2] = ret;
+        return 0;
+      }
+    }
+  }
+  op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER);
+  if (JS_IsException(op1)) {
+    JS_FreeValue(ctx, op2);
+    goto exception;
+  }
+  op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER);
+  if (JS_IsException(op2)) {
+    JS_FreeValue(ctx, op1);
+    goto exception;
+  }
+  tag1 = JS_VALUE_GET_NORM_TAG(op1);
+  tag2 = JS_VALUE_GET_NORM_TAG(op2);
+
+  if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) {
+    JSString *p1, *p2;
+    p1 = JS_VALUE_GET_STRING(op1);
+    p2 = JS_VALUE_GET_STRING(op2);
+    res = js_string_compare(ctx, p1, p2);
+    switch(op) {
+      case OP_lt:
+        res = (res < 0);
+        break;
+      case OP_lte:
+        res = (res <= 0);
+        break;
+      case OP_gt:
+        res = (res > 0);
+        break;
+      default:
+      case OP_gte:
+        res = (res >= 0);
+        break;
+    }
+    JS_FreeValue(ctx, op1);
+    JS_FreeValue(ctx, op2);
+  } else if ((tag1 <= JS_TAG_NULL || tag1 == JS_TAG_FLOAT64) &&
+             (tag2 <= JS_TAG_NULL || tag2 == JS_TAG_FLOAT64)) {
+    /* fast path for float64/int */
+    goto float64_compare;
+  } else {
+    if (((tag1 == JS_TAG_BIG_INT && tag2 == JS_TAG_STRING) ||
+         (tag2 == JS_TAG_BIG_INT && tag1 == JS_TAG_STRING)) &&
+        !is_math_mode(ctx)) {
+      if (tag1 == JS_TAG_STRING) {
+        op1 = JS_StringToBigInt(ctx, op1);
+        if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
+          goto invalid_bigint_string;
+      }
+      if (tag2 == JS_TAG_STRING) {
+        op2 = JS_StringToBigInt(ctx, op2);
+        if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT) {
+        invalid_bigint_string:
+          JS_FreeValue(ctx, op1);
+          JS_FreeValue(ctx, op2);
+          res = FALSE;
+          goto done;
+        }
+      }
+    } else {
+      op1 = JS_ToNumericFree(ctx, op1);
+      if (JS_IsException(op1)) {
+        JS_FreeValue(ctx, op2);
+        goto exception;
+      }
+      op2 = JS_ToNumericFree(ctx, op2);
+      if (JS_IsException(op2)) {
+        JS_FreeValue(ctx, op1);
+        goto exception;
+      }
+    }
+
+    tag1 = JS_VALUE_GET_NORM_TAG(op1);
+    tag2 = JS_VALUE_GET_NORM_TAG(op2);
+
+    if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
+      res = ctx->rt->bigdecimal_ops.compare(ctx, op, op1, op2);
+      if (res < 0)
+        goto exception;
+    } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
+      res = ctx->rt->bigfloat_ops.compare(ctx, op, op1, op2);
+      if (res < 0)
+        goto exception;
+    } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
+      res = ctx->rt->bigint_ops.compare(ctx, op, op1, op2);
+      if (res < 0)
+        goto exception;
+    } else {
+      double d1, d2;
+
+    float64_compare:
+      /* can use floating point comparison */
+      if (tag1 == JS_TAG_FLOAT64) {
+        d1 = JS_VALUE_GET_FLOAT64(op1);
+      } else {
+        d1 = JS_VALUE_GET_INT(op1);
+      }
+      if (tag2 == JS_TAG_FLOAT64) {
+        d2 = JS_VALUE_GET_FLOAT64(op2);
+      } else {
+        d2 = JS_VALUE_GET_INT(op2);
+      }
+      switch(op) {
+        case OP_lt:
+          res = (d1 < d2); /* if NaN return false */
+          break;
+        case OP_lte:
+          res = (d1 <= d2); /* if NaN return false */
+          break;
+        case OP_gt:
+          res = (d1 > d2); /* if NaN return false */
+          break;
+        default:
+        case OP_gte:
+          res = (d1 >= d2); /* if NaN return false */
+          break;
+      }
+    }
+  }
+done:
+  sp[-2] = JS_NewBool(ctx, res);
+  return 0;
+exception:
+  sp[-2] = JS_UNDEFINED;
+  sp[-1] = JS_UNDEFINED;
+  return -1;
+}
+
+BOOL tag_is_number(uint32_t tag)
+{
+  return (tag == JS_TAG_INT || tag == JS_TAG_BIG_INT ||
+          tag == JS_TAG_FLOAT64 || tag == JS_TAG_BIG_FLOAT ||
+          tag == JS_TAG_BIG_DECIMAL);
+}
+
+no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
+                                            BOOL is_neq)
+{
+  JSValue op1, op2, ret;
+  int res;
+  uint32_t tag1, tag2;
+
+  op1 = sp[-2];
+  op2 = sp[-1];
+redo:
+  tag1 = JS_VALUE_GET_NORM_TAG(op1);
+  tag2 = JS_VALUE_GET_NORM_TAG(op2);
+  if (tag_is_number(tag1) && tag_is_number(tag2)) {
+    if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
+      res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);
+    } else if ((tag1 == JS_TAG_FLOAT64 &&
+                (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64)) ||
+               (tag2 == JS_TAG_FLOAT64 &&
+                (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64))) {
+      double d1, d2;
+      if (tag1 == JS_TAG_FLOAT64) {
+        d1 = JS_VALUE_GET_FLOAT64(op1);
+      } else {
+        d1 = JS_VALUE_GET_INT(op1);
+      }
+      if (tag2 == JS_TAG_FLOAT64) {
+        d2 = JS_VALUE_GET_FLOAT64(op2);
+      } else {
+        d2 = JS_VALUE_GET_INT(op2);
+      }
+      res = (d1 == d2);
+    } else if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) {
+      res = ctx->rt->bigdecimal_ops.compare(ctx, OP_eq, op1, op2);
+      if (res < 0)
+        goto exception;
+    } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
+      res = ctx->rt->bigfloat_ops.compare(ctx, OP_eq, op1, op2);
+      if (res < 0)
+        goto exception;
+    } else {
+      res = ctx->rt->bigint_ops.compare(ctx, OP_eq, op1, op2);
+      if (res < 0)
+        goto exception;
+    }
+  } else if (tag1 == tag2) {
+    if (tag1 == JS_TAG_OBJECT) {
+      /* try the fallback operator */
+      res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
+                                       is_neq ? OP_neq : OP_eq,
+                                       FALSE, HINT_NONE);
+      if (res != 0) {
+        JS_FreeValue(ctx, op1);
+        JS_FreeValue(ctx, op2);
+        if (res < 0) {
+          goto exception;
+        } else {
+          sp[-2] = ret;
+          return 0;
+        }
+      }
+    }
+    res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
+  } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) ||
+             (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) {
+    res = TRUE;
+  } else if ((tag1 == JS_TAG_STRING && tag_is_number(tag2)) ||
+             (tag2 == JS_TAG_STRING && tag_is_number(tag1))) {
+
+    if ((tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) &&
+        !is_math_mode(ctx)) {
+      if (tag1 == JS_TAG_STRING) {
+        op1 = JS_StringToBigInt(ctx, op1);
+        if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
+          goto invalid_bigint_string;
+      }
+      if (tag2 == JS_TAG_STRING) {
+        op2 = JS_StringToBigInt(ctx, op2);
+        if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT) {
+        invalid_bigint_string:
+          JS_FreeValue(ctx, op1);
+          JS_FreeValue(ctx, op2);
+          res = FALSE;
+          goto done;
+        }
+      }
+    } else {
+      op1 = JS_ToNumericFree(ctx, op1);
+      if (JS_IsException(op1)) {
+        JS_FreeValue(ctx, op2);
+        goto exception;
+      }
+      op2 = JS_ToNumericFree(ctx, op2);
+      if (JS_IsException(op2)) {
+        JS_FreeValue(ctx, op1);
+        goto exception;
+      }
+    }
+    res = js_strict_eq(ctx, op1, op2);
+  } else if (tag1 == JS_TAG_BOOL) {
+    op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1));
+    goto redo;
+  } else if (tag2 == JS_TAG_BOOL) {
+    op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2));
+    goto redo;
+  } else if ((tag1 == JS_TAG_OBJECT &&
+              (tag_is_number(tag2) || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) ||
+             (tag2 == JS_TAG_OBJECT &&
+              (tag_is_number(tag1) || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL))) {
+
+    /* try the fallback operator */
+    res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
+                                     is_neq ? OP_neq : OP_eq,
+                                     FALSE, HINT_NONE);
+    if (res != 0) {
+      JS_FreeValue(ctx, op1);
+      JS_FreeValue(ctx, op2);
+      if (res < 0) {
+        goto exception;
+      } else {
+        sp[-2] = ret;
+        return 0;
+      }
+    }
+
+    op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
+    if (JS_IsException(op1)) {
+      JS_FreeValue(ctx, op2);
+      goto exception;
+    }
+    op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
+    if (JS_IsException(op2)) {
+      JS_FreeValue(ctx, op1);
+      goto exception;
+    }
+    goto redo;
+  } else {
+    /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */
+    if ((JS_IsHTMLDDA(ctx, op1) &&
+         (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) ||
+        (JS_IsHTMLDDA(ctx, op2) &&
+         (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) {
+      res = TRUE;
+    } else {
+      res = FALSE;
+    }
+    JS_FreeValue(ctx, op1);
+    JS_FreeValue(ctx, op2);
+  }
+done:
+  sp[-2] = JS_NewBool(ctx, res ^ is_neq);
+  return 0;
+exception:
+  sp[-2] = JS_UNDEFINED;
+  sp[-1] = JS_UNDEFINED;
+  return -1;
+}
+
+no_inline int js_shr_slow(JSContext *ctx, JSValue *sp)
+{
+  JSValue op1, op2;
+  uint32_t v1, v2, r;
+
+  op1 = sp[-2];
+  op2 = sp[-1];
+  op1 = JS_ToNumericFree(ctx, op1);
+  if (JS_IsException(op1)) {
+    JS_FreeValue(ctx, op2);
+    goto exception;
+  }
+  op2 = JS_ToNumericFree(ctx, op2);
+  if (JS_IsException(op2)) {
+    JS_FreeValue(ctx, op1);
+    goto exception;
+  }
+  /* XXX: could forbid >>> in bignum mode */
+  if (!is_math_mode(ctx) &&
+      (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT ||
+       JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_INT)) {
+    JS_ThrowTypeError(ctx, "bigint operands are forbidden for >>>");
+    JS_FreeValue(ctx, op1);
+    JS_FreeValue(ctx, op2);
+    goto exception;
+  }
+  /* cannot give an exception */
+  JS_ToUint32Free(ctx, &v1, op1);
+  JS_ToUint32Free(ctx, &v2, op2);
+  r = v1 >> (v2 & 0x1f);
+  sp[-2] = JS_NewUint32(ctx, r);
+  return 0;
+exception:
+  sp[-2] = JS_UNDEFINED;
+  sp[-1] = JS_UNDEFINED;
+  return -1;
+}
+
+JSValue js_mul_pow10_to_float64(JSContext *ctx, const bf_t *a,
+                                       int64_t exponent)
+{
+  bf_t r_s, *r = &r_s;
+  double d;
+  int ret;
+
+  /* always convert to Float64 */
+  bf_init(ctx->bf_ctx, r);
+  ret = bf_mul_pow_radix(r, a, 10, exponent,
+                         53, bf_set_exp_bits(11) | BF_RNDN |
+                                 BF_FLAG_SUBNORMAL);
+  bf_get_float64(r, &d, BF_RNDN);
+  bf_delete(r);
+  if (ret & BF_ST_MEM_ERROR)
+    return JS_ThrowOutOfMemory(ctx);
+  else
+    return __JS_NewFloat64(ctx, d);
+}
+
+no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp)
+{
+  bf_t a_s, *a, *r;
+  JSValue op1, op2, res;
+  int64_t e;
+  int ret;
+
+  res = JS_NewBigFloat(ctx);
+  if (JS_IsException(res))
+    return -1;
+  r = JS_GetBigFloat(res);
+  op1 = sp[-2];
+  op2 = sp[-1];
+  a = JS_ToBigFloat(ctx, &a_s, op1);
+  if (!a)
+    return -1;
+  if (JS_IsBigInt(ctx, op2)) {
+    ret = JS_ToBigInt64(ctx, &e, op2);
+  } else {
+    ret = JS_ToInt64(ctx, &e, op2);
+  }
+  if (ret) {
+    if (a == &a_s)
+      bf_delete(a);
+    JS_FreeValue(ctx, res);
+    return -1;
+  }
+
+  bf_mul_pow_radix(r, a, 10, e, ctx->fp_env.prec, ctx->fp_env.flags);
+  if (a == &a_s)
+    bf_delete(a);
+  JS_FreeValue(ctx, op1);
+  JS_FreeValue(ctx, op2);
+  sp[-2] = res;
+  return 0;
+}
+
+
+#else /* !CONFIG_BIGNUM */
+
+JSValue JS_ThrowUnsupportedBigint(JSContext *ctx)
+{
+  return JS_ThrowTypeError(ctx, "bigint is not supported");
+}
+
+JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)
+{
+  return JS_ThrowUnsupportedBigint(ctx);
+}
+
+JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
+{
+  return JS_ThrowUnsupportedBigint(ctx);
+}
+
+int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
+{
+  JS_ThrowUnsupportedBigint(ctx);
+  *pres = 0;
+  return -1;
+}
+
+no_inline __exception int js_unary_arith_slow(JSContext *ctx,
+                                                     JSValue *sp,
+                                                     OPCodeEnum op)
+{
+  JSValue op1;
+  double d;
+
+  op1 = sp[-1];
+  if (unlikely(JS_ToFloat64Free(ctx, &d, op1))) {
+    sp[-1] = JS_UNDEFINED;
+    return -1;
+  }
+  switch(op) {
+    case OP_inc:
+      d++;
+      break;
+    case OP_dec:
+      d--;
+      break;
+    case OP_plus:
+      break;
+    case OP_neg:
+      d = -d;
+      break;
+    default:
+      abort();
+  }
+  sp[-1] = JS_NewFloat64(ctx, d);
+  return 0;
+}
+
+/* specific case necessary for correct return value semantics */
+__exception int js_post_inc_slow(JSContext *ctx,
+                                        JSValue *sp, OPCodeEnum op)
+{
+  JSValue op1;
+  double d, r;
+
+  op1 = sp[-1];
+  if (unlikely(JS_ToFloat64Free(ctx, &d, op1))) {
+    sp[-1] = JS_UNDEFINED;
+    return -1;
+  }
+  r = d + 2 * (op - OP_post_dec) - 1;
+  sp[0] = JS_NewFloat64(ctx, r);
+  sp[-1] = JS_NewFloat64(ctx, d);
+  return 0;
+}
+
+no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
+                                                      OPCodeEnum op)
+{
+  JSValue op1, op2;
+  double d1, d2, r;
+
+  op1 = sp[-2];
+  op2 = sp[-1];
+  if (unlikely(JS_ToFloat64Free(ctx, &d1, op1))) {
+    JS_FreeValue(ctx, op2);
+    goto exception;
+  }
+  if (unlikely(JS_ToFloat64Free(ctx, &d2, op2))) {
+    goto exception;
+  }
+  switch(op) {
+    case OP_sub:
+      r = d1 - d2;
+      break;
+    case OP_mul:
+      r = d1 * d2;
+      break;
+    case OP_div:
+      r = d1 / d2;
+      break;
+    case OP_mod:
+      r = fmod(d1, d2);
+      break;
+    case OP_pow:
+      r = js_pow(d1, d2);
+      break;
+    default:
+      abort();
+  }
+  sp[-2] = JS_NewFloat64(ctx, r);
+  return 0;
+exception:
+  sp[-2] = JS_UNDEFINED;
+  sp[-1] = JS_UNDEFINED;
+  return -1;
+}
+
+no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
+{
+  JSValue op1, op2;
+  uint32_t tag1, tag2;
+
+  op1 = sp[-2];
+  op2 = sp[-1];
+  tag1 = JS_VALUE_GET_TAG(op1);
+  tag2 = JS_VALUE_GET_TAG(op2);
+  if ((tag1 == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag1)) &&
+      (tag2 == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag2))) {
+    goto add_numbers;
+  } else {
+    op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
+    if (JS_IsException(op1)) {
+      JS_FreeValue(ctx, op2);
+      goto exception;
+    }
+    op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
+    if (JS_IsException(op2)) {
+      JS_FreeValue(ctx, op1);
+      goto exception;
+    }
+    tag1 = JS_VALUE_GET_TAG(op1);
+    tag2 = JS_VALUE_GET_TAG(op2);
+    if (tag1 == JS_TAG_STRING || tag2 == JS_TAG_STRING) {
+      sp[-2] = JS_ConcatString(ctx, op1, op2);
+      if (JS_IsException(sp[-2]))
+        goto exception;
+    } else {
+      double d1, d2;
+    add_numbers:
+      if (JS_ToFloat64Free(ctx, &d1, op1)) {
+        JS_FreeValue(ctx, op2);
+        goto exception;
+      }
+      if (JS_ToFloat64Free(ctx, &d2, op2))
+        goto exception;
+      sp[-2] = JS_NewFloat64(ctx, d1 + d2);
+    }
+  }
+  return 0;
+exception:
+  sp[-2] = JS_UNDEFINED;
+  sp[-1] = JS_UNDEFINED;
+  return -1;
+}
+
+no_inline __exception int js_binary_logic_slow(JSContext *ctx,
+                                                      JSValue *sp,
+                                                      OPCodeEnum op)
+{
+  JSValue op1, op2;
+  uint32_t v1, v2, r;
+
+  op1 = sp[-2];
+  op2 = sp[-1];
+  if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {
+    JS_FreeValue(ctx, op2);
+    goto exception;
+  }
+  if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2)))
+    goto exception;
+  switch(op) {
+    case OP_shl:
+      r = v1 << (v2 & 0x1f);
+      break;
+    case OP_sar:
+      r = (int)v1 >> (v2 & 0x1f);
+      break;
+    case OP_and:
+      r = v1 & v2;
+      break;
+    case OP_or:
+      r = v1 | v2;
+      break;
+    case OP_xor:
+      r = v1 ^ v2;
+      break;
+    default:
+      abort();
+  }
+  sp[-2] = JS_NewInt32(ctx, r);
+  return 0;
+exception:
+  sp[-2] = JS_UNDEFINED;
+  sp[-1] = JS_UNDEFINED;
+  return -1;
+}
+
+no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
+{
+  int32_t v1;
+
+  if (unlikely(JS_ToInt32Free(ctx, &v1, sp[-1]))) {
+    sp[-1] = JS_UNDEFINED;
+    return -1;
+  }
+  sp[-1] = JS_NewInt32(ctx, ~v1);
+  return 0;
+}
+
+no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
+                                        OPCodeEnum op)
+{
+  JSValue op1, op2;
+  int res;
+
+  op1 = sp[-2];
+  op2 = sp[-1];
+  op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER);
+  if (JS_IsException(op1)) {
+    JS_FreeValue(ctx, op2);
+    goto exception;
+  }
+  op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER);
+  if (JS_IsException(op2)) {
+    JS_FreeValue(ctx, op1);
+    goto exception;
+  }
+  if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING &&
+      JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {
+    JSString *p1, *p2;
+    p1 = JS_VALUE_GET_STRING(op1);
+    p2 = JS_VALUE_GET_STRING(op2);
+    res = js_string_compare(ctx, p1, p2);
+    JS_FreeValue(ctx, op1);
+    JS_FreeValue(ctx, op2);
+    switch(op) {
+      case OP_lt:
+        res = (res < 0);
+        break;
+      case OP_lte:
+        res = (res <= 0);
+        break;
+      case OP_gt:
+        res = (res > 0);
+        break;
+      default:
+      case OP_gte:
+        res = (res >= 0);
+        break;
+    }
+  } else {
+    double d1, d2;
+    if (JS_ToFloat64Free(ctx, &d1, op1)) {
+      JS_FreeValue(ctx, op2);
+      goto exception;
+    }
+    if (JS_ToFloat64Free(ctx, &d2, op2))
+      goto exception;
+    switch(op) {
+      case OP_lt:
+        res = (d1 < d2); /* if NaN return false */
+        break;
+      case OP_lte:
+        res = (d1 <= d2); /* if NaN return false */
+        break;
+      case OP_gt:
+        res = (d1 > d2); /* if NaN return false */
+        break;
+      default:
+      case OP_gte:
+        res = (d1 >= d2); /* if NaN return false */
+        break;
+    }
+  }
+  sp[-2] = JS_NewBool(ctx, res);
+  return 0;
+exception:
+  sp[-2] = JS_UNDEFINED;
+  sp[-1] = JS_UNDEFINED;
+  return -1;
+}
+
+no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
+                                            BOOL is_neq)
+{
+  JSValue op1, op2;
+  int tag1, tag2;
+  BOOL res;
+
+  op1 = sp[-2];
+  op2 = sp[-1];
+redo:
+  tag1 = JS_VALUE_GET_NORM_TAG(op1);
+  tag2 = JS_VALUE_GET_NORM_TAG(op2);
+  if (tag1 == tag2 ||
+      (tag1 == JS_TAG_INT && tag2 == JS_TAG_FLOAT64) ||
+      (tag2 == JS_TAG_INT && tag1 == JS_TAG_FLOAT64)) {
+    res = js_strict_eq(ctx, op1, op2);
+  } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) ||
+             (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) {
+    res = TRUE;
+  } else if ((tag1 == JS_TAG_STRING && (tag2 == JS_TAG_INT ||
+                                        tag2 == JS_TAG_FLOAT64)) ||
+             (tag2 == JS_TAG_STRING && (tag1 == JS_TAG_INT ||
+                                        tag1 == JS_TAG_FLOAT64))) {
+    double d1;
+    double d2;
+    if (JS_ToFloat64Free(ctx, &d1, op1)) {
+      JS_FreeValue(ctx, op2);
+      goto exception;
+    }
+    if (JS_ToFloat64Free(ctx, &d2, op2))
+      goto exception;
+    res = (d1 == d2);
+  } else if (tag1 == JS_TAG_BOOL) {
+    op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1));
+    goto redo;
+  } else if (tag2 == JS_TAG_BOOL) {
+    op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2));
+    goto redo;
+  } else if (tag1 == JS_TAG_OBJECT &&
+             (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64 || tag2 == JS_TAG_STRING || tag2 == JS_TAG_SYMBOL)) {
+    op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
+    if (JS_IsException(op1)) {
+      JS_FreeValue(ctx, op2);
+      goto exception;
+    }
+    goto redo;
+  } else if (tag2 == JS_TAG_OBJECT &&
+             (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64 || tag1 == JS_TAG_STRING || tag1 == JS_TAG_SYMBOL)) {
+    op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
+    if (JS_IsException(op2)) {
+      JS_FreeValue(ctx, op1);
+      goto exception;
+    }
+    goto redo;
+  } else {
+    /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */
+    if ((JS_IsHTMLDDA(ctx, op1) &&
+         (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) ||
+        (JS_IsHTMLDDA(ctx, op2) &&
+         (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) {
+      res = TRUE;
+    } else {
+      res = FALSE;
+    }
+    JS_FreeValue(ctx, op1);
+    JS_FreeValue(ctx, op2);
+  }
+  sp[-2] = JS_NewBool(ctx, res ^ is_neq);
+  return 0;
+exception:
+  sp[-2] = JS_UNDEFINED;
+  sp[-1] = JS_UNDEFINED;
+  return -1;
+}
+
+no_inline int js_shr_slow(JSContext *ctx, JSValue *sp)
+{
+  JSValue op1, op2;
+  uint32_t v1, v2, r;
+
+  op1 = sp[-2];
+  op2 = sp[-1];
+  if (unlikely(JS_ToUint32Free(ctx, &v1, op1))) {
+    JS_FreeValue(ctx, op2);
+    goto exception;
+  }
+  if (unlikely(JS_ToUint32Free(ctx, &v2, op2)))
+    goto exception;
+  r = v1 >> (v2 & 0x1f);
+  sp[-2] = JS_NewUint32(ctx, r);
+  return 0;
+exception:
+  sp[-2] = JS_UNDEFINED;
+  sp[-1] = JS_UNDEFINED;
+  return -1;
+}
+
+#endif /* !CONFIG_BIGNUM */
+#ifdef CONFIG_BIGNUM
+
+/* Operators */
+
+void js_operator_set_finalizer(JSRuntime *rt, JSValue val)
+{
+  JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET);
+  int i, j;
+  JSBinaryOperatorDefEntry *ent;
+
+  if (opset) {
+    for(i = 0; i < JS_OVOP_COUNT; i++) {
+      if (opset->self_ops[i])
+        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[i]));
+    }
+    for(j = 0; j < opset->left.count; j++) {
+      ent = &opset->left.tab[j];
+      for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
+        if (ent->ops[i])
+          JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]));
+      }
+    }
+    js_free_rt(rt, opset->left.tab);
+    for(j = 0; j < opset->right.count; j++) {
+      ent = &opset->right.tab[j];
+      for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
+        if (ent->ops[i])
+          JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]));
+      }
+    }
+    js_free_rt(rt, opset->right.tab);
+    js_free_rt(rt, opset);
+  }
+}
+
+void js_operator_set_mark(JSRuntime *rt, JSValueConst val,
+                                 JS_MarkFunc *mark_func)
+{
+  JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET);
+  int i, j;
+  JSBinaryOperatorDefEntry *ent;
+
+  if (opset) {
+    for(i = 0; i < JS_OVOP_COUNT; i++) {
+      if (opset->self_ops[i])
+        JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[i]),
+                     mark_func);
+    }
+    for(j = 0; j < opset->left.count; j++) {
+      ent = &opset->left.tab[j];
+      for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
+        if (ent->ops[i])
+          JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]),
+                       mark_func);
+      }
+    }
+    for(j = 0; j < opset->right.count; j++) {
+      ent = &opset->right.tab[j];
+      for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
+        if (ent->ops[i])
+          JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]),
+                       mark_func);
+      }
+    }
+  }
+}
+
+
+/* create an OperatorSet object */
+JSValue js_operators_create_internal(JSContext *ctx,
+                                            int argc, JSValueConst *argv,
+                                            BOOL is_primitive)
+{
+  JSValue opset_obj, prop, obj;
+  JSOperatorSetData *opset, *opset1;
+  JSBinaryOperatorDef *def;
+  JSValueConst arg;
+  int i, j;
+  JSBinaryOperatorDefEntry *new_tab;
+  JSBinaryOperatorDefEntry *ent;
+  uint32_t op_count;
+
+  if (ctx->rt->operator_count == UINT32_MAX) {
+    return JS_ThrowTypeError(ctx, "too many operators");
+  }
+  opset_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_OPERATOR_SET);
+  if (JS_IsException(opset_obj))
+    goto fail;
+  opset = js_mallocz(ctx, sizeof(*opset));
+  if (!opset)
+    goto fail;
+  JS_SetOpaque(opset_obj, opset);
+  if (argc >= 1) {
+    arg = argv[0];
+    /* self operators */
+    for(i = 0; i < JS_OVOP_COUNT; i++) {
+      prop = JS_GetPropertyStr(ctx, arg, js_overloadable_operator_names[i]);
+      if (JS_IsException(prop))
+        goto fail;
+      if (!JS_IsUndefined(prop)) {
+        if (check_function(ctx, prop)) {
+          JS_FreeValue(ctx, prop);
+          goto fail;
+        }
+        opset->self_ops[i] = JS_VALUE_GET_OBJ(prop);
+      }
+    }
+  }
+  /* left & right operators */
+  for(j = 1; j < argc; j++) {
+    arg = argv[j];
+    prop = JS_GetPropertyStr(ctx, arg, "left");
+    if (JS_IsException(prop))
+      goto fail;
+    def = &opset->right;
+    if (JS_IsUndefined(prop)) {
+      prop = JS_GetPropertyStr(ctx, arg, "right");
+      if (JS_IsException(prop))
+        goto fail;
+      if (JS_IsUndefined(prop)) {
+        JS_ThrowTypeError(ctx, "left or right property must be present");
+        goto fail;
+      }
+      def = &opset->left;
+    }
+    /* get the operator set */
+    obj = JS_GetProperty(ctx, prop, JS_ATOM_prototype);
+    JS_FreeValue(ctx, prop);
+    if (JS_IsException(obj))
+      goto fail;
+    prop = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet);
+    JS_FreeValue(ctx, obj);
+    if (JS_IsException(prop))
+      goto fail;
+    opset1 = JS_GetOpaque2(ctx, prop, JS_CLASS_OPERATOR_SET);
+    if (!opset1) {
+      JS_FreeValue(ctx, prop);
+      goto fail;
+    }
+    op_count = opset1->operator_counter;
+    JS_FreeValue(ctx, prop);
+
+    /* we assume there are few entries */
+    new_tab = js_realloc(ctx, def->tab,
+                         (def->count + 1) * sizeof(def->tab[0]));
+    if (!new_tab)
+      goto fail;
+    def->tab = new_tab;
+    def->count++;
+    ent = def->tab + def->count - 1;
+    memset(ent, 0, sizeof(def->tab[0]));
+    ent->operator_index = op_count;
+
+    for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
+      prop = JS_GetPropertyStr(ctx, arg,
+                               js_overloadable_operator_names[i]);
+      if (JS_IsException(prop))
+        goto fail;
+      if (!JS_IsUndefined(prop)) {
+        if (check_function(ctx, prop)) {
+          JS_FreeValue(ctx, prop);
+          goto fail;
+        }
+        ent->ops[i] = JS_VALUE_GET_OBJ(prop);
+      }
+    }
+  }
+  opset->is_primitive = is_primitive;
+  opset->operator_counter = ctx->rt->operator_count++;
+  return opset_obj;
+fail:
+  JS_FreeValue(ctx, opset_obj);
+  return JS_EXCEPTION;
+}
+
+JSValue js_operators_create(JSContext *ctx, JSValueConst this_val,
+                                   int argc, JSValueConst *argv)
+{
+  return js_operators_create_internal(ctx, argc, argv, FALSE);
+}
+
+JSValue js_operators_updateBigIntOperators(JSContext *ctx, JSValueConst this_val,
+                                                  int argc, JSValueConst *argv)
+{
+  JSValue opset_obj, prop;
+  JSOperatorSetData *opset;
+  const JSOverloadableOperatorEnum ops[2] = { JS_OVOP_DIV, JS_OVOP_POW };
+  JSOverloadableOperatorEnum op;
+  int i;
+
+  opset_obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_BIG_INT],
+                             JS_ATOM_Symbol_operatorSet);
+  if (JS_IsException(opset_obj))
+    goto fail;
+  opset = JS_GetOpaque2(ctx, opset_obj, JS_CLASS_OPERATOR_SET);
+  if (!opset)
+    goto fail;
+  for(i = 0; i < countof(ops); i++) {
+    op = ops[i];
+    prop = JS_GetPropertyStr(ctx, argv[0],
+                             js_overloadable_operator_names[op]);
+    if (JS_IsException(prop))
+      goto fail;
+    if (!JS_IsUndefined(prop)) {
+      if (!JS_IsNull(prop) && check_function(ctx, prop)) {
+        JS_FreeValue(ctx, prop);
+        goto fail;
+      }
+      if (opset->self_ops[op])
+        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[op]));
+      if (JS_IsNull(prop)) {
+        opset->self_ops[op] = NULL;
+      } else {
+        opset->self_ops[op] = JS_VALUE_GET_PTR(prop);
+      }
+    }
+  }
+  JS_FreeValue(ctx, opset_obj);
+  return JS_UNDEFINED;
+fail:
+  JS_FreeValue(ctx, opset_obj);
+  return JS_EXCEPTION;
+}
+
+int js_operators_set_default(JSContext *ctx, JSValueConst obj)
+{
+  JSValue opset_obj;
+
+  if (!JS_IsObject(obj)) /* in case the prototype is not defined */
+    return 0;
+  opset_obj = js_operators_create_internal(ctx, 0, NULL, TRUE);
+  if (JS_IsException(opset_obj))
+    return -1;
+  /* cannot be modified by the user */
+  JS_DefinePropertyValue(ctx, obj, JS_ATOM_Symbol_operatorSet,
+                         opset_obj, 0);
+  return 0;
+}
+
+JSValue js_dummy_operators_ctor(JSContext *ctx, JSValueConst new_target,
+                                       int argc, JSValueConst *argv)
+{
+  return js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
+}
+
+JSValue js_global_operators(JSContext *ctx, JSValueConst this_val,
+                                   int argc, JSValueConst *argv)
+{
+  JSValue func_obj, proto, opset_obj;
+
+  func_obj = JS_UNDEFINED;
+  proto = JS_NewObject(ctx);
+  if (JS_IsException(proto))
+    return JS_EXCEPTION;
+  opset_obj = js_operators_create_internal(ctx, argc, argv, FALSE);
+  if (JS_IsException(opset_obj))
+    goto fail;
+  JS_DefinePropertyValue(ctx, proto, JS_ATOM_Symbol_operatorSet,
+                         opset_obj, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+  func_obj = JS_NewCFunction2(ctx, js_dummy_operators_ctor, "Operators",
+                              0, JS_CFUNC_constructor, 0);
+  if (JS_IsException(func_obj))
+    goto fail;
+  JS_SetConstructor2(ctx, func_obj, proto,
+                     0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+  JS_FreeValue(ctx, proto);
+  return func_obj;
+fail:
+  JS_FreeValue(ctx, proto);
+  JS_FreeValue(ctx, func_obj);
+  return JS_EXCEPTION;
+}
+
+const JSCFunctionListEntry js_operators_funcs[] = {
+    JS_CFUNC_DEF("create", 1, js_operators_create ),
+    JS_CFUNC_DEF("updateBigIntOperators", 2, js_operators_updateBigIntOperators ),
+};
+
+/* must be called after all overloadable base types are initialized */
+void JS_AddIntrinsicOperators(JSContext *ctx)
+{
+  JSValue obj;
+
+  ctx->allow_operator_overloading = TRUE;
+  obj = JS_NewCFunction(ctx, js_global_operators, "Operators", 1);
+  JS_SetPropertyFunctionList(ctx, obj,
+                             js_operators_funcs,
+                             countof(js_operators_funcs));
+  JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_Operators,
+                         obj,
+                         JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+  /* add default operatorSets */
+  js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BOOLEAN]);
+  js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_NUMBER]);
+  js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_STRING]);
+  js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_INT]);
+  js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT]);
+  js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL]);
+}
+
+/* BigInt */
+
+JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)
+{
+  uint32_t tag;
+
+redo:
+  tag = JS_VALUE_GET_NORM_TAG(val);
+  switch(tag) {
+    case JS_TAG_INT:
+    case JS_TAG_BOOL:
+      val = JS_NewBigInt64(ctx, JS_VALUE_GET_INT(val));
+      break;
+    case JS_TAG_BIG_INT:
+      break;
+    case JS_TAG_FLOAT64:
+    case JS_TAG_BIG_FLOAT:
+    {
+      bf_t *a, a_s;
+
+      a = JS_ToBigFloat(ctx, &a_s, val);
+      if (!bf_is_finite(a)) {
+        JS_FreeValue(ctx, val);
+        val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to bigint");
+      } else {
+        JSValue val1 = JS_NewBigInt(ctx);
+        bf_t *r;
+        int ret;
+        if (JS_IsException(val1)) {
+          JS_FreeValue(ctx, val);
+          return JS_EXCEPTION;
+        }
+        r = JS_GetBigInt(val1);
+        ret = bf_set(r, a);
+        ret |= bf_rint(r, BF_RNDZ);
+        JS_FreeValue(ctx, val);
+        if (ret & BF_ST_MEM_ERROR) {
+          JS_FreeValue(ctx, val1);
+          val = JS_ThrowOutOfMemory(ctx);
+        } else if (ret & BF_ST_INEXACT) {
+          JS_FreeValue(ctx, val1);
+          val = JS_ThrowRangeError(ctx, "cannot convert to bigint: not an integer");
+        } else {
+          val = JS_CompactBigInt(ctx, val1);
+        }
+      }
+      if (a == &a_s)
+        bf_delete(a);
+    }
+    break;
+    case JS_TAG_BIG_DECIMAL:
+      val = JS_ToStringFree(ctx, val);
+      if (JS_IsException(val))
+        break;
+      goto redo;
+    case JS_TAG_STRING:
+      val = JS_StringToBigIntErr(ctx, val);
+      break;
+    case JS_TAG_OBJECT:
+      val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
+      if (JS_IsException(val))
+        break;
+      goto redo;
+    case JS_TAG_NULL:
+    case JS_TAG_UNDEFINED:
+    default:
+      JS_FreeValue(ctx, val);
+      return JS_ThrowTypeError(ctx, "cannot convert to bigint");
+  }
+  return val;
+}
+
+JSValue js_bigint_constructor(JSContext *ctx,
+                                     JSValueConst new_target,
+                                     int argc, JSValueConst *argv)
+{
+  if (!JS_IsUndefined(new_target))
+    return JS_ThrowTypeError(ctx, "not a constructor");
+  return JS_ToBigIntCtorFree(ctx, JS_DupValue(ctx, argv[0]));
+}
+
+JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val)
+{
+  if (JS_IsBigInt(ctx, this_val))
+    return JS_DupValue(ctx, this_val);
+
+  if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
+    JSObject *p = JS_VALUE_GET_OBJ(this_val);
+    if (p->class_id == JS_CLASS_BIG_INT) {
+      if (JS_IsBigInt(ctx, p->u.object_data))
+        return JS_DupValue(ctx, p->u.object_data);
+    }
+  }
+  return JS_ThrowTypeError(ctx, "not a bigint");
+}
+
+JSValue js_bigint_toString(JSContext *ctx, JSValueConst this_val,
+                                  int argc, JSValueConst *argv)
+{
+  JSValue val;
+  int base;
+  JSValue ret;
+
+  val = js_thisBigIntValue(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  if (argc == 0 || JS_IsUndefined(argv[0])) {
+    base = 10;
+  } else {
+    base = js_get_radix(ctx, argv[0]);
+    if (base < 0)
+      goto fail;
+  }
+  ret = js_bigint_to_string1(ctx, val, base);
+  JS_FreeValue(ctx, val);
+  return ret;
+fail:
+  JS_FreeValue(ctx, val);
+  return JS_EXCEPTION;
+}
+
+JSValue js_bigint_valueOf(JSContext *ctx, JSValueConst this_val,
+                                 int argc, JSValueConst *argv)
+{
+  return js_thisBigIntValue(ctx, this_val);
+}
+
+JSValue js_bigint_div(JSContext *ctx,
+                             JSValueConst this_val,
+                             int argc, JSValueConst *argv, int magic)
+{
+  bf_t a_s, b_s, *a, *b, *r, *q;
+  int status;
+  JSValue q_val, r_val;
+
+  q_val = JS_NewBigInt(ctx);
+  if (JS_IsException(q_val))
+    return JS_EXCEPTION;
+  r_val = JS_NewBigInt(ctx);
+  if (JS_IsException(r_val))
+    goto fail;
+  b = NULL;
+  a = JS_ToBigInt(ctx, &a_s, argv[0]);
+  if (!a)
+    goto fail;
+  b = JS_ToBigInt(ctx, &b_s, argv[1]);
+  if (!b) {
+    JS_FreeBigInt(ctx, a, &a_s);
+    goto fail;
+  }
+  q = JS_GetBigInt(q_val);
+  r = JS_GetBigInt(r_val);
+  status = bf_divrem(q, r, a, b, BF_PREC_INF, BF_RNDZ, magic & 0xf);
+  JS_FreeBigInt(ctx, a, &a_s);
+  JS_FreeBigInt(ctx, b, &b_s);
+  if (unlikely(status)) {
+    throw_bf_exception(ctx, status);
+    goto fail;
+  }
+  q_val = JS_CompactBigInt(ctx, q_val);
+  if (magic & 0x10) {
+    JSValue ret;
+    ret = JS_NewArray(ctx);
+    if (JS_IsException(ret))
+      goto fail;
+    JS_SetPropertyUint32(ctx, ret, 0, q_val);
+    JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, r_val));
+    return ret;
+  } else {
+    JS_FreeValue(ctx, r_val);
+    return q_val;
+  }
+fail:
+  JS_FreeValue(ctx, q_val);
+  JS_FreeValue(ctx, r_val);
+  return JS_EXCEPTION;
+}
+
+JSValue js_bigint_sqrt(JSContext *ctx,
+                              JSValueConst this_val,
+                              int argc, JSValueConst *argv, int magic)
+{
+  bf_t a_s, *a, *r, *rem;
+  int status;
+  JSValue r_val, rem_val;
+
+  r_val = JS_NewBigInt(ctx);
+  if (JS_IsException(r_val))
+    return JS_EXCEPTION;
+  rem_val = JS_NewBigInt(ctx);
+  if (JS_IsException(rem_val))
+    return JS_EXCEPTION;
+  r = JS_GetBigInt(r_val);
+  rem = JS_GetBigInt(rem_val);
+
+  a = JS_ToBigInt(ctx, &a_s, argv[0]);
+  if (!a)
+    goto fail;
+  status = bf_sqrtrem(r, rem, a);
+  JS_FreeBigInt(ctx, a, &a_s);
+  if (unlikely(status & ~BF_ST_INEXACT)) {
+    throw_bf_exception(ctx, status);
+    goto fail;
+  }
+  r_val = JS_CompactBigInt(ctx, r_val);
+  if (magic) {
+    JSValue ret;
+    ret = JS_NewArray(ctx);
+    if (JS_IsException(ret))
+      goto fail;
+    JS_SetPropertyUint32(ctx, ret, 0, r_val);
+    JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, rem_val));
+    return ret;
+  } else {
+    JS_FreeValue(ctx, rem_val);
+    return r_val;
+  }
+fail:
+  JS_FreeValue(ctx, r_val);
+  JS_FreeValue(ctx, rem_val);
+  return JS_EXCEPTION;
+}
+
+JSValue js_bigint_op1(JSContext *ctx,
+                             JSValueConst this_val,
+                             int argc, JSValueConst *argv,
+                             int magic)
+{
+  bf_t a_s, *a;
+  int64_t res;
+
+  a = JS_ToBigInt(ctx, &a_s, argv[0]);
+  if (!a)
+    return JS_EXCEPTION;
+  switch(magic) {
+    case 0: /* floorLog2 */
+      if (a->sign || a->expn <= 0) {
+        res = -1;
+      } else {
+        res = a->expn - 1;
+      }
+      break;
+    case 1: /* ctz */
+      if (bf_is_zero(a)) {
+        res = -1;
+      } else {
+        res = bf_get_exp_min(a);
+      }
+      break;
+    default:
+      abort();
+  }
+  JS_FreeBigInt(ctx, a, &a_s);
+  return JS_NewBigInt64(ctx, res);
+}
+
+JSValue js_bigint_asUintN(JSContext *ctx,
+                                 JSValueConst this_val,
+                                 int argc, JSValueConst *argv, int asIntN)
+{
+  uint64_t bits;
+  bf_t a_s, *a = &a_s, *r, mask_s, *mask = &mask_s;
+  JSValue res;
+
+  if (JS_ToIndex(ctx, &bits, argv[0]))
+    return JS_EXCEPTION;
+  res = JS_NewBigInt(ctx);
+  if (JS_IsException(res))
+    return JS_EXCEPTION;
+  r = JS_GetBigInt(res);
+  a = JS_ToBigInt(ctx, &a_s, argv[1]);
+  if (!a) {
+    JS_FreeValue(ctx, res);
+    return JS_EXCEPTION;
+  }
+  /* XXX: optimize */
+  r = JS_GetBigInt(res);
+  bf_init(ctx->bf_ctx, mask);
+  bf_set_ui(mask, 1);
+  bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ);
+  bf_add_si(mask, mask, -1, BF_PREC_INF, BF_RNDZ);
+  bf_logic_and(r, a, mask);
+  if (asIntN && bits != 0) {
+    bf_set_ui(mask, 1);
+    bf_mul_2exp(mask, bits - 1, BF_PREC_INF, BF_RNDZ);
+    if (bf_cmpu(r, mask) >= 0) {
+      bf_set_ui(mask, 1);
+      bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ);
+      bf_sub(r, r, mask, BF_PREC_INF, BF_RNDZ);
+    }
+  }
+  bf_delete(mask);
+  JS_FreeBigInt(ctx, a, &a_s);
+  return JS_CompactBigInt(ctx, res);
+}
+
+const JSCFunctionListEntry js_bigint_funcs[] = {
+    JS_CFUNC_MAGIC_DEF("asUintN", 2, js_bigint_asUintN, 0 ),
+    JS_CFUNC_MAGIC_DEF("asIntN", 2, js_bigint_asUintN, 1 ),
+    /* QuickJS extensions */
+    JS_CFUNC_MAGIC_DEF("tdiv", 2, js_bigint_div, BF_RNDZ ),
+    JS_CFUNC_MAGIC_DEF("fdiv", 2, js_bigint_div, BF_RNDD ),
+    JS_CFUNC_MAGIC_DEF("cdiv", 2, js_bigint_div, BF_RNDU ),
+    JS_CFUNC_MAGIC_DEF("ediv", 2, js_bigint_div, BF_DIVREM_EUCLIDIAN ),
+    JS_CFUNC_MAGIC_DEF("tdivrem", 2, js_bigint_div, BF_RNDZ | 0x10 ),
+    JS_CFUNC_MAGIC_DEF("fdivrem", 2, js_bigint_div, BF_RNDD | 0x10 ),
+    JS_CFUNC_MAGIC_DEF("cdivrem", 2, js_bigint_div, BF_RNDU | 0x10 ),
+    JS_CFUNC_MAGIC_DEF("edivrem", 2, js_bigint_div, BF_DIVREM_EUCLIDIAN | 0x10 ),
+    JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigint_sqrt, 0 ),
+    JS_CFUNC_MAGIC_DEF("sqrtrem", 1, js_bigint_sqrt, 1 ),
+    JS_CFUNC_MAGIC_DEF("floorLog2", 1, js_bigint_op1, 0 ),
+    JS_CFUNC_MAGIC_DEF("ctz", 1, js_bigint_op1, 1 ),
+};
+
+const JSCFunctionListEntry js_bigint_proto_funcs[] = {
+    JS_CFUNC_DEF("toString", 0, js_bigint_toString ),
+    JS_CFUNC_DEF("valueOf", 0, js_bigint_valueOf ),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "BigInt", JS_PROP_CONFIGURABLE ),
+};
+
+void JS_AddIntrinsicBigInt(JSContext *ctx)
+{
+  JSRuntime *rt = ctx->rt;
+  JSValueConst obj1;
+
+  rt->bigint_ops.to_string = js_bigint_to_string;
+  rt->bigint_ops.from_string = js_string_to_bigint;
+  rt->bigint_ops.unary_arith = js_unary_arith_bigint;
+  rt->bigint_ops.binary_arith = js_binary_arith_bigint;
+  rt->bigint_ops.compare = js_compare_bigfloat;
+
+  ctx->class_proto[JS_CLASS_BIG_INT] = JS_NewObject(ctx);
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_INT],
+                             js_bigint_proto_funcs,
+                             countof(js_bigint_proto_funcs));
+  obj1 = JS_NewGlobalCConstructor(ctx, "BigInt", js_bigint_constructor, 1,
+                                  ctx->class_proto[JS_CLASS_BIG_INT]);
+  JS_SetPropertyFunctionList(ctx, obj1, js_bigint_funcs,
+                             countof(js_bigint_funcs));
+}
+
+/* BigFloat */
+
+JSValue js_thisBigFloatValue(JSContext *ctx, JSValueConst this_val)
+{
+  if (JS_IsBigFloat(this_val))
+    return JS_DupValue(ctx, this_val);
+
+  if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
+    JSObject *p = JS_VALUE_GET_OBJ(this_val);
+    if (p->class_id == JS_CLASS_BIG_FLOAT) {
+      if (JS_IsBigFloat(p->u.object_data))
+        return JS_DupValue(ctx, p->u.object_data);
+    }
+  }
+  return JS_ThrowTypeError(ctx, "not a bigfloat");
+}
+
+JSValue js_bigfloat_toString(JSContext *ctx, JSValueConst this_val,
+                                    int argc, JSValueConst *argv)
+{
+  JSValue val;
+  int base;
+  JSValue ret;
+
+  val = js_thisBigFloatValue(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  if (argc == 0 || JS_IsUndefined(argv[0])) {
+    base = 10;
+  } else {
+    base = js_get_radix(ctx, argv[0]);
+    if (base < 0)
+      goto fail;
+  }
+  ret = js_ftoa(ctx, val, base, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN);
+  JS_FreeValue(ctx, val);
+  return ret;
+fail:
+  JS_FreeValue(ctx, val);
+  return JS_EXCEPTION;
+}
+
+JSValue js_bigfloat_valueOf(JSContext *ctx, JSValueConst this_val,
+                                   int argc, JSValueConst *argv)
+{
+  return js_thisBigFloatValue(ctx, this_val);
+}
+
+int bigfloat_get_rnd_mode(JSContext *ctx, JSValueConst val)
+{
+  int rnd_mode;
+  if (JS_ToInt32Sat(ctx, &rnd_mode, val))
+    return -1;
+  if (rnd_mode < BF_RNDN || rnd_mode > BF_RNDF) {
+    JS_ThrowRangeError(ctx, "invalid rounding mode");
+    return -1;
+  }
+  return rnd_mode;
+}
+
+JSValue js_bigfloat_toFixed(JSContext *ctx, JSValueConst this_val,
+                                   int argc, JSValueConst *argv)
+{
+  JSValue val, ret;
+  int64_t f;
+  int rnd_mode, radix;
+
+  val = js_thisBigFloatValue(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  if (JS_ToInt64Sat(ctx, &f, argv[0]))
+    goto fail;
+  if (f < 0 || f > BF_PREC_MAX) {
+    JS_ThrowRangeError(ctx, "invalid number of digits");
+    goto fail;
+  }
+  rnd_mode = BF_RNDNA;
+  radix = 10;
+  /* XXX: swap parameter order for rounding mode and radix */
+  if (argc > 1) {
+    rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
+    if (rnd_mode < 0)
+      goto fail;
+  }
+  if (argc > 2) {
+    radix = js_get_radix(ctx, argv[2]);
+    if (radix < 0)
+      goto fail;
+  }
+  ret = js_ftoa(ctx, val, radix, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
+  JS_FreeValue(ctx, val);
+  return ret;
+fail:
+  JS_FreeValue(ctx, val);
+  return JS_EXCEPTION;
+}
+
+BOOL js_bigfloat_is_finite(JSContext *ctx, JSValueConst val)
+{
+  BOOL res;
+  uint32_t tag;
+
+  tag = JS_VALUE_GET_NORM_TAG(val);
+  switch(tag) {
+    case JS_TAG_BIG_FLOAT:
+    {
+      JSBigFloat *p = JS_VALUE_GET_PTR(val);
+      res = bf_is_finite(&p->num);
+    }
+    break;
+    default:
+      res = FALSE;
+      break;
+  }
+  return res;
+}
+
+JSValue js_bigfloat_toExponential(JSContext *ctx, JSValueConst this_val,
+                                         int argc, JSValueConst *argv)
+{
+  JSValue val, ret;
+  int64_t f;
+  int rnd_mode, radix;
+
+  val = js_thisBigFloatValue(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  if (JS_ToInt64Sat(ctx, &f, argv[0]))
+    goto fail;
+  if (!js_bigfloat_is_finite(ctx, val)) {
+    ret = JS_ToString(ctx, val);
+  } else if (JS_IsUndefined(argv[0])) {
+    ret = js_ftoa(ctx, val, 10, 0,
+                  BF_RNDN | BF_FTOA_FORMAT_FREE_MIN | BF_FTOA_FORCE_EXP);
+  } else {
+    if (f < 0 || f > BF_PREC_MAX) {
+      JS_ThrowRangeError(ctx, "invalid number of digits");
+      goto fail;
+    }
+    rnd_mode = BF_RNDNA;
+    radix = 10;
+    if (argc > 1) {
+      rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
+      if (rnd_mode < 0)
+        goto fail;
+    }
+    if (argc > 2) {
+      radix = js_get_radix(ctx, argv[2]);
+      if (radix < 0)
+        goto fail;
+    }
+    ret = js_ftoa(ctx, val, radix, f + 1,
+                  rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP);
+  }
+  JS_FreeValue(ctx, val);
+  return ret;
+fail:
+  JS_FreeValue(ctx, val);
+  return JS_EXCEPTION;
+}
+
+JSValue js_bigfloat_toPrecision(JSContext *ctx, JSValueConst this_val,
+                                       int argc, JSValueConst *argv)
+{
+  JSValue val, ret;
+  int64_t p;
+  int rnd_mode, radix;
+
+  val = js_thisBigFloatValue(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  if (JS_IsUndefined(argv[0]))
+    goto to_string;
+  if (JS_ToInt64Sat(ctx, &p, argv[0]))
+    goto fail;
+  if (!js_bigfloat_is_finite(ctx, val)) {
+  to_string:
+    ret = JS_ToString(ctx, this_val);
+  } else {
+    if (p < 1 || p > BF_PREC_MAX) {
+      JS_ThrowRangeError(ctx, "invalid number of digits");
+      goto fail;
+    }
+    rnd_mode = BF_RNDNA;
+    radix = 10;
+    if (argc > 1) {
+      rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
+      if (rnd_mode < 0)
+        goto fail;
+    }
+    if (argc > 2) {
+      radix = js_get_radix(ctx, argv[2]);
+      if (radix < 0)
+        goto fail;
+    }
+    ret = js_ftoa(ctx, val, radix, p, rnd_mode | BF_FTOA_FORMAT_FIXED);
+  }
+  JS_FreeValue(ctx, val);
+  return ret;
+fail:
+  JS_FreeValue(ctx, val);
+  return JS_EXCEPTION;
+}
+
+const JSCFunctionListEntry js_bigfloat_proto_funcs[] = {
+    JS_CFUNC_DEF("toString", 0, js_bigfloat_toString ),
+    JS_CFUNC_DEF("valueOf", 0, js_bigfloat_valueOf ),
+    JS_CFUNC_DEF("toPrecision", 1, js_bigfloat_toPrecision ),
+    JS_CFUNC_DEF("toFixed", 1, js_bigfloat_toFixed ),
+    JS_CFUNC_DEF("toExponential", 1, js_bigfloat_toExponential ),
+};
+
+JSValue js_bigfloat_constructor(JSContext *ctx,
+                                       JSValueConst new_target,
+                                       int argc, JSValueConst *argv)
+{
+  JSValue val;
+  if (!JS_IsUndefined(new_target))
+    return JS_ThrowTypeError(ctx, "not a constructor");
+  if (argc == 0) {
+    bf_t *r;
+    val = JS_NewBigFloat(ctx);
+    if (JS_IsException(val))
+      return val;
+    r = JS_GetBigFloat(val);
+    bf_set_zero(r, 0);
+  } else {
+    val = JS_DupValue(ctx, argv[0]);
+  redo:
+    switch(JS_VALUE_GET_NORM_TAG(val)) {
+      case JS_TAG_BIG_FLOAT:
+        break;
+      case JS_TAG_FLOAT64:
+      {
+        bf_t *r;
+        double d = JS_VALUE_GET_FLOAT64(val);
+        val = JS_NewBigFloat(ctx);
+        if (JS_IsException(val))
+          break;
+        r = JS_GetBigFloat(val);
+        if (bf_set_float64(r, d))
+          goto fail;
+      }
+      break;
+      case JS_TAG_INT:
+      {
+        bf_t *r;
+        int32_t v = JS_VALUE_GET_INT(val);
+        val = JS_NewBigFloat(ctx);
+        if (JS_IsException(val))
+          break;
+        r = JS_GetBigFloat(val);
+        if (bf_set_si(r, v))
+          goto fail;
+      }
+      break;
+      case JS_TAG_BIG_INT:
+        /* We keep the full precision of the integer */
+        {
+          JSBigFloat *p = JS_VALUE_GET_PTR(val);
+          val = JS_MKPTR(JS_TAG_BIG_FLOAT, p);
+        }
+        break;
+      case JS_TAG_BIG_DECIMAL:
+        val = JS_ToStringFree(ctx, val);
+        if (JS_IsException(val))
+          break;
+        goto redo;
+      case JS_TAG_STRING:
+      {
+        const char *str, *p;
+        size_t len;
+        int err;
+
+        str = JS_ToCStringLen(ctx, &len, val);
+        JS_FreeValue(ctx, val);
+        if (!str)
+          return JS_EXCEPTION;
+        p = str;
+        p += skip_spaces(p);
+        if ((p - str) == len) {
+          bf_t *r;
+          val = JS_NewBigFloat(ctx);
+          if (JS_IsException(val))
+            break;
+          r = JS_GetBigFloat(val);
+          bf_set_zero(r, 0);
+          err = 0;
+        } else {
+          val = js_atof(ctx, p, &p, 0, ATOD_ACCEPT_BIN_OCT |
+                                           ATOD_TYPE_BIG_FLOAT |
+                                           ATOD_ACCEPT_PREFIX_AFTER_SIGN);
+          if (JS_IsException(val)) {
+            JS_FreeCString(ctx, str);
+            return JS_EXCEPTION;
+          }
+          p += skip_spaces(p);
+          err = ((p - str) != len);
+        }
+        JS_FreeCString(ctx, str);
+        if (err) {
+          JS_FreeValue(ctx, val);
+          return JS_ThrowSyntaxError(ctx, "invalid bigfloat literal");
+        }
+      }
+      break;
+      case JS_TAG_OBJECT:
+        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
+        if (JS_IsException(val))
+          break;
+        goto redo;
+      case JS_TAG_NULL:
+      case JS_TAG_UNDEFINED:
+      default:
+        JS_FreeValue(ctx, val);
+        return JS_ThrowTypeError(ctx, "cannot convert to bigfloat");
+    }
+  }
+  return val;
+fail:
+  JS_FreeValue(ctx, val);
+  return JS_EXCEPTION;
+}
+
+JSValue js_bigfloat_get_const(JSContext *ctx,
+                                     JSValueConst this_val, int magic)
+{
+  bf_t *r;
+  JSValue val;
+  val = JS_NewBigFloat(ctx);
+  if (JS_IsException(val))
+    return val;
+  r = JS_GetBigFloat(val);
+  switch(magic) {
+    case 0: /* PI */
+      bf_const_pi(r, ctx->fp_env.prec, ctx->fp_env.flags);
+      break;
+    case 1: /* LN2 */
+      bf_const_log2(r, ctx->fp_env.prec, ctx->fp_env.flags);
+      break;
+    case 2: /* MIN_VALUE */
+    case 3: /* MAX_VALUE */
+    {
+      slimb_t e_range, e;
+      e_range = (limb_t)1 << (bf_get_exp_bits(ctx->fp_env.flags) - 1);
+      bf_set_ui(r, 1);
+      if (magic == 2) {
+        e = -e_range + 2;
+        if (ctx->fp_env.flags & BF_FLAG_SUBNORMAL)
+          e -= ctx->fp_env.prec - 1;
+        bf_mul_2exp(r, e, ctx->fp_env.prec, ctx->fp_env.flags);
+      } else {
+        bf_mul_2exp(r, ctx->fp_env.prec, ctx->fp_env.prec,
+                    ctx->fp_env.flags);
+        bf_add_si(r, r, -1, ctx->fp_env.prec, ctx->fp_env.flags);
+        bf_mul_2exp(r, e_range - ctx->fp_env.prec, ctx->fp_env.prec,
+                    ctx->fp_env.flags);
+      }
+    }
+    break;
+    case 4: /* EPSILON */
+      bf_set_ui(r, 1);
+      bf_mul_2exp(r, 1 - ctx->fp_env.prec,
+                  ctx->fp_env.prec, ctx->fp_env.flags);
+      break;
+    default:
+      abort();
+  }
+  return val;
+}
+
+JSValue js_bigfloat_parseFloat(JSContext *ctx, JSValueConst this_val,
+                                      int argc, JSValueConst *argv)
+{
+  bf_t *a;
+  const char *str;
+  JSValue ret;
+  int radix;
+  JSFloatEnv *fe;
+
+  str = JS_ToCString(ctx, argv[0]);
+  if (!str)
+    return JS_EXCEPTION;
+  if (JS_ToInt32(ctx, &radix, argv[1])) {
+  fail:
+    JS_FreeCString(ctx, str);
+    return JS_EXCEPTION;
+  }
+  if (radix != 0 && (radix < 2 || radix > 36)) {
+    JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
+    goto fail;
+  }
+  fe = &ctx->fp_env;
+  if (argc > 2) {
+    fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV);
+    if (!fe)
+      goto fail;
+  }
+  ret = JS_NewBigFloat(ctx);
+  if (JS_IsException(ret))
+    goto done;
+  a = JS_GetBigFloat(ret);
+  /* XXX: use js_atof() */
+  bf_atof(a, str, NULL, radix, fe->prec, fe->flags);
+done:
+  JS_FreeCString(ctx, str);
+  return ret;
+}
+
+JSValue js_bigfloat_isFinite(JSContext *ctx, JSValueConst this_val,
+                                    int argc, JSValueConst *argv)
+{
+  JSValueConst val = argv[0];
+  JSBigFloat *p;
+
+  if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT)
+    return JS_FALSE;
+  p = JS_VALUE_GET_PTR(val);
+  return JS_NewBool(ctx, bf_is_finite(&p->num));
+}
+
+JSValue js_bigfloat_isNaN(JSContext *ctx, JSValueConst this_val,
+                                 int argc, JSValueConst *argv)
+{
+  JSValueConst val = argv[0];
+  JSBigFloat *p;
+
+  if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT)
+    return JS_FALSE;
+  p = JS_VALUE_GET_PTR(val);
+  return JS_NewBool(ctx, bf_is_nan(&p->num));
+}
+
+enum {
+  MATH_OP_ABS,
+  MATH_OP_FLOOR,
+  MATH_OP_CEIL,
+  MATH_OP_ROUND,
+  MATH_OP_TRUNC,
+  MATH_OP_SQRT,
+  MATH_OP_FPROUND,
+  MATH_OP_ACOS,
+  MATH_OP_ASIN,
+  MATH_OP_ATAN,
+  MATH_OP_ATAN2,
+  MATH_OP_COS,
+  MATH_OP_EXP,
+  MATH_OP_LOG,
+  MATH_OP_POW,
+  MATH_OP_SIN,
+  MATH_OP_TAN,
+  MATH_OP_FMOD,
+  MATH_OP_REM,
+  MATH_OP_SIGN,
+
+  MATH_OP_ADD,
+  MATH_OP_SUB,
+  MATH_OP_MUL,
+  MATH_OP_DIV,
+};
+
+JSValue js_bigfloat_fop(JSContext *ctx, JSValueConst this_val,
+                               int argc, JSValueConst *argv, int magic)
+{
+  bf_t a_s, *a, *r;
+  JSFloatEnv *fe;
+  int rnd_mode;
+  JSValue op1, res;
+
+  op1 = JS_ToNumeric(ctx, argv[0]);
+  if (JS_IsException(op1))
+    return op1;
+  a = JS_ToBigFloat(ctx, &a_s, op1);
+  fe = &ctx->fp_env;
+  if (argc > 1) {
+    fe = JS_GetOpaque2(ctx, argv[1], JS_CLASS_FLOAT_ENV);
+    if (!fe)
+      goto fail;
+  }
+  res = JS_NewBigFloat(ctx);
+  if (JS_IsException(res)) {
+  fail:
+    if (a == &a_s)
+      bf_delete(a);
+    JS_FreeValue(ctx, op1);
+    return JS_EXCEPTION;
+  }
+  r = JS_GetBigFloat(res);
+  switch (magic) {
+    case MATH_OP_ABS:
+      bf_set(r, a);
+      r->sign = 0;
+      break;
+    case MATH_OP_FLOOR:
+      rnd_mode = BF_RNDD;
+      goto rint;
+    case MATH_OP_CEIL:
+      rnd_mode = BF_RNDU;
+      goto rint;
+    case MATH_OP_ROUND:
+      rnd_mode = BF_RNDNA;
+      goto rint;
+    case MATH_OP_TRUNC:
+      rnd_mode = BF_RNDZ;
+    rint:
+      bf_set(r, a);
+      fe->status |= bf_rint(r, rnd_mode);
+      break;
+    case MATH_OP_SQRT:
+      fe->status |= bf_sqrt(r, a, fe->prec, fe->flags);
+      break;
+    case MATH_OP_FPROUND:
+      bf_set(r, a);
+      fe->status |= bf_round(r, fe->prec, fe->flags);
+      break;
+    case MATH_OP_ACOS:
+      fe->status |= bf_acos(r, a, fe->prec, fe->flags);
+      break;
+    case MATH_OP_ASIN:
+      fe->status |= bf_asin(r, a, fe->prec, fe->flags);
+      break;
+    case MATH_OP_ATAN:
+      fe->status |= bf_atan(r, a, fe->prec, fe->flags);
+      break;
+    case MATH_OP_COS:
+      fe->status |= bf_cos(r, a, fe->prec, fe->flags);
+      break;
+    case MATH_OP_EXP:
+      fe->status |= bf_exp(r, a, fe->prec, fe->flags);
+      break;
+    case MATH_OP_LOG:
+      fe->status |= bf_log(r, a, fe->prec, fe->flags);
+      break;
+    case MATH_OP_SIN:
+      fe->status |= bf_sin(r, a, fe->prec, fe->flags);
+      break;
+    case MATH_OP_TAN:
+      fe->status |= bf_tan(r, a, fe->prec, fe->flags);
+      break;
+    case MATH_OP_SIGN:
+      if (bf_is_nan(a) || bf_is_zero(a)) {
+        bf_set(r, a);
+      } else {
+        bf_set_si(r, 1 - 2 * a->sign);
+      }
+      break;
+    default:
+      abort();
+  }
+  if (a == &a_s)
+    bf_delete(a);
+  JS_FreeValue(ctx, op1);
+  return res;
+}
+
+JSValue js_bigfloat_fop2(JSContext *ctx, JSValueConst this_val,
+                                int argc, JSValueConst *argv, int magic)
+{
+  bf_t a_s, *a, b_s, *b, r_s, *r = &r_s;
+  JSFloatEnv *fe;
+  JSValue op1, op2, res;
+
+  op1 = JS_ToNumeric(ctx, argv[0]);
+  if (JS_IsException(op1))
+    return op1;
+  op2 = JS_ToNumeric(ctx, argv[1]);
+  if (JS_IsException(op2)) {
+    JS_FreeValue(ctx, op1);
+    return op2;
+  }
+  a = JS_ToBigFloat(ctx, &a_s, op1);
+  b = JS_ToBigFloat(ctx, &b_s, op2);
+  fe = &ctx->fp_env;
+  if (argc > 2) {
+    fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV);
+    if (!fe)
+      goto fail;
+  }
+  res = JS_NewBigFloat(ctx);
+  if (JS_IsException(res)) {
+  fail:
+    if (a == &a_s)
+      bf_delete(a);
+    if (b == &b_s)
+      bf_delete(b);
+    JS_FreeValue(ctx, op1);
+    JS_FreeValue(ctx, op2);
+    return JS_EXCEPTION;
+  }
+  r = JS_GetBigFloat(res);
+  switch (magic) {
+    case MATH_OP_ATAN2:
+      fe->status |= bf_atan2(r, a, b, fe->prec, fe->flags);
+      break;
+    case MATH_OP_POW:
+      fe->status |= bf_pow(r, a, b, fe->prec, fe->flags | BF_POW_JS_QUIRKS);
+      break;
+    case MATH_OP_FMOD:
+      fe->status |= bf_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ);
+      break;
+    case MATH_OP_REM:
+      fe->status |= bf_rem(r, a, b, fe->prec, fe->flags, BF_RNDN);
+      break;
+    case MATH_OP_ADD:
+      fe->status |= bf_add(r, a, b, fe->prec, fe->flags);
+      break;
+    case MATH_OP_SUB:
+      fe->status |= bf_sub(r, a, b, fe->prec, fe->flags);
+      break;
+    case MATH_OP_MUL:
+      fe->status |= bf_mul(r, a, b, fe->prec, fe->flags);
+      break;
+    case MATH_OP_DIV:
+      fe->status |= bf_div(r, a, b, fe->prec, fe->flags);
+      break;
+    default:
+      abort();
+  }
+  if (a == &a_s)
+    bf_delete(a);
+  if (b == &b_s)
+    bf_delete(b);
+  JS_FreeValue(ctx, op1);
+  JS_FreeValue(ctx, op2);
+  return res;
+}
+
+const JSCFunctionListEntry js_bigfloat_funcs[] = {
+    JS_CGETSET_MAGIC_DEF("PI", js_bigfloat_get_const, NULL, 0 ),
+    JS_CGETSET_MAGIC_DEF("LN2", js_bigfloat_get_const, NULL, 1 ),
+    JS_CGETSET_MAGIC_DEF("MIN_VALUE", js_bigfloat_get_const, NULL, 2 ),
+    JS_CGETSET_MAGIC_DEF("MAX_VALUE", js_bigfloat_get_const, NULL, 3 ),
+    JS_CGETSET_MAGIC_DEF("EPSILON", js_bigfloat_get_const, NULL, 4 ),
+    JS_CFUNC_DEF("parseFloat", 1, js_bigfloat_parseFloat ),
+    JS_CFUNC_DEF("isFinite", 1, js_bigfloat_isFinite ),
+    JS_CFUNC_DEF("isNaN", 1, js_bigfloat_isNaN ),
+    JS_CFUNC_MAGIC_DEF("abs", 1, js_bigfloat_fop, MATH_OP_ABS ),
+    JS_CFUNC_MAGIC_DEF("fpRound", 1, js_bigfloat_fop, MATH_OP_FPROUND ),
+    JS_CFUNC_MAGIC_DEF("floor", 1, js_bigfloat_fop, MATH_OP_FLOOR ),
+    JS_CFUNC_MAGIC_DEF("ceil", 1, js_bigfloat_fop, MATH_OP_CEIL ),
+    JS_CFUNC_MAGIC_DEF("round", 1, js_bigfloat_fop, MATH_OP_ROUND ),
+    JS_CFUNC_MAGIC_DEF("trunc", 1, js_bigfloat_fop, MATH_OP_TRUNC ),
+    JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigfloat_fop, MATH_OP_SQRT ),
+    JS_CFUNC_MAGIC_DEF("acos", 1, js_bigfloat_fop, MATH_OP_ACOS ),
+    JS_CFUNC_MAGIC_DEF("asin", 1, js_bigfloat_fop, MATH_OP_ASIN ),
+    JS_CFUNC_MAGIC_DEF("atan", 1, js_bigfloat_fop, MATH_OP_ATAN ),
+    JS_CFUNC_MAGIC_DEF("atan2", 2, js_bigfloat_fop2, MATH_OP_ATAN2 ),
+    JS_CFUNC_MAGIC_DEF("cos", 1, js_bigfloat_fop, MATH_OP_COS ),
+    JS_CFUNC_MAGIC_DEF("exp", 1, js_bigfloat_fop, MATH_OP_EXP ),
+    JS_CFUNC_MAGIC_DEF("log", 1, js_bigfloat_fop, MATH_OP_LOG ),
+    JS_CFUNC_MAGIC_DEF("pow", 2, js_bigfloat_fop2, MATH_OP_POW ),
+    JS_CFUNC_MAGIC_DEF("sin", 1, js_bigfloat_fop, MATH_OP_SIN ),
+    JS_CFUNC_MAGIC_DEF("tan", 1, js_bigfloat_fop, MATH_OP_TAN ),
+    JS_CFUNC_MAGIC_DEF("sign", 1, js_bigfloat_fop, MATH_OP_SIGN ),
+    JS_CFUNC_MAGIC_DEF("add", 2, js_bigfloat_fop2, MATH_OP_ADD ),
+    JS_CFUNC_MAGIC_DEF("sub", 2, js_bigfloat_fop2, MATH_OP_SUB ),
+    JS_CFUNC_MAGIC_DEF("mul", 2, js_bigfloat_fop2, MATH_OP_MUL ),
+    JS_CFUNC_MAGIC_DEF("div", 2, js_bigfloat_fop2, MATH_OP_DIV ),
+    JS_CFUNC_MAGIC_DEF("fmod", 2, js_bigfloat_fop2, MATH_OP_FMOD ),
+    JS_CFUNC_MAGIC_DEF("remainder", 2, js_bigfloat_fop2, MATH_OP_REM ),
+};
+
+/* FloatEnv */
+
+JSValue js_float_env_constructor(JSContext *ctx,
+                                        JSValueConst new_target,
+                                        int argc, JSValueConst *argv)
+{
+  JSValue obj;
+  JSFloatEnv *fe;
+  int64_t prec;
+  int flags, rndmode;
+
+  prec = ctx->fp_env.prec;
+  flags = ctx->fp_env.flags;
+  if (!JS_IsUndefined(argv[0])) {
+    if (JS_ToInt64Sat(ctx, &prec, argv[0]))
+      return JS_EXCEPTION;
+    if (prec < BF_PREC_MIN || prec > BF_PREC_MAX)
+      return JS_ThrowRangeError(ctx, "invalid precision");
+    flags = BF_RNDN; /* RNDN, max exponent size, no subnormal */
+    if (argc > 1 && !JS_IsUndefined(argv[1])) {
+      if (JS_ToInt32Sat(ctx, &rndmode, argv[1]))
+        return JS_EXCEPTION;
+      if (rndmode < BF_RNDN || rndmode > BF_RNDF)
+        return JS_ThrowRangeError(ctx, "invalid rounding mode");
+      flags = rndmode;
+    }
+  }
+
+  obj = JS_NewObjectClass(ctx, JS_CLASS_FLOAT_ENV);
+  if (JS_IsException(obj))
+    return JS_EXCEPTION;
+  fe = js_malloc(ctx, sizeof(*fe));
+  if (!fe)
+    return JS_EXCEPTION;
+  fe->prec = prec;
+  fe->flags = flags;
+  fe->status = 0;
+  JS_SetOpaque(obj, fe);
+  return obj;
+}
+
+void js_float_env_finalizer(JSRuntime *rt, JSValue val)
+{
+  JSFloatEnv *fe = JS_GetOpaque(val, JS_CLASS_FLOAT_ENV);
+  js_free_rt(rt, fe);
+}
+
+JSValue js_float_env_get_prec(JSContext *ctx, JSValueConst this_val)
+{
+  return JS_NewInt64(ctx, ctx->fp_env.prec);
+}
+
+JSValue js_float_env_get_expBits(JSContext *ctx, JSValueConst this_val)
+{
+  return JS_NewInt32(ctx, bf_get_exp_bits(ctx->fp_env.flags));
+}
+
+JSValue js_float_env_setPrec(JSContext *ctx,
+                                    JSValueConst this_val,
+                                    int argc, JSValueConst *argv)
+{
+  JSValueConst func;
+  int exp_bits, flags, saved_flags;
+  JSValue ret;
+  limb_t saved_prec;
+  int64_t prec;
+
+  func = argv[0];
+  if (JS_ToInt64Sat(ctx, &prec, argv[1]))
+    return JS_EXCEPTION;
+  if (prec < BF_PREC_MIN || prec > BF_PREC_MAX)
+    return JS_ThrowRangeError(ctx, "invalid precision");
+  exp_bits = BF_EXP_BITS_MAX;
+
+  if (argc > 2 && !JS_IsUndefined(argv[2])) {
+    if (JS_ToInt32Sat(ctx, &exp_bits, argv[2]))
+      return JS_EXCEPTION;
+    if (exp_bits < BF_EXP_BITS_MIN || exp_bits > BF_EXP_BITS_MAX)
+      return JS_ThrowRangeError(ctx, "invalid number of exponent bits");
+  }
+
+  flags = BF_RNDN | BF_FLAG_SUBNORMAL | bf_set_exp_bits(exp_bits);
+
+  saved_prec = ctx->fp_env.prec;
+  saved_flags = ctx->fp_env.flags;
+
+  ctx->fp_env.prec = prec;
+  ctx->fp_env.flags = flags;
+
+  ret = JS_Call(ctx, func, JS_UNDEFINED, 0, NULL);
+  /* always restore the floating point precision */
+  ctx->fp_env.prec = saved_prec;
+  ctx->fp_env.flags = saved_flags;
+  return ret;
+}
+
+#define FE_PREC      (-1)
+#define FE_EXP       (-2)
+#define FE_RNDMODE   (-3)
+#define FE_SUBNORMAL (-4)
+
+JSValue js_float_env_proto_get_status(JSContext *ctx, JSValueConst this_val, int magic)
+{
+  JSFloatEnv *fe;
+  fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV);
+  if (!fe)
+    return JS_EXCEPTION;
+  switch(magic) {
+    case FE_PREC:
+      return JS_NewInt64(ctx, fe->prec);
+    case FE_EXP:
+      return JS_NewInt32(ctx, bf_get_exp_bits(fe->flags));
+    case FE_RNDMODE:
+      return JS_NewInt32(ctx, fe->flags & BF_RND_MASK);
+    case FE_SUBNORMAL:
+      return JS_NewBool(ctx, (fe->flags & BF_FLAG_SUBNORMAL) != 0);
+    default:
+      return JS_NewBool(ctx, (fe->status & magic) != 0);
+  }
+}
+
+JSValue js_float_env_proto_set_status(JSContext *ctx, JSValueConst this_val, JSValueConst val, int magic)
+{
+  JSFloatEnv *fe;
+  int b;
+  int64_t prec;
+
+  fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV);
+  if (!fe)
+    return JS_EXCEPTION;
+  switch(magic) {
+    case FE_PREC:
+      if (JS_ToInt64Sat(ctx, &prec, val))
+        return JS_EXCEPTION;
+      if (prec < BF_PREC_MIN || prec > BF_PREC_MAX)
+        return JS_ThrowRangeError(ctx, "invalid precision");
+      fe->prec = prec;
+      break;
+    case FE_EXP:
+      if (JS_ToInt32Sat(ctx, &b, val))
+        return JS_EXCEPTION;
+      if (b < BF_EXP_BITS_MIN || b > BF_EXP_BITS_MAX)
+        return JS_ThrowRangeError(ctx, "invalid number of exponent bits");
+      fe->flags = (fe->flags & ~(BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)) |
+                  bf_set_exp_bits(b);
+      break;
+    case FE_RNDMODE:
+      b = bigfloat_get_rnd_mode(ctx, val);
+      if (b < 0)
+        return JS_EXCEPTION;
+      fe->flags = (fe->flags & ~BF_RND_MASK) | b;
+      break;
+    case FE_SUBNORMAL:
+      b = JS_ToBool(ctx, val);
+      fe->flags = (fe->flags & ~BF_FLAG_SUBNORMAL) | (b ? BF_FLAG_SUBNORMAL: 0);
+      break;
+    default:
+      b = JS_ToBool(ctx, val);
+      fe->status = (fe->status & ~magic) & ((-b) & magic);
+      break;
+  }
+  return JS_UNDEFINED;
+}
+
+JSValue js_float_env_clearStatus(JSContext *ctx,
+                                        JSValueConst this_val,
+                                        int argc, JSValueConst *argv)
+{
+  JSFloatEnv *fe = JS_GetOpaque2(ctx, this_val, JS_CLASS_FLOAT_ENV);
+  if (!fe)
+    return JS_EXCEPTION;
+  fe->status = 0;
+  return JS_UNDEFINED;
+}
+
+const JSCFunctionListEntry js_float_env_funcs[] = {
+    JS_CGETSET_DEF("prec", js_float_env_get_prec, NULL ),
+    JS_CGETSET_DEF("expBits", js_float_env_get_expBits, NULL ),
+    JS_CFUNC_DEF("setPrec", 2, js_float_env_setPrec ),
+    JS_PROP_INT32_DEF("RNDN", BF_RNDN, 0 ),
+    JS_PROP_INT32_DEF("RNDZ", BF_RNDZ, 0 ),
+    JS_PROP_INT32_DEF("RNDU", BF_RNDU, 0 ),
+    JS_PROP_INT32_DEF("RNDD", BF_RNDD, 0 ),
+    JS_PROP_INT32_DEF("RNDNA", BF_RNDNA, 0 ),
+    JS_PROP_INT32_DEF("RNDA", BF_RNDA, 0 ),
+    JS_PROP_INT32_DEF("RNDF", BF_RNDF, 0 ),
+    JS_PROP_INT32_DEF("precMin", BF_PREC_MIN, 0 ),
+    JS_PROP_INT64_DEF("precMax", BF_PREC_MAX, 0 ),
+    JS_PROP_INT32_DEF("expBitsMin", BF_EXP_BITS_MIN, 0 ),
+    JS_PROP_INT32_DEF("expBitsMax", BF_EXP_BITS_MAX, 0 ),
+};
+
+const JSCFunctionListEntry js_float_env_proto_funcs[] = {
+    JS_CGETSET_MAGIC_DEF("prec", js_float_env_proto_get_status,
+                         js_float_env_proto_set_status, FE_PREC ),
+    JS_CGETSET_MAGIC_DEF("expBits", js_float_env_proto_get_status,
+                         js_float_env_proto_set_status, FE_EXP ),
+    JS_CGETSET_MAGIC_DEF("rndMode", js_float_env_proto_get_status,
+                         js_float_env_proto_set_status, FE_RNDMODE ),
+    JS_CGETSET_MAGIC_DEF("subnormal", js_float_env_proto_get_status,
+                         js_float_env_proto_set_status, FE_SUBNORMAL ),
+    JS_CGETSET_MAGIC_DEF("invalidOperation", js_float_env_proto_get_status,
+                         js_float_env_proto_set_status, BF_ST_INVALID_OP ),
+    JS_CGETSET_MAGIC_DEF("divideByZero", js_float_env_proto_get_status,
+                         js_float_env_proto_set_status, BF_ST_DIVIDE_ZERO ),
+    JS_CGETSET_MAGIC_DEF("overflow", js_float_env_proto_get_status,
+                         js_float_env_proto_set_status, BF_ST_OVERFLOW ),
+    JS_CGETSET_MAGIC_DEF("underflow", js_float_env_proto_get_status,
+                         js_float_env_proto_set_status, BF_ST_UNDERFLOW ),
+    JS_CGETSET_MAGIC_DEF("inexact", js_float_env_proto_get_status,
+                         js_float_env_proto_set_status, BF_ST_INEXACT ),
+    JS_CFUNC_DEF("clearStatus", 0, js_float_env_clearStatus ),
+};
+
+void JS_AddIntrinsicBigFloat(JSContext *ctx)
+{
+  JSRuntime *rt = ctx->rt;
+  JSValueConst obj1;
+
+  rt->bigfloat_ops.to_string = js_bigfloat_to_string;
+  rt->bigfloat_ops.from_string = js_string_to_bigfloat;
+  rt->bigfloat_ops.unary_arith = js_unary_arith_bigfloat;
+  rt->bigfloat_ops.binary_arith = js_binary_arith_bigfloat;
+  rt->bigfloat_ops.compare = js_compare_bigfloat;
+  rt->bigfloat_ops.mul_pow10_to_float64 = js_mul_pow10_to_float64;
+  rt->bigfloat_ops.mul_pow10 = js_mul_pow10;
+
+  ctx->class_proto[JS_CLASS_BIG_FLOAT] = JS_NewObject(ctx);
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT],
+                             js_bigfloat_proto_funcs,
+                             countof(js_bigfloat_proto_funcs));
+  obj1 = JS_NewGlobalCConstructor(ctx, "BigFloat", js_bigfloat_constructor, 1,
+                                  ctx->class_proto[JS_CLASS_BIG_FLOAT]);
+  JS_SetPropertyFunctionList(ctx, obj1, js_bigfloat_funcs,
+                             countof(js_bigfloat_funcs));
+
+  ctx->class_proto[JS_CLASS_FLOAT_ENV] = JS_NewObject(ctx);
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_FLOAT_ENV],
+                             js_float_env_proto_funcs,
+                             countof(js_float_env_proto_funcs));
+  obj1 = JS_NewGlobalCConstructorOnly(ctx, "BigFloatEnv",
+                                      js_float_env_constructor, 1,
+                                      ctx->class_proto[JS_CLASS_FLOAT_ENV]);
+  JS_SetPropertyFunctionList(ctx, obj1, js_float_env_funcs,
+                             countof(js_float_env_funcs));
+}
+
+/* BigDecimal */
+
+JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
+                                   BOOL allow_null_or_undefined)
+{
+redo:
+  switch(JS_VALUE_GET_NORM_TAG(val)) {
+    case JS_TAG_BIG_DECIMAL:
+      break;
+    case JS_TAG_NULL:
+      if (!allow_null_or_undefined)
+        goto fail;
+      /* fall thru */
+    case JS_TAG_BOOL:
+    case JS_TAG_INT:
+    {
+      bfdec_t *r;
+      int32_t v = JS_VALUE_GET_INT(val);
+
+      val = JS_NewBigDecimal(ctx);
+      if (JS_IsException(val))
+        break;
+      r = JS_GetBigDecimal(val);
+      if (bfdec_set_si(r, v)) {
+        JS_FreeValue(ctx, val);
+        val = JS_EXCEPTION;
+        break;
+      }
+    }
+    break;
+    case JS_TAG_FLOAT64:
+    case JS_TAG_BIG_INT:
+    case JS_TAG_BIG_FLOAT:
+      val = JS_ToStringFree(ctx, val);
+      if (JS_IsException(val))
+        break;
+      goto redo;
+    case JS_TAG_STRING:
+    {
+      const char *str, *p;
+      size_t len;
+      int err;
+
+      str = JS_ToCStringLen(ctx, &len, val);
+      JS_FreeValue(ctx, val);
+      if (!str)
+        return JS_EXCEPTION;
+      p = str;
+      p += skip_spaces(p);
+      if ((p - str) == len) {
+        bfdec_t *r;
+        val = JS_NewBigDecimal(ctx);
+        if (JS_IsException(val))
+          break;
+        r = JS_GetBigDecimal(val);
+        bfdec_set_zero(r, 0);
+        err = 0;
+      } else {
+        val = js_atof(ctx, p, &p, 0, ATOD_TYPE_BIG_DECIMAL);
+        if (JS_IsException(val)) {
+          JS_FreeCString(ctx, str);
+          return JS_EXCEPTION;
+        }
+        p += skip_spaces(p);
+        err = ((p - str) != len);
+      }
+      JS_FreeCString(ctx, str);
+      if (err) {
+        JS_FreeValue(ctx, val);
+        return JS_ThrowSyntaxError(ctx, "invalid bigdecimal literal");
+      }
+    }
+    break;
+    case JS_TAG_OBJECT:
+      val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
+      if (JS_IsException(val))
+        break;
+      goto redo;
+    case JS_TAG_UNDEFINED:
+    {
+      bfdec_t *r;
+      if (!allow_null_or_undefined)
+        goto fail;
+      val = JS_NewBigDecimal(ctx);
+      if (JS_IsException(val))
+        break;
+      r = JS_GetBigDecimal(val);
+      bfdec_set_nan(r);
+    }
+    break;
+    default:
+    fail:
+      JS_FreeValue(ctx, val);
+      return JS_ThrowTypeError(ctx, "cannot convert to bigdecimal");
+  }
+  return val;
+}
+
+JSValue js_bigdecimal_constructor(JSContext *ctx,
+                                         JSValueConst new_target,
+                                         int argc, JSValueConst *argv)
+{
+  JSValue val;
+  if (!JS_IsUndefined(new_target))
+    return JS_ThrowTypeError(ctx, "not a constructor");
+  if (argc == 0) {
+    bfdec_t *r;
+    val = JS_NewBigDecimal(ctx);
+    if (JS_IsException(val))
+      return val;
+    r = JS_GetBigDecimal(val);
+    bfdec_set_zero(r, 0);
+  } else {
+    val = JS_ToBigDecimalFree(ctx, JS_DupValue(ctx, argv[0]), FALSE);
+  }
+  return val;
+}
+
+JSValue js_thisBigDecimalValue(JSContext *ctx, JSValueConst this_val)
+{
+  if (JS_IsBigDecimal(this_val))
+    return JS_DupValue(ctx, this_val);
+
+  if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
+    JSObject *p = JS_VALUE_GET_OBJ(this_val);
+    if (p->class_id == JS_CLASS_BIG_DECIMAL) {
+      if (JS_IsBigDecimal(p->u.object_data))
+        return JS_DupValue(ctx, p->u.object_data);
+    }
+  }
+  return JS_ThrowTypeError(ctx, "not a bigdecimal");
+}
+
+JSValue js_bigdecimal_toString(JSContext *ctx, JSValueConst this_val,
+                                      int argc, JSValueConst *argv)
+{
+  JSValue val;
+
+  val = js_thisBigDecimalValue(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  return JS_ToStringFree(ctx, val);
+}
+
+JSValue js_bigdecimal_valueOf(JSContext *ctx, JSValueConst this_val,
+                                     int argc, JSValueConst *argv)
+{
+  return js_thisBigDecimalValue(ctx, this_val);
+}
+
+int js_bigdecimal_get_rnd_mode(JSContext *ctx, JSValueConst obj)
+{
+  const char *str;
+  size_t size;
+  int rnd_mode;
+
+  str = JS_ToCStringLen(ctx, &size, obj);
+  if (!str)
+    return -1;
+  if (strlen(str) != size)
+    goto invalid_rounding_mode;
+  if (!strcmp(str, "floor")) {
+    rnd_mode = BF_RNDD;
+  } else if (!strcmp(str, "ceiling")) {
+    rnd_mode = BF_RNDU;
+  } else if (!strcmp(str, "down")) {
+    rnd_mode = BF_RNDZ;
+  } else if (!strcmp(str, "up")) {
+    rnd_mode = BF_RNDA;
+  } else if (!strcmp(str, "half-even")) {
+    rnd_mode = BF_RNDN;
+  } else if (!strcmp(str, "half-up")) {
+    rnd_mode = BF_RNDNA;
+  } else {
+  invalid_rounding_mode:
+    JS_FreeCString(ctx, str);
+    JS_ThrowTypeError(ctx, "invalid rounding mode");
+    return -1;
+  }
+  JS_FreeCString(ctx, str);
+  return rnd_mode;
+}
+
+typedef struct {
+  int64_t prec;
+  bf_flags_t flags;
+} BigDecimalEnv;
+
+int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe,
+                                 JSValueConst obj)
+{
+  JSValue prop;
+  int64_t val;
+  BOOL has_prec;
+  int rnd_mode;
+
+  if (!JS_IsObject(obj)) {
+    JS_ThrowTypeErrorNotAnObject(ctx);
+    return -1;
+  }
+  prop = JS_GetProperty(ctx, obj, JS_ATOM_roundingMode);
+  if (JS_IsException(prop))
+    return -1;
+  rnd_mode = js_bigdecimal_get_rnd_mode(ctx, prop);
+  JS_FreeValue(ctx, prop);
+  if (rnd_mode < 0)
+    return -1;
+  fe->flags = rnd_mode;
+
+  prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumSignificantDigits);
+  if (JS_IsException(prop))
+    return -1;
+  has_prec = FALSE;
+  if (!JS_IsUndefined(prop)) {
+    if (JS_ToInt64SatFree(ctx, &val, prop))
+      return -1;
+    if (val < 1 || val > BF_PREC_MAX)
+      goto invalid_precision;
+    fe->prec = val;
+    has_prec = TRUE;
+  }
+
+  prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumFractionDigits);
+  if (JS_IsException(prop))
+    return -1;
+  if (!JS_IsUndefined(prop)) {
+    if (has_prec) {
+      JS_FreeValue(ctx, prop);
+      JS_ThrowTypeError(ctx, "cannot provide both maximumSignificantDigits and maximumFractionDigits");
+      return -1;
+    }
+    if (JS_ToInt64SatFree(ctx, &val, prop))
+      return -1;
+    if (val < 0 || val > BF_PREC_MAX) {
+    invalid_precision:
+      JS_ThrowTypeError(ctx, "invalid precision");
+      return -1;
+    }
+    fe->prec = val;
+    fe->flags |= BF_FLAG_RADPNT_PREC;
+    has_prec = TRUE;
+  }
+  if (!has_prec) {
+    JS_ThrowTypeError(ctx, "precision must be present");
+    return -1;
+  }
+  return 0;
+}
+
+
+JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val,
+                                 int argc, JSValueConst *argv, int magic)
+{
+  bfdec_t *a, *b, r_s, *r = &r_s;
+  JSValue op1, op2, res;
+  BigDecimalEnv fe_s, *fe = &fe_s;
+  int op_count, ret;
+
+  if (magic == MATH_OP_SQRT ||
+      magic == MATH_OP_ROUND)
+    op_count = 1;
+  else
+    op_count = 2;
+
+  op1 = JS_ToNumeric(ctx, argv[0]);
+  if (JS_IsException(op1))
+    return op1;
+  a = JS_ToBigDecimal(ctx, op1);
+  if (!a) {
+    JS_FreeValue(ctx, op1);
+    return JS_EXCEPTION;
+  }
+  if (op_count >= 2) {
+    op2 = JS_ToNumeric(ctx, argv[1]);
+    if (JS_IsException(op2)) {
+      JS_FreeValue(ctx, op1);
+      return op2;
+    }
+    b = JS_ToBigDecimal(ctx, op2);
+    if (!b)
+      goto fail;
+  } else {
+    op2 = JS_UNDEFINED;
+    b = NULL;
+  }
+  fe->flags = BF_RNDZ;
+  fe->prec = BF_PREC_INF;
+  if (op_count < argc) {
+    if (js_bigdecimal_get_env(ctx, fe, argv[op_count]))
+      goto fail;
+  }
+
+  res = JS_NewBigDecimal(ctx);
+  if (JS_IsException(res)) {
+  fail:
+    JS_FreeValue(ctx, op1);
+    JS_FreeValue(ctx, op2);
+    return JS_EXCEPTION;
+  }
+  r = JS_GetBigDecimal(res);
+  switch (magic) {
+    case MATH_OP_ADD:
+      ret = bfdec_add(r, a, b, fe->prec, fe->flags);
+      break;
+    case MATH_OP_SUB:
+      ret = bfdec_sub(r, a, b, fe->prec, fe->flags);
+      break;
+    case MATH_OP_MUL:
+      ret = bfdec_mul(r, a, b, fe->prec, fe->flags);
+      break;
+    case MATH_OP_DIV:
+      ret = bfdec_div(r, a, b, fe->prec, fe->flags);
+      break;
+    case MATH_OP_FMOD:
+      ret = bfdec_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ);
+      break;
+    case MATH_OP_SQRT:
+      ret = bfdec_sqrt(r, a, fe->prec, fe->flags);
+      break;
+    case MATH_OP_ROUND:
+      ret = bfdec_set(r, a);
+      if (!(ret & BF_ST_MEM_ERROR))
+        ret = bfdec_round(r, fe->prec, fe->flags);
+      break;
+    default:
+      abort();
+  }
+  JS_FreeValue(ctx, op1);
+  JS_FreeValue(ctx, op2);
+  ret &= BF_ST_MEM_ERROR | BF_ST_DIVIDE_ZERO | BF_ST_INVALID_OP |
+         BF_ST_OVERFLOW;
+  if (ret != 0) {
+    JS_FreeValue(ctx, res);
+    return throw_bf_exception(ctx, ret);
+  } else {
+    return res;
+  }
+}
+
+JSValue js_bigdecimal_toFixed(JSContext *ctx, JSValueConst this_val,
+                                     int argc, JSValueConst *argv)
+{
+  JSValue val, ret;
+  int64_t f;
+  int rnd_mode;
+
+  val = js_thisBigDecimalValue(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  if (JS_ToInt64Sat(ctx, &f, argv[0]))
+    goto fail;
+  if (f < 0 || f > BF_PREC_MAX) {
+    JS_ThrowRangeError(ctx, "invalid number of digits");
+    goto fail;
+  }
+  rnd_mode = BF_RNDNA;
+  if (argc > 1) {
+    rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
+    if (rnd_mode < 0)
+      goto fail;
+  }
+  ret = js_bigdecimal_to_string1(ctx, val, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
+  JS_FreeValue(ctx, val);
+  return ret;
+fail:
+  JS_FreeValue(ctx, val);
+  return JS_EXCEPTION;
+}
+
+JSValue js_bigdecimal_toExponential(JSContext *ctx, JSValueConst this_val,
+                                           int argc, JSValueConst *argv)
+{
+  JSValue val, ret;
+  int64_t f;
+  int rnd_mode;
+
+  val = js_thisBigDecimalValue(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  if (JS_ToInt64Sat(ctx, &f, argv[0]))
+    goto fail;
+  if (JS_IsUndefined(argv[0])) {
+    ret = js_bigdecimal_to_string1(ctx, val, 0,
+                                   BF_RNDN | BF_FTOA_FORMAT_FREE_MIN | BF_FTOA_FORCE_EXP);
+  } else {
+    if (f < 0 || f > BF_PREC_MAX) {
+      JS_ThrowRangeError(ctx, "invalid number of digits");
+      goto fail;
+    }
+    rnd_mode = BF_RNDNA;
+    if (argc > 1) {
+      rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
+      if (rnd_mode < 0)
+        goto fail;
+    }
+    ret = js_bigdecimal_to_string1(ctx, val, f + 1,
+                                   rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP);
+  }
+  JS_FreeValue(ctx, val);
+  return ret;
+fail:
+  JS_FreeValue(ctx, val);
+  return JS_EXCEPTION;
+}
+
+JSValue js_bigdecimal_toPrecision(JSContext *ctx, JSValueConst this_val,
+                                         int argc, JSValueConst *argv)
+{
+  JSValue val, ret;
+  int64_t p;
+  int rnd_mode;
+
+  val = js_thisBigDecimalValue(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  if (JS_IsUndefined(argv[0])) {
+    return JS_ToStringFree(ctx, val);
+  }
+  if (JS_ToInt64Sat(ctx, &p, argv[0]))
+    goto fail;
+  if (p < 1 || p > BF_PREC_MAX) {
+    JS_ThrowRangeError(ctx, "invalid number of digits");
+    goto fail;
+  }
+  rnd_mode = BF_RNDNA;
+  if (argc > 1) {
+    rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
+    if (rnd_mode < 0)
+      goto fail;
+  }
+  ret = js_bigdecimal_to_string1(ctx, val, p,
+                                 rnd_mode | BF_FTOA_FORMAT_FIXED);
+  JS_FreeValue(ctx, val);
+  return ret;
+fail:
+  JS_FreeValue(ctx, val);
+  return JS_EXCEPTION;
+}
+
+const JSCFunctionListEntry js_bigdecimal_proto_funcs[] = {
+    JS_CFUNC_DEF("toString", 0, js_bigdecimal_toString ),
+    JS_CFUNC_DEF("valueOf", 0, js_bigdecimal_valueOf ),
+    JS_CFUNC_DEF("toPrecision", 1, js_bigdecimal_toPrecision ),
+    JS_CFUNC_DEF("toFixed", 1, js_bigdecimal_toFixed ),
+    JS_CFUNC_DEF("toExponential", 1, js_bigdecimal_toExponential ),
+};
+
+const JSCFunctionListEntry js_bigdecimal_funcs[] = {
+    JS_CFUNC_MAGIC_DEF("add", 2, js_bigdecimal_fop, MATH_OP_ADD ),
+    JS_CFUNC_MAGIC_DEF("sub", 2, js_bigdecimal_fop, MATH_OP_SUB ),
+    JS_CFUNC_MAGIC_DEF("mul", 2, js_bigdecimal_fop, MATH_OP_MUL ),
+    JS_CFUNC_MAGIC_DEF("div", 2, js_bigdecimal_fop, MATH_OP_DIV ),
+    JS_CFUNC_MAGIC_DEF("mod", 2, js_bigdecimal_fop, MATH_OP_FMOD ),
+    JS_CFUNC_MAGIC_DEF("round", 1, js_bigdecimal_fop, MATH_OP_ROUND ),
+    JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigdecimal_fop, MATH_OP_SQRT ),
+};
+
+void JS_AddIntrinsicBigDecimal(JSContext *ctx)
+{
+  JSRuntime *rt = ctx->rt;
+  JSValueConst obj1;
+
+  rt->bigdecimal_ops.to_string = js_bigdecimal_to_string;
+  rt->bigdecimal_ops.from_string = js_string_to_bigdecimal;
+  rt->bigdecimal_ops.unary_arith = js_unary_arith_bigdecimal;
+  rt->bigdecimal_ops.binary_arith = js_binary_arith_bigdecimal;
+  rt->bigdecimal_ops.compare = js_compare_bigdecimal;
+
+  ctx->class_proto[JS_CLASS_BIG_DECIMAL] = JS_NewObject(ctx);
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL],
+                             js_bigdecimal_proto_funcs,
+                             countof(js_bigdecimal_proto_funcs));
+  obj1 = JS_NewGlobalCConstructor(ctx, "BigDecimal",
+                                  js_bigdecimal_constructor, 1,
+                                  ctx->class_proto[JS_CLASS_BIG_DECIMAL]);
+  JS_SetPropertyFunctionList(ctx, obj1, js_bigdecimal_funcs,
+                             countof(js_bigdecimal_funcs));
+}
+
+void JS_EnableBignumExt(JSContext *ctx, BOOL enable)
+{
+  ctx->bignum_ext = enable;
+}
+
+#endif /* CONFIG_BIGNUM */
\ No newline at end of file
diff --git a/src/core/builtins/js-big-num.h b/src/core/builtins/js-big-num.h
new file mode 100644
index 000000000..5270949a1
--- /dev/null
+++ b/src/core/builtins/js-big-num.h
@@ -0,0 +1,124 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_BIG_NUM_H
+#define QUICKJS_JS_BIG_NUM_H
+
+#include "quickjs/quickjs.h"
+#include "quickjs/cutils.h"
+#include "../types.h"
+
+#if CONFIG_BIGNUM
+#include "quickjs/libbf.h"
+
+JSValue JS_NewBigInt(JSContext *ctx);
+JSValue JS_NewBigInt64_1(JSContext *ctx, int64_t v);
+
+no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
+                                               OPCodeEnum op);
+no_inline __exception int js_unary_arith_slow(JSContext *ctx,
+                                              JSValue *sp,
+                                              OPCodeEnum op);
+__exception int js_post_inc_slow(JSContext *ctx,
+                                 JSValue *sp, OPCodeEnum op);
+no_inline int js_not_slow(JSContext *ctx, JSValue *sp);
+int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op,
+                             JSValue *pres, JSValue op1, JSValue op2);
+int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,
+                           JSValue *pres, JSValue op1, JSValue op2);
+int js_bfdec_pow(bfdec_t *r, const bfdec_t *a, const bfdec_t *b);
+int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op,
+                               JSValue *pres, JSValue op1, JSValue op2);
+no_inline __exception int js_binary_logic_slow(JSContext *ctx,
+                                               JSValue *sp,
+                                               OPCodeEnum op);
+/* Note: also used for bigint */
+int js_compare_bigfloat(JSContext *ctx, OPCodeEnum op,
+                        JSValue op1, JSValue op2);
+int js_compare_bigdecimal(JSContext *ctx, OPCodeEnum op,
+                          JSValue op1, JSValue op2);
+no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
+                                 OPCodeEnum op);
+no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
+                                     BOOL is_neq);
+no_inline int js_shr_slow(JSContext *ctx, JSValue *sp);
+JSValue js_mul_pow10_to_float64(JSContext *ctx, const bf_t *a,
+                                int64_t exponent);
+no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp);
+JSBigFloat *js_new_bf(JSContext *ctx);
+void js_float_env_finalizer(JSRuntime *rt, JSValue val);
+JSValue JS_NewBigFloat(JSContext *ctx);
+static inline bf_t *JS_GetBigFloat(JSValueConst val)
+{
+  JSBigFloat *p = JS_VALUE_GET_PTR(val);
+  return &p->num;
+}
+JSValue JS_NewBigDecimal(JSContext *ctx);
+static inline bfdec_t *JS_GetBigDecimal(JSValueConst val)
+{
+  JSBigDecimal *p = JS_VALUE_GET_PTR(val);
+  return &p->num;
+}
+JSValue JS_NewBigInt(JSContext *ctx);
+static inline bf_t *JS_GetBigInt(JSValueConst val) {
+  JSBigFloat *p = JS_VALUE_GET_PTR(val);
+  return &p->num;
+}
+JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
+                          BOOL convert_to_safe_integer);
+no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp);
+JSValue JS_CompactBigInt(JSContext *ctx, JSValue val);
+int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val);
+bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val);
+__maybe_unused JSValue JS_ToBigIntValueFree(JSContext *ctx, JSValue val);
+void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf);
+bf_t *JS_ToBigFloat(JSContext *ctx, bf_t *buf, JSValueConst val);
+JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
+                            BOOL allow_null_or_undefined);
+bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val);
+
+#else
+
+no_inline __exception int js_unary_arith_slow(JSContext *ctx,
+                                                     JSValue *sp,
+                                                     OPCodeEnum op);
+__exception int js_post_inc_slow(JSContext *ctx,
+                                        JSValue *sp, OPCodeEnum op);
+no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp);
+no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
+                                                      OPCodeEnum op);
+no_inline __exception int js_binary_logic_slow(JSContext *ctx,
+                                                      JSValue *sp,
+                                                      OPCodeEnum op);
+no_inline int js_not_slow(JSContext *ctx, JSValue *sp);
+no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
+                                        OPCodeEnum op);
+no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
+                                            BOOL is_neq);
+no_inline int js_shr_slow(JSContext *ctx, JSValue *sp);
+#endif
+
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-boolean.c b/src/core/builtins/js-boolean.c
new file mode 100644
index 000000000..3343d48ea
--- /dev/null
+++ b/src/core/builtins/js-boolean.c
@@ -0,0 +1,67 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-boolean.h"
+#include "../exception.h"
+#include "../object.h"
+
+/* Boolean */
+JSValue js_boolean_constructor(JSContext* ctx, JSValueConst new_target, int argc, JSValueConst* argv) {
+  JSValue val, obj;
+  val = JS_NewBool(ctx, JS_ToBool(ctx, argv[0]));
+  if (!JS_IsUndefined(new_target)) {
+    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_BOOLEAN);
+    if (!JS_IsException(obj))
+      JS_SetObjectData(ctx, obj, val);
+    return obj;
+  } else {
+    return val;
+  }
+}
+
+JSValue js_thisBooleanValue(JSContext* ctx, JSValueConst this_val) {
+  if (JS_VALUE_GET_TAG(this_val) == JS_TAG_BOOL)
+    return JS_DupValue(ctx, this_val);
+
+  if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
+    JSObject* p = JS_VALUE_GET_OBJ(this_val);
+    if (p->class_id == JS_CLASS_BOOLEAN) {
+      if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_BOOL)
+        return p->u.object_data;
+    }
+  }
+  return JS_ThrowTypeError(ctx, "not a boolean");
+}
+
+JSValue js_boolean_toString(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue val = js_thisBooleanValue(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ? JS_ATOM_true : JS_ATOM_false);
+}
+
+JSValue js_boolean_valueOf(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  return js_thisBooleanValue(ctx, this_val);
+}
diff --git a/src/core/builtins/js-boolean.h b/src/core/builtins/js-boolean.h
new file mode 100644
index 000000000..a3bce2d63
--- /dev/null
+++ b/src/core/builtins/js-boolean.h
@@ -0,0 +1,36 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_BOOLEAN_H
+#define QUICKJS_JS_BOOLEAN_H
+
+#include "quickjs/quickjs.h"
+
+JSValue js_boolean_constructor(JSContext* ctx, JSValueConst new_target, int argc, JSValueConst* argv);
+JSValue js_thisBooleanValue(JSContext* ctx, JSValueConst this_val);
+JSValue js_boolean_toString(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_boolean_valueOf(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-closures.c b/src/core/builtins/js-closures.c
new file mode 100644
index 000000000..9f844e5b8
--- /dev/null
+++ b/src/core/builtins/js-closures.c
@@ -0,0 +1,195 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-closures.h"
+#include "../gc.h"
+#include "../object.h"
+#include "js-function.h"
+#include "quickjs/list.h"
+
+JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf,
+                             int var_idx, BOOL is_arg)
+{
+  JSVarRef *var_ref;
+  struct list_head *el;
+
+  list_for_each(el, &sf->var_ref_list) {
+    var_ref = list_entry(el, JSVarRef, header.link);
+    if (var_ref->var_idx == var_idx && var_ref->is_arg == is_arg) {
+      var_ref->header.ref_count++;
+      return var_ref;
+    }
+  }
+  /* create a new one */
+  var_ref = js_malloc(ctx, sizeof(JSVarRef));
+  if (!var_ref)
+    return NULL;
+  var_ref->header.ref_count = 1;
+  var_ref->is_detached = FALSE;
+  var_ref->is_arg = is_arg;
+  var_ref->var_idx = var_idx;
+  list_add_tail(&var_ref->header.link, &sf->var_ref_list);
+  if (is_arg)
+    var_ref->pvalue = &sf->arg_buf[var_idx];
+  else
+    var_ref->pvalue = &sf->var_buf[var_idx];
+  var_ref->value = JS_UNDEFINED;
+  return var_ref;
+}
+
+JSValue js_closure2(JSContext *ctx, JSValue func_obj,
+                           JSFunctionBytecode *b,
+                           JSVarRef **cur_var_refs,
+                           JSStackFrame *sf)
+{
+  JSObject *p;
+  JSVarRef **var_refs;
+  int i;
+
+  p = JS_VALUE_GET_OBJ(func_obj);
+  p->u.func.function_bytecode = b;
+  p->u.func.home_object = NULL;
+  p->u.func.var_refs = NULL;
+  if (b->closure_var_count) {
+    var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count);
+    if (!var_refs)
+      goto fail;
+    p->u.func.var_refs = var_refs;
+    for(i = 0; i < b->closure_var_count; i++) {
+      JSClosureVar *cv = &b->closure_var[i];
+      JSVarRef *var_ref;
+      if (cv->is_local) {
+        /* reuse the existing variable reference if it already exists */
+        var_ref = get_var_ref(ctx, sf, cv->var_idx, cv->is_arg);
+        if (!var_ref)
+          goto fail;
+      } else {
+        var_ref = cur_var_refs[cv->var_idx];
+        var_ref->header.ref_count++;
+      }
+      var_refs[i] = var_ref;
+    }
+  }
+  return func_obj;
+fail:
+  /* bfunc is freed when func_obj is freed */
+  JS_FreeValue(ctx, func_obj);
+  return JS_EXCEPTION;
+}
+
+
+JSValue js_closure(JSContext *ctx, JSValue bfunc,
+                          JSVarRef **cur_var_refs,
+                          JSStackFrame *sf)
+{
+  JSFunctionBytecode *b;
+  JSValue func_obj;
+  JSAtom name_atom;
+
+  b = JS_VALUE_GET_PTR(bfunc);
+  func_obj = JS_NewObjectClass(ctx, func_kind_to_class_id[b->func_kind]);
+  if (JS_IsException(func_obj)) {
+    JS_FreeValue(ctx, bfunc);
+    return JS_EXCEPTION;
+  }
+  func_obj = js_closure2(ctx, func_obj, b, cur_var_refs, sf);
+  if (JS_IsException(func_obj)) {
+    /* bfunc has been freed */
+    goto fail;
+  }
+  name_atom = b->func_name;
+  if (name_atom == JS_ATOM_NULL)
+    name_atom = JS_ATOM_empty_string;
+  js_function_set_properties(ctx, func_obj, name_atom,
+                             b->defined_arg_count);
+
+  if (b->func_kind & JS_FUNC_GENERATOR) {
+    JSValue proto;
+    int proto_class_id;
+    /* generators have a prototype field which is used as
+       prototype for the generator object */
+    if (b->func_kind == JS_FUNC_ASYNC_GENERATOR)
+      proto_class_id = JS_CLASS_ASYNC_GENERATOR;
+    else
+      proto_class_id = JS_CLASS_GENERATOR;
+    proto = JS_NewObjectProto(ctx, ctx->class_proto[proto_class_id]);
+    if (JS_IsException(proto))
+      goto fail;
+    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype, proto,
+                           JS_PROP_WRITABLE);
+  } else if (b->has_prototype) {
+    /* add the 'prototype' property: delay instantiation to avoid
+       creating cycles for every javascript function. The prototype
+       object is created on the fly when first accessed */
+    JS_SetConstructorBit(ctx, func_obj, TRUE);
+    JS_DefineAutoInitProperty(ctx, func_obj, JS_ATOM_prototype,
+                              JS_AUTOINIT_ID_PROTOTYPE, NULL,
+                              JS_PROP_WRITABLE);
+  }
+  return func_obj;
+fail:
+  /* bfunc is freed when func_obj is freed */
+  JS_FreeValue(ctx, func_obj);
+  return JS_EXCEPTION;
+}
+
+void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int idx, int is_arg)
+{
+  struct list_head *el, *el1;
+  JSVarRef *var_ref;
+  int var_idx = idx;
+
+  list_for_each_safe(el, el1, &sf->var_ref_list) {
+    var_ref = list_entry(el, JSVarRef, header.link);
+    if (var_idx == var_ref->var_idx && var_ref->is_arg == is_arg) {
+      var_ref->value = JS_DupValue(ctx, sf->var_buf[var_idx]);
+      var_ref->pvalue = &var_ref->value;
+      list_del(&var_ref->header.link);
+      /* the reference is no longer to a local variable */
+      var_ref->is_detached = TRUE;
+      add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
+    }
+  }
+}
+
+
+void close_var_refs(JSRuntime* rt, JSStackFrame* sf) {
+  struct list_head *el, *el1;
+  JSVarRef* var_ref;
+  int var_idx;
+
+  list_for_each_safe(el, el1, &sf->var_ref_list) {
+    var_ref = list_entry(el, JSVarRef, header.link);
+    var_idx = var_ref->var_idx;
+    if (var_ref->is_arg)
+      var_ref->value = JS_DupValueRT(rt, sf->arg_buf[var_idx]);
+    else
+      var_ref->value = JS_DupValueRT(rt, sf->var_buf[var_idx]);
+    var_ref->pvalue = &var_ref->value;
+    /* the reference is no longer to a local variable */
+    var_ref->is_detached = TRUE;
+    add_gc_object(rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
+  }
+}
\ No newline at end of file
diff --git a/src/core/builtins/js-closures.h b/src/core/builtins/js-closures.h
new file mode 100644
index 000000000..ff4d24d1b
--- /dev/null
+++ b/src/core/builtins/js-closures.h
@@ -0,0 +1,49 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_CLOSURES_H
+#define QUICKJS_JS_CLOSURES_H
+
+#include "quickjs/quickjs.h"
+#include "quickjs/cutils.h"
+#include "../types.h"
+
+void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int idx, int is_arg);
+
+JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf,
+                             int var_idx, BOOL is_arg);
+
+JSValue js_closure2(JSContext *ctx, JSValue func_obj,
+                           JSFunctionBytecode *b,
+                           JSVarRef **cur_var_refs,
+                           JSStackFrame *sf);
+
+JSValue js_closure(JSContext *ctx, JSValue bfunc,
+                          JSVarRef **cur_var_refs,
+                          JSStackFrame *sf);
+
+void close_var_refs(JSRuntime* rt, JSStackFrame* sf);
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-date.c b/src/core/builtins/js-date.c
new file mode 100644
index 000000000..3c4792bfe
--- /dev/null
+++ b/src/core/builtins/js-date.c
@@ -0,0 +1,970 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-date.h"
+#include "../convertion.h"
+#include "../exception.h"
+#include "../function.h"
+#include "../object.h"
+#include "../runtime.h"
+#include "../string.h"
+#include "js-object.h"
+
+/* Date */
+
+int64_t math_mod(int64_t a, int64_t b) {
+  /* return positive modulo */
+  int64_t m = a % b;
+  return m + (m < 0) * b;
+}
+
+int64_t floor_div(int64_t a, int64_t b) {
+  /* integer division rounding toward -Infinity */
+  int64_t m = a % b;
+  return (a - (m + (m < 0) * b)) / b;
+}
+
+#if 0
+/* OS dependent: return the UTC time in ms since 1970. */
+JSValue js___date_now(JSContext *ctx, JSValueConst this_val,
+                             int argc, JSValueConst *argv)
+{
+    int64_t d;
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    d = (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
+    return JS_NewInt64(ctx, d);
+}
+#endif
+
+/* OS dependent. d = argv[0] is in ms from 1970. Return the difference
+   between UTC time and local time 'd' in minutes */
+int getTimezoneOffset(int64_t time) {
+#if defined(_WIN32)
+  /* XXX: TODO */
+  return 0;
+#else
+  time_t ti;
+  struct tm tm;
+
+  time /= 1000; /* convert to seconds */
+  if (sizeof(time_t) == 4) {
+    /* on 32-bit systems, we need to clamp the time value to the
+       range of `time_t`. This is better than truncating values to
+       32 bits and hopefully provides the same result as 64-bit
+       implementation of localtime_r.
+     */
+    if ((time_t)-1 < 0) {
+      if (time < INT32_MIN) {
+        time = INT32_MIN;
+      } else if (time > INT32_MAX) {
+        time = INT32_MAX;
+      }
+    } else {
+      if (time < 0) {
+        time = 0;
+      } else if (time > UINT32_MAX) {
+        time = UINT32_MAX;
+      }
+    }
+  }
+  ti = time;
+  localtime_r(&ti, &tm);
+  return -tm.tm_gmtoff / 60;
+#endif
+}
+
+/* OS dependent: return the UTC time in microseconds since 1970. */
+JSValue js___date_clock(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  int64_t d;
+  struct timeval tv;
+  gettimeofday(&tv, NULL);
+  d = (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
+  return JS_NewInt64(ctx, d);
+}
+
+__exception int JS_ThisTimeValue(JSContext* ctx, double* valp, JSValueConst this_val) {
+  if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
+    JSObject* p = JS_VALUE_GET_OBJ(this_val);
+    if (p->class_id == JS_CLASS_DATE && JS_IsNumber(p->u.object_data))
+      return JS_ToFloat64(ctx, valp, p->u.object_data);
+  }
+  JS_ThrowTypeError(ctx, "not a Date object");
+  return -1;
+}
+
+JSValue JS_SetThisTimeValue(JSContext* ctx, JSValueConst this_val, double v) {
+  if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
+    JSObject* p = JS_VALUE_GET_OBJ(this_val);
+    if (p->class_id == JS_CLASS_DATE) {
+      JS_FreeValue(ctx, p->u.object_data);
+      p->u.object_data = JS_NewFloat64(ctx, v);
+      return JS_DupValue(ctx, p->u.object_data);
+    }
+  }
+  return JS_ThrowTypeError(ctx, "not a Date object");
+}
+
+int64_t days_from_year(int64_t y) {
+  return 365 * (y - 1970) + floor_div(y - 1969, 4) - floor_div(y - 1901, 100) + floor_div(y - 1601, 400);
+}
+
+int64_t days_in_year(int64_t y) {
+  return 365 + !(y % 4) - !(y % 100) + !(y % 400);
+}
+
+/* return the year, update days */
+int64_t year_from_days(int64_t* days) {
+  int64_t y, d1, nd, d = *days;
+  y = floor_div(d * 10000, 3652425) + 1970;
+  /* the initial approximation is very good, so only a few
+     iterations are necessary */
+  for (;;) {
+    d1 = d - days_from_year(y);
+    if (d1 < 0) {
+      y--;
+      d1 += days_in_year(y);
+    } else {
+      nd = days_in_year(y);
+      if (d1 < nd)
+        break;
+      d1 -= nd;
+      y++;
+    }
+  }
+  *days = d1;
+  return y;
+}
+
+int const month_days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+char const month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
+char const day_names[] = "SunMonTueWedThuFriSat";
+
+__exception int get_date_fields(JSContext* ctx, JSValueConst obj, double fields[9], int is_local, int force) {
+  double dval;
+  int64_t d, days, wd, y, i, md, h, m, s, ms, tz = 0;
+
+  if (JS_ThisTimeValue(ctx, &dval, obj))
+    return -1;
+
+  if (isnan(dval)) {
+    if (!force)
+      return FALSE; /* NaN */
+    d = 0;          /* initialize all fields to 0 */
+  } else {
+    d = dval;
+    if (is_local) {
+      tz = -getTimezoneOffset(d);
+      d += tz * 60000;
+    }
+  }
+
+  /* result is >= 0, we can use % */
+  h = math_mod(d, 86400000);
+  days = (d - h) / 86400000;
+  ms = h % 1000;
+  h = (h - ms) / 1000;
+  s = h % 60;
+  h = (h - s) / 60;
+  m = h % 60;
+  h = (h - m) / 60;
+  wd = math_mod(days + 4, 7); /* week day */
+  y = year_from_days(&days);
+
+  for (i = 0; i < 11; i++) {
+    md = month_days[i];
+    if (i == 1)
+      md += days_in_year(y) - 365;
+    if (days < md)
+      break;
+    days -= md;
+  }
+  fields[0] = y;
+  fields[1] = i;
+  fields[2] = days + 1;
+  fields[3] = h;
+  fields[4] = m;
+  fields[5] = s;
+  fields[6] = ms;
+  fields[7] = wd;
+  fields[8] = tz;
+  return TRUE;
+}
+
+double time_clip(double t) {
+  if (t >= -8.64e15 && t <= 8.64e15)
+    return trunc(t) + 0.0; /* convert -0 to +0 */
+  else
+    return NAN;
+}
+
+/* The spec mandates the use of 'double' and it fixes the order
+   of the operations */
+double set_date_fields(double fields[], int is_local) {
+  int64_t y;
+  double days, d, h, m1;
+  int i, m, md;
+
+  m1 = fields[1];
+  m = fmod(m1, 12);
+  if (m < 0)
+    m += 12;
+  y = (int64_t)(fields[0] + floor(m1 / 12));
+  days = days_from_year(y);
+
+  for (i = 0; i < m; i++) {
+    md = month_days[i];
+    if (i == 1)
+      md += days_in_year(y) - 365;
+    days += md;
+  }
+  days += fields[2] - 1;
+  h = fields[3] * 3600000 + fields[4] * 60000 + fields[5] * 1000 + fields[6];
+  d = days * 86400000 + h;
+  if (is_local)
+    d += getTimezoneOffset(d) * 60000;
+  return time_clip(d);
+}
+
+JSValue get_date_field(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic) {
+  // get_date_field(obj, n, is_local)
+  double fields[9];
+  int res, n, is_local;
+
+  is_local = magic & 0x0F;
+  n = (magic >> 4) & 0x0F;
+  res = get_date_fields(ctx, this_val, fields, is_local, 0);
+  if (res < 0)
+    return JS_EXCEPTION;
+  if (!res)
+    return JS_NAN;
+
+  if (magic & 0x100) {  // getYear
+    fields[0] -= 1900;
+  }
+  return JS_NewFloat64(ctx, fields[n]);
+}
+
+JSValue set_date_field(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic) {
+  // _field(obj, first_field, end_field, args, is_local)
+  double fields[9];
+  int res, first_field, end_field, is_local, i, n;
+  double d, a;
+
+  d = NAN;
+  first_field = (magic >> 8) & 0x0F;
+  end_field = (magic >> 4) & 0x0F;
+  is_local = magic & 0x0F;
+
+  res = get_date_fields(ctx, this_val, fields, is_local, first_field == 0);
+  if (res < 0)
+    return JS_EXCEPTION;
+  if (res && argc > 0) {
+    n = end_field - first_field;
+    if (argc < n)
+      n = argc;
+    for (i = 0; i < n; i++) {
+      if (JS_ToFloat64(ctx, &a, argv[i]))
+        return JS_EXCEPTION;
+      if (!isfinite(a))
+        goto done;
+      fields[first_field + i] = trunc(a);
+    }
+    d = set_date_fields(fields, is_local);
+  }
+done:
+  return JS_SetThisTimeValue(ctx, this_val, d);
+}
+
+/* fmt:
+   0: toUTCString: "Tue, 02 Jan 2018 23:04:46 GMT"
+   1: toString: "Wed Jan 03 2018 00:05:22 GMT+0100 (CET)"
+   2: toISOString: "2018-01-02T23:02:56.927Z"
+   3: toLocaleString: "1/2/2018, 11:40:40 PM"
+   part: 1=date, 2=time 3=all
+   XXX: should use a variant of strftime().
+ */
+JSValue get_date_string(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic) {
+  // _string(obj, fmt, part)
+  char buf[64];
+  double fields[9];
+  int res, fmt, part, pos;
+  int y, mon, d, h, m, s, ms, wd, tz;
+
+  fmt = (magic >> 4) & 0x0F;
+  part = magic & 0x0F;
+
+  res = get_date_fields(ctx, this_val, fields, fmt & 1, 0);
+  if (res < 0)
+    return JS_EXCEPTION;
+  if (!res) {
+    if (fmt == 2)
+      return JS_ThrowRangeError(ctx, "Date value is NaN");
+    else
+      return JS_NewString(ctx, "Invalid Date");
+  }
+
+  y = fields[0];
+  mon = fields[1];
+  d = fields[2];
+  h = fields[3];
+  m = fields[4];
+  s = fields[5];
+  ms = fields[6];
+  wd = fields[7];
+  tz = fields[8];
+
+  pos = 0;
+
+  if (part & 1) { /* date part */
+    switch (fmt) {
+      case 0:
+        pos += snprintf(buf + pos, sizeof(buf) - pos, "%.3s, %02d %.3s %0*d ", day_names + wd * 3, d, month_names + mon * 3, 4 + (y < 0), y);
+        break;
+      case 1:
+        pos += snprintf(buf + pos, sizeof(buf) - pos, "%.3s %.3s %02d %0*d", day_names + wd * 3, month_names + mon * 3, d, 4 + (y < 0), y);
+        if (part == 3) {
+          buf[pos++] = ' ';
+        }
+        break;
+      case 2:
+        if (y >= 0 && y <= 9999) {
+          pos += snprintf(buf + pos, sizeof(buf) - pos, "%04d", y);
+        } else {
+          pos += snprintf(buf + pos, sizeof(buf) - pos, "%+07d", y);
+        }
+        pos += snprintf(buf + pos, sizeof(buf) - pos, "-%02d-%02dT", mon + 1, d);
+        break;
+      case 3:
+        pos += snprintf(buf + pos, sizeof(buf) - pos, "%02d/%02d/%0*d", mon + 1, d, 4 + (y < 0), y);
+        if (part == 3) {
+          buf[pos++] = ',';
+          buf[pos++] = ' ';
+        }
+        break;
+    }
+  }
+  if (part & 2) { /* time part */
+    switch (fmt) {
+      case 0:
+        pos += snprintf(buf + pos, sizeof(buf) - pos, "%02d:%02d:%02d GMT", h, m, s);
+        break;
+      case 1:
+        pos += snprintf(buf + pos, sizeof(buf) - pos, "%02d:%02d:%02d GMT", h, m, s);
+        if (tz < 0) {
+          buf[pos++] = '-';
+          tz = -tz;
+        } else {
+          buf[pos++] = '+';
+        }
+        /* tz is >= 0, can use % */
+        pos += snprintf(buf + pos, sizeof(buf) - pos, "%02d%02d", tz / 60, tz % 60);
+        /* XXX: tack the time zone code? */
+        break;
+      case 2:
+        pos += snprintf(buf + pos, sizeof(buf) - pos, "%02d:%02d:%02d.%03dZ", h, m, s, ms);
+        break;
+      case 3:
+        pos += snprintf(buf + pos, sizeof(buf) - pos, "%02d:%02d:%02d %cM", (h + 1) % 12 - 1, m, s, (h < 12) ? 'A' : 'P');
+        break;
+    }
+  }
+  return JS_NewStringLen(ctx, buf, pos);
+}
+
+/* OS dependent: return the UTC time in ms since 1970. */
+int64_t date_now(void) {
+  struct timeval tv;
+  gettimeofday(&tv, NULL);
+  return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
+}
+
+JSValue js_date_constructor(JSContext* ctx, JSValueConst new_target, int argc, JSValueConst* argv) {
+  // Date(y, mon, d, h, m, s, ms)
+  JSValue rv;
+  int i, n;
+  double a, val;
+
+  if (JS_IsUndefined(new_target)) {
+    /* invoked as function */
+    argc = 0;
+  }
+  n = argc;
+  if (n == 0) {
+    val = date_now();
+  } else if (n == 1) {
+    JSValue v, dv;
+    if (JS_VALUE_GET_TAG(argv[0]) == JS_TAG_OBJECT) {
+      JSObject* p = JS_VALUE_GET_OBJ(argv[0]);
+      if (p->class_id == JS_CLASS_DATE && JS_IsNumber(p->u.object_data)) {
+        if (JS_ToFloat64(ctx, &val, p->u.object_data))
+          return JS_EXCEPTION;
+        val = time_clip(val);
+        goto has_val;
+      }
+    }
+    v = JS_ToPrimitive(ctx, argv[0], HINT_NONE);
+    if (JS_IsString(v)) {
+      dv = js_Date_parse(ctx, JS_UNDEFINED, 1, (JSValueConst*)&v);
+      JS_FreeValue(ctx, v);
+      if (JS_IsException(dv))
+        return JS_EXCEPTION;
+      if (JS_ToFloat64Free(ctx, &val, dv))
+        return JS_EXCEPTION;
+    } else {
+      if (JS_ToFloat64Free(ctx, &val, v))
+        return JS_EXCEPTION;
+    }
+    val = time_clip(val);
+  } else {
+    double fields[] = {0, 0, 1, 0, 0, 0, 0};
+    if (n > 7)
+      n = 7;
+    for (i = 0; i < n; i++) {
+      if (JS_ToFloat64(ctx, &a, argv[i]))
+        return JS_EXCEPTION;
+      if (!isfinite(a))
+        break;
+      fields[i] = trunc(a);
+      if (i == 0 && fields[0] >= 0 && fields[0] < 100)
+        fields[0] += 1900;
+    }
+    val = (i == n) ? set_date_fields(fields, 1) : NAN;
+  }
+has_val:
+#if 0
+    JSValueConst args[3];
+    args[0] = new_target;
+    args[1] = ctx->class_proto[JS_CLASS_DATE];
+    args[2] = JS_NewFloat64(ctx, val);
+    rv = js___date_create(ctx, JS_UNDEFINED, 3, args);
+#else
+  rv = js_create_from_ctor(ctx, new_target, JS_CLASS_DATE);
+  if (!JS_IsException(rv))
+    JS_SetObjectData(ctx, rv, JS_NewFloat64(ctx, val));
+#endif
+  if (!JS_IsException(rv) && JS_IsUndefined(new_target)) {
+    /* invoked as a function, return (new Date()).toString(); */
+    JSValue s;
+    s = get_date_string(ctx, rv, 0, NULL, 0x13);
+    JS_FreeValue(ctx, rv);
+    rv = s;
+  }
+  return rv;
+}
+
+JSValue js_Date_UTC(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  // UTC(y, mon, d, h, m, s, ms)
+  double fields[] = {0, 0, 1, 0, 0, 0, 0};
+  int i, n;
+  double a;
+
+  n = argc;
+  if (n == 0)
+    return JS_NAN;
+  if (n > 7)
+    n = 7;
+  for (i = 0; i < n; i++) {
+    if (JS_ToFloat64(ctx, &a, argv[i]))
+      return JS_EXCEPTION;
+    if (!isfinite(a))
+      return JS_NAN;
+    fields[i] = trunc(a);
+    if (i == 0 && fields[0] >= 0 && fields[0] < 100)
+      fields[0] += 1900;
+  }
+  return JS_NewFloat64(ctx, set_date_fields(fields, 0));
+}
+
+void string_skip_spaces(JSString* sp, int* pp) {
+  while (*pp < sp->len && string_get(sp, *pp) == ' ')
+    *pp += 1;
+}
+
+void string_skip_non_spaces(JSString* sp, int* pp) {
+  while (*pp < sp->len && string_get(sp, *pp) != ' ')
+    *pp += 1;
+}
+
+/* parse a numeric field with an optional sign if accept_sign is TRUE */
+int string_get_digits(JSString* sp, int* pp, int64_t* pval) {
+  int64_t v = 0;
+  int c, p = *pp, p_start;
+
+  if (p >= sp->len)
+    return -1;
+  p_start = p;
+  while (p < sp->len) {
+    c = string_get(sp, p);
+    if (!(c >= '0' && c <= '9')) {
+      if (p == p_start)
+        return -1;
+      else
+        break;
+    }
+    v = v * 10 + c - '0';
+    p++;
+  }
+  *pval = v;
+  *pp = p;
+  return 0;
+}
+
+int string_get_signed_digits(JSString* sp, int* pp, int64_t* pval) {
+  int res, sgn, p = *pp;
+
+  if (p >= sp->len)
+    return -1;
+
+  sgn = string_get(sp, p);
+  if (sgn == '-' || sgn == '+')
+    p++;
+
+  res = string_get_digits(sp, &p, pval);
+  if (res == 0 && sgn == '-')
+    *pval = -*pval;
+  *pp = p;
+  return res;
+}
+
+/* parse a fixed width numeric field */
+int string_get_fixed_width_digits(JSString* sp, int* pp, int n, int64_t* pval) {
+  int64_t v = 0;
+  int i, c, p = *pp;
+
+  for (i = 0; i < n; i++) {
+    if (p >= sp->len)
+      return -1;
+    c = string_get(sp, p);
+    if (!(c >= '0' && c <= '9'))
+      return -1;
+    v = v * 10 + c - '0';
+    p++;
+  }
+  *pval = v;
+  *pp = p;
+  return 0;
+}
+
+int string_get_milliseconds(JSString* sp, int* pp, int64_t* pval) {
+  /* parse milliseconds as a fractional part, round to nearest */
+  /* XXX: the spec does not indicate which rounding should be used */
+  int mul = 1000, ms = 0, p = *pp, c, p_start;
+  if (p >= sp->len)
+    return -1;
+  p_start = p;
+  while (p < sp->len) {
+    c = string_get(sp, p);
+    if (!(c >= '0' && c <= '9')) {
+      if (p == p_start)
+        return -1;
+      else
+        break;
+    }
+    if (mul == 1 && c >= '5')
+      ms += 1;
+    ms += (c - '0') * (mul /= 10);
+    p++;
+  }
+  *pval = ms;
+  *pp = p;
+  return 0;
+}
+
+int find_abbrev(JSString* sp, int p, const char* list, int count) {
+  int n, i;
+
+  if (p + 3 <= sp->len) {
+    for (n = 0; n < count; n++) {
+      for (i = 0; i < 3; i++) {
+        if (string_get(sp, p + i) != month_names[n * 3 + i])
+          goto next;
+      }
+      return n;
+    next:;
+    }
+  }
+  return -1;
+}
+
+int string_get_month(JSString* sp, int* pp, int64_t* pval) {
+  int n;
+
+  string_skip_spaces(sp, pp);
+  n = find_abbrev(sp, *pp, month_names, 12);
+  if (n < 0)
+    return -1;
+
+  *pval = n;
+  *pp += 3;
+  return 0;
+}
+
+JSValue js_Date_parse(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  // parse(s)
+  JSValue s, rv;
+  int64_t fields[] = {0, 1, 1, 0, 0, 0, 0};
+  double fields1[7];
+  int64_t tz, hh, mm;
+  double d;
+  int p, i, c, sgn, l;
+  JSString* sp;
+  BOOL is_local;
+
+  rv = JS_NAN;
+
+  s = JS_ToString(ctx, argv[0]);
+  if (JS_IsException(s))
+    return JS_EXCEPTION;
+
+  sp = JS_VALUE_GET_STRING(s);
+  p = 0;
+  if (p < sp->len && (((c = string_get(sp, p)) >= '0' && c <= '9') || c == '+' || c == '-')) {
+    /* ISO format */
+    /* year field can be negative */
+    if (string_get_signed_digits(sp, &p, &fields[0]))
+      goto done;
+
+    for (i = 1; i < 7; i++) {
+      if (p >= sp->len)
+        break;
+      switch (i) {
+        case 1:
+        case 2:
+          c = '-';
+          break;
+        case 3:
+          c = 'T';
+          break;
+        case 4:
+        case 5:
+          c = ':';
+          break;
+        case 6:
+          c = '.';
+          break;
+      }
+      if (string_get(sp, p) != c)
+        break;
+      p++;
+      if (i == 6) {
+        if (string_get_milliseconds(sp, &p, &fields[i]))
+          goto done;
+      } else {
+        if (string_get_digits(sp, &p, &fields[i]))
+          goto done;
+      }
+    }
+    /* no time: UTC by default */
+    is_local = (i > 3);
+    fields[1] -= 1;
+
+    /* parse the time zone offset if present: [+-]HH:mm or [+-]HHmm */
+    tz = 0;
+    if (p < sp->len) {
+      sgn = string_get(sp, p);
+      if (sgn == '+' || sgn == '-') {
+        p++;
+        l = sp->len - p;
+        if (l != 4 && l != 5)
+          goto done;
+        if (string_get_fixed_width_digits(sp, &p, 2, &hh))
+          goto done;
+        if (l == 5) {
+          if (string_get(sp, p) != ':')
+            goto done;
+          p++;
+        }
+        if (string_get_fixed_width_digits(sp, &p, 2, &mm))
+          goto done;
+        tz = hh * 60 + mm;
+        if (sgn == '-')
+          tz = -tz;
+        is_local = FALSE;
+      } else if (sgn == 'Z') {
+        p++;
+        is_local = FALSE;
+      } else {
+        goto done;
+      }
+      /* error if extraneous characters */
+      if (p != sp->len)
+        goto done;
+    }
+  } else {
+    /* toString or toUTCString format */
+    /* skip the day of the week */
+    string_skip_non_spaces(sp, &p);
+    string_skip_spaces(sp, &p);
+    if (p >= sp->len)
+      goto done;
+    c = string_get(sp, p);
+    if (c >= '0' && c <= '9') {
+      /* day of month first */
+      if (string_get_digits(sp, &p, &fields[2]))
+        goto done;
+      if (string_get_month(sp, &p, &fields[1]))
+        goto done;
+    } else {
+      /* month first */
+      if (string_get_month(sp, &p, &fields[1]))
+        goto done;
+      string_skip_spaces(sp, &p);
+      if (string_get_digits(sp, &p, &fields[2]))
+        goto done;
+    }
+    /* year */
+    string_skip_spaces(sp, &p);
+    if (string_get_signed_digits(sp, &p, &fields[0]))
+      goto done;
+
+    /* hour, min, seconds */
+    string_skip_spaces(sp, &p);
+    for (i = 0; i < 3; i++) {
+      if (i == 1 || i == 2) {
+        if (p >= sp->len)
+          goto done;
+        if (string_get(sp, p) != ':')
+          goto done;
+        p++;
+      }
+      if (string_get_digits(sp, &p, &fields[3 + i]))
+        goto done;
+    }
+    // XXX: parse optional milliseconds?
+
+    /* parse the time zone offset if present: [+-]HHmm */
+    is_local = FALSE;
+    tz = 0;
+    for (tz = 0; p < sp->len; p++) {
+      sgn = string_get(sp, p);
+      if (sgn == '+' || sgn == '-') {
+        p++;
+        if (string_get_fixed_width_digits(sp, &p, 2, &hh))
+          goto done;
+        if (string_get_fixed_width_digits(sp, &p, 2, &mm))
+          goto done;
+        tz = hh * 60 + mm;
+        if (sgn == '-')
+          tz = -tz;
+        break;
+      }
+    }
+  }
+  for (i = 0; i < 7; i++)
+    fields1[i] = fields[i];
+  d = set_date_fields(fields1, is_local) - tz * 60000;
+  rv = JS_NewFloat64(ctx, d);
+
+done:
+  JS_FreeValue(ctx, s);
+  return rv;
+}
+
+JSValue js_Date_now(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  // now()
+  return JS_NewInt64(ctx, date_now());
+}
+
+JSValue js_date_Symbol_toPrimitive(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  // Symbol_toPrimitive(hint)
+  JSValueConst obj = this_val;
+  JSAtom hint = JS_ATOM_NULL;
+  int hint_num;
+
+  if (!JS_IsObject(obj))
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+
+  if (JS_IsString(argv[0])) {
+    hint = JS_ValueToAtom(ctx, argv[0]);
+    if (hint == JS_ATOM_NULL)
+      return JS_EXCEPTION;
+    JS_FreeAtom(ctx, hint);
+  }
+  switch (hint) {
+    case JS_ATOM_number:
+#ifdef CONFIG_BIGNUM
+    case JS_ATOM_integer:
+#endif
+      hint_num = HINT_NUMBER;
+      break;
+    case JS_ATOM_string:
+    case JS_ATOM_default:
+      hint_num = HINT_STRING;
+      break;
+    default:
+      return JS_ThrowTypeError(ctx, "invalid hint");
+  }
+  return JS_ToPrimitive(ctx, obj, hint_num | HINT_FORCE_ORDINARY);
+}
+
+JSValue js_date_getTimezoneOffset(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  // getTimezoneOffset()
+  double v;
+
+  if (JS_ThisTimeValue(ctx, &v, this_val))
+    return JS_EXCEPTION;
+  if (isnan(v))
+    return JS_NAN;
+  else
+    return JS_NewInt64(ctx, getTimezoneOffset((int64_t)trunc(v)));
+}
+
+JSValue js_date_getTime(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  // getTime()
+  double v;
+
+  if (JS_ThisTimeValue(ctx, &v, this_val))
+    return JS_EXCEPTION;
+  return JS_NewFloat64(ctx, v);
+}
+
+JSValue js_date_setTime(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  // setTime(v)
+  double v;
+
+  if (JS_ThisTimeValue(ctx, &v, this_val) || JS_ToFloat64(ctx, &v, argv[0]))
+    return JS_EXCEPTION;
+  return JS_SetThisTimeValue(ctx, this_val, time_clip(v));
+}
+
+JSValue js_date_setYear(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  // setYear(y)
+  double y;
+  JSValueConst args[1];
+
+  if (JS_ThisTimeValue(ctx, &y, this_val) || JS_ToFloat64(ctx, &y, argv[0]))
+    return JS_EXCEPTION;
+  y = +y;
+  if (isfinite(y)) {
+    y = trunc(y);
+    if (y >= 0 && y < 100)
+      y += 1900;
+  }
+  args[0] = JS_NewFloat64(ctx, y);
+  return set_date_field(ctx, this_val, 1, args, 0x011);
+}
+
+JSValue js_date_toJSON(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  // toJSON(key)
+  JSValue obj, tv, method, rv;
+  double d;
+
+  rv = JS_EXCEPTION;
+  tv = JS_UNDEFINED;
+
+  obj = JS_ToObject(ctx, this_val);
+  tv = JS_ToPrimitive(ctx, obj, HINT_NUMBER);
+  if (JS_IsException(tv))
+    goto exception;
+  if (JS_IsNumber(tv)) {
+    if (JS_ToFloat64(ctx, &d, tv) < 0)
+      goto exception;
+    if (!isfinite(d)) {
+      rv = JS_NULL;
+      goto done;
+    }
+  }
+  method = JS_GetPropertyStr(ctx, obj, "toISOString");
+  if (JS_IsException(method))
+    goto exception;
+  if (!JS_IsFunction(ctx, method)) {
+    JS_ThrowTypeError(ctx, "object needs toISOString method");
+    JS_FreeValue(ctx, method);
+    goto exception;
+  }
+  rv = JS_CallFree(ctx, method, obj, 0, NULL);
+exception:
+done:
+  JS_FreeValue(ctx, obj);
+  JS_FreeValue(ctx, tv);
+  return rv;
+}
+
+const JSCFunctionListEntry js_date_funcs[] = {
+    JS_CFUNC_DEF("now", 0, js_Date_now),
+    JS_CFUNC_DEF("parse", 1, js_Date_parse),
+    JS_CFUNC_DEF("UTC", 7, js_Date_UTC),
+};
+
+const JSCFunctionListEntry js_date_proto_funcs[] = {
+    JS_CFUNC_DEF("valueOf", 0, js_date_getTime),
+    JS_CFUNC_MAGIC_DEF("toString", 0, get_date_string, 0x13),
+    JS_CFUNC_DEF("[Symbol.toPrimitive]", 1, js_date_Symbol_toPrimitive),
+    JS_CFUNC_MAGIC_DEF("toUTCString", 0, get_date_string, 0x03),
+    JS_ALIAS_DEF("toGMTString", "toUTCString"),
+    JS_CFUNC_MAGIC_DEF("toISOString", 0, get_date_string, 0x23),
+    JS_CFUNC_MAGIC_DEF("toDateString", 0, get_date_string, 0x11),
+    JS_CFUNC_MAGIC_DEF("toTimeString", 0, get_date_string, 0x12),
+    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, get_date_string, 0x33),
+    JS_CFUNC_MAGIC_DEF("toLocaleDateString", 0, get_date_string, 0x31),
+    JS_CFUNC_MAGIC_DEF("toLocaleTimeString", 0, get_date_string, 0x32),
+    JS_CFUNC_DEF("getTimezoneOffset", 0, js_date_getTimezoneOffset),
+    JS_CFUNC_DEF("getTime", 0, js_date_getTime),
+    JS_CFUNC_MAGIC_DEF("getYear", 0, get_date_field, 0x101),
+    JS_CFUNC_MAGIC_DEF("getFullYear", 0, get_date_field, 0x01),
+    JS_CFUNC_MAGIC_DEF("getUTCFullYear", 0, get_date_field, 0x00),
+    JS_CFUNC_MAGIC_DEF("getMonth", 0, get_date_field, 0x11),
+    JS_CFUNC_MAGIC_DEF("getUTCMonth", 0, get_date_field, 0x10),
+    JS_CFUNC_MAGIC_DEF("getDate", 0, get_date_field, 0x21),
+    JS_CFUNC_MAGIC_DEF("getUTCDate", 0, get_date_field, 0x20),
+    JS_CFUNC_MAGIC_DEF("getHours", 0, get_date_field, 0x31),
+    JS_CFUNC_MAGIC_DEF("getUTCHours", 0, get_date_field, 0x30),
+    JS_CFUNC_MAGIC_DEF("getMinutes", 0, get_date_field, 0x41),
+    JS_CFUNC_MAGIC_DEF("getUTCMinutes", 0, get_date_field, 0x40),
+    JS_CFUNC_MAGIC_DEF("getSeconds", 0, get_date_field, 0x51),
+    JS_CFUNC_MAGIC_DEF("getUTCSeconds", 0, get_date_field, 0x50),
+    JS_CFUNC_MAGIC_DEF("getMilliseconds", 0, get_date_field, 0x61),
+    JS_CFUNC_MAGIC_DEF("getUTCMilliseconds", 0, get_date_field, 0x60),
+    JS_CFUNC_MAGIC_DEF("getDay", 0, get_date_field, 0x71),
+    JS_CFUNC_MAGIC_DEF("getUTCDay", 0, get_date_field, 0x70),
+    JS_CFUNC_DEF("setTime", 1, js_date_setTime),
+    JS_CFUNC_MAGIC_DEF("setMilliseconds", 1, set_date_field, 0x671),
+    JS_CFUNC_MAGIC_DEF("setUTCMilliseconds", 1, set_date_field, 0x670),
+    JS_CFUNC_MAGIC_DEF("setSeconds", 2, set_date_field, 0x571),
+    JS_CFUNC_MAGIC_DEF("setUTCSeconds", 2, set_date_field, 0x570),
+    JS_CFUNC_MAGIC_DEF("setMinutes", 3, set_date_field, 0x471),
+    JS_CFUNC_MAGIC_DEF("setUTCMinutes", 3, set_date_field, 0x470),
+    JS_CFUNC_MAGIC_DEF("setHours", 4, set_date_field, 0x371),
+    JS_CFUNC_MAGIC_DEF("setUTCHours", 4, set_date_field, 0x370),
+    JS_CFUNC_MAGIC_DEF("setDate", 1, set_date_field, 0x231),
+    JS_CFUNC_MAGIC_DEF("setUTCDate", 1, set_date_field, 0x230),
+    JS_CFUNC_MAGIC_DEF("setMonth", 2, set_date_field, 0x131),
+    JS_CFUNC_MAGIC_DEF("setUTCMonth", 2, set_date_field, 0x130),
+    JS_CFUNC_DEF("setYear", 1, js_date_setYear),
+    JS_CFUNC_MAGIC_DEF("setFullYear", 3, set_date_field, 0x031),
+    JS_CFUNC_MAGIC_DEF("setUTCFullYear", 3, set_date_field, 0x030),
+    JS_CFUNC_DEF("toJSON", 1, js_date_toJSON),
+};
+
+void JS_AddIntrinsicDate(JSContext* ctx) {
+  JSValueConst obj;
+
+  /* Date */
+  ctx->class_proto[JS_CLASS_DATE] = JS_NewObject(ctx);
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_DATE], js_date_proto_funcs, countof(js_date_proto_funcs));
+  obj = JS_NewGlobalCConstructor(ctx, "Date", js_date_constructor, 7, ctx->class_proto[JS_CLASS_DATE]);
+  JS_SetPropertyFunctionList(ctx, obj, js_date_funcs, countof(js_date_funcs));
+}
\ No newline at end of file
diff --git a/src/core/builtins/js-date.h b/src/core/builtins/js-date.h
new file mode 100644
index 000000000..ad25753e4
--- /dev/null
+++ b/src/core/builtins/js-date.h
@@ -0,0 +1,81 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_DATE_H
+#define QUICKJS_JS_DATE_H
+
+#include "quickjs/quickjs.h"
+#include "../types.h"
+
+JSValue js___date_clock(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+__exception int JS_ThisTimeValue(JSContext* ctx, double* valp, JSValueConst this_val);
+JSValue JS_SetThisTimeValue(JSContext* ctx, JSValueConst this_val, double v);
+int64_t days_from_year(int64_t y);
+int64_t days_in_year(int64_t y);
+/* return the year, update days */
+int64_t year_from_days(int64_t *days);
+__exception int get_date_fields(JSContext *ctx, JSValueConst obj,
+                                       double fields[9], int is_local, int force);
+double time_clip(double t);
+/* The spec mandates the use of 'double' and it fixes the order
+   of the operations */
+double set_date_fields(double fields[], int is_local);
+JSValue get_date_field(JSContext *ctx, JSValueConst this_val,
+                              int argc, JSValueConst *argv, int magic);
+JSValue set_date_field(JSContext *ctx, JSValueConst this_val,
+                              int argc, JSValueConst *argv, int magic);
+/* fmt:
+   0: toUTCString: "Tue, 02 Jan 2018 23:04:46 GMT"
+   1: toString: "Wed Jan 03 2018 00:05:22 GMT+0100 (CET)"
+   2: toISOString: "2018-01-02T23:02:56.927Z"
+   3: toLocaleString: "1/2/2018, 11:40:40 PM"
+   part: 1=date, 2=time 3=all
+   XXX: should use a variant of strftime().
+ */
+JSValue get_date_string(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic);
+/* OS dependent: return the UTC time in ms since 1970. */
+int64_t date_now(void);
+JSValue js_date_constructor(JSContext* ctx, JSValueConst new_target, int argc, JSValueConst* argv);
+JSValue js_Date_UTC(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+void string_skip_spaces(JSString* sp, int* pp);
+void string_skip_non_spaces(JSString* sp, int* pp);
+/* parse a numeric field with an optional sign if accept_sign is TRUE */
+int string_get_digits(JSString* sp, int* pp, int64_t* pval);
+int string_get_signed_digits(JSString* sp, int* pp, int64_t* pval);
+/* parse a fixed width numeric field */
+int string_get_fixed_width_digits(JSString* sp, int* pp, int n, int64_t* pval);
+int string_get_milliseconds(JSString* sp, int* pp, int64_t* pval);
+int find_abbrev(JSString* sp, int p, const char* list, int count);
+int string_get_month(JSString* sp, int* pp, int64_t* pval);
+JSValue js_Date_parse(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_Date_now(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_date_Symbol_toPrimitive(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_date_getTimezoneOffset(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_date_getTime(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_date_setTime(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_date_setYear(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_date_toJSON(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-function.c b/src/core/builtins/js-function.c
new file mode 100644
index 000000000..875979f46
--- /dev/null
+++ b/src/core/builtins/js-function.c
@@ -0,0 +1,644 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-function.h"
+#include "../convertion.h"
+#include "../exception.h"
+#include "../function.h"
+#include "../gc.h"
+#include "../object.h"
+#include "../runtime.h"
+#include "../string.h"
+#include "../types.h"
+#include "js-closures.h"
+#include "js-operator.h"
+
+void js_c_function_finalizer(JSRuntime* rt, JSValue val) {
+  JSObject* p = JS_VALUE_GET_OBJ(val);
+
+  if (p->u.cfunc.realm)
+    JS_FreeContext(p->u.cfunc.realm);
+}
+
+void js_c_function_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func) {
+  JSObject* p = JS_VALUE_GET_OBJ(val);
+
+  if (p->u.cfunc.realm)
+    mark_func(rt, &p->u.cfunc.realm->header);
+}
+
+void js_bytecode_function_finalizer(JSRuntime* rt, JSValue val) {
+  JSObject *p1, *p = JS_VALUE_GET_OBJ(val);
+  JSFunctionBytecode* b;
+  JSVarRef** var_refs;
+  int i;
+
+  p1 = p->u.func.home_object;
+  if (p1) {
+    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, p1));
+  }
+  b = p->u.func.function_bytecode;
+  if (b) {
+    var_refs = p->u.func.var_refs;
+    if (var_refs) {
+      for (i = 0; i < b->closure_var_count; i++)
+        free_var_ref(rt, var_refs[i]);
+      js_free_rt(rt, var_refs);
+    }
+    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b));
+  }
+}
+
+void js_bytecode_function_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func) {
+  JSObject* p = JS_VALUE_GET_OBJ(val);
+  JSVarRef** var_refs = p->u.func.var_refs;
+  JSFunctionBytecode* b = p->u.func.function_bytecode;
+  int i;
+
+  if (p->u.func.home_object) {
+    JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object), mark_func);
+  }
+  if (b) {
+    if (var_refs) {
+      for (i = 0; i < b->closure_var_count; i++) {
+        JSVarRef* var_ref = var_refs[i];
+        if (var_ref && var_ref->is_detached) {
+          mark_func(rt, &var_ref->header);
+        }
+      }
+    }
+    /* must mark the function bytecode because template objects may be
+       part of a cycle */
+    JS_MarkValue(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b), mark_func);
+  }
+}
+
+void js_bound_function_finalizer(JSRuntime* rt, JSValue val) {
+  JSObject* p = JS_VALUE_GET_OBJ(val);
+  JSBoundFunction* bf = p->u.bound_function;
+  int i;
+
+  JS_FreeValueRT(rt, bf->func_obj);
+  JS_FreeValueRT(rt, bf->this_val);
+  for (i = 0; i < bf->argc; i++) {
+    JS_FreeValueRT(rt, bf->argv[i]);
+  }
+  js_free_rt(rt, bf);
+}
+
+void js_bound_function_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func) {
+  JSObject* p = JS_VALUE_GET_OBJ(val);
+  JSBoundFunction* bf = p->u.bound_function;
+  int i;
+
+  JS_MarkValue(rt, bf->func_obj, mark_func);
+  JS_MarkValue(rt, bf->this_val, mark_func);
+  for (i = 0; i < bf->argc; i++)
+    JS_MarkValue(rt, bf->argv[i], mark_func);
+}
+
+void free_arg_list(JSContext* ctx, JSValue* tab, uint32_t len) {
+  uint32_t i;
+  for (i = 0; i < len; i++) {
+    JS_FreeValue(ctx, tab[i]);
+  }
+  js_free(ctx, tab);
+}
+
+JSValue js_function_proto(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  return JS_UNDEFINED;
+}
+
+/* XXX: add a specific eval mode so that Function("}), ({") is rejected */
+JSValue js_function_constructor(JSContext* ctx,
+                                       JSValueConst new_target,
+                                       int argc,
+                                       JSValueConst* argv,
+                                       int magic) {
+  JSFunctionKindEnum func_kind = magic;
+  int i, n, ret;
+  JSValue s, proto, obj = JS_UNDEFINED;
+  StringBuffer b_s, *b = &b_s;
+
+  string_buffer_init(ctx, b, 0);
+  string_buffer_putc8(b, '(');
+
+  if (func_kind == JS_FUNC_ASYNC || func_kind == JS_FUNC_ASYNC_GENERATOR) {
+    string_buffer_puts8(b, "async ");
+  }
+  string_buffer_puts8(b, "function");
+
+  if (func_kind == JS_FUNC_GENERATOR || func_kind == JS_FUNC_ASYNC_GENERATOR) {
+    string_buffer_putc8(b, '*');
+  }
+  string_buffer_puts8(b, " anonymous(");
+
+  n = argc - 1;
+  for (i = 0; i < n; i++) {
+    if (i != 0) {
+      string_buffer_putc8(b, ',');
+    }
+    if (string_buffer_concat_value(b, argv[i]))
+      goto fail;
+  }
+  string_buffer_puts8(b, "\n) {\n");
+  if (n >= 0) {
+    if (string_buffer_concat_value(b, argv[n]))
+      goto fail;
+  }
+  string_buffer_puts8(b, "\n})");
+  s = string_buffer_end(b);
+  if (JS_IsException(s))
+    goto fail1;
+
+  obj = JS_EvalObject(ctx, ctx->global_obj, s, JS_EVAL_TYPE_INDIRECT, -1);
+  JS_FreeValue(ctx, s);
+  if (JS_IsException(obj))
+    goto fail1;
+  if (!JS_IsUndefined(new_target)) {
+    /* set the prototype */
+    proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);
+    if (JS_IsException(proto))
+      goto fail1;
+    if (!JS_IsObject(proto)) {
+      JSContext* realm;
+      JS_FreeValue(ctx, proto);
+      realm = JS_GetFunctionRealm(ctx, new_target);
+      if (!realm)
+        goto fail1;
+      proto = JS_DupValue(ctx, realm->class_proto[func_kind_to_class_id[func_kind]]);
+    }
+    ret = JS_SetPrototypeInternal(ctx, obj, proto, TRUE);
+    JS_FreeValue(ctx, proto);
+    if (ret < 0)
+      goto fail1;
+  }
+  return obj;
+
+fail:
+  string_buffer_free(b);
+fail1:
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+__exception int js_get_length32(JSContext* ctx, uint32_t* pres, JSValueConst obj) {
+  JSValue len_val;
+  len_val = JS_GetProperty(ctx, obj, JS_ATOM_length);
+  if (JS_IsException(len_val)) {
+    *pres = 0;
+    return -1;
+  }
+  return JS_ToUint32Free(ctx, pres, len_val);
+}
+
+__exception int js_get_length64(JSContext* ctx, int64_t* pres, JSValueConst obj) {
+  JSValue len_val;
+  len_val = JS_GetProperty(ctx, obj, JS_ATOM_length);
+  if (JS_IsException(len_val)) {
+    *pres = 0;
+    return -1;
+  }
+  return JS_ToLengthFree(ctx, pres, len_val);
+}
+
+/* XXX: should use ValueArray */
+JSValue* build_arg_list(JSContext* ctx, uint32_t* plen, JSValueConst array_arg) {
+  uint32_t len, i;
+  JSValue *tab, ret;
+  JSObject* p;
+
+  if (JS_VALUE_GET_TAG(array_arg) != JS_TAG_OBJECT) {
+    JS_ThrowTypeError(ctx, "not a object");
+    return NULL;
+  }
+  if (js_get_length32(ctx, &len, array_arg))
+    return NULL;
+  if (len > JS_MAX_LOCAL_VARS) {
+    JS_ThrowInternalError(ctx, "too many arguments");
+    return NULL;
+  }
+  /* avoid allocating 0 bytes */
+  tab = js_mallocz(ctx, sizeof(tab[0]) * max_uint32(1, len));
+  if (!tab)
+    return NULL;
+  p = JS_VALUE_GET_OBJ(array_arg);
+  if ((p->class_id == JS_CLASS_ARRAY || p->class_id == JS_CLASS_ARGUMENTS) && p->fast_array &&
+      len == p->u.array.count) {
+    for (i = 0; i < len; i++) {
+      tab[i] = JS_DupValue(ctx, p->u.array.u.values[i]);
+    }
+  } else {
+    for (i = 0; i < len; i++) {
+      ret = JS_GetPropertyUint32(ctx, array_arg, i);
+      if (JS_IsException(ret)) {
+        free_arg_list(ctx, tab, i);
+        return NULL;
+      }
+      tab[i] = ret;
+    }
+  }
+  *plen = len;
+  return tab;
+}
+
+void js_function_set_properties(JSContext* ctx, JSValueConst func_obj, JSAtom name, int len) {
+  /* ES6 feature non compatible with ES5.1: length is configurable */
+  JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length, JS_NewInt32(ctx, len), JS_PROP_CONFIGURABLE);
+  JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, JS_AtomToString(ctx, name), JS_PROP_CONFIGURABLE);
+}
+
+/* magic value: 0 = normal apply, 1 = apply for constructor, 2 =
+   Reflect.apply */
+JSValue js_function_apply(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic) {
+  JSValueConst this_arg, array_arg;
+  uint32_t len;
+  JSValue *tab, ret;
+
+  if (check_function(ctx, this_val))
+    return JS_EXCEPTION;
+  this_arg = argv[0];
+  array_arg = argv[1];
+  if ((JS_VALUE_GET_TAG(array_arg) == JS_TAG_UNDEFINED || JS_VALUE_GET_TAG(array_arg) == JS_TAG_NULL) && magic != 2) {
+    return JS_Call(ctx, this_val, this_arg, 0, NULL);
+  }
+  tab = build_arg_list(ctx, &len, array_arg);
+  if (!tab)
+    return JS_EXCEPTION;
+  if (magic & 1) {
+    ret = JS_CallConstructor2(ctx, this_val, this_arg, len, (JSValueConst*)tab);
+  } else {
+    ret = JS_Call(ctx, this_val, this_arg, len, (JSValueConst*)tab);
+  }
+  free_arg_list(ctx, tab, len);
+  return ret;
+}
+
+JSValue js_function_call(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  if (argc <= 0) {
+    return JS_Call(ctx, this_val, JS_UNDEFINED, 0, NULL);
+  } else {
+    return JS_Call(ctx, this_val, argv[0], argc - 1, argv + 1);
+  }
+}
+
+JSValue js_function_bind(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSBoundFunction* bf;
+  JSValue func_obj, name1, len_val;
+  JSObject* p;
+  int arg_count, i, ret;
+
+  if (check_function(ctx, this_val))
+    return JS_EXCEPTION;
+
+  func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto, JS_CLASS_BOUND_FUNCTION);
+  if (JS_IsException(func_obj))
+    return JS_EXCEPTION;
+  p = JS_VALUE_GET_OBJ(func_obj);
+  p->is_constructor = JS_IsConstructor(ctx, this_val);
+  arg_count = max_int(0, argc - 1);
+  bf = js_malloc(ctx, sizeof(*bf) + arg_count * sizeof(JSValue));
+  if (!bf)
+    goto exception;
+  bf->func_obj = JS_DupValue(ctx, this_val);
+  bf->this_val = JS_DupValue(ctx, argv[0]);
+  bf->argc = arg_count;
+  for (i = 0; i < arg_count; i++) {
+    bf->argv[i] = JS_DupValue(ctx, argv[i + 1]);
+  }
+  p->u.bound_function = bf;
+
+  /* XXX: the spec could be simpler by only using GetOwnProperty */
+  ret = JS_GetOwnProperty(ctx, NULL, this_val, JS_ATOM_length);
+  if (ret < 0)
+    goto exception;
+  if (!ret) {
+    len_val = JS_NewInt32(ctx, 0);
+  } else {
+    len_val = JS_GetProperty(ctx, this_val, JS_ATOM_length);
+    if (JS_IsException(len_val))
+      goto exception;
+    if (JS_VALUE_GET_TAG(len_val) == JS_TAG_INT) {
+      /* most common case */
+      int len1 = JS_VALUE_GET_INT(len_val);
+      if (len1 <= arg_count)
+        len1 = 0;
+      else
+        len1 -= arg_count;
+      len_val = JS_NewInt32(ctx, len1);
+    } else if (JS_VALUE_GET_NORM_TAG(len_val) == JS_TAG_FLOAT64) {
+      double d = JS_VALUE_GET_FLOAT64(len_val);
+      if (isnan(d)) {
+        d = 0.0;
+      } else {
+        d = trunc(d);
+        if (d <= (double)arg_count)
+          d = 0.0;
+        else
+          d -= (double)arg_count; /* also converts -0 to +0 */
+      }
+      len_val = JS_NewFloat64(ctx, d);
+    } else {
+      JS_FreeValue(ctx, len_val);
+      len_val = JS_NewInt32(ctx, 0);
+    }
+  }
+  JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length, len_val, JS_PROP_CONFIGURABLE);
+
+  name1 = JS_GetProperty(ctx, this_val, JS_ATOM_name);
+  if (JS_IsException(name1))
+    goto exception;
+  if (!JS_IsString(name1)) {
+    JS_FreeValue(ctx, name1);
+    name1 = JS_AtomToString(ctx, JS_ATOM_empty_string);
+  }
+  name1 = JS_ConcatString3(ctx, "bound ", name1, "");
+  if (JS_IsException(name1))
+    goto exception;
+  JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name1, JS_PROP_CONFIGURABLE);
+  return func_obj;
+exception:
+  JS_FreeValue(ctx, func_obj);
+  return JS_EXCEPTION;
+}
+
+JSValue js_function_toString(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSObject* p;
+  JSFunctionKindEnum func_kind = JS_FUNC_NORMAL;
+
+  if (check_function(ctx, this_val))
+    return JS_EXCEPTION;
+
+  p = JS_VALUE_GET_OBJ(this_val);
+  if (js_class_has_bytecode(p->class_id)) {
+    JSFunctionBytecode* b = p->u.func.function_bytecode;
+    if (b->has_debug && b->debug.source) {
+      return JS_NewStringLen(ctx, b->debug.source, b->debug.source_len);
+    }
+    func_kind = b->func_kind;
+  }
+  {
+    JSValue name;
+    const char *pref, *suff;
+
+    switch (func_kind) {
+      default:
+      case JS_FUNC_NORMAL:
+        pref = "function ";
+        break;
+      case JS_FUNC_GENERATOR:
+        pref = "function *";
+        break;
+      case JS_FUNC_ASYNC:
+        pref = "async function ";
+        break;
+      case JS_FUNC_ASYNC_GENERATOR:
+        pref = "async function *";
+        break;
+    }
+    suff = "() {\n    [native code]\n}";
+    name = JS_GetProperty(ctx, this_val, JS_ATOM_name);
+    if (JS_IsUndefined(name))
+      name = JS_AtomToString(ctx, JS_ATOM_empty_string);
+    return JS_ConcatString3(ctx, pref, name, suff);
+  }
+}
+
+JSValue js_function_hasInstance(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  int ret;
+  ret = JS_OrdinaryIsInstanceOf(ctx, argv[0], this_val);
+  if (ret < 0)
+    return JS_EXCEPTION;
+  else
+    return JS_NewBool(ctx, ret);
+}
+
+/* XXX: not 100% compatible, but mozilla seems to use a similar
+   implementation to ensure that caller in non strict mode does not
+   throw (ES5 compatibility) */
+JSValue js_function_proto_caller(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSFunctionBytecode* b = JS_GetFunctionBytecode(this_val);
+  if (!b || (b->js_mode & JS_MODE_STRICT) || !b->has_prototype) {
+    return js_throw_type_error(ctx, this_val, 0, NULL);
+  }
+  return JS_UNDEFINED;
+}
+
+JSValue js_function_proto_fileName(JSContext* ctx, JSValueConst this_val) {
+  JSFunctionBytecode* b = JS_GetFunctionBytecode(this_val);
+  if (b && b->has_debug) {
+    return JS_AtomToString(ctx, b->debug.filename);
+  }
+  return JS_UNDEFINED;
+}
+
+JSValue js_function_proto_lineNumber(JSContext* ctx, JSValueConst this_val) {
+  JSFunctionBytecode* b = JS_GetFunctionBytecode(this_val);
+  if (b && b->has_debug) {
+    return JS_NewInt32(ctx, b->debug.line_num);
+  }
+  return JS_UNDEFINED;
+}
+
+int js_arguments_define_own_property(JSContext* ctx,
+                                            JSValueConst this_obj,
+                                            JSAtom prop,
+                                            JSValueConst val,
+                                            JSValueConst getter,
+                                            JSValueConst setter,
+                                            int flags) {
+  JSObject* p;
+  uint32_t idx;
+  p = JS_VALUE_GET_OBJ(this_obj);
+  /* convert to normal array when redefining an existing numeric field */
+  if (p->fast_array && JS_AtomIsArrayIndex(ctx, &idx, prop) && idx < p->u.array.count) {
+    if (convert_fast_array_to_array(ctx, p))
+      return -1;
+  }
+  /* run the default define own property */
+  return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter, flags | JS_PROP_NO_EXOTIC);
+}
+
+JSValue js_build_arguments(JSContext* ctx, int argc, JSValueConst* argv) {
+  JSValue val, *tab;
+  JSProperty* pr;
+  JSObject* p;
+  int i;
+
+  val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_ARGUMENTS);
+  if (JS_IsException(val))
+    return val;
+  p = JS_VALUE_GET_OBJ(val);
+
+  /* add the length field (cannot fail) */
+  pr = add_property(ctx, p, JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+  pr->u.value = JS_NewInt32(ctx, argc);
+
+  /* initialize the fast array part */
+  tab = NULL;
+  if (argc > 0) {
+    tab = js_malloc(ctx, sizeof(tab[0]) * argc);
+    if (!tab) {
+      JS_FreeValue(ctx, val);
+      return JS_EXCEPTION;
+    }
+    for (i = 0; i < argc; i++) {
+      tab[i] = JS_DupValue(ctx, argv[i]);
+    }
+  }
+  p->u.array.u.values = tab;
+  p->u.array.count = argc;
+
+  JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator, JS_DupValue(ctx, ctx->array_proto_values),
+                         JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
+  /* add callee property to throw a TypeError in strict mode */
+  JS_DefineProperty(ctx, val, JS_ATOM_callee, JS_UNDEFINED, ctx->throw_type_error, ctx->throw_type_error,
+                    JS_PROP_HAS_GET | JS_PROP_HAS_SET);
+  return val;
+}
+
+/* legacy arguments object: add references to the function arguments */
+JSValue js_build_mapped_arguments(JSContext* ctx,
+                                         int argc,
+                                         JSValueConst* argv,
+                                         JSStackFrame* sf,
+                                         int arg_count) {
+  JSValue val;
+  JSProperty* pr;
+  JSObject* p;
+  int i;
+
+  val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_MAPPED_ARGUMENTS);
+  if (JS_IsException(val))
+    return val;
+  p = JS_VALUE_GET_OBJ(val);
+
+  /* add the length field (cannot fail) */
+  pr = add_property(ctx, p, JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+  pr->u.value = JS_NewInt32(ctx, argc);
+
+  for (i = 0; i < arg_count; i++) {
+    JSVarRef* var_ref;
+    var_ref = get_var_ref(ctx, sf, i, TRUE);
+    if (!var_ref)
+      goto fail;
+    pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E | JS_PROP_VARREF);
+    if (!pr) {
+      free_var_ref(ctx->rt, var_ref);
+      goto fail;
+    }
+    pr->u.var_ref = var_ref;
+  }
+
+  /* the arguments not mapped to the arguments of the function can
+     be normal properties */
+  for (i = arg_count; i < argc; i++) {
+    if (JS_DefinePropertyValueUint32(ctx, val, i, JS_DupValue(ctx, argv[i]), JS_PROP_C_W_E) < 0)
+      goto fail;
+  }
+
+  JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator, JS_DupValue(ctx, ctx->array_proto_values),
+                         JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
+  /* callee returns this function in non strict mode */
+  JS_DefinePropertyValue(ctx, val, JS_ATOM_callee, JS_DupValue(ctx, ctx->rt->current_stack_frame->cur_func),
+                         JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
+  return val;
+fail:
+  JS_FreeValue(ctx, val);
+  return JS_EXCEPTION;
+}
+
+
+/* return NULL without exception if not a function or no bytecode */
+JSFunctionBytecode *JS_GetFunctionBytecode(JSValueConst val)
+{
+  JSObject *p;
+  if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
+    return NULL;
+  p = JS_VALUE_GET_OBJ(val);
+  if (!js_class_has_bytecode(p->class_id))
+    return NULL;
+  return p->u.func.function_bytecode;
+}
+
+void js_method_set_home_object(JSContext *ctx, JSValueConst func_obj,
+                                      JSValueConst home_obj)
+{
+  JSObject *p, *p1;
+  JSFunctionBytecode *b;
+
+  if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
+    return;
+  p = JS_VALUE_GET_OBJ(func_obj);
+  if (!js_class_has_bytecode(p->class_id))
+    return;
+  b = p->u.func.function_bytecode;
+  if (b->need_home_object) {
+    p1 = p->u.func.home_object;
+    if (p1) {
+      JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
+    }
+    if (JS_VALUE_GET_TAG(home_obj) == JS_TAG_OBJECT)
+      p1 = JS_VALUE_GET_OBJ(JS_DupValue(ctx, home_obj));
+    else
+      p1 = NULL;
+    p->u.func.home_object = p1;
+  }
+}
+
+JSValue js_get_function_name(JSContext *ctx, JSAtom name)
+{
+  JSValue name_str;
+
+  name_str = JS_AtomToString(ctx, name);
+  if (JS_AtomSymbolHasDescription(ctx, name)) {
+    name_str = JS_ConcatString3(ctx, "[", name_str, "]");
+  }
+  return name_str;
+}
+
+/* Modify the name of a method according to the atom and
+   'flags'. 'flags' is a bitmask of JS_PROP_HAS_GET and
+   JS_PROP_HAS_SET. Also set the home object of the method.
+   Return < 0 if exception. */
+int js_method_set_properties(JSContext *ctx, JSValueConst func_obj,
+                                    JSAtom name, int flags, JSValueConst home_obj)
+{
+  JSValue name_str;
+
+  name_str = js_get_function_name(ctx, name);
+  if (flags & JS_PROP_HAS_GET) {
+    name_str = JS_ConcatString3(ctx, "get ", name_str, "");
+  } else if (flags & JS_PROP_HAS_SET) {
+    name_str = JS_ConcatString3(ctx, "set ", name_str, "");
+  }
+  if (JS_IsException(name_str))
+    return -1;
+  if (JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name_str,
+                             JS_PROP_CONFIGURABLE) < 0)
+    return -1;
+  js_method_set_home_object(ctx, func_obj, home_obj);
+  return 0;
+}
diff --git a/src/core/builtins/js-function.h b/src/core/builtins/js-function.h
new file mode 100644
index 000000000..9f45018f9
--- /dev/null
+++ b/src/core/builtins/js-function.h
@@ -0,0 +1,114 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_FUNCTION_H
+#define QUICKJS_JS_FUNCTION_H
+
+#include "quickjs/quickjs.h"
+#include "../types.h"
+
+#define GLOBAL_VAR_OFFSET 0x40000000
+#define ARGUMENT_VAR_OFFSET 0x20000000
+
+static const uint16_t func_kind_to_class_id[] = {
+    [JS_FUNC_NORMAL] = JS_CLASS_BYTECODE_FUNCTION,
+    [JS_FUNC_GENERATOR] = JS_CLASS_GENERATOR_FUNCTION,
+    [JS_FUNC_ASYNC] = JS_CLASS_ASYNC_FUNCTION,
+    [JS_FUNC_ASYNC_GENERATOR] = JS_CLASS_ASYNC_GENERATOR_FUNCTION,
+};
+
+JSValue js_function_apply(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic);
+JSValue js_function_proto_caller(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+/* magic value: 0 = normal apply, 1 = apply for constructor, 2 =
+   Reflect.apply */
+JSValue js_function_apply(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic);
+JSValue js_function_call(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_function_bind(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_function_toString(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_function_hasInstance(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+/* XXX: not 100% compatible, but mozilla seems to use a similar
+   implementation to ensure that caller in non strict mode does not
+   throw (ES5 compatibility) */
+JSValue js_function_proto_caller(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_function_proto_fileName(JSContext* ctx, JSValueConst this_val);
+JSValue js_function_proto_lineNumber(JSContext* ctx, JSValueConst this_val);
+
+void js_c_function_finalizer(JSRuntime* rt, JSValue val);
+void js_c_function_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func);
+
+void js_bytecode_function_finalizer(JSRuntime* rt, JSValue val);
+void js_bytecode_function_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func);
+
+void js_bound_function_finalizer(JSRuntime* rt, JSValue val);
+void js_bound_function_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func);
+
+void free_arg_list(JSContext* ctx, JSValue* tab, uint32_t len);
+JSValue js_function_proto(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+
+/* XXX: add a specific eval mode so that Function("}), ({") is rejected */
+JSValue js_function_constructor(JSContext* ctx,
+                                       JSValueConst new_target,
+                                       int argc,
+                                       JSValueConst* argv,
+                                       int magic);
+__exception int js_get_length32(JSContext* ctx, uint32_t* pres, JSValueConst obj);
+__exception int js_get_length64(JSContext* ctx, int64_t* pres, JSValueConst obj);
+/* XXX: should use ValueArray */
+JSValue* build_arg_list(JSContext* ctx, uint32_t* plen, JSValueConst array_arg);
+
+void js_function_set_properties(JSContext *ctx, JSValueConst func_obj,
+                                       JSAtom name, int len);
+
+int js_arguments_define_own_property(JSContext* ctx,
+                                            JSValueConst this_obj,
+                                            JSAtom prop,
+                                            JSValueConst val,
+                                            JSValueConst getter,
+                                            JSValueConst setter,
+                                            int flags);
+JSValue js_build_arguments(JSContext* ctx, int argc, JSValueConst* argv);
+
+/* legacy arguments object: add references to the function arguments */
+JSValue js_build_mapped_arguments(JSContext* ctx,
+                                         int argc,
+                                         JSValueConst* argv,
+                                         JSStackFrame* sf,
+                                         int arg_count);
+
+/* return NULL without exception if not a function or no bytecode */
+JSFunctionBytecode *JS_GetFunctionBytecode(JSValueConst val);
+
+void js_method_set_home_object(JSContext *ctx, JSValueConst func_obj,
+                                      JSValueConst home_obj);
+JSValue js_get_function_name(JSContext *ctx, JSAtom name);
+/* Modify the name of a method according to the atom and
+   'flags'. 'flags' is a bitmask of JS_PROP_HAS_GET and
+   JS_PROP_HAS_SET. Also set the home object of the method.
+   Return < 0 if exception. */
+int js_method_set_properties(JSContext *ctx, JSValueConst func_obj,
+                                    JSAtom name, int flags, JSValueConst home_obj);
+
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-generator.c b/src/core/builtins/js-generator.c
new file mode 100644
index 000000000..400263360
--- /dev/null
+++ b/src/core/builtins/js-generator.c
@@ -0,0 +1,187 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-generator.h"
+#include "../exception.h"
+#include "../function.h"
+#include "../object.h"
+#include "js-async-function.h"
+#include "quickjs/cutils.h"
+
+/* Generators */
+void free_generator_stack_rt(JSRuntime *rt, JSGeneratorData *s)
+{
+  if (s->state == JS_GENERATOR_STATE_COMPLETED)
+    return;
+  async_func_free(rt, &s->func_state);
+  s->state = JS_GENERATOR_STATE_COMPLETED;
+}
+
+void js_generator_finalizer(JSRuntime *rt, JSValue obj)
+{
+  JSGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_GENERATOR);
+
+  if (s) {
+    free_generator_stack_rt(rt, s);
+    js_free_rt(rt, s);
+  }
+}
+
+void free_generator_stack(JSContext *ctx, JSGeneratorData *s)
+{
+  free_generator_stack_rt(ctx->rt, s);
+}
+
+void js_generator_mark(JSRuntime *rt, JSValueConst val,
+                              JS_MarkFunc *mark_func)
+{
+  JSObject *p = JS_VALUE_GET_OBJ(val);
+  JSGeneratorData *s = p->u.generator_data;
+
+  if (!s || s->state == JS_GENERATOR_STATE_COMPLETED)
+    return;
+  async_func_mark(rt, &s->func_state, mark_func);
+}
+
+JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
+                                 int argc, JSValueConst *argv,
+                                 BOOL *pdone, int magic)
+{
+  JSGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_GENERATOR);
+  JSStackFrame *sf;
+  JSValue ret, func_ret;
+
+  *pdone = TRUE;
+  if (!s)
+    return JS_ThrowTypeError(ctx, "not a generator");
+  sf = &s->func_state.frame;
+  switch(s->state) {
+    default:
+    case JS_GENERATOR_STATE_SUSPENDED_START:
+      if (magic == GEN_MAGIC_NEXT) {
+        goto exec_no_arg;
+      } else {
+        free_generator_stack(ctx, s);
+        goto done;
+      }
+      break;
+    case JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
+    case JS_GENERATOR_STATE_SUSPENDED_YIELD:
+      /* cur_sp[-1] was set to JS_UNDEFINED in the previous call */
+      ret = JS_DupValue(ctx, argv[0]);
+      if (magic == GEN_MAGIC_THROW &&
+          s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) {
+        JS_Throw(ctx, ret);
+        s->func_state.throw_flag = TRUE;
+      } else {
+        sf->cur_sp[-1] = ret;
+        sf->cur_sp[0] = JS_NewInt32(ctx, magic);
+        sf->cur_sp++;
+      exec_no_arg:
+        s->func_state.throw_flag = FALSE;
+      }
+      s->state = JS_GENERATOR_STATE_EXECUTING;
+      func_ret = async_func_resume(ctx, &s->func_state);
+      s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD;
+      if (JS_IsException(func_ret)) {
+        /* finalize the execution in case of exception */
+        free_generator_stack(ctx, s);
+        return func_ret;
+      }
+      if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) {
+        /* get the returned yield value at the top of the stack */
+        ret = sf->cur_sp[-1];
+        sf->cur_sp[-1] = JS_UNDEFINED;
+        if (JS_VALUE_GET_INT(func_ret) == FUNC_RET_YIELD_STAR) {
+          s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
+          /* return (value, done) object */
+          *pdone = 2;
+        } else {
+          *pdone = FALSE;
+        }
+      } else {
+        /* end of iterator */
+        ret = sf->cur_sp[-1];
+        sf->cur_sp[-1] = JS_UNDEFINED;
+        JS_FreeValue(ctx, func_ret);
+        free_generator_stack(ctx, s);
+      }
+      break;
+    case JS_GENERATOR_STATE_COMPLETED:
+    done:
+      /* execution is finished */
+      switch(magic) {
+        default:
+        case GEN_MAGIC_NEXT:
+          ret = JS_UNDEFINED;
+          break;
+        case GEN_MAGIC_RETURN:
+          ret = JS_DupValue(ctx, argv[0]);
+          break;
+        case GEN_MAGIC_THROW:
+          ret = JS_Throw(ctx, JS_DupValue(ctx, argv[0]));
+          break;
+      }
+      break;
+    case JS_GENERATOR_STATE_EXECUTING:
+      ret = JS_ThrowTypeError(ctx, "cannot invoke a running generator");
+      break;
+  }
+  return ret;
+}
+
+JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
+                                          JSValueConst this_obj,
+                                          int argc, JSValueConst *argv,
+                                          int flags)
+{
+  JSValue obj, func_ret;
+  JSGeneratorData *s;
+
+  s = js_mallocz(ctx, sizeof(*s));
+  if (!s)
+    return JS_EXCEPTION;
+  s->state = JS_GENERATOR_STATE_SUSPENDED_START;
+  if (async_func_init(ctx, &s->func_state, func_obj, this_obj, argc, argv)) {
+    s->state = JS_GENERATOR_STATE_COMPLETED;
+    goto fail;
+  }
+
+  /* execute the function up to 'OP_initial_yield' */
+  func_ret = async_func_resume(ctx, &s->func_state);
+  if (JS_IsException(func_ret))
+    goto fail;
+  JS_FreeValue(ctx, func_ret);
+
+  obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_GENERATOR);
+  if (JS_IsException(obj))
+    goto fail;
+  JS_SetOpaque(obj, s);
+  return obj;
+fail:
+  free_generator_stack_rt(ctx->rt, s);
+  js_free(ctx, s);
+  return JS_EXCEPTION;
+}
diff --git a/src/core/builtins/js-generator.h b/src/core/builtins/js-generator.h
new file mode 100644
index 000000000..7bd1ff9d5
--- /dev/null
+++ b/src/core/builtins/js-generator.h
@@ -0,0 +1,66 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_GENERATOR_H
+#define QUICKJS_JS_GENERATOR_H
+
+#include "quickjs/quickjs.h"
+#include "quickjs/cutils.h"
+#include "../types.h"
+
+/* XXX: use enum */
+#define GEN_MAGIC_NEXT   0
+#define GEN_MAGIC_RETURN 1
+#define GEN_MAGIC_THROW  2
+
+typedef enum JSGeneratorStateEnum {
+  JS_GENERATOR_STATE_SUSPENDED_START,
+  JS_GENERATOR_STATE_SUSPENDED_YIELD,
+  JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR,
+  JS_GENERATOR_STATE_EXECUTING,
+  JS_GENERATOR_STATE_COMPLETED,
+} JSGeneratorStateEnum;
+
+typedef struct JSGeneratorData {
+  JSGeneratorStateEnum state;
+  JSAsyncFunctionState func_state;
+} JSGeneratorData;
+
+void free_generator_stack_rt(JSRuntime *rt, JSGeneratorData *s);
+void js_generator_finalizer(JSRuntime *rt, JSValue obj);
+void free_generator_stack(JSContext *ctx, JSGeneratorData *s);
+void js_generator_mark(JSRuntime *rt, JSValueConst val,
+                              JS_MarkFunc *mark_func);
+
+JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
+                                 int argc, JSValueConst *argv,
+                                 BOOL *pdone, int magic);
+JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
+                                          JSValueConst this_obj,
+                                          int argc, JSValueConst *argv,
+                                          int flags);
+
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-json.c b/src/core/builtins/js-json.c
new file mode 100644
index 000000000..8d2bb45fd
--- /dev/null
+++ b/src/core/builtins/js-json.c
@@ -0,0 +1,738 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-json.h"
+#include "../convertion.h"
+#include "../exception.h"
+#include "../function.h"
+#include "../object.h"
+#include "../parser.h"
+#include "../runtime.h"
+#include "../string.h"
+#include "../types.h"
+#include "js-array.h"
+#include "js-function.h"
+#include "js-object.h"
+
+/* JSON */
+
+int json_parse_expect(JSParseState *s, int tok)
+{
+  if (s->token.val != tok) {
+    /* XXX: dump token correctly in all cases */
+    return js_parse_error(s, "expecting '%c'", tok);
+  }
+  return json_next_token(s);
+}
+
+JSValue json_parse_value(JSParseState *s)
+{
+  JSContext *ctx = s->ctx;
+  JSValue val = JS_NULL;
+  int ret;
+
+  switch(s->token.val) {
+    case '{':
+    {
+      JSValue prop_val;
+      JSAtom prop_name;
+
+      if (json_next_token(s))
+        goto fail;
+      val = JS_NewObject(ctx);
+      if (JS_IsException(val))
+        goto fail;
+      if (s->token.val != '}') {
+        for(;;) {
+          if (s->token.val == TOK_STRING) {
+            prop_name = JS_ValueToAtom(ctx, s->token.u.str.str);
+            if (prop_name == JS_ATOM_NULL)
+              goto fail;
+          } else if (s->ext_json && s->token.val == TOK_IDENT) {
+            prop_name = JS_DupAtom(ctx, s->token.u.ident.atom);
+          } else {
+            js_parse_error(s, "expecting property name");
+            goto fail;
+          }
+          if (json_next_token(s))
+            goto fail1;
+          if (json_parse_expect(s, ':'))
+            goto fail1;
+          prop_val = json_parse_value(s);
+          if (JS_IsException(prop_val)) {
+          fail1:
+            JS_FreeAtom(ctx, prop_name);
+            goto fail;
+          }
+          ret = JS_DefinePropertyValue(ctx, val, prop_name,
+                                       prop_val, JS_PROP_C_W_E);
+          JS_FreeAtom(ctx, prop_name);
+          if (ret < 0)
+            goto fail;
+
+          if (s->token.val != ',')
+            break;
+          if (json_next_token(s))
+            goto fail;
+          if (s->ext_json && s->token.val == '}')
+            break;
+        }
+      }
+      if (json_parse_expect(s, '}'))
+        goto fail;
+    }
+    break;
+    case '[':
+    {
+      JSValue el;
+      uint32_t idx;
+
+      if (json_next_token(s))
+        goto fail;
+      val = JS_NewArray(ctx);
+      if (JS_IsException(val))
+        goto fail;
+      if (s->token.val != ']') {
+        idx = 0;
+        for(;;) {
+          el = json_parse_value(s);
+          if (JS_IsException(el))
+            goto fail;
+          ret = JS_DefinePropertyValueUint32(ctx, val, idx, el, JS_PROP_C_W_E);
+          if (ret < 0)
+            goto fail;
+          if (s->token.val != ',')
+            break;
+          if (json_next_token(s))
+            goto fail;
+          idx++;
+          if (s->ext_json && s->token.val == ']')
+            break;
+        }
+      }
+      if (json_parse_expect(s, ']'))
+        goto fail;
+    }
+    break;
+    case TOK_STRING:
+      val = JS_DupValue(ctx, s->token.u.str.str);
+      if (json_next_token(s))
+        goto fail;
+      break;
+    case TOK_NUMBER:
+      val = s->token.u.num.val;
+      if (json_next_token(s))
+        goto fail;
+      break;
+    case TOK_IDENT:
+      if (s->token.u.ident.atom == JS_ATOM_false ||
+          s->token.u.ident.atom == JS_ATOM_true) {
+        val = JS_NewBool(ctx, (s->token.u.ident.atom == JS_ATOM_true));
+      } else if (s->token.u.ident.atom == JS_ATOM_null) {
+        val = JS_NULL;
+      } else {
+        goto def_token;
+      }
+      if (json_next_token(s))
+        goto fail;
+      break;
+    default:
+    def_token:
+      if (s->token.val == TOK_EOF) {
+        js_parse_error(s, "unexpected end of input");
+      } else {
+        js_parse_error(s, "unexpected token: '%.*s'",
+                       (int)(s->buf_ptr - s->token.ptr), s->token.ptr);
+      }
+      goto fail;
+  }
+  return val;
+fail:
+  JS_FreeValue(ctx, val);
+  return JS_EXCEPTION;
+}
+
+JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
+                      const char *filename, int flags)
+{
+  JSParseState s1, *s = &s1;
+  JSValue val = JS_UNDEFINED;
+
+  js_parse_init(ctx, s, buf, buf_len, filename);
+  s->ext_json = ((flags & JS_PARSE_JSON_EXT) != 0);
+  if (json_next_token(s))
+    goto fail;
+  val = json_parse_value(s);
+  if (JS_IsException(val))
+    goto fail;
+  if (s->token.val != TOK_EOF) {
+    if (js_parse_error(s, "unexpected data at the end"))
+      goto fail;
+  }
+  return val;
+fail:
+  JS_FreeValue(ctx, val);
+  free_token(s, &s->token);
+  return JS_EXCEPTION;
+}
+
+JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
+                     const char *filename)
+{
+  return JS_ParseJSON2(ctx, buf, buf_len, filename, 0);
+}
+
+JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
+                                         JSAtom name, JSValueConst reviver)
+{
+  JSValue val, new_el, name_val, res;
+  JSValueConst args[2];
+  int ret, is_array;
+  uint32_t i, len = 0;
+  JSAtom prop;
+  JSPropertyEnum *atoms = NULL;
+
+  if (js_check_stack_overflow(ctx->rt, 0)) {
+    return JS_ThrowStackOverflow(ctx);
+  }
+
+  val = JS_GetProperty(ctx, holder, name);
+  if (JS_IsException(val))
+    return val;
+  if (JS_IsObject(val)) {
+    is_array = JS_IsArray(ctx, val);
+    if (is_array < 0)
+      goto fail;
+    if (is_array) {
+      if (js_get_length32(ctx, &len, val))
+        goto fail;
+    } else {
+      ret = JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, JS_VALUE_GET_OBJ(val), JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK);
+      if (ret < 0)
+        goto fail;
+    }
+    for(i = 0; i < len; i++) {
+      if (is_array) {
+        prop = JS_NewAtomUInt32(ctx, i);
+        if (prop == JS_ATOM_NULL)
+          goto fail;
+      } else {
+        prop = JS_DupAtom(ctx, atoms[i].atom);
+      }
+      new_el = internalize_json_property(ctx, val, prop, reviver);
+      if (JS_IsException(new_el)) {
+        JS_FreeAtom(ctx, prop);
+        goto fail;
+      }
+      if (JS_IsUndefined(new_el)) {
+        ret = JS_DeleteProperty(ctx, val, prop, 0);
+      } else {
+        ret = JS_DefinePropertyValue(ctx, val, prop, new_el, JS_PROP_C_W_E);
+      }
+      JS_FreeAtom(ctx, prop);
+      if (ret < 0)
+        goto fail;
+    }
+  }
+  js_free_prop_enum(ctx, atoms, len);
+  atoms = NULL;
+  name_val = JS_AtomToValue(ctx, name);
+  if (JS_IsException(name_val))
+    goto fail;
+  args[0] = name_val;
+  args[1] = val;
+  res = JS_Call(ctx, reviver, holder, 2, args);
+  JS_FreeValue(ctx, name_val);
+  JS_FreeValue(ctx, val);
+  return res;
+fail:
+  js_free_prop_enum(ctx, atoms, len);
+  JS_FreeValue(ctx, val);
+  return JS_EXCEPTION;
+}
+
+JSValue js_json_parse(JSContext *ctx, JSValueConst this_val,
+                             int argc, JSValueConst *argv)
+{
+  JSValue obj, root;
+  JSValueConst reviver;
+  const char *str;
+  size_t len;
+
+  str = JS_ToCStringLen(ctx, &len, argv[0]);
+  if (!str)
+    return JS_EXCEPTION;
+  obj = JS_ParseJSON(ctx, str, len, "<input>");
+  JS_FreeCString(ctx, str);
+  if (JS_IsException(obj))
+    return obj;
+  if (argc > 1 && JS_IsFunction(ctx, argv[1])) {
+    reviver = argv[1];
+    root = JS_NewObject(ctx);
+    if (JS_IsException(root)) {
+      JS_FreeValue(ctx, obj);
+      return JS_EXCEPTION;
+    }
+    if (JS_DefinePropertyValue(ctx, root, JS_ATOM_empty_string, obj,
+                               JS_PROP_C_W_E) < 0) {
+      JS_FreeValue(ctx, root);
+      return JS_EXCEPTION;
+    }
+    obj = internalize_json_property(ctx, root, JS_ATOM_empty_string,
+                                    reviver);
+    JS_FreeValue(ctx, root);
+  }
+  return obj;
+}
+
+typedef struct JSONStringifyContext {
+  JSValueConst replacer_func;
+  JSValue stack;
+  JSValue property_list;
+  JSValue gap;
+  JSValue empty;
+  StringBuffer *b;
+} JSONStringifyContext;
+
+JSValue JS_ToQuotedStringFree(JSContext *ctx, JSValue val) {
+  JSValue r = JS_ToQuotedString(ctx, val);
+  JS_FreeValue(ctx, val);
+  return r;
+}
+
+JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,
+                             JSValueConst holder, JSValue val, JSValueConst key)
+{
+  JSValue v;
+  JSValueConst args[2];
+
+  if (JS_IsObject(val)
+#ifdef CONFIG_BIGNUM
+      ||  JS_IsBigInt(ctx, val)   /* XXX: probably useless */
+#endif
+  ) {
+    JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON);
+    if (JS_IsException(f))
+      goto exception;
+    if (JS_IsFunction(ctx, f)) {
+      v = JS_CallFree(ctx, f, val, 1, &key);
+      JS_FreeValue(ctx, val);
+      val = v;
+      if (JS_IsException(val))
+        goto exception;
+    } else {
+      JS_FreeValue(ctx, f);
+    }
+  }
+
+  if (!JS_IsUndefined(jsc->replacer_func)) {
+    args[0] = key;
+    args[1] = val;
+    v = JS_Call(ctx, jsc->replacer_func, holder, 2, args);
+    JS_FreeValue(ctx, val);
+    val = v;
+    if (JS_IsException(val))
+      goto exception;
+  }
+
+  switch (JS_VALUE_GET_NORM_TAG(val)) {
+    case JS_TAG_OBJECT:
+      if (JS_IsFunction(ctx, val))
+        break;
+    case JS_TAG_STRING:
+    case JS_TAG_INT:
+    case JS_TAG_FLOAT64:
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_FLOAT:
+#endif
+    case JS_TAG_BOOL:
+    case JS_TAG_NULL:
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_INT:
+#endif
+    case JS_TAG_EXCEPTION:
+      return val;
+    default:
+      break;
+  }
+  JS_FreeValue(ctx, val);
+  return JS_UNDEFINED;
+
+exception:
+  JS_FreeValue(ctx, val);
+  return JS_EXCEPTION;
+}
+
+int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
+                          JSValueConst holder, JSValue val,
+                          JSValueConst indent)
+{
+  JSValue indent1, sep, sep1, tab, v, prop;
+  JSObject *p;
+  int64_t i, len;
+  int cl, ret;
+  BOOL has_content;
+
+  indent1 = JS_UNDEFINED;
+  sep = JS_UNDEFINED;
+  sep1 = JS_UNDEFINED;
+  tab = JS_UNDEFINED;
+  prop = JS_UNDEFINED;
+
+  switch (JS_VALUE_GET_NORM_TAG(val)) {
+    case JS_TAG_OBJECT:
+      p = JS_VALUE_GET_OBJ(val);
+      cl = p->class_id;
+      if (cl == JS_CLASS_STRING) {
+        val = JS_ToStringFree(ctx, val);
+        if (JS_IsException(val))
+          goto exception;
+        val = JS_ToQuotedStringFree(ctx, val);
+        if (JS_IsException(val))
+          goto exception;
+        return string_buffer_concat_value_free(jsc->b, val);
+      } else if (cl == JS_CLASS_NUMBER) {
+        val = JS_ToNumberFree(ctx, val);
+        if (JS_IsException(val))
+          goto exception;
+        return string_buffer_concat_value_free(jsc->b, val);
+      } else if (cl == JS_CLASS_BOOLEAN) {
+        ret = string_buffer_concat_value(jsc->b, p->u.object_data);
+        JS_FreeValue(ctx, val);
+        return ret;
+      }
+#ifdef CONFIG_BIGNUM
+      else if (cl == JS_CLASS_BIG_FLOAT) {
+        return string_buffer_concat_value_free(jsc->b, val);
+      } else if (cl == JS_CLASS_BIG_INT) {
+        JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify");
+        goto exception;
+      }
+#endif
+      v = js_array_includes(ctx, jsc->stack, 1, (JSValueConst *)&val);
+      if (JS_IsException(v))
+        goto exception;
+      if (JS_ToBoolFree(ctx, v)) {
+        JS_ThrowTypeError(ctx, "circular reference");
+        goto exception;
+      }
+      indent1 = JS_ConcatString(ctx, JS_DupValue(ctx, indent), JS_DupValue(ctx, jsc->gap));
+      if (JS_IsException(indent1))
+        goto exception;
+      if (!JS_IsEmptyString(jsc->gap)) {
+        sep = JS_ConcatString3(ctx, "\n", JS_DupValue(ctx, indent1), "");
+        if (JS_IsException(sep))
+          goto exception;
+        sep1 = JS_NewString(ctx, " ");
+        if (JS_IsException(sep1))
+          goto exception;
+      } else {
+        sep = JS_DupValue(ctx, jsc->empty);
+        sep1 = JS_DupValue(ctx, jsc->empty);
+      }
+      v = js_array_push(ctx, jsc->stack, 1, (JSValueConst *)&val, 0);
+      if (check_exception_free(ctx, v))
+        goto exception;
+      ret = JS_IsArray(ctx, val);
+      if (ret < 0)
+        goto exception;
+      if (ret) {
+        if (js_get_length64(ctx, &len, val))
+          goto exception;
+        string_buffer_putc8(jsc->b, '[');
+        for(i = 0; i < len; i++) {
+          if (i > 0)
+            string_buffer_putc8(jsc->b, ',');
+          string_buffer_concat_value(jsc->b, sep);
+          v = JS_GetPropertyInt64(ctx, val, i);
+          if (JS_IsException(v))
+            goto exception;
+          /* XXX: could do this string conversion only when needed */
+          prop = JS_ToStringFree(ctx, JS_NewInt64(ctx, i));
+          if (JS_IsException(prop))
+            goto exception;
+          v = js_json_check(ctx, jsc, val, v, prop);
+          JS_FreeValue(ctx, prop);
+          prop = JS_UNDEFINED;
+          if (JS_IsException(v))
+            goto exception;
+          if (JS_IsUndefined(v))
+            v = JS_NULL;
+          if (js_json_to_str(ctx, jsc, val, v, indent1))
+            goto exception;
+        }
+        if (len > 0 && !JS_IsEmptyString(jsc->gap)) {
+          string_buffer_putc8(jsc->b, '\n');
+          string_buffer_concat_value(jsc->b, indent);
+        }
+        string_buffer_putc8(jsc->b, ']');
+      } else {
+        if (!JS_IsUndefined(jsc->property_list))
+          tab = JS_DupValue(ctx, jsc->property_list);
+        else
+          tab = js_object_keys(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val, JS_ITERATOR_KIND_KEY);
+        if (JS_IsException(tab))
+          goto exception;
+        if (js_get_length64(ctx, &len, tab))
+          goto exception;
+        string_buffer_putc8(jsc->b, '{');
+        has_content = FALSE;
+        for(i = 0; i < len; i++) {
+          JS_FreeValue(ctx, prop);
+          prop = JS_GetPropertyInt64(ctx, tab, i);
+          if (JS_IsException(prop))
+            goto exception;
+          v = JS_GetPropertyValue(ctx, val, JS_DupValue(ctx, prop));
+          if (JS_IsException(v))
+            goto exception;
+          v = js_json_check(ctx, jsc, val, v, prop);
+          if (JS_IsException(v))
+            goto exception;
+          if (!JS_IsUndefined(v)) {
+            if (has_content)
+              string_buffer_putc8(jsc->b, ',');
+            prop = JS_ToQuotedStringFree(ctx, prop);
+            if (JS_IsException(prop)) {
+              JS_FreeValue(ctx, v);
+              goto exception;
+            }
+            string_buffer_concat_value(jsc->b, sep);
+            string_buffer_concat_value(jsc->b, prop);
+            string_buffer_putc8(jsc->b, ':');
+            string_buffer_concat_value(jsc->b, sep1);
+            if (js_json_to_str(ctx, jsc, val, v, indent1))
+              goto exception;
+            has_content = TRUE;
+          }
+        }
+        if (has_content && JS_VALUE_GET_STRING(jsc->gap)->len != 0) {
+          string_buffer_putc8(jsc->b, '\n');
+          string_buffer_concat_value(jsc->b, indent);
+        }
+        string_buffer_putc8(jsc->b, '}');
+      }
+      if (check_exception_free(ctx, js_array_pop(ctx, jsc->stack, 0, NULL, 0)))
+        goto exception;
+      JS_FreeValue(ctx, val);
+      JS_FreeValue(ctx, tab);
+      JS_FreeValue(ctx, sep);
+      JS_FreeValue(ctx, sep1);
+      JS_FreeValue(ctx, indent1);
+      JS_FreeValue(ctx, prop);
+      return 0;
+    case JS_TAG_STRING:
+      val = JS_ToQuotedStringFree(ctx, val);
+      if (JS_IsException(val))
+        goto exception;
+      goto concat_value;
+    case JS_TAG_FLOAT64:
+      if (!isfinite(JS_VALUE_GET_FLOAT64(val))) {
+        val = JS_NULL;
+      }
+      goto concat_value;
+    case JS_TAG_INT:
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_FLOAT:
+#endif
+    case JS_TAG_BOOL:
+    case JS_TAG_NULL:
+    concat_value:
+      return string_buffer_concat_value_free(jsc->b, val);
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_INT:
+      JS_ThrowTypeError(ctx, "bigint are forbidden in JSON.stringify");
+      goto exception;
+#endif
+    default:
+      JS_FreeValue(ctx, val);
+      return 0;
+  }
+
+exception:
+  JS_FreeValue(ctx, val);
+  JS_FreeValue(ctx, tab);
+  JS_FreeValue(ctx, sep);
+  JS_FreeValue(ctx, sep1);
+  JS_FreeValue(ctx, indent1);
+  JS_FreeValue(ctx, prop);
+  return -1;
+}
+
+JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
+                         JSValueConst replacer, JSValueConst space0)
+{
+  StringBuffer b_s;
+  JSONStringifyContext jsc_s, *jsc = &jsc_s;
+  JSValue val, v, space, ret, wrapper;
+  int res;
+  int64_t i, j, n;
+
+  jsc->replacer_func = JS_UNDEFINED;
+  jsc->stack = JS_UNDEFINED;
+  jsc->property_list = JS_UNDEFINED;
+  jsc->gap = JS_UNDEFINED;
+  jsc->b = &b_s;
+  jsc->empty = JS_AtomToString(ctx, JS_ATOM_empty_string);
+  ret = JS_UNDEFINED;
+  wrapper = JS_UNDEFINED;
+
+  string_buffer_init(ctx, jsc->b, 0);
+  jsc->stack = JS_NewArray(ctx);
+  if (JS_IsException(jsc->stack))
+    goto exception;
+  if (JS_IsFunction(ctx, replacer)) {
+    jsc->replacer_func = replacer;
+  } else {
+    res = JS_IsArray(ctx, replacer);
+    if (res < 0)
+      goto exception;
+    if (res) {
+      /* XXX: enumeration is not fully correct */
+      jsc->property_list = JS_NewArray(ctx);
+      if (JS_IsException(jsc->property_list))
+        goto exception;
+      if (js_get_length64(ctx, &n, replacer))
+        goto exception;
+      for (i = j = 0; i < n; i++) {
+        JSValue present;
+        v = JS_GetPropertyInt64(ctx, replacer, i);
+        if (JS_IsException(v))
+          goto exception;
+        if (JS_IsObject(v)) {
+          JSObject *p = JS_VALUE_GET_OBJ(v);
+          if (p->class_id == JS_CLASS_STRING ||
+              p->class_id == JS_CLASS_NUMBER) {
+            v = JS_ToStringFree(ctx, v);
+            if (JS_IsException(v))
+              goto exception;
+          } else {
+            JS_FreeValue(ctx, v);
+            continue;
+          }
+        } else if (JS_IsNumber(v)) {
+          v = JS_ToStringFree(ctx, v);
+          if (JS_IsException(v))
+            goto exception;
+        } else if (!JS_IsString(v)) {
+          JS_FreeValue(ctx, v);
+          continue;
+        }
+        present = js_array_includes(ctx, jsc->property_list,
+                                    1, (JSValueConst *)&v);
+        if (JS_IsException(present)) {
+          JS_FreeValue(ctx, v);
+          goto exception;
+        }
+        if (!JS_ToBoolFree(ctx, present)) {
+          JS_SetPropertyInt64(ctx, jsc->property_list, j++, v);
+        } else {
+          JS_FreeValue(ctx, v);
+        }
+      }
+    }
+  }
+  space = JS_DupValue(ctx, space0);
+  if (JS_IsObject(space)) {
+    JSObject *p = JS_VALUE_GET_OBJ(space);
+    if (p->class_id == JS_CLASS_NUMBER) {
+      space = JS_ToNumberFree(ctx, space);
+    } else if (p->class_id == JS_CLASS_STRING) {
+      space = JS_ToStringFree(ctx, space);
+    }
+    if (JS_IsException(space)) {
+      JS_FreeValue(ctx, space);
+      goto exception;
+    }
+  }
+  if (JS_IsNumber(space)) {
+    int n;
+    if (JS_ToInt32Clamp(ctx, &n, space, 0, 10, 0))
+      goto exception;
+    jsc->gap = JS_NewStringLen(ctx, "          ", n);
+  } else if (JS_IsString(space)) {
+    JSString *p = JS_VALUE_GET_STRING(space);
+    jsc->gap = js_sub_string(ctx, p, 0, min_int(p->len, 10));
+  } else {
+    jsc->gap = JS_DupValue(ctx, jsc->empty);
+  }
+  JS_FreeValue(ctx, space);
+  if (JS_IsException(jsc->gap))
+    goto exception;
+  wrapper = JS_NewObject(ctx);
+  if (JS_IsException(wrapper))
+    goto exception;
+  if (JS_DefinePropertyValue(ctx, wrapper, JS_ATOM_empty_string,
+                             JS_DupValue(ctx, obj), JS_PROP_C_W_E) < 0)
+    goto exception;
+  val = JS_DupValue(ctx, obj);
+
+  val = js_json_check(ctx, jsc, wrapper, val, jsc->empty);
+  if (JS_IsException(val))
+    goto exception;
+  if (JS_IsUndefined(val)) {
+    ret = JS_UNDEFINED;
+    goto done1;
+  }
+  if (js_json_to_str(ctx, jsc, wrapper, val, jsc->empty))
+    goto exception;
+
+  ret = string_buffer_end(jsc->b);
+  goto done;
+
+exception:
+  ret = JS_EXCEPTION;
+done1:
+  string_buffer_free(jsc->b);
+done:
+  JS_FreeValue(ctx, wrapper);
+  JS_FreeValue(ctx, jsc->empty);
+  JS_FreeValue(ctx, jsc->gap);
+  JS_FreeValue(ctx, jsc->property_list);
+  JS_FreeValue(ctx, jsc->stack);
+  return ret;
+}
+
+JSValue js_json_stringify(JSContext *ctx, JSValueConst this_val,
+                                 int argc, JSValueConst *argv)
+{
+  // stringify(val, replacer, space)
+  return JS_JSONStringify(ctx, argv[0], argv[1], argv[2]);
+}
+
+const JSCFunctionListEntry js_json_funcs[] = {
+    JS_CFUNC_DEF("parse", 2, js_json_parse ),
+    JS_CFUNC_DEF("stringify", 3, js_json_stringify ),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "JSON", JS_PROP_CONFIGURABLE ),
+};
+
+const JSCFunctionListEntry js_json_obj[] = {
+    JS_OBJECT_DEF("JSON", js_json_funcs, countof(js_json_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
+};
+
+void JS_AddIntrinsicJSON(JSContext *ctx)
+{
+  /* add JSON as autoinit object */
+  JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_json_obj, countof(js_json_obj));
+}
\ No newline at end of file
diff --git a/src/core/builtins/js-json.h b/src/core/builtins/js-json.h
new file mode 100644
index 000000000..d35e86c48
--- /dev/null
+++ b/src/core/builtins/js-json.h
@@ -0,0 +1,31 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_JSON_H
+#define QUICKJS_JS_JSON_H
+
+#include "quickjs/quickjs.h"
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-map.c b/src/core/builtins/js-map.c
new file mode 100644
index 000000000..4262596b8
--- /dev/null
+++ b/src/core/builtins/js-map.c
@@ -0,0 +1,811 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-map.h"
+#include "../exception.h"
+#include "../object.h"
+#include "../runtime.h"
+#include "../string.h"
+#include "js-array.h"
+#include "js-operator.h"
+
+/* Set/Map/WeakSet/WeakMap */
+
+typedef struct JSMapRecord {
+  int ref_count; /* used during enumeration to avoid freeing the record */
+  BOOL empty; /* TRUE if the record is deleted */
+  struct JSMapState *map;
+  struct JSMapRecord *next_weak_ref;
+  struct list_head link;
+  struct list_head hash_link;
+  JSValue key;
+  JSValue value;
+} JSMapRecord;
+
+typedef struct JSMapState {
+  BOOL is_weak; /* TRUE if WeakSet/WeakMap */
+  struct list_head records; /* list of JSMapRecord.link */
+  uint32_t record_count;
+  struct list_head *hash_table;
+  uint32_t hash_size; /* must be a power of two */
+  uint32_t record_count_threshold; /* count at which a hash table
+                                      resize is needed */
+} JSMapState;
+
+#define MAGIC_SET (1 << 0)
+#define MAGIC_WEAK (1 << 1)
+
+JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target,
+                                  int argc, JSValueConst *argv, int magic)
+{
+  JSMapState *s;
+  JSValue obj, adder = JS_UNDEFINED, iter = JS_UNDEFINED, next_method = JS_UNDEFINED;
+  JSValueConst arr;
+  BOOL is_set, is_weak;
+
+  is_set = magic & MAGIC_SET;
+  is_weak = ((magic & MAGIC_WEAK) != 0);
+  obj = js_create_from_ctor(ctx, new_target, JS_CLASS_MAP + magic);
+  if (JS_IsException(obj))
+    return JS_EXCEPTION;
+  s = js_mallocz(ctx, sizeof(*s));
+  if (!s)
+    goto fail;
+  init_list_head(&s->records);
+  s->is_weak = is_weak;
+  JS_SetOpaque(obj, s);
+  s->hash_size = 1;
+  s->hash_table = js_malloc(ctx, sizeof(s->hash_table[0]) * s->hash_size);
+  if (!s->hash_table)
+    goto fail;
+  init_list_head(&s->hash_table[0]);
+  s->record_count_threshold = 4;
+
+  arr = JS_UNDEFINED;
+  if (argc > 0)
+    arr = argv[0];
+  if (!JS_IsUndefined(arr) && !JS_IsNull(arr)) {
+    JSValue item, ret;
+    BOOL done;
+
+    adder = JS_GetProperty(ctx, obj, is_set ? JS_ATOM_add : JS_ATOM_set);
+    if (JS_IsException(adder))
+      goto fail;
+    if (!JS_IsFunction(ctx, adder)) {
+      JS_ThrowTypeError(ctx, "set/add is not a function");
+      goto fail;
+    }
+
+    iter = JS_GetIterator(ctx, arr, FALSE);
+    if (JS_IsException(iter))
+      goto fail;
+    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
+    if (JS_IsException(next_method))
+      goto fail;
+
+    for(;;) {
+      item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
+      if (JS_IsException(item))
+        goto fail;
+      if (done) {
+        JS_FreeValue(ctx, item);
+        break;
+      }
+      if (is_set) {
+        ret = JS_Call(ctx, adder, obj, 1, (JSValueConst *)&item);
+        if (JS_IsException(ret)) {
+          JS_FreeValue(ctx, item);
+          goto fail;
+        }
+      } else {
+        JSValue key, value;
+        JSValueConst args[2];
+        key = JS_UNDEFINED;
+        value = JS_UNDEFINED;
+        if (!JS_IsObject(item)) {
+          JS_ThrowTypeErrorNotAnObject(ctx);
+          goto fail1;
+        }
+        key = JS_GetPropertyUint32(ctx, item, 0);
+        if (JS_IsException(key))
+          goto fail1;
+        value = JS_GetPropertyUint32(ctx, item, 1);
+        if (JS_IsException(value))
+          goto fail1;
+        args[0] = key;
+        args[1] = value;
+        ret = JS_Call(ctx, adder, obj, 2, args);
+        if (JS_IsException(ret)) {
+        fail1:
+          JS_FreeValue(ctx, item);
+          JS_FreeValue(ctx, key);
+          JS_FreeValue(ctx, value);
+          goto fail;
+        }
+        JS_FreeValue(ctx, key);
+        JS_FreeValue(ctx, value);
+      }
+      JS_FreeValue(ctx, ret);
+      JS_FreeValue(ctx, item);
+    }
+    JS_FreeValue(ctx, next_method);
+    JS_FreeValue(ctx, iter);
+    JS_FreeValue(ctx, adder);
+  }
+  return obj;
+fail:
+  if (JS_IsObject(iter)) {
+    /* close the iterator object, preserving pending exception */
+    JS_IteratorClose(ctx, iter, TRUE);
+  }
+  JS_FreeValue(ctx, next_method);
+  JS_FreeValue(ctx, iter);
+  JS_FreeValue(ctx, adder);
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+/* XXX: could normalize strings to speed up comparison */
+JSValueConst map_normalize_key(JSContext *ctx, JSValueConst key)
+{
+  uint32_t tag = JS_VALUE_GET_TAG(key);
+  /* convert -0.0 to +0.0 */
+  if (JS_TAG_IS_FLOAT64(tag) && JS_VALUE_GET_FLOAT64(key) == 0.0) {
+    key = JS_NewInt32(ctx, 0);
+  }
+  return key;
+}
+
+/* XXX: better hash ? */
+uint32_t map_hash_key(JSContext *ctx, JSValueConst key)
+{
+  uint32_t tag = JS_VALUE_GET_NORM_TAG(key);
+  uint32_t h;
+  double d;
+  JSFloat64Union u;
+
+  switch(tag) {
+    case JS_TAG_BOOL:
+      h = JS_VALUE_GET_INT(key);
+      break;
+    case JS_TAG_STRING:
+      h = hash_string(JS_VALUE_GET_STRING(key), 0);
+      break;
+    case JS_TAG_OBJECT:
+    case JS_TAG_SYMBOL:
+      h = (uintptr_t)JS_VALUE_GET_PTR(key) * 3163;
+      break;
+    case JS_TAG_INT:
+      d = JS_VALUE_GET_INT(key) * 3163;
+      goto hash_float64;
+    case JS_TAG_FLOAT64:
+      d = JS_VALUE_GET_FLOAT64(key);
+      /* normalize the NaN */
+      if (isnan(d))
+        d = JS_FLOAT64_NAN;
+    hash_float64:
+      u.d = d;
+      h = (u.u32[0] ^ u.u32[1]) * 3163;
+      break;
+    default:
+      h = 0; /* XXX: bignum support */
+      break;
+  }
+  h ^= tag;
+  return h;
+}
+
+JSMapRecord *map_find_record(JSContext *ctx, JSMapState *s,
+                                    JSValueConst key)
+{
+  struct list_head *el;
+  JSMapRecord *mr;
+  uint32_t h;
+  h = map_hash_key(ctx, key) & (s->hash_size - 1);
+  list_for_each(el, &s->hash_table[h]) {
+    mr = list_entry(el, JSMapRecord, hash_link);
+    if (js_same_value_zero(ctx, mr->key, key))
+      return mr;
+  }
+  return NULL;
+}
+
+void map_hash_resize(JSContext *ctx, JSMapState *s)
+{
+  uint32_t new_hash_size, i, h;
+  size_t slack;
+  struct list_head *new_hash_table, *el;
+  JSMapRecord *mr;
+
+  /* XXX: no reporting of memory allocation failure */
+  if (s->hash_size == 1)
+    new_hash_size = 4;
+  else
+    new_hash_size = s->hash_size * 2;
+  new_hash_table = js_realloc2(ctx, s->hash_table,
+                               sizeof(new_hash_table[0]) * new_hash_size, &slack);
+  if (!new_hash_table)
+    return;
+  new_hash_size += slack / sizeof(*new_hash_table);
+
+  for(i = 0; i < new_hash_size; i++)
+    init_list_head(&new_hash_table[i]);
+
+  list_for_each(el, &s->records) {
+    mr = list_entry(el, JSMapRecord, link);
+    if (!mr->empty) {
+      h = map_hash_key(ctx, mr->key) & (new_hash_size - 1);
+      list_add_tail(&mr->hash_link, &new_hash_table[h]);
+    }
+  }
+  s->hash_table = new_hash_table;
+  s->hash_size = new_hash_size;
+  s->record_count_threshold = new_hash_size * 2;
+}
+
+JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s,
+                                   JSValueConst key)
+{
+  uint32_t h;
+  JSMapRecord *mr;
+
+  mr = js_malloc(ctx, sizeof(*mr));
+  if (!mr)
+    return NULL;
+  mr->ref_count = 1;
+  mr->map = s;
+  mr->empty = FALSE;
+  if (s->is_weak) {
+    JSObject *p = JS_VALUE_GET_OBJ(key);
+    /* Add the weak reference */
+    mr->next_weak_ref = p->first_weak_ref;
+    p->first_weak_ref = mr;
+  } else {
+    JS_DupValue(ctx, key);
+  }
+  mr->key = (JSValue)key;
+  h = map_hash_key(ctx, key) & (s->hash_size - 1);
+  list_add_tail(&mr->hash_link, &s->hash_table[h]);
+  list_add_tail(&mr->link, &s->records);
+  s->record_count++;
+  if (s->record_count >= s->record_count_threshold) {
+    map_hash_resize(ctx, s);
+  }
+  return mr;
+}
+
+/* Remove the weak reference from the object weak
+   reference list. we don't use a doubly linked list to
+   save space, assuming a given object has few weak
+       references to it */
+void delete_weak_ref(JSRuntime *rt, JSMapRecord *mr)
+{
+  JSMapRecord **pmr, *mr1;
+  JSObject *p;
+
+  p = JS_VALUE_GET_OBJ(mr->key);
+  pmr = &p->first_weak_ref;
+  for(;;) {
+    mr1 = *pmr;
+    assert(mr1 != NULL);
+    if (mr1 == mr)
+      break;
+    pmr = &mr1->next_weak_ref;
+  }
+  *pmr = mr1->next_weak_ref;
+}
+
+void map_delete_record(JSRuntime *rt, JSMapState *s, JSMapRecord *mr)
+{
+  if (mr->empty)
+    return;
+  list_del(&mr->hash_link);
+  if (s->is_weak) {
+    delete_weak_ref(rt, mr);
+  } else {
+    JS_FreeValueRT(rt, mr->key);
+  }
+  JS_FreeValueRT(rt, mr->value);
+  if (--mr->ref_count == 0) {
+    list_del(&mr->link);
+    js_free_rt(rt, mr);
+  } else {
+    /* keep a zombie record for iterators */
+    mr->empty = TRUE;
+    mr->key = JS_UNDEFINED;
+    mr->value = JS_UNDEFINED;
+  }
+  s->record_count--;
+}
+
+void map_decref_record(JSRuntime *rt, JSMapRecord *mr)
+{
+  if (--mr->ref_count == 0) {
+    /* the record can be safely removed */
+    assert(mr->empty);
+    list_del(&mr->link);
+    js_free_rt(rt, mr);
+  }
+}
+
+void reset_weak_ref(JSRuntime *rt, JSObject *p)
+{
+  JSMapRecord *mr, *mr_next;
+  JSMapState *s;
+
+  /* first pass to remove the records from the WeakMap/WeakSet
+     lists */
+  for(mr = p->first_weak_ref; mr != NULL; mr = mr->next_weak_ref) {
+    s = mr->map;
+    assert(s->is_weak);
+    assert(!mr->empty); /* no iterator on WeakMap/WeakSet */
+    list_del(&mr->hash_link);
+    list_del(&mr->link);
+  }
+
+  /* second pass to free the values to avoid modifying the weak
+     reference list while traversing it. */
+  for(mr = p->first_weak_ref; mr != NULL; mr = mr_next) {
+    mr_next = mr->next_weak_ref;
+    JS_FreeValueRT(rt, mr->value);
+    js_free_rt(rt, mr);
+  }
+
+  p->first_weak_ref = NULL; /* fail safe */
+}
+
+JSValue js_map_set(JSContext *ctx, JSValueConst this_val,
+                          int argc, JSValueConst *argv, int magic)
+{
+  JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
+  JSMapRecord *mr;
+  JSValueConst key, value;
+
+  if (!s)
+    return JS_EXCEPTION;
+  key = map_normalize_key(ctx, argv[0]);
+  if (s->is_weak && !JS_IsObject(key))
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+  if (magic & MAGIC_SET)
+    value = JS_UNDEFINED;
+  else
+    value = argv[1];
+  mr = map_find_record(ctx, s, key);
+  if (mr) {
+    JS_FreeValue(ctx, mr->value);
+  } else {
+    mr = map_add_record(ctx, s, key);
+    if (!mr)
+      return JS_EXCEPTION;
+  }
+  mr->value = JS_DupValue(ctx, value);
+  return JS_DupValue(ctx, this_val);
+}
+
+JSValue js_map_get(JSContext *ctx, JSValueConst this_val,
+                          int argc, JSValueConst *argv, int magic)
+{
+  JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
+  JSMapRecord *mr;
+  JSValueConst key;
+
+  if (!s)
+    return JS_EXCEPTION;
+  key = map_normalize_key(ctx, argv[0]);
+  mr = map_find_record(ctx, s, key);
+  if (!mr)
+    return JS_UNDEFINED;
+  else
+    return JS_DupValue(ctx, mr->value);
+}
+
+JSValue js_map_has(JSContext *ctx, JSValueConst this_val,
+                          int argc, JSValueConst *argv, int magic)
+{
+  JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
+  JSMapRecord *mr;
+  JSValueConst key;
+
+  if (!s)
+    return JS_EXCEPTION;
+  key = map_normalize_key(ctx, argv[0]);
+  mr = map_find_record(ctx, s, key);
+  return JS_NewBool(ctx, (mr != NULL));
+}
+
+JSValue js_map_delete(JSContext *ctx, JSValueConst this_val,
+                             int argc, JSValueConst *argv, int magic)
+{
+  JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
+  JSMapRecord *mr;
+  JSValueConst key;
+
+  if (!s)
+    return JS_EXCEPTION;
+  key = map_normalize_key(ctx, argv[0]);
+  mr = map_find_record(ctx, s, key);
+  if (!mr)
+    return JS_FALSE;
+  map_delete_record(ctx->rt, s, mr);
+  return JS_TRUE;
+}
+
+JSValue js_map_clear(JSContext *ctx, JSValueConst this_val,
+                            int argc, JSValueConst *argv, int magic)
+{
+  JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
+  struct list_head *el, *el1;
+  JSMapRecord *mr;
+
+  if (!s)
+    return JS_EXCEPTION;
+  list_for_each_safe(el, el1, &s->records) {
+    mr = list_entry(el, JSMapRecord, link);
+    map_delete_record(ctx->rt, s, mr);
+  }
+  return JS_UNDEFINED;
+}
+
+JSValue js_map_get_size(JSContext *ctx, JSValueConst this_val, int magic)
+{
+  JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
+  if (!s)
+    return JS_EXCEPTION;
+  return JS_NewUint32(ctx, s->record_count);
+}
+
+JSValue js_map_forEach(JSContext *ctx, JSValueConst this_val,
+                              int argc, JSValueConst *argv, int magic)
+{
+  JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
+  JSValueConst func, this_arg;
+  JSValue ret, args[3];
+  struct list_head *el;
+  JSMapRecord *mr;
+
+  if (!s)
+    return JS_EXCEPTION;
+  func = argv[0];
+  if (argc > 1)
+    this_arg = argv[1];
+  else
+    this_arg = JS_UNDEFINED;
+  if (check_function(ctx, func))
+    return JS_EXCEPTION;
+  /* Note: the list can be modified while traversing it, but the
+     current element is locked */
+  el = s->records.next;
+  while (el != &s->records) {
+    mr = list_entry(el, JSMapRecord, link);
+    if (!mr->empty) {
+      mr->ref_count++;
+      /* must duplicate in case the record is deleted */
+      args[1] = JS_DupValue(ctx, mr->key);
+      if (magic)
+        args[0] = args[1];
+      else
+        args[0] = JS_DupValue(ctx, mr->value);
+      args[2] = (JSValue)this_val;
+      ret = JS_Call(ctx, func, this_arg, 3, (JSValueConst *)args);
+      JS_FreeValue(ctx, args[0]);
+      if (!magic)
+        JS_FreeValue(ctx, args[1]);
+      el = el->next;
+      map_decref_record(ctx->rt, mr);
+      if (JS_IsException(ret))
+        return ret;
+      JS_FreeValue(ctx, ret);
+    } else {
+      el = el->next;
+    }
+  }
+  return JS_UNDEFINED;
+}
+
+void js_map_finalizer(JSRuntime *rt, JSValue val)
+{
+  JSObject *p;
+  JSMapState *s;
+  struct list_head *el, *el1;
+  JSMapRecord *mr;
+
+  p = JS_VALUE_GET_OBJ(val);
+  s = p->u.map_state;
+  if (s) {
+    /* if the object is deleted we are sure that no iterator is
+       using it */
+    list_for_each_safe(el, el1, &s->records) {
+      mr = list_entry(el, JSMapRecord, link);
+      if (!mr->empty) {
+        if (s->is_weak)
+          delete_weak_ref(rt, mr);
+        else
+          JS_FreeValueRT(rt, mr->key);
+        JS_FreeValueRT(rt, mr->value);
+      }
+      js_free_rt(rt, mr);
+    }
+    js_free_rt(rt, s->hash_table);
+    js_free_rt(rt, s);
+  }
+}
+
+void js_map_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
+{
+  JSObject *p = JS_VALUE_GET_OBJ(val);
+  JSMapState *s;
+  struct list_head *el;
+  JSMapRecord *mr;
+
+  s = p->u.map_state;
+  if (s) {
+    list_for_each(el, &s->records) {
+      mr = list_entry(el, JSMapRecord, link);
+      if (!s->is_weak)
+        JS_MarkValue(rt, mr->key, mark_func);
+      JS_MarkValue(rt, mr->value, mark_func);
+    }
+  }
+}
+
+/* Map Iterator */
+
+typedef struct JSMapIteratorData {
+  JSValue obj;
+  JSIteratorKindEnum kind;
+  JSMapRecord *cur_record;
+} JSMapIteratorData;
+
+void js_map_iterator_finalizer(JSRuntime *rt, JSValue val)
+{
+  JSObject *p;
+  JSMapIteratorData *it;
+
+  p = JS_VALUE_GET_OBJ(val);
+  it = p->u.map_iterator_data;
+  if (it) {
+    /* During the GC sweep phase the Map finalizer may be
+       called before the Map iterator finalizer */
+    if (JS_IsLiveObject(rt, it->obj) && it->cur_record) {
+      map_decref_record(rt, it->cur_record);
+    }
+    JS_FreeValueRT(rt, it->obj);
+    js_free_rt(rt, it);
+  }
+}
+
+void js_map_iterator_mark(JSRuntime *rt, JSValueConst val,
+                                 JS_MarkFunc *mark_func)
+{
+  JSObject *p = JS_VALUE_GET_OBJ(val);
+  JSMapIteratorData *it;
+  it = p->u.map_iterator_data;
+  if (it) {
+    /* the record is already marked by the object */
+    JS_MarkValue(rt, it->obj, mark_func);
+  }
+}
+
+JSValue js_create_map_iterator(JSContext *ctx, JSValueConst this_val,
+                                      int argc, JSValueConst *argv, int magic)
+{
+  JSIteratorKindEnum kind;
+  JSMapState *s;
+  JSMapIteratorData *it;
+  JSValue enum_obj;
+
+  kind = magic >> 2;
+  magic &= 3;
+  s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
+  if (!s)
+    return JS_EXCEPTION;
+  enum_obj = JS_NewObjectClass(ctx, JS_CLASS_MAP_ITERATOR + magic);
+  if (JS_IsException(enum_obj))
+    goto fail;
+  it = js_malloc(ctx, sizeof(*it));
+  if (!it) {
+    JS_FreeValue(ctx, enum_obj);
+    goto fail;
+  }
+  it->obj = JS_DupValue(ctx, this_val);
+  it->kind = kind;
+  it->cur_record = NULL;
+  JS_SetOpaque(enum_obj, it);
+  return enum_obj;
+fail:
+  return JS_EXCEPTION;
+}
+
+JSValue js_map_iterator_next(JSContext *ctx, JSValueConst this_val,
+                                    int argc, JSValueConst *argv,
+                                    BOOL *pdone, int magic)
+{
+  JSMapIteratorData *it;
+  JSMapState *s;
+  JSMapRecord *mr;
+  struct list_head *el;
+
+  it = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP_ITERATOR + magic);
+  if (!it) {
+    *pdone = FALSE;
+    return JS_EXCEPTION;
+  }
+  if (JS_IsUndefined(it->obj))
+    goto done;
+  s = JS_GetOpaque(it->obj, JS_CLASS_MAP + magic);
+  assert(s != NULL);
+  if (!it->cur_record) {
+    el = s->records.next;
+  } else {
+    mr = it->cur_record;
+    el = mr->link.next;
+    map_decref_record(ctx->rt, mr); /* the record can be freed here */
+  }
+  for(;;) {
+    if (el == &s->records) {
+      /* no more record  */
+      it->cur_record = NULL;
+      JS_FreeValue(ctx, it->obj);
+      it->obj = JS_UNDEFINED;
+    done:
+      /* end of enumeration */
+      *pdone = TRUE;
+      return JS_UNDEFINED;
+    }
+    mr = list_entry(el, JSMapRecord, link);
+    if (!mr->empty)
+      break;
+    /* get the next record */
+    el = mr->link.next;
+  }
+
+  /* lock the record so that it won't be freed */
+  mr->ref_count++;
+  it->cur_record = mr;
+  *pdone = FALSE;
+
+  if (it->kind == JS_ITERATOR_KIND_KEY) {
+    return JS_DupValue(ctx, mr->key);
+  } else {
+    JSValueConst args[2];
+    args[0] = mr->key;
+    if (magic)
+      args[1] = mr->key;
+    else
+      args[1] = mr->value;
+    if (it->kind == JS_ITERATOR_KIND_VALUE) {
+      return JS_DupValue(ctx, args[1]);
+    } else {
+      return js_create_array(ctx, 2, args);
+    }
+  }
+}
+
+const JSCFunctionListEntry js_map_funcs[] = {
+    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
+};
+
+const JSCFunctionListEntry js_map_proto_funcs[] = {
+    JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, 0 ),
+    JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, 0 ),
+    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, 0 ),
+    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, 0 ),
+    JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, 0 ),
+    JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, 0),
+    JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, 0 ),
+    JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_VALUE << 2) | 0 ),
+    JS_CFUNC_MAGIC_DEF("keys", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | 0 ),
+    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | 0 ),
+    JS_ALIAS_DEF("[Symbol.iterator]", "entries" ),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Map", JS_PROP_CONFIGURABLE ),
+};
+
+const JSCFunctionListEntry js_map_iterator_proto_funcs[] = {
+    JS_ITERATOR_NEXT_DEF("next", 0, js_map_iterator_next, 0 ),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Map Iterator", JS_PROP_CONFIGURABLE ),
+};
+
+const JSCFunctionListEntry js_set_proto_funcs[] = {
+    JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET ),
+    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET ),
+    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET ),
+    JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, MAGIC_SET ),
+    JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, MAGIC_SET ),
+    JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, MAGIC_SET ),
+    JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | MAGIC_SET ),
+    JS_ALIAS_DEF("keys", "values" ),
+    JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
+    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | MAGIC_SET ),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set", JS_PROP_CONFIGURABLE ),
+};
+
+const JSCFunctionListEntry js_set_iterator_proto_funcs[] = {
+    JS_ITERATOR_NEXT_DEF("next", 0, js_map_iterator_next, MAGIC_SET ),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set Iterator", JS_PROP_CONFIGURABLE ),
+};
+
+const JSCFunctionListEntry js_weak_map_proto_funcs[] = {
+    JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, MAGIC_WEAK ),
+    JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, MAGIC_WEAK ),
+    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_WEAK ),
+    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_WEAK ),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakMap", JS_PROP_CONFIGURABLE ),
+};
+
+const JSCFunctionListEntry js_weak_set_proto_funcs[] = {
+    JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET | MAGIC_WEAK ),
+    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET | MAGIC_WEAK ),
+    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET | MAGIC_WEAK ),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakSet", JS_PROP_CONFIGURABLE ),
+};
+
+const JSCFunctionListEntry * const js_map_proto_funcs_ptr[6] = {
+    js_map_proto_funcs,
+    js_set_proto_funcs,
+    js_weak_map_proto_funcs,
+    js_weak_set_proto_funcs,
+    js_map_iterator_proto_funcs,
+    js_set_iterator_proto_funcs,
+};
+
+const uint8_t js_map_proto_funcs_count[6] = {
+    countof(js_map_proto_funcs),
+    countof(js_set_proto_funcs),
+    countof(js_weak_map_proto_funcs),
+    countof(js_weak_set_proto_funcs),
+    countof(js_map_iterator_proto_funcs),
+    countof(js_set_iterator_proto_funcs),
+};
+
+void JS_AddIntrinsicMapSet(JSContext *ctx)
+{
+  int i;
+  JSValue obj1;
+  char buf[ATOM_GET_STR_BUF_SIZE];
+
+  for(i = 0; i < 4; i++) {
+    const char *name = JS_AtomGetStr(ctx, buf, sizeof(buf),
+                                     JS_ATOM_Map + i);
+    ctx->class_proto[JS_CLASS_MAP + i] = JS_NewObject(ctx);
+    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP + i],
+                               js_map_proto_funcs_ptr[i],
+                               js_map_proto_funcs_count[i]);
+    obj1 = JS_NewCFunctionMagic(ctx, js_map_constructor, name, 0,
+                                JS_CFUNC_constructor_magic, i);
+    if (i < 2) {
+      JS_SetPropertyFunctionList(ctx, obj1, js_map_funcs,
+                                 countof(js_map_funcs));
+    }
+    JS_NewGlobalCConstructor2(ctx, obj1, name, ctx->class_proto[JS_CLASS_MAP + i]);
+  }
+
+  for(i = 0; i < 2; i++) {
+    ctx->class_proto[JS_CLASS_MAP_ITERATOR + i] =
+        JS_NewObjectProto(ctx, ctx->iterator_proto);
+    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP_ITERATOR + i],
+                               js_map_proto_funcs_ptr[i + 4],
+                               js_map_proto_funcs_count[i + 4]);
+  }
+}
\ No newline at end of file
diff --git a/src/core/builtins/js-map.h b/src/core/builtins/js-map.h
new file mode 100644
index 000000000..f3482d403
--- /dev/null
+++ b/src/core/builtins/js-map.h
@@ -0,0 +1,33 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_MAP_H
+#define QUICKJS_JS_MAP_H
+
+#include "quickjs/quickjs.h"
+
+void reset_weak_ref(JSRuntime *rt, JSObject *p);
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-math.c b/src/core/builtins/js-math.c
new file mode 100644
index 000000000..7ddc9bc1a
--- /dev/null
+++ b/src/core/builtins/js-math.c
@@ -0,0 +1,238 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-math.h"
+
+/* Math */
+
+/* precondition: a and b are not NaN */
+double js_fmin(double a, double b)
+{
+  if (a == 0 && b == 0) {
+    JSFloat64Union a1, b1;
+    a1.d = a;
+    b1.d = b;
+    a1.u64 |= b1.u64;
+    return a1.d;
+  } else {
+    return fmin(a, b);
+  }
+}
+
+/* precondition: a and b are not NaN */
+double js_fmax(double a, double b)
+{
+  if (a == 0 && b == 0) {
+    JSFloat64Union a1, b1;
+    a1.d = a;
+    b1.d = b;
+    a1.u64 &= b1.u64;
+    return a1.d;
+  } else {
+    return fmax(a, b);
+  }
+}
+
+JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,
+                               int argc, JSValueConst *argv, int magic)
+{
+  BOOL is_max = magic;
+  double r, a;
+  int i;
+  uint32_t tag;
+
+  if (unlikely(argc == 0)) {
+    return __JS_NewFloat64(ctx, is_max ? -1.0 / 0.0 : 1.0 / 0.0);
+  }
+
+  tag = JS_VALUE_GET_TAG(argv[0]);
+  if (tag == JS_TAG_INT) {
+    int a1, r1 = JS_VALUE_GET_INT(argv[0]);
+    for(i = 1; i < argc; i++) {
+      tag = JS_VALUE_GET_TAG(argv[i]);
+      if (tag != JS_TAG_INT) {
+        r = r1;
+        goto generic_case;
+      }
+      a1 = JS_VALUE_GET_INT(argv[i]);
+      if (is_max)
+        r1 = max_int(r1, a1);
+      else
+        r1 = min_int(r1, a1);
+
+    }
+    return JS_NewInt32(ctx, r1);
+  } else {
+    if (JS_ToFloat64(ctx, &r, argv[0]))
+      return JS_EXCEPTION;
+    i = 1;
+  generic_case:
+    while (i < argc) {
+      if (JS_ToFloat64(ctx, &a, argv[i]))
+        return JS_EXCEPTION;
+      if (!isnan(r)) {
+        if (isnan(a)) {
+          r = a;
+        } else {
+          if (is_max)
+            r = js_fmax(r, a);
+          else
+            r = js_fmin(r, a);
+        }
+      }
+      i++;
+    }
+    return JS_NewFloat64(ctx, r);
+  }
+}
+
+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_round(double a)
+{
+  JSFloat64Union u;
+  uint64_t frac_mask, one;
+  unsigned int e, s;
+
+  u.d = a;
+  e = (u.u64 >> 52) & 0x7ff;
+  if (e < 1023) {
+    /* abs(a) < 1 */
+    if (e == (1023 - 1) && u.u64 != 0xbfe0000000000000) {
+      /* abs(a) > 0.5 or a = 0.5: return +/-1.0 */
+      u.u64 = (u.u64 & ((uint64_t)1 << 63)) | ((uint64_t)1023 << 52);
+    } else {
+      /* return +/-0.0 */
+      u.u64 &= (uint64_t)1 << 63;
+    }
+  } else if (e < (1023 + 52)) {
+    s = u.u64 >> 63;
+    one = (uint64_t)1 << (52 - (e - 1023));
+    frac_mask = one - 1;
+    u.u64 += (one >> 1) - s;
+    u.u64 &= ~frac_mask; /* truncate to an integer */
+  }
+  /* otherwise: abs(a) >= 2^52, or NaN, +/-Infinity: no change */
+  return u.d;
+}
+
+JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val,
+                             int argc, JSValueConst *argv)
+{
+  double r, a;
+  int i;
+
+  r = 0;
+  if (argc > 0) {
+    if (JS_ToFloat64(ctx, &r, argv[0]))
+      return JS_EXCEPTION;
+    if (argc == 1) {
+      r = fabs(r);
+    } else {
+      /* use the built-in function to minimize precision loss */
+      for (i = 1; i < argc; i++) {
+        if (JS_ToFloat64(ctx, &a, argv[i]))
+          return JS_EXCEPTION;
+        r = hypot(r, a);
+      }
+    }
+  }
+  return JS_NewFloat64(ctx, r);
+}
+
+double js_math_fround(double a)
+{
+  return (float)a;
+}
+
+JSValue js_math_imul(JSContext *ctx, JSValueConst this_val,
+                            int argc, JSValueConst *argv)
+{
+  int a, b;
+
+  if (JS_ToInt32(ctx, &a, argv[0]))
+    return JS_EXCEPTION;
+  if (JS_ToInt32(ctx, &b, argv[1]))
+    return JS_EXCEPTION;
+  /* purposely ignoring overflow */
+  return JS_NewInt32(ctx, a * b);
+}
+
+JSValue js_math_clz32(JSContext *ctx, JSValueConst this_val,
+                             int argc, JSValueConst *argv)
+{
+  uint32_t a, r;
+
+  if (JS_ToUint32(ctx, &a, argv[0]))
+    return JS_EXCEPTION;
+  if (a == 0)
+    r = 32;
+  else
+    r = clz32(a);
+  return JS_NewInt32(ctx, r);
+}
+
+/* xorshift* random number generator by Marsaglia */
+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;
+}
+
+void js_random_init(JSContext *ctx)
+{
+  struct timeval tv;
+  gettimeofday(&tv, NULL);
+  ctx->random_state = ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec;
+  /* the state must be non zero */
+  if (ctx->random_state == 0)
+    ctx->random_state = 1;
+}
+
+JSValue js_math_random(JSContext *ctx, JSValueConst this_val,
+                              int argc, JSValueConst *argv)
+{
+  JSFloat64Union u;
+  uint64_t v;
+
+  v = xorshift64star(&ctx->random_state);
+  /* 1.0 <= u.d < 2 */
+  u.u64 = ((uint64_t)0x3ff << 52) | (v >> 12);
+  return __JS_NewFloat64(ctx, u.d - 1.0);
+}
+
diff --git a/src/core/builtins/js-math.h b/src/core/builtins/js-math.h
new file mode 100644
index 000000000..9f1991133
--- /dev/null
+++ b/src/core/builtins/js-math.h
@@ -0,0 +1,54 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_MATH_H
+#define QUICKJS_JS_MATH_H
+
+#include "quickjs/quickjs.h"
+#include "quickjs/cutils.h"
+#include "../types.h"
+
+/* precondition: a and b are not NaN */
+double js_fmin(double a, double b);
+/* precondition: a and b are not NaN */
+double js_fmax(double a, double b);
+JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,
+                               int argc, JSValueConst *argv, int magic);
+double js_math_sign(double a);
+double js_math_round(double a);
+JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val,
+                             int argc, JSValueConst *argv);
+double js_math_fround(double a);
+JSValue js_math_imul(JSContext *ctx, JSValueConst this_val,
+                            int argc, JSValueConst *argv);
+JSValue js_math_clz32(JSContext *ctx, JSValueConst this_val,
+                             int argc, JSValueConst *argv);
+/* xorshift* random number generator by Marsaglia */
+uint64_t xorshift64star(uint64_t *pstate);
+void js_random_init(JSContext *ctx);
+JSValue js_math_random(JSContext *ctx, JSValueConst this_val,
+                              int argc, JSValueConst *argv);
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-number.c b/src/core/builtins/js-number.c
new file mode 100644
index 000000000..24227bb7b
--- /dev/null
+++ b/src/core/builtins/js-number.c
@@ -0,0 +1,308 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-number.h"
+#include "../convertion.h"
+#include "../exception.h"
+#include "../object.h"
+#include "../runtime.h"
+
+/* Number */
+JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target,
+                                     int argc, JSValueConst *argv)
+{
+  JSValue val, obj;
+  if (argc == 0) {
+    val = JS_NewInt32(ctx, 0);
+  } else {
+    val = JS_ToNumeric(ctx, argv[0]);
+    if (JS_IsException(val))
+      return val;
+    switch(JS_VALUE_GET_TAG(val)) {
+#ifdef CONFIG_BIGNUM
+      case JS_TAG_BIG_INT:
+      case JS_TAG_BIG_FLOAT:
+      {
+        JSBigFloat *p = JS_VALUE_GET_PTR(val);
+        double d;
+        bf_get_float64(&p->num, &d, BF_RNDN);
+        JS_FreeValue(ctx, val);
+        val = __JS_NewFloat64(ctx, d);
+      }
+      break;
+      case JS_TAG_BIG_DECIMAL:
+        val = JS_ToStringFree(ctx, val);
+        if (JS_IsException(val))
+          return val;
+        val = JS_ToNumberFree(ctx, val);
+        if (JS_IsException(val))
+          return val;
+        break;
+#endif
+      default:
+        break;
+    }
+  }
+  if (!JS_IsUndefined(new_target)) {
+    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_NUMBER);
+    if (!JS_IsException(obj))
+      JS_SetObjectData(ctx, obj, val);
+    return obj;
+  } else {
+    return val;
+  }
+}
+
+#if 0
+JSValue js_number___toInteger(JSContext *ctx, JSValueConst this_val,
+                                     int argc, JSValueConst *argv)
+{
+    return JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[0]));
+}
+
+JSValue js_number___toLength(JSContext *ctx, JSValueConst this_val,
+                                    int argc, JSValueConst *argv)
+{
+    int64_t v;
+    if (JS_ToLengthFree(ctx, &v, JS_DupValue(ctx, argv[0])))
+        return JS_EXCEPTION;
+    return JS_NewInt64(ctx, v);
+}
+#endif
+
+JSValue js_number_isNaN(JSContext *ctx, JSValueConst this_val,
+                               int argc, JSValueConst *argv)
+{
+  if (!JS_IsNumber(argv[0]))
+    return JS_FALSE;
+  return js_global_isNaN(ctx, this_val, argc, argv);
+}
+
+JSValue js_number_isFinite(JSContext *ctx, JSValueConst this_val,
+                                  int argc, JSValueConst *argv)
+{
+  if (!JS_IsNumber(argv[0]))
+    return JS_FALSE;
+  return js_global_isFinite(ctx, this_val, argc, argv);
+}
+
+JSValue js_number_isInteger(JSContext *ctx, JSValueConst this_val,
+                                   int argc, JSValueConst *argv)
+{
+  int ret;
+  ret = JS_NumberIsInteger(ctx, argv[0]);
+  if (ret < 0)
+    return JS_EXCEPTION;
+  else
+    return JS_NewBool(ctx, ret);
+}
+
+JSValue js_number_isSafeInteger(JSContext *ctx, JSValueConst this_val,
+                                       int argc, JSValueConst *argv)
+{
+  double d;
+  if (!JS_IsNumber(argv[0]))
+    return JS_FALSE;
+  if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
+    return JS_EXCEPTION;
+  return JS_NewBool(ctx, is_safe_integer(d));
+}
+
+JSValue js_thisNumberValue(JSContext *ctx, JSValueConst this_val)
+{
+  if (JS_IsNumber(this_val))
+    return JS_DupValue(ctx, this_val);
+
+  if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
+    JSObject *p = JS_VALUE_GET_OBJ(this_val);
+    if (p->class_id == JS_CLASS_NUMBER) {
+      if (JS_IsNumber(p->u.object_data))
+        return JS_DupValue(ctx, p->u.object_data);
+    }
+  }
+  return JS_ThrowTypeError(ctx, "not a number");
+}
+
+JSValue js_number_valueOf(JSContext *ctx, JSValueConst this_val,
+                                 int argc, JSValueConst *argv)
+{
+  return js_thisNumberValue(ctx, this_val);
+}
+
+int js_get_radix(JSContext *ctx, JSValueConst val)
+{
+  int radix;
+  if (JS_ToInt32Sat(ctx, &radix, val))
+    return -1;
+  if (radix < 2 || radix > 36) {
+    JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
+    return -1;
+  }
+  return radix;
+}
+
+JSValue js_number_toString(JSContext *ctx, JSValueConst this_val,
+                                  int argc, JSValueConst *argv, int magic)
+{
+  JSValue val;
+  int base;
+  double d;
+
+  val = js_thisNumberValue(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  if (magic || JS_IsUndefined(argv[0])) {
+    base = 10;
+  } else {
+    base = js_get_radix(ctx, argv[0]);
+    if (base < 0)
+      goto fail;
+  }
+  if (JS_ToFloat64Free(ctx, &d, val))
+    return JS_EXCEPTION;
+  return js_dtoa(ctx, d, base, 0, JS_DTOA_VAR_FORMAT);
+fail:
+  JS_FreeValue(ctx, val);
+  return JS_EXCEPTION;
+}
+
+JSValue js_number_toFixed(JSContext *ctx, JSValueConst this_val,
+                                 int argc, JSValueConst *argv)
+{
+  JSValue val;
+  int f;
+  double d;
+
+  val = js_thisNumberValue(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  if (JS_ToFloat64Free(ctx, &d, val))
+    return JS_EXCEPTION;
+  if (JS_ToInt32Sat(ctx, &f, argv[0]))
+    return JS_EXCEPTION;
+  if (f < 0 || f > 100)
+    return JS_ThrowRangeError(ctx, "invalid number of digits");
+  if (fabs(d) >= 1e21) {
+    return JS_ToStringFree(ctx, __JS_NewFloat64(ctx, d));
+  } else {
+    return js_dtoa(ctx, d, 10, f, JS_DTOA_FRAC_FORMAT);
+  }
+}
+
+JSValue js_number_toExponential(JSContext *ctx, JSValueConst this_val,
+                                       int argc, JSValueConst *argv)
+{
+  JSValue val;
+  int f, flags;
+  double d;
+
+  val = js_thisNumberValue(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  if (JS_ToFloat64Free(ctx, &d, val))
+    return JS_EXCEPTION;
+  if (JS_ToInt32Sat(ctx, &f, argv[0]))
+    return JS_EXCEPTION;
+  if (!isfinite(d)) {
+    return JS_ToStringFree(ctx,  __JS_NewFloat64(ctx, d));
+  }
+  if (JS_IsUndefined(argv[0])) {
+    flags = 0;
+    f = 0;
+  } else {
+    if (f < 0 || f > 100)
+      return JS_ThrowRangeError(ctx, "invalid number of digits");
+    f++;
+    flags = JS_DTOA_FIXED_FORMAT;
+  }
+  return js_dtoa(ctx, d, 10, f, flags | JS_DTOA_FORCE_EXP);
+}
+
+JSValue js_number_toPrecision(JSContext *ctx, JSValueConst this_val,
+                                     int argc, JSValueConst *argv)
+{
+  JSValue val;
+  int p;
+  double d;
+
+  val = js_thisNumberValue(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  if (JS_ToFloat64Free(ctx, &d, val))
+    return JS_EXCEPTION;
+  if (JS_IsUndefined(argv[0]))
+    goto to_string;
+  if (JS_ToInt32Sat(ctx, &p, argv[0]))
+    return JS_EXCEPTION;
+  if (!isfinite(d)) {
+  to_string:
+    return JS_ToStringFree(ctx,  __JS_NewFloat64(ctx, d));
+  }
+  if (p < 1 || p > 100)
+    return JS_ThrowRangeError(ctx, "invalid number of digits");
+  return js_dtoa(ctx, d, 10, p, JS_DTOA_FIXED_FORMAT);
+}
+
+JSValue js_parseInt(JSContext *ctx, JSValueConst this_val,
+                           int argc, JSValueConst *argv)
+{
+  const char *str, *p;
+  int radix, flags;
+  JSValue ret;
+
+  str = JS_ToCString(ctx, argv[0]);
+  if (!str)
+    return JS_EXCEPTION;
+  if (JS_ToInt32(ctx, &radix, argv[1])) {
+    JS_FreeCString(ctx, str);
+    return JS_EXCEPTION;
+  }
+  if (radix != 0 && (radix < 2 || radix > 36)) {
+    ret = JS_NAN;
+  } else {
+    p = str;
+    p += skip_spaces(p);
+    flags = ATOD_INT_ONLY | ATOD_ACCEPT_PREFIX_AFTER_SIGN;
+    ret = js_atof(ctx, p, NULL, radix, flags);
+  }
+  JS_FreeCString(ctx, str);
+  return ret;
+}
+
+JSValue js_parseFloat(JSContext *ctx, JSValueConst this_val,
+                             int argc, JSValueConst *argv)
+{
+  const char *str, *p;
+  JSValue ret;
+
+  str = JS_ToCString(ctx, argv[0]);
+  if (!str)
+    return JS_EXCEPTION;
+  p = str;
+  p += skip_spaces(p);
+  ret = js_atof(ctx, p, NULL, 10, 0);
+  JS_FreeCString(ctx, str);
+  return ret;
+}
\ No newline at end of file
diff --git a/src/core/builtins/js-number.h b/src/core/builtins/js-number.h
new file mode 100644
index 000000000..a49099383
--- /dev/null
+++ b/src/core/builtins/js-number.h
@@ -0,0 +1,64 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_NUMBER_H
+#define QUICKJS_JS_NUMBER_H
+
+#include "quickjs/quickjs.h"
+
+/* Number */
+JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target,
+                                     int argc, JSValueConst *argv);
+
+JSValue js_number_isNaN(JSContext *ctx, JSValueConst this_val,
+                               int argc, JSValueConst *argv);
+
+JSValue js_number_isFinite(JSContext *ctx, JSValueConst this_val,
+                                  int argc, JSValueConst *argv);
+
+JSValue js_number_isInteger(JSContext *ctx, JSValueConst this_val,
+                                   int argc, JSValueConst *argv);
+
+JSValue js_number_isSafeInteger(JSContext *ctx, JSValueConst this_val,
+                                       int argc, JSValueConst *argv);
+
+JSValue js_thisNumberValue(JSContext *ctx, JSValueConst this_val);
+JSValue js_number_valueOf(JSContext *ctx, JSValueConst this_val,
+                                 int argc, JSValueConst *argv);
+int js_get_radix(JSContext *ctx, JSValueConst val);
+JSValue js_number_toString(JSContext *ctx, JSValueConst this_val,
+                                  int argc, JSValueConst *argv, int magic);
+JSValue js_number_toFixed(JSContext *ctx, JSValueConst this_val,
+                                 int argc, JSValueConst *argv);
+JSValue js_number_toExponential(JSContext *ctx, JSValueConst this_val,
+                                       int argc, JSValueConst *argv);
+JSValue js_number_toPrecision(JSContext *ctx, JSValueConst this_val,
+                                     int argc, JSValueConst *argv);
+
+JSValue js_parseInt(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_parseFloat(JSContext *ctx, JSValueConst this_val,
+                             int argc, JSValueConst *argv);
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-object.c b/src/core/builtins/js-object.c
new file mode 100644
index 000000000..a5b557bcf
--- /dev/null
+++ b/src/core/builtins/js-object.c
@@ -0,0 +1,1090 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-object.h"
+#include "../convertion.h"
+#include "../exception.h"
+#include "../object.h"
+#include "../runtime.h"
+#include "../string.h"
+#include "js-operator.h"
+
+void js_object_data_finalizer(JSRuntime* rt, JSValue val) {
+  JSObject* p = JS_VALUE_GET_OBJ(val);
+  JS_FreeValueRT(rt, p->u.object_data);
+  p->u.object_data = JS_UNDEFINED;
+}
+
+void js_object_data_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func) {
+  JSObject* p = JS_VALUE_GET_OBJ(val);
+  JS_MarkValue(rt, p->u.object_data, mark_func);
+}
+
+/* Object class */
+
+JSValue JS_ToObject(JSContext* ctx, JSValueConst val) {
+  int tag = JS_VALUE_GET_NORM_TAG(val);
+  JSValue obj;
+
+  switch (tag) {
+    default:
+    case JS_TAG_NULL:
+    case JS_TAG_UNDEFINED:
+      return JS_ThrowTypeError(ctx, "cannot convert to object");
+    case JS_TAG_OBJECT:
+    case JS_TAG_EXCEPTION:
+      return JS_DupValue(ctx, val);
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_INT:
+      obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT);
+      goto set_value;
+    case JS_TAG_BIG_FLOAT:
+      obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_FLOAT);
+      goto set_value;
+    case JS_TAG_BIG_DECIMAL:
+      obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_DECIMAL);
+      goto set_value;
+#endif
+    case JS_TAG_INT:
+    case JS_TAG_FLOAT64:
+      obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER);
+      goto set_value;
+    case JS_TAG_STRING:
+      /* XXX: should call the string constructor */
+      {
+        JSString* p1 = JS_VALUE_GET_STRING(val);
+        obj = JS_NewObjectClass(ctx, JS_CLASS_STRING);
+        JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, JS_NewInt32(ctx, p1->len), 0);
+      }
+      goto set_value;
+    case JS_TAG_BOOL:
+      obj = JS_NewObjectClass(ctx, JS_CLASS_BOOLEAN);
+      goto set_value;
+    case JS_TAG_SYMBOL:
+      obj = JS_NewObjectClass(ctx, JS_CLASS_SYMBOL);
+    set_value:
+      if (!JS_IsException(obj))
+        JS_SetObjectData(ctx, obj, JS_DupValue(ctx, val));
+      return obj;
+  }
+}
+
+JSValue JS_ToObjectFree(JSContext* ctx, JSValue val) {
+  JSValue obj = JS_ToObject(ctx, val);
+  JS_FreeValue(ctx, val);
+  return obj;
+}
+
+int js_obj_to_desc(JSContext* ctx, JSPropertyDescriptor* d, JSValueConst desc) {
+  JSValue val, getter, setter;
+  int flags;
+
+  if (!JS_IsObject(desc)) {
+    JS_ThrowTypeErrorNotAnObject(ctx);
+    return -1;
+  }
+  flags = 0;
+  val = JS_UNDEFINED;
+  getter = JS_UNDEFINED;
+  setter = JS_UNDEFINED;
+  if (JS_HasProperty(ctx, desc, JS_ATOM_configurable)) {
+    JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_configurable);
+    if (JS_IsException(prop))
+      goto fail;
+    flags |= JS_PROP_HAS_CONFIGURABLE;
+    if (JS_ToBoolFree(ctx, prop))
+      flags |= JS_PROP_CONFIGURABLE;
+  }
+  if (JS_HasProperty(ctx, desc, JS_ATOM_writable)) {
+    JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_writable);
+    if (JS_IsException(prop))
+      goto fail;
+    flags |= JS_PROP_HAS_WRITABLE;
+    if (JS_ToBoolFree(ctx, prop))
+      flags |= JS_PROP_WRITABLE;
+  }
+  if (JS_HasProperty(ctx, desc, JS_ATOM_enumerable)) {
+    JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_enumerable);
+    if (JS_IsException(prop))
+      goto fail;
+    flags |= JS_PROP_HAS_ENUMERABLE;
+    if (JS_ToBoolFree(ctx, prop))
+      flags |= JS_PROP_ENUMERABLE;
+  }
+  if (JS_HasProperty(ctx, desc, JS_ATOM_value)) {
+    flags |= JS_PROP_HAS_VALUE;
+    val = JS_GetProperty(ctx, desc, JS_ATOM_value);
+    if (JS_IsException(val))
+      goto fail;
+  }
+  if (JS_HasProperty(ctx, desc, JS_ATOM_get)) {
+    flags |= JS_PROP_HAS_GET;
+    getter = JS_GetProperty(ctx, desc, JS_ATOM_get);
+    if (JS_IsException(getter) || !(JS_IsUndefined(getter) || JS_IsFunction(ctx, getter))) {
+      JS_ThrowTypeError(ctx, "invalid getter");
+      goto fail;
+    }
+  }
+  if (JS_HasProperty(ctx, desc, JS_ATOM_set)) {
+    flags |= JS_PROP_HAS_SET;
+    setter = JS_GetProperty(ctx, desc, JS_ATOM_set);
+    if (JS_IsException(setter) || !(JS_IsUndefined(setter) || JS_IsFunction(ctx, setter))) {
+      JS_ThrowTypeError(ctx, "invalid setter");
+      goto fail;
+    }
+  }
+  if ((flags & (JS_PROP_HAS_SET | JS_PROP_HAS_GET)) && (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE))) {
+    JS_ThrowTypeError(ctx, "cannot have setter/getter and value or writable");
+    goto fail;
+  }
+  d->flags = flags;
+  d->value = val;
+  d->getter = getter;
+  d->setter = setter;
+  return 0;
+fail:
+  JS_FreeValue(ctx, val);
+  JS_FreeValue(ctx, getter);
+  JS_FreeValue(ctx, setter);
+  return -1;
+}
+
+__exception int JS_DefinePropertyDesc(JSContext* ctx,
+                                             JSValueConst obj,
+                                             JSAtom prop,
+                                             JSValueConst desc,
+                                             int flags) {
+  JSPropertyDescriptor d;
+  int ret;
+
+  if (js_obj_to_desc(ctx, &d, desc) < 0)
+    return -1;
+
+  ret = JS_DefineProperty(ctx, obj, prop, d.value, d.getter, d.setter, d.flags | flags);
+  js_free_desc(ctx, &d);
+  return ret;
+}
+
+__exception int JS_ObjectDefineProperties(JSContext* ctx, JSValueConst obj, JSValueConst properties) {
+  JSValue props, desc;
+  JSObject* p;
+  JSPropertyEnum* atoms;
+  uint32_t len, i;
+  int ret = -1;
+
+  if (!JS_IsObject(obj)) {
+    JS_ThrowTypeErrorNotAnObject(ctx);
+    return -1;
+  }
+  desc = JS_UNDEFINED;
+  props = JS_ToObject(ctx, properties);
+  if (JS_IsException(props))
+    return -1;
+  p = JS_VALUE_GET_OBJ(props);
+  if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK) <
+      0)
+    goto exception;
+  for (i = 0; i < len; i++) {
+    JS_FreeValue(ctx, desc);
+    desc = JS_GetProperty(ctx, props, atoms[i].atom);
+    if (JS_IsException(desc))
+      goto exception;
+    if (JS_DefinePropertyDesc(ctx, obj, atoms[i].atom, desc, JS_PROP_THROW) < 0)
+      goto exception;
+  }
+  ret = 0;
+
+exception:
+  js_free_prop_enum(ctx, atoms, len);
+  JS_FreeValue(ctx, props);
+  JS_FreeValue(ctx, desc);
+  return ret;
+}
+
+JSValue js_object_constructor(JSContext* ctx, JSValueConst new_target, int argc, JSValueConst* argv) {
+  JSValue ret;
+  if (!JS_IsUndefined(new_target) && JS_VALUE_GET_OBJ(new_target) != JS_VALUE_GET_OBJ(JS_GetActiveFunction(ctx))) {
+    ret = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
+  } else {
+    int tag = JS_VALUE_GET_NORM_TAG(argv[0]);
+    switch (tag) {
+      case JS_TAG_NULL:
+      case JS_TAG_UNDEFINED:
+        ret = JS_NewObject(ctx);
+        break;
+      default:
+        ret = JS_ToObject(ctx, argv[0]);
+        break;
+    }
+  }
+  return ret;
+}
+
+JSValue js_object_create(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValueConst proto, props;
+  JSValue obj;
+
+  proto = argv[0];
+  if (!JS_IsObject(proto) && !JS_IsNull(proto))
+    return JS_ThrowTypeError(ctx, "not a prototype");
+  obj = JS_NewObjectProto(ctx, proto);
+  if (JS_IsException(obj))
+    return JS_EXCEPTION;
+  props = argv[1];
+  if (!JS_IsUndefined(props)) {
+    if (JS_ObjectDefineProperties(ctx, obj, props)) {
+      JS_FreeValue(ctx, obj);
+      return JS_EXCEPTION;
+    }
+  }
+  return obj;
+}
+
+JSValue js_object_getPrototypeOf(JSContext* ctx,
+                                        JSValueConst this_val,
+                                        int argc,
+                                        JSValueConst* argv,
+                                        int magic) {
+  JSValueConst val;
+
+  val = argv[0];
+  if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) {
+    /* ES6 feature non compatible with ES5.1: primitive types are
+       accepted */
+    if (magic || JS_VALUE_GET_TAG(val) == JS_TAG_NULL || JS_VALUE_GET_TAG(val) == JS_TAG_UNDEFINED)
+      return JS_ThrowTypeErrorNotAnObject(ctx);
+  }
+  return JS_GetPrototype(ctx, val);
+}
+
+JSValue js_object_setPrototypeOf(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValueConst obj;
+  obj = argv[0];
+  if (JS_SetPrototypeInternal(ctx, obj, argv[1], TRUE) < 0)
+    return JS_EXCEPTION;
+  return JS_DupValue(ctx, obj);
+}
+
+/* magic = 1 if called as Reflect.defineProperty */
+JSValue js_object_defineProperty(JSContext* ctx,
+                                        JSValueConst this_val,
+                                        int argc,
+                                        JSValueConst* argv,
+                                        int magic) {
+  JSValueConst obj, prop, desc;
+  int ret, flags;
+  JSAtom atom;
+
+  obj = argv[0];
+  prop = argv[1];
+  desc = argv[2];
+
+  if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+  atom = JS_ValueToAtom(ctx, prop);
+  if (unlikely(atom == JS_ATOM_NULL))
+    return JS_EXCEPTION;
+  flags = 0;
+  if (!magic)
+    flags |= JS_PROP_THROW;
+  ret = JS_DefinePropertyDesc(ctx, obj, atom, desc, flags);
+  JS_FreeAtom(ctx, atom);
+  if (ret < 0) {
+    return JS_EXCEPTION;
+  } else if (magic) {
+    return JS_NewBool(ctx, ret);
+  } else {
+    return JS_DupValue(ctx, obj);
+  }
+}
+
+JSValue js_object_defineProperties(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  // defineProperties(obj, properties)
+  JSValueConst obj = argv[0];
+
+  if (JS_ObjectDefineProperties(ctx, obj, argv[1]))
+    return JS_EXCEPTION;
+  else
+    return JS_DupValue(ctx, obj);
+}
+
+/* magic = 1 if called as __defineSetter__ */
+JSValue js_object___defineGetter__(JSContext* ctx,
+                                          JSValueConst this_val,
+                                          int argc,
+                                          JSValueConst* argv,
+                                          int magic) {
+  JSValue obj;
+  JSValueConst prop, value, get, set;
+  int ret, flags;
+  JSAtom atom;
+
+  prop = argv[0];
+  value = argv[1];
+
+  obj = JS_ToObject(ctx, this_val);
+  if (JS_IsException(obj))
+    return JS_EXCEPTION;
+
+  if (check_function(ctx, value)) {
+    JS_FreeValue(ctx, obj);
+    return JS_EXCEPTION;
+  }
+  atom = JS_ValueToAtom(ctx, prop);
+  if (unlikely(atom == JS_ATOM_NULL)) {
+    JS_FreeValue(ctx, obj);
+    return JS_EXCEPTION;
+  }
+  flags = JS_PROP_THROW | JS_PROP_HAS_ENUMERABLE | JS_PROP_ENUMERABLE | JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE;
+  if (magic) {
+    get = JS_UNDEFINED;
+    set = value;
+    flags |= JS_PROP_HAS_SET;
+  } else {
+    get = value;
+    set = JS_UNDEFINED;
+    flags |= JS_PROP_HAS_GET;
+  }
+  ret = JS_DefineProperty(ctx, obj, atom, JS_UNDEFINED, get, set, flags);
+  JS_FreeValue(ctx, obj);
+  JS_FreeAtom(ctx, atom);
+  if (ret < 0) {
+    return JS_EXCEPTION;
+  } else {
+    return JS_UNDEFINED;
+  }
+}
+
+JSValue js_object_getOwnPropertyDescriptor(JSContext* ctx,
+                                                  JSValueConst this_val,
+                                                  int argc,
+                                                  JSValueConst* argv,
+                                                  int magic) {
+  JSValueConst prop;
+  JSAtom atom;
+  JSValue ret, obj;
+  JSPropertyDescriptor desc;
+  int res, flags;
+
+  if (magic) {
+    /* Reflect.getOwnPropertyDescriptor case */
+    if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT)
+      return JS_ThrowTypeErrorNotAnObject(ctx);
+    obj = JS_DupValue(ctx, argv[0]);
+  } else {
+    obj = JS_ToObject(ctx, argv[0]);
+    if (JS_IsException(obj))
+      return obj;
+  }
+  prop = argv[1];
+  atom = JS_ValueToAtom(ctx, prop);
+  if (unlikely(atom == JS_ATOM_NULL))
+    goto exception;
+  ret = JS_UNDEFINED;
+  if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
+    res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), atom);
+    if (res < 0)
+      goto exception;
+    if (res) {
+      ret = JS_NewObject(ctx);
+      if (JS_IsException(ret))
+        goto exception1;
+      flags = JS_PROP_C_W_E | JS_PROP_THROW;
+      if (desc.flags & JS_PROP_GETSET) {
+        if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, desc.getter), flags) < 0 ||
+            JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, desc.setter), flags) < 0)
+          goto exception1;
+      } else {
+        if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, desc.value), flags) < 0 ||
+            JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable, JS_NewBool(ctx, (desc.flags & JS_PROP_WRITABLE) != 0),
+                                   flags) < 0)
+          goto exception1;
+      }
+      if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable, JS_NewBool(ctx, (desc.flags & JS_PROP_ENUMERABLE) != 0),
+                                 flags) < 0 ||
+          JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
+                                 JS_NewBool(ctx, (desc.flags & JS_PROP_CONFIGURABLE) != 0), flags) < 0)
+        goto exception1;
+      js_free_desc(ctx, &desc);
+    }
+  }
+  JS_FreeAtom(ctx, atom);
+  JS_FreeValue(ctx, obj);
+  return ret;
+
+exception1:
+  js_free_desc(ctx, &desc);
+  JS_FreeValue(ctx, ret);
+exception:
+  JS_FreeAtom(ctx, atom);
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+JSValue js_object_getOwnPropertyDescriptors(JSContext* ctx,
+                                                   JSValueConst this_val,
+                                                   int argc,
+                                                   JSValueConst* argv) {
+  // getOwnPropertyDescriptors(obj)
+  JSValue obj, r;
+  JSObject* p;
+  JSPropertyEnum* props;
+  uint32_t len, i;
+
+  r = JS_UNDEFINED;
+  obj = JS_ToObject(ctx, argv[0]);
+  if (JS_IsException(obj))
+    return JS_EXCEPTION;
+
+  p = JS_VALUE_GET_OBJ(obj);
+  if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK))
+    goto exception;
+  r = JS_NewObject(ctx);
+  if (JS_IsException(r))
+    goto exception;
+  for (i = 0; i < len; i++) {
+    JSValue atomValue, desc;
+    JSValueConst args[2];
+
+    atomValue = JS_AtomToValue(ctx, props[i].atom);
+    if (JS_IsException(atomValue))
+      goto exception;
+    args[0] = obj;
+    args[1] = atomValue;
+    desc = js_object_getOwnPropertyDescriptor(ctx, JS_UNDEFINED, 2, args, 0);
+    JS_FreeValue(ctx, atomValue);
+    if (JS_IsException(desc))
+      goto exception;
+    if (!JS_IsUndefined(desc)) {
+      if (JS_DefinePropertyValue(ctx, r, props[i].atom, desc, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+        goto exception;
+    }
+  }
+  js_free_prop_enum(ctx, props, len);
+  JS_FreeValue(ctx, obj);
+  return r;
+
+exception:
+  js_free_prop_enum(ctx, props, len);
+  JS_FreeValue(ctx, obj);
+  JS_FreeValue(ctx, r);
+  return JS_EXCEPTION;
+}
+
+JSValue js_object_getOwnPropertyNames(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  return JS_GetOwnPropertyNames2(ctx, argv[0], JS_GPN_STRING_MASK, JS_ITERATOR_KIND_KEY);
+}
+
+JSValue js_object_getOwnPropertySymbols(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  return JS_GetOwnPropertyNames2(ctx, argv[0], JS_GPN_SYMBOL_MASK, JS_ITERATOR_KIND_KEY);
+}
+
+JSValue js_object_keys(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int kind) {
+  return JS_GetOwnPropertyNames2(ctx, argv[0], JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK, kind);
+}
+
+JSValue js_object_isExtensible(JSContext* ctx,
+                                      JSValueConst this_val,
+                                      int argc,
+                                      JSValueConst* argv,
+                                      int reflect) {
+  JSValueConst obj;
+  int ret;
+
+  obj = argv[0];
+  if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
+    if (reflect)
+      return JS_ThrowTypeErrorNotAnObject(ctx);
+    else
+      return JS_FALSE;
+  }
+  ret = JS_IsExtensible(ctx, obj);
+  if (ret < 0)
+    return JS_EXCEPTION;
+  else
+    return JS_NewBool(ctx, ret);
+}
+
+JSValue js_object_preventExtensions(JSContext* ctx,
+                                           JSValueConst this_val,
+                                           int argc,
+                                           JSValueConst* argv,
+                                           int reflect) {
+  JSValueConst obj;
+  int ret;
+
+  obj = argv[0];
+  if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
+    if (reflect)
+      return JS_ThrowTypeErrorNotAnObject(ctx);
+    else
+      return JS_DupValue(ctx, obj);
+  }
+  ret = JS_PreventExtensions(ctx, obj);
+  if (ret < 0)
+    return JS_EXCEPTION;
+  if (reflect) {
+    return JS_NewBool(ctx, ret);
+  } else {
+    if (!ret)
+      return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
+    return JS_DupValue(ctx, obj);
+  }
+}
+
+JSValue js_object_hasOwnProperty(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue obj;
+  JSAtom atom;
+  JSObject* p;
+  BOOL ret;
+
+  atom = JS_ValueToAtom(ctx, argv[0]); /* must be done first */
+  if (unlikely(atom == JS_ATOM_NULL))
+    return JS_EXCEPTION;
+  obj = JS_ToObject(ctx, this_val);
+  if (JS_IsException(obj)) {
+    JS_FreeAtom(ctx, atom);
+    return obj;
+  }
+  p = JS_VALUE_GET_OBJ(obj);
+  ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);
+  JS_FreeAtom(ctx, atom);
+  JS_FreeValue(ctx, obj);
+  if (ret < 0)
+    return JS_EXCEPTION;
+  else
+    return JS_NewBool(ctx, ret);
+}
+
+JSValue js_object_valueOf(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  return JS_ToObject(ctx, this_val);
+}
+
+JSValue js_object_toString(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue obj, tag;
+  int is_array;
+  JSAtom atom;
+  JSObject* p;
+
+  if (JS_IsNull(this_val)) {
+    tag = JS_NewString(ctx, "Null");
+  } else if (JS_IsUndefined(this_val)) {
+    tag = JS_NewString(ctx, "Undefined");
+  } else {
+    obj = JS_ToObject(ctx, this_val);
+    if (JS_IsException(obj))
+      return obj;
+    is_array = JS_IsArray(ctx, obj);
+    if (is_array < 0) {
+      JS_FreeValue(ctx, obj);
+      return JS_EXCEPTION;
+    }
+    if (is_array) {
+      atom = JS_ATOM_Array;
+    } else if (JS_IsFunction(ctx, obj)) {
+      atom = JS_ATOM_Function;
+    } else {
+      p = JS_VALUE_GET_OBJ(obj);
+      switch (p->class_id) {
+        case JS_CLASS_STRING:
+        case JS_CLASS_ARGUMENTS:
+        case JS_CLASS_MAPPED_ARGUMENTS:
+        case JS_CLASS_ERROR:
+        case JS_CLASS_BOOLEAN:
+        case JS_CLASS_NUMBER:
+        case JS_CLASS_DATE:
+        case JS_CLASS_REGEXP:
+          atom = ctx->rt->class_array[p->class_id].class_name;
+          break;
+        default:
+          atom = JS_ATOM_Object;
+          break;
+      }
+    }
+    tag = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_toStringTag);
+    JS_FreeValue(ctx, obj);
+    if (JS_IsException(tag))
+      return JS_EXCEPTION;
+    if (!JS_IsString(tag)) {
+      JS_FreeValue(ctx, tag);
+      tag = JS_AtomToString(ctx, atom);
+    }
+  }
+  return JS_ConcatString3(ctx, "[object ", tag, "]");
+}
+
+JSValue js_object_toLocaleString(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  return JS_Invoke(ctx, this_val, JS_ATOM_toString, 0, NULL);
+}
+
+JSValue js_object_assign(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  // Object.assign(obj, source1)
+  JSValue obj, s;
+  int i;
+
+  s = JS_UNDEFINED;
+  obj = JS_ToObject(ctx, argv[0]);
+  if (JS_IsException(obj))
+    goto exception;
+  for (i = 1; i < argc; i++) {
+    if (!JS_IsNull(argv[i]) && !JS_IsUndefined(argv[i])) {
+      s = JS_ToObject(ctx, argv[i]);
+      if (JS_IsException(s))
+        goto exception;
+      if (JS_CopyDataProperties(ctx, obj, s, JS_UNDEFINED, TRUE))
+        goto exception;
+      JS_FreeValue(ctx, s);
+    }
+  }
+  return obj;
+exception:
+  JS_FreeValue(ctx, obj);
+  JS_FreeValue(ctx, s);
+  return JS_EXCEPTION;
+}
+
+JSValue js_object_seal(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int freeze_flag) {
+  JSValueConst obj = argv[0];
+  JSObject* p;
+  JSPropertyEnum* props;
+  uint32_t len, i;
+  int flags, desc_flags, res;
+
+  if (!JS_IsObject(obj))
+    return JS_DupValue(ctx, obj);
+
+  res = JS_PreventExtensions(ctx, obj);
+  if (res < 0)
+    return JS_EXCEPTION;
+  if (!res) {
+    return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
+  }
+
+  p = JS_VALUE_GET_OBJ(obj);
+  flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK;
+  if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags))
+    return JS_EXCEPTION;
+
+  for (i = 0; i < len; i++) {
+    JSPropertyDescriptor desc;
+    JSAtom prop = props[i].atom;
+
+    desc_flags = JS_PROP_THROW | JS_PROP_HAS_CONFIGURABLE;
+    if (freeze_flag) {
+      res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
+      if (res < 0)
+        goto exception;
+      if (res) {
+        if (desc.flags & JS_PROP_WRITABLE)
+          desc_flags |= JS_PROP_HAS_WRITABLE;
+        js_free_desc(ctx, &desc);
+      }
+    }
+    if (JS_DefineProperty(ctx, obj, prop, JS_UNDEFINED, JS_UNDEFINED, JS_UNDEFINED, desc_flags) < 0)
+      goto exception;
+  }
+  js_free_prop_enum(ctx, props, len);
+  return JS_DupValue(ctx, obj);
+
+exception:
+  js_free_prop_enum(ctx, props, len);
+  return JS_EXCEPTION;
+}
+
+JSValue js_object_isSealed(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int is_frozen) {
+  JSValueConst obj = argv[0];
+  JSObject* p;
+  JSPropertyEnum* props;
+  uint32_t len, i;
+  int flags, res;
+
+  if (!JS_IsObject(obj))
+    return JS_TRUE;
+
+  p = JS_VALUE_GET_OBJ(obj);
+  flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK;
+  if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags))
+    return JS_EXCEPTION;
+
+  for (i = 0; i < len; i++) {
+    JSPropertyDescriptor desc;
+    JSAtom prop = props[i].atom;
+
+    res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
+    if (res < 0)
+      goto exception;
+    if (res) {
+      js_free_desc(ctx, &desc);
+      if ((desc.flags & JS_PROP_CONFIGURABLE) || (is_frozen && (desc.flags & JS_PROP_WRITABLE))) {
+        res = FALSE;
+        goto done;
+      }
+    }
+  }
+  res = JS_IsExtensible(ctx, obj);
+  if (res < 0)
+    return JS_EXCEPTION;
+  res ^= 1;
+done:
+  js_free_prop_enum(ctx, props, len);
+  return JS_NewBool(ctx, res);
+
+exception:
+  js_free_prop_enum(ctx, props, len);
+  return JS_EXCEPTION;
+}
+
+JSValue js_object_fromEntries(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue obj, iter, next_method = JS_UNDEFINED;
+  JSValueConst iterable;
+  BOOL done;
+
+  /*  RequireObjectCoercible() not necessary because it is tested in
+      JS_GetIterator() by JS_GetProperty() */
+  iterable = argv[0];
+
+  obj = JS_NewObject(ctx);
+  if (JS_IsException(obj))
+    return obj;
+
+  iter = JS_GetIterator(ctx, iterable, FALSE);
+  if (JS_IsException(iter))
+    goto fail;
+  next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
+  if (JS_IsException(next_method))
+    goto fail;
+
+  for (;;) {
+    JSValue key, value, item;
+    item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
+    if (JS_IsException(item))
+      goto fail;
+    if (done) {
+      JS_FreeValue(ctx, item);
+      break;
+    }
+
+    key = JS_UNDEFINED;
+    value = JS_UNDEFINED;
+    if (!JS_IsObject(item)) {
+      JS_ThrowTypeErrorNotAnObject(ctx);
+      goto fail1;
+    }
+    key = JS_GetPropertyUint32(ctx, item, 0);
+    if (JS_IsException(key))
+      goto fail1;
+    value = JS_GetPropertyUint32(ctx, item, 1);
+    if (JS_IsException(value)) {
+      JS_FreeValue(ctx, key);
+      goto fail1;
+    }
+    if (JS_DefinePropertyValueValue(ctx, obj, key, value, JS_PROP_C_W_E | JS_PROP_THROW) < 0) {
+    fail1:
+      JS_FreeValue(ctx, item);
+      goto fail;
+    }
+    JS_FreeValue(ctx, item);
+  }
+  JS_FreeValue(ctx, next_method);
+  JS_FreeValue(ctx, iter);
+  return obj;
+fail:
+  if (JS_IsObject(iter)) {
+    /* close the iterator object, preserving pending exception */
+    JS_IteratorClose(ctx, iter, TRUE);
+  }
+  JS_FreeValue(ctx, next_method);
+  JS_FreeValue(ctx, iter);
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+#if 0
+/* Note: corresponds to ECMA spec: CreateDataPropertyOrThrow() */
+JSValue js_object___setOwnProperty(JSContext *ctx, JSValueConst this_val,
+                                          int argc, JSValueConst *argv)
+{
+    int ret;
+    ret = JS_DefinePropertyValueValue(ctx, argv[0], JS_DupValue(ctx, argv[1]),
+                                      JS_DupValue(ctx, argv[2]),
+                                      JS_PROP_C_W_E | JS_PROP_THROW);
+    if (ret < 0)
+        return JS_EXCEPTION;
+    else
+        return JS_NewBool(ctx, ret);
+}
+
+JSValue js_object___toObject(JSContext *ctx, JSValueConst this_val,
+                                    int argc, JSValueConst *argv)
+{
+    return JS_ToObject(ctx, argv[0]);
+}
+
+JSValue js_object___toPrimitive(JSContext *ctx, JSValueConst this_val,
+                                       int argc, JSValueConst *argv)
+{
+    int hint = HINT_NONE;
+
+    if (JS_VALUE_GET_TAG(argv[1]) == JS_TAG_INT)
+        hint = JS_VALUE_GET_INT(argv[1]);
+
+    return JS_ToPrimitive(ctx, argv[0], hint);
+}
+#endif
+
+/* return an empty string if not an object */
+JSValue js_object___getClass(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSAtom atom;
+  JSObject* p;
+  uint32_t tag;
+  int class_id;
+
+  tag = JS_VALUE_GET_NORM_TAG(argv[0]);
+  if (tag == JS_TAG_OBJECT) {
+    p = JS_VALUE_GET_OBJ(argv[0]);
+    class_id = p->class_id;
+    if (class_id == JS_CLASS_PROXY && JS_IsFunction(ctx, argv[0]))
+      class_id = JS_CLASS_BYTECODE_FUNCTION;
+    atom = ctx->rt->class_array[class_id].class_name;
+  } else {
+    atom = JS_ATOM_empty_string;
+  }
+  return JS_AtomToString(ctx, atom);
+}
+
+JSValue js_object_is(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  return JS_NewBool(ctx, js_same_value(ctx, argv[0], argv[1]));
+}
+
+#if 0
+JSValue js_object___getObjectData(JSContext *ctx, JSValueConst this_val,
+                                         int argc, JSValueConst *argv)
+{
+    return JS_GetObjectData(ctx, argv[0]);
+}
+
+JSValue js_object___setObjectData(JSContext *ctx, JSValueConst this_val,
+                                         int argc, JSValueConst *argv)
+{
+    if (JS_SetObjectData(ctx, argv[0], JS_DupValue(ctx, argv[1])))
+        return JS_EXCEPTION;
+    return JS_DupValue(ctx, argv[1]);
+}
+
+JSValue js_object___toPropertyKey(JSContext *ctx, JSValueConst this_val,
+                                         int argc, JSValueConst *argv)
+{
+    return JS_ToPropertyKey(ctx, argv[0]);
+}
+
+JSValue js_object___isObject(JSContext *ctx, JSValueConst this_val,
+                                    int argc, JSValueConst *argv)
+{
+    return JS_NewBool(ctx, JS_IsObject(argv[0]));
+}
+
+JSValue js_object___isSameValueZero(JSContext *ctx, JSValueConst this_val,
+                                           int argc, JSValueConst *argv)
+{
+    return JS_NewBool(ctx, js_same_value_zero(ctx, argv[0], argv[1]));
+}
+
+JSValue js_object___isConstructor(JSContext *ctx, JSValueConst this_val,
+                                         int argc, JSValueConst *argv)
+{
+    return JS_NewBool(ctx, JS_IsConstructor(ctx, argv[0]));
+}
+#endif
+
+JSValue JS_SpeciesConstructor(JSContext* ctx, JSValueConst obj, JSValueConst defaultConstructor) {
+  JSValue ctor, species;
+
+  if (!JS_IsObject(obj))
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+  ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);
+  if (JS_IsException(ctor))
+    return ctor;
+  if (JS_IsUndefined(ctor))
+    return JS_DupValue(ctx, defaultConstructor);
+  if (!JS_IsObject(ctor)) {
+    JS_FreeValue(ctx, ctor);
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+  }
+  species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species);
+  JS_FreeValue(ctx, ctor);
+  if (JS_IsException(species))
+    return species;
+  if (JS_IsUndefined(species) || JS_IsNull(species))
+    return JS_DupValue(ctx, defaultConstructor);
+  if (!JS_IsConstructor(ctx, species)) {
+    JS_FreeValue(ctx, species);
+    return JS_ThrowTypeError(ctx, "not a constructor");
+  }
+  return species;
+}
+
+#if 0
+JSValue js_object___speciesConstructor(JSContext *ctx, JSValueConst this_val,
+                                              int argc, JSValueConst *argv)
+{
+    return JS_SpeciesConstructor(ctx, argv[0], argv[1]);
+}
+#endif
+
+JSValue js_object_get___proto__(JSContext* ctx, JSValueConst this_val) {
+  JSValue val, ret;
+
+  val = JS_ToObject(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  ret = JS_GetPrototype(ctx, val);
+  JS_FreeValue(ctx, val);
+  return ret;
+}
+
+JSValue js_object_set___proto__(JSContext* ctx, JSValueConst this_val, JSValueConst proto) {
+  if (JS_IsUndefined(this_val) || JS_IsNull(this_val))
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+  if (!JS_IsObject(proto) && !JS_IsNull(proto))
+    return JS_UNDEFINED;
+  if (JS_SetPrototypeInternal(ctx, this_val, proto, TRUE) < 0)
+    return JS_EXCEPTION;
+  else
+    return JS_UNDEFINED;
+}
+
+JSValue js_object_isPrototypeOf(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue obj, v1;
+  JSValueConst v;
+  int res;
+
+  v = argv[0];
+  if (!JS_IsObject(v))
+    return JS_FALSE;
+  obj = JS_ToObject(ctx, this_val);
+  if (JS_IsException(obj))
+    return JS_EXCEPTION;
+  v1 = JS_DupValue(ctx, v);
+  for (;;) {
+    v1 = JS_GetPrototypeFree(ctx, v1);
+    if (JS_IsException(v1))
+      goto exception;
+    if (JS_IsNull(v1)) {
+      res = FALSE;
+      break;
+    }
+    if (JS_VALUE_GET_OBJ(obj) == JS_VALUE_GET_OBJ(v1)) {
+      res = TRUE;
+      break;
+    }
+    /* avoid infinite loop (possible with proxies) */
+    if (js_poll_interrupts(ctx))
+      goto exception;
+  }
+  JS_FreeValue(ctx, v1);
+  JS_FreeValue(ctx, obj);
+  return JS_NewBool(ctx, res);
+
+exception:
+  JS_FreeValue(ctx, v1);
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+JSValue js_object_propertyIsEnumerable(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue obj, res = JS_EXCEPTION;
+  JSAtom prop = JS_ATOM_NULL;
+  JSPropertyDescriptor desc;
+  int has_prop;
+
+  obj = JS_ToObject(ctx, this_val);
+  if (JS_IsException(obj))
+    goto exception;
+  prop = JS_ValueToAtom(ctx, argv[0]);
+  if (unlikely(prop == JS_ATOM_NULL))
+    goto exception;
+
+  has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);
+  if (has_prop < 0)
+    goto exception;
+  if (has_prop) {
+    res = JS_NewBool(ctx, (desc.flags & JS_PROP_ENUMERABLE) != 0);
+    js_free_desc(ctx, &desc);
+  } else {
+    res = JS_FALSE;
+  }
+
+exception:
+  JS_FreeAtom(ctx, prop);
+  JS_FreeValue(ctx, obj);
+  return res;
+}
+
+JSValue js_object___lookupGetter__(JSContext* ctx,
+                                          JSValueConst this_val,
+                                          int argc,
+                                          JSValueConst* argv,
+                                          int setter) {
+  JSValue obj, res = JS_EXCEPTION;
+  JSAtom prop = JS_ATOM_NULL;
+  JSPropertyDescriptor desc;
+  int has_prop;
+
+  obj = JS_ToObject(ctx, this_val);
+  if (JS_IsException(obj))
+    goto exception;
+  prop = JS_ValueToAtom(ctx, argv[0]);
+  if (unlikely(prop == JS_ATOM_NULL))
+    goto exception;
+
+  for (;;) {
+    has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);
+    if (has_prop < 0)
+      goto exception;
+    if (has_prop) {
+      if (desc.flags & JS_PROP_GETSET)
+        res = JS_DupValue(ctx, setter ? desc.setter : desc.getter);
+      else
+        res = JS_UNDEFINED;
+      js_free_desc(ctx, &desc);
+      break;
+    }
+    obj = JS_GetPrototypeFree(ctx, obj);
+    if (JS_IsException(obj))
+      goto exception;
+    if (JS_IsNull(obj)) {
+      res = JS_UNDEFINED;
+      break;
+    }
+    /* avoid infinite loop (possible with proxies) */
+    if (js_poll_interrupts(ctx))
+      goto exception;
+  }
+
+exception:
+  JS_FreeAtom(ctx, prop);
+  JS_FreeValue(ctx, obj);
+  return res;
+}
diff --git a/src/core/builtins/js-object.h b/src/core/builtins/js-object.h
new file mode 100644
index 000000000..4af695542
--- /dev/null
+++ b/src/core/builtins/js-object.h
@@ -0,0 +1,80 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_OBJECT_H
+#define QUICKJS_JS_OBJECT_H
+
+#include "quickjs/quickjs.h"
+#include "quickjs/cutils.h"
+#include "quickjs/list.h"
+#include "../types.h"
+
+JSValue JS_ToObject(JSContext* ctx, JSValueConst val);
+JSValue JS_ToObjectFree(JSContext* ctx, JSValue val);
+int js_obj_to_desc(JSContext* ctx, JSPropertyDescriptor* d, JSValueConst desc);
+__exception int JS_DefinePropertyDesc(JSContext* ctx, JSValueConst obj, JSAtom prop, JSValueConst desc, int flags);
+__exception int JS_ObjectDefineProperties(JSContext* ctx, JSValueConst obj, JSValueConst properties);
+JSValue js_object_constructor(JSContext* ctx, JSValueConst new_target, int argc, JSValueConst* argv);
+JSValue js_object_create(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_object_getPrototypeOf(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic);
+JSValue js_object_setPrototypeOf(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+/* magic = 1 if called as Reflect.defineProperty */
+JSValue js_object_defineProperty(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic);
+JSValue js_object_defineProperties(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+/* magic = 1 if called as __defineSetter__ */
+JSValue js_object___defineGetter__(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic);
+JSValue js_object_getOwnPropertyDescriptor(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic);
+JSValue js_object_getOwnPropertyDescriptors(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_object_getOwnPropertyNames(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_object_getOwnPropertySymbols(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_object_keys(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int kind);
+JSValue js_object_isExtensible(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int reflect);
+JSValue js_object_preventExtensions(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int reflect);
+JSValue js_object_hasOwnProperty(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_object_valueOf(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_object_toString(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_object_toLocaleString(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_object_assign(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_object_seal(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int freeze_flag);
+JSValue js_object_isSealed(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int is_frozen);
+JSValue js_object_fromEntries(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+/* return an empty string if not an object */
+JSValue js_object___getClass(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_object_is(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue JS_SpeciesConstructor(JSContext* ctx, JSValueConst obj, JSValueConst defaultConstructor);
+JSValue js_object_get___proto__(JSContext* ctx, JSValueConst this_val);
+JSValue js_object_set___proto__(JSContext* ctx, JSValueConst this_val, JSValueConst proto);
+JSValue js_object_isPrototypeOf(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_object_propertyIsEnumerable(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_object___lookupGetter__(JSContext* ctx,
+                                          JSValueConst this_val,
+                                          int argc,
+                                          JSValueConst* argv,
+                                          int setter);
+
+void js_object_data_finalizer(JSRuntime* rt, JSValue val);
+void js_object_data_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func);
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-operator.c b/src/core/builtins/js-operator.c
new file mode 100644
index 000000000..0b85de124
--- /dev/null
+++ b/src/core/builtins/js-operator.c
@@ -0,0 +1,813 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-operator.h"
+
+#include "../convertion.h"
+#include "../exception.h"
+#include "../function.h"
+#include "../object.h"
+#include "../runtime.h"
+#include "../string.h"
+#include "js-object.h"
+
+void js_for_in_iterator_finalizer(JSRuntime* rt, JSValue val) {
+  JSObject* p = JS_VALUE_GET_OBJ(val);
+  JSForInIterator* it = p->u.for_in_iterator;
+  JS_FreeValueRT(rt, it->obj);
+  js_free_rt(rt, it);
+}
+
+void js_for_in_iterator_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func) {
+  JSObject* p = JS_VALUE_GET_OBJ(val);
+  JSForInIterator* it = p->u.for_in_iterator;
+  JS_MarkValue(rt, it->obj, mark_func);
+}
+
+double js_pow(double a, double b) {
+  if (unlikely(!isfinite(b)) && fabs(a) == 1) {
+    /* not compatible with IEEE 754 */
+    return JS_FLOAT64_NAN;
+  } else {
+    return pow(a, b);
+  }
+}
+
+/* XXX: Should take JSValueConst arguments */
+BOOL js_strict_eq2(JSContext* ctx, JSValue op1, JSValue op2, JSStrictEqModeEnum eq_mode) {
+  BOOL res;
+  int tag1, tag2;
+  double d1, d2;
+
+  tag1 = JS_VALUE_GET_NORM_TAG(op1);
+  tag2 = JS_VALUE_GET_NORM_TAG(op2);
+  switch (tag1) {
+    case JS_TAG_BOOL:
+      if (tag1 != tag2) {
+        res = FALSE;
+      } else {
+        res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);
+        goto done_no_free;
+      }
+      break;
+    case JS_TAG_NULL:
+    case JS_TAG_UNDEFINED:
+      res = (tag1 == tag2);
+      break;
+    case JS_TAG_STRING: {
+      JSString *p1, *p2;
+      if (tag1 != tag2) {
+        res = FALSE;
+      } else {
+        p1 = JS_VALUE_GET_STRING(op1);
+        p2 = JS_VALUE_GET_STRING(op2);
+        res = (js_string_compare(ctx, p1, p2) == 0);
+      }
+    } break;
+    case JS_TAG_SYMBOL: {
+      JSAtomStruct *p1, *p2;
+      if (tag1 != tag2) {
+        res = FALSE;
+      } else {
+        p1 = JS_VALUE_GET_PTR(op1);
+        p2 = JS_VALUE_GET_PTR(op2);
+        res = (p1 == p2);
+      }
+    } break;
+    case JS_TAG_OBJECT:
+      if (tag1 != tag2)
+        res = FALSE;
+      else
+        res = JS_VALUE_GET_OBJ(op1) == JS_VALUE_GET_OBJ(op2);
+      break;
+    case JS_TAG_INT:
+      d1 = JS_VALUE_GET_INT(op1);
+      if (tag2 == JS_TAG_INT) {
+        d2 = JS_VALUE_GET_INT(op2);
+        goto number_test;
+      } else if (tag2 == JS_TAG_FLOAT64) {
+        d2 = JS_VALUE_GET_FLOAT64(op2);
+        goto number_test;
+      } else {
+        res = FALSE;
+      }
+      break;
+    case JS_TAG_FLOAT64:
+      d1 = JS_VALUE_GET_FLOAT64(op1);
+      if (tag2 == JS_TAG_FLOAT64) {
+        d2 = JS_VALUE_GET_FLOAT64(op2);
+      } else if (tag2 == JS_TAG_INT) {
+        d2 = JS_VALUE_GET_INT(op2);
+      } else {
+        res = FALSE;
+        break;
+      }
+    number_test:
+      if (unlikely(eq_mode >= JS_EQ_SAME_VALUE)) {
+        JSFloat64Union u1, u2;
+        /* NaN is not always normalized, so this test is necessary */
+        if (isnan(d1) || isnan(d2)) {
+          res = isnan(d1) == isnan(d2);
+        } else if (eq_mode == JS_EQ_SAME_VALUE_ZERO) {
+          res = (d1 == d2); /* +0 == -0 */
+        } else {
+          u1.d = d1;
+          u2.d = d2;
+          res = (u1.u64 == u2.u64); /* +0 != -0 */
+        }
+      } else {
+        res = (d1 == d2); /* if NaN return false and +0 == -0 */
+      }
+      goto done_no_free;
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_INT: {
+      bf_t a_s, *a, b_s, *b;
+      if (tag1 != tag2) {
+        res = FALSE;
+        break;
+      }
+      a = JS_ToBigFloat(ctx, &a_s, op1);
+      b = JS_ToBigFloat(ctx, &b_s, op2);
+      res = bf_cmp_eq(a, b);
+      if (a == &a_s)
+        bf_delete(a);
+      if (b == &b_s)
+        bf_delete(b);
+    } break;
+    case JS_TAG_BIG_FLOAT: {
+      JSBigFloat *p1, *p2;
+      const bf_t *a, *b;
+      if (tag1 != tag2) {
+        res = FALSE;
+        break;
+      }
+      p1 = JS_VALUE_GET_PTR(op1);
+      p2 = JS_VALUE_GET_PTR(op2);
+      a = &p1->num;
+      b = &p2->num;
+      if (unlikely(eq_mode >= JS_EQ_SAME_VALUE)) {
+        if (eq_mode == JS_EQ_SAME_VALUE_ZERO && a->expn == BF_EXP_ZERO && b->expn == BF_EXP_ZERO) {
+          res = TRUE;
+        } else {
+          res = (bf_cmp_full(a, b) == 0);
+        }
+      } else {
+        res = bf_cmp_eq(a, b);
+      }
+    } break;
+    case JS_TAG_BIG_DECIMAL: {
+      JSBigDecimal *p1, *p2;
+      const bfdec_t *a, *b;
+      if (tag1 != tag2) {
+        res = FALSE;
+        break;
+      }
+      p1 = JS_VALUE_GET_PTR(op1);
+      p2 = JS_VALUE_GET_PTR(op2);
+      a = &p1->num;
+      b = &p2->num;
+      res = bfdec_cmp_eq(a, b);
+    } break;
+#endif
+    default:
+      res = FALSE;
+      break;
+  }
+  JS_FreeValue(ctx, op1);
+  JS_FreeValue(ctx, op2);
+done_no_free:
+  return res;
+}
+
+BOOL js_strict_eq(JSContext* ctx, JSValue op1, JSValue op2) {
+  return js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
+}
+
+BOOL js_same_value(JSContext* ctx, JSValueConst op1, JSValueConst op2) {
+  return js_strict_eq2(ctx, JS_DupValue(ctx, op1), JS_DupValue(ctx, op2), JS_EQ_SAME_VALUE);
+}
+
+BOOL js_same_value_zero(JSContext* ctx, JSValueConst op1, JSValueConst op2) {
+  return js_strict_eq2(ctx, JS_DupValue(ctx, op1), JS_DupValue(ctx, op2), JS_EQ_SAME_VALUE_ZERO);
+}
+
+no_inline int js_strict_eq_slow(JSContext* ctx, JSValue* sp, BOOL is_neq) {
+  BOOL res;
+  res = js_strict_eq(ctx, sp[-2], sp[-1]);
+  sp[-2] = JS_NewBool(ctx, res ^ is_neq);
+  return 0;
+}
+
+__exception int js_operator_in(JSContext* ctx, JSValue* sp) {
+  JSValue op1, op2;
+  JSAtom atom;
+  int ret;
+
+  op1 = sp[-2];
+  op2 = sp[-1];
+
+  if (JS_VALUE_GET_TAG(op2) != JS_TAG_OBJECT) {
+    JS_ThrowTypeError(ctx, "invalid 'in' operand");
+    return -1;
+  }
+  atom = JS_ValueToAtom(ctx, op1);
+  if (unlikely(atom == JS_ATOM_NULL))
+    return -1;
+  ret = JS_HasProperty(ctx, op2, atom);
+  JS_FreeAtom(ctx, atom);
+  if (ret < 0)
+    return -1;
+  JS_FreeValue(ctx, op1);
+  JS_FreeValue(ctx, op2);
+  sp[-2] = JS_NewBool(ctx, ret);
+  return 0;
+}
+
+__exception int js_has_unscopable(JSContext* ctx, JSValueConst obj, JSAtom atom) {
+  JSValue arr, val;
+  int ret;
+
+  arr = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_unscopables);
+  if (JS_IsException(arr))
+    return -1;
+  ret = 0;
+  if (JS_IsObject(arr)) {
+    val = JS_GetProperty(ctx, arr, atom);
+    ret = JS_ToBoolFree(ctx, val);
+  }
+  JS_FreeValue(ctx, arr);
+  return ret;
+}
+
+__exception int js_operator_instanceof(JSContext* ctx, JSValue* sp) {
+  JSValue op1, op2;
+  BOOL ret;
+
+  op1 = sp[-2];
+  op2 = sp[-1];
+  ret = JS_IsInstanceOf(ctx, op1, op2);
+  if (ret < 0)
+    return ret;
+  JS_FreeValue(ctx, op1);
+  JS_FreeValue(ctx, op2);
+  sp[-2] = JS_NewBool(ctx, ret);
+  return 0;
+}
+
+__exception int js_operator_typeof(JSContext* ctx, JSValueConst op1) {
+  JSAtom atom;
+  uint32_t tag;
+
+  tag = JS_VALUE_GET_NORM_TAG(op1);
+  switch (tag) {
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_INT:
+      atom = JS_ATOM_bigint;
+      break;
+    case JS_TAG_BIG_FLOAT:
+      atom = JS_ATOM_bigfloat;
+      break;
+    case JS_TAG_BIG_DECIMAL:
+      atom = JS_ATOM_bigdecimal;
+      break;
+#endif
+    case JS_TAG_INT:
+    case JS_TAG_FLOAT64:
+      atom = JS_ATOM_number;
+      break;
+    case JS_TAG_UNDEFINED:
+      atom = JS_ATOM_undefined;
+      break;
+    case JS_TAG_BOOL:
+      atom = JS_ATOM_boolean;
+      break;
+    case JS_TAG_STRING:
+      atom = JS_ATOM_string;
+      break;
+    case JS_TAG_OBJECT: {
+      JSObject* p;
+      p = JS_VALUE_GET_OBJ(op1);
+      if (unlikely(p->is_HTMLDDA))
+        atom = JS_ATOM_undefined;
+      else if (JS_IsFunction(ctx, op1))
+        atom = JS_ATOM_function;
+      else
+        goto obj_type;
+    } break;
+    case JS_TAG_NULL:
+    obj_type:
+      atom = JS_ATOM_object;
+      break;
+    case JS_TAG_SYMBOL:
+      atom = JS_ATOM_symbol;
+      break;
+    default:
+      atom = JS_ATOM_unknown;
+      break;
+  }
+  return atom;
+}
+
+__exception int js_operator_delete(JSContext* ctx, JSValue* sp) {
+  JSValue op1, op2;
+  JSAtom atom;
+  int ret;
+
+  op1 = sp[-2];
+  op2 = sp[-1];
+  atom = JS_ValueToAtom(ctx, op2);
+  if (unlikely(atom == JS_ATOM_NULL))
+    return -1;
+  ret = JS_DeleteProperty(ctx, op1, atom, JS_PROP_THROW_STRICT);
+  JS_FreeAtom(ctx, atom);
+  if (unlikely(ret < 0))
+    return -1;
+  JS_FreeValue(ctx, op1);
+  JS_FreeValue(ctx, op2);
+  sp[-2] = JS_NewBool(ctx, ret);
+  return 0;
+}
+
+JSValue js_throw_type_error(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  return JS_ThrowTypeError(ctx, "invalid property access");
+}
+
+JSValue js_build_rest(JSContext* ctx, int first, int argc, JSValueConst* argv) {
+  JSValue val;
+  int i, ret;
+
+  val = JS_NewArray(ctx);
+  if (JS_IsException(val))
+    return val;
+  for (i = first; i < argc; i++) {
+    ret = JS_DefinePropertyValueUint32(ctx, val, i - first, JS_DupValue(ctx, argv[i]), JS_PROP_C_W_E);
+    if (ret < 0) {
+      JS_FreeValue(ctx, val);
+      return JS_EXCEPTION;
+    }
+  }
+  return val;
+}
+
+JSValue build_for_in_iterator(JSContext* ctx, JSValue obj) {
+  JSObject* p;
+  JSPropertyEnum* tab_atom;
+  int i;
+  JSValue enum_obj, obj1;
+  JSForInIterator* it;
+  uint32_t tag, tab_atom_count;
+
+  tag = JS_VALUE_GET_TAG(obj);
+  if (tag != JS_TAG_OBJECT && tag != JS_TAG_NULL && tag != JS_TAG_UNDEFINED) {
+    obj = JS_ToObjectFree(ctx, obj);
+  }
+
+  it = js_malloc(ctx, sizeof(*it));
+  if (!it) {
+    JS_FreeValue(ctx, obj);
+    return JS_EXCEPTION;
+  }
+  enum_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_FOR_IN_ITERATOR);
+  if (JS_IsException(enum_obj)) {
+    js_free(ctx, it);
+    JS_FreeValue(ctx, obj);
+    return JS_EXCEPTION;
+  }
+  it->is_array = FALSE;
+  it->obj = obj;
+  it->idx = 0;
+  p = JS_VALUE_GET_OBJ(enum_obj);
+  p->u.for_in_iterator = it;
+
+  if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)
+    return enum_obj;
+
+  /* fast path: assume no enumerable properties in the prototype chain */
+  obj1 = JS_DupValue(ctx, obj);
+  for (;;) {
+    obj1 = JS_GetPrototypeFree(ctx, obj1);
+    if (JS_IsNull(obj1))
+      break;
+    if (JS_IsException(obj1))
+      goto fail;
+    if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, JS_VALUE_GET_OBJ(obj1),
+                                       JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) {
+      JS_FreeValue(ctx, obj1);
+      goto fail;
+    }
+    js_free_prop_enum(ctx, tab_atom, tab_atom_count);
+    if (tab_atom_count != 0) {
+      JS_FreeValue(ctx, obj1);
+      goto slow_path;
+    }
+    /* must check for timeout to avoid infinite loop */
+    if (js_poll_interrupts(ctx)) {
+      JS_FreeValue(ctx, obj1);
+      goto fail;
+    }
+  }
+
+  p = JS_VALUE_GET_OBJ(obj);
+
+  if (p->fast_array) {
+    JSShape* sh;
+    JSShapeProperty* prs;
+    /* check that there are no enumerable normal fields */
+    sh = p->shape;
+    for (i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
+      if (prs->flags & JS_PROP_ENUMERABLE)
+        goto normal_case;
+    }
+    /* for fast arrays, we only store the number of elements */
+    it->is_array = TRUE;
+    it->array_length = p->u.array.count;
+  } else {
+  normal_case:
+    if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p, JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY))
+      goto fail;
+    for (i = 0; i < tab_atom_count; i++) {
+      JS_SetPropertyInternal(ctx, enum_obj, tab_atom[i].atom, JS_NULL, 0);
+    }
+    js_free_prop_enum(ctx, tab_atom, tab_atom_count);
+  }
+  return enum_obj;
+
+slow_path:
+  /* non enumerable properties hide the enumerables ones in the
+     prototype chain */
+  obj1 = JS_DupValue(ctx, obj);
+  for (;;) {
+    if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, JS_VALUE_GET_OBJ(obj1),
+                                       JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
+      JS_FreeValue(ctx, obj1);
+      goto fail;
+    }
+    for (i = 0; i < tab_atom_count; i++) {
+      JS_DefinePropertyValue(ctx, enum_obj, tab_atom[i].atom, JS_NULL,
+                             (tab_atom[i].is_enumerable ? JS_PROP_ENUMERABLE : 0));
+    }
+    js_free_prop_enum(ctx, tab_atom, tab_atom_count);
+    obj1 = JS_GetPrototypeFree(ctx, obj1);
+    if (JS_IsNull(obj1))
+      break;
+    if (JS_IsException(obj1))
+      goto fail;
+    /* must check for timeout to avoid infinite loop */
+    if (js_poll_interrupts(ctx)) {
+      JS_FreeValue(ctx, obj1);
+      goto fail;
+    }
+  }
+  return enum_obj;
+
+fail:
+  JS_FreeValue(ctx, enum_obj);
+  return JS_EXCEPTION;
+}
+
+/* obj -> enum_obj */
+__exception int js_for_in_start(JSContext* ctx, JSValue* sp) {
+  sp[-1] = build_for_in_iterator(ctx, sp[-1]);
+  if (JS_IsException(sp[-1]))
+    return -1;
+  return 0;
+}
+
+/* enum_obj -> enum_obj value done */
+__exception int js_for_in_next(JSContext* ctx, JSValue* sp) {
+  JSValueConst enum_obj;
+  JSObject* p;
+  JSAtom prop;
+  JSForInIterator* it;
+  int ret;
+
+  enum_obj = sp[-1];
+  /* fail safe */
+  if (JS_VALUE_GET_TAG(enum_obj) != JS_TAG_OBJECT)
+    goto done;
+  p = JS_VALUE_GET_OBJ(enum_obj);
+  if (p->class_id != JS_CLASS_FOR_IN_ITERATOR)
+    goto done;
+  it = p->u.for_in_iterator;
+
+  for (;;) {
+    if (it->is_array) {
+      if (it->idx >= it->array_length)
+        goto done;
+      prop = __JS_AtomFromUInt32(it->idx);
+      it->idx++;
+    } else {
+      JSShape* sh = p->shape;
+      JSShapeProperty* prs;
+      if (it->idx >= sh->prop_count)
+        goto done;
+      prs = get_shape_prop(sh) + it->idx;
+      prop = prs->atom;
+      it->idx++;
+      if (prop == JS_ATOM_NULL || !(prs->flags & JS_PROP_ENUMERABLE))
+        continue;
+    }
+    /* check if the property was deleted */
+    ret = JS_HasProperty(ctx, it->obj, prop);
+    if (ret < 0)
+      return ret;
+    if (ret)
+      break;
+  }
+  /* return the property */
+  sp[0] = JS_AtomToValue(ctx, prop);
+  sp[1] = JS_FALSE;
+  return 0;
+done:
+  /* return the end */
+  sp[0] = JS_UNDEFINED;
+  sp[1] = JS_TRUE;
+  return 0;
+}
+
+JSValue JS_GetIterator2(JSContext* ctx, JSValueConst obj, JSValueConst method) {
+  JSValue enum_obj;
+
+  enum_obj = JS_Call(ctx, method, obj, 0, NULL);
+  if (JS_IsException(enum_obj))
+    return enum_obj;
+  if (!JS_IsObject(enum_obj)) {
+    JS_FreeValue(ctx, enum_obj);
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+  }
+  return enum_obj;
+}
+
+
+JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx,
+                                              JSValueConst sync_iter)
+{
+  JSValue async_iter, next_method;
+  JSAsyncFromSyncIteratorData *s;
+
+  next_method = JS_GetProperty(ctx, sync_iter, JS_ATOM_next);
+  if (JS_IsException(next_method))
+    return JS_EXCEPTION;
+  async_iter = JS_NewObjectClass(ctx, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
+  if (JS_IsException(async_iter)) {
+    JS_FreeValue(ctx, next_method);
+    return async_iter;
+  }
+  s = js_mallocz(ctx, sizeof(*s));
+  if (!s) {
+    JS_FreeValue(ctx, async_iter);
+    JS_FreeValue(ctx, next_method);
+    return JS_EXCEPTION;
+  }
+  s->sync_iter = JS_DupValue(ctx, sync_iter);
+  s->next_method = next_method;
+  JS_SetOpaque(async_iter, s);
+  return async_iter;
+}
+
+JSValue JS_GetIterator(JSContext* ctx, JSValueConst obj, BOOL is_async) {
+  JSValue method, ret, sync_iter;
+
+  if (is_async) {
+    method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_asyncIterator);
+    if (JS_IsException(method))
+      return method;
+    if (JS_IsUndefined(method) || JS_IsNull(method)) {
+      method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
+      if (JS_IsException(method))
+        return method;
+      sync_iter = JS_GetIterator2(ctx, obj, method);
+      JS_FreeValue(ctx, method);
+      if (JS_IsException(sync_iter))
+        return sync_iter;
+      ret = JS_CreateAsyncFromSyncIterator(ctx, sync_iter);
+      JS_FreeValue(ctx, sync_iter);
+      return ret;
+    }
+  } else {
+    method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
+    if (JS_IsException(method))
+      return method;
+  }
+  if (!JS_IsFunction(ctx, method)) {
+    JS_FreeValue(ctx, method);
+    return JS_ThrowTypeError(ctx, "value is not iterable");
+  }
+  ret = JS_GetIterator2(ctx, obj, method);
+  JS_FreeValue(ctx, method);
+  return ret;
+}
+
+/* return *pdone = 2 if the iterator object is not parsed */
+JSValue JS_IteratorNext2(JSContext* ctx,
+                                JSValueConst enum_obj,
+                                JSValueConst method,
+                                int argc,
+                                JSValueConst* argv,
+                                int* pdone) {
+  JSValue obj;
+
+  /* fast path for the built-in iterators (avoid creating the
+     intermediate result object) */
+  if (JS_IsObject(method)) {
+    JSObject* p = JS_VALUE_GET_OBJ(method);
+    if (p->class_id == JS_CLASS_C_FUNCTION && p->u.cfunc.cproto == JS_CFUNC_iterator_next) {
+      JSCFunctionType func;
+      JSValueConst args[1];
+
+      /* in case the function expects one argument */
+      if (argc == 0) {
+        args[0] = JS_UNDEFINED;
+        argv = args;
+      }
+      func = p->u.cfunc.c_function;
+      return func.iterator_next(ctx, enum_obj, argc, argv, pdone, p->u.cfunc.magic);
+    }
+  }
+  obj = JS_Call(ctx, method, enum_obj, argc, argv);
+  if (JS_IsException(obj))
+    goto fail;
+  if (!JS_IsObject(obj)) {
+    JS_FreeValue(ctx, obj);
+    JS_ThrowTypeError(ctx, "iterator must return an object");
+    goto fail;
+  }
+  *pdone = 2;
+  return obj;
+fail:
+  *pdone = FALSE;
+  return JS_EXCEPTION;
+}
+
+JSValue JS_IteratorNext(JSContext* ctx,
+                               JSValueConst enum_obj,
+                               JSValueConst method,
+                               int argc,
+                               JSValueConst* argv,
+                               BOOL* pdone) {
+  JSValue obj, value, done_val;
+  int done;
+
+  obj = JS_IteratorNext2(ctx, enum_obj, method, argc, argv, &done);
+  if (JS_IsException(obj))
+    goto fail;
+  if (done != 2) {
+    *pdone = done;
+    return obj;
+  } else {
+    done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);
+    if (JS_IsException(done_val))
+      goto fail;
+    *pdone = JS_ToBoolFree(ctx, done_val);
+    value = JS_UNDEFINED;
+    if (!*pdone) {
+      value = JS_GetProperty(ctx, obj, JS_ATOM_value);
+    }
+    JS_FreeValue(ctx, obj);
+    return value;
+  }
+fail:
+  JS_FreeValue(ctx, obj);
+  *pdone = FALSE;
+  return JS_EXCEPTION;
+}
+
+/* return < 0 in case of exception */
+int JS_IteratorClose(JSContext* ctx, JSValueConst enum_obj, BOOL is_exception_pending) {
+  JSValue method, ret, ex_obj;
+  int res;
+
+  if (is_exception_pending) {
+    ex_obj = ctx->rt->current_exception;
+    ctx->rt->current_exception = JS_NULL;
+    res = -1;
+  } else {
+    ex_obj = JS_UNDEFINED;
+    res = 0;
+  }
+  method = JS_GetProperty(ctx, enum_obj, JS_ATOM_return);
+  if (JS_IsException(method)) {
+    res = -1;
+    goto done;
+  }
+  if (JS_IsUndefined(method) || JS_IsNull(method)) {
+    goto done;
+  }
+  ret = JS_CallFree(ctx, method, enum_obj, 0, NULL);
+  if (!is_exception_pending) {
+    if (JS_IsException(ret)) {
+      res = -1;
+    } else if (!JS_IsObject(ret)) {
+      JS_ThrowTypeErrorNotAnObject(ctx);
+      res = -1;
+    }
+  }
+  JS_FreeValue(ctx, ret);
+done:
+  if (is_exception_pending) {
+    JS_Throw(ctx, ex_obj);
+  }
+  return res;
+}
+
+/* obj -> enum_rec (3 slots) */
+__exception int js_for_of_start(JSContext* ctx, JSValue* sp, BOOL is_async) {
+  JSValue op1, obj, method;
+  op1 = sp[-1];
+  obj = JS_GetIterator(ctx, op1, is_async);
+  if (JS_IsException(obj))
+    return -1;
+  JS_FreeValue(ctx, op1);
+  sp[-1] = obj;
+  method = JS_GetProperty(ctx, obj, JS_ATOM_next);
+  if (JS_IsException(method))
+    return -1;
+  sp[0] = method;
+  return 0;
+}
+
+/* enum_rec [objs] -> enum_rec [objs] value done. There are 'offset'
+   objs. If 'done' is true or in case of exception, 'enum_rec' is set
+   to undefined. If 'done' is true, 'value' is always set to
+   undefined. */
+__exception int js_for_of_next(JSContext* ctx, JSValue* sp, int offset) {
+  JSValue value = JS_UNDEFINED;
+  int done = 1;
+
+  if (likely(!JS_IsUndefined(sp[offset]))) {
+    value = JS_IteratorNext(ctx, sp[offset], sp[offset + 1], 0, NULL, &done);
+    if (JS_IsException(value))
+      done = -1;
+    if (done) {
+      /* value is JS_UNDEFINED or JS_EXCEPTION */
+      /* replace the iteration object with undefined */
+      JS_FreeValue(ctx, sp[offset]);
+      sp[offset] = JS_UNDEFINED;
+      if (done < 0) {
+        return -1;
+      } else {
+        JS_FreeValue(ctx, value);
+        value = JS_UNDEFINED;
+      }
+    }
+  }
+  sp[0] = value;
+  sp[1] = JS_NewBool(ctx, done);
+  return 0;
+}
+
+JSValue JS_IteratorGetCompleteValue(JSContext* ctx, JSValueConst obj, BOOL* pdone) {
+  JSValue done_val, value;
+  BOOL done;
+  done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);
+  if (JS_IsException(done_val))
+    goto fail;
+  done = JS_ToBoolFree(ctx, done_val);
+  value = JS_GetProperty(ctx, obj, JS_ATOM_value);
+  if (JS_IsException(value))
+    goto fail;
+  *pdone = done;
+  return value;
+fail:
+  *pdone = FALSE;
+  return JS_EXCEPTION;
+}
+
+__exception int js_iterator_get_value_done(JSContext* ctx, JSValue* sp) {
+  JSValue obj, value;
+  BOOL done;
+  obj = sp[-1];
+  if (!JS_IsObject(obj)) {
+    JS_ThrowTypeError(ctx, "iterator must return an object");
+    return -1;
+  }
+  value = JS_IteratorGetCompleteValue(ctx, obj, &done);
+  if (JS_IsException(value))
+    return -1;
+  JS_FreeValue(ctx, obj);
+  sp[-1] = value;
+  sp[0] = JS_NewBool(ctx, done);
+  return 0;
+}
\ No newline at end of file
diff --git a/src/core/builtins/js-operator.h b/src/core/builtins/js-operator.h
new file mode 100644
index 000000000..a7e5e4cfe
--- /dev/null
+++ b/src/core/builtins/js-operator.h
@@ -0,0 +1,79 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_OPERATOR_H
+#define QUICKJS_JS_OPERATOR_H
+
+#include "quickjs/cutils.h"
+#include "quickjs/quickjs.h"
+#include "../types.h"
+
+typedef struct JSAsyncFromSyncIteratorData {
+  JSValue sync_iter;
+  JSValue next_method;
+} JSAsyncFromSyncIteratorData;
+
+void js_for_in_iterator_finalizer(JSRuntime* rt, JSValue val);
+void js_for_in_iterator_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func);
+
+void js_for_in_iterator_finalizer(JSRuntime* rt, JSValue val);
+void js_for_in_iterator_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func);
+
+JSValue JS_GetIterator2(JSContext* ctx, JSValueConst obj, JSValueConst method);
+JSValue JS_CreateAsyncFromSyncIterator(JSContext* ctx, JSValueConst sync_iter);
+JSValue JS_GetIterator(JSContext* ctx, JSValueConst obj, BOOL is_async);
+JSValue JS_IteratorGetCompleteValue(JSContext* ctx, JSValueConst obj, BOOL* pdone);
+
+/* return *pdone = 2 if the iterator object is not parsed */
+JSValue JS_IteratorNext2(JSContext* ctx, JSValueConst enum_obj, JSValueConst method, int argc, JSValueConst* argv, int* pdone);
+JSValue JS_IteratorNext(JSContext* ctx, JSValueConst enum_obj, JSValueConst method, int argc, JSValueConst* argv, BOOL* pdone);
+/* return < 0 in case of exception */
+int JS_IteratorClose(JSContext* ctx, JSValueConst enum_obj, BOOL is_exception_pending);
+/* obj -> enum_rec (3 slots) */
+__exception int js_for_of_start(JSContext* ctx, JSValue* sp, BOOL is_async);
+double js_pow(double a, double b);
+JSValue js_throw_type_error(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_build_rest(JSContext* ctx, int first, int argc, JSValueConst* argv);
+JSValue build_for_in_iterator(JSContext* ctx, JSValue obj);
+/* obj -> enum_obj */
+__exception int js_for_in_start(JSContext* ctx, JSValue* sp);
+/* enum_obj -> enum_obj value done */
+__exception int js_for_in_next(JSContext* ctx, JSValue* sp);
+__exception int js_for_of_next(JSContext* ctx, JSValue* sp, int offset);
+
+BOOL js_strict_eq2(JSContext* ctx, JSValue op1, JSValue op2, JSStrictEqModeEnum eq_mode);
+BOOL js_strict_eq(JSContext* ctx, JSValue op1, JSValue op2);
+BOOL js_same_value(JSContext* ctx, JSValueConst op1, JSValueConst op2);
+BOOL js_same_value_zero(JSContext* ctx, JSValueConst op1, JSValueConst op2);
+no_inline int js_strict_eq_slow(JSContext* ctx, JSValue* sp, BOOL is_neq);
+__exception int js_operator_in(JSContext* ctx, JSValue* sp);
+__exception int js_has_unscopable(JSContext* ctx, JSValueConst obj, JSAtom atom);
+__exception int js_operator_instanceof(JSContext* ctx, JSValue* sp);
+__exception int js_operator_typeof(JSContext* ctx, JSValueConst op1);
+__exception int js_operator_delete(JSContext* ctx, JSValue* sp);
+
+__exception int js_iterator_get_value_done(JSContext* ctx, JSValue* sp);
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-promise.c b/src/core/builtins/js-promise.c
new file mode 100644
index 000000000..0f6d87d5c
--- /dev/null
+++ b/src/core/builtins/js-promise.c
@@ -0,0 +1,1321 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-promise.h"
+#include "../convertion.h"
+#include "../exception.h"
+#include "../function.h"
+#include "../object.h"
+#include "../runtime.h"
+#include "js-array.h"
+#include "js-async-function.h"
+#include "js-async-generator.h"
+#include "js-function.h"
+#include "js-generator.h"
+#include "js-object.h"
+#include "js-operator.h"
+
+/* Promise */
+
+typedef enum JSPromiseStateEnum {
+  JS_PROMISE_PENDING,
+  JS_PROMISE_FULFILLED,
+  JS_PROMISE_REJECTED,
+} JSPromiseStateEnum;
+
+typedef struct JSPromiseData {
+  JSPromiseStateEnum promise_state;
+  /* 0=fulfill, 1=reject, list of JSPromiseReactionData.link */
+  struct list_head promise_reactions[2];
+  BOOL is_handled; /* Note: only useful to debug */
+  JSValue promise_result;
+} JSPromiseData;
+
+typedef struct JSPromiseFunctionDataResolved {
+  int ref_count;
+  BOOL already_resolved;
+} JSPromiseFunctionDataResolved;
+
+typedef struct JSPromiseFunctionData {
+  JSValue promise;
+  JSPromiseFunctionDataResolved *presolved;
+} JSPromiseFunctionData;
+
+typedef struct JSPromiseReactionData {
+  struct list_head link; /* not used in promise_reaction_job */
+  JSValue resolving_funcs[2];
+  JSValue handler;
+} JSPromiseReactionData;
+
+int js_create_resolving_functions(JSContext *ctx, JSValue *args,
+                                         JSValueConst promise);
+
+void promise_reaction_data_free(JSRuntime *rt,
+                                       JSPromiseReactionData *rd)
+{
+  JS_FreeValueRT(rt, rd->resolving_funcs[0]);
+  JS_FreeValueRT(rt, rd->resolving_funcs[1]);
+  JS_FreeValueRT(rt, rd->handler);
+  js_free_rt(rt, rd);
+}
+
+JSValue promise_reaction_job(JSContext *ctx, int argc,
+                                    JSValueConst *argv)
+{
+  JSValueConst handler, arg, func;
+  JSValue res, res2;
+  BOOL is_reject;
+
+  assert(argc == 5);
+  handler = argv[2];
+  is_reject = JS_ToBool(ctx, argv[3]);
+  arg = argv[4];
+#ifdef DUMP_PROMISE
+  printf("promise_reaction_job: is_reject=%d\n", is_reject);
+#endif
+
+  if (JS_IsUndefined(handler)) {
+    if (is_reject) {
+      res = JS_Throw(ctx, JS_DupValue(ctx, arg));
+    } else {
+      res = JS_DupValue(ctx, arg);
+    }
+  } else {
+    res = JS_Call(ctx, handler, JS_UNDEFINED, 1, &arg);
+  }
+  is_reject = JS_IsException(res);
+  if (is_reject)
+    res = JS_GetException(ctx);
+  func = argv[is_reject];
+  /* as an extension, we support undefined as value to avoid
+     creating a dummy promise in the 'await' implementation of async
+     functions */
+  if (!JS_IsUndefined(func)) {
+    res2 = JS_Call(ctx, func, JS_UNDEFINED,
+                   1, (JSValueConst *)&res);
+  } else {
+    res2 = JS_UNDEFINED;
+  }
+  JS_FreeValue(ctx, res);
+
+  return res2;
+}
+
+void JS_SetHostPromiseRejectionTracker(JSRuntime *rt,
+                                       JSHostPromiseRejectionTracker *cb,
+                                       void *opaque)
+{
+  rt->host_promise_rejection_tracker = cb;
+  rt->host_promise_rejection_tracker_opaque = opaque;
+}
+
+void fulfill_or_reject_promise(JSContext *ctx, JSValueConst promise,
+                                      JSValueConst value, BOOL is_reject)
+{
+  JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
+  struct list_head *el, *el1;
+  JSPromiseReactionData *rd;
+  JSValueConst args[5];
+
+  if (!s || s->promise_state != JS_PROMISE_PENDING)
+    return; /* should never happen */
+  set_value(ctx, &s->promise_result, JS_DupValue(ctx, value));
+  s->promise_state = JS_PROMISE_FULFILLED + is_reject;
+#ifdef DUMP_PROMISE
+  printf("fulfill_or_reject_promise: is_reject=%d\n", is_reject);
+#endif
+  if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {
+    JSRuntime *rt = ctx->rt;
+    if (rt->host_promise_rejection_tracker) {
+      rt->host_promise_rejection_tracker(ctx, promise, value, FALSE,
+                                         rt->host_promise_rejection_tracker_opaque);
+    }
+  }
+
+  list_for_each_safe(el, el1, &s->promise_reactions[is_reject]) {
+    rd = list_entry(el, JSPromiseReactionData, link);
+    args[0] = rd->resolving_funcs[0];
+    args[1] = rd->resolving_funcs[1];
+    args[2] = rd->handler;
+    args[3] = JS_NewBool(ctx, is_reject);
+    args[4] = value;
+    JS_EnqueueJob(ctx, promise_reaction_job, 5, args);
+    list_del(&rd->link);
+    promise_reaction_data_free(ctx->rt, rd);
+  }
+
+  list_for_each_safe(el, el1, &s->promise_reactions[1 - is_reject]) {
+    rd = list_entry(el, JSPromiseReactionData, link);
+    list_del(&rd->link);
+    promise_reaction_data_free(ctx->rt, rd);
+  }
+}
+
+void reject_promise(JSContext *ctx, JSValueConst promise,
+                           JSValueConst value)
+{
+  fulfill_or_reject_promise(ctx, promise, value, TRUE);
+}
+
+JSValue js_promise_resolve_thenable_job(JSContext *ctx,
+                                               int argc, JSValueConst *argv)
+{
+  JSValueConst promise, thenable, then;
+  JSValue args[2], res;
+
+#ifdef DUMP_PROMISE
+  printf("js_promise_resolve_thenable_job\n");
+#endif
+  assert(argc == 3);
+  promise = argv[0];
+  thenable = argv[1];
+  then = argv[2];
+  if (js_create_resolving_functions(ctx, args, promise) < 0)
+    return JS_EXCEPTION;
+  res = JS_Call(ctx, then, thenable, 2, (JSValueConst *)args);
+  if (JS_IsException(res)) {
+    JSValue error = JS_GetException(ctx);
+    res = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error);
+    JS_FreeValue(ctx, error);
+  }
+  JS_FreeValue(ctx, args[0]);
+  JS_FreeValue(ctx, args[1]);
+  return res;
+}
+
+void js_promise_resolve_function_free_resolved(JSRuntime *rt,
+                                                      JSPromiseFunctionDataResolved *sr)
+{
+  if (--sr->ref_count == 0) {
+    js_free_rt(rt, sr);
+  }
+}
+
+int js_create_resolving_functions(JSContext *ctx,
+                                         JSValue *resolving_funcs,
+                                         JSValueConst promise)
+
+{
+  JSValue obj;
+  JSPromiseFunctionData *s;
+  JSPromiseFunctionDataResolved *sr;
+  int i, ret;
+
+  sr = js_malloc(ctx, sizeof(*sr));
+  if (!sr)
+    return -1;
+  sr->ref_count = 1;
+  sr->already_resolved = FALSE; /* must be shared between the two functions */
+  ret = 0;
+  for(i = 0; i < 2; i++) {
+    obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
+                                 JS_CLASS_PROMISE_RESOLVE_FUNCTION + i);
+    if (JS_IsException(obj))
+      goto fail;
+    s = js_malloc(ctx, sizeof(*s));
+    if (!s) {
+      JS_FreeValue(ctx, obj);
+    fail:
+
+      if (i != 0)
+        JS_FreeValue(ctx, resolving_funcs[0]);
+      ret = -1;
+      break;
+    }
+    sr->ref_count++;
+    s->presolved = sr;
+    s->promise = JS_DupValue(ctx, promise);
+    JS_SetOpaque(obj, s);
+    js_function_set_properties(ctx, obj, JS_ATOM_empty_string, 1);
+    resolving_funcs[i] = obj;
+  }
+  js_promise_resolve_function_free_resolved(ctx->rt, sr);
+  return ret;
+}
+
+void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val)
+{
+  JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data;
+  if (s) {
+    js_promise_resolve_function_free_resolved(rt, s->presolved);
+    JS_FreeValueRT(rt, s->promise);
+    js_free_rt(rt, s);
+  }
+}
+
+void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
+                                             JS_MarkFunc *mark_func)
+{
+  JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data;
+  if (s) {
+    JS_MarkValue(rt, s->promise, mark_func);
+  }
+}
+
+JSValue js_promise_resolve_function_call(JSContext *ctx,
+                                                JSValueConst func_obj,
+                                                JSValueConst this_val,
+                                                int argc, JSValueConst *argv,
+                                                int flags)
+{
+  JSObject *p = JS_VALUE_GET_OBJ(func_obj);
+  JSPromiseFunctionData *s;
+  JSValueConst resolution, args[3];
+  JSValue then;
+  BOOL is_reject;
+
+  s = p->u.promise_function_data;
+  if (!s || s->presolved->already_resolved)
+    return JS_UNDEFINED;
+  s->presolved->already_resolved = TRUE;
+  is_reject = p->class_id - JS_CLASS_PROMISE_RESOLVE_FUNCTION;
+  if (argc > 0)
+    resolution = argv[0];
+  else
+    resolution = JS_UNDEFINED;
+#ifdef DUMP_PROMISE
+  printf("js_promise_resolving_function_call: is_reject=%d resolution=", is_reject);
+  JS_DumpValue(ctx, resolution);
+  printf("\n");
+#endif
+  if (is_reject || !JS_IsObject(resolution)) {
+    goto done;
+  } else if (js_same_value(ctx, resolution, s->promise)) {
+    JS_ThrowTypeError(ctx, "promise self resolution");
+    goto fail_reject;
+  }
+  then = JS_GetProperty(ctx, resolution, JS_ATOM_then);
+  if (JS_IsException(then)) {
+    JSValue error;
+  fail_reject:
+    error = JS_GetException(ctx);
+    reject_promise(ctx, s->promise, error);
+    JS_FreeValue(ctx, error);
+  } else if (!JS_IsFunction(ctx, then)) {
+    JS_FreeValue(ctx, then);
+  done:
+    fulfill_or_reject_promise(ctx, s->promise, resolution, is_reject);
+  } else {
+    args[0] = s->promise;
+    args[1] = resolution;
+    args[2] = then;
+    JS_EnqueueJob(ctx, js_promise_resolve_thenable_job, 3, args);
+    JS_FreeValue(ctx, then);
+  }
+  return JS_UNDEFINED;
+}
+
+void js_promise_finalizer(JSRuntime *rt, JSValue val)
+{
+  JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE);
+  struct list_head *el, *el1;
+  int i;
+
+  if (!s)
+    return;
+  for(i = 0; i < 2; i++) {
+    list_for_each_safe(el, el1, &s->promise_reactions[i]) {
+      JSPromiseReactionData *rd =
+          list_entry(el, JSPromiseReactionData, link);
+      promise_reaction_data_free(rt, rd);
+    }
+  }
+  JS_FreeValueRT(rt, s->promise_result);
+  js_free_rt(rt, s);
+}
+
+void js_promise_mark(JSRuntime *rt, JSValueConst val,
+                            JS_MarkFunc *mark_func)
+{
+  JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE);
+  struct list_head *el;
+  int i;
+
+  if (!s)
+    return;
+  for(i = 0; i < 2; i++) {
+    list_for_each(el, &s->promise_reactions[i]) {
+      JSPromiseReactionData *rd =
+          list_entry(el, JSPromiseReactionData, link);
+      JS_MarkValue(rt, rd->resolving_funcs[0], mark_func);
+      JS_MarkValue(rt, rd->resolving_funcs[1], mark_func);
+      JS_MarkValue(rt, rd->handler, mark_func);
+    }
+  }
+  JS_MarkValue(rt, s->promise_result, mark_func);
+}
+
+JSValue js_promise_constructor(JSContext *ctx, JSValueConst new_target,
+                                      int argc, JSValueConst *argv)
+{
+  JSValueConst executor;
+  JSValue obj;
+  JSPromiseData *s;
+  JSValue args[2], ret;
+  int i;
+
+  executor = argv[0];
+  if (check_function(ctx, executor))
+    return JS_EXCEPTION;
+  obj = js_create_from_ctor(ctx, new_target, JS_CLASS_PROMISE);
+  if (JS_IsException(obj))
+    return JS_EXCEPTION;
+  s = js_mallocz(ctx, sizeof(*s));
+  if (!s)
+    goto fail;
+  s->promise_state = JS_PROMISE_PENDING;
+  s->is_handled = FALSE;
+  for(i = 0; i < 2; i++)
+    init_list_head(&s->promise_reactions[i]);
+  s->promise_result = JS_UNDEFINED;
+  JS_SetOpaque(obj, s);
+  if (js_create_resolving_functions(ctx, args, obj))
+    goto fail;
+  ret = JS_Call(ctx, executor, JS_UNDEFINED, 2, (JSValueConst *)args);
+  if (JS_IsException(ret)) {
+    JSValue ret2, error;
+    error = JS_GetException(ctx);
+    ret2 = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error);
+    JS_FreeValue(ctx, error);
+    if (JS_IsException(ret2))
+      goto fail1;
+    JS_FreeValue(ctx, ret2);
+  }
+  JS_FreeValue(ctx, ret);
+  JS_FreeValue(ctx, args[0]);
+  JS_FreeValue(ctx, args[1]);
+  return obj;
+fail1:
+  JS_FreeValue(ctx, args[0]);
+  JS_FreeValue(ctx, args[1]);
+fail:
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+JSValue js_promise_executor(JSContext *ctx,
+                                   JSValueConst this_val,
+                                   int argc, JSValueConst *argv,
+                                   int magic, JSValue *func_data)
+{
+  int i;
+
+  for(i = 0; i < 2; i++) {
+    if (!JS_IsUndefined(func_data[i]))
+      return JS_ThrowTypeError(ctx, "resolving function already set");
+    func_data[i] = JS_DupValue(ctx, argv[i]);
+  }
+  return JS_UNDEFINED;
+}
+
+JSValue js_promise_executor_new(JSContext *ctx)
+{
+  JSValueConst func_data[2];
+
+  func_data[0] = JS_UNDEFINED;
+  func_data[1] = JS_UNDEFINED;
+  return JS_NewCFunctionData(ctx, js_promise_executor, 2,
+                             0, 2, func_data);
+}
+
+JSValue js_new_promise_capability(JSContext *ctx,
+                                         JSValue *resolving_funcs,
+                                         JSValueConst ctor)
+{
+  JSValue executor, result_promise;
+  JSCFunctionDataRecord *s;
+  int i;
+
+  executor = js_promise_executor_new(ctx);
+  if (JS_IsException(executor))
+    return executor;
+
+  if (JS_IsUndefined(ctor)) {
+    result_promise = js_promise_constructor(ctx, ctor, 1,
+                                            (JSValueConst *)&executor);
+  } else {
+    result_promise = JS_CallConstructor(ctx, ctor, 1,
+                                        (JSValueConst *)&executor);
+  }
+  if (JS_IsException(result_promise))
+    goto fail;
+  s = JS_GetOpaque(executor, JS_CLASS_C_FUNCTION_DATA);
+  for(i = 0; i < 2; i++) {
+    if (check_function(ctx, s->data[i]))
+      goto fail;
+  }
+  for(i = 0; i < 2; i++)
+    resolving_funcs[i] = JS_DupValue(ctx, s->data[i]);
+  JS_FreeValue(ctx, executor);
+  return result_promise;
+fail:
+  JS_FreeValue(ctx, executor);
+  JS_FreeValue(ctx, result_promise);
+  return JS_EXCEPTION;
+}
+
+JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs)
+{
+  return js_new_promise_capability(ctx, resolving_funcs, JS_UNDEFINED);
+}
+
+JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
+                                  int argc, JSValueConst *argv, int magic)
+{
+  JSValue result_promise, resolving_funcs[2], ret;
+  BOOL is_reject = magic;
+
+  if (!JS_IsObject(this_val))
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+  if (!is_reject && JS_GetOpaque(argv[0], JS_CLASS_PROMISE)) {
+    JSValue ctor;
+    BOOL is_same;
+    ctor = JS_GetProperty(ctx, argv[0], JS_ATOM_constructor);
+    if (JS_IsException(ctor))
+      return ctor;
+    is_same = js_same_value(ctx, ctor, this_val);
+    JS_FreeValue(ctx, ctor);
+    if (is_same)
+      return JS_DupValue(ctx, argv[0]);
+  }
+  result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
+  if (JS_IsException(result_promise))
+    return result_promise;
+  ret = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED, 1, argv);
+  JS_FreeValue(ctx, resolving_funcs[0]);
+  JS_FreeValue(ctx, resolving_funcs[1]);
+  if (JS_IsException(ret)) {
+    JS_FreeValue(ctx, result_promise);
+    return ret;
+  }
+  JS_FreeValue(ctx, ret);
+  return result_promise;
+}
+
+#if 0
+JSValue js_promise___newPromiseCapability(JSContext *ctx,
+                                                 JSValueConst this_val,
+                                                 int argc, JSValueConst *argv)
+{
+    JSValue result_promise, resolving_funcs[2], obj;
+    JSValueConst ctor;
+    ctor = argv[0];
+    if (!JS_IsObject(ctor))
+        return JS_ThrowTypeErrorNotAnObject(ctx);
+    result_promise = js_new_promise_capability(ctx, resolving_funcs, ctor);
+    if (JS_IsException(result_promise))
+        return result_promise;
+    obj = JS_NewObject(ctx);
+    if (JS_IsException(obj)) {
+        JS_FreeValue(ctx, resolving_funcs[0]);
+        JS_FreeValue(ctx, resolving_funcs[1]);
+        JS_FreeValue(ctx, result_promise);
+        return JS_EXCEPTION;
+    }
+    JS_DefinePropertyValue(ctx, obj, JS_ATOM_promise, result_promise, JS_PROP_C_W_E);
+    JS_DefinePropertyValue(ctx, obj, JS_ATOM_resolve, resolving_funcs[0], JS_PROP_C_W_E);
+    JS_DefinePropertyValue(ctx, obj, JS_ATOM_reject, resolving_funcs[1], JS_PROP_C_W_E);
+    return obj;
+}
+#endif
+
+__exception int remainingElementsCount_add(JSContext *ctx,
+                                                  JSValueConst resolve_element_env,
+                                                  int addend)
+{
+  JSValue val;
+  int remainingElementsCount;
+
+  val = JS_GetPropertyUint32(ctx, resolve_element_env, 0);
+  if (JS_IsException(val))
+    return -1;
+  if (JS_ToInt32Free(ctx, &remainingElementsCount, val))
+    return -1;
+  remainingElementsCount += addend;
+  if (JS_SetPropertyUint32(ctx, resolve_element_env, 0,
+                           JS_NewInt32(ctx, remainingElementsCount)) < 0)
+    return -1;
+  return (remainingElementsCount == 0);
+}
+
+#define PROMISE_MAGIC_all        0
+#define PROMISE_MAGIC_allSettled 1
+#define PROMISE_MAGIC_any        2
+
+JSValue js_promise_all_resolve_element(JSContext *ctx,
+                                              JSValueConst this_val,
+                                              int argc, JSValueConst *argv,
+                                              int magic,
+                                              JSValue *func_data)
+{
+  int resolve_type = magic & 3;
+  int is_reject = magic & 4;
+  BOOL alreadyCalled = JS_ToBool(ctx, func_data[0]);
+  JSValueConst values = func_data[2];
+  JSValueConst resolve = func_data[3];
+  JSValueConst resolve_element_env = func_data[4];
+  JSValue ret, obj;
+  int is_zero, index;
+
+  if (JS_ToInt32(ctx, &index, func_data[1]))
+    return JS_EXCEPTION;
+  if (alreadyCalled)
+    return JS_UNDEFINED;
+  func_data[0] = JS_NewBool(ctx, TRUE);
+
+  if (resolve_type == PROMISE_MAGIC_allSettled) {
+    JSValue str;
+
+    obj = JS_NewObject(ctx);
+    if (JS_IsException(obj))
+      return JS_EXCEPTION;
+    str = JS_NewString(ctx, is_reject ? "rejected" : "fulfilled");
+    if (JS_IsException(str))
+      goto fail1;
+    if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_status,
+                               str,
+                               JS_PROP_C_W_E) < 0)
+      goto fail1;
+    if (JS_DefinePropertyValue(ctx, obj,
+                               is_reject ? JS_ATOM_reason : JS_ATOM_value,
+                               JS_DupValue(ctx, argv[0]),
+                               JS_PROP_C_W_E) < 0) {
+    fail1:
+      JS_FreeValue(ctx, obj);
+      return JS_EXCEPTION;
+    }
+  } else {
+    obj = JS_DupValue(ctx, argv[0]);
+  }
+  if (JS_DefinePropertyValueUint32(ctx, values, index,
+                                   obj, JS_PROP_C_W_E) < 0)
+    return JS_EXCEPTION;
+
+  is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1);
+  if (is_zero < 0)
+    return JS_EXCEPTION;
+  if (is_zero) {
+    if (resolve_type == PROMISE_MAGIC_any) {
+      JSValue error;
+      error = js_aggregate_error_constructor(ctx, values);
+      if (JS_IsException(error))
+        return JS_EXCEPTION;
+      ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&error);
+      JS_FreeValue(ctx, error);
+    } else {
+      ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&values);
+    }
+    if (JS_IsException(ret))
+      return ret;
+    JS_FreeValue(ctx, ret);
+  }
+  return JS_UNDEFINED;
+}
+
+/* magic = 0: Promise.all 1: Promise.allSettled */
+JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
+                              int argc, JSValueConst *argv, int magic)
+{
+  JSValue result_promise, resolving_funcs[2], item, next_promise, ret;
+  JSValue next_method = JS_UNDEFINED, values = JS_UNDEFINED;
+  JSValue resolve_element_env = JS_UNDEFINED, resolve_element, reject_element;
+  JSValue promise_resolve = JS_UNDEFINED, iter = JS_UNDEFINED;
+  JSValueConst then_args[2], resolve_element_data[5];
+  BOOL done;
+  int index, is_zero, is_promise_any = (magic == PROMISE_MAGIC_any);
+
+  if (!JS_IsObject(this_val))
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+  result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
+  if (JS_IsException(result_promise))
+    return result_promise;
+  promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);
+  if (JS_IsException(promise_resolve) ||
+      check_function(ctx, promise_resolve))
+    goto fail_reject;
+  iter = JS_GetIterator(ctx, argv[0], FALSE);
+  if (JS_IsException(iter)) {
+    JSValue error;
+  fail_reject:
+    error = JS_GetException(ctx);
+    ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
+                  (JSValueConst *)&error);
+    JS_FreeValue(ctx, error);
+    if (JS_IsException(ret))
+      goto fail;
+    JS_FreeValue(ctx, ret);
+  } else {
+    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
+    if (JS_IsException(next_method))
+      goto fail_reject;
+    values = JS_NewArray(ctx);
+    if (JS_IsException(values))
+      goto fail_reject;
+    resolve_element_env = JS_NewArray(ctx);
+    if (JS_IsException(resolve_element_env))
+      goto fail_reject;
+    /* remainingElementsCount field */
+    if (JS_DefinePropertyValueUint32(ctx, resolve_element_env, 0,
+                                     JS_NewInt32(ctx, 1),
+                                     JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
+      goto fail_reject;
+
+    index = 0;
+    for(;;) {
+      /* XXX: conformance: should close the iterator if error on 'done'
+         access, but not on 'value' access */
+      item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
+      if (JS_IsException(item))
+        goto fail_reject;
+      if (done)
+        break;
+      next_promise = JS_Call(ctx, promise_resolve,
+                             this_val, 1, (JSValueConst *)&item);
+      JS_FreeValue(ctx, item);
+      if (JS_IsException(next_promise)) {
+      fail_reject1:
+        JS_IteratorClose(ctx, iter, TRUE);
+        goto fail_reject;
+      }
+      resolve_element_data[0] = JS_NewBool(ctx, FALSE);
+      resolve_element_data[1] = (JSValueConst)JS_NewInt32(ctx, index);
+      resolve_element_data[2] = values;
+      resolve_element_data[3] = resolving_funcs[is_promise_any];
+      resolve_element_data[4] = resolve_element_env;
+      resolve_element =
+          JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,
+                              magic, 5, resolve_element_data);
+      if (JS_IsException(resolve_element)) {
+        JS_FreeValue(ctx, next_promise);
+        goto fail_reject1;
+      }
+
+      if (magic == PROMISE_MAGIC_allSettled) {
+        reject_element =
+            JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,
+                                magic | 4, 5, resolve_element_data);
+        if (JS_IsException(reject_element)) {
+          JS_FreeValue(ctx, next_promise);
+          goto fail_reject1;
+        }
+      } else if (magic == PROMISE_MAGIC_any) {
+        if (JS_DefinePropertyValueUint32(ctx, values, index,
+                                         JS_UNDEFINED, JS_PROP_C_W_E) < 0)
+          goto fail_reject1;
+        reject_element = resolve_element;
+        resolve_element = JS_DupValue(ctx, resolving_funcs[0]);
+      } else {
+        reject_element = JS_DupValue(ctx, resolving_funcs[1]);
+      }
+
+      if (remainingElementsCount_add(ctx, resolve_element_env, 1) < 0) {
+        JS_FreeValue(ctx, next_promise);
+        JS_FreeValue(ctx, resolve_element);
+        JS_FreeValue(ctx, reject_element);
+        goto fail_reject1;
+      }
+
+      then_args[0] = resolve_element;
+      then_args[1] = reject_element;
+      ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2, then_args);
+      JS_FreeValue(ctx, resolve_element);
+      JS_FreeValue(ctx, reject_element);
+      if (check_exception_free(ctx, ret))
+        goto fail_reject1;
+      index++;
+    }
+
+    is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1);
+    if (is_zero < 0)
+      goto fail_reject;
+    if (is_zero) {
+      if (magic == PROMISE_MAGIC_any) {
+        JSValue error;
+        error = js_aggregate_error_constructor(ctx, values);
+        if (JS_IsException(error))
+          goto fail_reject;
+        JS_FreeValue(ctx, values);
+        values = error;
+      }
+      ret = JS_Call(ctx, resolving_funcs[is_promise_any], JS_UNDEFINED,
+                    1, (JSValueConst *)&values);
+      if (check_exception_free(ctx, ret))
+        goto fail_reject;
+    }
+  }
+done:
+  JS_FreeValue(ctx, promise_resolve);
+  JS_FreeValue(ctx, resolve_element_env);
+  JS_FreeValue(ctx, values);
+  JS_FreeValue(ctx, next_method);
+  JS_FreeValue(ctx, iter);
+  JS_FreeValue(ctx, resolving_funcs[0]);
+  JS_FreeValue(ctx, resolving_funcs[1]);
+  return result_promise;
+fail:
+  JS_FreeValue(ctx, result_promise);
+  result_promise = JS_EXCEPTION;
+  goto done;
+}
+
+JSValue js_promise_race(JSContext *ctx, JSValueConst this_val,
+                               int argc, JSValueConst *argv)
+{
+  JSValue result_promise, resolving_funcs[2], item, next_promise, ret;
+  JSValue next_method = JS_UNDEFINED, iter = JS_UNDEFINED;
+  JSValue promise_resolve = JS_UNDEFINED;
+  BOOL done;
+
+  if (!JS_IsObject(this_val))
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+  result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
+  if (JS_IsException(result_promise))
+    return result_promise;
+  promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);
+  if (JS_IsException(promise_resolve) ||
+      check_function(ctx, promise_resolve))
+    goto fail_reject;
+  iter = JS_GetIterator(ctx, argv[0], FALSE);
+  if (JS_IsException(iter)) {
+    JSValue error;
+  fail_reject:
+    error = JS_GetException(ctx);
+    ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
+                  (JSValueConst *)&error);
+    JS_FreeValue(ctx, error);
+    if (JS_IsException(ret))
+      goto fail;
+    JS_FreeValue(ctx, ret);
+  } else {
+    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
+    if (JS_IsException(next_method))
+      goto fail_reject;
+
+    for(;;) {
+      /* XXX: conformance: should close the iterator if error on 'done'
+         access, but not on 'value' access */
+      item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
+      if (JS_IsException(item))
+        goto fail_reject;
+      if (done)
+        break;
+      next_promise = JS_Call(ctx, promise_resolve,
+                             this_val, 1, (JSValueConst *)&item);
+      JS_FreeValue(ctx, item);
+      if (JS_IsException(next_promise)) {
+      fail_reject1:
+        JS_IteratorClose(ctx, iter, TRUE);
+        goto fail_reject;
+      }
+      ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2,
+                          (JSValueConst *)resolving_funcs);
+      if (check_exception_free(ctx, ret))
+        goto fail_reject1;
+    }
+  }
+done:
+  JS_FreeValue(ctx, promise_resolve);
+  JS_FreeValue(ctx, next_method);
+  JS_FreeValue(ctx, iter);
+  JS_FreeValue(ctx, resolving_funcs[0]);
+  JS_FreeValue(ctx, resolving_funcs[1]);
+  return result_promise;
+fail:
+  //JS_FreeValue(ctx, next_method); // why not???
+  JS_FreeValue(ctx, result_promise);
+  result_promise = JS_EXCEPTION;
+  goto done;
+}
+
+__exception int perform_promise_then(JSContext *ctx,
+                                            JSValueConst promise,
+                                            JSValueConst *resolve_reject,
+                                            JSValueConst *cap_resolving_funcs)
+{
+  JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
+  JSPromiseReactionData *rd_array[2], *rd;
+  int i, j;
+
+  rd_array[0] = NULL;
+  rd_array[1] = NULL;
+  for(i = 0; i < 2; i++) {
+    JSValueConst handler;
+    rd = js_mallocz(ctx, sizeof(*rd));
+    if (!rd) {
+      if (i == 1)
+        promise_reaction_data_free(ctx->rt, rd_array[0]);
+      return -1;
+    }
+    for(j = 0; j < 2; j++)
+      rd->resolving_funcs[j] = JS_DupValue(ctx, cap_resolving_funcs[j]);
+    handler = resolve_reject[i];
+    if (!JS_IsFunction(ctx, handler))
+      handler = JS_UNDEFINED;
+    rd->handler = JS_DupValue(ctx, handler);
+    rd_array[i] = rd;
+  }
+
+  if (s->promise_state == JS_PROMISE_PENDING) {
+    for(i = 0; i < 2; i++)
+      list_add_tail(&rd_array[i]->link, &s->promise_reactions[i]);
+  } else {
+    JSValueConst args[5];
+    if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {
+      JSRuntime *rt = ctx->rt;
+      if (rt->host_promise_rejection_tracker) {
+        rt->host_promise_rejection_tracker(ctx, promise, s->promise_result,
+                                           TRUE, rt->host_promise_rejection_tracker_opaque);
+      }
+    }
+    i = s->promise_state - JS_PROMISE_FULFILLED;
+    rd = rd_array[i];
+    args[0] = rd->resolving_funcs[0];
+    args[1] = rd->resolving_funcs[1];
+    args[2] = rd->handler;
+    args[3] = JS_NewBool(ctx, i);
+    args[4] = s->promise_result;
+    JS_EnqueueJob(ctx, promise_reaction_job, 5, args);
+    for(i = 0; i < 2; i++)
+      promise_reaction_data_free(ctx->rt, rd_array[i]);
+  }
+  s->is_handled = TRUE;
+  return 0;
+}
+
+JSValue js_promise_then(JSContext *ctx, JSValueConst this_val,
+                               int argc, JSValueConst *argv)
+{
+  JSValue ctor, result_promise, resolving_funcs[2];
+  JSPromiseData *s;
+  int i, ret;
+
+  s = JS_GetOpaque2(ctx, this_val, JS_CLASS_PROMISE);
+  if (!s)
+    return JS_EXCEPTION;
+
+  ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
+  if (JS_IsException(ctor))
+    return ctor;
+  result_promise = js_new_promise_capability(ctx, resolving_funcs, ctor);
+  JS_FreeValue(ctx, ctor);
+  if (JS_IsException(result_promise))
+    return result_promise;
+  ret = perform_promise_then(ctx, this_val, argv,
+                             (JSValueConst *)resolving_funcs);
+  for(i = 0; i < 2; i++)
+    JS_FreeValue(ctx, resolving_funcs[i]);
+  if (ret) {
+    JS_FreeValue(ctx, result_promise);
+    return JS_EXCEPTION;
+  }
+  return result_promise;
+}
+
+JSValue js_promise_catch(JSContext *ctx, JSValueConst this_val,
+                                int argc, JSValueConst *argv)
+{
+  JSValueConst args[2];
+  args[0] = JS_UNDEFINED;
+  args[1] = argv[0];
+  return JS_Invoke(ctx, this_val, JS_ATOM_then, 2, args);
+}
+
+JSValue js_promise_finally_value_thunk(JSContext *ctx, JSValueConst this_val,
+                                              int argc, JSValueConst *argv,
+                                              int magic, JSValue *func_data)
+{
+  return JS_DupValue(ctx, func_data[0]);
+}
+
+JSValue js_promise_finally_thrower(JSContext *ctx, JSValueConst this_val,
+                                          int argc, JSValueConst *argv,
+                                          int magic, JSValue *func_data)
+{
+  return JS_Throw(ctx, JS_DupValue(ctx, func_data[0]));
+}
+
+JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_val,
+                                            int argc, JSValueConst *argv,
+                                            int magic, JSValue *func_data)
+{
+  JSValueConst ctor = func_data[0];
+  JSValueConst onFinally = func_data[1];
+  JSValue res, promise, ret, then_func;
+
+  res = JS_Call(ctx, onFinally, JS_UNDEFINED, 0, NULL);
+  if (JS_IsException(res))
+    return res;
+  promise = js_promise_resolve(ctx, ctor, 1, (JSValueConst *)&res, 0);
+  JS_FreeValue(ctx, res);
+  if (JS_IsException(promise))
+    return promise;
+  if (magic == 0) {
+    then_func = JS_NewCFunctionData(ctx, js_promise_finally_value_thunk, 0,
+                                    0, 1, argv);
+  } else {
+    then_func = JS_NewCFunctionData(ctx, js_promise_finally_thrower, 0,
+                                    0, 1, argv);
+  }
+  if (JS_IsException(then_func)) {
+    JS_FreeValue(ctx, promise);
+    return then_func;
+  }
+  ret = JS_InvokeFree(ctx, promise, JS_ATOM_then, 1, (JSValueConst *)&then_func);
+  JS_FreeValue(ctx, then_func);
+  return ret;
+}
+
+JSValue js_promise_finally(JSContext *ctx, JSValueConst this_val,
+                                  int argc, JSValueConst *argv)
+{
+  JSValueConst onFinally = argv[0];
+  JSValue ctor, ret;
+  JSValue then_funcs[2];
+  JSValueConst func_data[2];
+  int i;
+
+  ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
+  if (JS_IsException(ctor))
+    return ctor;
+  if (!JS_IsFunction(ctx, onFinally)) {
+    then_funcs[0] = JS_DupValue(ctx, onFinally);
+    then_funcs[1] = JS_DupValue(ctx, onFinally);
+  } else {
+    func_data[0] = ctor;
+    func_data[1] = onFinally;
+    for(i = 0; i < 2; i++) {
+      then_funcs[i] = JS_NewCFunctionData(ctx, js_promise_then_finally_func, 1, i, 2, func_data);
+      if (JS_IsException(then_funcs[i])) {
+        if (i == 1)
+          JS_FreeValue(ctx, then_funcs[0]);
+        JS_FreeValue(ctx, ctor);
+        return JS_EXCEPTION;
+      }
+    }
+  }
+  JS_FreeValue(ctx, ctor);
+  ret = JS_Invoke(ctx, this_val, JS_ATOM_then, 2, (JSValueConst *)then_funcs);
+  JS_FreeValue(ctx, then_funcs[0]);
+  JS_FreeValue(ctx, then_funcs[1]);
+  return ret;
+}
+
+
+void js_async_from_sync_iterator_finalizer(JSRuntime *rt, JSValue val)
+{
+  JSAsyncFromSyncIteratorData *s =
+      JS_GetOpaque(val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
+  if (s) {
+    JS_FreeValueRT(rt, s->sync_iter);
+    JS_FreeValueRT(rt, s->next_method);
+    js_free_rt(rt, s);
+  }
+}
+
+void js_async_from_sync_iterator_mark(JSRuntime *rt, JSValueConst val,
+                                             JS_MarkFunc *mark_func)
+{
+  JSAsyncFromSyncIteratorData *s =
+      JS_GetOpaque(val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
+  if (s) {
+    JS_MarkValue(rt, s->sync_iter, mark_func);
+    JS_MarkValue(rt, s->next_method, mark_func);
+  }
+}
+
+
+JSValue js_async_from_sync_iterator_unwrap(JSContext *ctx,
+                                                  JSValueConst this_val,
+                                                  int argc, JSValueConst *argv,
+                                                  int magic, JSValue *func_data)
+{
+  return js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]),
+                                   JS_ToBool(ctx, func_data[0]));
+}
+
+JSValue js_async_from_sync_iterator_unwrap_func_create(JSContext *ctx,
+                                                              BOOL done)
+{
+  JSValueConst func_data[1];
+
+  func_data[0] = (JSValueConst)JS_NewBool(ctx, done);
+  return JS_NewCFunctionData(ctx, js_async_from_sync_iterator_unwrap,
+                             1, 0, 1, func_data);
+}
+
+/* AsyncIteratorPrototype */
+
+const JSCFunctionListEntry js_async_iterator_proto_funcs[] = {
+    JS_CFUNC_DEF("[Symbol.asyncIterator]", 0, js_iterator_proto_iterator ),
+};
+
+JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst this_val,
+                                                int argc, JSValueConst *argv,
+                                                int magic)
+{
+  JSValue promise, resolving_funcs[2], value, err, method;
+  JSAsyncFromSyncIteratorData *s;
+  int done;
+  int is_reject;
+
+  promise = JS_NewPromiseCapability(ctx, resolving_funcs);
+  if (JS_IsException(promise))
+    return JS_EXCEPTION;
+  s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
+  if (!s) {
+    JS_ThrowTypeError(ctx, "not an Async-from-Sync Iterator");
+    goto reject;
+  }
+
+  if (magic == GEN_MAGIC_NEXT) {
+    method = JS_DupValue(ctx, s->next_method);
+  } else {
+    method = JS_GetProperty(ctx, s->sync_iter,
+                            magic == GEN_MAGIC_RETURN ? JS_ATOM_return :
+                                                      JS_ATOM_throw);
+    if (JS_IsException(method))
+      goto reject;
+    if (JS_IsUndefined(method) || JS_IsNull(method)) {
+      if (magic == GEN_MAGIC_RETURN) {
+        err = js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]), TRUE);
+        is_reject = 0;
+      } else {
+        err = JS_DupValue(ctx, argv[0]);
+        is_reject = 1;
+      }
+      goto done_resolve;
+    }
+  }
+  value = JS_IteratorNext2(ctx, s->sync_iter, method,
+                           argc >= 1 ? 1 : 0, argv, &done);
+  JS_FreeValue(ctx, method);
+  if (JS_IsException(value))
+    goto reject;
+  if (done == 2) {
+    JSValue obj = value;
+    value = JS_IteratorGetCompleteValue(ctx, obj, &done);
+    JS_FreeValue(ctx, obj);
+    if (JS_IsException(value))
+      goto reject;
+  }
+
+  if (JS_IsException(value)) {
+    JSValue res2;
+  reject:
+    err = JS_GetException(ctx);
+    is_reject = 1;
+  done_resolve:
+    res2 = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED,
+                   1, (JSValueConst *)&err);
+    JS_FreeValue(ctx, err);
+    JS_FreeValue(ctx, res2);
+    JS_FreeValue(ctx, resolving_funcs[0]);
+    JS_FreeValue(ctx, resolving_funcs[1]);
+    return promise;
+  }
+  {
+    JSValue value_wrapper_promise, resolve_reject[2];
+    int res;
+
+    value_wrapper_promise = js_promise_resolve(ctx, ctx->promise_ctor,
+                                               1, (JSValueConst *)&value, 0);
+    if (JS_IsException(value_wrapper_promise)) {
+      JS_FreeValue(ctx, value);
+      goto reject;
+    }
+
+    resolve_reject[0] =
+        js_async_from_sync_iterator_unwrap_func_create(ctx, done);
+    if (JS_IsException(resolve_reject[0])) {
+      JS_FreeValue(ctx, value_wrapper_promise);
+      goto fail;
+    }
+    JS_FreeValue(ctx, value);
+    resolve_reject[1] = JS_UNDEFINED;
+
+    res = perform_promise_then(ctx, value_wrapper_promise,
+                               (JSValueConst *)resolve_reject,
+                               (JSValueConst *)resolving_funcs);
+    JS_FreeValue(ctx, resolve_reject[0]);
+    JS_FreeValue(ctx, value_wrapper_promise);
+    JS_FreeValue(ctx, resolving_funcs[0]);
+    JS_FreeValue(ctx, resolving_funcs[1]);
+    if (res) {
+      JS_FreeValue(ctx, promise);
+      return JS_EXCEPTION;
+    }
+  }
+  return promise;
+fail:
+  JS_FreeValue(ctx, value);
+  JS_FreeValue(ctx, resolving_funcs[0]);
+  JS_FreeValue(ctx, resolving_funcs[1]);
+  JS_FreeValue(ctx, promise);
+  return JS_EXCEPTION;
+}
+
+
+const JSCFunctionListEntry js_promise_funcs[] = {
+    JS_CFUNC_MAGIC_DEF("resolve", 1, js_promise_resolve, 0 ),
+    JS_CFUNC_MAGIC_DEF("reject", 1, js_promise_resolve, 1 ),
+    JS_CFUNC_MAGIC_DEF("all", 1, js_promise_all, PROMISE_MAGIC_all ),
+    JS_CFUNC_MAGIC_DEF("allSettled", 1, js_promise_all, PROMISE_MAGIC_allSettled ),
+    JS_CFUNC_MAGIC_DEF("any", 1, js_promise_all, PROMISE_MAGIC_any ),
+    JS_CFUNC_DEF("race", 1, js_promise_race ),
+    //JS_CFUNC_DEF("__newPromiseCapability", 1, js_promise___newPromiseCapability ),
+    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL),
+};
+
+const JSCFunctionListEntry js_promise_proto_funcs[] = {
+    JS_CFUNC_DEF("then", 2, js_promise_then ),
+    JS_CFUNC_DEF("catch", 1, js_promise_catch ),
+    JS_CFUNC_DEF("finally", 1, js_promise_finally ),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Promise", JS_PROP_CONFIGURABLE ),
+};
+
+/* AsyncFunction */
+const JSCFunctionListEntry js_async_function_proto_funcs[] = {
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncFunction", JS_PROP_CONFIGURABLE ),
+};
+
+
+const JSCFunctionListEntry js_async_from_sync_iterator_proto_funcs[] = {
+    JS_CFUNC_MAGIC_DEF("next", 1, js_async_from_sync_iterator_next, GEN_MAGIC_NEXT ),
+    JS_CFUNC_MAGIC_DEF("return", 1, js_async_from_sync_iterator_next, GEN_MAGIC_RETURN ),
+    JS_CFUNC_MAGIC_DEF("throw", 1, js_async_from_sync_iterator_next, GEN_MAGIC_THROW ),
+};
+
+/* AsyncGeneratorFunction */
+
+const JSCFunctionListEntry js_async_generator_function_proto_funcs[] = {
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncGeneratorFunction", JS_PROP_CONFIGURABLE ),
+};
+
+/* AsyncGenerator prototype */
+
+const JSCFunctionListEntry js_async_generator_proto_funcs[] = {
+    JS_CFUNC_MAGIC_DEF("next", 1, js_async_generator_next, GEN_MAGIC_NEXT ),
+    JS_CFUNC_MAGIC_DEF("return", 1, js_async_generator_next, GEN_MAGIC_RETURN ),
+    JS_CFUNC_MAGIC_DEF("throw", 1, js_async_generator_next, GEN_MAGIC_THROW ),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncGenerator", JS_PROP_CONFIGURABLE ),
+};
+
+JSClassShortDef const js_async_class_def[] = {
+    { JS_ATOM_Promise, js_promise_finalizer, js_promise_mark },                      /* JS_CLASS_PROMISE */
+    { JS_ATOM_PromiseResolveFunction, js_promise_resolve_function_finalizer, js_promise_resolve_function_mark }, /* JS_CLASS_PROMISE_RESOLVE_FUNCTION */
+    { JS_ATOM_PromiseRejectFunction, js_promise_resolve_function_finalizer, js_promise_resolve_function_mark }, /* JS_CLASS_PROMISE_REJECT_FUNCTION */
+    { JS_ATOM_AsyncFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_ASYNC_FUNCTION */
+    { JS_ATOM_AsyncFunctionResolve, js_async_function_resolve_finalizer, js_async_function_resolve_mark }, /* JS_CLASS_ASYNC_FUNCTION_RESOLVE */
+    { JS_ATOM_AsyncFunctionReject, js_async_function_resolve_finalizer, js_async_function_resolve_mark }, /* JS_CLASS_ASYNC_FUNCTION_REJECT */
+    { JS_ATOM_empty_string, js_async_from_sync_iterator_finalizer, js_async_from_sync_iterator_mark }, /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */
+    { JS_ATOM_AsyncGeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_ASYNC_GENERATOR_FUNCTION */
+    { JS_ATOM_AsyncGenerator, js_async_generator_finalizer, js_async_generator_mark },  /* JS_CLASS_ASYNC_GENERATOR */
+};
+
+
+void JS_AddIntrinsicPromise(JSContext *ctx)
+{
+  JSRuntime *rt = ctx->rt;
+  JSValue obj1;
+
+  if (!JS_IsRegisteredClass(rt, JS_CLASS_PROMISE)) {
+    init_class_range(rt, js_async_class_def, JS_CLASS_PROMISE,
+                     countof(js_async_class_def));
+    rt->class_array[JS_CLASS_PROMISE_RESOLVE_FUNCTION].call = js_promise_resolve_function_call;
+    rt->class_array[JS_CLASS_PROMISE_REJECT_FUNCTION].call = js_promise_resolve_function_call;
+    rt->class_array[JS_CLASS_ASYNC_FUNCTION].call = js_async_function_call;
+    rt->class_array[JS_CLASS_ASYNC_FUNCTION_RESOLVE].call = js_async_function_resolve_call;
+    rt->class_array[JS_CLASS_ASYNC_FUNCTION_REJECT].call = js_async_function_resolve_call;
+    rt->class_array[JS_CLASS_ASYNC_GENERATOR_FUNCTION].call = js_async_generator_function_call;
+  }
+
+  /* Promise */
+  ctx->class_proto[JS_CLASS_PROMISE] = JS_NewObject(ctx);
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_PROMISE],
+                             js_promise_proto_funcs,
+                             countof(js_promise_proto_funcs));
+  obj1 = JS_NewCFunction2(ctx, js_promise_constructor, "Promise", 1,
+                          JS_CFUNC_constructor, 0);
+  ctx->promise_ctor = JS_DupValue(ctx, obj1);
+  JS_SetPropertyFunctionList(ctx, obj1,
+                             js_promise_funcs,
+                             countof(js_promise_funcs));
+  JS_NewGlobalCConstructor2(ctx, obj1, "Promise",
+                            ctx->class_proto[JS_CLASS_PROMISE]);
+
+  /* AsyncFunction */
+  ctx->class_proto[JS_CLASS_ASYNC_FUNCTION] = JS_NewObjectProto(ctx, ctx->function_proto);
+  obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor,
+                          "AsyncFunction", 1,
+                          JS_CFUNC_constructor_or_func_magic, JS_FUNC_ASYNC,
+                          ctx->function_ctor);
+  JS_SetPropertyFunctionList(ctx,
+                             ctx->class_proto[JS_CLASS_ASYNC_FUNCTION],
+                             js_async_function_proto_funcs,
+                             countof(js_async_function_proto_funcs));
+  JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_ASYNC_FUNCTION],
+                     0, JS_PROP_CONFIGURABLE);
+  JS_FreeValue(ctx, obj1);
+
+  /* AsyncIteratorPrototype */
+  ctx->async_iterator_proto = JS_NewObject(ctx);
+  JS_SetPropertyFunctionList(ctx, ctx->async_iterator_proto,
+                             js_async_iterator_proto_funcs,
+                             countof(js_async_iterator_proto_funcs));
+
+  /* AsyncFromSyncIteratorPrototype */
+  ctx->class_proto[JS_CLASS_ASYNC_FROM_SYNC_ITERATOR] =
+      JS_NewObjectProto(ctx, ctx->async_iterator_proto);
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ASYNC_FROM_SYNC_ITERATOR],
+                             js_async_from_sync_iterator_proto_funcs,
+                             countof(js_async_from_sync_iterator_proto_funcs));
+
+  /* AsyncGeneratorPrototype */
+  ctx->class_proto[JS_CLASS_ASYNC_GENERATOR] =
+      JS_NewObjectProto(ctx, ctx->async_iterator_proto);
+  JS_SetPropertyFunctionList(ctx,
+                             ctx->class_proto[JS_CLASS_ASYNC_GENERATOR],
+                             js_async_generator_proto_funcs,
+                             countof(js_async_generator_proto_funcs));
+
+  /* AsyncGeneratorFunction */
+  ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION] =
+      JS_NewObjectProto(ctx, ctx->function_proto);
+  obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor,
+                          "AsyncGeneratorFunction", 1,
+                          JS_CFUNC_constructor_or_func_magic,
+                          JS_FUNC_ASYNC_GENERATOR,
+                          ctx->function_ctor);
+  JS_SetPropertyFunctionList(ctx,
+                             ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
+                             js_async_generator_function_proto_funcs,
+                             countof(js_async_generator_function_proto_funcs));
+  JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
+                     ctx->class_proto[JS_CLASS_ASYNC_GENERATOR],
+                     JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE);
+  JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
+                     0, JS_PROP_CONFIGURABLE);
+  JS_FreeValue(ctx, obj1);
+}
\ No newline at end of file
diff --git a/src/core/builtins/js-promise.h b/src/core/builtins/js-promise.h
new file mode 100644
index 000000000..87ccd2729
--- /dev/null
+++ b/src/core/builtins/js-promise.h
@@ -0,0 +1,40 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_PROMISE_H
+#define QUICKJS_JS_PROMISE_H
+
+#include "quickjs/quickjs.h"
+#include "../types.h"
+
+JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
+                                  int argc, JSValueConst *argv, int magic);
+
+__exception int perform_promise_then(JSContext *ctx,
+                                            JSValueConst promise,
+                                            JSValueConst *resolve_reject,
+                                            JSValueConst *cap_resolving_funcs);
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-proxy.c b/src/core/builtins/js-proxy.c
new file mode 100644
index 000000000..f027ffe0b
--- /dev/null
+++ b/src/core/builtins/js-proxy.c
@@ -0,0 +1,989 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-proxy.h"
+#include "../convertion.h"
+#include "../exception.h"
+#include "../function.h"
+#include "../object.h"
+#include "../runtime.h"
+#include "../types.h"
+#include "js-array.h"
+#include "js-function.h"
+#include "js-object.h"
+#include "js-operator.h"
+
+/* Proxy */
+
+void js_proxy_finalizer(JSRuntime *rt, JSValue val)
+{
+  JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY);
+  if (s) {
+    JS_FreeValueRT(rt, s->target);
+    JS_FreeValueRT(rt, s->handler);
+    js_free_rt(rt, s);
+  }
+}
+
+void js_proxy_mark(JSRuntime *rt, JSValueConst val,
+                          JS_MarkFunc *mark_func)
+{
+  JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY);
+  if (s) {
+    JS_MarkValue(rt, s->target, mark_func);
+    JS_MarkValue(rt, s->handler, mark_func);
+  }
+}
+
+JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx)
+{
+  return JS_ThrowTypeError(ctx, "revoked proxy");
+}
+
+JSProxyData *get_proxy_method(JSContext *ctx, JSValue *pmethod,
+                                     JSValueConst obj, JSAtom name)
+{
+  JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY);
+  JSValue method;
+
+  /* safer to test recursion in all proxy methods */
+  if (js_check_stack_overflow(ctx->rt, 0)) {
+    JS_ThrowStackOverflow(ctx);
+    return NULL;
+  }
+
+  /* 's' should never be NULL */
+  if (s->is_revoked) {
+    JS_ThrowTypeErrorRevokedProxy(ctx);
+    return NULL;
+  }
+  method = JS_GetProperty(ctx, s->handler, name);
+  if (JS_IsException(method))
+    return NULL;
+  if (JS_IsNull(method))
+    method = JS_UNDEFINED;
+  *pmethod = method;
+  return s;
+}
+
+JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj)
+{
+  JSProxyData *s;
+  JSValue method, ret, proto1;
+  int res;
+
+  s = get_proxy_method(ctx, &method, obj, JS_ATOM_getPrototypeOf);
+  if (!s)
+    return JS_EXCEPTION;
+  if (JS_IsUndefined(method))
+    return JS_GetPrototype(ctx, s->target);
+  ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
+  if (JS_IsException(ret))
+    return ret;
+  if (JS_VALUE_GET_TAG(ret) != JS_TAG_NULL &&
+      JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
+    goto fail;
+  }
+  res = JS_IsExtensible(ctx, s->target);
+  if (res < 0) {
+    JS_FreeValue(ctx, ret);
+    return JS_EXCEPTION;
+  }
+  if (!res) {
+    /* check invariant */
+    proto1 = JS_GetPrototype(ctx, s->target);
+    if (JS_IsException(proto1)) {
+      JS_FreeValue(ctx, ret);
+      return JS_EXCEPTION;
+    }
+    if (JS_VALUE_GET_OBJ(proto1) != JS_VALUE_GET_OBJ(ret)) {
+      JS_FreeValue(ctx, proto1);
+    fail:
+      JS_FreeValue(ctx, ret);
+      return JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
+    }
+    JS_FreeValue(ctx, proto1);
+  }
+  return ret;
+}
+
+int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
+                                   JSValueConst proto_val, BOOL throw_flag)
+{
+  JSProxyData *s;
+  JSValue method, ret, proto1;
+  JSValueConst args[2];
+  BOOL res;
+  int res2;
+
+  s = get_proxy_method(ctx, &method, obj, JS_ATOM_setPrototypeOf);
+  if (!s)
+    return -1;
+  if (JS_IsUndefined(method))
+    return JS_SetPrototypeInternal(ctx, s->target, proto_val, throw_flag);
+  args[0] = s->target;
+  args[1] = proto_val;
+  ret = JS_CallFree(ctx, method, s->handler, 2, args);
+  if (JS_IsException(ret))
+    return -1;
+  res = JS_ToBoolFree(ctx, ret);
+  if (!res) {
+    if (throw_flag) {
+      JS_ThrowTypeError(ctx, "proxy: bad prototype");
+      return -1;
+    } else {
+      return FALSE;
+    }
+  }
+  res2 = JS_IsExtensible(ctx, s->target);
+  if (res2 < 0)
+    return -1;
+  if (!res2) {
+    proto1 = JS_GetPrototype(ctx, s->target);
+    if (JS_IsException(proto1))
+      return -1;
+    if (JS_VALUE_GET_OBJ(proto_val) != JS_VALUE_GET_OBJ(proto1)) {
+      JS_FreeValue(ctx, proto1);
+      JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
+      return -1;
+    }
+    JS_FreeValue(ctx, proto1);
+  }
+  return TRUE;
+}
+
+int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj)
+{
+  JSProxyData *s;
+  JSValue method, ret;
+  BOOL res;
+  int res2;
+
+  s = get_proxy_method(ctx, &method, obj, JS_ATOM_isExtensible);
+  if (!s)
+    return -1;
+  if (JS_IsUndefined(method))
+    return JS_IsExtensible(ctx, s->target);
+  ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
+  if (JS_IsException(ret))
+    return -1;
+  res = JS_ToBoolFree(ctx, ret);
+  res2 = JS_IsExtensible(ctx, s->target);
+  if (res2 < 0)
+    return res2;
+  if (res != res2) {
+    JS_ThrowTypeError(ctx, "proxy: inconsistent isExtensible");
+    return -1;
+  }
+  return res;
+}
+
+int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj)
+{
+  JSProxyData *s;
+  JSValue method, ret;
+  BOOL res;
+  int res2;
+
+  s = get_proxy_method(ctx, &method, obj, JS_ATOM_preventExtensions);
+  if (!s)
+    return -1;
+  if (JS_IsUndefined(method))
+    return JS_PreventExtensions(ctx, s->target);
+  ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
+  if (JS_IsException(ret))
+    return -1;
+  res = JS_ToBoolFree(ctx, ret);
+  if (res) {
+    res2 = JS_IsExtensible(ctx, s->target);
+    if (res2 < 0)
+      return res2;
+    if (res2) {
+      JS_ThrowTypeError(ctx, "proxy: inconsistent preventExtensions");
+      return -1;
+    }
+  }
+  return res;
+}
+
+int js_proxy_has(JSContext *ctx, JSValueConst obj, JSAtom atom)
+{
+  JSProxyData *s;
+  JSValue method, ret1, atom_val;
+  int ret, res;
+  JSObject *p;
+  JSValueConst args[2];
+  BOOL res2;
+
+  s = get_proxy_method(ctx, &method, obj, JS_ATOM_has);
+  if (!s)
+    return -1;
+  if (JS_IsUndefined(method))
+    return JS_HasProperty(ctx, s->target, atom);
+  atom_val = JS_AtomToValue(ctx, atom);
+  if (JS_IsException(atom_val)) {
+    JS_FreeValue(ctx, method);
+    return -1;
+  }
+  args[0] = s->target;
+  args[1] = atom_val;
+  ret1 = JS_CallFree(ctx, method, s->handler, 2, args);
+  JS_FreeValue(ctx, atom_val);
+  if (JS_IsException(ret1))
+    return -1;
+  ret = JS_ToBoolFree(ctx, ret1);
+  if (!ret) {
+    JSPropertyDescriptor desc;
+    p = JS_VALUE_GET_OBJ(s->target);
+    res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
+    if (res < 0)
+      return -1;
+    if (res) {
+      res2 = !(desc.flags & JS_PROP_CONFIGURABLE);
+      js_free_desc(ctx, &desc);
+      if (res2 || !p->extensible) {
+        JS_ThrowTypeError(ctx, "proxy: inconsistent has");
+        return -1;
+      }
+    }
+  }
+  return ret;
+}
+
+JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom,
+                            JSValueConst receiver)
+{
+  JSProxyData *s;
+  JSValue method, ret, atom_val;
+  int res;
+  JSValueConst args[3];
+  JSPropertyDescriptor desc;
+
+  s = get_proxy_method(ctx, &method, obj, JS_ATOM_get);
+  if (!s)
+    return JS_EXCEPTION;
+  /* Note: recursion is possible thru the prototype of s->target */
+  if (JS_IsUndefined(method))
+    return JS_GetPropertyInternal(ctx, s->target, atom, receiver, FALSE);
+  atom_val = JS_AtomToValue(ctx, atom);
+  if (JS_IsException(atom_val)) {
+    JS_FreeValue(ctx, method);
+    return JS_EXCEPTION;
+  }
+  args[0] = s->target;
+  args[1] = atom_val;
+  args[2] = receiver;
+  ret = JS_CallFree(ctx, method, s->handler, 3, args);
+  JS_FreeValue(ctx, atom_val);
+  if (JS_IsException(ret))
+    return JS_EXCEPTION;
+  res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
+  if (res < 0)
+    return JS_EXCEPTION;
+  if (res) {
+    if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {
+      if (!js_same_value(ctx, desc.value, ret)) {
+        goto fail;
+      }
+    } else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET) {
+      if (JS_IsUndefined(desc.getter) && !JS_IsUndefined(ret)) {
+      fail:
+        js_free_desc(ctx, &desc);
+        JS_FreeValue(ctx, ret);
+        return JS_ThrowTypeError(ctx, "proxy: inconsistent get");
+      }
+    }
+    js_free_desc(ctx, &desc);
+  }
+  return ret;
+}
+
+int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom,
+                        JSValueConst value, JSValueConst receiver, int flags)
+{
+  JSProxyData *s;
+  JSValue method, ret1, atom_val;
+  int ret, res;
+  JSValueConst args[4];
+
+  s = get_proxy_method(ctx, &method, obj, JS_ATOM_set);
+  if (!s)
+    return -1;
+  if (JS_IsUndefined(method)) {
+    return JS_SetPropertyGeneric(ctx, s->target, atom,
+                                 JS_DupValue(ctx, value), receiver,
+                                 flags);
+  }
+  atom_val = JS_AtomToValue(ctx, atom);
+  if (JS_IsException(atom_val)) {
+    JS_FreeValue(ctx, method);
+    return -1;
+  }
+  args[0] = s->target;
+  args[1] = atom_val;
+  args[2] = value;
+  args[3] = receiver;
+  ret1 = JS_CallFree(ctx, method, s->handler, 4, args);
+  JS_FreeValue(ctx, atom_val);
+  if (JS_IsException(ret1))
+    return -1;
+  ret = JS_ToBoolFree(ctx, ret1);
+  if (ret) {
+    JSPropertyDescriptor desc;
+    res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
+    if (res < 0)
+      return -1;
+    if (res) {
+      if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {
+        if (!js_same_value(ctx, desc.value, value)) {
+          goto fail;
+        }
+      } else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET && JS_IsUndefined(desc.setter)) {
+      fail:
+        js_free_desc(ctx, &desc);
+        JS_ThrowTypeError(ctx, "proxy: inconsistent set");
+        return -1;
+      }
+      js_free_desc(ctx, &desc);
+    }
+  } else {
+    if ((flags & JS_PROP_THROW) ||
+        ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
+      JS_ThrowTypeError(ctx, "proxy: cannot set property");
+      return -1;
+    }
+  }
+  return ret;
+}
+
+JSValue js_create_desc(JSContext *ctx, JSValueConst val,
+                              JSValueConst getter, JSValueConst setter,
+                              int flags)
+{
+  JSValue ret;
+  ret = JS_NewObject(ctx);
+  if (JS_IsException(ret))
+    return ret;
+  if (flags & JS_PROP_HAS_GET) {
+    JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, getter),
+                           JS_PROP_C_W_E);
+  }
+  if (flags & JS_PROP_HAS_SET) {
+    JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, setter),
+                           JS_PROP_C_W_E);
+  }
+  if (flags & JS_PROP_HAS_VALUE) {
+    JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, val),
+                           JS_PROP_C_W_E);
+  }
+  if (flags & JS_PROP_HAS_WRITABLE) {
+    JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,
+                           JS_NewBool(ctx, (flags & JS_PROP_WRITABLE) != 0),
+                           JS_PROP_C_W_E);
+  }
+  if (flags & JS_PROP_HAS_ENUMERABLE) {
+    JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,
+                           JS_NewBool(ctx, (flags & JS_PROP_ENUMERABLE) != 0),
+                           JS_PROP_C_W_E);
+  }
+  if (flags & JS_PROP_HAS_CONFIGURABLE) {
+    JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
+                           JS_NewBool(ctx, (flags & JS_PROP_CONFIGURABLE) != 0),
+                           JS_PROP_C_W_E);
+  }
+  return ret;
+}
+
+int js_proxy_get_own_property(JSContext *ctx, JSPropertyDescriptor *pdesc,
+                                     JSValueConst obj, JSAtom prop)
+{
+  JSProxyData *s;
+  JSValue method, trap_result_obj, prop_val;
+  int res, target_desc_ret, ret;
+  JSObject *p;
+  JSValueConst args[2];
+  JSPropertyDescriptor result_desc, target_desc;
+
+  s = get_proxy_method(ctx, &method, obj, JS_ATOM_getOwnPropertyDescriptor);
+  if (!s)
+    return -1;
+  p = JS_VALUE_GET_OBJ(s->target);
+  if (JS_IsUndefined(method)) {
+    return JS_GetOwnPropertyInternal(ctx, pdesc, p, prop);
+  }
+  prop_val = JS_AtomToValue(ctx, prop);
+  if (JS_IsException(prop_val)) {
+    JS_FreeValue(ctx, method);
+    return -1;
+  }
+  args[0] = s->target;
+  args[1] = prop_val;
+  trap_result_obj = JS_CallFree(ctx, method, s->handler, 2, args);
+  JS_FreeValue(ctx, prop_val);
+  if (JS_IsException(trap_result_obj))
+    return -1;
+  if (!JS_IsObject(trap_result_obj) && !JS_IsUndefined(trap_result_obj)) {
+    JS_FreeValue(ctx, trap_result_obj);
+    goto fail;
+  }
+  target_desc_ret = JS_GetOwnPropertyInternal(ctx, &target_desc, p, prop);
+  if (target_desc_ret < 0) {
+    JS_FreeValue(ctx, trap_result_obj);
+    return -1;
+  }
+  if (target_desc_ret)
+    js_free_desc(ctx, &target_desc);
+  if (JS_IsUndefined(trap_result_obj)) {
+    if (target_desc_ret) {
+      if (!(target_desc.flags & JS_PROP_CONFIGURABLE) || !p->extensible)
+        goto fail;
+    }
+    ret = FALSE;
+  } else {
+    int flags1, extensible_target;
+    extensible_target = JS_IsExtensible(ctx, s->target);
+    if (extensible_target < 0) {
+      JS_FreeValue(ctx, trap_result_obj);
+      return -1;
+    }
+    res = js_obj_to_desc(ctx, &result_desc, trap_result_obj);
+    JS_FreeValue(ctx, trap_result_obj);
+    if (res < 0)
+      return -1;
+
+    if (target_desc_ret) {
+      /* convert result_desc.flags to defineProperty flags */
+      flags1 = result_desc.flags | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE;
+      if (result_desc.flags & JS_PROP_GETSET)
+        flags1 |= JS_PROP_HAS_GET | JS_PROP_HAS_SET;
+      else
+        flags1 |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE;
+      /* XXX: not complete check: need to compare value &
+         getter/setter as in defineproperty */
+      if (!check_define_prop_flags(target_desc.flags, flags1))
+        goto fail1;
+    } else {
+      if (!extensible_target)
+        goto fail1;
+    }
+    if (!(result_desc.flags & JS_PROP_CONFIGURABLE)) {
+      if (!target_desc_ret || (target_desc.flags & JS_PROP_CONFIGURABLE))
+        goto fail1;
+      if ((result_desc.flags &
+           (JS_PROP_GETSET | JS_PROP_WRITABLE)) == 0 &&
+          target_desc_ret &&
+          (target_desc.flags & JS_PROP_WRITABLE) != 0) {
+        /* proxy-missing-checks */
+      fail1:
+        js_free_desc(ctx, &result_desc);
+      fail:
+        JS_ThrowTypeError(ctx, "proxy: inconsistent getOwnPropertyDescriptor");
+        return -1;
+      }
+    }
+    ret = TRUE;
+    if (pdesc) {
+      *pdesc = result_desc;
+    } else {
+      js_free_desc(ctx, &result_desc);
+    }
+  }
+  return ret;
+}
+
+int js_proxy_define_own_property(JSContext *ctx, JSValueConst obj,
+                                        JSAtom prop, JSValueConst val,
+                                        JSValueConst getter, JSValueConst setter,
+                                        int flags)
+{
+  JSProxyData *s;
+  JSValue method, ret1, prop_val, desc_val;
+  int res, ret;
+  JSObject *p;
+  JSValueConst args[3];
+  JSPropertyDescriptor desc;
+  BOOL setting_not_configurable;
+
+  s = get_proxy_method(ctx, &method, obj, JS_ATOM_defineProperty);
+  if (!s)
+    return -1;
+  if (JS_IsUndefined(method)) {
+    return JS_DefineProperty(ctx, s->target, prop, val, getter, setter, flags);
+  }
+  prop_val = JS_AtomToValue(ctx, prop);
+  if (JS_IsException(prop_val)) {
+    JS_FreeValue(ctx, method);
+    return -1;
+  }
+  desc_val = js_create_desc(ctx, val, getter, setter, flags);
+  if (JS_IsException(desc_val)) {
+    JS_FreeValue(ctx, prop_val);
+    JS_FreeValue(ctx, method);
+    return -1;
+  }
+  args[0] = s->target;
+  args[1] = prop_val;
+  args[2] = desc_val;
+  ret1 = JS_CallFree(ctx, method, s->handler, 3, args);
+  JS_FreeValue(ctx, prop_val);
+  JS_FreeValue(ctx, desc_val);
+  if (JS_IsException(ret1))
+    return -1;
+  ret = JS_ToBoolFree(ctx, ret1);
+  if (!ret) {
+    if (flags & JS_PROP_THROW) {
+      JS_ThrowTypeError(ctx, "proxy: defineProperty exception");
+      return -1;
+    } else {
+      return 0;
+    }
+  }
+  p = JS_VALUE_GET_OBJ(s->target);
+  res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
+  if (res < 0)
+    return -1;
+  setting_not_configurable = ((flags & (JS_PROP_HAS_CONFIGURABLE |
+                                        JS_PROP_CONFIGURABLE)) ==
+                              JS_PROP_HAS_CONFIGURABLE);
+  if (!res) {
+    if (!p->extensible || setting_not_configurable)
+      goto fail;
+  } else {
+    if (!check_define_prop_flags(desc.flags, flags) ||
+        ((desc.flags & JS_PROP_CONFIGURABLE) && setting_not_configurable)) {
+      goto fail1;
+    }
+    if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
+      if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) ==
+          JS_PROP_GETSET) {
+        if ((flags & JS_PROP_HAS_GET) &&
+            !js_same_value(ctx, getter, desc.getter)) {
+          goto fail1;
+        }
+        if ((flags & JS_PROP_HAS_SET) &&
+            !js_same_value(ctx, setter, desc.setter)) {
+          goto fail1;
+        }
+      }
+    } else if (flags & JS_PROP_HAS_VALUE) {
+      if ((desc.flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) ==
+              JS_PROP_WRITABLE && !(flags & JS_PROP_WRITABLE)) {
+        /* missing-proxy-check feature */
+        goto fail1;
+      } else if ((desc.flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 &&
+                 !js_same_value(ctx, val, desc.value)) {
+        goto fail1;
+      }
+    }
+    if (flags & JS_PROP_HAS_WRITABLE) {
+      if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE |
+                         JS_PROP_WRITABLE)) == JS_PROP_WRITABLE) {
+        /* proxy-missing-checks */
+      fail1:
+        js_free_desc(ctx, &desc);
+      fail:
+        JS_ThrowTypeError(ctx, "proxy: inconsistent defineProperty");
+        return -1;
+      }
+    }
+    js_free_desc(ctx, &desc);
+  }
+  return 1;
+}
+
+int js_proxy_delete_property(JSContext *ctx, JSValueConst obj,
+                                    JSAtom atom)
+{
+  JSProxyData *s;
+  JSValue method, ret, atom_val;
+  int res, res2, is_extensible;
+  JSValueConst args[2];
+
+  s = get_proxy_method(ctx, &method, obj, JS_ATOM_deleteProperty);
+  if (!s)
+    return -1;
+  if (JS_IsUndefined(method)) {
+    return JS_DeleteProperty(ctx, s->target, atom, 0);
+  }
+  atom_val = JS_AtomToValue(ctx, atom);;
+  if (JS_IsException(atom_val)) {
+    JS_FreeValue(ctx, method);
+    return -1;
+  }
+  args[0] = s->target;
+  args[1] = atom_val;
+  ret = JS_CallFree(ctx, method, s->handler, 2, args);
+  JS_FreeValue(ctx, atom_val);
+  if (JS_IsException(ret))
+    return -1;
+  res = JS_ToBoolFree(ctx, ret);
+  if (res) {
+    JSPropertyDescriptor desc;
+    res2 = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
+    if (res2 < 0)
+      return -1;
+    if (res2) {
+      if (!(desc.flags & JS_PROP_CONFIGURABLE))
+        goto fail;
+      is_extensible = JS_IsExtensible(ctx, s->target);
+      if (is_extensible < 0)
+        goto fail1;
+      if (!is_extensible) {
+        /* proxy-missing-checks */
+      fail:
+        JS_ThrowTypeError(ctx, "proxy: inconsistent deleteProperty");
+      fail1:
+        js_free_desc(ctx, &desc);
+        return -1;
+      }
+      js_free_desc(ctx, &desc);
+    }
+  }
+  return res;
+}
+
+/* return the index of the property or -1 if not found */
+int find_prop_key(const JSPropertyEnum *tab, int n, JSAtom atom)
+{
+  int i;
+  for(i = 0; i < n; i++) {
+    if (tab[i].atom == atom)
+      return i;
+  }
+  return -1;
+}
+
+int js_proxy_get_own_property_names(JSContext *ctx,
+                                           JSPropertyEnum **ptab,
+                                           uint32_t *plen,
+                                           JSValueConst obj)
+{
+  JSProxyData *s;
+  JSValue method, prop_array, val;
+  uint32_t len, i, len2;
+  JSPropertyEnum *tab, *tab2;
+  JSAtom atom;
+  JSPropertyDescriptor desc;
+  int res, is_extensible, idx;
+
+  s = get_proxy_method(ctx, &method, obj, JS_ATOM_ownKeys);
+  if (!s)
+    return -1;
+  if (JS_IsUndefined(method)) {
+    return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen,
+                                          JS_VALUE_GET_OBJ(s->target),
+                                          JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK);
+  }
+  prop_array = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
+  if (JS_IsException(prop_array))
+    return -1;
+  tab = NULL;
+  len = 0;
+  tab2 = NULL;
+  len2 = 0;
+  if (js_get_length32(ctx, &len, prop_array))
+    goto fail;
+  if (len > 0) {
+    tab = js_mallocz(ctx, sizeof(tab[0]) * len);
+    if (!tab)
+      goto fail;
+  }
+  for(i = 0; i < len; i++) {
+    val = JS_GetPropertyUint32(ctx, prop_array, i);
+    if (JS_IsException(val))
+      goto fail;
+    if (!JS_IsString(val) && !JS_IsSymbol(val)) {
+      JS_FreeValue(ctx, val);
+      JS_ThrowTypeError(ctx, "proxy: properties must be strings or symbols");
+      goto fail;
+    }
+    atom = JS_ValueToAtom(ctx, val);
+    JS_FreeValue(ctx, val);
+    if (atom == JS_ATOM_NULL)
+      goto fail;
+    tab[i].atom = atom;
+    tab[i].is_enumerable = FALSE; /* XXX: redundant? */
+  }
+
+  /* check duplicate properties (XXX: inefficient, could store the
+     * properties an a temporary object to use the hash) */
+  for(i = 1; i < len; i++) {
+    if (find_prop_key(tab, i, tab[i].atom) >= 0) {
+      JS_ThrowTypeError(ctx, "proxy: duplicate property");
+      goto fail;
+    }
+  }
+
+  is_extensible = JS_IsExtensible(ctx, s->target);
+  if (is_extensible < 0)
+    goto fail;
+
+  /* check if there are non configurable properties */
+  if (s->is_revoked) {
+    JS_ThrowTypeErrorRevokedProxy(ctx);
+    goto fail;
+  }
+  if (JS_GetOwnPropertyNamesInternal(ctx, &tab2, &len2, JS_VALUE_GET_OBJ(s->target),
+                                     JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK))
+    goto fail;
+  for(i = 0; i < len2; i++) {
+    if (s->is_revoked) {
+      JS_ThrowTypeErrorRevokedProxy(ctx);
+      goto fail;
+    }
+    res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target),
+                                    tab2[i].atom);
+    if (res < 0)
+      goto fail;
+    if (res) {  /* safety, property should be found */
+      js_free_desc(ctx, &desc);
+      if (!(desc.flags & JS_PROP_CONFIGURABLE) || !is_extensible) {
+        idx = find_prop_key(tab, len, tab2[i].atom);
+        if (idx < 0) {
+          JS_ThrowTypeError(ctx, "proxy: target property must be present in proxy ownKeys");
+          goto fail;
+        }
+        /* mark the property as found */
+        if (!is_extensible)
+          tab[idx].is_enumerable = TRUE;
+      }
+    }
+  }
+  if (!is_extensible) {
+    /* check that all property in 'tab' were checked */
+    for(i = 0; i < len; i++) {
+      if (!tab[i].is_enumerable) {
+        JS_ThrowTypeError(ctx, "proxy: property not present in target were returned by non extensible proxy");
+        goto fail;
+      }
+    }
+  }
+
+  js_free_prop_enum(ctx, tab2, len2);
+  JS_FreeValue(ctx, prop_array);
+  *ptab = tab;
+  *plen = len;
+  return 0;
+fail:
+  js_free_prop_enum(ctx, tab2, len2);
+  js_free_prop_enum(ctx, tab, len);
+  JS_FreeValue(ctx, prop_array);
+  return -1;
+}
+
+JSValue js_proxy_call_constructor(JSContext *ctx, JSValueConst func_obj,
+                                         JSValueConst new_target,
+                                         int argc, JSValueConst *argv)
+{
+  JSProxyData *s;
+  JSValue method, arg_array, ret;
+  JSValueConst args[3];
+
+  s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_construct);
+  if (!s)
+    return JS_EXCEPTION;
+  if (!JS_IsConstructor(ctx, s->target))
+    return JS_ThrowTypeError(ctx, "not a constructor");
+  if (JS_IsUndefined(method))
+    return JS_CallConstructor2(ctx, s->target, new_target, argc, argv);
+  arg_array = js_create_array(ctx, argc, argv);
+  if (JS_IsException(arg_array)) {
+    ret = JS_EXCEPTION;
+    goto fail;
+  }
+  args[0] = s->target;
+  args[1] = arg_array;
+  args[2] = new_target;
+  ret = JS_Call(ctx, method, s->handler, 3, args);
+  if (!JS_IsException(ret) && JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
+    JS_FreeValue(ctx, ret);
+    ret = JS_ThrowTypeErrorNotAnObject(ctx);
+  }
+fail:
+  JS_FreeValue(ctx, method);
+  JS_FreeValue(ctx, arg_array);
+  return ret;
+}
+
+JSValue js_proxy_call(JSContext *ctx, JSValueConst func_obj,
+                             JSValueConst this_obj,
+                             int argc, JSValueConst *argv, int flags)
+{
+  JSProxyData *s;
+  JSValue method, arg_array, ret;
+  JSValueConst args[3];
+
+  if (flags & JS_CALL_FLAG_CONSTRUCTOR)
+    return js_proxy_call_constructor(ctx, func_obj, this_obj, argc, argv);
+
+  s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_apply);
+  if (!s)
+    return JS_EXCEPTION;
+  if (!s->is_func) {
+    JS_FreeValue(ctx, method);
+    return JS_ThrowTypeError(ctx, "not a function");
+  }
+  if (JS_IsUndefined(method))
+    return JS_Call(ctx, s->target, this_obj, argc, argv);
+  arg_array = js_create_array(ctx, argc, argv);
+  if (JS_IsException(arg_array)) {
+    ret = JS_EXCEPTION;
+    goto fail;
+  }
+  args[0] = s->target;
+  args[1] = this_obj;
+  args[2] = arg_array;
+  ret = JS_Call(ctx, method, s->handler, 3, args);
+fail:
+  JS_FreeValue(ctx, method);
+  JS_FreeValue(ctx, arg_array);
+  return ret;
+}
+
+int js_proxy_isArray(JSContext *ctx, JSValueConst obj)
+{
+  JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY);
+  if (!s)
+    return FALSE;
+  if (s->is_revoked) {
+    JS_ThrowTypeErrorRevokedProxy(ctx);
+    return -1;
+  }
+  return JS_IsArray(ctx, s->target);
+}
+
+static const JSClassExoticMethods js_proxy_exotic_methods = {
+    .get_own_property = js_proxy_get_own_property,
+    .define_own_property = js_proxy_define_own_property,
+    .delete_property = js_proxy_delete_property,
+    .get_own_property_names = js_proxy_get_own_property_names,
+    .has_property = js_proxy_has,
+    .get_property = js_proxy_get,
+    .set_property = js_proxy_set,
+};
+
+JSValue js_proxy_constructor(JSContext *ctx, JSValueConst this_val,
+                                    int argc, JSValueConst *argv)
+{
+  JSValueConst target, handler;
+  JSValue obj;
+  JSProxyData *s;
+
+  target = argv[0];
+  handler = argv[1];
+  if (JS_VALUE_GET_TAG(target) != JS_TAG_OBJECT ||
+      JS_VALUE_GET_TAG(handler) != JS_TAG_OBJECT)
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+
+  obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_PROXY);
+  if (JS_IsException(obj))
+    return obj;
+  s = js_malloc(ctx, sizeof(JSProxyData));
+  if (!s) {
+    JS_FreeValue(ctx, obj);
+    return JS_EXCEPTION;
+  }
+  s->target = JS_DupValue(ctx, target);
+  s->handler = JS_DupValue(ctx, handler);
+  s->is_func = JS_IsFunction(ctx, target);
+  s->is_revoked = FALSE;
+  JS_SetOpaque(obj, s);
+  JS_SetConstructorBit(ctx, obj, JS_IsConstructor(ctx, target));
+  return obj;
+}
+
+JSValue js_proxy_revoke(JSContext *ctx, JSValueConst this_val,
+                               int argc, JSValueConst *argv, int magic,
+                               JSValue *func_data)
+{
+  JSProxyData *s = JS_GetOpaque(func_data[0], JS_CLASS_PROXY);
+  if (s) {
+    /* We do not free the handler and target in case they are
+       referenced as constants in the C call stack */
+    s->is_revoked = TRUE;
+    JS_FreeValue(ctx, func_data[0]);
+    func_data[0] = JS_NULL;
+  }
+  return JS_UNDEFINED;
+}
+
+JSValue js_proxy_revoke_constructor(JSContext *ctx,
+                                           JSValueConst proxy_obj)
+{
+  return JS_NewCFunctionData(ctx, js_proxy_revoke, 0, 0, 1, &proxy_obj);
+}
+
+JSValue js_proxy_revocable(JSContext *ctx, JSValueConst this_val,
+                                  int argc, JSValueConst *argv)
+{
+  JSValue proxy_obj, revoke_obj = JS_UNDEFINED, obj;
+
+  proxy_obj = js_proxy_constructor(ctx, JS_UNDEFINED, argc, argv);
+  if (JS_IsException(proxy_obj))
+    goto fail;
+  revoke_obj = js_proxy_revoke_constructor(ctx, proxy_obj);
+  if (JS_IsException(revoke_obj))
+    goto fail;
+  obj = JS_NewObject(ctx);
+  if (JS_IsException(obj))
+    goto fail;
+  // XXX: exceptions?
+  JS_DefinePropertyValue(ctx, obj, JS_ATOM_proxy, proxy_obj, JS_PROP_C_W_E);
+  JS_DefinePropertyValue(ctx, obj, JS_ATOM_revoke, revoke_obj, JS_PROP_C_W_E);
+  return obj;
+fail:
+  JS_FreeValue(ctx, proxy_obj);
+  JS_FreeValue(ctx, revoke_obj);
+  return JS_EXCEPTION;
+}
+
+const JSCFunctionListEntry js_proxy_funcs[] = {
+    JS_CFUNC_DEF("revocable", 2, js_proxy_revocable ),
+};
+
+const JSClassShortDef js_proxy_class_def[] = {
+    { JS_ATOM_Object, js_proxy_finalizer, js_proxy_mark }, /* JS_CLASS_PROXY */
+};
+
+void JS_AddIntrinsicProxy(JSContext *ctx)
+{
+  JSRuntime *rt = ctx->rt;
+  JSValue obj1;
+
+  if (!JS_IsRegisteredClass(rt, JS_CLASS_PROXY)) {
+    init_class_range(rt, js_proxy_class_def, JS_CLASS_PROXY,
+                     countof(js_proxy_class_def));
+    rt->class_array[JS_CLASS_PROXY].exotic = &js_proxy_exotic_methods;
+    rt->class_array[JS_CLASS_PROXY].call = js_proxy_call;
+  }
+
+  obj1 = JS_NewCFunction2(ctx, js_proxy_constructor, "Proxy", 2,
+                          JS_CFUNC_constructor, 0);
+  JS_SetConstructorBit(ctx, obj1, TRUE);
+  JS_SetPropertyFunctionList(ctx, obj1, js_proxy_funcs,
+                             countof(js_proxy_funcs));
+  JS_DefinePropertyValueStr(ctx, ctx->global_obj, "Proxy",
+                            obj1, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+}
\ No newline at end of file
diff --git a/src/core/builtins/js-proxy.h b/src/core/builtins/js-proxy.h
new file mode 100644
index 000000000..3e9c6cbe6
--- /dev/null
+++ b/src/core/builtins/js-proxy.h
@@ -0,0 +1,78 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_PROXY_H
+#define QUICKJS_JS_PROXY_H
+
+#include "quickjs/quickjs.h"
+#include "quickjs/cutils.h"
+
+int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj);
+int js_proxy_preventExtensions(JSContext *ctx, JSValueConst obj);
+int js_proxy_has(JSContext *ctx, JSValueConst obj, JSAtom atom);
+JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom,
+                            JSValueConst receiver);
+int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom,
+                        JSValueConst value, JSValueConst receiver, int flags);
+JSValue js_create_desc(JSContext *ctx, JSValueConst val,
+                              JSValueConst getter, JSValueConst setter,
+                              int flags);
+int js_proxy_get_own_property(JSContext *ctx, JSPropertyDescriptor *pdesc,
+                                     JSValueConst obj, JSAtom prop);
+int js_proxy_define_own_property(JSContext *ctx, JSValueConst obj,
+                                        JSAtom prop, JSValueConst val,
+                                        JSValueConst getter, JSValueConst setter,
+                                        int flags);
+int js_proxy_delete_property(JSContext *ctx, JSValueConst obj,
+                                    JSAtom atom);
+/* return the index of the property or -1 if not found */
+int find_prop_key(const JSPropertyEnum *tab, int n, JSAtom atom);
+int js_proxy_get_own_property_names(JSContext *ctx,
+                                           JSPropertyEnum **ptab,
+                                           uint32_t *plen,
+                                           JSValueConst obj);
+JSValue js_proxy_call_constructor(JSContext *ctx, JSValueConst func_obj,
+                                         JSValueConst new_target,
+                                         int argc, JSValueConst *argv);
+JSValue js_proxy_call(JSContext *ctx, JSValueConst func_obj,
+                             JSValueConst this_obj,
+                             int argc, JSValueConst *argv, int flags);
+int js_proxy_isArray(JSContext *ctx, JSValueConst obj);
+JSValue js_proxy_constructor(JSContext *ctx, JSValueConst this_val,
+                                    int argc, JSValueConst *argv);
+JSValue js_proxy_revoke(JSContext *ctx, JSValueConst this_val,
+                               int argc, JSValueConst *argv, int magic,
+                               JSValue *func_data);
+JSValue js_proxy_revoke_constructor(JSContext *ctx,
+                                           JSValueConst proxy_obj);
+JSValue js_proxy_revocable(JSContext *ctx, JSValueConst this_val,
+                                  int argc, JSValueConst *argv);
+
+
+JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj);
+int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
+                                   JSValueConst proto_val, BOOL throw_flag);
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-reflect.c b/src/core/builtins/js-reflect.c
new file mode 100644
index 000000000..92d94cd77
--- /dev/null
+++ b/src/core/builtins/js-reflect.c
@@ -0,0 +1,176 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-reflect.h"
+#include "../exception.h"
+#include "../object.h"
+#include "../runtime.h"
+#include "js-function.h"
+
+/* Reflect */
+JSValue js_reflect_apply(JSContext *ctx, JSValueConst this_val,
+                                int argc, JSValueConst *argv)
+{
+  return js_function_apply(ctx, argv[0], max_int(0, argc - 1), argv + 1, 2);
+}
+
+JSValue js_reflect_construct(JSContext *ctx, JSValueConst this_val,
+                                    int argc, JSValueConst *argv)
+{
+  JSValueConst func, array_arg, new_target;
+  JSValue *tab, ret;
+  uint32_t len;
+
+  func = argv[0];
+  array_arg = argv[1];
+  if (argc > 2) {
+    new_target = argv[2];
+    if (!JS_IsConstructor(ctx, new_target))
+      return JS_ThrowTypeError(ctx, "not a constructor");
+  } else {
+    new_target = func;
+  }
+  tab = build_arg_list(ctx, &len, array_arg);
+  if (!tab)
+    return JS_EXCEPTION;
+  ret = JS_CallConstructor2(ctx, func, new_target, len, (JSValueConst *)tab);
+  free_arg_list(ctx, tab, len);
+  return ret;
+}
+
+JSValue js_reflect_deleteProperty(JSContext *ctx, JSValueConst this_val,
+                                         int argc, JSValueConst *argv)
+{
+  JSValueConst obj;
+  JSAtom atom;
+  int ret;
+
+  obj = argv[0];
+  if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+  atom = JS_ValueToAtom(ctx, argv[1]);
+  if (unlikely(atom == JS_ATOM_NULL))
+    return JS_EXCEPTION;
+  ret = JS_DeleteProperty(ctx, obj, atom, 0);
+  JS_FreeAtom(ctx, atom);
+  if (ret < 0)
+    return JS_EXCEPTION;
+  else
+    return JS_NewBool(ctx, ret);
+}
+
+JSValue js_reflect_get(JSContext *ctx, JSValueConst this_val,
+                              int argc, JSValueConst *argv)
+{
+  JSValueConst obj, prop, receiver;
+  JSAtom atom;
+  JSValue ret;
+
+  obj = argv[0];
+  prop = argv[1];
+  if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+  if (argc > 2)
+    receiver = argv[2];
+  else
+    receiver = obj;
+  atom = JS_ValueToAtom(ctx, prop);
+  if (unlikely(atom == JS_ATOM_NULL))
+    return JS_EXCEPTION;
+  ret = JS_GetPropertyInternal(ctx, obj, atom, receiver, FALSE);
+  JS_FreeAtom(ctx, atom);
+  return ret;
+}
+
+JSValue js_reflect_has(JSContext *ctx, JSValueConst this_val,
+                              int argc, JSValueConst *argv)
+{
+  JSValueConst obj, prop;
+  JSAtom atom;
+  int ret;
+
+  obj = argv[0];
+  prop = argv[1];
+  if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+  atom = JS_ValueToAtom(ctx, prop);
+  if (unlikely(atom == JS_ATOM_NULL))
+    return JS_EXCEPTION;
+  ret = JS_HasProperty(ctx, obj, atom);
+  JS_FreeAtom(ctx, atom);
+  if (ret < 0)
+    return JS_EXCEPTION;
+  else
+    return JS_NewBool(ctx, ret);
+}
+
+JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val,
+                              int argc, JSValueConst *argv)
+{
+  JSValueConst obj, prop, val, receiver;
+  int ret;
+  JSAtom atom;
+
+  obj = argv[0];
+  prop = argv[1];
+  val = argv[2];
+  if (argc > 3)
+    receiver = argv[3];
+  else
+    receiver = obj;
+  if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+  atom = JS_ValueToAtom(ctx, prop);
+  if (unlikely(atom == JS_ATOM_NULL))
+    return JS_EXCEPTION;
+  ret = JS_SetPropertyGeneric(ctx, obj, atom,
+                              JS_DupValue(ctx, val), receiver, 0);
+  JS_FreeAtom(ctx, atom);
+  if (ret < 0)
+    return JS_EXCEPTION;
+  else
+    return JS_NewBool(ctx, ret);
+}
+
+JSValue js_reflect_setPrototypeOf(JSContext *ctx, JSValueConst this_val,
+                                         int argc, JSValueConst *argv)
+{
+  int ret;
+  ret = JS_SetPrototypeInternal(ctx, argv[0], argv[1], FALSE);
+  if (ret < 0)
+    return JS_EXCEPTION;
+  else
+    return JS_NewBool(ctx, ret);
+}
+
+JSValue js_reflect_ownKeys(JSContext *ctx, JSValueConst this_val,
+                                  int argc, JSValueConst *argv)
+{
+  if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT)
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+  return JS_GetOwnPropertyNames2(ctx, argv[0],
+                                 JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK,
+                                 JS_ITERATOR_KIND_KEY);
+}
diff --git a/src/core/builtins/js-reflect.h b/src/core/builtins/js-reflect.h
new file mode 100644
index 000000000..bba75e619
--- /dev/null
+++ b/src/core/builtins/js-reflect.h
@@ -0,0 +1,48 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_REFLECT_H
+#define QUICKJS_JS_REFLECT_H
+
+#include "quickjs/quickjs.h"
+
+JSValue js_reflect_apply(JSContext *ctx, JSValueConst this_val,
+                                int argc, JSValueConst *argv);
+JSValue js_reflect_construct(JSContext *ctx, JSValueConst this_val,
+                                    int argc, JSValueConst *argv);
+JSValue js_reflect_deleteProperty(JSContext *ctx, JSValueConst this_val,
+                                         int argc, JSValueConst *argv);
+JSValue js_reflect_get(JSContext *ctx, JSValueConst this_val,
+                              int argc, JSValueConst *argv);
+JSValue js_reflect_has(JSContext *ctx, JSValueConst this_val,
+                              int argc, JSValueConst *argv);
+JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val,
+                              int argc, JSValueConst *argv);
+JSValue js_reflect_setPrototypeOf(JSContext *ctx, JSValueConst this_val,
+                                         int argc, JSValueConst *argv);
+JSValue js_reflect_ownKeys(JSContext *ctx, JSValueConst this_val,
+                                  int argc, JSValueConst *argv);
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-regexp.c b/src/core/builtins/js-regexp.c
new file mode 100644
index 000000000..dcddca8e6
--- /dev/null
+++ b/src/core/builtins/js-regexp.c
@@ -0,0 +1,1491 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "quickjs/libregexp-opcode.h"
+#include "quickjs/libregexp.h"
+
+#include "../convertion.h"
+#include "../exception.h"
+#include "../function.h"
+#include "../object.h"
+#include "../runtime.h"
+#include "../string.h"
+#include "js-array.h"
+#include "js-function.h"
+#include "js-object.h"
+#include "js-operator.h"
+#include "js-regexp.h"
+#include "js-string.h"
+
+/* RegExp */
+
+void js_regexp_finalizer(JSRuntime *rt, JSValue val)
+{
+  JSObject *p = JS_VALUE_GET_OBJ(val);
+  JSRegExp *re = &p->u.regexp;
+  JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, re->bytecode));
+  JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, re->pattern));
+}
+
+/* create a string containing the RegExp bytecode */
+JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
+                                 JSValueConst flags)
+{
+  const char *str;
+  int re_flags, mask;
+  uint8_t *re_bytecode_buf;
+  size_t i, len;
+  int re_bytecode_len;
+  JSValue ret;
+  char error_msg[64];
+
+  re_flags = 0;
+  if (!JS_IsUndefined(flags)) {
+    str = JS_ToCStringLen(ctx, &len, flags);
+    if (!str)
+      return JS_EXCEPTION;
+    /* XXX: re_flags = LRE_FLAG_OCTAL unless strict mode? */
+    for (i = 0; i < len; i++) {
+      switch(str[i]) {
+        case 'g':
+          mask = LRE_FLAG_GLOBAL;
+          break;
+        case 'i':
+          mask = LRE_FLAG_IGNORECASE;
+          break;
+        case 'm':
+          mask = LRE_FLAG_MULTILINE;
+          break;
+        case 's':
+          mask = LRE_FLAG_DOTALL;
+          break;
+        case 'u':
+          mask = LRE_FLAG_UTF16;
+          break;
+        case 'y':
+          mask = LRE_FLAG_STICKY;
+          break;
+        default:
+          goto bad_flags;
+      }
+      if ((re_flags & mask) != 0) {
+      bad_flags:
+        JS_FreeCString(ctx, str);
+        return JS_ThrowSyntaxError(ctx, "invalid regular expression flags");
+      }
+      re_flags |= mask;
+    }
+    JS_FreeCString(ctx, str);
+  }
+
+  str = JS_ToCStringLen2(ctx, &len, pattern, !(re_flags & LRE_FLAG_UTF16));
+  if (!str)
+    return JS_EXCEPTION;
+  re_bytecode_buf = lre_compile(&re_bytecode_len, error_msg,
+                                sizeof(error_msg), str, len, re_flags, ctx);
+  JS_FreeCString(ctx, str);
+  if (!re_bytecode_buf) {
+    JS_ThrowSyntaxError(ctx, "%s", error_msg);
+    return JS_EXCEPTION;
+  }
+
+  ret = js_new_string8(ctx, re_bytecode_buf, re_bytecode_len);
+  js_free(ctx, re_bytecode_buf);
+  return ret;
+}
+
+/* create a RegExp object from a string containing the RegExp bytecode
+   and the source pattern */
+JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor,
+                                              JSValue pattern, JSValue bc)
+{
+  JSValue obj;
+  JSObject *p;
+  JSRegExp *re;
+
+  /* sanity check */
+  if (JS_VALUE_GET_TAG(bc) != JS_TAG_STRING ||
+      JS_VALUE_GET_TAG(pattern) != JS_TAG_STRING) {
+    JS_ThrowTypeError(ctx, "string expected");
+  fail:
+    JS_FreeValue(ctx, bc);
+    JS_FreeValue(ctx, pattern);
+    return JS_EXCEPTION;
+  }
+
+  obj = js_create_from_ctor(ctx, ctor, JS_CLASS_REGEXP);
+  if (JS_IsException(obj))
+    goto fail;
+  p = JS_VALUE_GET_OBJ(obj);
+  re = &p->u.regexp;
+  re->pattern = JS_VALUE_GET_STRING(pattern);
+  re->bytecode = JS_VALUE_GET_STRING(bc);
+  JS_DefinePropertyValue(ctx, obj, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0),
+                         JS_PROP_WRITABLE);
+  return obj;
+}
+
+JSRegExp *js_get_regexp(JSContext *ctx, JSValueConst obj, BOOL throw_error)
+{
+  if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
+    JSObject *p = JS_VALUE_GET_OBJ(obj);
+    if (p->class_id == JS_CLASS_REGEXP)
+      return &p->u.regexp;
+  }
+  if (throw_error) {
+    JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP);
+  }
+  return NULL;
+}
+
+/* return < 0 if exception or TRUE/FALSE */
+int js_is_regexp(JSContext *ctx, JSValueConst obj)
+{
+  JSValue m;
+
+  if (!JS_IsObject(obj))
+    return FALSE;
+  m = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_match);
+  if (JS_IsException(m))
+    return -1;
+  if (!JS_IsUndefined(m))
+    return JS_ToBoolFree(ctx, m);
+  return js_get_regexp(ctx, obj, FALSE) != NULL;
+}
+
+JSValue js_regexp_constructor(JSContext *ctx, JSValueConst new_target,
+                                     int argc, JSValueConst *argv)
+{
+  JSValue pattern, flags, bc, val;
+  JSValueConst pat, flags1;
+  JSRegExp *re;
+  int pat_is_regexp;
+
+  pat = argv[0];
+  flags1 = argv[1];
+  pat_is_regexp = js_is_regexp(ctx, pat);
+  if (pat_is_regexp < 0)
+    return JS_EXCEPTION;
+  if (JS_IsUndefined(new_target)) {
+    /* called as a function */
+    new_target = JS_GetActiveFunction(ctx);
+    if (pat_is_regexp && JS_IsUndefined(flags1)) {
+      JSValue ctor;
+      BOOL res;
+      ctor = JS_GetProperty(ctx, pat, JS_ATOM_constructor);
+      if (JS_IsException(ctor))
+        return ctor;
+      res = js_same_value(ctx, ctor, new_target);
+      JS_FreeValue(ctx, ctor);
+      if (res)
+        return JS_DupValue(ctx, pat);
+    }
+  }
+  re = js_get_regexp(ctx, pat, FALSE);
+  if (re) {
+    pattern = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
+    if (JS_IsUndefined(flags1)) {
+      bc = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->bytecode));
+      goto no_compilation;
+    } else {
+      flags = JS_ToString(ctx, flags1);
+      if (JS_IsException(flags))
+        goto fail;
+    }
+  } else {
+    flags = JS_UNDEFINED;
+    if (pat_is_regexp) {
+      pattern = JS_GetProperty(ctx, pat, JS_ATOM_source);
+      if (JS_IsException(pattern))
+        goto fail;
+      if (JS_IsUndefined(flags1)) {
+        flags = JS_GetProperty(ctx, pat, JS_ATOM_flags);
+        if (JS_IsException(flags))
+          goto fail;
+      } else {
+        flags = JS_DupValue(ctx, flags1);
+      }
+    } else {
+      pattern = JS_DupValue(ctx, pat);
+      flags = JS_DupValue(ctx, flags1);
+    }
+    if (JS_IsUndefined(pattern)) {
+      pattern = JS_AtomToString(ctx, JS_ATOM_empty_string);
+    } else {
+      val = pattern;
+      pattern = JS_ToString(ctx, val);
+      JS_FreeValue(ctx, val);
+      if (JS_IsException(pattern))
+        goto fail;
+    }
+  }
+  bc = js_compile_regexp(ctx, pattern, flags);
+  if (JS_IsException(bc))
+    goto fail;
+  JS_FreeValue(ctx, flags);
+no_compilation:
+  return js_regexp_constructor_internal(ctx, new_target, pattern, bc);
+fail:
+  JS_FreeValue(ctx, pattern);
+  JS_FreeValue(ctx, flags);
+  return JS_EXCEPTION;
+}
+
+JSValue js_regexp_compile(JSContext *ctx, JSValueConst this_val,
+                                 int argc, JSValueConst *argv)
+{
+  JSRegExp *re1, *re;
+  JSValueConst pattern1, flags1;
+  JSValue bc, pattern;
+
+  re = js_get_regexp(ctx, this_val, TRUE);
+  if (!re)
+    return JS_EXCEPTION;
+  pattern1 = argv[0];
+  flags1 = argv[1];
+  re1 = js_get_regexp(ctx, pattern1, FALSE);
+  if (re1) {
+    if (!JS_IsUndefined(flags1))
+      return JS_ThrowTypeError(ctx, "flags must be undefined");
+    pattern = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re1->pattern));
+    bc = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re1->bytecode));
+  } else {
+    bc = JS_UNDEFINED;
+    if (JS_IsUndefined(pattern1))
+      pattern = JS_AtomToString(ctx, JS_ATOM_empty_string);
+    else
+      pattern = JS_ToString(ctx, pattern1);
+    if (JS_IsException(pattern))
+      goto fail;
+    bc = js_compile_regexp(ctx, pattern, flags1);
+    if (JS_IsException(bc))
+      goto fail;
+  }
+  JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
+  JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, re->bytecode));
+  re->pattern = JS_VALUE_GET_STRING(pattern);
+  re->bytecode = JS_VALUE_GET_STRING(bc);
+  if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
+                     JS_NewInt32(ctx, 0)) < 0)
+    return JS_EXCEPTION;
+  return JS_DupValue(ctx, this_val);
+fail:
+  JS_FreeValue(ctx, pattern);
+  JS_FreeValue(ctx, bc);
+  return JS_EXCEPTION;
+}
+
+#if 0
+JSValue js_regexp_get___source(JSContext *ctx, JSValueConst this_val)
+{
+    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
+    if (!re)
+        return JS_EXCEPTION;
+    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
+}
+
+JSValue js_regexp_get___flags(JSContext *ctx, JSValueConst this_val)
+{
+    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
+    int flags;
+
+    if (!re)
+        return JS_EXCEPTION;
+    flags = lre_get_flags(re->bytecode->u.str8);
+    return JS_NewInt32(ctx, flags);
+}
+#endif
+
+JSValue js_regexp_get_source(JSContext *ctx, JSValueConst this_val)
+{
+  JSRegExp *re;
+  JSString *p;
+  StringBuffer b_s, *b = &b_s;
+  int i, n, c, c2, bra;
+
+  if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+
+  if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP]))
+    goto empty_regex;
+
+  re = js_get_regexp(ctx, this_val, TRUE);
+  if (!re)
+    return JS_EXCEPTION;
+
+  p = re->pattern;
+
+  if (p->len == 0) {
+  empty_regex:
+    return JS_NewString(ctx, "(?:)");
+  }
+  string_buffer_init2(ctx, b, p->len, p->is_wide_char);
+
+  /* Escape '/' and newline sequences as needed */
+  bra = 0;
+  for (i = 0, n = p->len; i < n;) {
+    c2 = -1;
+    switch (c = string_get(p, i++)) {
+      case '\\':
+        if (i < n)
+          c2 = string_get(p, i++);
+        break;
+      case ']':
+        bra = 0;
+        break;
+      case '[':
+        if (!bra) {
+          if (i < n && string_get(p, i) == ']')
+            c2 = string_get(p, i++);
+          bra = 1;
+        }
+        break;
+      case '\n':
+        c = '\\';
+        c2 = 'n';
+        break;
+      case '\r':
+        c = '\\';
+        c2 = 'r';
+        break;
+      case '/':
+        if (!bra) {
+          c = '\\';
+          c2 = '/';
+        }
+        break;
+    }
+    string_buffer_putc16(b, c);
+    if (c2 >= 0)
+      string_buffer_putc16(b, c2);
+  }
+  return string_buffer_end(b);
+}
+
+JSValue js_regexp_get_flag(JSContext *ctx, JSValueConst this_val, int mask)
+{
+  JSRegExp *re;
+  int flags;
+
+  if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+
+  re = js_get_regexp(ctx, this_val, FALSE);
+  if (!re) {
+    if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP]))
+      return JS_UNDEFINED;
+    else
+      return JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP);
+  }
+
+  flags = lre_get_flags(re->bytecode->u.str8);
+  return JS_NewBool(ctx, (flags & mask) != 0);
+}
+
+JSValue js_regexp_get_flags(JSContext *ctx, JSValueConst this_val)
+{
+  char str[8], *p = str;
+  int res;
+
+  if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+
+  res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, JS_ATOM_global));
+  if (res < 0)
+    goto exception;
+  if (res)
+    *p++ = 'g';
+  res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "ignoreCase"));
+  if (res < 0)
+    goto exception;
+  if (res)
+    *p++ = 'i';
+  res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "multiline"));
+  if (res < 0)
+    goto exception;
+  if (res)
+    *p++ = 'm';
+  res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "dotAll"));
+  if (res < 0)
+    goto exception;
+  if (res)
+    *p++ = 's';
+  res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, JS_ATOM_unicode));
+  if (res < 0)
+    goto exception;
+  if (res)
+    *p++ = 'u';
+  res = JS_ToBoolFree(ctx, JS_GetPropertyStr(ctx, this_val, "sticky"));
+  if (res < 0)
+    goto exception;
+  if (res)
+    *p++ = 'y';
+  return JS_NewStringLen(ctx, str, p - str);
+
+exception:
+  return JS_EXCEPTION;
+}
+
+JSValue js_regexp_toString(JSContext *ctx, JSValueConst this_val,
+                                  int argc, JSValueConst *argv)
+{
+  JSValue pattern, flags;
+  StringBuffer b_s, *b = &b_s;
+
+  if (!JS_IsObject(this_val))
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+
+  string_buffer_init(ctx, b, 0);
+  string_buffer_putc8(b, '/');
+  pattern = JS_GetProperty(ctx, this_val, JS_ATOM_source);
+  if (string_buffer_concat_value_free(b, pattern))
+    goto fail;
+  string_buffer_putc8(b, '/');
+  flags = JS_GetProperty(ctx, this_val, JS_ATOM_flags);
+  if (string_buffer_concat_value_free(b, flags))
+    goto fail;
+  return string_buffer_end(b);
+
+fail:
+  string_buffer_free(b);
+  return JS_EXCEPTION;
+}
+
+BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size)
+{
+  JSContext *ctx = opaque;
+  return js_check_stack_overflow(ctx->rt, alloca_size);
+}
+
+void *lre_realloc(void *opaque, void *ptr, size_t size)
+{
+  JSContext *ctx = opaque;
+  /* No JS exception is raised here */
+  return js_realloc_rt(ctx->rt, ptr, size);
+}
+
+JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val,
+                              int argc, JSValueConst *argv)
+{
+  JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
+  JSString *str;
+  JSValue str_val, obj, val, groups = JS_UNDEFINED;
+  uint8_t *re_bytecode;
+  int ret;
+  uint8_t **capture, *str_buf;
+  int capture_count, shift, i, re_flags;
+  int64_t last_index;
+  const char *group_name_ptr;
+
+  if (!re)
+    return JS_EXCEPTION;
+  str_val = JS_ToString(ctx, argv[0]);
+  if (JS_IsException(str_val))
+    return str_val;
+  val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex);
+  if (JS_IsException(val) ||
+      JS_ToLengthFree(ctx, &last_index, val)) {
+    JS_FreeValue(ctx, str_val);
+    return JS_EXCEPTION;
+  }
+  re_bytecode = re->bytecode->u.str8;
+  re_flags = lre_get_flags(re_bytecode);
+  if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {
+    last_index = 0;
+  }
+  str = JS_VALUE_GET_STRING(str_val);
+  capture_count = lre_get_capture_count(re_bytecode);
+  capture = NULL;
+  if (capture_count > 0) {
+    capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2);
+    if (!capture) {
+      JS_FreeValue(ctx, str_val);
+      return JS_EXCEPTION;
+    }
+  }
+  shift = str->is_wide_char;
+  str_buf = str->u.str8;
+  if (last_index > str->len) {
+    ret = 2;
+  } else {
+    ret = lre_exec(capture, re_bytecode,
+                   str_buf, last_index, str->len,
+                   shift, ctx);
+  }
+  obj = JS_NULL;
+  if (ret != 1) {
+    if (ret >= 0) {
+      if (ret == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
+        if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
+                           JS_NewInt32(ctx, 0)) < 0)
+          goto fail;
+      }
+    } else {
+      JS_ThrowInternalError(ctx, "out of memory in regexp execution");
+      goto fail;
+    }
+    JS_FreeValue(ctx, str_val);
+  } else {
+    int prop_flags;
+    if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) {
+      if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
+                         JS_NewInt32(ctx, (capture[1] - str_buf) >> shift)) < 0)
+        goto fail;
+    }
+    obj = JS_NewArray(ctx);
+    if (JS_IsException(obj))
+      goto fail;
+    prop_flags = JS_PROP_C_W_E | JS_PROP_THROW;
+    group_name_ptr = lre_get_groupnames(re_bytecode);
+    if (group_name_ptr) {
+      groups = JS_NewObjectProto(ctx, JS_NULL);
+      if (JS_IsException(groups))
+        goto fail;
+    }
+
+    for(i = 0; i < capture_count; i++) {
+      int start, end;
+      JSValue val;
+      if (capture[2 * i] == NULL ||
+          capture[2 * i + 1] == NULL) {
+        val = JS_UNDEFINED;
+      } else {
+        start = (capture[2 * i] - str_buf) >> shift;
+        end = (capture[2 * i + 1] - str_buf) >> shift;
+        val = js_sub_string(ctx, str, start, end);
+        if (JS_IsException(val))
+          goto fail;
+      }
+      if (group_name_ptr && i > 0) {
+        if (*group_name_ptr) {
+          if (JS_DefinePropertyValueStr(ctx, groups, group_name_ptr,
+                                        JS_DupValue(ctx, val),
+                                        prop_flags) < 0) {
+            JS_FreeValue(ctx, val);
+            goto fail;
+          }
+        }
+        group_name_ptr += strlen(group_name_ptr) + 1;
+      }
+      if (JS_DefinePropertyValueUint32(ctx, obj, i, val, prop_flags) < 0)
+        goto fail;
+    }
+    if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_groups,
+                               groups, prop_flags) < 0)
+      goto fail;
+    if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_index,
+                               JS_NewInt32(ctx, (capture[0] - str_buf) >> shift), prop_flags) < 0)
+      goto fail;
+    if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_input, str_val, prop_flags) < 0)
+      goto fail1;
+  }
+  js_free(ctx, capture);
+  return obj;
+fail:
+  JS_FreeValue(ctx, groups);
+  JS_FreeValue(ctx, str_val);
+fail1:
+  JS_FreeValue(ctx, obj);
+  js_free(ctx, capture);
+  return JS_EXCEPTION;
+}
+
+/* delete portions of a string that match a given regex */
+JSValue JS_RegExpDelete(JSContext *ctx, JSValueConst this_val, JSValueConst arg)
+{
+  JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
+  JSString *str;
+  JSValue str_val, val;
+  uint8_t *re_bytecode;
+  int ret;
+  uint8_t **capture, *str_buf;
+  int capture_count, shift, re_flags;
+  int next_src_pos, start, end;
+  int64_t last_index;
+  StringBuffer b_s, *b = &b_s;
+
+  if (!re)
+    return JS_EXCEPTION;
+
+  string_buffer_init(ctx, b, 0);
+
+  capture = NULL;
+  str_val = JS_ToString(ctx, arg);
+  if (JS_IsException(str_val))
+    goto fail;
+  str = JS_VALUE_GET_STRING(str_val);
+  re_bytecode = re->bytecode->u.str8;
+  re_flags = lre_get_flags(re_bytecode);
+  if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {
+    last_index = 0;
+  } else {
+    val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex);
+    if (JS_IsException(val) || JS_ToLengthFree(ctx, &last_index, val))
+      goto fail;
+  }
+  capture_count = lre_get_capture_count(re_bytecode);
+  if (capture_count > 0) {
+    capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2);
+    if (!capture)
+      goto fail;
+  }
+  shift = str->is_wide_char;
+  str_buf = str->u.str8;
+  next_src_pos = 0;
+  for (;;) {
+    if (last_index > str->len)
+      break;
+
+    ret = lre_exec(capture, re_bytecode,
+                   str_buf, last_index, str->len, shift, ctx);
+    if (ret != 1) {
+      if (ret >= 0) {
+        if (ret == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
+          if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
+                             JS_NewInt32(ctx, 0)) < 0)
+            goto fail;
+        }
+      } else {
+        JS_ThrowInternalError(ctx, "out of memory in regexp execution");
+        goto fail;
+      }
+      break;
+    }
+    start = (capture[0] - str_buf) >> shift;
+    end = (capture[1] - str_buf) >> shift;
+    last_index = end;
+    if (next_src_pos < start) {
+      if (string_buffer_concat(b, str, next_src_pos, start))
+        goto fail;
+    }
+    next_src_pos = end;
+    if (!(re_flags & LRE_FLAG_GLOBAL)) {
+      if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
+                         JS_NewInt32(ctx, end)) < 0)
+        goto fail;
+      break;
+    }
+    if (end == start) {
+      if (!(re_flags & LRE_FLAG_UTF16) || (unsigned)end >= str->len || !str->is_wide_char) {
+        end++;
+      } else {
+        string_getc(str, &end);
+      }
+    }
+    last_index = end;
+  }
+  if (string_buffer_concat(b, str, next_src_pos, str->len))
+    goto fail;
+  JS_FreeValue(ctx, str_val);
+  js_free(ctx, capture);
+  return string_buffer_end(b);
+fail:
+  JS_FreeValue(ctx, str_val);
+  js_free(ctx, capture);
+  string_buffer_free(b);
+  return JS_EXCEPTION;
+}
+
+JSValue JS_RegExpExec(JSContext *ctx, JSValueConst r, JSValueConst s)
+{
+  JSValue method, ret;
+
+  method = JS_GetProperty(ctx, r, JS_ATOM_exec);
+  if (JS_IsException(method))
+    return method;
+  if (JS_IsFunction(ctx, method)) {
+    ret = JS_CallFree(ctx, method, r, 1, &s);
+    if (JS_IsException(ret))
+      return ret;
+    if (!JS_IsObject(ret) && !JS_IsNull(ret)) {
+      JS_FreeValue(ctx, ret);
+      return JS_ThrowTypeError(ctx, "RegExp exec method must return an object or null");
+    }
+    return ret;
+  }
+  JS_FreeValue(ctx, method);
+  return js_regexp_exec(ctx, r, 1, &s);
+}
+
+#if 0
+JSValue js_regexp___RegExpExec(JSContext *ctx, JSValueConst this_val,
+                                      int argc, JSValueConst *argv)
+{
+    return JS_RegExpExec(ctx, argv[0], argv[1]);
+}
+JSValue js_regexp___RegExpDelete(JSContext *ctx, JSValueConst this_val,
+                                        int argc, JSValueConst *argv)
+{
+    return JS_RegExpDelete(ctx, argv[0], argv[1]);
+}
+#endif
+
+JSValue js_regexp_test(JSContext *ctx, JSValueConst this_val,
+                              int argc, JSValueConst *argv)
+{
+  JSValue val;
+  BOOL ret;
+
+  val = JS_RegExpExec(ctx, this_val, argv[0]);
+  if (JS_IsException(val))
+    return JS_EXCEPTION;
+  ret = !JS_IsNull(val);
+  JS_FreeValue(ctx, val);
+  return JS_NewBool(ctx, ret);
+}
+
+JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val,
+                                      int argc, JSValueConst *argv)
+{
+  // [Symbol.match](str)
+  JSValueConst rx = this_val;
+  JSValue A, S, result, matchStr;
+  int global, n, fullUnicode, isEmpty;
+  JSString *p;
+
+  if (!JS_IsObject(rx))
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+
+  A = JS_UNDEFINED;
+  result = JS_UNDEFINED;
+  matchStr = JS_UNDEFINED;
+  S = JS_ToString(ctx, argv[0]);
+  if (JS_IsException(S))
+    goto exception;
+
+  global = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_global));
+  if (global < 0)
+    goto exception;
+
+  if (!global) {
+    A = JS_RegExpExec(ctx, rx, S);
+  } else {
+    fullUnicode = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_unicode));
+    if (fullUnicode < 0)
+      goto exception;
+
+    if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0)
+      goto exception;
+    A = JS_NewArray(ctx);
+    if (JS_IsException(A))
+      goto exception;
+    n = 0;
+    for(;;) {
+      JS_FreeValue(ctx, result);
+      result = JS_RegExpExec(ctx, rx, S);
+      if (JS_IsException(result))
+        goto exception;
+      if (JS_IsNull(result))
+        break;
+      matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
+      if (JS_IsException(matchStr))
+        goto exception;
+      isEmpty = JS_IsEmptyString(matchStr);
+      if (JS_SetPropertyInt64(ctx, A, n++, matchStr) < 0)
+        goto exception;
+      if (isEmpty) {
+        int64_t thisIndex, nextIndex;
+        if (JS_ToLengthFree(ctx, &thisIndex,
+                            JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0)
+          goto exception;
+        p = JS_VALUE_GET_STRING(S);
+        nextIndex = string_advance_index(p, thisIndex, fullUnicode);
+        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0)
+          goto exception;
+      }
+    }
+    if (n == 0) {
+      JS_FreeValue(ctx, A);
+      A = JS_NULL;
+    }
+  }
+  JS_FreeValue(ctx, result);
+  JS_FreeValue(ctx, S);
+  return A;
+
+exception:
+  JS_FreeValue(ctx, A);
+  JS_FreeValue(ctx, result);
+  JS_FreeValue(ctx, S);
+  return JS_EXCEPTION;
+}
+
+typedef struct JSRegExpStringIteratorData {
+  JSValue iterating_regexp;
+  JSValue iterated_string;
+  BOOL global;
+  BOOL unicode;
+  BOOL done;
+} JSRegExpStringIteratorData;
+
+void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val)
+{
+  JSObject *p = JS_VALUE_GET_OBJ(val);
+  JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data;
+  if (it) {
+    JS_FreeValueRT(rt, it->iterating_regexp);
+    JS_FreeValueRT(rt, it->iterated_string);
+    js_free_rt(rt, it);
+  }
+}
+
+void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val,
+                                           JS_MarkFunc *mark_func)
+{
+  JSObject *p = JS_VALUE_GET_OBJ(val);
+  JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data;
+  if (it) {
+    JS_MarkValue(rt, it->iterating_regexp, mark_func);
+    JS_MarkValue(rt, it->iterated_string, mark_func);
+  }
+}
+
+JSValue js_regexp_string_iterator_next(JSContext *ctx,
+                                              JSValueConst this_val,
+                                              int argc, JSValueConst *argv,
+                                              BOOL *pdone, int magic)
+{
+  JSRegExpStringIteratorData *it;
+  JSValueConst R, S;
+  JSValue matchStr = JS_UNDEFINED, match = JS_UNDEFINED;
+  JSString *sp;
+
+  it = JS_GetOpaque2(ctx, this_val, JS_CLASS_REGEXP_STRING_ITERATOR);
+  if (!it)
+    goto exception;
+  if (it->done) {
+    *pdone = TRUE;
+    return JS_UNDEFINED;
+  }
+  R = it->iterating_regexp;
+  S = it->iterated_string;
+  match = JS_RegExpExec(ctx, R, S);
+  if (JS_IsException(match))
+    goto exception;
+  if (JS_IsNull(match)) {
+    it->done = TRUE;
+    *pdone = TRUE;
+    return JS_UNDEFINED;
+  } else if (it->global) {
+    matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, match, 0));
+    if (JS_IsException(matchStr))
+      goto exception;
+    if (JS_IsEmptyString(matchStr)) {
+      int64_t thisIndex, nextIndex;
+      if (JS_ToLengthFree(ctx, &thisIndex,
+                          JS_GetProperty(ctx, R, JS_ATOM_lastIndex)) < 0)
+        goto exception;
+      sp = JS_VALUE_GET_STRING(S);
+      nextIndex = string_advance_index(sp, thisIndex, it->unicode);
+      if (JS_SetProperty(ctx, R, JS_ATOM_lastIndex,
+                         JS_NewInt64(ctx, nextIndex)) < 0)
+        goto exception;
+    }
+    JS_FreeValue(ctx, matchStr);
+  } else {
+    it->done = TRUE;
+  }
+  *pdone = FALSE;
+  return match;
+exception:
+  JS_FreeValue(ctx, match);
+  JS_FreeValue(ctx, matchStr);
+  *pdone = FALSE;
+  return JS_EXCEPTION;
+}
+
+JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val,
+                                         int argc, JSValueConst *argv)
+{
+  // [Symbol.matchAll](str)
+  JSValueConst R = this_val;
+  JSValue S, C, flags, matcher, iter;
+  JSValueConst args[2];
+  JSString *strp;
+  int64_t lastIndex;
+  JSRegExpStringIteratorData *it;
+
+  if (!JS_IsObject(R))
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+
+  C = JS_UNDEFINED;
+  flags = JS_UNDEFINED;
+  matcher = JS_UNDEFINED;
+  iter = JS_UNDEFINED;
+
+  S = JS_ToString(ctx, argv[0]);
+  if (JS_IsException(S))
+    goto exception;
+  C = JS_SpeciesConstructor(ctx, R, ctx->regexp_ctor);
+  if (JS_IsException(C))
+    goto exception;
+  flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, R, JS_ATOM_flags));
+  if (JS_IsException(flags))
+    goto exception;
+  args[0] = R;
+  args[1] = flags;
+  matcher = JS_CallConstructor(ctx, C, 2, args);
+  if (JS_IsException(matcher))
+    goto exception;
+  if (JS_ToLengthFree(ctx, &lastIndex,
+                      JS_GetProperty(ctx, R, JS_ATOM_lastIndex)))
+    goto exception;
+  if (JS_SetProperty(ctx, matcher, JS_ATOM_lastIndex,
+                     JS_NewInt64(ctx, lastIndex)) < 0)
+    goto exception;
+
+  iter = JS_NewObjectClass(ctx, JS_CLASS_REGEXP_STRING_ITERATOR);
+  if (JS_IsException(iter))
+    goto exception;
+  it = js_malloc(ctx, sizeof(*it));
+  if (!it)
+    goto exception;
+  it->iterating_regexp = matcher;
+  it->iterated_string = S;
+  strp = JS_VALUE_GET_STRING(flags);
+  it->global = string_indexof_char(strp, 'g', 0) >= 0;
+  it->unicode = string_indexof_char(strp, 'u', 0) >= 0;
+  it->done = FALSE;
+  JS_SetOpaque(iter, it);
+
+  JS_FreeValue(ctx, C);
+  JS_FreeValue(ctx, flags);
+  return iter;
+exception:
+  JS_FreeValue(ctx, S);
+  JS_FreeValue(ctx, C);
+  JS_FreeValue(ctx, flags);
+  JS_FreeValue(ctx, matcher);
+  JS_FreeValue(ctx, iter);
+  return JS_EXCEPTION;
+}
+
+typedef struct ValueBuffer {
+  JSContext *ctx;
+  JSValue *arr;
+  JSValue def[4];
+  int len;
+  int size;
+  int error_status;
+} ValueBuffer;
+
+int value_buffer_init(JSContext *ctx, ValueBuffer *b)
+{
+  b->ctx = ctx;
+  b->len = 0;
+  b->size = 4;
+  b->error_status = 0;
+  b->arr = b->def;
+  return 0;
+}
+
+void value_buffer_free(ValueBuffer *b)
+{
+  while (b->len > 0)
+    JS_FreeValue(b->ctx, b->arr[--b->len]);
+  if (b->arr != b->def)
+    js_free(b->ctx, b->arr);
+  b->arr = b->def;
+  b->size = 4;
+}
+
+int value_buffer_append(ValueBuffer *b, JSValue val)
+{
+  if (b->error_status)
+    return -1;
+
+  if (b->len >= b->size) {
+    int new_size = (b->len + (b->len >> 1) + 31) & ~16;
+    size_t slack;
+    JSValue *new_arr;
+
+    if (b->arr == b->def) {
+      new_arr = js_realloc2(b->ctx, NULL, sizeof(*b->arr) * new_size, &slack);
+      if (new_arr)
+        memcpy(new_arr, b->def, sizeof b->def);
+    } else {
+      new_arr = js_realloc2(b->ctx, b->arr, sizeof(*b->arr) * new_size, &slack);
+    }
+    if (!new_arr) {
+      value_buffer_free(b);
+      JS_FreeValue(b->ctx, val);
+      b->error_status = -1;
+      return -1;
+    }
+    new_size += slack / sizeof(*new_arr);
+    b->arr = new_arr;
+    b->size = new_size;
+  }
+  b->arr[b->len++] = val;
+  return 0;
+}
+
+int js_is_standard_regexp(JSContext *ctx, JSValueConst rx)
+{
+  JSValue val;
+  int res;
+
+  val = JS_GetProperty(ctx, rx, JS_ATOM_constructor);
+  if (JS_IsException(val))
+    return -1;
+  // rx.constructor === RegExp
+  res = js_same_value(ctx, val, ctx->regexp_ctor);
+  JS_FreeValue(ctx, val);
+  if (res) {
+    val = JS_GetProperty(ctx, rx, JS_ATOM_exec);
+    if (JS_IsException(val))
+      return -1;
+    // rx.exec === RE_exec
+    res = JS_IsCFunction(ctx, val, js_regexp_exec, 0);
+    JS_FreeValue(ctx, val);
+  }
+  return res;
+}
+
+JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
+                                        int argc, JSValueConst *argv)
+{
+  // [Symbol.replace](str, rep)
+  JSValueConst rx = this_val, rep = argv[1];
+  JSValueConst args[6];
+  JSValue str, rep_val, matched, tab, rep_str, namedCaptures, res;
+  JSString *sp, *rp;
+  StringBuffer b_s, *b = &b_s;
+  ValueBuffer v_b, *results = &v_b;
+  int nextSourcePosition, n, j, functionalReplace, is_global, fullUnicode;
+  uint32_t nCaptures;
+  int64_t position;
+
+  if (!JS_IsObject(rx))
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+
+  string_buffer_init(ctx, b, 0);
+  value_buffer_init(ctx, results);
+
+  rep_val = JS_UNDEFINED;
+  matched = JS_UNDEFINED;
+  tab = JS_UNDEFINED;
+  rep_str = JS_UNDEFINED;
+  namedCaptures = JS_UNDEFINED;
+
+  str = JS_ToString(ctx, argv[0]);
+  if (JS_IsException(str))
+    goto exception;
+
+  sp = JS_VALUE_GET_STRING(str);
+  rp = NULL;
+  functionalReplace = JS_IsFunction(ctx, rep);
+  if (!functionalReplace) {
+    rep_val = JS_ToString(ctx, rep);
+    if (JS_IsException(rep_val))
+      goto exception;
+    rp = JS_VALUE_GET_STRING(rep_val);
+  }
+  fullUnicode = 0;
+  is_global = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_global));
+  if (is_global < 0)
+    goto exception;
+  if (is_global) {
+    fullUnicode = JS_ToBoolFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_unicode));
+    if (fullUnicode < 0)
+      goto exception;
+    if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0)
+      goto exception;
+  }
+
+  if (rp && rp->len == 0 && is_global && js_is_standard_regexp(ctx, rx)) {
+    /* use faster version for simple cases */
+    res = JS_RegExpDelete(ctx, rx, str);
+    goto done;
+  }
+  for(;;) {
+    JSValue result;
+    result = JS_RegExpExec(ctx, rx, str);
+    if (JS_IsException(result))
+      goto exception;
+    if (JS_IsNull(result))
+      break;
+    if (value_buffer_append(results, result) < 0)
+      goto exception;
+    if (!is_global)
+      break;
+    JS_FreeValue(ctx, matched);
+    matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
+    if (JS_IsException(matched))
+      goto exception;
+    if (JS_IsEmptyString(matched)) {
+      /* always advance of at least one char */
+      int64_t thisIndex, nextIndex;
+      if (JS_ToLengthFree(ctx, &thisIndex, JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0)
+        goto exception;
+      nextIndex = string_advance_index(sp, thisIndex, fullUnicode);
+      if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0)
+        goto exception;
+    }
+  }
+  nextSourcePosition = 0;
+  for(j = 0; j < results->len; j++) {
+    JSValueConst result;
+    result = results->arr[j];
+    if (js_get_length32(ctx, &nCaptures, result) < 0)
+      goto exception;
+    JS_FreeValue(ctx, matched);
+    matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
+    if (JS_IsException(matched))
+      goto exception;
+    if (JS_ToLengthFree(ctx, &position, JS_GetProperty(ctx, result, JS_ATOM_index)))
+      goto exception;
+    if (position > sp->len)
+      position = sp->len;
+    else if (position < 0)
+      position = 0;
+    /* ignore substition if going backward (can happen
+       with custom regexp object) */
+    JS_FreeValue(ctx, tab);
+    tab = JS_NewArray(ctx);
+    if (JS_IsException(tab))
+      goto exception;
+    if (JS_DefinePropertyValueInt64(ctx, tab, 0, JS_DupValue(ctx, matched),
+                                    JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+      goto exception;
+    for(n = 1; n < nCaptures; n++) {
+      JSValue capN;
+      capN = JS_GetPropertyInt64(ctx, result, n);
+      if (JS_IsException(capN))
+        goto exception;
+      if (!JS_IsUndefined(capN)) {
+        capN = JS_ToStringFree(ctx, capN);
+        if (JS_IsException(capN))
+          goto exception;
+      }
+      if (JS_DefinePropertyValueInt64(ctx, tab, n, capN,
+                                      JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+        goto exception;
+    }
+    JS_FreeValue(ctx, namedCaptures);
+    namedCaptures = JS_GetProperty(ctx, result, JS_ATOM_groups);
+    if (JS_IsException(namedCaptures))
+      goto exception;
+    if (functionalReplace) {
+      if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_NewInt32(ctx, position), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+        goto exception;
+      if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, str), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+        goto exception;
+      if (!JS_IsUndefined(namedCaptures)) {
+        if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, namedCaptures), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+          goto exception;
+      }
+      args[0] = JS_UNDEFINED;
+      args[1] = tab;
+      JS_FreeValue(ctx, rep_str);
+      rep_str = JS_ToStringFree(ctx, js_function_apply(ctx, rep, 2, args, 0));
+    } else {
+      JSValue namedCaptures1;
+      if (!JS_IsUndefined(namedCaptures)) {
+        namedCaptures1 = JS_ToObject(ctx, namedCaptures);
+        if (JS_IsException(namedCaptures1))
+          goto exception;
+      } else {
+        namedCaptures1 = JS_UNDEFINED;
+      }
+      args[0] = matched;
+      args[1] = str;
+      args[2] = JS_NewInt32(ctx, position);
+      args[3] = tab;
+      args[4] = namedCaptures1;
+      args[5] = rep_val;
+      JS_FreeValue(ctx, rep_str);
+      rep_str = js_string___GetSubstitution(ctx, JS_UNDEFINED, 6, args);
+      JS_FreeValue(ctx, namedCaptures1);
+    }
+    if (JS_IsException(rep_str))
+      goto exception;
+    if (position >= nextSourcePosition) {
+      string_buffer_concat(b, sp, nextSourcePosition, position);
+      string_buffer_concat_value(b, rep_str);
+      nextSourcePosition = position + JS_VALUE_GET_STRING(matched)->len;
+    }
+  }
+  string_buffer_concat(b, sp, nextSourcePosition, sp->len);
+  res = string_buffer_end(b);
+  goto done1;
+
+exception:
+  res = JS_EXCEPTION;
+done:
+  string_buffer_free(b);
+done1:
+  value_buffer_free(results);
+  JS_FreeValue(ctx, rep_val);
+  JS_FreeValue(ctx, matched);
+  JS_FreeValue(ctx, tab);
+  JS_FreeValue(ctx, rep_str);
+  JS_FreeValue(ctx, namedCaptures);
+  JS_FreeValue(ctx, str);
+  return res;
+}
+
+JSValue js_regexp_Symbol_search(JSContext *ctx, JSValueConst this_val,
+                                       int argc, JSValueConst *argv)
+{
+  JSValueConst rx = this_val;
+  JSValue str, previousLastIndex, currentLastIndex, result, index;
+
+  if (!JS_IsObject(rx))
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+
+  result = JS_UNDEFINED;
+  currentLastIndex = JS_UNDEFINED;
+  previousLastIndex = JS_UNDEFINED;
+  str = JS_ToString(ctx, argv[0]);
+  if (JS_IsException(str))
+    goto exception;
+
+  previousLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex);
+  if (JS_IsException(previousLastIndex))
+    goto exception;
+
+  if (!js_same_value(ctx, previousLastIndex, JS_NewInt32(ctx, 0))) {
+    if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0) {
+      goto exception;
+    }
+  }
+  result = JS_RegExpExec(ctx, rx, str);
+  if (JS_IsException(result))
+    goto exception;
+  currentLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex);
+  if (JS_IsException(currentLastIndex))
+    goto exception;
+  if (js_same_value(ctx, currentLastIndex, previousLastIndex)) {
+    JS_FreeValue(ctx, previousLastIndex);
+  } else {
+    if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, previousLastIndex) < 0) {
+      previousLastIndex = JS_UNDEFINED;
+      goto exception;
+    }
+  }
+  JS_FreeValue(ctx, str);
+  JS_FreeValue(ctx, currentLastIndex);
+
+  if (JS_IsNull(result)) {
+    return JS_NewInt32(ctx, -1);
+  } else {
+    index = JS_GetProperty(ctx, result, JS_ATOM_index);
+    JS_FreeValue(ctx, result);
+    return index;
+  }
+
+exception:
+  JS_FreeValue(ctx, result);
+  JS_FreeValue(ctx, str);
+  JS_FreeValue(ctx, currentLastIndex);
+  JS_FreeValue(ctx, previousLastIndex);
+  return JS_EXCEPTION;
+}
+
+JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val,
+                                      int argc, JSValueConst *argv)
+{
+  // [Symbol.split](str, limit)
+  JSValueConst rx = this_val;
+  JSValueConst args[2];
+  JSValue str, ctor, splitter, A, flags, z, sub;
+  JSString *strp;
+  uint32_t lim, size, p, q;
+  int unicodeMatching;
+  int64_t lengthA, e, numberOfCaptures, i;
+
+  if (!JS_IsObject(rx))
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+
+  ctor = JS_UNDEFINED;
+  splitter = JS_UNDEFINED;
+  A = JS_UNDEFINED;
+  flags = JS_UNDEFINED;
+  z = JS_UNDEFINED;
+  str = JS_ToString(ctx, argv[0]);
+  if (JS_IsException(str))
+    goto exception;
+  ctor = JS_SpeciesConstructor(ctx, rx, ctx->regexp_ctor);
+  if (JS_IsException(ctor))
+    goto exception;
+  flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_flags));
+  if (JS_IsException(flags))
+    goto exception;
+  strp = JS_VALUE_GET_STRING(flags);
+  unicodeMatching = string_indexof_char(strp, 'u', 0) >= 0;
+  if (string_indexof_char(strp, 'y', 0) < 0) {
+    flags = JS_ConcatString3(ctx, "", flags, "y");
+    if (JS_IsException(flags))
+      goto exception;
+  }
+  args[0] = rx;
+  args[1] = flags;
+  splitter = JS_CallConstructor(ctx, ctor, 2, args);
+  if (JS_IsException(splitter))
+    goto exception;
+  A = JS_NewArray(ctx);
+  if (JS_IsException(A))
+    goto exception;
+  lengthA = 0;
+  if (JS_IsUndefined(argv[1])) {
+    lim = 0xffffffff;
+  } else {
+    if (JS_ToUint32(ctx, &lim, argv[1]) < 0)
+      goto exception;
+    if (lim == 0)
+      goto done;
+  }
+  strp = JS_VALUE_GET_STRING(str);
+  p = q = 0;
+  size = strp->len;
+  if (size == 0) {
+    z = JS_RegExpExec(ctx, splitter, str);
+    if (JS_IsException(z))
+      goto exception;
+    if (JS_IsNull(z))
+      goto add_tail;
+    goto done;
+  }
+  while (q < size) {
+    if (JS_SetProperty(ctx, splitter, JS_ATOM_lastIndex, JS_NewInt32(ctx, q)) < 0)
+      goto exception;
+    JS_FreeValue(ctx, z);
+    z = JS_RegExpExec(ctx, splitter, str);
+    if (JS_IsException(z))
+      goto exception;
+    if (JS_IsNull(z)) {
+      q = string_advance_index(strp, q, unicodeMatching);
+    } else {
+      if (JS_ToLengthFree(ctx, &e, JS_GetProperty(ctx, splitter, JS_ATOM_lastIndex)))
+        goto exception;
+      if (e > size)
+        e = size;
+      if (e == p) {
+        q = string_advance_index(strp, q, unicodeMatching);
+      } else {
+        sub = js_sub_string(ctx, strp, p, q);
+        if (JS_IsException(sub))
+          goto exception;
+        if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub,
+                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+          goto exception;
+        if (lengthA == lim)
+          goto done;
+        p = e;
+        if (js_get_length64(ctx, &numberOfCaptures, z))
+          goto exception;
+        for(i = 1; i < numberOfCaptures; i++) {
+          sub = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, z, i));
+          if (JS_IsException(sub))
+            goto exception;
+          if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+            goto exception;
+          if (lengthA == lim)
+            goto done;
+        }
+        q = p;
+      }
+    }
+  }
+add_tail:
+  if (p > size)
+    p = size;
+  sub = js_sub_string(ctx, strp, p, size);
+  if (JS_IsException(sub))
+    goto exception;
+  if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+    goto exception;
+  goto done;
+exception:
+  JS_FreeValue(ctx, A);
+  A = JS_EXCEPTION;
+done:
+  JS_FreeValue(ctx, str);
+  JS_FreeValue(ctx, ctor);
+  JS_FreeValue(ctx, splitter);
+  JS_FreeValue(ctx, flags);
+  JS_FreeValue(ctx, z);
+  return A;
+}
+
+const JSCFunctionListEntry js_regexp_funcs[] = {
+    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
+    //JS_CFUNC_DEF("__RegExpExec", 2, js_regexp___RegExpExec ),
+    //JS_CFUNC_DEF("__RegExpDelete", 2, js_regexp___RegExpDelete ),
+};
+
+const JSCFunctionListEntry js_regexp_proto_funcs[] = {
+    JS_CGETSET_DEF("flags", js_regexp_get_flags, NULL ),
+    JS_CGETSET_DEF("source", js_regexp_get_source, NULL ),
+    JS_CGETSET_MAGIC_DEF("global", js_regexp_get_flag, NULL, 1 ),
+    JS_CGETSET_MAGIC_DEF("ignoreCase", js_regexp_get_flag, NULL, 2 ),
+    JS_CGETSET_MAGIC_DEF("multiline", js_regexp_get_flag, NULL, 4 ),
+    JS_CGETSET_MAGIC_DEF("dotAll", js_regexp_get_flag, NULL, 8 ),
+    JS_CGETSET_MAGIC_DEF("unicode", js_regexp_get_flag, NULL, 16 ),
+    JS_CGETSET_MAGIC_DEF("sticky", js_regexp_get_flag, NULL, 32 ),
+    JS_CFUNC_DEF("exec", 1, js_regexp_exec ),
+    JS_CFUNC_DEF("compile", 2, js_regexp_compile ),
+    JS_CFUNC_DEF("test", 1, js_regexp_test ),
+    JS_CFUNC_DEF("toString", 0, js_regexp_toString ),
+    JS_CFUNC_DEF("[Symbol.replace]", 2, js_regexp_Symbol_replace ),
+    JS_CFUNC_DEF("[Symbol.match]", 1, js_regexp_Symbol_match ),
+    JS_CFUNC_DEF("[Symbol.matchAll]", 1, js_regexp_Symbol_matchAll ),
+    JS_CFUNC_DEF("[Symbol.search]", 1, js_regexp_Symbol_search ),
+    JS_CFUNC_DEF("[Symbol.split]", 2, js_regexp_Symbol_split ),
+    //JS_CGETSET_DEF("__source", js_regexp_get___source, NULL ),
+    //JS_CGETSET_DEF("__flags", js_regexp_get___flags, NULL ),
+};
+
+const JSCFunctionListEntry js_regexp_string_iterator_proto_funcs[] = {
+    JS_ITERATOR_NEXT_DEF("next", 0, js_regexp_string_iterator_next, 0 ),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "RegExp String Iterator", JS_PROP_CONFIGURABLE ),
+};
+
+void JS_AddIntrinsicRegExpCompiler(JSContext *ctx)
+{
+  ctx->compile_regexp = js_compile_regexp;
+}
+
+void JS_AddIntrinsicRegExp(JSContext *ctx)
+{
+  JSValueConst obj;
+
+  JS_AddIntrinsicRegExpCompiler(ctx);
+
+  ctx->class_proto[JS_CLASS_REGEXP] = JS_NewObject(ctx);
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_REGEXP], js_regexp_proto_funcs,
+                             countof(js_regexp_proto_funcs));
+  obj = JS_NewGlobalCConstructor(ctx, "RegExp", js_regexp_constructor, 2,
+                                 ctx->class_proto[JS_CLASS_REGEXP]);
+  ctx->regexp_ctor = JS_DupValue(ctx, obj);
+  JS_SetPropertyFunctionList(ctx, obj, js_regexp_funcs, countof(js_regexp_funcs));
+
+  ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR] =
+      JS_NewObjectProto(ctx, ctx->iterator_proto);
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR],
+                             js_regexp_string_iterator_proto_funcs,
+                             countof(js_regexp_string_iterator_proto_funcs));
+}
diff --git a/src/core/builtins/js-regexp.h b/src/core/builtins/js-regexp.h
new file mode 100644
index 000000000..ae39742d6
--- /dev/null
+++ b/src/core/builtins/js-regexp.h
@@ -0,0 +1,36 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_REGEXP_H
+#define QUICKJS_JS_REGEXP_H
+
+#include "quickjs/quickjs.h"
+
+JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
+                                 JSValueConst flags);
+JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor,
+                                              JSValue pattern, JSValue bc);
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-string.c b/src/core/builtins/js-string.c
new file mode 100644
index 000000000..e706a01be
--- /dev/null
+++ b/src/core/builtins/js-string.c
@@ -0,0 +1,1497 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-string.h"
+#include "../convertion.h"
+#include "../exception.h"
+#include "../function.h"
+#include "../object.h"
+#include "../string.h"
+#include "../types.h"
+#include "js-function.h"
+#include "js-object.h"
+#include "js-array.h"
+#include "quickjs/libregexp.h"
+
+/* String */
+
+int js_string_get_own_property(JSContext* ctx, JSPropertyDescriptor* desc, JSValueConst obj, JSAtom prop) {
+  JSObject* p;
+  JSString* p1;
+  uint32_t idx, ch;
+
+  /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
+  if (__JS_AtomIsTaggedInt(prop)) {
+    p = JS_VALUE_GET_OBJ(obj);
+    if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
+      p1 = JS_VALUE_GET_STRING(p->u.object_data);
+      idx = __JS_AtomToUInt32(prop);
+      if (idx < p1->len) {
+        if (desc) {
+          if (p1->is_wide_char)
+            ch = p1->u.str16[idx];
+          else
+            ch = p1->u.str8[idx];
+          desc->flags = JS_PROP_ENUMERABLE;
+          desc->value = js_new_string_char(ctx, ch);
+          desc->getter = JS_UNDEFINED;
+          desc->setter = JS_UNDEFINED;
+        }
+        return TRUE;
+      }
+    }
+  }
+  return FALSE;
+}
+
+int js_string_define_own_property(JSContext* ctx, JSValueConst this_obj, JSAtom prop, JSValueConst val, JSValueConst getter, JSValueConst setter, int flags) {
+  uint32_t idx;
+  JSObject* p;
+  JSString *p1, *p2;
+
+  if (__JS_AtomIsTaggedInt(prop)) {
+    idx = __JS_AtomToUInt32(prop);
+    p = JS_VALUE_GET_OBJ(this_obj);
+    if (JS_VALUE_GET_TAG(p->u.object_data) != JS_TAG_STRING)
+      goto def;
+    p1 = JS_VALUE_GET_STRING(p->u.object_data);
+    if (idx >= p1->len)
+      goto def;
+    if (!check_define_prop_flags(JS_PROP_ENUMERABLE, flags))
+      goto fail;
+    /* check that the same value is configured */
+    if (flags & JS_PROP_HAS_VALUE) {
+      if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
+        goto fail;
+      p2 = JS_VALUE_GET_STRING(val);
+      if (p2->len != 1)
+        goto fail;
+      if (string_get(p1, idx) != string_get(p2, 0)) {
+      fail:
+        return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
+      }
+    }
+    return TRUE;
+  } else {
+  def:
+    return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter, flags | JS_PROP_NO_EXOTIC);
+  }
+}
+
+int js_string_delete_property(JSContext* ctx, JSValueConst obj, JSAtom prop) {
+  uint32_t idx;
+
+  if (__JS_AtomIsTaggedInt(prop)) {
+    idx = __JS_AtomToUInt32(prop);
+    if (idx < js_string_obj_get_length(ctx, obj)) {
+      return FALSE;
+    }
+  }
+  return TRUE;
+}
+
+static const JSClassExoticMethods js_string_exotic_methods = {
+    .get_own_property = js_string_get_own_property,
+    .define_own_property = js_string_define_own_property,
+    .delete_property = js_string_delete_property,
+};
+
+JSValue js_string_constructor(JSContext* ctx, JSValueConst new_target, int argc, JSValueConst* argv) {
+  JSValue val, obj;
+  if (argc == 0) {
+    val = JS_AtomToString(ctx, JS_ATOM_empty_string);
+  } else {
+    if (JS_IsUndefined(new_target) && JS_IsSymbol(argv[0])) {
+      JSAtomStruct* p = JS_VALUE_GET_PTR(argv[0]);
+      val = JS_ConcatString3(ctx, "Symbol(", JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p)), ")");
+    } else {
+      val = JS_ToString(ctx, argv[0]);
+    }
+    if (JS_IsException(val))
+      return val;
+  }
+  if (!JS_IsUndefined(new_target)) {
+    JSString* p1 = JS_VALUE_GET_STRING(val);
+
+    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_STRING);
+    if (!JS_IsException(obj)) {
+      JS_SetObjectData(ctx, obj, val);
+      JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, JS_NewInt32(ctx, p1->len), 0);
+    }
+    return obj;
+  } else {
+    return val;
+  }
+}
+
+JSValue js_thisStringValue(JSContext* ctx, JSValueConst this_val) {
+  if (JS_VALUE_GET_TAG(this_val) == JS_TAG_STRING)
+    return JS_DupValue(ctx, this_val);
+
+  if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
+    JSObject* p = JS_VALUE_GET_OBJ(this_val);
+    if (p->class_id == JS_CLASS_STRING) {
+      if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING)
+        return JS_DupValue(ctx, p->u.object_data);
+    }
+  }
+  return JS_ThrowTypeError(ctx, "not a string");
+}
+
+JSValue js_string_fromCharCode(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  int i;
+  StringBuffer b_s, *b = &b_s;
+
+  string_buffer_init(ctx, b, argc);
+
+  for (i = 0; i < argc; i++) {
+    int32_t c;
+    if (JS_ToInt32(ctx, &c, argv[i]) || string_buffer_putc16(b, c & 0xffff)) {
+      string_buffer_free(b);
+      return JS_EXCEPTION;
+    }
+  }
+  return string_buffer_end(b);
+}
+
+JSValue js_string_fromCodePoint(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  double d;
+  int i, c;
+  StringBuffer b_s, *b = &b_s;
+
+  /* XXX: could pre-compute string length if all arguments are JS_TAG_INT */
+
+  if (string_buffer_init(ctx, b, argc))
+    goto fail;
+  for (i = 0; i < argc; i++) {
+    if (JS_VALUE_GET_TAG(argv[i]) == JS_TAG_INT) {
+      c = JS_VALUE_GET_INT(argv[i]);
+      if (c < 0 || c > 0x10ffff)
+        goto range_error;
+    } else {
+      if (JS_ToFloat64(ctx, &d, argv[i]))
+        goto fail;
+      if (d < 0 || d > 0x10ffff || (c = (int)d) != d)
+        goto range_error;
+    }
+    if (string_buffer_putc(b, c))
+      goto fail;
+  }
+  return string_buffer_end(b);
+
+range_error:
+  JS_ThrowRangeError(ctx, "invalid code point");
+fail:
+  string_buffer_free(b);
+  return JS_EXCEPTION;
+}
+
+JSValue js_string_raw(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  // raw(temp,...a)
+  JSValue cooked, val, raw;
+  StringBuffer b_s, *b = &b_s;
+  int64_t i, n;
+
+  string_buffer_init(ctx, b, 0);
+  raw = JS_UNDEFINED;
+  cooked = JS_ToObject(ctx, argv[0]);
+  if (JS_IsException(cooked))
+    goto exception;
+  raw = JS_ToObjectFree(ctx, JS_GetProperty(ctx, cooked, JS_ATOM_raw));
+  if (JS_IsException(raw))
+    goto exception;
+  if (js_get_length64(ctx, &n, raw) < 0)
+    goto exception;
+
+  for (i = 0; i < n; i++) {
+    val = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, raw, i));
+    if (JS_IsException(val))
+      goto exception;
+    string_buffer_concat_value_free(b, val);
+    if (i < n - 1 && i + 1 < argc) {
+      if (string_buffer_concat_value(b, argv[i + 1]))
+        goto exception;
+    }
+  }
+  JS_FreeValue(ctx, cooked);
+  JS_FreeValue(ctx, raw);
+  return string_buffer_end(b);
+
+exception:
+  JS_FreeValue(ctx, cooked);
+  JS_FreeValue(ctx, raw);
+  string_buffer_free(b);
+  return JS_EXCEPTION;
+}
+
+/* only used in test262 */
+JSValue js_string_codePointRange(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  uint32_t start, end, i, n;
+  StringBuffer b_s, *b = &b_s;
+
+  if (JS_ToUint32(ctx, &start, argv[0]) || JS_ToUint32(ctx, &end, argv[1]))
+    return JS_EXCEPTION;
+  end = min_uint32(end, 0x10ffff + 1);
+
+  if (start > end) {
+    start = end;
+  }
+  n = end - start;
+  if (end > 0x10000) {
+    n += end - max_uint32(start, 0x10000);
+  }
+  if (string_buffer_init2(ctx, b, n, end >= 0x100))
+    return JS_EXCEPTION;
+  for (i = start; i < end; i++) {
+    string_buffer_putc(b, i);
+  }
+  return string_buffer_end(b);
+}
+
+#if 0
+JSValue js_string___isSpace(JSContext *ctx, JSValueConst this_val,
+                                   int argc, JSValueConst *argv)
+{
+    int c;
+    if (JS_ToInt32(ctx, &c, argv[0]))
+        return JS_EXCEPTION;
+    return JS_NewBool(ctx, lre_is_space(c));
+}
+#endif
+
+JSValue js_string_charCodeAt(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue val, ret;
+  JSString* p;
+  int idx, c;
+
+  val = JS_ToStringCheckObject(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  p = JS_VALUE_GET_STRING(val);
+  if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
+    JS_FreeValue(ctx, val);
+    return JS_EXCEPTION;
+  }
+  if (idx < 0 || idx >= p->len) {
+    ret = JS_NAN;
+  } else {
+    if (p->is_wide_char)
+      c = p->u.str16[idx];
+    else
+      c = p->u.str8[idx];
+    ret = JS_NewInt32(ctx, c);
+  }
+  JS_FreeValue(ctx, val);
+  return ret;
+}
+
+JSValue js_string_charAt(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue val, ret;
+  JSString* p;
+  int idx, c;
+
+  val = JS_ToStringCheckObject(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  p = JS_VALUE_GET_STRING(val);
+  if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
+    JS_FreeValue(ctx, val);
+    return JS_EXCEPTION;
+  }
+  if (idx < 0 || idx >= p->len) {
+    ret = js_new_string8(ctx, NULL, 0);
+  } else {
+    if (p->is_wide_char)
+      c = p->u.str16[idx];
+    else
+      c = p->u.str8[idx];
+    ret = js_new_string_char(ctx, c);
+  }
+  JS_FreeValue(ctx, val);
+  return ret;
+}
+
+JSValue js_string_codePointAt(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue val, ret;
+  JSString* p;
+  int idx, c;
+
+  val = JS_ToStringCheckObject(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  p = JS_VALUE_GET_STRING(val);
+  if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
+    JS_FreeValue(ctx, val);
+    return JS_EXCEPTION;
+  }
+  if (idx < 0 || idx >= p->len) {
+    ret = JS_UNDEFINED;
+  } else {
+    c = string_getc(p, &idx);
+    ret = JS_NewInt32(ctx, c);
+  }
+  JS_FreeValue(ctx, val);
+  return ret;
+}
+
+JSValue js_string_concat(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue r;
+  int i;
+
+  /* XXX: Use more efficient method */
+  /* XXX: This method is OK if r has a single refcount */
+  /* XXX: should use string_buffer? */
+  r = JS_ToStringCheckObject(ctx, this_val);
+  for (i = 0; i < argc; i++) {
+    if (JS_IsException(r))
+      break;
+    r = JS_ConcatString(ctx, r, JS_DupValue(ctx, argv[i]));
+  }
+  return r;
+}
+
+int string_cmp(JSString* p1, JSString* p2, int x1, int x2, int len) {
+  int i, c1, c2;
+  for (i = 0; i < len; i++) {
+    if ((c1 = string_get(p1, x1 + i)) != (c2 = string_get(p2, x2 + i)))
+      return c1 - c2;
+  }
+  return 0;
+}
+
+int string_indexof_char(JSString* p, int c, int from) {
+  /* assuming 0 <= from <= p->len */
+  int i, len = p->len;
+  if (p->is_wide_char) {
+    for (i = from; i < len; i++) {
+      if (p->u.str16[i] == c)
+        return i;
+    }
+  } else {
+    if ((c & ~0xff) == 0) {
+      for (i = from; i < len; i++) {
+        if (p->u.str8[i] == (uint8_t)c)
+          return i;
+      }
+    }
+  }
+  return -1;
+}
+
+int string_indexof(JSString* p1, JSString* p2, int from) {
+  /* assuming 0 <= from <= p1->len */
+  int c, i, j, len1 = p1->len, len2 = p2->len;
+  if (len2 == 0)
+    return from;
+  for (i = from, c = string_get(p2, 0); i + len2 <= len1; i = j + 1) {
+    j = string_indexof_char(p1, c, i);
+    if (j < 0 || j + len2 > len1)
+      break;
+    if (!string_cmp(p1, p2, j + 1, 1, len2 - 1))
+      return j;
+  }
+  return -1;
+}
+
+int64_t string_advance_index(JSString* p, int64_t index, BOOL unicode) {
+  if (!unicode || index >= p->len || !p->is_wide_char) {
+    index++;
+  } else {
+    int index32 = (int)index;
+    string_getc(p, &index32);
+    index = index32;
+  }
+  return index;
+}
+
+JSValue js_string_indexOf(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int lastIndexOf) {
+  JSValue str, v;
+  int i, len, v_len, pos, start, stop, ret, inc;
+  JSString* p;
+  JSString* p1;
+
+  str = JS_ToStringCheckObject(ctx, this_val);
+  if (JS_IsException(str))
+    return str;
+  v = JS_ToString(ctx, argv[0]);
+  if (JS_IsException(v))
+    goto fail;
+  p = JS_VALUE_GET_STRING(str);
+  p1 = JS_VALUE_GET_STRING(v);
+  len = p->len;
+  v_len = p1->len;
+  if (lastIndexOf) {
+    pos = len - v_len;
+    if (argc > 1) {
+      double d;
+      if (JS_ToFloat64(ctx, &d, argv[1]))
+        goto fail;
+      if (!isnan(d)) {
+        if (d <= 0)
+          pos = 0;
+        else if (d < pos)
+          pos = d;
+      }
+    }
+    start = pos;
+    stop = 0;
+    inc = -1;
+  } else {
+    pos = 0;
+    if (argc > 1) {
+      if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0))
+        goto fail;
+    }
+    start = pos;
+    stop = len - v_len;
+    inc = 1;
+  }
+  ret = -1;
+  if (len >= v_len && inc * (stop - start) >= 0) {
+    for (i = start;; i += inc) {
+      if (!string_cmp(p, p1, i, 0, v_len)) {
+        ret = i;
+        break;
+      }
+      if (i == stop)
+        break;
+    }
+  }
+  JS_FreeValue(ctx, str);
+  JS_FreeValue(ctx, v);
+  return JS_NewInt32(ctx, ret);
+
+fail:
+  JS_FreeValue(ctx, str);
+  JS_FreeValue(ctx, v);
+  return JS_EXCEPTION;
+}
+
+/* return < 0 if exception or TRUE/FALSE */
+int js_is_regexp(JSContext* ctx, JSValueConst obj);
+
+JSValue js_string_includes(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic) {
+  JSValue str, v = JS_UNDEFINED;
+  int i, len, v_len, pos, start, stop, ret;
+  JSString* p;
+  JSString* p1;
+
+  str = JS_ToStringCheckObject(ctx, this_val);
+  if (JS_IsException(str))
+    return str;
+  ret = js_is_regexp(ctx, argv[0]);
+  if (ret) {
+    if (ret > 0)
+      JS_ThrowTypeError(ctx, "regex not supported");
+    goto fail;
+  }
+  v = JS_ToString(ctx, argv[0]);
+  if (JS_IsException(v))
+    goto fail;
+  p = JS_VALUE_GET_STRING(str);
+  p1 = JS_VALUE_GET_STRING(v);
+  len = p->len;
+  v_len = p1->len;
+  pos = (magic == 2) ? len : 0;
+  if (argc > 1 && !JS_IsUndefined(argv[1])) {
+    if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0))
+      goto fail;
+  }
+  len -= v_len;
+  ret = 0;
+  if (magic == 0) {
+    start = pos;
+    stop = len;
+  } else {
+    if (magic == 1) {
+      if (pos > len)
+        goto done;
+    } else {
+      pos -= v_len;
+    }
+    start = stop = pos;
+  }
+  if (start >= 0 && start <= stop) {
+    for (i = start;; i++) {
+      if (!string_cmp(p, p1, i, 0, v_len)) {
+        ret = 1;
+        break;
+      }
+      if (i == stop)
+        break;
+    }
+  }
+done:
+  JS_FreeValue(ctx, str);
+  JS_FreeValue(ctx, v);
+  return JS_NewBool(ctx, ret);
+
+fail:
+  JS_FreeValue(ctx, str);
+  JS_FreeValue(ctx, v);
+  return JS_EXCEPTION;
+}
+
+int check_regexp_g_flag(JSContext* ctx, JSValueConst regexp) {
+  int ret;
+  JSValue flags;
+
+  ret = js_is_regexp(ctx, regexp);
+  if (ret < 0)
+    return -1;
+  if (ret) {
+    flags = JS_GetProperty(ctx, regexp, JS_ATOM_flags);
+    if (JS_IsException(flags))
+      return -1;
+    if (JS_IsUndefined(flags) || JS_IsNull(flags)) {
+      JS_ThrowTypeError(ctx, "cannot convert to object");
+      return -1;
+    }
+    flags = JS_ToStringFree(ctx, flags);
+    if (JS_IsException(flags))
+      return -1;
+    ret = string_indexof_char(JS_VALUE_GET_STRING(flags), 'g', 0);
+    JS_FreeValue(ctx, flags);
+    if (ret < 0) {
+      JS_ThrowTypeError(ctx, "regexp must have the 'g' flag");
+      return -1;
+    }
+  }
+  return 0;
+}
+
+JSValue js_string_match(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int atom) {
+  // match(rx), search(rx), matchAll(rx)
+  // atom is JS_ATOM_Symbol_match, JS_ATOM_Symbol_search, or JS_ATOM_Symbol_matchAll
+  JSValueConst O = this_val, regexp = argv[0], args[2];
+  JSValue matcher, S, rx, result, str;
+  int args_len;
+
+  if (JS_IsUndefined(O) || JS_IsNull(O))
+    return JS_ThrowTypeError(ctx, "cannot convert to object");
+
+  if (!JS_IsUndefined(regexp) && !JS_IsNull(regexp)) {
+    matcher = JS_GetProperty(ctx, regexp, atom);
+    if (JS_IsException(matcher))
+      return JS_EXCEPTION;
+    if (atom == JS_ATOM_Symbol_matchAll) {
+      if (check_regexp_g_flag(ctx, regexp) < 0) {
+        JS_FreeValue(ctx, matcher);
+        return JS_EXCEPTION;
+      }
+    }
+    if (!JS_IsUndefined(matcher) && !JS_IsNull(matcher)) {
+      return JS_CallFree(ctx, matcher, regexp, 1, &O);
+    }
+  }
+  S = JS_ToString(ctx, O);
+  if (JS_IsException(S))
+    return JS_EXCEPTION;
+  args_len = 1;
+  args[0] = regexp;
+  str = JS_UNDEFINED;
+  if (atom == JS_ATOM_Symbol_matchAll) {
+    str = JS_NewString(ctx, "g");
+    if (JS_IsException(str))
+      goto fail;
+    args[args_len++] = (JSValueConst)str;
+  }
+  rx = JS_CallConstructor(ctx, ctx->regexp_ctor, args_len, args);
+  JS_FreeValue(ctx, str);
+  if (JS_IsException(rx)) {
+  fail:
+    JS_FreeValue(ctx, S);
+    return JS_EXCEPTION;
+  }
+  result = JS_InvokeFree(ctx, rx, atom, 1, (JSValueConst*)&S);
+  JS_FreeValue(ctx, S);
+  return result;
+}
+
+JSValue js_string___GetSubstitution(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  // GetSubstitution(matched, str, position, captures, namedCaptures, rep)
+  JSValueConst matched, str, captures, namedCaptures, rep;
+  JSValue capture, name, s;
+  uint32_t position, len, matched_len, captures_len;
+  int i, j, j0, k, k1;
+  int c, c1;
+  StringBuffer b_s, *b = &b_s;
+  JSString *sp, *rp;
+
+  matched = argv[0];
+  str = argv[1];
+  captures = argv[3];
+  namedCaptures = argv[4];
+  rep = argv[5];
+
+  if (!JS_IsString(rep) || !JS_IsString(str))
+    return JS_ThrowTypeError(ctx, "not a string");
+
+  sp = JS_VALUE_GET_STRING(str);
+  rp = JS_VALUE_GET_STRING(rep);
+
+  string_buffer_init(ctx, b, 0);
+
+  captures_len = 0;
+  if (!JS_IsUndefined(captures)) {
+    if (js_get_length32(ctx, &captures_len, captures))
+      goto exception;
+  }
+  if (js_get_length32(ctx, &matched_len, matched))
+    goto exception;
+  if (JS_ToUint32(ctx, &position, argv[2]) < 0)
+    goto exception;
+
+  len = rp->len;
+  i = 0;
+  for (;;) {
+    j = string_indexof_char(rp, '$', i);
+    if (j < 0 || j + 1 >= len)
+      break;
+    string_buffer_concat(b, rp, i, j);
+    j0 = j++;
+    c = string_get(rp, j++);
+    if (c == '$') {
+      string_buffer_putc8(b, '$');
+    } else if (c == '&') {
+      if (string_buffer_concat_value(b, matched))
+        goto exception;
+    } else if (c == '`') {
+      string_buffer_concat(b, sp, 0, position);
+    } else if (c == '\'') {
+      string_buffer_concat(b, sp, position + matched_len, sp->len);
+    } else if (c >= '0' && c <= '9') {
+      k = c - '0';
+      if (j < len) {
+        c1 = string_get(rp, j);
+        if (c1 >= '0' && c1 <= '9') {
+          /* This behavior is specified in ES6 and refined in ECMA 2019 */
+          /* ECMA 2019 does not have the extra test, but
+             Test262 S15.5.4.11_A3_T1..3 require this behavior */
+          k1 = k * 10 + c1 - '0';
+          if (k1 >= 1 && k1 < captures_len) {
+            k = k1;
+            j++;
+          }
+        }
+      }
+      if (k >= 1 && k < captures_len) {
+        s = JS_GetPropertyInt64(ctx, captures, k);
+        if (JS_IsException(s))
+          goto exception;
+        if (!JS_IsUndefined(s)) {
+          if (string_buffer_concat_value_free(b, s))
+            goto exception;
+        }
+      } else {
+        goto norep;
+      }
+    } else if (c == '<' && !JS_IsUndefined(namedCaptures)) {
+      k = string_indexof_char(rp, '>', j);
+      if (k < 0)
+        goto norep;
+      name = js_sub_string(ctx, rp, j, k);
+      if (JS_IsException(name))
+        goto exception;
+      capture = JS_GetPropertyValue(ctx, namedCaptures, name);
+      if (JS_IsException(capture))
+        goto exception;
+      if (!JS_IsUndefined(capture)) {
+        if (string_buffer_concat_value_free(b, capture))
+          goto exception;
+      }
+      j = k + 1;
+    } else {
+    norep:
+      string_buffer_concat(b, rp, j0, j);
+    }
+    i = j;
+  }
+  string_buffer_concat(b, rp, i, rp->len);
+  return string_buffer_end(b);
+exception:
+  string_buffer_free(b);
+  return JS_EXCEPTION;
+}
+
+JSValue js_string_replace(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int is_replaceAll) {
+  // replace(rx, rep)
+  JSValueConst O = this_val, searchValue = argv[0], replaceValue = argv[1];
+  JSValueConst args[6];
+  JSValue str, search_str, replaceValue_str, repl_str;
+  JSString *sp, *searchp;
+  StringBuffer b_s, *b = &b_s;
+  int pos, functionalReplace, endOfLastMatch;
+  BOOL is_first;
+
+  if (JS_IsUndefined(O) || JS_IsNull(O))
+    return JS_ThrowTypeError(ctx, "cannot convert to object");
+
+  search_str = JS_UNDEFINED;
+  replaceValue_str = JS_UNDEFINED;
+  repl_str = JS_UNDEFINED;
+
+  if (!JS_IsUndefined(searchValue) && !JS_IsNull(searchValue)) {
+    JSValue replacer;
+    if (is_replaceAll) {
+      if (check_regexp_g_flag(ctx, searchValue) < 0)
+        return JS_EXCEPTION;
+    }
+    replacer = JS_GetProperty(ctx, searchValue, JS_ATOM_Symbol_replace);
+    if (JS_IsException(replacer))
+      return JS_EXCEPTION;
+    if (!JS_IsUndefined(replacer) && !JS_IsNull(replacer)) {
+      args[0] = O;
+      args[1] = replaceValue;
+      return JS_CallFree(ctx, replacer, searchValue, 2, args);
+    }
+  }
+  string_buffer_init(ctx, b, 0);
+
+  str = JS_ToString(ctx, O);
+  if (JS_IsException(str))
+    goto exception;
+  search_str = JS_ToString(ctx, searchValue);
+  if (JS_IsException(search_str))
+    goto exception;
+  functionalReplace = JS_IsFunction(ctx, replaceValue);
+  if (!functionalReplace) {
+    replaceValue_str = JS_ToString(ctx, replaceValue);
+    if (JS_IsException(replaceValue_str))
+      goto exception;
+  }
+
+  sp = JS_VALUE_GET_STRING(str);
+  searchp = JS_VALUE_GET_STRING(search_str);
+  endOfLastMatch = 0;
+  is_first = TRUE;
+  for (;;) {
+    if (unlikely(searchp->len == 0)) {
+      if (is_first)
+        pos = 0;
+      else if (endOfLastMatch >= sp->len)
+        pos = -1;
+      else
+        pos = endOfLastMatch + 1;
+    } else {
+      pos = string_indexof(sp, searchp, endOfLastMatch);
+    }
+    if (pos < 0) {
+      if (is_first) {
+        string_buffer_free(b);
+        JS_FreeValue(ctx, search_str);
+        JS_FreeValue(ctx, replaceValue_str);
+        return str;
+      } else {
+        break;
+      }
+    }
+    if (functionalReplace) {
+      args[0] = search_str;
+      args[1] = JS_NewInt32(ctx, pos);
+      args[2] = str;
+      repl_str = JS_ToStringFree(ctx, JS_Call(ctx, replaceValue, JS_UNDEFINED, 3, args));
+    } else {
+      args[0] = search_str;
+      args[1] = str;
+      args[2] = JS_NewInt32(ctx, pos);
+      args[3] = JS_UNDEFINED;
+      args[4] = JS_UNDEFINED;
+      args[5] = replaceValue_str;
+      repl_str = js_string___GetSubstitution(ctx, JS_UNDEFINED, 6, args);
+    }
+    if (JS_IsException(repl_str))
+      goto exception;
+
+    string_buffer_concat(b, sp, endOfLastMatch, pos);
+    string_buffer_concat_value_free(b, repl_str);
+    endOfLastMatch = pos + searchp->len;
+    is_first = FALSE;
+    if (!is_replaceAll)
+      break;
+  }
+  string_buffer_concat(b, sp, endOfLastMatch, sp->len);
+  JS_FreeValue(ctx, search_str);
+  JS_FreeValue(ctx, replaceValue_str);
+  JS_FreeValue(ctx, str);
+  return string_buffer_end(b);
+
+exception:
+  string_buffer_free(b);
+  JS_FreeValue(ctx, search_str);
+  JS_FreeValue(ctx, replaceValue_str);
+  JS_FreeValue(ctx, str);
+  return JS_EXCEPTION;
+}
+
+JSValue js_string_split(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  // split(sep, limit)
+  JSValueConst O = this_val, separator = argv[0], limit = argv[1];
+  JSValueConst args[2];
+  JSValue S, A, R, T;
+  uint32_t lim, lengthA;
+  int64_t p, q, s, r, e;
+  JSString *sp, *rp;
+
+  if (JS_IsUndefined(O) || JS_IsNull(O))
+    return JS_ThrowTypeError(ctx, "cannot convert to object");
+
+  S = JS_UNDEFINED;
+  A = JS_UNDEFINED;
+  R = JS_UNDEFINED;
+
+  if (!JS_IsUndefined(separator) && !JS_IsNull(separator)) {
+    JSValue splitter;
+    splitter = JS_GetProperty(ctx, separator, JS_ATOM_Symbol_split);
+    if (JS_IsException(splitter))
+      return JS_EXCEPTION;
+    if (!JS_IsUndefined(splitter) && !JS_IsNull(splitter)) {
+      args[0] = O;
+      args[1] = limit;
+      return JS_CallFree(ctx, splitter, separator, 2, args);
+    }
+  }
+  S = JS_ToString(ctx, O);
+  if (JS_IsException(S))
+    goto exception;
+  A = JS_NewArray(ctx);
+  if (JS_IsException(A))
+    goto exception;
+  lengthA = 0;
+  if (JS_IsUndefined(limit)) {
+    lim = 0xffffffff;
+  } else {
+    if (JS_ToUint32(ctx, &lim, limit) < 0)
+      goto exception;
+  }
+  sp = JS_VALUE_GET_STRING(S);
+  s = sp->len;
+  R = JS_ToString(ctx, separator);
+  if (JS_IsException(R))
+    goto exception;
+  rp = JS_VALUE_GET_STRING(R);
+  r = rp->len;
+  p = 0;
+  if (lim == 0)
+    goto done;
+  if (JS_IsUndefined(separator))
+    goto add_tail;
+  if (s == 0) {
+    if (r != 0)
+      goto add_tail;
+    goto done;
+  }
+  q = p;
+  for (q = p; (q += !r) <= s - r - !r; q = p = e + r) {
+    e = string_indexof(sp, rp, q);
+    if (e < 0)
+      break;
+    T = js_sub_string(ctx, sp, p, e);
+    if (JS_IsException(T))
+      goto exception;
+    if (JS_CreateDataPropertyUint32(ctx, A, lengthA++, T, 0) < 0)
+      goto exception;
+    if (lengthA == lim)
+      goto done;
+  }
+add_tail:
+  T = js_sub_string(ctx, sp, p, s);
+  if (JS_IsException(T))
+    goto exception;
+  if (JS_CreateDataPropertyUint32(ctx, A, lengthA++, T, 0) < 0)
+    goto exception;
+done:
+  JS_FreeValue(ctx, S);
+  JS_FreeValue(ctx, R);
+  return A;
+
+exception:
+  JS_FreeValue(ctx, A);
+  JS_FreeValue(ctx, S);
+  JS_FreeValue(ctx, R);
+  return JS_EXCEPTION;
+}
+
+JSValue js_string_substring(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue str, ret;
+  int a, b, start, end;
+  JSString* p;
+
+  str = JS_ToStringCheckObject(ctx, this_val);
+  if (JS_IsException(str))
+    return str;
+  p = JS_VALUE_GET_STRING(str);
+  if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, p->len, 0)) {
+    JS_FreeValue(ctx, str);
+    return JS_EXCEPTION;
+  }
+  b = p->len;
+  if (!JS_IsUndefined(argv[1])) {
+    if (JS_ToInt32Clamp(ctx, &b, argv[1], 0, p->len, 0)) {
+      JS_FreeValue(ctx, str);
+      return JS_EXCEPTION;
+    }
+  }
+  if (a < b) {
+    start = a;
+    end = b;
+  } else {
+    start = b;
+    end = a;
+  }
+  ret = js_sub_string(ctx, p, start, end);
+  JS_FreeValue(ctx, str);
+  return ret;
+}
+
+JSValue js_string_substr(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue str, ret;
+  int a, len, n;
+  JSString* p;
+
+  str = JS_ToStringCheckObject(ctx, this_val);
+  if (JS_IsException(str))
+    return str;
+  p = JS_VALUE_GET_STRING(str);
+  len = p->len;
+  if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, len, len)) {
+    JS_FreeValue(ctx, str);
+    return JS_EXCEPTION;
+  }
+  n = len - a;
+  if (!JS_IsUndefined(argv[1])) {
+    if (JS_ToInt32Clamp(ctx, &n, argv[1], 0, len - a, 0)) {
+      JS_FreeValue(ctx, str);
+      return JS_EXCEPTION;
+    }
+  }
+  ret = js_sub_string(ctx, p, a, a + n);
+  JS_FreeValue(ctx, str);
+  return ret;
+}
+
+JSValue js_string_slice(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue str, ret;
+  int len, start, end;
+  JSString* p;
+
+  str = JS_ToStringCheckObject(ctx, this_val);
+  if (JS_IsException(str))
+    return str;
+  p = JS_VALUE_GET_STRING(str);
+  len = p->len;
+  if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len)) {
+    JS_FreeValue(ctx, str);
+    return JS_EXCEPTION;
+  }
+  end = len;
+  if (!JS_IsUndefined(argv[1])) {
+    if (JS_ToInt32Clamp(ctx, &end, argv[1], 0, len, len)) {
+      JS_FreeValue(ctx, str);
+      return JS_EXCEPTION;
+    }
+  }
+  ret = js_sub_string(ctx, p, start, max_int(end, start));
+  JS_FreeValue(ctx, str);
+  return ret;
+}
+
+JSValue js_string_pad(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int padEnd) {
+  JSValue str, v = JS_UNDEFINED;
+  StringBuffer b_s, *b = &b_s;
+  JSString *p, *p1 = NULL;
+  int n, len, c = ' ';
+
+  str = JS_ToStringCheckObject(ctx, this_val);
+  if (JS_IsException(str))
+    goto fail1;
+  if (JS_ToInt32Sat(ctx, &n, argv[0]))
+    goto fail2;
+  p = JS_VALUE_GET_STRING(str);
+  len = p->len;
+  if (len >= n)
+    return str;
+  if (argc > 1 && !JS_IsUndefined(argv[1])) {
+    v = JS_ToString(ctx, argv[1]);
+    if (JS_IsException(v))
+      goto fail2;
+    p1 = JS_VALUE_GET_STRING(v);
+    if (p1->len == 0) {
+      JS_FreeValue(ctx, v);
+      return str;
+    }
+    if (p1->len == 1) {
+      c = string_get(p1, 0);
+      p1 = NULL;
+    }
+  }
+  if (n > JS_STRING_LEN_MAX) {
+    JS_ThrowInternalError(ctx, "string too long");
+    goto fail2;
+  }
+  if (string_buffer_init(ctx, b, n))
+    goto fail3;
+  n -= len;
+  if (padEnd) {
+    if (string_buffer_concat(b, p, 0, len))
+      goto fail;
+  }
+  if (p1) {
+    while (n > 0) {
+      int chunk = min_int(n, p1->len);
+      if (string_buffer_concat(b, p1, 0, chunk))
+        goto fail;
+      n -= chunk;
+    }
+  } else {
+    if (string_buffer_fill(b, c, n))
+      goto fail;
+  }
+  if (!padEnd) {
+    if (string_buffer_concat(b, p, 0, len))
+      goto fail;
+  }
+  JS_FreeValue(ctx, v);
+  JS_FreeValue(ctx, str);
+  return string_buffer_end(b);
+
+fail:
+  string_buffer_free(b);
+fail3:
+  JS_FreeValue(ctx, v);
+fail2:
+  JS_FreeValue(ctx, str);
+fail1:
+  return JS_EXCEPTION;
+}
+
+JSValue js_string_repeat(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue str;
+  StringBuffer b_s, *b = &b_s;
+  JSString* p;
+  int64_t val;
+  int n, len;
+
+  str = JS_ToStringCheckObject(ctx, this_val);
+  if (JS_IsException(str))
+    goto fail;
+  if (JS_ToInt64Sat(ctx, &val, argv[0]))
+    goto fail;
+  if (val < 0 || val > 2147483647) {
+    JS_ThrowRangeError(ctx, "invalid repeat count");
+    goto fail;
+  }
+  n = val;
+  p = JS_VALUE_GET_STRING(str);
+  len = p->len;
+  if (len == 0 || n == 1)
+    return str;
+  if (val * len > JS_STRING_LEN_MAX) {
+    JS_ThrowInternalError(ctx, "string too long");
+    goto fail;
+  }
+  if (string_buffer_init2(ctx, b, n * len, p->is_wide_char))
+    goto fail;
+  if (len == 1) {
+    string_buffer_fill(b, string_get(p, 0), n);
+  } else {
+    while (n-- > 0) {
+      string_buffer_concat(b, p, 0, len);
+    }
+  }
+  JS_FreeValue(ctx, str);
+  return string_buffer_end(b);
+
+fail:
+  JS_FreeValue(ctx, str);
+  return JS_EXCEPTION;
+}
+
+JSValue js_string_trim(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic) {
+  JSValue str, ret;
+  int a, b, len;
+  JSString* p;
+
+  str = JS_ToStringCheckObject(ctx, this_val);
+  if (JS_IsException(str))
+    return str;
+  p = JS_VALUE_GET_STRING(str);
+  a = 0;
+  b = len = p->len;
+  if (magic & 1) {
+    while (a < len && lre_is_space(string_get(p, a)))
+      a++;
+  }
+  if (magic & 2) {
+    while (b > a && lre_is_space(string_get(p, b - 1)))
+      b--;
+  }
+  ret = js_sub_string(ctx, p, a, b);
+  JS_FreeValue(ctx, str);
+  return ret;
+}
+
+JSValue js_string___quote(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  return JS_ToQuotedString(ctx, this_val);
+}
+
+/* return 0 if before the first char */
+int string_prevc(JSString* p, int* pidx) {
+  int idx, c, c1;
+
+  idx = *pidx;
+  if (idx <= 0)
+    return 0;
+  idx--;
+  if (p->is_wide_char) {
+    c = p->u.str16[idx];
+    if (c >= 0xdc00 && c < 0xe000 && idx > 0) {
+      c1 = p->u.str16[idx - 1];
+      if (c1 >= 0xd800 && c1 <= 0xdc00) {
+        c = (((c1 & 0x3ff) << 10) | (c & 0x3ff)) + 0x10000;
+        idx--;
+      }
+    }
+  } else {
+    c = p->u.str8[idx];
+  }
+  *pidx = idx;
+  return c;
+}
+
+BOOL test_final_sigma(JSString* p, int sigma_pos) {
+  int k, c1;
+
+  /* before C: skip case ignorable chars and check there is
+     a cased letter */
+  k = sigma_pos;
+  for (;;) {
+    c1 = string_prevc(p, &k);
+    if (!lre_is_case_ignorable(c1))
+      break;
+  }
+  if (!lre_is_cased(c1))
+    return FALSE;
+
+  /* after C: skip case ignorable chars and check there is
+     no cased letter */
+  k = sigma_pos + 1;
+  for (;;) {
+    if (k >= p->len)
+      return TRUE;
+    c1 = string_getc(p, &k);
+    if (!lre_is_case_ignorable(c1))
+      break;
+  }
+  return !lre_is_cased(c1);
+}
+
+JSValue js_string_localeCompare(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue a, b;
+  int cmp;
+
+  a = JS_ToStringCheckObject(ctx, this_val);
+  if (JS_IsException(a))
+    return JS_EXCEPTION;
+  b = JS_ToString(ctx, argv[0]);
+  if (JS_IsException(b)) {
+    JS_FreeValue(ctx, a);
+    return JS_EXCEPTION;
+  }
+  cmp = js_string_compare(ctx, JS_VALUE_GET_STRING(a), JS_VALUE_GET_STRING(b));
+  JS_FreeValue(ctx, a);
+  JS_FreeValue(ctx, b);
+  return JS_NewInt32(ctx, cmp);
+}
+
+JSValue js_string_toLowerCase(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int to_lower) {
+  JSValue val;
+  StringBuffer b_s, *b = &b_s;
+  JSString* p;
+  int i, c, j, l;
+  uint32_t res[LRE_CC_RES_LEN_MAX];
+
+  val = JS_ToStringCheckObject(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  p = JS_VALUE_GET_STRING(val);
+  if (p->len == 0)
+    return val;
+  if (string_buffer_init(ctx, b, p->len))
+    goto fail;
+  for (i = 0; i < p->len;) {
+    c = string_getc(p, &i);
+    if (c == 0x3a3 && to_lower && test_final_sigma(p, i - 1)) {
+      res[0] = 0x3c2; /* final sigma */
+      l = 1;
+    } else {
+      l = lre_case_conv(res, c, to_lower);
+    }
+    for (j = 0; j < l; j++) {
+      if (string_buffer_putc(b, res[j]))
+        goto fail;
+    }
+  }
+  JS_FreeValue(ctx, val);
+  return string_buffer_end(b);
+fail:
+  JS_FreeValue(ctx, val);
+  string_buffer_free(b);
+  return JS_EXCEPTION;
+}
+
+#ifdef CONFIG_ALL_UNICODE
+
+/* return (-1, NULL) if exception, otherwise (len, buf) */
+int JS_ToUTF32String(JSContext* ctx, uint32_t** pbuf, JSValueConst val1) {
+  JSValue val;
+  JSString* p;
+  uint32_t* buf;
+  int i, j, len;
+
+  val = JS_ToString(ctx, val1);
+  if (JS_IsException(val))
+    return -1;
+  p = JS_VALUE_GET_STRING(val);
+  len = p->len;
+  /* UTF32 buffer length is len minus the number of correct surrogates pairs */
+  buf = js_malloc(ctx, sizeof(buf[0]) * max_int(len, 1));
+  if (!buf) {
+    JS_FreeValue(ctx, val);
+    goto fail;
+  }
+  for (i = j = 0; i < len;)
+    buf[j++] = string_getc(p, &i);
+  JS_FreeValue(ctx, val);
+  *pbuf = buf;
+  return j;
+fail:
+  *pbuf = NULL;
+  return -1;
+}
+
+JSValue JS_NewUTF32String(JSContext* ctx, const uint32_t* buf, int len) {
+  int i;
+  StringBuffer b_s, *b = &b_s;
+  if (string_buffer_init(ctx, b, len))
+    return JS_EXCEPTION;
+  for (i = 0; i < len; i++) {
+    if (string_buffer_putc(b, buf[i]))
+      goto fail;
+  }
+  return string_buffer_end(b);
+fail:
+  string_buffer_free(b);
+  return JS_EXCEPTION;
+}
+
+JSValue js_string_normalize(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  const char *form, *p;
+  size_t form_len;
+  int is_compat, buf_len, out_len;
+  UnicodeNormalizationEnum n_type;
+  JSValue val;
+  uint32_t *buf, *out_buf;
+
+  val = JS_ToStringCheckObject(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  buf_len = JS_ToUTF32String(ctx, &buf, val);
+  JS_FreeValue(ctx, val);
+  if (buf_len < 0)
+    return JS_EXCEPTION;
+
+  if (argc == 0 || JS_IsUndefined(argv[0])) {
+    n_type = UNICODE_NFC;
+  } else {
+    form = JS_ToCStringLen(ctx, &form_len, argv[0]);
+    if (!form)
+      goto fail1;
+    p = form;
+    if (p[0] != 'N' || p[1] != 'F')
+      goto bad_form;
+    p += 2;
+    is_compat = FALSE;
+    if (*p == 'K') {
+      is_compat = TRUE;
+      p++;
+    }
+    if (*p == 'C' || *p == 'D') {
+      n_type = UNICODE_NFC + is_compat * 2 + (*p - 'C');
+      if ((p + 1 - form) != form_len)
+        goto bad_form;
+    } else {
+    bad_form:
+      JS_FreeCString(ctx, form);
+      JS_ThrowRangeError(ctx, "bad normalization form");
+    fail1:
+      js_free(ctx, buf);
+      return JS_EXCEPTION;
+    }
+    JS_FreeCString(ctx, form);
+  }
+
+  out_len = unicode_normalize(&out_buf, buf, buf_len, n_type, ctx->rt, (DynBufReallocFunc*)js_realloc_rt);
+  js_free(ctx, buf);
+  if (out_len < 0)
+    return JS_EXCEPTION;
+  val = JS_NewUTF32String(ctx, out_buf, out_len);
+  js_free(ctx, out_buf);
+  return val;
+}
+#endif /* CONFIG_ALL_UNICODE */
+
+/* also used for String.prototype.valueOf */
+JSValue js_string_toString(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  return js_thisStringValue(ctx, this_val);
+}
+
+#if 0
+JSValue js_string___toStringCheckObject(JSContext *ctx, JSValueConst this_val,
+                                               int argc, JSValueConst *argv)
+{
+    return JS_ToStringCheckObject(ctx, argv[0]);
+}
+
+JSValue js_string___toString(JSContext *ctx, JSValueConst this_val,
+                                    int argc, JSValueConst *argv)
+{
+    return JS_ToString(ctx, argv[0]);
+}
+
+JSValue js_string___advanceStringIndex(JSContext *ctx, JSValueConst
+                                              this_val,
+                                              int argc, JSValueConst *argv)
+{
+    JSValue str;
+    int idx;
+    BOOL is_unicode;
+    JSString *p;
+
+    str = JS_ToString(ctx, argv[0]);
+    if (JS_IsException(str))
+        return str;
+    if (JS_ToInt32Sat(ctx, &idx, argv[1])) {
+        JS_FreeValue(ctx, str);
+        return JS_EXCEPTION;
+    }
+    is_unicode = JS_ToBool(ctx, argv[2]);
+    p = JS_VALUE_GET_STRING(str);
+    if (!is_unicode || (unsigned)idx >= p->len || !p->is_wide_char) {
+        idx++;
+    } else {
+        string_getc(p, &idx);
+    }
+    JS_FreeValue(ctx, str);
+    return JS_NewInt32(ctx, idx);
+}
+#endif
+
+/* String Iterator */
+
+JSValue js_string_iterator_next(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, BOOL* pdone, int magic) {
+  JSArrayIteratorData* it;
+  uint32_t idx, c, start;
+  JSString* p;
+
+  it = JS_GetOpaque2(ctx, this_val, JS_CLASS_STRING_ITERATOR);
+  if (!it) {
+    *pdone = FALSE;
+    return JS_EXCEPTION;
+  }
+  if (JS_IsUndefined(it->obj))
+    goto done;
+  p = JS_VALUE_GET_STRING(it->obj);
+  idx = it->idx;
+  if (idx >= p->len) {
+    JS_FreeValue(ctx, it->obj);
+    it->obj = JS_UNDEFINED;
+  done:
+    *pdone = TRUE;
+    return JS_UNDEFINED;
+  }
+
+  start = idx;
+  c = string_getc(p, (int*)&idx);
+  it->idx = idx;
+  *pdone = FALSE;
+  if (c <= 0xffff) {
+    return js_new_string_char(ctx, c);
+  } else {
+    return js_new_string16(ctx, p->u.str16 + start, 2);
+  }
+}
+
+JSValue js_string_CreateHTML(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic) {
+  JSValue str;
+  const JSString* p;
+  StringBuffer b_s, *b = &b_s;
+  struct {
+    const char *tag, *attr;
+  } const defs[] = {
+      {"a", "name"}, {"big", NULL}, {"blink", NULL}, {"b", NULL},      {"tt", NULL},  {"font", "color"}, {"font", "size"},
+      {"i", NULL},   {"a", "href"}, {"small", NULL}, {"strike", NULL}, {"sub", NULL}, {"sup", NULL},
+  };
+
+  str = JS_ToStringCheckObject(ctx, this_val);
+  if (JS_IsException(str))
+    return JS_EXCEPTION;
+  string_buffer_init(ctx, b, 7);
+  string_buffer_putc8(b, '<');
+  string_buffer_puts8(b, defs[magic].tag);
+  if (defs[magic].attr) {
+    // r += " " + attr + "=\"" + value + "\"";
+    JSValue value;
+    int i;
+
+    string_buffer_putc8(b, ' ');
+    string_buffer_puts8(b, defs[magic].attr);
+    string_buffer_puts8(b, "=\"");
+    value = JS_ToStringCheckObject(ctx, argv[0]);
+    if (JS_IsException(value)) {
+      JS_FreeValue(ctx, str);
+      string_buffer_free(b);
+      return JS_EXCEPTION;
+    }
+    p = JS_VALUE_GET_STRING(value);
+    for (i = 0; i < p->len; i++) {
+      int c = string_get(p, i);
+      if (c == '"') {
+        string_buffer_puts8(b, "&quot;");
+      } else {
+        string_buffer_putc16(b, c);
+      }
+    }
+    JS_FreeValue(ctx, value);
+    string_buffer_putc8(b, '\"');
+  }
+  // return r + ">" + str + "</" + tag + ">";
+  string_buffer_putc8(b, '>');
+  string_buffer_concat_value_free(b, str);
+  string_buffer_puts8(b, "</");
+  string_buffer_puts8(b, defs[magic].tag);
+  string_buffer_putc8(b, '>');
+  return string_buffer_end(b);
+}
diff --git a/src/core/builtins/js-string.h b/src/core/builtins/js-string.h
new file mode 100644
index 000000000..2f6142e39
--- /dev/null
+++ b/src/core/builtins/js-string.h
@@ -0,0 +1,91 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_STRING_H
+#define QUICKJS_JS_STRING_H
+
+#include "quickjs/quickjs.h"
+#include "quickjs/cutils.h"
+#include "../types.h"
+
+/* ES6 Annex B 2.3.2 etc. */
+enum {
+  magic_string_anchor,
+  magic_string_big,
+  magic_string_blink,
+  magic_string_bold,
+  magic_string_fixed,
+  magic_string_fontcolor,
+  magic_string_fontsize,
+  magic_string_italics,
+  magic_string_link,
+  magic_string_small,
+  magic_string_strike,
+  magic_string_sub,
+  magic_string_sup,
+};
+
+int js_string_get_own_property(JSContext* ctx, JSPropertyDescriptor* desc, JSValueConst obj, JSAtom prop);
+int js_string_define_own_property(JSContext* ctx, JSValueConst this_obj, JSAtom prop, JSValueConst val, JSValueConst getter, JSValueConst setter, int flags);
+int js_string_delete_property(JSContext* ctx, JSValueConst obj, JSAtom prop);
+JSValue js_string_constructor(JSContext* ctx, JSValueConst new_target, int argc, JSValueConst* argv);
+JSValue js_thisStringValue(JSContext* ctx, JSValueConst this_val) ;
+JSValue js_string_fromCharCode(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_string_fromCodePoint(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_string_raw(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+/* only used in test262 */
+JSValue js_string_codePointRange(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_string_charCodeAt(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_string_charAt(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_string_codePointAt(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_string_concat(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+int string_cmp(JSString* p1, JSString* p2, int x1, int x2, int len);
+int string_indexof_char(JSString* p, int c, int from);
+int string_indexof(JSString* p1, JSString* p2, int from);
+int64_t string_advance_index(JSString* p, int64_t index, BOOL unicode);
+JSValue js_string_indexOf(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int lastIndexOf) ;
+int js_is_regexp(JSContext* ctx, JSValueConst obj);;
+JSValue js_string_includes(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic);
+int check_regexp_g_flag(JSContext* ctx, JSValueConst regexp);
+JSValue js_string_match(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int atom);
+JSValue js_string___GetSubstitution(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_string_replace(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int is_replaceAll);
+JSValue js_string_split(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_string_substring(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_string_substr(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_string_slice(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_string_pad(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int padEnd);
+JSValue js_string_repeat(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_string_trim(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic);
+JSValue js_string___quote(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+int string_prevc(JSString* p, int* pidx);
+BOOL test_final_sigma(JSString* p, int sigma_pos);
+JSValue js_string_localeCompare(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_string_toLowerCase(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int to_lower);
+JSValue js_string_toString(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_string_iterator_next(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, BOOL* pdone, int magic);
+JSValue js_string_CreateHTML(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic);
+
+#endif
\ No newline at end of file
diff --git a/src/core/builtins/js-symbol.c b/src/core/builtins/js-symbol.c
new file mode 100644
index 000000000..547e83006
--- /dev/null
+++ b/src/core/builtins/js-symbol.c
@@ -0,0 +1,127 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-symbol.h"
+#include "../exception.h"
+#include "../string.h"
+#include "../types.h"
+#include "js-string.h"
+
+/* Symbol */
+
+JSValue js_symbol_constructor(JSContext *ctx, JSValueConst new_target,
+                                     int argc, JSValueConst *argv)
+{
+  JSValue str;
+  JSString *p;
+
+  if (!JS_IsUndefined(new_target))
+    return JS_ThrowTypeError(ctx, "not a constructor");
+  if (argc == 0 || JS_IsUndefined(argv[0])) {
+    p = NULL;
+  } else {
+    str = JS_ToString(ctx, argv[0]);
+    if (JS_IsException(str))
+      return JS_EXCEPTION;
+    p = JS_VALUE_GET_STRING(str);
+  }
+  return JS_NewSymbol(ctx, p, JS_ATOM_TYPE_SYMBOL);
+}
+
+JSValue js_thisSymbolValue(JSContext *ctx, JSValueConst this_val)
+{
+  if (JS_VALUE_GET_TAG(this_val) == JS_TAG_SYMBOL)
+    return JS_DupValue(ctx, this_val);
+
+  if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
+    JSObject *p = JS_VALUE_GET_OBJ(this_val);
+    if (p->class_id == JS_CLASS_SYMBOL) {
+      if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_SYMBOL)
+        return JS_DupValue(ctx, p->u.object_data);
+    }
+  }
+  return JS_ThrowTypeError(ctx, "not a symbol");
+}
+
+JSValue js_symbol_toString(JSContext *ctx, JSValueConst this_val,
+                                  int argc, JSValueConst *argv)
+{
+  JSValue val, ret;
+  val = js_thisSymbolValue(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  /* XXX: use JS_ToStringInternal() with a flags */
+  ret = js_string_constructor(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val);
+  JS_FreeValue(ctx, val);
+  return ret;
+}
+
+JSValue js_symbol_valueOf(JSContext *ctx, JSValueConst this_val,
+                                 int argc, JSValueConst *argv)
+{
+  return js_thisSymbolValue(ctx, this_val);
+}
+
+JSValue js_symbol_get_description(JSContext *ctx, JSValueConst this_val)
+{
+  JSValue val, ret;
+  JSAtomStruct *p;
+
+  val = js_thisSymbolValue(ctx, this_val);
+  if (JS_IsException(val))
+    return val;
+  p = JS_VALUE_GET_PTR(val);
+  if (p->len == 0 && p->is_wide_char != 0) {
+    ret = JS_UNDEFINED;
+  } else {
+    ret = JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p));
+  }
+  JS_FreeValue(ctx, val);
+  return ret;
+}
+
+JSValue js_symbol_for(JSContext *ctx, JSValueConst this_val,
+                             int argc, JSValueConst *argv)
+{
+  JSValue str;
+
+  str = JS_ToString(ctx, argv[0]);
+  if (JS_IsException(str))
+    return JS_EXCEPTION;
+  return JS_NewSymbol(ctx, JS_VALUE_GET_STRING(str), JS_ATOM_TYPE_GLOBAL_SYMBOL);
+}
+
+JSValue js_symbol_keyFor(JSContext *ctx, JSValueConst this_val,
+                                int argc, JSValueConst *argv)
+{
+  JSAtomStruct *p;
+
+  if (!JS_IsSymbol(argv[0]))
+    return JS_ThrowTypeError(ctx, "not a symbol");
+  p = JS_VALUE_GET_PTR(argv[0]);
+  if (p->atom_type != JS_ATOM_TYPE_GLOBAL_SYMBOL)
+    return JS_UNDEFINED;
+  return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
+}
\ No newline at end of file
diff --git a/src/core/builtins/js-symbol.h b/src/core/builtins/js-symbol.h
new file mode 100644
index 000000000..f3db3081f
--- /dev/null
+++ b/src/core/builtins/js-symbol.h
@@ -0,0 +1,44 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_SYMBOL_H
+#define QUICKJS_JS_SYMBOL_H
+
+#include "quickjs/quickjs.h"
+
+JSValue js_symbol_constructor(JSContext *ctx, JSValueConst new_target,
+                                     int argc, JSValueConst *argv);
+JSValue js_thisSymbolValue(JSContext *ctx, JSValueConst this_val);
+JSValue js_symbol_toString(JSContext *ctx, JSValueConst this_val,
+                                  int argc, JSValueConst *argv);
+JSValue js_symbol_valueOf(JSContext *ctx, JSValueConst this_val,
+                                 int argc, JSValueConst *argv);
+JSValue js_symbol_get_description(JSContext *ctx, JSValueConst this_val);
+JSValue js_symbol_for(JSContext *ctx, JSValueConst this_val,
+                             int argc, JSValueConst *argv);
+JSValue js_symbol_keyFor(JSContext *ctx, JSValueConst this_val,
+                                int argc, JSValueConst *argv);
+
+#endif
diff --git a/src/core/builtins/js-typed-array.c b/src/core/builtins/js-typed-array.c
new file mode 100644
index 000000000..8a4c0c603
--- /dev/null
+++ b/src/core/builtins/js-typed-array.c
@@ -0,0 +1,2269 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "js-typed-array.h"
+#include "../convertion.h"
+#include "../exception.h"
+#include "../function.h"
+#include "../object.h"
+#include "../runtime.h"
+#include "../string.h"
+#include "js-array.h"
+#include "js-atomics.h"
+#include "js-function.h"
+#include "js-object.h"
+#include "js-operator.h"
+
+/* Typed Arrays */
+
+static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT] = {0, 0, 0, 1, 1, 2, 2,
+#ifdef CONFIG_BIGNUM
+                                                                    3, 3, /* BigInt64Array, BigUint64Array */
+#endif
+                                                                    2, 3};
+
+JSValue
+js_array_buffer_constructor3(JSContext* ctx, JSValueConst new_target, uint64_t len, JSClassID class_id, uint8_t* buf, JSFreeArrayBufferDataFunc* free_func, void* opaque, BOOL alloc_flag) {
+  JSRuntime* rt = ctx->rt;
+  JSValue obj;
+  JSArrayBuffer* abuf = NULL;
+
+  obj = js_create_from_ctor(ctx, new_target, class_id);
+  if (JS_IsException(obj))
+    return obj;
+  /* XXX: we are currently limited to 2 GB */
+  if (len > INT32_MAX) {
+    JS_ThrowRangeError(ctx, "invalid array buffer length");
+    goto fail;
+  }
+  abuf = js_malloc(ctx, sizeof(*abuf));
+  if (!abuf)
+    goto fail;
+  abuf->byte_length = len;
+  if (alloc_flag) {
+    if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER && rt->sab_funcs.sab_alloc) {
+      abuf->data = rt->sab_funcs.sab_alloc(rt->sab_funcs.sab_opaque, max_int(len, 1));
+      if (!abuf->data)
+        goto fail;
+      memset(abuf->data, 0, len);
+    } else {
+      /* the allocation must be done after the object creation */
+      abuf->data = js_mallocz(ctx, max_int(len, 1));
+      if (!abuf->data)
+        goto fail;
+    }
+  } else {
+    if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER && rt->sab_funcs.sab_dup) {
+      rt->sab_funcs.sab_dup(rt->sab_funcs.sab_opaque, buf);
+    }
+    abuf->data = buf;
+  }
+  init_list_head(&abuf->array_list);
+  abuf->detached = FALSE;
+  abuf->shared = (class_id == JS_CLASS_SHARED_ARRAY_BUFFER);
+  abuf->opaque = opaque;
+  abuf->free_func = free_func;
+  if (alloc_flag && buf)
+    memcpy(abuf->data, buf, len);
+  JS_SetOpaque(obj, abuf);
+  return obj;
+fail:
+  JS_FreeValue(ctx, obj);
+  js_free(ctx, abuf);
+  return JS_EXCEPTION;
+}
+
+void js_array_buffer_free(JSRuntime* rt, void* opaque, void* ptr) {
+  js_free_rt(rt, ptr);
+}
+
+JSValue js_array_buffer_constructor2(JSContext* ctx, JSValueConst new_target, uint64_t len, JSClassID class_id) {
+  return js_array_buffer_constructor3(ctx, new_target, len, class_id, NULL, js_array_buffer_free, NULL, TRUE);
+}
+
+JSValue js_array_buffer_constructor1(JSContext* ctx, JSValueConst new_target, uint64_t len) {
+  return js_array_buffer_constructor2(ctx, new_target, len, JS_CLASS_ARRAY_BUFFER);
+}
+
+JSValue JS_NewArrayBuffer(JSContext* ctx, uint8_t* buf, size_t len, JSFreeArrayBufferDataFunc* free_func, void* opaque, BOOL is_shared) {
+  return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len, is_shared ? JS_CLASS_SHARED_ARRAY_BUFFER : JS_CLASS_ARRAY_BUFFER, buf, free_func, opaque, FALSE);
+}
+
+/* create a new ArrayBuffer of length 'len' and copy 'buf' to it */
+JSValue JS_NewArrayBufferCopy(JSContext* ctx, const uint8_t* buf, size_t len) {
+  return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len, JS_CLASS_ARRAY_BUFFER, (uint8_t*)buf, js_array_buffer_free, NULL, TRUE);
+}
+
+JSValue js_array_buffer_constructor(JSContext* ctx, JSValueConst new_target, int argc, JSValueConst* argv) {
+  uint64_t len;
+  if (JS_ToIndex(ctx, &len, argv[0]))
+    return JS_EXCEPTION;
+  return js_array_buffer_constructor1(ctx, new_target, len);
+}
+
+JSValue js_shared_array_buffer_constructor(JSContext* ctx, JSValueConst new_target, int argc, JSValueConst* argv) {
+  uint64_t len;
+  if (JS_ToIndex(ctx, &len, argv[0]))
+    return JS_EXCEPTION;
+  return js_array_buffer_constructor2(ctx, new_target, len, JS_CLASS_SHARED_ARRAY_BUFFER);
+}
+
+/* also used for SharedArrayBuffer */
+void js_array_buffer_finalizer(JSRuntime* rt, JSValue val) {
+  JSObject* p = JS_VALUE_GET_OBJ(val);
+  JSArrayBuffer* abuf = p->u.array_buffer;
+  if (abuf) {
+    /* The ArrayBuffer finalizer may be called before the typed
+       array finalizers using it, so abuf->array_list is not
+       necessarily empty. */
+    // assert(list_empty(&abuf->array_list));
+    if (abuf->shared && rt->sab_funcs.sab_free) {
+      rt->sab_funcs.sab_free(rt->sab_funcs.sab_opaque, abuf->data);
+    } else {
+      if (abuf->free_func)
+        abuf->free_func(rt, abuf->opaque, abuf->data);
+    }
+    js_free_rt(rt, abuf);
+  }
+}
+
+JSValue js_array_buffer_isView(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSObject* p;
+  BOOL res;
+  res = FALSE;
+  if (JS_VALUE_GET_TAG(argv[0]) == JS_TAG_OBJECT) {
+    p = JS_VALUE_GET_OBJ(argv[0]);
+    if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_DATAVIEW) {
+      res = TRUE;
+    }
+  }
+  return JS_NewBool(ctx, res);
+}
+
+const JSCFunctionListEntry js_array_buffer_funcs[] = {
+    JS_CFUNC_DEF("isView", 1, js_array_buffer_isView),
+    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL),
+};
+
+JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext* ctx) {
+  return JS_ThrowTypeError(ctx, "ArrayBuffer is detached");
+}
+
+JSValue js_array_buffer_get_byteLength(JSContext* ctx, JSValueConst this_val, int class_id) {
+  JSArrayBuffer* abuf = JS_GetOpaque2(ctx, this_val, class_id);
+  if (!abuf)
+    return JS_EXCEPTION;
+  /* return 0 if detached */
+  return JS_NewUint32(ctx, abuf->byte_length);
+}
+
+void JS_DetachArrayBuffer(JSContext* ctx, JSValueConst obj) {
+  JSArrayBuffer* abuf = JS_GetOpaque(obj, JS_CLASS_ARRAY_BUFFER);
+  struct list_head* el;
+
+  if (!abuf || abuf->detached)
+    return;
+  if (abuf->free_func)
+    abuf->free_func(ctx->rt, abuf->opaque, abuf->data);
+  abuf->data = NULL;
+  abuf->byte_length = 0;
+  abuf->detached = TRUE;
+
+  list_for_each(el, &abuf->array_list) {
+    JSTypedArray* ta;
+    JSObject* p;
+
+    ta = list_entry(el, JSTypedArray, link);
+    p = ta->obj;
+    /* Note: the typed array length and offset fields are not modified */
+    if (p->class_id != JS_CLASS_DATAVIEW) {
+      p->u.array.count = 0;
+      p->u.array.u.ptr = NULL;
+    }
+  }
+}
+
+/* get an ArrayBuffer or SharedArrayBuffer */
+JSArrayBuffer* js_get_array_buffer(JSContext* ctx, JSValueConst obj) {
+  JSObject* p;
+  if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
+    goto fail;
+  p = JS_VALUE_GET_OBJ(obj);
+  if (p->class_id != JS_CLASS_ARRAY_BUFFER && p->class_id != JS_CLASS_SHARED_ARRAY_BUFFER) {
+  fail:
+    JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_ARRAY_BUFFER);
+    return NULL;
+  }
+  return p->u.array_buffer;
+}
+
+/* return NULL if exception. WARNING: any JS call can detach the
+   buffer and render the returned pointer invalid */
+uint8_t* JS_GetArrayBuffer(JSContext* ctx, size_t* psize, JSValueConst obj) {
+  JSArrayBuffer* abuf = js_get_array_buffer(ctx, obj);
+  if (!abuf)
+    goto fail;
+  if (abuf->detached) {
+    JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+    goto fail;
+  }
+  *psize = abuf->byte_length;
+  return abuf->data;
+fail:
+  *psize = 0;
+  return NULL;
+}
+
+JSValue js_array_buffer_slice(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int class_id) {
+  JSArrayBuffer *abuf, *new_abuf;
+  int64_t len, start, end, new_len;
+  JSValue ctor, new_obj;
+
+  abuf = JS_GetOpaque2(ctx, this_val, class_id);
+  if (!abuf)
+    return JS_EXCEPTION;
+  if (abuf->detached)
+    return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+  len = abuf->byte_length;
+
+  if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
+    return JS_EXCEPTION;
+
+  end = len;
+  if (!JS_IsUndefined(argv[1])) {
+    if (JS_ToInt64Clamp(ctx, &end, argv[1], 0, len, len))
+      return JS_EXCEPTION;
+  }
+  new_len = max_int64(end - start, 0);
+  ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
+  if (JS_IsException(ctor))
+    return ctor;
+  if (JS_IsUndefined(ctor)) {
+    new_obj = js_array_buffer_constructor2(ctx, JS_UNDEFINED, new_len, class_id);
+  } else {
+    JSValue args[1];
+    args[0] = JS_NewInt64(ctx, new_len);
+    new_obj = JS_CallConstructor(ctx, ctor, 1, (JSValueConst*)args);
+    JS_FreeValue(ctx, ctor);
+    JS_FreeValue(ctx, args[0]);
+  }
+  if (JS_IsException(new_obj))
+    return new_obj;
+  new_abuf = JS_GetOpaque2(ctx, new_obj, class_id);
+  if (!new_abuf)
+    goto fail;
+  if (js_same_value(ctx, new_obj, this_val)) {
+    JS_ThrowTypeError(ctx, "cannot use identical ArrayBuffer");
+    goto fail;
+  }
+  if (new_abuf->detached) {
+    JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+    goto fail;
+  }
+  if (new_abuf->byte_length < new_len) {
+    JS_ThrowTypeError(ctx, "new ArrayBuffer is too small");
+    goto fail;
+  }
+  /* must test again because of side effects */
+  if (abuf->detached) {
+    JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+    goto fail;
+  }
+  memcpy(new_abuf->data, abuf->data + start, new_len);
+  return new_obj;
+fail:
+  JS_FreeValue(ctx, new_obj);
+  return JS_EXCEPTION;
+}
+
+const JSCFunctionListEntry js_array_buffer_proto_funcs[] = {
+    JS_CGETSET_MAGIC_DEF("byteLength", js_array_buffer_get_byteLength, NULL, JS_CLASS_ARRAY_BUFFER),
+    JS_CFUNC_MAGIC_DEF("slice", 2, js_array_buffer_slice, JS_CLASS_ARRAY_BUFFER),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "ArrayBuffer", JS_PROP_CONFIGURABLE),
+};
+
+/* SharedArrayBuffer */
+
+const JSCFunctionListEntry js_shared_array_buffer_funcs[] = {
+    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL),
+};
+
+const JSCFunctionListEntry js_shared_array_buffer_proto_funcs[] = {
+    JS_CGETSET_MAGIC_DEF("byteLength", js_array_buffer_get_byteLength, NULL, JS_CLASS_SHARED_ARRAY_BUFFER),
+    JS_CFUNC_MAGIC_DEF("slice", 2, js_array_buffer_slice, JS_CLASS_SHARED_ARRAY_BUFFER),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "SharedArrayBuffer", JS_PROP_CONFIGURABLE),
+};
+
+JSObject* get_typed_array(JSContext* ctx, JSValueConst this_val, int is_dataview) {
+  JSObject* p;
+  if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
+    goto fail;
+  p = JS_VALUE_GET_OBJ(this_val);
+  if (is_dataview) {
+    if (p->class_id != JS_CLASS_DATAVIEW)
+      goto fail;
+  } else {
+    if (!(p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY)) {
+    fail:
+      JS_ThrowTypeError(ctx, "not a %s", is_dataview ? "DataView" : "TypedArray");
+      return NULL;
+    }
+  }
+  return p;
+}
+
+/* WARNING: 'p' must be a typed array */
+BOOL typed_array_is_detached(JSContext* ctx, JSObject* p) {
+  JSTypedArray* ta = p->u.typed_array;
+  JSArrayBuffer* abuf = ta->buffer->u.array_buffer;
+  /* XXX: could simplify test by ensuring that
+     p->u.array.u.ptr is NULL iff it is detached */
+  return abuf->detached;
+}
+
+
+int validate_typed_array(JSContext* ctx, JSValueConst this_val) {
+  JSObject* p;
+  p = get_typed_array(ctx, this_val, 0);
+  if (!p)
+    return -1;
+  if (typed_array_is_detached(ctx, p)) {
+    JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+    return -1;
+  }
+  return 0;
+}
+
+JSValue js_typed_array_get_length(JSContext* ctx, JSValueConst this_val) {
+  JSObject* p;
+  p = get_typed_array(ctx, this_val, 0);
+  if (!p)
+    return JS_EXCEPTION;
+  return JS_NewInt32(ctx, p->u.array.count);
+}
+
+JSValue js_typed_array_get_buffer(JSContext* ctx, JSValueConst this_val, int is_dataview) {
+  JSObject* p;
+  JSTypedArray* ta;
+  p = get_typed_array(ctx, this_val, is_dataview);
+  if (!p)
+    return JS_EXCEPTION;
+  ta = p->u.typed_array;
+  return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
+}
+
+JSValue js_typed_array_get_byteLength(JSContext* ctx, JSValueConst this_val, int is_dataview) {
+  JSObject* p;
+  JSTypedArray* ta;
+  p = get_typed_array(ctx, this_val, is_dataview);
+  if (!p)
+    return JS_EXCEPTION;
+  if (typed_array_is_detached(ctx, p)) {
+    if (is_dataview) {
+      return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+    } else {
+      return JS_NewInt32(ctx, 0);
+    }
+  }
+  ta = p->u.typed_array;
+  return JS_NewInt32(ctx, ta->length);
+}
+
+JSValue js_typed_array_get_byteOffset(JSContext* ctx, JSValueConst this_val, int is_dataview) {
+  JSObject* p;
+  JSTypedArray* ta;
+  p = get_typed_array(ctx, this_val, is_dataview);
+  if (!p)
+    return JS_EXCEPTION;
+  if (typed_array_is_detached(ctx, p)) {
+    if (is_dataview) {
+      return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+    } else {
+      return JS_NewInt32(ctx, 0);
+    }
+  }
+  ta = p->u.typed_array;
+  return JS_NewInt32(ctx, ta->offset);
+}
+
+/* Return the buffer associated to the typed array or an exception if
+   it is not a typed array or if the buffer is detached. pbyte_offset,
+   pbyte_length or pbytes_per_element can be NULL. */
+JSValue JS_GetTypedArrayBuffer(JSContext* ctx, JSValueConst obj, size_t* pbyte_offset, size_t* pbyte_length, size_t* pbytes_per_element) {
+  JSObject* p;
+  JSTypedArray* ta;
+  p = get_typed_array(ctx, obj, FALSE);
+  if (!p)
+    return JS_EXCEPTION;
+  if (typed_array_is_detached(ctx, p))
+    return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+  ta = p->u.typed_array;
+  if (pbyte_offset)
+    *pbyte_offset = ta->offset;
+  if (pbyte_length)
+    *pbyte_length = ta->length;
+  if (pbytes_per_element) {
+    *pbytes_per_element = 1 << typed_array_size_log2(p->class_id);
+  }
+  return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
+}
+
+JSValue js_typed_array_get_toStringTag(JSContext* ctx, JSValueConst this_val) {
+  JSObject* p;
+  if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
+    return JS_UNDEFINED;
+  p = JS_VALUE_GET_OBJ(this_val);
+  if (!(p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY))
+    return JS_UNDEFINED;
+  return JS_AtomToString(ctx, ctx->rt->class_array[p->class_id].class_name);
+}
+
+JSValue js_typed_array_set_internal(JSContext* ctx, JSValueConst dst, JSValueConst src, JSValueConst off) {
+  JSObject* p;
+  JSObject* src_p;
+  uint32_t i;
+  int64_t src_len, offset;
+  JSValue val, src_obj = JS_UNDEFINED;
+
+  p = get_typed_array(ctx, dst, 0);
+  if (!p)
+    goto fail;
+  if (JS_ToInt64Sat(ctx, &offset, off))
+    goto fail;
+  if (offset < 0)
+    goto range_error;
+  if (typed_array_is_detached(ctx, p)) {
+  detached:
+    JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+    goto fail;
+  }
+  src_obj = JS_ToObject(ctx, src);
+  if (JS_IsException(src_obj))
+    goto fail;
+  src_p = JS_VALUE_GET_OBJ(src_obj);
+  if (src_p->class_id >= JS_CLASS_UINT8C_ARRAY && src_p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
+    JSTypedArray* dest_ta = p->u.typed_array;
+    JSArrayBuffer* dest_abuf = dest_ta->buffer->u.array_buffer;
+    JSTypedArray* src_ta = src_p->u.typed_array;
+    JSArrayBuffer* src_abuf = src_ta->buffer->u.array_buffer;
+    int shift = typed_array_size_log2(p->class_id);
+
+    if (src_abuf->detached)
+      goto detached;
+
+    src_len = src_p->u.array.count;
+    if (offset > (int64_t)(p->u.array.count - src_len))
+      goto range_error;
+
+    /* copying between typed objects */
+    if (src_p->class_id == p->class_id) {
+      /* same type, use memmove */
+      memmove(dest_abuf->data + dest_ta->offset + (offset << shift), src_abuf->data + src_ta->offset, src_len << shift);
+      goto done;
+    }
+    if (dest_abuf->data == src_abuf->data) {
+      /* copying between the same buffer using different types of mappings
+         would require a temporary buffer */
+    }
+    /* otherwise, default behavior is slow but correct */
+  } else {
+    if (js_get_length64(ctx, &src_len, src_obj))
+      goto fail;
+    if (offset > (int64_t)(p->u.array.count - src_len)) {
+    range_error:
+      JS_ThrowRangeError(ctx, "invalid array length");
+      goto fail;
+    }
+  }
+  for (i = 0; i < src_len; i++) {
+    val = JS_GetPropertyUint32(ctx, src_obj, i);
+    if (JS_IsException(val))
+      goto fail;
+    if (JS_SetPropertyUint32(ctx, dst, offset + i, val) < 0)
+      goto fail;
+  }
+done:
+  JS_FreeValue(ctx, src_obj);
+  return JS_UNDEFINED;
+fail:
+  JS_FreeValue(ctx, src_obj);
+  return JS_EXCEPTION;
+}
+
+JSValue js_typed_array_set(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValueConst offset = JS_UNDEFINED;
+  if (argc > 1) {
+    offset = argv[1];
+  }
+  return js_typed_array_set_internal(ctx, this_val, argv[0], offset);
+}
+
+JSValue js_create_typed_array_iterator(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int magic) {
+  if (validate_typed_array(ctx, this_val))
+    return JS_EXCEPTION;
+  return js_create_array_iterator(ctx, this_val, argc, argv, magic);
+}
+
+/* return < 0 if exception */
+int js_typed_array_get_length_internal(JSContext* ctx, JSValueConst obj) {
+  JSObject* p;
+  p = get_typed_array(ctx, obj, 0);
+  if (!p)
+    return -1;
+  if (typed_array_is_detached(ctx, p)) {
+    JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+    return -1;
+  }
+  return p->u.array.count;
+}
+
+#if 0
+/* validate a typed array and return its length */
+JSValue js_typed_array___getLength(JSContext *ctx,
+                                          JSValueConst this_val,
+                                          int argc, JSValueConst *argv)
+{
+    BOOL ignore_detached = JS_ToBool(ctx, argv[1]);
+
+    if (ignore_detached) {
+        return js_typed_array_get_length(ctx, argv[0]);
+    } else {
+        int len;
+        len = js_typed_array_get_length_internal(ctx, argv[0]);
+        if (len < 0)
+            return JS_EXCEPTION;
+        return JS_NewInt32(ctx, len);
+    }
+}
+#endif
+
+JSValue js_typed_array_create(JSContext* ctx, JSValueConst ctor, int argc, JSValueConst* argv) {
+  JSValue ret;
+  int new_len;
+  int64_t len;
+
+  ret = JS_CallConstructor(ctx, ctor, argc, argv);
+  if (JS_IsException(ret))
+    return ret;
+  /* validate the typed array */
+  new_len = js_typed_array_get_length_internal(ctx, ret);
+  if (new_len < 0)
+    goto fail;
+  if (argc == 1) {
+    /* ensure that it is large enough */
+    if (JS_ToLengthFree(ctx, &len, JS_DupValue(ctx, argv[0])))
+      goto fail;
+    if (new_len < len) {
+      JS_ThrowTypeError(ctx, "TypedArray length is too small");
+    fail:
+      JS_FreeValue(ctx, ret);
+      return JS_EXCEPTION;
+    }
+  }
+  return ret;
+}
+
+#if 0
+JSValue js_typed_array___create(JSContext *ctx,
+                                       JSValueConst this_val,
+                                       int argc, JSValueConst *argv)
+{
+    return js_typed_array_create(ctx, argv[0], max_int(argc - 1, 0), argv + 1);
+}
+#endif
+
+JSValue js_typed_array___speciesCreate(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValueConst obj;
+  JSObject* p;
+  JSValue ctor, ret;
+  int argc1;
+
+  obj = argv[0];
+  p = get_typed_array(ctx, obj, 0);
+  if (!p)
+    return JS_EXCEPTION;
+  ctor = JS_SpeciesConstructor(ctx, obj, JS_UNDEFINED);
+  if (JS_IsException(ctor))
+    return ctor;
+  argc1 = max_int(argc - 1, 0);
+  if (JS_IsUndefined(ctor)) {
+    ret = js_typed_array_constructor(ctx, JS_UNDEFINED, argc1, argv + 1, p->class_id);
+  } else {
+    ret = js_typed_array_create(ctx, ctor, argc1, argv + 1);
+    JS_FreeValue(ctx, ctor);
+  }
+  return ret;
+}
+
+JSValue js_typed_array_from(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  // from(items, mapfn = void 0, this_arg = void 0)
+  JSValueConst items = argv[0], mapfn, this_arg;
+  JSValueConst args[2];
+  JSValue stack[2];
+  JSValue iter, arr, r, v, v2;
+  int64_t k, len;
+  int done, mapping;
+
+  mapping = FALSE;
+  mapfn = JS_UNDEFINED;
+  this_arg = JS_UNDEFINED;
+  r = JS_UNDEFINED;
+  arr = JS_UNDEFINED;
+  stack[0] = JS_UNDEFINED;
+  stack[1] = JS_UNDEFINED;
+
+  if (argc > 1) {
+    mapfn = argv[1];
+    if (!JS_IsUndefined(mapfn)) {
+      if (check_function(ctx, mapfn))
+        goto exception;
+      mapping = 1;
+      if (argc > 2)
+        this_arg = argv[2];
+    }
+  }
+  iter = JS_GetProperty(ctx, items, JS_ATOM_Symbol_iterator);
+  if (JS_IsException(iter))
+    goto exception;
+  if (!JS_IsUndefined(iter)) {
+    JS_FreeValue(ctx, iter);
+    arr = JS_NewArray(ctx);
+    if (JS_IsException(arr))
+      goto exception;
+    stack[0] = JS_DupValue(ctx, items);
+    if (js_for_of_start(ctx, &stack[1], FALSE))
+      goto exception;
+    for (k = 0;; k++) {
+      v = JS_IteratorNext(ctx, stack[0], stack[1], 0, NULL, &done);
+      if (JS_IsException(v))
+        goto exception_close;
+      if (done)
+        break;
+      if (JS_DefinePropertyValueInt64(ctx, arr, k, v, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+        goto exception_close;
+    }
+  } else {
+    arr = JS_ToObject(ctx, items);
+    if (JS_IsException(arr))
+      goto exception;
+  }
+  if (js_get_length64(ctx, &len, arr) < 0)
+    goto exception;
+  v = JS_NewInt64(ctx, len);
+  args[0] = v;
+  r = js_typed_array_create(ctx, this_val, 1, args);
+  JS_FreeValue(ctx, v);
+  if (JS_IsException(r))
+    goto exception;
+  for (k = 0; k < len; k++) {
+    v = JS_GetPropertyInt64(ctx, arr, k);
+    if (JS_IsException(v))
+      goto exception;
+    if (mapping) {
+      args[0] = v;
+      args[1] = JS_NewInt32(ctx, k);
+      v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
+      JS_FreeValue(ctx, v);
+      v = v2;
+      if (JS_IsException(v))
+        goto exception;
+    }
+    if (JS_SetPropertyInt64(ctx, r, k, v) < 0)
+      goto exception;
+  }
+  goto done;
+
+exception_close:
+  if (!JS_IsUndefined(stack[0]))
+    JS_IteratorClose(ctx, stack[0], TRUE);
+exception:
+  JS_FreeValue(ctx, r);
+  r = JS_EXCEPTION;
+done:
+  JS_FreeValue(ctx, arr);
+  JS_FreeValue(ctx, stack[0]);
+  JS_FreeValue(ctx, stack[1]);
+  return r;
+}
+
+JSValue js_typed_array_of(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue obj;
+  JSValueConst args[1];
+  int i;
+
+  args[0] = JS_NewInt32(ctx, argc);
+  obj = js_typed_array_create(ctx, this_val, 1, args);
+  if (JS_IsException(obj))
+    return obj;
+
+  for (i = 0; i < argc; i++) {
+    if (JS_SetPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i])) < 0) {
+      JS_FreeValue(ctx, obj);
+      return JS_EXCEPTION;
+    }
+  }
+  return obj;
+}
+
+JSValue js_typed_array_copyWithin(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSObject* p;
+  int len, to, from, final, count, shift;
+
+  len = js_typed_array_get_length_internal(ctx, this_val);
+  if (len < 0)
+    return JS_EXCEPTION;
+
+  if (JS_ToInt32Clamp(ctx, &to, argv[0], 0, len, len))
+    return JS_EXCEPTION;
+
+  if (JS_ToInt32Clamp(ctx, &from, argv[1], 0, len, len))
+    return JS_EXCEPTION;
+
+  final = len;
+  if (argc > 2 && !JS_IsUndefined(argv[2])) {
+    if (JS_ToInt32Clamp(ctx, &final, argv[2], 0, len, len))
+      return JS_EXCEPTION;
+  }
+
+  count = min_int(final - from, len - to);
+  if (count > 0) {
+    p = JS_VALUE_GET_OBJ(this_val);
+    if (typed_array_is_detached(ctx, p))
+      return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+    shift = typed_array_size_log2(p->class_id);
+    memmove(p->u.array.u.uint8_ptr + (to << shift), p->u.array.u.uint8_ptr + (from << shift), count << shift);
+  }
+  return JS_DupValue(ctx, this_val);
+}
+
+JSValue js_typed_array_fill(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSObject* p;
+  int len, k, final, shift;
+  uint64_t v64;
+
+  len = js_typed_array_get_length_internal(ctx, this_val);
+  if (len < 0)
+    return JS_EXCEPTION;
+  p = JS_VALUE_GET_OBJ(this_val);
+
+  if (p->class_id == JS_CLASS_UINT8C_ARRAY) {
+    int32_t v;
+    if (JS_ToUint8ClampFree(ctx, &v, JS_DupValue(ctx, argv[0])))
+      return JS_EXCEPTION;
+    v64 = v;
+  } else if (p->class_id <= JS_CLASS_UINT32_ARRAY) {
+    uint32_t v;
+    if (JS_ToUint32(ctx, &v, argv[0]))
+      return JS_EXCEPTION;
+    v64 = v;
+  } else
+#ifdef CONFIG_BIGNUM
+      if (p->class_id <= JS_CLASS_BIG_UINT64_ARRAY) {
+    if (JS_ToBigInt64(ctx, (int64_t*)&v64, argv[0]))
+      return JS_EXCEPTION;
+  } else
+#endif
+  {
+    double d;
+    if (JS_ToFloat64(ctx, &d, argv[0]))
+      return JS_EXCEPTION;
+    if (p->class_id == JS_CLASS_FLOAT32_ARRAY) {
+      union {
+        float f;
+        uint32_t u32;
+      } u;
+      u.f = d;
+      v64 = u.u32;
+    } else {
+      JSFloat64Union u;
+      u.d = d;
+      v64 = u.u64;
+    }
+  }
+
+  k = 0;
+  if (argc > 1) {
+    if (JS_ToInt32Clamp(ctx, &k, argv[1], 0, len, len))
+      return JS_EXCEPTION;
+  }
+
+  final = len;
+  if (argc > 2 && !JS_IsUndefined(argv[2])) {
+    if (JS_ToInt32Clamp(ctx, &final, argv[2], 0, len, len))
+      return JS_EXCEPTION;
+  }
+
+  if (typed_array_is_detached(ctx, p))
+    return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+
+  shift = typed_array_size_log2(p->class_id);
+  switch (shift) {
+    case 0:
+      if (k < final) {
+        memset(p->u.array.u.uint8_ptr + k, v64, final - k);
+      }
+      break;
+    case 1:
+      for (; k < final; k++) {
+        p->u.array.u.uint16_ptr[k] = v64;
+      }
+      break;
+    case 2:
+      for (; k < final; k++) {
+        p->u.array.u.uint32_ptr[k] = v64;
+      }
+      break;
+    case 3:
+      for (; k < final; k++) {
+        p->u.array.u.uint64_ptr[k] = v64;
+      }
+      break;
+    default:
+      abort();
+  }
+  return JS_DupValue(ctx, this_val);
+}
+
+JSValue js_typed_array_find(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int findIndex) {
+  JSValueConst func, this_arg;
+  JSValueConst args[3];
+  JSValue val, index_val, res;
+  int len, k;
+
+  val = JS_UNDEFINED;
+  len = js_typed_array_get_length_internal(ctx, this_val);
+  if (len < 0)
+    goto exception;
+
+  func = argv[0];
+  if (check_function(ctx, func))
+    goto exception;
+
+  this_arg = JS_UNDEFINED;
+  if (argc > 1)
+    this_arg = argv[1];
+
+  for (k = 0; k < len; k++) {
+    index_val = JS_NewInt32(ctx, k);
+    val = JS_GetPropertyValue(ctx, this_val, index_val);
+    if (JS_IsException(val))
+      goto exception;
+    args[0] = val;
+    args[1] = index_val;
+    args[2] = this_val;
+    res = JS_Call(ctx, func, this_arg, 3, args);
+    if (JS_IsException(res))
+      goto exception;
+    if (JS_ToBoolFree(ctx, res)) {
+      if (findIndex) {
+        JS_FreeValue(ctx, val);
+        return index_val;
+      } else {
+        return val;
+      }
+    }
+    JS_FreeValue(ctx, val);
+  }
+  if (findIndex)
+    return JS_NewInt32(ctx, -1);
+  else
+    return JS_UNDEFINED;
+
+exception:
+  JS_FreeValue(ctx, val);
+  return JS_EXCEPTION;
+}
+
+#define special_indexOf 0
+#define special_lastIndexOf 1
+#define special_includes -1
+
+JSValue js_typed_array_indexOf(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int special) {
+  JSObject* p;
+  int len, tag, is_int, is_bigint, k, stop, inc, res = -1;
+  int64_t v64;
+  double d;
+  float f;
+
+  len = js_typed_array_get_length_internal(ctx, this_val);
+  if (len < 0)
+    goto exception;
+  if (len == 0)
+    goto done;
+
+  if (special == special_lastIndexOf) {
+    k = len - 1;
+    if (argc > 1) {
+      if (JS_ToFloat64(ctx, &d, argv[1]))
+        goto exception;
+      if (isnan(d)) {
+        k = 0;
+      } else {
+        if (d >= 0) {
+          if (d < k) {
+            k = d;
+          }
+        } else {
+          d += len;
+          if (d < 0)
+            goto done;
+          k = d;
+        }
+      }
+    }
+    stop = -1;
+    inc = -1;
+  } else {
+    k = 0;
+    if (argc > 1) {
+      if (JS_ToInt32Clamp(ctx, &k, argv[1], 0, len, len))
+        goto exception;
+    }
+    stop = len;
+    inc = 1;
+  }
+
+  p = JS_VALUE_GET_OBJ(this_val);
+  /* if the array was detached, no need to go further (but no
+     exception is raised) */
+  if (typed_array_is_detached(ctx, p)) {
+    /* "includes" scans all the properties, so "undefined" can match */
+    if (special == special_includes && JS_IsUndefined(argv[0]) && len > 0)
+      res = 0;
+    goto done;
+  }
+
+  is_bigint = 0;
+  is_int = 0; /* avoid warning */
+  v64 = 0;    /* avoid warning */
+  tag = JS_VALUE_GET_NORM_TAG(argv[0]);
+  if (tag == JS_TAG_INT) {
+    is_int = 1;
+    v64 = JS_VALUE_GET_INT(argv[0]);
+    d = v64;
+  } else if (tag == JS_TAG_FLOAT64) {
+    d = JS_VALUE_GET_FLOAT64(argv[0]);
+    v64 = d;
+    is_int = (v64 == d);
+  } else
+#ifdef CONFIG_BIGNUM
+      if (tag == JS_TAG_BIG_INT) {
+    JSBigFloat* p1 = JS_VALUE_GET_PTR(argv[0]);
+
+    if (p->class_id == JS_CLASS_BIG_INT64_ARRAY) {
+      if (bf_get_int64(&v64, &p1->num, 0) != 0)
+        goto done;
+    } else if (p->class_id == JS_CLASS_BIG_UINT64_ARRAY) {
+      if (bf_get_uint64((uint64_t*)&v64, &p1->num) != 0)
+        goto done;
+    } else {
+      goto done;
+    }
+    d = 0;
+    is_bigint = 1;
+  } else
+#endif
+  {
+    goto done;
+  }
+
+  switch (p->class_id) {
+    case JS_CLASS_INT8_ARRAY:
+      if (is_int && (int8_t)v64 == v64)
+        goto scan8;
+      break;
+    case JS_CLASS_UINT8C_ARRAY:
+    case JS_CLASS_UINT8_ARRAY:
+      if (is_int && (uint8_t)v64 == v64) {
+        const uint8_t *pv, *pp;
+        uint16_t v;
+      scan8:
+        pv = p->u.array.u.uint8_ptr;
+        v = v64;
+        if (inc > 0) {
+          pp = memchr(pv + k, v, len - k);
+          if (pp)
+            res = pp - pv;
+        } else {
+          for (; k != stop; k += inc) {
+            if (pv[k] == v) {
+              res = k;
+              break;
+            }
+          }
+        }
+      }
+      break;
+    case JS_CLASS_INT16_ARRAY:
+      if (is_int && (int16_t)v64 == v64)
+        goto scan16;
+      break;
+    case JS_CLASS_UINT16_ARRAY:
+      if (is_int && (uint16_t)v64 == v64) {
+        const uint16_t* pv;
+        uint16_t v;
+      scan16:
+        pv = p->u.array.u.uint16_ptr;
+        v = v64;
+        for (; k != stop; k += inc) {
+          if (pv[k] == v) {
+            res = k;
+            break;
+          }
+        }
+      }
+      break;
+    case JS_CLASS_INT32_ARRAY:
+      if (is_int && (int32_t)v64 == v64)
+        goto scan32;
+      break;
+    case JS_CLASS_UINT32_ARRAY:
+      if (is_int && (uint32_t)v64 == v64) {
+        const uint32_t* pv;
+        uint32_t v;
+      scan32:
+        pv = p->u.array.u.uint32_ptr;
+        v = v64;
+        for (; k != stop; k += inc) {
+          if (pv[k] == v) {
+            res = k;
+            break;
+          }
+        }
+      }
+      break;
+    case JS_CLASS_FLOAT32_ARRAY:
+      if (is_bigint)
+        break;
+      if (isnan(d)) {
+        const float* pv = p->u.array.u.float_ptr;
+        /* special case: indexOf returns -1, includes finds NaN */
+        if (special != special_includes)
+          goto done;
+        for (; k != stop; k += inc) {
+          if (isnan(pv[k])) {
+            res = k;
+            break;
+          }
+        }
+      } else if ((f = (float)d) == d) {
+        const float* pv = p->u.array.u.float_ptr;
+        for (; k != stop; k += inc) {
+          if (pv[k] == f) {
+            res = k;
+            break;
+          }
+        }
+      }
+      break;
+    case JS_CLASS_FLOAT64_ARRAY:
+      if (is_bigint)
+        break;
+      if (isnan(d)) {
+        const double* pv = p->u.array.u.double_ptr;
+        /* special case: indexOf returns -1, includes finds NaN */
+        if (special != special_includes)
+          goto done;
+        for (; k != stop; k += inc) {
+          if (isnan(pv[k])) {
+            res = k;
+            break;
+          }
+        }
+      } else {
+        const double* pv = p->u.array.u.double_ptr;
+        for (; k != stop; k += inc) {
+          if (pv[k] == d) {
+            res = k;
+            break;
+          }
+        }
+      }
+      break;
+#ifdef CONFIG_BIGNUM
+    case JS_CLASS_BIG_INT64_ARRAY:
+      if (is_bigint || (is_math_mode(ctx) && is_int && v64 >= -MAX_SAFE_INTEGER && v64 <= MAX_SAFE_INTEGER)) {
+        goto scan64;
+      }
+      break;
+    case JS_CLASS_BIG_UINT64_ARRAY:
+      if (is_bigint || (is_math_mode(ctx) && is_int && v64 >= 0 && v64 <= MAX_SAFE_INTEGER)) {
+        const uint64_t* pv;
+        uint64_t v;
+      scan64:
+        pv = p->u.array.u.uint64_ptr;
+        v = v64;
+        for (; k != stop; k += inc) {
+          if (pv[k] == v) {
+            res = k;
+            break;
+          }
+        }
+      }
+      break;
+#endif
+  }
+
+done:
+  if (special == special_includes)
+    return JS_NewBool(ctx, res >= 0);
+  else
+    return JS_NewInt32(ctx, res);
+
+exception:
+  return JS_EXCEPTION;
+}
+
+JSValue js_typed_array_join(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int toLocaleString) {
+  JSValue sep = JS_UNDEFINED, el;
+  StringBuffer b_s, *b = &b_s;
+  JSString* p = NULL;
+  int i, n;
+  int c;
+
+  n = js_typed_array_get_length_internal(ctx, this_val);
+  if (n < 0)
+    goto exception;
+
+  c = ','; /* default separator */
+  if (!toLocaleString && argc > 0 && !JS_IsUndefined(argv[0])) {
+    sep = JS_ToString(ctx, argv[0]);
+    if (JS_IsException(sep))
+      goto exception;
+    p = JS_VALUE_GET_STRING(sep);
+    if (p->len == 1 && !p->is_wide_char)
+      c = p->u.str8[0];
+    else
+      c = -1;
+  }
+  string_buffer_init(ctx, b, 0);
+
+  /* XXX: optimize with direct access */
+  for (i = 0; i < n; i++) {
+    if (i > 0) {
+      if (c >= 0) {
+        if (string_buffer_putc8(b, c))
+          goto fail;
+      } else {
+        if (string_buffer_concat(b, p, 0, p->len))
+          goto fail;
+      }
+    }
+    el = JS_GetPropertyUint32(ctx, this_val, i);
+    /* Can return undefined for example if the typed array is detached */
+    if (!JS_IsNull(el) && !JS_IsUndefined(el)) {
+      if (JS_IsException(el))
+        goto fail;
+      if (toLocaleString) {
+        el = JS_ToLocaleStringFree(ctx, el);
+      }
+      if (string_buffer_concat_value_free(b, el))
+        goto fail;
+    }
+  }
+  JS_FreeValue(ctx, sep);
+  return string_buffer_end(b);
+
+fail:
+  string_buffer_free(b);
+  JS_FreeValue(ctx, sep);
+exception:
+  return JS_EXCEPTION;
+}
+
+JSValue js_typed_array_reverse(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSObject* p;
+  int len;
+
+  len = js_typed_array_get_length_internal(ctx, this_val);
+  if (len < 0)
+    return JS_EXCEPTION;
+  if (len > 0) {
+    p = JS_VALUE_GET_OBJ(this_val);
+    switch (typed_array_size_log2(p->class_id)) {
+      case 0: {
+        uint8_t* p1 = p->u.array.u.uint8_ptr;
+        uint8_t* p2 = p1 + len - 1;
+        while (p1 < p2) {
+          uint8_t v = *p1;
+          *p1++ = *p2;
+          *p2-- = v;
+        }
+      } break;
+      case 1: {
+        uint16_t* p1 = p->u.array.u.uint16_ptr;
+        uint16_t* p2 = p1 + len - 1;
+        while (p1 < p2) {
+          uint16_t v = *p1;
+          *p1++ = *p2;
+          *p2-- = v;
+        }
+      } break;
+      case 2: {
+        uint32_t* p1 = p->u.array.u.uint32_ptr;
+        uint32_t* p2 = p1 + len - 1;
+        while (p1 < p2) {
+          uint32_t v = *p1;
+          *p1++ = *p2;
+          *p2-- = v;
+        }
+      } break;
+      case 3: {
+        uint64_t* p1 = p->u.array.u.uint64_ptr;
+        uint64_t* p2 = p1 + len - 1;
+        while (p1 < p2) {
+          uint64_t v = *p1;
+          *p1++ = *p2;
+          *p2-- = v;
+        }
+      } break;
+      default:
+        abort();
+    }
+  }
+  return JS_DupValue(ctx, this_val);
+}
+
+JSValue js_typed_array_slice(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValueConst args[2];
+  JSValue arr, val;
+  JSObject *p, *p1;
+  int n, len, start, final, count, shift;
+
+  arr = JS_UNDEFINED;
+  len = js_typed_array_get_length_internal(ctx, this_val);
+  if (len < 0)
+    goto exception;
+
+  if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))
+    goto exception;
+  final = len;
+  if (!JS_IsUndefined(argv[1])) {
+    if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len))
+      goto exception;
+  }
+  count = max_int(final - start, 0);
+
+  p = get_typed_array(ctx, this_val, 0);
+  if (p == NULL)
+    goto exception;
+  shift = typed_array_size_log2(p->class_id);
+
+  args[0] = this_val;
+  args[1] = JS_NewInt32(ctx, count);
+  arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
+  if (JS_IsException(arr))
+    goto exception;
+
+  if (count > 0) {
+    if (validate_typed_array(ctx, this_val) || validate_typed_array(ctx, arr))
+      goto exception;
+
+    p1 = get_typed_array(ctx, arr, 0);
+    if (p1 != NULL && p->class_id == p1->class_id && typed_array_get_length(ctx, p1) >= count && typed_array_get_length(ctx, p) >= start + count) {
+      memcpy(p1->u.array.u.uint8_ptr, p->u.array.u.uint8_ptr + (start << shift), count << shift);
+    } else {
+      for (n = 0; n < count; n++) {
+        val = JS_GetPropertyValue(ctx, this_val, JS_NewInt32(ctx, start + n));
+        if (JS_IsException(val))
+          goto exception;
+        if (JS_SetPropertyValue(ctx, arr, JS_NewInt32(ctx, n), val, JS_PROP_THROW) < 0)
+          goto exception;
+      }
+    }
+  }
+  return arr;
+
+exception:
+  JS_FreeValue(ctx, arr);
+  return JS_EXCEPTION;
+}
+
+JSValue js_typed_array_subarray(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValueConst args[4];
+  JSValue arr, byteOffset, ta_buffer;
+  JSObject* p;
+  int len, start, final, count, shift, offset;
+
+  p = get_typed_array(ctx, this_val, 0);
+  if (!p)
+    goto exception;
+  len = p->u.array.count;
+  if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))
+    goto exception;
+
+  final = len;
+  if (!JS_IsUndefined(argv[1])) {
+    if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len))
+      goto exception;
+  }
+  count = max_int(final - start, 0);
+  byteOffset = js_typed_array_get_byteOffset(ctx, this_val, 0);
+  if (JS_IsException(byteOffset))
+    goto exception;
+  shift = typed_array_size_log2(p->class_id);
+  offset = JS_VALUE_GET_INT(byteOffset) + (start << shift);
+  JS_FreeValue(ctx, byteOffset);
+  ta_buffer = js_typed_array_get_buffer(ctx, this_val, 0);
+  if (JS_IsException(ta_buffer))
+    goto exception;
+  args[0] = this_val;
+  args[1] = ta_buffer;
+  args[2] = JS_NewInt32(ctx, offset);
+  args[3] = JS_NewInt32(ctx, count);
+  arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 4, args);
+  JS_FreeValue(ctx, ta_buffer);
+  return arr;
+
+exception:
+  return JS_EXCEPTION;
+}
+
+/* TypedArray.prototype.sort */
+
+int js_cmp_doubles(double x, double y) {
+  if (isnan(x))
+    return isnan(y) ? 0 : +1;
+  if (isnan(y))
+    return -1;
+  if (x < y)
+    return -1;
+  if (x > y)
+    return 1;
+  if (x != 0)
+    return 0;
+  if (signbit(x))
+    return signbit(y) ? 0 : -1;
+  else
+    return signbit(y) ? 1 : 0;
+}
+
+int js_TA_cmp_int8(const void* a, const void* b, void* opaque) {
+  return *(const int8_t*)a - *(const int8_t*)b;
+}
+
+int js_TA_cmp_uint8(const void* a, const void* b, void* opaque) {
+  return *(const uint8_t*)a - *(const uint8_t*)b;
+}
+
+int js_TA_cmp_int16(const void* a, const void* b, void* opaque) {
+  return *(const int16_t*)a - *(const int16_t*)b;
+}
+
+int js_TA_cmp_uint16(const void* a, const void* b, void* opaque) {
+  return *(const uint16_t*)a - *(const uint16_t*)b;
+}
+
+int js_TA_cmp_int32(const void* a, const void* b, void* opaque) {
+  int32_t x = *(const int32_t*)a;
+  int32_t y = *(const int32_t*)b;
+  return (y < x) - (y > x);
+}
+
+int js_TA_cmp_uint32(const void* a, const void* b, void* opaque) {
+  uint32_t x = *(const uint32_t*)a;
+  uint32_t y = *(const uint32_t*)b;
+  return (y < x) - (y > x);
+}
+
+#ifdef CONFIG_BIGNUM
+int js_TA_cmp_int64(const void* a, const void* b, void* opaque) {
+  int64_t x = *(const int64_t*)a;
+  int64_t y = *(const int64_t*)b;
+  return (y < x) - (y > x);
+}
+
+int js_TA_cmp_uint64(const void* a, const void* b, void* opaque) {
+  uint64_t x = *(const uint64_t*)a;
+  uint64_t y = *(const uint64_t*)b;
+  return (y < x) - (y > x);
+}
+#endif
+
+int js_TA_cmp_float32(const void* a, const void* b, void* opaque) {
+  return js_cmp_doubles(*(const float*)a, *(const float*)b);
+}
+
+int js_TA_cmp_float64(const void* a, const void* b, void* opaque) {
+  return js_cmp_doubles(*(const double*)a, *(const double*)b);
+}
+
+JSValue js_TA_get_int8(JSContext* ctx, const void* a) {
+  return JS_NewInt32(ctx, *(const int8_t*)a);
+}
+
+JSValue js_TA_get_uint8(JSContext* ctx, const void* a) {
+  return JS_NewInt32(ctx, *(const uint8_t*)a);
+}
+
+JSValue js_TA_get_int16(JSContext* ctx, const void* a) {
+  return JS_NewInt32(ctx, *(const int16_t*)a);
+}
+
+JSValue js_TA_get_uint16(JSContext* ctx, const void* a) {
+  return JS_NewInt32(ctx, *(const uint16_t*)a);
+}
+
+JSValue js_TA_get_int32(JSContext* ctx, const void* a) {
+  return JS_NewInt32(ctx, *(const int32_t*)a);
+}
+
+JSValue js_TA_get_uint32(JSContext* ctx, const void* a) {
+  return JS_NewUint32(ctx, *(const uint32_t*)a);
+}
+
+#ifdef CONFIG_BIGNUM
+JSValue js_TA_get_int64(JSContext* ctx, const void* a) {
+  return JS_NewBigInt64(ctx, *(int64_t*)a);
+}
+
+JSValue js_TA_get_uint64(JSContext* ctx, const void* a) {
+  return JS_NewBigUint64(ctx, *(uint64_t*)a);
+}
+#endif
+
+JSValue js_TA_get_float32(JSContext* ctx, const void* a) {
+  return __JS_NewFloat64(ctx, *(const float*)a);
+}
+
+JSValue js_TA_get_float64(JSContext* ctx, const void* a) {
+  return __JS_NewFloat64(ctx, *(const double*)a);
+}
+
+struct TA_sort_context {
+  JSContext* ctx;
+  int exception;
+  JSValueConst arr;
+  JSValueConst cmp;
+  JSValue (*getfun)(JSContext* ctx, const void* a);
+  uint8_t* array_ptr; /* cannot change unless the array is detached */
+  int elt_size;
+};
+
+int js_TA_cmp_generic(const void* a, const void* b, void* opaque) {
+  struct TA_sort_context* psc = opaque;
+  JSContext* ctx = psc->ctx;
+  uint32_t a_idx, b_idx;
+  JSValueConst argv[2];
+  JSValue res;
+  int cmp;
+
+  cmp = 0;
+  if (!psc->exception) {
+    a_idx = *(uint32_t*)a;
+    b_idx = *(uint32_t*)b;
+    argv[0] = psc->getfun(ctx, psc->array_ptr + a_idx * (size_t)psc->elt_size);
+    argv[1] = psc->getfun(ctx, psc->array_ptr + b_idx * (size_t)(psc->elt_size));
+    res = JS_Call(ctx, psc->cmp, JS_UNDEFINED, 2, argv);
+    if (JS_IsException(res)) {
+      psc->exception = 1;
+      goto done;
+    }
+    if (JS_VALUE_GET_TAG(res) == JS_TAG_INT) {
+      int val = JS_VALUE_GET_INT(res);
+      cmp = (val > 0) - (val < 0);
+    } else {
+      double val;
+      if (JS_ToFloat64Free(ctx, &val, res) < 0) {
+        psc->exception = 1;
+        goto done;
+      } else {
+        cmp = (val > 0) - (val < 0);
+      }
+    }
+    if (cmp == 0) {
+      /* make sort stable: compare array offsets */
+      cmp = (a_idx > b_idx) - (a_idx < b_idx);
+    }
+    if (validate_typed_array(ctx, psc->arr) < 0) {
+      psc->exception = 1;
+    }
+  done:
+    JS_FreeValue(ctx, (JSValue)argv[0]);
+    JS_FreeValue(ctx, (JSValue)argv[1]);
+  }
+  return cmp;
+}
+
+JSValue js_typed_array_sort(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSObject* p;
+  int len;
+  size_t elt_size;
+  struct TA_sort_context tsc;
+  void* array_ptr;
+  int (*cmpfun)(const void* a, const void* b, void* opaque);
+
+  tsc.ctx = ctx;
+  tsc.exception = 0;
+  tsc.arr = this_val;
+  tsc.cmp = argv[0];
+
+  len = js_typed_array_get_length_internal(ctx, this_val);
+  if (len < 0)
+    return JS_EXCEPTION;
+  if (!JS_IsUndefined(tsc.cmp) && check_function(ctx, tsc.cmp))
+    return JS_EXCEPTION;
+
+  if (len > 1) {
+    p = JS_VALUE_GET_OBJ(this_val);
+    switch (p->class_id) {
+      case JS_CLASS_INT8_ARRAY:
+        tsc.getfun = js_TA_get_int8;
+        cmpfun = js_TA_cmp_int8;
+        break;
+      case JS_CLASS_UINT8C_ARRAY:
+      case JS_CLASS_UINT8_ARRAY:
+        tsc.getfun = js_TA_get_uint8;
+        cmpfun = js_TA_cmp_uint8;
+        break;
+      case JS_CLASS_INT16_ARRAY:
+        tsc.getfun = js_TA_get_int16;
+        cmpfun = js_TA_cmp_int16;
+        break;
+      case JS_CLASS_UINT16_ARRAY:
+        tsc.getfun = js_TA_get_uint16;
+        cmpfun = js_TA_cmp_uint16;
+        break;
+      case JS_CLASS_INT32_ARRAY:
+        tsc.getfun = js_TA_get_int32;
+        cmpfun = js_TA_cmp_int32;
+        break;
+      case JS_CLASS_UINT32_ARRAY:
+        tsc.getfun = js_TA_get_uint32;
+        cmpfun = js_TA_cmp_uint32;
+        break;
+#ifdef CONFIG_BIGNUM
+      case JS_CLASS_BIG_INT64_ARRAY:
+        tsc.getfun = js_TA_get_int64;
+        cmpfun = js_TA_cmp_int64;
+        break;
+      case JS_CLASS_BIG_UINT64_ARRAY:
+        tsc.getfun = js_TA_get_uint64;
+        cmpfun = js_TA_cmp_uint64;
+        break;
+#endif
+      case JS_CLASS_FLOAT32_ARRAY:
+        tsc.getfun = js_TA_get_float32;
+        cmpfun = js_TA_cmp_float32;
+        break;
+      case JS_CLASS_FLOAT64_ARRAY:
+        tsc.getfun = js_TA_get_float64;
+        cmpfun = js_TA_cmp_float64;
+        break;
+      default:
+        abort();
+    }
+    array_ptr = p->u.array.u.ptr;
+    elt_size = 1 << typed_array_size_log2(p->class_id);
+    if (!JS_IsUndefined(tsc.cmp)) {
+      uint32_t* array_idx;
+      void* array_tmp;
+      size_t i, j;
+
+      /* XXX: a stable sort would use less memory */
+      array_idx = js_malloc(ctx, len * sizeof(array_idx[0]));
+      if (!array_idx)
+        return JS_EXCEPTION;
+      for (i = 0; i < len; i++)
+        array_idx[i] = i;
+      tsc.array_ptr = array_ptr;
+      tsc.elt_size = elt_size;
+      rqsort(array_idx, len, sizeof(array_idx[0]), js_TA_cmp_generic, &tsc);
+      if (tsc.exception)
+        goto fail;
+      array_tmp = js_malloc(ctx, len * elt_size);
+      if (!array_tmp) {
+      fail:
+        js_free(ctx, array_idx);
+        return JS_EXCEPTION;
+      }
+      memcpy(array_tmp, array_ptr, len * elt_size);
+      switch (elt_size) {
+        case 1:
+          for (i = 0; i < len; i++) {
+            j = array_idx[i];
+            ((uint8_t*)array_ptr)[i] = ((uint8_t*)array_tmp)[j];
+          }
+          break;
+        case 2:
+          for (i = 0; i < len; i++) {
+            j = array_idx[i];
+            ((uint16_t*)array_ptr)[i] = ((uint16_t*)array_tmp)[j];
+          }
+          break;
+        case 4:
+          for (i = 0; i < len; i++) {
+            j = array_idx[i];
+            ((uint32_t*)array_ptr)[i] = ((uint32_t*)array_tmp)[j];
+          }
+          break;
+        case 8:
+          for (i = 0; i < len; i++) {
+            j = array_idx[i];
+            ((uint64_t*)array_ptr)[i] = ((uint64_t*)array_tmp)[j];
+          }
+          break;
+        default:
+          abort();
+      }
+      js_free(ctx, array_tmp);
+      js_free(ctx, array_idx);
+    } else {
+      rqsort(array_ptr, len, elt_size, cmpfun, &tsc);
+      if (tsc.exception)
+        return JS_EXCEPTION;
+    }
+  }
+  return JS_DupValue(ctx, this_val);
+}
+
+const JSCFunctionListEntry js_typed_array_base_funcs[] = {
+    JS_CFUNC_DEF("from", 1, js_typed_array_from), JS_CFUNC_DEF("of", 0, js_typed_array_of), JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL),
+    // JS_CFUNC_DEF("__getLength", 2, js_typed_array___getLength ),
+    // JS_CFUNC_DEF("__create", 2, js_typed_array___create ),
+    // JS_CFUNC_DEF("__speciesCreate", 2, js_typed_array___speciesCreate ),
+};
+
+const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = {
+    JS_CGETSET_DEF("length", js_typed_array_get_length, NULL),
+    JS_CGETSET_MAGIC_DEF("buffer", js_typed_array_get_buffer, NULL, 0),
+    JS_CGETSET_MAGIC_DEF("byteLength", js_typed_array_get_byteLength, NULL, 0),
+    JS_CGETSET_MAGIC_DEF("byteOffset", js_typed_array_get_byteOffset, NULL, 0),
+    JS_CFUNC_DEF("set", 1, js_typed_array_set),
+    JS_CFUNC_MAGIC_DEF("values", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_VALUE),
+    JS_ALIAS_DEF("[Symbol.iterator]", "values"),
+    JS_CFUNC_MAGIC_DEF("keys", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_KEY),
+    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE),
+    JS_CGETSET_DEF("[Symbol.toStringTag]", js_typed_array_get_toStringTag, NULL),
+    JS_CFUNC_DEF("copyWithin", 2, js_typed_array_copyWithin),
+    JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every | special_TA),
+    JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some | special_TA),
+    JS_CFUNC_MAGIC_DEF("forEach", 1, js_array_every, special_forEach | special_TA),
+    JS_CFUNC_MAGIC_DEF("map", 1, js_array_every, special_map | special_TA),
+    JS_CFUNC_MAGIC_DEF("filter", 1, js_array_every, special_filter | special_TA),
+    JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce | special_TA),
+    JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight | special_TA),
+    JS_CFUNC_DEF("fill", 1, js_typed_array_fill),
+    JS_CFUNC_MAGIC_DEF("find", 1, js_typed_array_find, 0),
+    JS_CFUNC_MAGIC_DEF("findIndex", 1, js_typed_array_find, 1),
+    JS_CFUNC_DEF("reverse", 0, js_typed_array_reverse),
+    JS_CFUNC_DEF("slice", 2, js_typed_array_slice),
+    JS_CFUNC_DEF("subarray", 2, js_typed_array_subarray),
+    JS_CFUNC_DEF("sort", 1, js_typed_array_sort),
+    JS_CFUNC_MAGIC_DEF("join", 1, js_typed_array_join, 0),
+    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_typed_array_join, 1),
+    JS_CFUNC_MAGIC_DEF("indexOf", 1, js_typed_array_indexOf, special_indexOf),
+    JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_typed_array_indexOf, special_lastIndexOf),
+    JS_CFUNC_MAGIC_DEF("includes", 1, js_typed_array_indexOf, special_includes),
+    // JS_ALIAS_BASE_DEF("toString", "toString", 2 /* Array.prototype. */), @@@
+};
+
+JSValue js_typed_array_base_constructor(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  return JS_ThrowTypeError(ctx, "cannot be called");
+}
+
+/* 'obj' must be an allocated typed array object */
+int typed_array_init(JSContext* ctx, JSValueConst obj, JSValue buffer, uint64_t offset, uint64_t len) {
+  JSTypedArray* ta;
+  JSObject *p, *pbuffer;
+  JSArrayBuffer* abuf;
+  int size_log2;
+
+  p = JS_VALUE_GET_OBJ(obj);
+  size_log2 = typed_array_size_log2(p->class_id);
+  ta = js_malloc(ctx, sizeof(*ta));
+  if (!ta) {
+    JS_FreeValue(ctx, buffer);
+    return -1;
+  }
+  pbuffer = JS_VALUE_GET_OBJ(buffer);
+  abuf = pbuffer->u.array_buffer;
+  ta->obj = p;
+  ta->buffer = pbuffer;
+  ta->offset = offset;
+  ta->length = len << size_log2;
+  list_add_tail(&ta->link, &abuf->array_list);
+  p->u.typed_array = ta;
+  p->u.array.count = len;
+  p->u.array.u.ptr = abuf->data + offset;
+  return 0;
+}
+
+JSValue js_array_from_iterator(JSContext* ctx, uint32_t* plen, JSValueConst obj, JSValueConst method) {
+  JSValue arr, iter, next_method = JS_UNDEFINED, val;
+  BOOL done;
+  uint32_t k;
+
+  *plen = 0;
+  arr = JS_NewArray(ctx);
+  if (JS_IsException(arr))
+    return arr;
+  iter = JS_GetIterator2(ctx, obj, method);
+  if (JS_IsException(iter))
+    goto fail;
+  next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
+  if (JS_IsException(next_method))
+    goto fail;
+  k = 0;
+  for (;;) {
+    val = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
+    if (JS_IsException(val))
+      goto fail;
+    if (done) {
+      JS_FreeValue(ctx, val);
+      break;
+    }
+    if (JS_CreateDataPropertyUint32(ctx, arr, k, val, JS_PROP_THROW) < 0)
+      goto fail;
+    k++;
+  }
+  JS_FreeValue(ctx, next_method);
+  JS_FreeValue(ctx, iter);
+  *plen = k;
+  return arr;
+fail:
+  JS_FreeValue(ctx, next_method);
+  JS_FreeValue(ctx, iter);
+  JS_FreeValue(ctx, arr);
+  return JS_EXCEPTION;
+}
+
+JSValue js_typed_array_constructor_obj(JSContext* ctx, JSValueConst new_target, JSValueConst obj, int classid) {
+  JSValue iter, ret, arr = JS_UNDEFINED, val, buffer;
+  uint32_t i;
+  int size_log2;
+  int64_t len;
+
+  size_log2 = typed_array_size_log2(classid);
+  ret = js_create_from_ctor(ctx, new_target, classid);
+  if (JS_IsException(ret))
+    return JS_EXCEPTION;
+
+  iter = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
+  if (JS_IsException(iter))
+    goto fail;
+  if (!JS_IsUndefined(iter) && !JS_IsNull(iter)) {
+    uint32_t len1;
+    arr = js_array_from_iterator(ctx, &len1, obj, iter);
+    JS_FreeValue(ctx, iter);
+    if (JS_IsException(arr))
+      goto fail;
+    len = len1;
+  } else {
+    if (js_get_length64(ctx, &len, obj))
+      goto fail;
+    arr = JS_DupValue(ctx, obj);
+  }
+
+  buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED, len << size_log2);
+  if (JS_IsException(buffer))
+    goto fail;
+  if (typed_array_init(ctx, ret, buffer, 0, len))
+    goto fail;
+
+  for (i = 0; i < len; i++) {
+    val = JS_GetPropertyUint32(ctx, arr, i);
+    if (JS_IsException(val))
+      goto fail;
+    if (JS_SetPropertyUint32(ctx, ret, i, val) < 0)
+      goto fail;
+  }
+  JS_FreeValue(ctx, arr);
+  return ret;
+fail:
+  JS_FreeValue(ctx, arr);
+  JS_FreeValue(ctx, ret);
+  return JS_EXCEPTION;
+}
+
+JSValue js_typed_array_constructor_ta(JSContext* ctx, JSValueConst new_target, JSValueConst src_obj, int classid) {
+  JSObject *p, *src_buffer;
+  JSTypedArray* ta;
+  JSValue ctor, obj, buffer;
+  uint32_t len, i;
+  int size_log2;
+  JSArrayBuffer *src_abuf, *abuf;
+
+  obj = js_create_from_ctor(ctx, new_target, classid);
+  if (JS_IsException(obj))
+    return obj;
+  p = JS_VALUE_GET_OBJ(src_obj);
+  if (typed_array_is_detached(ctx, p)) {
+    JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+    goto fail;
+  }
+  ta = p->u.typed_array;
+  len = p->u.array.count;
+  src_buffer = ta->buffer;
+  src_abuf = src_buffer->u.array_buffer;
+  if (!src_abuf->shared) {
+    ctor = JS_SpeciesConstructor(ctx, JS_MKPTR(JS_TAG_OBJECT, src_buffer), JS_UNDEFINED);
+    if (JS_IsException(ctor))
+      goto fail;
+  } else {
+    /* force ArrayBuffer default constructor */
+    ctor = JS_UNDEFINED;
+  }
+  size_log2 = typed_array_size_log2(classid);
+  buffer = js_array_buffer_constructor1(ctx, ctor, (uint64_t)len << size_log2);
+  JS_FreeValue(ctx, ctor);
+  if (JS_IsException(buffer))
+    goto fail;
+  /* necessary because it could have been detached */
+  if (typed_array_is_detached(ctx, p)) {
+    JS_FreeValue(ctx, buffer);
+    JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+    goto fail;
+  }
+  abuf = JS_GetOpaque(buffer, JS_CLASS_ARRAY_BUFFER);
+  if (typed_array_init(ctx, obj, buffer, 0, len))
+    goto fail;
+  if (p->class_id == classid) {
+    /* same type: copy the content */
+    memcpy(abuf->data, src_abuf->data + ta->offset, abuf->byte_length);
+  } else {
+    for (i = 0; i < len; i++) {
+      JSValue val;
+      val = JS_GetPropertyUint32(ctx, src_obj, i);
+      if (JS_IsException(val))
+        goto fail;
+      if (JS_SetPropertyUint32(ctx, obj, i, val) < 0)
+        goto fail;
+    }
+  }
+  return obj;
+fail:
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+JSValue js_typed_array_constructor(JSContext* ctx, JSValueConst new_target, int argc, JSValueConst* argv, int classid) {
+  JSValue buffer, obj;
+  JSArrayBuffer* abuf;
+  int size_log2;
+  uint64_t len, offset;
+
+  size_log2 = typed_array_size_log2(classid);
+  if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT) {
+    if (JS_ToIndex(ctx, &len, argv[0]))
+      return JS_EXCEPTION;
+    buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED, len << size_log2);
+    if (JS_IsException(buffer))
+      return JS_EXCEPTION;
+    offset = 0;
+  } else {
+    JSObject* p = JS_VALUE_GET_OBJ(argv[0]);
+    if (p->class_id == JS_CLASS_ARRAY_BUFFER || p->class_id == JS_CLASS_SHARED_ARRAY_BUFFER) {
+      abuf = p->u.array_buffer;
+      if (JS_ToIndex(ctx, &offset, argv[1]))
+        return JS_EXCEPTION;
+      if (abuf->detached)
+        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+      if ((offset & ((1 << size_log2) - 1)) != 0 || offset > abuf->byte_length)
+        return JS_ThrowRangeError(ctx, "invalid offset");
+      if (JS_IsUndefined(argv[2])) {
+        if ((abuf->byte_length & ((1 << size_log2) - 1)) != 0)
+          goto invalid_length;
+        len = (abuf->byte_length - offset) >> size_log2;
+      } else {
+        if (JS_ToIndex(ctx, &len, argv[2]))
+          return JS_EXCEPTION;
+        if (abuf->detached)
+          return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+        if ((offset + (len << size_log2)) > abuf->byte_length) {
+        invalid_length:
+          return JS_ThrowRangeError(ctx, "invalid length");
+        }
+      }
+      buffer = JS_DupValue(ctx, argv[0]);
+    } else {
+      if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
+        return js_typed_array_constructor_ta(ctx, new_target, argv[0], classid);
+      } else {
+        return js_typed_array_constructor_obj(ctx, new_target, argv[0], classid);
+      }
+    }
+  }
+
+  obj = js_create_from_ctor(ctx, new_target, classid);
+  if (JS_IsException(obj)) {
+    JS_FreeValue(ctx, buffer);
+    return JS_EXCEPTION;
+  }
+  if (typed_array_init(ctx, obj, buffer, offset, len)) {
+    JS_FreeValue(ctx, obj);
+    return JS_EXCEPTION;
+  }
+  return obj;
+}
+
+void js_typed_array_finalizer(JSRuntime* rt, JSValue val) {
+  JSObject* p = JS_VALUE_GET_OBJ(val);
+  JSTypedArray* ta = p->u.typed_array;
+  if (ta) {
+    /* during the GC the finalizers are called in an arbitrary
+       order so the ArrayBuffer finalizer may have been called */
+    if (JS_IsLiveObject(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer))) {
+      list_del(&ta->link);
+    }
+    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
+    js_free_rt(rt, ta);
+  }
+}
+
+void js_typed_array_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func) {
+  JSObject* p = JS_VALUE_GET_OBJ(val);
+  JSTypedArray* ta = p->u.typed_array;
+  if (ta) {
+    JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer), mark_func);
+  }
+}
+
+JSValue js_dataview_constructor(JSContext* ctx, JSValueConst new_target, int argc, JSValueConst* argv) {
+  JSArrayBuffer* abuf;
+  uint64_t offset;
+  uint32_t len;
+  JSValueConst buffer;
+  JSValue obj;
+  JSTypedArray* ta;
+  JSObject* p;
+
+  buffer = argv[0];
+  abuf = js_get_array_buffer(ctx, buffer);
+  if (!abuf)
+    return JS_EXCEPTION;
+  offset = 0;
+  if (argc > 1) {
+    if (JS_ToIndex(ctx, &offset, argv[1]))
+      return JS_EXCEPTION;
+  }
+  if (abuf->detached)
+    return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+  if (offset > abuf->byte_length)
+    return JS_ThrowRangeError(ctx, "invalid byteOffset");
+  len = abuf->byte_length - offset;
+  if (argc > 2 && !JS_IsUndefined(argv[2])) {
+    uint64_t l;
+    if (JS_ToIndex(ctx, &l, argv[2]))
+      return JS_EXCEPTION;
+    if (l > len)
+      return JS_ThrowRangeError(ctx, "invalid byteLength");
+    len = l;
+  }
+
+  obj = js_create_from_ctor(ctx, new_target, JS_CLASS_DATAVIEW);
+  if (JS_IsException(obj))
+    return JS_EXCEPTION;
+  if (abuf->detached) {
+    /* could have been detached in js_create_from_ctor() */
+    JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+    goto fail;
+  }
+  ta = js_malloc(ctx, sizeof(*ta));
+  if (!ta) {
+  fail:
+    JS_FreeValue(ctx, obj);
+    return JS_EXCEPTION;
+  }
+  p = JS_VALUE_GET_OBJ(obj);
+  ta->obj = p;
+  ta->buffer = JS_VALUE_GET_OBJ(JS_DupValue(ctx, buffer));
+  ta->offset = offset;
+  ta->length = len;
+  list_add_tail(&ta->link, &abuf->array_list);
+  p->u.typed_array = ta;
+  return obj;
+}
+
+JSValue js_dataview_getValue(JSContext* ctx, JSValueConst this_obj, int argc, JSValueConst* argv, int class_id) {
+  JSTypedArray* ta;
+  JSArrayBuffer* abuf;
+  int is_swap, size;
+  uint8_t* ptr;
+  uint32_t v;
+  uint64_t pos;
+
+  ta = JS_GetOpaque2(ctx, this_obj, JS_CLASS_DATAVIEW);
+  if (!ta)
+    return JS_EXCEPTION;
+  size = 1 << typed_array_size_log2(class_id);
+  if (JS_ToIndex(ctx, &pos, argv[0]))
+    return JS_EXCEPTION;
+  is_swap = FALSE;
+  if (argc > 1)
+    is_swap = JS_ToBool(ctx, argv[1]);
+#ifndef WORDS_BIGENDIAN
+  is_swap ^= 1;
+#endif
+  abuf = ta->buffer->u.array_buffer;
+  if (abuf->detached)
+    return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+  if ((pos + size) > ta->length)
+    return JS_ThrowRangeError(ctx, "out of bound");
+  ptr = abuf->data + ta->offset + pos;
+
+  switch (class_id) {
+    case JS_CLASS_INT8_ARRAY:
+      return JS_NewInt32(ctx, *(int8_t*)ptr);
+    case JS_CLASS_UINT8_ARRAY:
+      return JS_NewInt32(ctx, *(uint8_t*)ptr);
+    case JS_CLASS_INT16_ARRAY:
+      v = get_u16(ptr);
+      if (is_swap)
+        v = bswap16(v);
+      return JS_NewInt32(ctx, (int16_t)v);
+    case JS_CLASS_UINT16_ARRAY:
+      v = get_u16(ptr);
+      if (is_swap)
+        v = bswap16(v);
+      return JS_NewInt32(ctx, v);
+    case JS_CLASS_INT32_ARRAY:
+      v = get_u32(ptr);
+      if (is_swap)
+        v = bswap32(v);
+      return JS_NewInt32(ctx, v);
+    case JS_CLASS_UINT32_ARRAY:
+      v = get_u32(ptr);
+      if (is_swap)
+        v = bswap32(v);
+      return JS_NewUint32(ctx, v);
+#ifdef CONFIG_BIGNUM
+    case JS_CLASS_BIG_INT64_ARRAY: {
+      uint64_t v;
+      v = get_u64(ptr);
+      if (is_swap)
+        v = bswap64(v);
+      return JS_NewBigInt64(ctx, v);
+    } break;
+    case JS_CLASS_BIG_UINT64_ARRAY: {
+      uint64_t v;
+      v = get_u64(ptr);
+      if (is_swap)
+        v = bswap64(v);
+      return JS_NewBigUint64(ctx, v);
+    } break;
+#endif
+    case JS_CLASS_FLOAT32_ARRAY: {
+      union {
+        float f;
+        uint32_t i;
+      } u;
+      v = get_u32(ptr);
+      if (is_swap)
+        v = bswap32(v);
+      u.i = v;
+      return __JS_NewFloat64(ctx, u.f);
+    }
+    case JS_CLASS_FLOAT64_ARRAY: {
+      union {
+        double f;
+        uint64_t i;
+      } u;
+      u.i = get_u64(ptr);
+      if (is_swap)
+        u.i = bswap64(u.i);
+      return __JS_NewFloat64(ctx, u.f);
+    }
+    default:
+      abort();
+  }
+}
+
+JSValue js_dataview_setValue(JSContext* ctx, JSValueConst this_obj, int argc, JSValueConst* argv, int class_id) {
+  JSTypedArray* ta;
+  JSArrayBuffer* abuf;
+  int is_swap, size;
+  uint8_t* ptr;
+  uint64_t v64;
+  uint32_t v;
+  uint64_t pos;
+  JSValueConst val;
+
+  ta = JS_GetOpaque2(ctx, this_obj, JS_CLASS_DATAVIEW);
+  if (!ta)
+    return JS_EXCEPTION;
+  size = 1 << typed_array_size_log2(class_id);
+  if (JS_ToIndex(ctx, &pos, argv[0]))
+    return JS_EXCEPTION;
+  val = argv[1];
+  v = 0;   /* avoid warning */
+  v64 = 0; /* avoid warning */
+  if (class_id <= JS_CLASS_UINT32_ARRAY) {
+    if (JS_ToUint32(ctx, &v, val))
+      return JS_EXCEPTION;
+  } else
+#ifdef CONFIG_BIGNUM
+      if (class_id <= JS_CLASS_BIG_UINT64_ARRAY) {
+    if (JS_ToBigInt64(ctx, (int64_t*)&v64, val))
+      return JS_EXCEPTION;
+  } else
+#endif
+  {
+    double d;
+    if (JS_ToFloat64(ctx, &d, val))
+      return JS_EXCEPTION;
+    if (class_id == JS_CLASS_FLOAT32_ARRAY) {
+      union {
+        float f;
+        uint32_t i;
+      } u;
+      u.f = d;
+      v = u.i;
+    } else {
+      JSFloat64Union u;
+      u.d = d;
+      v64 = u.u64;
+    }
+  }
+  is_swap = FALSE;
+  if (argc > 2)
+    is_swap = JS_ToBool(ctx, argv[2]);
+#ifndef WORDS_BIGENDIAN
+  is_swap ^= 1;
+#endif
+  abuf = ta->buffer->u.array_buffer;
+  if (abuf->detached)
+    return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+  if ((pos + size) > ta->length)
+    return JS_ThrowRangeError(ctx, "out of bound");
+  ptr = abuf->data + ta->offset + pos;
+
+  switch (class_id) {
+    case JS_CLASS_INT8_ARRAY:
+    case JS_CLASS_UINT8_ARRAY:
+      *ptr = v;
+      break;
+    case JS_CLASS_INT16_ARRAY:
+    case JS_CLASS_UINT16_ARRAY:
+      if (is_swap)
+        v = bswap16(v);
+      put_u16(ptr, v);
+      break;
+    case JS_CLASS_INT32_ARRAY:
+    case JS_CLASS_UINT32_ARRAY:
+    case JS_CLASS_FLOAT32_ARRAY:
+      if (is_swap)
+        v = bswap32(v);
+      put_u32(ptr, v);
+      break;
+#ifdef CONFIG_BIGNUM
+    case JS_CLASS_BIG_INT64_ARRAY:
+    case JS_CLASS_BIG_UINT64_ARRAY:
+#endif
+    case JS_CLASS_FLOAT64_ARRAY:
+      if (is_swap)
+        v64 = bswap64(v64);
+      put_u64(ptr, v64);
+      break;
+    default:
+      abort();
+  }
+  return JS_UNDEFINED;
+}
+
+const JSCFunctionListEntry js_dataview_proto_funcs[] = {
+    JS_CGETSET_MAGIC_DEF("buffer", js_typed_array_get_buffer, NULL, 1),
+    JS_CGETSET_MAGIC_DEF("byteLength", js_typed_array_get_byteLength, NULL, 1),
+    JS_CGETSET_MAGIC_DEF("byteOffset", js_typed_array_get_byteOffset, NULL, 1),
+    JS_CFUNC_MAGIC_DEF("getInt8", 1, js_dataview_getValue, JS_CLASS_INT8_ARRAY),
+    JS_CFUNC_MAGIC_DEF("getUint8", 1, js_dataview_getValue, JS_CLASS_UINT8_ARRAY),
+    JS_CFUNC_MAGIC_DEF("getInt16", 1, js_dataview_getValue, JS_CLASS_INT16_ARRAY),
+    JS_CFUNC_MAGIC_DEF("getUint16", 1, js_dataview_getValue, JS_CLASS_UINT16_ARRAY),
+    JS_CFUNC_MAGIC_DEF("getInt32", 1, js_dataview_getValue, JS_CLASS_INT32_ARRAY),
+    JS_CFUNC_MAGIC_DEF("getUint32", 1, js_dataview_getValue, JS_CLASS_UINT32_ARRAY),
+#ifdef CONFIG_BIGNUM
+    JS_CFUNC_MAGIC_DEF("getBigInt64", 1, js_dataview_getValue, JS_CLASS_BIG_INT64_ARRAY),
+    JS_CFUNC_MAGIC_DEF("getBigUint64", 1, js_dataview_getValue, JS_CLASS_BIG_UINT64_ARRAY),
+#endif
+    JS_CFUNC_MAGIC_DEF("getFloat32", 1, js_dataview_getValue, JS_CLASS_FLOAT32_ARRAY),
+    JS_CFUNC_MAGIC_DEF("getFloat64", 1, js_dataview_getValue, JS_CLASS_FLOAT64_ARRAY),
+    JS_CFUNC_MAGIC_DEF("setInt8", 2, js_dataview_setValue, JS_CLASS_INT8_ARRAY),
+    JS_CFUNC_MAGIC_DEF("setUint8", 2, js_dataview_setValue, JS_CLASS_UINT8_ARRAY),
+    JS_CFUNC_MAGIC_DEF("setInt16", 2, js_dataview_setValue, JS_CLASS_INT16_ARRAY),
+    JS_CFUNC_MAGIC_DEF("setUint16", 2, js_dataview_setValue, JS_CLASS_UINT16_ARRAY),
+    JS_CFUNC_MAGIC_DEF("setInt32", 2, js_dataview_setValue, JS_CLASS_INT32_ARRAY),
+    JS_CFUNC_MAGIC_DEF("setUint32", 2, js_dataview_setValue, JS_CLASS_UINT32_ARRAY),
+#ifdef CONFIG_BIGNUM
+    JS_CFUNC_MAGIC_DEF("setBigInt64", 2, js_dataview_setValue, JS_CLASS_BIG_INT64_ARRAY),
+    JS_CFUNC_MAGIC_DEF("setBigUint64", 2, js_dataview_setValue, JS_CLASS_BIG_UINT64_ARRAY),
+#endif
+    JS_CFUNC_MAGIC_DEF("setFloat32", 2, js_dataview_setValue, JS_CLASS_FLOAT32_ARRAY),
+    JS_CFUNC_MAGIC_DEF("setFloat64", 2, js_dataview_setValue, JS_CLASS_FLOAT64_ARRAY),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "DataView", JS_PROP_CONFIGURABLE),
+};
+
+void JS_AddIntrinsicTypedArrays(JSContext* ctx) {
+  JSValue typed_array_base_proto, typed_array_base_func;
+  JSValueConst array_buffer_func, shared_array_buffer_func;
+  int i;
+
+  ctx->class_proto[JS_CLASS_ARRAY_BUFFER] = JS_NewObject(ctx);
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY_BUFFER], js_array_buffer_proto_funcs, countof(js_array_buffer_proto_funcs));
+
+  array_buffer_func = JS_NewGlobalCConstructorOnly(ctx, "ArrayBuffer", js_array_buffer_constructor, 1, ctx->class_proto[JS_CLASS_ARRAY_BUFFER]);
+  JS_SetPropertyFunctionList(ctx, array_buffer_func, js_array_buffer_funcs, countof(js_array_buffer_funcs));
+
+  ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER] = JS_NewObject(ctx);
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER], js_shared_array_buffer_proto_funcs, countof(js_shared_array_buffer_proto_funcs));
+
+  shared_array_buffer_func = JS_NewGlobalCConstructorOnly(ctx, "SharedArrayBuffer", js_shared_array_buffer_constructor, 1, ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER]);
+  JS_SetPropertyFunctionList(ctx, shared_array_buffer_func, js_shared_array_buffer_funcs, countof(js_shared_array_buffer_funcs));
+
+  typed_array_base_proto = JS_NewObject(ctx);
+  JS_SetPropertyFunctionList(ctx, typed_array_base_proto, js_typed_array_base_proto_funcs, countof(js_typed_array_base_proto_funcs));
+
+  /* TypedArray.prototype.toString must be the same object as Array.prototype.toString */
+  JSValue obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_toString);
+  /* XXX: should use alias method in JSCFunctionListEntry */  //@@@
+  JS_DefinePropertyValue(ctx, typed_array_base_proto, JS_ATOM_toString, obj, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+
+  typed_array_base_func = JS_NewCFunction(ctx, js_typed_array_base_constructor, "TypedArray", 0);
+  JS_SetPropertyFunctionList(ctx, typed_array_base_func, js_typed_array_base_funcs, countof(js_typed_array_base_funcs));
+  JS_SetConstructor(ctx, typed_array_base_func, typed_array_base_proto);
+
+  for (i = JS_CLASS_UINT8C_ARRAY; i < JS_CLASS_UINT8C_ARRAY + JS_TYPED_ARRAY_COUNT; i++) {
+    JSValue func_obj;
+    char buf[ATOM_GET_STR_BUF_SIZE];
+    const char* name;
+
+    ctx->class_proto[i] = JS_NewObjectProto(ctx, typed_array_base_proto);
+    JS_DefinePropertyValueStr(ctx, ctx->class_proto[i], "BYTES_PER_ELEMENT", JS_NewInt32(ctx, 1 << typed_array_size_log2(i)), 0);
+    name = JS_AtomGetStr(ctx, buf, sizeof(buf), JS_ATOM_Uint8ClampedArray + i - JS_CLASS_UINT8C_ARRAY);
+    func_obj = JS_NewCFunction3(ctx, (JSCFunction*)js_typed_array_constructor, name, 3, JS_CFUNC_constructor_magic, i, typed_array_base_func);
+    JS_NewGlobalCConstructor2(ctx, func_obj, name, ctx->class_proto[i]);
+    JS_DefinePropertyValueStr(ctx, func_obj, "BYTES_PER_ELEMENT", JS_NewInt32(ctx, 1 << typed_array_size_log2(i)), 0);
+  }
+  JS_FreeValue(ctx, typed_array_base_proto);
+  JS_FreeValue(ctx, typed_array_base_func);
+
+  /* DataView */
+  ctx->class_proto[JS_CLASS_DATAVIEW] = JS_NewObject(ctx);
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_DATAVIEW], js_dataview_proto_funcs, countof(js_dataview_proto_funcs));
+  JS_NewGlobalCConstructorOnly(ctx, "DataView", js_dataview_constructor, 1, ctx->class_proto[JS_CLASS_DATAVIEW]);
+  /* Atomics */
+#ifdef CONFIG_ATOMICS
+  JS_AddIntrinsicAtomics(ctx);
+#endif
+}
\ No newline at end of file
diff --git a/src/core/builtins/js-typed-array.h b/src/core/builtins/js-typed-array.h
new file mode 100644
index 000000000..9569a9484
--- /dev/null
+++ b/src/core/builtins/js-typed-array.h
@@ -0,0 +1,40 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_JS_TYPED_ARRAY_H
+#define QUICKJS_JS_TYPED_ARRAY_H
+
+#include "../types.h"
+#include "quickjs/cutils.h"
+#include "quickjs/quickjs.h"
+
+JSValue js_array_buffer_constructor3(JSContext* ctx, JSValueConst new_target, uint64_t len, JSClassID class_id, uint8_t* buf, JSFreeArrayBufferDataFunc* free_func, void* opaque, BOOL alloc_flag);
+JSValue js_typed_array_constructor(JSContext* ctx, JSValueConst new_target, int argc, JSValueConst* argv, int classid);
+
+JSArrayBuffer* js_get_array_buffer(JSContext* ctx, JSValueConst obj);
+BOOL typed_array_is_detached(JSContext* ctx, JSObject* p);
+JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext* ctx);
+
+#endif
\ No newline at end of file
diff --git a/src/core/bytecode.c b/src/core/bytecode.c
new file mode 100644
index 000000000..a39c35e5f
--- /dev/null
+++ b/src/core/bytecode.c
@@ -0,0 +1,2093 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "bytecode.h"
+#include "builtins/js-function.h"
+#include "builtins/js-object.h"
+#include "builtins/js-typed-array.h"
+#include "exception.h"
+#include "function.h"
+#include "gc.h"
+#include "malloc.h"
+#include "module.h"
+#include "object.h"
+#include "parser.h"
+#include "runtime.h"
+#include "shape.h"
+#include "string.h"
+
+void free_function_bytecode(JSRuntime* rt, JSFunctionBytecode* b) {
+  int i;
+
+#if 0
+    {
+        char buf[ATOM_GET_STR_BUF_SIZE];
+        printf("freeing %s\n",
+               JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
+    }
+#endif
+  free_bytecode_atoms(rt, b->byte_code_buf, b->byte_code_len, TRUE);
+
+  if (b->vardefs) {
+    for (i = 0; i < b->arg_count + b->var_count; i++) {
+      JS_FreeAtomRT(rt, b->vardefs[i].var_name);
+    }
+  }
+  for (i = 0; i < b->cpool_count; i++)
+    JS_FreeValueRT(rt, b->cpool[i]);
+
+  for (i = 0; i < b->closure_var_count; i++) {
+    JSClosureVar* cv = &b->closure_var[i];
+    JS_FreeAtomRT(rt, cv->var_name);
+  }
+  if (b->realm)
+    JS_FreeContext(b->realm);
+
+  JS_FreeAtomRT(rt, b->func_name);
+  if (b->has_debug) {
+    JS_FreeAtomRT(rt, b->debug.filename);
+    js_free_rt(rt, b->debug.pc2line_buf);
+    js_free_rt(rt, b->debug.source);
+  }
+
+  remove_gc_object(&b->header);
+  if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && b->header.ref_count != 0) {
+    list_add_tail(&b->header.link, &rt->gc_zero_ref_count_list);
+  } else {
+    js_free_rt(rt, b);
+  }
+}
+
+void free_bytecode_atoms(JSRuntime* rt, const uint8_t* bc_buf, int bc_len, BOOL use_short_opcodes) {
+  int pos, len, op;
+  JSAtom atom;
+  const JSOpCode* oi;
+
+  pos = 0;
+  while (pos < bc_len) {
+    op = bc_buf[pos];
+    if (use_short_opcodes)
+      oi = &short_opcode_info(op);
+    else
+      oi = &opcode_info[op];
+
+    len = oi->size;
+    switch (oi->fmt) {
+      case OP_FMT_atom:
+      case OP_FMT_atom_u8:
+      case OP_FMT_atom_u16:
+      case OP_FMT_atom_label_u8:
+      case OP_FMT_atom_label_u16:
+        atom = get_u32(bc_buf + pos + 1);
+        JS_FreeAtomRT(rt, atom);
+        break;
+      default:
+        break;
+    }
+    pos += len;
+  }
+}
+
+/*******************************************************************/
+/* binary object writer & reader */
+
+typedef enum BCTagEnum {
+  BC_TAG_NULL = 1,
+  BC_TAG_UNDEFINED,
+  BC_TAG_BOOL_FALSE,
+  BC_TAG_BOOL_TRUE,
+  BC_TAG_INT32,
+  BC_TAG_FLOAT64,
+  BC_TAG_STRING,
+  BC_TAG_OBJECT,
+  BC_TAG_ARRAY,
+  BC_TAG_BIG_INT,
+  BC_TAG_BIG_FLOAT,
+  BC_TAG_BIG_DECIMAL,
+  BC_TAG_TEMPLATE_OBJECT,
+  BC_TAG_FUNCTION_BYTECODE,
+  BC_TAG_MODULE,
+  BC_TAG_TYPED_ARRAY,
+  BC_TAG_ARRAY_BUFFER,
+  BC_TAG_SHARED_ARRAY_BUFFER,
+  BC_TAG_DATE,
+  BC_TAG_OBJECT_VALUE,
+  BC_TAG_OBJECT_REFERENCE,
+} BCTagEnum;
+
+#ifdef CONFIG_BIGNUM
+#define BC_BASE_VERSION 2
+#else
+#define BC_BASE_VERSION 1
+#endif
+#define BC_BE_VERSION 0x40
+#ifdef WORDS_BIGENDIAN
+#define BC_VERSION (BC_BASE_VERSION | BC_BE_VERSION)
+#else
+#define BC_VERSION BC_BASE_VERSION
+#endif
+
+typedef struct BCWriterState {
+  JSContext* ctx;
+  DynBuf dbuf;
+  BOOL byte_swap : 8;
+  BOOL allow_bytecode : 8;
+  BOOL allow_sab : 8;
+  BOOL allow_reference : 8;
+  uint32_t first_atom;
+  uint32_t* atom_to_idx;
+  int atom_to_idx_size;
+  JSAtom* idx_to_atom;
+  int idx_to_atom_count;
+  int idx_to_atom_size;
+  uint8_t** sab_tab;
+  int sab_tab_len;
+  int sab_tab_size;
+  /* list of referenced objects (used if allow_reference = TRUE) */
+  JSObjectList object_list;
+} BCWriterState;
+
+#ifdef DUMP_READ_OBJECT
+static const char* const bc_tag_str[] = {
+    "invalid",           "null",     "undefined",   "false",           "true",       "int32",
+    "float64",           "string",   "object",      "array",           "bigint",     "bigfloat",
+    "bigdecimal",        "template", "function",    "module",          "TypedArray", "ArrayBuffer",
+    "SharedArrayBuffer", "Date",     "ObjectValue", "ObjectReference",
+};
+#endif
+
+static void bc_put_u8(BCWriterState* s, uint8_t v) {
+  dbuf_putc(&s->dbuf, v);
+}
+
+static void bc_put_u16(BCWriterState* s, uint16_t v) {
+  if (s->byte_swap)
+    v = bswap16(v);
+  dbuf_put_u16(&s->dbuf, v);
+}
+
+static __maybe_unused void bc_put_u32(BCWriterState* s, uint32_t v) {
+  if (s->byte_swap)
+    v = bswap32(v);
+  dbuf_put_u32(&s->dbuf, v);
+}
+
+static void bc_put_u64(BCWriterState* s, uint64_t v) {
+  if (s->byte_swap)
+    v = bswap64(v);
+  dbuf_put(&s->dbuf, (uint8_t*)&v, sizeof(v));
+}
+
+static void bc_put_leb128(BCWriterState* s, uint32_t v) {
+  dbuf_put_leb128(&s->dbuf, v);
+}
+
+static void bc_put_sleb128(BCWriterState* s, int32_t v) {
+  dbuf_put_sleb128(&s->dbuf, v);
+}
+
+static void bc_set_flags(uint32_t* pflags, int* pidx, uint32_t val, int n) {
+  *pflags = *pflags | (val << *pidx);
+  *pidx += n;
+}
+
+static int bc_atom_to_idx(BCWriterState* s, uint32_t* pres, JSAtom atom) {
+  uint32_t v;
+
+  if (atom < s->first_atom || __JS_AtomIsTaggedInt(atom)) {
+    *pres = atom;
+    return 0;
+  }
+  atom -= s->first_atom;
+  if (atom < s->atom_to_idx_size && s->atom_to_idx[atom] != 0) {
+    *pres = s->atom_to_idx[atom];
+    return 0;
+  }
+  if (atom >= s->atom_to_idx_size) {
+    int old_size, i;
+    old_size = s->atom_to_idx_size;
+    if (js_resize_array(s->ctx, (void**)&s->atom_to_idx, sizeof(s->atom_to_idx[0]), &s->atom_to_idx_size, atom + 1))
+      return -1;
+    /* XXX: could add a specific js_resize_array() function to do it */
+    for (i = old_size; i < s->atom_to_idx_size; i++)
+      s->atom_to_idx[i] = 0;
+  }
+  if (js_resize_array(s->ctx, (void**)&s->idx_to_atom, sizeof(s->idx_to_atom[0]), &s->idx_to_atom_size,
+                      s->idx_to_atom_count + 1))
+    goto fail;
+
+  v = s->idx_to_atom_count++;
+  s->idx_to_atom[v] = atom + s->first_atom;
+  v += s->first_atom;
+  s->atom_to_idx[atom] = v;
+  *pres = v;
+  return 0;
+fail:
+  *pres = 0;
+  return -1;
+}
+
+static int bc_put_atom(BCWriterState* s, JSAtom atom) {
+  uint32_t v;
+
+  if (__JS_AtomIsTaggedInt(atom)) {
+    v = (__JS_AtomToUInt32(atom) << 1) | 1;
+  } else {
+    if (bc_atom_to_idx(s, &v, atom))
+      return -1;
+    v <<= 1;
+  }
+  bc_put_leb128(s, v);
+  return 0;
+}
+
+static void bc_byte_swap(uint8_t* bc_buf, int bc_len) {
+  int pos, len, op, fmt;
+
+  pos = 0;
+  while (pos < bc_len) {
+    op = bc_buf[pos];
+    len = short_opcode_info(op).size;
+    fmt = short_opcode_info(op).fmt;
+    switch (fmt) {
+      case OP_FMT_u16:
+      case OP_FMT_i16:
+      case OP_FMT_label16:
+      case OP_FMT_npop:
+      case OP_FMT_loc:
+      case OP_FMT_arg:
+      case OP_FMT_var_ref:
+        put_u16(bc_buf + pos + 1, bswap16(get_u16(bc_buf + pos + 1)));
+        break;
+      case OP_FMT_i32:
+      case OP_FMT_u32:
+      case OP_FMT_const:
+      case OP_FMT_label:
+      case OP_FMT_atom:
+      case OP_FMT_atom_u8:
+        put_u32(bc_buf + pos + 1, bswap32(get_u32(bc_buf + pos + 1)));
+        break;
+      case OP_FMT_atom_u16:
+      case OP_FMT_label_u16:
+        put_u32(bc_buf + pos + 1, bswap32(get_u32(bc_buf + pos + 1)));
+        put_u16(bc_buf + pos + 1 + 4, bswap16(get_u16(bc_buf + pos + 1 + 4)));
+        break;
+      case OP_FMT_atom_label_u8:
+      case OP_FMT_atom_label_u16:
+        put_u32(bc_buf + pos + 1, bswap32(get_u32(bc_buf + pos + 1)));
+        put_u32(bc_buf + pos + 1 + 4, bswap32(get_u32(bc_buf + pos + 1 + 4)));
+        if (fmt == OP_FMT_atom_label_u16) {
+          put_u16(bc_buf + pos + 1 + 4 + 4, bswap16(get_u16(bc_buf + pos + 1 + 4 + 4)));
+        }
+        break;
+      case OP_FMT_npop_u16:
+        put_u16(bc_buf + pos + 1, bswap16(get_u16(bc_buf + pos + 1)));
+        put_u16(bc_buf + pos + 1 + 2, bswap16(get_u16(bc_buf + pos + 1 + 2)));
+        break;
+      default:
+        break;
+    }
+    pos += len;
+  }
+}
+
+static int JS_WriteFunctionBytecode(BCWriterState* s, const uint8_t* bc_buf1, int bc_len) {
+  int pos, len, op;
+  JSAtom atom;
+  uint8_t* bc_buf;
+  uint32_t val;
+
+  bc_buf = js_malloc(s->ctx, bc_len);
+  if (!bc_buf)
+    return -1;
+  memcpy(bc_buf, bc_buf1, bc_len);
+
+  pos = 0;
+  while (pos < bc_len) {
+    op = bc_buf[pos];
+    len = short_opcode_info(op).size;
+    switch (short_opcode_info(op).fmt) {
+      case OP_FMT_atom:
+      case OP_FMT_atom_u8:
+      case OP_FMT_atom_u16:
+      case OP_FMT_atom_label_u8:
+      case OP_FMT_atom_label_u16:
+        atom = get_u32(bc_buf + pos + 1);
+        if (bc_atom_to_idx(s, &val, atom))
+          goto fail;
+        put_u32(bc_buf + pos + 1, val);
+        break;
+      default:
+        break;
+    }
+    pos += len;
+  }
+
+  if (s->byte_swap)
+    bc_byte_swap(bc_buf, bc_len);
+
+  dbuf_put(&s->dbuf, bc_buf, bc_len);
+
+  js_free(s->ctx, bc_buf);
+  return 0;
+fail:
+  js_free(s->ctx, bc_buf);
+  return -1;
+}
+
+static void JS_WriteString(BCWriterState* s, JSString* p) {
+  int i;
+  bc_put_leb128(s, ((uint32_t)p->len << 1) | p->is_wide_char);
+  if (p->is_wide_char) {
+    for (i = 0; i < p->len; i++)
+      bc_put_u16(s, p->u.str16[i]);
+  } else {
+    dbuf_put(&s->dbuf, p->u.str8, p->len);
+  }
+}
+
+#ifdef CONFIG_BIGNUM
+static int JS_WriteBigNum(BCWriterState* s, JSValueConst obj) {
+  uint32_t tag, tag1;
+  int64_t e;
+  JSBigFloat* bf = JS_VALUE_GET_PTR(obj);
+  bf_t* a = &bf->num;
+  size_t len, i, n1, j;
+  limb_t v;
+
+  tag = JS_VALUE_GET_TAG(obj);
+  switch (tag) {
+    case JS_TAG_BIG_INT:
+      tag1 = BC_TAG_BIG_INT;
+      break;
+    case JS_TAG_BIG_FLOAT:
+      tag1 = BC_TAG_BIG_FLOAT;
+      break;
+    case JS_TAG_BIG_DECIMAL:
+      tag1 = BC_TAG_BIG_DECIMAL;
+      break;
+    default:
+      abort();
+  }
+  bc_put_u8(s, tag1);
+
+  /* sign + exponent */
+  if (a->expn == BF_EXP_ZERO)
+    e = 0;
+  else if (a->expn == BF_EXP_INF)
+    e = 1;
+  else if (a->expn == BF_EXP_NAN)
+    e = 2;
+  else if (a->expn >= 0)
+    e = a->expn + 3;
+  else
+    e = a->expn;
+  e = (e << 1) | a->sign;
+  if (e < INT32_MIN || e > INT32_MAX) {
+    JS_ThrowInternalError(s->ctx, "bignum exponent is too large");
+    return -1;
+  }
+  bc_put_sleb128(s, e);
+
+  /* mantissa */
+  if (a->len != 0) {
+    if (tag != JS_TAG_BIG_DECIMAL) {
+      i = 0;
+      while (i < a->len && a->tab[i] == 0)
+        i++;
+      assert(i < a->len);
+      v = a->tab[i];
+      n1 = sizeof(limb_t);
+      while ((v & 0xff) == 0) {
+        n1--;
+        v >>= 8;
+      }
+      i++;
+      len = (a->len - i) * sizeof(limb_t) + n1;
+      if (len > INT32_MAX) {
+        JS_ThrowInternalError(s->ctx, "bignum is too large");
+        return -1;
+      }
+      bc_put_leb128(s, len);
+      /* always saved in byte based little endian representation */
+      for (j = 0; j < n1; j++) {
+        dbuf_putc(&s->dbuf, v >> (j * 8));
+      }
+      for (; i < a->len; i++) {
+        limb_t v = a->tab[i];
+#if LIMB_BITS == 32
+#ifdef WORDS_BIGENDIAN
+        v = bswap32(v);
+#endif
+        dbuf_put_u32(&s->dbuf, v);
+#else
+#ifdef WORDS_BIGENDIAN
+        v = bswap64(v);
+#endif
+        dbuf_put_u64(&s->dbuf, v);
+#endif
+      }
+    } else {
+      int bpos, d;
+      uint8_t v8;
+      size_t i0;
+
+      /* little endian BCD */
+      i = 0;
+      while (i < a->len && a->tab[i] == 0)
+        i++;
+      assert(i < a->len);
+      len = a->len * LIMB_DIGITS;
+      v = a->tab[i];
+      j = 0;
+      while ((v % 10) == 0) {
+        j++;
+        v /= 10;
+      }
+      len -= j;
+      assert(len > 0);
+      if (len > INT32_MAX) {
+        JS_ThrowInternalError(s->ctx, "bignum is too large");
+        return -1;
+      }
+      bc_put_leb128(s, len);
+
+      bpos = 0;
+      v8 = 0;
+      i0 = i;
+      for (; i < a->len; i++) {
+        if (i != i0) {
+          v = a->tab[i];
+          j = 0;
+        }
+        for (; j < LIMB_DIGITS; j++) {
+          d = v % 10;
+          v /= 10;
+          if (bpos == 0) {
+            v8 = d;
+            bpos = 1;
+          } else {
+            dbuf_putc(&s->dbuf, v8 | (d << 4));
+            bpos = 0;
+          }
+        }
+      }
+      /* flush the last digit */
+      if (bpos) {
+        dbuf_putc(&s->dbuf, v8);
+      }
+    }
+  }
+  return 0;
+}
+#endif /* CONFIG_BIGNUM */
+
+static int JS_WriteObjectRec(BCWriterState* s, JSValueConst obj);
+
+static int JS_WriteFunctionTag(BCWriterState* s, JSValueConst obj) {
+  JSFunctionBytecode* b = JS_VALUE_GET_PTR(obj);
+  uint32_t flags;
+  int idx, i;
+
+  bc_put_u8(s, BC_TAG_FUNCTION_BYTECODE);
+  flags = idx = 0;
+  bc_set_flags(&flags, &idx, b->has_prototype, 1);
+  bc_set_flags(&flags, &idx, b->has_simple_parameter_list, 1);
+  bc_set_flags(&flags, &idx, b->is_derived_class_constructor, 1);
+  bc_set_flags(&flags, &idx, b->need_home_object, 1);
+  bc_set_flags(&flags, &idx, b->func_kind, 2);
+  bc_set_flags(&flags, &idx, b->new_target_allowed, 1);
+  bc_set_flags(&flags, &idx, b->super_call_allowed, 1);
+  bc_set_flags(&flags, &idx, b->super_allowed, 1);
+  bc_set_flags(&flags, &idx, b->arguments_allowed, 1);
+  bc_set_flags(&flags, &idx, b->has_debug, 1);
+  bc_set_flags(&flags, &idx, b->backtrace_barrier, 1);
+  assert(idx <= 16);
+  bc_put_u16(s, flags);
+  bc_put_u8(s, b->js_mode);
+  bc_put_atom(s, b->func_name);
+
+  bc_put_leb128(s, b->arg_count);
+  bc_put_leb128(s, b->var_count);
+  bc_put_leb128(s, b->defined_arg_count);
+  bc_put_leb128(s, b->stack_size);
+  bc_put_leb128(s, b->closure_var_count);
+  bc_put_leb128(s, b->cpool_count);
+  bc_put_leb128(s, b->byte_code_len);
+  if (b->vardefs) {
+    /* XXX: this field is redundant */
+    bc_put_leb128(s, b->arg_count + b->var_count);
+    for (i = 0; i < b->arg_count + b->var_count; i++) {
+      JSVarDef* vd = &b->vardefs[i];
+      bc_put_atom(s, vd->var_name);
+      bc_put_leb128(s, vd->scope_level);
+      bc_put_leb128(s, vd->scope_next + 1);
+      flags = idx = 0;
+      bc_set_flags(&flags, &idx, vd->var_kind, 4);
+      bc_set_flags(&flags, &idx, vd->is_const, 1);
+      bc_set_flags(&flags, &idx, vd->is_lexical, 1);
+      bc_set_flags(&flags, &idx, vd->is_captured, 1);
+      assert(idx <= 8);
+      bc_put_u8(s, flags);
+    }
+  } else {
+    bc_put_leb128(s, 0);
+  }
+
+  for (i = 0; i < b->closure_var_count; i++) {
+    JSClosureVar* cv = &b->closure_var[i];
+    bc_put_atom(s, cv->var_name);
+    bc_put_leb128(s, cv->var_idx);
+    flags = idx = 0;
+    bc_set_flags(&flags, &idx, cv->is_local, 1);
+    bc_set_flags(&flags, &idx, cv->is_arg, 1);
+    bc_set_flags(&flags, &idx, cv->is_const, 1);
+    bc_set_flags(&flags, &idx, cv->is_lexical, 1);
+    bc_set_flags(&flags, &idx, cv->var_kind, 4);
+    assert(idx <= 8);
+    bc_put_u8(s, flags);
+  }
+
+  if (JS_WriteFunctionBytecode(s, b->byte_code_buf, b->byte_code_len))
+    goto fail;
+
+  if (b->has_debug) {
+    bc_put_atom(s, b->debug.filename);
+    bc_put_leb128(s, b->debug.line_num);
+    bc_put_leb128(s, b->debug.pc2line_len);
+    dbuf_put(&s->dbuf, b->debug.pc2line_buf, b->debug.pc2line_len);
+  }
+
+  for (i = 0; i < b->cpool_count; i++) {
+    if (JS_WriteObjectRec(s, b->cpool[i]))
+      goto fail;
+  }
+  return 0;
+fail:
+  return -1;
+}
+
+static int JS_WriteModule(BCWriterState* s, JSValueConst obj) {
+  JSModuleDef* m = JS_VALUE_GET_PTR(obj);
+  int i;
+
+  bc_put_u8(s, BC_TAG_MODULE);
+  bc_put_atom(s, m->module_name);
+
+  bc_put_leb128(s, m->req_module_entries_count);
+  for (i = 0; i < m->req_module_entries_count; i++) {
+    JSReqModuleEntry* rme = &m->req_module_entries[i];
+    bc_put_atom(s, rme->module_name);
+  }
+
+  bc_put_leb128(s, m->export_entries_count);
+  for (i = 0; i < m->export_entries_count; i++) {
+    JSExportEntry* me = &m->export_entries[i];
+    bc_put_u8(s, me->export_type);
+    if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
+      bc_put_leb128(s, me->u.local.var_idx);
+    } else {
+      bc_put_leb128(s, me->u.req_module_idx);
+      bc_put_atom(s, me->local_name);
+    }
+    bc_put_atom(s, me->export_name);
+  }
+
+  bc_put_leb128(s, m->star_export_entries_count);
+  for (i = 0; i < m->star_export_entries_count; i++) {
+    JSStarExportEntry* se = &m->star_export_entries[i];
+    bc_put_leb128(s, se->req_module_idx);
+  }
+
+  bc_put_leb128(s, m->import_entries_count);
+  for (i = 0; i < m->import_entries_count; i++) {
+    JSImportEntry* mi = &m->import_entries[i];
+    bc_put_leb128(s, mi->var_idx);
+    bc_put_atom(s, mi->import_name);
+    bc_put_leb128(s, mi->req_module_idx);
+  }
+
+  if (JS_WriteObjectRec(s, m->func_obj))
+    goto fail;
+  return 0;
+fail:
+  return -1;
+}
+
+static int JS_WriteArray(BCWriterState* s, JSValueConst obj) {
+  JSObject* p = JS_VALUE_GET_OBJ(obj);
+  uint32_t i, len;
+  JSValue val;
+  int ret;
+  BOOL is_template;
+
+  if (s->allow_bytecode && !p->extensible) {
+    /* not extensible array: we consider it is a
+       template when we are saving bytecode */
+    bc_put_u8(s, BC_TAG_TEMPLATE_OBJECT);
+    is_template = TRUE;
+  } else {
+    bc_put_u8(s, BC_TAG_ARRAY);
+    is_template = FALSE;
+  }
+  if (js_get_length32(s->ctx, &len, obj))
+    goto fail1;
+  bc_put_leb128(s, len);
+  for (i = 0; i < len; i++) {
+    val = JS_GetPropertyUint32(s->ctx, obj, i);
+    if (JS_IsException(val))
+      goto fail1;
+    ret = JS_WriteObjectRec(s, val);
+    JS_FreeValue(s->ctx, val);
+    if (ret)
+      goto fail1;
+  }
+  if (is_template) {
+    val = JS_GetProperty(s->ctx, obj, JS_ATOM_raw);
+    if (JS_IsException(val))
+      goto fail1;
+    ret = JS_WriteObjectRec(s, val);
+    JS_FreeValue(s->ctx, val);
+    if (ret)
+      goto fail1;
+  }
+  return 0;
+fail1:
+  return -1;
+}
+
+static int JS_WriteObjectTag(BCWriterState* s, JSValueConst obj) {
+  JSObject* p = JS_VALUE_GET_OBJ(obj);
+  uint32_t i, prop_count;
+  JSShape* sh;
+  JSShapeProperty* pr;
+  int pass;
+  JSAtom atom;
+
+  bc_put_u8(s, BC_TAG_OBJECT);
+  prop_count = 0;
+  sh = p->shape;
+  for (pass = 0; pass < 2; pass++) {
+    if (pass == 1)
+      bc_put_leb128(s, prop_count);
+    for (i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {
+      atom = pr->atom;
+      if (atom != JS_ATOM_NULL && JS_AtomIsString(s->ctx, atom) && (pr->flags & JS_PROP_ENUMERABLE)) {
+        if (pr->flags & JS_PROP_TMASK) {
+          JS_ThrowTypeError(s->ctx, "only value properties are supported");
+          goto fail;
+        }
+        if (pass == 0) {
+          prop_count++;
+        } else {
+          bc_put_atom(s, atom);
+          if (JS_WriteObjectRec(s, p->prop[i].u.value))
+            goto fail;
+        }
+      }
+    }
+  }
+  return 0;
+fail:
+  return -1;
+}
+
+static int JS_WriteTypedArray(BCWriterState* s, JSValueConst obj) {
+  JSObject* p = JS_VALUE_GET_OBJ(obj);
+  JSTypedArray* ta = p->u.typed_array;
+
+  bc_put_u8(s, BC_TAG_TYPED_ARRAY);
+  bc_put_u8(s, p->class_id - JS_CLASS_UINT8C_ARRAY);
+  bc_put_leb128(s, p->u.array.count);
+  bc_put_leb128(s, ta->offset);
+  if (JS_WriteObjectRec(s, JS_MKPTR(JS_TAG_OBJECT, ta->buffer)))
+    return -1;
+  return 0;
+}
+
+static int JS_WriteArrayBuffer(BCWriterState* s, JSValueConst obj) {
+  JSObject* p = JS_VALUE_GET_OBJ(obj);
+  JSArrayBuffer* abuf = p->u.array_buffer;
+  if (abuf->detached) {
+    JS_ThrowTypeErrorDetachedArrayBuffer(s->ctx);
+    return -1;
+  }
+  bc_put_u8(s, BC_TAG_ARRAY_BUFFER);
+  bc_put_leb128(s, abuf->byte_length);
+  dbuf_put(&s->dbuf, abuf->data, abuf->byte_length);
+  return 0;
+}
+
+static int JS_WriteSharedArrayBuffer(BCWriterState* s, JSValueConst obj) {
+  JSObject* p = JS_VALUE_GET_OBJ(obj);
+  JSArrayBuffer* abuf = p->u.array_buffer;
+  assert(!abuf->detached); /* SharedArrayBuffer are never detached */
+  bc_put_u8(s, BC_TAG_SHARED_ARRAY_BUFFER);
+  bc_put_leb128(s, abuf->byte_length);
+  bc_put_u64(s, (uintptr_t)abuf->data);
+  if (js_resize_array(s->ctx, (void**)&s->sab_tab, sizeof(s->sab_tab[0]), &s->sab_tab_size, s->sab_tab_len + 1))
+    return -1;
+  /* keep the SAB pointer so that the user can clone it or free it */
+  s->sab_tab[s->sab_tab_len++] = abuf->data;
+  return 0;
+}
+
+static int JS_WriteObjectRec(BCWriterState* s, JSValueConst obj) {
+  uint32_t tag;
+
+  if (js_check_stack_overflow(s->ctx->rt, 0)) {
+    JS_ThrowStackOverflow(s->ctx);
+    return -1;
+  }
+
+  tag = JS_VALUE_GET_NORM_TAG(obj);
+  switch (tag) {
+    case JS_TAG_NULL:
+      bc_put_u8(s, BC_TAG_NULL);
+      break;
+    case JS_TAG_UNDEFINED:
+      bc_put_u8(s, BC_TAG_UNDEFINED);
+      break;
+    case JS_TAG_BOOL:
+      bc_put_u8(s, BC_TAG_BOOL_FALSE + JS_VALUE_GET_INT(obj));
+      break;
+    case JS_TAG_INT:
+      bc_put_u8(s, BC_TAG_INT32);
+      bc_put_sleb128(s, JS_VALUE_GET_INT(obj));
+      break;
+    case JS_TAG_FLOAT64: {
+      JSFloat64Union u;
+      bc_put_u8(s, BC_TAG_FLOAT64);
+      u.d = JS_VALUE_GET_FLOAT64(obj);
+      bc_put_u64(s, u.u64);
+    } break;
+    case JS_TAG_STRING: {
+      JSString* p = JS_VALUE_GET_STRING(obj);
+      bc_put_u8(s, BC_TAG_STRING);
+      JS_WriteString(s, p);
+    } break;
+    case JS_TAG_FUNCTION_BYTECODE:
+      if (!s->allow_bytecode)
+        goto invalid_tag;
+      if (JS_WriteFunctionTag(s, obj))
+        goto fail;
+      break;
+    case JS_TAG_MODULE:
+      if (!s->allow_bytecode)
+        goto invalid_tag;
+      if (JS_WriteModule(s, obj))
+        goto fail;
+      break;
+    case JS_TAG_OBJECT: {
+      JSObject* p = JS_VALUE_GET_OBJ(obj);
+      int ret, idx;
+
+      if (s->allow_reference) {
+        idx = js_object_list_find(s->ctx, &s->object_list, p);
+        if (idx >= 0) {
+          bc_put_u8(s, BC_TAG_OBJECT_REFERENCE);
+          bc_put_leb128(s, idx);
+          break;
+        } else {
+          if (js_object_list_add(s->ctx, &s->object_list, p))
+            goto fail;
+        }
+      } else {
+        if (p->tmp_mark) {
+          JS_ThrowTypeError(s->ctx, "circular reference");
+          goto fail;
+        }
+        p->tmp_mark = 1;
+      }
+      switch (p->class_id) {
+        case JS_CLASS_ARRAY:
+          ret = JS_WriteArray(s, obj);
+          break;
+        case JS_CLASS_OBJECT:
+          ret = JS_WriteObjectTag(s, obj);
+          break;
+        case JS_CLASS_ARRAY_BUFFER:
+          ret = JS_WriteArrayBuffer(s, obj);
+          break;
+        case JS_CLASS_SHARED_ARRAY_BUFFER:
+          if (!s->allow_sab)
+            goto invalid_tag;
+          ret = JS_WriteSharedArrayBuffer(s, obj);
+          break;
+        case JS_CLASS_DATE:
+          bc_put_u8(s, BC_TAG_DATE);
+          ret = JS_WriteObjectRec(s, p->u.object_data);
+          break;
+        case JS_CLASS_NUMBER:
+        case JS_CLASS_STRING:
+        case JS_CLASS_BOOLEAN:
+#ifdef CONFIG_BIGNUM
+        case JS_CLASS_BIG_INT:
+        case JS_CLASS_BIG_FLOAT:
+        case JS_CLASS_BIG_DECIMAL:
+#endif
+          bc_put_u8(s, BC_TAG_OBJECT_VALUE);
+          ret = JS_WriteObjectRec(s, p->u.object_data);
+          break;
+        default:
+          if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
+            ret = JS_WriteTypedArray(s, obj);
+          } else {
+            JS_ThrowTypeError(s->ctx, "unsupported object class");
+            ret = -1;
+          }
+          break;
+      }
+      p->tmp_mark = 0;
+      if (ret)
+        goto fail;
+    } break;
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_INT:
+    case JS_TAG_BIG_FLOAT:
+    case JS_TAG_BIG_DECIMAL:
+      if (JS_WriteBigNum(s, obj))
+        goto fail;
+      break;
+#endif
+    default:
+    invalid_tag:
+      JS_ThrowInternalError(s->ctx, "unsupported tag (%d)", tag);
+      goto fail;
+  }
+  return 0;
+
+fail:
+  return -1;
+}
+
+/* create the atom table */
+static int JS_WriteObjectAtoms(BCWriterState* s) {
+  JSRuntime* rt = s->ctx->rt;
+  DynBuf dbuf1;
+  int i, atoms_size;
+  uint8_t version;
+
+  dbuf1 = s->dbuf;
+  js_dbuf_init(s->ctx, &s->dbuf);
+
+  version = BC_VERSION;
+  if (s->byte_swap)
+    version ^= BC_BE_VERSION;
+  bc_put_u8(s, version);
+
+  bc_put_leb128(s, s->idx_to_atom_count);
+  for (i = 0; i < s->idx_to_atom_count; i++) {
+    JSAtomStruct* p = rt->atom_array[s->idx_to_atom[i]];
+    JS_WriteString(s, p);
+  }
+  /* XXX: should check for OOM in above phase */
+
+  /* move the atoms at the start */
+  /* XXX: could just append dbuf1 data, but it uses more memory if
+     dbuf1 is larger than dbuf */
+  atoms_size = s->dbuf.size;
+  if (dbuf_realloc(&dbuf1, dbuf1.size + atoms_size))
+    goto fail;
+  memmove(dbuf1.buf + atoms_size, dbuf1.buf, dbuf1.size);
+  memcpy(dbuf1.buf, s->dbuf.buf, atoms_size);
+  dbuf1.size += atoms_size;
+  dbuf_free(&s->dbuf);
+  s->dbuf = dbuf1;
+  return 0;
+fail:
+  dbuf_free(&dbuf1);
+  return -1;
+}
+
+uint8_t* JS_WriteObject2(JSContext* ctx,
+                         size_t* psize,
+                         JSValueConst obj,
+                         int flags,
+                         uint8_t*** psab_tab,
+                         size_t* psab_tab_len) {
+  BCWriterState ss, *s = &ss;
+
+  memset(s, 0, sizeof(*s));
+  s->ctx = ctx;
+  /* XXX: byte swapped output is untested */
+  s->byte_swap = ((flags & JS_WRITE_OBJ_BSWAP) != 0);
+  s->allow_bytecode = ((flags & JS_WRITE_OBJ_BYTECODE) != 0);
+  s->allow_sab = ((flags & JS_WRITE_OBJ_SAB) != 0);
+  s->allow_reference = ((flags & JS_WRITE_OBJ_REFERENCE) != 0);
+  /* XXX: could use a different version when bytecode is included */
+  if (s->allow_bytecode)
+    s->first_atom = JS_ATOM_END;
+  else
+    s->first_atom = 1;
+  js_dbuf_init(ctx, &s->dbuf);
+  js_object_list_init(&s->object_list);
+
+  if (JS_WriteObjectRec(s, obj))
+    goto fail;
+  if (JS_WriteObjectAtoms(s))
+    goto fail;
+  js_object_list_end(ctx, &s->object_list);
+  js_free(ctx, s->atom_to_idx);
+  js_free(ctx, s->idx_to_atom);
+  *psize = s->dbuf.size;
+  if (psab_tab)
+    *psab_tab = s->sab_tab;
+  if (psab_tab_len)
+    *psab_tab_len = s->sab_tab_len;
+  return s->dbuf.buf;
+fail:
+  js_object_list_end(ctx, &s->object_list);
+  js_free(ctx, s->atom_to_idx);
+  js_free(ctx, s->idx_to_atom);
+  dbuf_free(&s->dbuf);
+  *psize = 0;
+  if (psab_tab)
+    *psab_tab = NULL;
+  if (psab_tab_len)
+    *psab_tab_len = 0;
+  return NULL;
+}
+
+uint8_t* JS_WriteObject(JSContext* ctx, size_t* psize, JSValueConst obj, int flags) {
+  return JS_WriteObject2(ctx, psize, obj, flags, NULL, NULL);
+}
+
+typedef struct BCReaderState {
+  JSContext* ctx;
+  const uint8_t *buf_start, *ptr, *buf_end;
+  uint32_t first_atom;
+  uint32_t idx_to_atom_count;
+  JSAtom* idx_to_atom;
+  int error_state;
+  BOOL allow_sab : 8;
+  BOOL allow_bytecode : 8;
+  BOOL is_rom_data : 8;
+  BOOL allow_reference : 8;
+  /* object references */
+  JSObject** objects;
+  int objects_count;
+  int objects_size;
+
+#ifdef DUMP_READ_OBJECT
+  const uint8_t* ptr_last;
+  int level;
+#endif
+} BCReaderState;
+
+#ifdef DUMP_READ_OBJECT
+static void __attribute__((format(printf, 2, 3))) bc_read_trace(BCReaderState* s, const char* fmt, ...) {
+  va_list ap;
+  int i, n, n0;
+
+  if (!s->ptr_last)
+    s->ptr_last = s->buf_start;
+
+  n = n0 = 0;
+  if (s->ptr > s->ptr_last || s->ptr == s->buf_start) {
+    n0 = printf("%04x: ", (int)(s->ptr_last - s->buf_start));
+    n += n0;
+  }
+  for (i = 0; s->ptr_last < s->ptr; i++) {
+    if ((i & 7) == 0 && i > 0) {
+      printf("\n%*s", n0, "");
+      n = n0;
+    }
+    n += printf(" %02x", *s->ptr_last++);
+  }
+  if (*fmt == '}')
+    s->level--;
+  if (n < 32 + s->level * 2) {
+    printf("%*s", 32 + s->level * 2 - n, "");
+  }
+  va_start(ap, fmt);
+  vfprintf(stdout, fmt, ap);
+  va_end(ap);
+  if (strchr(fmt, '{'))
+    s->level++;
+}
+#else
+#define bc_read_trace(...)
+#endif
+
+static int bc_read_error_end(BCReaderState* s) {
+  if (!s->error_state) {
+    JS_ThrowSyntaxError(s->ctx, "read after the end of the buffer");
+  }
+  return s->error_state = -1;
+}
+
+static int bc_get_u8(BCReaderState* s, uint8_t* pval) {
+  if (unlikely(s->buf_end - s->ptr < 1)) {
+    *pval = 0; /* avoid warning */
+    return bc_read_error_end(s);
+  }
+  *pval = *s->ptr++;
+  return 0;
+}
+
+static int bc_get_u16(BCReaderState* s, uint16_t* pval) {
+  if (unlikely(s->buf_end - s->ptr < 2)) {
+    *pval = 0; /* avoid warning */
+    return bc_read_error_end(s);
+  }
+  *pval = get_u16(s->ptr);
+  s->ptr += 2;
+  return 0;
+}
+
+static __maybe_unused int bc_get_u32(BCReaderState* s, uint32_t* pval) {
+  if (unlikely(s->buf_end - s->ptr < 4)) {
+    *pval = 0; /* avoid warning */
+    return bc_read_error_end(s);
+  }
+  *pval = get_u32(s->ptr);
+  s->ptr += 4;
+  return 0;
+}
+
+static int bc_get_u64(BCReaderState* s, uint64_t* pval) {
+  if (unlikely(s->buf_end - s->ptr < 8)) {
+    *pval = 0; /* avoid warning */
+    return bc_read_error_end(s);
+  }
+  *pval = get_u64(s->ptr);
+  s->ptr += 8;
+  return 0;
+}
+
+static int bc_get_leb128(BCReaderState* s, uint32_t* pval) {
+  int ret;
+  ret = get_leb128(pval, s->ptr, s->buf_end);
+  if (unlikely(ret < 0))
+    return bc_read_error_end(s);
+  s->ptr += ret;
+  return 0;
+}
+
+static int bc_get_sleb128(BCReaderState* s, int32_t* pval) {
+  int ret;
+  ret = get_sleb128(pval, s->ptr, s->buf_end);
+  if (unlikely(ret < 0))
+    return bc_read_error_end(s);
+  s->ptr += ret;
+  return 0;
+}
+
+/* XXX: used to read an `int` with a positive value */
+static int bc_get_leb128_int(BCReaderState* s, int* pval) {
+  return bc_get_leb128(s, (uint32_t*)pval);
+}
+
+static int bc_get_leb128_u16(BCReaderState* s, uint16_t* pval) {
+  uint32_t val;
+  if (bc_get_leb128(s, &val)) {
+    *pval = 0;
+    return -1;
+  }
+  *pval = val;
+  return 0;
+}
+
+static int bc_get_buf(BCReaderState* s, uint8_t* buf, uint32_t buf_len) {
+  if (buf_len != 0) {
+    if (unlikely(!buf || s->buf_end - s->ptr < buf_len))
+      return bc_read_error_end(s);
+    memcpy(buf, s->ptr, buf_len);
+    s->ptr += buf_len;
+  }
+  return 0;
+}
+
+static int bc_idx_to_atom(BCReaderState* s, JSAtom* patom, uint32_t idx) {
+  JSAtom atom;
+
+  if (__JS_AtomIsTaggedInt(idx)) {
+    atom = idx;
+  } else if (idx < s->first_atom) {
+    atom = JS_DupAtom(s->ctx, idx);
+  } else {
+    idx -= s->first_atom;
+    if (idx >= s->idx_to_atom_count) {
+      JS_ThrowSyntaxError(s->ctx, "invalid atom index (pos=%u)", (unsigned int)(s->ptr - s->buf_start));
+      *patom = JS_ATOM_NULL;
+      return s->error_state = -1;
+    }
+    atom = JS_DupAtom(s->ctx, s->idx_to_atom[idx]);
+  }
+  *patom = atom;
+  return 0;
+}
+
+static int bc_get_atom(BCReaderState* s, JSAtom* patom) {
+  uint32_t v;
+  if (bc_get_leb128(s, &v))
+    return -1;
+  if (v & 1) {
+    *patom = __JS_AtomFromUInt32(v >> 1);
+    return 0;
+  } else {
+    return bc_idx_to_atom(s, patom, v >> 1);
+  }
+}
+
+static JSString* JS_ReadString(BCReaderState* s) {
+  uint32_t len;
+  size_t size;
+  BOOL is_wide_char;
+  JSString* p;
+
+  if (bc_get_leb128(s, &len))
+    return NULL;
+  is_wide_char = len & 1;
+  len >>= 1;
+  p = js_alloc_string(s->ctx, len, is_wide_char);
+  if (!p) {
+    s->error_state = -1;
+    return NULL;
+  }
+  size = (size_t)len << is_wide_char;
+  if ((s->buf_end - s->ptr) < size) {
+    bc_read_error_end(s);
+    js_free_string(s->ctx->rt, p);
+    return NULL;
+  }
+  memcpy(p->u.str8, s->ptr, size);
+  s->ptr += size;
+  if (!is_wide_char) {
+    p->u.str8[size] = '\0'; /* add the trailing zero for 8 bit strings */
+  }
+#ifdef DUMP_READ_OBJECT
+  JS_DumpString(s->ctx->rt, p);
+  printf("\n");
+#endif
+  return p;
+}
+
+static uint32_t bc_get_flags(uint32_t flags, int* pidx, int n) {
+  uint32_t val;
+  /* XXX: this does not work for n == 32 */
+  val = (flags >> *pidx) & ((1U << n) - 1);
+  *pidx += n;
+  return val;
+}
+
+static int JS_ReadFunctionBytecode(BCReaderState* s, JSFunctionBytecode* b, int byte_code_offset, uint32_t bc_len) {
+  uint8_t* bc_buf;
+  int pos, len, op;
+  JSAtom atom;
+  uint32_t idx;
+
+  if (s->is_rom_data) {
+    /* directly use the input buffer */
+    if (unlikely(s->buf_end - s->ptr < bc_len))
+      return bc_read_error_end(s);
+    bc_buf = (uint8_t*)s->ptr;
+    s->ptr += bc_len;
+  } else {
+    bc_buf = (void*)((uint8_t*)b + byte_code_offset);
+    if (bc_get_buf(s, bc_buf, bc_len))
+      return -1;
+  }
+  b->byte_code_buf = bc_buf;
+
+  pos = 0;
+  while (pos < bc_len) {
+    op = bc_buf[pos];
+    len = short_opcode_info(op).size;
+    switch (short_opcode_info(op).fmt) {
+      case OP_FMT_atom:
+      case OP_FMT_atom_u8:
+      case OP_FMT_atom_u16:
+      case OP_FMT_atom_label_u8:
+      case OP_FMT_atom_label_u16:
+        idx = get_u32(bc_buf + pos + 1);
+        if (s->is_rom_data) {
+          /* just increment the reference count of the atom */
+          JS_DupAtom(s->ctx, (JSAtom)idx);
+        } else {
+          if (bc_idx_to_atom(s, &atom, idx)) {
+            /* Note: the atoms will be freed up to this position */
+            b->byte_code_len = pos;
+            return -1;
+          }
+          put_u32(bc_buf + pos + 1, atom);
+#ifdef DUMP_READ_OBJECT
+          bc_read_trace(s, "at %d, fixup atom: ", pos + 1);
+          print_atom(s->ctx, atom);
+          printf("\n");
+#endif
+        }
+        break;
+      default:
+        break;
+    }
+    pos += len;
+  }
+  return 0;
+}
+
+#ifdef CONFIG_BIGNUM
+static JSValue JS_ReadBigNum(BCReaderState* s, int tag) {
+  JSValue obj = JS_UNDEFINED;
+  uint8_t v8;
+  int32_t e;
+  uint32_t len;
+  limb_t l, i, n, j;
+  JSBigFloat* p;
+  limb_t v;
+  bf_t* a;
+  int bpos, d;
+
+  p = js_new_bf(s->ctx);
+  if (!p)
+    goto fail;
+  switch (tag) {
+    case BC_TAG_BIG_INT:
+      obj = JS_MKPTR(JS_TAG_BIG_INT, p);
+      break;
+    case BC_TAG_BIG_FLOAT:
+      obj = JS_MKPTR(JS_TAG_BIG_FLOAT, p);
+      break;
+    case BC_TAG_BIG_DECIMAL:
+      obj = JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
+      break;
+    default:
+      abort();
+  }
+
+  /* sign + exponent */
+  if (bc_get_sleb128(s, &e))
+    goto fail;
+
+  a = &p->num;
+  a->sign = e & 1;
+  e >>= 1;
+  if (e == 0)
+    a->expn = BF_EXP_ZERO;
+  else if (e == 1)
+    a->expn = BF_EXP_INF;
+  else if (e == 2)
+    a->expn = BF_EXP_NAN;
+  else if (e >= 3)
+    a->expn = e - 3;
+  else
+    a->expn = e;
+
+  /* mantissa */
+  if (a->expn != BF_EXP_ZERO && a->expn != BF_EXP_INF && a->expn != BF_EXP_NAN) {
+    if (bc_get_leb128(s, &len))
+      goto fail;
+    bc_read_trace(s, "len=%" PRId64 "\n", (int64_t)len);
+    if (len == 0) {
+      JS_ThrowInternalError(s->ctx, "invalid bignum length");
+      goto fail;
+    }
+    if (tag != BC_TAG_BIG_DECIMAL)
+      l = (len + sizeof(limb_t) - 1) / sizeof(limb_t);
+    else
+      l = (len + LIMB_DIGITS - 1) / LIMB_DIGITS;
+    if (bf_resize(a, l)) {
+      JS_ThrowOutOfMemory(s->ctx);
+      goto fail;
+    }
+    if (tag != BC_TAG_BIG_DECIMAL) {
+      n = len & (sizeof(limb_t) - 1);
+      if (n != 0) {
+        v = 0;
+        for (i = 0; i < n; i++) {
+          if (bc_get_u8(s, &v8))
+            goto fail;
+          v |= (limb_t)v8 << ((sizeof(limb_t) - n + i) * 8);
+        }
+        a->tab[0] = v;
+        i = 1;
+      } else {
+        i = 0;
+      }
+      for (; i < l; i++) {
+#if LIMB_BITS == 32
+        if (bc_get_u32(s, &v))
+          goto fail;
+#ifdef WORDS_BIGENDIAN
+        v = bswap32(v);
+#endif
+#else
+        if (bc_get_u64(s, &v))
+          goto fail;
+#ifdef WORDS_BIGENDIAN
+        v = bswap64(v);
+#endif
+#endif
+        a->tab[i] = v;
+      }
+    } else {
+      bpos = 0;
+      for (i = 0; i < l; i++) {
+        if (i == 0 && (n = len % LIMB_DIGITS) != 0) {
+          j = LIMB_DIGITS - n;
+        } else {
+          j = 0;
+        }
+        v = 0;
+        for (; j < LIMB_DIGITS; j++) {
+          if (bpos == 0) {
+            if (bc_get_u8(s, &v8))
+              goto fail;
+            d = v8 & 0xf;
+            bpos = 1;
+          } else {
+            d = v8 >> 4;
+            bpos = 0;
+          }
+          if (d >= 10) {
+            JS_ThrowInternalError(s->ctx, "invalid digit");
+            goto fail;
+          }
+          v += mp_pow_dec[j] * d;
+        }
+        a->tab[i] = v;
+      }
+    }
+  }
+  bc_read_trace(s, "}\n");
+  return obj;
+fail:
+  JS_FreeValue(s->ctx, obj);
+  return JS_EXCEPTION;
+}
+#endif /* CONFIG_BIGNUM */
+
+static JSValue JS_ReadObjectRec(BCReaderState* s);
+
+static int BC_add_object_ref1(BCReaderState* s, JSObject* p) {
+  if (s->allow_reference) {
+    if (js_resize_array(s->ctx, (void*)&s->objects, sizeof(s->objects[0]), &s->objects_size, s->objects_count + 1))
+      return -1;
+    s->objects[s->objects_count++] = p;
+  }
+  return 0;
+}
+
+static int BC_add_object_ref(BCReaderState* s, JSValueConst obj) {
+  return BC_add_object_ref1(s, JS_VALUE_GET_OBJ(obj));
+}
+
+static JSValue JS_ReadFunctionTag(BCReaderState* s) {
+  JSContext* ctx = s->ctx;
+  JSFunctionBytecode bc, *b;
+  JSValue obj = JS_UNDEFINED;
+  uint16_t v16;
+  uint8_t v8;
+  int idx, i, local_count;
+  int function_size, cpool_offset, byte_code_offset;
+  int closure_var_offset, vardefs_offset;
+
+  memset(&bc, 0, sizeof(bc));
+  bc.header.ref_count = 1;
+  // bc.gc_header.mark = 0;
+
+  if (bc_get_u16(s, &v16))
+    goto fail;
+  idx = 0;
+  bc.has_prototype = bc_get_flags(v16, &idx, 1);
+  bc.has_simple_parameter_list = bc_get_flags(v16, &idx, 1);
+  bc.is_derived_class_constructor = bc_get_flags(v16, &idx, 1);
+  bc.need_home_object = bc_get_flags(v16, &idx, 1);
+  bc.func_kind = bc_get_flags(v16, &idx, 2);
+  bc.new_target_allowed = bc_get_flags(v16, &idx, 1);
+  bc.super_call_allowed = bc_get_flags(v16, &idx, 1);
+  bc.super_allowed = bc_get_flags(v16, &idx, 1);
+  bc.arguments_allowed = bc_get_flags(v16, &idx, 1);
+  bc.has_debug = bc_get_flags(v16, &idx, 1);
+  bc.backtrace_barrier = bc_get_flags(v16, &idx, 1);
+  bc.read_only_bytecode = s->is_rom_data;
+  if (bc_get_u8(s, &v8))
+    goto fail;
+  bc.js_mode = v8;
+  if (bc_get_atom(s, &bc.func_name))  //@ atom leak if failure
+    goto fail;
+  if (bc_get_leb128_u16(s, &bc.arg_count))
+    goto fail;
+  if (bc_get_leb128_u16(s, &bc.var_count))
+    goto fail;
+  if (bc_get_leb128_u16(s, &bc.defined_arg_count))
+    goto fail;
+  if (bc_get_leb128_u16(s, &bc.stack_size))
+    goto fail;
+  if (bc_get_leb128_int(s, &bc.closure_var_count))
+    goto fail;
+  if (bc_get_leb128_int(s, &bc.cpool_count))
+    goto fail;
+  if (bc_get_leb128_int(s, &bc.byte_code_len))
+    goto fail;
+  if (bc_get_leb128_int(s, &local_count))
+    goto fail;
+
+  if (bc.has_debug) {
+    function_size = sizeof(*b);
+  } else {
+    function_size = offsetof(JSFunctionBytecode, debug);
+  }
+  cpool_offset = function_size;
+  function_size += bc.cpool_count * sizeof(*bc.cpool);
+  vardefs_offset = function_size;
+  function_size += local_count * sizeof(*bc.vardefs);
+  closure_var_offset = function_size;
+  function_size += bc.closure_var_count * sizeof(*bc.closure_var);
+  byte_code_offset = function_size;
+  if (!bc.read_only_bytecode) {
+    function_size += bc.byte_code_len;
+  }
+
+  b = js_mallocz(ctx, function_size);
+  if (!b)
+    return JS_EXCEPTION;
+
+  memcpy(b, &bc, offsetof(JSFunctionBytecode, debug));
+  b->header.ref_count = 1;
+  if (local_count != 0) {
+    b->vardefs = (void*)((uint8_t*)b + vardefs_offset);
+  }
+  if (b->closure_var_count != 0) {
+    b->closure_var = (void*)((uint8_t*)b + closure_var_offset);
+  }
+  if (b->cpool_count != 0) {
+    b->cpool = (void*)((uint8_t*)b + cpool_offset);
+  }
+
+  add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
+
+  obj = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);
+
+#ifdef DUMP_READ_OBJECT
+  bc_read_trace(s, "name: ");
+  print_atom(s->ctx, b->func_name);
+  printf("\n");
+#endif
+  bc_read_trace(s, "args=%d vars=%d defargs=%d closures=%d cpool=%d\n", b->arg_count, b->var_count,
+                b->defined_arg_count, b->closure_var_count, b->cpool_count);
+  bc_read_trace(s, "stack=%d bclen=%d locals=%d\n", b->stack_size, b->byte_code_len, local_count);
+
+  if (local_count != 0) {
+    bc_read_trace(s, "vars {\n");
+    for (i = 0; i < local_count; i++) {
+      JSVarDef* vd = &b->vardefs[i];
+      if (bc_get_atom(s, &vd->var_name))
+        goto fail;
+      if (bc_get_leb128_int(s, &vd->scope_level))
+        goto fail;
+      if (bc_get_leb128_int(s, &vd->scope_next))
+        goto fail;
+      vd->scope_next--;
+      if (bc_get_u8(s, &v8))
+        goto fail;
+      idx = 0;
+      vd->var_kind = bc_get_flags(v8, &idx, 4);
+      vd->is_const = bc_get_flags(v8, &idx, 1);
+      vd->is_lexical = bc_get_flags(v8, &idx, 1);
+      vd->is_captured = bc_get_flags(v8, &idx, 1);
+#ifdef DUMP_READ_OBJECT
+      bc_read_trace(s, "name: ");
+      print_atom(s->ctx, vd->var_name);
+      printf("\n");
+#endif
+    }
+    bc_read_trace(s, "}\n");
+  }
+  if (b->closure_var_count != 0) {
+    bc_read_trace(s, "closure vars {\n");
+    for (i = 0; i < b->closure_var_count; i++) {
+      JSClosureVar* cv = &b->closure_var[i];
+      int var_idx;
+      if (bc_get_atom(s, &cv->var_name))
+        goto fail;
+      if (bc_get_leb128_int(s, &var_idx))
+        goto fail;
+      cv->var_idx = var_idx;
+      if (bc_get_u8(s, &v8))
+        goto fail;
+      idx = 0;
+      cv->is_local = bc_get_flags(v8, &idx, 1);
+      cv->is_arg = bc_get_flags(v8, &idx, 1);
+      cv->is_const = bc_get_flags(v8, &idx, 1);
+      cv->is_lexical = bc_get_flags(v8, &idx, 1);
+      cv->var_kind = bc_get_flags(v8, &idx, 4);
+#ifdef DUMP_READ_OBJECT
+      bc_read_trace(s, "name: ");
+      print_atom(s->ctx, cv->var_name);
+      printf("\n");
+#endif
+    }
+    bc_read_trace(s, "}\n");
+  }
+  {
+    bc_read_trace(s, "bytecode {\n");
+    if (JS_ReadFunctionBytecode(s, b, byte_code_offset, b->byte_code_len))
+      goto fail;
+    bc_read_trace(s, "}\n");
+  }
+  if (b->has_debug) {
+    /* read optional debug information */
+    bc_read_trace(s, "debug {\n");
+    if (bc_get_atom(s, &b->debug.filename))
+      goto fail;
+    if (bc_get_leb128_int(s, &b->debug.line_num))
+      goto fail;
+    if (bc_get_leb128_int(s, &b->debug.pc2line_len))
+      goto fail;
+    if (b->debug.pc2line_len) {
+      b->debug.pc2line_buf = js_mallocz(ctx, b->debug.pc2line_len);
+      if (!b->debug.pc2line_buf)
+        goto fail;
+      if (bc_get_buf(s, b->debug.pc2line_buf, b->debug.pc2line_len))
+        goto fail;
+    }
+#ifdef DUMP_READ_OBJECT
+    bc_read_trace(s, "filename: ");
+    print_atom(s->ctx, b->debug.filename);
+    printf("\n");
+#endif
+    bc_read_trace(s, "}\n");
+  }
+  if (b->cpool_count != 0) {
+    bc_read_trace(s, "cpool {\n");
+    for (i = 0; i < b->cpool_count; i++) {
+      JSValue val;
+      val = JS_ReadObjectRec(s);
+      if (JS_IsException(val))
+        goto fail;
+      b->cpool[i] = val;
+    }
+    bc_read_trace(s, "}\n");
+  }
+  b->realm = JS_DupContext(ctx);
+  return obj;
+fail:
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+static JSValue JS_ReadModule(BCReaderState* s) {
+  JSContext* ctx = s->ctx;
+  JSValue obj;
+  JSModuleDef* m = NULL;
+  JSAtom module_name;
+  int i;
+  uint8_t v8;
+
+  if (bc_get_atom(s, &module_name))
+    goto fail;
+#ifdef DUMP_READ_OBJECT
+  bc_read_trace(s, "name: ");
+  print_atom(s->ctx, module_name);
+  printf("\n");
+#endif
+  m = js_new_module_def(ctx, module_name);
+  if (!m)
+    goto fail;
+  obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
+  if (bc_get_leb128_int(s, &m->req_module_entries_count))
+    goto fail;
+  if (m->req_module_entries_count != 0) {
+    m->req_module_entries_size = m->req_module_entries_count;
+    m->req_module_entries = js_mallocz(ctx, sizeof(m->req_module_entries[0]) * m->req_module_entries_size);
+    if (!m->req_module_entries)
+      goto fail;
+    for (i = 0; i < m->req_module_entries_count; i++) {
+      JSReqModuleEntry* rme = &m->req_module_entries[i];
+      if (bc_get_atom(s, &rme->module_name))
+        goto fail;
+    }
+  }
+
+  if (bc_get_leb128_int(s, &m->export_entries_count))
+    goto fail;
+  if (m->export_entries_count != 0) {
+    m->export_entries_size = m->export_entries_count;
+    m->export_entries = js_mallocz(ctx, sizeof(m->export_entries[0]) * m->export_entries_size);
+    if (!m->export_entries)
+      goto fail;
+    for (i = 0; i < m->export_entries_count; i++) {
+      JSExportEntry* me = &m->export_entries[i];
+      if (bc_get_u8(s, &v8))
+        goto fail;
+      me->export_type = v8;
+      if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
+        if (bc_get_leb128_int(s, &me->u.local.var_idx))
+          goto fail;
+      } else {
+        if (bc_get_leb128_int(s, &me->u.req_module_idx))
+          goto fail;
+        if (bc_get_atom(s, &me->local_name))
+          goto fail;
+      }
+      if (bc_get_atom(s, &me->export_name))
+        goto fail;
+    }
+  }
+
+  if (bc_get_leb128_int(s, &m->star_export_entries_count))
+    goto fail;
+  if (m->star_export_entries_count != 0) {
+    m->star_export_entries_size = m->star_export_entries_count;
+    m->star_export_entries = js_mallocz(ctx, sizeof(m->star_export_entries[0]) * m->star_export_entries_size);
+    if (!m->star_export_entries)
+      goto fail;
+    for (i = 0; i < m->star_export_entries_count; i++) {
+      JSStarExportEntry* se = &m->star_export_entries[i];
+      if (bc_get_leb128_int(s, &se->req_module_idx))
+        goto fail;
+    }
+  }
+
+  if (bc_get_leb128_int(s, &m->import_entries_count))
+    goto fail;
+  if (m->import_entries_count != 0) {
+    m->import_entries_size = m->import_entries_count;
+    m->import_entries = js_mallocz(ctx, sizeof(m->import_entries[0]) * m->import_entries_size);
+    if (!m->import_entries)
+      goto fail;
+    for (i = 0; i < m->import_entries_count; i++) {
+      JSImportEntry* mi = &m->import_entries[i];
+      if (bc_get_leb128_int(s, &mi->var_idx))
+        goto fail;
+      if (bc_get_atom(s, &mi->import_name))
+        goto fail;
+      if (bc_get_leb128_int(s, &mi->req_module_idx))
+        goto fail;
+    }
+  }
+
+  m->func_obj = JS_ReadObjectRec(s);
+  if (JS_IsException(m->func_obj))
+    goto fail;
+  return obj;
+fail:
+  if (m) {
+    js_free_module_def(ctx, m);
+  }
+  return JS_EXCEPTION;
+}
+
+static JSValue JS_ReadObjectTag(BCReaderState* s) {
+  JSContext* ctx = s->ctx;
+  JSValue obj;
+  uint32_t prop_count, i;
+  JSAtom atom;
+  JSValue val;
+  int ret;
+
+  obj = JS_NewObject(ctx);
+  if (BC_add_object_ref(s, obj))
+    goto fail;
+  if (bc_get_leb128(s, &prop_count))
+    goto fail;
+  for (i = 0; i < prop_count; i++) {
+    if (bc_get_atom(s, &atom))
+      goto fail;
+#ifdef DUMP_READ_OBJECT
+    bc_read_trace(s, "propname: ");
+    print_atom(s->ctx, atom);
+    printf("\n");
+#endif
+    val = JS_ReadObjectRec(s);
+    if (JS_IsException(val)) {
+      JS_FreeAtom(ctx, atom);
+      goto fail;
+    }
+    ret = JS_DefinePropertyValue(ctx, obj, atom, val, JS_PROP_C_W_E);
+    JS_FreeAtom(ctx, atom);
+    if (ret < 0)
+      goto fail;
+  }
+  return obj;
+fail:
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+static JSValue JS_ReadArray(BCReaderState* s, int tag) {
+  JSContext* ctx = s->ctx;
+  JSValue obj;
+  uint32_t len, i;
+  JSValue val;
+  int ret, prop_flags;
+  BOOL is_template;
+
+  obj = JS_NewArray(ctx);
+  if (BC_add_object_ref(s, obj))
+    goto fail;
+  is_template = (tag == BC_TAG_TEMPLATE_OBJECT);
+  if (bc_get_leb128(s, &len))
+    goto fail;
+  for (i = 0; i < len; i++) {
+    val = JS_ReadObjectRec(s);
+    if (JS_IsException(val))
+      goto fail;
+    if (is_template)
+      prop_flags = JS_PROP_ENUMERABLE;
+    else
+      prop_flags = JS_PROP_C_W_E;
+    ret = JS_DefinePropertyValueUint32(ctx, obj, i, val, prop_flags);
+    if (ret < 0)
+      goto fail;
+  }
+  if (is_template) {
+    val = JS_ReadObjectRec(s);
+    if (JS_IsException(val))
+      goto fail;
+    if (!JS_IsUndefined(val)) {
+      ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_raw, val, 0);
+      if (ret < 0)
+        goto fail;
+    }
+    JS_PreventExtensions(ctx, obj);
+  }
+  return obj;
+fail:
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+static JSValue JS_ReadTypedArray(BCReaderState* s) {
+  JSContext* ctx = s->ctx;
+  JSValue obj = JS_UNDEFINED, array_buffer = JS_UNDEFINED;
+  uint8_t array_tag;
+  JSValueConst args[3];
+  uint32_t offset, len, idx;
+
+  if (bc_get_u8(s, &array_tag))
+    return JS_EXCEPTION;
+  if (array_tag >= JS_TYPED_ARRAY_COUNT)
+    return JS_ThrowTypeError(ctx, "invalid typed array");
+  if (bc_get_leb128(s, &len))
+    return JS_EXCEPTION;
+  if (bc_get_leb128(s, &offset))
+    return JS_EXCEPTION;
+  /* XXX: this hack could be avoided if the typed array could be
+     created before the array buffer */
+  idx = s->objects_count;
+  if (BC_add_object_ref1(s, NULL))
+    goto fail;
+  array_buffer = JS_ReadObjectRec(s);
+  if (JS_IsException(array_buffer))
+    return JS_EXCEPTION;
+  if (!js_get_array_buffer(ctx, array_buffer)) {
+    JS_FreeValue(ctx, array_buffer);
+    return JS_EXCEPTION;
+  }
+  args[0] = array_buffer;
+  args[1] = JS_NewInt64(ctx, offset);
+  args[2] = JS_NewInt64(ctx, len);
+  obj = js_typed_array_constructor(ctx, JS_UNDEFINED, 3, args, JS_CLASS_UINT8C_ARRAY + array_tag);
+  if (JS_IsException(obj))
+    goto fail;
+  if (s->allow_reference) {
+    s->objects[idx] = JS_VALUE_GET_OBJ(obj);
+  }
+  JS_FreeValue(ctx, array_buffer);
+  return obj;
+fail:
+  JS_FreeValue(ctx, array_buffer);
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+static JSValue JS_ReadArrayBuffer(BCReaderState* s) {
+  JSContext* ctx = s->ctx;
+  uint32_t byte_length;
+  JSValue obj;
+
+  if (bc_get_leb128(s, &byte_length))
+    return JS_EXCEPTION;
+  if (unlikely(s->buf_end - s->ptr < byte_length)) {
+    bc_read_error_end(s);
+    return JS_EXCEPTION;
+  }
+  obj = JS_NewArrayBufferCopy(ctx, s->ptr, byte_length);
+  if (JS_IsException(obj))
+    goto fail;
+  if (BC_add_object_ref(s, obj))
+    goto fail;
+  s->ptr += byte_length;
+  return obj;
+fail:
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+static JSValue JS_ReadSharedArrayBuffer(BCReaderState* s) {
+  JSContext* ctx = s->ctx;
+  uint32_t byte_length;
+  uint8_t* data_ptr;
+  JSValue obj;
+  uint64_t u64;
+
+  if (bc_get_leb128(s, &byte_length))
+    return JS_EXCEPTION;
+  if (bc_get_u64(s, &u64))
+    return JS_EXCEPTION;
+  data_ptr = (uint8_t*)(uintptr_t)u64;
+  /* the SharedArrayBuffer is cloned */
+  obj = js_array_buffer_constructor3(ctx, JS_UNDEFINED, byte_length, JS_CLASS_SHARED_ARRAY_BUFFER, data_ptr, NULL, NULL,
+                                     FALSE);
+  if (JS_IsException(obj))
+    goto fail;
+  if (BC_add_object_ref(s, obj))
+    goto fail;
+  return obj;
+fail:
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+static JSValue JS_ReadDate(BCReaderState* s) {
+  JSContext* ctx = s->ctx;
+  JSValue val, obj = JS_UNDEFINED;
+
+  val = JS_ReadObjectRec(s);
+  if (JS_IsException(val))
+    goto fail;
+  if (!JS_IsNumber(val)) {
+    JS_ThrowTypeError(ctx, "Number tag expected for date");
+    goto fail;
+  }
+  obj = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_DATE], JS_CLASS_DATE);
+  if (JS_IsException(obj))
+    goto fail;
+  if (BC_add_object_ref(s, obj))
+    goto fail;
+  JS_SetObjectData(ctx, obj, val);
+  return obj;
+fail:
+  JS_FreeValue(ctx, val);
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+static JSValue JS_ReadObjectValue(BCReaderState* s) {
+  JSContext* ctx = s->ctx;
+  JSValue val, obj = JS_UNDEFINED;
+
+  val = JS_ReadObjectRec(s);
+  if (JS_IsException(val))
+    goto fail;
+  obj = JS_ToObject(ctx, val);
+  if (JS_IsException(obj))
+    goto fail;
+  if (BC_add_object_ref(s, obj))
+    goto fail;
+  JS_FreeValue(ctx, val);
+  return obj;
+fail:
+  JS_FreeValue(ctx, val);
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+static JSValue JS_ReadObjectRec(BCReaderState* s) {
+  JSContext* ctx = s->ctx;
+  uint8_t tag;
+  JSValue obj = JS_UNDEFINED;
+
+  if (js_check_stack_overflow(ctx->rt, 0))
+    return JS_ThrowStackOverflow(ctx);
+
+  if (bc_get_u8(s, &tag))
+    return JS_EXCEPTION;
+
+  bc_read_trace(s, "%s {\n", bc_tag_str[tag]);
+
+  switch (tag) {
+    case BC_TAG_NULL:
+      obj = JS_NULL;
+      break;
+    case BC_TAG_UNDEFINED:
+      obj = JS_UNDEFINED;
+      break;
+    case BC_TAG_BOOL_FALSE:
+    case BC_TAG_BOOL_TRUE:
+      obj = JS_NewBool(ctx, tag - BC_TAG_BOOL_FALSE);
+      break;
+    case BC_TAG_INT32: {
+      int32_t val;
+      if (bc_get_sleb128(s, &val))
+        return JS_EXCEPTION;
+      bc_read_trace(s, "%d\n", val);
+      obj = JS_NewInt32(ctx, val);
+    } break;
+    case BC_TAG_FLOAT64: {
+      JSFloat64Union u;
+      if (bc_get_u64(s, &u.u64))
+        return JS_EXCEPTION;
+      bc_read_trace(s, "%g\n", u.d);
+      obj = __JS_NewFloat64(ctx, u.d);
+    } break;
+    case BC_TAG_STRING: {
+      JSString* p;
+      p = JS_ReadString(s);
+      if (!p)
+        return JS_EXCEPTION;
+      obj = JS_MKPTR(JS_TAG_STRING, p);
+    } break;
+    case BC_TAG_FUNCTION_BYTECODE:
+      if (!s->allow_bytecode)
+        goto invalid_tag;
+      obj = JS_ReadFunctionTag(s);
+      break;
+    case BC_TAG_MODULE:
+      if (!s->allow_bytecode)
+        goto invalid_tag;
+      obj = JS_ReadModule(s);
+      break;
+    case BC_TAG_OBJECT:
+      obj = JS_ReadObjectTag(s);
+      break;
+    case BC_TAG_ARRAY:
+    case BC_TAG_TEMPLATE_OBJECT:
+      obj = JS_ReadArray(s, tag);
+      break;
+    case BC_TAG_TYPED_ARRAY:
+      obj = JS_ReadTypedArray(s);
+      break;
+    case BC_TAG_ARRAY_BUFFER:
+      obj = JS_ReadArrayBuffer(s);
+      break;
+    case BC_TAG_SHARED_ARRAY_BUFFER:
+      if (!s->allow_sab || !ctx->rt->sab_funcs.sab_dup)
+        goto invalid_tag;
+      obj = JS_ReadSharedArrayBuffer(s);
+      break;
+    case BC_TAG_DATE:
+      obj = JS_ReadDate(s);
+      break;
+    case BC_TAG_OBJECT_VALUE:
+      obj = JS_ReadObjectValue(s);
+      break;
+#ifdef CONFIG_BIGNUM
+    case BC_TAG_BIG_INT:
+    case BC_TAG_BIG_FLOAT:
+    case BC_TAG_BIG_DECIMAL:
+      obj = JS_ReadBigNum(s, tag);
+      break;
+#endif
+    case BC_TAG_OBJECT_REFERENCE: {
+      uint32_t val;
+      if (!s->allow_reference)
+        return JS_ThrowSyntaxError(ctx, "object references are not allowed");
+      if (bc_get_leb128(s, &val))
+        return JS_EXCEPTION;
+      bc_read_trace(s, "%u\n", val);
+      if (val >= s->objects_count) {
+        return JS_ThrowSyntaxError(ctx, "invalid object reference (%u >= %u)", val, s->objects_count);
+      }
+      obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, s->objects[val]));
+    } break;
+    default:
+    invalid_tag:
+      return JS_ThrowSyntaxError(ctx, "invalid tag (tag=%d pos=%u)", tag, (unsigned int)(s->ptr - s->buf_start));
+  }
+  bc_read_trace(s, "}\n");
+  return obj;
+}
+
+static int JS_ReadObjectAtoms(BCReaderState* s) {
+  uint8_t v8;
+  JSString* p;
+  int i;
+  JSAtom atom;
+
+  if (bc_get_u8(s, &v8))
+    return -1;
+  /* XXX: could support byte swapped input */
+  if (v8 != BC_VERSION) {
+    JS_ThrowSyntaxError(s->ctx, "invalid version (%d expected=%d)", v8, BC_VERSION);
+    return -1;
+  }
+  if (bc_get_leb128(s, &s->idx_to_atom_count))
+    return -1;
+
+  bc_read_trace(s, "%d atom indexes {\n", s->idx_to_atom_count);
+
+  if (s->idx_to_atom_count != 0) {
+    s->idx_to_atom = js_mallocz(s->ctx, s->idx_to_atom_count * sizeof(s->idx_to_atom[0]));
+    if (!s->idx_to_atom)
+      return s->error_state = -1;
+  }
+  for (i = 0; i < s->idx_to_atom_count; i++) {
+    p = JS_ReadString(s);
+    if (!p)
+      return -1;
+    atom = JS_NewAtomStr(s->ctx, p);
+    if (atom == JS_ATOM_NULL)
+      return s->error_state = -1;
+    s->idx_to_atom[i] = atom;
+    if (s->is_rom_data && (atom != (i + s->first_atom)))
+      s->is_rom_data = FALSE; /* atoms must be relocated */
+  }
+  bc_read_trace(s, "}\n");
+  return 0;
+}
+
+static void bc_reader_free(BCReaderState* s) {
+  int i;
+  if (s->idx_to_atom) {
+    for (i = 0; i < s->idx_to_atom_count; i++) {
+      JS_FreeAtom(s->ctx, s->idx_to_atom[i]);
+    }
+    js_free(s->ctx, s->idx_to_atom);
+  }
+  js_free(s->ctx, s->objects);
+}
+
+JSValue JS_ReadObject(JSContext* ctx, const uint8_t* buf, size_t buf_len, int flags) {
+  BCReaderState ss, *s = &ss;
+  JSValue obj;
+
+  ctx->binary_object_count += 1;
+  ctx->binary_object_size += buf_len;
+
+  memset(s, 0, sizeof(*s));
+  s->ctx = ctx;
+  s->buf_start = buf;
+  s->buf_end = buf + buf_len;
+  s->ptr = buf;
+  s->allow_bytecode = ((flags & JS_READ_OBJ_BYTECODE) != 0);
+  s->is_rom_data = ((flags & JS_READ_OBJ_ROM_DATA) != 0);
+  s->allow_sab = ((flags & JS_READ_OBJ_SAB) != 0);
+  s->allow_reference = ((flags & JS_READ_OBJ_REFERENCE) != 0);
+  if (s->allow_bytecode)
+    s->first_atom = JS_ATOM_END;
+  else
+    s->first_atom = 1;
+  if (JS_ReadObjectAtoms(s)) {
+    obj = JS_EXCEPTION;
+  } else {
+    obj = JS_ReadObjectRec(s);
+  }
+  bc_reader_free(s);
+  return obj;
+}
\ No newline at end of file
diff --git a/src/core/bytecode.h b/src/core/bytecode.h
new file mode 100644
index 000000000..c7bfbe16b
--- /dev/null
+++ b/src/core/bytecode.h
@@ -0,0 +1,38 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_BYTECODE_H
+#define QUICKJS_BYTECODE_H
+
+#include "quickjs/quickjs.h"
+#include "quickjs/cutils.h"
+#include "types.h"
+
+void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b);
+void free_bytecode_atoms(JSRuntime *rt,
+                         const uint8_t *bc_buf, int bc_len,
+                                BOOL use_short_opcodes);;
+
+#endif
\ No newline at end of file
diff --git a/src/core/convertion.c b/src/core/convertion.c
new file mode 100644
index 000000000..440a8692c
--- /dev/null
+++ b/src/core/convertion.c
@@ -0,0 +1,1674 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "convertion.h"
+#include "builtins/js-big-num.h"
+#include "exception.h"
+#include "function.h"
+#include "quickjs/libregexp.h"
+#include "string.h"
+
+static JSValue JS_ToNumberHintFree(JSContext* ctx, JSValue val, JSToNumberHintEnum flag);
+
+int skip_spaces(const char* pc) {
+  const uint8_t *p, *p_next, *p_start;
+  uint32_t c;
+
+  p = p_start = (const uint8_t*)pc;
+  for (;;) {
+    c = *p;
+    if (c < 128) {
+      if (!((c >= 0x09 && c <= 0x0d) || (c == 0x20)))
+        break;
+      p++;
+    } else {
+      c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
+      if (!lre_is_space(c))
+        break;
+      p = p_next;
+    }
+  }
+  return p - p_start;
+}
+
+JSValue JS_ToPrimitiveFree(JSContext* ctx, JSValue val, int hint) {
+  int i;
+  BOOL force_ordinary;
+
+  JSAtom method_name;
+  JSValue method, ret;
+  if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
+    return val;
+  force_ordinary = hint & HINT_FORCE_ORDINARY;
+  hint &= ~HINT_FORCE_ORDINARY;
+  if (!force_ordinary) {
+    method = JS_GetProperty(ctx, val, JS_ATOM_Symbol_toPrimitive);
+    if (JS_IsException(method))
+      goto exception;
+    /* ECMA says *If exoticToPrim is not undefined* but tests in
+       test262 use null as a non callable converter */
+    if (!JS_IsUndefined(method) && !JS_IsNull(method)) {
+      JSAtom atom;
+      JSValue arg;
+      switch (hint) {
+        case HINT_STRING:
+          atom = JS_ATOM_string;
+          break;
+        case HINT_NUMBER:
+          atom = JS_ATOM_number;
+          break;
+        default:
+        case HINT_NONE:
+          atom = JS_ATOM_default;
+          break;
+      }
+      arg = JS_AtomToString(ctx, atom);
+      ret = JS_CallFree(ctx, method, val, 1, (JSValueConst*)&arg);
+      JS_FreeValue(ctx, arg);
+      if (JS_IsException(ret))
+        goto exception;
+      JS_FreeValue(ctx, val);
+      if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT)
+        return ret;
+      JS_FreeValue(ctx, ret);
+      return JS_ThrowTypeError(ctx, "toPrimitive");
+    }
+  }
+  if (hint != HINT_STRING)
+    hint = HINT_NUMBER;
+  for (i = 0; i < 2; i++) {
+    if ((i ^ hint) == 0) {
+      method_name = JS_ATOM_toString;
+    } else {
+      method_name = JS_ATOM_valueOf;
+    }
+    method = JS_GetProperty(ctx, val, method_name);
+    if (JS_IsException(method))
+      goto exception;
+    if (JS_IsFunction(ctx, method)) {
+      ret = JS_CallFree(ctx, method, val, 0, NULL);
+      if (JS_IsException(ret))
+        goto exception;
+      if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
+        JS_FreeValue(ctx, val);
+        return ret;
+      }
+      JS_FreeValue(ctx, ret);
+    } else {
+      JS_FreeValue(ctx, method);
+    }
+  }
+  JS_ThrowTypeError(ctx, "toPrimitive");
+exception:
+  JS_FreeValue(ctx, val);
+  return JS_EXCEPTION;
+}
+
+JSValue JS_ToPrimitive(JSContext* ctx, JSValueConst val, int hint) {
+  return JS_ToPrimitiveFree(ctx, JS_DupValue(ctx, val), hint);
+}
+
+__exception int JS_ToArrayLengthFree(JSContext* ctx, uint32_t* plen, JSValue val, BOOL is_array_ctor) {
+  uint32_t tag, len;
+
+  tag = JS_VALUE_GET_TAG(val);
+  switch (tag) {
+    case JS_TAG_INT:
+    case JS_TAG_BOOL:
+    case JS_TAG_NULL: {
+      int v;
+      v = JS_VALUE_GET_INT(val);
+      if (v < 0)
+        goto fail;
+      len = v;
+    } break;
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_INT:
+    case JS_TAG_BIG_FLOAT: {
+      JSBigFloat* p = JS_VALUE_GET_PTR(val);
+      bf_t a;
+      BOOL res;
+      bf_get_int32((int32_t*)&len, &p->num, BF_GET_INT_MOD);
+      bf_init(ctx->bf_ctx, &a);
+      bf_set_ui(&a, len);
+      res = bf_cmp_eq(&a, &p->num);
+      bf_delete(&a);
+      JS_FreeValue(ctx, val);
+      if (!res)
+        goto fail;
+    } break;
+#endif
+    default:
+      if (JS_TAG_IS_FLOAT64(tag)) {
+        double d;
+        d = JS_VALUE_GET_FLOAT64(val);
+        len = (uint32_t)d;
+        if (len != d)
+          goto fail;
+      } else {
+        uint32_t len1;
+
+        if (is_array_ctor) {
+          val = JS_ToNumberFree(ctx, val);
+          if (JS_IsException(val))
+            return -1;
+          /* cannot recurse because val is a number */
+          if (JS_ToArrayLengthFree(ctx, &len, val, TRUE))
+            return -1;
+        } else {
+          /* legacy behavior: must do the conversion twice and compare */
+          if (JS_ToUint32(ctx, &len, val)) {
+            JS_FreeValue(ctx, val);
+            return -1;
+          }
+          val = JS_ToNumberFree(ctx, val);
+          if (JS_IsException(val))
+            return -1;
+          /* cannot recurse because val is a number */
+          if (JS_ToArrayLengthFree(ctx, &len1, val, FALSE))
+            return -1;
+          if (len1 != len) {
+          fail:
+            JS_ThrowRangeError(ctx, "invalid array length");
+            return -1;
+          }
+        }
+      }
+      break;
+  }
+  *plen = len;
+  return 0;
+}
+
+JSValue JS_ToNumber(JSContext* ctx, JSValueConst val) {
+  return JS_ToNumberFree(ctx, JS_DupValue(ctx, val));
+}
+
+JSValue JS_ToNumberFree(JSContext* ctx, JSValue val) {
+  return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMBER);
+}
+
+JSValue JS_ToNumericFree(JSContext* ctx, JSValue val) {
+  return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC);
+}
+
+JSValue JS_ToNumeric(JSContext* ctx, JSValueConst val) {
+  return JS_ToNumericFree(ctx, JS_DupValue(ctx, val));
+}
+
+static JSValue JS_ToNumberHintFree(JSContext* ctx, JSValue val, JSToNumberHintEnum flag) {
+  uint32_t tag;
+  JSValue ret;
+
+redo:
+  tag = JS_VALUE_GET_NORM_TAG(val);
+  switch (tag) {
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_DECIMAL:
+      if (flag != TON_FLAG_NUMERIC) {
+        JS_FreeValue(ctx, val);
+        return JS_ThrowTypeError(ctx, "cannot convert bigdecimal to number");
+      }
+      ret = val;
+      break;
+    case JS_TAG_BIG_INT:
+      if (flag != TON_FLAG_NUMERIC) {
+        JS_FreeValue(ctx, val);
+        return JS_ThrowTypeError(ctx, "cannot convert bigint to number");
+      }
+      ret = val;
+      break;
+    case JS_TAG_BIG_FLOAT:
+      if (flag != TON_FLAG_NUMERIC) {
+        JS_FreeValue(ctx, val);
+        return JS_ThrowTypeError(ctx, "cannot convert bigfloat to number");
+      }
+      ret = val;
+      break;
+#endif
+    case JS_TAG_FLOAT64:
+    case JS_TAG_INT:
+    case JS_TAG_EXCEPTION:
+      ret = val;
+      break;
+    case JS_TAG_BOOL:
+    case JS_TAG_NULL:
+      ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));
+      break;
+    case JS_TAG_UNDEFINED:
+      ret = JS_NAN;
+      break;
+    case JS_TAG_OBJECT:
+      val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
+      if (JS_IsException(val))
+        return JS_EXCEPTION;
+      goto redo;
+    case JS_TAG_STRING: {
+      const char* str;
+      const char* p;
+      size_t len;
+
+      str = JS_ToCStringLen(ctx, &len, val);
+      JS_FreeValue(ctx, val);
+      if (!str)
+        return JS_EXCEPTION;
+      p = str;
+      p += skip_spaces(p);
+      if ((p - str) == len) {
+        ret = JS_NewInt32(ctx, 0);
+      } else {
+        int flags = ATOD_ACCEPT_BIN_OCT;
+        ret = js_atof(ctx, p, &p, 0, flags);
+        if (!JS_IsException(ret)) {
+          p += skip_spaces(p);
+          if ((p - str) != len) {
+            JS_FreeValue(ctx, ret);
+            ret = JS_NAN;
+          }
+        }
+      }
+      JS_FreeCString(ctx, str);
+    } break;
+    case JS_TAG_SYMBOL:
+      JS_FreeValue(ctx, val);
+      return JS_ThrowTypeError(ctx, "cannot convert symbol to number");
+    default:
+      JS_FreeValue(ctx, val);
+      ret = JS_NAN;
+      break;
+  }
+  return ret;
+}
+
+__exception int __JS_ToFloat64Free(JSContext* ctx, double* pres, JSValue val) {
+  double d;
+  uint32_t tag;
+
+  val = JS_ToNumberFree(ctx, val);
+  if (JS_IsException(val)) {
+    *pres = JS_FLOAT64_NAN;
+    return -1;
+  }
+  tag = JS_VALUE_GET_NORM_TAG(val);
+  switch (tag) {
+    case JS_TAG_INT:
+      d = JS_VALUE_GET_INT(val);
+      break;
+    case JS_TAG_FLOAT64:
+      d = JS_VALUE_GET_FLOAT64(val);
+      break;
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_INT:
+    case JS_TAG_BIG_FLOAT: {
+      JSBigFloat* p = JS_VALUE_GET_PTR(val);
+      /* XXX: there can be a double rounding issue with some
+         primitives (such as JS_ToUint8ClampFree()), but it is
+         not critical to fix it. */
+      bf_get_float64(&p->num, &d, BF_RNDN);
+      JS_FreeValue(ctx, val);
+    } break;
+#endif
+    default:
+      abort();
+  }
+  *pres = d;
+  return 0;
+}
+
+int JS_ToFloat64(JSContext* ctx, double* pres, JSValueConst val) {
+  return JS_ToFloat64Free(ctx, pres, JS_DupValue(ctx, val));
+}
+
+/* same as JS_ToNumber() but return 0 in case of NaN/Undefined */
+__maybe_unused JSValue JS_ToIntegerFree(JSContext* ctx, JSValue val) {
+  uint32_t tag;
+  JSValue ret;
+
+redo:
+  tag = JS_VALUE_GET_NORM_TAG(val);
+  switch (tag) {
+    case JS_TAG_INT:
+    case JS_TAG_BOOL:
+    case JS_TAG_NULL:
+    case JS_TAG_UNDEFINED:
+      ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));
+      break;
+    case JS_TAG_FLOAT64: {
+      double d = JS_VALUE_GET_FLOAT64(val);
+      if (isnan(d)) {
+        ret = JS_NewInt32(ctx, 0);
+      } else {
+        /* convert -0 to +0 */
+        d = trunc(d) + 0.0;
+        ret = JS_NewFloat64(ctx, d);
+      }
+    } break;
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_FLOAT: {
+      bf_t a_s, *a, r_s, *r = &r_s;
+      BOOL is_nan;
+
+      a = JS_ToBigFloat(ctx, &a_s, val);
+      if (!bf_is_finite(a)) {
+        is_nan = bf_is_nan(a);
+        if (is_nan)
+          ret = JS_NewInt32(ctx, 0);
+        else
+          ret = JS_DupValue(ctx, val);
+      } else {
+        ret = JS_NewBigInt(ctx);
+        if (!JS_IsException(ret)) {
+          r = JS_GetBigInt(ret);
+          bf_set(r, a);
+          bf_rint(r, BF_RNDZ);
+          ret = JS_CompactBigInt(ctx, ret);
+        }
+      }
+      if (a == &a_s)
+        bf_delete(a);
+      JS_FreeValue(ctx, val);
+    } break;
+#endif
+    default:
+      val = JS_ToNumberFree(ctx, val);
+      if (JS_IsException(val))
+        return val;
+      goto redo;
+  }
+  return ret;
+}
+
+/* Note: the integer value is satured to 32 bits */
+int JS_ToInt32SatFree(JSContext* ctx, int* pres, JSValue val) {
+  uint32_t tag;
+  int ret;
+
+redo:
+  tag = JS_VALUE_GET_NORM_TAG(val);
+  switch (tag) {
+    case JS_TAG_INT:
+    case JS_TAG_BOOL:
+    case JS_TAG_NULL:
+    case JS_TAG_UNDEFINED:
+      ret = JS_VALUE_GET_INT(val);
+      break;
+    case JS_TAG_EXCEPTION:
+      *pres = 0;
+      return -1;
+    case JS_TAG_FLOAT64: {
+      double d = JS_VALUE_GET_FLOAT64(val);
+      if (isnan(d)) {
+        ret = 0;
+      } else {
+        if (d < INT32_MIN)
+          ret = INT32_MIN;
+        else if (d > INT32_MAX)
+          ret = INT32_MAX;
+        else
+          ret = (int)d;
+      }
+    } break;
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_FLOAT: {
+      JSBigFloat* p = JS_VALUE_GET_PTR(val);
+      bf_get_int32(&ret, &p->num, 0);
+      JS_FreeValue(ctx, val);
+    } break;
+#endif
+    default:
+      val = JS_ToNumberFree(ctx, val);
+      if (JS_IsException(val)) {
+        *pres = 0;
+        return -1;
+      }
+      goto redo;
+  }
+  *pres = ret;
+  return 0;
+}
+
+int JS_ToInt32Sat(JSContext* ctx, int* pres, JSValueConst val) {
+  return JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val));
+}
+
+int JS_ToInt32Clamp(JSContext* ctx, int* pres, JSValueConst val, int min, int max, int min_offset) {
+  int res = JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val));
+  if (res == 0) {
+    if (*pres < min) {
+      *pres += min_offset;
+      if (*pres < min)
+        *pres = min;
+    } else {
+      if (*pres > max)
+        *pres = max;
+    }
+  }
+  return res;
+}
+
+int JS_ToInt64SatFree(JSContext* ctx, int64_t* pres, JSValue val) {
+  uint32_t tag;
+
+redo:
+  tag = JS_VALUE_GET_NORM_TAG(val);
+  switch (tag) {
+    case JS_TAG_INT:
+    case JS_TAG_BOOL:
+    case JS_TAG_NULL:
+    case JS_TAG_UNDEFINED:
+      *pres = JS_VALUE_GET_INT(val);
+      return 0;
+    case JS_TAG_EXCEPTION:
+      *pres = 0;
+      return -1;
+    case JS_TAG_FLOAT64: {
+      double d = JS_VALUE_GET_FLOAT64(val);
+      if (isnan(d)) {
+        *pres = 0;
+      } else {
+        if (d < INT64_MIN)
+          *pres = INT64_MIN;
+        else if (d > INT64_MAX)
+          *pres = INT64_MAX;
+        else
+          *pres = (int64_t)d;
+      }
+    }
+      return 0;
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_FLOAT: {
+      JSBigFloat* p = JS_VALUE_GET_PTR(val);
+      bf_get_int64(pres, &p->num, 0);
+      JS_FreeValue(ctx, val);
+    }
+      return 0;
+#endif
+    default:
+      val = JS_ToNumberFree(ctx, val);
+      if (JS_IsException(val)) {
+        *pres = 0;
+        return -1;
+      }
+      goto redo;
+  }
+}
+
+int JS_ToInt64Sat(JSContext* ctx, int64_t* pres, JSValueConst val) {
+  return JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val));
+}
+
+int JS_ToInt64Clamp(JSContext* ctx, int64_t* pres, JSValueConst val, int64_t min, int64_t max, int64_t neg_offset) {
+  int res = JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val));
+  if (res == 0) {
+    if (*pres < 0)
+      *pres += neg_offset;
+    if (*pres < min)
+      *pres = min;
+    else if (*pres > max)
+      *pres = max;
+  }
+  return res;
+}
+
+/* Same as JS_ToInt32Free() but with a 64 bit result. Return (<0, 0)
+   in case of exception */
+int JS_ToInt64Free(JSContext* ctx, int64_t* pres, JSValue val) {
+  uint32_t tag;
+  int64_t ret;
+
+redo:
+  tag = JS_VALUE_GET_NORM_TAG(val);
+  switch (tag) {
+    case JS_TAG_INT:
+    case JS_TAG_BOOL:
+    case JS_TAG_NULL:
+    case JS_TAG_UNDEFINED:
+      ret = JS_VALUE_GET_INT(val);
+      break;
+    case JS_TAG_FLOAT64: {
+      JSFloat64Union u;
+      double d;
+      int e;
+      d = JS_VALUE_GET_FLOAT64(val);
+      u.d = d;
+      /* we avoid doing fmod(x, 2^64) */
+      e = (u.u64 >> 52) & 0x7ff;
+      if (likely(e <= (1023 + 62))) {
+        /* fast case */
+        ret = (int64_t)d;
+      } else if (e <= (1023 + 62 + 53)) {
+        uint64_t v;
+        /* remainder modulo 2^64 */
+        v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);
+        ret = v << ((e - 1023) - 52);
+        /* take the sign into account */
+        if (u.u64 >> 63)
+          ret = -ret;
+      } else {
+        ret = 0; /* also handles NaN and +inf */
+      }
+    } break;
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_FLOAT: {
+      JSBigFloat* p = JS_VALUE_GET_PTR(val);
+      bf_get_int64(&ret, &p->num, BF_GET_INT_MOD);
+      JS_FreeValue(ctx, val);
+    } break;
+#endif
+    default:
+      val = JS_ToNumberFree(ctx, val);
+      if (JS_IsException(val)) {
+        *pres = 0;
+        return -1;
+      }
+      goto redo;
+  }
+  *pres = ret;
+  return 0;
+}
+
+int JS_ToInt64(JSContext* ctx, int64_t* pres, JSValueConst val) {
+  return JS_ToInt64Free(ctx, pres, JS_DupValue(ctx, val));
+}
+
+int JS_ToInt64Ext(JSContext* ctx, int64_t* pres, JSValueConst val) {
+  if (JS_IsBigInt(ctx, val))
+    return JS_ToBigInt64(ctx, pres, val);
+  else
+    return JS_ToInt64(ctx, pres, val);
+}
+
+/* return (<0, 0) in case of exception */
+int JS_ToInt32Free(JSContext* ctx, int32_t* pres, JSValue val) {
+  uint32_t tag;
+  int32_t ret;
+
+redo:
+  tag = JS_VALUE_GET_NORM_TAG(val);
+  switch (tag) {
+    case JS_TAG_INT:
+    case JS_TAG_BOOL:
+    case JS_TAG_NULL:
+    case JS_TAG_UNDEFINED:
+      ret = JS_VALUE_GET_INT(val);
+      break;
+    case JS_TAG_FLOAT64: {
+      JSFloat64Union u;
+      double d;
+      int e;
+      d = JS_VALUE_GET_FLOAT64(val);
+      u.d = d;
+      /* we avoid doing fmod(x, 2^32) */
+      e = (u.u64 >> 52) & 0x7ff;
+      if (likely(e <= (1023 + 30))) {
+        /* fast case */
+        ret = (int32_t)d;
+      } else if (e <= (1023 + 30 + 53)) {
+        uint64_t v;
+        /* remainder modulo 2^32 */
+        v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);
+        v = v << ((e - 1023) - 52 + 32);
+        ret = v >> 32;
+        /* take the sign into account */
+        if (u.u64 >> 63)
+          ret = -ret;
+      } else {
+        ret = 0; /* also handles NaN and +inf */
+      }
+    } break;
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_FLOAT: {
+      JSBigFloat* p = JS_VALUE_GET_PTR(val);
+      bf_get_int32(&ret, &p->num, BF_GET_INT_MOD);
+      JS_FreeValue(ctx, val);
+    } break;
+#endif
+    default:
+      val = JS_ToNumberFree(ctx, val);
+      if (JS_IsException(val)) {
+        *pres = 0;
+        return -1;
+      }
+      goto redo;
+  }
+  *pres = ret;
+  return 0;
+}
+
+int JS_ToInt32(JSContext* ctx, int32_t* pres, JSValueConst val) {
+  return JS_ToInt32Free(ctx, pres, JS_DupValue(ctx, val));
+}
+
+int JS_ToUint8ClampFree(JSContext* ctx, int32_t* pres, JSValue val) {
+  uint32_t tag;
+  int res;
+
+redo:
+  tag = JS_VALUE_GET_NORM_TAG(val);
+  switch (tag) {
+    case JS_TAG_INT:
+    case JS_TAG_BOOL:
+    case JS_TAG_NULL:
+    case JS_TAG_UNDEFINED:
+      res = JS_VALUE_GET_INT(val);
+#ifdef CONFIG_BIGNUM
+    int_clamp:
+#endif
+      res = max_int(0, min_int(255, res));
+      break;
+    case JS_TAG_FLOAT64: {
+      double d = JS_VALUE_GET_FLOAT64(val);
+      if (isnan(d)) {
+        res = 0;
+      } else {
+        if (d < 0)
+          res = 0;
+        else if (d > 255)
+          res = 255;
+        else
+          res = lrint(d);
+      }
+    } break;
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_FLOAT: {
+      JSBigFloat* p = JS_VALUE_GET_PTR(val);
+      bf_t r_s, *r = &r_s;
+      bf_init(ctx->bf_ctx, r);
+      bf_set(r, &p->num);
+      bf_rint(r, BF_RNDN);
+      bf_get_int32(&res, r, 0);
+      bf_delete(r);
+      JS_FreeValue(ctx, val);
+    }
+      goto int_clamp;
+#endif
+    default:
+      val = JS_ToNumberFree(ctx, val);
+      if (JS_IsException(val)) {
+        *pres = 0;
+        return -1;
+      }
+      goto redo;
+  }
+  *pres = res;
+  return 0;
+}
+
+int JS_ToBoolFree(JSContext* ctx, JSValue val) {
+  uint32_t tag = JS_VALUE_GET_TAG(val);
+  switch (tag) {
+    case JS_TAG_INT:
+      return JS_VALUE_GET_INT(val) != 0;
+    case JS_TAG_BOOL:
+    case JS_TAG_NULL:
+    case JS_TAG_UNDEFINED:
+      return JS_VALUE_GET_INT(val);
+    case JS_TAG_EXCEPTION:
+      return -1;
+    case JS_TAG_STRING: {
+      BOOL ret = JS_VALUE_GET_STRING(val)->len != 0;
+      JS_FreeValue(ctx, val);
+      return ret;
+    }
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_INT:
+    case JS_TAG_BIG_FLOAT: {
+      JSBigFloat* p = JS_VALUE_GET_PTR(val);
+      BOOL ret;
+      ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN;
+      JS_FreeValue(ctx, val);
+      return ret;
+    }
+    case JS_TAG_BIG_DECIMAL: {
+      JSBigDecimal* p = JS_VALUE_GET_PTR(val);
+      BOOL ret;
+      ret = p->num.expn != BF_EXP_ZERO && p->num.expn != BF_EXP_NAN;
+      JS_FreeValue(ctx, val);
+      return ret;
+    }
+#endif
+    case JS_TAG_OBJECT: {
+      JSObject* p = JS_VALUE_GET_OBJ(val);
+      BOOL ret;
+      ret = !p->is_HTMLDDA;
+      JS_FreeValue(ctx, val);
+      return ret;
+    } break;
+    default:
+      if (JS_TAG_IS_FLOAT64(tag)) {
+        double d = JS_VALUE_GET_FLOAT64(val);
+        return !isnan(d) && d != 0;
+      } else {
+        JS_FreeValue(ctx, val);
+        return TRUE;
+      }
+  }
+}
+
+int JS_ToBool(JSContext* ctx, JSValueConst val) {
+  return JS_ToBoolFree(ctx, JS_DupValue(ctx, val));
+}
+
+/* XXX: remove */
+double js_strtod(const char* p, int radix, BOOL is_float) {
+  double d;
+  int c;
+
+  if (!is_float || radix != 10) {
+    uint64_t n_max, n;
+    int int_exp, is_neg;
+
+    is_neg = 0;
+    if (*p == '-') {
+      is_neg = 1;
+      p++;
+    }
+
+    /* skip leading zeros */
+    while (*p == '0')
+      p++;
+    n = 0;
+    if (radix == 10)
+      n_max = ((uint64_t)-1 - 9) / 10; /* most common case */
+    else
+      n_max = ((uint64_t)-1 - (radix - 1)) / radix;
+    /* XXX: could be more precise */
+    int_exp = 0;
+    while (*p != '\0') {
+      c = to_digit((uint8_t)*p);
+      if (c >= radix)
+        break;
+      if (n <= n_max) {
+        n = n * radix + c;
+      } else {
+        int_exp++;
+      }
+      p++;
+    }
+    d = n;
+    if (int_exp != 0) {
+      d *= pow(radix, int_exp);
+    }
+    if (is_neg)
+      d = -d;
+  } else {
+    d = strtod(p, NULL);
+  }
+  return d;
+}
+
+#ifdef CONFIG_BIGNUM
+JSValue js_string_to_bigint(JSContext* ctx, const char* buf, int radix, int flags, slimb_t* pexponent) {
+  bf_t a_s, *a = &a_s;
+  int ret;
+  JSValue val;
+  val = JS_NewBigInt(ctx);
+  if (JS_IsException(val))
+    return val;
+  a = JS_GetBigInt(val);
+  ret = bf_atof(a, buf, NULL, radix, BF_PREC_INF, BF_RNDZ);
+  if (ret & BF_ST_MEM_ERROR) {
+    JS_FreeValue(ctx, val);
+    return JS_ThrowOutOfMemory(ctx);
+  }
+  val = JS_CompactBigInt1(ctx, val, (flags & ATOD_MODE_BIGINT) != 0);
+  return val;
+}
+
+JSValue js_string_to_bigfloat(JSContext* ctx, const char* buf, int radix, int flags, slimb_t* pexponent) {
+  bf_t* a;
+  int ret;
+  JSValue val;
+
+  val = JS_NewBigFloat(ctx);
+  if (JS_IsException(val))
+    return val;
+  a = JS_GetBigFloat(val);
+  if (flags & ATOD_ACCEPT_SUFFIX) {
+    /* return the exponent to get infinite precision */
+    ret = bf_atof2(a, pexponent, buf, NULL, radix, BF_PREC_INF, BF_RNDZ | BF_ATOF_EXPONENT);
+  } else {
+    ret = bf_atof(a, buf, NULL, radix, ctx->fp_env.prec, ctx->fp_env.flags);
+  }
+  if (ret & BF_ST_MEM_ERROR) {
+    JS_FreeValue(ctx, val);
+    return JS_ThrowOutOfMemory(ctx);
+  }
+  return val;
+}
+
+JSValue js_string_to_bigdecimal(JSContext* ctx, const char* buf, int radix, int flags, slimb_t* pexponent) {
+  bfdec_t* a;
+  int ret;
+  JSValue val;
+
+  val = JS_NewBigDecimal(ctx);
+  if (JS_IsException(val))
+    return val;
+  a = JS_GetBigDecimal(val);
+  ret = bfdec_atof(a, buf, NULL, BF_PREC_INF, BF_RNDZ | BF_ATOF_NO_NAN_INF);
+  if (ret & BF_ST_MEM_ERROR) {
+    JS_FreeValue(ctx, val);
+    return JS_ThrowOutOfMemory(ctx);
+  }
+  return val;
+}
+
+#endif
+
+/* return an exception in case of memory error. Return JS_NAN if
+   invalid syntax */
+#ifdef CONFIG_BIGNUM
+JSValue js_atof2(JSContext* ctx, const char* str, const char** pp, int radix, int flags, slimb_t* pexponent)
+#else
+JSValue js_atof(JSContext* ctx, const char* str, const char** pp, int radix, int flags)
+#endif
+{
+  const char *p, *p_start;
+  int sep, is_neg;
+  BOOL is_float, has_legacy_octal;
+  int atod_type = flags & ATOD_TYPE_MASK;
+  char buf1[64], *buf;
+  int i, j, len;
+  BOOL buf_allocated = FALSE;
+  JSValue val;
+
+  /* optional separator between digits */
+  sep = (flags & ATOD_ACCEPT_UNDERSCORES) ? '_' : 256;
+  has_legacy_octal = FALSE;
+
+  p = str;
+  p_start = p;
+  is_neg = 0;
+  if (p[0] == '+') {
+    p++;
+    p_start++;
+    if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN))
+      goto no_radix_prefix;
+  } else if (p[0] == '-') {
+    p++;
+    p_start++;
+    is_neg = 1;
+    if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN))
+      goto no_radix_prefix;
+  }
+  if (p[0] == '0') {
+    if ((p[1] == 'x' || p[1] == 'X') && (radix == 0 || radix == 16)) {
+      p += 2;
+      radix = 16;
+    } else if ((p[1] == 'o' || p[1] == 'O') && radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) {
+      p += 2;
+      radix = 8;
+    } else if ((p[1] == 'b' || p[1] == 'B') && radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) {
+      p += 2;
+      radix = 2;
+    } else if ((p[1] >= '0' && p[1] <= '9') && radix == 0 && (flags & ATOD_ACCEPT_LEGACY_OCTAL)) {
+      int i;
+      has_legacy_octal = TRUE;
+      sep = 256;
+      for (i = 1; (p[i] >= '0' && p[i] <= '7'); i++)
+        continue;
+      if (p[i] == '8' || p[i] == '9')
+        goto no_prefix;
+      p += 1;
+      radix = 8;
+    } else {
+      goto no_prefix;
+    }
+    /* there must be a digit after the prefix */
+    if (to_digit((uint8_t)*p) >= radix)
+      goto fail;
+  no_prefix:;
+  } else {
+  no_radix_prefix:
+    if (!(flags & ATOD_INT_ONLY) && (atod_type == ATOD_TYPE_FLOAT64 || atod_type == ATOD_TYPE_BIG_FLOAT) && strstart(p, "Infinity", &p)) {
+#ifdef CONFIG_BIGNUM
+      if (atod_type == ATOD_TYPE_BIG_FLOAT) {
+        bf_t* a;
+        val = JS_NewBigFloat(ctx);
+        if (JS_IsException(val))
+          goto done;
+        a = JS_GetBigFloat(val);
+        bf_set_inf(a, is_neg);
+      } else
+#endif
+      {
+        double d = 1.0 / 0.0;
+        if (is_neg)
+          d = -d;
+        val = JS_NewFloat64(ctx, d);
+      }
+      goto done;
+    }
+  }
+  if (radix == 0)
+    radix = 10;
+  is_float = FALSE;
+  p_start = p;
+  while (to_digit((uint8_t)*p) < radix || (*p == sep && (radix != 10 || p != p_start + 1 || p[-1] != '0') && to_digit((uint8_t)p[1]) < radix)) {
+    p++;
+  }
+  if (!(flags & ATOD_INT_ONLY)) {
+    if (*p == '.' && (p > p_start || to_digit((uint8_t)p[1]) < radix)) {
+      is_float = TRUE;
+      p++;
+      if (*p == sep)
+        goto fail;
+      while (to_digit((uint8_t)*p) < radix || (*p == sep && to_digit((uint8_t)p[1]) < radix))
+        p++;
+    }
+    if (p > p_start && (((*p == 'e' || *p == 'E') && radix == 10) || ((*p == 'p' || *p == 'P') && (radix == 2 || radix == 8 || radix == 16)))) {
+      const char* p1 = p + 1;
+      is_float = TRUE;
+      if (*p1 == '+') {
+        p1++;
+      } else if (*p1 == '-') {
+        p1++;
+      }
+      if (is_digit((uint8_t)*p1)) {
+        p = p1 + 1;
+        while (is_digit((uint8_t)*p) || (*p == sep && is_digit((uint8_t)p[1])))
+          p++;
+      }
+    }
+  }
+  if (p == p_start)
+    goto fail;
+
+  buf = buf1;
+  buf_allocated = FALSE;
+  len = p - p_start;
+  if (unlikely((len + 2) > sizeof(buf1))) {
+    buf = js_malloc_rt(ctx->rt, len + 2); /* no exception raised */
+    if (!buf)
+      goto mem_error;
+    buf_allocated = TRUE;
+  }
+  /* remove the separators and the radix prefixes */
+  j = 0;
+  if (is_neg)
+    buf[j++] = '-';
+  for (i = 0; i < len; i++) {
+    if (p_start[i] != '_')
+      buf[j++] = p_start[i];
+  }
+  buf[j] = '\0';
+
+#ifdef CONFIG_BIGNUM
+  if (flags & ATOD_ACCEPT_SUFFIX) {
+    if (*p == 'n') {
+      p++;
+      atod_type = ATOD_TYPE_BIG_INT;
+    } else if (*p == 'l') {
+      p++;
+      atod_type = ATOD_TYPE_BIG_FLOAT;
+    } else if (*p == 'm') {
+      p++;
+      atod_type = ATOD_TYPE_BIG_DECIMAL;
+    } else {
+      if (flags & ATOD_MODE_BIGINT) {
+        if (!is_float)
+          atod_type = ATOD_TYPE_BIG_INT;
+        if (has_legacy_octal)
+          goto fail;
+      } else {
+        if (is_float && radix != 10)
+          goto fail;
+      }
+    }
+  } else {
+    if (atod_type == ATOD_TYPE_FLOAT64) {
+      if (flags & ATOD_MODE_BIGINT) {
+        if (!is_float)
+          atod_type = ATOD_TYPE_BIG_INT;
+        if (has_legacy_octal)
+          goto fail;
+      } else {
+        if (is_float && radix != 10)
+          goto fail;
+      }
+    }
+  }
+
+  switch (atod_type) {
+    case ATOD_TYPE_FLOAT64: {
+      double d;
+      d = js_strtod(buf, radix, is_float);
+      /* return int or float64 */
+      val = JS_NewFloat64(ctx, d);
+    } break;
+    case ATOD_TYPE_BIG_INT:
+      if (has_legacy_octal || is_float)
+        goto fail;
+      val = ctx->rt->bigint_ops.from_string(ctx, buf, radix, flags, NULL);
+      break;
+    case ATOD_TYPE_BIG_FLOAT:
+      if (has_legacy_octal)
+        goto fail;
+      val = ctx->rt->bigfloat_ops.from_string(ctx, buf, radix, flags, pexponent);
+      break;
+    case ATOD_TYPE_BIG_DECIMAL:
+      if (radix != 10)
+        goto fail;
+      val = ctx->rt->bigdecimal_ops.from_string(ctx, buf, radix, flags, NULL);
+      break;
+    default:
+      abort();
+  }
+#else
+  {
+    double d;
+    (void)has_legacy_octal;
+    if (is_float && radix != 10)
+      goto fail;
+    d = js_strtod(buf, radix, is_float);
+    val = JS_NewFloat64(ctx, d);
+  }
+#endif
+
+done:
+  if (buf_allocated)
+    js_free_rt(ctx->rt, buf);
+  if (pp)
+    *pp = p;
+  return val;
+fail:
+  val = JS_NAN;
+  goto done;
+mem_error:
+  val = JS_ThrowOutOfMemory(ctx);
+  goto done;
+}
+
+#ifdef CONFIG_BIGNUM
+JSValue js_atof(JSContext* ctx, const char* str, const char** pp, int radix, int flags) {
+  return js_atof2(ctx, str, pp, radix, flags, NULL);
+}
+#endif
+
+BOOL is_safe_integer(double d) {
+  return isfinite(d) && floor(d) == d && fabs(d) <= (double)MAX_SAFE_INTEGER;
+}
+
+int JS_ToIndex(JSContext* ctx, uint64_t* plen, JSValueConst val) {
+  int64_t v;
+  if (JS_ToInt64Sat(ctx, &v, val))
+    return -1;
+  if (v < 0 || v > MAX_SAFE_INTEGER) {
+    JS_ThrowRangeError(ctx, "invalid array index");
+    *plen = 0;
+    return -1;
+  }
+  *plen = v;
+  return 0;
+}
+
+/* convert a value to a length between 0 and MAX_SAFE_INTEGER.
+   return -1 for exception */
+__exception int JS_ToLengthFree(JSContext* ctx, int64_t* plen, JSValue val) {
+  int res = JS_ToInt64Clamp(ctx, plen, val, 0, MAX_SAFE_INTEGER, 0);
+  JS_FreeValue(ctx, val);
+  return res;
+}
+
+/* Note: can return an exception */
+int JS_NumberIsInteger(JSContext* ctx, JSValueConst val) {
+  double d;
+  if (!JS_IsNumber(val))
+    return FALSE;
+  if (unlikely(JS_ToFloat64(ctx, &d, val)))
+    return -1;
+  return isfinite(d) && floor(d) == d;
+}
+
+BOOL JS_NumberIsNegativeOrMinusZero(JSContext* ctx, JSValueConst val) {
+  uint32_t tag;
+
+  tag = JS_VALUE_GET_NORM_TAG(val);
+  switch (tag) {
+    case JS_TAG_INT: {
+      int v;
+      v = JS_VALUE_GET_INT(val);
+      return (v < 0);
+    }
+    case JS_TAG_FLOAT64: {
+      JSFloat64Union u;
+      u.d = JS_VALUE_GET_FLOAT64(val);
+      return (u.u64 >> 63);
+    }
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_INT: {
+      JSBigFloat* p = JS_VALUE_GET_PTR(val);
+      /* Note: integer zeros are not necessarily positive */
+      return p->num.sign && !bf_is_zero(&p->num);
+    }
+    case JS_TAG_BIG_FLOAT: {
+      JSBigFloat* p = JS_VALUE_GET_PTR(val);
+      return p->num.sign;
+    } break;
+    case JS_TAG_BIG_DECIMAL: {
+      JSBigDecimal* p = JS_VALUE_GET_PTR(val);
+      return p->num.sign;
+    } break;
+#endif
+    default:
+      return FALSE;
+  }
+}
+
+#ifdef CONFIG_BIGNUM
+
+JSValue js_bigint_to_string1(JSContext* ctx, JSValueConst val, int radix) {
+  JSValue ret;
+  bf_t a_s, *a;
+  char* str;
+  int saved_sign;
+
+  a = JS_ToBigInt(ctx, &a_s, val);
+  if (!a)
+    return JS_EXCEPTION;
+  saved_sign = a->sign;
+  if (a->expn == BF_EXP_ZERO)
+    a->sign = 0;
+  str = bf_ftoa(NULL, a, radix, 0, BF_RNDZ | BF_FTOA_FORMAT_FRAC | BF_FTOA_JS_QUIRKS);
+  a->sign = saved_sign;
+  JS_FreeBigInt(ctx, a, &a_s);
+  if (!str)
+    return JS_ThrowOutOfMemory(ctx);
+  ret = JS_NewString(ctx, str);
+  bf_free(ctx->bf_ctx, str);
+  return ret;
+}
+
+JSValue js_bigint_to_string(JSContext* ctx, JSValueConst val) {
+  return js_bigint_to_string1(ctx, val, 10);
+}
+
+JSValue js_ftoa(JSContext* ctx, JSValueConst val1, int radix, limb_t prec, bf_flags_t flags) {
+  JSValue val, ret;
+  bf_t a_s, *a;
+  char* str;
+  int saved_sign;
+
+  val = JS_ToNumeric(ctx, val1);
+  if (JS_IsException(val))
+    return val;
+  a = JS_ToBigFloat(ctx, &a_s, val);
+  saved_sign = a->sign;
+  if (a->expn == BF_EXP_ZERO)
+    a->sign = 0;
+  flags |= BF_FTOA_JS_QUIRKS;
+  if ((flags & BF_FTOA_FORMAT_MASK) == BF_FTOA_FORMAT_FREE_MIN) {
+    /* Note: for floating point numbers with a radix which is not
+       a power of two, the current precision is used to compute
+       the number of digits. */
+    if ((radix & (radix - 1)) != 0) {
+      bf_t r_s, *r = &r_s;
+      int prec, flags1;
+      /* must round first */
+      if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) {
+        prec = ctx->fp_env.prec;
+        flags1 = ctx->fp_env.flags & (BF_FLAG_SUBNORMAL | (BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT));
+      } else {
+        prec = 53;
+        flags1 = bf_set_exp_bits(11) | BF_FLAG_SUBNORMAL;
+      }
+      bf_init(ctx->bf_ctx, r);
+      bf_set(r, a);
+      bf_round(r, prec, flags1 | BF_RNDN);
+      str = bf_ftoa(NULL, r, radix, prec, flags1 | flags);
+      bf_delete(r);
+    } else {
+      str = bf_ftoa(NULL, a, radix, BF_PREC_INF, flags);
+    }
+  } else {
+    str = bf_ftoa(NULL, a, radix, prec, flags);
+  }
+  a->sign = saved_sign;
+  if (a == &a_s)
+    bf_delete(a);
+  JS_FreeValue(ctx, val);
+  if (!str)
+    return JS_ThrowOutOfMemory(ctx);
+  ret = JS_NewString(ctx, str);
+  bf_free(ctx->bf_ctx, str);
+  return ret;
+}
+
+JSValue js_bigfloat_to_string(JSContext* ctx, JSValueConst val) {
+  return js_ftoa(ctx, val, 10, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN);
+}
+
+JSValue js_bigdecimal_to_string1(JSContext* ctx, JSValueConst val, limb_t prec, int flags) {
+  JSValue ret;
+  bfdec_t* a;
+  char* str;
+  int saved_sign;
+
+  a = JS_ToBigDecimal(ctx, val);
+  saved_sign = a->sign;
+  if (a->expn == BF_EXP_ZERO)
+    a->sign = 0;
+  str = bfdec_ftoa(NULL, a, prec, flags | BF_FTOA_JS_QUIRKS);
+  a->sign = saved_sign;
+  if (!str)
+    return JS_ThrowOutOfMemory(ctx);
+  ret = JS_NewString(ctx, str);
+  bf_free(ctx->bf_ctx, str);
+  return ret;
+}
+
+JSValue js_bigdecimal_to_string(JSContext* ctx, JSValueConst val) {
+  return js_bigdecimal_to_string1(ctx, val, 0, BF_RNDZ | BF_FTOA_FORMAT_FREE);
+}
+
+#endif /* CONFIG_BIGNUM */
+
+/* 2 <= base <= 36 */
+char* i64toa(char* buf_end, int64_t n, unsigned int base) {
+  char* q = buf_end;
+  int digit, is_neg;
+
+  is_neg = 0;
+  if (n < 0) {
+    is_neg = 1;
+    n = -n;
+  }
+  *--q = '\0';
+  do {
+    digit = (uint64_t)n % base;
+    n = (uint64_t)n / base;
+    if (digit < 10)
+      digit += '0';
+    else
+      digit += 'a' - 10;
+    *--q = digit;
+  } while (n != 0);
+  if (is_neg)
+    *--q = '-';
+  return q;
+}
+
+/* buf1 contains the printf result */
+void js_ecvt1(double d, int n_digits, int* decpt, int* sign, char* buf, int rounding_mode, char* buf1, int buf1_size) {
+  if (rounding_mode != FE_TONEAREST)
+    fesetround(rounding_mode);
+  snprintf(buf1, buf1_size, "%+.*e", n_digits - 1, d);
+  if (rounding_mode != FE_TONEAREST)
+    fesetround(FE_TONEAREST);
+  *sign = (buf1[0] == '-');
+  /* mantissa */
+  buf[0] = buf1[1];
+  if (n_digits > 1)
+    memcpy(buf + 1, buf1 + 3, n_digits - 1);
+  buf[n_digits] = '\0';
+  /* exponent */
+  *decpt = atoi(buf1 + n_digits + 2 + (n_digits > 1)) + 1;
+}
+
+/* needed because ecvt usually limits the number of digits to
+   17. Return the number of digits. */
+int js_ecvt(double d, int n_digits, int* decpt, int* sign, char* buf, BOOL is_fixed) {
+  int rounding_mode;
+  char buf_tmp[JS_DTOA_BUF_SIZE];
+
+  if (!is_fixed) {
+    unsigned int n_digits_min, n_digits_max;
+    /* find the minimum amount of digits (XXX: inefficient but simple) */
+    n_digits_min = 1;
+    n_digits_max = 17;
+    while (n_digits_min < n_digits_max) {
+      n_digits = (n_digits_min + n_digits_max) / 2;
+      js_ecvt1(d, n_digits, decpt, sign, buf, FE_TONEAREST, buf_tmp, sizeof(buf_tmp));
+      if (strtod(buf_tmp, NULL) == d) {
+        /* no need to keep the trailing zeros */
+        while (n_digits >= 2 && buf[n_digits - 1] == '0')
+          n_digits--;
+        n_digits_max = n_digits;
+      } else {
+        n_digits_min = n_digits + 1;
+      }
+    }
+    n_digits = n_digits_max;
+    rounding_mode = FE_TONEAREST;
+  } else {
+    rounding_mode = FE_TONEAREST;
+#ifdef CONFIG_PRINTF_RNDN
+    {
+      char buf1[JS_DTOA_BUF_SIZE], buf2[JS_DTOA_BUF_SIZE];
+      int decpt1, sign1, decpt2, sign2;
+      /* The JS rounding is specified as round to nearest ties away
+         from zero (RNDNA), but in printf the "ties" case is not
+         specified (for example it is RNDN for glibc, RNDNA for
+         Windows), so we must round manually. */
+      js_ecvt1(d, n_digits + 1, &decpt1, &sign1, buf1, FE_TONEAREST, buf_tmp, sizeof(buf_tmp));
+      /* XXX: could use 2 digits to reduce the average running time */
+      if (buf1[n_digits] == '5') {
+        js_ecvt1(d, n_digits + 1, &decpt1, &sign1, buf1, FE_DOWNWARD, buf_tmp, sizeof(buf_tmp));
+        js_ecvt1(d, n_digits + 1, &decpt2, &sign2, buf2, FE_UPWARD, buf_tmp, sizeof(buf_tmp));
+        if (memcmp(buf1, buf2, n_digits + 1) == 0 && decpt1 == decpt2) {
+          /* exact result: round away from zero */
+          if (sign1)
+            rounding_mode = FE_DOWNWARD;
+          else
+            rounding_mode = FE_UPWARD;
+        }
+      }
+    }
+#endif /* CONFIG_PRINTF_RNDN */
+  }
+  js_ecvt1(d, n_digits, decpt, sign, buf, rounding_mode, buf_tmp, sizeof(buf_tmp));
+  return n_digits;
+}
+
+int js_fcvt1(char* buf, int buf_size, double d, int n_digits, int rounding_mode) {
+  int n;
+  if (rounding_mode != FE_TONEAREST)
+    fesetround(rounding_mode);
+  n = snprintf(buf, buf_size, "%.*f", n_digits, d);
+  if (rounding_mode != FE_TONEAREST)
+    fesetround(FE_TONEAREST);
+  assert(n < buf_size);
+  return n;
+}
+
+void js_fcvt(char* buf, int buf_size, double d, int n_digits) {
+  int rounding_mode;
+  rounding_mode = FE_TONEAREST;
+#ifdef CONFIG_PRINTF_RNDN
+  {
+    int n1, n2;
+    char buf1[JS_DTOA_BUF_SIZE];
+    char buf2[JS_DTOA_BUF_SIZE];
+
+    /* The JS rounding is specified as round to nearest ties away from
+       zero (RNDNA), but in printf the "ties" case is not specified
+       (for example it is RNDN for glibc, RNDNA for Windows), so we
+       must round manually. */
+    n1 = js_fcvt1(buf1, sizeof(buf1), d, n_digits + 1, FE_TONEAREST);
+    rounding_mode = FE_TONEAREST;
+    /* XXX: could use 2 digits to reduce the average running time */
+    if (buf1[n1 - 1] == '5') {
+      n1 = js_fcvt1(buf1, sizeof(buf1), d, n_digits + 1, FE_DOWNWARD);
+      n2 = js_fcvt1(buf2, sizeof(buf2), d, n_digits + 1, FE_UPWARD);
+      if (n1 == n2 && memcmp(buf1, buf2, n1) == 0) {
+        /* exact result: round away from zero */
+        if (buf1[0] == '-')
+          rounding_mode = FE_DOWNWARD;
+        else
+          rounding_mode = FE_UPWARD;
+      }
+    }
+  }
+#endif /* CONFIG_PRINTF_RNDN */
+  js_fcvt1(buf, buf_size, d, n_digits, rounding_mode);
+}
+
+/* XXX: slow and maybe not fully correct. Use libbf when it is fast enough.
+   XXX: radix != 10 is only supported for small integers
+*/
+void js_dtoa1(char* buf, double d, int radix, int n_digits, int flags) {
+  char* q;
+
+  if (!isfinite(d)) {
+    if (isnan(d)) {
+      strcpy(buf, "NaN");
+    } else {
+      q = buf;
+      if (d < 0)
+        *q++ = '-';
+      strcpy(q, "Infinity");
+    }
+  } else if (flags == JS_DTOA_VAR_FORMAT) {
+    int64_t i64;
+    char buf1[70], *ptr;
+    i64 = (int64_t)d;
+    if (d != i64 || i64 > MAX_SAFE_INTEGER || i64 < -MAX_SAFE_INTEGER)
+      goto generic_conv;
+    /* fast path for integers */
+    ptr = i64toa(buf1 + sizeof(buf1), i64, radix);
+    strcpy(buf, ptr);
+  } else {
+    if (d == 0.0)
+      d = 0.0; /* convert -0 to 0 */
+    if (flags == JS_DTOA_FRAC_FORMAT) {
+      js_fcvt(buf, JS_DTOA_BUF_SIZE, d, n_digits);
+    } else {
+      char buf1[JS_DTOA_BUF_SIZE];
+      int sign, decpt, k, n, i, p, n_max;
+      BOOL is_fixed;
+    generic_conv:
+      is_fixed = ((flags & 3) == JS_DTOA_FIXED_FORMAT);
+      if (is_fixed) {
+        n_max = n_digits;
+      } else {
+        n_max = 21;
+      }
+      /* the number has k digits (k >= 1) */
+      k = js_ecvt(d, n_digits, &decpt, &sign, buf1, is_fixed);
+      n = decpt; /* d=10^(n-k)*(buf1) i.e. d= < x.yyyy 10^(n-1) */
+      q = buf;
+      if (sign)
+        *q++ = '-';
+      if (flags & JS_DTOA_FORCE_EXP)
+        goto force_exp;
+      if (n >= 1 && n <= n_max) {
+        if (k <= n) {
+          memcpy(q, buf1, k);
+          q += k;
+          for (i = 0; i < (n - k); i++)
+            *q++ = '0';
+          *q = '\0';
+        } else {
+          /* k > n */
+          memcpy(q, buf1, n);
+          q += n;
+          *q++ = '.';
+          for (i = 0; i < (k - n); i++)
+            *q++ = buf1[n + i];
+          *q = '\0';
+        }
+      } else if (n >= -5 && n <= 0) {
+        *q++ = '0';
+        *q++ = '.';
+        for (i = 0; i < -n; i++)
+          *q++ = '0';
+        memcpy(q, buf1, k);
+        q += k;
+        *q = '\0';
+      } else {
+      force_exp:
+        /* exponential notation */
+        *q++ = buf1[0];
+        if (k > 1) {
+          *q++ = '.';
+          for (i = 1; i < k; i++)
+            *q++ = buf1[i];
+        }
+        *q++ = 'e';
+        p = n - 1;
+        if (p >= 0)
+          *q++ = '+';
+        sprintf(q, "%d", p);
+      }
+    }
+  }
+}
+
+JSValue js_dtoa(JSContext* ctx, double d, int radix, int n_digits, int flags) {
+  char buf[JS_DTOA_BUF_SIZE];
+  js_dtoa1(buf, d, radix, n_digits, flags);
+  return JS_NewString(ctx, buf);
+}
+
+JSValue JS_ToStringInternal(JSContext* ctx, JSValueConst val, BOOL is_ToPropertyKey) {
+  uint32_t tag;
+  const char* str;
+  char buf[32];
+
+  tag = JS_VALUE_GET_NORM_TAG(val);
+  switch (tag) {
+    case JS_TAG_STRING:
+      return JS_DupValue(ctx, val);
+    case JS_TAG_INT:
+      snprintf(buf, sizeof(buf), "%d", JS_VALUE_GET_INT(val));
+      str = buf;
+      goto new_string;
+    case JS_TAG_BOOL:
+      return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ? JS_ATOM_true : JS_ATOM_false);
+    case JS_TAG_NULL:
+      return JS_AtomToString(ctx, JS_ATOM_null);
+    case JS_TAG_UNDEFINED:
+      return JS_AtomToString(ctx, JS_ATOM_undefined);
+    case JS_TAG_EXCEPTION:
+      return JS_EXCEPTION;
+    case JS_TAG_OBJECT: {
+      JSValue val1, ret;
+      val1 = JS_ToPrimitive(ctx, val, HINT_STRING);
+      if (JS_IsException(val1))
+        return val1;
+      ret = JS_ToStringInternal(ctx, val1, is_ToPropertyKey);
+      JS_FreeValue(ctx, val1);
+      return ret;
+    } break;
+    case JS_TAG_FUNCTION_BYTECODE:
+      str = "[function bytecode]";
+      goto new_string;
+    case JS_TAG_SYMBOL:
+      if (is_ToPropertyKey) {
+        return JS_DupValue(ctx, val);
+      } else {
+        return JS_ThrowTypeError(ctx, "cannot convert symbol to string");
+      }
+    case JS_TAG_FLOAT64:
+      return js_dtoa(ctx, JS_VALUE_GET_FLOAT64(val), 10, 0, JS_DTOA_VAR_FORMAT);
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_INT:
+      return ctx->rt->bigint_ops.to_string(ctx, val);
+    case JS_TAG_BIG_FLOAT:
+      return ctx->rt->bigfloat_ops.to_string(ctx, val);
+    case JS_TAG_BIG_DECIMAL:
+      return ctx->rt->bigdecimal_ops.to_string(ctx, val);
+#endif
+    default:
+      str = "[unsupported type]";
+    new_string:
+      return JS_NewString(ctx, str);
+  }
+}
+
+JSValue JS_ToString(JSContext* ctx, JSValueConst val) {
+  return JS_ToStringInternal(ctx, val, FALSE);
+}
+
+JSValue JS_ToStringFree(JSContext* ctx, JSValue val) {
+  JSValue ret;
+  ret = JS_ToString(ctx, val);
+  JS_FreeValue(ctx, val);
+  return ret;
+}
+
+JSValue JS_ToLocaleStringFree(JSContext* ctx, JSValue val) {
+  if (JS_IsUndefined(val) || JS_IsNull(val))
+    return JS_ToStringFree(ctx, val);
+  return JS_InvokeFree(ctx, val, JS_ATOM_toLocaleString, 0, NULL);
+}
+
+JSValue JS_ToPropertyKey(JSContext* ctx, JSValueConst val) {
+  return JS_ToStringInternal(ctx, val, TRUE);
+}
+
+JSValue JS_ToStringCheckObject(JSContext* ctx, JSValueConst val) {
+  uint32_t tag = JS_VALUE_GET_TAG(val);
+  if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)
+    return JS_ThrowTypeError(ctx, "null or undefined are forbidden");
+  return JS_ToString(ctx, val);
+}
+
+JSValue JS_ToQuotedString(JSContext* ctx, JSValueConst val1) {
+  JSValue val;
+  JSString* p;
+  int i;
+  uint32_t c;
+  StringBuffer b_s, *b = &b_s;
+  char buf[16];
+
+  val = JS_ToStringCheckObject(ctx, val1);
+  if (JS_IsException(val))
+    return val;
+  p = JS_VALUE_GET_STRING(val);
+
+  if (string_buffer_init(ctx, b, p->len + 2))
+    goto fail;
+
+  if (string_buffer_putc8(b, '\"'))
+    goto fail;
+  for (i = 0; i < p->len;) {
+    c = string_getc(p, &i);
+    switch (c) {
+      case '\t':
+        c = 't';
+        goto quote;
+      case '\r':
+        c = 'r';
+        goto quote;
+      case '\n':
+        c = 'n';
+        goto quote;
+      case '\b':
+        c = 'b';
+        goto quote;
+      case '\f':
+        c = 'f';
+        goto quote;
+      case '\"':
+      case '\\':
+      quote:
+        if (string_buffer_putc8(b, '\\'))
+          goto fail;
+        if (string_buffer_putc8(b, c))
+          goto fail;
+        break;
+      default:
+        if (c < 32 || (c >= 0xd800 && c < 0xe000)) {
+          snprintf(buf, sizeof(buf), "\\u%04x", c);
+          if (string_buffer_puts8(b, buf))
+            goto fail;
+        } else {
+          if (string_buffer_putc(b, c))
+            goto fail;
+        }
+        break;
+    }
+  }
+  if (string_buffer_putc8(b, '\"'))
+    goto fail;
+  JS_FreeValue(ctx, val);
+  return string_buffer_end(b);
+fail:
+  JS_FreeValue(ctx, val);
+  string_buffer_free(b);
+  return JS_EXCEPTION;
+}
diff --git a/src/core/convertion.h b/src/core/convertion.h
new file mode 100644
index 000000000..5e9256eb3
--- /dev/null
+++ b/src/core/convertion.h
@@ -0,0 +1,168 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_CONVERTION_H
+#define QUICKJS_CONVERTION_H
+
+#include "quickjs/quickjs.h"
+#include "quickjs/cutils.h"
+#include "types.h"
+
+#define HINT_STRING 0
+#define HINT_NUMBER 1
+#define HINT_NONE 2
+/* don't try Symbol.toPrimitive */
+#define HINT_FORCE_ORDINARY (1 << 4)
+
+#define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1)
+
+/* maximum buffer size for js_dtoa */
+#define JS_DTOA_BUF_SIZE 128
+
+/* radix != 10 is only supported with flags = JS_DTOA_VAR_FORMAT */
+/* use as many digits as necessary */
+#define JS_DTOA_VAR_FORMAT (0 << 0)
+/* use n_digits significant digits (1 <= n_digits <= 101) */
+#define JS_DTOA_FIXED_FORMAT (1 << 0)
+/* force fractional format: [-]dd.dd with n_digits fractional digits */
+#define JS_DTOA_FRAC_FORMAT (2 << 0)
+/* force exponential notation either in fixed or variable format */
+#define JS_DTOA_FORCE_EXP (1 << 2)
+
+typedef enum JSToNumberHintEnum {
+  TON_FLAG_NUMBER,
+  TON_FLAG_NUMERIC,
+} JSToNumberHintEnum;
+
+int skip_spaces(const char* pc);
+JSValue JS_ToPrimitiveFree(JSContext* ctx, JSValue val, int hint);
+JSValue JS_ToPrimitive(JSContext* ctx, JSValueConst val, int hint);
+
+__exception int JS_ToArrayLengthFree(JSContext* ctx, uint32_t* plen, JSValue val, BOOL is_array_ctor);
+
+JSValue JS_ToNumberFree(JSContext* ctx, JSValue val);
+JSValue JS_ToNumericFree(JSContext* ctx, JSValue val);
+JSValue JS_ToNumeric(JSContext* ctx, JSValueConst val);
+__exception int __JS_ToFloat64Free(JSContext* ctx, double* pres, JSValue val);
+/* same as JS_ToNumber() but return 0 in case of NaN/Undefined */
+__maybe_unused JSValue JS_ToIntegerFree(JSContext* ctx, JSValue val);
+/* Note: the integer value is satured to 32 bits */
+int JS_ToInt32SatFree(JSContext* ctx, int* pres, JSValue val);
+int JS_ToInt32Sat(JSContext* ctx, int* pres, JSValueConst val);
+int JS_ToInt32Clamp(JSContext* ctx, int* pres, JSValueConst val, int min, int max, int min_offset);
+int JS_ToInt64SatFree(JSContext* ctx, int64_t* pres, JSValue val);
+int JS_ToInt64Sat(JSContext* ctx, int64_t* pres, JSValueConst val);
+int JS_ToInt64Clamp(JSContext* ctx, int64_t* pres, JSValueConst val, int64_t min, int64_t max, int64_t neg_offset);
+/* Same as JS_ToInt32Free() but with a 64 bit result. Return (<0, 0)
+   in case of exception */
+int JS_ToInt64Free(JSContext* ctx, int64_t* pres, JSValue val);
+JSValue JS_ToNumber(JSContext* ctx, JSValueConst val);
+
+JSValue JS_ToStringFree(JSContext* ctx, JSValue val);
+int JS_ToBoolFree(JSContext* ctx, JSValue val);
+int JS_ToInt32Free(JSContext* ctx, int32_t* pres, JSValue val);
+static inline int JS_ToFloat64Free(JSContext* ctx, double* pres, JSValue val) {
+  uint32_t tag;
+
+  tag = JS_VALUE_GET_TAG(val);
+  if (tag <= JS_TAG_NULL) {
+    *pres = JS_VALUE_GET_INT(val);
+    return 0;
+  } else if (JS_TAG_IS_FLOAT64(tag)) {
+    *pres = JS_VALUE_GET_FLOAT64(val);
+    return 0;
+  } else {
+    return __JS_ToFloat64Free(ctx, pres, val);
+  }
+}
+
+static inline int JS_ToUint32Free(JSContext* ctx, uint32_t* pres, JSValue val) {
+  return JS_ToInt32Free(ctx, (int32_t*)pres, val);
+}
+int JS_ToUint8ClampFree(JSContext* ctx, int32_t* pres, JSValue val);
+
+static inline int to_digit(int c) {
+  if (c >= '0' && c <= '9')
+    return c - '0';
+  else if (c >= 'A' && c <= 'Z')
+    return c - 'A' + 10;
+  else if (c >= 'a' && c <= 'z')
+    return c - 'a' + 10;
+  else
+    return 36;
+}
+/* XXX: remove */
+double js_strtod(const char* p, int radix, BOOL is_float);
+
+#ifdef CONFIG_BIGNUM
+JSValue js_string_to_bigint(JSContext* ctx, const char* buf, int radix, int flags, slimb_t* pexponent);
+JSValue js_string_to_bigfloat(JSContext* ctx, const char* buf, int radix, int flags, slimb_t* pexponent);
+JSValue js_string_to_bigdecimal(JSContext* ctx, const char* buf, int radix, int flags, slimb_t* pexponent);
+JSValue js_atof(JSContext* ctx, const char* str, const char** pp, int radix, int flags);
+JSValue js_atof2(JSContext* ctx, const char* str, const char** pp, int radix, int flags, slimb_t* pexponent);
+#else
+JSValue js_atof(JSContext* ctx, const char* str, const char** pp, int radix, int flags);
+#endif
+
+BOOL is_safe_integer(double d);
+/* convert a value to a length between 0 and MAX_SAFE_INTEGER.
+   return -1 for exception */
+__exception int JS_ToLengthFree(JSContext* ctx, int64_t* plen, JSValue val);
+/* Note: can return an exception */
+int JS_NumberIsInteger(JSContext* ctx, JSValueConst val);
+BOOL JS_NumberIsNegativeOrMinusZero(JSContext* ctx, JSValueConst val);
+
+#ifdef CONFIG_BIGNUM
+JSValue js_bigint_to_string1(JSContext* ctx, JSValueConst val, int radix);
+JSValue js_bigint_to_string(JSContext* ctx, JSValueConst val);
+JSValue js_ftoa(JSContext* ctx, JSValueConst val1, int radix, limb_t prec, bf_flags_t flags);
+JSValue js_bigfloat_to_string(JSContext* ctx, JSValueConst val);
+JSValue js_bigdecimal_to_string1(JSContext* ctx, JSValueConst val, limb_t prec, int flags);
+JSValue js_bigdecimal_to_string(JSContext* ctx, JSValueConst val);
+#endif
+
+/* 2 <= base <= 36 */
+char* i64toa(char* buf_end, int64_t n, unsigned int base);
+/* buf1 contains the printf result */
+void js_ecvt1(double d, int n_digits, int* decpt, int* sign, char* buf, int rounding_mode, char* buf1, int buf1_size);
+
+/* needed because ecvt usually limits the number of digits to
+   17. Return the number of digits. */
+int js_ecvt(double d, int n_digits, int* decpt, int* sign, char* buf, BOOL is_fixed);
+int js_fcvt1(char* buf, int buf_size, double d, int n_digits, int rounding_mode);
+void js_fcvt(char* buf, int buf_size, double d, int n_digits);
+
+/* XXX: slow and maybe not fully correct. Use libbf when it is fast enough.
+   XXX: radix != 10 is only supported for small integers
+*/
+void js_dtoa1(char* buf, double d, int radix, int n_digits, int flags);
+JSValue js_dtoa(JSContext* ctx, double d, int radix, int n_digits, int flags);
+JSValue JS_ToStringInternal(JSContext* ctx, JSValueConst val, BOOL is_ToPropertyKey);
+
+JSValue JS_ToLocaleStringFree(JSContext* ctx, JSValue val);
+JSValue JS_ToStringCheckObject(JSContext* ctx, JSValueConst val);
+JSValue JS_ToQuotedString(JSContext* ctx, JSValueConst val1);
+
+#endif
\ No newline at end of file
diff --git a/src/core/exception.c b/src/core/exception.c
new file mode 100644
index 000000000..f25b88134
--- /dev/null
+++ b/src/core/exception.c
@@ -0,0 +1,257 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "exception.h"
+#include "builtins/js-function.h"
+#include "runtime.h"
+#include "string.h"
+
+JSValue JS_NewError(JSContext* ctx) {
+  return JS_NewObjectClass(ctx, JS_CLASS_ERROR);
+}
+
+JSValue JS_ThrowError2(JSContext* ctx, JSErrorEnum error_num, const char* fmt, va_list ap, BOOL add_backtrace) {
+  char buf[256];
+  JSValue obj, ret;
+
+  vsnprintf(buf, sizeof(buf), fmt, ap);
+  obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[error_num], JS_CLASS_ERROR);
+  if (unlikely(JS_IsException(obj))) {
+    /* out of memory: throw JS_NULL to avoid recursing */
+    obj = JS_NULL;
+  } else {
+    JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, JS_NewString(ctx, buf), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+  }
+  if (add_backtrace) {
+    build_backtrace(ctx, obj, NULL, 0, 0);
+  }
+  ret = JS_Throw(ctx, obj);
+  return ret;
+}
+
+JSValue JS_ThrowError(JSContext* ctx, JSErrorEnum error_num, const char* fmt, va_list ap) {
+  JSRuntime* rt = ctx->rt;
+  JSStackFrame* sf;
+  BOOL add_backtrace;
+
+  /* the backtrace is added later if called from a bytecode function */
+  sf = rt->current_stack_frame;
+  add_backtrace = !rt->in_out_of_memory && (!sf || (JS_GetFunctionBytecode(sf->cur_func) == NULL));
+  return JS_ThrowError2(ctx, error_num, fmt, ap, add_backtrace);
+}
+
+JSValue __attribute__((format(printf, 2, 3))) JS_ThrowSyntaxError(JSContext* ctx, const char* fmt, ...) {
+  JSValue val;
+  va_list ap;
+
+  va_start(ap, fmt);
+  val = JS_ThrowError(ctx, JS_SYNTAX_ERROR, fmt, ap);
+  va_end(ap);
+  return val;
+}
+
+JSValue __attribute__((format(printf, 2, 3))) JS_ThrowTypeError(JSContext* ctx, const char* fmt, ...) {
+  JSValue val;
+  va_list ap;
+
+  va_start(ap, fmt);
+  val = JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);
+  va_end(ap);
+  return val;
+}
+
+int __attribute__((format(printf, 3, 4)))
+JS_ThrowTypeErrorOrFalse(JSContext* ctx, int flags, const char* fmt, ...) {
+  va_list ap;
+
+  if ((flags & JS_PROP_THROW) || ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
+    va_start(ap, fmt);
+    JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);
+    va_end(ap);
+    return -1;
+  } else {
+    return FALSE;
+  }
+}
+
+/* never use it directly */
+JSValue __attribute__((format(printf, 3, 4)))
+__JS_ThrowTypeErrorAtom(JSContext* ctx, JSAtom atom, const char* fmt, ...) {
+  char buf[ATOM_GET_STR_BUF_SIZE];
+  return JS_ThrowTypeError(ctx, fmt, JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
+}
+
+/* never use it directly */
+JSValue __attribute__((format(printf, 3, 4)))
+__JS_ThrowSyntaxErrorAtom(JSContext* ctx, JSAtom atom, const char* fmt, ...) {
+  char buf[ATOM_GET_STR_BUF_SIZE];
+  return JS_ThrowSyntaxError(ctx, fmt, JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
+}
+
+/* WARNING: obj is freed */
+JSValue JS_Throw(JSContext *ctx, JSValue obj)
+{
+  JSRuntime *rt = ctx->rt;
+  JS_FreeValue(ctx, rt->current_exception);
+  rt->current_exception = obj;
+  return JS_EXCEPTION;
+}
+
+/* return the pending exception (cannot be called twice). */
+JSValue JS_GetException(JSContext *ctx)
+{
+  JSValue val;
+  JSRuntime *rt = ctx->rt;
+  val = rt->current_exception;
+  rt->current_exception = JS_NULL;
+  return val;
+}
+
+JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom)
+{
+  return JS_ThrowTypeErrorAtom(ctx, "private class field '%s' does not exist",
+                               atom);
+}
+
+int JS_ThrowTypeErrorReadOnly(JSContext* ctx, int flags, JSAtom atom) {
+  if ((flags & JS_PROP_THROW) || ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
+    JS_ThrowTypeErrorAtom(ctx, "'%s' is read-only", atom);
+    return -1;
+  } else {
+    return FALSE;
+  }
+}
+
+JSValue __attribute__((format(printf, 2, 3))) JS_ThrowReferenceError(JSContext* ctx, const char* fmt, ...) {
+  JSValue val;
+  va_list ap;
+
+  va_start(ap, fmt);
+  val = JS_ThrowError(ctx, JS_REFERENCE_ERROR, fmt, ap);
+  va_end(ap);
+  return val;
+}
+
+JSValue __attribute__((format(printf, 2, 3))) JS_ThrowRangeError(JSContext* ctx, const char* fmt, ...) {
+  JSValue val;
+  va_list ap;
+
+  va_start(ap, fmt);
+  val = JS_ThrowError(ctx, JS_RANGE_ERROR, fmt, ap);
+  va_end(ap);
+  return val;
+}
+
+JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext* ctx, const char* fmt, ...) {
+  JSValue val;
+  va_list ap;
+
+  va_start(ap, fmt);
+  val = JS_ThrowError(ctx, JS_INTERNAL_ERROR, fmt, ap);
+  va_end(ap);
+  return val;
+}
+
+JSValue JS_ThrowOutOfMemory(JSContext* ctx) {
+  JSRuntime* rt = ctx->rt;
+  if (!rt->in_out_of_memory) {
+    rt->in_out_of_memory = TRUE;
+    JS_ThrowInternalError(ctx, "out of memory");
+    rt->in_out_of_memory = FALSE;
+  }
+  return JS_EXCEPTION;
+}
+
+JSValue JS_ThrowStackOverflow(JSContext* ctx) {
+  return JS_ThrowInternalError(ctx, "stack overflow");
+}
+
+JSValue JS_ThrowTypeErrorNotAnObject(JSContext* ctx) {
+  return JS_ThrowTypeError(ctx, "not an object");
+}
+
+JSValue JS_ThrowTypeErrorNotASymbol(JSContext* ctx) {
+  return JS_ThrowTypeError(ctx, "not a symbol");
+}
+
+JSValue JS_ThrowReferenceErrorNotDefined(JSContext* ctx, JSAtom name) {
+  char buf[ATOM_GET_STR_BUF_SIZE];
+  return JS_ThrowReferenceError(ctx, "'%s' is not defined", JS_AtomGetStr(ctx, buf, sizeof(buf), name));
+}
+
+JSValue JS_ThrowReferenceErrorUninitialized(JSContext* ctx, JSAtom name) {
+  char buf[ATOM_GET_STR_BUF_SIZE];
+  return JS_ThrowReferenceError(ctx, "%s is not initialized",
+                                name == JS_ATOM_NULL ? "lexical variable" : JS_AtomGetStr(ctx, buf, sizeof(buf), name));
+}
+
+JSValue JS_ThrowReferenceErrorUninitialized2(JSContext* ctx, JSFunctionBytecode* b, int idx, BOOL is_ref) {
+  JSAtom atom = JS_ATOM_NULL;
+  if (is_ref) {
+    atom = b->closure_var[idx].var_name;
+  } else {
+    /* not present if the function is stripped and contains no eval() */
+    if (b->vardefs)
+      atom = b->vardefs[b->arg_count + idx].var_name;
+  }
+  return JS_ThrowReferenceErrorUninitialized(ctx, atom);
+}
+
+JSValue JS_ThrowTypeErrorInvalidClass(JSContext* ctx, int class_id) {
+  JSRuntime* rt = ctx->rt;
+  JSAtom name;
+  name = rt->class_array[class_id].class_name;
+  return JS_ThrowTypeErrorAtom(ctx, "%s object expected", name);
+}
+
+BOOL JS_IsError(JSContext* ctx, JSValueConst val) {
+  JSObject* p;
+  if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
+    return FALSE;
+  p = JS_VALUE_GET_OBJ(val);
+  return (p->class_id == JS_CLASS_ERROR);
+}
+
+/* used to avoid catching interrupt exceptions */
+BOOL JS_IsUncatchableError(JSContext* ctx, JSValueConst val) {
+  JSObject* p;
+  if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
+    return FALSE;
+  p = JS_VALUE_GET_OBJ(val);
+  return p->class_id == JS_CLASS_ERROR && p->is_uncatchable_error;
+}
+
+void JS_SetUncatchableError(JSContext* ctx, JSValueConst val, BOOL flag) {
+  JSObject* p;
+  if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
+    return;
+  p = JS_VALUE_GET_OBJ(val);
+  if (p->class_id == JS_CLASS_ERROR)
+    p->is_uncatchable_error = flag;
+}
+
+void JS_ResetUncatchableError(JSContext* ctx) {
+  JS_SetUncatchableError(ctx, ctx->rt->current_exception, FALSE);
+}
\ No newline at end of file
diff --git a/src/core/exception.h b/src/core/exception.h
new file mode 100644
index 000000000..8f2869508
--- /dev/null
+++ b/src/core/exception.h
@@ -0,0 +1,78 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_EXCEPTION_H
+#define QUICKJS_EXCEPTION_H
+
+#include "quickjs/cutils.h"
+#include "quickjs/quickjs.h"
+#include "types.h"
+
+#define JS_DEFINE_CLASS_HAS_HERITAGE (1 << 0)
+
+/* %s is replaced by 'atom'. The macro is used so that gcc can check
+    the format string. */
+#define JS_ThrowTypeErrorAtom(ctx, fmt, atom) __JS_ThrowTypeErrorAtom(ctx, atom, fmt, "")
+#define JS_ThrowSyntaxErrorAtom(ctx, fmt, atom) __JS_ThrowSyntaxErrorAtom(ctx, atom, fmt, "")
+
+JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext* ctx, const char* fmt, ...);
+JSValue JS_ThrowError2(JSContext* ctx, JSErrorEnum error_num, const char* fmt, va_list ap, BOOL add_backtrace);
+JSValue JS_ThrowError(JSContext* ctx, JSErrorEnum error_num, const char* fmt, va_list ap);
+
+int __attribute__((format(printf, 3, 4))) JS_ThrowTypeErrorOrFalse(JSContext* ctx, int flags, const char* fmt, ...);
+JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowTypeErrorAtom(JSContext* ctx, JSAtom atom, const char* fmt, ...);
+JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowSyntaxErrorAtom(JSContext* ctx, JSAtom atom, const char* fmt, ...);
+
+JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext* ctx, JSAtom atom);
+
+int JS_ThrowTypeErrorReadOnly(JSContext* ctx, int flags, JSAtom atom);
+JSValue JS_ThrowOutOfMemory(JSContext* ctx);
+JSValue JS_ThrowTypeErrorRevokedProxy(JSContext* ctx);
+JSValue JS_ThrowStackOverflow(JSContext* ctx);
+JSValue JS_ThrowTypeErrorNotAnObject(JSContext* ctx);
+JSValue JS_ThrowTypeErrorNotASymbol(JSContext* ctx);
+JSValue JS_ThrowReferenceErrorNotDefined(JSContext* ctx, JSAtom name);
+JSValue JS_ThrowReferenceErrorUninitialized(JSContext* ctx, JSAtom name);
+JSValue JS_ThrowReferenceErrorUninitialized2(JSContext* ctx, JSFunctionBytecode* b, int idx, BOOL is_ref);
+JSValue JS_ThrowTypeErrorInvalidClass(JSContext* ctx, int class_id);
+
+void JS_SetUncatchableError(JSContext* ctx, JSValueConst val, BOOL flag);
+
+/* used to avoid catching interrupt exceptions */
+BOOL JS_IsUncatchableError(JSContext* ctx, JSValueConst val);
+
+JSValue JS_Throw(JSContext* ctx, JSValue obj);
+JSValue JS_GetException(JSContext* ctx);
+JS_BOOL JS_IsError(JSContext* ctx, JSValueConst val);
+void JS_ResetUncatchableError(JSContext* ctx);
+JSValue JS_NewError(JSContext* ctx);
+JSValue __js_printf_like(2, 3) JS_ThrowSyntaxError(JSContext* ctx, const char* fmt, ...);
+JSValue __js_printf_like(2, 3) JS_ThrowTypeError(JSContext* ctx, const char* fmt, ...);
+JSValue __js_printf_like(2, 3) JS_ThrowReferenceError(JSContext* ctx, const char* fmt, ...);
+JSValue __js_printf_like(2, 3) JS_ThrowRangeError(JSContext* ctx, const char* fmt, ...);
+JSValue __js_printf_like(2, 3) JS_ThrowInternalError(JSContext* ctx, const char* fmt, ...);
+JSValue JS_ThrowOutOfMemory(JSContext* ctx);
+
+#endif
\ No newline at end of file
diff --git a/src/core/function.c b/src/core/function.c
new file mode 100644
index 000000000..8cb36c123
--- /dev/null
+++ b/src/core/function.c
@@ -0,0 +1,2879 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "function.h"
+#include <quickjs/cutils.h>
+#include "builtins/js-array.h"
+#include "builtins/js-big-num.h"
+#include "builtins/js-closures.h"
+#include "builtins/js-function.h"
+#include "builtins/js-object.h"
+#include "builtins/js-operator.h"
+#include "builtins/js-regexp.h"
+#include "convertion.h"
+#include "exception.h"
+#include "gc.h"
+#include "module.h"
+#include "object.h"
+#include "parser.h"
+#include "runtime.h"
+#include "string.h"
+
+JSValue js_call_c_function(JSContext* ctx,
+                                  JSValueConst func_obj,
+                                  JSValueConst this_obj,
+                                  int argc,
+                                  JSValueConst* argv,
+                                  int flags) {
+  JSRuntime* rt = ctx->rt;
+  JSCFunctionType func;
+  JSObject* p;
+  JSStackFrame sf_s, *sf = &sf_s, *prev_sf;
+  JSValue ret_val;
+  JSValueConst* arg_buf;
+  int arg_count, i;
+  JSCFunctionEnum cproto;
+
+  p = JS_VALUE_GET_OBJ(func_obj);
+  cproto = p->u.cfunc.cproto;
+  arg_count = p->u.cfunc.length;
+
+  /* better to always check stack overflow */
+  if (js_check_stack_overflow(rt, sizeof(arg_buf[0]) * arg_count))
+    return JS_ThrowStackOverflow(ctx);
+
+  prev_sf = rt->current_stack_frame;
+  sf->prev_frame = prev_sf;
+  rt->current_stack_frame = sf;
+  ctx = p->u.cfunc.realm; /* change the current realm */
+
+#ifdef CONFIG_BIGNUM
+  /* we only propagate the bignum mode as some runtime functions
+     test it */
+  if (prev_sf)
+    sf->js_mode = prev_sf->js_mode & JS_MODE_MATH;
+  else
+    sf->js_mode = 0;
+#else
+  sf->js_mode = 0;
+#endif
+  sf->cur_func = (JSValue)func_obj;
+  sf->arg_count = argc;
+  arg_buf = argv;
+
+  if (unlikely(argc < arg_count)) {
+    /* ensure that at least argc_count arguments are readable */
+    arg_buf = alloca(sizeof(arg_buf[0]) * arg_count);
+    for (i = 0; i < argc; i++)
+      arg_buf[i] = argv[i];
+    for (i = argc; i < arg_count; i++)
+      arg_buf[i] = JS_UNDEFINED;
+    sf->arg_count = arg_count;
+  }
+  sf->arg_buf = (JSValue*)arg_buf;
+
+  func = p->u.cfunc.c_function;
+  switch (cproto) {
+    case JS_CFUNC_constructor:
+    case JS_CFUNC_constructor_or_func:
+      if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) {
+        if (cproto == JS_CFUNC_constructor) {
+        not_a_constructor:
+          ret_val = JS_ThrowTypeError(ctx, "must be called with new");
+          break;
+        } else {
+          this_obj = JS_UNDEFINED;
+        }
+      }
+      /* here this_obj is new_target */
+      /* fall thru */
+    case JS_CFUNC_generic:
+      ret_val = func.generic(ctx, this_obj, argc, arg_buf);
+      break;
+    case JS_CFUNC_constructor_magic:
+    case JS_CFUNC_constructor_or_func_magic:
+      if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) {
+        if (cproto == JS_CFUNC_constructor_magic) {
+          goto not_a_constructor;
+        } else {
+          this_obj = JS_UNDEFINED;
+        }
+      }
+      /* fall thru */
+    case JS_CFUNC_generic_magic:
+      ret_val = func.generic_magic(ctx, this_obj, argc, arg_buf, p->u.cfunc.magic);
+      break;
+    case JS_CFUNC_getter:
+      ret_val = func.getter(ctx, this_obj);
+      break;
+    case JS_CFUNC_setter:
+      ret_val = func.setter(ctx, this_obj, arg_buf[0]);
+      break;
+    case JS_CFUNC_getter_magic:
+      ret_val = func.getter_magic(ctx, this_obj, p->u.cfunc.magic);
+      break;
+    case JS_CFUNC_setter_magic:
+      ret_val = func.setter_magic(ctx, this_obj, arg_buf[0], p->u.cfunc.magic);
+      break;
+    case JS_CFUNC_f_f: {
+      double d1;
+
+      if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) {
+        ret_val = JS_EXCEPTION;
+        break;
+      }
+      ret_val = JS_NewFloat64(ctx, func.f_f(d1));
+    } break;
+    case JS_CFUNC_f_f_f: {
+      double d1, d2;
+
+      if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) {
+        ret_val = JS_EXCEPTION;
+        break;
+      }
+      if (unlikely(JS_ToFloat64(ctx, &d2, arg_buf[1]))) {
+        ret_val = JS_EXCEPTION;
+        break;
+      }
+      ret_val = JS_NewFloat64(ctx, func.f_f_f(d1, d2));
+    } break;
+    case JS_CFUNC_iterator_next: {
+      int done;
+      ret_val = func.iterator_next(ctx, this_obj, argc, arg_buf, &done, p->u.cfunc.magic);
+      if (!JS_IsException(ret_val) && done != 2) {
+        ret_val = js_create_iterator_result(ctx, ret_val, done);
+      }
+    } break;
+    default:
+      abort();
+  }
+
+  rt->current_stack_frame = sf->prev_frame;
+  return ret_val;
+}
+
+JSValue js_call_bound_function(JSContext* ctx,
+                                      JSValueConst func_obj,
+                                      JSValueConst this_obj,
+                                      int argc,
+                                      JSValueConst* argv,
+                                      int flags) {
+  JSObject* p;
+  JSBoundFunction* bf;
+  JSValueConst *arg_buf, new_target;
+  int arg_count, i;
+
+  p = JS_VALUE_GET_OBJ(func_obj);
+  bf = p->u.bound_function;
+  arg_count = bf->argc + argc;
+  if (js_check_stack_overflow(ctx->rt, sizeof(JSValue) * arg_count))
+    return JS_ThrowStackOverflow(ctx);
+  arg_buf = alloca(sizeof(JSValue) * arg_count);
+  for (i = 0; i < bf->argc; i++) {
+    arg_buf[i] = bf->argv[i];
+  }
+  for (i = 0; i < argc; i++) {
+    arg_buf[bf->argc + i] = argv[i];
+  }
+  if (flags & JS_CALL_FLAG_CONSTRUCTOR) {
+    new_target = this_obj;
+    if (js_same_value(ctx, func_obj, new_target))
+      new_target = bf->func_obj;
+    return JS_CallConstructor2(ctx, bf->func_obj, new_target, arg_count, arg_buf);
+  } else {
+    return JS_Call(ctx, bf->func_obj, bf->this_val, arg_count, arg_buf);
+  }
+}
+
+/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */
+JSValue JS_CallInternal(JSContext* caller_ctx,
+                               JSValueConst func_obj,
+                               JSValueConst this_obj,
+                               JSValueConst new_target,
+                               int argc,
+                               JSValue* argv,
+                               int flags) {
+  JSRuntime* rt = caller_ctx->rt;
+  JSContext* ctx;
+  JSObject* p;
+  JSFunctionBytecode* b;
+  JSStackFrame sf_s, *sf = &sf_s;
+  const uint8_t* pc;
+  int opcode, arg_allocated_size, i;
+  JSValue *local_buf, *stack_buf, *var_buf, *arg_buf, *sp, ret_val, *pval;
+  JSVarRef** var_refs;
+  size_t alloca_size;
+
+#if !DIRECT_DISPATCH
+#define SWITCH(pc) switch (opcode = *pc++)
+#define CASE(op) case op
+#define DEFAULT default
+#define BREAK break
+#else
+  static const void* const dispatch_table[256] = {
+#define DEF(id, size, n_pop, n_push, f) &&case_OP_##id,
+#if SHORT_OPCODES
+#define def(id, size, n_pop, n_push, f)
+#else
+#define def(id, size, n_pop, n_push, f) &&case_default,
+#endif
+#include "quickjs/quickjs-opcode.h"
+    [OP_COUNT... 255] = &&case_default
+  };
+#define SWITCH(pc) goto* dispatch_table[opcode = *pc++];
+#define CASE(op) case_##op
+#define DEFAULT case_default
+#define BREAK SWITCH(pc)
+#endif
+
+  if (js_poll_interrupts(caller_ctx))
+    return JS_EXCEPTION;
+  if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)) {
+    if (flags & JS_CALL_FLAG_GENERATOR) {
+      JSAsyncFunctionState* s = JS_VALUE_GET_PTR(func_obj);
+      /* func_obj get contains a pointer to JSFuncAsyncState */
+      /* the stack frame is already allocated */
+      sf = &s->frame;
+      p = JS_VALUE_GET_OBJ(sf->cur_func);
+      b = p->u.func.function_bytecode;
+      ctx = b->realm;
+      var_refs = p->u.func.var_refs;
+      local_buf = arg_buf = sf->arg_buf;
+      var_buf = sf->var_buf;
+      stack_buf = sf->var_buf + b->var_count;
+      sp = sf->cur_sp;
+      sf->cur_sp = NULL; /* cur_sp is NULL if the function is running */
+      pc = sf->cur_pc;
+      sf->prev_frame = rt->current_stack_frame;
+      rt->current_stack_frame = sf;
+      if (s->throw_flag)
+        goto exception;
+      else
+        goto restart;
+    } else {
+      goto not_a_function;
+    }
+  }
+  p = JS_VALUE_GET_OBJ(func_obj);
+  if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {
+    JSClassCall* call_func;
+    call_func = rt->class_array[p->class_id].call;
+    if (!call_func) {
+    not_a_function:
+      return JS_ThrowTypeError(caller_ctx, "not a function");
+    }
+    return call_func(caller_ctx, func_obj, this_obj, argc, (JSValueConst*)argv, flags);
+  }
+  b = p->u.func.function_bytecode;
+
+  if (unlikely(argc < b->arg_count || (flags & JS_CALL_FLAG_COPY_ARGV))) {
+    arg_allocated_size = b->arg_count;
+  } else {
+    arg_allocated_size = 0;
+  }
+
+  alloca_size = sizeof(JSValue) * (arg_allocated_size + b->var_count + b->stack_size);
+  if (js_check_stack_overflow(rt, alloca_size))
+    return JS_ThrowStackOverflow(caller_ctx);
+
+  sf->js_mode = b->js_mode;
+  arg_buf = argv;
+  sf->arg_count = argc;
+  sf->cur_func = (JSValue)func_obj;
+  init_list_head(&sf->var_ref_list);
+  var_refs = p->u.func.var_refs;
+
+  local_buf = alloca(alloca_size);
+  if (unlikely(arg_allocated_size)) {
+    int n = min_int(argc, b->arg_count);
+    arg_buf = local_buf;
+    for (i = 0; i < n; i++)
+      arg_buf[i] = JS_DupValue(caller_ctx, argv[i]);
+    for (; i < b->arg_count; i++)
+      arg_buf[i] = JS_UNDEFINED;
+    sf->arg_count = b->arg_count;
+  }
+  var_buf = local_buf + arg_allocated_size;
+  sf->var_buf = var_buf;
+  sf->arg_buf = arg_buf;
+
+  for (i = 0; i < b->var_count; i++)
+    var_buf[i] = JS_UNDEFINED;
+
+  stack_buf = var_buf + b->var_count;
+  sp = stack_buf;
+  pc = b->byte_code_buf;
+  sf->prev_frame = rt->current_stack_frame;
+  rt->current_stack_frame = sf;
+  ctx = b->realm; /* set the current realm */
+
+restart:
+  for (;;) {
+    int call_argc;
+    JSValue* call_argv;
+
+    SWITCH(pc) {
+      CASE(OP_push_i32) : * sp++ = JS_NewInt32(ctx, get_u32(pc));
+      pc += 4;
+      BREAK;
+      CASE(OP_push_const) : * sp++ = JS_DupValue(ctx, b->cpool[get_u32(pc)]);
+      pc += 4;
+      BREAK;
+#if SHORT_OPCODES
+      CASE(OP_push_minus1)
+          : CASE(OP_push_0)
+          : CASE(OP_push_1)
+          : CASE(OP_push_2)
+          : CASE(OP_push_3)
+          : CASE(OP_push_4)
+          : CASE(OP_push_5) : CASE(OP_push_6) : CASE(OP_push_7) : * sp++ = JS_NewInt32(ctx, opcode - OP_push_0);
+      BREAK;
+      CASE(OP_push_i8) : * sp++ = JS_NewInt32(ctx, get_i8(pc));
+      pc += 1;
+      BREAK;
+      CASE(OP_push_i16) : * sp++ = JS_NewInt32(ctx, get_i16(pc));
+      pc += 2;
+      BREAK;
+      CASE(OP_push_const8) : * sp++ = JS_DupValue(ctx, b->cpool[*pc++]);
+      BREAK;
+      CASE(OP_fclosure8) : * sp++ = js_closure(ctx, JS_DupValue(ctx, b->cpool[*pc++]), var_refs, sf);
+      if (unlikely(JS_IsException(sp[-1])))
+        goto exception;
+      BREAK;
+      CASE(OP_push_empty_string) : * sp++ = JS_AtomToString(ctx, JS_ATOM_empty_string);
+      BREAK;
+      CASE(OP_get_length) : {
+        JSValue val;
+
+        val = JS_GetProperty(ctx, sp[-1], JS_ATOM_length);
+        if (unlikely(JS_IsException(val)))
+          goto exception;
+        JS_FreeValue(ctx, sp[-1]);
+        sp[-1] = val;
+      }
+      BREAK;
+#endif
+      CASE(OP_push_atom_value) : * sp++ = JS_AtomToValue(ctx, get_u32(pc));
+      pc += 4;
+      BREAK;
+      CASE(OP_undefined) : * sp++ = JS_UNDEFINED;
+      BREAK;
+      CASE(OP_null) : * sp++ = JS_NULL;
+      BREAK;
+      CASE(OP_push_this)
+          : /* OP_push_this is only called at the start of a function */
+      {
+        JSValue val;
+        if (!(b->js_mode & JS_MODE_STRICT)) {
+          uint32_t tag = JS_VALUE_GET_TAG(this_obj);
+          if (likely(tag == JS_TAG_OBJECT))
+            goto normal_this;
+          if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) {
+            val = JS_DupValue(ctx, ctx->global_obj);
+          } else {
+            val = JS_ToObject(ctx, this_obj);
+            if (JS_IsException(val))
+              goto exception;
+          }
+        } else {
+        normal_this:
+          val = JS_DupValue(ctx, this_obj);
+        }
+        *sp++ = val;
+      }
+      BREAK;
+      CASE(OP_push_false) : * sp++ = JS_FALSE;
+      BREAK;
+      CASE(OP_push_true) : * sp++ = JS_TRUE;
+      BREAK;
+      CASE(OP_object) : * sp++ = JS_NewObject(ctx);
+      if (unlikely(JS_IsException(sp[-1])))
+        goto exception;
+      BREAK;
+      CASE(OP_special_object) : {
+        int arg = *pc++;
+        switch (arg) {
+          case OP_SPECIAL_OBJECT_ARGUMENTS:
+            *sp++ = js_build_arguments(ctx, argc, (JSValueConst*)argv);
+            if (unlikely(JS_IsException(sp[-1])))
+              goto exception;
+            break;
+          case OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS:
+            *sp++ = js_build_mapped_arguments(ctx, argc, (JSValueConst*)argv, sf, min_int(argc, b->arg_count));
+            if (unlikely(JS_IsException(sp[-1])))
+              goto exception;
+            break;
+          case OP_SPECIAL_OBJECT_THIS_FUNC:
+            *sp++ = JS_DupValue(ctx, sf->cur_func);
+            break;
+          case OP_SPECIAL_OBJECT_NEW_TARGET:
+            *sp++ = JS_DupValue(ctx, new_target);
+            break;
+          case OP_SPECIAL_OBJECT_HOME_OBJECT: {
+            JSObject* p1;
+            p1 = p->u.func.home_object;
+            if (unlikely(!p1))
+              *sp++ = JS_UNDEFINED;
+            else
+              *sp++ = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
+          } break;
+          case OP_SPECIAL_OBJECT_VAR_OBJECT:
+            *sp++ = JS_NewObjectProto(ctx, JS_NULL);
+            if (unlikely(JS_IsException(sp[-1])))
+              goto exception;
+            break;
+          case OP_SPECIAL_OBJECT_IMPORT_META:
+            *sp++ = js_import_meta(ctx);
+            if (unlikely(JS_IsException(sp[-1])))
+              goto exception;
+            break;
+          default:
+            abort();
+        }
+      }
+      BREAK;
+      CASE(OP_rest) : {
+        int first = get_u16(pc);
+        pc += 2;
+        *sp++ = js_build_rest(ctx, first, argc, (JSValueConst*)argv);
+        if (unlikely(JS_IsException(sp[-1])))
+          goto exception;
+      }
+      BREAK;
+
+      CASE(OP_drop) : JS_FreeValue(ctx, sp[-1]);
+      sp--;
+      BREAK;
+      CASE(OP_nip) : JS_FreeValue(ctx, sp[-2]);
+      sp[-2] = sp[-1];
+      sp--;
+      BREAK;
+      CASE(OP_nip1)
+          : /* a b c -> b c */
+            JS_FreeValue(ctx, sp[-3]);
+      sp[-3] = sp[-2];
+      sp[-2] = sp[-1];
+      sp--;
+      BREAK;
+      CASE(OP_dup) : sp[0] = JS_DupValue(ctx, sp[-1]);
+      sp++;
+      BREAK;
+      CASE(OP_dup2)
+          : /* a b -> a b a b */
+            sp[0] = JS_DupValue(ctx, sp[-2]);
+      sp[1] = JS_DupValue(ctx, sp[-1]);
+      sp += 2;
+      BREAK;
+      CASE(OP_dup3)
+          : /* a b c -> a b c a b c */
+            sp[0] = JS_DupValue(ctx, sp[-3]);
+      sp[1] = JS_DupValue(ctx, sp[-2]);
+      sp[2] = JS_DupValue(ctx, sp[-1]);
+      sp += 3;
+      BREAK;
+      CASE(OP_dup1)
+          : /* a b -> a a b */
+            sp[0] = sp[-1];
+      sp[-1] = JS_DupValue(ctx, sp[-2]);
+      sp++;
+      BREAK;
+      CASE(OP_insert2)
+          : /* obj a -> a obj a (dup_x1) */
+            sp[0] = sp[-1];
+      sp[-1] = sp[-2];
+      sp[-2] = JS_DupValue(ctx, sp[0]);
+      sp++;
+      BREAK;
+      CASE(OP_insert3)
+          : /* obj prop a -> a obj prop a (dup_x2) */
+            sp[0] = sp[-1];
+      sp[-1] = sp[-2];
+      sp[-2] = sp[-3];
+      sp[-3] = JS_DupValue(ctx, sp[0]);
+      sp++;
+      BREAK;
+      CASE(OP_insert4)
+          : /* this obj prop a -> a this obj prop a */
+            sp[0] = sp[-1];
+      sp[-1] = sp[-2];
+      sp[-2] = sp[-3];
+      sp[-3] = sp[-4];
+      sp[-4] = JS_DupValue(ctx, sp[0]);
+      sp++;
+      BREAK;
+      CASE(OP_perm3)
+          : /* obj a b -> a obj b (213) */
+      {
+        JSValue tmp;
+        tmp = sp[-2];
+        sp[-2] = sp[-3];
+        sp[-3] = tmp;
+      }
+      BREAK;
+      CASE(OP_rot3l)
+          : /* x a b -> a b x (231) */
+      {
+        JSValue tmp;
+        tmp = sp[-3];
+        sp[-3] = sp[-2];
+        sp[-2] = sp[-1];
+        sp[-1] = tmp;
+      }
+      BREAK;
+      CASE(OP_rot4l)
+          : /* x a b c -> a b c x */
+      {
+        JSValue tmp;
+        tmp = sp[-4];
+        sp[-4] = sp[-3];
+        sp[-3] = sp[-2];
+        sp[-2] = sp[-1];
+        sp[-1] = tmp;
+      }
+      BREAK;
+      CASE(OP_rot5l)
+          : /* x a b c d -> a b c d x */
+      {
+        JSValue tmp;
+        tmp = sp[-5];
+        sp[-5] = sp[-4];
+        sp[-4] = sp[-3];
+        sp[-3] = sp[-2];
+        sp[-2] = sp[-1];
+        sp[-1] = tmp;
+      }
+      BREAK;
+      CASE(OP_rot3r)
+          : /* a b x -> x a b (312) */
+      {
+        JSValue tmp;
+        tmp = sp[-1];
+        sp[-1] = sp[-2];
+        sp[-2] = sp[-3];
+        sp[-3] = tmp;
+      }
+      BREAK;
+      CASE(OP_perm4)
+          : /* obj prop a b -> a obj prop b */
+      {
+        JSValue tmp;
+        tmp = sp[-2];
+        sp[-2] = sp[-3];
+        sp[-3] = sp[-4];
+        sp[-4] = tmp;
+      }
+      BREAK;
+      CASE(OP_perm5)
+          : /* this obj prop a b -> a this obj prop b */
+      {
+        JSValue tmp;
+        tmp = sp[-2];
+        sp[-2] = sp[-3];
+        sp[-3] = sp[-4];
+        sp[-4] = sp[-5];
+        sp[-5] = tmp;
+      }
+      BREAK;
+      CASE(OP_swap)
+          : /* a b -> b a */
+      {
+        JSValue tmp;
+        tmp = sp[-2];
+        sp[-2] = sp[-1];
+        sp[-1] = tmp;
+      }
+      BREAK;
+      CASE(OP_swap2)
+          : /* a b c d -> c d a b */
+      {
+        JSValue tmp1, tmp2;
+        tmp1 = sp[-4];
+        tmp2 = sp[-3];
+        sp[-4] = sp[-2];
+        sp[-3] = sp[-1];
+        sp[-2] = tmp1;
+        sp[-1] = tmp2;
+      }
+      BREAK;
+
+      CASE(OP_fclosure) : {
+        JSValue bfunc = JS_DupValue(ctx, b->cpool[get_u32(pc)]);
+        pc += 4;
+        *sp++ = js_closure(ctx, bfunc, var_refs, sf);
+        if (unlikely(JS_IsException(sp[-1])))
+          goto exception;
+      }
+      BREAK;
+#if SHORT_OPCODES
+      CASE(OP_call0) : CASE(OP_call1) : CASE(OP_call2) : CASE(OP_call3) : call_argc = opcode - OP_call0;
+      goto has_call_argc;
+#endif
+      CASE(OP_call) : CASE(OP_tail_call) : {
+        call_argc = get_u16(pc);
+        pc += 2;
+        goto has_call_argc;
+      has_call_argc:
+        call_argv = sp - call_argc;
+        sf->cur_pc = pc;
+        ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED, JS_UNDEFINED, call_argc, call_argv, 0);
+        if (unlikely(JS_IsException(ret_val)))
+          goto exception;
+        if (opcode == OP_tail_call)
+          goto done;
+        for (i = -1; i < call_argc; i++)
+          JS_FreeValue(ctx, call_argv[i]);
+        sp -= call_argc + 1;
+        *sp++ = ret_val;
+      }
+      BREAK;
+      CASE(OP_call_constructor) : {
+        call_argc = get_u16(pc);
+        pc += 2;
+        call_argv = sp - call_argc;
+        sf->cur_pc = pc;
+        ret_val = JS_CallConstructorInternal(ctx, call_argv[-2], call_argv[-1], call_argc, call_argv, 0);
+        if (unlikely(JS_IsException(ret_val)))
+          goto exception;
+        for (i = -2; i < call_argc; i++)
+          JS_FreeValue(ctx, call_argv[i]);
+        sp -= call_argc + 2;
+        *sp++ = ret_val;
+      }
+      BREAK;
+      CASE(OP_call_method) : CASE(OP_tail_call_method) : {
+        call_argc = get_u16(pc);
+        pc += 2;
+        call_argv = sp - call_argc;
+        sf->cur_pc = pc;
+        ret_val = JS_CallInternal(ctx, call_argv[-1], call_argv[-2], JS_UNDEFINED, call_argc, call_argv, 0);
+        if (unlikely(JS_IsException(ret_val)))
+          goto exception;
+        if (opcode == OP_tail_call_method)
+          goto done;
+        for (i = -2; i < call_argc; i++)
+          JS_FreeValue(ctx, call_argv[i]);
+        sp -= call_argc + 2;
+        *sp++ = ret_val;
+      }
+      BREAK;
+      CASE(OP_array_from) : {
+        int i, ret;
+
+        call_argc = get_u16(pc);
+        pc += 2;
+        ret_val = JS_NewArray(ctx);
+        if (unlikely(JS_IsException(ret_val)))
+          goto exception;
+        call_argv = sp - call_argc;
+        for (i = 0; i < call_argc; i++) {
+          ret =
+              JS_DefinePropertyValue(ctx, ret_val, __JS_AtomFromUInt32(i), call_argv[i], JS_PROP_C_W_E | JS_PROP_THROW);
+          call_argv[i] = JS_UNDEFINED;
+          if (ret < 0) {
+            JS_FreeValue(ctx, ret_val);
+            goto exception;
+          }
+        }
+        sp -= call_argc;
+        *sp++ = ret_val;
+      }
+      BREAK;
+
+      CASE(OP_apply) : {
+        int magic;
+        magic = get_u16(pc);
+        pc += 2;
+
+        ret_val = js_function_apply(ctx, sp[-3], 2, (JSValueConst*)&sp[-2], magic);
+        if (unlikely(JS_IsException(ret_val)))
+          goto exception;
+        JS_FreeValue(ctx, sp[-3]);
+        JS_FreeValue(ctx, sp[-2]);
+        JS_FreeValue(ctx, sp[-1]);
+        sp -= 3;
+        *sp++ = ret_val;
+      }
+      BREAK;
+      CASE(OP_return) : ret_val = *--sp;
+      goto done;
+      CASE(OP_return_undef) : ret_val = JS_UNDEFINED;
+      goto done;
+
+      CASE(OP_check_ctor_return)
+          : /* return TRUE if 'this' should be returned */
+            if (!JS_IsObject(sp[-1])) {
+        if (!JS_IsUndefined(sp[-1])) {
+          JS_ThrowTypeError(caller_ctx, "derived class constructor must return an object or undefined");
+          goto exception;
+        }
+        sp[0] = JS_TRUE;
+      }
+      else {
+        sp[0] = JS_FALSE;
+      }
+      sp++;
+      BREAK;
+      CASE(OP_check_ctor) : if (JS_IsUndefined(new_target)) {
+        JS_ThrowTypeError(ctx, "class constructors must be invoked with 'new'");
+        goto exception;
+      }
+      BREAK;
+      CASE(OP_check_brand) : if (JS_CheckBrand(ctx, sp[-2], sp[-1]) < 0) goto exception;
+      BREAK;
+      CASE(OP_add_brand) : if (JS_AddBrand(ctx, sp[-2], sp[-1]) < 0) goto exception;
+      JS_FreeValue(ctx, sp[-2]);
+      JS_FreeValue(ctx, sp[-1]);
+      sp -= 2;
+      BREAK;
+
+      CASE(OP_throw) : JS_Throw(ctx, *--sp);
+      goto exception;
+
+      CASE(OP_throw_error)
+          :
+      {
+        JSAtom atom;
+        int type;
+        atom = get_u32(pc);
+        type = pc[4];
+        pc += 5;
+        if (type == JS_THROW_VAR_RO)
+          JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, atom);
+        else if (type == JS_THROW_VAR_REDECL)
+          JS_ThrowSyntaxErrorVarRedeclaration(ctx, atom);
+        else if (type == JS_THROW_VAR_UNINITIALIZED)
+          JS_ThrowReferenceErrorUninitialized(ctx, atom);
+        else if (type == JS_THROW_ERROR_DELETE_SUPER)
+          JS_ThrowReferenceError(ctx, "unsupported reference to 'super'");
+        else if (type == JS_THROW_ERROR_ITERATOR_THROW)
+          JS_ThrowTypeError(ctx, "iterator does not have a throw method");
+        else
+          JS_ThrowInternalError(ctx, "invalid throw var type %d", type);
+      }
+      goto exception;
+
+      CASE(OP_eval) : {
+        JSValueConst obj;
+        int scope_idx;
+        call_argc = get_u16(pc);
+        scope_idx = get_u16(pc + 2) - 1;
+        pc += 4;
+        call_argv = sp - call_argc;
+        sf->cur_pc = pc;
+        if (js_same_value(ctx, call_argv[-1], ctx->eval_obj)) {
+          if (call_argc >= 1)
+            obj = call_argv[0];
+          else
+            obj = JS_UNDEFINED;
+          ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj, JS_EVAL_TYPE_DIRECT, scope_idx);
+        } else {
+          ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED, JS_UNDEFINED, call_argc, call_argv, 0);
+        }
+        if (unlikely(JS_IsException(ret_val)))
+          goto exception;
+        for (i = -1; i < call_argc; i++)
+          JS_FreeValue(ctx, call_argv[i]);
+        sp -= call_argc + 1;
+        *sp++ = ret_val;
+      }
+      BREAK;
+      /* could merge with OP_apply */
+      CASE(OP_apply_eval) : {
+        int scope_idx;
+        uint32_t len;
+        JSValue* tab;
+        JSValueConst obj;
+
+        scope_idx = get_u16(pc) - 1;
+        pc += 2;
+        tab = build_arg_list(ctx, &len, sp[-1]);
+        if (!tab)
+          goto exception;
+        if (js_same_value(ctx, sp[-2], ctx->eval_obj)) {
+          if (len >= 1)
+            obj = tab[0];
+          else
+            obj = JS_UNDEFINED;
+          ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj, JS_EVAL_TYPE_DIRECT, scope_idx);
+        } else {
+          ret_val = JS_Call(ctx, sp[-2], JS_UNDEFINED, len, (JSValueConst*)tab);
+        }
+        free_arg_list(ctx, tab, len);
+        if (unlikely(JS_IsException(ret_val)))
+          goto exception;
+        JS_FreeValue(ctx, sp[-2]);
+        JS_FreeValue(ctx, sp[-1]);
+        sp -= 2;
+        *sp++ = ret_val;
+      }
+      BREAK;
+
+      CASE(OP_regexp) : {
+        sp[-2] = js_regexp_constructor_internal(ctx, JS_UNDEFINED, sp[-2], sp[-1]);
+        sp--;
+      }
+      BREAK;
+
+      CASE(OP_get_super) : {
+        JSValue proto;
+        proto = JS_GetPrototype(ctx, sp[-1]);
+        if (JS_IsException(proto))
+          goto exception;
+        JS_FreeValue(ctx, sp[-1]);
+        sp[-1] = proto;
+      }
+      BREAK;
+
+      CASE(OP_import) : {
+        JSValue val;
+        val = js_dynamic_import(ctx, sp[-1]);
+        if (JS_IsException(val))
+          goto exception;
+        JS_FreeValue(ctx, sp[-1]);
+        sp[-1] = val;
+      }
+      BREAK;
+
+      CASE(OP_check_var) : {
+        int ret;
+        JSAtom atom;
+        atom = get_u32(pc);
+        pc += 4;
+
+        ret = JS_CheckGlobalVar(ctx, atom);
+        if (ret < 0)
+          goto exception;
+        *sp++ = JS_NewBool(ctx, ret);
+      }
+      BREAK;
+
+      CASE(OP_get_var_undef) : CASE(OP_get_var) : {
+        JSValue val;
+        JSAtom atom;
+        atom = get_u32(pc);
+        pc += 4;
+
+        val = JS_GetGlobalVar(ctx, atom, opcode - OP_get_var_undef);
+        if (unlikely(JS_IsException(val)))
+          goto exception;
+        *sp++ = val;
+      }
+      BREAK;
+
+      CASE(OP_put_var) : CASE(OP_put_var_init) : {
+        int ret;
+        JSAtom atom;
+        atom = get_u32(pc);
+        pc += 4;
+
+        ret = JS_SetGlobalVar(ctx, atom, sp[-1], opcode - OP_put_var);
+        sp--;
+        if (unlikely(ret < 0))
+          goto exception;
+      }
+      BREAK;
+
+      CASE(OP_put_var_strict) : {
+        int ret;
+        JSAtom atom;
+        atom = get_u32(pc);
+        pc += 4;
+
+        /* sp[-2] is JS_TRUE or JS_FALSE */
+        if (unlikely(!JS_VALUE_GET_INT(sp[-2]))) {
+          JS_ThrowReferenceErrorNotDefined(ctx, atom);
+          goto exception;
+        }
+        ret = JS_SetGlobalVar(ctx, atom, sp[-1], 2);
+        sp -= 2;
+        if (unlikely(ret < 0))
+          goto exception;
+      }
+      BREAK;
+
+      CASE(OP_check_define_var) : {
+        JSAtom atom;
+        int flags;
+        atom = get_u32(pc);
+        flags = pc[4];
+        pc += 5;
+        if (JS_CheckDefineGlobalVar(ctx, atom, flags))
+          goto exception;
+      }
+      BREAK;
+      CASE(OP_define_var) : {
+        JSAtom atom;
+        int flags;
+        atom = get_u32(pc);
+        flags = pc[4];
+        pc += 5;
+        if (JS_DefineGlobalVar(ctx, atom, flags))
+          goto exception;
+      }
+      BREAK;
+      CASE(OP_define_func) : {
+        JSAtom atom;
+        int flags;
+        atom = get_u32(pc);
+        flags = pc[4];
+        pc += 5;
+        if (JS_DefineGlobalFunction(ctx, atom, sp[-1], flags))
+          goto exception;
+        JS_FreeValue(ctx, sp[-1]);
+        sp--;
+      }
+      BREAK;
+
+      CASE(OP_get_loc) : {
+        int idx;
+        idx = get_u16(pc);
+        pc += 2;
+        sp[0] = JS_DupValue(ctx, var_buf[idx]);
+        sp++;
+      }
+      BREAK;
+      CASE(OP_put_loc) : {
+        int idx;
+        idx = get_u16(pc);
+        pc += 2;
+        set_value(ctx, &var_buf[idx], sp[-1]);
+        sp--;
+      }
+      BREAK;
+      CASE(OP_set_loc) : {
+        int idx;
+        idx = get_u16(pc);
+        pc += 2;
+        set_value(ctx, &var_buf[idx], JS_DupValue(ctx, sp[-1]));
+      }
+      BREAK;
+      CASE(OP_get_arg) : {
+        int idx;
+        idx = get_u16(pc);
+        pc += 2;
+        sp[0] = JS_DupValue(ctx, arg_buf[idx]);
+        sp++;
+      }
+      BREAK;
+      CASE(OP_put_arg) : {
+        int idx;
+        idx = get_u16(pc);
+        pc += 2;
+        set_value(ctx, &arg_buf[idx], sp[-1]);
+        sp--;
+      }
+      BREAK;
+      CASE(OP_set_arg) : {
+        int idx;
+        idx = get_u16(pc);
+        pc += 2;
+        set_value(ctx, &arg_buf[idx], JS_DupValue(ctx, sp[-1]));
+      }
+      BREAK;
+
+#if SHORT_OPCODES
+      CASE(OP_get_loc8) : * sp++ = JS_DupValue(ctx, var_buf[*pc++]);
+      BREAK;
+      CASE(OP_put_loc8) : set_value(ctx, &var_buf[*pc++], *--sp);
+      BREAK;
+      CASE(OP_set_loc8) : set_value(ctx, &var_buf[*pc++], JS_DupValue(ctx, sp[-1]));
+      BREAK;
+
+      CASE(OP_get_loc0) : * sp++ = JS_DupValue(ctx, var_buf[0]);
+      BREAK;
+      CASE(OP_get_loc1) : * sp++ = JS_DupValue(ctx, var_buf[1]);
+      BREAK;
+      CASE(OP_get_loc2) : * sp++ = JS_DupValue(ctx, var_buf[2]);
+      BREAK;
+      CASE(OP_get_loc3) : * sp++ = JS_DupValue(ctx, var_buf[3]);
+      BREAK;
+      CASE(OP_put_loc0) : set_value(ctx, &var_buf[0], *--sp);
+      BREAK;
+      CASE(OP_put_loc1) : set_value(ctx, &var_buf[1], *--sp);
+      BREAK;
+      CASE(OP_put_loc2) : set_value(ctx, &var_buf[2], *--sp);
+      BREAK;
+      CASE(OP_put_loc3) : set_value(ctx, &var_buf[3], *--sp);
+      BREAK;
+      CASE(OP_set_loc0) : set_value(ctx, &var_buf[0], JS_DupValue(ctx, sp[-1]));
+      BREAK;
+      CASE(OP_set_loc1) : set_value(ctx, &var_buf[1], JS_DupValue(ctx, sp[-1]));
+      BREAK;
+      CASE(OP_set_loc2) : set_value(ctx, &var_buf[2], JS_DupValue(ctx, sp[-1]));
+      BREAK;
+      CASE(OP_set_loc3) : set_value(ctx, &var_buf[3], JS_DupValue(ctx, sp[-1]));
+      BREAK;
+      CASE(OP_get_arg0) : * sp++ = JS_DupValue(ctx, arg_buf[0]);
+      BREAK;
+      CASE(OP_get_arg1) : * sp++ = JS_DupValue(ctx, arg_buf[1]);
+      BREAK;
+      CASE(OP_get_arg2) : * sp++ = JS_DupValue(ctx, arg_buf[2]);
+      BREAK;
+      CASE(OP_get_arg3) : * sp++ = JS_DupValue(ctx, arg_buf[3]);
+      BREAK;
+      CASE(OP_put_arg0) : set_value(ctx, &arg_buf[0], *--sp);
+      BREAK;
+      CASE(OP_put_arg1) : set_value(ctx, &arg_buf[1], *--sp);
+      BREAK;
+      CASE(OP_put_arg2) : set_value(ctx, &arg_buf[2], *--sp);
+      BREAK;
+      CASE(OP_put_arg3) : set_value(ctx, &arg_buf[3], *--sp);
+      BREAK;
+      CASE(OP_set_arg0) : set_value(ctx, &arg_buf[0], JS_DupValue(ctx, sp[-1]));
+      BREAK;
+      CASE(OP_set_arg1) : set_value(ctx, &arg_buf[1], JS_DupValue(ctx, sp[-1]));
+      BREAK;
+      CASE(OP_set_arg2) : set_value(ctx, &arg_buf[2], JS_DupValue(ctx, sp[-1]));
+      BREAK;
+      CASE(OP_set_arg3) : set_value(ctx, &arg_buf[3], JS_DupValue(ctx, sp[-1]));
+      BREAK;
+      CASE(OP_get_var_ref0) : * sp++ = JS_DupValue(ctx, *var_refs[0]->pvalue);
+      BREAK;
+      CASE(OP_get_var_ref1) : * sp++ = JS_DupValue(ctx, *var_refs[1]->pvalue);
+      BREAK;
+      CASE(OP_get_var_ref2) : * sp++ = JS_DupValue(ctx, *var_refs[2]->pvalue);
+      BREAK;
+      CASE(OP_get_var_ref3) : * sp++ = JS_DupValue(ctx, *var_refs[3]->pvalue);
+      BREAK;
+      CASE(OP_put_var_ref0) : set_value(ctx, var_refs[0]->pvalue, *--sp);
+      BREAK;
+      CASE(OP_put_var_ref1) : set_value(ctx, var_refs[1]->pvalue, *--sp);
+      BREAK;
+      CASE(OP_put_var_ref2) : set_value(ctx, var_refs[2]->pvalue, *--sp);
+      BREAK;
+      CASE(OP_put_var_ref3) : set_value(ctx, var_refs[3]->pvalue, *--sp);
+      BREAK;
+      CASE(OP_set_var_ref0) : set_value(ctx, var_refs[0]->pvalue, JS_DupValue(ctx, sp[-1]));
+      BREAK;
+      CASE(OP_set_var_ref1) : set_value(ctx, var_refs[1]->pvalue, JS_DupValue(ctx, sp[-1]));
+      BREAK;
+      CASE(OP_set_var_ref2) : set_value(ctx, var_refs[2]->pvalue, JS_DupValue(ctx, sp[-1]));
+      BREAK;
+      CASE(OP_set_var_ref3) : set_value(ctx, var_refs[3]->pvalue, JS_DupValue(ctx, sp[-1]));
+      BREAK;
+#endif
+
+      CASE(OP_get_var_ref) : {
+        int idx;
+        JSValue val;
+        idx = get_u16(pc);
+        pc += 2;
+        val = *var_refs[idx]->pvalue;
+        sp[0] = JS_DupValue(ctx, val);
+        sp++;
+      }
+      BREAK;
+      CASE(OP_put_var_ref) : {
+        int idx;
+        idx = get_u16(pc);
+        pc += 2;
+        set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
+        sp--;
+      }
+      BREAK;
+      CASE(OP_set_var_ref) : {
+        int idx;
+        idx = get_u16(pc);
+        pc += 2;
+        set_value(ctx, var_refs[idx]->pvalue, JS_DupValue(ctx, sp[-1]));
+      }
+      BREAK;
+      CASE(OP_get_var_ref_check) : {
+        int idx;
+        JSValue val;
+        idx = get_u16(pc);
+        pc += 2;
+        val = *var_refs[idx]->pvalue;
+        if (unlikely(JS_IsUninitialized(val))) {
+          JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
+          goto exception;
+        }
+        sp[0] = JS_DupValue(ctx, val);
+        sp++;
+      }
+      BREAK;
+      CASE(OP_put_var_ref_check) : {
+        int idx;
+        idx = get_u16(pc);
+        pc += 2;
+        if (unlikely(JS_IsUninitialized(*var_refs[idx]->pvalue))) {
+          JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
+          goto exception;
+        }
+        set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
+        sp--;
+      }
+      BREAK;
+      CASE(OP_put_var_ref_check_init) : {
+        int idx;
+        idx = get_u16(pc);
+        pc += 2;
+        if (unlikely(!JS_IsUninitialized(*var_refs[idx]->pvalue))) {
+          JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
+          goto exception;
+        }
+        set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
+        sp--;
+      }
+      BREAK;
+      CASE(OP_set_loc_uninitialized) : {
+        int idx;
+        idx = get_u16(pc);
+        pc += 2;
+        set_value(ctx, &var_buf[idx], JS_UNINITIALIZED);
+      }
+      BREAK;
+      CASE(OP_get_loc_check) : {
+        int idx;
+        idx = get_u16(pc);
+        pc += 2;
+        if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
+          JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);
+          goto exception;
+        }
+        sp[0] = JS_DupValue(ctx, var_buf[idx]);
+        sp++;
+      }
+      BREAK;
+      CASE(OP_put_loc_check) : {
+        int idx;
+        idx = get_u16(pc);
+        pc += 2;
+        if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
+          JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);
+          goto exception;
+        }
+        set_value(ctx, &var_buf[idx], sp[-1]);
+        sp--;
+      }
+      BREAK;
+      CASE(OP_put_loc_check_init) : {
+        int idx;
+        idx = get_u16(pc);
+        pc += 2;
+        if (unlikely(!JS_IsUninitialized(var_buf[idx]))) {
+          JS_ThrowReferenceError(ctx, "'this' can be initialized only once");
+          goto exception;
+        }
+        set_value(ctx, &var_buf[idx], sp[-1]);
+        sp--;
+      }
+      BREAK;
+      CASE(OP_close_loc) : {
+        int idx;
+        idx = get_u16(pc);
+        pc += 2;
+        close_lexical_var(ctx, sf, idx, FALSE);
+      }
+      BREAK;
+
+      CASE(OP_make_loc_ref) : CASE(OP_make_arg_ref) : CASE(OP_make_var_ref_ref) : {
+        JSVarRef* var_ref;
+        JSProperty* pr;
+        JSAtom atom;
+        int idx;
+        atom = get_u32(pc);
+        idx = get_u16(pc + 4);
+        pc += 6;
+        *sp++ = JS_NewObjectProto(ctx, JS_NULL);
+        if (unlikely(JS_IsException(sp[-1])))
+          goto exception;
+        if (opcode == OP_make_var_ref_ref) {
+          var_ref = var_refs[idx];
+          var_ref->header.ref_count++;
+        } else {
+          var_ref = get_var_ref(ctx, sf, idx, opcode == OP_make_arg_ref);
+          if (!var_ref)
+            goto exception;
+        }
+        pr = add_property(ctx, JS_VALUE_GET_OBJ(sp[-1]), atom, JS_PROP_WRITABLE | JS_PROP_VARREF);
+        if (!pr) {
+          free_var_ref(rt, var_ref);
+          goto exception;
+        }
+        pr->u.var_ref = var_ref;
+        *sp++ = JS_AtomToValue(ctx, atom);
+      }
+      BREAK;
+      CASE(OP_make_var_ref) : {
+        JSAtom atom;
+        atom = get_u32(pc);
+        pc += 4;
+
+        if (JS_GetGlobalVarRef(ctx, atom, sp))
+          goto exception;
+        sp += 2;
+      }
+      BREAK;
+
+      CASE(OP_goto) : pc += (int32_t)get_u32(pc);
+      if (unlikely(js_poll_interrupts(ctx)))
+        goto exception;
+      BREAK;
+#if SHORT_OPCODES
+      CASE(OP_goto16) : pc += (int16_t)get_u16(pc);
+      if (unlikely(js_poll_interrupts(ctx)))
+        goto exception;
+      BREAK;
+      CASE(OP_goto8) : pc += (int8_t)pc[0];
+      if (unlikely(js_poll_interrupts(ctx)))
+        goto exception;
+      BREAK;
+#endif
+      CASE(OP_if_true) : {
+        int res;
+        JSValue op1;
+
+        op1 = sp[-1];
+        pc += 4;
+        if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
+          res = JS_VALUE_GET_INT(op1);
+        } else {
+          res = JS_ToBoolFree(ctx, op1);
+        }
+        sp--;
+        if (res) {
+          pc += (int32_t)get_u32(pc - 4) - 4;
+        }
+        if (unlikely(js_poll_interrupts(ctx)))
+          goto exception;
+      }
+      BREAK;
+      CASE(OP_if_false) : {
+        int res;
+        JSValue op1;
+
+        op1 = sp[-1];
+        pc += 4;
+        if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
+          res = JS_VALUE_GET_INT(op1);
+        } else {
+          res = JS_ToBoolFree(ctx, op1);
+        }
+        sp--;
+        if (!res) {
+          pc += (int32_t)get_u32(pc - 4) - 4;
+        }
+        if (unlikely(js_poll_interrupts(ctx)))
+          goto exception;
+      }
+      BREAK;
+#if SHORT_OPCODES
+      CASE(OP_if_true8) : {
+        int res;
+        JSValue op1;
+
+        op1 = sp[-1];
+        pc += 1;
+        if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
+          res = JS_VALUE_GET_INT(op1);
+        } else {
+          res = JS_ToBoolFree(ctx, op1);
+        }
+        sp--;
+        if (res) {
+          pc += (int8_t)pc[-1] - 1;
+        }
+        if (unlikely(js_poll_interrupts(ctx)))
+          goto exception;
+      }
+      BREAK;
+      CASE(OP_if_false8) : {
+        int res;
+        JSValue op1;
+
+        op1 = sp[-1];
+        pc += 1;
+        if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
+          res = JS_VALUE_GET_INT(op1);
+        } else {
+          res = JS_ToBoolFree(ctx, op1);
+        }
+        sp--;
+        if (!res) {
+          pc += (int8_t)pc[-1] - 1;
+        }
+        if (unlikely(js_poll_interrupts(ctx)))
+          goto exception;
+      }
+      BREAK;
+#endif
+      CASE(OP_catch) : {
+        int32_t diff;
+        diff = get_u32(pc);
+        sp[0] = JS_NewCatchOffset(ctx, pc + diff - b->byte_code_buf);
+        sp++;
+        pc += 4;
+      }
+      BREAK;
+      CASE(OP_gosub) : {
+        int32_t diff;
+        diff = get_u32(pc);
+        /* XXX: should have a different tag to avoid security flaw */
+        sp[0] = JS_NewInt32(ctx, pc + 4 - b->byte_code_buf);
+        sp++;
+        pc += diff;
+      }
+      BREAK;
+      CASE(OP_ret) : {
+        JSValue op1;
+        uint32_t pos;
+        op1 = sp[-1];
+        if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_INT))
+          goto ret_fail;
+        pos = JS_VALUE_GET_INT(op1);
+        if (unlikely(pos >= b->byte_code_len)) {
+        ret_fail:
+          JS_ThrowInternalError(ctx, "invalid ret value");
+          goto exception;
+        }
+        sp--;
+        pc = b->byte_code_buf + pos;
+      }
+      BREAK;
+
+      CASE(OP_for_in_start) : if (js_for_in_start(ctx, sp)) goto exception;
+      BREAK;
+      CASE(OP_for_in_next) : if (js_for_in_next(ctx, sp)) goto exception;
+      sp += 2;
+      BREAK;
+      CASE(OP_for_of_start) : if (js_for_of_start(ctx, sp, FALSE)) goto exception;
+      sp += 1;
+      *sp++ = JS_NewCatchOffset(ctx, 0);
+      BREAK;
+      CASE(OP_for_of_next) : {
+        int offset = -3 - pc[0];
+        pc += 1;
+        if (js_for_of_next(ctx, sp, offset))
+          goto exception;
+        sp += 2;
+      }
+      BREAK;
+      CASE(OP_for_await_of_start) : if (js_for_of_start(ctx, sp, TRUE)) goto exception;
+      sp += 1;
+      *sp++ = JS_NewCatchOffset(ctx, 0);
+      BREAK;
+      CASE(OP_iterator_get_value_done) : if (js_iterator_get_value_done(ctx, sp)) goto exception;
+      sp += 1;
+      BREAK;
+      CASE(OP_iterator_check_object) : if (unlikely(!JS_IsObject(sp[-1]))) {
+        JS_ThrowTypeError(ctx, "iterator must return an object");
+        goto exception;
+      }
+      BREAK;
+
+      CASE(OP_iterator_close)
+          :                      /* iter_obj next catch_offset -> */
+            sp--;                /* drop the catch offset to avoid getting caught by exception */
+      JS_FreeValue(ctx, sp[-1]); /* drop the next method */
+      sp--;
+      if (!JS_IsUndefined(sp[-1])) {
+        if (JS_IteratorClose(ctx, sp[-1], FALSE))
+          goto exception;
+        JS_FreeValue(ctx, sp[-1]);
+      }
+      sp--;
+      BREAK;
+      CASE(OP_iterator_close_return) : {
+        JSValue ret_val;
+        /* iter_obj next catch_offset ... ret_val ->
+           ret_eval iter_obj next catch_offset */
+        ret_val = *--sp;
+        while (sp > stack_buf && JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_CATCH_OFFSET) {
+          JS_FreeValue(ctx, *--sp);
+        }
+        if (unlikely(sp < stack_buf + 3)) {
+          JS_ThrowInternalError(ctx, "iterator_close_return");
+          JS_FreeValue(ctx, ret_val);
+          goto exception;
+        }
+        sp[0] = sp[-1];
+        sp[-1] = sp[-2];
+        sp[-2] = sp[-3];
+        sp[-3] = ret_val;
+        sp++;
+      }
+      BREAK;
+
+      CASE(OP_iterator_next)
+          : /* stack: iter_obj next catch_offset val */
+      {
+        JSValue ret;
+        ret = JS_Call(ctx, sp[-3], sp[-4], 1, (JSValueConst*)(sp - 1));
+        if (JS_IsException(ret))
+          goto exception;
+        JS_FreeValue(ctx, sp[-1]);
+        sp[-1] = ret;
+      }
+      BREAK;
+
+      CASE(OP_iterator_call)
+          : /* stack: iter_obj next catch_offset val */
+      {
+        JSValue method, ret;
+        BOOL ret_flag;
+        int flags;
+        flags = *pc++;
+        method = JS_GetProperty(ctx, sp[-4], (flags & 1) ? JS_ATOM_throw : JS_ATOM_return);
+        if (JS_IsException(method))
+          goto exception;
+        if (JS_IsUndefined(method) || JS_IsNull(method)) {
+          ret_flag = TRUE;
+        } else {
+          if (flags & 2) {
+            /* no argument */
+            ret = JS_CallFree(ctx, method, sp[-4], 0, NULL);
+          } else {
+            ret = JS_CallFree(ctx, method, sp[-4], 1, (JSValueConst*)(sp - 1));
+          }
+          if (JS_IsException(ret))
+            goto exception;
+          JS_FreeValue(ctx, sp[-1]);
+          sp[-1] = ret;
+          ret_flag = FALSE;
+        }
+        sp[0] = JS_NewBool(ctx, ret_flag);
+        sp += 1;
+      }
+      BREAK;
+
+      CASE(OP_lnot) : {
+        int res;
+        JSValue op1;
+
+        op1 = sp[-1];
+        if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
+          res = JS_VALUE_GET_INT(op1) != 0;
+        } else {
+          res = JS_ToBoolFree(ctx, op1);
+        }
+        sp[-1] = JS_NewBool(ctx, !res);
+      }
+      BREAK;
+
+      CASE(OP_get_field) : {
+        JSValue val;
+        JSAtom atom;
+        atom = get_u32(pc);
+        pc += 4;
+
+        val = JS_GetProperty(ctx, sp[-1], atom);
+        if (unlikely(JS_IsException(val)))
+          goto exception;
+        JS_FreeValue(ctx, sp[-1]);
+        sp[-1] = val;
+      }
+      BREAK;
+
+      CASE(OP_get_field2) : {
+        JSValue val;
+        JSAtom atom;
+        atom = get_u32(pc);
+        pc += 4;
+
+        val = JS_GetProperty(ctx, sp[-1], atom);
+        if (unlikely(JS_IsException(val)))
+          goto exception;
+        *sp++ = val;
+      }
+      BREAK;
+
+      CASE(OP_put_field) : {
+        int ret;
+        JSAtom atom;
+        atom = get_u32(pc);
+        pc += 4;
+
+        ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1], JS_PROP_THROW_STRICT);
+        JS_FreeValue(ctx, sp[-2]);
+        sp -= 2;
+        if (unlikely(ret < 0))
+          goto exception;
+      }
+      BREAK;
+
+      CASE(OP_private_symbol) : {
+        JSAtom atom;
+        JSValue val;
+
+        atom = get_u32(pc);
+        pc += 4;
+        val = JS_NewSymbolFromAtom(ctx, atom, JS_ATOM_TYPE_PRIVATE);
+        if (JS_IsException(val))
+          goto exception;
+        *sp++ = val;
+      }
+      BREAK;
+
+      CASE(OP_get_private_field) : {
+        JSValue val;
+
+        val = JS_GetPrivateField(ctx, sp[-2], sp[-1]);
+        JS_FreeValue(ctx, sp[-1]);
+        JS_FreeValue(ctx, sp[-2]);
+        sp[-2] = val;
+        sp--;
+        if (unlikely(JS_IsException(val)))
+          goto exception;
+      }
+      BREAK;
+
+      CASE(OP_put_private_field) : {
+        int ret;
+        ret = JS_SetPrivateField(ctx, sp[-3], sp[-1], sp[-2]);
+        JS_FreeValue(ctx, sp[-3]);
+        JS_FreeValue(ctx, sp[-1]);
+        sp -= 3;
+        if (unlikely(ret < 0))
+          goto exception;
+      }
+      BREAK;
+
+      CASE(OP_define_private_field) : {
+        int ret;
+        ret = JS_DefinePrivateField(ctx, sp[-3], sp[-2], sp[-1]);
+        JS_FreeValue(ctx, sp[-2]);
+        sp -= 2;
+        if (unlikely(ret < 0))
+          goto exception;
+      }
+      BREAK;
+
+      CASE(OP_define_field) : {
+        int ret;
+        JSAtom atom;
+        atom = get_u32(pc);
+        pc += 4;
+
+        ret = JS_DefinePropertyValue(ctx, sp[-2], atom, sp[-1], JS_PROP_C_W_E | JS_PROP_THROW);
+        sp--;
+        if (unlikely(ret < 0))
+          goto exception;
+      }
+      BREAK;
+
+      CASE(OP_set_name) : {
+        int ret;
+        JSAtom atom;
+        atom = get_u32(pc);
+        pc += 4;
+
+        ret = JS_DefineObjectName(ctx, sp[-1], atom, JS_PROP_CONFIGURABLE);
+        if (unlikely(ret < 0))
+          goto exception;
+      }
+      BREAK;
+      CASE(OP_set_name_computed) : {
+        int ret;
+        ret = JS_DefineObjectNameComputed(ctx, sp[-1], sp[-2], JS_PROP_CONFIGURABLE);
+        if (unlikely(ret < 0))
+          goto exception;
+      }
+      BREAK;
+      CASE(OP_set_proto) : {
+        JSValue proto;
+        proto = sp[-1];
+        if (JS_IsObject(proto) || JS_IsNull(proto)) {
+          if (JS_SetPrototypeInternal(ctx, sp[-2], proto, TRUE) < 0)
+            goto exception;
+        }
+        JS_FreeValue(ctx, proto);
+        sp--;
+      }
+      BREAK;
+      CASE(OP_set_home_object) : js_method_set_home_object(ctx, sp[-1], sp[-2]);
+      BREAK;
+      CASE(OP_define_method) : CASE(OP_define_method_computed) : {
+        JSValue getter, setter, value;
+        JSValueConst obj;
+        JSAtom atom;
+        int flags, ret, op_flags;
+        BOOL is_computed;
+
+        is_computed = (opcode == OP_define_method_computed);
+        if (is_computed) {
+          atom = JS_ValueToAtom(ctx, sp[-2]);
+          if (unlikely(atom == JS_ATOM_NULL))
+            goto exception;
+          opcode += OP_define_method - OP_define_method_computed;
+        } else {
+          atom = get_u32(pc);
+          pc += 4;
+        }
+        op_flags = *pc++;
+
+        obj = sp[-2 - is_computed];
+        flags = JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE | JS_PROP_THROW;
+        if (op_flags & OP_DEFINE_METHOD_ENUMERABLE)
+          flags |= JS_PROP_ENUMERABLE;
+        op_flags &= 3;
+        value = JS_UNDEFINED;
+        getter = JS_UNDEFINED;
+        setter = JS_UNDEFINED;
+        if (op_flags == OP_DEFINE_METHOD_METHOD) {
+          value = sp[-1];
+          flags |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE;
+        } else if (op_flags == OP_DEFINE_METHOD_GETTER) {
+          getter = sp[-1];
+          flags |= JS_PROP_HAS_GET;
+        } else {
+          setter = sp[-1];
+          flags |= JS_PROP_HAS_SET;
+        }
+        ret = js_method_set_properties(ctx, sp[-1], atom, flags, obj);
+        if (ret >= 0) {
+          ret = JS_DefineProperty(ctx, obj, atom, value, getter, setter, flags);
+        }
+        JS_FreeValue(ctx, sp[-1]);
+        if (is_computed) {
+          JS_FreeAtom(ctx, atom);
+          JS_FreeValue(ctx, sp[-2]);
+        }
+        sp -= 1 + is_computed;
+        if (unlikely(ret < 0))
+          goto exception;
+      }
+      BREAK;
+
+      CASE(OP_define_class) : CASE(OP_define_class_computed) : {
+        int class_flags;
+        JSAtom atom;
+
+        atom = get_u32(pc);
+        class_flags = pc[4];
+        pc += 5;
+        if (js_op_define_class(ctx, sp, atom, class_flags, var_refs, sf, (opcode == OP_define_class_computed)) < 0)
+          goto exception;
+      }
+      BREAK;
+
+      CASE(OP_get_array_el) : {
+        JSValue val;
+
+        val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
+        JS_FreeValue(ctx, sp[-2]);
+        sp[-2] = val;
+        sp--;
+        if (unlikely(JS_IsException(val)))
+          goto exception;
+      }
+      BREAK;
+
+      CASE(OP_get_array_el2) : {
+        JSValue val;
+
+        val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
+        sp[-1] = val;
+        if (unlikely(JS_IsException(val)))
+          goto exception;
+      }
+      BREAK;
+
+      CASE(OP_get_ref_value) : {
+        JSValue val;
+        if (unlikely(JS_IsUndefined(sp[-2]))) {
+          JSAtom atom = JS_ValueToAtom(ctx, sp[-1]);
+          if (atom != JS_ATOM_NULL) {
+            JS_ThrowReferenceErrorNotDefined(ctx, atom);
+            JS_FreeAtom(ctx, atom);
+          }
+          goto exception;
+        }
+        val = JS_GetPropertyValue(ctx, sp[-2], JS_DupValue(ctx, sp[-1]));
+        if (unlikely(JS_IsException(val)))
+          goto exception;
+        sp[0] = val;
+        sp++;
+      }
+      BREAK;
+
+      CASE(OP_get_super_value) : {
+        JSValue val;
+        JSAtom atom;
+        atom = JS_ValueToAtom(ctx, sp[-1]);
+        if (unlikely(atom == JS_ATOM_NULL))
+          goto exception;
+        val = JS_GetPropertyInternal(ctx, sp[-2], atom, sp[-3], FALSE);
+        JS_FreeAtom(ctx, atom);
+        if (unlikely(JS_IsException(val)))
+          goto exception;
+        JS_FreeValue(ctx, sp[-1]);
+        JS_FreeValue(ctx, sp[-2]);
+        JS_FreeValue(ctx, sp[-3]);
+        sp[-3] = val;
+        sp -= 2;
+      }
+      BREAK;
+
+      CASE(OP_put_array_el) : {
+        int ret;
+
+        ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT);
+        JS_FreeValue(ctx, sp[-3]);
+        sp -= 3;
+        if (unlikely(ret < 0))
+          goto exception;
+      }
+      BREAK;
+
+      CASE(OP_put_ref_value) : {
+        int ret, flags;
+        flags = JS_PROP_THROW_STRICT;
+        if (unlikely(JS_IsUndefined(sp[-3]))) {
+          if (is_strict_mode(ctx)) {
+            JSAtom atom = JS_ValueToAtom(ctx, sp[-2]);
+            if (atom != JS_ATOM_NULL) {
+              JS_ThrowReferenceErrorNotDefined(ctx, atom);
+              JS_FreeAtom(ctx, atom);
+            }
+            goto exception;
+          } else {
+            sp[-3] = JS_DupValue(ctx, ctx->global_obj);
+          }
+        } else {
+          if (is_strict_mode(ctx))
+            flags |= JS_PROP_NO_ADD;
+        }
+        ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], flags);
+        JS_FreeValue(ctx, sp[-3]);
+        sp -= 3;
+        if (unlikely(ret < 0))
+          goto exception;
+      }
+      BREAK;
+
+      CASE(OP_put_super_value) : {
+        int ret;
+        JSAtom atom;
+        if (JS_VALUE_GET_TAG(sp[-3]) != JS_TAG_OBJECT) {
+          JS_ThrowTypeErrorNotAnObject(ctx);
+          goto exception;
+        }
+        atom = JS_ValueToAtom(ctx, sp[-2]);
+        if (unlikely(atom == JS_ATOM_NULL))
+          goto exception;
+        ret = JS_SetPropertyGeneric(ctx, sp[-3], atom, sp[-1], sp[-4], JS_PROP_THROW_STRICT);
+        JS_FreeAtom(ctx, atom);
+        JS_FreeValue(ctx, sp[-4]);
+        JS_FreeValue(ctx, sp[-3]);
+        JS_FreeValue(ctx, sp[-2]);
+        sp -= 4;
+        if (ret < 0)
+          goto exception;
+      }
+      BREAK;
+
+      CASE(OP_define_array_el) : {
+        int ret;
+        ret = JS_DefinePropertyValueValue(ctx, sp[-3], JS_DupValue(ctx, sp[-2]), sp[-1], JS_PROP_C_W_E | JS_PROP_THROW);
+        sp -= 1;
+        if (unlikely(ret < 0))
+          goto exception;
+      }
+      BREAK;
+
+      CASE(OP_append)
+          : /* array pos enumobj -- array pos */
+      {
+        if (js_append_enumerate(ctx, sp))
+          goto exception;
+        JS_FreeValue(ctx, *--sp);
+      }
+      BREAK;
+
+      CASE(OP_copy_data_properties)
+          : /* target source excludeList */
+      {
+        /* stack offsets (-1 based):
+           2 bits for target,
+           3 bits for source,
+           2 bits for exclusionList */
+        int mask;
+
+        mask = *pc++;
+        if (JS_CopyDataProperties(ctx, sp[-1 - (mask & 3)], sp[-1 - ((mask >> 2) & 7)], sp[-1 - ((mask >> 5) & 7)], 0))
+          goto exception;
+      }
+      BREAK;
+
+      CASE(OP_add) : {
+        JSValue op1, op2;
+        op1 = sp[-2];
+        op2 = sp[-1];
+        if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
+          int64_t r;
+          r = (int64_t)JS_VALUE_GET_INT(op1) + JS_VALUE_GET_INT(op2);
+          if (unlikely((int)r != r))
+            goto add_slow;
+          sp[-2] = JS_NewInt32(ctx, r);
+          sp--;
+        } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
+          sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) + JS_VALUE_GET_FLOAT64(op2));
+          sp--;
+        } else {
+        add_slow:
+          if (js_add_slow(ctx, sp))
+            goto exception;
+          sp--;
+        }
+      }
+      BREAK;
+      CASE(OP_add_loc) : {
+        JSValue* pv;
+        int idx;
+        idx = *pc;
+        pc += 1;
+
+        pv = &var_buf[idx];
+        if (likely(JS_VALUE_IS_BOTH_INT(*pv, sp[-1]))) {
+          int64_t r;
+          r = (int64_t)JS_VALUE_GET_INT(*pv) + JS_VALUE_GET_INT(sp[-1]);
+          if (unlikely((int)r != r))
+            goto add_loc_slow;
+          *pv = JS_NewInt32(ctx, r);
+          sp--;
+        } else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING) {
+          JSValue op1;
+          op1 = sp[-1];
+          sp--;
+          op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
+          if (JS_IsException(op1))
+            goto exception;
+          op1 = JS_ConcatString(ctx, JS_DupValue(ctx, *pv), op1);
+          if (JS_IsException(op1))
+            goto exception;
+          set_value(ctx, pv, op1);
+        } else {
+          JSValue ops[2];
+        add_loc_slow:
+          /* In case of exception, js_add_slow frees ops[0]
+             and ops[1], so we must duplicate *pv */
+          ops[0] = JS_DupValue(ctx, *pv);
+          ops[1] = sp[-1];
+          sp--;
+          if (js_add_slow(ctx, ops + 2))
+            goto exception;
+          set_value(ctx, pv, ops[0]);
+        }
+      }
+      BREAK;
+      CASE(OP_sub) : {
+        JSValue op1, op2;
+        op1 = sp[-2];
+        op2 = sp[-1];
+        if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
+          int64_t r;
+          r = (int64_t)JS_VALUE_GET_INT(op1) - JS_VALUE_GET_INT(op2);
+          if (unlikely((int)r != r))
+            goto binary_arith_slow;
+          sp[-2] = JS_NewInt32(ctx, r);
+          sp--;
+        } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
+          sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) - JS_VALUE_GET_FLOAT64(op2));
+          sp--;
+        } else {
+          goto binary_arith_slow;
+        }
+      }
+      BREAK;
+      CASE(OP_mul) : {
+        JSValue op1, op2;
+        double d;
+        op1 = sp[-2];
+        op2 = sp[-1];
+        if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
+          int32_t v1, v2;
+          int64_t r;
+          v1 = JS_VALUE_GET_INT(op1);
+          v2 = JS_VALUE_GET_INT(op2);
+          r = (int64_t)v1 * v2;
+          if (unlikely((int)r != r)) {
+#ifdef CONFIG_BIGNUM
+            if (unlikely(sf->js_mode & JS_MODE_MATH) && (r < -MAX_SAFE_INTEGER || r > MAX_SAFE_INTEGER))
+              goto binary_arith_slow;
+#endif
+            d = (double)r;
+            goto mul_fp_res;
+          }
+          /* need to test zero case for -0 result */
+          if (unlikely(r == 0 && (v1 | v2) < 0)) {
+            d = -0.0;
+            goto mul_fp_res;
+          }
+          sp[-2] = JS_NewInt32(ctx, r);
+          sp--;
+        } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
+#ifdef CONFIG_BIGNUM
+          if (unlikely(sf->js_mode & JS_MODE_MATH))
+            goto binary_arith_slow;
+#endif
+          d = JS_VALUE_GET_FLOAT64(op1) * JS_VALUE_GET_FLOAT64(op2);
+        mul_fp_res:
+          sp[-2] = __JS_NewFloat64(ctx, d);
+          sp--;
+        } else {
+          goto binary_arith_slow;
+        }
+      }
+      BREAK;
+      CASE(OP_div) : {
+        JSValue op1, op2;
+        op1 = sp[-2];
+        op2 = sp[-1];
+        if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
+          int v1, v2;
+          if (unlikely(sf->js_mode & JS_MODE_MATH))
+            goto binary_arith_slow;
+          v1 = JS_VALUE_GET_INT(op1);
+          v2 = JS_VALUE_GET_INT(op2);
+          sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2);
+          sp--;
+        } else {
+          goto binary_arith_slow;
+        }
+      }
+      BREAK;
+      CASE(OP_mod)
+          :
+#ifdef CONFIG_BIGNUM
+            CASE(OP_math_mod)
+          :
+#endif
+      {
+        JSValue op1, op2;
+        op1 = sp[-2];
+        op2 = sp[-1];
+        if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
+          int v1, v2, r;
+          v1 = JS_VALUE_GET_INT(op1);
+          v2 = JS_VALUE_GET_INT(op2);
+          /* We must avoid v2 = 0, v1 = INT32_MIN and v2 =
+             -1 and the cases where the result is -0. */
+          if (unlikely(v1 < 0 || v2 <= 0))
+            goto binary_arith_slow;
+          r = v1 % v2;
+          sp[-2] = JS_NewInt32(ctx, r);
+          sp--;
+        } else {
+          goto binary_arith_slow;
+        }
+      }
+      BREAK;
+      CASE(OP_pow) : binary_arith_slow : if (js_binary_arith_slow(ctx, sp, opcode)) goto exception;
+      sp--;
+      BREAK;
+
+      CASE(OP_plus) : {
+        JSValue op1;
+        uint32_t tag;
+        op1 = sp[-1];
+        tag = JS_VALUE_GET_TAG(op1);
+        if (tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag)) {
+        } else {
+          if (js_unary_arith_slow(ctx, sp, opcode))
+            goto exception;
+        }
+      }
+      BREAK;
+      CASE(OP_neg) : {
+        JSValue op1;
+        uint32_t tag;
+        int val;
+        double d;
+        op1 = sp[-1];
+        tag = JS_VALUE_GET_TAG(op1);
+        if (tag == JS_TAG_INT) {
+          val = JS_VALUE_GET_INT(op1);
+          /* Note: -0 cannot be expressed as integer */
+          if (unlikely(val == 0)) {
+            d = -0.0;
+            goto neg_fp_res;
+          }
+          if (unlikely(val == INT32_MIN)) {
+            d = -(double)val;
+            goto neg_fp_res;
+          }
+          sp[-1] = JS_NewInt32(ctx, -val);
+        } else if (JS_TAG_IS_FLOAT64(tag)) {
+          d = -JS_VALUE_GET_FLOAT64(op1);
+        neg_fp_res:
+          sp[-1] = __JS_NewFloat64(ctx, d);
+        } else {
+          if (js_unary_arith_slow(ctx, sp, opcode))
+            goto exception;
+        }
+      }
+      BREAK;
+      CASE(OP_inc) : {
+        JSValue op1;
+        int val;
+        op1 = sp[-1];
+        if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
+          val = JS_VALUE_GET_INT(op1);
+          if (unlikely(val == INT32_MAX))
+            goto inc_slow;
+          sp[-1] = JS_NewInt32(ctx, val + 1);
+        } else {
+        inc_slow:
+          if (js_unary_arith_slow(ctx, sp, opcode))
+            goto exception;
+        }
+      }
+      BREAK;
+      CASE(OP_dec) : {
+        JSValue op1;
+        int val;
+        op1 = sp[-1];
+        if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
+          val = JS_VALUE_GET_INT(op1);
+          if (unlikely(val == INT32_MIN))
+            goto dec_slow;
+          sp[-1] = JS_NewInt32(ctx, val - 1);
+        } else {
+        dec_slow:
+          if (js_unary_arith_slow(ctx, sp, opcode))
+            goto exception;
+        }
+      }
+      BREAK;
+      CASE(OP_post_inc) : CASE(OP_post_dec) : if (js_post_inc_slow(ctx, sp, opcode)) goto exception;
+      sp++;
+      BREAK;
+      CASE(OP_inc_loc) : {
+        JSValue op1;
+        int val;
+        int idx;
+        idx = *pc;
+        pc += 1;
+
+        op1 = var_buf[idx];
+        if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
+          val = JS_VALUE_GET_INT(op1);
+          if (unlikely(val == INT32_MAX))
+            goto inc_loc_slow;
+          var_buf[idx] = JS_NewInt32(ctx, val + 1);
+        } else {
+        inc_loc_slow:
+          /* must duplicate otherwise the variable value may
+             be destroyed before JS code accesses it */
+          op1 = JS_DupValue(ctx, op1);
+          if (js_unary_arith_slow(ctx, &op1 + 1, OP_inc))
+            goto exception;
+          set_value(ctx, &var_buf[idx], op1);
+        }
+      }
+      BREAK;
+      CASE(OP_dec_loc) : {
+        JSValue op1;
+        int val;
+        int idx;
+        idx = *pc;
+        pc += 1;
+
+        op1 = var_buf[idx];
+        if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
+          val = JS_VALUE_GET_INT(op1);
+          if (unlikely(val == INT32_MIN))
+            goto dec_loc_slow;
+          var_buf[idx] = JS_NewInt32(ctx, val - 1);
+        } else {
+        dec_loc_slow:
+          /* must duplicate otherwise the variable value may
+             be destroyed before JS code accesses it */
+          op1 = JS_DupValue(ctx, op1);
+          if (js_unary_arith_slow(ctx, &op1 + 1, OP_dec))
+            goto exception;
+          set_value(ctx, &var_buf[idx], op1);
+        }
+      }
+      BREAK;
+      CASE(OP_not) : {
+        JSValue op1;
+        op1 = sp[-1];
+        if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
+          sp[-1] = JS_NewInt32(ctx, ~JS_VALUE_GET_INT(op1));
+        } else {
+          if (js_not_slow(ctx, sp))
+            goto exception;
+        }
+      }
+      BREAK;
+
+      CASE(OP_shl) : {
+        JSValue op1, op2;
+        op1 = sp[-2];
+        op2 = sp[-1];
+        if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
+          uint32_t v1, v2;
+          v1 = JS_VALUE_GET_INT(op1);
+          v2 = JS_VALUE_GET_INT(op2);
+#ifdef CONFIG_BIGNUM
+          {
+            int64_t r;
+            if (unlikely(sf->js_mode & JS_MODE_MATH)) {
+              if (v2 > 0x1f)
+                goto shl_slow;
+              r = (int64_t)v1 << v2;
+              if ((int)r != r)
+                goto shl_slow;
+            } else {
+              v2 &= 0x1f;
+            }
+          }
+#else
+          v2 &= 0x1f;
+#endif
+          sp[-2] = JS_NewInt32(ctx, v1 << v2);
+          sp--;
+        } else {
+#ifdef CONFIG_BIGNUM
+        shl_slow:
+#endif
+          if (js_binary_logic_slow(ctx, sp, opcode))
+            goto exception;
+          sp--;
+        }
+      }
+      BREAK;
+      CASE(OP_shr) : {
+        JSValue op1, op2;
+        op1 = sp[-2];
+        op2 = sp[-1];
+        if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
+          uint32_t v2;
+          v2 = JS_VALUE_GET_INT(op2);
+          /* v1 >>> v2 retains its JS semantics if CONFIG_BIGNUM */
+          v2 &= 0x1f;
+          sp[-2] = JS_NewUint32(ctx, (uint32_t)JS_VALUE_GET_INT(op1) >> v2);
+          sp--;
+        } else {
+          if (js_shr_slow(ctx, sp))
+            goto exception;
+          sp--;
+        }
+      }
+      BREAK;
+      CASE(OP_sar) : {
+        JSValue op1, op2;
+        op1 = sp[-2];
+        op2 = sp[-1];
+        if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
+          uint32_t v2;
+          v2 = JS_VALUE_GET_INT(op2);
+#ifdef CONFIG_BIGNUM
+          if (unlikely(v2 > 0x1f)) {
+            if (unlikely(sf->js_mode & JS_MODE_MATH))
+              goto sar_slow;
+            else
+              v2 &= 0x1f;
+          }
+#else
+          v2 &= 0x1f;
+#endif
+          sp[-2] = JS_NewInt32(ctx, (int)JS_VALUE_GET_INT(op1) >> v2);
+          sp--;
+        } else {
+#ifdef CONFIG_BIGNUM
+        sar_slow:
+#endif
+          if (js_binary_logic_slow(ctx, sp, opcode))
+            goto exception;
+          sp--;
+        }
+      }
+      BREAK;
+      CASE(OP_and) : {
+        JSValue op1, op2;
+        op1 = sp[-2];
+        op2 = sp[-1];
+        if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
+          sp[-2] = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1) & JS_VALUE_GET_INT(op2));
+          sp--;
+        } else {
+          if (js_binary_logic_slow(ctx, sp, opcode))
+            goto exception;
+          sp--;
+        }
+      }
+      BREAK;
+      CASE(OP_or) : {
+        JSValue op1, op2;
+        op1 = sp[-2];
+        op2 = sp[-1];
+        if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
+          sp[-2] = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1) | JS_VALUE_GET_INT(op2));
+          sp--;
+        } else {
+          if (js_binary_logic_slow(ctx, sp, opcode))
+            goto exception;
+          sp--;
+        }
+      }
+      BREAK;
+      CASE(OP_xor) : {
+        JSValue op1, op2;
+        op1 = sp[-2];
+        op2 = sp[-1];
+        if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
+          sp[-2] = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1) ^ JS_VALUE_GET_INT(op2));
+          sp--;
+        } else {
+          if (js_binary_logic_slow(ctx, sp, opcode))
+            goto exception;
+          sp--;
+        }
+      }
+      BREAK;
+
+#define OP_CMP(opcode, binary_op, slow_call)                                           \
+  CASE(opcode) : {                                                                     \
+    JSValue op1, op2;                                                                  \
+    op1 = sp[-2];                                                                      \
+    op2 = sp[-1];                                                                      \
+    if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {                                      \
+      sp[-2] = JS_NewBool(ctx, JS_VALUE_GET_INT(op1) binary_op JS_VALUE_GET_INT(op2)); \
+      sp--;                                                                            \
+    } else {                                                                           \
+      if (slow_call)                                                                   \
+        goto exception;                                                                \
+      sp--;                                                                            \
+    }                                                                                  \
+  }                                                                                    \
+  BREAK
+
+      OP_CMP(OP_lt, <, js_relational_slow(ctx, sp, opcode));
+      OP_CMP(OP_lte, <=, js_relational_slow(ctx, sp, opcode));
+      OP_CMP(OP_gt, >, js_relational_slow(ctx, sp, opcode));
+      OP_CMP(OP_gte, >=, js_relational_slow(ctx, sp, opcode));
+      OP_CMP(OP_eq, ==, js_eq_slow(ctx, sp, 0));
+      OP_CMP(OP_neq, !=, js_eq_slow(ctx, sp, 1));
+      OP_CMP(OP_strict_eq, ==, js_strict_eq_slow(ctx, sp, 0));
+      OP_CMP(OP_strict_neq, !=, js_strict_eq_slow(ctx, sp, 1));
+
+#ifdef CONFIG_BIGNUM
+      CASE(OP_mul_pow10) : if (rt->bigfloat_ops.mul_pow10(ctx, sp)) goto exception;
+      sp--;
+      BREAK;
+#endif
+      CASE(OP_in) : if (js_operator_in(ctx, sp)) goto exception;
+      sp--;
+      BREAK;
+      CASE(OP_instanceof) : if (js_operator_instanceof(ctx, sp)) goto exception;
+      sp--;
+      BREAK;
+      CASE(OP_typeof) : {
+        JSValue op1;
+        JSAtom atom;
+
+        op1 = sp[-1];
+        atom = js_operator_typeof(ctx, op1);
+        JS_FreeValue(ctx, op1);
+        sp[-1] = JS_AtomToString(ctx, atom);
+      }
+      BREAK;
+      CASE(OP_delete) : if (js_operator_delete(ctx, sp)) goto exception;
+      sp--;
+      BREAK;
+      CASE(OP_delete_var) : {
+        JSAtom atom;
+        int ret;
+
+        atom = get_u32(pc);
+        pc += 4;
+
+        ret = JS_DeleteProperty(ctx, ctx->global_obj, atom, 0);
+        if (unlikely(ret < 0))
+          goto exception;
+        *sp++ = JS_NewBool(ctx, ret);
+      }
+      BREAK;
+
+      CASE(OP_to_object) : if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_OBJECT) {
+        ret_val = JS_ToObject(ctx, sp[-1]);
+        if (JS_IsException(ret_val))
+          goto exception;
+        JS_FreeValue(ctx, sp[-1]);
+        sp[-1] = ret_val;
+      }
+      BREAK;
+
+      CASE(OP_to_propkey) : switch (JS_VALUE_GET_TAG(sp[-1])) {
+        case JS_TAG_INT:
+        case JS_TAG_STRING:
+        case JS_TAG_SYMBOL:
+          break;
+        default:
+          ret_val = JS_ToPropertyKey(ctx, sp[-1]);
+          if (JS_IsException(ret_val))
+            goto exception;
+          JS_FreeValue(ctx, sp[-1]);
+          sp[-1] = ret_val;
+          break;
+      }
+      BREAK;
+
+      CASE(OP_to_propkey2)
+          : /* must be tested first */
+            if (unlikely(JS_IsUndefined(sp[-2]) || JS_IsNull(sp[-2]))) {
+        JS_ThrowTypeError(ctx, "value has no property");
+        goto exception;
+      }
+      switch (JS_VALUE_GET_TAG(sp[-1])) {
+        case JS_TAG_INT:
+        case JS_TAG_STRING:
+        case JS_TAG_SYMBOL:
+          break;
+        default:
+          ret_val = JS_ToPropertyKey(ctx, sp[-1]);
+          if (JS_IsException(ret_val))
+            goto exception;
+          JS_FreeValue(ctx, sp[-1]);
+          sp[-1] = ret_val;
+          break;
+      }
+      BREAK;
+#if 0
+        CASE(OP_to_string):
+            if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_STRING) {
+                ret_val = JS_ToString(ctx, sp[-1]);
+                if (JS_IsException(ret_val))
+                    goto exception;
+                JS_FreeValue(ctx, sp[-1]);
+                sp[-1] = ret_val;
+            }
+            BREAK;
+#endif
+      CASE(OP_with_get_var)
+          : CASE(OP_with_put_var)
+          : CASE(OP_with_delete_var) : CASE(OP_with_make_ref) : CASE(OP_with_get_ref) : CASE(OP_with_get_ref_undef) : {
+        JSAtom atom;
+        int32_t diff;
+        JSValue obj, val;
+        int ret, is_with;
+        atom = get_u32(pc);
+        diff = get_u32(pc + 4);
+        is_with = pc[8];
+        pc += 9;
+
+        obj = sp[-1];
+        ret = JS_HasProperty(ctx, obj, atom);
+        if (unlikely(ret < 0))
+          goto exception;
+        if (ret) {
+          if (is_with) {
+            ret = js_has_unscopable(ctx, obj, atom);
+            if (unlikely(ret < 0))
+              goto exception;
+            if (ret)
+              goto no_with;
+          }
+          switch (opcode) {
+            case OP_with_get_var:
+              val = JS_GetProperty(ctx, obj, atom);
+              if (unlikely(JS_IsException(val)))
+                goto exception;
+              set_value(ctx, &sp[-1], val);
+              break;
+            case OP_with_put_var:
+              /* XXX: check if strict mode */
+              ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2], JS_PROP_THROW_STRICT);
+              JS_FreeValue(ctx, sp[-1]);
+              sp -= 2;
+              if (unlikely(ret < 0))
+                goto exception;
+              break;
+            case OP_with_delete_var:
+              ret = JS_DeleteProperty(ctx, obj, atom, 0);
+              if (unlikely(ret < 0))
+                goto exception;
+              JS_FreeValue(ctx, sp[-1]);
+              sp[-1] = JS_NewBool(ctx, ret);
+              break;
+            case OP_with_make_ref:
+              /* produce a pair object/propname on the stack */
+              *sp++ = JS_AtomToValue(ctx, atom);
+              break;
+            case OP_with_get_ref:
+              /* produce a pair object/method on the stack */
+              val = JS_GetProperty(ctx, obj, atom);
+              if (unlikely(JS_IsException(val)))
+                goto exception;
+              *sp++ = val;
+              break;
+            case OP_with_get_ref_undef:
+              /* produce a pair undefined/function on the stack */
+              val = JS_GetProperty(ctx, obj, atom);
+              if (unlikely(JS_IsException(val)))
+                goto exception;
+              JS_FreeValue(ctx, sp[-1]);
+              sp[-1] = JS_UNDEFINED;
+              *sp++ = val;
+              break;
+          }
+          pc += diff - 5;
+        } else {
+        no_with:
+          /* if not jumping, drop the object argument */
+          JS_FreeValue(ctx, sp[-1]);
+          sp--;
+        }
+      }
+      BREAK;
+
+      CASE(OP_await) : ret_val = JS_NewInt32(ctx, FUNC_RET_AWAIT);
+      goto done_generator;
+      CASE(OP_yield) : ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD);
+      goto done_generator;
+      CASE(OP_yield_star) : CASE(OP_async_yield_star) : ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD_STAR);
+      goto done_generator;
+      CASE(OP_return_async) : CASE(OP_initial_yield) : ret_val = JS_UNDEFINED;
+      goto done_generator;
+
+      CASE(OP_nop) : BREAK;
+      CASE(OP_is_undefined_or_null)
+          : if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED || JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) {
+        goto set_true;
+      }
+      else {
+        goto free_and_set_false;
+      }
+#if SHORT_OPCODES
+      CASE(OP_is_undefined) : if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED) {
+        goto set_true;
+      }
+      else {
+        goto free_and_set_false;
+      }
+      CASE(OP_is_null) : if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) {
+        goto set_true;
+      }
+      else {
+        goto free_and_set_false;
+      }
+      /* XXX: could merge to a single opcode */
+      CASE(OP_typeof_is_undefined)
+          : /* different from OP_is_undefined because of isHTMLDDA */
+            if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_undefined) {
+        goto free_and_set_true;
+      }
+      else {
+        goto free_and_set_false;
+      }
+      CASE(OP_typeof_is_function) : if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_function) {
+        goto free_and_set_true;
+      }
+      else {
+        goto free_and_set_false;
+      }
+    free_and_set_true:
+      JS_FreeValue(ctx, sp[-1]);
+#endif
+    set_true:
+      sp[-1] = JS_TRUE;
+      BREAK;
+    free_and_set_false:
+      JS_FreeValue(ctx, sp[-1]);
+      sp[-1] = JS_FALSE;
+      BREAK;
+      CASE(OP_invalid)
+          : DEFAULT
+          : JS_ThrowInternalError(ctx, "invalid opcode: pc=%u opcode=0x%02x", (int)(pc - b->byte_code_buf - 1), opcode);
+      goto exception;
+    }
+  }
+exception:
+  if (is_backtrace_needed(ctx, rt->current_exception)) {
+    /* add the backtrace information now (it is not done
+       before if the exception happens in a bytecode
+       operation */
+    sf->cur_pc = pc;
+    build_backtrace(ctx, rt->current_exception, NULL, 0, 0);
+  }
+  if (!JS_IsUncatchableError(ctx, rt->current_exception)) {
+    while (sp > stack_buf) {
+      JSValue val = *--sp;
+      JS_FreeValue(ctx, val);
+      if (JS_VALUE_GET_TAG(val) == JS_TAG_CATCH_OFFSET) {
+        int pos = JS_VALUE_GET_INT(val);
+        if (pos == 0) {
+          /* enumerator: close it with a throw */
+          JS_FreeValue(ctx, sp[-1]); /* drop the next method */
+          sp--;
+          JS_IteratorClose(ctx, sp[-1], TRUE);
+        } else {
+          *sp++ = rt->current_exception;
+          rt->current_exception = JS_NULL;
+          pc = b->byte_code_buf + pos;
+          goto restart;
+        }
+      }
+    }
+  }
+  ret_val = JS_EXCEPTION;
+  /* the local variables are freed by the caller in the generator
+     case. Hence the label 'done' should never be reached in a
+     generator function. */
+  if (b->func_kind != JS_FUNC_NORMAL) {
+  done_generator:
+    sf->cur_pc = pc;
+    sf->cur_sp = sp;
+  } else {
+  done:
+    if (unlikely(!list_empty(&sf->var_ref_list))) {
+      /* variable references reference the stack: must close them */
+      close_var_refs(rt, sf);
+    }
+    /* free the local variables and stack */
+    for (pval = local_buf; pval < sp; pval++) {
+      JS_FreeValue(ctx, *pval);
+    }
+  }
+  rt->current_stack_frame = sf->prev_frame;
+  return ret_val;
+}
+
+JSValue JS_Call(JSContext* ctx, JSValueConst func_obj, JSValueConst this_obj, int argc, JSValueConst* argv) {
+  return JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED, argc, (JSValue*)argv, JS_CALL_FLAG_COPY_ARGV);
+}
+
+JSValue JS_CallFree(JSContext* ctx, JSValue func_obj, JSValueConst this_obj, int argc, JSValueConst* argv) {
+  JSValue res = JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED, argc, (JSValue*)argv, JS_CALL_FLAG_COPY_ARGV);
+  JS_FreeValue(ctx, func_obj);
+  return res;
+}
+
+JSValue JS_InvokeFree(JSContext* ctx, JSValue this_val, JSAtom atom, int argc, JSValueConst* argv) {
+  JSValue res = JS_Invoke(ctx, this_val, atom, argc, argv);
+  JS_FreeValue(ctx, this_val);
+  return res;
+}
+
+/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */
+JSValue JS_CallConstructorInternal(JSContext* ctx,
+                                          JSValueConst func_obj,
+                                          JSValueConst new_target,
+                                          int argc,
+                                          JSValue* argv,
+                                          int flags) {
+  JSObject* p;
+  JSFunctionBytecode* b;
+
+  if (js_poll_interrupts(ctx))
+    return JS_EXCEPTION;
+  flags |= JS_CALL_FLAG_CONSTRUCTOR;
+  if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT))
+    goto not_a_function;
+  p = JS_VALUE_GET_OBJ(func_obj);
+  if (unlikely(!p->is_constructor))
+    return JS_ThrowTypeError(ctx, "not a constructor");
+  if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {
+    JSClassCall* call_func;
+    call_func = ctx->rt->class_array[p->class_id].call;
+    if (!call_func) {
+    not_a_function:
+      return JS_ThrowTypeError(ctx, "not a function");
+    }
+    return call_func(ctx, func_obj, new_target, argc, (JSValueConst*)argv, flags);
+  }
+
+  b = p->u.func.function_bytecode;
+  if (b->is_derived_class_constructor) {
+    return JS_CallInternal(ctx, func_obj, JS_UNDEFINED, new_target, argc, argv, flags);
+  } else {
+    JSValue obj, ret;
+    /* legacy constructor behavior */
+    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
+    if (JS_IsException(obj))
+      return JS_EXCEPTION;
+    ret = JS_CallInternal(ctx, func_obj, obj, new_target, argc, argv, flags);
+    if (JS_VALUE_GET_TAG(ret) == JS_TAG_OBJECT || JS_IsException(ret)) {
+      JS_FreeValue(ctx, obj);
+      return ret;
+    } else {
+      JS_FreeValue(ctx, ret);
+      return obj;
+    }
+  }
+}
+
+BOOL JS_IsCFunction(JSContext* ctx, JSValueConst val, JSCFunction* func, int magic) {
+  JSObject* p;
+  if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
+    return FALSE;
+  p = JS_VALUE_GET_OBJ(val);
+  if (p->class_id == JS_CLASS_C_FUNCTION)
+    return (p->u.cfunc.c_function.generic == func && p->u.cfunc.magic == magic);
+  else
+    return FALSE;
+}
+
+BOOL JS_IsConstructor(JSContext* ctx, JSValueConst val) {
+  JSObject* p;
+  if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
+    return FALSE;
+  p = JS_VALUE_GET_OBJ(val);
+  return p->is_constructor;
+}
+
+JSValue JS_CallConstructor2(JSContext* ctx,
+                            JSValueConst func_obj,
+                            JSValueConst new_target,
+                            int argc,
+                            JSValueConst* argv) {
+  return JS_CallConstructorInternal(ctx, func_obj, new_target, argc, (JSValue*)argv, JS_CALL_FLAG_COPY_ARGV);
+}
+
+JSValue JS_CallConstructor(JSContext* ctx, JSValueConst func_obj, int argc, JSValueConst* argv) {
+  return JS_CallConstructorInternal(ctx, func_obj, func_obj, argc, (JSValue*)argv, JS_CALL_FLAG_COPY_ARGV);
+}
+
+JSValue JS_Invoke(JSContext* ctx, JSValueConst this_val, JSAtom atom, int argc, JSValueConst* argv) {
+  JSValue func_obj;
+  func_obj = JS_GetProperty(ctx, this_val, atom);
+  if (JS_IsException(func_obj))
+    return func_obj;
+  return JS_CallFree(ctx, func_obj, this_val, argc, argv);
+}
+
+/* Note: at least 'length' arguments will be readable in 'argv' */
+JSValue JS_NewCFunction3(JSContext* ctx,
+                                JSCFunction* func,
+                                const char* name,
+                                int length,
+                                JSCFunctionEnum cproto,
+                                int magic,
+                                JSValueConst proto_val) {
+  JSValue func_obj;
+  JSObject* p;
+  JSAtom name_atom;
+
+  func_obj = JS_NewObjectProtoClass(ctx, proto_val, JS_CLASS_C_FUNCTION);
+  if (JS_IsException(func_obj))
+    return func_obj;
+  p = JS_VALUE_GET_OBJ(func_obj);
+  p->u.cfunc.realm = JS_DupContext(ctx);
+  p->u.cfunc.c_function.generic = func;
+  p->u.cfunc.length = length;
+  p->u.cfunc.cproto = cproto;
+  p->u.cfunc.magic = magic;
+  p->is_constructor = (cproto == JS_CFUNC_constructor || cproto == JS_CFUNC_constructor_magic ||
+                       cproto == JS_CFUNC_constructor_or_func || cproto == JS_CFUNC_constructor_or_func_magic);
+  if (!name)
+    name = "";
+  name_atom = JS_NewAtom(ctx, name);
+  js_function_set_properties(ctx, func_obj, name_atom, length);
+  JS_FreeAtom(ctx, name_atom);
+  return func_obj;
+}
+
+/* Note: at least 'length' arguments will be readable in 'argv' */
+JSValue JS_NewCFunction2(JSContext* ctx,
+                         JSCFunction* func,
+                         const char* name,
+                         int length,
+                         JSCFunctionEnum cproto,
+                         int magic) {
+  return JS_NewCFunction3(ctx, func, name, length, cproto, magic, ctx->function_proto);
+}
+
+/* warning: the refcount of the context is not incremented. Return
+   NULL in case of exception (case of revoked proxy only) */
+JSContext* JS_GetFunctionRealm(JSContext* ctx, JSValueConst func_obj) {
+  JSObject* p;
+  JSContext* realm;
+
+  if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
+    return ctx;
+  p = JS_VALUE_GET_OBJ(func_obj);
+  switch (p->class_id) {
+    case JS_CLASS_C_FUNCTION:
+      realm = p->u.cfunc.realm;
+      break;
+    case JS_CLASS_BYTECODE_FUNCTION:
+    case JS_CLASS_GENERATOR_FUNCTION:
+    case JS_CLASS_ASYNC_FUNCTION:
+    case JS_CLASS_ASYNC_GENERATOR_FUNCTION: {
+      JSFunctionBytecode* b;
+      b = p->u.func.function_bytecode;
+      realm = b->realm;
+    } break;
+    case JS_CLASS_PROXY: {
+      JSProxyData* s = p->u.opaque;
+      if (!s)
+        return ctx;
+      if (s->is_revoked) {
+        JS_ThrowTypeErrorRevokedProxy(ctx);
+        return NULL;
+      } else {
+        realm = JS_GetFunctionRealm(ctx, s->target);
+      }
+    } break;
+    case JS_CLASS_BOUND_FUNCTION: {
+      JSBoundFunction* bf = p->u.bound_function;
+      realm = JS_GetFunctionRealm(ctx, bf->func_obj);
+    } break;
+    default:
+      realm = ctx;
+      break;
+  }
+  return realm;
+}
+
+void js_c_function_data_finalizer(JSRuntime* rt, JSValue val) {
+  JSCFunctionDataRecord* s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA);
+  int i;
+
+  if (s) {
+    for (i = 0; i < s->data_len; i++) {
+      JS_FreeValueRT(rt, s->data[i]);
+    }
+    js_free_rt(rt, s);
+  }
+}
+
+void js_c_function_data_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func) {
+  JSCFunctionDataRecord* s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA);
+  int i;
+
+  if (s) {
+    for (i = 0; i < s->data_len; i++) {
+      JS_MarkValue(rt, s->data[i], mark_func);
+    }
+  }
+}
+
+JSValue js_c_function_data_call(JSContext* ctx,
+                                       JSValueConst func_obj,
+                                       JSValueConst this_val,
+                                       int argc,
+                                       JSValueConst* argv,
+                                       int flags) {
+  JSCFunctionDataRecord* s = JS_GetOpaque(func_obj, JS_CLASS_C_FUNCTION_DATA);
+  JSValueConst* arg_buf;
+  int i;
+
+  /* XXX: could add the function on the stack for debug */
+  if (unlikely(argc < s->length)) {
+    arg_buf = alloca(sizeof(arg_buf[0]) * s->length);
+    for (i = 0; i < argc; i++)
+      arg_buf[i] = argv[i];
+    for (i = argc; i < s->length; i++)
+      arg_buf[i] = JS_UNDEFINED;
+  } else {
+    arg_buf = argv;
+  }
+
+  return s->func(ctx, this_val, argc, arg_buf, s->magic, s->data);
+}
+
+int js_op_define_class(JSContext* ctx,
+                              JSValue* sp,
+                              JSAtom class_name,
+                              int class_flags,
+                              JSVarRef** cur_var_refs,
+                              JSStackFrame* sf,
+                              BOOL is_computed_name) {
+  JSValue bfunc, parent_class, proto = JS_UNDEFINED;
+  JSValue ctor = JS_UNDEFINED, parent_proto = JS_UNDEFINED;
+  JSFunctionBytecode* b;
+
+  parent_class = sp[-2];
+  bfunc = sp[-1];
+
+  if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE) {
+    if (JS_IsNull(parent_class)) {
+      parent_proto = JS_NULL;
+      parent_class = JS_DupValue(ctx, ctx->function_proto);
+    } else {
+      if (!JS_IsConstructor(ctx, parent_class)) {
+        JS_ThrowTypeError(ctx, "parent class must be constructor");
+        goto fail;
+      }
+      parent_proto = JS_GetProperty(ctx, parent_class, JS_ATOM_prototype);
+      if (JS_IsException(parent_proto))
+        goto fail;
+      if (!JS_IsNull(parent_proto) && !JS_IsObject(parent_proto)) {
+        JS_ThrowTypeError(ctx, "parent prototype must be an object or null");
+        goto fail;
+      }
+    }
+  } else {
+    /* parent_class is JS_UNDEFINED in this case */
+    parent_proto = JS_DupValue(ctx, ctx->class_proto[JS_CLASS_OBJECT]);
+    parent_class = JS_DupValue(ctx, ctx->function_proto);
+  }
+  proto = JS_NewObjectProto(ctx, parent_proto);
+  if (JS_IsException(proto))
+    goto fail;
+
+  b = JS_VALUE_GET_PTR(bfunc);
+  assert(b->func_kind == JS_FUNC_NORMAL);
+  ctor = JS_NewObjectProtoClass(ctx, parent_class, JS_CLASS_BYTECODE_FUNCTION);
+  if (JS_IsException(ctor))
+    goto fail;
+  ctor = js_closure2(ctx, ctor, b, cur_var_refs, sf);
+  bfunc = JS_UNDEFINED;
+  if (JS_IsException(ctor))
+    goto fail;
+  js_method_set_home_object(ctx, ctor, proto);
+  JS_SetConstructorBit(ctx, ctor, TRUE);
+
+  JS_DefinePropertyValue(ctx, ctor, JS_ATOM_length, JS_NewInt32(ctx, b->defined_arg_count), JS_PROP_CONFIGURABLE);
+
+  if (is_computed_name) {
+    if (JS_DefineObjectNameComputed(ctx, ctor, sp[-3], JS_PROP_CONFIGURABLE) < 0)
+      goto fail;
+  } else {
+    if (JS_DefineObjectName(ctx, ctor, class_name, JS_PROP_CONFIGURABLE) < 0)
+      goto fail;
+  }
+
+  /* the constructor property must be first. It can be overriden by
+     computed property names */
+  if (JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor, JS_DupValue(ctx, ctor),
+                             JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE | JS_PROP_THROW) < 0)
+    goto fail;
+  /* set the prototype property */
+  if (JS_DefinePropertyValue(ctx, ctor, JS_ATOM_prototype, JS_DupValue(ctx, proto), JS_PROP_THROW) < 0)
+    goto fail;
+  set_cycle_flag(ctx, ctor);
+  set_cycle_flag(ctx, proto);
+
+  JS_FreeValue(ctx, parent_proto);
+  JS_FreeValue(ctx, parent_class);
+
+  sp[-2] = ctor;
+  sp[-1] = proto;
+  return 0;
+fail:
+  JS_FreeValue(ctx, parent_class);
+  JS_FreeValue(ctx, parent_proto);
+  JS_FreeValue(ctx, bfunc);
+  JS_FreeValue(ctx, proto);
+  JS_FreeValue(ctx, ctor);
+  sp[-2] = JS_UNDEFINED;
+  sp[-1] = JS_UNDEFINED;
+  return -1;
+};
diff --git a/src/core/function.h b/src/core/function.h
new file mode 100644
index 000000000..d188194be
--- /dev/null
+++ b/src/core/function.h
@@ -0,0 +1,153 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_FUNCTION_H
+#define QUICKJS_FUNCTION_H
+
+#include "quickjs/cutils.h"
+#include "quickjs/quickjs.h"
+#include "types.h"
+
+#define JS_CALL_FLAG_COPY_ARGV (1 << 1)
+#define JS_CALL_FLAG_GENERATOR (1 << 2)
+
+#define OP_DEFINE_METHOD_METHOD 0
+#define OP_DEFINE_METHOD_GETTER 1
+#define OP_DEFINE_METHOD_SETTER 2
+#define OP_DEFINE_METHOD_ENUMERABLE 4
+
+#define JS_THROW_VAR_RO 0
+#define JS_THROW_VAR_REDECL 1
+#define JS_THROW_VAR_UNINITIALIZED 2
+#define JS_THROW_ERROR_DELETE_SUPER 3
+#define JS_THROW_ERROR_ITERATOR_THROW 4
+
+typedef struct JSCFunctionDataRecord {
+  JSCFunctionData* func;
+  uint8_t length;
+  uint8_t data_len;
+  uint16_t magic;
+  JSValue data[0];
+} JSCFunctionDataRecord;
+
+/* argument of OP_special_object */
+typedef enum {
+  OP_SPECIAL_OBJECT_ARGUMENTS,
+  OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS,
+  OP_SPECIAL_OBJECT_THIS_FUNC,
+  OP_SPECIAL_OBJECT_NEW_TARGET,
+  OP_SPECIAL_OBJECT_HOME_OBJECT,
+  OP_SPECIAL_OBJECT_VAR_OBJECT,
+  OP_SPECIAL_OBJECT_IMPORT_META,
+} OPSpecialObjectEnum;
+
+#define FUNC_RET_AWAIT 0
+#define FUNC_RET_YIELD 1
+#define FUNC_RET_YIELD_STAR 2
+
+#if !defined(CONFIG_STACK_CHECK)
+/* no stack limitation */
+static inline uintptr_t js_get_stack_pointer(void) {
+  return 0;
+}
+
+static inline BOOL js_check_stack_overflow(JSRuntime* rt, size_t alloca_size) {
+  return FALSE;
+}
+#else
+/* Note: OS and CPU dependent */
+static inline uintptr_t js_get_stack_pointer(void) {
+  return (uintptr_t)__builtin_frame_address(0);
+}
+
+static inline BOOL js_check_stack_overflow(JSRuntime* rt, size_t alloca_size) {
+  uintptr_t sp;
+  sp = js_get_stack_pointer() - alloca_size;
+  return unlikely(sp < rt->stack_limit);
+}
+#endif
+
+JSValue js_call_c_function(JSContext* ctx,
+                                  JSValueConst func_obj,
+                                  JSValueConst this_obj,
+                                  int argc,
+                                  JSValueConst* argv,
+                                  int flags);
+JSValue js_call_bound_function(JSContext* ctx,
+                                      JSValueConst func_obj,
+                                      JSValueConst this_obj,
+                                      int argc,
+                                      JSValueConst* argv,
+                                      int flags);
+JSValue JS_CallInternal(JSContext* ctx,
+                               JSValueConst func_obj,
+                               JSValueConst this_obj,
+                               JSValueConst new_target,
+                               int argc,
+                               JSValue* argv,
+                               int flags);
+JSValue JS_CallConstructorInternal(JSContext* ctx,
+                                          JSValueConst func_obj,
+                                          JSValueConst new_target,
+                                          int argc,
+                                          JSValue* argv,
+                                          int flags);
+BOOL JS_IsCFunction(JSContext* ctx, JSValueConst val, JSCFunction* func, int magic);
+
+/* Note: at least 'length' arguments will be readable in 'argv' */
+JSValue JS_NewCFunction3(JSContext* ctx,
+                                JSCFunction* func,
+                                const char* name,
+                                int length,
+                                JSCFunctionEnum cproto,
+                                int magic,
+                                JSValueConst proto_val);
+
+/* warning: the refcount of the context is not incremented. Return
+   NULL in case of exception (case of revoked proxy only) */
+JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValueConst func_obj);
+
+JSValue JS_CallFree(JSContext* ctx, JSValue func_obj, JSValueConst this_obj, int argc, JSValueConst* argv);
+JSValue JS_InvokeFree(JSContext* ctx, JSValue this_val, JSAtom atom, int argc, JSValueConst* argv);
+
+void js_c_function_data_finalizer(JSRuntime* rt, JSValue val);
+void js_c_function_data_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func);
+
+JSValue js_c_function_data_call(JSContext* ctx,
+                                       JSValueConst func_obj,
+                                       JSValueConst this_val,
+                                       int argc,
+                                       JSValueConst* argv,
+                                       int flags);
+
+int js_op_define_class(JSContext* ctx,
+                              JSValue* sp,
+                              JSAtom class_name,
+                              int class_flags,
+                              JSVarRef** cur_var_refs,
+                              JSStackFrame* sf,
+                              BOOL is_computed_name);
+
+#endif
diff --git a/src/core/gc.c b/src/core/gc.c
new file mode 100644
index 000000000..a260d106a
--- /dev/null
+++ b/src/core/gc.c
@@ -0,0 +1,806 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "gc.h"
+#include "builtins/js-async-function.h"
+#include "builtins/js-map.h"
+#include "builtins/js-proxy.h"
+#include "bytecode.h"
+#include "malloc.h"
+#include "module.h"
+#include "object.h"
+#include "parser.h"
+#include "runtime.h"
+#include "shape.h"
+#include "string.h"
+
+__maybe_unused void JS_DumpObjectHeader(JSRuntime* rt) {
+  printf("%14s %4s %4s %14s %10s %s\n", "ADDRESS", "REFS", "SHRF", "PROTO", "CLASS", "PROPS");
+}
+
+/* for debug only: dump an object without side effect */
+__maybe_unused void JS_DumpObject(JSRuntime* rt, JSObject* p) {
+  uint32_t i;
+  char atom_buf[ATOM_GET_STR_BUF_SIZE];
+  JSShape* sh;
+  JSShapeProperty* prs;
+  JSProperty* pr;
+  BOOL is_first = TRUE;
+
+  /* XXX: should encode atoms with special characters */
+  sh = p->shape; /* the shape can be NULL while freeing an object */
+  printf("%14p %4d ", (void*)p, p->header.ref_count);
+  if (sh) {
+    printf("%3d%c %14p ", sh->header.ref_count, " *"[sh->is_hashed], (void*)sh -> proto);
+  } else {
+    printf("%3s  %14s ", "-", "-");
+  }
+  printf("%10s ", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), rt->class_array[p->class_id].class_name));
+  if (p->is_exotic && p->fast_array) {
+    printf("[ ");
+    for (i = 0; i < p->u.array.count; i++) {
+      if (i != 0)
+        printf(", ");
+      switch (p->class_id) {
+        case JS_CLASS_ARRAY:
+        case JS_CLASS_ARGUMENTS:
+          JS_DumpValueShort(rt, p->u.array.u.values[i]);
+          break;
+        case JS_CLASS_UINT8C_ARRAY:
+        case JS_CLASS_INT8_ARRAY:
+        case JS_CLASS_UINT8_ARRAY:
+        case JS_CLASS_INT16_ARRAY:
+        case JS_CLASS_UINT16_ARRAY:
+        case JS_CLASS_INT32_ARRAY:
+        case JS_CLASS_UINT32_ARRAY:
+#ifdef CONFIG_BIGNUM
+        case JS_CLASS_BIG_INT64_ARRAY:
+        case JS_CLASS_BIG_UINT64_ARRAY:
+#endif
+        case JS_CLASS_FLOAT32_ARRAY:
+        case JS_CLASS_FLOAT64_ARRAY: {
+          int size = 1 << typed_array_size_log2(p->class_id);
+          const uint8_t* b = p->u.array.u.uint8_ptr + i * size;
+          while (size-- > 0)
+            printf("%02X", *b++);
+        } break;
+      }
+    }
+    printf(" ] ");
+  }
+
+  if (sh) {
+    printf("{ ");
+    for (i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
+      if (prs->atom != JS_ATOM_NULL) {
+        pr = &p->prop[i];
+        if (!is_first)
+          printf(", ");
+        printf("%s: ", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), prs->atom));
+        if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
+          printf("[getset %p %p]", (void*)pr->u.getset.getter, (void*)pr->u.getset.setter);
+        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
+          printf("[varref %p]", (void*)pr->u.var_ref);
+        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
+          printf("[autoinit %p %d %p]", (void*)js_autoinit_get_realm(pr), js_autoinit_get_id(pr), (void*)pr->u.init.opaque);
+        } else {
+          JS_DumpValueShort(rt, pr->u.value);
+        }
+        is_first = FALSE;
+      }
+    }
+    printf(" }");
+  }
+
+  if (js_class_has_bytecode(p->class_id)) {
+    JSFunctionBytecode* b = p->u.func.function_bytecode;
+    JSVarRef** var_refs;
+    if (b->closure_var_count) {
+      var_refs = p->u.func.var_refs;
+      printf(" Closure:");
+      for (i = 0; i < b->closure_var_count; i++) {
+        printf(" ");
+        JS_DumpValueShort(rt, var_refs[i]->value);
+      }
+      if (p->u.func.home_object) {
+        printf(" HomeObject: ");
+        JS_DumpValueShort(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object));
+      }
+    }
+  }
+  printf("\n");
+}
+
+__maybe_unused void JS_DumpGCObject(JSRuntime* rt, JSGCObjectHeader* p) {
+  if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
+    JS_DumpObject(rt, (JSObject*)p);
+  } else {
+    printf("%14p %4d ", (void*)p, p->ref_count);
+    switch (p->gc_obj_type) {
+      case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
+        printf("[function bytecode]");
+        break;
+      case JS_GC_OBJ_TYPE_SHAPE:
+        printf("[shape]");
+        break;
+      case JS_GC_OBJ_TYPE_VAR_REF:
+        printf("[var_ref]");
+        break;
+      case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
+        printf("[async_function]");
+        break;
+      case JS_GC_OBJ_TYPE_JS_CONTEXT:
+        printf("[js_context]");
+        break;
+      default:
+        printf("[unknown %d]", p->gc_obj_type);
+        break;
+    }
+    printf("\n");
+  }
+}
+
+/* return -1 if exception (proxy case) or TRUE/FALSE */
+int JS_IsArray(JSContext* ctx, JSValueConst val) {
+  JSObject* p;
+  if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {
+    p = JS_VALUE_GET_OBJ(val);
+    if (unlikely(p->class_id == JS_CLASS_PROXY))
+      return js_proxy_isArray(ctx, val);
+    else
+      return p->class_id == JS_CLASS_ARRAY;
+  } else {
+    return FALSE;
+  }
+}
+
+__maybe_unused void JS_DumpValueShort(JSRuntime* rt, JSValueConst val) {
+  uint32_t tag = JS_VALUE_GET_NORM_TAG(val);
+  const char* str;
+
+  switch (tag) {
+    case JS_TAG_INT:
+      printf("%d", JS_VALUE_GET_INT(val));
+      break;
+    case JS_TAG_BOOL:
+      if (JS_VALUE_GET_BOOL(val))
+        str = "true";
+      else
+        str = "false";
+      goto print_str;
+    case JS_TAG_NULL:
+      str = "null";
+      goto print_str;
+    case JS_TAG_EXCEPTION:
+      str = "exception";
+      goto print_str;
+    case JS_TAG_UNINITIALIZED:
+      str = "uninitialized";
+      goto print_str;
+    case JS_TAG_UNDEFINED:
+      str = "undefined";
+    print_str:
+      printf("%s", str);
+      break;
+    case JS_TAG_FLOAT64:
+      printf("%.14g", JS_VALUE_GET_FLOAT64(val));
+      break;
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_INT: {
+      JSBigFloat* p = JS_VALUE_GET_PTR(val);
+      char* str;
+      str = bf_ftoa(NULL, &p->num, 10, 0, BF_RNDZ | BF_FTOA_FORMAT_FRAC);
+      printf("%sn", str);
+      bf_realloc(&rt->bf_ctx, str, 0);
+    } break;
+    case JS_TAG_BIG_FLOAT: {
+      JSBigFloat* p = JS_VALUE_GET_PTR(val);
+      char* str;
+      str = bf_ftoa(NULL, &p->num, 16, BF_PREC_INF, BF_RNDZ | BF_FTOA_FORMAT_FREE | BF_FTOA_ADD_PREFIX);
+      printf("%sl", str);
+      bf_free(&rt->bf_ctx, str);
+    } break;
+    case JS_TAG_BIG_DECIMAL: {
+      JSBigDecimal* p = JS_VALUE_GET_PTR(val);
+      char* str;
+      str = bfdec_ftoa(NULL, &p->num, BF_PREC_INF, BF_RNDZ | BF_FTOA_FORMAT_FREE);
+      printf("%sm", str);
+      bf_free(&rt->bf_ctx, str);
+    } break;
+#endif
+    case JS_TAG_STRING: {
+      JSString* p;
+      p = JS_VALUE_GET_STRING(val);
+      JS_DumpString(rt, p);
+    } break;
+    case JS_TAG_FUNCTION_BYTECODE: {
+      JSFunctionBytecode* b = JS_VALUE_GET_PTR(val);
+      char buf[ATOM_GET_STR_BUF_SIZE];
+      printf("[bytecode %s]", JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
+    } break;
+    case JS_TAG_OBJECT: {
+      JSObject* p = JS_VALUE_GET_OBJ(val);
+      JSAtom atom = rt->class_array[p->class_id].class_name;
+      char atom_buf[ATOM_GET_STR_BUF_SIZE];
+      printf("[%s %p]", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), atom), (void*)p);
+    } break;
+    case JS_TAG_SYMBOL: {
+      JSAtomStruct* p = JS_VALUE_GET_PTR(val);
+      char atom_buf[ATOM_GET_STR_BUF_SIZE];
+      printf("Symbol(%s)", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), js_get_atom_index(rt, p)));
+    } break;
+    case JS_TAG_MODULE:
+      printf("[module]");
+      break;
+    default:
+      printf("[unknown tag %d]", tag);
+      break;
+  }
+}
+
+__maybe_unused void JS_DumpValue(JSContext* ctx, JSValueConst val) {
+  JS_DumpValueShort(ctx->rt, val);
+}
+
+__maybe_unused void JS_PrintValue(JSContext* ctx, const char* str, JSValueConst val) {
+  printf("%s=", str);
+  JS_DumpValueShort(ctx->rt, val);
+  printf("\n");
+}
+
+void js_object_list_init(JSObjectList* s) {
+  memset(s, 0, sizeof(*s));
+}
+
+uint32_t js_object_list_get_hash(JSObject* p, uint32_t hash_size) {
+  return ((uintptr_t)p * 3163) & (hash_size - 1);
+}
+
+int js_object_list_resize_hash(JSContext* ctx, JSObjectList* s, uint32_t new_hash_size) {
+  JSObjectListEntry* e;
+  uint32_t i, h, *new_hash_table;
+
+  new_hash_table = js_malloc(ctx, sizeof(new_hash_table[0]) * new_hash_size);
+  if (!new_hash_table)
+    return -1;
+  js_free(ctx, s->hash_table);
+  s->hash_table = new_hash_table;
+  s->hash_size = new_hash_size;
+
+  for (i = 0; i < s->hash_size; i++) {
+    s->hash_table[i] = -1;
+  }
+  for (i = 0; i < s->object_count; i++) {
+    e = &s->object_tab[i];
+    h = js_object_list_get_hash(e->obj, s->hash_size);
+    e->hash_next = s->hash_table[h];
+    s->hash_table[h] = i;
+  }
+  return 0;
+}
+
+/* the reference count of 'obj' is not modified. Return 0 if OK, -1 if
+   memory error */
+int js_object_list_add(JSContext* ctx, JSObjectList* s, JSObject* obj) {
+  JSObjectListEntry* e;
+  uint32_t h, new_hash_size;
+
+  if (js_resize_array(ctx, (void*)&s->object_tab, sizeof(s->object_tab[0]), &s->object_size, s->object_count + 1))
+    return -1;
+  if (unlikely((s->object_count + 1) >= s->hash_size)) {
+    new_hash_size = max_uint32(s->hash_size, 4);
+    while (new_hash_size <= s->object_count)
+      new_hash_size *= 2;
+    if (js_object_list_resize_hash(ctx, s, new_hash_size))
+      return -1;
+  }
+  e = &s->object_tab[s->object_count++];
+  h = js_object_list_get_hash(obj, s->hash_size);
+  e->obj = obj;
+  e->hash_next = s->hash_table[h];
+  s->hash_table[h] = s->object_count - 1;
+  return 0;
+}
+
+/* return -1 if not present or the object index */
+int js_object_list_find(JSContext* ctx, JSObjectList* s, JSObject* obj) {
+  JSObjectListEntry* e;
+  uint32_t h, p;
+
+  /* must test empty size because there is no hash table */
+  if (s->object_count == 0)
+    return -1;
+  h = js_object_list_get_hash(obj, s->hash_size);
+  p = s->hash_table[h];
+  while (p != -1) {
+    e = &s->object_tab[p];
+    if (e->obj == obj)
+      return p;
+    p = e->hash_next;
+  }
+  return -1;
+}
+
+void js_object_list_end(JSContext* ctx, JSObjectList* s) {
+  js_free(ctx, s->object_tab);
+  js_free(ctx, s->hash_table);
+}
+
+/* indicate that the object may be part of a function prototype cycle */
+void set_cycle_flag(JSContext* ctx, JSValueConst obj) {}
+
+void remove_gc_object(JSGCObjectHeader* h) {
+  list_del(&h->link);
+}
+
+void free_var_ref(JSRuntime* rt, JSVarRef* var_ref) {
+  if (var_ref) {
+    assert(var_ref->header.ref_count > 0);
+    if (--var_ref->header.ref_count == 0) {
+      if (var_ref->is_detached) {
+        JS_FreeValueRT(rt, var_ref->value);
+        remove_gc_object(&var_ref->header);
+      } else {
+        list_del(&var_ref->header.link); /* still on the stack */
+      }
+      js_free_rt(rt, var_ref);
+    }
+  }
+}
+
+void free_object(JSRuntime* rt, JSObject* p) {
+  int i;
+  JSClassFinalizer* finalizer;
+  JSShape* sh;
+  JSShapeProperty* pr;
+
+  p->free_mark = 1; /* used to tell the object is invalid when
+                       freeing cycles */
+  /* free all the fields */
+  sh = p->shape;
+  pr = get_shape_prop(sh);
+  for (i = 0; i < sh->prop_count; i++) {
+    free_property(rt, &p->prop[i], pr->flags);
+    pr++;
+  }
+  js_free_rt(rt, p->prop);
+  /* as an optimization we destroy the shape immediately without
+     putting it in gc_zero_ref_count_list */
+  js_free_shape(rt, sh);
+
+  /* fail safe */
+  p->shape = NULL;
+  p->prop = NULL;
+
+  if (unlikely(p->first_weak_ref)) {
+    reset_weak_ref(rt, p);
+  }
+
+  finalizer = rt->class_array[p->class_id].finalizer;
+  if (finalizer)
+    (*finalizer)(rt, JS_MKPTR(JS_TAG_OBJECT, p));
+
+  /* fail safe */
+  p->class_id = 0;
+  p->u.opaque = NULL;
+  p->u.func.var_refs = NULL;
+  p->u.func.home_object = NULL;
+
+  remove_gc_object(&p->header);
+  if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && p->header.ref_count != 0) {
+    list_add_tail(&p->header.link, &rt->gc_zero_ref_count_list);
+  } else {
+    js_free_rt(rt, p);
+  }
+}
+
+void free_gc_object(JSRuntime* rt, JSGCObjectHeader* gp) {
+  switch (gp->gc_obj_type) {
+    case JS_GC_OBJ_TYPE_JS_OBJECT:
+      free_object(rt, (JSObject*)gp);
+      break;
+    case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
+      free_function_bytecode(rt, (JSFunctionBytecode*)gp);
+      break;
+    default:
+      abort();
+  }
+}
+
+void free_zero_refcount(JSRuntime* rt) {
+  struct list_head* el;
+  JSGCObjectHeader* p;
+
+  rt->gc_phase = JS_GC_PHASE_DECREF;
+  for (;;) {
+    el = rt->gc_zero_ref_count_list.next;
+    if (el == &rt->gc_zero_ref_count_list)
+      break;
+    p = list_entry(el, JSGCObjectHeader, link);
+    assert(p->ref_count == 0);
+    free_gc_object(rt, p);
+  }
+  rt->gc_phase = JS_GC_PHASE_NONE;
+}
+
+/* called with the ref_count of 'v' reaches zero. */
+void __JS_FreeValueRT(JSRuntime* rt, JSValue v) {
+  uint32_t tag = JS_VALUE_GET_TAG(v);
+
+#ifdef DUMP_FREE
+  {
+    printf("Freeing ");
+    if (tag == JS_TAG_OBJECT) {
+      JS_DumpObject(rt, JS_VALUE_GET_OBJ(v));
+    } else {
+      JS_DumpValueShort(rt, v);
+      printf("\n");
+    }
+  }
+#endif
+
+  switch (tag) {
+    case JS_TAG_STRING: {
+      JSString* p = JS_VALUE_GET_STRING(v);
+      if (p->atom_type) {
+        JS_FreeAtomStruct(rt, p);
+      } else {
+#ifdef DUMP_LEAKS
+        list_del(&p->link);
+#endif
+        js_free_rt(rt, p);
+      }
+    } break;
+    case JS_TAG_OBJECT:
+    case JS_TAG_FUNCTION_BYTECODE: {
+      JSGCObjectHeader* p = JS_VALUE_GET_PTR(v);
+      if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {
+        list_del(&p->link);
+        list_add(&p->link, &rt->gc_zero_ref_count_list);
+        if (rt->gc_phase == JS_GC_PHASE_NONE) {
+          free_zero_refcount(rt);
+        }
+      }
+    } break;
+    case JS_TAG_MODULE:
+      abort(); /* never freed here */
+      break;
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_INT:
+    case JS_TAG_BIG_FLOAT: {
+      JSBigFloat* bf = JS_VALUE_GET_PTR(v);
+      bf_delete(&bf->num);
+      js_free_rt(rt, bf);
+    } break;
+    case JS_TAG_BIG_DECIMAL: {
+      JSBigDecimal* bf = JS_VALUE_GET_PTR(v);
+      bfdec_delete(&bf->num);
+      js_free_rt(rt, bf);
+    } break;
+#endif
+    case JS_TAG_SYMBOL: {
+      JSAtomStruct* p = JS_VALUE_GET_PTR(v);
+      JS_FreeAtomStruct(rt, p);
+    } break;
+    default:
+      printf("__JS_FreeValue: unknown tag=%d\n", tag);
+      abort();
+  }
+}
+
+void __JS_FreeValue(JSContext* ctx, JSValue v) {
+  __JS_FreeValueRT(ctx->rt, v);
+}
+
+/* garbage collection */
+
+void add_gc_object(JSRuntime* rt, JSGCObjectHeader* h, JSGCObjectTypeEnum type) {
+  h->mark = 0;
+  h->gc_obj_type = type;
+  list_add_tail(&h->link, &rt->gc_obj_list);
+}
+
+void JS_MarkValue(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func) {
+  if (JS_VALUE_HAS_REF_COUNT(val)) {
+    switch (JS_VALUE_GET_TAG(val)) {
+      case JS_TAG_OBJECT:
+      case JS_TAG_FUNCTION_BYTECODE:
+        mark_func(rt, JS_VALUE_GET_PTR(val));
+        break;
+      default:
+        break;
+    }
+  }
+}
+
+/* XXX: would be more efficient with separate module lists */
+void js_free_modules(JSContext* ctx, JSFreeModuleEnum flag) {
+  struct list_head *el, *el1;
+  list_for_each_safe(el, el1, &ctx->loaded_modules) {
+    JSModuleDef* m = list_entry(el, JSModuleDef, link);
+    if (flag == JS_FREE_MODULE_ALL || (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved) || (flag == JS_FREE_MODULE_NOT_EVALUATED && !m->evaluated)) {
+      js_free_module_def(ctx, m);
+    }
+  }
+}
+
+JSContext* JS_DupContext(JSContext* ctx) {
+  ctx->header.ref_count++;
+  return ctx;
+}
+
+/* used by the GC */
+void JS_MarkContext(JSRuntime* rt, JSContext* ctx, JS_MarkFunc* mark_func) {
+  int i;
+  struct list_head* el;
+
+  /* modules are not seen by the GC, so we directly mark the objects
+     referenced by each module */
+  list_for_each(el, &ctx->loaded_modules) {
+    JSModuleDef* m = list_entry(el, JSModuleDef, link);
+    js_mark_module_def(rt, m, mark_func);
+  }
+
+  JS_MarkValue(rt, ctx->global_obj, mark_func);
+  JS_MarkValue(rt, ctx->global_var_obj, mark_func);
+
+  JS_MarkValue(rt, ctx->throw_type_error, mark_func);
+  JS_MarkValue(rt, ctx->eval_obj, mark_func);
+
+  JS_MarkValue(rt, ctx->array_proto_values, mark_func);
+  for (i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
+    JS_MarkValue(rt, ctx->native_error_proto[i], mark_func);
+  }
+  for (i = 0; i < rt->class_count; i++) {
+    JS_MarkValue(rt, ctx->class_proto[i], mark_func);
+  }
+  JS_MarkValue(rt, ctx->iterator_proto, mark_func);
+  JS_MarkValue(rt, ctx->async_iterator_proto, mark_func);
+  JS_MarkValue(rt, ctx->promise_ctor, mark_func);
+  JS_MarkValue(rt, ctx->array_ctor, mark_func);
+  JS_MarkValue(rt, ctx->regexp_ctor, mark_func);
+  JS_MarkValue(rt, ctx->function_ctor, mark_func);
+  JS_MarkValue(rt, ctx->function_proto, mark_func);
+
+  if (ctx->array_shape)
+    mark_func(rt, &ctx->array_shape->header);
+}
+
+void mark_children(JSRuntime* rt, JSGCObjectHeader* gp, JS_MarkFunc* mark_func) {
+  switch (gp->gc_obj_type) {
+    case JS_GC_OBJ_TYPE_JS_OBJECT: {
+      JSObject* p = (JSObject*)gp;
+      JSShapeProperty* prs;
+      JSShape* sh;
+      int i;
+      sh = p->shape;
+      mark_func(rt, &sh->header);
+      /* mark all the fields */
+      prs = get_shape_prop(sh);
+      for (i = 0; i < sh->prop_count; i++) {
+        JSProperty* pr = &p->prop[i];
+        if (prs->atom != JS_ATOM_NULL) {
+          if (prs->flags & JS_PROP_TMASK) {
+            if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
+              if (pr->u.getset.getter)
+                mark_func(rt, &pr->u.getset.getter->header);
+              if (pr->u.getset.setter)
+                mark_func(rt, &pr->u.getset.setter->header);
+            } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
+              if (pr->u.var_ref->is_detached) {
+                /* Note: the tag does not matter
+                   provided it is a GC object */
+                mark_func(rt, &pr->u.var_ref->header);
+              }
+            } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
+              js_autoinit_mark(rt, pr, mark_func);
+            }
+          } else {
+            JS_MarkValue(rt, pr->u.value, mark_func);
+          }
+        }
+        prs++;
+      }
+
+      if (p->class_id != JS_CLASS_OBJECT) {
+        JSClassGCMark* gc_mark;
+        gc_mark = rt->class_array[p->class_id].gc_mark;
+        if (gc_mark)
+          gc_mark(rt, JS_MKPTR(JS_TAG_OBJECT, p), mark_func);
+      }
+    } break;
+    case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
+      /* the template objects can be part of a cycle */
+      {
+        JSFunctionBytecode* b = (JSFunctionBytecode*)gp;
+        int i;
+        for (i = 0; i < b->cpool_count; i++) {
+          JS_MarkValue(rt, b->cpool[i], mark_func);
+        }
+        if (b->realm)
+          mark_func(rt, &b->realm->header);
+      }
+      break;
+    case JS_GC_OBJ_TYPE_VAR_REF: {
+      JSVarRef* var_ref = (JSVarRef*)gp;
+      /* only detached variable referenced are taken into account */
+      assert(var_ref->is_detached);
+      JS_MarkValue(rt, *var_ref->pvalue, mark_func);
+    } break;
+    case JS_GC_OBJ_TYPE_ASYNC_FUNCTION: {
+      JSAsyncFunctionData* s = (JSAsyncFunctionData*)gp;
+      if (s->is_active)
+        async_func_mark(rt, &s->func_state, mark_func);
+      JS_MarkValue(rt, s->resolving_funcs[0], mark_func);
+      JS_MarkValue(rt, s->resolving_funcs[1], mark_func);
+    } break;
+    case JS_GC_OBJ_TYPE_SHAPE: {
+      JSShape* sh = (JSShape*)gp;
+      if (sh->proto != NULL) {
+        mark_func(rt, &sh->proto->header);
+      }
+    } break;
+    case JS_GC_OBJ_TYPE_JS_CONTEXT: {
+      JSContext* ctx = (JSContext*)gp;
+      JS_MarkContext(rt, ctx, mark_func);
+    } break;
+    default:
+      abort();
+  }
+}
+
+void gc_decref_child(JSRuntime* rt, JSGCObjectHeader* p) {
+  assert(p->ref_count > 0);
+  p->ref_count--;
+  if (p->ref_count == 0 && p->mark == 1) {
+    list_del(&p->link);
+    list_add_tail(&p->link, &rt->tmp_obj_list);
+  }
+}
+
+void gc_decref(JSRuntime* rt) {
+  struct list_head *el, *el1;
+  JSGCObjectHeader* p;
+
+  init_list_head(&rt->tmp_obj_list);
+
+  /* decrement the refcount of all the children of all the GC
+     objects and move the GC objects with zero refcount to
+     tmp_obj_list */
+  list_for_each_safe(el, el1, &rt->gc_obj_list) {
+    p = list_entry(el, JSGCObjectHeader, link);
+    assert(p->mark == 0);
+    mark_children(rt, p, gc_decref_child);
+    p->mark = 1;
+    if (p->ref_count == 0) {
+      list_del(&p->link);
+      list_add_tail(&p->link, &rt->tmp_obj_list);
+    }
+  }
+}
+
+void gc_scan_incref_child(JSRuntime* rt, JSGCObjectHeader* p) {
+  p->ref_count++;
+  if (p->ref_count == 1) {
+    /* ref_count was 0: remove from tmp_obj_list and add at the
+       end of gc_obj_list */
+    list_del(&p->link);
+    list_add_tail(&p->link, &rt->gc_obj_list);
+    p->mark = 0; /* reset the mark for the next GC call */
+  }
+}
+
+void gc_scan_incref_child2(JSRuntime* rt, JSGCObjectHeader* p) {
+  p->ref_count++;
+}
+
+void gc_scan(JSRuntime* rt) {
+  struct list_head* el;
+  JSGCObjectHeader* p;
+
+  /* keep the objects with a refcount > 0 and their children. */
+  list_for_each(el, &rt->gc_obj_list) {
+    p = list_entry(el, JSGCObjectHeader, link);
+    assert(p->ref_count > 0);
+    p->mark = 0; /* reset the mark for the next GC call */
+    mark_children(rt, p, gc_scan_incref_child);
+  }
+
+  /* restore the refcount of the objects to be deleted. */
+  list_for_each(el, &rt->tmp_obj_list) {
+    p = list_entry(el, JSGCObjectHeader, link);
+    mark_children(rt, p, gc_scan_incref_child2);
+  }
+}
+
+void gc_free_cycles(JSRuntime* rt) {
+  struct list_head *el, *el1;
+  JSGCObjectHeader* p;
+#ifdef DUMP_GC_FREE
+  BOOL header_done = FALSE;
+#endif
+
+  rt->gc_phase = JS_GC_PHASE_REMOVE_CYCLES;
+
+  for (;;) {
+    el = rt->tmp_obj_list.next;
+    if (el == &rt->tmp_obj_list)
+      break;
+    p = list_entry(el, JSGCObjectHeader, link);
+    /* Only need to free the GC object associated with JS
+       values. The rest will be automatically removed because they
+       must be referenced by them. */
+    switch (p->gc_obj_type) {
+      case JS_GC_OBJ_TYPE_JS_OBJECT:
+      case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
+#ifdef DUMP_GC_FREE
+        if (!header_done) {
+          printf("Freeing cycles:\n");
+          JS_DumpObjectHeader(rt);
+          header_done = TRUE;
+        }
+        JS_DumpGCObject(rt, p);
+#endif
+        free_gc_object(rt, p);
+        break;
+      default:
+        list_del(&p->link);
+        list_add_tail(&p->link, &rt->gc_zero_ref_count_list);
+        break;
+    }
+  }
+  rt->gc_phase = JS_GC_PHASE_NONE;
+
+  list_for_each_safe(el, el1, &rt->gc_zero_ref_count_list) {
+    p = list_entry(el, JSGCObjectHeader, link);
+    assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT || p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
+    js_free_rt(rt, p);
+  }
+
+  init_list_head(&rt->gc_zero_ref_count_list);
+}
+
+void JS_RunGC(JSRuntime* rt) {
+  /* decrement the reference of the children of each object. mark =
+     1 after this pass. */
+  gc_decref(rt);
+
+  /* keep the GC objects with a non zero refcount and their childs */
+  gc_scan(rt);
+
+  /* free the GC objects in a cycle */
+  gc_free_cycles(rt);
+}
+
+/* Return false if not an object or if the object has already been
+   freed (zombie objects are visible in finalizers when freeing
+   cycles). */
+BOOL JS_IsLiveObject(JSRuntime* rt, JSValueConst obj) {
+  JSObject* p;
+  if (!JS_IsObject(obj))
+    return FALSE;
+  p = JS_VALUE_GET_OBJ(obj);
+  return !p->free_mark;
+}
\ No newline at end of file
diff --git a/src/core/gc.h b/src/core/gc.h
new file mode 100644
index 000000000..70183fdb5
--- /dev/null
+++ b/src/core/gc.h
@@ -0,0 +1,120 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_GC_H
+#define QUICKJS_GC_H
+
+#include "quickjs/quickjs.h"
+#include "quickjs/cutils.h"
+#include "quickjs/list.h"
+#include "types.h"
+
+/* object list */
+
+typedef struct {
+  JSObject* obj;
+  uint32_t hash_next; /* -1 if no next entry */
+} JSObjectListEntry;
+
+/* XXX: reuse it to optimize weak references */
+typedef struct {
+  JSObjectListEntry* object_tab;
+  int object_count;
+  int object_size;
+  uint32_t* hash_table;
+  uint32_t hash_size;
+} JSObjectList;
+
+typedef enum JSFreeModuleEnum {
+  JS_FREE_MODULE_ALL,
+  JS_FREE_MODULE_NOT_RESOLVED,
+  JS_FREE_MODULE_NOT_EVALUATED,
+} JSFreeModuleEnum;
+
+void js_object_list_init(JSObjectList* s);
+uint32_t js_object_list_get_hash(JSObject* p, uint32_t hash_size);
+int js_object_list_resize_hash(JSContext* ctx, JSObjectList* s, uint32_t new_hash_size);
+/* the reference count of 'obj' is not modified. Return 0 if OK, -1 if
+   memory error */
+int js_object_list_add(JSContext* ctx, JSObjectList* s, JSObject* obj);
+
+/* return -1 if not present or the object index */
+int js_object_list_find(JSContext* ctx, JSObjectList* s, JSObject* obj);
+
+void js_object_list_end(JSContext* ctx, JSObjectList* s);
+void free_gc_object(JSRuntime* rt, JSGCObjectHeader* gp);
+void free_zero_refcount(JSRuntime* rt);
+
+/* XXX: would be more efficient with separate module lists */
+void js_free_modules(JSContext* ctx, JSFreeModuleEnum flag);
+
+__maybe_unused void JS_DumpObjectHeader(JSRuntime* rt);
+__maybe_unused void JS_DumpObject(JSRuntime* rt, JSObject* p);
+__maybe_unused void JS_DumpGCObject(JSRuntime* rt, JSGCObjectHeader* p);
+__maybe_unused void JS_DumpValueShort(JSRuntime* rt, JSValueConst val);
+__maybe_unused void JS_DumpValue(JSContext* ctx, JSValueConst val);
+__maybe_unused void JS_PrintValue(JSContext* ctx, const char* str, JSValueConst val);
+
+/* used by the GC */
+void JS_MarkContext(JSRuntime* rt, JSContext* ctx, JS_MarkFunc* mark_func);
+
+void mark_children(JSRuntime* rt, JSGCObjectHeader* gp, JS_MarkFunc* mark_func);
+void gc_decref_child(JSRuntime* rt, JSGCObjectHeader* p);
+void gc_decref(JSRuntime* rt);
+void gc_scan_incref_child(JSRuntime* rt, JSGCObjectHeader* p);
+void gc_scan_incref_child2(JSRuntime* rt, JSGCObjectHeader* p);
+void gc_scan(JSRuntime* rt);
+void gc_free_cycles(JSRuntime* rt);
+
+    void free_var_ref(JSRuntime* rt, JSVarRef* var_ref);
+void free_object(JSRuntime* rt, JSObject* p);
+void add_gc_object(JSRuntime* rt, JSGCObjectHeader* h, JSGCObjectTypeEnum type);
+void set_cycle_flag(JSContext* ctx, JSValueConst obj);
+void remove_gc_object(JSGCObjectHeader* h);
+void js_regexp_finalizer(JSRuntime* rt, JSValue val);
+void js_array_buffer_finalizer(JSRuntime* rt, JSValue val);
+void js_typed_array_finalizer(JSRuntime* rt, JSValue val);
+void js_typed_array_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func);
+void js_proxy_finalizer(JSRuntime* rt, JSValue val);
+void js_proxy_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func);
+void js_map_finalizer(JSRuntime* rt, JSValue val);
+void js_map_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func);
+void js_map_iterator_finalizer(JSRuntime* rt, JSValue val);
+void js_map_iterator_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func);
+
+void js_regexp_string_iterator_finalizer(JSRuntime* rt, JSValue val);
+void js_regexp_string_iterator_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func);
+void js_generator_finalizer(JSRuntime* rt, JSValue obj);
+void js_generator_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func);
+void js_promise_finalizer(JSRuntime* rt, JSValue val);
+void js_promise_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func);
+void js_promise_resolve_function_finalizer(JSRuntime* rt, JSValue val);
+void js_promise_resolve_function_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func);
+#ifdef CONFIG_BIGNUM
+void js_operator_set_finalizer(JSRuntime* rt, JSValue val);
+void js_operator_set_mark(JSRuntime* rt, JSValueConst val, JS_MarkFunc* mark_func);
+#endif
+
+#endif
diff --git a/src/core/malloc.c b/src/core/malloc.c
new file mode 100644
index 000000000..abe08160d
--- /dev/null
+++ b/src/core/malloc.c
@@ -0,0 +1,242 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "quickjs/cutils.h"
+#include "malloc.h"
+#include "exception.h"
+
+void js_trigger_gc(JSRuntime* rt, size_t size) {
+  BOOL force_gc;
+#ifdef FORCE_GC_AT_MALLOC
+  force_gc = TRUE;
+#else
+  force_gc = ((rt->malloc_state.malloc_size + size) > rt->malloc_gc_threshold);
+#endif
+  if (force_gc) {
+#ifdef DUMP_GC
+    printf("GC: size=%" PRIu64 "\n", (uint64_t)rt->malloc_state.malloc_size);
+#endif
+    JS_RunGC(rt);
+    rt->malloc_gc_threshold = rt->malloc_state.malloc_size + (rt->malloc_state.malloc_size >> 1);
+  }
+}
+
+
+/* default memory allocation functions with memory limitation */
+static inline size_t js_def_malloc_usable_size(void* ptr) {
+#if defined(__APPLE__)
+  return malloc_size(ptr);
+#elif defined(_WIN32)
+  return _msize(ptr);
+#elif defined(EMSCRIPTEN)
+  return 0;
+#elif defined(__linux__)
+  return malloc_usable_size(ptr);
+#else
+  /* change this to `return 0;` if compilation fails */
+  return malloc_usable_size(ptr);
+#endif
+}
+
+size_t js_malloc_usable_size_unknown(const void* ptr) {
+  return 0;
+}
+
+void* js_malloc_rt(JSRuntime* rt, size_t size) {
+  return rt->mf.js_malloc(&rt->malloc_state, size);
+}
+
+void js_free_rt(JSRuntime* rt, void* ptr) {
+  rt->mf.js_free(&rt->malloc_state, ptr);
+}
+
+void* js_realloc_rt(JSRuntime* rt, void* ptr, size_t size) {
+  return rt->mf.js_realloc(&rt->malloc_state, ptr, size);
+}
+
+size_t js_malloc_usable_size_rt(JSRuntime* rt, const void* ptr) {
+  return rt->mf.js_malloc_usable_size(ptr);
+}
+
+void* js_mallocz_rt(JSRuntime* rt, size_t size) {
+  void* ptr;
+  ptr = js_malloc_rt(rt, size);
+  if (!ptr)
+    return NULL;
+  return memset(ptr, 0, size);
+}
+
+#ifdef CONFIG_BIGNUM
+/* called by libbf */
+void* js_bf_realloc(void* opaque, void* ptr, size_t size) {
+  JSRuntime* rt = opaque;
+  return js_realloc_rt(rt, ptr, size);
+}
+#endif /* CONFIG_BIGNUM */
+
+/* Throw out of memory in case of error */
+void* js_malloc(JSContext* ctx, size_t size) {
+  void* ptr;
+  ptr = js_malloc_rt(ctx->rt, size);
+  if (unlikely(!ptr)) {
+    JS_ThrowOutOfMemory(ctx);
+    return NULL;
+  }
+  return ptr;
+}
+
+/* Throw out of memory in case of error */
+void* js_mallocz(JSContext* ctx, size_t size) {
+  void* ptr;
+  ptr = js_mallocz_rt(ctx->rt, size);
+  if (unlikely(!ptr)) {
+    JS_ThrowOutOfMemory(ctx);
+    return NULL;
+  }
+  return ptr;
+}
+
+void js_free(JSContext* ctx, void* ptr) {
+  js_free_rt(ctx->rt, ptr);
+}
+
+/* Throw out of memory in case of error */
+void* js_realloc(JSContext* ctx, void* ptr, size_t size) {
+  void* ret;
+  ret = js_realloc_rt(ctx->rt, ptr, size);
+  if (unlikely(!ret && size != 0)) {
+    JS_ThrowOutOfMemory(ctx);
+    return NULL;
+  }
+  return ret;
+}
+
+/* store extra allocated size in *pslack if successful */
+void* js_realloc2(JSContext* ctx, void* ptr, size_t size, size_t* pslack) {
+  void* ret;
+  ret = js_realloc_rt(ctx->rt, ptr, size);
+  if (unlikely(!ret && size != 0)) {
+    JS_ThrowOutOfMemory(ctx);
+    return NULL;
+  }
+  if (pslack) {
+    size_t new_size = js_malloc_usable_size_rt(ctx->rt, ret);
+    *pslack = (new_size > size) ? new_size - size : 0;
+  }
+  return ret;
+}
+
+size_t js_malloc_usable_size(JSContext* ctx, const void* ptr) {
+  return js_malloc_usable_size_rt(ctx->rt, ptr);
+}
+
+/* Throw out of memory exception in case of error */
+char* js_strndup(JSContext* ctx, const char* s, size_t n) {
+  char* ptr;
+  ptr = js_malloc(ctx, n + 1);
+  if (ptr) {
+    memcpy(ptr, s, n);
+    ptr[n] = '\0';
+  }
+  return ptr;
+}
+
+char* js_strdup(JSContext* ctx, const char* str) {
+  return js_strndup(ctx, str, strlen(str));
+}
+
+no_inline int js_realloc_array(JSContext* ctx, void** parray, int elem_size, int* psize, int req_size) {
+  int new_size;
+  size_t slack;
+  void* new_array;
+  /* XXX: potential arithmetic overflow */
+  new_size = max_int(req_size, *psize * 3 / 2);
+  new_array = js_realloc2(ctx, *parray, new_size * elem_size, &slack);
+  if (!new_array)
+    return -1;
+  new_size += slack / elem_size;
+  *psize = new_size;
+  *parray = new_array;
+  return 0;
+}
+
+void* js_def_malloc(JSMallocState* s, size_t size) {
+  void* ptr;
+
+  /* Do not allocate zero bytes: behavior is platform dependent */
+  assert(size != 0);
+
+  if (unlikely(s->malloc_size + size > s->malloc_limit))
+    return NULL;
+
+  ptr = malloc(size);
+  if (!ptr)
+    return NULL;
+
+  s->malloc_count++;
+  s->malloc_size += js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
+  return ptr;
+}
+
+void js_def_free(JSMallocState* s, void* ptr) {
+  if (!ptr)
+    return;
+
+  s->malloc_count--;
+  s->malloc_size -= js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
+  free(ptr);
+}
+
+void* js_def_realloc(JSMallocState* s, void* ptr, size_t size) {
+  size_t old_size;
+
+  if (!ptr) {
+    if (size == 0)
+      return NULL;
+    return js_def_malloc(s, size);
+  }
+  old_size = js_def_malloc_usable_size(ptr);
+  if (size == 0) {
+    s->malloc_count--;
+    s->malloc_size -= old_size + MALLOC_OVERHEAD;
+    free(ptr);
+    return NULL;
+  }
+  if (s->malloc_size + size - old_size > s->malloc_limit)
+    return NULL;
+
+  ptr = realloc(ptr, size);
+  if (!ptr)
+    return NULL;
+
+  s->malloc_size += js_def_malloc_usable_size(ptr) - old_size;
+  return ptr;
+}
+
+/* use -1 to disable automatic GC */
+void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold)
+{
+  rt->malloc_gc_threshold = gc_threshold;
+}
\ No newline at end of file
diff --git a/src/core/malloc.h b/src/core/malloc.h
new file mode 100644
index 000000000..e9c4b39a8
--- /dev/null
+++ b/src/core/malloc.h
@@ -0,0 +1,59 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_MALLOC_H
+#define QUICKJS_MALLOC_H
+
+#include "quickjs/quickjs.h"
+#include "quickjs/cutils.h"
+#include "types.h"
+
+void js_trigger_gc(JSRuntime* rt, size_t size);
+no_inline int js_realloc_array(JSContext* ctx, void** parray, int elem_size, int* psize, int req_size);
+
+/* resize the array and update its size if req_size > *psize */
+static inline int js_resize_array(JSContext* ctx, void** parray, int elem_size, int* psize, int req_size) {
+  if (unlikely(req_size > *psize))
+    return js_realloc_array(ctx, parray, elem_size, psize, req_size);
+  else
+    return 0;
+}
+
+static inline void js_dbuf_init(JSContext* ctx, DynBuf* s) {
+  dbuf_init2(s, ctx->rt, (DynBufReallocFunc*)js_realloc_rt);
+}
+
+
+void* js_def_malloc(JSMallocState* s, size_t size);
+void js_def_free(JSMallocState* s, void* ptr);
+void* js_def_realloc(JSMallocState* s, void* ptr, size_t size);
+size_t js_malloc_usable_size_unknown(const void* ptr);
+
+
+#if CONFIG_BIGNUM
+void* js_bf_realloc(void* opaque, void* ptr, size_t size);
+#endif
+
+#endif
\ No newline at end of file
diff --git a/src/core/memory.c b/src/core/memory.c
new file mode 100644
index 000000000..674358566
--- /dev/null
+++ b/src/core/memory.c
@@ -0,0 +1,529 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "memory.h"
+#include "function.h"
+#include "runtime.h"
+#include "shape.h"
+#include "string.h"
+
+/* Compute memory used by various object types */
+/* XXX: poor man's approach to handling multiply referenced objects */
+typedef struct JSMemoryUsage_helper {
+  double memory_used_count;
+  double str_count;
+  double str_size;
+  int64_t js_func_count;
+  double js_func_size;
+  int64_t js_func_code_size;
+  int64_t js_func_pc2line_count;
+  int64_t js_func_pc2line_size;
+} JSMemoryUsage_helper;
+
+static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp);
+
+static void compute_jsstring_size(JSString *str, JSMemoryUsage_helper *hp)
+{
+  if (!str->atom_type) {  /* atoms are handled separately */
+    double s_ref_count = str->header.ref_count;
+    hp->str_count += 1 / s_ref_count;
+    hp->str_size += ((sizeof(*str) + (str->len << str->is_wide_char) +
+                      1 - str->is_wide_char) / s_ref_count);
+  }
+}
+
+static void compute_bytecode_size(JSFunctionBytecode *b, JSMemoryUsage_helper *hp)
+{
+  int memory_used_count, js_func_size, i;
+
+  memory_used_count = 0;
+  js_func_size = offsetof(JSFunctionBytecode, debug);
+  if (b->vardefs) {
+    js_func_size += (b->arg_count + b->var_count) * sizeof(*b->vardefs);
+  }
+  if (b->cpool) {
+    js_func_size += b->cpool_count * sizeof(*b->cpool);
+    for (i = 0; i < b->cpool_count; i++) {
+      JSValueConst val = b->cpool[i];
+      compute_value_size(val, hp);
+    }
+  }
+  if (b->closure_var) {
+    js_func_size += b->closure_var_count * sizeof(*b->closure_var);
+  }
+  if (!b->read_only_bytecode && b->byte_code_buf) {
+    hp->js_func_code_size += b->byte_code_len;
+  }
+  if (b->has_debug) {
+    js_func_size += sizeof(*b) - offsetof(JSFunctionBytecode, debug);
+    if (b->debug.source) {
+      memory_used_count++;
+      js_func_size += b->debug.source_len + 1;
+    }
+    if (b->debug.pc2line_len) {
+      memory_used_count++;
+      hp->js_func_pc2line_count += 1;
+      hp->js_func_pc2line_size += b->debug.pc2line_len;
+    }
+  }
+  hp->js_func_size += js_func_size;
+  hp->js_func_count += 1;
+  hp->memory_used_count += memory_used_count;
+}
+
+static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp)
+{
+  switch(JS_VALUE_GET_TAG(val)) {
+    case JS_TAG_STRING:
+      compute_jsstring_size(JS_VALUE_GET_STRING(val), hp);
+      break;
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_INT:
+    case JS_TAG_BIG_FLOAT:
+    case JS_TAG_BIG_DECIMAL:
+      /* should track JSBigFloat usage */
+      break;
+#endif
+  }
+}
+
+void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
+{
+  struct list_head *el, *el1;
+  int i;
+  JSMemoryUsage_helper mem = { 0 }, *hp = &mem;
+
+  memset(s, 0, sizeof(*s));
+  s->malloc_count = rt->malloc_state.malloc_count;
+  s->malloc_size = rt->malloc_state.malloc_size;
+  s->malloc_limit = rt->malloc_state.malloc_limit;
+
+  s->memory_used_count = 2; /* rt + rt->class_array */
+  s->memory_used_size = sizeof(JSRuntime) + sizeof(JSValue) * rt->class_count;
+
+  list_for_each(el, &rt->context_list) {
+    JSContext *ctx = list_entry(el, JSContext, link);
+    JSShape *sh = ctx->array_shape;
+    s->memory_used_count += 2; /* ctx + ctx->class_proto */
+    s->memory_used_size += sizeof(JSContext) +
+                           sizeof(JSValue) * rt->class_count;
+    s->binary_object_count += ctx->binary_object_count;
+    s->binary_object_size += ctx->binary_object_size;
+
+    /* the hashed shapes are counted separately */
+    if (sh && !sh->is_hashed) {
+      int hash_size = sh->prop_hash_mask + 1;
+      s->shape_count++;
+      s->shape_size += get_shape_size(hash_size, sh->prop_size);
+    }
+    list_for_each(el1, &ctx->loaded_modules) {
+      JSModuleDef *m = list_entry(el1, JSModuleDef, link);
+      s->memory_used_count += 1;
+      s->memory_used_size += sizeof(*m);
+      if (m->req_module_entries) {
+        s->memory_used_count += 1;
+        s->memory_used_size += m->req_module_entries_count * sizeof(*m->req_module_entries);
+      }
+      if (m->export_entries) {
+        s->memory_used_count += 1;
+        s->memory_used_size += m->export_entries_count * sizeof(*m->export_entries);
+        for (i = 0; i < m->export_entries_count; i++) {
+          JSExportEntry *me = &m->export_entries[i];
+          if (me->export_type == JS_EXPORT_TYPE_LOCAL && me->u.local.var_ref) {
+            /* potential multiple count */
+            s->memory_used_count += 1;
+            compute_value_size(me->u.local.var_ref->value, hp);
+          }
+        }
+      }
+      if (m->star_export_entries) {
+        s->memory_used_count += 1;
+        s->memory_used_size += m->star_export_entries_count * sizeof(*m->star_export_entries);
+      }
+      if (m->import_entries) {
+        s->memory_used_count += 1;
+        s->memory_used_size += m->import_entries_count * sizeof(*m->import_entries);
+      }
+      compute_value_size(m->module_ns, hp);
+      compute_value_size(m->func_obj, hp);
+    }
+  }
+
+  list_for_each(el, &rt->gc_obj_list) {
+    JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link);
+    JSObject *p;
+    JSShape *sh;
+    JSShapeProperty *prs;
+
+    /* XXX: could count the other GC object types too */
+    if (gp->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE) {
+      compute_bytecode_size((JSFunctionBytecode *)gp, hp);
+      continue;
+    } else if (gp->gc_obj_type != JS_GC_OBJ_TYPE_JS_OBJECT) {
+      continue;
+    }
+    p = (JSObject *)gp;
+    sh = p->shape;
+    s->obj_count++;
+    if (p->prop) {
+      s->memory_used_count++;
+      s->prop_size += sh->prop_size * sizeof(*p->prop);
+      s->prop_count += sh->prop_count;
+      prs = get_shape_prop(sh);
+      for(i = 0; i < sh->prop_count; i++) {
+        JSProperty *pr = &p->prop[i];
+        if (prs->atom != JS_ATOM_NULL && !(prs->flags & JS_PROP_TMASK)) {
+          compute_value_size(pr->u.value, hp);
+        }
+        prs++;
+      }
+    }
+    /* the hashed shapes are counted separately */
+    if (!sh->is_hashed) {
+      int hash_size = sh->prop_hash_mask + 1;
+      s->shape_count++;
+      s->shape_size += get_shape_size(hash_size, sh->prop_size);
+    }
+
+    switch(p->class_id) {
+      case JS_CLASS_ARRAY:             /* u.array | length */
+      case JS_CLASS_ARGUMENTS:         /* u.array | length */
+        s->array_count++;
+        if (p->fast_array) {
+          s->fast_array_count++;
+          if (p->u.array.u.values) {
+            s->memory_used_count++;
+            s->memory_used_size += p->u.array.count *
+                                   sizeof(*p->u.array.u.values);
+            s->fast_array_elements += p->u.array.count;
+            for (i = 0; i < p->u.array.count; i++) {
+              compute_value_size(p->u.array.u.values[i], hp);
+            }
+          }
+        }
+        break;
+      case JS_CLASS_NUMBER:            /* u.object_data */
+      case JS_CLASS_STRING:            /* u.object_data */
+      case JS_CLASS_BOOLEAN:           /* u.object_data */
+      case JS_CLASS_SYMBOL:            /* u.object_data */
+      case JS_CLASS_DATE:              /* u.object_data */
+#ifdef CONFIG_BIGNUM
+      case JS_CLASS_BIG_INT:           /* u.object_data */
+      case JS_CLASS_BIG_FLOAT:         /* u.object_data */
+      case JS_CLASS_BIG_DECIMAL:         /* u.object_data */
+#endif
+        compute_value_size(p->u.object_data, hp);
+        break;
+      case JS_CLASS_C_FUNCTION:        /* u.cfunc */
+        s->c_func_count++;
+        break;
+      case JS_CLASS_BYTECODE_FUNCTION: /* u.func */
+      {
+        JSFunctionBytecode *b = p->u.func.function_bytecode;
+        JSVarRef **var_refs = p->u.func.var_refs;
+        /* home_object: object will be accounted for in list scan */
+        if (var_refs) {
+          s->memory_used_count++;
+          s->js_func_size += b->closure_var_count * sizeof(*var_refs);
+          for (i = 0; i < b->closure_var_count; i++) {
+            if (var_refs[i]) {
+              double ref_count = var_refs[i]->header.ref_count;
+              s->memory_used_count += 1 / ref_count;
+              s->js_func_size += sizeof(*var_refs[i]) / ref_count;
+              /* handle non object closed values */
+              if (var_refs[i]->pvalue == &var_refs[i]->value) {
+                /* potential multiple count */
+                compute_value_size(var_refs[i]->value, hp);
+              }
+            }
+          }
+        }
+      }
+      break;
+      case JS_CLASS_BOUND_FUNCTION:    /* u.bound_function */
+      {
+        JSBoundFunction *bf = p->u.bound_function;
+        /* func_obj and this_val are objects */
+        for (i = 0; i < bf->argc; i++) {
+          compute_value_size(bf->argv[i], hp);
+        }
+        s->memory_used_count += 1;
+        s->memory_used_size += sizeof(*bf) + bf->argc * sizeof(*bf->argv);
+      }
+      break;
+      case JS_CLASS_C_FUNCTION_DATA:   /* u.c_function_data_record */
+      {
+        JSCFunctionDataRecord *fd = p->u.c_function_data_record;
+        if (fd) {
+          for (i = 0; i < fd->data_len; i++) {
+            compute_value_size(fd->data[i], hp);
+          }
+          s->memory_used_count += 1;
+          s->memory_used_size += sizeof(*fd) + fd->data_len * sizeof(*fd->data);
+        }
+      }
+      break;
+      case JS_CLASS_REGEXP:            /* u.regexp */
+        compute_jsstring_size(p->u.regexp.pattern, hp);
+        compute_jsstring_size(p->u.regexp.bytecode, hp);
+        break;
+
+      case JS_CLASS_FOR_IN_ITERATOR:   /* u.for_in_iterator */
+      {
+        JSForInIterator *it = p->u.for_in_iterator;
+        if (it) {
+          compute_value_size(it->obj, hp);
+          s->memory_used_count += 1;
+          s->memory_used_size += sizeof(*it);
+        }
+      }
+      break;
+      case JS_CLASS_ARRAY_BUFFER:      /* u.array_buffer */
+      case JS_CLASS_SHARED_ARRAY_BUFFER: /* u.array_buffer */
+      {
+        JSArrayBuffer *abuf = p->u.array_buffer;
+        if (abuf) {
+          s->memory_used_count += 1;
+          s->memory_used_size += sizeof(*abuf);
+          if (abuf->data) {
+            s->memory_used_count += 1;
+            s->memory_used_size += abuf->byte_length;
+          }
+        }
+      }
+      break;
+      case JS_CLASS_GENERATOR:         /* u.generator_data */
+      case JS_CLASS_UINT8C_ARRAY:      /* u.typed_array / u.array */
+      case JS_CLASS_INT8_ARRAY:        /* u.typed_array / u.array */
+      case JS_CLASS_UINT8_ARRAY:       /* u.typed_array / u.array */
+      case JS_CLASS_INT16_ARRAY:       /* u.typed_array / u.array */
+      case JS_CLASS_UINT16_ARRAY:      /* u.typed_array / u.array */
+      case JS_CLASS_INT32_ARRAY:       /* u.typed_array / u.array */
+      case JS_CLASS_UINT32_ARRAY:      /* u.typed_array / u.array */
+#ifdef CONFIG_BIGNUM
+      case JS_CLASS_BIG_INT64_ARRAY:   /* u.typed_array / u.array */
+      case JS_CLASS_BIG_UINT64_ARRAY:  /* u.typed_array / u.array */
+#endif
+      case JS_CLASS_FLOAT32_ARRAY:     /* u.typed_array / u.array */
+      case JS_CLASS_FLOAT64_ARRAY:     /* u.typed_array / u.array */
+      case JS_CLASS_DATAVIEW:          /* u.typed_array */
+#ifdef CONFIG_BIGNUM
+      case JS_CLASS_FLOAT_ENV:         /* u.float_env */
+#endif
+      case JS_CLASS_MAP:               /* u.map_state */
+      case JS_CLASS_SET:               /* u.map_state */
+      case JS_CLASS_WEAKMAP:           /* u.map_state */
+      case JS_CLASS_WEAKSET:           /* u.map_state */
+      case JS_CLASS_MAP_ITERATOR:      /* u.map_iterator_data */
+      case JS_CLASS_SET_ITERATOR:      /* u.map_iterator_data */
+      case JS_CLASS_ARRAY_ITERATOR:    /* u.array_iterator_data */
+      case JS_CLASS_STRING_ITERATOR:   /* u.array_iterator_data */
+      case JS_CLASS_PROXY:             /* u.proxy_data */
+      case JS_CLASS_PROMISE:           /* u.promise_data */
+      case JS_CLASS_PROMISE_RESOLVE_FUNCTION:  /* u.promise_function_data */
+      case JS_CLASS_PROMISE_REJECT_FUNCTION:   /* u.promise_function_data */
+      case JS_CLASS_ASYNC_FUNCTION_RESOLVE:    /* u.async_function_data */
+      case JS_CLASS_ASYNC_FUNCTION_REJECT:     /* u.async_function_data */
+      case JS_CLASS_ASYNC_FROM_SYNC_ITERATOR:  /* u.async_from_sync_iterator_data */
+      case JS_CLASS_ASYNC_GENERATOR:   /* u.async_generator_data */
+                                              /* TODO */
+      default:
+        /* XXX: class definition should have an opaque block size */
+        if (p->u.opaque) {
+          s->memory_used_count += 1;
+        }
+        break;
+    }
+  }
+  s->obj_size += s->obj_count * sizeof(JSObject);
+
+  /* hashed shapes */
+  s->memory_used_count++; /* rt->shape_hash */
+  s->memory_used_size += sizeof(rt->shape_hash[0]) * rt->shape_hash_size;
+  for(i = 0; i < rt->shape_hash_size; i++) {
+    JSShape *sh;
+    for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) {
+      int hash_size = sh->prop_hash_mask + 1;
+      s->shape_count++;
+      s->shape_size += get_shape_size(hash_size, sh->prop_size);
+    }
+  }
+
+  /* atoms */
+  s->memory_used_count += 2; /* rt->atom_array, rt->atom_hash */
+  s->atom_count = rt->atom_count;
+  s->atom_size = sizeof(rt->atom_array[0]) * rt->atom_size +
+                 sizeof(rt->atom_hash[0]) * rt->atom_hash_size;
+  for(i = 0; i < rt->atom_size; i++) {
+    JSAtomStruct *p = rt->atom_array[i];
+    if (!atom_is_free(p)) {
+      s->atom_size += (sizeof(*p) + (p->len << p->is_wide_char) +
+                       1 - p->is_wide_char);
+    }
+  }
+  s->str_count = round(mem.str_count);
+  s->str_size = round(mem.str_size);
+  s->js_func_count = mem.js_func_count;
+  s->js_func_size = round(mem.js_func_size);
+  s->js_func_code_size = mem.js_func_code_size;
+  s->js_func_pc2line_count = mem.js_func_pc2line_count;
+  s->js_func_pc2line_size = mem.js_func_pc2line_size;
+  s->memory_used_count += round(mem.memory_used_count) +
+                          s->atom_count + s->str_count +
+                          s->obj_count + s->shape_count +
+                          s->js_func_count + s->js_func_pc2line_count;
+  s->memory_used_size += s->atom_size + s->str_size +
+                         s->obj_size + s->prop_size + s->shape_size +
+                         s->js_func_size + s->js_func_code_size + s->js_func_pc2line_size;
+}
+
+void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt)
+{
+  fprintf(fp, "QuickJS memory usage -- "
+#ifdef CONFIG_BIGNUM
+          "BigNum "
+#endif
+          CONFIG_VERSION " version, %d-bit, malloc limit: %"PRId64"\n\n",
+          (int)sizeof(void *) * 8, (int64_t)(ssize_t)s->malloc_limit);
+#if 1
+  if (rt) {
+    static const struct {
+      const char *name;
+      size_t size;
+    } object_types[] = {
+        { "JSRuntime", sizeof(JSRuntime) },
+        { "JSContext", sizeof(JSContext) },
+        { "JSObject", sizeof(JSObject) },
+        { "JSString", sizeof(JSString) },
+        { "JSFunctionBytecode", sizeof(JSFunctionBytecode) },
+    };
+    int i, usage_size_ok = 0;
+    for(i = 0; i < countof(object_types); i++) {
+      unsigned int size = object_types[i].size;
+      void *p = js_malloc_rt(rt, size);
+      if (p) {
+        unsigned int size1 = js_malloc_usable_size_rt(rt, p);
+        if (size1 >= size) {
+          usage_size_ok = 1;
+          fprintf(fp, "  %3u + %-2u  %s\n",
+                  size, size1 - size, object_types[i].name);
+        }
+        js_free_rt(rt, p);
+      }
+    }
+    if (!usage_size_ok) {
+      fprintf(fp, "  malloc_usable_size unavailable\n");
+    }
+    {
+      int obj_classes[JS_CLASS_INIT_COUNT + 1] = { 0 };
+      int class_id;
+      struct list_head *el;
+      list_for_each(el, &rt->gc_obj_list) {
+        JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link);
+        JSObject *p;
+        if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
+          p = (JSObject *)gp;
+          obj_classes[min_uint32(p->class_id, JS_CLASS_INIT_COUNT)]++;
+        }
+      }
+      fprintf(fp, "\n" "JSObject classes\n");
+      if (obj_classes[0])
+        fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[0], 0, "none");
+      for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) {
+        if (obj_classes[class_id]) {
+          char buf[ATOM_GET_STR_BUF_SIZE];
+          fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[class_id], class_id,
+                  JS_AtomGetStrRT(rt, buf, sizeof(buf), js_std_class_def[class_id - 1].class_name));
+        }
+      }
+      if (obj_classes[JS_CLASS_INIT_COUNT])
+        fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[JS_CLASS_INIT_COUNT], 0, "other");
+    }
+    fprintf(fp, "\n");
+  }
+#endif
+  fprintf(fp, "%-20s %8s %8s\n", "NAME", "COUNT", "SIZE");
+
+  if (s->malloc_count) {
+    fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per block)\n",
+            "memory allocated", s->malloc_count, s->malloc_size,
+            (double)s->malloc_size / s->malloc_count);
+    fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%d overhead, %0.1f average slack)\n",
+            "memory used", s->memory_used_count, s->memory_used_size,
+            MALLOC_OVERHEAD, ((double)(s->malloc_size - s->memory_used_size) /
+                              s->memory_used_count));
+  }
+  if (s->atom_count) {
+    fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per atom)\n",
+            "atoms", s->atom_count, s->atom_size,
+            (double)s->atom_size / s->atom_count);
+  }
+  if (s->str_count) {
+    fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per string)\n",
+            "strings", s->str_count, s->str_size,
+            (double)s->str_size / s->str_count);
+  }
+  if (s->obj_count) {
+    fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per object)\n",
+            "objects", s->obj_count, s->obj_size,
+            (double)s->obj_size / s->obj_count);
+    fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per object)\n",
+            "  properties", s->prop_count, s->prop_size,
+            (double)s->prop_count / s->obj_count);
+    fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per shape)\n",
+            "  shapes", s->shape_count, s->shape_size,
+            (double)s->shape_size / s->shape_count);
+  }
+  if (s->js_func_count) {
+    fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n",
+            "bytecode functions", s->js_func_count, s->js_func_size);
+    fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per function)\n",
+            "  bytecode", s->js_func_count, s->js_func_code_size,
+            (double)s->js_func_code_size / s->js_func_count);
+    if (s->js_func_pc2line_count) {
+      fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per function)\n",
+              "  pc2line", s->js_func_pc2line_count,
+              s->js_func_pc2line_size,
+              (double)s->js_func_pc2line_size / s->js_func_pc2line_count);
+    }
+  }
+  if (s->c_func_count) {
+    fprintf(fp, "%-20s %8"PRId64"\n", "C functions", s->c_func_count);
+  }
+  if (s->array_count) {
+    fprintf(fp, "%-20s %8"PRId64"\n", "arrays", s->array_count);
+    if (s->fast_array_count) {
+      fprintf(fp, "%-20s %8"PRId64"\n", "  fast arrays", s->fast_array_count);
+      fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per fast array)\n",
+              "  elements", s->fast_array_elements,
+              s->fast_array_elements * (int)sizeof(JSValue),
+              (double)s->fast_array_elements / s->fast_array_count);
+    }
+  }
+  if (s->binary_object_count) {
+    fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n",
+            "binary objects", s->binary_object_count, s->binary_object_size);
+  }
+}
diff --git a/src/core/memory.h b/src/core/memory.h
new file mode 100644
index 000000000..1154ab566
--- /dev/null
+++ b/src/core/memory.h
@@ -0,0 +1,32 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_MEMORY_H
+#define QUICKJS_MEMORY_H
+
+#include "quickjs/quickjs.h"
+#include "quickjs/cutils.h"
+
+#endif
\ No newline at end of file
diff --git a/src/core/module.c b/src/core/module.c
new file mode 100644
index 000000000..5edb48921
--- /dev/null
+++ b/src/core/module.c
@@ -0,0 +1,1298 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "module.h"
+#include "exception.h"
+#include "function.h"
+#include "gc.h"
+#include "malloc.h"
+#include "object.h"
+#include "parser.h"
+#include "runtime.h"
+#include "string.h"
+
+/* 'name' is freed */
+JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name)
+{
+  JSModuleDef *m;
+  m = js_mallocz(ctx, sizeof(*m));
+  if (!m) {
+    JS_FreeAtom(ctx, name);
+    return NULL;
+  }
+  m->header.ref_count = 1;
+  m->module_name = name;
+  m->module_ns = JS_UNDEFINED;
+  m->func_obj = JS_UNDEFINED;
+  m->eval_exception = JS_UNDEFINED;
+  m->meta_obj = JS_UNDEFINED;
+  list_add_tail(&m->link, &ctx->loaded_modules);
+  return m;
+}
+
+void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
+                               JS_MarkFunc *mark_func)
+{
+  int i;
+
+  for(i = 0; i < m->export_entries_count; i++) {
+    JSExportEntry *me = &m->export_entries[i];
+    if (me->export_type == JS_EXPORT_TYPE_LOCAL &&
+        me->u.local.var_ref) {
+      mark_func(rt, &me->u.local.var_ref->header);
+    }
+  }
+
+  JS_MarkValue(rt, m->module_ns, mark_func);
+  JS_MarkValue(rt, m->func_obj, mark_func);
+  JS_MarkValue(rt, m->eval_exception, mark_func);
+  JS_MarkValue(rt, m->meta_obj, mark_func);
+}
+
+void js_free_module_def(JSContext *ctx, JSModuleDef *m)
+{
+  int i;
+
+  JS_FreeAtom(ctx, m->module_name);
+
+  for(i = 0; i < m->req_module_entries_count; i++) {
+    JSReqModuleEntry *rme = &m->req_module_entries[i];
+    JS_FreeAtom(ctx, rme->module_name);
+  }
+  js_free(ctx, m->req_module_entries);
+
+  for(i = 0; i < m->export_entries_count; i++) {
+    JSExportEntry *me = &m->export_entries[i];
+    if (me->export_type == JS_EXPORT_TYPE_LOCAL)
+      free_var_ref(ctx->rt, me->u.local.var_ref);
+    JS_FreeAtom(ctx, me->export_name);
+    JS_FreeAtom(ctx, me->local_name);
+  }
+  js_free(ctx, m->export_entries);
+
+  js_free(ctx, m->star_export_entries);
+
+  for(i = 0; i < m->import_entries_count; i++) {
+    JSImportEntry *mi = &m->import_entries[i];
+    JS_FreeAtom(ctx, mi->import_name);
+  }
+  js_free(ctx, m->import_entries);
+
+  JS_FreeValue(ctx, m->module_ns);
+  JS_FreeValue(ctx, m->func_obj);
+  JS_FreeValue(ctx, m->eval_exception);
+  JS_FreeValue(ctx, m->meta_obj);
+  list_del(&m->link);
+  js_free(ctx, m);
+}
+
+int add_req_module_entry(JSContext *ctx, JSModuleDef *m,
+                                JSAtom module_name)
+{
+  JSReqModuleEntry *rme;
+  int i;
+
+  /* no need to add the module request if it is already present */
+  for(i = 0; i < m->req_module_entries_count; i++) {
+    rme = &m->req_module_entries[i];
+    if (rme->module_name == module_name)
+      return i;
+  }
+
+  if (js_resize_array(ctx, (void **)&m->req_module_entries,
+                      sizeof(JSReqModuleEntry),
+                      &m->req_module_entries_size,
+                      m->req_module_entries_count + 1))
+    return -1;
+  rme = &m->req_module_entries[m->req_module_entries_count++];
+  rme->module_name = JS_DupAtom(ctx, module_name);
+  rme->module = NULL;
+  return i;
+}
+
+JSExportEntry *find_export_entry(JSContext *ctx, JSModuleDef *m,
+                                        JSAtom export_name)
+{
+  JSExportEntry *me;
+  int i;
+  for(i = 0; i < m->export_entries_count; i++) {
+    me = &m->export_entries[i];
+    if (me->export_name == export_name)
+      return me;
+  }
+  return NULL;
+}
+
+/* create a C module */
+JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str,
+                           JSModuleInitFunc *func)
+{
+  JSModuleDef *m;
+  JSAtom name;
+  name = JS_NewAtom(ctx, name_str);
+  if (name == JS_ATOM_NULL)
+    return NULL;
+  m = js_new_module_def(ctx, name);
+  m->init_func = func;
+  return m;
+}
+
+int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name)
+{
+  JSExportEntry *me;
+  JSAtom name;
+  name = JS_NewAtom(ctx, export_name);
+  if (name == JS_ATOM_NULL)
+    return -1;
+  me = add_export_entry2(ctx, NULL, m, JS_ATOM_NULL, name,
+                         JS_EXPORT_TYPE_LOCAL);
+  JS_FreeAtom(ctx, name);
+  if (!me)
+    return -1;
+  else
+    return 0;
+}
+
+int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name,
+                       JSValue val)
+{
+  JSExportEntry *me;
+  JSAtom name;
+  name = JS_NewAtom(ctx, export_name);
+  if (name == JS_ATOM_NULL)
+    goto fail;
+  me = find_export_entry(ctx, m, name);
+  JS_FreeAtom(ctx, name);
+  if (!me)
+    goto fail;
+  set_value(ctx, me->u.local.var_ref->pvalue, val);
+  return 0;
+fail:
+  JS_FreeValue(ctx, val);
+  return -1;
+}
+
+void JS_SetModuleLoaderFunc(JSRuntime *rt,
+                            JSModuleNormalizeFunc *module_normalize,
+                            JSModuleLoaderFunc *module_loader, void *opaque)
+{
+  rt->module_normalize_func = module_normalize;
+  rt->module_loader_func = module_loader;
+  rt->module_loader_opaque = opaque;
+}
+
+/* default module filename normalizer */
+char *js_default_module_normalize_name(JSContext *ctx,
+                                              const char *base_name,
+                                              const char *name)
+{
+  char *filename, *p;
+  const char *r;
+  int len;
+
+  if (name[0] != '.') {
+    /* if no initial dot, the module name is not modified */
+    return js_strdup(ctx, name);
+  }
+
+  p = strrchr(base_name, '/');
+  if (p)
+    len = p - base_name;
+  else
+    len = 0;
+
+  filename = js_malloc(ctx, len + strlen(name) + 1 + 1);
+  if (!filename)
+    return NULL;
+  memcpy(filename, base_name, len);
+  filename[len] = '\0';
+
+  /* we only normalize the leading '..' or '.' */
+  r = name;
+  for(;;) {
+    if (r[0] == '.' && r[1] == '/') {
+      r += 2;
+    } else if (r[0] == '.' && r[1] == '.' && r[2] == '/') {
+      /* remove the last path element of filename, except if "."
+         or ".." */
+      if (filename[0] == '\0')
+        break;
+      p = strrchr(filename, '/');
+      if (!p)
+        p = filename;
+      else
+        p++;
+      if (!strcmp(p, ".") || !strcmp(p, ".."))
+        break;
+      if (p > filename)
+        p--;
+      *p = '\0';
+      r += 3;
+    } else {
+      break;
+    }
+  }
+  if (filename[0] != '\0')
+    strcat(filename, "/");
+  strcat(filename, r);
+  //    printf("normalize: %s %s -> %s\n", base_name, name, filename);
+  return filename;
+}
+
+JSModuleDef *js_find_loaded_module(JSContext *ctx, JSAtom name)
+{
+  struct list_head *el;
+  JSModuleDef *m;
+
+  /* first look at the loaded modules */
+  list_for_each(el, &ctx->loaded_modules) {
+    m = list_entry(el, JSModuleDef, link);
+    if (m->module_name == name)
+      return m;
+  }
+  return NULL;
+}
+
+/* return NULL in case of exception (e.g. module could not be loaded) */
+JSModuleDef *js_host_resolve_imported_module(JSContext *ctx,
+                                                    const char *base_cname,
+                                                    const char *cname1)
+{
+  JSRuntime *rt = ctx->rt;
+  JSModuleDef *m;
+  char *cname;
+  JSAtom module_name;
+
+  if (!rt->module_normalize_func) {
+    cname = js_default_module_normalize_name(ctx, base_cname, cname1);
+  } else {
+    cname = rt->module_normalize_func(ctx, base_cname, cname1,
+                                      rt->module_loader_opaque);
+  }
+  if (!cname)
+    return NULL;
+
+  module_name = JS_NewAtom(ctx, cname);
+  if (module_name == JS_ATOM_NULL) {
+    js_free(ctx, cname);
+    return NULL;
+  }
+
+  /* first look at the loaded modules */
+  m = js_find_loaded_module(ctx, module_name);
+  if (m) {
+    js_free(ctx, cname);
+    JS_FreeAtom(ctx, module_name);
+    return m;
+  }
+
+  JS_FreeAtom(ctx, module_name);
+
+  /* load the module */
+  if (!rt->module_loader_func) {
+    /* XXX: use a syntax error ? */
+    JS_ThrowReferenceError(ctx, "could not load module '%s'",
+                           cname);
+    js_free(ctx, cname);
+    return NULL;
+  }
+
+  m = rt->module_loader_func(ctx, cname, rt->module_loader_opaque);
+  js_free(ctx, cname);
+  return m;
+}
+
+JSModuleDef *js_host_resolve_imported_module_atom(JSContext *ctx,
+                                                         JSAtom base_module_name,
+                                                         JSAtom module_name1)
+{
+  const char *base_cname, *cname;
+  JSModuleDef *m;
+
+  base_cname = JS_AtomToCString(ctx, base_module_name);
+  if (!base_cname)
+    return NULL;
+  cname = JS_AtomToCString(ctx, module_name1);
+  if (!cname) {
+    JS_FreeCString(ctx, base_cname);
+    return NULL;
+  }
+  m = js_host_resolve_imported_module(ctx, base_cname, cname);
+  JS_FreeCString(ctx, base_cname);
+  JS_FreeCString(ctx, cname);
+  return m;
+}
+
+static int find_resolve_entry(JSResolveState *s,
+                              JSModuleDef *m, JSAtom name)
+{
+  int i;
+  for(i = 0; i < s->count; i++) {
+    JSResolveEntry *re = &s->array[i];
+    if (re->module == m && re->name == name)
+      return i;
+  }
+  return -1;
+}
+
+static int add_resolve_entry(JSContext *ctx, JSResolveState *s,
+                             JSModuleDef *m, JSAtom name)
+{
+  JSResolveEntry *re;
+
+  if (js_resize_array(ctx, (void **)&s->array,
+                      sizeof(JSResolveEntry),
+                      &s->size, s->count + 1))
+    return -1;
+  re = &s->array[s->count++];
+  re->module = m;
+  re->name = JS_DupAtom(ctx, name);
+  return 0;
+}
+
+typedef enum JSResolveResultEnum {
+  JS_RESOLVE_RES_EXCEPTION = -1, /* memory alloc error */
+  JS_RESOLVE_RES_FOUND = 0,
+  JS_RESOLVE_RES_NOT_FOUND,
+  JS_RESOLVE_RES_CIRCULAR,
+  JS_RESOLVE_RES_AMBIGUOUS,
+} JSResolveResultEnum;
+
+static JSResolveResultEnum js_resolve_export1(JSContext *ctx,
+                                              JSModuleDef **pmodule,
+                                              JSExportEntry **pme,
+                                              JSModuleDef *m,
+                                              JSAtom export_name,
+                                              JSResolveState *s)
+{
+  JSExportEntry *me;
+
+  *pmodule = NULL;
+  *pme = NULL;
+  if (find_resolve_entry(s, m, export_name) >= 0)
+    return JS_RESOLVE_RES_CIRCULAR;
+  if (add_resolve_entry(ctx, s, m, export_name) < 0)
+    return JS_RESOLVE_RES_EXCEPTION;
+  me = find_export_entry(ctx, m, export_name);
+  if (me) {
+    if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
+      /* local export */
+      *pmodule = m;
+      *pme = me;
+      return JS_RESOLVE_RES_FOUND;
+    } else {
+      /* indirect export */
+      JSModuleDef *m1;
+      m1 = m->req_module_entries[me->u.req_module_idx].module;
+      if (me->local_name == JS_ATOM__star_) {
+        /* export ns from */
+        *pmodule = m;
+        *pme = me;
+        return JS_RESOLVE_RES_FOUND;
+      } else {
+        return js_resolve_export1(ctx, pmodule, pme, m1,
+                                  me->local_name, s);
+      }
+    }
+  } else {
+    if (export_name != JS_ATOM_default) {
+      /* not found in direct or indirect exports: try star exports */
+      int i;
+
+      for(i = 0; i < m->star_export_entries_count; i++) {
+        JSStarExportEntry *se = &m->star_export_entries[i];
+        JSModuleDef *m1, *res_m;
+        JSExportEntry *res_me;
+        JSResolveResultEnum ret;
+
+        m1 = m->req_module_entries[se->req_module_idx].module;
+        ret = js_resolve_export1(ctx, &res_m, &res_me, m1,
+                                 export_name, s);
+        if (ret == JS_RESOLVE_RES_AMBIGUOUS ||
+            ret == JS_RESOLVE_RES_EXCEPTION) {
+          return ret;
+        } else if (ret == JS_RESOLVE_RES_FOUND) {
+          if (*pme != NULL) {
+            if (*pmodule != res_m ||
+                res_me->local_name != (*pme)->local_name) {
+              *pmodule = NULL;
+              *pme = NULL;
+              return JS_RESOLVE_RES_AMBIGUOUS;
+            }
+          } else {
+            *pmodule = res_m;
+            *pme = res_me;
+          }
+        }
+      }
+      if (*pme != NULL)
+        return JS_RESOLVE_RES_FOUND;
+    }
+    return JS_RESOLVE_RES_NOT_FOUND;
+  }
+}
+
+/* If the return value is JS_RESOLVE_RES_FOUND, return the module
+  (*pmodule) and the corresponding local export entry
+  (*pme). Otherwise return (NULL, NULL) */
+static JSResolveResultEnum js_resolve_export(JSContext *ctx,
+                                             JSModuleDef **pmodule,
+                                             JSExportEntry **pme,
+                                             JSModuleDef *m,
+                                             JSAtom export_name)
+{
+  JSResolveState ss, *s = &ss;
+  int i;
+  JSResolveResultEnum ret;
+
+  s->array = NULL;
+  s->size = 0;
+  s->count = 0;
+
+  ret = js_resolve_export1(ctx, pmodule, pme, m, export_name, s);
+
+  for(i = 0; i < s->count; i++)
+    JS_FreeAtom(ctx, s->array[i].name);
+  js_free(ctx, s->array);
+
+  return ret;
+}
+
+static void js_resolve_export_throw_error(JSContext *ctx,
+                                          JSResolveResultEnum res,
+                                          JSModuleDef *m, JSAtom export_name)
+{
+  char buf1[ATOM_GET_STR_BUF_SIZE];
+  char buf2[ATOM_GET_STR_BUF_SIZE];
+  switch(res) {
+    case JS_RESOLVE_RES_EXCEPTION:
+      break;
+    default:
+    case JS_RESOLVE_RES_NOT_FOUND:
+      JS_ThrowSyntaxError(ctx, "Could not find export '%s' in module '%s'",
+                          JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
+                          JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
+      break;
+    case JS_RESOLVE_RES_CIRCULAR:
+      JS_ThrowSyntaxError(ctx, "circular reference when looking for export '%s' in module '%s'",
+                          JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
+                          JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
+      break;
+    case JS_RESOLVE_RES_AMBIGUOUS:
+      JS_ThrowSyntaxError(ctx, "export '%s' in module '%s' is ambiguous",
+                          JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
+                          JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
+      break;
+  }
+}
+
+
+typedef enum {
+  EXPORTED_NAME_AMBIGUOUS,
+  EXPORTED_NAME_NORMAL,
+  EXPORTED_NAME_NS,
+} ExportedNameEntryEnum;
+
+typedef struct ExportedNameEntry {
+  JSAtom export_name;
+  ExportedNameEntryEnum export_type;
+  union {
+    JSExportEntry *me; /* using when the list is built */
+    JSVarRef *var_ref; /* EXPORTED_NAME_NORMAL */
+    JSModuleDef *module; /* for EXPORTED_NAME_NS */
+  } u;
+} ExportedNameEntry;
+
+typedef struct GetExportNamesState {
+  JSModuleDef **modules;
+  int modules_size;
+  int modules_count;
+
+  ExportedNameEntry *exported_names;
+  int exported_names_size;
+  int exported_names_count;
+} GetExportNamesState;
+
+static int find_exported_name(GetExportNamesState *s, JSAtom name)
+{
+  int i;
+  for(i = 0; i < s->exported_names_count; i++) {
+    if (s->exported_names[i].export_name == name)
+      return i;
+  }
+  return -1;
+}
+
+static __exception int get_exported_names(JSContext *ctx,
+                                          GetExportNamesState *s,
+                                          JSModuleDef *m, BOOL from_star)
+{
+  ExportedNameEntry *en;
+  int i, j;
+
+  /* check circular reference */
+  for(i = 0; i < s->modules_count; i++) {
+    if (s->modules[i] == m)
+      return 0;
+  }
+  if (js_resize_array(ctx, (void **)&s->modules, sizeof(s->modules[0]),
+                      &s->modules_size, s->modules_count + 1))
+    return -1;
+  s->modules[s->modules_count++] = m;
+
+  for(i = 0; i < m->export_entries_count; i++) {
+    JSExportEntry *me = &m->export_entries[i];
+    if (from_star && me->export_name == JS_ATOM_default)
+      continue;
+    j = find_exported_name(s, me->export_name);
+    if (j < 0) {
+      if (js_resize_array(ctx, (void **)&s->exported_names, sizeof(s->exported_names[0]),
+                          &s->exported_names_size,
+                          s->exported_names_count + 1))
+        return -1;
+      en = &s->exported_names[s->exported_names_count++];
+      en->export_name = me->export_name;
+      /* avoid a second lookup for simple module exports */
+      if (from_star || me->export_type != JS_EXPORT_TYPE_LOCAL)
+        en->u.me = NULL;
+      else
+        en->u.me = me;
+    } else {
+      en = &s->exported_names[j];
+      en->u.me = NULL;
+    }
+  }
+  for(i = 0; i < m->star_export_entries_count; i++) {
+    JSStarExportEntry *se = &m->star_export_entries[i];
+    JSModuleDef *m1;
+    m1 = m->req_module_entries[se->req_module_idx].module;
+    if (get_exported_names(ctx, s, m1, TRUE))
+      return -1;
+  }
+  return 0;
+}
+
+/* Unfortunately, the spec gives a different behavior from GetOwnProperty ! */
+static int js_module_ns_has(JSContext *ctx, JSValueConst obj, JSAtom atom)
+{
+  return (find_own_property1(JS_VALUE_GET_OBJ(obj), atom) != NULL);
+}
+
+static const JSClassExoticMethods js_module_ns_exotic_methods = {
+    .has_property = js_module_ns_has,
+};
+
+static int exported_names_cmp(const void *p1, const void *p2, void *opaque)
+{
+  JSContext *ctx = opaque;
+  const ExportedNameEntry *me1 = p1;
+  const ExportedNameEntry *me2 = p2;
+  JSValue str1, str2;
+  int ret;
+
+  /* XXX: should avoid allocation memory in atom comparison */
+  str1 = JS_AtomToString(ctx, me1->export_name);
+  str2 = JS_AtomToString(ctx, me2->export_name);
+  if (JS_IsException(str1) || JS_IsException(str2)) {
+    /* XXX: raise an error ? */
+    ret = 0;
+  } else {
+    ret = js_string_compare(ctx, JS_VALUE_GET_STRING(str1),
+                            JS_VALUE_GET_STRING(str2));
+  }
+  JS_FreeValue(ctx, str1);
+  JS_FreeValue(ctx, str2);
+  return ret;
+}
+
+static JSValue js_get_module_ns(JSContext *ctx, JSModuleDef *m);
+
+JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
+                                     void *opaque)
+{
+  JSModuleDef *m = opaque;
+  return js_get_module_ns(ctx, m);
+}
+
+static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m)
+{
+  JSValue obj;
+  JSObject *p;
+  GetExportNamesState s_s, *s = &s_s;
+  int i, ret;
+  JSProperty *pr;
+
+  obj = JS_NewObjectClass(ctx, JS_CLASS_MODULE_NS);
+  if (JS_IsException(obj))
+    return obj;
+  p = JS_VALUE_GET_OBJ(obj);
+
+  memset(s, 0, sizeof(*s));
+  ret = get_exported_names(ctx, s, m, FALSE);
+  js_free(ctx, s->modules);
+  if (ret)
+    goto fail;
+
+  /* Resolve the exported names. The ambiguous exports are removed */
+  for(i = 0; i < s->exported_names_count; i++) {
+    ExportedNameEntry *en = &s->exported_names[i];
+    JSResolveResultEnum res;
+    JSExportEntry *res_me;
+    JSModuleDef *res_m;
+
+    if (en->u.me) {
+      res_me = en->u.me; /* fast case: no resolution needed */
+      res_m = m;
+      res = JS_RESOLVE_RES_FOUND;
+    } else {
+      res = js_resolve_export(ctx, &res_m, &res_me, m,
+                              en->export_name);
+    }
+    if (res != JS_RESOLVE_RES_FOUND) {
+      if (res != JS_RESOLVE_RES_AMBIGUOUS) {
+        js_resolve_export_throw_error(ctx, res, m, en->export_name);
+        goto fail;
+      }
+      en->export_type = EXPORTED_NAME_AMBIGUOUS;
+    } else {
+      if (res_me->local_name == JS_ATOM__star_) {
+        en->export_type = EXPORTED_NAME_NS;
+        en->u.module = res_m->req_module_entries[res_me->u.req_module_idx].module;
+      } else {
+        en->export_type = EXPORTED_NAME_NORMAL;
+        if (res_me->u.local.var_ref) {
+          en->u.var_ref = res_me->u.local.var_ref;
+        } else {
+          JSObject *p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
+          p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
+          en->u.var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];
+        }
+      }
+    }
+  }
+
+  /* sort the exported names */
+  rqsort(s->exported_names, s->exported_names_count,
+         sizeof(s->exported_names[0]), exported_names_cmp, ctx);
+
+  for(i = 0; i < s->exported_names_count; i++) {
+    ExportedNameEntry *en = &s->exported_names[i];
+    switch(en->export_type) {
+      case EXPORTED_NAME_NORMAL:
+      {
+        JSVarRef *var_ref = en->u.var_ref;
+        pr = add_property(ctx, p, en->export_name,
+                          JS_PROP_ENUMERABLE | JS_PROP_WRITABLE |
+                              JS_PROP_VARREF);
+        if (!pr)
+          goto fail;
+        var_ref->header.ref_count++;
+        pr->u.var_ref = var_ref;
+      }
+      break;
+      case EXPORTED_NAME_NS:
+        /* the exported namespace must be created on demand */
+        if (JS_DefineAutoInitProperty(ctx, obj,
+                                      en->export_name,
+                                      JS_AUTOINIT_ID_MODULE_NS,
+                                      en->u.module, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
+          goto fail;
+        break;
+      default:
+        break;
+    }
+  }
+
+  js_free(ctx, s->exported_names);
+
+  JS_DefinePropertyValue(ctx, obj, JS_ATOM_Symbol_toStringTag,
+                         JS_AtomToString(ctx, JS_ATOM_Module),
+                         0);
+
+  p->extensible = FALSE;
+  return obj;
+fail:
+  js_free(ctx, s->exported_names);
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+static JSValue js_get_module_ns(JSContext *ctx, JSModuleDef *m)
+{
+  if (JS_IsUndefined(m->module_ns)) {
+    JSValue val;
+    val = js_build_module_ns(ctx, m);
+    if (JS_IsException(val))
+      return JS_EXCEPTION;
+    m->module_ns = val;
+  }
+  return JS_DupValue(ctx, m->module_ns);
+}
+
+/* Load all the required modules for module 'm' */
+int js_resolve_module(JSContext *ctx, JSModuleDef *m)
+{
+  int i;
+  JSModuleDef *m1;
+
+  if (m->resolved)
+    return 0;
+#ifdef DUMP_MODULE_RESOLVE
+  {
+    char buf1[ATOM_GET_STR_BUF_SIZE];
+    printf("resolving module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
+  }
+#endif
+  m->resolved = TRUE;
+  /* resolve each requested module */
+  for(i = 0; i < m->req_module_entries_count; i++) {
+    JSReqModuleEntry *rme = &m->req_module_entries[i];
+    m1 = js_host_resolve_imported_module_atom(ctx, m->module_name,
+                                              rme->module_name);
+    if (!m1)
+      return -1;
+    rme->module = m1;
+    /* already done in js_host_resolve_imported_module() except if
+       the module was loaded with JS_EvalBinary() */
+    if (js_resolve_module(ctx, m1) < 0)
+      return -1;
+  }
+  return 0;
+}
+
+static JSVarRef *js_create_module_var(JSContext *ctx, BOOL is_lexical)
+{
+  JSVarRef *var_ref;
+  var_ref = js_malloc(ctx, sizeof(JSVarRef));
+  if (!var_ref)
+    return NULL;
+  var_ref->header.ref_count = 1;
+  if (is_lexical)
+    var_ref->value = JS_UNINITIALIZED;
+  else
+    var_ref->value = JS_UNDEFINED;
+  var_ref->pvalue = &var_ref->value;
+  var_ref->is_detached = TRUE;
+  add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
+  return var_ref;
+}
+
+/* Create the <eval> function associated with the module */
+static int js_create_module_bytecode_function(JSContext *ctx, JSModuleDef *m)
+{
+  JSFunctionBytecode *b;
+  int i;
+  JSVarRef **var_refs;
+  JSValue func_obj, bfunc;
+  JSObject *p;
+
+  bfunc = m->func_obj;
+  func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
+                                    JS_CLASS_BYTECODE_FUNCTION);
+
+  if (JS_IsException(func_obj))
+    return -1;
+  b = JS_VALUE_GET_PTR(bfunc);
+
+  p = JS_VALUE_GET_OBJ(func_obj);
+  p->u.func.function_bytecode = b;
+  b->header.ref_count++;
+  p->u.func.home_object = NULL;
+  p->u.func.var_refs = NULL;
+  if (b->closure_var_count) {
+    var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count);
+    if (!var_refs)
+      goto fail;
+    p->u.func.var_refs = var_refs;
+
+    /* create the global variables. The other variables are
+       imported from other modules */
+    for(i = 0; i < b->closure_var_count; i++) {
+      JSClosureVar *cv = &b->closure_var[i];
+      JSVarRef *var_ref;
+      if (cv->is_local) {
+        var_ref = js_create_module_var(ctx, cv->is_lexical);
+        if (!var_ref)
+          goto fail;
+#ifdef DUMP_MODULE_RESOLVE
+        printf("local %d: %p\n", i, var_ref);
+#endif
+        var_refs[i] = var_ref;
+      }
+    }
+  }
+  m->func_obj = func_obj;
+  JS_FreeValue(ctx, bfunc);
+  return 0;
+fail:
+  JS_FreeValue(ctx, func_obj);
+  return -1;
+}
+
+/* must be done before js_link_module() because of cyclic references */
+int js_create_module_function(JSContext *ctx, JSModuleDef *m)
+{
+  BOOL is_c_module;
+  int i;
+  JSVarRef *var_ref;
+
+  if (m->func_created)
+    return 0;
+
+  is_c_module = (m->init_func != NULL);
+
+  if (is_c_module) {
+    /* initialize the exported variables */
+    for(i = 0; i < m->export_entries_count; i++) {
+      JSExportEntry *me = &m->export_entries[i];
+      if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
+        var_ref = js_create_module_var(ctx, FALSE);
+        if (!var_ref)
+          return -1;
+        me->u.local.var_ref = var_ref;
+      }
+    }
+  } else {
+    if (js_create_module_bytecode_function(ctx, m))
+      return -1;
+  }
+  m->func_created = TRUE;
+
+  /* do it on the dependencies */
+
+  for(i = 0; i < m->req_module_entries_count; i++) {
+    JSReqModuleEntry *rme = &m->req_module_entries[i];
+    if (js_create_module_function(ctx, rme->module) < 0)
+      return -1;
+  }
+
+  return 0;
+}
+
+
+/* Prepare a module to be executed by resolving all the imported
+   variables. */
+int js_link_module(JSContext *ctx, JSModuleDef *m)
+{
+  int i;
+  JSImportEntry *mi;
+  JSModuleDef *m1;
+  JSVarRef **var_refs, *var_ref;
+  JSObject *p;
+  BOOL is_c_module;
+  JSValue ret_val;
+
+  if (m->instantiated)
+    return 0;
+  m->instantiated = TRUE;
+
+#ifdef DUMP_MODULE_RESOLVE
+  {
+    char buf1[ATOM_GET_STR_BUF_SIZE];
+    printf("start instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
+  }
+#endif
+
+  for(i = 0; i < m->req_module_entries_count; i++) {
+    JSReqModuleEntry *rme = &m->req_module_entries[i];
+    if (js_link_module(ctx, rme->module) < 0)
+      goto fail;
+  }
+
+#ifdef DUMP_MODULE_RESOLVE
+  {
+    char buf1[ATOM_GET_STR_BUF_SIZE];
+    printf("instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
+  }
+#endif
+  /* check the indirect exports */
+  for(i = 0; i < m->export_entries_count; i++) {
+    JSExportEntry *me = &m->export_entries[i];
+    if (me->export_type == JS_EXPORT_TYPE_INDIRECT &&
+        me->local_name != JS_ATOM__star_) {
+      JSResolveResultEnum ret;
+      JSExportEntry *res_me;
+      JSModuleDef *res_m, *m1;
+      m1 = m->req_module_entries[me->u.req_module_idx].module;
+      ret = js_resolve_export(ctx, &res_m, &res_me, m1, me->local_name);
+      if (ret != JS_RESOLVE_RES_FOUND) {
+        js_resolve_export_throw_error(ctx, ret, m, me->export_name);
+        goto fail;
+      }
+    }
+  }
+
+#ifdef DUMP_MODULE_RESOLVE
+  {
+    printf("exported bindings:\n");
+    for(i = 0; i < m->export_entries_count; i++) {
+      JSExportEntry *me = &m->export_entries[i];
+      printf(" name="); print_atom(ctx, me->export_name);
+      printf(" local="); print_atom(ctx, me->local_name);
+      printf(" type=%d idx=%d\n", me->export_type, me->u.local.var_idx);
+    }
+  }
+#endif
+
+  is_c_module = (m->init_func != NULL);
+
+  if (!is_c_module) {
+    p = JS_VALUE_GET_OBJ(m->func_obj);
+    var_refs = p->u.func.var_refs;
+
+    for(i = 0; i < m->import_entries_count; i++) {
+      mi = &m->import_entries[i];
+#ifdef DUMP_MODULE_RESOLVE
+      printf("import var_idx=%d name=", mi->var_idx);
+      print_atom(ctx, mi->import_name);
+      printf(": ");
+#endif
+      m1 = m->req_module_entries[mi->req_module_idx].module;
+      if (mi->import_name == JS_ATOM__star_) {
+        JSValue val;
+        /* name space import */
+        val = js_get_module_ns(ctx, m1);
+        if (JS_IsException(val))
+          goto fail;
+        set_value(ctx, &var_refs[mi->var_idx]->value, val);
+#ifdef DUMP_MODULE_RESOLVE
+        printf("namespace\n");
+#endif
+      } else {
+        JSResolveResultEnum ret;
+        JSExportEntry *res_me;
+        JSModuleDef *res_m;
+        JSObject *p1;
+
+        ret = js_resolve_export(ctx, &res_m,
+                                &res_me, m1, mi->import_name);
+        if (ret != JS_RESOLVE_RES_FOUND) {
+          js_resolve_export_throw_error(ctx, ret, m1, mi->import_name);
+          goto fail;
+        }
+        if (res_me->local_name == JS_ATOM__star_) {
+          JSValue val;
+          JSModuleDef *m2;
+          /* name space import from */
+          m2 = res_m->req_module_entries[res_me->u.req_module_idx].module;
+          val = js_get_module_ns(ctx, m2);
+          if (JS_IsException(val))
+            goto fail;
+          var_ref = js_create_module_var(ctx, TRUE);
+          if (!var_ref) {
+            JS_FreeValue(ctx, val);
+            goto fail;
+          }
+          set_value(ctx, &var_ref->value, val);
+          var_refs[mi->var_idx] = var_ref;
+#ifdef DUMP_MODULE_RESOLVE
+          printf("namespace from\n");
+#endif
+        } else {
+          var_ref = res_me->u.local.var_ref;
+          if (!var_ref) {
+            p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
+            var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];
+          }
+          var_ref->header.ref_count++;
+          var_refs[mi->var_idx] = var_ref;
+#ifdef DUMP_MODULE_RESOLVE
+          printf("local export (var_ref=%p)\n", var_ref);
+#endif
+        }
+      }
+    }
+
+    /* keep the exported variables in the module export entries (they
+       are used when the eval function is deleted and cannot be
+       initialized before in case imports are exported) */
+    for(i = 0; i < m->export_entries_count; i++) {
+      JSExportEntry *me = &m->export_entries[i];
+      if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
+        var_ref = var_refs[me->u.local.var_idx];
+        var_ref->header.ref_count++;
+        me->u.local.var_ref = var_ref;
+      }
+    }
+
+    /* initialize the global variables */
+    ret_val = JS_Call(ctx, m->func_obj, JS_TRUE, 0, NULL);
+    if (JS_IsException(ret_val))
+      goto fail;
+    JS_FreeValue(ctx, ret_val);
+  }
+
+#ifdef DUMP_MODULE_RESOLVE
+  printf("done instantiate\n");
+#endif
+  return 0;
+fail:
+  return -1;
+}
+
+/* return JS_ATOM_NULL if the name cannot be found. Only works with
+   not striped bytecode functions. */
+JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels)
+{
+  JSStackFrame *sf;
+  JSFunctionBytecode *b;
+  JSObject *p;
+  /* XXX: currently we just use the filename of the englobing
+     function. It does not work for eval(). Need to add a
+     ScriptOrModule info in JSFunctionBytecode */
+  sf = ctx->rt->current_stack_frame;
+  if (!sf)
+    return JS_ATOM_NULL;
+  while (n_stack_levels-- > 0) {
+    sf = sf->prev_frame;
+    if (!sf)
+      return JS_ATOM_NULL;
+  }
+  if (JS_VALUE_GET_TAG(sf->cur_func) != JS_TAG_OBJECT)
+    return JS_ATOM_NULL;
+  p = JS_VALUE_GET_OBJ(sf->cur_func);
+  if (!js_class_has_bytecode(p->class_id))
+    return JS_ATOM_NULL;
+  b = p->u.func.function_bytecode;
+  if (!b->has_debug)
+    return JS_ATOM_NULL;
+  return JS_DupAtom(ctx, b->debug.filename);
+}
+
+JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m)
+{
+  return JS_DupAtom(ctx, m->module_name);
+}
+
+JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m)
+{
+  JSValue obj;
+  /* allocate meta_obj only if requested to save memory */
+  obj = m->meta_obj;
+  if (JS_IsUndefined(obj)) {
+    obj = JS_NewObjectProto(ctx, JS_NULL);
+    if (JS_IsException(obj))
+      return JS_EXCEPTION;
+    m->meta_obj = obj;
+  }
+  return JS_DupValue(ctx, obj);
+}
+
+JSValue js_import_meta(JSContext *ctx)
+{
+  JSAtom filename;
+  JSModuleDef *m;
+
+  filename = JS_GetScriptOrModuleName(ctx, 0);
+  if (filename == JS_ATOM_NULL)
+    goto fail;
+
+  /* XXX: inefficient, need to add a module or script pointer in
+     JSFunctionBytecode */
+  m = js_find_loaded_module(ctx, filename);
+  JS_FreeAtom(ctx, filename);
+  if (!m) {
+  fail:
+    JS_ThrowTypeError(ctx, "import.meta not supported in this context");
+    return JS_EXCEPTION;
+  }
+  return JS_GetImportMeta(ctx, m);
+}
+
+/* used by os.Worker() and import() */
+JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename,
+                          const char *filename)
+{
+  JSModuleDef *m;
+  JSValue ret, func_obj;
+
+  m = js_host_resolve_imported_module(ctx, basename, filename);
+  if (!m)
+    return NULL;
+
+  if (js_resolve_module(ctx, m) < 0) {
+    js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);
+    return NULL;
+  }
+
+  /* Evaluate the module code */
+  func_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
+  ret = JS_EvalFunction(ctx, func_obj);
+  if (JS_IsException(ret))
+    return NULL;
+  JS_FreeValue(ctx, ret);
+  return m;
+}
+
+static JSValue js_dynamic_import_job(JSContext *ctx,
+                                     int argc, JSValueConst *argv)
+{
+  JSValueConst *resolving_funcs = argv;
+  JSValueConst basename_val = argv[2];
+  JSValueConst specifier = argv[3];
+  JSModuleDef *m;
+  const char *basename = NULL, *filename;
+  JSValue ret, err, ns;
+
+  if (!JS_IsString(basename_val)) {
+    JS_ThrowTypeError(ctx, "no function filename for import()");
+    goto exception;
+  }
+  basename = JS_ToCString(ctx, basename_val);
+  if (!basename)
+    goto exception;
+
+  filename = JS_ToCString(ctx, specifier);
+  if (!filename)
+    goto exception;
+
+  m = JS_RunModule(ctx, basename, filename);
+  JS_FreeCString(ctx, filename);
+  if (!m)
+    goto exception;
+
+  /* return the module namespace */
+  ns = js_get_module_ns(ctx, m);
+  if (JS_IsException(ns))
+    goto exception;
+
+  ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED,
+                1, (JSValueConst *)&ns);
+  JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
+  JS_FreeValue(ctx, ns);
+  JS_FreeCString(ctx, basename);
+  return JS_UNDEFINED;
+exception:
+
+  err = JS_GetException(ctx);
+  ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
+                1, (JSValueConst *)&err);
+  JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
+  JS_FreeValue(ctx, err);
+  JS_FreeCString(ctx, basename);
+  return JS_UNDEFINED;
+}
+
+JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier)
+{
+  JSAtom basename;
+  JSValue promise, resolving_funcs[2], basename_val;
+  JSValueConst args[4];
+
+  basename = JS_GetScriptOrModuleName(ctx, 0);
+  if (basename == JS_ATOM_NULL)
+    basename_val = JS_NULL;
+  else
+    basename_val = JS_AtomToValue(ctx, basename);
+  JS_FreeAtom(ctx, basename);
+  if (JS_IsException(basename_val))
+    return basename_val;
+
+  promise = JS_NewPromiseCapability(ctx, resolving_funcs);
+  if (JS_IsException(promise)) {
+    JS_FreeValue(ctx, basename_val);
+    return promise;
+  }
+
+  args[0] = resolving_funcs[0];
+  args[1] = resolving_funcs[1];
+  args[2] = basename_val;
+  args[3] = specifier;
+
+  JS_EnqueueJob(ctx, js_dynamic_import_job, 4, args);
+
+  JS_FreeValue(ctx, basename_val);
+  JS_FreeValue(ctx, resolving_funcs[0]);
+  JS_FreeValue(ctx, resolving_funcs[1]);
+  return promise;
+}
+
+/* Run the <eval> function of the module and of all its requested
+   modules. */
+JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m)
+{
+  JSModuleDef *m1;
+  int i;
+  JSValue ret_val;
+
+  if (m->eval_mark)
+    return JS_UNDEFINED; /* avoid cycles */
+
+  if (m->evaluated) {
+    /* if the module was already evaluated, rethrow the exception
+       it raised */
+    if (m->eval_has_exception) {
+      return JS_Throw(ctx, JS_DupValue(ctx, m->eval_exception));
+    } else {
+      return JS_UNDEFINED;
+    }
+  }
+
+  m->eval_mark = TRUE;
+
+  for(i = 0; i < m->req_module_entries_count; i++) {
+    JSReqModuleEntry *rme = &m->req_module_entries[i];
+    m1 = rme->module;
+    if (!m1->eval_mark) {
+      ret_val = js_evaluate_module(ctx, m1);
+      if (JS_IsException(ret_val)) {
+        m->eval_mark = FALSE;
+        return ret_val;
+      }
+      JS_FreeValue(ctx, ret_val);
+    }
+  }
+
+  if (m->init_func) {
+    /* C module init */
+    if (m->init_func(ctx, m) < 0)
+      ret_val = JS_EXCEPTION;
+    else
+      ret_val = JS_UNDEFINED;
+  } else {
+    ret_val = JS_CallFree(ctx, m->func_obj, JS_UNDEFINED, 0, NULL);
+    m->func_obj = JS_UNDEFINED;
+  }
+  if (JS_IsException(ret_val)) {
+    /* save the thrown exception value */
+    m->eval_has_exception = TRUE;
+    m->eval_exception = JS_DupValue(ctx, ctx->rt->current_exception);
+  }
+  m->eval_mark = FALSE;
+  m->evaluated = TRUE;
+  return ret_val;
+}
+
+int JS_ResolveModule(JSContext *ctx, JSValueConst obj)
+{
+  if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
+    JSModuleDef *m = JS_VALUE_GET_PTR(obj);
+    if (js_resolve_module(ctx, m) < 0) {
+      js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);
+      return -1;
+    }
+  }
+  return 0;
+}
diff --git a/src/core/module.h b/src/core/module.h
new file mode 100644
index 000000000..d5061359b
--- /dev/null
+++ b/src/core/module.h
@@ -0,0 +1,85 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_MODULE_H
+#define QUICKJS_MODULE_H
+
+#include "quickjs/quickjs.h"
+#include "types.h"
+
+typedef struct JSResolveEntry {
+  JSModuleDef *module;
+  JSAtom name;
+} JSResolveEntry;
+
+typedef struct JSResolveState {
+  JSResolveEntry *array;
+  int size;
+  int count;
+} JSResolveState;
+
+/* 'name' is freed */
+JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name);
+
+void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
+                               JS_MarkFunc *mark_func);
+
+int add_req_module_entry(JSContext *ctx, JSModuleDef *m,
+                                JSAtom module_name);
+
+JSExportEntry *find_export_entry(JSContext *ctx, JSModuleDef *m,
+                                        JSAtom export_name);
+
+char *js_default_module_normalize_name(JSContext *ctx,
+                                              const char *base_name,
+                                              const char *name);
+
+JSModuleDef *js_find_loaded_module(JSContext *ctx, JSAtom name);
+
+/* return NULL in case of exception (e.g. module could not be loaded) */
+JSModuleDef *js_host_resolve_imported_module(JSContext *ctx,
+                                                    const char *base_cname,
+                                                    const char *cname1);
+
+JSModuleDef *js_host_resolve_imported_module_atom(JSContext *ctx,
+                                                         JSAtom base_module_name,
+                                                         JSAtom module_name1);
+
+int js_create_module_function(JSContext *ctx, JSModuleDef *m);
+
+/* Load all the required modules for module 'm' */
+int js_resolve_module(JSContext *ctx, JSModuleDef *m);
+
+/* Prepare a module to be executed by resolving all the imported
+   variables. */
+int js_link_module(JSContext *ctx, JSModuleDef *m);
+
+/* Run the <eval> function of the module and of all its requested
+   modules. */
+JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m);
+
+JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier);
+
+#endif
\ No newline at end of file
diff --git a/src/core/object.c b/src/core/object.c
new file mode 100644
index 000000000..5eb81b692
--- /dev/null
+++ b/src/core/object.c
@@ -0,0 +1,2217 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "object.h"
+#include "builtins/js-function.h"
+#include "builtins/js-object.h"
+#include "builtins/js-operator.h"
+#include "builtins/js-proxy.h"
+#include "convertion.h"
+#include "exception.h"
+#include "function.h"
+#include "gc.h"
+#include "parser.h"
+#include "runtime.h"
+#include "shape.h"
+#include "string.h"
+#include "types.h"
+
+JSValue JS_GetPropertyValue(JSContext* ctx, JSValueConst this_obj, JSValue prop) {
+  JSAtom atom;
+  JSValue ret;
+
+  if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT && JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {
+    JSObject* p;
+    uint32_t idx, len;
+    /* fast path for array access */
+    p = JS_VALUE_GET_OBJ(this_obj);
+    idx = JS_VALUE_GET_INT(prop);
+    len = (uint32_t)p->u.array.count;
+    if (unlikely(idx >= len))
+      goto slow_path;
+    switch (p->class_id) {
+      case JS_CLASS_ARRAY:
+      case JS_CLASS_ARGUMENTS:
+        return JS_DupValue(ctx, p->u.array.u.values[idx]);
+      case JS_CLASS_INT8_ARRAY:
+        return JS_NewInt32(ctx, p->u.array.u.int8_ptr[idx]);
+      case JS_CLASS_UINT8C_ARRAY:
+      case JS_CLASS_UINT8_ARRAY:
+        return JS_NewInt32(ctx, p->u.array.u.uint8_ptr[idx]);
+      case JS_CLASS_INT16_ARRAY:
+        return JS_NewInt32(ctx, p->u.array.u.int16_ptr[idx]);
+      case JS_CLASS_UINT16_ARRAY:
+        return JS_NewInt32(ctx, p->u.array.u.uint16_ptr[idx]);
+      case JS_CLASS_INT32_ARRAY:
+        return JS_NewInt32(ctx, p->u.array.u.int32_ptr[idx]);
+      case JS_CLASS_UINT32_ARRAY:
+        return JS_NewUint32(ctx, p->u.array.u.uint32_ptr[idx]);
+#ifdef CONFIG_BIGNUM
+      case JS_CLASS_BIG_INT64_ARRAY:
+        return JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]);
+      case JS_CLASS_BIG_UINT64_ARRAY:
+        return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]);
+#endif
+      case JS_CLASS_FLOAT32_ARRAY:
+        return __JS_NewFloat64(ctx, p->u.array.u.float_ptr[idx]);
+      case JS_CLASS_FLOAT64_ARRAY:
+        return __JS_NewFloat64(ctx, p->u.array.u.double_ptr[idx]);
+      default:
+        goto slow_path;
+    }
+  } else {
+  slow_path:
+    atom = JS_ValueToAtom(ctx, prop);
+    JS_FreeValue(ctx, prop);
+    if (unlikely(atom == JS_ATOM_NULL))
+      return JS_EXCEPTION;
+    ret = JS_GetProperty(ctx, this_obj, atom);
+    JS_FreeAtom(ctx, atom);
+    return ret;
+  }
+}
+
+JSValue JS_GetPropertyUint32(JSContext* ctx, JSValueConst this_obj, uint32_t idx) {
+  return JS_GetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx));
+}
+
+/* Check if an object has a generalized numeric property. Return value:
+   -1 for exception,
+   TRUE if property exists, stored into *pval,
+   FALSE if proprty does not exist.
+ */
+int JS_TryGetPropertyInt64(JSContext* ctx, JSValueConst obj, int64_t idx, JSValue* pval) {
+  JSValue val = JS_UNDEFINED;
+  JSAtom prop;
+  int present;
+
+  if (likely((uint64_t)idx <= JS_ATOM_MAX_INT)) {
+    /* fast path */
+    present = JS_HasProperty(ctx, obj, __JS_AtomFromUInt32(idx));
+    if (present > 0) {
+      val = JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx));
+      if (unlikely(JS_IsException(val)))
+        present = -1;
+    }
+  } else {
+    prop = JS_NewAtomInt64(ctx, idx);
+    present = -1;
+    if (likely(prop != JS_ATOM_NULL)) {
+      present = JS_HasProperty(ctx, obj, prop);
+      if (present > 0) {
+        val = JS_GetProperty(ctx, obj, prop);
+        if (unlikely(JS_IsException(val)))
+          present = -1;
+      }
+      JS_FreeAtom(ctx, prop);
+    }
+  }
+  *pval = val;
+  return present;
+}
+
+JSValue JS_GetPropertyInt64(JSContext* ctx, JSValueConst obj, int64_t idx) {
+  JSAtom prop;
+  JSValue val;
+
+  if ((uint64_t)idx <= INT32_MAX) {
+    /* fast path for fast arrays */
+    return JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx));
+  }
+  prop = JS_NewAtomInt64(ctx, idx);
+  if (prop == JS_ATOM_NULL)
+    return JS_EXCEPTION;
+
+  val = JS_GetProperty(ctx, obj, prop);
+  JS_FreeAtom(ctx, prop);
+  return val;
+}
+
+JSValue JS_GetPropertyStr(JSContext* ctx, JSValueConst this_obj, const char* prop) {
+  JSAtom atom;
+  JSValue ret;
+  atom = JS_NewAtom(ctx, prop);
+  ret = JS_GetProperty(ctx, this_obj, atom);
+  JS_FreeAtom(ctx, atom);
+  return ret;
+}
+
+/* Note: the property value is not initialized. Return NULL if memory
+   error. */
+JSProperty* add_property(JSContext* ctx, JSObject* p, JSAtom prop, int prop_flags) {
+  JSShape *sh, *new_sh;
+
+  sh = p->shape;
+  if (sh->is_hashed) {
+    /* try to find an existing shape */
+    new_sh = find_hashed_shape_prop(ctx->rt, sh, prop, prop_flags);
+    if (new_sh) {
+      /* matching shape found: use it */
+      /*  the property array may need to be resized */
+      if (new_sh->prop_size != sh->prop_size) {
+        JSProperty* new_prop;
+        new_prop = js_realloc(ctx, p->prop, sizeof(p->prop[0]) * new_sh->prop_size);
+        if (!new_prop)
+          return NULL;
+        p->prop = new_prop;
+      }
+      p->shape = js_dup_shape(new_sh);
+      js_free_shape(ctx->rt, sh);
+      return &p->prop[new_sh->prop_count - 1];
+    } else if (sh->header.ref_count != 1) {
+      /* if the shape is shared, clone it */
+      new_sh = js_clone_shape(ctx, sh);
+      if (!new_sh)
+        return NULL;
+      /* hash the cloned shape */
+      new_sh->is_hashed = TRUE;
+      js_shape_hash_link(ctx->rt, new_sh);
+      js_free_shape(ctx->rt, p->shape);
+      p->shape = new_sh;
+    }
+  }
+  assert(p->shape->header.ref_count == 1);
+  if (add_shape_property(ctx, &p->shape, p, prop, prop_flags))
+    return NULL;
+  return &p->prop[p->shape->prop_count - 1];
+}
+
+/* can be called on Array or Arguments objects. return < 0 if
+   memory alloc error. */
+no_inline __exception int convert_fast_array_to_array(JSContext* ctx, JSObject* p) {
+  JSProperty* pr;
+  JSShape* sh;
+  JSValue* tab;
+  uint32_t i, len, new_count;
+
+  if (js_shape_prepare_update(ctx, p, NULL))
+    return -1;
+  len = p->u.array.count;
+  /* resize the properties once to simplify the error handling */
+  sh = p->shape;
+  new_count = sh->prop_count + len;
+  if (new_count > sh->prop_size) {
+    if (resize_properties(ctx, &p->shape, p, new_count))
+      return -1;
+  }
+
+  tab = p->u.array.u.values;
+  for (i = 0; i < len; i++) {
+    /* add_property cannot fail here but
+       __JS_AtomFromUInt32(i) fails for i > INT32_MAX */
+    pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E);
+    pr->u.value = *tab++;
+  }
+  js_free(ctx, p->u.array.u.values);
+  p->u.array.count = 0;
+  p->u.array.u.values = NULL; /* fail safe */
+  p->u.array.u1.size = 0;
+  p->fast_array = 0;
+  return 0;
+}
+
+int delete_property(JSContext* ctx, JSObject* p, JSAtom atom) {
+  JSShape* sh;
+  JSShapeProperty *pr, *lpr, *prop;
+  JSProperty* pr1;
+  uint32_t lpr_idx;
+  intptr_t h, h1;
+
+redo:
+  sh = p->shape;
+  h1 = atom & sh->prop_hash_mask;
+  h = prop_hash_end(sh)[-h1 - 1];
+  prop = get_shape_prop(sh);
+  lpr = NULL;
+  lpr_idx = 0; /* prevent warning */
+  while (h != 0) {
+    pr = &prop[h - 1];
+    if (likely(pr->atom == atom)) {
+      /* found ! */
+      if (!(pr->flags & JS_PROP_CONFIGURABLE))
+        return FALSE;
+      /* realloc the shape if needed */
+      if (lpr)
+        lpr_idx = lpr - get_shape_prop(sh);
+      if (js_shape_prepare_update(ctx, p, &pr))
+        return -1;
+      sh = p->shape;
+      /* remove property */
+      if (lpr) {
+        lpr = get_shape_prop(sh) + lpr_idx;
+        lpr->hash_next = pr->hash_next;
+      } else {
+        prop_hash_end(sh)[-h1 - 1] = pr->hash_next;
+      }
+      sh->deleted_prop_count++;
+      /* free the entry */
+      pr1 = &p->prop[h - 1];
+      free_property(ctx->rt, pr1, pr->flags);
+      JS_FreeAtom(ctx, pr->atom);
+      /* put default values */
+      pr->flags = 0;
+      pr->atom = JS_ATOM_NULL;
+      pr1->u.value = JS_UNDEFINED;
+
+      /* compact the properties if too many deleted properties */
+      if (sh->deleted_prop_count >= 8 && sh->deleted_prop_count >= ((unsigned)sh->prop_count / 2)) {
+        compact_properties(ctx, p);
+      }
+      return TRUE;
+    }
+    lpr = pr;
+    h = pr->hash_next;
+  }
+
+  if (p->is_exotic) {
+    if (p->fast_array) {
+      uint32_t idx;
+      if (JS_AtomIsArrayIndex(ctx, &idx, atom) && idx < p->u.array.count) {
+        if (p->class_id == JS_CLASS_ARRAY || p->class_id == JS_CLASS_ARGUMENTS) {
+          /* Special case deleting the last element of a fast Array */
+          if (idx == p->u.array.count - 1) {
+            JS_FreeValue(ctx, p->u.array.u.values[idx]);
+            p->u.array.count = idx;
+            return TRUE;
+          }
+          if (convert_fast_array_to_array(ctx, p))
+            return -1;
+          goto redo;
+        } else {
+          return FALSE;
+        }
+      }
+    } else {
+      const JSClassExoticMethods* em = ctx->rt->class_array[p->class_id].exotic;
+      if (em && em->delete_property) {
+        return em->delete_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), atom);
+      }
+    }
+  }
+  /* not found */
+  return TRUE;
+}
+
+int call_setter(JSContext* ctx, JSObject* setter, JSValueConst this_obj, JSValue val, int flags) {
+  JSValue ret, func;
+  if (likely(setter)) {
+    func = JS_MKPTR(JS_TAG_OBJECT, setter);
+    /* Note: the field could be removed in the setter */
+    func = JS_DupValue(ctx, func);
+    ret = JS_CallFree(ctx, func, this_obj, 1, (JSValueConst*)&val);
+    JS_FreeValue(ctx, val);
+    if (JS_IsException(ret))
+      return -1;
+    JS_FreeValue(ctx, ret);
+    return TRUE;
+  } else {
+    JS_FreeValue(ctx, val);
+    if ((flags & JS_PROP_THROW) || ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
+      JS_ThrowTypeError(ctx, "no setter for property");
+      return -1;
+    }
+    return FALSE;
+  }
+}
+
+void free_property(JSRuntime* rt, JSProperty* pr, int prop_flags) {
+  if (unlikely(prop_flags & JS_PROP_TMASK)) {
+    if ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
+      if (pr->u.getset.getter)
+        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
+      if (pr->u.getset.setter)
+        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
+    } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
+      free_var_ref(rt, pr->u.var_ref);
+    } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
+      js_autoinit_free(rt, pr);
+    }
+  } else {
+    JS_FreeValueRT(rt, pr->u.value);
+  }
+}
+
+/* return the value associated to the autoinit property or an exception */
+typedef JSValue JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
+
+static JSAutoInitFunc *js_autoinit_func_table[] = {
+    js_instantiate_prototype, /* JS_AUTOINIT_ID_PROTOTYPE */
+    js_module_ns_autoinit, /* JS_AUTOINIT_ID_MODULE_NS */
+    JS_InstantiateFunctionListItem2, /* JS_AUTOINIT_ID_PROP */
+};
+
+/* warning: 'prs' is reallocated after it */
+static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop,
+                               JSProperty *pr, JSShapeProperty *prs)
+{
+  JSValue val;
+  JSContext *realm;
+  JSAutoInitFunc *func;
+
+  if (js_shape_prepare_update(ctx, p, &prs))
+    return -1;
+
+  realm = js_autoinit_get_realm(pr);
+  func = js_autoinit_func_table[js_autoinit_get_id(pr)];
+  /* 'func' shall not modify the object properties 'pr' */
+  val = func(realm, p, prop, pr->u.init.opaque);
+  js_autoinit_free(ctx->rt, pr);
+  prs->flags &= ~JS_PROP_TMASK;
+  pr->u.value = JS_UNDEFINED;
+  if (JS_IsException(val))
+    return -1;
+  pr->u.value = val;
+  return 0;
+}
+
+JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
+                               JSAtom prop, JSValueConst this_obj,
+                               BOOL throw_ref_error)
+{
+  JSObject *p;
+  JSProperty *pr;
+  JSShapeProperty *prs;
+  uint32_t tag;
+
+  tag = JS_VALUE_GET_TAG(obj);
+  if (unlikely(tag != JS_TAG_OBJECT)) {
+    switch(tag) {
+      case JS_TAG_NULL:
+        return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of null", prop);
+      case JS_TAG_UNDEFINED:
+        return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of undefined", prop);
+      case JS_TAG_EXCEPTION:
+        return JS_EXCEPTION;
+      case JS_TAG_STRING:
+      {
+        JSString *p1 = JS_VALUE_GET_STRING(obj);
+        if (__JS_AtomIsTaggedInt(prop)) {
+          uint32_t idx, ch;
+          idx = __JS_AtomToUInt32(prop);
+          if (idx < p1->len) {
+            if (p1->is_wide_char)
+              ch = p1->u.str16[idx];
+            else
+              ch = p1->u.str8[idx];
+            return js_new_string_char(ctx, ch);
+          }
+        } else if (prop == JS_ATOM_length) {
+          return JS_NewInt32(ctx, p1->len);
+        }
+      }
+      break;
+      default:
+        break;
+    }
+    /* cannot raise an exception */
+    p = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj));
+    if (!p)
+      return JS_UNDEFINED;
+  } else {
+    p = JS_VALUE_GET_OBJ(obj);
+  }
+
+  for(;;) {
+    prs = find_own_property(&pr, p, prop);
+    if (prs) {
+      /* found */
+      if (unlikely(prs->flags & JS_PROP_TMASK)) {
+        if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
+          if (unlikely(!pr->u.getset.getter)) {
+            return JS_UNDEFINED;
+          } else {
+            JSValue func = JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter);
+            /* Note: the field could be removed in the getter */
+            func = JS_DupValue(ctx, func);
+            return JS_CallFree(ctx, func, this_obj, 0, NULL);
+          }
+        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
+          JSValue val = *pr->u.var_ref->pvalue;
+          if (unlikely(JS_IsUninitialized(val)))
+            return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
+          return JS_DupValue(ctx, val);
+        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
+          /* Instantiate property and retry */
+          if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
+            return JS_EXCEPTION;
+          continue;
+        }
+      } else {
+        return JS_DupValue(ctx, pr->u.value);
+      }
+    }
+    if (unlikely(p->is_exotic)) {
+      /* exotic behaviors */
+      if (p->fast_array) {
+        if (__JS_AtomIsTaggedInt(prop)) {
+          uint32_t idx = __JS_AtomToUInt32(prop);
+          if (idx < p->u.array.count) {
+            /* we avoid duplicating the code */
+            return JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
+          } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
+                     p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
+            return JS_UNDEFINED;
+          }
+        } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
+                   p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
+          int ret;
+          ret = JS_AtomIsNumericIndex(ctx, prop);
+          if (ret != 0) {
+            if (ret < 0)
+              return JS_EXCEPTION;
+            return JS_UNDEFINED;
+          }
+        }
+      } else {
+        const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
+        if (em) {
+          if (em->get_property) {
+            JSValue obj1, retval;
+            /* XXX: should pass throw_ref_error */
+            /* Note: if 'p' is a prototype, it can be
+               freed in the called function */
+            obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+            retval = em->get_property(ctx, obj1, prop, this_obj);
+            JS_FreeValue(ctx, obj1);
+            return retval;
+          }
+          if (em->get_own_property) {
+            JSPropertyDescriptor desc;
+            int ret;
+            JSValue obj1;
+
+            /* Note: if 'p' is a prototype, it can be
+               freed in the called function */
+            obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+            ret = em->get_own_property(ctx, &desc, obj1, prop);
+            JS_FreeValue(ctx, obj1);
+            if (ret < 0)
+              return JS_EXCEPTION;
+            if (ret) {
+              if (desc.flags & JS_PROP_GETSET) {
+                JS_FreeValue(ctx, desc.setter);
+                return JS_CallFree(ctx, desc.getter, this_obj, 0, NULL);
+              } else {
+                return desc.value;
+              }
+            }
+          }
+        }
+      }
+    }
+    p = p->shape->proto;
+    if (!p)
+      break;
+  }
+  if (unlikely(throw_ref_error)) {
+    return JS_ThrowReferenceErrorNotDefined(ctx, prop);
+  } else {
+    return JS_UNDEFINED;
+  }
+}
+
+JSValue JS_GetOwnPropertyNames2(JSContext* ctx, JSValueConst obj1, int flags, int kind) {
+  JSValue obj, r, val, key, value;
+  JSObject* p;
+  JSPropertyEnum* atoms;
+  uint32_t len, i, j;
+
+  r = JS_UNDEFINED;
+  val = JS_UNDEFINED;
+  obj = JS_ToObject(ctx, obj1);
+  if (JS_IsException(obj))
+    return JS_EXCEPTION;
+  p = JS_VALUE_GET_OBJ(obj);
+  if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, flags & ~JS_GPN_ENUM_ONLY))
+    goto exception;
+  r = JS_NewArray(ctx);
+  if (JS_IsException(r))
+    goto exception;
+  for (j = i = 0; i < len; i++) {
+    JSAtom atom = atoms[i].atom;
+    if (flags & JS_GPN_ENUM_ONLY) {
+      JSPropertyDescriptor desc;
+      int res;
+
+      /* Check if property is still enumerable */
+      res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
+      if (res < 0)
+        goto exception;
+      if (!res)
+        continue;
+      js_free_desc(ctx, &desc);
+      if (!(desc.flags & JS_PROP_ENUMERABLE))
+        continue;
+    }
+    switch (kind) {
+      default:
+      case JS_ITERATOR_KIND_KEY:
+        val = JS_AtomToValue(ctx, atom);
+        if (JS_IsException(val))
+          goto exception;
+        break;
+      case JS_ITERATOR_KIND_VALUE:
+        val = JS_GetProperty(ctx, obj, atom);
+        if (JS_IsException(val))
+          goto exception;
+        break;
+      case JS_ITERATOR_KIND_KEY_AND_VALUE:
+        val = JS_NewArray(ctx);
+        if (JS_IsException(val))
+          goto exception;
+        key = JS_AtomToValue(ctx, atom);
+        if (JS_IsException(key))
+          goto exception1;
+        if (JS_CreateDataPropertyUint32(ctx, val, 0, key, JS_PROP_THROW) < 0)
+          goto exception1;
+        value = JS_GetProperty(ctx, obj, atom);
+        if (JS_IsException(value))
+          goto exception1;
+        if (JS_CreateDataPropertyUint32(ctx, val, 1, value, JS_PROP_THROW) < 0)
+          goto exception1;
+        break;
+    }
+    if (JS_CreateDataPropertyUint32(ctx, r, j++, val, 0) < 0)
+      goto exception;
+  }
+  goto done;
+
+exception1:
+  JS_FreeValue(ctx, val);
+exception:
+  JS_FreeValue(ctx, r);
+  r = JS_EXCEPTION;
+done:
+  js_free_prop_enum(ctx, atoms, len);
+  JS_FreeValue(ctx, obj);
+  return r;
+}
+
+
+/* return FALSE if not OK */
+BOOL check_define_prop_flags(int prop_flags, int flags)
+{
+  BOOL has_accessor, is_getset;
+
+  if (!(prop_flags & JS_PROP_CONFIGURABLE)) {
+    if ((flags & (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) ==
+        (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) {
+      return FALSE;
+    }
+    if ((flags & JS_PROP_HAS_ENUMERABLE) &&
+        (flags & JS_PROP_ENUMERABLE) != (prop_flags & JS_PROP_ENUMERABLE))
+      return FALSE;
+  }
+  if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE |
+               JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
+    if (!(prop_flags & JS_PROP_CONFIGURABLE)) {
+      has_accessor = ((flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) != 0);
+      is_getset = ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET);
+      if (has_accessor != is_getset)
+        return FALSE;
+      if (!has_accessor && !is_getset && !(prop_flags & JS_PROP_WRITABLE)) {
+        /* not writable: cannot set the writable bit */
+        if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
+            (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE))
+          return FALSE;
+      }
+    }
+  }
+  return TRUE;
+}
+
+void js_free_prop_enum(JSContext* ctx, JSPropertyEnum* tab, uint32_t len) {
+  uint32_t i;
+  if (tab) {
+    for (i = 0; i < len; i++)
+      JS_FreeAtom(ctx, tab[i].atom);
+    js_free(ctx, tab);
+  }
+}
+
+void js_free_desc(JSContext* ctx, JSPropertyDescriptor* desc) {
+  JS_FreeValue(ctx, desc->getter);
+  JS_FreeValue(ctx, desc->setter);
+  JS_FreeValue(ctx, desc->value);
+}
+
+__exception int JS_CopyDataProperties(JSContext* ctx, JSValueConst target, JSValueConst source, JSValueConst excluded, BOOL setprop) {
+  JSPropertyEnum* tab_atom;
+  JSValue val;
+  uint32_t i, tab_atom_count;
+  JSObject* p;
+  JSObject* pexcl = NULL;
+  int ret, gpn_flags;
+  JSPropertyDescriptor desc;
+  BOOL is_enumerable;
+
+  if (JS_VALUE_GET_TAG(source) != JS_TAG_OBJECT)
+    return 0;
+
+  if (JS_VALUE_GET_TAG(excluded) == JS_TAG_OBJECT)
+    pexcl = JS_VALUE_GET_OBJ(excluded);
+
+  p = JS_VALUE_GET_OBJ(source);
+
+  gpn_flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK | JS_GPN_ENUM_ONLY;
+  if (p->is_exotic) {
+    const JSClassExoticMethods* em = ctx->rt->class_array[p->class_id].exotic;
+    /* cannot use JS_GPN_ENUM_ONLY with e.g. proxies because it
+       introduces a visible change */
+    if (em && em->get_own_property_names) {
+      gpn_flags &= ~JS_GPN_ENUM_ONLY;
+    }
+  }
+  if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p, gpn_flags))
+    return -1;
+
+  for (i = 0; i < tab_atom_count; i++) {
+    if (pexcl) {
+      ret = JS_GetOwnPropertyInternal(ctx, NULL, pexcl, tab_atom[i].atom);
+      if (ret) {
+        if (ret < 0)
+          goto exception;
+        continue;
+      }
+    }
+    if (!(gpn_flags & JS_GPN_ENUM_ONLY)) {
+      /* test if the property is enumerable */
+      ret = JS_GetOwnPropertyInternal(ctx, &desc, p, tab_atom[i].atom);
+      if (ret < 0)
+        goto exception;
+      if (!ret)
+        continue;
+      is_enumerable = (desc.flags & JS_PROP_ENUMERABLE) != 0;
+      js_free_desc(ctx, &desc);
+      if (!is_enumerable)
+        continue;
+    }
+    val = JS_GetProperty(ctx, source, tab_atom[i].atom);
+    if (JS_IsException(val))
+      goto exception;
+    if (setprop)
+      ret = JS_SetProperty(ctx, target, tab_atom[i].atom, val);
+    else
+      ret = JS_DefinePropertyValue(ctx, target, tab_atom[i].atom, val, JS_PROP_C_W_E);
+    if (ret < 0)
+      goto exception;
+  }
+  js_free_prop_enum(ctx, tab_atom, tab_atom_count);
+  return 0;
+exception:
+  js_free_prop_enum(ctx, tab_atom, tab_atom_count);
+  return -1;
+}
+
+JSValue js_instantiate_prototype(JSContext* ctx, JSObject* p, JSAtom atom, void* opaque) {
+  JSValue obj, this_val;
+  int ret;
+
+  this_val = JS_MKPTR(JS_TAG_OBJECT, p);
+  obj = JS_NewObject(ctx);
+  if (JS_IsException(obj))
+    return JS_EXCEPTION;
+  set_cycle_flag(ctx, obj);
+  set_cycle_flag(ctx, this_val);
+  ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_constructor, JS_DupValue(ctx, this_val), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+  if (ret < 0) {
+    JS_FreeValue(ctx, obj);
+    return JS_EXCEPTION;
+  }
+  return obj;
+}
+
+JSValue js_create_from_ctor(JSContext* ctx, JSValueConst ctor, int class_id) {
+  JSValue proto, obj;
+  JSContext* realm;
+
+  if (JS_IsUndefined(ctor)) {
+    proto = JS_DupValue(ctx, ctx->class_proto[class_id]);
+  } else {
+    proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);
+    if (JS_IsException(proto))
+      return proto;
+    if (!JS_IsObject(proto)) {
+      JS_FreeValue(ctx, proto);
+      realm = JS_GetFunctionRealm(ctx, ctor);
+      if (!realm)
+        return JS_EXCEPTION;
+      proto = JS_DupValue(ctx, realm->class_proto[class_id]);
+    }
+  }
+  obj = JS_NewObjectProtoClass(ctx, proto, class_id);
+  JS_FreeValue(ctx, proto);
+  return obj;
+}
+
+/* return -1 if exception (Proxy object only) or TRUE/FALSE */
+int JS_IsExtensible(JSContext* ctx, JSValueConst obj) {
+  JSObject* p;
+
+  if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
+    return FALSE;
+  p = JS_VALUE_GET_OBJ(obj);
+  if (unlikely(p->class_id == JS_CLASS_PROXY))
+    return js_proxy_isExtensible(ctx, obj);
+  else
+    return p->extensible;
+}
+
+/* return -1 if exception (Proxy object only) or TRUE/FALSE */
+int JS_PreventExtensions(JSContext* ctx, JSValueConst obj) {
+  JSObject* p;
+
+  if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
+    return FALSE;
+  p = JS_VALUE_GET_OBJ(obj);
+  if (unlikely(p->class_id == JS_CLASS_PROXY))
+    return js_proxy_preventExtensions(ctx, obj);
+  p->extensible = FALSE;
+  return TRUE;
+}
+
+/* return -1 if exception otherwise TRUE or FALSE */
+int JS_HasProperty(JSContext* ctx, JSValueConst obj, JSAtom prop) {
+  JSObject* p;
+  int ret;
+  JSValue obj1;
+
+  if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
+    return FALSE;
+  p = JS_VALUE_GET_OBJ(obj);
+  for (;;) {
+    if (p->is_exotic) {
+      const JSClassExoticMethods* em = ctx->rt->class_array[p->class_id].exotic;
+      if (em && em->has_property) {
+        /* has_property can free the prototype */
+        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+        ret = em->has_property(ctx, obj1, prop);
+        JS_FreeValue(ctx, obj1);
+        return ret;
+      }
+    }
+    /* JS_GetOwnPropertyInternal can free the prototype */
+    JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+    ret = JS_GetOwnPropertyInternal(ctx, NULL, p, prop);
+    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+    if (ret != 0)
+      return ret;
+    if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
+      ret = JS_AtomIsNumericIndex(ctx, prop);
+      if (ret != 0) {
+        if (ret < 0)
+          return -1;
+        return FALSE;
+      }
+    }
+    p = p->shape->proto;
+    if (!p)
+      break;
+  }
+  return FALSE;
+}
+
+/* Private fields can be added even on non extensible objects or
+   Proxies */
+int JS_DefinePrivateField(JSContext* ctx, JSValueConst obj, JSValueConst name, JSValue val) {
+  JSObject* p;
+  JSShapeProperty* prs;
+  JSProperty* pr;
+  JSAtom prop;
+
+  if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
+    JS_ThrowTypeErrorNotAnObject(ctx);
+    goto fail;
+  }
+  /* safety check */
+  if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) {
+    JS_ThrowTypeErrorNotASymbol(ctx);
+    goto fail;
+  }
+  prop = js_symbol_to_atom(ctx, (JSValue)name);
+  p = JS_VALUE_GET_OBJ(obj);
+  prs = find_own_property(&pr, p, prop);
+  if (prs) {
+    JS_ThrowTypeErrorAtom(ctx, "private class field '%s' already exists", prop);
+    goto fail;
+  }
+  pr = add_property(ctx, p, prop, JS_PROP_C_W_E);
+  if (unlikely(!pr)) {
+  fail:
+    JS_FreeValue(ctx, val);
+    return -1;
+  }
+  pr->u.value = val;
+  return 0;
+}
+
+JSValue JS_GetPrivateField(JSContext* ctx, JSValueConst obj, JSValueConst name) {
+  JSObject* p;
+  JSShapeProperty* prs;
+  JSProperty* pr;
+  JSAtom prop;
+
+  if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+  /* safety check */
+  if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL))
+    return JS_ThrowTypeErrorNotASymbol(ctx);
+  prop = js_symbol_to_atom(ctx, (JSValue)name);
+  p = JS_VALUE_GET_OBJ(obj);
+  prs = find_own_property(&pr, p, prop);
+  if (!prs) {
+    JS_ThrowTypeErrorPrivateNotFound(ctx, prop);
+    return JS_EXCEPTION;
+  }
+  return JS_DupValue(ctx, pr->u.value);
+}
+
+int JS_SetPrivateField(JSContext* ctx, JSValueConst obj, JSValueConst name, JSValue val) {
+  JSObject* p;
+  JSShapeProperty* prs;
+  JSProperty* pr;
+  JSAtom prop;
+
+  if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
+    JS_ThrowTypeErrorNotAnObject(ctx);
+    goto fail;
+  }
+  /* safety check */
+  if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) {
+    JS_ThrowTypeErrorNotASymbol(ctx);
+    goto fail;
+  }
+  prop = js_symbol_to_atom(ctx, (JSValue)name);
+  p = JS_VALUE_GET_OBJ(obj);
+  prs = find_own_property(&pr, p, prop);
+  if (!prs) {
+    JS_ThrowTypeErrorPrivateNotFound(ctx, prop);
+  fail:
+    JS_FreeValue(ctx, val);
+    return -1;
+  }
+  set_value(ctx, &pr->u.value, val);
+  return 0;
+}
+
+int JS_AddBrand(JSContext* ctx, JSValueConst obj, JSValueConst home_obj) {
+  JSObject *p, *p1;
+  JSShapeProperty* prs;
+  JSProperty* pr;
+  JSValue brand;
+  JSAtom brand_atom;
+
+  if (unlikely(JS_VALUE_GET_TAG(home_obj) != JS_TAG_OBJECT)) {
+    JS_ThrowTypeErrorNotAnObject(ctx);
+    return -1;
+  }
+  p = JS_VALUE_GET_OBJ(home_obj);
+  prs = find_own_property(&pr, p, JS_ATOM_Private_brand);
+  if (!prs) {
+    brand = JS_NewSymbolFromAtom(ctx, JS_ATOM_brand, JS_ATOM_TYPE_PRIVATE);
+    if (JS_IsException(brand))
+      return -1;
+    /* if the brand is not present, add it */
+    pr = add_property(ctx, p, JS_ATOM_Private_brand, JS_PROP_C_W_E);
+    if (!pr) {
+      JS_FreeValue(ctx, brand);
+      return -1;
+    }
+    pr->u.value = JS_DupValue(ctx, brand);
+  } else {
+    brand = JS_DupValue(ctx, pr->u.value);
+  }
+  brand_atom = js_symbol_to_atom(ctx, brand);
+
+  if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
+    JS_ThrowTypeErrorNotAnObject(ctx);
+    JS_FreeAtom(ctx, brand_atom);
+    return -1;
+  }
+  p1 = JS_VALUE_GET_OBJ(obj);
+  pr = add_property(ctx, p1, brand_atom, JS_PROP_C_W_E);
+  JS_FreeAtom(ctx, brand_atom);
+  if (!pr)
+    return -1;
+  pr->u.value = JS_UNDEFINED;
+  return 0;
+}
+
+int JS_CheckBrand(JSContext* ctx, JSValueConst obj, JSValueConst func) {
+  JSObject *p, *p1, *home_obj;
+  JSShapeProperty* prs;
+  JSProperty* pr;
+  JSValueConst brand;
+
+  /* get the home object of 'func' */
+  if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)) {
+  not_obj:
+    JS_ThrowTypeErrorNotAnObject(ctx);
+    return -1;
+  }
+  p1 = JS_VALUE_GET_OBJ(func);
+  if (!js_class_has_bytecode(p1->class_id))
+    goto not_obj;
+  home_obj = p1->u.func.home_object;
+  if (!home_obj)
+    goto not_obj;
+  prs = find_own_property(&pr, home_obj, JS_ATOM_Private_brand);
+  if (!prs) {
+    JS_ThrowTypeError(ctx, "expecting <brand> private field");
+    return -1;
+  }
+  brand = pr->u.value;
+  /* safety check */
+  if (unlikely(JS_VALUE_GET_TAG(brand) != JS_TAG_SYMBOL))
+    goto not_obj;
+
+  /* get the brand array of 'obj' */
+  if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
+    goto not_obj;
+  p = JS_VALUE_GET_OBJ(obj);
+  prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, (JSValue)brand));
+  if (!prs) {
+    JS_ThrowTypeError(ctx, "invalid brand on object");
+    return -1;
+  }
+  return 0;
+}
+
+uint32_t js_string_obj_get_length(JSContext* ctx, JSValueConst obj) {
+  JSObject* p;
+  JSString* p1;
+  uint32_t len = 0;
+
+  /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
+  p = JS_VALUE_GET_OBJ(obj);
+  if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
+    p1 = JS_VALUE_GET_STRING(p->u.object_data);
+    len = p1->len;
+  }
+  return len;
+}
+
+
+static int num_keys_cmp(const void *p1, const void *p2, void *opaque)
+{
+  JSContext *ctx = opaque;
+  JSAtom atom1 = ((const JSPropertyEnum *)p1)->atom;
+  JSAtom atom2 = ((const JSPropertyEnum *)p2)->atom;
+  uint32_t v1, v2;
+  BOOL atom1_is_integer, atom2_is_integer;
+
+  atom1_is_integer = JS_AtomIsArrayIndex(ctx, &v1, atom1);
+  atom2_is_integer = JS_AtomIsArrayIndex(ctx, &v2, atom2);
+  assert(atom1_is_integer && atom2_is_integer);
+  if (v1 < v2)
+    return -1;
+  else if (v1 == v2)
+    return 0;
+  else
+    return 1;
+}
+
+
+/* return < 0 in case if exception, 0 if OK. ptab and its atoms must
+   be freed by the user. */
+int __exception JS_GetOwnPropertyNamesInternal(JSContext* ctx, JSPropertyEnum** ptab, uint32_t* plen, JSObject* p, int flags) {
+  int i, j;
+  JSShape* sh;
+  JSShapeProperty* prs;
+  JSPropertyEnum *tab_atom, *tab_exotic;
+  JSAtom atom;
+  uint32_t num_keys_count, str_keys_count, sym_keys_count, atom_count;
+  uint32_t num_index, str_index, sym_index, exotic_count, exotic_keys_count;
+  BOOL is_enumerable, num_sorted;
+  uint32_t num_key;
+  JSAtomKindEnum kind;
+
+  /* clear pointer for consistency in case of failure */
+  *ptab = NULL;
+  *plen = 0;
+
+  /* compute the number of returned properties */
+  num_keys_count = 0;
+  str_keys_count = 0;
+  sym_keys_count = 0;
+  exotic_keys_count = 0;
+  exotic_count = 0;
+  tab_exotic = NULL;
+  sh = p->shape;
+  for (i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
+    atom = prs->atom;
+    if (atom != JS_ATOM_NULL) {
+      is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0);
+      kind = JS_AtomGetKind(ctx, atom);
+      if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) && ((flags >> kind) & 1) != 0) {
+        /* need to raise an exception in case of the module
+           name space (implicit GetOwnProperty) */
+        if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) && (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY))) {
+          JSVarRef* var_ref = p->prop[i].u.var_ref;
+          if (unlikely(JS_IsUninitialized(*var_ref->pvalue))) {
+            JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
+            return -1;
+          }
+        }
+        if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
+          num_keys_count++;
+        } else if (kind == JS_ATOM_KIND_STRING) {
+          str_keys_count++;
+        } else {
+          sym_keys_count++;
+        }
+      }
+    }
+  }
+
+  if (p->is_exotic) {
+    if (p->fast_array) {
+      if (flags & JS_GPN_STRING_MASK) {
+        num_keys_count += p->u.array.count;
+      }
+    } else if (p->class_id == JS_CLASS_STRING) {
+      if (flags & JS_GPN_STRING_MASK) {
+        num_keys_count += js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+      }
+    } else {
+      const JSClassExoticMethods* em = ctx->rt->class_array[p->class_id].exotic;
+      if (em && em->get_own_property_names) {
+        if (em->get_own_property_names(ctx, &tab_exotic, &exotic_count, JS_MKPTR(JS_TAG_OBJECT, p)))
+          return -1;
+        for (i = 0; i < exotic_count; i++) {
+          atom = tab_exotic[i].atom;
+          kind = JS_AtomGetKind(ctx, atom);
+          if (((flags >> kind) & 1) != 0) {
+            is_enumerable = FALSE;
+            if (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY)) {
+              JSPropertyDescriptor desc;
+              int res;
+              /* set the "is_enumerable" field if necessary */
+              res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
+              if (res < 0) {
+                js_free_prop_enum(ctx, tab_exotic, exotic_count);
+                return -1;
+              }
+              if (res) {
+                is_enumerable = ((desc.flags & JS_PROP_ENUMERABLE) != 0);
+                js_free_desc(ctx, &desc);
+              }
+              tab_exotic[i].is_enumerable = is_enumerable;
+            }
+            if (!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) {
+              exotic_keys_count++;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  /* fill them */
+
+  atom_count = num_keys_count + str_keys_count + sym_keys_count + exotic_keys_count;
+  /* avoid allocating 0 bytes */
+  tab_atom = js_malloc(ctx, sizeof(tab_atom[0]) * max_int(atom_count, 1));
+  if (!tab_atom) {
+    js_free_prop_enum(ctx, tab_exotic, exotic_count);
+    return -1;
+  }
+
+  num_index = 0;
+  str_index = num_keys_count;
+  sym_index = str_index + str_keys_count;
+
+  num_sorted = TRUE;
+  sh = p->shape;
+  for (i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
+    atom = prs->atom;
+    if (atom != JS_ATOM_NULL) {
+      is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0);
+      kind = JS_AtomGetKind(ctx, atom);
+      if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) && ((flags >> kind) & 1) != 0) {
+        if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
+          j = num_index++;
+          num_sorted = FALSE;
+        } else if (kind == JS_ATOM_KIND_STRING) {
+          j = str_index++;
+        } else {
+          j = sym_index++;
+        }
+        tab_atom[j].atom = JS_DupAtom(ctx, atom);
+        tab_atom[j].is_enumerable = is_enumerable;
+      }
+    }
+  }
+
+  if (p->is_exotic) {
+    int len;
+    if (p->fast_array) {
+      if (flags & JS_GPN_STRING_MASK) {
+        len = p->u.array.count;
+        goto add_array_keys;
+      }
+    } else if (p->class_id == JS_CLASS_STRING) {
+      if (flags & JS_GPN_STRING_MASK) {
+        len = js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+      add_array_keys:
+        for (i = 0; i < len; i++) {
+          tab_atom[num_index].atom = __JS_AtomFromUInt32(i);
+          if (tab_atom[num_index].atom == JS_ATOM_NULL) {
+            js_free_prop_enum(ctx, tab_atom, num_index);
+            return -1;
+          }
+          tab_atom[num_index].is_enumerable = TRUE;
+          num_index++;
+        }
+      }
+    } else {
+      /* Note: exotic keys are not reordered and comes after the object own properties. */
+      for (i = 0; i < exotic_count; i++) {
+        atom = tab_exotic[i].atom;
+        is_enumerable = tab_exotic[i].is_enumerable;
+        kind = JS_AtomGetKind(ctx, atom);
+        if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) && ((flags >> kind) & 1) != 0) {
+          tab_atom[sym_index].atom = atom;
+          tab_atom[sym_index].is_enumerable = is_enumerable;
+          sym_index++;
+        } else {
+          JS_FreeAtom(ctx, atom);
+        }
+      }
+      js_free(ctx, tab_exotic);
+    }
+  }
+
+  assert(num_index == num_keys_count);
+  assert(str_index == num_keys_count + str_keys_count);
+  assert(sym_index == atom_count);
+
+  if (num_keys_count != 0 && !num_sorted) {
+    rqsort(tab_atom, num_keys_count, sizeof(tab_atom[0]), num_keys_cmp, ctx);
+  }
+  *ptab = tab_atom;
+  *plen = atom_count;
+  return 0;
+}
+
+int JS_GetOwnPropertyNames(JSContext* ctx, JSPropertyEnum** ptab, uint32_t* plen, JSValueConst obj, int flags) {
+  if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
+    JS_ThrowTypeErrorNotAnObject(ctx);
+    return -1;
+  }
+  return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen, JS_VALUE_GET_OBJ(obj), flags);
+}
+
+/* Return -1 if exception,
+   FALSE if the property does not exist, TRUE if it exists. If TRUE is
+   returned, the property descriptor 'desc' is filled present. */
+int JS_GetOwnPropertyInternal(JSContext* ctx, JSPropertyDescriptor* desc, JSObject* p, JSAtom prop) {
+  JSShapeProperty* prs;
+  JSProperty* pr;
+
+retry:
+  prs = find_own_property(&pr, p, prop);
+  if (prs) {
+    if (desc) {
+      desc->flags = prs->flags & JS_PROP_C_W_E;
+      desc->getter = JS_UNDEFINED;
+      desc->setter = JS_UNDEFINED;
+      desc->value = JS_UNDEFINED;
+      if (unlikely(prs->flags & JS_PROP_TMASK)) {
+        if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
+          desc->flags |= JS_PROP_GETSET;
+          if (pr->u.getset.getter)
+            desc->getter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
+          if (pr->u.getset.setter)
+            desc->setter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
+        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
+          JSValue val = *pr->u.var_ref->pvalue;
+          if (unlikely(JS_IsUninitialized(val))) {
+            JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
+            return -1;
+          }
+          desc->value = JS_DupValue(ctx, val);
+        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
+          /* Instantiate property and retry */
+          if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
+            return -1;
+          goto retry;
+        }
+      } else {
+        desc->value = JS_DupValue(ctx, pr->u.value);
+      }
+    } else {
+      /* for consistency, send the exception even if desc is NULL */
+      if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF)) {
+        if (unlikely(JS_IsUninitialized(*pr->u.var_ref->pvalue))) {
+          JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
+          return -1;
+        }
+      } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
+        /* nothing to do: delay instantiation until actual value and/or attributes are read */
+      }
+    }
+    return TRUE;
+  }
+  if (p->is_exotic) {
+    if (p->fast_array) {
+      /* specific case for fast arrays */
+      if (__JS_AtomIsTaggedInt(prop)) {
+        uint32_t idx;
+        idx = __JS_AtomToUInt32(prop);
+        if (idx < p->u.array.count) {
+          if (desc) {
+            desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE | JS_PROP_CONFIGURABLE;
+            desc->getter = JS_UNDEFINED;
+            desc->setter = JS_UNDEFINED;
+            desc->value = JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
+          }
+          return TRUE;
+        }
+      }
+    } else {
+      const JSClassExoticMethods* em = ctx->rt->class_array[p->class_id].exotic;
+      if (em && em->get_own_property) {
+        return em->get_own_property(ctx, desc, JS_MKPTR(JS_TAG_OBJECT, p), prop);
+      }
+    }
+  }
+  return FALSE;
+}
+
+int JS_GetOwnProperty(JSContext* ctx, JSPropertyDescriptor* desc, JSValueConst obj, JSAtom prop) {
+  if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
+    JS_ThrowTypeErrorNotAnObject(ctx);
+    return -1;
+  }
+  return JS_GetOwnPropertyInternal(ctx, desc, JS_VALUE_GET_OBJ(obj), prop);
+}
+
+/* allowed flags:
+   JS_PROP_CONFIGURABLE, JS_PROP_WRITABLE, JS_PROP_ENUMERABLE
+   JS_PROP_HAS_GET, JS_PROP_HAS_SET, JS_PROP_HAS_VALUE,
+   JS_PROP_HAS_CONFIGURABLE, JS_PROP_HAS_WRITABLE, JS_PROP_HAS_ENUMERABLE,
+   JS_PROP_THROW, JS_PROP_NO_EXOTIC.
+   If JS_PROP_THROW is set, return an exception instead of FALSE.
+   if JS_PROP_NO_EXOTIC is set, do not call the exotic
+   define_own_property callback.
+   return -1 (exception), FALSE or TRUE.
+*/
+int JS_DefineProperty(JSContext* ctx, JSValueConst this_obj, JSAtom prop, JSValueConst val, JSValueConst getter, JSValueConst setter, int flags) {
+  JSObject* p;
+  JSShapeProperty* prs;
+  JSProperty* pr;
+  int mask, res;
+
+  if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT) {
+    JS_ThrowTypeErrorNotAnObject(ctx);
+    return -1;
+  }
+  p = JS_VALUE_GET_OBJ(this_obj);
+
+redo_prop_update:
+  prs = find_own_property(&pr, p, prop);
+  if (prs) {
+    /* the range of the Array length property is always tested before */
+    if ((prs->flags & JS_PROP_LENGTH) && (flags & JS_PROP_HAS_VALUE)) {
+      uint32_t array_length;
+      if (JS_ToArrayLengthFree(ctx, &array_length, JS_DupValue(ctx, val), FALSE)) {
+        return -1;
+      }
+      /* this code relies on the fact that Uint32 are never allocated */
+      val = (JSValueConst)JS_NewUint32(ctx, array_length);
+      /* prs may have been modified */
+      prs = find_own_property(&pr, p, prop);
+      assert(prs != NULL);
+    }
+    /* property already exists */
+    if (!check_define_prop_flags(prs->flags, flags)) {
+    not_configurable:
+      return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
+    }
+
+    if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
+      /* Instantiate property and retry */
+      if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
+        return -1;
+      goto redo_prop_update;
+    }
+
+    if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
+      if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
+        JSObject *new_getter, *new_setter;
+
+        if (JS_IsFunction(ctx, getter)) {
+          new_getter = JS_VALUE_GET_OBJ(getter);
+        } else {
+          new_getter = NULL;
+        }
+        if (JS_IsFunction(ctx, setter)) {
+          new_setter = JS_VALUE_GET_OBJ(setter);
+        } else {
+          new_setter = NULL;
+        }
+
+        if ((prs->flags & JS_PROP_TMASK) != JS_PROP_GETSET) {
+          if (js_shape_prepare_update(ctx, p, &prs))
+            return -1;
+          /* convert to getset */
+          if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
+            free_var_ref(ctx->rt, pr->u.var_ref);
+          } else {
+            JS_FreeValue(ctx, pr->u.value);
+          }
+          prs->flags = (prs->flags & (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) | JS_PROP_GETSET;
+          pr->u.getset.getter = NULL;
+          pr->u.getset.setter = NULL;
+        } else {
+          if (!(prs->flags & JS_PROP_CONFIGURABLE)) {
+            if ((flags & JS_PROP_HAS_GET) && new_getter != pr->u.getset.getter) {
+              goto not_configurable;
+            }
+            if ((flags & JS_PROP_HAS_SET) && new_setter != pr->u.getset.setter) {
+              goto not_configurable;
+            }
+          }
+        }
+        if (flags & JS_PROP_HAS_GET) {
+          if (pr->u.getset.getter)
+            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
+          if (new_getter)
+            JS_DupValue(ctx, getter);
+          pr->u.getset.getter = new_getter;
+        }
+        if (flags & JS_PROP_HAS_SET) {
+          if (pr->u.getset.setter)
+            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
+          if (new_setter)
+            JS_DupValue(ctx, setter);
+          pr->u.getset.setter = new_setter;
+        }
+      } else {
+        if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
+          /* convert to data descriptor */
+          if (js_shape_prepare_update(ctx, p, &prs))
+            return -1;
+          if (pr->u.getset.getter)
+            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
+          if (pr->u.getset.setter)
+            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
+          prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
+          pr->u.value = JS_UNDEFINED;
+        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
+          /* Note: JS_PROP_VARREF is always writable */
+        } else {
+          if ((prs->flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 && (flags & JS_PROP_HAS_VALUE)) {
+            if (!js_same_value(ctx, val, pr->u.value)) {
+              goto not_configurable;
+            } else {
+              return TRUE;
+            }
+          }
+        }
+        if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
+          if (flags & JS_PROP_HAS_VALUE) {
+            if (p->class_id == JS_CLASS_MODULE_NS) {
+              /* JS_PROP_WRITABLE is always true for variable
+                 references, but they are write protected in module name
+                 spaces. */
+              if (!js_same_value(ctx, val, *pr->u.var_ref->pvalue))
+                goto not_configurable;
+            }
+            /* update the reference */
+            set_value(ctx, pr->u.var_ref->pvalue, JS_DupValue(ctx, val));
+          }
+          /* if writable is set to false, no longer a
+             reference (for mapped arguments) */
+          if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) {
+            JSValue val1;
+            if (js_shape_prepare_update(ctx, p, &prs))
+              return -1;
+            val1 = JS_DupValue(ctx, *pr->u.var_ref->pvalue);
+            free_var_ref(ctx->rt, pr->u.var_ref);
+            pr->u.value = val1;
+            prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
+          }
+        } else if (prs->flags & JS_PROP_LENGTH) {
+          if (flags & JS_PROP_HAS_VALUE) {
+            /* Note: no JS code is executable because
+               'val' is guaranted to be a Uint32 */
+            res = set_array_length(ctx, p, JS_DupValue(ctx, val), flags);
+          } else {
+            res = TRUE;
+          }
+          /* still need to reset the writable flag if
+             needed.  The JS_PROP_LENGTH is kept because the
+             Uint32 test is still done if the length
+             property is read-only. */
+          if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) {
+            prs = get_shape_prop(p->shape);
+            if (js_update_property_flags(ctx, p, &prs, prs->flags & ~JS_PROP_WRITABLE))
+              return -1;
+          }
+          return res;
+        } else {
+          if (flags & JS_PROP_HAS_VALUE) {
+            JS_FreeValue(ctx, pr->u.value);
+            pr->u.value = JS_DupValue(ctx, val);
+          }
+          if (flags & JS_PROP_HAS_WRITABLE) {
+            if (js_update_property_flags(ctx, p, &prs, (prs->flags & ~JS_PROP_WRITABLE) | (flags & JS_PROP_WRITABLE)))
+              return -1;
+          }
+        }
+      }
+    }
+    mask = 0;
+    if (flags & JS_PROP_HAS_CONFIGURABLE)
+      mask |= JS_PROP_CONFIGURABLE;
+    if (flags & JS_PROP_HAS_ENUMERABLE)
+      mask |= JS_PROP_ENUMERABLE;
+    if (js_update_property_flags(ctx, p, &prs, (prs->flags & ~mask) | (flags & mask)))
+      return -1;
+    return TRUE;
+  }
+
+  /* handle modification of fast array elements */
+  if (p->fast_array) {
+    uint32_t idx;
+    uint32_t prop_flags;
+    if (p->class_id == JS_CLASS_ARRAY) {
+      if (__JS_AtomIsTaggedInt(prop)) {
+        idx = __JS_AtomToUInt32(prop);
+        if (idx < p->u.array.count) {
+          prop_flags = get_prop_flags(flags, JS_PROP_C_W_E);
+          if (prop_flags != JS_PROP_C_W_E)
+            goto convert_to_slow_array;
+          if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
+          convert_to_slow_array:
+            if (convert_fast_array_to_array(ctx, p))
+              return -1;
+            else
+              goto redo_prop_update;
+          }
+          if (flags & JS_PROP_HAS_VALUE) {
+            set_value(ctx, &p->u.array.u.values[idx], JS_DupValue(ctx, val));
+          }
+          return TRUE;
+        }
+      }
+    } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
+      JSValue num;
+      int ret;
+
+      if (!__JS_AtomIsTaggedInt(prop)) {
+        /* slow path with to handle all numeric indexes */
+        num = JS_AtomIsNumericIndex1(ctx, prop);
+        if (JS_IsUndefined(num))
+          goto typed_array_done;
+        if (JS_IsException(num))
+          return -1;
+        ret = JS_NumberIsInteger(ctx, num);
+        if (ret < 0) {
+          JS_FreeValue(ctx, num);
+          return -1;
+        }
+        if (!ret) {
+          JS_FreeValue(ctx, num);
+          return JS_ThrowTypeErrorOrFalse(ctx, flags, "non integer index in typed array");
+        }
+        ret = JS_NumberIsNegativeOrMinusZero(ctx, num);
+        JS_FreeValue(ctx, num);
+        if (ret) {
+          return JS_ThrowTypeErrorOrFalse(ctx, flags, "negative index in typed array");
+        }
+        if (!__JS_AtomIsTaggedInt(prop))
+          goto typed_array_oob;
+      }
+      idx = __JS_AtomToUInt32(prop);
+      /* if the typed array is detached, p->u.array.count = 0 */
+      if (idx >= typed_array_get_length(ctx, p)) {
+      typed_array_oob:
+        return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound index in typed array");
+      }
+      prop_flags = get_prop_flags(flags, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+      if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET) || prop_flags != (JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE)) {
+        return JS_ThrowTypeErrorOrFalse(ctx, flags, "invalid descriptor flags");
+      }
+      if (flags & JS_PROP_HAS_VALUE) {
+        return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), JS_DupValue(ctx, val), flags);
+      }
+      return TRUE;
+    typed_array_done:;
+    }
+  }
+
+  return JS_CreateProperty(ctx, p, prop, val, getter, setter, flags);
+}
+
+int JS_DefineAutoInitProperty(JSContext* ctx, JSValueConst this_obj, JSAtom prop, JSAutoInitIDEnum id, void* opaque, int flags) {
+  JSObject* p;
+  JSProperty* pr;
+
+  if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT)
+    return FALSE;
+
+  p = JS_VALUE_GET_OBJ(this_obj);
+
+  if (find_own_property(&pr, p, prop)) {
+    /* property already exists */
+    abort();
+    return FALSE;
+  }
+
+  /* Specialized CreateProperty */
+  pr = add_property(ctx, p, prop, (flags & JS_PROP_C_W_E) | JS_PROP_AUTOINIT);
+  if (unlikely(!pr))
+    return -1;
+  pr->u.init.realm_and_id = (uintptr_t)JS_DupContext(ctx);
+  assert((pr->u.init.realm_and_id & 3) == 0);
+  assert(id <= 3);
+  pr->u.init.realm_and_id |= id;
+  pr->u.init.opaque = opaque;
+  return TRUE;
+}
+
+/* shortcut to add or redefine a new property value */
+int JS_DefinePropertyValue(JSContext* ctx, JSValueConst this_obj, JSAtom prop, JSValue val, int flags) {
+  int ret;
+  ret = JS_DefineProperty(ctx, this_obj, prop, val, JS_UNDEFINED, JS_UNDEFINED, flags | JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE);
+  JS_FreeValue(ctx, val);
+  return ret;
+}
+
+int JS_DefinePropertyValueValue(JSContext* ctx, JSValueConst this_obj, JSValue prop, JSValue val, int flags) {
+  JSAtom atom;
+  int ret;
+  atom = JS_ValueToAtom(ctx, prop);
+  JS_FreeValue(ctx, prop);
+  if (unlikely(atom == JS_ATOM_NULL)) {
+    JS_FreeValue(ctx, val);
+    return -1;
+  }
+  ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
+  JS_FreeAtom(ctx, atom);
+  return ret;
+}
+
+int JS_DefinePropertyValueUint32(JSContext* ctx, JSValueConst this_obj, uint32_t idx, JSValue val, int flags) {
+  return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewUint32(ctx, idx), val, flags);
+}
+
+int JS_DefinePropertyValueInt64(JSContext* ctx, JSValueConst this_obj, int64_t idx, JSValue val, int flags) {
+  return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx), val, flags);
+}
+
+int JS_DefinePropertyValueStr(JSContext* ctx, JSValueConst this_obj, const char* prop, JSValue val, int flags) {
+  JSAtom atom;
+  int ret;
+  atom = JS_NewAtom(ctx, prop);
+  ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
+  JS_FreeAtom(ctx, atom);
+  return ret;
+}
+
+/* shortcut to add getter & setter */
+int JS_DefinePropertyGetSet(JSContext* ctx, JSValueConst this_obj, JSAtom prop, JSValue getter, JSValue setter, int flags) {
+  int ret;
+  ret = JS_DefineProperty(ctx, this_obj, prop, JS_UNDEFINED, getter, setter, flags | JS_PROP_HAS_GET | JS_PROP_HAS_SET | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE);
+  JS_FreeValue(ctx, getter);
+  JS_FreeValue(ctx, setter);
+  return ret;
+}
+
+/* generic (and slower) version of JS_SetProperty() for
+ * Reflect.set(). 'obj' must be an object.  */
+int JS_SetPropertyGeneric(JSContext* ctx, JSValueConst obj, JSAtom prop, JSValue val, JSValueConst this_obj, int flags) {
+  int ret;
+  JSPropertyDescriptor desc;
+  JSValue obj1;
+  JSObject* p;
+
+  obj1 = JS_DupValue(ctx, obj);
+  for (;;) {
+    p = JS_VALUE_GET_OBJ(obj1);
+    if (p->is_exotic) {
+      const JSClassExoticMethods* em = ctx->rt->class_array[p->class_id].exotic;
+      if (em && em->set_property) {
+        ret = em->set_property(ctx, obj1, prop, val, this_obj, flags);
+        JS_FreeValue(ctx, obj1);
+        JS_FreeValue(ctx, val);
+        return ret;
+      }
+    }
+
+    ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
+    if (ret < 0) {
+      JS_FreeValue(ctx, obj1);
+      JS_FreeValue(ctx, val);
+      return ret;
+    }
+    if (ret) {
+      if (desc.flags & JS_PROP_GETSET) {
+        JSObject* setter;
+        if (JS_IsUndefined(desc.setter))
+          setter = NULL;
+        else
+          setter = JS_VALUE_GET_OBJ(desc.setter);
+        ret = call_setter(ctx, setter, this_obj, val, flags);
+        JS_FreeValue(ctx, desc.getter);
+        JS_FreeValue(ctx, desc.setter);
+        JS_FreeValue(ctx, obj1);
+        return ret;
+      } else {
+        JS_FreeValue(ctx, desc.value);
+        if (!(desc.flags & JS_PROP_WRITABLE)) {
+          JS_FreeValue(ctx, obj1);
+          goto read_only_error;
+        }
+      }
+      break;
+    }
+    /* Note: at this point 'obj1' cannot be a proxy. XXX: may have
+       to check recursion */
+    obj1 = JS_GetPrototypeFree(ctx, obj1);
+    if (JS_IsNull(obj1))
+      break;
+  }
+  JS_FreeValue(ctx, obj1);
+
+  if (!JS_IsObject(this_obj)) {
+    JS_FreeValue(ctx, val);
+    return JS_ThrowTypeErrorOrFalse(ctx, flags, "receiver is not an object");
+  }
+
+  p = JS_VALUE_GET_OBJ(this_obj);
+
+  /* modify the property in this_obj if it already exists */
+  ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
+  if (ret < 0) {
+    JS_FreeValue(ctx, val);
+    return ret;
+  }
+  if (ret) {
+    if (desc.flags & JS_PROP_GETSET) {
+      JS_FreeValue(ctx, desc.getter);
+      JS_FreeValue(ctx, desc.setter);
+      JS_FreeValue(ctx, val);
+      return JS_ThrowTypeErrorOrFalse(ctx, flags, "setter is forbidden");
+    } else {
+      JS_FreeValue(ctx, desc.value);
+      if (!(desc.flags & JS_PROP_WRITABLE) || p->class_id == JS_CLASS_MODULE_NS) {
+      read_only_error:
+        JS_FreeValue(ctx, val);
+        return JS_ThrowTypeErrorReadOnly(ctx, flags, prop);
+      }
+    }
+    ret = JS_DefineProperty(ctx, this_obj, prop, val, JS_UNDEFINED, JS_UNDEFINED, JS_PROP_HAS_VALUE);
+    JS_FreeValue(ctx, val);
+    return ret;
+  }
+
+  ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED, flags | JS_PROP_HAS_VALUE | JS_PROP_HAS_ENUMERABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_CONFIGURABLE | JS_PROP_C_W_E);
+  JS_FreeValue(ctx, val);
+  return ret;
+}
+
+/* return -1 in case of exception or TRUE or FALSE. Warning: 'val' is
+   freed by the function. 'flags' is a bitmask of JS_PROP_NO_ADD,
+   JS_PROP_THROW or JS_PROP_THROW_STRICT. If JS_PROP_NO_ADD is set,
+   the new property is not added and an error is raised. */
+int JS_SetPropertyInternal(JSContext* ctx, JSValueConst this_obj, JSAtom prop, JSValue val, int flags) {
+  JSObject *p, *p1;
+  JSShapeProperty* prs;
+  JSProperty* pr;
+  uint32_t tag;
+  JSPropertyDescriptor desc;
+  int ret;
+#if 0
+    printf("JS_SetPropertyInternal: "); print_atom(ctx, prop); printf("\n");
+#endif
+  tag = JS_VALUE_GET_TAG(this_obj);
+  if (unlikely(tag != JS_TAG_OBJECT)) {
+    switch (tag) {
+      case JS_TAG_NULL:
+        JS_FreeValue(ctx, val);
+        JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop);
+        return -1;
+      case JS_TAG_UNDEFINED:
+        JS_FreeValue(ctx, val);
+        JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop);
+        return -1;
+      default:
+        /* even on a primitive type we can have setters on the prototype */
+        p = NULL;
+        p1 = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, this_obj));
+        goto prototype_lookup;
+    }
+  }
+  p = JS_VALUE_GET_OBJ(this_obj);
+retry:
+  prs = find_own_property(&pr, p, prop);
+  if (prs) {
+    if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE | JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) {
+      /* fast case */
+      set_value(ctx, &pr->u.value, val);
+      return TRUE;
+    } else if (prs->flags & JS_PROP_LENGTH) {
+      assert(p->class_id == JS_CLASS_ARRAY);
+      assert(prop == JS_ATOM_length);
+      return set_array_length(ctx, p, val, flags);
+    } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
+      return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);
+    } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
+      /* JS_PROP_WRITABLE is always true for variable
+         references, but they are write protected in module name
+         spaces. */
+      if (p->class_id == JS_CLASS_MODULE_NS)
+        goto read_only_prop;
+      set_value(ctx, pr->u.var_ref->pvalue, val);
+      return TRUE;
+    } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
+      /* Instantiate property and retry (potentially useless) */
+      if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) {
+        JS_FreeValue(ctx, val);
+        return -1;
+      }
+      goto retry;
+    } else {
+      goto read_only_prop;
+    }
+  }
+
+  p1 = p;
+  for (;;) {
+    if (p1->is_exotic) {
+      if (p1->fast_array) {
+        if (__JS_AtomIsTaggedInt(prop)) {
+          uint32_t idx = __JS_AtomToUInt32(prop);
+          if (idx < p1->u.array.count) {
+            if (unlikely(p == p1))
+              return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val, flags);
+            else
+              break;
+          } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY && p1->class_id <= JS_CLASS_FLOAT64_ARRAY) {
+            goto typed_array_oob;
+          }
+        } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY && p1->class_id <= JS_CLASS_FLOAT64_ARRAY) {
+          ret = JS_AtomIsNumericIndex(ctx, prop);
+          if (ret != 0) {
+            if (ret < 0) {
+              JS_FreeValue(ctx, val);
+              return -1;
+            }
+          typed_array_oob:
+            val = JS_ToNumberFree(ctx, val);
+            JS_FreeValue(ctx, val);
+            if (JS_IsException(val))
+              return -1;
+            return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
+          }
+        }
+      } else {
+        const JSClassExoticMethods* em = ctx->rt->class_array[p1->class_id].exotic;
+        if (em) {
+          JSValue obj1;
+          if (em->set_property) {
+            /* set_property can free the prototype */
+            obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
+            ret = em->set_property(ctx, obj1, prop, val, this_obj, flags);
+            JS_FreeValue(ctx, obj1);
+            JS_FreeValue(ctx, val);
+            return ret;
+          }
+          if (em->get_own_property) {
+            /* get_own_property can free the prototype */
+            obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
+            ret = em->get_own_property(ctx, &desc, obj1, prop);
+            JS_FreeValue(ctx, obj1);
+            if (ret < 0) {
+              JS_FreeValue(ctx, val);
+              return ret;
+            }
+            if (ret) {
+              if (desc.flags & JS_PROP_GETSET) {
+                JSObject* setter;
+                if (JS_IsUndefined(desc.setter))
+                  setter = NULL;
+                else
+                  setter = JS_VALUE_GET_OBJ(desc.setter);
+                ret = call_setter(ctx, setter, this_obj, val, flags);
+                JS_FreeValue(ctx, desc.getter);
+                JS_FreeValue(ctx, desc.setter);
+                return ret;
+              } else {
+                JS_FreeValue(ctx, desc.value);
+                if (!(desc.flags & JS_PROP_WRITABLE))
+                  goto read_only_prop;
+                if (likely(p == p1)) {
+                  ret = JS_DefineProperty(ctx, this_obj, prop, val, JS_UNDEFINED, JS_UNDEFINED, JS_PROP_HAS_VALUE);
+                  JS_FreeValue(ctx, val);
+                  return ret;
+                } else {
+                  break;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    p1 = p1->shape->proto;
+  prototype_lookup:
+    if (!p1)
+      break;
+
+  retry2:
+    prs = find_own_property(&pr, p1, prop);
+    if (prs) {
+      if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
+        return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);
+      } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
+        /* Instantiate property and retry (potentially useless) */
+        if (JS_AutoInitProperty(ctx, p1, prop, pr, prs))
+          return -1;
+        goto retry2;
+      } else if (!(prs->flags & JS_PROP_WRITABLE)) {
+      read_only_prop:
+        JS_FreeValue(ctx, val);
+        return JS_ThrowTypeErrorReadOnly(ctx, flags, prop);
+      }
+    }
+  }
+
+  if (unlikely(flags & JS_PROP_NO_ADD)) {
+    JS_FreeValue(ctx, val);
+    JS_ThrowReferenceErrorNotDefined(ctx, prop);
+    return -1;
+  }
+
+  if (unlikely(!p)) {
+    JS_FreeValue(ctx, val);
+    return JS_ThrowTypeErrorOrFalse(ctx, flags, "not an object");
+  }
+
+  if (unlikely(!p->extensible)) {
+    JS_FreeValue(ctx, val);
+    return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible");
+  }
+
+  if (p->is_exotic) {
+    if (p->class_id == JS_CLASS_ARRAY && p->fast_array && __JS_AtomIsTaggedInt(prop)) {
+      uint32_t idx = __JS_AtomToUInt32(prop);
+      if (idx == p->u.array.count) {
+        /* fast case */
+        return add_fast_array_element(ctx, p, val, flags);
+      } else {
+        goto generic_create_prop;
+      }
+    } else {
+    generic_create_prop:
+      ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED, flags | JS_PROP_HAS_VALUE | JS_PROP_HAS_ENUMERABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_CONFIGURABLE | JS_PROP_C_W_E);
+      JS_FreeValue(ctx, val);
+      return ret;
+    }
+  }
+
+  pr = add_property(ctx, p, prop, JS_PROP_C_W_E);
+  if (unlikely(!pr)) {
+    JS_FreeValue(ctx, val);
+    return -1;
+  }
+  pr->u.value = val;
+  return TRUE;
+}
+
+/* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */
+int JS_SetPropertyValue(JSContext* ctx, JSValueConst this_obj, JSValue prop, JSValue val, int flags) {
+  if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT && JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {
+    JSObject* p;
+    uint32_t idx;
+    double d;
+    int32_t v;
+
+    /* fast path for array access */
+    p = JS_VALUE_GET_OBJ(this_obj);
+    idx = JS_VALUE_GET_INT(prop);
+    switch (p->class_id) {
+      case JS_CLASS_ARRAY:
+        if (unlikely(idx >= (uint32_t)p->u.array.count)) {
+          JSObject* p1;
+          JSShape* sh1;
+
+          /* fast path to add an element to the array */
+          if (idx != (uint32_t)p->u.array.count || !p->fast_array || !p->extensible)
+            goto slow_path;
+          /* check if prototype chain has a numeric property */
+          p1 = p->shape->proto;
+          while (p1 != NULL) {
+            sh1 = p1->shape;
+            if (p1->class_id == JS_CLASS_ARRAY) {
+              if (unlikely(!p1->fast_array))
+                goto slow_path;
+            } else if (p1->class_id == JS_CLASS_OBJECT) {
+              if (unlikely(sh1->has_small_array_index))
+                goto slow_path;
+            } else {
+              goto slow_path;
+            }
+            p1 = sh1->proto;
+          }
+          /* add element */
+          return add_fast_array_element(ctx, p, val, flags);
+        }
+        set_value(ctx, &p->u.array.u.values[idx], val);
+        break;
+      case JS_CLASS_ARGUMENTS:
+        if (unlikely(idx >= (uint32_t)p->u.array.count))
+          goto slow_path;
+        set_value(ctx, &p->u.array.u.values[idx], val);
+        break;
+      case JS_CLASS_UINT8C_ARRAY:
+        if (JS_ToUint8ClampFree(ctx, &v, val))
+          return -1;
+        /* Note: the conversion can detach the typed array, so the
+           array bound check must be done after */
+        if (unlikely(idx >= (uint32_t)p->u.array.count))
+          goto ta_out_of_bound;
+        p->u.array.u.uint8_ptr[idx] = v;
+        break;
+      case JS_CLASS_INT8_ARRAY:
+      case JS_CLASS_UINT8_ARRAY:
+        if (JS_ToInt32Free(ctx, &v, val))
+          return -1;
+        if (unlikely(idx >= (uint32_t)p->u.array.count))
+          goto ta_out_of_bound;
+        p->u.array.u.uint8_ptr[idx] = v;
+        break;
+      case JS_CLASS_INT16_ARRAY:
+      case JS_CLASS_UINT16_ARRAY:
+        if (JS_ToInt32Free(ctx, &v, val))
+          return -1;
+        if (unlikely(idx >= (uint32_t)p->u.array.count))
+          goto ta_out_of_bound;
+        p->u.array.u.uint16_ptr[idx] = v;
+        break;
+      case JS_CLASS_INT32_ARRAY:
+      case JS_CLASS_UINT32_ARRAY:
+        if (JS_ToInt32Free(ctx, &v, val))
+          return -1;
+        if (unlikely(idx >= (uint32_t)p->u.array.count))
+          goto ta_out_of_bound;
+        p->u.array.u.uint32_ptr[idx] = v;
+        break;
+#ifdef CONFIG_BIGNUM
+      case JS_CLASS_BIG_INT64_ARRAY:
+      case JS_CLASS_BIG_UINT64_ARRAY:
+        /* XXX: need specific conversion function */
+        {
+          int64_t v;
+          if (JS_ToBigInt64Free(ctx, &v, val))
+            return -1;
+          if (unlikely(idx >= (uint32_t)p->u.array.count))
+            goto ta_out_of_bound;
+          p->u.array.u.uint64_ptr[idx] = v;
+        }
+        break;
+#endif
+      case JS_CLASS_FLOAT32_ARRAY:
+        if (JS_ToFloat64Free(ctx, &d, val))
+          return -1;
+        if (unlikely(idx >= (uint32_t)p->u.array.count))
+          goto ta_out_of_bound;
+        p->u.array.u.float_ptr[idx] = d;
+        break;
+      case JS_CLASS_FLOAT64_ARRAY:
+        if (JS_ToFloat64Free(ctx, &d, val))
+          return -1;
+        if (unlikely(idx >= (uint32_t)p->u.array.count)) {
+        ta_out_of_bound:
+          return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
+        }
+        p->u.array.u.double_ptr[idx] = d;
+        break;
+      default:
+        goto slow_path;
+    }
+    return TRUE;
+  } else {
+    JSAtom atom;
+    int ret;
+  slow_path:
+    atom = JS_ValueToAtom(ctx, prop);
+    JS_FreeValue(ctx, prop);
+    if (unlikely(atom == JS_ATOM_NULL)) {
+      JS_FreeValue(ctx, val);
+      return -1;
+    }
+    ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, flags);
+    JS_FreeAtom(ctx, atom);
+    return ret;
+  }
+}
+
+int JS_SetPropertyUint32(JSContext* ctx, JSValueConst this_obj, uint32_t idx, JSValue val) {
+  return JS_SetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx), val, JS_PROP_THROW);
+}
+
+int JS_SetPropertyInt64(JSContext* ctx, JSValueConst this_obj, int64_t idx, JSValue val) {
+  JSAtom prop;
+  int res;
+
+  if ((uint64_t)idx <= INT32_MAX) {
+    /* fast path for fast arrays */
+    return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val, JS_PROP_THROW);
+  }
+  prop = JS_NewAtomInt64(ctx, idx);
+  if (prop == JS_ATOM_NULL) {
+    JS_FreeValue(ctx, val);
+    return -1;
+  }
+  res = JS_SetProperty(ctx, this_obj, prop, val);
+  JS_FreeAtom(ctx, prop);
+  return res;
+}
+
+int JS_SetPropertyStr(JSContext* ctx, JSValueConst this_obj, const char* prop, JSValue val) {
+  JSAtom atom;
+  int ret;
+  atom = JS_NewAtom(ctx, prop);
+  ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, JS_PROP_THROW);
+  JS_FreeAtom(ctx, atom);
+  return ret;
+}
+
+int JS_CreateDataPropertyUint32(JSContext* ctx, JSValueConst this_obj, int64_t idx, JSValue val, int flags) {
+  return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx), val, flags | JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE);
+}
+
+/* return TRUE if 'obj' has a non empty 'name' string */
+BOOL js_object_has_name(JSContext* ctx, JSValueConst obj) {
+  JSProperty* pr;
+  JSShapeProperty* prs;
+  JSValueConst val;
+  JSString* p;
+
+  prs = find_own_property(&pr, JS_VALUE_GET_OBJ(obj), JS_ATOM_name);
+  if (!prs)
+    return FALSE;
+  if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
+    return TRUE;
+  val = pr->u.value;
+  if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
+    return TRUE;
+  p = JS_VALUE_GET_STRING(val);
+  return (p->len != 0);
+}
+
+int JS_DefineObjectName(JSContext* ctx, JSValueConst obj, JSAtom name, int flags) {
+  if (name != JS_ATOM_NULL && JS_IsObject(obj) && !js_object_has_name(ctx, obj) && JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, JS_AtomToString(ctx, name), flags) < 0) {
+    return -1;
+  }
+  return 0;
+}
+
+int JS_DefineObjectNameComputed(JSContext* ctx, JSValueConst obj, JSValueConst str, int flags) {
+  if (JS_IsObject(obj) && !js_object_has_name(ctx, obj)) {
+    JSAtom prop;
+    JSValue name_str;
+    prop = JS_ValueToAtom(ctx, str);
+    if (prop == JS_ATOM_NULL)
+      return -1;
+    name_str = js_get_function_name(ctx, prop);
+    JS_FreeAtom(ctx, prop);
+    if (JS_IsException(name_str))
+      return -1;
+    if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, name_str, flags) < 0)
+      return -1;
+  }
+  return 0;
+}
+
+#if 0
+static JSValue JS_GetObjectData(JSContext *ctx, JSValueConst obj)
+{
+    JSObject *p;
+
+    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
+        p = JS_VALUE_GET_OBJ(obj);
+        switch(p->class_id) {
+        case JS_CLASS_NUMBER:
+        case JS_CLASS_STRING:
+        case JS_CLASS_BOOLEAN:
+        case JS_CLASS_SYMBOL:
+        case JS_CLASS_DATE:
+#ifdef CONFIG_BIGNUM
+        case JS_CLASS_BIG_INT:
+        case JS_CLASS_BIG_FLOAT:
+        case JS_CLASS_BIG_DECIMAL:
+#endif
+            return JS_DupValue(ctx, p->u.object_data);
+        }
+    }
+    return JS_UNDEFINED;
+}
+#endif
+
+int JS_SetObjectData(JSContext* ctx, JSValueConst obj, JSValue val) {
+  JSObject* p;
+
+  if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
+    p = JS_VALUE_GET_OBJ(obj);
+    switch (p->class_id) {
+      case JS_CLASS_NUMBER:
+      case JS_CLASS_STRING:
+      case JS_CLASS_BOOLEAN:
+      case JS_CLASS_SYMBOL:
+      case JS_CLASS_DATE:
+#ifdef CONFIG_BIGNUM
+      case JS_CLASS_BIG_INT:
+      case JS_CLASS_BIG_FLOAT:
+      case JS_CLASS_BIG_DECIMAL:
+#endif
+        JS_FreeValue(ctx, p->u.object_data);
+        p->u.object_data = val;
+        return 0;
+    }
+  }
+  JS_FreeValue(ctx, val);
+  if (!JS_IsException(obj))
+    JS_ThrowTypeError(ctx, "invalid object type");
+  return -1;
+}
+
+JSValue JS_NewObjectClass(JSContext* ctx, int class_id) {
+  return JS_NewObjectProtoClass(ctx, ctx->class_proto[class_id], class_id);
+}
+
+JSValue JS_NewObjectProto(JSContext* ctx, JSValueConst proto) {
+  return JS_NewObjectProtoClass(ctx, proto, JS_CLASS_OBJECT);
+}
+
+JSValue JS_NewObject(JSContext* ctx) {
+  /* inline JS_NewObjectClass(ctx, JS_CLASS_OBJECT); */
+  return JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_OBJECT);
+}
\ No newline at end of file
diff --git a/src/core/object.h b/src/core/object.h
new file mode 100644
index 000000000..45ce183bb
--- /dev/null
+++ b/src/core/object.h
@@ -0,0 +1,170 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_OBJECT_H
+#define QUICKJS_OBJECT_H
+
+#include "quickjs/cutils.h"
+#include "quickjs/quickjs.h"
+#include "shape.h"
+#include "types.h"
+
+JSValue JS_GetPropertyValue(JSContext* ctx, JSValueConst this_obj, JSValue prop);
+
+/* Check if an object has a generalized numeric property. Return value:
+   -1 for exception,
+   TRUE if property exists, stored into *pval,
+   FALSE if proprty does not exist.
+ */
+int JS_TryGetPropertyInt64(JSContext* ctx, JSValueConst obj, int64_t idx, JSValue* pval);
+JSValue JS_GetPropertyInt64(JSContext* ctx, JSValueConst obj, int64_t idx);
+
+/* can be called on Array or Arguments objects. return < 0 if
+   memory alloc error. */
+no_inline __exception int convert_fast_array_to_array(JSContext* ctx, JSObject* p);
+
+int delete_property(JSContext* ctx, JSObject* p, JSAtom atom);
+int call_setter(JSContext* ctx, JSObject* setter, JSValueConst this_obj, JSValue val, int flags);
+void free_property(JSRuntime* rt, JSProperty* pr, int prop_flags);
+JSProperty* add_property(JSContext* ctx, JSObject* p, JSAtom prop, int prop_flags);
+
+static force_inline JSShapeProperty* find_own_property1(JSObject* p, JSAtom atom) {
+  JSShape* sh;
+  JSShapeProperty *pr, *prop;
+  intptr_t h;
+  sh = p->shape;
+  h = (uintptr_t)atom & sh->prop_hash_mask;
+  h = prop_hash_end(sh)[-h - 1];
+  prop = get_shape_prop(sh);
+  while (h) {
+    pr = &prop[h - 1];
+    if (likely(pr->atom == atom)) {
+      return pr;
+    }
+    h = pr->hash_next;
+  }
+  return NULL;
+};
+static force_inline JSShapeProperty* find_own_property(JSProperty** ppr, JSObject* p, JSAtom atom) {
+  JSShape* sh;
+  JSShapeProperty *pr, *prop;
+  intptr_t h;
+  sh = p->shape;
+  h = (uintptr_t)atom & sh->prop_hash_mask;
+  h = prop_hash_end(sh)[-h - 1];
+  prop = get_shape_prop(sh);
+  while (h) {
+    pr = &prop[h - 1];
+    if (likely(pr->atom == atom)) {
+      *ppr = &p->prop[h - 1];
+      /* the compiler should be able to assume that pr != NULL here */
+      return pr;
+    }
+    h = pr->hash_next;
+  }
+  *ppr = NULL;
+  return NULL;
+};
+
+/* return FALSE if not OK */
+BOOL check_define_prop_flags(int prop_flags, int flags);;
+void js_free_prop_enum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len);
+void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc);;
+
+JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
+JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor,
+                                   int class_id);
+
+__exception int JS_CopyDataProperties(JSContext *ctx,
+                                             JSValueConst target,
+                                             JSValueConst source,
+                                             JSValueConst excluded,
+                                             BOOL setprop);
+
+int JS_DefinePropertyValueValue(JSContext* ctx, JSValueConst this_obj, JSValue prop, JSValue val, int flags);
+int JS_DefinePropertyValueInt64(JSContext* ctx, JSValueConst this_obj, int64_t idx, JSValue val, int flags);
+int JS_SetPropertyGeneric(JSContext* ctx, JSValueConst obj, JSAtom prop, JSValue val, JSValueConst this_obj, int flags);
+/* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */
+int JS_SetPropertyValue(JSContext* ctx, JSValueConst this_obj, JSValue prop, JSValue val, int flags);
+
+/* return -1 if exception (Proxy object only) or TRUE/FALSE */
+int JS_IsExtensible(JSContext *ctx, JSValueConst obj);
+
+/* return -1 if exception (Proxy object only) or TRUE/FALSE */
+int JS_PreventExtensions(JSContext *ctx, JSValueConst obj);
+
+JSValue JS_GetOwnPropertyNames2(JSContext* ctx, JSValueConst obj1, int flags, int kind);
+/* return -1 if exception otherwise TRUE or FALSE */
+int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop);
+
+/* Private fields can be added even on non extensible objects or
+   Proxies */
+int JS_DefinePrivateField(JSContext *ctx, JSValueConst obj,
+                                 JSValueConst name, JSValue val);
+
+JSValue JS_GetPrivateField(JSContext *ctx, JSValueConst obj,
+                                  JSValueConst name);
+
+int JS_SetPrivateField(JSContext *ctx, JSValueConst obj,
+                              JSValueConst name, JSValue val);
+
+int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj);
+int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func);
+
+uint32_t js_string_obj_get_length(JSContext *ctx,
+                                         JSValueConst obj);
+
+/* return < 0 in case if exception, 0 if OK. ptab and its atoms must
+   be freed by the user. */
+int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
+                                                      JSPropertyEnum **ptab,
+                                                      uint32_t *plen,
+                                                      JSObject *p, int flags);
+/* Return -1 if exception,
+   FALSE if the property does not exist, TRUE if it exists. If TRUE is
+   returned, the property descriptor 'desc' is filled present. */
+int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc,
+                                     JSObject *p, JSAtom prop);
+
+int JS_CreateDataPropertyUint32(JSContext* ctx, JSValueConst this_obj, int64_t idx, JSValue val, int flags);
+
+int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc,
+                      JSValueConst obj, JSAtom prop);
+
+int JS_DefineAutoInitProperty(JSContext* ctx,
+                                     JSValueConst this_obj,
+                                     JSAtom prop,
+                                     JSAutoInitIDEnum id,
+                                     void* opaque,
+                                     int flags);
+
+/* return TRUE if 'obj' has a non empty 'name' string */
+BOOL js_object_has_name(JSContext* ctx, JSValueConst obj);
+int JS_DefineObjectName(JSContext* ctx, JSValueConst obj, JSAtom name, int flags);
+int JS_DefineObjectNameComputed(JSContext* ctx, JSValueConst obj, JSValueConst str, int flags);
+
+int JS_SetObjectData(JSContext *ctx, JSValueConst obj, JSValue val);
+
+#endif
\ No newline at end of file
diff --git a/src/core/parser.c b/src/core/parser.c
new file mode 100644
index 000000000..dbed59004
--- /dev/null
+++ b/src/core/parser.c
@@ -0,0 +1,12208 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#include "parser.h"
+#include "builtins/js-function.h"
+#include "convertion.h"
+#include "exception.h"
+#include "function.h"
+#include "bytecode.h"
+#include "gc.h"
+#include "malloc.h"
+#include "module.h"
+#include "object.h"
+#include "quickjs/libregexp.h"
+#include "runtime.h"
+#include "string.h"
+
+static __exception int next_token(JSParseState *s);
+
+void free_token(JSParseState *s, JSToken *token)
+{
+  switch(token->val) {
+#ifdef CONFIG_BIGNUM
+    case TOK_NUMBER:
+      JS_FreeValue(s->ctx, token->u.num.val);
+      break;
+#endif
+    case TOK_STRING:
+    case TOK_TEMPLATE:
+      JS_FreeValue(s->ctx, token->u.str.str);
+      break;
+    case TOK_REGEXP:
+      JS_FreeValue(s->ctx, token->u.regexp.body);
+      JS_FreeValue(s->ctx, token->u.regexp.flags);
+      break;
+    case TOK_IDENT:
+    case TOK_PRIVATE_NAME:
+      JS_FreeAtom(s->ctx, token->u.ident.atom);
+      break;
+    default:
+      if (token->val >= TOK_FIRST_KEYWORD &&
+          token->val <= TOK_LAST_KEYWORD) {
+        JS_FreeAtom(s->ctx, token->u.ident.atom);
+      }
+      break;
+  }
+}
+
+static void __attribute((unused)) dump_token(JSParseState *s,
+                                             const JSToken *token)
+{
+  switch(token->val) {
+    case TOK_NUMBER:
+    {
+      double d;
+      JS_ToFloat64(s->ctx, &d, token->u.num.val);  /* no exception possible */
+      printf("number: %.14g\n", d);
+    }
+    break;
+    case TOK_IDENT:
+    dump_atom:
+    {
+      char buf[ATOM_GET_STR_BUF_SIZE];
+      printf("ident: '%s'\n",
+             JS_AtomGetStr(s->ctx, buf, sizeof(buf), token->u.ident.atom));
+    }
+    break;
+    case TOK_STRING:
+    {
+      const char *str;
+      /* XXX: quote the string */
+      str = JS_ToCString(s->ctx, token->u.str.str);
+      printf("string: '%s'\n", str);
+      JS_FreeCString(s->ctx, str);
+    }
+    break;
+    case TOK_TEMPLATE:
+    {
+      const char *str;
+      str = JS_ToCString(s->ctx, token->u.str.str);
+      printf("template: `%s`\n", str);
+      JS_FreeCString(s->ctx, str);
+    }
+    break;
+    case TOK_REGEXP:
+    {
+      const char *str, *str2;
+      str = JS_ToCString(s->ctx, token->u.regexp.body);
+      str2 = JS_ToCString(s->ctx, token->u.regexp.flags);
+      printf("regexp: '%s' '%s'\n", str, str2);
+      JS_FreeCString(s->ctx, str);
+      JS_FreeCString(s->ctx, str2);
+    }
+    break;
+    case TOK_EOF:
+      printf("eof\n");
+      break;
+    default:
+      if (s->token.val >= TOK_NULL && s->token.val <= TOK_LAST_KEYWORD) {
+        goto dump_atom;
+      } else if (s->token.val >= 256) {
+        printf("token: %d\n", token->val);
+      } else {
+        printf("token: '%c'\n", token->val);
+      }
+      break;
+  }
+}
+
+int __attribute__((format(printf, 2, 3))) js_parse_error(JSParseState *s, const char *fmt, ...)
+{
+  JSContext *ctx = s->ctx;
+  va_list ap;
+  int backtrace_flags;
+
+  va_start(ap, fmt);
+  JS_ThrowError2(ctx, JS_SYNTAX_ERROR, fmt, ap, FALSE);
+  va_end(ap);
+  backtrace_flags = 0;
+  if (s->cur_func && s->cur_func->backtrace_barrier)
+    backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL;
+  build_backtrace(ctx, ctx->rt->current_exception, s->filename, s->line_num,
+                  backtrace_flags);
+  return -1;
+}
+
+static int js_parse_expect(JSParseState *s, int tok)
+{
+  if (s->token.val != tok) {
+    /* XXX: dump token correctly in all cases */
+    return js_parse_error(s, "expecting '%c'", tok);
+  }
+  return next_token(s);
+}
+
+static int js_parse_expect_semi(JSParseState *s)
+{
+  if (s->token.val != ';') {
+    /* automatic insertion of ';' */
+    if (s->token.val == TOK_EOF || s->token.val == '}' || s->got_lf) {
+      return 0;
+    }
+    return js_parse_error(s, "expecting '%c'", ';');
+  }
+  return next_token(s);
+}
+
+static int js_parse_error_reserved_identifier(JSParseState *s)
+{
+  char buf1[ATOM_GET_STR_BUF_SIZE];
+  return js_parse_error(s, "'%s' is a reserved identifier",
+                        JS_AtomGetStr(s->ctx, buf1, sizeof(buf1),
+                                      s->token.u.ident.atom));
+}
+
+static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p)
+{
+  uint32_t c;
+  StringBuffer b_s, *b = &b_s;
+
+  /* p points to the first byte of the template part */
+  if (string_buffer_init(s->ctx, b, 32))
+    goto fail;
+  for(;;) {
+    if (p >= s->buf_end)
+      goto unexpected_eof;
+    c = *p++;
+    if (c == '`') {
+      /* template end part */
+      break;
+    }
+    if (c == '$' && *p == '{') {
+      /* template start or middle part */
+      p++;
+      break;
+    }
+    if (c == '\\') {
+      if (string_buffer_putc8(b, c))
+        goto fail;
+      if (p >= s->buf_end)
+        goto unexpected_eof;
+      c = *p++;
+    }
+    /* newline sequences are normalized as single '\n' bytes */
+    if (c == '\r') {
+      if (*p == '\n')
+        p++;
+      c = '\n';
+    }
+    if (c == '\n') {
+      s->line_num++;
+    } else if (c >= 0x80) {
+      const uint8_t *p_next;
+      c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
+      if (c > 0x10FFFF) {
+        js_parse_error(s, "invalid UTF-8 sequence");
+        goto fail;
+      }
+      p = p_next;
+    }
+    if (string_buffer_putc(b, c))
+      goto fail;
+  }
+  s->token.val = TOK_TEMPLATE;
+  s->token.u.str.sep = c;
+  s->token.u.str.str = string_buffer_end(b);
+  s->buf_ptr = p;
+  return 0;
+
+unexpected_eof:
+  js_parse_error(s, "unexpected end of string");
+fail:
+  string_buffer_free(b);
+  return -1;
+}
+
+static __exception int js_parse_string(JSParseState *s, int sep,
+                                       BOOL do_throw, const uint8_t *p,
+                                       JSToken *token, const uint8_t **pp)
+{
+  int ret;
+  uint32_t c;
+  StringBuffer b_s, *b = &b_s;
+
+  /* string */
+  if (string_buffer_init(s->ctx, b, 32))
+    goto fail;
+  for(;;) {
+    if (p >= s->buf_end)
+      goto invalid_char;
+    c = *p;
+    if (c < 0x20) {
+      if (!s->cur_func) {
+        if (do_throw)
+          js_parse_error(s, "invalid character in a JSON string");
+        goto fail;
+      }
+      if (sep == '`') {
+        if (c == '\r') {
+          if (p[1] == '\n')
+            p++;
+          c = '\n';
+        }
+        /* do not update s->line_num */
+      } else if (c == '\n' || c == '\r')
+        goto invalid_char;
+    }
+    p++;
+    if (c == sep)
+      break;
+    if (c == '$' && *p == '{' && sep == '`') {
+      /* template start or middle part */
+      p++;
+      break;
+    }
+    if (c == '\\') {
+      c = *p;
+      /* XXX: need a specific JSON case to avoid
+         accepting invalid escapes */
+      switch(c) {
+        case '\0':
+          if (p >= s->buf_end)
+            goto invalid_char;
+          p++;
+          break;
+        case '\'':
+        case '\"':
+        case '\\':
+          p++;
+          break;
+        case '\r':  /* accept DOS and MAC newline sequences */
+          if (p[1] == '\n') {
+            p++;
+          }
+          /* fall thru */
+        case '\n':
+          /* ignore escaped newline sequence */
+          p++;
+          if (sep != '`')
+            s->line_num++;
+          continue;
+        default:
+          if (c >= '0' && c <= '9') {
+            if (!s->cur_func)
+              goto invalid_escape; /* JSON case */
+            if (!(s->cur_func->js_mode & JS_MODE_STRICT) && sep != '`')
+              goto parse_escape;
+            if (c == '0' && !(p[1] >= '0' && p[1] <= '9')) {
+              p++;
+              c = '\0';
+            } else {
+              if (c >= '8' || sep == '`') {
+                /* Note: according to ES2021, \8 and \9 are not
+                   accepted in strict mode or in templates. */
+                goto invalid_escape;
+              } else {
+                if (do_throw)
+                  js_parse_error(s, "octal escape sequences are not allowed in strict mode");
+              }
+              goto fail;
+            }
+          } else if (c >= 0x80) {
+            const uint8_t *p_next;
+            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
+            if (c > 0x10FFFF) {
+              goto invalid_utf8;
+            }
+            p = p_next;
+            /* LS or PS are skipped */
+            if (c == CP_LS || c == CP_PS)
+              continue;
+          } else {
+          parse_escape:
+            ret = lre_parse_escape(&p, TRUE);
+            if (ret == -1) {
+            invalid_escape:
+              if (do_throw)
+                js_parse_error(s, "malformed escape sequence in string literal");
+              goto fail;
+            } else if (ret < 0) {
+              /* ignore the '\' (could output a warning) */
+              p++;
+            } else {
+              c = ret;
+            }
+          }
+          break;
+      }
+    } else if (c >= 0x80) {
+      const uint8_t *p_next;
+      c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
+      if (c > 0x10FFFF)
+        goto invalid_utf8;
+      p = p_next;
+    }
+    if (string_buffer_putc(b, c))
+      goto fail;
+  }
+  token->val = TOK_STRING;
+  token->u.str.sep = c;
+  token->u.str.str = string_buffer_end(b);
+  *pp = p;
+  return 0;
+
+invalid_utf8:
+  if (do_throw)
+    js_parse_error(s, "invalid UTF-8 sequence");
+  goto fail;
+invalid_char:
+  if (do_throw)
+    js_parse_error(s, "unexpected end of string");
+fail:
+  string_buffer_free(b);
+  return -1;
+}
+
+static inline BOOL token_is_pseudo_keyword(JSParseState *s, JSAtom atom) {
+  return s->token.val == TOK_IDENT && s->token.u.ident.atom == atom &&
+         !s->token.u.ident.has_escape;
+}
+
+static __exception int js_parse_regexp(JSParseState *s)
+{
+  const uint8_t *p;
+  BOOL in_class;
+  StringBuffer b_s, *b = &b_s;
+  StringBuffer b2_s, *b2 = &b2_s;
+  uint32_t c;
+
+  p = s->buf_ptr;
+  p++;
+  in_class = FALSE;
+  if (string_buffer_init(s->ctx, b, 32))
+    return -1;
+  if (string_buffer_init(s->ctx, b2, 1))
+    goto fail;
+  for(;;) {
+    if (p >= s->buf_end) {
+    eof_error:
+      js_parse_error(s, "unexpected end of regexp");
+      goto fail;
+    }
+    c = *p++;
+    if (c == '\n' || c == '\r') {
+      goto eol_error;
+    } else if (c == '/') {
+      if (!in_class)
+        break;
+    } else if (c == '[') {
+      in_class = TRUE;
+    } else if (c == ']') {
+      /* XXX: incorrect as the first character in a class */
+      in_class = FALSE;
+    } else if (c == '\\') {
+      if (string_buffer_putc8(b, c))
+        goto fail;
+      c = *p++;
+      if (c == '\n' || c == '\r')
+        goto eol_error;
+      else if (c == '\0' && p >= s->buf_end)
+        goto eof_error;
+      else if (c >= 0x80) {
+        const uint8_t *p_next;
+        c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
+        if (c > 0x10FFFF) {
+          goto invalid_utf8;
+        }
+        p = p_next;
+        if (c == CP_LS || c == CP_PS)
+          goto eol_error;
+      }
+    } else if (c >= 0x80) {
+      const uint8_t *p_next;
+      c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
+      if (c > 0x10FFFF) {
+      invalid_utf8:
+        js_parse_error(s, "invalid UTF-8 sequence");
+        goto fail;
+      }
+      p = p_next;
+      /* LS or PS are considered as line terminator */
+      if (c == CP_LS || c == CP_PS) {
+      eol_error:
+        js_parse_error(s, "unexpected line terminator in regexp");
+        goto fail;
+      }
+    }
+    if (string_buffer_putc(b, c))
+      goto fail;
+  }
+
+  /* flags */
+  for(;;) {
+    const uint8_t *p_next = p;
+    c = *p_next++;
+    if (c >= 0x80) {
+      c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
+      if (c > 0x10FFFF) {
+        goto invalid_utf8;
+      }
+    }
+    if (!lre_js_is_ident_next(c))
+      break;
+    if (string_buffer_putc(b2, c))
+      goto fail;
+    p = p_next;
+  }
+
+  s->token.val = TOK_REGEXP;
+  s->token.u.regexp.body = string_buffer_end(b);
+  s->token.u.regexp.flags = string_buffer_end(b2);
+  s->buf_ptr = p;
+  return 0;
+fail:
+  string_buffer_free(b);
+  string_buffer_free(b2);
+  return -1;
+}
+
+static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize,
+                                     char *static_buf)
+{
+  char *buf, *new_buf;
+  size_t size, new_size;
+
+  buf = *pbuf;
+  size = *psize;
+  if (size >= (SIZE_MAX / 3) * 2)
+    new_size = SIZE_MAX;
+  else
+    new_size = size + (size >> 1);
+  if (buf == static_buf) {
+    new_buf = js_malloc(ctx, new_size);
+    if (!new_buf)
+      return -1;
+    memcpy(new_buf, buf, size);
+  } else {
+    new_buf = js_realloc(ctx, buf, new_size);
+    if (!new_buf)
+      return -1;
+  }
+  *pbuf = new_buf;
+  *psize = new_size;
+  return 0;
+}
+
+/* 'c' is the first character. Return JS_ATOM_NULL in case of error */
+static JSAtom parse_ident(JSParseState *s, const uint8_t **pp,
+                          BOOL *pident_has_escape, int c, BOOL is_private)
+{
+  const uint8_t *p, *p1;
+  char ident_buf[128], *buf;
+  size_t ident_size, ident_pos;
+  JSAtom atom;
+
+  p = *pp;
+  buf = ident_buf;
+  ident_size = sizeof(ident_buf);
+  ident_pos = 0;
+  if (is_private)
+    buf[ident_pos++] = '#';
+  for(;;) {
+    p1 = p;
+
+    if (c < 128) {
+      buf[ident_pos++] = c;
+    } else {
+      ident_pos += unicode_to_utf8((uint8_t*)buf + ident_pos, c);
+    }
+    c = *p1++;
+    if (c == '\\' && *p1 == 'u') {
+      c = lre_parse_escape(&p1, TRUE);
+      *pident_has_escape = TRUE;
+    } else if (c >= 128) {
+      c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
+    }
+    if (!lre_js_is_ident_next(c))
+      break;
+    p = p1;
+    if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
+      if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) {
+        atom = JS_ATOM_NULL;
+        goto done;
+      }
+    }
+  }
+  atom = JS_NewAtomLen(s->ctx, buf, ident_pos);
+done:
+  if (unlikely(buf != ident_buf))
+    js_free(s->ctx, buf);
+  *pp = p;
+  return atom;
+}
+
+
+static __exception int next_token(JSParseState *s)
+{
+  const uint8_t *p;
+  int c;
+  BOOL ident_has_escape;
+  JSAtom atom;
+
+  if (js_check_stack_overflow(s->ctx->rt, 0)) {
+    return js_parse_error(s, "stack overflow");
+  }
+
+  free_token(s, &s->token);
+
+  p = s->last_ptr = s->buf_ptr;
+  s->got_lf = FALSE;
+  s->last_line_num = s->token.line_num;
+redo:
+  s->token.line_num = s->line_num;
+  s->token.ptr = p;
+  c = *p;
+  switch(c) {
+    case 0:
+      if (p >= s->buf_end) {
+        s->token.val = TOK_EOF;
+      } else {
+        goto def_token;
+      }
+      break;
+    case '`':
+      if (js_parse_template_part(s, p + 1))
+        goto fail;
+      p = s->buf_ptr;
+      break;
+    case '\'':
+    case '\"':
+      if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))
+        goto fail;
+      break;
+    case '\r':  /* accept DOS and MAC newline sequences */
+      if (p[1] == '\n') {
+        p++;
+      }
+      /* fall thru */
+    case '\n':
+      p++;
+    line_terminator:
+      s->got_lf = TRUE;
+      s->line_num++;
+      goto redo;
+    case '\f':
+    case '\v':
+    case ' ':
+    case '\t':
+      p++;
+      goto redo;
+    case '/':
+      if (p[1] == '*') {
+        /* comment */
+        p += 2;
+        for(;;) {
+          if (*p == '\0' && p >= s->buf_end) {
+            js_parse_error(s, "unexpected end of comment");
+            goto fail;
+          }
+          if (p[0] == '*' && p[1] == '/') {
+            p += 2;
+            break;
+          }
+          if (*p == '\n') {
+            s->line_num++;
+            s->got_lf = TRUE; /* considered as LF for ASI */
+            p++;
+          } else if (*p == '\r') {
+            s->got_lf = TRUE; /* considered as LF for ASI */
+            p++;
+          } else if (*p >= 0x80) {
+            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
+            if (c == CP_LS || c == CP_PS) {
+              s->got_lf = TRUE; /* considered as LF for ASI */
+            } else if (c == -1) {
+              p++; /* skip invalid UTF-8 */
+            }
+          } else {
+            p++;
+          }
+        }
+        goto redo;
+      } else if (p[1] == '/') {
+        /* line comment */
+        p += 2;
+      skip_line_comment:
+        for(;;) {
+          if (*p == '\0' && p >= s->buf_end)
+            break;
+          if (*p == '\r' || *p == '\n')
+            break;
+          if (*p >= 0x80) {
+            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
+            /* LS or PS are considered as line terminator */
+            if (c == CP_LS || c == CP_PS) {
+              break;
+            } else if (c == -1) {
+              p++; /* skip invalid UTF-8 */
+            }
+          } else {
+            p++;
+          }
+        }
+        goto redo;
+      } else if (p[1] == '=') {
+        p += 2;
+        s->token.val = TOK_DIV_ASSIGN;
+      } else {
+        p++;
+        s->token.val = c;
+      }
+      break;
+    case '\\':
+      if (p[1] == 'u') {
+        const uint8_t *p1 = p + 1;
+        int c1 = lre_parse_escape(&p1, TRUE);
+        if (c1 >= 0 && lre_js_is_ident_first(c1)) {
+          c = c1;
+          p = p1;
+          ident_has_escape = TRUE;
+          goto has_ident;
+        } else {
+          /* XXX: syntax error? */
+        }
+      }
+      goto def_token;
+    case 'a': case 'b': case 'c': case 'd':
+    case 'e': case 'f': case 'g': case 'h':
+    case 'i': case 'j': case 'k': case 'l':
+    case 'm': case 'n': case 'o': case 'p':
+    case 'q': case 'r': case 's': case 't':
+    case 'u': case 'v': case 'w': case 'x':
+    case 'y': case 'z':
+    case 'A': case 'B': case 'C': case 'D':
+    case 'E': case 'F': case 'G': case 'H':
+    case 'I': case 'J': case 'K': case 'L':
+    case 'M': case 'N': case 'O': case 'P':
+    case 'Q': case 'R': case 'S': case 'T':
+    case 'U': case 'V': case 'W': case 'X':
+    case 'Y': case 'Z':
+    case '_':
+    case '$':
+      /* identifier */
+      p++;
+      ident_has_escape = FALSE;
+    has_ident:
+      atom = parse_ident(s, &p, &ident_has_escape, c, FALSE);
+      if (atom == JS_ATOM_NULL)
+        goto fail;
+      s->token.u.ident.atom = atom;
+      s->token.u.ident.has_escape = ident_has_escape;
+      s->token.u.ident.is_reserved = FALSE;
+      if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD ||
+          (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD &&
+           (s->cur_func->js_mode & JS_MODE_STRICT)) ||
+          (s->token.u.ident.atom == JS_ATOM_yield &&
+           ((s->cur_func->func_kind & JS_FUNC_GENERATOR) ||
+            (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
+             !s->cur_func->in_function_body && s->cur_func->parent &&
+             (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) ||
+          (s->token.u.ident.atom == JS_ATOM_await &&
+           (s->is_module ||
+            (((s->cur_func->func_kind & JS_FUNC_ASYNC) ||
+              (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
+               !s->cur_func->in_function_body && s->cur_func->parent &&
+               (s->cur_func->parent->func_kind & JS_FUNC_ASYNC))))))) {
+        if (ident_has_escape) {
+          s->token.u.ident.is_reserved = TRUE;
+          s->token.val = TOK_IDENT;
+        } else {
+          /* The keywords atoms are pre allocated */
+          s->token.val = s->token.u.ident.atom - 1 + TOK_FIRST_KEYWORD;
+        }
+      } else {
+        s->token.val = TOK_IDENT;
+      }
+      break;
+    case '#':
+      /* private name */
+      {
+        const uint8_t *p1;
+        p++;
+        p1 = p;
+        c = *p1++;
+        if (c == '\\' && *p1 == 'u') {
+          c = lre_parse_escape(&p1, TRUE);
+        } else if (c >= 128) {
+          c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
+        }
+        if (!lre_js_is_ident_first(c)) {
+          js_parse_error(s, "invalid first character of private name");
+          goto fail;
+        }
+        p = p1;
+        ident_has_escape = FALSE; /* not used */
+        atom = parse_ident(s, &p, &ident_has_escape, c, TRUE);
+        if (atom == JS_ATOM_NULL)
+          goto fail;
+        s->token.u.ident.atom = atom;
+        s->token.val = TOK_PRIVATE_NAME;
+      }
+      break;
+    case '.':
+      if (p[1] == '.' && p[2] == '.') {
+        p += 3;
+        s->token.val = TOK_ELLIPSIS;
+        break;
+      }
+      if (p[1] >= '0' && p[1] <= '9') {
+        goto parse_number;
+      } else {
+        goto def_token;
+      }
+      break;
+    case '0':
+      /* in strict mode, octal literals are not accepted */
+      if (is_digit(p[1]) && (s->cur_func->js_mode & JS_MODE_STRICT)) {
+        js_parse_error(s, "octal literals are deprecated in strict mode");
+        goto fail;
+      }
+      goto parse_number;
+    case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8':
+    case '9':
+      /* number */
+    parse_number:
+    {
+      JSValue ret;
+      const uint8_t *p1;
+      int flags, radix;
+      flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL |
+              ATOD_ACCEPT_UNDERSCORES;
+#ifdef CONFIG_BIGNUM
+      flags |= ATOD_ACCEPT_SUFFIX;
+      if (s->cur_func->js_mode & JS_MODE_MATH) {
+        flags |= ATOD_MODE_BIGINT;
+        if (s->cur_func->js_mode & JS_MODE_MATH)
+          flags |= ATOD_TYPE_BIG_FLOAT;
+      }
+#endif
+      radix = 0;
+#ifdef CONFIG_BIGNUM
+      s->token.u.num.exponent = 0;
+      ret = js_atof2(s->ctx, (const char *)p, (const char **)&p, radix,
+                     flags, &s->token.u.num.exponent);
+#else
+      ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix,
+                    flags);
+#endif
+      if (JS_IsException(ret))
+        goto fail;
+      /* reject `10instanceof Number` */
+      if (JS_VALUE_IS_NAN(ret) ||
+          lre_js_is_ident_next(unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1))) {
+        JS_FreeValue(s->ctx, ret);
+        js_parse_error(s, "invalid number literal");
+        goto fail;
+      }
+      s->token.val = TOK_NUMBER;
+      s->token.u.num.val = ret;
+    }
+    break;
+    case '*':
+      if (p[1] == '=') {
+        p += 2;
+        s->token.val = TOK_MUL_ASSIGN;
+      } else if (p[1] == '*') {
+        if (p[2] == '=') {
+          p += 3;
+          s->token.val = TOK_POW_ASSIGN;
+        } else {
+          p += 2;
+          s->token.val = TOK_POW;
+        }
+      } else {
+        goto def_token;
+      }
+      break;
+    case '%':
+      if (p[1] == '=') {
+        p += 2;
+        s->token.val = TOK_MOD_ASSIGN;
+      } else {
+        goto def_token;
+      }
+      break;
+    case '+':
+      if (p[1] == '=') {
+        p += 2;
+        s->token.val = TOK_PLUS_ASSIGN;
+      } else if (p[1] == '+') {
+        p += 2;
+        s->token.val = TOK_INC;
+      } else {
+        goto def_token;
+      }
+      break;
+    case '-':
+      if (p[1] == '=') {
+        p += 2;
+        s->token.val = TOK_MINUS_ASSIGN;
+      } else if (p[1] == '-') {
+        if (s->allow_html_comments &&
+            p[2] == '>' && s->last_line_num != s->line_num) {
+          /* Annex B: `-->` at beginning of line is an html comment end.
+             It extends to the end of the line.
+           */
+          goto skip_line_comment;
+        }
+        p += 2;
+        s->token.val = TOK_DEC;
+      } else {
+        goto def_token;
+      }
+      break;
+    case '<':
+      if (p[1] == '=') {
+        p += 2;
+        s->token.val = TOK_LTE;
+      } else if (p[1] == '<') {
+        if (p[2] == '=') {
+          p += 3;
+          s->token.val = TOK_SHL_ASSIGN;
+        } else {
+          p += 2;
+          s->token.val = TOK_SHL;
+        }
+      } else if (s->allow_html_comments &&
+                 p[1] == '!' && p[2] == '-' && p[3] == '-') {
+        /* Annex B: handle `<!--` single line html comments */
+        goto skip_line_comment;
+      } 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 if (p[1] == '>') {
+        p += 2;
+        s->token.val = TOK_ARROW;
+      } 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] == '&') {
+        if (p[2] == '=') {
+          p += 3;
+          s->token.val = TOK_LAND_ASSIGN;
+        } else {
+          p += 2;
+          s->token.val = TOK_LAND;
+        }
+      } else {
+        goto def_token;
+      }
+      break;
+#ifdef CONFIG_BIGNUM
+      /* in math mode, '^' is the power operator. '^^' is always the
+         xor operator and '**' is always the power operator */
+    case '^':
+      if (p[1] == '=') {
+        p += 2;
+        if (s->cur_func->js_mode & JS_MODE_MATH)
+          s->token.val = TOK_MATH_POW_ASSIGN;
+        else
+          s->token.val = TOK_XOR_ASSIGN;
+      } else if (p[1] == '^') {
+        if (p[2] == '=') {
+          p += 3;
+          s->token.val = TOK_XOR_ASSIGN;
+        } else {
+          p += 2;
+          s->token.val = '^';
+        }
+      } else {
+        p++;
+        if (s->cur_func->js_mode & JS_MODE_MATH)
+          s->token.val = TOK_MATH_POW;
+        else
+          s->token.val = '^';
+      }
+      break;
+#else
+    case '^':
+      if (p[1] == '=') {
+        p += 2;
+        s->token.val = TOK_XOR_ASSIGN;
+      } else {
+        goto def_token;
+      }
+      break;
+#endif
+    case '|':
+      if (p[1] == '=') {
+        p += 2;
+        s->token.val = TOK_OR_ASSIGN;
+      } else if (p[1] == '|') {
+        if (p[2] == '=') {
+          p += 3;
+          s->token.val = TOK_LOR_ASSIGN;
+        } else {
+          p += 2;
+          s->token.val = TOK_LOR;
+        }
+      } else {
+        goto def_token;
+      }
+      break;
+    case '?':
+      if (p[1] == '?') {
+        if (p[2] == '=') {
+          p += 3;
+          s->token.val = TOK_DOUBLE_QUESTION_MARK_ASSIGN;
+        } else {
+          p += 2;
+          s->token.val = TOK_DOUBLE_QUESTION_MARK;
+        }
+      } else if (p[1] == '.' && !(p[2] >= '0' && p[2] <= '9')) {
+        p += 2;
+        s->token.val = TOK_QUESTION_MARK_DOT;
+      } else {
+        goto def_token;
+      }
+      break;
+    default:
+      if (c >= 128) {
+        /* unicode value */
+        c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
+        switch(c) {
+          case CP_PS:
+          case CP_LS:
+            /* XXX: should avoid incrementing line_number, but
+               needed to handle HTML comments */
+            goto line_terminator;
+          default:
+            if (lre_is_space(c)) {
+              goto redo;
+            } else if (lre_js_is_ident_first(c)) {
+              ident_has_escape = FALSE;
+              goto has_ident;
+            } else {
+              js_parse_error(s, "unexpected character");
+              goto fail;
+            }
+        }
+      }
+    def_token:
+      s->token.val = c;
+      p++;
+      break;
+  }
+  s->buf_ptr = p;
+
+  //    dump_token(s, &s->token);
+  return 0;
+
+fail:
+  s->token.val = TOK_ERROR;
+  return -1;
+}
+
+/* 'c' is the first character. Return JS_ATOM_NULL in case of error */
+static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c)
+{
+  const uint8_t *p;
+  char ident_buf[128], *buf;
+  size_t ident_size, ident_pos;
+  JSAtom atom;
+
+  p = *pp;
+  buf = ident_buf;
+  ident_size = sizeof(ident_buf);
+  ident_pos = 0;
+  for(;;) {
+    buf[ident_pos++] = c;
+    c = *p;
+    if (c >= 128 ||
+        !((lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1))
+      break;
+    p++;
+    if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
+      if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) {
+        atom = JS_ATOM_NULL;
+        goto done;
+      }
+    }
+  }
+  atom = JS_NewAtomLen(s->ctx, buf, ident_pos);
+done:
+  if (unlikely(buf != ident_buf))
+    js_free(s->ctx, buf);
+  *pp = p;
+  return atom;
+}
+
+__exception int json_next_token(JSParseState *s)
+{
+  const uint8_t *p;
+  int c;
+  JSAtom atom;
+
+  if (js_check_stack_overflow(s->ctx->rt, 0)) {
+    return js_parse_error(s, "stack overflow");
+  }
+
+  free_token(s, &s->token);
+
+  p = s->last_ptr = s->buf_ptr;
+  s->last_line_num = s->token.line_num;
+redo:
+  s->token.line_num = s->line_num;
+  s->token.ptr = p;
+  c = *p;
+  switch(c) {
+    case 0:
+      if (p >= s->buf_end) {
+        s->token.val = TOK_EOF;
+      } else {
+        goto def_token;
+      }
+      break;
+    case '\'':
+      if (!s->ext_json) {
+        /* JSON does not accept single quoted strings */
+        goto def_token;
+      }
+      /* fall through */
+    case '\"':
+      if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))
+        goto fail;
+      break;
+    case '\r':  /* accept DOS and MAC newline sequences */
+      if (p[1] == '\n') {
+        p++;
+      }
+      /* fall thru */
+    case '\n':
+      p++;
+      s->line_num++;
+      goto redo;
+    case '\f':
+    case '\v':
+      if (!s->ext_json) {
+        /* JSONWhitespace does not match <VT>, nor <FF> */
+        goto def_token;
+      }
+      /* fall through */
+    case ' ':
+    case '\t':
+      p++;
+      goto redo;
+    case '/':
+      if (!s->ext_json) {
+        /* JSON does not accept comments */
+        goto def_token;
+      }
+      if (p[1] == '*') {
+        /* comment */
+        p += 2;
+        for(;;) {
+          if (*p == '\0' && p >= s->buf_end) {
+            js_parse_error(s, "unexpected end of comment");
+            goto fail;
+          }
+          if (p[0] == '*' && p[1] == '/') {
+            p += 2;
+            break;
+          }
+          if (*p == '\n') {
+            s->line_num++;
+            p++;
+          } else if (*p == '\r') {
+            p++;
+          } else if (*p >= 0x80) {
+            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
+            if (c == -1) {
+              p++; /* skip invalid UTF-8 */
+            }
+          } else {
+            p++;
+          }
+        }
+        goto redo;
+      } else if (p[1] == '/') {
+        /* line comment */
+        p += 2;
+        for(;;) {
+          if (*p == '\0' && p >= s->buf_end)
+            break;
+          if (*p == '\r' || *p == '\n')
+            break;
+          if (*p >= 0x80) {
+            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
+            /* LS or PS are considered as line terminator */
+            if (c == CP_LS || c == CP_PS) {
+              break;
+            } else if (c == -1) {
+              p++; /* skip invalid UTF-8 */
+            }
+          } else {
+            p++;
+          }
+        }
+        goto redo;
+      } else {
+        goto def_token;
+      }
+      break;
+    case 'a': case 'b': case 'c': case 'd':
+    case 'e': case 'f': case 'g': case 'h':
+    case 'i': case 'j': case 'k': case 'l':
+    case 'm': case 'n': case 'o': case 'p':
+    case 'q': case 'r': case 's': case 't':
+    case 'u': case 'v': case 'w': case 'x':
+    case 'y': case 'z':
+    case 'A': case 'B': case 'C': case 'D':
+    case 'E': case 'F': case 'G': case 'H':
+    case 'I': case 'J': case 'K': case 'L':
+    case 'M': case 'N': case 'O': case 'P':
+    case 'Q': case 'R': case 'S': case 'T':
+    case 'U': case 'V': case 'W': case 'X':
+    case 'Y': case 'Z':
+    case '_':
+    case '$':
+      /* identifier : only pure ascii characters are accepted */
+      p++;
+      atom = json_parse_ident(s, &p, c);
+      if (atom == JS_ATOM_NULL)
+        goto fail;
+      s->token.u.ident.atom = atom;
+      s->token.u.ident.has_escape = FALSE;
+      s->token.u.ident.is_reserved = FALSE;
+      s->token.val = TOK_IDENT;
+      break;
+    case '+':
+      if (!s->ext_json || !is_digit(p[1]))
+        goto def_token;
+      goto parse_number;
+    case '0':
+      if (is_digit(p[1]))
+        goto def_token;
+      goto parse_number;
+    case '-':
+      if (!is_digit(p[1]))
+        goto def_token;
+      goto parse_number;
+    case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8':
+    case '9':
+      /* number */
+    parse_number:
+    {
+      JSValue ret;
+      int flags, radix;
+      if (!s->ext_json) {
+        flags = 0;
+        radix = 10;
+      } else {
+        flags = ATOD_ACCEPT_BIN_OCT;
+        radix = 0;
+      }
+      ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix,
+                    flags);
+      if (JS_IsException(ret))
+        goto fail;
+      s->token.val = TOK_NUMBER;
+      s->token.u.num.val = ret;
+    }
+    break;
+    default:
+      if (c >= 128) {
+        js_parse_error(s, "unexpected character");
+        goto fail;
+      }
+    def_token:
+      s->token.val = c;
+      p++;
+      break;
+  }
+  s->buf_ptr = p;
+
+  //    dump_token(s, &s->token);
+  return 0;
+
+fail:
+  s->token.val = TOK_ERROR;
+  return -1;
+}
+
+/* only used for ':' and '=>', 'let' or 'function' look-ahead. *pp is
+   only set if TOK_IMPORT is returned */
+/* XXX: handle all unicode cases */
+static int simple_next_token(const uint8_t **pp, BOOL no_line_terminator)
+{
+  const uint8_t *p;
+  uint32_t c;
+
+  /* skip spaces and comments */
+  p = *pp;
+  for (;;) {
+    switch(c = *p++) {
+      case '\r':
+      case '\n':
+        if (no_line_terminator)
+          return '\n';
+        continue;
+      case ' ':
+      case '\t':
+      case '\v':
+      case '\f':
+        continue;
+      case '/':
+        if (*p == '/') {
+          if (no_line_terminator)
+            return '\n';
+          while (*p && *p != '\r' && *p != '\n')
+            p++;
+          continue;
+        }
+        if (*p == '*') {
+          while (*++p) {
+            if ((*p == '\r' || *p == '\n') && no_line_terminator)
+              return '\n';
+            if (*p == '*' && p[1] == '/') {
+              p += 2;
+              break;
+            }
+          }
+          continue;
+        }
+        break;
+      case '=':
+        if (*p == '>')
+          return TOK_ARROW;
+        break;
+      default:
+        if (lre_js_is_ident_first(c)) {
+          if (c == 'i') {
+            if (p[0] == 'n' && !lre_js_is_ident_next(p[1])) {
+              return TOK_IN;
+            }
+            if (p[0] == 'm' && p[1] == 'p' && p[2] == 'o' &&
+                p[3] == 'r' && p[4] == 't' &&
+                !lre_js_is_ident_next(p[5])) {
+              *pp = p + 5;
+              return TOK_IMPORT;
+            }
+          } else if (c == 'o' && *p == 'f' && !lre_js_is_ident_next(p[1])) {
+            return TOK_OF;
+          } else if (c == 'e' &&
+                     p[0] == 'x' && p[1] == 'p' && p[2] == 'o' &&
+                     p[3] == 'r' && p[4] == 't' &&
+                     !lre_js_is_ident_next(p[5])) {
+            *pp = p + 5;
+            return TOK_EXPORT;
+          } else if (c == 'f' && p[0] == 'u' && p[1] == 'n' &&
+                     p[2] == 'c' && p[3] == 't' && p[4] == 'i' &&
+                     p[5] == 'o' && p[6] == 'n' && !lre_js_is_ident_next(p[7])) {
+            return TOK_FUNCTION;
+          }
+          return TOK_IDENT;
+        }
+        break;
+    }
+    return c;
+  }
+}
+
+static int peek_token(JSParseState *s, BOOL no_line_terminator)
+{
+  const uint8_t *p = s->buf_ptr;
+  return simple_next_token(&p, no_line_terminator);
+}
+
+/* return true if 'input' contains the source of a module
+   (heuristic). 'input' must be a zero terminated.
+
+   Heuristic: skip comments and expect 'import' keyword not followed
+   by '(' or '.' or export keyword.
+*/
+BOOL JS_DetectModule(const char *input, size_t input_len)
+{
+  const uint8_t *p = (const uint8_t *)input;
+  int tok;
+  switch(simple_next_token(&p, FALSE)) {
+    case TOK_IMPORT:
+      tok = simple_next_token(&p, FALSE);
+      return (tok != '.' && tok != '(');
+    case TOK_EXPORT:
+      return TRUE;
+    default:
+      return FALSE;
+  }
+}
+
+static inline int get_prev_opcode(JSFunctionDef *fd) {
+  if (fd->last_opcode_pos < 0)
+    return OP_invalid;
+  else
+    return fd->byte_code.buf[fd->last_opcode_pos];
+}
+
+static BOOL js_is_live_code(JSParseState *s) {
+  switch (get_prev_opcode(s->cur_func)) {
+    case OP_tail_call:
+    case OP_tail_call_method:
+    case OP_return:
+    case OP_return_undef:
+    case OP_return_async:
+    case OP_throw:
+    case OP_throw_error:
+    case OP_goto:
+#if SHORT_OPCODES
+    case OP_goto8:
+    case OP_goto16:
+#endif
+    case OP_ret:
+      return FALSE;
+    default:
+      return TRUE;
+  }
+}
+
+static void emit_u8(JSParseState *s, uint8_t val)
+{
+  dbuf_putc(&s->cur_func->byte_code, val);
+}
+
+static void emit_u16(JSParseState *s, uint16_t val)
+{
+  dbuf_put_u16(&s->cur_func->byte_code, val);
+}
+
+static void emit_u32(JSParseState *s, uint32_t val)
+{
+  dbuf_put_u32(&s->cur_func->byte_code, val);
+}
+
+static void emit_op(JSParseState *s, uint8_t val)
+{
+  JSFunctionDef *fd = s->cur_func;
+  DynBuf *bc = &fd->byte_code;
+
+  /* Use the line number of the last token used, not the next token,
+     nor the current offset in the source file.
+   */
+  if (unlikely(fd->last_opcode_line_num != s->last_line_num)) {
+    dbuf_putc(bc, OP_line_num);
+    dbuf_put_u32(bc, s->last_line_num);
+    fd->last_opcode_line_num = s->last_line_num;
+  }
+  fd->last_opcode_pos = bc->size;
+  dbuf_putc(bc, val);
+}
+
+static void emit_atom(JSParseState *s, JSAtom name)
+{
+  emit_u32(s, JS_DupAtom(s->ctx, name));
+}
+
+static int update_label(JSFunctionDef *s, int label, int delta)
+{
+  LabelSlot *ls;
+
+  assert(label >= 0 && label < s->label_count);
+  ls = &s->label_slots[label];
+  ls->ref_count += delta;
+  assert(ls->ref_count >= 0);
+  return ls->ref_count;
+}
+
+static int new_label_fd(JSFunctionDef *fd, int label)
+{
+  LabelSlot *ls;
+
+  if (label < 0) {
+    if (js_resize_array(fd->ctx, (void *)&fd->label_slots,
+                        sizeof(fd->label_slots[0]),
+                        &fd->label_size, fd->label_count + 1))
+      return -1;
+    label = fd->label_count++;
+    ls = &fd->label_slots[label];
+    ls->ref_count = 0;
+    ls->pos = -1;
+    ls->pos2 = -1;
+    ls->addr = -1;
+    ls->first_reloc = NULL;
+  }
+  return label;
+}
+
+static int new_label(JSParseState *s)
+{
+  return new_label_fd(s->cur_func, -1);
+}
+
+/* return the label ID offset */
+static int emit_label(JSParseState *s, int label)
+{
+  if (label >= 0) {
+    emit_op(s, OP_label);
+    emit_u32(s, label);
+    s->cur_func->label_slots[label].pos = s->cur_func->byte_code.size;
+    return s->cur_func->byte_code.size - 4;
+  } else {
+    return -1;
+  }
+}
+
+/* return label or -1 if dead code */
+static int emit_goto(JSParseState *s, int opcode, int label)
+{
+  if (js_is_live_code(s)) {
+    if (label < 0)
+      label = new_label(s);
+    emit_op(s, opcode);
+    emit_u32(s, label);
+    s->cur_func->label_slots[label].ref_count++;
+    return label;
+  }
+  return -1;
+}
+
+/* return the constant pool index. 'val' is not duplicated. */
+static int cpool_add(JSParseState *s, JSValue val)
+{
+  JSFunctionDef *fd = s->cur_func;
+
+  if (js_resize_array(s->ctx, (void *)&fd->cpool, sizeof(fd->cpool[0]),
+                      &fd->cpool_size, fd->cpool_count + 1))
+    return -1;
+  fd->cpool[fd->cpool_count++] = val;
+  return fd->cpool_count - 1;
+}
+
+static __exception int emit_push_const(JSParseState *s, JSValueConst val,
+                                       BOOL as_atom)
+{
+  int idx;
+
+  if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING && as_atom) {
+    JSAtom atom;
+    /* warning: JS_NewAtomStr frees the string value */
+    JS_DupValue(s->ctx, val);
+    atom = JS_NewAtomStr(s->ctx, JS_VALUE_GET_STRING(val));
+    if (atom != JS_ATOM_NULL && !__JS_AtomIsTaggedInt(atom)) {
+      emit_op(s, OP_push_atom_value);
+      emit_u32(s, atom);
+      return 0;
+    }
+  }
+
+  idx = cpool_add(s, JS_DupValue(s->ctx, val));
+  if (idx < 0)
+    return -1;
+  emit_op(s, OP_push_const);
+  emit_u32(s, idx);
+  return 0;
+}
+
+/* return the variable index or -1 if not found,
+   add ARGUMENT_VAR_OFFSET for argument variables */
+static int find_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
+{
+  int i;
+  for(i = fd->arg_count; i-- > 0;) {
+    if (fd->args[i].var_name == name)
+      return i | ARGUMENT_VAR_OFFSET;
+  }
+  return -1;
+}
+
+static int find_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
+{
+  int i;
+  for(i = fd->var_count; i-- > 0;) {
+    if (fd->vars[i].var_name == name && fd->vars[i].scope_level == 0)
+      return i;
+  }
+  return find_arg(ctx, fd, name);
+}
+
+/* find a variable declaration in a given scope */
+static int find_var_in_scope(JSContext *ctx, JSFunctionDef *fd,
+                             JSAtom name, int scope_level)
+{
+  int scope_idx;
+  for(scope_idx = fd->scopes[scope_level].first; scope_idx >= 0;
+       scope_idx = fd->vars[scope_idx].scope_next) {
+    if (fd->vars[scope_idx].scope_level != scope_level)
+      break;
+    if (fd->vars[scope_idx].var_name == name)
+      return scope_idx;
+  }
+  return -1;
+}
+
+/* return true if scope == parent_scope or if scope is a child of
+   parent_scope */
+static BOOL is_child_scope(JSContext *ctx, JSFunctionDef *fd,
+                           int scope, int parent_scope)
+{
+  while (scope >= 0) {
+    if (scope == parent_scope)
+      return TRUE;
+    scope = fd->scopes[scope].parent;
+  }
+  return FALSE;
+}
+
+/* find a 'var' declaration in the same scope or a child scope */
+static int find_var_in_child_scope(JSContext *ctx, JSFunctionDef *fd,
+                                   JSAtom name, int scope_level)
+{
+  int i;
+  for(i = 0; i < fd->var_count; i++) {
+    JSVarDef *vd = &fd->vars[i];
+    if (vd->var_name == name && vd->scope_level == 0) {
+      if (is_child_scope(ctx, fd, vd->scope_next,
+                         scope_level))
+        return i;
+    }
+  }
+  return -1;
+}
+
+
+static JSGlobalVar *find_global_var(JSFunctionDef *fd, JSAtom name)
+{
+  int i;
+  for(i = 0; i < fd->global_var_count; i++) {
+    JSGlobalVar *hf = &fd->global_vars[i];
+    if (hf->var_name == name)
+      return hf;
+  }
+  return NULL;
+
+}
+
+static JSGlobalVar *find_lexical_global_var(JSFunctionDef *fd, JSAtom name)
+{
+  JSGlobalVar *hf = find_global_var(fd, name);
+  if (hf && hf->is_lexical)
+    return hf;
+  else
+    return NULL;
+}
+
+static int find_lexical_decl(JSContext *ctx, JSFunctionDef *fd, JSAtom name,
+                             int scope_idx, BOOL check_catch_var)
+{
+  while (scope_idx >= 0) {
+    JSVarDef *vd = &fd->vars[scope_idx];
+    if (vd->var_name == name &&
+        (vd->is_lexical || (vd->var_kind == JS_VAR_CATCH &&
+                            check_catch_var)))
+      return scope_idx;
+    scope_idx = vd->scope_next;
+  }
+
+  if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_GLOBAL) {
+    if (find_lexical_global_var(fd, name))
+      return GLOBAL_VAR_OFFSET;
+  }
+  return -1;
+}
+
+static int push_scope(JSParseState *s) {
+  if (s->cur_func) {
+    JSFunctionDef *fd = s->cur_func;
+    int scope = fd->scope_count;
+    /* XXX: should check for scope overflow */
+    if ((fd->scope_count + 1) > fd->scope_size) {
+      int new_size;
+      size_t slack;
+      JSVarScope *new_buf;
+      /* XXX: potential arithmetic overflow */
+      new_size = max_int(fd->scope_count + 1, fd->scope_size * 3 / 2);
+      if (fd->scopes == fd->def_scope_array) {
+        new_buf = js_realloc2(s->ctx, NULL, new_size * sizeof(*fd->scopes), &slack);
+        if (!new_buf)
+          return -1;
+        memcpy(new_buf, fd->scopes, fd->scope_count * sizeof(*fd->scopes));
+      } else {
+        new_buf = js_realloc2(s->ctx, fd->scopes, new_size * sizeof(*fd->scopes), &slack);
+        if (!new_buf)
+          return -1;
+      }
+      new_size += slack / sizeof(*new_buf);
+      fd->scopes = new_buf;
+      fd->scope_size = new_size;
+    }
+    fd->scope_count++;
+    fd->scopes[scope].parent = fd->scope_level;
+    fd->scopes[scope].first = fd->scope_first;
+    emit_op(s, OP_enter_scope);
+    emit_u16(s, scope);
+    return fd->scope_level = scope;
+  }
+  return 0;
+}
+
+static int get_first_lexical_var(JSFunctionDef *fd, int scope)
+{
+  while (scope >= 0) {
+    int scope_idx = fd->scopes[scope].first;
+    if (scope_idx >= 0)
+      return scope_idx;
+    scope = fd->scopes[scope].parent;
+  }
+  return -1;
+}
+
+static void pop_scope(JSParseState *s) {
+  if (s->cur_func) {
+    /* disable scoped variables */
+    JSFunctionDef *fd = s->cur_func;
+    int scope = fd->scope_level;
+    emit_op(s, OP_leave_scope);
+    emit_u16(s, scope);
+    fd->scope_level = fd->scopes[scope].parent;
+    fd->scope_first = get_first_lexical_var(fd, fd->scope_level);
+  }
+}
+
+static void close_scopes(JSParseState *s, int scope, int scope_stop)
+{
+  while (scope > scope_stop) {
+    emit_op(s, OP_leave_scope);
+    emit_u16(s, scope);
+    scope = s->cur_func->scopes[scope].parent;
+  }
+}
+
+/* return the variable index or -1 if error */
+static int add_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
+{
+  JSVarDef *vd;
+
+  /* the local variable indexes are currently stored on 16 bits */
+  if (fd->var_count >= JS_MAX_LOCAL_VARS) {
+    JS_ThrowInternalError(ctx, "too many local variables");
+    return -1;
+  }
+  if (js_resize_array(ctx, (void **)&fd->vars, sizeof(fd->vars[0]),
+                      &fd->var_size, fd->var_count + 1))
+    return -1;
+  vd = &fd->vars[fd->var_count++];
+  memset(vd, 0, sizeof(*vd));
+  vd->var_name = JS_DupAtom(ctx, name);
+  vd->func_pool_idx = -1;
+  return fd->var_count - 1;
+}
+
+static int add_scope_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name,
+                         JSVarKindEnum var_kind)
+{
+  int idx = add_var(ctx, fd, name);
+  if (idx >= 0) {
+    JSVarDef *vd = &fd->vars[idx];
+    vd->var_kind = var_kind;
+    vd->scope_level = fd->scope_level;
+    vd->scope_next = fd->scope_first;
+    fd->scopes[fd->scope_level].first = idx;
+    fd->scope_first = idx;
+  }
+  return idx;
+}
+
+static int add_func_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
+{
+  int idx = fd->func_var_idx;
+  if (idx < 0 && (idx = add_var(ctx, fd, name)) >= 0) {
+    fd->func_var_idx = idx;
+    fd->vars[idx].var_kind = JS_VAR_FUNCTION_NAME;
+    if (fd->js_mode & JS_MODE_STRICT)
+      fd->vars[idx].is_const = TRUE;
+  }
+  return idx;
+}
+
+static int add_arguments_var(JSContext *ctx, JSFunctionDef *fd)
+{
+  int idx = fd->arguments_var_idx;
+  if (idx < 0 && (idx = add_var(ctx, fd, JS_ATOM_arguments)) >= 0) {
+    fd->arguments_var_idx = idx;
+  }
+  return idx;
+}
+
+/* add an argument definition in the argument scope. Only needed when
+   "eval()" may be called in the argument scope. Return 0 if OK. */
+static int add_arguments_arg(JSContext *ctx, JSFunctionDef *fd)
+{
+  int idx;
+  if (fd->arguments_arg_idx < 0) {
+    idx = find_var_in_scope(ctx, fd, JS_ATOM_arguments, ARG_SCOPE_INDEX);
+    if (idx < 0) {
+      /* XXX: the scope links are not fully updated. May be an
+         issue if there are child scopes of the argument
+         scope */
+      idx = add_var(ctx, fd, JS_ATOM_arguments);
+      if (idx < 0)
+        return -1;
+      fd->vars[idx].scope_next = fd->scopes[ARG_SCOPE_INDEX].first;
+      fd->scopes[ARG_SCOPE_INDEX].first = idx;
+      fd->vars[idx].scope_level = ARG_SCOPE_INDEX;
+      fd->vars[idx].is_lexical = TRUE;
+
+      fd->arguments_arg_idx = idx;
+    }
+  }
+  return 0;
+}
+
+static int add_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
+{
+  JSVarDef *vd;
+
+  /* the local variable indexes are currently stored on 16 bits */
+  if (fd->arg_count >= JS_MAX_LOCAL_VARS) {
+    JS_ThrowInternalError(ctx, "too many arguments");
+    return -1;
+  }
+  if (js_resize_array(ctx, (void **)&fd->args, sizeof(fd->args[0]),
+                      &fd->arg_size, fd->arg_count + 1))
+    return -1;
+  vd = &fd->args[fd->arg_count++];
+  memset(vd, 0, sizeof(*vd));
+  vd->var_name = JS_DupAtom(ctx, name);
+  vd->func_pool_idx = -1;
+  return fd->arg_count - 1;
+}
+
+/* add a global variable definition */
+static JSGlobalVar *add_global_var(JSContext *ctx, JSFunctionDef *s,
+                                   JSAtom name)
+{
+  JSGlobalVar *hf;
+
+  if (js_resize_array(ctx, (void **)&s->global_vars,
+                      sizeof(s->global_vars[0]),
+                      &s->global_var_size, s->global_var_count + 1))
+    return NULL;
+  hf = &s->global_vars[s->global_var_count++];
+  hf->cpool_idx = -1;
+  hf->force_init = FALSE;
+  hf->is_lexical = FALSE;
+  hf->is_const = FALSE;
+  hf->scope_level = s->scope_level;
+  hf->var_name = JS_DupAtom(ctx, name);
+  return hf;
+}
+
+typedef enum {
+  JS_VAR_DEF_WITH,
+  JS_VAR_DEF_LET,
+  JS_VAR_DEF_CONST,
+  JS_VAR_DEF_FUNCTION_DECL, /* function declaration */
+  JS_VAR_DEF_NEW_FUNCTION_DECL, /* async/generator function declaration */
+  JS_VAR_DEF_CATCH,
+  JS_VAR_DEF_VAR,
+} JSVarDefEnum;
+
+static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
+                      JSVarDefEnum var_def_type)
+{
+  JSContext *ctx = s->ctx;
+  JSVarDef *vd;
+  int idx;
+
+  switch (var_def_type) {
+    case JS_VAR_DEF_WITH:
+      idx = add_scope_var(ctx, fd, name, JS_VAR_NORMAL);
+      break;
+
+    case JS_VAR_DEF_LET:
+    case JS_VAR_DEF_CONST:
+    case JS_VAR_DEF_FUNCTION_DECL:
+    case JS_VAR_DEF_NEW_FUNCTION_DECL:
+      idx = find_lexical_decl(ctx, fd, name, fd->scope_first, TRUE);
+      if (idx >= 0) {
+        if (idx < GLOBAL_VAR_OFFSET) {
+          if (fd->vars[idx].scope_level == fd->scope_level) {
+            /* same scope: in non strict mode, functions
+               can be redefined (annex B.3.3.4). */
+            if (!(!(fd->js_mode & JS_MODE_STRICT) &&
+                  var_def_type == JS_VAR_DEF_FUNCTION_DECL &&
+                  fd->vars[idx].var_kind == JS_VAR_FUNCTION_DECL)) {
+              goto redef_lex_error;
+            }
+          } else if (fd->vars[idx].var_kind == JS_VAR_CATCH && (fd->vars[idx].scope_level + 2) == fd->scope_level) {
+            goto redef_lex_error;
+          }
+        } else {
+          if (fd->scope_level == fd->body_scope) {
+          redef_lex_error:
+            /* redefining a scoped var in the same scope: error */
+            return js_parse_error(s, "invalid redefinition of lexical identifier");
+          }
+        }
+      }
+      if (var_def_type != JS_VAR_DEF_FUNCTION_DECL &&
+          var_def_type != JS_VAR_DEF_NEW_FUNCTION_DECL &&
+          fd->scope_level == fd->body_scope &&
+          find_arg(ctx, fd, name) >= 0) {
+        /* lexical variable redefines a parameter name */
+        return js_parse_error(s, "invalid redefinition of parameter name");
+      }
+
+      if (find_var_in_child_scope(ctx, fd, name, fd->scope_level) >= 0) {
+        return js_parse_error(s, "invalid redefinition of a variable");
+      }
+
+      if (fd->is_global_var) {
+        JSGlobalVar *hf;
+        hf = find_global_var(fd, name);
+        if (hf && is_child_scope(ctx, fd, hf->scope_level,
+                                 fd->scope_level)) {
+          return js_parse_error(s, "invalid redefinition of global identifier");
+        }
+      }
+
+      if (fd->is_eval &&
+          (fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
+           fd->eval_type == JS_EVAL_TYPE_MODULE) &&
+          fd->scope_level == fd->body_scope) {
+        JSGlobalVar *hf;
+        hf = add_global_var(s->ctx, fd, name);
+        if (!hf)
+          return -1;
+        hf->is_lexical = TRUE;
+        hf->is_const = (var_def_type == JS_VAR_DEF_CONST);
+        idx = GLOBAL_VAR_OFFSET;
+      } else {
+        JSVarKindEnum var_kind;
+        if (var_def_type == JS_VAR_DEF_FUNCTION_DECL)
+          var_kind = JS_VAR_FUNCTION_DECL;
+        else if (var_def_type == JS_VAR_DEF_NEW_FUNCTION_DECL)
+          var_kind = JS_VAR_NEW_FUNCTION_DECL;
+        else
+          var_kind = JS_VAR_NORMAL;
+        idx = add_scope_var(ctx, fd, name, var_kind);
+        if (idx >= 0) {
+          vd = &fd->vars[idx];
+          vd->is_lexical = 1;
+          vd->is_const = (var_def_type == JS_VAR_DEF_CONST);
+        }
+      }
+      break;
+
+    case JS_VAR_DEF_CATCH:
+      idx = add_scope_var(ctx, fd, name, JS_VAR_CATCH);
+      break;
+
+    case JS_VAR_DEF_VAR:
+      if (find_lexical_decl(ctx, fd, name, fd->scope_first,
+                            FALSE) >= 0) {
+      invalid_lexical_redefinition:
+        /* error to redefine a var that inside a lexical scope */
+        return js_parse_error(s, "invalid redefinition of lexical identifier");
+      }
+      if (fd->is_global_var) {
+        JSGlobalVar *hf;
+        hf = find_global_var(fd, name);
+        if (hf && hf->is_lexical && hf->scope_level == fd->scope_level &&
+            fd->eval_type == JS_EVAL_TYPE_MODULE) {
+          goto invalid_lexical_redefinition;
+        }
+        hf = add_global_var(s->ctx, fd, name);
+        if (!hf)
+          return -1;
+        idx = GLOBAL_VAR_OFFSET;
+      } else {
+        /* if the variable already exists, don't add it again  */
+        idx = find_var(ctx, fd, name);
+        if (idx >= 0)
+          break;
+        idx = add_var(ctx, fd, name);
+        if (idx >= 0) {
+          if (name == JS_ATOM_arguments && fd->has_arguments_binding)
+            fd->arguments_var_idx = idx;
+          fd->vars[idx].scope_next = fd->scope_level;
+        }
+      }
+      break;
+    default:
+      abort();
+  }
+  return idx;
+}
+
+/* add a private field variable in the current scope */
+static int add_private_class_field(JSParseState *s, JSFunctionDef *fd,
+                                   JSAtom name, JSVarKindEnum var_kind)
+{
+  JSContext *ctx = s->ctx;
+  JSVarDef *vd;
+  int idx;
+
+  idx = add_scope_var(ctx, fd, name, var_kind);
+  if (idx < 0)
+    return idx;
+  vd = &fd->vars[idx];
+  vd->is_lexical = 1;
+  vd->is_const = 1;
+  return idx;
+}
+
+static __exception int js_parse_expr(JSParseState *s);
+static __exception int js_parse_function_decl(JSParseState *s,
+                                              JSParseFunctionEnum func_type,
+                                              JSFunctionKindEnum func_kind,
+                                              JSAtom func_name, const uint8_t *ptr,
+                                              int start_line);
+static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s);
+static __exception int js_parse_function_decl2(JSParseState *s,
+                                               JSParseFunctionEnum func_type,
+                                               JSFunctionKindEnum func_kind,
+                                               JSAtom func_name,
+                                               const uint8_t *ptr,
+                                               int function_line_num,
+                                               JSParseExportEnum export_flag,
+                                               JSFunctionDef **pfd);
+static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags);
+static __exception int js_parse_assign_expr(JSParseState *s);
+static __exception int js_parse_unary(JSParseState *s, int parse_flags);
+static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
+                             JSAtom label_name,
+                             int label_break, int label_cont,
+                             int drop_count);
+static void pop_break_entry(JSFunctionDef *fd);
+static JSExportEntry *add_export_entry(JSParseState *s, JSModuleDef *m,
+                                       JSAtom local_name, JSAtom export_name,
+                                       JSExportTypeEnum export_type);
+
+/* Note: all the fields are already sealed except length */
+static int seal_template_obj(JSContext *ctx, JSValueConst obj)
+{
+  JSObject *p;
+  JSShapeProperty *prs;
+
+  p = JS_VALUE_GET_OBJ(obj);
+  prs = find_own_property1(p, JS_ATOM_length);
+  if (prs) {
+    if (js_update_property_flags(ctx, p, &prs,
+                                 prs->flags & ~(JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)))
+      return -1;
+  }
+  p->extensible = FALSE;
+  return 0;
+}
+
+static __exception int js_parse_template(JSParseState *s, int call, int *argc)
+{
+  JSContext *ctx = s->ctx;
+  JSValue raw_array, template_object;
+  JSToken cooked;
+  int depth, ret;
+
+  raw_array = JS_UNDEFINED; /* avoid warning */
+  template_object = JS_UNDEFINED; /* avoid warning */
+  if (call) {
+    /* Create a template object: an array of cooked strings */
+    /* Create an array of raw strings and store it to the raw property */
+    template_object = JS_NewArray(ctx);
+    if (JS_IsException(template_object))
+      return -1;
+    //        pool_idx = s->cur_func->cpool_count;
+    ret = emit_push_const(s, template_object, 0);
+    JS_FreeValue(ctx, template_object);
+    if (ret)
+      return -1;
+    raw_array = JS_NewArray(ctx);
+    if (JS_IsException(raw_array))
+      return -1;
+    if (JS_DefinePropertyValue(ctx, template_object, JS_ATOM_raw,
+                               raw_array, JS_PROP_THROW) < 0) {
+      return -1;
+    }
+  }
+
+  depth = 0;
+  while (s->token.val == TOK_TEMPLATE) {
+    const uint8_t *p = s->token.ptr + 1;
+    cooked = s->token;
+    if (call) {
+      if (JS_DefinePropertyValueUint32(ctx, raw_array, depth,
+                                       JS_DupValue(ctx, s->token.u.str.str),
+                                       JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) {
+        return -1;
+      }
+      /* re-parse the string with escape sequences but do not throw a
+         syntax error if it contains invalid sequences
+       */
+      if (js_parse_string(s, '`', FALSE, p, &cooked, &p)) {
+        cooked.u.str.str = JS_UNDEFINED;
+      }
+      if (JS_DefinePropertyValueUint32(ctx, template_object, depth,
+                                       cooked.u.str.str,
+                                       JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) {
+        return -1;
+      }
+    } else {
+      JSString *str;
+      /* re-parse the string with escape sequences and throw a
+         syntax error if it contains invalid sequences
+       */
+      JS_FreeValue(ctx, s->token.u.str.str);
+      s->token.u.str.str = JS_UNDEFINED;
+      if (js_parse_string(s, '`', TRUE, p, &cooked, &p))
+        return -1;
+      str = JS_VALUE_GET_STRING(cooked.u.str.str);
+      if (str->len != 0 || depth == 0) {
+        ret = emit_push_const(s, cooked.u.str.str, 1);
+        JS_FreeValue(s->ctx, cooked.u.str.str);
+        if (ret)
+          return -1;
+        if (depth == 0) {
+          if (s->token.u.str.sep == '`')
+            goto done1;
+          emit_op(s, OP_get_field2);
+          emit_atom(s, JS_ATOM_concat);
+        }
+        depth++;
+      } else {
+        JS_FreeValue(s->ctx, cooked.u.str.str);
+      }
+    }
+    if (s->token.u.str.sep == '`')
+      goto done;
+    if (next_token(s))
+      return -1;
+    if (js_parse_expr(s))
+      return -1;
+    depth++;
+    if (s->token.val != '}') {
+      return js_parse_error(s, "expected '}' after template expression");
+    }
+    /* XXX: should convert to string at this stage? */
+    free_token(s, &s->token);
+    /* Resume TOK_TEMPLATE parsing (s->token.line_num and
+         * s->token.ptr are OK) */
+    s->got_lf = FALSE;
+    s->last_line_num = s->token.line_num;
+    if (js_parse_template_part(s, s->buf_ptr))
+      return -1;
+  }
+  return js_parse_expect(s, TOK_TEMPLATE);
+
+done:
+  if (call) {
+    /* Seal the objects */
+    seal_template_obj(ctx, raw_array);
+    seal_template_obj(ctx, template_object);
+    *argc = depth + 1;
+  } else {
+    emit_op(s, OP_call_method);
+    emit_u16(s, depth - 1);
+  }
+done1:
+  return next_token(s);
+}
+
+
+#define PROP_TYPE_IDENT 0
+#define PROP_TYPE_VAR   1
+#define PROP_TYPE_GET   2
+#define PROP_TYPE_SET   3
+#define PROP_TYPE_STAR  4
+#define PROP_TYPE_ASYNC 5
+#define PROP_TYPE_ASYNC_STAR 6
+
+#define PROP_TYPE_PRIVATE (1 << 4)
+
+static BOOL token_is_ident(int tok)
+{
+  /* Accept keywords and reserved words as property names */
+  return (tok == TOK_IDENT ||
+          (tok >= TOK_FIRST_KEYWORD &&
+           tok <= TOK_LAST_KEYWORD));
+}
+
+/* if the property is an expression, name = JS_ATOM_NULL */
+static int __exception js_parse_property_name(JSParseState *s,
+                                              JSAtom *pname,
+                                              BOOL allow_method, BOOL allow_var,
+                                              BOOL allow_private)
+{
+  int is_private = 0;
+  BOOL is_non_reserved_ident;
+  JSAtom name;
+  int prop_type;
+
+  prop_type = PROP_TYPE_IDENT;
+  if (allow_method) {
+    if (token_is_pseudo_keyword(s, JS_ATOM_get)
+        ||  token_is_pseudo_keyword(s, JS_ATOM_set)) {
+      /* get x(), set x() */
+      name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
+      if (next_token(s))
+        goto fail1;
+      if (s->token.val == ':' || s->token.val == ',' ||
+          s->token.val == '}' || s->token.val == '(') {
+        is_non_reserved_ident = TRUE;
+        goto ident_found;
+      }
+      prop_type = PROP_TYPE_GET + (name == JS_ATOM_set);
+      JS_FreeAtom(s->ctx, name);
+    } else if (s->token.val == '*') {
+      if (next_token(s))
+        goto fail;
+      prop_type = PROP_TYPE_STAR;
+    } else if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
+               peek_token(s, TRUE) != '\n') {
+      name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
+      if (next_token(s))
+        goto fail1;
+      if (s->token.val == ':' || s->token.val == ',' ||
+          s->token.val == '}' || s->token.val == '(') {
+        is_non_reserved_ident = TRUE;
+        goto ident_found;
+      }
+      JS_FreeAtom(s->ctx, name);
+      if (s->token.val == '*') {
+        if (next_token(s))
+          goto fail;
+        prop_type = PROP_TYPE_ASYNC_STAR;
+      } else {
+        prop_type = PROP_TYPE_ASYNC;
+      }
+    }
+  }
+
+  if (token_is_ident(s->token.val)) {
+    /* variable can only be a non-reserved identifier */
+    is_non_reserved_ident =
+        (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved);
+    /* keywords and reserved words have a valid atom */
+    name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
+    if (next_token(s))
+      goto fail1;
+  ident_found:
+    if (is_non_reserved_ident &&
+        prop_type == PROP_TYPE_IDENT && allow_var) {
+      if (!(s->token.val == ':' ||
+            (s->token.val == '(' && allow_method))) {
+        prop_type = PROP_TYPE_VAR;
+      }
+    }
+  } else if (s->token.val == TOK_STRING) {
+    name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
+    if (name == JS_ATOM_NULL)
+      goto fail;
+    if (next_token(s))
+      goto fail1;
+  } else if (s->token.val == TOK_NUMBER) {
+    JSValue val;
+    val = s->token.u.num.val;
+#ifdef CONFIG_BIGNUM
+    if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) {
+      JSBigFloat *p = JS_VALUE_GET_PTR(val);
+      val = s->ctx->rt->bigfloat_ops.
+            mul_pow10_to_float64(s->ctx, &p->num,
+                                 s->token.u.num.exponent);
+      if (JS_IsException(val))
+        goto fail;
+      name = JS_ValueToAtom(s->ctx, val);
+      JS_FreeValue(s->ctx, val);
+    } else
+#endif
+    {
+      name = JS_ValueToAtom(s->ctx, val);
+    }
+    if (name == JS_ATOM_NULL)
+      goto fail;
+    if (next_token(s))
+      goto fail1;
+  } else if (s->token.val == '[') {
+    if (next_token(s))
+      goto fail;
+    if (js_parse_expr(s))
+      goto fail;
+    if (js_parse_expect(s, ']'))
+      goto fail;
+    name = JS_ATOM_NULL;
+  } else if (s->token.val == TOK_PRIVATE_NAME && allow_private) {
+    name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
+    if (next_token(s))
+      goto fail1;
+    is_private = PROP_TYPE_PRIVATE;
+  } else {
+    goto invalid_prop;
+  }
+  if (prop_type != PROP_TYPE_IDENT && prop_type != PROP_TYPE_VAR &&
+      s->token.val != '(') {
+    JS_FreeAtom(s->ctx, name);
+  invalid_prop:
+    js_parse_error(s, "invalid property name");
+    goto fail;
+  }
+  *pname = name;
+  return prop_type | is_private;
+fail1:
+  JS_FreeAtom(s->ctx, name);
+fail:
+  *pname = JS_ATOM_NULL;
+  return -1;
+}
+
+typedef struct JSParsePos {
+  int last_line_num;
+  int line_num;
+  BOOL got_lf;
+  const uint8_t *ptr;
+} JSParsePos;
+
+static int js_parse_get_pos(JSParseState *s, JSParsePos *sp)
+{
+  sp->last_line_num = s->last_line_num;
+  sp->line_num = s->token.line_num;
+  sp->ptr = s->token.ptr;
+  sp->got_lf = s->got_lf;
+  return 0;
+}
+
+static __exception int js_parse_seek_token(JSParseState *s, const JSParsePos *sp)
+{
+  s->token.line_num = sp->last_line_num;
+  s->line_num = sp->line_num;
+  s->buf_ptr = sp->ptr;
+  s->got_lf = sp->got_lf;
+  return next_token(s);
+}
+
+/* return TRUE if a regexp literal is allowed after this token */
+static BOOL is_regexp_allowed(int tok)
+{
+  switch (tok) {
+    case TOK_NUMBER:
+    case TOK_STRING:
+    case TOK_REGEXP:
+    case TOK_DEC:
+    case TOK_INC:
+    case TOK_NULL:
+    case TOK_FALSE:
+    case TOK_TRUE:
+    case TOK_THIS:
+    case ')':
+    case ']':
+    case '}': /* XXX: regexp may occur after */
+    case TOK_IDENT:
+      return FALSE;
+    default:
+      return TRUE;
+  }
+}
+
+#define SKIP_HAS_SEMI       (1 << 0)
+#define SKIP_HAS_ELLIPSIS   (1 << 1)
+#define SKIP_HAS_ASSIGNMENT (1 << 2)
+
+/* XXX: improve speed with early bailout */
+/* XXX: no longer works if regexps are present. Could use previous
+   regexp parsing heuristics to handle most cases */
+static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_terminator)
+{
+  char state[256];
+  size_t level = 0;
+  JSParsePos pos;
+  int last_tok, tok = TOK_EOF;
+  int c, tok_len, bits = 0;
+
+  /* protect from underflow */
+  state[level++] = 0;
+
+  js_parse_get_pos(s, &pos);
+  last_tok = 0;
+  for (;;) {
+    switch(s->token.val) {
+      case '(':
+      case '[':
+      case '{':
+        if (level >= sizeof(state))
+          goto done;
+        state[level++] = s->token.val;
+        break;
+      case ')':
+        if (state[--level] != '(')
+          goto done;
+        break;
+      case ']':
+        if (state[--level] != '[')
+          goto done;
+        break;
+      case '}':
+        c = state[--level];
+        if (c == '`') {
+          /* continue the parsing of the template */
+          free_token(s, &s->token);
+          /* Resume TOK_TEMPLATE parsing (s->token.line_num and
+                 * s->token.ptr are OK) */
+          s->got_lf = FALSE;
+          s->last_line_num = s->token.line_num;
+          if (js_parse_template_part(s, s->buf_ptr))
+            goto done;
+          goto handle_template;
+        } else if (c != '{') {
+          goto done;
+        }
+        break;
+      case TOK_TEMPLATE:
+      handle_template:
+        if (s->token.u.str.sep != '`') {
+          /* '${' inside the template : closing '}' and continue
+             parsing the template */
+          if (level >= sizeof(state))
+            goto done;
+          state[level++] = '`';
+        }
+        break;
+      case TOK_EOF:
+        goto done;
+      case ';':
+        if (level == 2) {
+          bits |= SKIP_HAS_SEMI;
+        }
+        break;
+      case TOK_ELLIPSIS:
+        if (level == 2) {
+          bits |= SKIP_HAS_ELLIPSIS;
+        }
+        break;
+      case '=':
+        bits |= SKIP_HAS_ASSIGNMENT;
+        break;
+
+      case TOK_DIV_ASSIGN:
+        tok_len = 2;
+        goto parse_regexp;
+      case '/':
+        tok_len = 1;
+      parse_regexp:
+        if (is_regexp_allowed(last_tok)) {
+          s->buf_ptr -= tok_len;
+          if (js_parse_regexp(s)) {
+            /* XXX: should clear the exception */
+            goto done;
+          }
+        }
+        break;
+    }
+    /* last_tok is only used to recognize regexps */
+    if (s->token.val == TOK_IDENT &&
+        (token_is_pseudo_keyword(s, JS_ATOM_of) ||
+         token_is_pseudo_keyword(s, JS_ATOM_yield))) {
+      last_tok = TOK_OF;
+    } else {
+      last_tok = s->token.val;
+    }
+    if (next_token(s)) {
+      /* XXX: should clear the exception generated by next_token() */
+      break;
+    }
+    if (level <= 1) {
+      tok = s->token.val;
+      if (token_is_pseudo_keyword(s, JS_ATOM_of))
+        tok = TOK_OF;
+      if (no_line_terminator && s->last_line_num != s->token.line_num)
+        tok = '\n';
+      break;
+    }
+  }
+done:
+  if (pbits) {
+    *pbits = bits;
+  }
+  if (js_parse_seek_token(s, &pos))
+    return -1;
+  return tok;
+}
+
+static void set_object_name(JSParseState *s, JSAtom name)
+{
+  JSFunctionDef *fd = s->cur_func;
+  int opcode;
+
+  opcode = get_prev_opcode(fd);
+  if (opcode == OP_set_name) {
+    /* XXX: should free atom after OP_set_name? */
+    fd->byte_code.size = fd->last_opcode_pos;
+    fd->last_opcode_pos = -1;
+    emit_op(s, OP_set_name);
+    emit_atom(s, name);
+  } else if (opcode == OP_set_class_name) {
+    int define_class_pos;
+    JSAtom atom;
+    define_class_pos = fd->last_opcode_pos + 1 -
+                       get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
+    assert(fd->byte_code.buf[define_class_pos] == OP_define_class);
+    /* for consistency we free the previous atom which is
+       JS_ATOM_empty_string */
+    atom = get_u32(fd->byte_code.buf + define_class_pos + 1);
+    JS_FreeAtom(s->ctx, atom);
+    put_u32(fd->byte_code.buf + define_class_pos + 1,
+            JS_DupAtom(s->ctx, name));
+    fd->last_opcode_pos = -1;
+  }
+}
+
+static void set_object_name_computed(JSParseState *s)
+{
+  JSFunctionDef *fd = s->cur_func;
+  int opcode;
+
+  opcode = get_prev_opcode(fd);
+  if (opcode == OP_set_name) {
+    /* XXX: should free atom after OP_set_name? */
+    fd->byte_code.size = fd->last_opcode_pos;
+    fd->last_opcode_pos = -1;
+    emit_op(s, OP_set_name_computed);
+  } else if (opcode == OP_set_class_name) {
+    int define_class_pos;
+    define_class_pos = fd->last_opcode_pos + 1 -
+                       get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
+    assert(fd->byte_code.buf[define_class_pos] == OP_define_class);
+    fd->byte_code.buf[define_class_pos] = OP_define_class_computed;
+    fd->last_opcode_pos = -1;
+  }
+}
+
+static __exception int js_parse_object_literal(JSParseState *s)
+{
+  JSAtom name = JS_ATOM_NULL;
+  const uint8_t *start_ptr;
+  int start_line, prop_type;
+  BOOL has_proto;
+
+  if (next_token(s))
+    goto fail;
+  /* XXX: add an initial length that will be patched back */
+  emit_op(s, OP_object);
+  has_proto = FALSE;
+  while (s->token.val != '}') {
+    /* specific case for getter/setter */
+    start_ptr = s->token.ptr;
+    start_line = s->token.line_num;
+
+    if (s->token.val == TOK_ELLIPSIS) {
+      if (next_token(s))
+        return -1;
+      if (js_parse_assign_expr(s))
+        return -1;
+      emit_op(s, OP_null);  /* dummy excludeList */
+      emit_op(s, OP_copy_data_properties);
+      emit_u8(s, 2 | (1 << 2) | (0 << 5));
+      emit_op(s, OP_drop); /* pop excludeList */
+      emit_op(s, OP_drop); /* pop src object */
+      goto next;
+    }
+
+    prop_type = js_parse_property_name(s, &name, TRUE, TRUE, FALSE);
+    if (prop_type < 0)
+      goto fail;
+
+    if (prop_type == PROP_TYPE_VAR) {
+      /* shortcut for x: x */
+      emit_op(s, OP_scope_get_var);
+      emit_atom(s, name);
+      emit_u16(s, s->cur_func->scope_level);
+      emit_op(s, OP_define_field);
+      emit_atom(s, name);
+    } else if (s->token.val == '(') {
+      BOOL is_getset = (prop_type == PROP_TYPE_GET ||
+                        prop_type == PROP_TYPE_SET);
+      JSParseFunctionEnum func_type;
+      JSFunctionKindEnum func_kind;
+      int op_flags;
+
+      func_kind = JS_FUNC_NORMAL;
+      if (is_getset) {
+        func_type = JS_PARSE_FUNC_GETTER + prop_type - PROP_TYPE_GET;
+      } else {
+        func_type = JS_PARSE_FUNC_METHOD;
+        if (prop_type == PROP_TYPE_STAR)
+          func_kind = JS_FUNC_GENERATOR;
+        else if (prop_type == PROP_TYPE_ASYNC)
+          func_kind = JS_FUNC_ASYNC;
+        else if (prop_type == PROP_TYPE_ASYNC_STAR)
+          func_kind = JS_FUNC_ASYNC_GENERATOR;
+      }
+      if (js_parse_function_decl(s, func_type, func_kind, JS_ATOM_NULL,
+                                 start_ptr, start_line))
+        goto fail;
+      if (name == JS_ATOM_NULL) {
+        emit_op(s, OP_define_method_computed);
+      } else {
+        emit_op(s, OP_define_method);
+        emit_atom(s, name);
+      }
+      if (is_getset) {
+        op_flags = OP_DEFINE_METHOD_GETTER +
+                   prop_type - PROP_TYPE_GET;
+      } else {
+        op_flags = OP_DEFINE_METHOD_METHOD;
+      }
+      emit_u8(s, op_flags | OP_DEFINE_METHOD_ENUMERABLE);
+    } else {
+      if (js_parse_expect(s, ':'))
+        goto fail;
+      if (js_parse_assign_expr(s))
+        goto fail;
+      if (name == JS_ATOM_NULL) {
+        set_object_name_computed(s);
+        emit_op(s, OP_define_array_el);
+        emit_op(s, OP_drop);
+      } else if (name == JS_ATOM___proto__) {
+        if (has_proto) {
+          js_parse_error(s, "duplicate __proto__ property name");
+          goto fail;
+        }
+        emit_op(s, OP_set_proto);
+        has_proto = TRUE;
+      } else {
+        set_object_name(s, name);
+        emit_op(s, OP_define_field);
+        emit_atom(s, name);
+      }
+    }
+    JS_FreeAtom(s->ctx, name);
+  next:
+    name = JS_ATOM_NULL;
+    if (s->token.val != ',')
+      break;
+    if (next_token(s))
+      goto fail;
+  }
+  if (js_parse_expect(s, '}'))
+    goto fail;
+  return 0;
+fail:
+  JS_FreeAtom(s->ctx, name);
+  return -1;
+}
+
+/* allow the 'in' binary operator */
+#define PF_IN_ACCEPTED  (1 << 0)
+/* allow function calls parsing in js_parse_postfix_expr() */
+#define PF_POSTFIX_CALL (1 << 1)
+/* allow arrow functions parsing in js_parse_postfix_expr() */
+#define PF_ARROW_FUNC   (1 << 2)
+/* allow the exponentiation operator in js_parse_unary() */
+#define PF_POW_ALLOWED  (1 << 3)
+/* forbid the exponentiation operator in js_parse_unary() */
+#define PF_POW_FORBIDDEN (1 << 4)
+
+static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags);
+
+static __exception int js_parse_left_hand_side_expr(JSParseState *s)
+{
+  return js_parse_postfix_expr(s, PF_POSTFIX_CALL);
+}
+
+/* XXX: could generate specific bytecode */
+static __exception int js_parse_class_default_ctor(JSParseState *s,
+                                                   BOOL has_super,
+                                                   JSFunctionDef **pfd)
+{
+  JSParsePos pos;
+  const char *str;
+  int ret, line_num;
+  JSParseFunctionEnum func_type;
+  const uint8_t *saved_buf_end;
+
+  js_parse_get_pos(s, &pos);
+  if (has_super) {
+    /* spec change: no argument evaluation */
+    str = "(){super(...arguments);}";
+    func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR;
+  } else {
+    str = "(){}";
+    func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;
+  }
+  line_num = s->token.line_num;
+  saved_buf_end = s->buf_end;
+  s->buf_ptr = (uint8_t *)str;
+  s->buf_end = (uint8_t *)(str + strlen(str));
+  ret = next_token(s);
+  if (!ret) {
+    ret = js_parse_function_decl2(s, func_type, JS_FUNC_NORMAL,
+                                  JS_ATOM_NULL, (uint8_t *)str,
+                                  line_num, JS_PARSE_EXPORT_NONE, pfd);
+  }
+  s->buf_end = saved_buf_end;
+  ret |= js_parse_seek_token(s, &pos);
+  return ret;
+}
+
+/* find field in the current scope */
+static int find_private_class_field(JSContext *ctx, JSFunctionDef *fd,
+                                    JSAtom name, int scope_level)
+{
+  int idx;
+  idx = fd->scopes[scope_level].first;
+  while (idx != -1) {
+    if (fd->vars[idx].scope_level != scope_level)
+      break;
+    if (fd->vars[idx].var_name == name)
+      return idx;
+    idx = fd->vars[idx].scope_next;
+  }
+  return -1;
+}
+
+/* initialize the class fields, called by the constructor. Note:
+   super() can be called in an arrow function, so <this> and
+   <class_fields_init> can be variable references */
+static void emit_class_field_init(JSParseState *s)
+{
+  int label_next;
+
+  emit_op(s, OP_scope_get_var);
+  emit_atom(s, JS_ATOM_class_fields_init);
+  emit_u16(s, s->cur_func->scope_level);
+
+  /* no need to call the class field initializer if not defined */
+  emit_op(s, OP_dup);
+  label_next = emit_goto(s, OP_if_false, -1);
+
+  emit_op(s, OP_scope_get_var);
+  emit_atom(s, JS_ATOM_this);
+  emit_u16(s, 0);
+
+  emit_op(s, OP_swap);
+
+  emit_op(s, OP_call_method);
+  emit_u16(s, 0);
+
+  emit_label(s, label_next);
+  emit_op(s, OP_drop);
+}
+
+/* build a private setter function name from the private getter name */
+static JSAtom get_private_setter_name(JSContext *ctx, JSAtom name)
+{
+  return js_atom_concat_str(ctx, name, "<set>");
+}
+
+typedef struct {
+  JSFunctionDef *fields_init_fd;
+  int computed_fields_count;
+  BOOL has_brand;
+  int brand_push_pos;
+} ClassFieldsDef;
+
+static __exception int emit_class_init_start(JSParseState *s,
+                                             ClassFieldsDef *cf)
+{
+  int label_add_brand;
+
+  cf->fields_init_fd = js_parse_function_class_fields_init(s);
+  if (!cf->fields_init_fd)
+    return -1;
+
+  s->cur_func = cf->fields_init_fd;
+
+  /* XXX: would be better to add the code only if needed, maybe in a
+     later pass */
+  emit_op(s, OP_push_false); /* will be patched later */
+  cf->brand_push_pos = cf->fields_init_fd->last_opcode_pos;
+  label_add_brand = emit_goto(s, OP_if_false, -1);
+
+  emit_op(s, OP_scope_get_var);
+  emit_atom(s, JS_ATOM_this);
+  emit_u16(s, 0);
+
+  emit_op(s, OP_scope_get_var);
+  emit_atom(s, JS_ATOM_home_object);
+  emit_u16(s, 0);
+
+  emit_op(s, OP_add_brand);
+
+  emit_label(s, label_add_brand);
+
+  s->cur_func = s->cur_func->parent;
+  return 0;
+}
+
+static __exception int add_brand(JSParseState *s, ClassFieldsDef *cf)
+{
+  if (!cf->has_brand) {
+    /* define the brand field in 'this' of the initializer */
+    if (!cf->fields_init_fd) {
+      if (emit_class_init_start(s, cf))
+        return -1;
+    }
+    /* patch the start of the function to enable the OP_add_brand code */
+    cf->fields_init_fd->byte_code.buf[cf->brand_push_pos] = OP_push_true;
+
+    cf->has_brand = TRUE;
+  }
+  return 0;
+}
+
+static void emit_class_init_end(JSParseState *s, ClassFieldsDef *cf)
+{
+  int cpool_idx;
+
+  s->cur_func = cf->fields_init_fd;
+  emit_op(s, OP_return_undef);
+  s->cur_func = s->cur_func->parent;
+
+  cpool_idx = cpool_add(s, JS_NULL);
+  cf->fields_init_fd->parent_cpool_idx = cpool_idx;
+  emit_op(s, OP_fclosure);
+  emit_u32(s, cpool_idx);
+  emit_op(s, OP_set_home_object);
+}
+
+
+static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
+                                      JSParseExportEnum export_flag)
+{
+  JSContext *ctx = s->ctx;
+  JSFunctionDef *fd = s->cur_func;
+  JSAtom name = JS_ATOM_NULL, class_name = JS_ATOM_NULL, class_name1;
+  JSAtom class_var_name = JS_ATOM_NULL;
+  JSFunctionDef *method_fd, *ctor_fd;
+  int saved_js_mode, class_name_var_idx, prop_type, ctor_cpool_offset;
+  int class_flags = 0, i, define_class_offset;
+  BOOL is_static, is_private;
+  const uint8_t *class_start_ptr = s->token.ptr;
+  const uint8_t *start_ptr;
+  ClassFieldsDef class_fields[2];
+
+  /* classes are parsed and executed in strict mode */
+  saved_js_mode = fd->js_mode;
+  fd->js_mode |= JS_MODE_STRICT;
+  if (next_token(s))
+    goto fail;
+  if (s->token.val == TOK_IDENT) {
+    if (s->token.u.ident.is_reserved) {
+      js_parse_error_reserved_identifier(s);
+      goto fail;
+    }
+    class_name = JS_DupAtom(ctx, s->token.u.ident.atom);
+    if (next_token(s))
+      goto fail;
+  } else if (!is_class_expr && export_flag != JS_PARSE_EXPORT_DEFAULT) {
+    js_parse_error(s, "class statement requires a name");
+    goto fail;
+  }
+  if (!is_class_expr) {
+    if (class_name == JS_ATOM_NULL)
+      class_var_name = JS_ATOM__default_; /* export default */
+    else
+      class_var_name = class_name;
+    class_var_name = JS_DupAtom(ctx, class_var_name);
+  }
+
+  push_scope(s);
+
+  if (s->token.val == TOK_EXTENDS) {
+    class_flags = JS_DEFINE_CLASS_HAS_HERITAGE;
+    if (next_token(s))
+      goto fail;
+    if (js_parse_left_hand_side_expr(s))
+      goto fail;
+  } else {
+    emit_op(s, OP_undefined);
+  }
+
+  /* add a 'const' definition for the class name */
+  if (class_name != JS_ATOM_NULL) {
+    class_name_var_idx = define_var(s, fd, class_name, JS_VAR_DEF_CONST);
+    if (class_name_var_idx < 0)
+      goto fail;
+  }
+
+  if (js_parse_expect(s, '{'))
+    goto fail;
+
+  /* this scope contains the private fields */
+  push_scope(s);
+
+  emit_op(s, OP_push_const);
+  ctor_cpool_offset = fd->byte_code.size;
+  emit_u32(s, 0); /* will be patched at the end of the class parsing */
+
+  if (class_name == JS_ATOM_NULL) {
+    if (class_var_name != JS_ATOM_NULL)
+      class_name1 = JS_ATOM_default;
+    else
+      class_name1 = JS_ATOM_empty_string;
+  } else {
+    class_name1 = class_name;
+  }
+
+  emit_op(s, OP_define_class);
+  emit_atom(s, class_name1);
+  emit_u8(s, class_flags);
+  define_class_offset = fd->last_opcode_pos;
+
+  for(i = 0; i < 2; i++) {
+    ClassFieldsDef *cf = &class_fields[i];
+    cf->fields_init_fd = NULL;
+    cf->computed_fields_count = 0;
+    cf->has_brand = FALSE;
+  }
+
+  ctor_fd = NULL;
+  while (s->token.val != '}') {
+    if (s->token.val == ';') {
+      if (next_token(s))
+        goto fail;
+      continue;
+    }
+    is_static = (s->token.val == TOK_STATIC);
+    prop_type = -1;
+    if (is_static) {
+      if (next_token(s))
+        goto fail;
+      /* allow "static" field name */
+      if (s->token.val == ';' || s->token.val == '=') {
+        is_static = FALSE;
+        name = JS_DupAtom(ctx, JS_ATOM_static);
+        prop_type = PROP_TYPE_IDENT;
+      }
+    }
+    if (is_static)
+      emit_op(s, OP_swap);
+    start_ptr = s->token.ptr;
+    if (prop_type < 0) {
+      prop_type = js_parse_property_name(s, &name, TRUE, FALSE, TRUE);
+      if (prop_type < 0)
+        goto fail;
+    }
+    is_private = prop_type & PROP_TYPE_PRIVATE;
+    prop_type &= ~PROP_TYPE_PRIVATE;
+
+    if ((name == JS_ATOM_constructor && !is_static &&
+         prop_type != PROP_TYPE_IDENT) ||
+        (name == JS_ATOM_prototype && is_static) ||
+        name == JS_ATOM_hash_constructor) {
+      js_parse_error(s, "invalid method name");
+      goto fail;
+    }
+    if (prop_type == PROP_TYPE_GET || prop_type == PROP_TYPE_SET) {
+      BOOL is_set = prop_type - PROP_TYPE_GET;
+      JSFunctionDef *method_fd;
+
+      if (is_private) {
+        int idx, var_kind;
+        idx = find_private_class_field(ctx, fd, name, fd->scope_level);
+        if (idx >= 0) {
+          var_kind = fd->vars[idx].var_kind;
+          if (var_kind == JS_VAR_PRIVATE_FIELD ||
+              var_kind == JS_VAR_PRIVATE_METHOD ||
+              var_kind == JS_VAR_PRIVATE_GETTER_SETTER ||
+              var_kind == (JS_VAR_PRIVATE_GETTER + is_set)) {
+            goto private_field_already_defined;
+          }
+          fd->vars[idx].var_kind = JS_VAR_PRIVATE_GETTER_SETTER;
+        } else {
+          if (add_private_class_field(s, fd, name,
+                                      JS_VAR_PRIVATE_GETTER + is_set) < 0)
+            goto fail;
+        }
+        if (add_brand(s, &class_fields[is_static]) < 0)
+          goto fail;
+      }
+
+      if (js_parse_function_decl2(s, JS_PARSE_FUNC_GETTER + is_set,
+                                  JS_FUNC_NORMAL, JS_ATOM_NULL,
+                                  start_ptr, s->token.line_num,
+                                  JS_PARSE_EXPORT_NONE, &method_fd))
+        goto fail;
+      if (is_private) {
+        method_fd->need_home_object = TRUE; /* needed for brand check */
+        emit_op(s, OP_set_home_object);
+        /* XXX: missing function name */
+        emit_op(s, OP_scope_put_var_init);
+        if (is_set) {
+          JSAtom setter_name;
+          int ret;
+
+          setter_name = get_private_setter_name(ctx, name);
+          if (setter_name == JS_ATOM_NULL)
+            goto fail;
+          emit_atom(s, setter_name);
+          ret = add_private_class_field(s, fd, setter_name,
+                                        JS_VAR_PRIVATE_SETTER);
+          JS_FreeAtom(ctx, setter_name);
+          if (ret < 0)
+            goto fail;
+        } else {
+          emit_atom(s, name);
+        }
+        emit_u16(s, s->cur_func->scope_level);
+      } else {
+        if (name == JS_ATOM_NULL) {
+          emit_op(s, OP_define_method_computed);
+        } else {
+          emit_op(s, OP_define_method);
+          emit_atom(s, name);
+        }
+        emit_u8(s, OP_DEFINE_METHOD_GETTER + is_set);
+      }
+    } else if (prop_type == PROP_TYPE_IDENT && s->token.val != '(') {
+      ClassFieldsDef *cf = &class_fields[is_static];
+      JSAtom field_var_name = JS_ATOM_NULL;
+
+      /* class field */
+
+      /* XXX: spec: not consistent with method name checks */
+      if (name == JS_ATOM_constructor || name == JS_ATOM_prototype) {
+        js_parse_error(s, "invalid field name");
+        goto fail;
+      }
+
+      if (is_private) {
+        if (find_private_class_field(ctx, fd, name,
+                                     fd->scope_level) >= 0) {
+          goto private_field_already_defined;
+        }
+        if (add_private_class_field(s, fd, name,
+                                    JS_VAR_PRIVATE_FIELD) < 0)
+          goto fail;
+        emit_op(s, OP_private_symbol);
+        emit_atom(s, name);
+        emit_op(s, OP_scope_put_var_init);
+        emit_atom(s, name);
+        emit_u16(s, s->cur_func->scope_level);
+      }
+
+      if (!cf->fields_init_fd) {
+        if (emit_class_init_start(s, cf))
+          goto fail;
+      }
+      if (name == JS_ATOM_NULL ) {
+        /* save the computed field name into a variable */
+        field_var_name = js_atom_concat_num(ctx, JS_ATOM_computed_field + is_static, cf->computed_fields_count);
+        if (field_var_name == JS_ATOM_NULL)
+          goto fail;
+        if (define_var(s, fd, field_var_name, JS_VAR_DEF_CONST) < 0) {
+          JS_FreeAtom(ctx, field_var_name);
+          goto fail;
+        }
+        emit_op(s, OP_to_propkey);
+        emit_op(s, OP_scope_put_var_init);
+        emit_atom(s, field_var_name);
+        emit_u16(s, s->cur_func->scope_level);
+      }
+      s->cur_func = cf->fields_init_fd;
+      emit_op(s, OP_scope_get_var);
+      emit_atom(s, JS_ATOM_this);
+      emit_u16(s, 0);
+
+      if (name == JS_ATOM_NULL) {
+        emit_op(s, OP_scope_get_var);
+        emit_atom(s, field_var_name);
+        emit_u16(s, s->cur_func->scope_level);
+        cf->computed_fields_count++;
+        JS_FreeAtom(ctx, field_var_name);
+      } else if (is_private) {
+        emit_op(s, OP_scope_get_var);
+        emit_atom(s, name);
+        emit_u16(s, s->cur_func->scope_level);
+      }
+
+      if (s->token.val == '=') {
+        if (next_token(s))
+          goto fail;
+        if (js_parse_assign_expr(s))
+          goto fail;
+      } else {
+        emit_op(s, OP_undefined);
+      }
+      if (is_private) {
+        set_object_name_computed(s);
+        emit_op(s, OP_define_private_field);
+      } else if (name == JS_ATOM_NULL) {
+        set_object_name_computed(s);
+        emit_op(s, OP_define_array_el);
+        emit_op(s, OP_drop);
+      } else {
+        set_object_name(s, name);
+        emit_op(s, OP_define_field);
+        emit_atom(s, name);
+      }
+      s->cur_func = s->cur_func->parent;
+      if (js_parse_expect_semi(s))
+        goto fail;
+    } else {
+      JSParseFunctionEnum func_type;
+      JSFunctionKindEnum func_kind;
+
+      func_type = JS_PARSE_FUNC_METHOD;
+      func_kind = JS_FUNC_NORMAL;
+      if (prop_type == PROP_TYPE_STAR) {
+        func_kind = JS_FUNC_GENERATOR;
+      } else if (prop_type == PROP_TYPE_ASYNC) {
+        func_kind = JS_FUNC_ASYNC;
+      } else if (prop_type == PROP_TYPE_ASYNC_STAR) {
+        func_kind = JS_FUNC_ASYNC_GENERATOR;
+      } else if (name == JS_ATOM_constructor && !is_static) {
+        if (ctor_fd) {
+          js_parse_error(s, "property constructor appears more than once");
+          goto fail;
+        }
+        if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE)
+          func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR;
+        else
+          func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;
+      }
+      if (is_private) {
+        if (add_brand(s, &class_fields[is_static]) < 0)
+          goto fail;
+      }
+      if (js_parse_function_decl2(s, func_type, func_kind, JS_ATOM_NULL, start_ptr, s->token.line_num, JS_PARSE_EXPORT_NONE, &method_fd))
+        goto fail;
+      if (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR ||
+          func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) {
+        ctor_fd = method_fd;
+      } else if (is_private) {
+        method_fd->need_home_object = TRUE; /* needed for brand check */
+        if (find_private_class_field(ctx, fd, name,
+                                     fd->scope_level) >= 0) {
+        private_field_already_defined:
+          js_parse_error(s, "private class field is already defined");
+          goto fail;
+        }
+        if (add_private_class_field(s, fd, name,
+                                    JS_VAR_PRIVATE_METHOD) < 0)
+          goto fail;
+        emit_op(s, OP_set_home_object);
+        emit_op(s, OP_set_name);
+        emit_atom(s, name);
+        emit_op(s, OP_scope_put_var_init);
+        emit_atom(s, name);
+        emit_u16(s, s->cur_func->scope_level);
+      } else {
+        if (name == JS_ATOM_NULL) {
+          emit_op(s, OP_define_method_computed);
+        } else {
+          emit_op(s, OP_define_method);
+          emit_atom(s, name);
+        }
+        emit_u8(s, OP_DEFINE_METHOD_METHOD);
+      }
+    }
+    if (is_static)
+      emit_op(s, OP_swap);
+    JS_FreeAtom(ctx, name);
+    name = JS_ATOM_NULL;
+  }
+
+  if (s->token.val != '}') {
+    js_parse_error(s, "expecting '%c'", '}');
+    goto fail;
+  }
+
+  if (!ctor_fd) {
+    if (js_parse_class_default_ctor(s, class_flags & JS_DEFINE_CLASS_HAS_HERITAGE, &ctor_fd))
+      goto fail;
+  }
+  /* patch the constant pool index for the constructor */
+  put_u32(fd->byte_code.buf + ctor_cpool_offset, ctor_fd->parent_cpool_idx);
+
+  /* store the class source code in the constructor. */
+  if (!(fd->js_mode & JS_MODE_STRIP)) {
+    js_free(ctx, ctor_fd->source);
+    ctor_fd->source_len = s->buf_ptr - class_start_ptr;
+    ctor_fd->source = js_strndup(ctx, (const char *)class_start_ptr,
+                                 ctor_fd->source_len);
+    if (!ctor_fd->source)
+      goto fail;
+  }
+
+  /* consume the '}' */
+  if (next_token(s))
+    goto fail;
+
+  /* store the function to initialize the fields to that it can be
+     referenced by the constructor */
+  {
+    ClassFieldsDef *cf = &class_fields[0];
+    int var_idx;
+
+    var_idx = define_var(s, fd, JS_ATOM_class_fields_init,
+                         JS_VAR_DEF_CONST);
+    if (var_idx < 0)
+      goto fail;
+    if (cf->fields_init_fd) {
+      emit_class_init_end(s, cf);
+    } else {
+      emit_op(s, OP_undefined);
+    }
+    emit_op(s, OP_scope_put_var_init);
+    emit_atom(s, JS_ATOM_class_fields_init);
+    emit_u16(s, s->cur_func->scope_level);
+  }
+
+  /* drop the prototype */
+  emit_op(s, OP_drop);
+
+  /* initialize the static fields */
+  if (class_fields[1].fields_init_fd != NULL) {
+    ClassFieldsDef *cf = &class_fields[1];
+    emit_op(s, OP_dup);
+    emit_class_init_end(s, cf);
+    emit_op(s, OP_call_method);
+    emit_u16(s, 0);
+    emit_op(s, OP_drop);
+  }
+
+  if (class_name != JS_ATOM_NULL) {
+    /* store the class name in the scoped class name variable (it
+       is independent from the class statement variable
+       definition) */
+    emit_op(s, OP_dup);
+    emit_op(s, OP_scope_put_var_init);
+    emit_atom(s, class_name);
+    emit_u16(s, fd->scope_level);
+  }
+  pop_scope(s);
+  pop_scope(s);
+
+  /* the class statements have a block level scope */
+  if (class_var_name != JS_ATOM_NULL) {
+    if (define_var(s, fd, class_var_name, JS_VAR_DEF_LET) < 0)
+      goto fail;
+    emit_op(s, OP_scope_put_var_init);
+    emit_atom(s, class_var_name);
+    emit_u16(s, fd->scope_level);
+  } else {
+    if (class_name == JS_ATOM_NULL) {
+      /* cannot use OP_set_name because the name of the class
+         must be defined before the static initializers are
+         executed */
+      emit_op(s, OP_set_class_name);
+      emit_u32(s, fd->last_opcode_pos + 1 - define_class_offset);
+    }
+  }
+
+  if (export_flag != JS_PARSE_EXPORT_NONE) {
+    if (!add_export_entry(s, fd->module,
+                          class_var_name,
+                          export_flag == JS_PARSE_EXPORT_NAMED ? class_var_name : JS_ATOM_default,
+                          JS_EXPORT_TYPE_LOCAL))
+      goto fail;
+  }
+
+  JS_FreeAtom(ctx, class_name);
+  JS_FreeAtom(ctx, class_var_name);
+  fd->js_mode = saved_js_mode;
+  return 0;
+fail:
+  JS_FreeAtom(ctx, name);
+  JS_FreeAtom(ctx, class_name);
+  JS_FreeAtom(ctx, class_var_name);
+  fd->js_mode = saved_js_mode;
+  return -1;
+}
+
+static __exception int js_parse_array_literal(JSParseState *s)
+{
+  uint32_t idx;
+  BOOL need_length;
+
+  if (next_token(s))
+    return -1;
+  /* small regular arrays are created on the stack */
+  idx = 0;
+  while (s->token.val != ']' && idx < 32) {
+    if (s->token.val == ',' || s->token.val == TOK_ELLIPSIS)
+      break;
+    if (js_parse_assign_expr(s))
+      return -1;
+    idx++;
+    /* accept trailing comma */
+    if (s->token.val == ',') {
+      if (next_token(s))
+        return -1;
+    } else
+        if (s->token.val != ']')
+      goto done;
+  }
+  emit_op(s, OP_array_from);
+  emit_u16(s, idx);
+
+  /* larger arrays and holes are handled with explicit indices */
+  need_length = FALSE;
+  while (s->token.val != ']' && idx < 0x7fffffff) {
+    if (s->token.val == TOK_ELLIPSIS)
+      break;
+    need_length = TRUE;
+    if (s->token.val != ',') {
+      if (js_parse_assign_expr(s))
+        return -1;
+      emit_op(s, OP_define_field);
+      emit_u32(s, __JS_AtomFromUInt32(idx));
+      need_length = FALSE;
+    }
+    idx++;
+    /* accept trailing comma */
+    if (s->token.val == ',') {
+      if (next_token(s))
+        return -1;
+    }
+  }
+  if (s->token.val == ']') {
+    if (need_length) {
+      /* Set the length: Cannot use OP_define_field because
+         length is not configurable */
+      emit_op(s, OP_dup);
+      emit_op(s, OP_push_i32);
+      emit_u32(s, idx);
+      emit_op(s, OP_put_field);
+      emit_atom(s, JS_ATOM_length);
+    }
+    goto done;
+  }
+
+  /* huge arrays and spread elements require a dynamic index on the stack */
+  emit_op(s, OP_push_i32);
+  emit_u32(s, idx);
+
+  /* stack has array, index */
+  while (s->token.val != ']') {
+    if (s->token.val == TOK_ELLIPSIS) {
+      if (next_token(s))
+        return -1;
+      if (js_parse_assign_expr(s))
+        return -1;
+#if 1
+      emit_op(s, OP_append);
+#else
+      int label_next, label_done;
+      label_next = new_label(s);
+      label_done = new_label(s);
+      /* enumerate object */
+      emit_op(s, OP_for_of_start);
+      emit_op(s, OP_rot5l);
+      emit_op(s, OP_rot5l);
+      emit_label(s, label_next);
+      /* on stack: enum_rec array idx */
+      emit_op(s, OP_for_of_next);
+      emit_u8(s, 2);
+      emit_goto(s, OP_if_true, label_done);
+      /* append element */
+      /* enum_rec array idx val -> enum_rec array new_idx */
+      emit_op(s, OP_define_array_el);
+      emit_op(s, OP_inc);
+      emit_goto(s, OP_goto, label_next);
+      emit_label(s, label_done);
+      /* close enumeration */
+      emit_op(s, OP_drop); /* drop undef val */
+      emit_op(s, OP_nip1); /* drop enum_rec */
+      emit_op(s, OP_nip1);
+      emit_op(s, OP_nip1);
+#endif
+    } else {
+      need_length = TRUE;
+      if (s->token.val != ',') {
+        if (js_parse_assign_expr(s))
+          return -1;
+        /* a idx val */
+        emit_op(s, OP_define_array_el);
+        need_length = FALSE;
+      }
+      emit_op(s, OP_inc);
+    }
+    if (s->token.val != ',')
+      break;
+    if (next_token(s))
+      return -1;
+  }
+  if (need_length) {
+    /* Set the length: cannot use OP_define_field because
+       length is not configurable */
+    emit_op(s, OP_dup1);    /* array length - array array length */
+    emit_op(s, OP_put_field);
+    emit_atom(s, JS_ATOM_length);
+  } else {
+    emit_op(s, OP_drop);    /* array length - array */
+  }
+done:
+  return js_parse_expect(s, ']');
+}
+
+/* XXX: remove */
+static BOOL has_with_scope(JSFunctionDef *s, int scope_level)
+{
+  /* check if scope chain contains a with statement */
+  while (s) {
+    int scope_idx = s->scopes[scope_level].first;
+    while (scope_idx >= 0) {
+      JSVarDef *vd = &s->vars[scope_idx];
+
+      if (vd->var_name == JS_ATOM__with_)
+        return TRUE;
+      scope_idx = vd->scope_next;
+    }
+    /* check parent scopes */
+    scope_level = s->parent_scope_level;
+    s = s->parent;
+  }
+  return FALSE;
+}
+
+static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
+                                  JSAtom *pname, int *plabel, int *pdepth, BOOL keep,
+                                  int tok)
+{
+  JSFunctionDef *fd;
+  int opcode, scope, label, depth;
+  JSAtom name;
+
+  /* we check the last opcode to get the lvalue type */
+  fd = s->cur_func;
+  scope = 0;
+  name = JS_ATOM_NULL;
+  label = -1;
+  depth = 0;
+  switch(opcode = get_prev_opcode(fd)) {
+    case OP_scope_get_var:
+      name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
+      scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
+      if ((name == JS_ATOM_arguments || name == JS_ATOM_eval) &&
+          (fd->js_mode & JS_MODE_STRICT)) {
+        return js_parse_error(s, "invalid lvalue in strict mode");
+      }
+      if (name == JS_ATOM_this || name == JS_ATOM_new_target)
+        goto invalid_lvalue;
+      depth = 2;  /* will generate OP_get_ref_value */
+      break;
+    case OP_get_field:
+      name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
+      depth = 1;
+      break;
+    case OP_scope_get_private_field:
+      name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
+      scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
+      depth = 1;
+      break;
+    case OP_get_array_el:
+      depth = 2;
+      break;
+    case OP_get_super_value:
+      depth = 3;
+      break;
+    default:
+    invalid_lvalue:
+      if (tok == TOK_FOR) {
+        return js_parse_error(s, "invalid for in/of left hand-side");
+      } else if (tok == TOK_INC || tok == TOK_DEC) {
+        return js_parse_error(s, "invalid increment/decrement operand");
+      } else if (tok == '[' || tok == '{') {
+        return js_parse_error(s, "invalid destructuring target");
+      } else {
+        return js_parse_error(s, "invalid assignment left-hand side");
+      }
+  }
+  /* remove the last opcode */
+  fd->byte_code.size = fd->last_opcode_pos;
+  fd->last_opcode_pos = -1;
+
+  if (keep) {
+    /* get the value but keep the object/fields on the stack */
+    switch(opcode) {
+      case OP_scope_get_var:
+        label = new_label(s);
+        emit_op(s, OP_scope_make_ref);
+        emit_atom(s, name);
+        emit_u32(s, label);
+        emit_u16(s, scope);
+        update_label(fd, label, 1);
+        emit_op(s, OP_get_ref_value);
+        opcode = OP_get_ref_value;
+        break;
+      case OP_get_field:
+        emit_op(s, OP_get_field2);
+        emit_atom(s, name);
+        break;
+      case OP_scope_get_private_field:
+        emit_op(s, OP_scope_get_private_field2);
+        emit_atom(s, name);
+        emit_u16(s, scope);
+        break;
+      case OP_get_array_el:
+        /* XXX: replace by a single opcode ? */
+        emit_op(s, OP_to_propkey2);
+        emit_op(s, OP_dup2);
+        emit_op(s, OP_get_array_el);
+        break;
+      case OP_get_super_value:
+        emit_op(s, OP_to_propkey);
+        emit_op(s, OP_dup3);
+        emit_op(s, OP_get_super_value);
+        break;
+      default:
+        abort();
+    }
+  } else {
+    switch(opcode) {
+      case OP_scope_get_var:
+        label = new_label(s);
+        emit_op(s, OP_scope_make_ref);
+        emit_atom(s, name);
+        emit_u32(s, label);
+        emit_u16(s, scope);
+        update_label(fd, label, 1);
+        opcode = OP_get_ref_value;
+        break;
+      case OP_get_array_el:
+        emit_op(s, OP_to_propkey2);
+        break;
+      case OP_get_super_value:
+        emit_op(s, OP_to_propkey);
+        break;
+    }
+  }
+
+  *popcode = opcode;
+  *pscope = scope;
+  /* name has refcount for OP_get_field and OP_get_ref_value,
+     and JS_ATOM_NULL for other opcodes */
+  *pname = name;
+  *plabel = label;
+  if (pdepth)
+    *pdepth = depth;
+  return 0;
+}
+
+typedef enum {
+  PUT_LVALUE_NOKEEP, /* [depth] v -> */
+  PUT_LVALUE_NOKEEP_DEPTH, /* [depth] v -> , keep depth (currently
+                               just disable optimizations) */
+  PUT_LVALUE_KEEP_TOP,  /* [depth] v -> v */
+  PUT_LVALUE_KEEP_SECOND, /* [depth] v0 v -> v0 */
+  PUT_LVALUE_NOKEEP_BOTTOM, /* v [depth] -> */
+} PutLValueEnum;
+
+/* name has a live reference. 'is_let' is only used with opcode =
+   OP_scope_get_var which is never generated by get_lvalue(). */
+static void put_lvalue(JSParseState *s, int opcode, int scope,
+                       JSAtom name, int label, PutLValueEnum special,
+                       BOOL is_let)
+{
+  switch(opcode) {
+    case OP_get_field:
+    case OP_scope_get_private_field:
+      /* depth = 1 */
+      switch(special) {
+        case PUT_LVALUE_NOKEEP:
+        case PUT_LVALUE_NOKEEP_DEPTH:
+          break;
+        case PUT_LVALUE_KEEP_TOP:
+          emit_op(s, OP_insert2); /* obj v -> v obj v */
+          break;
+        case PUT_LVALUE_KEEP_SECOND:
+          emit_op(s, OP_perm3); /* obj v0 v -> v0 obj v */
+          break;
+        case PUT_LVALUE_NOKEEP_BOTTOM:
+          emit_op(s, OP_swap);
+          break;
+        default:
+          abort();
+      }
+      break;
+    case OP_get_array_el:
+    case OP_get_ref_value:
+      /* depth = 2 */
+      if (opcode == OP_get_ref_value) {
+        JS_FreeAtom(s->ctx, name);
+        emit_label(s, label);
+      }
+      switch(special) {
+        case PUT_LVALUE_NOKEEP:
+          emit_op(s, OP_nop); /* will trigger optimization */
+          break;
+        case PUT_LVALUE_NOKEEP_DEPTH:
+          break;
+        case PUT_LVALUE_KEEP_TOP:
+          emit_op(s, OP_insert3); /* obj prop v -> v obj prop v */
+          break;
+        case PUT_LVALUE_KEEP_SECOND:
+          emit_op(s, OP_perm4); /* obj prop v0 v -> v0 obj prop v */
+          break;
+        case PUT_LVALUE_NOKEEP_BOTTOM:
+          emit_op(s, OP_rot3l);
+          break;
+        default:
+          abort();
+      }
+      break;
+    case OP_get_super_value:
+      /* depth = 3 */
+      switch(special) {
+        case PUT_LVALUE_NOKEEP:
+        case PUT_LVALUE_NOKEEP_DEPTH:
+          break;
+        case PUT_LVALUE_KEEP_TOP:
+          emit_op(s, OP_insert4); /* this obj prop v -> v this obj prop v */
+          break;
+        case PUT_LVALUE_KEEP_SECOND:
+          emit_op(s, OP_perm5); /* this obj prop v0 v -> v0 this obj prop v */
+          break;
+        case PUT_LVALUE_NOKEEP_BOTTOM:
+          emit_op(s, OP_rot4l);
+          break;
+        default:
+          abort();
+      }
+      break;
+    default:
+      break;
+  }
+
+  switch(opcode) {
+    case OP_scope_get_var:  /* val -- */
+      assert(special == PUT_LVALUE_NOKEEP ||
+             special == PUT_LVALUE_NOKEEP_DEPTH);
+      emit_op(s, is_let ? OP_scope_put_var_init : OP_scope_put_var);
+      emit_u32(s, name);  /* has refcount */
+      emit_u16(s, scope);
+      break;
+    case OP_get_field:
+      emit_op(s, OP_put_field);
+      emit_u32(s, name);  /* name has refcount */
+      break;
+    case OP_scope_get_private_field:
+      emit_op(s, OP_scope_put_private_field);
+      emit_u32(s, name);  /* name has refcount */
+      emit_u16(s, scope);
+      break;
+    case OP_get_array_el:
+      emit_op(s, OP_put_array_el);
+      break;
+    case OP_get_ref_value:
+      emit_op(s, OP_put_ref_value);
+      break;
+    case OP_get_super_value:
+      emit_op(s, OP_put_super_value);
+      break;
+    default:
+      abort();
+  }
+}
+
+static __exception int js_parse_expr_paren(JSParseState *s)
+{
+  if (js_parse_expect(s, '('))
+    return -1;
+  if (js_parse_expr(s))
+    return -1;
+  if (js_parse_expect(s, ')'))
+    return -1;
+  return 0;
+}
+
+static int js_unsupported_keyword(JSParseState *s, JSAtom atom)
+{
+  char buf[ATOM_GET_STR_BUF_SIZE];
+  return js_parse_error(s, "unsupported keyword: %s",
+                        JS_AtomGetStr(s->ctx, buf, sizeof(buf), atom));
+}
+
+static __exception int js_define_var(JSParseState *s, JSAtom name, int tok)
+{
+  JSFunctionDef *fd = s->cur_func;
+  JSVarDefEnum var_def_type;
+
+  if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) {
+    return js_parse_error(s, "yield is a reserved identifier");
+  }
+  if ((name == JS_ATOM_arguments || name == JS_ATOM_eval)
+      &&  (fd->js_mode & JS_MODE_STRICT)) {
+    return js_parse_error(s, "invalid variable name in strict mode");
+  }
+  if ((name == JS_ATOM_let || name == JS_ATOM_undefined)
+      &&  (tok == TOK_LET || tok == TOK_CONST)) {
+    return js_parse_error(s, "invalid lexical variable name");
+  }
+  switch(tok) {
+    case TOK_LET:
+      var_def_type = JS_VAR_DEF_LET;
+      break;
+    case TOK_CONST:
+      var_def_type = JS_VAR_DEF_CONST;
+      break;
+    case TOK_VAR:
+      var_def_type = JS_VAR_DEF_VAR;
+      break;
+    case TOK_CATCH:
+      var_def_type = JS_VAR_DEF_CATCH;
+      break;
+    default:
+      abort();
+  }
+  if (define_var(s, fd, name, var_def_type) < 0)
+    return -1;
+  return 0;
+}
+
+static void js_emit_spread_code(JSParseState *s, int depth)
+{
+  int label_rest_next, label_rest_done;
+
+  /* XXX: could check if enum object is an actual array and optimize
+     slice extraction. enumeration record and target array are in a
+     different order from OP_append case. */
+  /* enum_rec xxx -- enum_rec xxx array 0 */
+  emit_op(s, OP_array_from);
+  emit_u16(s, 0);
+  emit_op(s, OP_push_i32);
+  emit_u32(s, 0);
+  emit_label(s, label_rest_next = new_label(s));
+  emit_op(s, OP_for_of_next);
+  emit_u8(s, 2 + depth);
+  label_rest_done = emit_goto(s, OP_if_true, -1);
+  /* array idx val -- array idx */
+  emit_op(s, OP_define_array_el);
+  emit_op(s, OP_inc);
+  emit_goto(s, OP_goto, label_rest_next);
+  emit_label(s, label_rest_done);
+  /* enum_rec xxx array idx undef -- enum_rec xxx array */
+  emit_op(s, OP_drop);
+  emit_op(s, OP_drop);
+}
+
+static int js_parse_check_duplicate_parameter(JSParseState *s, JSAtom name)
+{
+  /* Check for duplicate parameter names */
+  JSFunctionDef *fd = s->cur_func;
+  int i;
+  for (i = 0; i < fd->arg_count; i++) {
+    if (fd->args[i].var_name == name)
+      goto duplicate;
+  }
+  for (i = 0; i < fd->var_count; i++) {
+    if (fd->vars[i].var_name == name)
+      goto duplicate;
+  }
+  return 0;
+
+duplicate:
+  return js_parse_error(s, "duplicate parameter names not allowed in this context");
+}
+
+static JSAtom js_parse_destructuring_var(JSParseState *s, int tok, int is_arg)
+{
+  JSAtom name;
+
+  if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)
+      ||  ((s->cur_func->js_mode & JS_MODE_STRICT) &&
+          (s->token.u.ident.atom == JS_ATOM_eval || s->token.u.ident.atom == JS_ATOM_arguments))) {
+    js_parse_error(s, "invalid destructuring target");
+    return JS_ATOM_NULL;
+  }
+  name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
+  if (is_arg && js_parse_check_duplicate_parameter(s, name))
+    goto fail;
+  if (next_token(s))
+    goto fail;
+
+  return name;
+fail:
+  JS_FreeAtom(s->ctx, name);
+  return JS_ATOM_NULL;
+}
+
+/* Return -1 if error, 0 if no initializer, 1 if an initializer is
+   present at the top level. */
+static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
+                                          int hasval, int has_ellipsis,
+                                          BOOL allow_initializer)
+{
+  int label_parse, label_assign, label_done, label_lvalue, depth_lvalue;
+  int start_addr, assign_addr;
+  JSAtom prop_name, var_name;
+  int opcode, scope, tok1, skip_bits;
+  BOOL has_initializer;
+
+  if (has_ellipsis < 0) {
+    /* pre-parse destructuration target for spread detection */
+    js_parse_skip_parens_token(s, &skip_bits, FALSE);
+    has_ellipsis = skip_bits & SKIP_HAS_ELLIPSIS;
+  }
+
+  label_parse = new_label(s);
+  label_assign = new_label(s);
+
+  start_addr = s->cur_func->byte_code.size;
+  if (hasval) {
+    /* consume value from the stack */
+    emit_op(s, OP_dup);
+    emit_op(s, OP_undefined);
+    emit_op(s, OP_strict_eq);
+    emit_goto(s, OP_if_true, label_parse);
+    emit_label(s, label_assign);
+  } else {
+    emit_goto(s, OP_goto, label_parse);
+    emit_label(s, label_assign);
+    /* leave value on the stack */
+    emit_op(s, OP_dup);
+  }
+  assign_addr = s->cur_func->byte_code.size;
+  if (s->token.val == '{') {
+    if (next_token(s))
+      return -1;
+    /* throw an exception if the value cannot be converted to an object */
+    emit_op(s, OP_to_object);
+    if (has_ellipsis) {
+      /* add excludeList on stack just below src object */
+      emit_op(s, OP_object);
+      emit_op(s, OP_swap);
+    }
+    while (s->token.val != '}') {
+      int prop_type;
+      if (s->token.val == TOK_ELLIPSIS) {
+        if (!has_ellipsis) {
+          JS_ThrowInternalError(s->ctx, "unexpected ellipsis token");
+          return -1;
+        }
+        if (next_token(s))
+          return -1;
+        if (tok) {
+          var_name = js_parse_destructuring_var(s, tok, is_arg);
+          if (var_name == JS_ATOM_NULL)
+            return -1;
+          opcode = OP_scope_get_var;
+          scope = s->cur_func->scope_level;
+          label_lvalue = -1;
+          depth_lvalue = 0;
+        } else {
+          if (js_parse_left_hand_side_expr(s))
+            return -1;
+
+          if (get_lvalue(s, &opcode, &scope, &var_name,
+                         &label_lvalue, &depth_lvalue, FALSE, '{'))
+            return -1;
+        }
+        if (s->token.val != '}') {
+          js_parse_error(s, "assignment rest property must be last");
+          goto var_error;
+        }
+        emit_op(s, OP_object);  /* target */
+        emit_op(s, OP_copy_data_properties);
+        emit_u8(s, 0 | ((depth_lvalue + 1) << 2) | ((depth_lvalue + 2) << 5));
+        goto set_val;
+      }
+      prop_type = js_parse_property_name(s, &prop_name, FALSE, TRUE, FALSE);
+      if (prop_type < 0)
+        return -1;
+      var_name = JS_ATOM_NULL;
+      opcode = OP_scope_get_var;
+      scope = s->cur_func->scope_level;
+      label_lvalue = -1;
+      depth_lvalue = 0;
+      if (prop_type == PROP_TYPE_IDENT) {
+        if (next_token(s))
+          goto prop_error;
+        if ((s->token.val == '[' || s->token.val == '{')
+            &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' ||
+                tok1 == '=' || tok1 == '}')) {
+          if (prop_name == JS_ATOM_NULL) {
+            /* computed property name on stack */
+            if (has_ellipsis) {
+              /* define the property in excludeList */
+              emit_op(s, OP_to_propkey); /* avoid calling ToString twice */
+              emit_op(s, OP_perm3); /* TOS: src excludeList prop */
+              emit_op(s, OP_null); /* TOS: src excludeList prop null */
+              emit_op(s, OP_define_array_el); /* TOS: src excludeList prop */
+              emit_op(s, OP_perm3); /* TOS: excludeList src prop */
+            }
+            /* get the computed property from the source object */
+            emit_op(s, OP_get_array_el2);
+          } else {
+            /* named property */
+            if (has_ellipsis) {
+              /* define the property in excludeList */
+              emit_op(s, OP_swap); /* TOS: src excludeList */
+              emit_op(s, OP_null); /* TOS: src excludeList null */
+              emit_op(s, OP_define_field); /* TOS: src excludeList */
+              emit_atom(s, prop_name);
+              emit_op(s, OP_swap); /* TOS: excludeList src */
+            }
+            /* get the named property from the source object */
+            emit_op(s, OP_get_field2);
+            emit_u32(s, prop_name);
+          }
+          if (js_parse_destructuring_element(s, tok, is_arg, TRUE, -1, TRUE) < 0)
+            return -1;
+          if (s->token.val == '}')
+            break;
+          /* accept a trailing comma before the '}' */
+          if (js_parse_expect(s, ','))
+            return -1;
+          continue;
+        }
+        if (prop_name == JS_ATOM_NULL) {
+          emit_op(s, OP_to_propkey2);
+          if (has_ellipsis) {
+            /* define the property in excludeList */
+            emit_op(s, OP_perm3);
+            emit_op(s, OP_null);
+            emit_op(s, OP_define_array_el);
+            emit_op(s, OP_perm3);
+          }
+          /* source prop -- source source prop */
+          emit_op(s, OP_dup1);
+        } else {
+          if (has_ellipsis) {
+            /* define the property in excludeList */
+            emit_op(s, OP_swap);
+            emit_op(s, OP_null);
+            emit_op(s, OP_define_field);
+            emit_atom(s, prop_name);
+            emit_op(s, OP_swap);
+          }
+          /* source -- source source */
+          emit_op(s, OP_dup);
+        }
+        if (tok) {
+          var_name = js_parse_destructuring_var(s, tok, is_arg);
+          if (var_name == JS_ATOM_NULL)
+            goto prop_error;
+        } else {
+          if (js_parse_left_hand_side_expr(s))
+            goto prop_error;
+        lvalue:
+          if (get_lvalue(s, &opcode, &scope, &var_name,
+                         &label_lvalue, &depth_lvalue, FALSE, '{'))
+            goto prop_error;
+          /* swap ref and lvalue object if any */
+          if (prop_name == JS_ATOM_NULL) {
+            switch(depth_lvalue) {
+              case 1:
+                /* source prop x -> x source prop */
+                emit_op(s, OP_rot3r);
+                break;
+              case 2:
+                /* source prop x y -> x y source prop */
+                emit_op(s, OP_swap2);   /* t p2 s p1 */
+                break;
+              case 3:
+                /* source prop x y z -> x y z source prop */
+                emit_op(s, OP_rot5l);
+                emit_op(s, OP_rot5l);
+                break;
+            }
+          } else {
+            switch(depth_lvalue) {
+              case 1:
+                /* source x -> x source */
+                emit_op(s, OP_swap);
+                break;
+              case 2:
+                /* source x y -> x y source */
+                emit_op(s, OP_rot3l);
+                break;
+              case 3:
+                /* source x y z -> x y z source */
+                emit_op(s, OP_rot4l);
+                break;
+            }
+          }
+        }
+        if (prop_name == JS_ATOM_NULL) {
+          /* computed property name on stack */
+          /* XXX: should have OP_get_array_el2x with depth */
+          /* source prop -- val */
+          emit_op(s, OP_get_array_el);
+        } else {
+          /* named property */
+          /* XXX: should have OP_get_field2x with depth */
+          /* source -- val */
+          emit_op(s, OP_get_field);
+          emit_u32(s, prop_name);
+        }
+      } else {
+        /* prop_type = PROP_TYPE_VAR, cannot be a computed property */
+        if (is_arg && js_parse_check_duplicate_parameter(s, prop_name))
+          goto prop_error;
+        if ((s->cur_func->js_mode & JS_MODE_STRICT) &&
+            (prop_name == JS_ATOM_eval || prop_name == JS_ATOM_arguments)) {
+          js_parse_error(s, "invalid destructuring target");
+          goto prop_error;
+        }
+        if (has_ellipsis) {
+          /* define the property in excludeList */
+          emit_op(s, OP_swap);
+          emit_op(s, OP_null);
+          emit_op(s, OP_define_field);
+          emit_atom(s, prop_name);
+          emit_op(s, OP_swap);
+        }
+        if (!tok || tok == TOK_VAR) {
+          /* generate reference */
+          /* source -- source source */
+          emit_op(s, OP_dup);
+          emit_op(s, OP_scope_get_var);
+          emit_atom(s, prop_name);
+          emit_u16(s, s->cur_func->scope_level);
+          goto lvalue;
+        }
+        var_name = JS_DupAtom(s->ctx, prop_name);
+        /* source -- source val */
+        emit_op(s, OP_get_field2);
+        emit_u32(s, prop_name);
+      }
+    set_val:
+      if (tok) {
+        if (js_define_var(s, var_name, tok))
+          goto var_error;
+        scope = s->cur_func->scope_level;
+      }
+      if (s->token.val == '=') {  /* handle optional default value */
+        int label_hasval;
+        emit_op(s, OP_dup);
+        emit_op(s, OP_undefined);
+        emit_op(s, OP_strict_eq);
+        label_hasval = emit_goto(s, OP_if_false, -1);
+        if (next_token(s))
+          goto var_error;
+        emit_op(s, OP_drop);
+        if (js_parse_assign_expr(s))
+          goto var_error;
+        if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
+          set_object_name(s, var_name);
+        emit_label(s, label_hasval);
+      }
+      /* store value into lvalue object */
+      put_lvalue(s, opcode, scope, var_name, label_lvalue,
+                 PUT_LVALUE_NOKEEP_DEPTH,
+                 (tok == TOK_CONST || tok == TOK_LET));
+      if (s->token.val == '}')
+        break;
+      /* accept a trailing comma before the '}' */
+      if (js_parse_expect(s, ','))
+        return -1;
+    }
+    /* drop the source object */
+    emit_op(s, OP_drop);
+    if (has_ellipsis) {
+      emit_op(s, OP_drop); /* pop excludeList */
+    }
+    if (next_token(s))
+      return -1;
+  } else if (s->token.val == '[') {
+    BOOL has_spread;
+    int enum_depth;
+    BlockEnv block_env;
+
+    if (next_token(s))
+      return -1;
+    /* the block environment is only needed in generators in case
+       'yield' triggers a 'return' */
+    push_break_entry(s->cur_func, &block_env,
+                     JS_ATOM_NULL, -1, -1, 2);
+    block_env.has_iterator = TRUE;
+    emit_op(s, OP_for_of_start);
+    has_spread = FALSE;
+    while (s->token.val != ']') {
+      /* get the next value */
+      if (s->token.val == TOK_ELLIPSIS) {
+        if (next_token(s))
+          return -1;
+        if (s->token.val == ',' || s->token.val == ']')
+          return js_parse_error(s, "missing binding pattern...");
+        has_spread = TRUE;
+      }
+      if (s->token.val == ',') {
+        /* do nothing, skip the value, has_spread is false */
+        emit_op(s, OP_for_of_next);
+        emit_u8(s, 0);
+        emit_op(s, OP_drop);
+        emit_op(s, OP_drop);
+      } else if ((s->token.val == '[' || s->token.val == '{')
+                 &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' ||
+                     tok1 == '=' || tok1 == ']')) {
+        if (has_spread) {
+          if (tok1 == '=')
+            return js_parse_error(s, "rest element cannot have a default value");
+          js_emit_spread_code(s, 0);
+        } else {
+          emit_op(s, OP_for_of_next);
+          emit_u8(s, 0);
+          emit_op(s, OP_drop);
+        }
+        if (js_parse_destructuring_element(s, tok, is_arg, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
+          return -1;
+      } else {
+        var_name = JS_ATOM_NULL;
+        enum_depth = 0;
+        if (tok) {
+          var_name = js_parse_destructuring_var(s, tok, is_arg);
+          if (var_name == JS_ATOM_NULL)
+            goto var_error;
+          if (js_define_var(s, var_name, tok))
+            goto var_error;
+          opcode = OP_scope_get_var;
+          scope = s->cur_func->scope_level;
+        } else {
+          if (js_parse_left_hand_side_expr(s))
+            return -1;
+          if (get_lvalue(s, &opcode, &scope, &var_name,
+                         &label_lvalue, &enum_depth, FALSE, '[')) {
+            return -1;
+          }
+        }
+        if (has_spread) {
+          js_emit_spread_code(s, enum_depth);
+        } else {
+          emit_op(s, OP_for_of_next);
+          emit_u8(s, enum_depth);
+          emit_op(s, OP_drop);
+        }
+        if (s->token.val == '=' && !has_spread) {
+          /* handle optional default value */
+          int label_hasval;
+          emit_op(s, OP_dup);
+          emit_op(s, OP_undefined);
+          emit_op(s, OP_strict_eq);
+          label_hasval = emit_goto(s, OP_if_false, -1);
+          if (next_token(s))
+            goto var_error;
+          emit_op(s, OP_drop);
+          if (js_parse_assign_expr(s))
+            goto var_error;
+          if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
+            set_object_name(s, var_name);
+          emit_label(s, label_hasval);
+        }
+        /* store value into lvalue object */
+        put_lvalue(s, opcode, scope, var_name,
+                   label_lvalue, PUT_LVALUE_NOKEEP_DEPTH,
+                   (tok == TOK_CONST || tok == TOK_LET));
+      }
+      if (s->token.val == ']')
+        break;
+      if (has_spread)
+        return js_parse_error(s, "rest element must be the last one");
+      /* accept a trailing comma before the ']' */
+      if (js_parse_expect(s, ','))
+        return -1;
+    }
+    /* close iterator object:
+       if completed, enum_obj has been replaced by undefined */
+    emit_op(s, OP_iterator_close);
+    pop_break_entry(s->cur_func);
+    if (next_token(s))
+      return -1;
+  } else {
+    return js_parse_error(s, "invalid assignment syntax");
+  }
+  if (s->token.val == '=' && allow_initializer) {
+    label_done = emit_goto(s, OP_goto, -1);
+    if (next_token(s))
+      return -1;
+    emit_label(s, label_parse);
+    if (hasval)
+      emit_op(s, OP_drop);
+    if (js_parse_assign_expr(s))
+      return -1;
+    emit_goto(s, OP_goto, label_assign);
+    emit_label(s, label_done);
+    has_initializer = TRUE;
+  } else {
+    /* normally hasval is true except if
+       js_parse_skip_parens_token() was wrong in the parsing */
+    //        assert(hasval);
+    if (!hasval) {
+      js_parse_error(s, "too complicated destructuring expression");
+      return -1;
+    }
+    /* remove test and decrement label ref count */
+    memset(s->cur_func->byte_code.buf + start_addr, OP_nop,
+           assign_addr - start_addr);
+    s->cur_func->label_slots[label_parse].ref_count--;
+    has_initializer = FALSE;
+  }
+  return has_initializer;
+
+prop_error:
+  JS_FreeAtom(s->ctx, prop_name);
+var_error:
+  JS_FreeAtom(s->ctx, var_name);
+  return -1;
+}
+
+typedef enum FuncCallType {
+  FUNC_CALL_NORMAL,
+  FUNC_CALL_NEW,
+  FUNC_CALL_SUPER_CTOR,
+  FUNC_CALL_TEMPLATE,
+} FuncCallType;
+
+static void optional_chain_test(JSParseState *s, int *poptional_chaining_label,
+                                int drop_count)
+{
+  int label_next, i;
+  if (*poptional_chaining_label < 0)
+    *poptional_chaining_label = new_label(s);
+  /* XXX: could be more efficient with a specific opcode */
+  emit_op(s, OP_dup);
+  emit_op(s, OP_is_undefined_or_null);
+  label_next = emit_goto(s, OP_if_false, -1);
+  for(i = 0; i < drop_count; i++)
+    emit_op(s, OP_drop);
+  emit_op(s, OP_undefined);
+  emit_goto(s, OP_goto, *poptional_chaining_label);
+  emit_label(s, label_next);
+}
+
+/* allowed parse_flags: PF_POSTFIX_CALL, PF_ARROW_FUNC */
+static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
+{
+  FuncCallType call_type;
+  int optional_chaining_label;
+  BOOL accept_lparen = (parse_flags & PF_POSTFIX_CALL) != 0;
+
+  call_type = FUNC_CALL_NORMAL;
+  switch(s->token.val) {
+    case TOK_NUMBER:
+    {
+      JSValue val;
+      val = s->token.u.num.val;
+
+      if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) {
+        emit_op(s, OP_push_i32);
+        emit_u32(s, JS_VALUE_GET_INT(val));
+      } else
+#ifdef CONFIG_BIGNUM
+          if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) {
+        slimb_t e;
+        int ret;
+
+        /* need a runtime conversion */
+        /* XXX: could add a cache and/or do it once at
+           the start of the function */
+        if (emit_push_const(s, val, 0) < 0)
+          return -1;
+        e = s->token.u.num.exponent;
+        if (e == (int32_t)e) {
+          emit_op(s, OP_push_i32);
+          emit_u32(s, e);
+        } else {
+          val = JS_NewBigInt64_1(s->ctx, e);
+          if (JS_IsException(val))
+            return -1;
+          ret = emit_push_const(s, val, 0);
+          JS_FreeValue(s->ctx, val);
+          if (ret < 0)
+            return -1;
+        }
+        emit_op(s, OP_mul_pow10);
+      } else
+#endif
+      {
+        if (emit_push_const(s, val, 0) < 0)
+          return -1;
+      }
+    }
+      if (next_token(s))
+        return -1;
+      break;
+    case TOK_TEMPLATE:
+      if (js_parse_template(s, 0, NULL))
+        return -1;
+      break;
+    case TOK_STRING:
+      if (emit_push_const(s, s->token.u.str.str, 1))
+        return -1;
+      if (next_token(s))
+        return -1;
+      break;
+
+    case TOK_DIV_ASSIGN:
+      s->buf_ptr -= 2;
+      goto parse_regexp;
+    case '/':
+      s->buf_ptr--;
+    parse_regexp:
+    {
+      JSValue str;
+      int ret, backtrace_flags;
+      if (!s->ctx->compile_regexp)
+        return js_parse_error(s, "RegExp are not supported");
+      /* the previous token is '/' or '/=', so no need to free */
+      if (js_parse_regexp(s))
+        return -1;
+      ret = emit_push_const(s, s->token.u.regexp.body, 0);
+      str = s->ctx->compile_regexp(s->ctx, s->token.u.regexp.body,
+                                   s->token.u.regexp.flags);
+      if (JS_IsException(str)) {
+        /* add the line number info */
+        backtrace_flags = 0;
+        if (s->cur_func && s->cur_func->backtrace_barrier)
+          backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL;
+        build_backtrace(s->ctx, s->ctx->rt->current_exception,
+                        s->filename, s->token.line_num,
+                        backtrace_flags);
+        return -1;
+      }
+      ret = emit_push_const(s, str, 0);
+      JS_FreeValue(s->ctx, str);
+      if (ret)
+        return -1;
+      /* we use a specific opcode to be sure the correct
+         function is called (otherwise the bytecode would have
+         to be verified by the RegExp constructor) */
+      emit_op(s, OP_regexp);
+      if (next_token(s))
+        return -1;
+    }
+    break;
+    case '(':
+      if ((parse_flags & PF_ARROW_FUNC) &&
+          js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) {
+        if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
+                                   JS_FUNC_NORMAL, JS_ATOM_NULL,
+                                   s->token.ptr, s->token.line_num))
+          return -1;
+      } else {
+        if (js_parse_expr_paren(s))
+          return -1;
+      }
+      break;
+    case TOK_FUNCTION:
+      if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR,
+                                 JS_FUNC_NORMAL, JS_ATOM_NULL,
+                                 s->token.ptr, s->token.line_num))
+        return -1;
+      break;
+    case TOK_CLASS:
+      if (js_parse_class(s, TRUE, JS_PARSE_EXPORT_NONE))
+        return -1;
+      break;
+    case TOK_NULL:
+      if (next_token(s))
+        return -1;
+      emit_op(s, OP_null);
+      break;
+    case TOK_THIS:
+      if (next_token(s))
+        return -1;
+      emit_op(s, OP_scope_get_var);
+      emit_atom(s, JS_ATOM_this);
+      emit_u16(s, 0);
+      break;
+    case TOK_FALSE:
+      if (next_token(s))
+        return -1;
+      emit_op(s, OP_push_false);
+      break;
+    case TOK_TRUE:
+      if (next_token(s))
+        return -1;
+      emit_op(s, OP_push_true);
+      break;
+    case TOK_IDENT:
+    {
+      JSAtom name;
+      if (s->token.u.ident.is_reserved) {
+        return js_parse_error_reserved_identifier(s);
+      }
+      if ((parse_flags & PF_ARROW_FUNC) &&
+          peek_token(s, TRUE) == TOK_ARROW) {
+        if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
+                                   JS_FUNC_NORMAL, JS_ATOM_NULL,
+                                   s->token.ptr, s->token.line_num))
+          return -1;
+      } else if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
+                 peek_token(s, TRUE) != '\n') {
+        const uint8_t *source_ptr;
+        int source_line_num;
+
+        source_ptr = s->token.ptr;
+        source_line_num = s->token.line_num;
+        if (next_token(s))
+          return -1;
+        if (s->token.val == TOK_FUNCTION) {
+          if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR,
+                                     JS_FUNC_ASYNC, JS_ATOM_NULL,
+                                     source_ptr, source_line_num))
+            return -1;
+        } else if ((parse_flags & PF_ARROW_FUNC) &&
+                   ((s->token.val == '(' &&
+                     js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) ||
+                    (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
+                     peek_token(s, TRUE) == TOK_ARROW))) {
+          if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
+                                     JS_FUNC_ASYNC, JS_ATOM_NULL,
+                                     source_ptr, source_line_num))
+            return -1;
+        } else {
+          name = JS_DupAtom(s->ctx, JS_ATOM_async);
+          goto do_get_var;
+        }
+      } else {
+        if (s->token.u.ident.atom == JS_ATOM_arguments &&
+            !s->cur_func->arguments_allowed) {
+          js_parse_error(s, "'arguments' identifier is not allowed in class field initializer");
+          return -1;
+        }
+        name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
+        if (next_token(s))  /* update line number before emitting code */
+          return -1;
+      do_get_var:
+        emit_op(s, OP_scope_get_var);
+        emit_u32(s, name);
+        emit_u16(s, s->cur_func->scope_level);
+      }
+    }
+    break;
+    case '{':
+    case '[':
+    {
+      int skip_bits;
+      if (js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
+        if (js_parse_destructuring_element(s, 0, 0, FALSE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
+          return -1;
+      } else {
+        if (s->token.val == '{') {
+          if (js_parse_object_literal(s))
+            return -1;
+        } else {
+          if (js_parse_array_literal(s))
+            return -1;
+        }
+      }
+    }
+    break;
+    case TOK_NEW:
+      if (next_token(s))
+        return -1;
+      if (s->token.val == '.') {
+        if (next_token(s))
+          return -1;
+        if (!token_is_pseudo_keyword(s, JS_ATOM_target))
+          return js_parse_error(s, "expecting target");
+        if (!s->cur_func->new_target_allowed)
+          return js_parse_error(s, "new.target only allowed within functions");
+        if (next_token(s))
+          return -1;
+        emit_op(s, OP_scope_get_var);
+        emit_atom(s, JS_ATOM_new_target);
+        emit_u16(s, 0);
+      } else {
+        if (js_parse_postfix_expr(s, 0))
+          return -1;
+        accept_lparen = TRUE;
+        if (s->token.val != '(') {
+          /* new operator on an object */
+          emit_op(s, OP_dup);
+          emit_op(s, OP_call_constructor);
+          emit_u16(s, 0);
+        } else {
+          call_type = FUNC_CALL_NEW;
+        }
+      }
+      break;
+    case TOK_SUPER:
+      if (next_token(s))
+        return -1;
+      if (s->token.val == '(') {
+        if (!s->cur_func->super_call_allowed)
+          return js_parse_error(s, "super() is only valid in a derived class constructor");
+        call_type = FUNC_CALL_SUPER_CTOR;
+      } else if (s->token.val == '.' || s->token.val == '[') {
+        if (!s->cur_func->super_allowed)
+          return js_parse_error(s, "'super' is only valid in a method");
+        emit_op(s, OP_scope_get_var);
+        emit_atom(s, JS_ATOM_this);
+        emit_u16(s, 0);
+        emit_op(s, OP_scope_get_var);
+        emit_atom(s, JS_ATOM_home_object);
+        emit_u16(s, 0);
+        emit_op(s, OP_get_super);
+      } else {
+        return js_parse_error(s, "invalid use of 'super'");
+      }
+      break;
+    case TOK_IMPORT:
+      if (next_token(s))
+        return -1;
+      if (s->token.val == '.') {
+        if (next_token(s))
+          return -1;
+        if (!token_is_pseudo_keyword(s, JS_ATOM_meta))
+          return js_parse_error(s, "meta expected");
+        if (!s->is_module)
+          return js_parse_error(s, "import.meta only valid in module code");
+        if (next_token(s))
+          return -1;
+        emit_op(s, OP_special_object);
+        emit_u8(s, OP_SPECIAL_OBJECT_IMPORT_META);
+      } else {
+        if (js_parse_expect(s, '('))
+          return -1;
+        if (!accept_lparen)
+          return js_parse_error(s, "invalid use of 'import()'");
+        if (js_parse_assign_expr(s))
+          return -1;
+        if (js_parse_expect(s, ')'))
+          return -1;
+        emit_op(s, OP_import);
+      }
+      break;
+    default:
+      return js_parse_error(s, "unexpected token in expression: '%.*s'",
+                            (int)(s->buf_ptr - s->token.ptr), s->token.ptr);
+  }
+
+  optional_chaining_label = -1;
+  for(;;) {
+    JSFunctionDef *fd = s->cur_func;
+    BOOL has_optional_chain = FALSE;
+
+    if (s->token.val == TOK_QUESTION_MARK_DOT) {
+      /* optional chaining */
+      if (next_token(s))
+        return -1;
+      has_optional_chain = TRUE;
+      if (s->token.val == '(' && accept_lparen) {
+        goto parse_func_call;
+      } else if (s->token.val == '[') {
+        goto parse_array_access;
+      } else {
+        goto parse_property;
+      }
+    } else if (s->token.val == TOK_TEMPLATE &&
+               call_type == FUNC_CALL_NORMAL) {
+      if (optional_chaining_label >= 0) {
+        return js_parse_error(s, "template literal cannot appear in an optional chain");
+      }
+      call_type = FUNC_CALL_TEMPLATE;
+      goto parse_func_call2;
+    } else if (s->token.val == '(' && accept_lparen) {
+      int opcode, arg_count, drop_count;
+
+      /* function call */
+    parse_func_call:
+      if (next_token(s))
+        return -1;
+
+      if (call_type == FUNC_CALL_NORMAL) {
+      parse_func_call2:
+        switch(opcode = get_prev_opcode(fd)) {
+          case OP_get_field:
+            /* keep the object on the stack */
+            fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;
+            drop_count = 2;
+            break;
+          case OP_scope_get_private_field:
+            /* keep the object on the stack */
+            fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_private_field2;
+            drop_count = 2;
+            break;
+          case OP_get_array_el:
+            /* keep the object on the stack */
+            fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;
+            drop_count = 2;
+            break;
+          case OP_scope_get_var:
+          {
+            JSAtom name;
+            int scope;
+            name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
+            scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
+            if (name == JS_ATOM_eval && call_type == FUNC_CALL_NORMAL && !has_optional_chain) {
+              /* direct 'eval' */
+              opcode = OP_eval;
+            } else {
+              /* verify if function name resolves to a simple
+                 get_loc/get_arg: a function call inside a `with`
+                 statement can resolve to a method call of the
+                 `with` context object
+               */
+              /* XXX: always generate the OP_scope_get_ref
+                 and remove it in variable resolution
+                 pass ? */
+              if (has_with_scope(fd, scope)) {
+                opcode = OP_scope_get_ref;
+                fd->byte_code.buf[fd->last_opcode_pos] = opcode;
+              }
+            }
+            drop_count = 1;
+          }
+          break;
+          case OP_get_super_value:
+            fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el;
+            /* on stack: this func_obj */
+            opcode = OP_get_array_el;
+            drop_count = 2;
+            break;
+          default:
+            opcode = OP_invalid;
+            drop_count = 1;
+            break;
+        }
+        if (has_optional_chain) {
+          optional_chain_test(s, &optional_chaining_label,
+                              drop_count);
+        }
+      } else {
+        opcode = OP_invalid;
+      }
+
+      if (call_type == FUNC_CALL_TEMPLATE) {
+        if (js_parse_template(s, 1, &arg_count))
+          return -1;
+        goto emit_func_call;
+      } else if (call_type == FUNC_CALL_SUPER_CTOR) {
+        emit_op(s, OP_scope_get_var);
+        emit_atom(s, JS_ATOM_this_active_func);
+        emit_u16(s, 0);
+
+        emit_op(s, OP_get_super);
+
+        emit_op(s, OP_scope_get_var);
+        emit_atom(s, JS_ATOM_new_target);
+        emit_u16(s, 0);
+      } else if (call_type == FUNC_CALL_NEW) {
+        emit_op(s, OP_dup); /* new.target = function */
+      }
+
+      /* parse arguments */
+      arg_count = 0;
+      while (s->token.val != ')') {
+        if (arg_count >= 65535) {
+          return js_parse_error(s, "Too many call arguments");
+        }
+        if (s->token.val == TOK_ELLIPSIS)
+          break;
+        if (js_parse_assign_expr(s))
+          return -1;
+        arg_count++;
+        if (s->token.val == ')')
+          break;
+        /* accept a trailing comma before the ')' */
+        if (js_parse_expect(s, ','))
+          return -1;
+      }
+      if (s->token.val == TOK_ELLIPSIS) {
+        emit_op(s, OP_array_from);
+        emit_u16(s, arg_count);
+        emit_op(s, OP_push_i32);
+        emit_u32(s, arg_count);
+
+        /* on stack: array idx */
+        while (s->token.val != ')') {
+          if (s->token.val == TOK_ELLIPSIS) {
+            if (next_token(s))
+              return -1;
+            if (js_parse_assign_expr(s))
+              return -1;
+#if 1
+            /* XXX: could pass is_last indicator? */
+            emit_op(s, OP_append);
+#else
+            int label_next, label_done;
+            label_next = new_label(s);
+            label_done = new_label(s);
+            /* push enumerate object below array/idx pair */
+            emit_op(s, OP_for_of_start);
+            emit_op(s, OP_rot5l);
+            emit_op(s, OP_rot5l);
+            emit_label(s, label_next);
+            /* on stack: enum_rec array idx */
+            emit_op(s, OP_for_of_next);
+            emit_u8(s, 2);
+            emit_goto(s, OP_if_true, label_done);
+            /* append element */
+            /* enum_rec array idx val -> enum_rec array new_idx */
+            emit_op(s, OP_define_array_el);
+            emit_op(s, OP_inc);
+            emit_goto(s, OP_goto, label_next);
+            emit_label(s, label_done);
+            /* close enumeration, drop enum_rec and idx */
+            emit_op(s, OP_drop); /* drop undef */
+            emit_op(s, OP_nip1); /* drop enum_rec */
+            emit_op(s, OP_nip1);
+            emit_op(s, OP_nip1);
+#endif
+          } else {
+            if (js_parse_assign_expr(s))
+              return -1;
+            /* array idx val */
+            emit_op(s, OP_define_array_el);
+            emit_op(s, OP_inc);
+          }
+          if (s->token.val == ')')
+            break;
+          /* accept a trailing comma before the ')' */
+          if (js_parse_expect(s, ','))
+            return -1;
+        }
+        if (next_token(s))
+          return -1;
+        /* drop the index */
+        emit_op(s, OP_drop);
+
+        /* apply function call */
+        switch(opcode) {
+          case OP_get_field:
+          case OP_scope_get_private_field:
+          case OP_get_array_el:
+          case OP_scope_get_ref:
+            /* obj func array -> func obj array */
+            emit_op(s, OP_perm3);
+            emit_op(s, OP_apply);
+            emit_u16(s, call_type == FUNC_CALL_NEW);
+            break;
+          case OP_eval:
+            emit_op(s, OP_apply_eval);
+            emit_u16(s, fd->scope_level);
+            fd->has_eval_call = TRUE;
+            break;
+          default:
+            if (call_type == FUNC_CALL_SUPER_CTOR) {
+              emit_op(s, OP_apply);
+              emit_u16(s, 1);
+              /* set the 'this' value */
+              emit_op(s, OP_dup);
+              emit_op(s, OP_scope_put_var_init);
+              emit_atom(s, JS_ATOM_this);
+              emit_u16(s, 0);
+
+              emit_class_field_init(s);
+            } else if (call_type == FUNC_CALL_NEW) {
+              /* obj func array -> func obj array */
+              emit_op(s, OP_perm3);
+              emit_op(s, OP_apply);
+              emit_u16(s, 1);
+            } else {
+              /* func array -> func undef array */
+              emit_op(s, OP_undefined);
+              emit_op(s, OP_swap);
+              emit_op(s, OP_apply);
+              emit_u16(s, 0);
+            }
+            break;
+        }
+      } else {
+        if (next_token(s))
+          return -1;
+      emit_func_call:
+        switch(opcode) {
+          case OP_get_field:
+          case OP_scope_get_private_field:
+          case OP_get_array_el:
+          case OP_scope_get_ref:
+            emit_op(s, OP_call_method);
+            emit_u16(s, arg_count);
+            break;
+          case OP_eval:
+            emit_op(s, OP_eval);
+            emit_u16(s, arg_count);
+            emit_u16(s, fd->scope_level);
+            fd->has_eval_call = TRUE;
+            break;
+          default:
+            if (call_type == FUNC_CALL_SUPER_CTOR) {
+              emit_op(s, OP_call_constructor);
+              emit_u16(s, arg_count);
+
+              /* set the 'this' value */
+              emit_op(s, OP_dup);
+              emit_op(s, OP_scope_put_var_init);
+              emit_atom(s, JS_ATOM_this);
+              emit_u16(s, 0);
+
+              emit_class_field_init(s);
+            } else if (call_type == FUNC_CALL_NEW) {
+              emit_op(s, OP_call_constructor);
+              emit_u16(s, arg_count);
+            } else {
+              emit_op(s, OP_call);
+              emit_u16(s, arg_count);
+            }
+            break;
+        }
+      }
+      call_type = FUNC_CALL_NORMAL;
+    } else if (s->token.val == '.') {
+      if (next_token(s))
+        return -1;
+    parse_property:
+      if (s->token.val == TOK_PRIVATE_NAME) {
+        /* private class field */
+        if (get_prev_opcode(fd) == OP_get_super) {
+          return js_parse_error(s, "private class field forbidden after super");
+        }
+        if (has_optional_chain) {
+          optional_chain_test(s, &optional_chaining_label, 1);
+        }
+        emit_op(s, OP_scope_get_private_field);
+        emit_atom(s, s->token.u.ident.atom);
+        emit_u16(s, s->cur_func->scope_level);
+      } else {
+        if (!token_is_ident(s->token.val)) {
+          return js_parse_error(s, "expecting field name");
+        }
+        if (get_prev_opcode(fd) == OP_get_super) {
+          JSValue val;
+          int ret;
+          val = JS_AtomToValue(s->ctx, s->token.u.ident.atom);
+          ret = emit_push_const(s, val, 1);
+          JS_FreeValue(s->ctx, val);
+          if (ret)
+            return -1;
+          emit_op(s, OP_get_super_value);
+        } else {
+          if (has_optional_chain) {
+            optional_chain_test(s, &optional_chaining_label, 1);
+          }
+          emit_op(s, OP_get_field);
+          emit_atom(s, s->token.u.ident.atom);
+        }
+      }
+      if (next_token(s))
+        return -1;
+    } else if (s->token.val == '[') {
+      int prev_op;
+
+    parse_array_access:
+      prev_op = get_prev_opcode(fd);
+      if (has_optional_chain) {
+        optional_chain_test(s, &optional_chaining_label, 1);
+      }
+      if (next_token(s))
+        return -1;
+      if (js_parse_expr(s))
+        return -1;
+      if (js_parse_expect(s, ']'))
+        return -1;
+      if (prev_op == OP_get_super) {
+        emit_op(s, OP_get_super_value);
+      } else {
+        emit_op(s, OP_get_array_el);
+      }
+    } else {
+      break;
+    }
+  }
+  if (optional_chaining_label >= 0)
+    emit_label(s, optional_chaining_label);
+  return 0;
+}
+
+static __exception int js_parse_delete(JSParseState *s)
+{
+  JSFunctionDef *fd = s->cur_func;
+  JSAtom name;
+  int opcode;
+
+  if (next_token(s))
+    return -1;
+  if (js_parse_unary(s, PF_POW_FORBIDDEN))
+    return -1;
+  switch(opcode = get_prev_opcode(fd)) {
+    case OP_get_field:
+    {
+      JSValue val;
+      int ret;
+
+      name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
+      fd->byte_code.size = fd->last_opcode_pos;
+      fd->last_opcode_pos = -1;
+      val = JS_AtomToValue(s->ctx, name);
+      ret = emit_push_const(s, val, 1);
+      JS_FreeValue(s->ctx, val);
+      JS_FreeAtom(s->ctx, name);
+      if (ret)
+        return ret;
+    }
+      goto do_delete;
+    case OP_get_array_el:
+      fd->byte_code.size = fd->last_opcode_pos;
+      fd->last_opcode_pos = -1;
+    do_delete:
+      emit_op(s, OP_delete);
+      break;
+    case OP_scope_get_var:
+      /* 'delete this': this is not a reference */
+      name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
+      if (name == JS_ATOM_this || name == JS_ATOM_new_target)
+        goto ret_true;
+      if (fd->js_mode & JS_MODE_STRICT) {
+        return js_parse_error(s, "cannot delete a direct reference in strict mode");
+      } else {
+        fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_delete_var;
+      }
+      break;
+    case OP_scope_get_private_field:
+      return js_parse_error(s, "cannot delete a private class field");
+    case OP_get_super_value:
+      emit_op(s, OP_throw_error);
+      emit_atom(s, JS_ATOM_NULL);
+      emit_u8(s, JS_THROW_ERROR_DELETE_SUPER);
+      break;
+    default:
+    ret_true:
+      emit_op(s, OP_drop);
+      emit_op(s, OP_push_true);
+      break;
+  }
+  return 0;
+}
+
+/* allowed parse_flags: PF_ARROW_FUNC, PF_POW_ALLOWED, PF_POW_FORBIDDEN */
+static __exception int js_parse_unary(JSParseState *s, int parse_flags)
+{
+  int op;
+
+  switch(s->token.val) {
+    case '+':
+    case '-':
+    case '!':
+    case '~':
+    case TOK_VOID:
+      op = s->token.val;
+      if (next_token(s))
+        return -1;
+      if (js_parse_unary(s, PF_POW_FORBIDDEN))
+        return -1;
+      switch(op) {
+        case '-':
+          emit_op(s, OP_neg);
+          break;
+        case '+':
+          emit_op(s, OP_plus);
+          break;
+        case '!':
+          emit_op(s, OP_lnot);
+          break;
+        case '~':
+          emit_op(s, OP_not);
+          break;
+        case TOK_VOID:
+          emit_op(s, OP_drop);
+          emit_op(s, OP_undefined);
+          break;
+        default:
+          abort();
+      }
+      parse_flags = 0;
+      break;
+    case TOK_DEC:
+    case TOK_INC:
+    {
+      int opcode, op, scope, label;
+      JSAtom name;
+      op = s->token.val;
+      if (next_token(s))
+        return -1;
+      if (js_parse_unary(s, 0))
+        return -1;
+      if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))
+        return -1;
+      emit_op(s, OP_dec + op - TOK_DEC);
+      put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP,
+                 FALSE);
+    }
+    break;
+    case TOK_TYPEOF:
+    {
+      JSFunctionDef *fd;
+      if (next_token(s))
+        return -1;
+      if (js_parse_unary(s, PF_POW_FORBIDDEN))
+        return -1;
+      /* reference access should not return an exception, so we
+         patch the get_var */
+      fd = s->cur_func;
+      if (get_prev_opcode(fd) == OP_scope_get_var) {
+        fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_var_undef;
+      }
+      emit_op(s, OP_typeof);
+      parse_flags = 0;
+    }
+    break;
+    case TOK_DELETE:
+      if (js_parse_delete(s))
+        return -1;
+      parse_flags = 0;
+      break;
+    case TOK_AWAIT:
+      if (!(s->cur_func->func_kind & JS_FUNC_ASYNC))
+        return js_parse_error(s, "unexpected 'await' keyword");
+      if (!s->cur_func->in_function_body)
+        return js_parse_error(s, "await in default expression");
+      if (next_token(s))
+        return -1;
+      if (js_parse_unary(s, PF_POW_FORBIDDEN))
+        return -1;
+      emit_op(s, OP_await);
+      parse_flags = 0;
+      break;
+    default:
+      if (js_parse_postfix_expr(s, (parse_flags & PF_ARROW_FUNC) |
+                                       PF_POSTFIX_CALL))
+        return -1;
+      if (!s->got_lf &&
+          (s->token.val == TOK_DEC || s->token.val == TOK_INC)) {
+        int opcode, op, scope, label;
+        JSAtom name;
+        op = s->token.val;
+        if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))
+          return -1;
+        emit_op(s, OP_post_dec + op - TOK_DEC);
+        put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_SECOND,
+                   FALSE);
+        if (next_token(s))
+          return -1;
+      }
+      break;
+  }
+  if (parse_flags & (PF_POW_ALLOWED | PF_POW_FORBIDDEN)) {
+#ifdef CONFIG_BIGNUM
+    if (s->token.val == TOK_POW || s->token.val == TOK_MATH_POW) {
+      /* Extended exponentiation syntax rules: we extend the ES7
+         grammar in order to have more intuitive semantics:
+         -2**2 evaluates to -4. */
+      if (!(s->cur_func->js_mode & JS_MODE_MATH)) {
+        if (parse_flags & PF_POW_FORBIDDEN) {
+          JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'");
+          return -1;
+        }
+      }
+      if (next_token(s))
+        return -1;
+      if (js_parse_unary(s, PF_POW_ALLOWED))
+        return -1;
+      emit_op(s, OP_pow);
+    }
+#else
+    if (s->token.val == TOK_POW) {
+      /* Strict ES7 exponentiation syntax rules: To solve
+         conficting semantics between different implementations
+         regarding the precedence of prefix operators and the
+         postifx exponential, ES7 specifies that -2**2 is a
+         syntax error. */
+      if (parse_flags & PF_POW_FORBIDDEN) {
+        JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'");
+        return -1;
+      }
+      if (next_token(s))
+        return -1;
+      if (js_parse_unary(s, PF_POW_ALLOWED))
+        return -1;
+      emit_op(s, OP_pow);
+    }
+#endif
+  }
+  return 0;
+}
+
+/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
+static __exception int js_parse_expr_binary(JSParseState *s, int level,
+                                            int parse_flags)
+{
+  int op, opcode;
+
+  if (level == 0) {
+    return js_parse_unary(s, (parse_flags & PF_ARROW_FUNC) |
+                                 PF_POW_ALLOWED);
+  }
+  if (js_parse_expr_binary(s, level - 1, parse_flags))
+    return -1;
+  for(;;) {
+    op = s->token.val;
+    switch(level) {
+      case 1:
+        switch(op) {
+          case '*':
+            opcode = OP_mul;
+            break;
+          case '/':
+            opcode = OP_div;
+            break;
+          case '%':
+#ifdef CONFIG_BIGNUM
+            if (s->cur_func->js_mode & JS_MODE_MATH)
+              opcode = OP_math_mod;
+            else
+#endif
+              opcode = OP_mod;
+            break;
+          default:
+            return 0;
+        }
+        break;
+      case 2:
+        switch(op) {
+          case '+':
+            opcode = OP_add;
+            break;
+          case '-':
+            opcode = OP_sub;
+            break;
+          default:
+            return 0;
+        }
+        break;
+      case 3:
+        switch(op) {
+          case TOK_SHL:
+            opcode = OP_shl;
+            break;
+          case TOK_SAR:
+            opcode = OP_sar;
+            break;
+          case TOK_SHR:
+            opcode = OP_shr;
+            break;
+          default:
+            return 0;
+        }
+        break;
+      case 4:
+        switch(op) {
+          case '<':
+            opcode = OP_lt;
+            break;
+          case '>':
+            opcode = OP_gt;
+            break;
+          case TOK_LTE:
+            opcode = OP_lte;
+            break;
+          case TOK_GTE:
+            opcode = OP_gte;
+            break;
+          case TOK_INSTANCEOF:
+            opcode = OP_instanceof;
+            break;
+          case TOK_IN:
+            if (parse_flags & PF_IN_ACCEPTED) {
+              opcode = OP_in;
+            } else {
+              return 0;
+            }
+            break;
+          default:
+            return 0;
+        }
+        break;
+      case 5:
+        switch(op) {
+          case TOK_EQ:
+            opcode = OP_eq;
+            break;
+          case TOK_NEQ:
+            opcode = OP_neq;
+            break;
+          case TOK_STRICT_EQ:
+            opcode = OP_strict_eq;
+            break;
+          case TOK_STRICT_NEQ:
+            opcode = OP_strict_neq;
+            break;
+          default:
+            return 0;
+        }
+        break;
+      case 6:
+        switch(op) {
+          case '&':
+            opcode = OP_and;
+            break;
+          default:
+            return 0;
+        }
+        break;
+      case 7:
+        switch(op) {
+          case '^':
+            opcode = OP_xor;
+            break;
+          default:
+            return 0;
+        }
+        break;
+      case 8:
+        switch(op) {
+          case '|':
+            opcode = OP_or;
+            break;
+          default:
+            return 0;
+        }
+        break;
+      default:
+        abort();
+    }
+    if (next_token(s))
+      return -1;
+    if (js_parse_expr_binary(s, level - 1, parse_flags & ~PF_ARROW_FUNC))
+      return -1;
+    emit_op(s, opcode);
+  }
+  return 0;
+}
+
+/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
+static __exception int js_parse_logical_and_or(JSParseState *s, int op,
+                                               int parse_flags)
+{
+  int label1;
+
+  if (op == TOK_LAND) {
+    if (js_parse_expr_binary(s, 8, parse_flags))
+      return -1;
+  } else {
+    if (js_parse_logical_and_or(s, TOK_LAND, parse_flags))
+      return -1;
+  }
+  if (s->token.val == op) {
+    label1 = new_label(s);
+
+    for(;;) {
+      if (next_token(s))
+        return -1;
+      emit_op(s, OP_dup);
+      emit_goto(s, op == TOK_LAND ? OP_if_false : OP_if_true, label1);
+      emit_op(s, OP_drop);
+
+      if (op == TOK_LAND) {
+        if (js_parse_expr_binary(s, 8, parse_flags & ~PF_ARROW_FUNC))
+          return -1;
+      } else {
+        if (js_parse_logical_and_or(s, TOK_LAND,
+                                    parse_flags & ~PF_ARROW_FUNC))
+          return -1;
+      }
+      if (s->token.val != op) {
+        if (s->token.val == TOK_DOUBLE_QUESTION_MARK)
+          return js_parse_error(s, "cannot mix ?? with && or ||");
+        break;
+      }
+    }
+
+    emit_label(s, label1);
+  }
+  return 0;
+}
+
+static __exception int js_parse_coalesce_expr(JSParseState *s, int parse_flags)
+{
+  int label1;
+
+  if (js_parse_logical_and_or(s, TOK_LOR, parse_flags))
+    return -1;
+  if (s->token.val == TOK_DOUBLE_QUESTION_MARK) {
+    label1 = new_label(s);
+    for(;;) {
+      if (next_token(s))
+        return -1;
+
+      emit_op(s, OP_dup);
+      emit_op(s, OP_is_undefined_or_null);
+      emit_goto(s, OP_if_false, label1);
+      emit_op(s, OP_drop);
+
+      if (js_parse_expr_binary(s, 8, parse_flags & ~PF_ARROW_FUNC))
+        return -1;
+      if (s->token.val != TOK_DOUBLE_QUESTION_MARK)
+        break;
+    }
+    emit_label(s, label1);
+  }
+  return 0;
+}
+
+/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
+static __exception int js_parse_cond_expr(JSParseState *s, int parse_flags)
+{
+  int label1, label2;
+
+  if (js_parse_coalesce_expr(s, parse_flags))
+    return -1;
+  if (s->token.val == '?') {
+    if (next_token(s))
+      return -1;
+    label1 = emit_goto(s, OP_if_false, -1);
+
+    if (js_parse_assign_expr(s))
+      return -1;
+    if (js_parse_expect(s, ':'))
+      return -1;
+
+    label2 = emit_goto(s, OP_goto, -1);
+
+    emit_label(s, label1);
+
+    if (js_parse_assign_expr2(s, parse_flags & PF_IN_ACCEPTED))
+      return -1;
+
+    emit_label(s, label2);
+  }
+  return 0;
+}
+
+static void emit_return(JSParseState *s, BOOL hasval);
+
+/* allowed parse_flags: PF_IN_ACCEPTED */
+static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
+{
+  int opcode, op, scope;
+  JSAtom name0 = JS_ATOM_NULL;
+  JSAtom name;
+
+  if (s->token.val == TOK_YIELD) {
+    BOOL is_star = FALSE, is_async;
+
+    if (!(s->cur_func->func_kind & JS_FUNC_GENERATOR))
+      return js_parse_error(s, "unexpected 'yield' keyword");
+    if (!s->cur_func->in_function_body)
+      return js_parse_error(s, "yield in default expression");
+    if (next_token(s))
+      return -1;
+    /* XXX: is there a better method to detect 'yield' without
+       parameters ? */
+    if (s->token.val != ';' && s->token.val != ')' &&
+        s->token.val != ']' && s->token.val != '}' &&
+        s->token.val != ',' && s->token.val != ':' && !s->got_lf) {
+      if (s->token.val == '*') {
+        is_star = TRUE;
+        if (next_token(s))
+          return -1;
+      }
+      if (js_parse_assign_expr2(s, parse_flags))
+        return -1;
+    } else {
+      emit_op(s, OP_undefined);
+    }
+    is_async = (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR);
+
+    if (is_star) {
+      int label_loop, label_return, label_next;
+      int label_return1, label_yield, label_throw, label_throw1;
+      int label_throw2;
+
+      label_loop = new_label(s);
+      label_yield = new_label(s);
+
+      emit_op(s, is_async ? OP_for_await_of_start : OP_for_of_start);
+
+      /* remove the catch offset (XXX: could avoid pushing back
+         undefined) */
+      emit_op(s, OP_drop);
+      emit_op(s, OP_undefined);
+
+      emit_op(s, OP_undefined); /* initial value */
+
+      emit_label(s, label_loop);
+      emit_op(s, OP_iterator_next);
+      if (is_async)
+        emit_op(s, OP_await);
+      emit_op(s, OP_iterator_check_object);
+      emit_op(s, OP_get_field2);
+      emit_atom(s, JS_ATOM_done);
+      label_next = emit_goto(s, OP_if_true, -1); /* end of loop */
+      emit_label(s, label_yield);
+      if (is_async) {
+        /* OP_async_yield_star takes the value as parameter */
+        emit_op(s, OP_get_field);
+        emit_atom(s, JS_ATOM_value);
+        emit_op(s, OP_await);
+        emit_op(s, OP_async_yield_star);
+      } else {
+        /* OP_yield_star takes (value, done) as parameter */
+        emit_op(s, OP_yield_star);
+      }
+      emit_op(s, OP_dup);
+      label_return = emit_goto(s, OP_if_true, -1);
+      emit_op(s, OP_drop);
+      emit_goto(s, OP_goto, label_loop);
+
+      emit_label(s, label_return);
+      emit_op(s, OP_push_i32);
+      emit_u32(s, 2);
+      emit_op(s, OP_strict_eq);
+      label_throw = emit_goto(s, OP_if_true, -1);
+
+      /* return handling */
+      if (is_async)
+        emit_op(s, OP_await);
+      emit_op(s, OP_iterator_call);
+      emit_u8(s, 0);
+      label_return1 = emit_goto(s, OP_if_true, -1);
+      if (is_async)
+        emit_op(s, OP_await);
+      emit_op(s, OP_iterator_check_object);
+      emit_op(s, OP_get_field2);
+      emit_atom(s, JS_ATOM_done);
+      emit_goto(s, OP_if_false, label_yield);
+
+      emit_op(s, OP_get_field);
+      emit_atom(s, JS_ATOM_value);
+
+      emit_label(s, label_return1);
+      emit_op(s, OP_nip);
+      emit_op(s, OP_nip);
+      emit_op(s, OP_nip);
+      emit_return(s, TRUE);
+
+      /* throw handling */
+      emit_label(s, label_throw);
+      emit_op(s, OP_iterator_call);
+      emit_u8(s, 1);
+      label_throw1 = emit_goto(s, OP_if_true, -1);
+      if (is_async)
+        emit_op(s, OP_await);
+      emit_op(s, OP_iterator_check_object);
+      emit_op(s, OP_get_field2);
+      emit_atom(s, JS_ATOM_done);
+      emit_goto(s, OP_if_false, label_yield);
+      emit_goto(s, OP_goto, label_next);
+      /* close the iterator and throw a type error exception */
+      emit_label(s, label_throw1);
+      emit_op(s, OP_iterator_call);
+      emit_u8(s, 2);
+      label_throw2 = emit_goto(s, OP_if_true, -1);
+      if (is_async)
+        emit_op(s, OP_await);
+      emit_label(s, label_throw2);
+
+      emit_op(s, OP_throw_error);
+      emit_atom(s, JS_ATOM_NULL);
+      emit_u8(s, JS_THROW_ERROR_ITERATOR_THROW);
+
+      emit_label(s, label_next);
+      emit_op(s, OP_get_field);
+      emit_atom(s, JS_ATOM_value);
+      emit_op(s, OP_nip); /* keep the value associated with
+                             done = true */
+      emit_op(s, OP_nip);
+      emit_op(s, OP_nip);
+    } else {
+      int label_next;
+
+      if (is_async)
+        emit_op(s, OP_await);
+      emit_op(s, OP_yield);
+      label_next = emit_goto(s, OP_if_false, -1);
+      emit_return(s, TRUE);
+      emit_label(s, label_next);
+    }
+    return 0;
+  }
+  if (s->token.val == TOK_IDENT) {
+    /* name0 is used to check for OP_set_name pattern, not duplicated */
+    name0 = s->token.u.ident.atom;
+  }
+  if (js_parse_cond_expr(s, parse_flags | PF_ARROW_FUNC))
+    return -1;
+
+  op = s->token.val;
+  if (op == '=' || (op >= TOK_MUL_ASSIGN && op <= TOK_POW_ASSIGN)) {
+    int label;
+    if (next_token(s))
+      return -1;
+    if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, (op != '='), op) < 0)
+      return -1;
+
+    if (js_parse_assign_expr2(s, parse_flags)) {
+      JS_FreeAtom(s->ctx, name);
+      return -1;
+    }
+
+    if (op == '=') {
+      if (opcode == OP_get_ref_value && name == name0) {
+        set_object_name(s, name);
+      }
+    } else {
+      static const uint8_t assign_opcodes[] = {
+          OP_mul, OP_div, OP_mod, OP_add, OP_sub,
+          OP_shl, OP_sar, OP_shr, OP_and, OP_xor, OP_or,
+#ifdef CONFIG_BIGNUM
+          OP_pow,
+#endif
+          OP_pow,
+      };
+      op = assign_opcodes[op - TOK_MUL_ASSIGN];
+#ifdef CONFIG_BIGNUM
+      if (s->cur_func->js_mode & JS_MODE_MATH) {
+        if (op == OP_mod)
+          op = OP_math_mod;
+      }
+#endif
+      emit_op(s, op);
+    }
+    put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP, FALSE);
+  } else if (op >= TOK_LAND_ASSIGN && op <= TOK_DOUBLE_QUESTION_MARK_ASSIGN) {
+    int label, label1, depth_lvalue, label2;
+
+    if (next_token(s))
+      return -1;
+    if (get_lvalue(s, &opcode, &scope, &name, &label,
+                   &depth_lvalue, TRUE, op) < 0)
+      return -1;
+
+    emit_op(s, OP_dup);
+    if (op == TOK_DOUBLE_QUESTION_MARK_ASSIGN)
+      emit_op(s, OP_is_undefined_or_null);
+    label1 = emit_goto(s, op == TOK_LOR_ASSIGN ? OP_if_true : OP_if_false,
+                       -1);
+    emit_op(s, OP_drop);
+
+    if (js_parse_assign_expr2(s, parse_flags)) {
+      JS_FreeAtom(s->ctx, name);
+      return -1;
+    }
+
+    if (opcode == OP_get_ref_value && name == name0) {
+      set_object_name(s, name);
+    }
+
+    switch(depth_lvalue) {
+      case 1:
+        emit_op(s, OP_insert2);
+        break;
+      case 2:
+        emit_op(s, OP_insert3);
+        break;
+      case 3:
+        emit_op(s, OP_insert4);
+        break;
+      default:
+        abort();
+    }
+
+    /* XXX: we disable the OP_put_ref_value optimization by not
+       using put_lvalue() otherwise depth_lvalue is not correct */
+    put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_NOKEEP_DEPTH,
+               FALSE);
+    label2 = emit_goto(s, OP_goto, -1);
+
+    emit_label(s, label1);
+
+    /* remove the lvalue stack entries */
+    while (depth_lvalue != 0) {
+      emit_op(s, OP_nip);
+      depth_lvalue--;
+    }
+
+    emit_label(s, label2);
+  }
+  return 0;
+}
+
+static __exception int js_parse_assign_expr(JSParseState *s)
+{
+  return js_parse_assign_expr2(s, PF_IN_ACCEPTED);
+}
+
+/* allowed parse_flags: PF_IN_ACCEPTED */
+static __exception int js_parse_expr2(JSParseState *s, int parse_flags)
+{
+  BOOL comma = FALSE;
+  for(;;) {
+    if (js_parse_assign_expr2(s, parse_flags))
+      return -1;
+    if (comma) {
+      /* prevent get_lvalue from using the last expression
+         as an lvalue. This also prevents the conversion of
+         of get_var to get_ref for method lookup in function
+         call inside `with` statement.
+       */
+      s->cur_func->last_opcode_pos = -1;
+    }
+    if (s->token.val != ',')
+      break;
+    comma = TRUE;
+    if (next_token(s))
+      return -1;
+    emit_op(s, OP_drop);
+  }
+  return 0;
+}
+
+static __exception int js_parse_expr(JSParseState *s)
+{
+  return js_parse_expr2(s, PF_IN_ACCEPTED);
+}
+
+static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
+                             JSAtom label_name,
+                             int label_break, int label_cont,
+                             int drop_count)
+{
+  be->prev = fd->top_break;
+  fd->top_break = be;
+  be->label_name = label_name;
+  be->label_break = label_break;
+  be->label_cont = label_cont;
+  be->drop_count = drop_count;
+  be->label_finally = -1;
+  be->scope_level = fd->scope_level;
+  be->has_iterator = FALSE;
+}
+
+static void pop_break_entry(JSFunctionDef *fd)
+{
+  BlockEnv *be;
+  be = fd->top_break;
+  fd->top_break = be->prev;
+}
+
+static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont)
+{
+  BlockEnv *top;
+  int i, scope_level;
+
+  scope_level = s->cur_func->scope_level;
+  top = s->cur_func->top_break;
+  while (top != NULL) {
+    close_scopes(s, scope_level, top->scope_level);
+    scope_level = top->scope_level;
+    if (is_cont &&
+        top->label_cont != -1 &&
+        (name == JS_ATOM_NULL || top->label_name == name)) {
+      /* continue stays inside the same block */
+      emit_goto(s, OP_goto, top->label_cont);
+      return 0;
+    }
+    if (!is_cont &&
+        top->label_break != -1 &&
+        (name == JS_ATOM_NULL || top->label_name == name)) {
+      emit_goto(s, OP_goto, top->label_break);
+      return 0;
+    }
+    i = 0;
+    if (top->has_iterator) {
+      emit_op(s, OP_iterator_close);
+      i += 3;
+    }
+    for(; i < top->drop_count; i++)
+      emit_op(s, OP_drop);
+    if (top->label_finally != -1) {
+      /* must push dummy value to keep same stack depth */
+      emit_op(s, OP_undefined);
+      emit_goto(s, OP_gosub, top->label_finally);
+      emit_op(s, OP_drop);
+    }
+    top = top->prev;
+  }
+  if (name == JS_ATOM_NULL) {
+    if (is_cont)
+      return js_parse_error(s, "continue must be inside loop");
+    else
+      return js_parse_error(s, "break must be inside loop or switch");
+  } else {
+    return js_parse_error(s, "break/continue label not found");
+  }
+}
+
+/* execute the finally blocks before return */
+static void emit_return(JSParseState *s, BOOL hasval)
+{
+  BlockEnv *top;
+  int drop_count;
+
+  drop_count = 0;
+  top = s->cur_func->top_break;
+  while (top != NULL) {
+    /* XXX: emit the appropriate OP_leave_scope opcodes? Probably not
+       required as all local variables will be closed upon returning
+       from JS_CallInternal, but not in the same order. */
+    if (top->has_iterator) {
+      /* with 'yield', the exact number of OP_drop to emit is
+         unknown, so we use a specific operation to look for
+         the catch offset */
+      if (!hasval) {
+        emit_op(s, OP_undefined);
+        hasval = TRUE;
+      }
+      emit_op(s, OP_iterator_close_return);
+      if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
+        int label_next, label_next2;
+
+        emit_op(s, OP_drop); /* catch offset */
+        emit_op(s, OP_drop); /* next */
+        emit_op(s, OP_get_field2);
+        emit_atom(s, JS_ATOM_return);
+        /* stack: iter_obj return_func */
+        emit_op(s, OP_dup);
+        emit_op(s, OP_is_undefined_or_null);
+        label_next = emit_goto(s, OP_if_true, -1);
+        emit_op(s, OP_call_method);
+        emit_u16(s, 0);
+        emit_op(s, OP_iterator_check_object);
+        emit_op(s, OP_await);
+        label_next2 = emit_goto(s, OP_goto, -1);
+        emit_label(s, label_next);
+        emit_op(s, OP_drop);
+        emit_label(s, label_next2);
+        emit_op(s, OP_drop);
+      } else {
+        emit_op(s, OP_iterator_close);
+      }
+      drop_count = -3;
+    }
+    drop_count += top->drop_count;
+    if (top->label_finally != -1) {
+      while(drop_count) {
+        /* must keep the stack top if hasval */
+        emit_op(s, hasval ? OP_nip : OP_drop);
+        drop_count--;
+      }
+      if (!hasval) {
+        /* must push return value to keep same stack size */
+        emit_op(s, OP_undefined);
+        hasval = TRUE;
+      }
+      emit_goto(s, OP_gosub, top->label_finally);
+    }
+    top = top->prev;
+  }
+  if (s->cur_func->is_derived_class_constructor) {
+    int label_return;
+
+    /* 'this' can be uninitialized, so it may be accessed only if
+       the derived class constructor does not return an object */
+    if (hasval) {
+      emit_op(s, OP_check_ctor_return);
+      label_return = emit_goto(s, OP_if_false, -1);
+      emit_op(s, OP_drop);
+    } else {
+      label_return = -1;
+    }
+
+    /* XXX: if this is not initialized, should throw the
+       ReferenceError in the caller realm */
+    emit_op(s, OP_scope_get_var);
+    emit_atom(s, JS_ATOM_this);
+    emit_u16(s, 0);
+
+    emit_label(s, label_return);
+    emit_op(s, OP_return);
+  } else if (s->cur_func->func_kind != JS_FUNC_NORMAL) {
+    if (!hasval) {
+      emit_op(s, OP_undefined);
+    } else if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
+      emit_op(s, OP_await);
+    }
+    emit_op(s, OP_return_async);
+  } else {
+    emit_op(s, hasval ? OP_return : OP_return_undef);
+  }
+}
+
+#define DECL_MASK_FUNC  (1 << 0) /* allow normal function declaration */
+/* ored with DECL_MASK_FUNC if function declarations are allowed with a label */
+#define DECL_MASK_FUNC_WITH_LABEL (1 << 1)
+#define DECL_MASK_OTHER (1 << 2) /* all other declarations */
+#define DECL_MASK_ALL   (DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL | DECL_MASK_OTHER)
+
+static __exception int js_parse_statement_or_decl(JSParseState *s,
+                                                  int decl_mask);
+
+static __exception int js_parse_statement(JSParseState *s)
+{
+  return js_parse_statement_or_decl(s, 0);
+}
+
+static __exception int js_parse_block(JSParseState *s)
+{
+  if (js_parse_expect(s, '{'))
+    return -1;
+  if (s->token.val != '}') {
+    push_scope(s);
+    for(;;) {
+      if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
+        return -1;
+      if (s->token.val == '}')
+        break;
+    }
+    pop_scope(s);
+  }
+  if (next_token(s))
+    return -1;
+  return 0;
+}
+
+/* allowed parse_flags: PF_IN_ACCEPTED */
+static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
+                                    BOOL export_flag)
+{
+  JSContext *ctx = s->ctx;
+  JSFunctionDef *fd = s->cur_func;
+  JSAtom name = JS_ATOM_NULL;
+
+  for (;;) {
+    if (s->token.val == TOK_IDENT) {
+      if (s->token.u.ident.is_reserved) {
+        return js_parse_error_reserved_identifier(s);
+      }
+      name = JS_DupAtom(ctx, s->token.u.ident.atom);
+      if (name == JS_ATOM_let && (tok == TOK_LET || tok == TOK_CONST)) {
+        js_parse_error(s, "'let' is not a valid lexical identifier");
+        goto var_error;
+      }
+      if (next_token(s))
+        goto var_error;
+      if (js_define_var(s, name, tok))
+        goto var_error;
+      if (export_flag) {
+        if (!add_export_entry(s, s->cur_func->module, name, name,
+                              JS_EXPORT_TYPE_LOCAL))
+          goto var_error;
+      }
+
+      if (s->token.val == '=') {
+        if (next_token(s))
+          goto var_error;
+        if (tok == TOK_VAR) {
+          /* Must make a reference for proper `with` semantics */
+          int opcode, scope, label;
+          JSAtom name1;
+
+          emit_op(s, OP_scope_get_var);
+          emit_atom(s, name);
+          emit_u16(s, fd->scope_level);
+          if (get_lvalue(s, &opcode, &scope, &name1, &label, NULL, FALSE, '=') < 0)
+            goto var_error;
+          if (js_parse_assign_expr2(s, parse_flags)) {
+            JS_FreeAtom(ctx, name1);
+            goto var_error;
+          }
+          set_object_name(s, name);
+          put_lvalue(s, opcode, scope, name1, label,
+                     PUT_LVALUE_NOKEEP, FALSE);
+        } else {
+          if (js_parse_assign_expr2(s, parse_flags))
+            goto var_error;
+          set_object_name(s, name);
+          emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ?
+                                                          OP_scope_put_var_init : OP_scope_put_var);
+          emit_atom(s, name);
+          emit_u16(s, fd->scope_level);
+        }
+      } else {
+        if (tok == TOK_CONST) {
+          js_parse_error(s, "missing initializer for const variable");
+          goto var_error;
+        }
+        if (tok == TOK_LET) {
+          /* initialize lexical variable upon entering its scope */
+          emit_op(s, OP_undefined);
+          emit_op(s, OP_scope_put_var_init);
+          emit_atom(s, name);
+          emit_u16(s, fd->scope_level);
+        }
+      }
+      JS_FreeAtom(ctx, name);
+    } else {
+      int skip_bits;
+      if ((s->token.val == '[' || s->token.val == '{')
+          &&  js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
+        emit_op(s, OP_undefined);
+        if (js_parse_destructuring_element(s, tok, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
+          return -1;
+      } else {
+        return js_parse_error(s, "variable name expected");
+      }
+    }
+    if (s->token.val != ',')
+      break;
+    if (next_token(s))
+      return -1;
+  }
+  return 0;
+
+var_error:
+  JS_FreeAtom(ctx, name);
+  return -1;
+}
+
+/* test if the current token is a label. Use simplistic look-ahead scanner */
+static BOOL is_label(JSParseState *s)
+{
+  return (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
+          peek_token(s, FALSE) == ':');
+}
+
+/* test if the current token is a let keyword. Use simplistic look-ahead scanner */
+static int is_let(JSParseState *s, int decl_mask)
+{
+  int res = FALSE;
+
+  if (token_is_pseudo_keyword(s, JS_ATOM_let)) {
+#if 1
+    JSParsePos pos;
+    js_parse_get_pos(s, &pos);
+    for (;;) {
+      if (next_token(s)) {
+        res = -1;
+        break;
+      }
+      if (s->token.val == '[') {
+        /* let [ is a syntax restriction:
+           it never introduces an ExpressionStatement */
+        res = TRUE;
+        break;
+      }
+      if (s->token.val == '{' ||
+          (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved) ||
+          s->token.val == TOK_LET ||
+          s->token.val == TOK_YIELD ||
+          s->token.val == TOK_AWAIT) {
+        /* Check for possible ASI if not scanning for Declaration */
+        /* XXX: should also check that `{` introduces a BindingPattern,
+           but Firefox does not and rejects eval("let=1;let\n{if(1)2;}") */
+        if (s->last_line_num == s->token.line_num || (decl_mask & DECL_MASK_OTHER)) {
+          res = TRUE;
+          break;
+        }
+        break;
+      }
+      break;
+    }
+    if (js_parse_seek_token(s, &pos)) {
+      res = -1;
+    }
+#else
+    int tok = peek_token(s, TRUE);
+    if (tok == '{' || tok == TOK_IDENT || peek_token(s, FALSE) == '[') {
+      res = TRUE;
+    }
+#endif
+  }
+  return res;
+}
+
+/* XXX: handle IteratorClose when exiting the loop before the
+   enumeration is done */
+static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
+                                          BOOL is_async)
+{
+  JSContext *ctx = s->ctx;
+  JSFunctionDef *fd = s->cur_func;
+  JSAtom var_name;
+  BOOL has_initializer, is_for_of, has_destructuring;
+  int tok, tok1, opcode, scope, block_scope_level;
+  int label_next, label_expr, label_cont, label_body, label_break;
+  int pos_next, pos_expr;
+  BlockEnv break_entry;
+
+  has_initializer = FALSE;
+  has_destructuring = FALSE;
+  is_for_of = FALSE;
+  block_scope_level = fd->scope_level;
+  label_cont = new_label(s);
+  label_body = new_label(s);
+  label_break = new_label(s);
+  label_next = new_label(s);
+
+  /* create scope for the lexical variables declared in the enumeration
+     expressions. XXX: Not completely correct because of weird capturing
+     semantics in `for (i of o) a.push(function(){return i})` */
+  push_scope(s);
+
+  /* local for_in scope starts here so individual elements
+     can be closed in statement. */
+  push_break_entry(s->cur_func, &break_entry,
+                   label_name, label_break, label_cont, 1);
+  break_entry.scope_level = block_scope_level;
+
+  label_expr = emit_goto(s, OP_goto, -1);
+
+  pos_next = s->cur_func->byte_code.size;
+  emit_label(s, label_next);
+
+  tok = s->token.val;
+  switch (is_let(s, DECL_MASK_OTHER)) {
+    case TRUE:
+      tok = TOK_LET;
+      break;
+    case FALSE:
+      break;
+    default:
+      return -1;
+  }
+  if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) {
+    if (next_token(s))
+      return -1;
+
+    if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
+      if (s->token.val == '[' || s->token.val == '{') {
+        if (js_parse_destructuring_element(s, tok, 0, TRUE, -1, FALSE) < 0)
+          return -1;
+        has_destructuring = TRUE;
+      } else {
+        return js_parse_error(s, "variable name expected");
+      }
+      var_name = JS_ATOM_NULL;
+    } else {
+      var_name = JS_DupAtom(ctx, s->token.u.ident.atom);
+      if (next_token(s)) {
+        JS_FreeAtom(s->ctx, var_name);
+        return -1;
+      }
+      if (js_define_var(s, var_name, tok)) {
+        JS_FreeAtom(s->ctx, var_name);
+        return -1;
+      }
+      emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ?
+                                                      OP_scope_put_var_init : OP_scope_put_var);
+      emit_atom(s, var_name);
+      emit_u16(s, fd->scope_level);
+    }
+  } else {
+    int skip_bits;
+    if ((s->token.val == '[' || s->token.val == '{')
+        &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == TOK_IN || tok1 == TOK_OF)) {
+      if (js_parse_destructuring_element(s, 0, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
+        return -1;
+    } else {
+      int lvalue_label;
+      if (js_parse_left_hand_side_expr(s))
+        return -1;
+      if (get_lvalue(s, &opcode, &scope, &var_name, &lvalue_label,
+                     NULL, FALSE, TOK_FOR))
+        return -1;
+      put_lvalue(s, opcode, scope, var_name, lvalue_label,
+                 PUT_LVALUE_NOKEEP_BOTTOM, FALSE);
+    }
+    var_name = JS_ATOM_NULL;
+  }
+  emit_goto(s, OP_goto, label_body);
+
+  pos_expr = s->cur_func->byte_code.size;
+  emit_label(s, label_expr);
+  if (s->token.val == '=') {
+    /* XXX: potential scoping issue if inside `with` statement */
+    has_initializer = TRUE;
+    /* parse and evaluate initializer prior to evaluating the
+       object (only used with "for in" with a non lexical variable
+       in non strict mode */
+    if (next_token(s) || js_parse_assign_expr2(s, 0)) {
+      JS_FreeAtom(ctx, var_name);
+      return -1;
+    }
+    if (var_name != JS_ATOM_NULL) {
+      emit_op(s, OP_scope_put_var);
+      emit_atom(s, var_name);
+      emit_u16(s, fd->scope_level);
+    }
+  }
+  JS_FreeAtom(ctx, var_name);
+
+  if (token_is_pseudo_keyword(s, JS_ATOM_of)) {
+    break_entry.has_iterator = is_for_of = TRUE;
+    break_entry.drop_count += 2;
+    if (has_initializer)
+      goto initializer_error;
+  } else if (s->token.val == TOK_IN) {
+    if (is_async)
+      return js_parse_error(s, "'for await' loop should be used with 'of'");
+    if (has_initializer &&
+        (tok != TOK_VAR || (fd->js_mode & JS_MODE_STRICT) ||
+         has_destructuring)) {
+    initializer_error:
+      return js_parse_error(s, "a declaration in the head of a for-%s loop can't have an initializer",
+                            is_for_of ? "of" : "in");
+    }
+  } else {
+    return js_parse_error(s, "expected 'of' or 'in' in for control expression");
+  }
+  if (next_token(s))
+    return -1;
+  if (is_for_of) {
+    if (js_parse_assign_expr(s))
+      return -1;
+  } else {
+    if (js_parse_expr(s))
+      return -1;
+  }
+  /* close the scope after having evaluated the expression so that
+     the TDZ values are in the closures */
+  close_scopes(s, s->cur_func->scope_level, block_scope_level);
+  if (is_for_of) {
+    if (is_async)
+      emit_op(s, OP_for_await_of_start);
+    else
+      emit_op(s, OP_for_of_start);
+    /* on stack: enum_rec */
+  } else {
+    emit_op(s, OP_for_in_start);
+    /* on stack: enum_obj */
+  }
+  emit_goto(s, OP_goto, label_cont);
+
+  if (js_parse_expect(s, ')'))
+    return -1;
+
+  if (OPTIMIZE) {
+    /* move the `next` code here */
+    DynBuf *bc = &s->cur_func->byte_code;
+    int chunk_size = pos_expr - pos_next;
+    int offset = bc->size - pos_next;
+    int i;
+    dbuf_realloc(bc, bc->size + chunk_size);
+    dbuf_put(bc, bc->buf + pos_next, chunk_size);
+    memset(bc->buf + pos_next, OP_nop, chunk_size);
+    /* `next` part ends with a goto */
+    s->cur_func->last_opcode_pos = bc->size - 5;
+    /* relocate labels */
+    for (i = label_cont; i < s->cur_func->label_count; i++) {
+      LabelSlot *ls = &s->cur_func->label_slots[i];
+      if (ls->pos >= pos_next && ls->pos < pos_expr)
+        ls->pos += offset;
+    }
+  }
+
+  emit_label(s, label_body);
+  if (js_parse_statement(s))
+    return -1;
+
+  close_scopes(s, s->cur_func->scope_level, block_scope_level);
+
+  emit_label(s, label_cont);
+  if (is_for_of) {
+    if (is_async) {
+      /* call the next method */
+      /* stack: iter_obj next catch_offset */
+      emit_op(s, OP_dup3);
+      emit_op(s, OP_drop);
+      emit_op(s, OP_call_method);
+      emit_u16(s, 0);
+      /* get the result of the promise */
+      emit_op(s, OP_await);
+      /* unwrap the value and done values */
+      emit_op(s, OP_iterator_get_value_done);
+    } else {
+      emit_op(s, OP_for_of_next);
+      emit_u8(s, 0);
+    }
+  } else {
+    emit_op(s, OP_for_in_next);
+  }
+  /* on stack: enum_rec / enum_obj value bool */
+  emit_goto(s, OP_if_false, label_next);
+  /* drop the undefined value from for_xx_next */
+  emit_op(s, OP_drop);
+
+  emit_label(s, label_break);
+  if (is_for_of) {
+    /* close and drop enum_rec */
+    emit_op(s, OP_iterator_close);
+  } else {
+    emit_op(s, OP_drop);
+  }
+  pop_break_entry(s->cur_func);
+  pop_scope(s);
+  return 0;
+}
+
+static void set_eval_ret_undefined(JSParseState *s)
+{
+  if (s->cur_func->eval_ret_idx >= 0) {
+    emit_op(s, OP_undefined);
+    emit_op(s, OP_put_loc);
+    emit_u16(s, s->cur_func->eval_ret_idx);
+  }
+}
+
+static __exception int js_parse_statement_or_decl(JSParseState *s,
+                                                  int decl_mask)
+{
+  JSContext *ctx = s->ctx;
+  JSAtom label_name;
+  int tok;
+
+  /* specific label handling */
+  /* XXX: support multiple labels on loop statements */
+  label_name = JS_ATOM_NULL;
+  if (is_label(s)) {
+    BlockEnv *be;
+
+    label_name = JS_DupAtom(ctx, s->token.u.ident.atom);
+
+    for (be = s->cur_func->top_break; be; be = be->prev) {
+      if (be->label_name == label_name) {
+        js_parse_error(s, "duplicate label name");
+        goto fail;
+      }
+    }
+
+    if (next_token(s))
+      goto fail;
+    if (js_parse_expect(s, ':'))
+      goto fail;
+    if (s->token.val != TOK_FOR
+        &&  s->token.val != TOK_DO
+        &&  s->token.val != TOK_WHILE) {
+      /* labelled regular statement */
+      int label_break, mask;
+      BlockEnv break_entry;
+
+      label_break = new_label(s);
+      push_break_entry(s->cur_func, &break_entry,
+                       label_name, label_break, -1, 0);
+      if (!(s->cur_func->js_mode & JS_MODE_STRICT) &&
+          (decl_mask & DECL_MASK_FUNC_WITH_LABEL)) {
+        mask = DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL;
+      } else {
+        mask = 0;
+      }
+      if (js_parse_statement_or_decl(s, mask))
+        goto fail;
+      emit_label(s, label_break);
+      pop_break_entry(s->cur_func);
+      goto done;
+    }
+  }
+
+  switch(tok = s->token.val) {
+    case '{':
+      if (js_parse_block(s))
+        goto fail;
+      break;
+    case TOK_RETURN:
+      if (s->cur_func->is_eval) {
+        js_parse_error(s, "return not in a function");
+        goto fail;
+      }
+      if (next_token(s))
+        goto fail;
+      if (s->token.val != ';' && s->token.val != '}' && !s->got_lf) {
+        if (js_parse_expr(s))
+          goto fail;
+        emit_return(s, TRUE);
+      } else {
+        emit_return(s, FALSE);
+      }
+      if (js_parse_expect_semi(s))
+        goto fail;
+      break;
+    case TOK_THROW:
+      if (next_token(s))
+        goto fail;
+      if (s->got_lf) {
+        js_parse_error(s, "line terminator not allowed after throw");
+        goto fail;
+      }
+      if (js_parse_expr(s))
+        goto fail;
+      emit_op(s, OP_throw);
+      if (js_parse_expect_semi(s))
+        goto fail;
+      break;
+    case TOK_LET:
+    case TOK_CONST:
+    haslet:
+      if (!(decl_mask & DECL_MASK_OTHER)) {
+        js_parse_error(s, "lexical declarations can't appear in single-statement context");
+        goto fail;
+      }
+      /* fall thru */
+    case TOK_VAR:
+      if (next_token(s))
+        goto fail;
+      if (js_parse_var(s, TRUE, tok, FALSE))
+        goto fail;
+      if (js_parse_expect_semi(s))
+        goto fail;
+      break;
+    case TOK_IF:
+    {
+      int label1, label2, mask;
+      if (next_token(s))
+        goto fail;
+      /* create a new scope for `let f;if(1) function f(){}` */
+      push_scope(s);
+      set_eval_ret_undefined(s);
+      if (js_parse_expr_paren(s))
+        goto fail;
+      label1 = emit_goto(s, OP_if_false, -1);
+      if (s->cur_func->js_mode & JS_MODE_STRICT)
+        mask = 0;
+      else
+        mask = DECL_MASK_FUNC; /* Annex B.3.4 */
+
+      if (js_parse_statement_or_decl(s, mask))
+        goto fail;
+
+      if (s->token.val == TOK_ELSE) {
+        label2 = emit_goto(s, OP_goto, -1);
+        if (next_token(s))
+          goto fail;
+
+        emit_label(s, label1);
+        if (js_parse_statement_or_decl(s, mask))
+          goto fail;
+
+        label1 = label2;
+      }
+      emit_label(s, label1);
+      pop_scope(s);
+    }
+    break;
+    case TOK_WHILE:
+    {
+      int label_cont, label_break;
+      BlockEnv break_entry;
+
+      label_cont = new_label(s);
+      label_break = new_label(s);
+
+      push_break_entry(s->cur_func, &break_entry,
+                       label_name, label_break, label_cont, 0);
+
+      if (next_token(s))
+        goto fail;
+
+      set_eval_ret_undefined(s);
+
+      emit_label(s, label_cont);
+      if (js_parse_expr_paren(s))
+        goto fail;
+      emit_goto(s, OP_if_false, label_break);
+
+      if (js_parse_statement(s))
+        goto fail;
+      emit_goto(s, OP_goto, label_cont);
+
+      emit_label(s, label_break);
+
+      pop_break_entry(s->cur_func);
+    }
+    break;
+    case TOK_DO:
+    {
+      int label_cont, label_break, label1;
+      BlockEnv break_entry;
+
+      label_cont = new_label(s);
+      label_break = new_label(s);
+      label1 = new_label(s);
+
+      push_break_entry(s->cur_func, &break_entry,
+                       label_name, label_break, label_cont, 0);
+
+      if (next_token(s))
+        goto fail;
+
+      emit_label(s, label1);
+
+      set_eval_ret_undefined(s);
+
+      if (js_parse_statement(s))
+        goto fail;
+
+      emit_label(s, label_cont);
+      if (js_parse_expect(s, TOK_WHILE))
+        goto fail;
+      if (js_parse_expr_paren(s))
+        goto fail;
+      /* Insert semicolon if missing */
+      if (s->token.val == ';') {
+        if (next_token(s))
+          goto fail;
+      }
+      emit_goto(s, OP_if_true, label1);
+
+      emit_label(s, label_break);
+
+      pop_break_entry(s->cur_func);
+    }
+    break;
+    case TOK_FOR:
+    {
+      int label_cont, label_break, label_body, label_test;
+      int pos_cont, pos_body, block_scope_level;
+      BlockEnv break_entry;
+      int tok, bits;
+      BOOL is_async;
+
+      if (next_token(s))
+        goto fail;
+
+      set_eval_ret_undefined(s);
+      bits = 0;
+      is_async = FALSE;
+      if (s->token.val == '(') {
+        js_parse_skip_parens_token(s, &bits, FALSE);
+      } else if (s->token.val == TOK_AWAIT) {
+        if (!(s->cur_func->func_kind & JS_FUNC_ASYNC)) {
+          js_parse_error(s, "for await is only valid in asynchronous functions");
+          goto fail;
+        }
+        is_async = TRUE;
+        if (next_token(s))
+          goto fail;
+      }
+      if (js_parse_expect(s, '('))
+        goto fail;
+
+      if (!(bits & SKIP_HAS_SEMI)) {
+        /* parse for/in or for/of */
+        if (js_parse_for_in_of(s, label_name, is_async))
+          goto fail;
+        break;
+      }
+      block_scope_level = s->cur_func->scope_level;
+
+      /* create scope for the lexical variables declared in the initial,
+         test and increment expressions */
+      push_scope(s);
+      /* initial expression */
+      tok = s->token.val;
+      if (tok != ';') {
+        switch (is_let(s, DECL_MASK_OTHER)) {
+          case TRUE:
+            tok = TOK_LET;
+            break;
+          case FALSE:
+            break;
+          default:
+            goto fail;
+        }
+        if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) {
+          if (next_token(s))
+            goto fail;
+          if (js_parse_var(s, FALSE, tok, FALSE))
+            goto fail;
+        } else {
+          if (js_parse_expr2(s, FALSE))
+            goto fail;
+          emit_op(s, OP_drop);
+        }
+
+        /* close the closures before the first iteration */
+        close_scopes(s, s->cur_func->scope_level, block_scope_level);
+      }
+      if (js_parse_expect(s, ';'))
+        goto fail;
+
+      label_test = new_label(s);
+      label_cont = new_label(s);
+      label_body = new_label(s);
+      label_break = new_label(s);
+
+      push_break_entry(s->cur_func, &break_entry,
+                       label_name, label_break, label_cont, 0);
+
+      /* test expression */
+      if (s->token.val == ';') {
+        /* no test expression */
+        label_test = label_body;
+      } else {
+        emit_label(s, label_test);
+        if (js_parse_expr(s))
+          goto fail;
+        emit_goto(s, OP_if_false, label_break);
+      }
+      if (js_parse_expect(s, ';'))
+        goto fail;
+
+      if (s->token.val == ')') {
+        /* no end expression */
+        break_entry.label_cont = label_cont = label_test;
+        pos_cont = 0; /* avoid warning */
+      } else {
+        /* skip the end expression */
+        emit_goto(s, OP_goto, label_body);
+
+        pos_cont = s->cur_func->byte_code.size;
+        emit_label(s, label_cont);
+        if (js_parse_expr(s))
+          goto fail;
+        emit_op(s, OP_drop);
+        if (label_test != label_body)
+          emit_goto(s, OP_goto, label_test);
+      }
+      if (js_parse_expect(s, ')'))
+        goto fail;
+
+      pos_body = s->cur_func->byte_code.size;
+      emit_label(s, label_body);
+      if (js_parse_statement(s))
+        goto fail;
+
+      /* close the closures before the next iteration */
+      /* XXX: check continue case */
+      close_scopes(s, s->cur_func->scope_level, block_scope_level);
+
+      if (OPTIMIZE && label_test != label_body && label_cont != label_test) {
+        /* move the increment code here */
+        DynBuf *bc = &s->cur_func->byte_code;
+        int chunk_size = pos_body - pos_cont;
+        int offset = bc->size - pos_cont;
+        int i;
+        dbuf_realloc(bc, bc->size + chunk_size);
+        dbuf_put(bc, bc->buf + pos_cont, chunk_size);
+        memset(bc->buf + pos_cont, OP_nop, chunk_size);
+        /* increment part ends with a goto */
+        s->cur_func->last_opcode_pos = bc->size - 5;
+        /* relocate labels */
+        for (i = label_cont; i < s->cur_func->label_count; i++) {
+          LabelSlot *ls = &s->cur_func->label_slots[i];
+          if (ls->pos >= pos_cont && ls->pos < pos_body)
+            ls->pos += offset;
+        }
+      } else {
+        emit_goto(s, OP_goto, label_cont);
+      }
+
+      emit_label(s, label_break);
+
+      pop_break_entry(s->cur_func);
+      pop_scope(s);
+    }
+    break;
+    case TOK_BREAK:
+    case TOK_CONTINUE:
+    {
+      int is_cont = s->token.val - TOK_BREAK;
+      int label;
+
+      if (next_token(s))
+        goto fail;
+      if (!s->got_lf && s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)
+        label = s->token.u.ident.atom;
+      else
+        label = JS_ATOM_NULL;
+      if (emit_break(s, label, is_cont))
+        goto fail;
+      if (label != JS_ATOM_NULL) {
+        if (next_token(s))
+          goto fail;
+      }
+      if (js_parse_expect_semi(s))
+        goto fail;
+    }
+    break;
+    case TOK_SWITCH:
+    {
+      int label_case, label_break, label1;
+      int default_label_pos;
+      BlockEnv break_entry;
+
+      if (next_token(s))
+        goto fail;
+
+      set_eval_ret_undefined(s);
+      if (js_parse_expr_paren(s))
+        goto fail;
+
+      push_scope(s);
+      label_break = new_label(s);
+      push_break_entry(s->cur_func, &break_entry,
+                       label_name, label_break, -1, 1);
+
+      if (js_parse_expect(s, '{'))
+        goto fail;
+
+      default_label_pos = -1;
+      label_case = -1;
+      while (s->token.val != '}') {
+        if (s->token.val == TOK_CASE) {
+          label1 = -1;
+          if (label_case >= 0) {
+            /* skip the case if needed */
+            label1 = emit_goto(s, OP_goto, -1);
+          }
+          emit_label(s, label_case);
+          label_case = -1;
+          for (;;) {
+            /* parse a sequence of case clauses */
+            if (next_token(s))
+              goto fail;
+            emit_op(s, OP_dup);
+            if (js_parse_expr(s))
+              goto fail;
+            if (js_parse_expect(s, ':'))
+              goto fail;
+            emit_op(s, OP_strict_eq);
+            if (s->token.val == TOK_CASE) {
+              label1 = emit_goto(s, OP_if_true, label1);
+            } else {
+              label_case = emit_goto(s, OP_if_false, -1);
+              emit_label(s, label1);
+              break;
+            }
+          }
+        } else if (s->token.val == TOK_DEFAULT) {
+          if (next_token(s))
+            goto fail;
+          if (js_parse_expect(s, ':'))
+            goto fail;
+          if (default_label_pos >= 0) {
+            js_parse_error(s, "duplicate default");
+            goto fail;
+          }
+          if (label_case < 0) {
+            /* falling thru direct from switch expression */
+            label_case = emit_goto(s, OP_goto, -1);
+          }
+          /* Emit a dummy label opcode. Label will be patched after
+             the end of the switch body. Do not use emit_label(s, 0)
+             because it would clobber label 0 address, preventing
+             proper optimizer operation.
+           */
+          emit_op(s, OP_label);
+          emit_u32(s, 0);
+          default_label_pos = s->cur_func->byte_code.size - 4;
+        } else {
+          if (label_case < 0) {
+            /* falling thru direct from switch expression */
+            js_parse_error(s, "invalid switch statement");
+            goto fail;
+          }
+          if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
+            goto fail;
+        }
+      }
+      if (js_parse_expect(s, '}'))
+        goto fail;
+      if (default_label_pos >= 0) {
+        /* Ugly patch for the the `default` label, shameful and risky */
+        put_u32(s->cur_func->byte_code.buf + default_label_pos,
+                label_case);
+        s->cur_func->label_slots[label_case].pos = default_label_pos + 4;
+      } else {
+        emit_label(s, label_case);
+      }
+      emit_label(s, label_break);
+      emit_op(s, OP_drop); /* drop the switch expression */
+
+      pop_break_entry(s->cur_func);
+      pop_scope(s);
+    }
+    break;
+    case TOK_TRY:
+    {
+      int label_catch, label_catch2, label_finally, label_end;
+      JSAtom name;
+      BlockEnv block_env;
+
+      set_eval_ret_undefined(s);
+      if (next_token(s))
+        goto fail;
+      label_catch = new_label(s);
+      label_catch2 = new_label(s);
+      label_finally = new_label(s);
+      label_end = new_label(s);
+
+      emit_goto(s, OP_catch, label_catch);
+
+      push_break_entry(s->cur_func, &block_env,
+                       JS_ATOM_NULL, -1, -1, 1);
+      block_env.label_finally = label_finally;
+
+      if (js_parse_block(s))
+        goto fail;
+
+      pop_break_entry(s->cur_func);
+
+      if (js_is_live_code(s)) {
+        /* drop the catch offset */
+        emit_op(s, OP_drop);
+        /* must push dummy value to keep same stack size */
+        emit_op(s, OP_undefined);
+        emit_goto(s, OP_gosub, label_finally);
+        emit_op(s, OP_drop);
+
+        emit_goto(s, OP_goto, label_end);
+      }
+
+      if (s->token.val == TOK_CATCH) {
+        if (next_token(s))
+          goto fail;
+
+        push_scope(s);  /* catch variable */
+        emit_label(s, label_catch);
+
+        if (s->token.val == '{') {
+          /* support optional-catch-binding feature */
+          emit_op(s, OP_drop);    /* pop the exception object */
+        } else {
+          if (js_parse_expect(s, '('))
+            goto fail;
+          if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
+            if (s->token.val == '[' || s->token.val == '{') {
+              /* XXX: TOK_LET is not completely correct */
+              if (js_parse_destructuring_element(s, TOK_LET, 0, TRUE, -1, TRUE) < 0)
+                goto fail;
+            } else {
+              js_parse_error(s, "identifier expected");
+              goto fail;
+            }
+          } else {
+            name = JS_DupAtom(ctx, s->token.u.ident.atom);
+            if (next_token(s)
+                ||  js_define_var(s, name, TOK_CATCH) < 0) {
+              JS_FreeAtom(ctx, name);
+              goto fail;
+            }
+            /* store the exception value in the catch variable */
+            emit_op(s, OP_scope_put_var);
+            emit_u32(s, name);
+            emit_u16(s, s->cur_func->scope_level);
+          }
+          if (js_parse_expect(s, ')'))
+            goto fail;
+        }
+        /* XXX: should keep the address to nop it out if there is no finally block */
+        emit_goto(s, OP_catch, label_catch2);
+
+        push_scope(s);  /* catch block */
+        push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL,
+                         -1, -1, 1);
+        block_env.label_finally = label_finally;
+
+        if (js_parse_block(s))
+          goto fail;
+
+        pop_break_entry(s->cur_func);
+        pop_scope(s);  /* catch block */
+        pop_scope(s);  /* catch variable */
+
+        if (js_is_live_code(s)) {
+          /* drop the catch2 offset */
+          emit_op(s, OP_drop);
+          /* XXX: should keep the address to nop it out if there is no finally block */
+          /* must push dummy value to keep same stack size */
+          emit_op(s, OP_undefined);
+          emit_goto(s, OP_gosub, label_finally);
+          emit_op(s, OP_drop);
+          emit_goto(s, OP_goto, label_end);
+        }
+        /* catch exceptions thrown in the catch block to execute the
+                 * finally clause and rethrow the exception */
+        emit_label(s, label_catch2);
+        /* catch value is at TOS, no need to push undefined */
+        emit_goto(s, OP_gosub, label_finally);
+        emit_op(s, OP_throw);
+
+      } else if (s->token.val == TOK_FINALLY) {
+        /* finally without catch : execute the finally clause
+                 * and rethrow the exception */
+        emit_label(s, label_catch);
+        /* catch value is at TOS, no need to push undefined */
+        emit_goto(s, OP_gosub, label_finally);
+        emit_op(s, OP_throw);
+      } else {
+        js_parse_error(s, "expecting catch or finally");
+        goto fail;
+      }
+      emit_label(s, label_finally);
+      if (s->token.val == TOK_FINALLY) {
+        int saved_eval_ret_idx = 0; /* avoid warning */
+
+        if (next_token(s))
+          goto fail;
+        /* on the stack: ret_value gosub_ret_value */
+        push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL,
+                         -1, -1, 2);
+
+        if (s->cur_func->eval_ret_idx >= 0) {
+          /* 'finally' updates eval_ret only if not a normal
+             termination */
+          saved_eval_ret_idx =
+              add_var(s->ctx, s->cur_func, JS_ATOM__ret_);
+          if (saved_eval_ret_idx < 0)
+            goto fail;
+          emit_op(s, OP_get_loc);
+          emit_u16(s, s->cur_func->eval_ret_idx);
+          emit_op(s, OP_put_loc);
+          emit_u16(s, saved_eval_ret_idx);
+          set_eval_ret_undefined(s);
+        }
+
+        if (js_parse_block(s))
+          goto fail;
+
+        if (s->cur_func->eval_ret_idx >= 0) {
+          emit_op(s, OP_get_loc);
+          emit_u16(s, saved_eval_ret_idx);
+          emit_op(s, OP_put_loc);
+          emit_u16(s, s->cur_func->eval_ret_idx);
+        }
+        pop_break_entry(s->cur_func);
+      }
+      emit_op(s, OP_ret);
+      emit_label(s, label_end);
+    }
+    break;
+    case ';':
+      /* empty statement */
+      if (next_token(s))
+        goto fail;
+      break;
+    case TOK_WITH:
+      if (s->cur_func->js_mode & JS_MODE_STRICT) {
+        js_parse_error(s, "invalid keyword: with");
+        goto fail;
+      } else {
+        int with_idx;
+
+        if (next_token(s))
+          goto fail;
+
+        if (js_parse_expr_paren(s))
+          goto fail;
+
+        push_scope(s);
+        with_idx = define_var(s, s->cur_func, JS_ATOM__with_,
+                              JS_VAR_DEF_WITH);
+        if (with_idx < 0)
+          goto fail;
+        emit_op(s, OP_to_object);
+        emit_op(s, OP_put_loc);
+        emit_u16(s, with_idx);
+
+        set_eval_ret_undefined(s);
+        if (js_parse_statement(s))
+          goto fail;
+
+        /* Popping scope drops lexical context for the with object variable */
+        pop_scope(s);
+      }
+      break;
+    case TOK_FUNCTION:
+      /* ES6 Annex B.3.2 and B.3.3 semantics */
+      if (!(decl_mask & DECL_MASK_FUNC))
+        goto func_decl_error;
+      if (!(decl_mask & DECL_MASK_OTHER) && peek_token(s, FALSE) == '*')
+        goto func_decl_error;
+      goto parse_func_var;
+    case TOK_IDENT:
+      if (s->token.u.ident.is_reserved) {
+        js_parse_error_reserved_identifier(s);
+        goto fail;
+      }
+      /* Determine if `let` introduces a Declaration or an ExpressionStatement */
+      switch (is_let(s, decl_mask)) {
+        case TRUE:
+          tok = TOK_LET;
+          goto haslet;
+        case FALSE:
+          break;
+        default:
+          goto fail;
+      }
+      if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
+          peek_token(s, TRUE) == TOK_FUNCTION) {
+        if (!(decl_mask & DECL_MASK_OTHER)) {
+        func_decl_error:
+          js_parse_error(s, "function declarations can't appear in single-statement context");
+          goto fail;
+        }
+      parse_func_var:
+        if (js_parse_function_decl(s, JS_PARSE_FUNC_VAR,
+                                   JS_FUNC_NORMAL, JS_ATOM_NULL,
+                                   s->token.ptr, s->token.line_num))
+          goto fail;
+        break;
+      }
+      goto hasexpr;
+
+    case TOK_CLASS:
+      if (!(decl_mask & DECL_MASK_OTHER)) {
+        js_parse_error(s, "class declarations can't appear in single-statement context");
+        goto fail;
+      }
+      if (js_parse_class(s, FALSE, JS_PARSE_EXPORT_NONE))
+        return -1;
+      break;
+
+    case TOK_DEBUGGER:
+      /* currently no debugger, so just skip the keyword */
+      if (next_token(s))
+        goto fail;
+      if (js_parse_expect_semi(s))
+        goto fail;
+      break;
+
+    case TOK_ENUM:
+    case TOK_EXPORT:
+    case TOK_EXTENDS:
+      js_unsupported_keyword(s, s->token.u.ident.atom);
+      goto fail;
+
+    default:
+    hasexpr:
+      if (js_parse_expr(s))
+        goto fail;
+      if (s->cur_func->eval_ret_idx >= 0) {
+        /* store the expression value so that it can be returned
+           by eval() */
+        emit_op(s, OP_put_loc);
+        emit_u16(s, s->cur_func->eval_ret_idx);
+      } else {
+        emit_op(s, OP_drop); /* drop the result */
+      }
+      if (js_parse_expect_semi(s))
+        goto fail;
+      break;
+  }
+done:
+  JS_FreeAtom(ctx, label_name);
+  return 0;
+fail:
+  JS_FreeAtom(ctx, label_name);
+  return -1;
+}
+
+JSExportEntry *add_export_entry2(JSContext *ctx,
+                                        JSParseState *s, JSModuleDef *m,
+                                        JSAtom local_name, JSAtom export_name,
+                                        JSExportTypeEnum export_type)
+{
+  JSExportEntry *me;
+
+  if (find_export_entry(ctx, m, export_name)) {
+    char buf1[ATOM_GET_STR_BUF_SIZE];
+    if (s) {
+      js_parse_error(s, "duplicate exported name '%s'",
+                     JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name));
+    } else {
+      JS_ThrowSyntaxErrorAtom(ctx, "duplicate exported name '%s'", export_name);
+    }
+    return NULL;
+  }
+
+  if (js_resize_array(ctx, (void **)&m->export_entries,
+                      sizeof(JSExportEntry),
+                      &m->export_entries_size,
+                      m->export_entries_count + 1))
+    return NULL;
+  me = &m->export_entries[m->export_entries_count++];
+  memset(me, 0, sizeof(*me));
+  me->local_name = JS_DupAtom(ctx, local_name);
+  me->export_name = JS_DupAtom(ctx, export_name);
+  me->export_type = export_type;
+  return me;
+}
+
+static JSExportEntry *add_export_entry(JSParseState *s, JSModuleDef *m,
+                                       JSAtom local_name, JSAtom export_name,
+                                       JSExportTypeEnum export_type)
+{
+  return add_export_entry2(s->ctx, s, m, local_name, export_name,
+                           export_type);
+}
+
+static int add_star_export_entry(JSContext *ctx, JSModuleDef *m,
+                                 int req_module_idx)
+{
+  JSStarExportEntry *se;
+
+  if (js_resize_array(ctx, (void **)&m->star_export_entries,
+                      sizeof(JSStarExportEntry),
+                      &m->star_export_entries_size,
+                      m->star_export_entries_count + 1))
+    return -1;
+  se = &m->star_export_entries[m->star_export_entries_count++];
+  se->req_module_idx = req_module_idx;
+  return 0;
+}
+
+
+static __exception JSAtom js_parse_from_clause(JSParseState *s)
+{
+  JSAtom module_name;
+  if (!token_is_pseudo_keyword(s, JS_ATOM_from)) {
+    js_parse_error(s, "from clause expected");
+    return JS_ATOM_NULL;
+  }
+  if (next_token(s))
+    return JS_ATOM_NULL;
+  if (s->token.val != TOK_STRING) {
+    js_parse_error(s, "string expected");
+    return JS_ATOM_NULL;
+  }
+  module_name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
+  if (module_name == JS_ATOM_NULL)
+    return JS_ATOM_NULL;
+  if (next_token(s)) {
+    JS_FreeAtom(s->ctx, module_name);
+    return JS_ATOM_NULL;
+  }
+  return module_name;
+}
+
+static __exception int js_parse_export(JSParseState *s)
+{
+  JSContext *ctx = s->ctx;
+  JSModuleDef *m = s->cur_func->module;
+  JSAtom local_name, export_name;
+  int first_export, idx, i, tok;
+  JSAtom module_name;
+  JSExportEntry *me;
+
+  if (next_token(s))
+    return -1;
+
+  tok = s->token.val;
+  if (tok == TOK_CLASS) {
+    return js_parse_class(s, FALSE, JS_PARSE_EXPORT_NAMED);
+  } else if (tok == TOK_FUNCTION ||
+             (token_is_pseudo_keyword(s, JS_ATOM_async) &&
+              peek_token(s, TRUE) == TOK_FUNCTION)) {
+    return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT,
+                                   JS_FUNC_NORMAL, JS_ATOM_NULL,
+                                   s->token.ptr, s->token.line_num,
+                                   JS_PARSE_EXPORT_NAMED, NULL);
+  }
+
+  if (next_token(s))
+    return -1;
+
+  switch(tok) {
+    case '{':
+      first_export = m->export_entries_count;
+      while (s->token.val != '}') {
+        if (!token_is_ident(s->token.val)) {
+          js_parse_error(s, "identifier expected");
+          return -1;
+        }
+        local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
+        export_name = JS_ATOM_NULL;
+        if (next_token(s))
+          goto fail;
+        if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
+          if (next_token(s))
+            goto fail;
+          if (!token_is_ident(s->token.val)) {
+            js_parse_error(s, "identifier expected");
+            goto fail;
+          }
+          export_name = JS_DupAtom(ctx, s->token.u.ident.atom);
+          if (next_token(s)) {
+          fail:
+            JS_FreeAtom(ctx, local_name);
+          fail1:
+            JS_FreeAtom(ctx, export_name);
+            return -1;
+          }
+        } else {
+          export_name = JS_DupAtom(ctx, local_name);
+        }
+        me = add_export_entry(s, m, local_name, export_name,
+                              JS_EXPORT_TYPE_LOCAL);
+        JS_FreeAtom(ctx, local_name);
+        JS_FreeAtom(ctx, export_name);
+        if (!me)
+          return -1;
+        if (s->token.val != ',')
+          break;
+        if (next_token(s))
+          return -1;
+      }
+      if (js_parse_expect(s, '}'))
+        return -1;
+      if (token_is_pseudo_keyword(s, JS_ATOM_from)) {
+        module_name = js_parse_from_clause(s);
+        if (module_name == JS_ATOM_NULL)
+          return -1;
+        idx = add_req_module_entry(ctx, m, module_name);
+        JS_FreeAtom(ctx, module_name);
+        if (idx < 0)
+          return -1;
+        for(i = first_export; i < m->export_entries_count; i++) {
+          me = &m->export_entries[i];
+          me->export_type = JS_EXPORT_TYPE_INDIRECT;
+          me->u.req_module_idx = idx;
+        }
+      }
+      break;
+    case '*':
+      if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
+        /* export ns from */
+        if (next_token(s))
+          return -1;
+        if (!token_is_ident(s->token.val)) {
+          js_parse_error(s, "identifier expected");
+          return -1;
+        }
+        export_name = JS_DupAtom(ctx, s->token.u.ident.atom);
+        if (next_token(s))
+          goto fail1;
+        module_name = js_parse_from_clause(s);
+        if (module_name == JS_ATOM_NULL)
+          goto fail1;
+        idx = add_req_module_entry(ctx, m, module_name);
+        JS_FreeAtom(ctx, module_name);
+        if (idx < 0)
+          goto fail1;
+        me = add_export_entry(s, m, JS_ATOM__star_, export_name,
+                              JS_EXPORT_TYPE_INDIRECT);
+        JS_FreeAtom(ctx, export_name);
+        if (!me)
+          return -1;
+        me->u.req_module_idx = idx;
+      } else {
+        module_name = js_parse_from_clause(s);
+        if (module_name == JS_ATOM_NULL)
+          return -1;
+        idx = add_req_module_entry(ctx, m, module_name);
+        JS_FreeAtom(ctx, module_name);
+        if (idx < 0)
+          return -1;
+        if (add_star_export_entry(ctx, m, idx) < 0)
+          return -1;
+      }
+      break;
+    case TOK_DEFAULT:
+      if (s->token.val == TOK_CLASS) {
+        return js_parse_class(s, FALSE, JS_PARSE_EXPORT_DEFAULT);
+      } else if (s->token.val == TOK_FUNCTION ||
+                 (token_is_pseudo_keyword(s, JS_ATOM_async) &&
+                  peek_token(s, TRUE) == TOK_FUNCTION)) {
+        return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT,
+                                       JS_FUNC_NORMAL, JS_ATOM_NULL,
+                                       s->token.ptr, s->token.line_num,
+                                       JS_PARSE_EXPORT_DEFAULT, NULL);
+      } else {
+        if (js_parse_assign_expr(s))
+          return -1;
+      }
+      /* set the name of anonymous functions */
+      set_object_name(s, JS_ATOM_default);
+
+      /* store the value in the _default_ global variable and export
+         it */
+      local_name = JS_ATOM__default_;
+      if (define_var(s, s->cur_func, local_name, JS_VAR_DEF_LET) < 0)
+        return -1;
+      emit_op(s, OP_scope_put_var_init);
+      emit_atom(s, local_name);
+      emit_u16(s, 0);
+
+      if (!add_export_entry(s, m, local_name, JS_ATOM_default,
+                            JS_EXPORT_TYPE_LOCAL))
+        return -1;
+      break;
+    case TOK_VAR:
+    case TOK_LET:
+    case TOK_CONST:
+      return js_parse_var(s, TRUE, tok, TRUE);
+    default:
+      return js_parse_error(s, "invalid export syntax");
+  }
+  return js_parse_expect_semi(s);
+}
+
+static int add_closure_var(JSContext *ctx, JSFunctionDef *s,
+                           BOOL is_local, BOOL is_arg,
+                           int var_idx, JSAtom var_name,
+                           BOOL is_const, BOOL is_lexical,
+                           JSVarKindEnum var_kind);
+
+static int add_import(JSParseState *s, JSModuleDef *m,
+                      JSAtom local_name, JSAtom import_name)
+{
+  JSContext *ctx = s->ctx;
+  int i, var_idx;
+  JSImportEntry *mi;
+  BOOL is_local;
+
+  if (local_name == JS_ATOM_arguments || local_name == JS_ATOM_eval)
+    return js_parse_error(s, "invalid import binding");
+
+  if (local_name != JS_ATOM_default) {
+    for (i = 0; i < s->cur_func->closure_var_count; i++) {
+      if (s->cur_func->closure_var[i].var_name == local_name)
+        return js_parse_error(s, "duplicate import binding");
+    }
+  }
+
+  is_local = (import_name == JS_ATOM__star_);
+  var_idx = add_closure_var(ctx, s->cur_func, is_local, FALSE,
+                            m->import_entries_count,
+                            local_name, TRUE, TRUE, FALSE);
+  if (var_idx < 0)
+    return -1;
+  if (js_resize_array(ctx, (void **)&m->import_entries,
+                      sizeof(JSImportEntry),
+                      &m->import_entries_size,
+                      m->import_entries_count + 1))
+    return -1;
+  mi = &m->import_entries[m->import_entries_count++];
+  mi->import_name = JS_DupAtom(ctx, import_name);
+  mi->var_idx = var_idx;
+  return 0;
+}
+
+static __exception int js_parse_import(JSParseState *s)
+{
+  JSContext *ctx = s->ctx;
+  JSModuleDef *m = s->cur_func->module;
+  JSAtom local_name, import_name, module_name;
+  int first_import, i, idx;
+
+  if (next_token(s))
+    return -1;
+
+  first_import = m->import_entries_count;
+  if (s->token.val == TOK_STRING) {
+    module_name = JS_ValueToAtom(ctx, s->token.u.str.str);
+    if (module_name == JS_ATOM_NULL)
+      return -1;
+    if (next_token(s)) {
+      JS_FreeAtom(ctx, module_name);
+      return -1;
+    }
+  } else {
+    if (s->token.val == TOK_IDENT) {
+      if (s->token.u.ident.is_reserved) {
+        return js_parse_error_reserved_identifier(s);
+      }
+      /* "default" import */
+      local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
+      import_name = JS_ATOM_default;
+      if (next_token(s))
+        goto fail;
+      if (add_import(s, m, local_name, import_name))
+        goto fail;
+      JS_FreeAtom(ctx, local_name);
+
+      if (s->token.val != ',')
+        goto end_import_clause;
+      if (next_token(s))
+        return -1;
+    }
+
+    if (s->token.val == '*') {
+      /* name space import */
+      if (next_token(s))
+        return -1;
+      if (!token_is_pseudo_keyword(s, JS_ATOM_as))
+        return js_parse_error(s, "expecting 'as'");
+      if (next_token(s))
+        return -1;
+      if (!token_is_ident(s->token.val)) {
+        js_parse_error(s, "identifier expected");
+        return -1;
+      }
+      local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
+      import_name = JS_ATOM__star_;
+      if (next_token(s))
+        goto fail;
+      if (add_import(s, m, local_name, import_name))
+        goto fail;
+      JS_FreeAtom(ctx, local_name);
+    } else if (s->token.val == '{') {
+      if (next_token(s))
+        return -1;
+
+      while (s->token.val != '}') {
+        if (!token_is_ident(s->token.val)) {
+          js_parse_error(s, "identifier expected");
+          return -1;
+        }
+        import_name = JS_DupAtom(ctx, s->token.u.ident.atom);
+        local_name = JS_ATOM_NULL;
+        if (next_token(s))
+          goto fail;
+        if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
+          if (next_token(s))
+            goto fail;
+          if (!token_is_ident(s->token.val)) {
+            js_parse_error(s, "identifier expected");
+            goto fail;
+          }
+          local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
+          if (next_token(s)) {
+          fail:
+            JS_FreeAtom(ctx, local_name);
+            JS_FreeAtom(ctx, import_name);
+            return -1;
+          }
+        } else {
+          local_name = JS_DupAtom(ctx, import_name);
+        }
+        if (add_import(s, m, local_name, import_name))
+          goto fail;
+        JS_FreeAtom(ctx, local_name);
+        JS_FreeAtom(ctx, import_name);
+        if (s->token.val != ',')
+          break;
+        if (next_token(s))
+          return -1;
+      }
+      if (js_parse_expect(s, '}'))
+        return -1;
+    }
+  end_import_clause:
+    module_name = js_parse_from_clause(s);
+    if (module_name == JS_ATOM_NULL)
+      return -1;
+  }
+  idx = add_req_module_entry(ctx, m, module_name);
+  JS_FreeAtom(ctx, module_name);
+  if (idx < 0)
+    return -1;
+  for(i = first_import; i < m->import_entries_count; i++)
+    m->import_entries[i].req_module_idx = idx;
+
+  return js_parse_expect_semi(s);
+}
+
+static __exception int js_parse_source_element(JSParseState *s)
+{
+  JSFunctionDef *fd = s->cur_func;
+  int tok;
+
+  if (s->token.val == TOK_FUNCTION ||
+      (token_is_pseudo_keyword(s, JS_ATOM_async) &&
+       peek_token(s, TRUE) == TOK_FUNCTION)) {
+    if (js_parse_function_decl(s, JS_PARSE_FUNC_STATEMENT,
+                               JS_FUNC_NORMAL, JS_ATOM_NULL,
+                               s->token.ptr, s->token.line_num))
+      return -1;
+  } else if (s->token.val == TOK_EXPORT && fd->module) {
+    if (js_parse_export(s))
+      return -1;
+  } else if (s->token.val == TOK_IMPORT && fd->module &&
+             ((tok = peek_token(s, FALSE)) != '(' && tok != '.'))  {
+    /* the peek_token is needed to avoid confusion with ImportCall
+       (dynamic import) or import.meta */
+    if (js_parse_import(s))
+      return -1;
+  } else {
+    if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
+      return -1;
+  }
+  return 0;
+}
+
+JSFunctionDef *js_new_function_def(JSContext *ctx,
+                                          JSFunctionDef *parent,
+                                          BOOL is_eval,
+                                          BOOL is_func_expr,
+                                          const char *filename, int line_num)
+{
+  JSFunctionDef *fd;
+
+  fd = js_mallocz(ctx, sizeof(*fd));
+  if (!fd)
+    return NULL;
+
+  fd->ctx = ctx;
+  init_list_head(&fd->child_list);
+
+  /* insert in parent list */
+  fd->parent = parent;
+  fd->parent_cpool_idx = -1;
+  if (parent) {
+    list_add_tail(&fd->link, &parent->child_list);
+    fd->js_mode = parent->js_mode;
+    fd->parent_scope_level = parent->scope_level;
+  }
+
+  fd->is_eval = is_eval;
+  fd->is_func_expr = is_func_expr;
+  js_dbuf_init(ctx, &fd->byte_code);
+  fd->last_opcode_pos = -1;
+  fd->func_name = JS_ATOM_NULL;
+  fd->var_object_idx = -1;
+  fd->arg_var_object_idx = -1;
+  fd->arguments_var_idx = -1;
+  fd->arguments_arg_idx = -1;
+  fd->func_var_idx = -1;
+  fd->eval_ret_idx = -1;
+  fd->this_var_idx = -1;
+  fd->new_target_var_idx = -1;
+  fd->this_active_func_var_idx = -1;
+  fd->home_object_var_idx = -1;
+
+  /* XXX: should distinguish arg, var and var object and body scopes */
+  fd->scopes = fd->def_scope_array;
+  fd->scope_size = countof(fd->def_scope_array);
+  fd->scope_count = 1;
+  fd->scopes[0].first = -1;
+  fd->scopes[0].parent = -1;
+  fd->scope_level = 0;  /* 0: var/arg scope */
+  fd->scope_first = -1;
+  fd->body_scope = -1;
+
+  fd->filename = JS_NewAtom(ctx, filename);
+  fd->line_num = line_num;
+
+  js_dbuf_init(ctx, &fd->pc2line);
+  //fd->pc2line_last_line_num = line_num;
+  //fd->pc2line_last_pc = 0;
+  fd->last_opcode_line_num = line_num;
+
+  return fd;
+}
+
+static void js_free_function_def(JSContext *ctx, JSFunctionDef *fd)
+{
+  int i;
+  struct list_head *el, *el1;
+
+  /* free the child functions */
+  list_for_each_safe(el, el1, &fd->child_list) {
+    JSFunctionDef *fd1;
+    fd1 = list_entry(el, JSFunctionDef, link);
+    js_free_function_def(ctx, fd1);
+  }
+
+  free_bytecode_atoms(ctx->rt, fd->byte_code.buf, fd->byte_code.size,
+                      fd->use_short_opcodes);
+  dbuf_free(&fd->byte_code);
+  js_free(ctx, fd->jump_slots);
+  js_free(ctx, fd->label_slots);
+  js_free(ctx, fd->line_number_slots);
+
+  for(i = 0; i < fd->cpool_count; i++) {
+    JS_FreeValue(ctx, fd->cpool[i]);
+  }
+  js_free(ctx, fd->cpool);
+
+  JS_FreeAtom(ctx, fd->func_name);
+
+  for(i = 0; i < fd->var_count; i++) {
+    JS_FreeAtom(ctx, fd->vars[i].var_name);
+  }
+  js_free(ctx, fd->vars);
+  for(i = 0; i < fd->arg_count; i++) {
+    JS_FreeAtom(ctx, fd->args[i].var_name);
+  }
+  js_free(ctx, fd->args);
+
+  for(i = 0; i < fd->global_var_count; i++) {
+    JS_FreeAtom(ctx, fd->global_vars[i].var_name);
+  }
+  js_free(ctx, fd->global_vars);
+
+  for(i = 0; i < fd->closure_var_count; i++) {
+    JSClosureVar *cv = &fd->closure_var[i];
+    JS_FreeAtom(ctx, cv->var_name);
+  }
+  js_free(ctx, fd->closure_var);
+
+  if (fd->scopes != fd->def_scope_array)
+    js_free(ctx, fd->scopes);
+
+  JS_FreeAtom(ctx, fd->filename);
+  dbuf_free(&fd->pc2line);
+
+  js_free(ctx, fd->source);
+
+  if (fd->parent) {
+    /* remove in parent list */
+    list_del(&fd->link);
+  }
+  js_free(ctx, fd);
+}
+
+#ifdef DUMP_BYTECODE
+static const char *skip_lines(const char *p, int n) {
+  while (n-- > 0 && *p) {
+    while (*p && *p++ != '\n')
+      continue;
+  }
+  return p;
+}
+
+static void print_lines(const char *source, int line, int line1) {
+  const char *s = source;
+  const char *p = skip_lines(s, line);
+  if (*p) {
+    while (line++ < line1) {
+      p = skip_lines(s = p, 1);
+      printf(";; %.*s", (int)(p - s), s);
+      if (!*p) {
+        if (p[-1] != '\n')
+          printf("\n");
+        break;
+      }
+    }
+  }
+}
+
+static void dump_byte_code(JSContext *ctx, int pass,
+                           const uint8_t *tab, int len,
+                           const JSVarDef *args, int arg_count,
+                           const JSVarDef *vars, int var_count,
+                           const JSClosureVar *closure_var, int closure_var_count,
+                           const JSValue *cpool, uint32_t cpool_count,
+                           const char *source, int line_num,
+                           const LabelSlot *label_slots, JSFunctionBytecode *b)
+{
+  const JSOpCode *oi;
+  int pos, pos_next, op, size, idx, addr, line, line1, in_source;
+  uint8_t *bits = js_mallocz(ctx, len * sizeof(*bits));
+  BOOL use_short_opcodes = (b != NULL);
+
+  /* scan for jump targets */
+  for (pos = 0; pos < len; pos = pos_next) {
+    op = tab[pos];
+    if (use_short_opcodes)
+      oi = &short_opcode_info(op);
+    else
+      oi = &opcode_info[op];
+    pos_next = pos + oi->size;
+    if (op < OP_COUNT) {
+      switch (oi->fmt) {
+#if SHORT_OPCODES
+        case OP_FMT_label8:
+          pos++;
+          addr = (int8_t)tab[pos];
+          goto has_addr;
+        case OP_FMT_label16:
+          pos++;
+          addr = (int16_t)get_u16(tab + pos);
+          goto has_addr;
+#endif
+        case OP_FMT_atom_label_u8:
+        case OP_FMT_atom_label_u16:
+          pos += 4;
+          /* fall thru */
+        case OP_FMT_label:
+        case OP_FMT_label_u16:
+          pos++;
+          addr = get_u32(tab + pos);
+          goto has_addr;
+        has_addr:
+          if (pass == 1)
+            addr = label_slots[addr].pos;
+          if (pass == 2)
+            addr = label_slots[addr].pos2;
+          if (pass == 3)
+            addr += pos;
+          if (addr >= 0 && addr < len)
+            bits[addr] |= 1;
+          break;
+      }
+    }
+  }
+  in_source = 0;
+  if (source) {
+    /* Always print first line: needed if single line */
+    print_lines(source, 0, 1);
+    in_source = 1;
+  }
+  line1 = line = 1;
+  pos = 0;
+  while (pos < len) {
+    op = tab[pos];
+    if (source) {
+      if (b) {
+        line1 = find_line_num(ctx, b, pos) - line_num + 1;
+      } else if (op == OP_line_num) {
+        line1 = get_u32(tab + pos + 1) - line_num + 1;
+      }
+      if (line1 > line) {
+        if (!in_source)
+          printf("\n");
+        in_source = 1;
+        print_lines(source, line, line1);
+        line = line1;
+        //bits[pos] |= 2;
+      }
+    }
+    if (in_source)
+      printf("\n");
+    in_source = 0;
+    if (op >= OP_COUNT) {
+      printf("invalid opcode (0x%02x)\n", op);
+      pos++;
+      continue;
+    }
+    if (use_short_opcodes)
+      oi = &short_opcode_info(op);
+    else
+      oi = &opcode_info[op];
+    size = oi->size;
+    if (pos + size > len) {
+      printf("truncated opcode (0x%02x)\n", op);
+      break;
+    }
+#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 16)
+    {
+      int i, x, x0;
+      x = x0 = printf("%5d ", pos);
+      for (i = 0; i < size; i++) {
+        if (i == 6) {
+          printf("\n%*s", x = x0, "");
+        }
+        x += printf(" %02X", tab[pos + i]);
+      }
+      printf("%*s", x0 + 20 - x, "");
+    }
+#endif
+    if (bits[pos]) {
+      printf("%5d:  ", pos);
+    } else {
+      printf("        ");
+    }
+    printf("%s", oi->name);
+    pos++;
+    switch(oi->fmt) {
+      case OP_FMT_none_int:
+        printf(" %d", op - OP_push_0);
+        break;
+      case OP_FMT_npopx:
+        printf(" %d", op - OP_call0);
+        break;
+      case OP_FMT_u8:
+        printf(" %u", get_u8(tab + pos));
+        break;
+      case OP_FMT_i8:
+        printf(" %d", get_i8(tab + pos));
+        break;
+      case OP_FMT_u16:
+      case OP_FMT_npop:
+        printf(" %u", get_u16(tab + pos));
+        break;
+      case OP_FMT_npop_u16:
+        printf(" %u,%u", get_u16(tab + pos), get_u16(tab + pos + 2));
+        break;
+      case OP_FMT_i16:
+        printf(" %d", get_i16(tab + pos));
+        break;
+      case OP_FMT_i32:
+        printf(" %d", get_i32(tab + pos));
+        break;
+      case OP_FMT_u32:
+        printf(" %u", get_u32(tab + pos));
+        break;
+#if SHORT_OPCODES
+      case OP_FMT_label8:
+        addr = get_i8(tab + pos);
+        goto has_addr1;
+      case OP_FMT_label16:
+        addr = get_i16(tab + pos);
+        goto has_addr1;
+#endif
+      case OP_FMT_label:
+        addr = get_u32(tab + pos);
+        goto has_addr1;
+      has_addr1:
+        if (pass == 1)
+          printf(" %u:%u", addr, label_slots[addr].pos);
+        if (pass == 2)
+          printf(" %u:%u", addr, label_slots[addr].pos2);
+        if (pass == 3)
+          printf(" %u", addr + pos);
+        break;
+      case OP_FMT_label_u16:
+        addr = get_u32(tab + pos);
+        if (pass == 1)
+          printf(" %u:%u", addr, label_slots[addr].pos);
+        if (pass == 2)
+          printf(" %u:%u", addr, label_slots[addr].pos2);
+        if (pass == 3)
+          printf(" %u", addr + pos);
+        printf(",%u", get_u16(tab + pos + 4));
+        break;
+#if SHORT_OPCODES
+      case OP_FMT_const8:
+        idx = get_u8(tab + pos);
+        goto has_pool_idx;
+#endif
+      case OP_FMT_const:
+        idx = get_u32(tab + pos);
+        goto has_pool_idx;
+      has_pool_idx:
+        printf(" %u: ", idx);
+        if (idx < cpool_count) {
+          JS_DumpValue(ctx, cpool[idx]);
+        }
+        break;
+      case OP_FMT_atom:
+        printf(" ");
+        print_atom(ctx, get_u32(tab + pos));
+        break;
+      case OP_FMT_atom_u8:
+        printf(" ");
+        print_atom(ctx, get_u32(tab + pos));
+        printf(",%d", get_u8(tab + pos + 4));
+        break;
+      case OP_FMT_atom_u16:
+        printf(" ");
+        print_atom(ctx, get_u32(tab + pos));
+        printf(",%d", get_u16(tab + pos + 4));
+        break;
+      case OP_FMT_atom_label_u8:
+      case OP_FMT_atom_label_u16:
+        printf(" ");
+        print_atom(ctx, get_u32(tab + pos));
+        addr = get_u32(tab + pos + 4);
+        if (pass == 1)
+          printf(",%u:%u", addr, label_slots[addr].pos);
+        if (pass == 2)
+          printf(",%u:%u", addr, label_slots[addr].pos2);
+        if (pass == 3)
+          printf(",%u", addr + pos + 4);
+        if (oi->fmt == OP_FMT_atom_label_u8)
+          printf(",%u", get_u8(tab + pos + 8));
+        else
+          printf(",%u", get_u16(tab + pos + 8));
+        break;
+      case OP_FMT_none_loc:
+        idx = (op - OP_get_loc0) % 4;
+        goto has_loc;
+      case OP_FMT_loc8:
+        idx = get_u8(tab + pos);
+        goto has_loc;
+      case OP_FMT_loc:
+        idx = get_u16(tab + pos);
+      has_loc:
+        printf(" %d: ", idx);
+        if (idx < var_count) {
+          print_atom(ctx, vars[idx].var_name);
+        }
+        break;
+      case OP_FMT_none_arg:
+        idx = (op - OP_get_arg0) % 4;
+        goto has_arg;
+      case OP_FMT_arg:
+        idx = get_u16(tab + pos);
+      has_arg:
+        printf(" %d: ", idx);
+        if (idx < arg_count) {
+          print_atom(ctx, args[idx].var_name);
+        }
+        break;
+      case OP_FMT_none_var_ref:
+        idx = (op - OP_get_var_ref0) % 4;
+        goto has_var_ref;
+      case OP_FMT_var_ref:
+        idx = get_u16(tab + pos);
+      has_var_ref:
+        printf(" %d: ", idx);
+        if (idx < closure_var_count) {
+          print_atom(ctx, closure_var[idx].var_name);
+        }
+        break;
+      default:
+        break;
+    }
+    printf("\n");
+    pos += oi->size - 1;
+  }
+  if (source) {
+    if (!in_source)
+      printf("\n");
+    print_lines(source, line, INT32_MAX);
+  }
+  js_free(ctx, bits);
+}
+
+static __maybe_unused void dump_pc2line(JSContext *ctx, const uint8_t *buf, int len,
+                                        int line_num)
+{
+  const uint8_t *p_end, *p_next, *p;
+  int pc, v;
+  unsigned int op;
+
+  if (len <= 0)
+    return;
+
+  printf("%5s %5s\n", "PC", "LINE");
+
+  p = buf;
+  p_end = buf + len;
+  pc = 0;
+  while (p < p_end) {
+    op = *p++;
+    if (op == 0) {
+      v = unicode_from_utf8(p, p_end - p, &p_next);
+      if (v < 0)
+        goto fail;
+      pc += v;
+      p = p_next;
+      v = unicode_from_utf8(p, p_end - p, &p_next);
+      if (v < 0) {
+      fail:
+        printf("invalid pc2line encode pos=%d\n", (int)(p - buf));
+        return;
+      }
+      if (!(v & 1)) {
+        v = v >> 1;
+      } else {
+        v = -(v >> 1) - 1;
+      }
+      line_num += v;
+      p = p_next;
+    } else {
+      op -= PC2LINE_OP_FIRST;
+      pc += (op / PC2LINE_RANGE);
+      line_num += (op % PC2LINE_RANGE) + PC2LINE_BASE;
+    }
+    printf("%5d %5d\n", pc, line_num);
+  }
+}
+
+static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionBytecode *b)
+{
+  int i;
+  char atom_buf[ATOM_GET_STR_BUF_SIZE];
+  const char *str;
+
+  if (b->has_debug && b->debug.filename != JS_ATOM_NULL) {
+    str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->debug.filename);
+    printf("%s:%d: ", str, b->debug.line_num);
+  }
+
+  str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->func_name);
+  printf("function: %s%s\n", &"*"[b->func_kind != JS_FUNC_GENERATOR], str);
+  if (b->js_mode) {
+    printf("  mode:");
+    if (b->js_mode & JS_MODE_STRICT)
+      printf(" strict");
+#ifdef CONFIG_BIGNUM
+    if (b->js_mode & JS_MODE_MATH)
+      printf(" math");
+#endif
+    printf("\n");
+  }
+  if (b->arg_count && b->vardefs) {
+    printf("  args:");
+    for(i = 0; i < b->arg_count; i++) {
+      printf(" %s", JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf),
+                                  b->vardefs[i].var_name));
+    }
+    printf("\n");
+  }
+  if (b->var_count && b->vardefs) {
+    printf("  locals:\n");
+    for(i = 0; i < b->var_count; i++) {
+      JSVarDef *vd = &b->vardefs[b->arg_count + i];
+      printf("%5d: %s %s", i,
+             vd->var_kind == JS_VAR_CATCH ? "catch" :
+             (vd->var_kind == JS_VAR_FUNCTION_DECL ||
+              vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) ? "function" :
+             vd->is_const ? "const" :
+             vd->is_lexical ? "let" : "var",
+             JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), vd->var_name));
+      if (vd->scope_level)
+        printf(" [level:%d next:%d]", vd->scope_level, vd->scope_next);
+      printf("\n");
+    }
+  }
+  if (b->closure_var_count) {
+    printf("  closure vars:\n");
+    for(i = 0; i < b->closure_var_count; i++) {
+      JSClosureVar *cv = &b->closure_var[i];
+      printf("%5d: %s %s:%s%d %s\n", i,
+             JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), cv->var_name),
+             cv->is_local ? "local" : "parent",
+             cv->is_arg ? "arg" : "loc", cv->var_idx,
+             cv->is_const ? "const" :
+             cv->is_lexical ? "let" : "var");
+    }
+  }
+  printf("  stack_size: %d\n", b->stack_size);
+  printf("  opcodes:\n");
+  dump_byte_code(ctx, 3, b->byte_code_buf, b->byte_code_len,
+                 b->vardefs, b->arg_count,
+                 b->vardefs ? b->vardefs + b->arg_count : NULL, b->var_count,
+                 b->closure_var, b->closure_var_count,
+                 b->cpool, b->cpool_count,
+                 b->has_debug ? b->debug.source : NULL,
+                 b->has_debug ? b->debug.line_num : -1, NULL, b);
+#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 32)
+  if (b->has_debug)
+    dump_pc2line(ctx, b->debug.pc2line_buf, b->debug.pc2line_len, b->debug.line_num);
+#endif
+  printf("\n");
+}
+#endif
+
+static int add_closure_var(JSContext *ctx, JSFunctionDef *s,
+                           BOOL is_local, BOOL is_arg,
+                           int var_idx, JSAtom var_name,
+                           BOOL is_const, BOOL is_lexical,
+                           JSVarKindEnum var_kind)
+{
+  JSClosureVar *cv;
+
+  /* the closure variable indexes are currently stored on 16 bits */
+  if (s->closure_var_count >= JS_MAX_LOCAL_VARS) {
+    JS_ThrowInternalError(ctx, "too many closure variables");
+    return -1;
+  }
+
+  if (js_resize_array(ctx, (void **)&s->closure_var,
+                      sizeof(s->closure_var[0]),
+                      &s->closure_var_size, s->closure_var_count + 1))
+    return -1;
+  cv = &s->closure_var[s->closure_var_count++];
+  cv->is_local = is_local;
+  cv->is_arg = is_arg;
+  cv->is_const = is_const;
+  cv->is_lexical = is_lexical;
+  cv->var_kind = var_kind;
+  cv->var_idx = var_idx;
+  cv->var_name = JS_DupAtom(ctx, var_name);
+  return s->closure_var_count - 1;
+}
+
+static int find_closure_var(JSContext *ctx, JSFunctionDef *s,
+                            JSAtom var_name)
+{
+  int i;
+  for(i = 0; i < s->closure_var_count; i++) {
+    JSClosureVar *cv = &s->closure_var[i];
+    if (cv->var_name == var_name)
+      return i;
+  }
+  return -1;
+}
+
+/* 'fd' must be a parent of 's'. Create in 's' a closure referencing a
+   local variable (is_local = TRUE) or a closure (is_local = FALSE) in
+   'fd' */
+static int get_closure_var2(JSContext *ctx, JSFunctionDef *s,
+                            JSFunctionDef *fd, BOOL is_local,
+                            BOOL is_arg, int var_idx, JSAtom var_name,
+                            BOOL is_const, BOOL is_lexical,
+                            JSVarKindEnum var_kind)
+{
+  int i;
+
+  if (fd != s->parent) {
+    var_idx = get_closure_var2(ctx, s->parent, fd, is_local,
+                               is_arg, var_idx, var_name,
+                               is_const, is_lexical, var_kind);
+    if (var_idx < 0)
+      return -1;
+    is_local = FALSE;
+  }
+  for(i = 0; i < s->closure_var_count; i++) {
+    JSClosureVar *cv = &s->closure_var[i];
+    if (cv->var_idx == var_idx && cv->is_arg == is_arg &&
+        cv->is_local == is_local)
+      return i;
+  }
+  return add_closure_var(ctx, s, is_local, is_arg, var_idx, var_name,
+                         is_const, is_lexical, var_kind);
+}
+
+static int get_closure_var(JSContext *ctx, JSFunctionDef *s,
+                           JSFunctionDef *fd, BOOL is_arg,
+                           int var_idx, JSAtom var_name,
+                           BOOL is_const, BOOL is_lexical,
+                           JSVarKindEnum var_kind)
+{
+  return get_closure_var2(ctx, s, fd, TRUE, is_arg,
+                          var_idx, var_name, is_const, is_lexical,
+                          var_kind);
+}
+
+static int get_with_scope_opcode(int op)
+{
+  if (op == OP_scope_get_var_undef)
+    return OP_with_get_var;
+  else
+    return OP_with_get_var + (op - OP_scope_get_var);
+}
+
+static BOOL can_opt_put_ref_value(const uint8_t *bc_buf, int pos)
+{
+  int opcode = bc_buf[pos];
+  return (bc_buf[pos + 1] == OP_put_ref_value &&
+          (opcode == OP_insert3 ||
+           opcode == OP_perm4 ||
+           opcode == OP_nop ||
+           opcode == OP_rot3l));
+}
+
+static BOOL can_opt_put_global_ref_value(const uint8_t *bc_buf, int pos)
+{
+  int opcode = bc_buf[pos];
+  return (bc_buf[pos + 1] == OP_put_ref_value &&
+          (opcode == OP_insert3 ||
+           opcode == OP_perm4 ||
+           opcode == OP_nop ||
+           opcode == OP_rot3l));
+}
+
+static int optimize_scope_make_ref(JSContext *ctx, JSFunctionDef *s,
+                                   DynBuf *bc, uint8_t *bc_buf,
+                                   LabelSlot *ls, int pos_next,
+                                   int get_op, int var_idx)
+{
+  int label_pos, end_pos, pos;
+
+  /* XXX: should optimize `loc(a) += expr` as `expr add_loc(a)`
+     but only if expr does not modify `a`.
+     should scan the code between pos_next and label_pos
+     for operations that can potentially change `a`:
+     OP_scope_make_ref(a), function calls, jumps and gosub.
+   */
+  /* replace the reference get/put with normal variable
+     accesses */
+  if (bc_buf[pos_next] == OP_get_ref_value) {
+    dbuf_putc(bc, get_op);
+    dbuf_put_u16(bc, var_idx);
+    pos_next++;
+  }
+  /* remove the OP_label to make room for replacement */
+  /* label should have a refcount of 0 anyway */
+  /* XXX: should avoid this patch by inserting nops in phase 1 */
+  label_pos = ls->pos;
+  pos = label_pos - 5;
+  assert(bc_buf[pos] == OP_label);
+  /* label points to an instruction pair:
+     - insert3 / put_ref_value
+     - perm4 / put_ref_value
+     - rot3l / put_ref_value
+     - nop / put_ref_value
+   */
+  end_pos = label_pos + 2;
+  if (bc_buf[label_pos] == OP_insert3)
+    bc_buf[pos++] = OP_dup;
+  bc_buf[pos] = get_op + 1;
+  put_u16(bc_buf + pos + 1, var_idx);
+  pos += 3;
+  /* pad with OP_nop */
+  while (pos < end_pos)
+    bc_buf[pos++] = OP_nop;
+  return pos_next;
+}
+
+static int optimize_scope_make_global_ref(JSContext *ctx, JSFunctionDef *s,
+                                          DynBuf *bc, uint8_t *bc_buf,
+                                          LabelSlot *ls, int pos_next,
+                                          JSAtom var_name)
+{
+  int label_pos, end_pos, pos, op;
+  BOOL is_strict;
+  is_strict = ((s->js_mode & JS_MODE_STRICT) != 0);
+
+  /* replace the reference get/put with normal variable
+     accesses */
+  if (is_strict) {
+    /* need to check if the variable exists before evaluating the right
+       expression */
+    /* XXX: need an extra OP_true if destructuring an array */
+    dbuf_putc(bc, OP_check_var);
+    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+  } else {
+    /* XXX: need 2 extra OP_true if destructuring an array */
+  }
+  if (bc_buf[pos_next] == OP_get_ref_value) {
+    dbuf_putc(bc, OP_get_var);
+    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+    pos_next++;
+  }
+  /* remove the OP_label to make room for replacement */
+  /* label should have a refcount of 0 anyway */
+  /* XXX: should have emitted several OP_nop to avoid this kludge */
+  label_pos = ls->pos;
+  pos = label_pos - 5;
+  assert(bc_buf[pos] == OP_label);
+  end_pos = label_pos + 2;
+  op = bc_buf[label_pos];
+  if (is_strict) {
+    if (op != OP_nop) {
+      switch(op) {
+        case OP_insert3:
+          op = OP_insert2;
+          break;
+        case OP_perm4:
+          op = OP_perm3;
+          break;
+        case OP_rot3l:
+          op = OP_swap;
+          break;
+        default:
+          abort();
+      }
+      bc_buf[pos++] = op;
+    }
+  } else {
+    if (op == OP_insert3)
+      bc_buf[pos++] = OP_dup;
+  }
+  if (is_strict) {
+    bc_buf[pos] = OP_put_var_strict;
+    /* XXX: need 1 extra OP_drop if destructuring an array */
+  } else {
+    bc_buf[pos] = OP_put_var;
+    /* XXX: need 2 extra OP_drop if destructuring an array */
+  }
+  put_u32(bc_buf + pos + 1, JS_DupAtom(ctx, var_name));
+  pos += 5;
+  /* pad with OP_nop */
+  while (pos < end_pos)
+    bc_buf[pos++] = OP_nop;
+  return pos_next;
+}
+
+static int add_var_this(JSContext *ctx, JSFunctionDef *fd)
+{
+  int idx;
+  idx = add_var(ctx, fd, JS_ATOM_this);
+  if (idx >= 0 && fd->is_derived_class_constructor) {
+    JSVarDef *vd = &fd->vars[idx];
+    /* XXX: should have is_this flag or var type */
+    vd->is_lexical = 1; /* used to trigger 'uninitialized' checks
+                           in a derived class constructor */
+  }
+  return idx;
+}
+
+static int resolve_pseudo_var(JSContext *ctx, JSFunctionDef *s,
+                              JSAtom var_name)
+{
+  int var_idx;
+
+  if (!s->has_this_binding)
+    return -1;
+  switch(var_name) {
+    case JS_ATOM_home_object:
+      /* 'home_object' pseudo variable */
+      if (s->home_object_var_idx < 0)
+        s->home_object_var_idx = add_var(ctx, s, var_name);
+      var_idx = s->home_object_var_idx;
+      break;
+    case JS_ATOM_this_active_func:
+      /* 'this.active_func' pseudo variable */
+      if (s->this_active_func_var_idx < 0)
+        s->this_active_func_var_idx = add_var(ctx, s, var_name);
+      var_idx = s->this_active_func_var_idx;
+      break;
+    case JS_ATOM_new_target:
+      /* 'new.target' pseudo variable */
+      if (s->new_target_var_idx < 0)
+        s->new_target_var_idx = add_var(ctx, s, var_name);
+      var_idx = s->new_target_var_idx;
+      break;
+    case JS_ATOM_this:
+      /* 'this' pseudo variable */
+      if (s->this_var_idx < 0)
+        s->this_var_idx = add_var_this(ctx, s);
+      var_idx = s->this_var_idx;
+      break;
+    default:
+      var_idx = -1;
+      break;
+  }
+  return var_idx;
+}
+
+/* test if 'var_name' is in the variable object on the stack. If is it
+   the case, handle it and jump to 'label_done' */
+static void var_object_test(JSContext *ctx, JSFunctionDef *s,
+                            JSAtom var_name, int op, DynBuf *bc,
+                            int *plabel_done, BOOL is_with)
+{
+  dbuf_putc(bc, get_with_scope_opcode(op));
+  dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+  *plabel_done = new_label_fd(s, *plabel_done);
+  dbuf_put_u32(bc, *plabel_done);
+  dbuf_putc(bc, is_with);
+  update_label(s, *plabel_done, 1);
+  s->jump_size++;
+}
+
+/* return the position of the next opcode */
+static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
+                             JSAtom var_name, int scope_level, int op,
+                             DynBuf *bc, uint8_t *bc_buf,
+                             LabelSlot *ls, int pos_next)
+{
+  int idx, var_idx, is_put;
+  int label_done;
+  JSFunctionDef *fd;
+  JSVarDef *vd;
+  BOOL is_pseudo_var, is_arg_scope;
+
+  label_done = -1;
+
+  /* XXX: could be simpler to use a specific function to
+     resolve the pseudo variables */
+  is_pseudo_var = (var_name == JS_ATOM_home_object ||
+                   var_name == JS_ATOM_this_active_func ||
+                   var_name == JS_ATOM_new_target ||
+                   var_name == JS_ATOM_this);
+
+  /* resolve local scoped variables */
+  var_idx = -1;
+  for (idx = s->scopes[scope_level].first; idx >= 0;) {
+    vd = &s->vars[idx];
+    if (vd->var_name == var_name) {
+      if (op == OP_scope_put_var || op == OP_scope_make_ref) {
+        if (vd->is_const) {
+          dbuf_putc(bc, OP_throw_error);
+          dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+          dbuf_putc(bc, JS_THROW_VAR_RO);
+          goto done;
+        }
+      }
+      var_idx = idx;
+      break;
+    } else
+        if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
+      dbuf_putc(bc, OP_get_loc);
+      dbuf_put_u16(bc, idx);
+      var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
+    }
+    idx = vd->scope_next;
+  }
+  is_arg_scope = (idx == ARG_SCOPE_END);
+  if (var_idx < 0) {
+    /* argument scope: variables are not visible but pseudo
+       variables are visible */
+    if (!is_arg_scope) {
+      var_idx = find_var(ctx, s, var_name);
+    }
+
+    if (var_idx < 0 && is_pseudo_var)
+      var_idx = resolve_pseudo_var(ctx, s, var_name);
+
+    if (var_idx < 0 && var_name == JS_ATOM_arguments &&
+        s->has_arguments_binding) {
+      /* 'arguments' pseudo variable */
+      var_idx = add_arguments_var(ctx, s);
+    }
+    if (var_idx < 0 && s->is_func_expr && var_name == s->func_name) {
+      /* add a new variable with the function name */
+      var_idx = add_func_var(ctx, s, var_name);
+    }
+  }
+  if (var_idx >= 0) {
+    if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&
+        !(var_idx & ARGUMENT_VAR_OFFSET) &&
+        s->vars[var_idx].is_const) {
+      /* only happens when assigning a function expression name
+         in strict mode */
+      dbuf_putc(bc, OP_throw_error);
+      dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+      dbuf_putc(bc, JS_THROW_VAR_RO);
+      goto done;
+    }
+    /* OP_scope_put_var_init is only used to initialize a
+       lexical variable, so it is never used in a with or var object. It
+       can be used with a closure (module global variable case). */
+    switch (op) {
+      case OP_scope_make_ref:
+        if (!(var_idx & ARGUMENT_VAR_OFFSET) &&
+            s->vars[var_idx].var_kind == JS_VAR_FUNCTION_NAME) {
+          /* Create a dummy object reference for the func_var */
+          dbuf_putc(bc, OP_object);
+          dbuf_putc(bc, OP_get_loc);
+          dbuf_put_u16(bc, var_idx);
+          dbuf_putc(bc, OP_define_field);
+          dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+          dbuf_putc(bc, OP_push_atom_value);
+          dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+        } else
+            if (label_done == -1 && can_opt_put_ref_value(bc_buf, ls->pos)) {
+          int get_op;
+          if (var_idx & ARGUMENT_VAR_OFFSET) {
+            get_op = OP_get_arg;
+            var_idx -= ARGUMENT_VAR_OFFSET;
+          } else {
+            if (s->vars[var_idx].is_lexical)
+              get_op = OP_get_loc_check;
+            else
+              get_op = OP_get_loc;
+          }
+          pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,
+                                             pos_next, get_op, var_idx);
+        } else {
+          /* Create a dummy object with a named slot that is
+             a reference to the local variable */
+          if (var_idx & ARGUMENT_VAR_OFFSET) {
+            dbuf_putc(bc, OP_make_arg_ref);
+            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+            dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
+          } else {
+            dbuf_putc(bc, OP_make_loc_ref);
+            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+            dbuf_put_u16(bc, var_idx);
+          }
+        }
+        break;
+      case OP_scope_get_ref:
+        dbuf_putc(bc, OP_undefined);
+        /* fall thru */
+      case OP_scope_get_var_undef:
+      case OP_scope_get_var:
+      case OP_scope_put_var:
+      case OP_scope_put_var_init:
+        is_put = (op == OP_scope_put_var || op == OP_scope_put_var_init);
+        if (var_idx & ARGUMENT_VAR_OFFSET) {
+          dbuf_putc(bc, OP_get_arg + is_put);
+          dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
+        } else {
+          if (is_put) {
+            if (s->vars[var_idx].is_lexical) {
+              if (op == OP_scope_put_var_init) {
+                /* 'this' can only be initialized once */
+                if (var_name == JS_ATOM_this)
+                  dbuf_putc(bc, OP_put_loc_check_init);
+                else
+                  dbuf_putc(bc, OP_put_loc);
+              } else {
+                dbuf_putc(bc, OP_put_loc_check);
+              }
+            } else {
+              dbuf_putc(bc, OP_put_loc);
+            }
+          } else {
+            if (s->vars[var_idx].is_lexical) {
+              dbuf_putc(bc, OP_get_loc_check);
+            } else {
+              dbuf_putc(bc, OP_get_loc);
+            }
+          }
+          dbuf_put_u16(bc, var_idx);
+        }
+        break;
+      case OP_scope_delete_var:
+        dbuf_putc(bc, OP_push_false);
+        break;
+    }
+    goto done;
+  }
+  /* check eval object */
+  if (!is_arg_scope && s->var_object_idx >= 0 && !is_pseudo_var) {
+    dbuf_putc(bc, OP_get_loc);
+    dbuf_put_u16(bc, s->var_object_idx);
+    var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
+  }
+  /* check eval object in argument scope */
+  if (s->arg_var_object_idx >= 0 && !is_pseudo_var) {
+    dbuf_putc(bc, OP_get_loc);
+    dbuf_put_u16(bc, s->arg_var_object_idx);
+    var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
+  }
+
+  /* check parent scopes */
+  for (fd = s; fd->parent;) {
+    scope_level = fd->parent_scope_level;
+    fd = fd->parent;
+    for (idx = fd->scopes[scope_level].first; idx >= 0;) {
+      vd = &fd->vars[idx];
+      if (vd->var_name == var_name) {
+        if (op == OP_scope_put_var || op == OP_scope_make_ref) {
+          if (vd->is_const) {
+            dbuf_putc(bc, OP_throw_error);
+            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+            dbuf_putc(bc, JS_THROW_VAR_RO);
+            goto done;
+          }
+        }
+        var_idx = idx;
+        break;
+      } else if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
+        vd->is_captured = 1;
+        idx = get_closure_var(ctx, s, fd, FALSE, idx, vd->var_name, FALSE, FALSE, JS_VAR_NORMAL);
+        if (idx >= 0) {
+          dbuf_putc(bc, OP_get_var_ref);
+          dbuf_put_u16(bc, idx);
+          var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
+        }
+      }
+      idx = vd->scope_next;
+    }
+    is_arg_scope = (idx == ARG_SCOPE_END);
+    if (var_idx >= 0)
+      break;
+
+    if (!is_arg_scope) {
+      var_idx = find_var(ctx, fd, var_name);
+      if (var_idx >= 0)
+        break;
+    }
+    if (is_pseudo_var) {
+      var_idx = resolve_pseudo_var(ctx, fd, var_name);
+      if (var_idx >= 0)
+        break;
+    }
+    if (var_name == JS_ATOM_arguments && fd->has_arguments_binding) {
+      var_idx = add_arguments_var(ctx, fd);
+      break;
+    }
+    if (fd->is_func_expr && fd->func_name == var_name) {
+      /* add a new variable with the function name */
+      var_idx = add_func_var(ctx, fd, var_name);
+      break;
+    }
+
+    /* check eval object */
+    if (!is_arg_scope && fd->var_object_idx >= 0 && !is_pseudo_var) {
+      vd = &fd->vars[fd->var_object_idx];
+      vd->is_captured = 1;
+      idx = get_closure_var(ctx, s, fd, FALSE,
+                            fd->var_object_idx, vd->var_name,
+                            FALSE, FALSE, JS_VAR_NORMAL);
+      dbuf_putc(bc, OP_get_var_ref);
+      dbuf_put_u16(bc, idx);
+      var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
+    }
+
+    /* check eval object in argument scope */
+    if (fd->arg_var_object_idx >= 0 && !is_pseudo_var) {
+      vd = &fd->vars[fd->arg_var_object_idx];
+      vd->is_captured = 1;
+      idx = get_closure_var(ctx, s, fd, FALSE,
+                            fd->arg_var_object_idx, vd->var_name,
+                            FALSE, FALSE, JS_VAR_NORMAL);
+      dbuf_putc(bc, OP_get_var_ref);
+      dbuf_put_u16(bc, idx);
+      var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
+    }
+
+    if (fd->is_eval)
+      break; /* it it necessarily the top level function */
+  }
+
+  /* check direct eval scope (in the closure of the eval function
+     which is necessarily at the top level) */
+  if (!fd)
+    fd = s;
+  if (var_idx < 0 && fd->is_eval) {
+    int idx1;
+    for (idx1 = 0; idx1 < fd->closure_var_count; idx1++) {
+      JSClosureVar *cv = &fd->closure_var[idx1];
+      if (var_name == cv->var_name) {
+        if (fd != s) {
+          idx = get_closure_var2(ctx, s, fd,
+                                 FALSE,
+                                 cv->is_arg, idx1,
+                                 cv->var_name, cv->is_const,
+                                 cv->is_lexical, cv->var_kind);
+        } else {
+          idx = idx1;
+        }
+        goto has_idx;
+      } else if ((cv->var_name == JS_ATOM__var_ ||
+                  cv->var_name == JS_ATOM__arg_var_ ||
+                  cv->var_name == JS_ATOM__with_) && !is_pseudo_var) {
+        int is_with = (cv->var_name == JS_ATOM__with_);
+        if (fd != s) {
+          idx = get_closure_var2(ctx, s, fd,
+                                 FALSE,
+                                 cv->is_arg, idx1,
+                                 cv->var_name, FALSE, FALSE,
+                                 JS_VAR_NORMAL);
+        } else {
+          idx = idx1;
+        }
+        dbuf_putc(bc, OP_get_var_ref);
+        dbuf_put_u16(bc, idx);
+        var_object_test(ctx, s, var_name, op, bc, &label_done, is_with);
+      }
+    }
+  }
+
+  if (var_idx >= 0) {
+    /* find the corresponding closure variable */
+    if (var_idx & ARGUMENT_VAR_OFFSET) {
+      fd->args[var_idx - ARGUMENT_VAR_OFFSET].is_captured = 1;
+      idx = get_closure_var(ctx, s, fd,
+                            TRUE, var_idx - ARGUMENT_VAR_OFFSET,
+                            var_name, FALSE, FALSE, JS_VAR_NORMAL);
+    } else {
+      fd->vars[var_idx].is_captured = 1;
+      idx = get_closure_var(ctx, s, fd,
+                            FALSE, var_idx,
+                            var_name,
+                            fd->vars[var_idx].is_const,
+                            fd->vars[var_idx].is_lexical,
+                            fd->vars[var_idx].var_kind);
+    }
+    if (idx >= 0) {
+    has_idx:
+      if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&
+          s->closure_var[idx].is_const) {
+        dbuf_putc(bc, OP_throw_error);
+        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+        dbuf_putc(bc, JS_THROW_VAR_RO);
+        goto done;
+      }
+      switch (op) {
+        case OP_scope_make_ref:
+          if (s->closure_var[idx].var_kind == JS_VAR_FUNCTION_NAME) {
+            /* Create a dummy object reference for the func_var */
+            dbuf_putc(bc, OP_object);
+            dbuf_putc(bc, OP_get_var_ref);
+            dbuf_put_u16(bc, idx);
+            dbuf_putc(bc, OP_define_field);
+            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+            dbuf_putc(bc, OP_push_atom_value);
+            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+          } else
+              if (label_done == -1 &&
+                  can_opt_put_ref_value(bc_buf, ls->pos)) {
+            int get_op;
+            if (s->closure_var[idx].is_lexical)
+              get_op = OP_get_var_ref_check;
+            else
+              get_op = OP_get_var_ref;
+            pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,
+                                               pos_next,
+                                               get_op, idx);
+          } else {
+            /* Create a dummy object with a named slot that is
+               a reference to the closure variable */
+            dbuf_putc(bc, OP_make_var_ref_ref);
+            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+            dbuf_put_u16(bc, idx);
+          }
+          break;
+        case OP_scope_get_ref:
+          /* XXX: should create a dummy object with a named slot that is
+             a reference to the closure variable */
+          dbuf_putc(bc, OP_undefined);
+          /* fall thru */
+        case OP_scope_get_var_undef:
+        case OP_scope_get_var:
+        case OP_scope_put_var:
+        case OP_scope_put_var_init:
+          is_put = (op == OP_scope_put_var ||
+                    op == OP_scope_put_var_init);
+          if (is_put) {
+            if (s->closure_var[idx].is_lexical) {
+              if (op == OP_scope_put_var_init) {
+                /* 'this' can only be initialized once */
+                if (var_name == JS_ATOM_this)
+                  dbuf_putc(bc, OP_put_var_ref_check_init);
+                else
+                  dbuf_putc(bc, OP_put_var_ref);
+              } else {
+                dbuf_putc(bc, OP_put_var_ref_check);
+              }
+            } else {
+              dbuf_putc(bc, OP_put_var_ref);
+            }
+          } else {
+            if (s->closure_var[idx].is_lexical) {
+              dbuf_putc(bc, OP_get_var_ref_check);
+            } else {
+              dbuf_putc(bc, OP_get_var_ref);
+            }
+          }
+          dbuf_put_u16(bc, idx);
+          break;
+        case OP_scope_delete_var:
+          dbuf_putc(bc, OP_push_false);
+          break;
+      }
+      goto done;
+    }
+  }
+
+  /* global variable access */
+
+  switch (op) {
+    case OP_scope_make_ref:
+      if (label_done == -1 && can_opt_put_global_ref_value(bc_buf, ls->pos)) {
+        pos_next = optimize_scope_make_global_ref(ctx, s, bc, bc_buf, ls,
+                                                  pos_next, var_name);
+      } else {
+        dbuf_putc(bc, OP_make_var_ref);
+        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+      }
+      break;
+    case OP_scope_get_ref:
+      /* XXX: should create a dummy object with a named slot that is
+         a reference to the global variable */
+      dbuf_putc(bc, OP_undefined);
+      dbuf_putc(bc, OP_get_var);
+      dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+      break;
+    case OP_scope_get_var_undef:
+    case OP_scope_get_var:
+    case OP_scope_put_var:
+      dbuf_putc(bc, OP_get_var_undef + (op - OP_scope_get_var_undef));
+      dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+      break;
+    case OP_scope_put_var_init:
+      dbuf_putc(bc, OP_put_var_init);
+      dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+      break;
+    case OP_scope_delete_var:
+      dbuf_putc(bc, OP_delete_var);
+      dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+      break;
+  }
+done:
+  if (label_done >= 0) {
+    dbuf_putc(bc, OP_label);
+    dbuf_put_u32(bc, label_done);
+    s->label_slots[label_done].pos2 = bc->size;
+  }
+  return pos_next;
+}
+
+/* search in all scopes */
+static int find_private_class_field_all(JSContext *ctx, JSFunctionDef *fd,
+                                        JSAtom name, int scope_level)
+{
+  int idx;
+
+  idx = fd->scopes[scope_level].first;
+  while (idx >= 0) {
+    if (fd->vars[idx].var_name == name)
+      return idx;
+    idx = fd->vars[idx].scope_next;
+  }
+  return -1;
+}
+
+static void get_loc_or_ref(DynBuf *bc, BOOL is_ref, int idx)
+{
+  /* if the field is not initialized, the error is catched when
+     accessing it */
+  if (is_ref)
+    dbuf_putc(bc, OP_get_var_ref);
+  else
+    dbuf_putc(bc, OP_get_loc);
+  dbuf_put_u16(bc, idx);
+}
+
+static int resolve_scope_private_field1(JSContext *ctx,
+                                        BOOL *pis_ref, int *pvar_kind,
+                                        JSFunctionDef *s,
+                                        JSAtom var_name, int scope_level)
+{
+  int idx, var_kind;
+  JSFunctionDef *fd;
+  BOOL is_ref;
+
+  fd = s;
+  is_ref = FALSE;
+  for(;;) {
+    idx = find_private_class_field_all(ctx, fd, var_name, scope_level);
+    if (idx >= 0) {
+      var_kind = fd->vars[idx].var_kind;
+      if (is_ref) {
+        idx = get_closure_var(ctx, s, fd, FALSE, idx, var_name,
+                              TRUE, TRUE, JS_VAR_NORMAL);
+        if (idx < 0)
+          return -1;
+      }
+      break;
+    }
+    scope_level = fd->parent_scope_level;
+    if (!fd->parent) {
+      if (fd->is_eval) {
+        /* closure of the eval function (top level) */
+        for (idx = 0; idx < fd->closure_var_count; idx++) {
+          JSClosureVar *cv = &fd->closure_var[idx];
+          if (cv->var_name == var_name) {
+            var_kind = cv->var_kind;
+            is_ref = TRUE;
+            if (fd != s) {
+              idx = get_closure_var2(ctx, s, fd,
+                                     FALSE,
+                                     cv->is_arg, idx,
+                                     cv->var_name, cv->is_const,
+                                     cv->is_lexical,
+                                     cv->var_kind);
+              if (idx < 0)
+                return -1;
+            }
+            goto done;
+          }
+        }
+      }
+      /* XXX: no line number info */
+      JS_ThrowSyntaxErrorAtom(ctx, "undefined private field '%s'",
+                              var_name);
+      return -1;
+    } else {
+      fd = fd->parent;
+    }
+    is_ref = TRUE;
+  }
+done:
+  *pis_ref = is_ref;
+  *pvar_kind = var_kind;
+  return idx;
+}
+
+/* return 0 if OK or -1 if the private field could not be resolved */
+static int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s,
+                                       JSAtom var_name, int scope_level, int op,
+                                       DynBuf *bc)
+{
+  int idx, var_kind;
+  BOOL is_ref;
+
+  idx = resolve_scope_private_field1(ctx, &is_ref, &var_kind, s,
+                                     var_name, scope_level);
+  if (idx < 0)
+    return -1;
+  assert(var_kind != JS_VAR_NORMAL);
+  switch (op) {
+    case OP_scope_get_private_field:
+    case OP_scope_get_private_field2:
+      switch(var_kind) {
+        case JS_VAR_PRIVATE_FIELD:
+          if (op == OP_scope_get_private_field2)
+            dbuf_putc(bc, OP_dup);
+          get_loc_or_ref(bc, is_ref, idx);
+          dbuf_putc(bc, OP_get_private_field);
+          break;
+        case JS_VAR_PRIVATE_METHOD:
+          get_loc_or_ref(bc, is_ref, idx);
+          dbuf_putc(bc, OP_check_brand);
+          if (op != OP_scope_get_private_field2)
+            dbuf_putc(bc, OP_nip);
+          break;
+        case JS_VAR_PRIVATE_GETTER:
+        case JS_VAR_PRIVATE_GETTER_SETTER:
+          if (op == OP_scope_get_private_field2)
+            dbuf_putc(bc, OP_dup);
+          get_loc_or_ref(bc, is_ref, idx);
+          dbuf_putc(bc, OP_check_brand);
+          dbuf_putc(bc, OP_call_method);
+          dbuf_put_u16(bc, 0);
+          break;
+        case JS_VAR_PRIVATE_SETTER:
+          /* XXX: add clearer error message */
+          dbuf_putc(bc, OP_throw_error);
+          dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+          dbuf_putc(bc, JS_THROW_VAR_RO);
+          break;
+        default:
+          abort();
+      }
+      break;
+    case OP_scope_put_private_field:
+      switch(var_kind) {
+        case JS_VAR_PRIVATE_FIELD:
+          get_loc_or_ref(bc, is_ref, idx);
+          dbuf_putc(bc, OP_put_private_field);
+          break;
+        case JS_VAR_PRIVATE_METHOD:
+        case JS_VAR_PRIVATE_GETTER:
+          /* XXX: add clearer error message */
+          dbuf_putc(bc, OP_throw_error);
+          dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+          dbuf_putc(bc, JS_THROW_VAR_RO);
+          break;
+        case JS_VAR_PRIVATE_SETTER:
+        case JS_VAR_PRIVATE_GETTER_SETTER:
+        {
+          JSAtom setter_name = get_private_setter_name(ctx, var_name);
+          if (setter_name == JS_ATOM_NULL)
+            return -1;
+          idx = resolve_scope_private_field1(ctx, &is_ref,
+                                             &var_kind, s,
+                                             setter_name, scope_level);
+          JS_FreeAtom(ctx, setter_name);
+          if (idx < 0)
+            return -1;
+          assert(var_kind == JS_VAR_PRIVATE_SETTER);
+          get_loc_or_ref(bc, is_ref, idx);
+          dbuf_putc(bc, OP_swap);
+          /* obj func value */
+          dbuf_putc(bc, OP_rot3r);
+          /* value obj func */
+          dbuf_putc(bc, OP_check_brand);
+          dbuf_putc(bc, OP_rot3l);
+          /* obj func value */
+          dbuf_putc(bc, OP_call_method);
+          dbuf_put_u16(bc, 1);
+        }
+        break;
+        default:
+          abort();
+      }
+      break;
+    default:
+      abort();
+  }
+  return 0;
+}
+
+static void mark_eval_captured_variables(JSContext *ctx, JSFunctionDef *s,
+                                         int scope_level)
+{
+  int idx;
+  JSVarDef *vd;
+
+  for (idx = s->scopes[scope_level].first; idx >= 0;) {
+    vd = &s->vars[idx];
+    vd->is_captured = 1;
+    idx = vd->scope_next;
+  }
+}
+
+/* XXX: should handle the argument scope generically */
+static BOOL is_var_in_arg_scope(const JSVarDef *vd)
+{
+  return (vd->var_name == JS_ATOM_home_object ||
+          vd->var_name == JS_ATOM_this_active_func ||
+          vd->var_name == JS_ATOM_new_target ||
+          vd->var_name == JS_ATOM_this ||
+          vd->var_name == JS_ATOM__arg_var_ ||
+          vd->var_kind == JS_VAR_FUNCTION_NAME);
+}
+
+static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
+{
+  JSFunctionDef *fd;
+  JSVarDef *vd;
+  int i, scope_level, scope_idx;
+  BOOL has_arguments_binding, has_this_binding, is_arg_scope;
+
+  /* in non strict mode, variables are created in the caller's
+     environment object */
+  if (!s->is_eval && !(s->js_mode & JS_MODE_STRICT)) {
+    s->var_object_idx = add_var(ctx, s, JS_ATOM__var_);
+    if (s->has_parameter_expressions) {
+      /* an additional variable object is needed for the
+         argument scope */
+      s->arg_var_object_idx = add_var(ctx, s, JS_ATOM__arg_var_);
+    }
+  }
+
+  /* eval can potentially use 'arguments' so we must define it */
+  has_this_binding = s->has_this_binding;
+  if (has_this_binding) {
+    if (s->this_var_idx < 0)
+      s->this_var_idx = add_var_this(ctx, s);
+    if (s->new_target_var_idx < 0)
+      s->new_target_var_idx = add_var(ctx, s, JS_ATOM_new_target);
+    if (s->is_derived_class_constructor && s->this_active_func_var_idx < 0)
+      s->this_active_func_var_idx = add_var(ctx, s, JS_ATOM_this_active_func);
+    if (s->has_home_object && s->home_object_var_idx < 0)
+      s->home_object_var_idx = add_var(ctx, s, JS_ATOM_home_object);
+  }
+  has_arguments_binding = s->has_arguments_binding;
+  if (has_arguments_binding) {
+    add_arguments_var(ctx, s);
+    /* also add an arguments binding in the argument scope to
+       raise an error if a direct eval in the argument scope tries
+       to redefine it */
+    if (s->has_parameter_expressions && !(s->js_mode & JS_MODE_STRICT))
+      add_arguments_arg(ctx, s);
+  }
+  if (s->is_func_expr && s->func_name != JS_ATOM_NULL)
+    add_func_var(ctx, s, s->func_name);
+
+  /* eval can use all the variables of the enclosing functions, so
+     they must be all put in the closure. The closure variables are
+     ordered by scope. It works only because no closure are created
+     before. */
+  assert(s->is_eval || s->closure_var_count == 0);
+
+  /* XXX: inefficient, but eval performance is less critical */
+  fd = s;
+  for(;;) {
+    scope_level = fd->parent_scope_level;
+    fd = fd->parent;
+    if (!fd)
+      break;
+    /* add 'this' if it was not previously added */
+    if (!has_this_binding && fd->has_this_binding) {
+      if (fd->this_var_idx < 0)
+        fd->this_var_idx = add_var_this(ctx, fd);
+      if (fd->new_target_var_idx < 0)
+        fd->new_target_var_idx = add_var(ctx, fd, JS_ATOM_new_target);
+      if (fd->is_derived_class_constructor && fd->this_active_func_var_idx < 0)
+        fd->this_active_func_var_idx = add_var(ctx, fd, JS_ATOM_this_active_func);
+      if (fd->has_home_object && fd->home_object_var_idx < 0)
+        fd->home_object_var_idx = add_var(ctx, fd, JS_ATOM_home_object);
+      has_this_binding = TRUE;
+    }
+    /* add 'arguments' if it was not previously added */
+    if (!has_arguments_binding && fd->has_arguments_binding) {
+      add_arguments_var(ctx, fd);
+      has_arguments_binding = TRUE;
+    }
+    /* add function name */
+    if (fd->is_func_expr && fd->func_name != JS_ATOM_NULL)
+      add_func_var(ctx, fd, fd->func_name);
+
+    /* add lexical variables */
+    scope_idx = fd->scopes[scope_level].first;
+    while (scope_idx >= 0) {
+      vd = &fd->vars[scope_idx];
+      vd->is_captured = 1;
+      get_closure_var(ctx, s, fd, FALSE, scope_idx,
+                      vd->var_name, vd->is_const, vd->is_lexical, vd->var_kind);
+      scope_idx = vd->scope_next;
+    }
+    is_arg_scope = (scope_idx == ARG_SCOPE_END);
+    if (!is_arg_scope) {
+      /* add unscoped variables */
+      for(i = 0; i < fd->arg_count; i++) {
+        vd = &fd->args[i];
+        if (vd->var_name != JS_ATOM_NULL) {
+          get_closure_var(ctx, s, fd,
+                          TRUE, i, vd->var_name, FALSE, FALSE,
+                          JS_VAR_NORMAL);
+        }
+      }
+      for(i = 0; i < fd->var_count; i++) {
+        vd = &fd->vars[i];
+        /* do not close top level last result */
+        if (vd->scope_level == 0 &&
+            vd->var_name != JS_ATOM__ret_ &&
+            vd->var_name != JS_ATOM_NULL) {
+          get_closure_var(ctx, s, fd,
+                          FALSE, i, vd->var_name, FALSE, FALSE,
+                          JS_VAR_NORMAL);
+        }
+      }
+    } else {
+      for(i = 0; i < fd->var_count; i++) {
+        vd = &fd->vars[i];
+        /* do not close top level last result */
+        if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
+          get_closure_var(ctx, s, fd,
+                          FALSE, i, vd->var_name, FALSE, FALSE,
+                          JS_VAR_NORMAL);
+        }
+      }
+    }
+    if (fd->is_eval) {
+      int idx;
+      /* add direct eval variables (we are necessarily at the
+         top level) */
+      for (idx = 0; idx < fd->closure_var_count; idx++) {
+        JSClosureVar *cv = &fd->closure_var[idx];
+        get_closure_var2(ctx, s, fd,
+                         FALSE, cv->is_arg,
+                         idx, cv->var_name, cv->is_const,
+                         cv->is_lexical, cv->var_kind);
+      }
+    }
+  }
+}
+
+static void set_closure_from_var(JSContext *ctx, JSClosureVar *cv,
+                                 JSVarDef *vd, int var_idx)
+{
+  cv->is_local = TRUE;
+  cv->is_arg = FALSE;
+  cv->is_const = vd->is_const;
+  cv->is_lexical = vd->is_lexical;
+  cv->var_kind = vd->var_kind;
+  cv->var_idx = var_idx;
+  cv->var_name = JS_DupAtom(ctx, vd->var_name);
+}
+
+/* for direct eval compilation: add references to the variables of the
+   calling function */
+static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
+                                             JSFunctionBytecode *b, int scope_idx)
+{
+  int i, count;
+  JSVarDef *vd;
+  BOOL is_arg_scope;
+
+  count = b->arg_count + b->var_count + b->closure_var_count;
+  s->closure_var = NULL;
+  s->closure_var_count = 0;
+  s->closure_var_size = count;
+  if (count == 0)
+    return 0;
+  s->closure_var = js_malloc(ctx, sizeof(s->closure_var[0]) * count);
+  if (!s->closure_var)
+    return -1;
+  /* Add lexical variables in scope at the point of evaluation */
+  for (i = scope_idx; i >= 0;) {
+    vd = &b->vardefs[b->arg_count + i];
+    if (vd->scope_level > 0) {
+      JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
+      set_closure_from_var(ctx, cv, vd, i);
+    }
+    i = vd->scope_next;
+  }
+  is_arg_scope = (i == ARG_SCOPE_END);
+  if (!is_arg_scope) {
+    /* Add argument variables */
+    for(i = 0; i < b->arg_count; i++) {
+      JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
+      vd = &b->vardefs[i];
+      cv->is_local = TRUE;
+      cv->is_arg = TRUE;
+      cv->is_const = FALSE;
+      cv->is_lexical = FALSE;
+      cv->var_kind = JS_VAR_NORMAL;
+      cv->var_idx = i;
+      cv->var_name = JS_DupAtom(ctx, vd->var_name);
+    }
+    /* Add local non lexical variables */
+    for(i = 0; i < b->var_count; i++) {
+      vd = &b->vardefs[b->arg_count + i];
+      if (vd->scope_level == 0 && vd->var_name != JS_ATOM__ret_) {
+        JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
+        set_closure_from_var(ctx, cv, vd, i);
+      }
+    }
+  } else {
+    /* only add pseudo variables */
+    for(i = 0; i < b->var_count; i++) {
+      vd = &b->vardefs[b->arg_count + i];
+      if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
+        JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
+        set_closure_from_var(ctx, cv, vd, i);
+      }
+    }
+  }
+  for(i = 0; i < b->closure_var_count; i++) {
+    JSClosureVar *cv0 = &b->closure_var[i];
+    JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
+    cv->is_local = FALSE;
+    cv->is_arg = cv0->is_arg;
+    cv->is_const = cv0->is_const;
+    cv->is_lexical = cv0->is_lexical;
+    cv->var_kind = cv0->var_kind;
+    cv->var_idx = i;
+    cv->var_name = JS_DupAtom(ctx, cv0->var_name);
+  }
+  return 0;
+}
+
+typedef struct CodeContext {
+  const uint8_t *bc_buf; /* code buffer */
+  int bc_len;   /* length of the code buffer */
+  int pos;      /* position past the matched code pattern */
+  int line_num; /* last visited OP_line_num parameter or -1 */
+  int op;
+  int idx;
+  int label;
+  int val;
+  JSAtom atom;
+} CodeContext;
+
+#define M2(op1, op2)            ((op1) | ((op2) << 8))
+#define M3(op1, op2, op3)       ((op1) | ((op2) << 8) | ((op3) << 16))
+#define M4(op1, op2, op3, op4)  ((op1) | ((op2) << 8) | ((op3) << 16) | ((op4) << 24))
+
+static BOOL code_match(CodeContext *s, int pos, ...)
+{
+  const uint8_t *tab = s->bc_buf;
+  int op, len, op1, line_num, pos_next;
+  va_list ap;
+  BOOL ret = FALSE;
+
+  line_num = -1;
+  va_start(ap, pos);
+
+  for(;;) {
+    op1 = va_arg(ap, int);
+    if (op1 == -1) {
+      s->pos = pos;
+      s->line_num = line_num;
+      ret = TRUE;
+      break;
+    }
+    for (;;) {
+      if (pos >= s->bc_len)
+        goto done;
+      op = tab[pos];
+      len = opcode_info[op].size;
+      pos_next = pos + len;
+      if (pos_next > s->bc_len)
+        goto done;
+      if (op == OP_line_num) {
+        line_num = get_u32(tab + pos + 1);
+        pos = pos_next;
+      } else {
+        break;
+      }
+    }
+    if (op != op1) {
+      if (op1 == (uint8_t)op1 || !op)
+        break;
+      if (op != (uint8_t)op1
+          &&  op != (uint8_t)(op1 >> 8)
+          &&  op != (uint8_t)(op1 >> 16)
+          &&  op != (uint8_t)(op1 >> 24)) {
+        break;
+      }
+      s->op = op;
+    }
+
+    pos++;
+    switch(opcode_info[op].fmt) {
+      case OP_FMT_loc8:
+      case OP_FMT_u8:
+      {
+        int idx = tab[pos];
+        int arg = va_arg(ap, int);
+        if (arg == -1) {
+          s->idx = idx;
+        } else {
+          if (arg != idx)
+            goto done;
+        }
+        break;
+      }
+      case OP_FMT_u16:
+      case OP_FMT_npop:
+      case OP_FMT_loc:
+      case OP_FMT_arg:
+      case OP_FMT_var_ref:
+      {
+        int idx = get_u16(tab + pos);
+        int arg = va_arg(ap, int);
+        if (arg == -1) {
+          s->idx = idx;
+        } else {
+          if (arg != idx)
+            goto done;
+        }
+        break;
+      }
+      case OP_FMT_i32:
+      case OP_FMT_u32:
+      case OP_FMT_label:
+      case OP_FMT_const:
+      {
+        s->label = get_u32(tab + pos);
+        break;
+      }
+      case OP_FMT_label_u16:
+      {
+        s->label = get_u32(tab + pos);
+        s->val = get_u16(tab + pos + 4);
+        break;
+      }
+      case OP_FMT_atom:
+      {
+        s->atom = get_u32(tab + pos);
+        break;
+      }
+      case OP_FMT_atom_u8:
+      {
+        s->atom = get_u32(tab + pos);
+        s->val = get_u8(tab + pos + 4);
+        break;
+      }
+      case OP_FMT_atom_u16:
+      {
+        s->atom = get_u32(tab + pos);
+        s->val = get_u16(tab + pos + 4);
+        break;
+      }
+      case OP_FMT_atom_label_u8:
+      {
+        s->atom = get_u32(tab + pos);
+        s->label = get_u32(tab + pos + 4);
+        s->val = get_u8(tab + pos + 8);
+        break;
+      }
+      default:
+        break;
+    }
+    pos = pos_next;
+  }
+done:
+  va_end(ap);
+  return ret;
+}
+
+static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, DynBuf *bc)
+{
+  int i, idx, label_next = -1;
+
+  /* add the hoisted functions in arguments and local variables */
+  for(i = 0; i < s->arg_count; i++) {
+    JSVarDef *vd = &s->args[i];
+    if (vd->func_pool_idx >= 0) {
+      dbuf_putc(bc, OP_fclosure);
+      dbuf_put_u32(bc, vd->func_pool_idx);
+      dbuf_putc(bc, OP_put_arg);
+      dbuf_put_u16(bc, i);
+    }
+  }
+  for(i = 0; i < s->var_count; i++) {
+    JSVarDef *vd = &s->vars[i];
+    if (vd->scope_level == 0 && vd->func_pool_idx >= 0) {
+      dbuf_putc(bc, OP_fclosure);
+      dbuf_put_u32(bc, vd->func_pool_idx);
+      dbuf_putc(bc, OP_put_loc);
+      dbuf_put_u16(bc, i);
+    }
+  }
+
+  /* the module global variables must be initialized before
+     evaluating the module so that the exported functions are
+     visible if there are cyclic module references */
+  if (s->module) {
+    label_next = new_label_fd(s, -1);
+
+    /* if 'this' is true, initialize the global variables and return */
+    dbuf_putc(bc, OP_push_this);
+    dbuf_putc(bc, OP_if_false);
+    dbuf_put_u32(bc, label_next);
+    update_label(s, label_next, 1);
+    s->jump_size++;
+  }
+
+  /* add the global variables (only happens if s->is_global_var is
+     true) */
+  for(i = 0; i < s->global_var_count; i++) {
+    JSGlobalVar *hf = &s->global_vars[i];
+    int has_closure = 0;
+    BOOL force_init = hf->force_init;
+    /* we are in an eval, so the closure contains all the
+       enclosing variables */
+    /* If the outer function has a variable environment,
+       create a property for the variable there */
+    for(idx = 0; idx < s->closure_var_count; idx++) {
+      JSClosureVar *cv = &s->closure_var[idx];
+      if (cv->var_name == hf->var_name) {
+        has_closure = 2;
+        force_init = FALSE;
+        break;
+      }
+      if (cv->var_name == JS_ATOM__var_ ||
+          cv->var_name == JS_ATOM__arg_var_) {
+        dbuf_putc(bc, OP_get_var_ref);
+        dbuf_put_u16(bc, idx);
+        has_closure = 1;
+        force_init = TRUE;
+        break;
+      }
+    }
+    if (!has_closure) {
+      int flags;
+
+      flags = 0;
+      if (s->eval_type != JS_EVAL_TYPE_GLOBAL)
+        flags |= JS_PROP_CONFIGURABLE;
+      if (hf->cpool_idx >= 0 && !hf->is_lexical) {
+        /* global function definitions need a specific handling */
+        dbuf_putc(bc, OP_fclosure);
+        dbuf_put_u32(bc, hf->cpool_idx);
+
+        dbuf_putc(bc, OP_define_func);
+        dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
+        dbuf_putc(bc, flags);
+
+        goto done_global_var;
+      } else {
+        if (hf->is_lexical) {
+          flags |= DEFINE_GLOBAL_LEX_VAR;
+          if (!hf->is_const)
+            flags |= JS_PROP_WRITABLE;
+        }
+        dbuf_putc(bc, OP_define_var);
+        dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
+        dbuf_putc(bc, flags);
+      }
+    }
+    if (hf->cpool_idx >= 0 || force_init) {
+      if (hf->cpool_idx >= 0) {
+        dbuf_putc(bc, OP_fclosure);
+        dbuf_put_u32(bc, hf->cpool_idx);
+        if (hf->var_name == JS_ATOM__default_) {
+          /* set default export function name */
+          dbuf_putc(bc, OP_set_name);
+          dbuf_put_u32(bc, JS_DupAtom(ctx, JS_ATOM_default));
+        }
+      } else {
+        dbuf_putc(bc, OP_undefined);
+      }
+      if (has_closure == 2) {
+        dbuf_putc(bc, OP_put_var_ref);
+        dbuf_put_u16(bc, idx);
+      } else if (has_closure == 1) {
+        dbuf_putc(bc, OP_define_field);
+        dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
+        dbuf_putc(bc, OP_drop);
+      } else {
+        /* XXX: Check if variable is writable and enumerable */
+        dbuf_putc(bc, OP_put_var);
+        dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
+      }
+    }
+  done_global_var:
+    JS_FreeAtom(ctx, hf->var_name);
+  }
+
+  if (s->module) {
+    dbuf_putc(bc, OP_return_undef);
+
+    dbuf_putc(bc, OP_label);
+    dbuf_put_u32(bc, label_next);
+    s->label_slots[label_next].pos2 = bc->size;
+  }
+
+  js_free(ctx, s->global_vars);
+  s->global_vars = NULL;
+  s->global_var_count = 0;
+  s->global_var_size = 0;
+}
+
+static int skip_dead_code(JSFunctionDef *s, const uint8_t *bc_buf, int bc_len,
+                          int pos, int *linep)
+{
+  int op, len, label;
+
+  for (; pos < bc_len; pos += len) {
+    op = bc_buf[pos];
+    len = opcode_info[op].size;
+    if (op == OP_line_num) {
+      *linep = get_u32(bc_buf + pos + 1);
+    } else
+        if (op == OP_label) {
+      label = get_u32(bc_buf + pos + 1);
+      if (update_label(s, label, 0) > 0)
+        break;
+#if 0
+            if (s->label_slots[label].first_reloc) {
+                printf("line %d: unreferenced label %d:%d has relocations\n",
+                       *linep, label, s->label_slots[label].pos2);
+            }
+#endif
+      assert(s->label_slots[label].first_reloc == NULL);
+    } else {
+      /* XXX: output a warning for unreachable code? */
+      JSAtom atom;
+      switch(opcode_info[op].fmt) {
+        case OP_FMT_label:
+        case OP_FMT_label_u16:
+          label = get_u32(bc_buf + pos + 1);
+          update_label(s, label, -1);
+          break;
+        case OP_FMT_atom_label_u8:
+        case OP_FMT_atom_label_u16:
+          label = get_u32(bc_buf + pos + 5);
+          update_label(s, label, -1);
+          /* fall thru */
+        case OP_FMT_atom:
+        case OP_FMT_atom_u8:
+        case OP_FMT_atom_u16:
+          atom = get_u32(bc_buf + pos + 1);
+          JS_FreeAtom(s->ctx, atom);
+          break;
+        default:
+          break;
+      }
+    }
+  }
+  return pos;
+}
+
+static int get_label_pos(JSFunctionDef *s, int label)
+{
+  int i, pos;
+  for (i = 0; i < 20; i++) {
+    pos = s->label_slots[label].pos;
+    for (;;) {
+      switch (s->byte_code.buf[pos]) {
+        case OP_line_num:
+        case OP_label:
+          pos += 5;
+          continue;
+        case OP_goto:
+          label = get_u32(s->byte_code.buf + pos + 1);
+          break;
+        default:
+          return pos;
+      }
+      break;
+    }
+  }
+  return pos;
+}
+
+/* convert global variable accesses to local variables or closure
+   variables when necessary */
+static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
+{
+  int pos, pos_next, bc_len, op, len, i, idx, line_num;
+  uint8_t *bc_buf;
+  JSAtom var_name;
+  DynBuf bc_out;
+  CodeContext cc;
+  int scope;
+
+  cc.bc_buf = bc_buf = s->byte_code.buf;
+  cc.bc_len = bc_len = s->byte_code.size;
+  js_dbuf_init(ctx, &bc_out);
+
+  /* first pass for runtime checks (must be done before the
+     variables are created) */
+  for(i = 0; i < s->global_var_count; i++) {
+    JSGlobalVar *hf = &s->global_vars[i];
+    int flags;
+
+    /* check if global variable (XXX: simplify) */
+    for(idx = 0; idx < s->closure_var_count; idx++) {
+      JSClosureVar *cv = &s->closure_var[idx];
+      if (cv->var_name == hf->var_name) {
+        if (s->eval_type == JS_EVAL_TYPE_DIRECT &&
+            cv->is_lexical) {
+          /* Check if a lexical variable is
+             redefined as 'var'. XXX: Could abort
+             compilation here, but for consistency
+             with the other checks, we delay the
+             error generation. */
+          dbuf_putc(&bc_out, OP_throw_error);
+          dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
+          dbuf_putc(&bc_out, JS_THROW_VAR_REDECL);
+        }
+        goto next;
+      }
+      if (cv->var_name == JS_ATOM__var_ ||
+          cv->var_name == JS_ATOM__arg_var_)
+        goto next;
+    }
+
+    dbuf_putc(&bc_out, OP_check_define_var);
+    dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
+    flags = 0;
+    if (hf->is_lexical)
+      flags |= DEFINE_GLOBAL_LEX_VAR;
+    if (hf->cpool_idx >= 0)
+      flags |= DEFINE_GLOBAL_FUNC_VAR;
+    dbuf_putc(&bc_out, flags);
+  next: ;
+  }
+
+  line_num = 0; /* avoid warning */
+  for (pos = 0; pos < bc_len; pos = pos_next) {
+    op = bc_buf[pos];
+    len = opcode_info[op].size;
+    pos_next = pos + len;
+    switch(op) {
+      case OP_line_num:
+        line_num = get_u32(bc_buf + pos + 1);
+        s->line_number_size++;
+        goto no_change;
+
+      case OP_eval: /* convert scope index to adjusted variable index */
+      {
+        int call_argc = get_u16(bc_buf + pos + 1);
+        scope = get_u16(bc_buf + pos + 1 + 2);
+        mark_eval_captured_variables(ctx, s, scope);
+        dbuf_putc(&bc_out, op);
+        dbuf_put_u16(&bc_out, call_argc);
+        dbuf_put_u16(&bc_out, s->scopes[scope].first + 1);
+      }
+      break;
+      case OP_apply_eval: /* convert scope index to adjusted variable index */
+        scope = get_u16(bc_buf + pos + 1);
+        mark_eval_captured_variables(ctx, s, scope);
+        dbuf_putc(&bc_out, op);
+        dbuf_put_u16(&bc_out, s->scopes[scope].first + 1);
+        break;
+      case OP_scope_get_var_undef:
+      case OP_scope_get_var:
+      case OP_scope_put_var:
+      case OP_scope_delete_var:
+      case OP_scope_get_ref:
+      case OP_scope_put_var_init:
+        var_name = get_u32(bc_buf + pos + 1);
+        scope = get_u16(bc_buf + pos + 5);
+        pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
+                                     NULL, NULL, pos_next);
+        JS_FreeAtom(ctx, var_name);
+        break;
+      case OP_scope_make_ref:
+      {
+        int label;
+        LabelSlot *ls;
+        var_name = get_u32(bc_buf + pos + 1);
+        label = get_u32(bc_buf + pos + 5);
+        scope = get_u16(bc_buf + pos + 9);
+        ls = &s->label_slots[label];
+        ls->ref_count--;  /* always remove label reference */
+        pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
+                                     bc_buf, ls, pos_next);
+        JS_FreeAtom(ctx, var_name);
+      }
+      break;
+      case OP_scope_get_private_field:
+      case OP_scope_get_private_field2:
+      case OP_scope_put_private_field:
+      {
+        int ret;
+        var_name = get_u32(bc_buf + pos + 1);
+        scope = get_u16(bc_buf + pos + 5);
+        ret = resolve_scope_private_field(ctx, s, var_name, scope, op, &bc_out);
+        if (ret < 0)
+          goto fail;
+        JS_FreeAtom(ctx, var_name);
+      }
+      break;
+      case OP_gosub:
+        s->jump_size++;
+        if (OPTIMIZE) {
+          /* remove calls to empty finalizers  */
+          int label;
+          LabelSlot *ls;
+
+          label = get_u32(bc_buf + pos + 1);
+          assert(label >= 0 && label < s->label_count);
+          ls = &s->label_slots[label];
+          if (code_match(&cc, ls->pos, OP_ret, -1)) {
+            ls->ref_count--;
+            break;
+          }
+        }
+        goto no_change;
+      case OP_drop:
+        if (0) {
+          /* remove drops before return_undef */
+          /* do not perform this optimization in pass2 because
+             it breaks patterns recognised in resolve_labels */
+          int pos1 = pos_next;
+          int line1 = line_num;
+          while (code_match(&cc, pos1, OP_drop, -1)) {
+            if (cc.line_num >= 0) line1 = cc.line_num;
+            pos1 = cc.pos;
+          }
+          if (code_match(&cc, pos1, OP_return_undef, -1)) {
+            pos_next = pos1;
+            if (line1 != -1 && line1 != line_num) {
+              line_num = line1;
+              s->line_number_size++;
+              dbuf_putc(&bc_out, OP_line_num);
+              dbuf_put_u32(&bc_out, line_num);
+            }
+            break;
+          }
+        }
+        goto no_change;
+      case OP_insert3:
+        if (OPTIMIZE) {
+          /* Transformation: insert3 put_array_el|put_ref_value drop -> put_array_el|put_ref_value */
+          if (code_match(&cc, pos_next, M2(OP_put_array_el, OP_put_ref_value), OP_drop, -1)) {
+            dbuf_putc(&bc_out, cc.op);
+            pos_next = cc.pos;
+            if (cc.line_num != -1 && cc.line_num != line_num) {
+              line_num = cc.line_num;
+              s->line_number_size++;
+              dbuf_putc(&bc_out, OP_line_num);
+              dbuf_put_u32(&bc_out, line_num);
+            }
+            break;
+          }
+        }
+        goto no_change;
+
+      case OP_goto:
+        s->jump_size++;
+        /* fall thru */
+      case OP_tail_call:
+      case OP_tail_call_method:
+      case OP_return:
+      case OP_return_undef:
+      case OP_throw:
+      case OP_throw_error:
+      case OP_ret:
+        if (OPTIMIZE) {
+          /* remove dead code */
+          int line = -1;
+          dbuf_put(&bc_out, bc_buf + pos, len);
+          pos = skip_dead_code(s, bc_buf, bc_len, pos + len, &line);
+          pos_next = pos;
+          if (pos < bc_len && line >= 0 && line_num != line) {
+            line_num = line;
+            s->line_number_size++;
+            dbuf_putc(&bc_out, OP_line_num);
+            dbuf_put_u32(&bc_out, line_num);
+          }
+          break;
+        }
+        goto no_change;
+
+      case OP_label:
+      {
+        int label;
+        LabelSlot *ls;
+
+        label = get_u32(bc_buf + pos + 1);
+        assert(label >= 0 && label < s->label_count);
+        ls = &s->label_slots[label];
+        ls->pos2 = bc_out.size + opcode_info[op].size;
+      }
+        goto no_change;
+
+      case OP_enter_scope:
+      {
+        int scope_idx, scope = get_u16(bc_buf + pos + 1);
+
+        if (scope == s->body_scope) {
+          instantiate_hoisted_definitions(ctx, s, &bc_out);
+        }
+
+        for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {
+          JSVarDef *vd = &s->vars[scope_idx];
+          if (vd->scope_level == scope) {
+            if (scope_idx != s->arguments_arg_idx) {
+              if (vd->var_kind == JS_VAR_FUNCTION_DECL ||
+                  vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) {
+                /* Initialize lexical variable upon entering scope */
+                dbuf_putc(&bc_out, OP_fclosure);
+                dbuf_put_u32(&bc_out, vd->func_pool_idx);
+                dbuf_putc(&bc_out, OP_put_loc);
+                dbuf_put_u16(&bc_out, scope_idx);
+              } else {
+                /* XXX: should check if variable can be used
+                   before initialization */
+                dbuf_putc(&bc_out, OP_set_loc_uninitialized);
+                dbuf_put_u16(&bc_out, scope_idx);
+              }
+            }
+            scope_idx = vd->scope_next;
+          } else {
+            break;
+          }
+        }
+      }
+      break;
+
+      case OP_leave_scope:
+      {
+        int scope_idx, scope = get_u16(bc_buf + pos + 1);
+
+        for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {
+          JSVarDef *vd = &s->vars[scope_idx];
+          if (vd->scope_level == scope) {
+            if (vd->is_captured) {
+              dbuf_putc(&bc_out, OP_close_loc);
+              dbuf_put_u16(&bc_out, scope_idx);
+            }
+            scope_idx = vd->scope_next;
+          } else {
+            break;
+          }
+        }
+      }
+      break;
+
+      case OP_set_name:
+      {
+        /* remove dummy set_name opcodes */
+        JSAtom name = get_u32(bc_buf + pos + 1);
+        if (name == JS_ATOM_NULL)
+          break;
+      }
+        goto no_change;
+
+      case OP_if_false:
+      case OP_if_true:
+      case OP_catch:
+        s->jump_size++;
+        goto no_change;
+
+      case OP_dup:
+        if (OPTIMIZE) {
+          /* Transformation: dup if_false(l1) drop, l1: if_false(l2) -> if_false(l2) */
+          /* Transformation: dup if_true(l1) drop, l1: if_true(l2) -> if_true(l2) */
+          if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), OP_drop, -1)) {
+            int lab0, lab1, op1, pos1, line1, pos2;
+            lab0 = lab1 = cc.label;
+            assert(lab1 >= 0 && lab1 < s->label_count);
+            op1 = cc.op;
+            pos1 = cc.pos;
+            line1 = cc.line_num;
+            while (code_match(&cc, (pos2 = get_label_pos(s, lab1)), OP_dup, op1, OP_drop, -1)) {
+              lab1 = cc.label;
+            }
+            if (code_match(&cc, pos2, op1, -1)) {
+              s->jump_size++;
+              update_label(s, lab0, -1);
+              update_label(s, cc.label, +1);
+              dbuf_putc(&bc_out, op1);
+              dbuf_put_u32(&bc_out, cc.label);
+              pos_next = pos1;
+              if (line1 != -1 && line1 != line_num) {
+                line_num = line1;
+                s->line_number_size++;
+                dbuf_putc(&bc_out, OP_line_num);
+                dbuf_put_u32(&bc_out, line_num);
+              }
+              break;
+            }
+          }
+        }
+        goto no_change;
+
+      case OP_nop:
+        /* remove erased code */
+        break;
+      case OP_set_class_name:
+        /* only used during parsing */
+        break;
+
+      default:
+      no_change:
+        dbuf_put(&bc_out, bc_buf + pos, len);
+        break;
+    }
+  }
+
+  /* set the new byte code */
+  dbuf_free(&s->byte_code);
+  s->byte_code = bc_out;
+  if (dbuf_error(&s->byte_code)) {
+    JS_ThrowOutOfMemory(ctx);
+    return -1;
+  }
+  return 0;
+fail:
+  /* continue the copy to keep the atom refcounts consistent */
+  /* XXX: find a better solution ? */
+  for (; pos < bc_len; pos = pos_next) {
+    op = bc_buf[pos];
+    len = opcode_info[op].size;
+    pos_next = pos + len;
+    dbuf_put(&bc_out, bc_buf + pos, len);
+  }
+  dbuf_free(&s->byte_code);
+  s->byte_code = bc_out;
+  return -1;
+}
+
+/* the pc2line table gives a line number for each PC value */
+static void add_pc2line_info(JSFunctionDef *s, uint32_t pc, int line_num)
+{
+  if (s->line_number_slots != NULL
+      &&  s->line_number_count < s->line_number_size
+      &&  pc >= s->line_number_last_pc
+      &&  line_num != s->line_number_last) {
+    s->line_number_slots[s->line_number_count].pc = pc;
+    s->line_number_slots[s->line_number_count].line_num = line_num;
+    s->line_number_count++;
+    s->line_number_last_pc = pc;
+    s->line_number_last = line_num;
+  }
+}
+
+static void compute_pc2line_info(JSFunctionDef *s)
+{
+  if (!(s->js_mode & JS_MODE_STRIP) && s->line_number_slots) {
+    int last_line_num = s->line_num;
+    uint32_t last_pc = 0;
+    int i;
+
+    js_dbuf_init(s->ctx, &s->pc2line);
+    for (i = 0; i < s->line_number_count; i++) {
+      uint32_t pc = s->line_number_slots[i].pc;
+      int line_num = s->line_number_slots[i].line_num;
+      int diff_pc, diff_line;
+
+      if (line_num < 0)
+        continue;
+
+      diff_pc = pc - last_pc;
+      diff_line = line_num - last_line_num;
+      if (diff_line == 0 || diff_pc < 0)
+        continue;
+
+      if (diff_line >= PC2LINE_BASE &&
+          diff_line < PC2LINE_BASE + PC2LINE_RANGE &&
+          diff_pc <= PC2LINE_DIFF_PC_MAX) {
+        dbuf_putc(&s->pc2line, (diff_line - PC2LINE_BASE) +
+                                   diff_pc * PC2LINE_RANGE + PC2LINE_OP_FIRST);
+      } else {
+        /* longer encoding */
+        dbuf_putc(&s->pc2line, 0);
+        dbuf_put_leb128(&s->pc2line, diff_pc);
+        dbuf_put_sleb128(&s->pc2line, diff_line);
+      }
+      last_pc = pc;
+      last_line_num = line_num;
+    }
+  }
+}
+
+static RelocEntry *add_reloc(JSContext *ctx, LabelSlot *ls, uint32_t addr, int size)
+{
+  RelocEntry *re;
+  re = js_malloc(ctx, sizeof(*re));
+  if (!re)
+    return NULL;
+  re->addr = addr;
+  re->size = size;
+  re->next = ls->first_reloc;
+  ls->first_reloc = re;
+  return re;
+}
+
+static BOOL code_has_label(CodeContext *s, int pos, int label)
+{
+  while (pos < s->bc_len) {
+    int op = s->bc_buf[pos];
+    if (op == OP_line_num) {
+      pos += 5;
+      continue;
+    }
+    if (op == OP_label) {
+      int lab = get_u32(s->bc_buf + pos + 1);
+      if (lab == label)
+        return TRUE;
+      pos += 5;
+      continue;
+    }
+    if (op == OP_goto) {
+      int lab = get_u32(s->bc_buf + pos + 1);
+      if (lab == label)
+        return TRUE;
+    }
+    break;
+  }
+  return FALSE;
+}
+
+/* return the target label, following the OP_goto jumps
+   the first opcode at destination is stored in *pop
+ */
+static int find_jump_target(JSFunctionDef *s, int label, int *pop, int *pline)
+{
+  int i, pos, op;
+
+  update_label(s, label, -1);
+  for (i = 0; i < 10; i++) {
+    assert(label >= 0 && label < s->label_count);
+    pos = s->label_slots[label].pos2;
+    for (;;) {
+      switch(op = s->byte_code.buf[pos]) {
+        case OP_line_num:
+          if (pline)
+            *pline = get_u32(s->byte_code.buf + pos + 1);
+          /* fall thru */
+        case OP_label:
+          pos += opcode_info[op].size;
+          continue;
+        case OP_goto:
+          label = get_u32(s->byte_code.buf + pos + 1);
+          break;
+        case OP_drop:
+          /* ignore drop opcodes if followed by OP_return_undef */
+          while (s->byte_code.buf[++pos] == OP_drop)
+            continue;
+          if (s->byte_code.buf[pos] == OP_return_undef)
+            op = OP_return_undef;
+          /* fall thru */
+        default:
+          goto done;
+      }
+      break;
+    }
+  }
+  /* cycle detected, could issue a warning */
+done:
+  *pop = op;
+  update_label(s, label, +1);
+  return label;
+}
+
+static void push_short_int(DynBuf *bc_out, int val)
+{
+#if SHORT_OPCODES
+  if (val >= -1 && val <= 7) {
+    dbuf_putc(bc_out, OP_push_0 + val);
+    return;
+  }
+  if (val == (int8_t)val) {
+    dbuf_putc(bc_out, OP_push_i8);
+    dbuf_putc(bc_out, val);
+    return;
+  }
+  if (val == (int16_t)val) {
+    dbuf_putc(bc_out, OP_push_i16);
+    dbuf_put_u16(bc_out, val);
+    return;
+  }
+#endif
+  dbuf_putc(bc_out, OP_push_i32);
+  dbuf_put_u32(bc_out, val);
+}
+
+static void put_short_code(DynBuf *bc_out, int op, int idx)
+{
+#if SHORT_OPCODES
+  if (idx < 4) {
+    switch (op) {
+      case OP_get_loc:
+        dbuf_putc(bc_out, OP_get_loc0 + idx);
+        return;
+      case OP_put_loc:
+        dbuf_putc(bc_out, OP_put_loc0 + idx);
+        return;
+      case OP_set_loc:
+        dbuf_putc(bc_out, OP_set_loc0 + idx);
+        return;
+      case OP_get_arg:
+        dbuf_putc(bc_out, OP_get_arg0 + idx);
+        return;
+      case OP_put_arg:
+        dbuf_putc(bc_out, OP_put_arg0 + idx);
+        return;
+      case OP_set_arg:
+        dbuf_putc(bc_out, OP_set_arg0 + idx);
+        return;
+      case OP_get_var_ref:
+        dbuf_putc(bc_out, OP_get_var_ref0 + idx);
+        return;
+      case OP_put_var_ref:
+        dbuf_putc(bc_out, OP_put_var_ref0 + idx);
+        return;
+      case OP_set_var_ref:
+        dbuf_putc(bc_out, OP_set_var_ref0 + idx);
+        return;
+      case OP_call:
+        dbuf_putc(bc_out, OP_call0 + idx);
+        return;
+    }
+  }
+  if (idx < 256) {
+    switch (op) {
+      case OP_get_loc:
+        dbuf_putc(bc_out, OP_get_loc8);
+        dbuf_putc(bc_out, idx);
+        return;
+      case OP_put_loc:
+        dbuf_putc(bc_out, OP_put_loc8);
+        dbuf_putc(bc_out, idx);
+        return;
+      case OP_set_loc:
+        dbuf_putc(bc_out, OP_set_loc8);
+        dbuf_putc(bc_out, idx);
+        return;
+    }
+  }
+#endif
+  dbuf_putc(bc_out, op);
+  dbuf_put_u16(bc_out, idx);
+}
+
+/* peephole optimizations and resolve goto/labels */
+static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
+{
+  int pos, pos_next, bc_len, op, op1, len, i, line_num;
+  const uint8_t *bc_buf;
+  DynBuf bc_out;
+  LabelSlot *label_slots, *ls;
+  RelocEntry *re, *re_next;
+  CodeContext cc;
+  int label;
+#if SHORT_OPCODES
+  JumpSlot *jp;
+#endif
+
+  label_slots = s->label_slots;
+
+  line_num = s->line_num;
+
+  cc.bc_buf = bc_buf = s->byte_code.buf;
+  cc.bc_len = bc_len = s->byte_code.size;
+  js_dbuf_init(ctx, &bc_out);
+
+#if SHORT_OPCODES
+  if (s->jump_size) {
+    s->jump_slots = js_mallocz(s->ctx, sizeof(*s->jump_slots) * s->jump_size);
+    if (s->jump_slots == NULL)
+      return -1;
+  }
+#endif
+  /* XXX: Should skip this phase if not generating SHORT_OPCODES */
+  if (s->line_number_size && !(s->js_mode & JS_MODE_STRIP)) {
+    s->line_number_slots = js_mallocz(s->ctx, sizeof(*s->line_number_slots) * s->line_number_size);
+    if (s->line_number_slots == NULL)
+      return -1;
+    s->line_number_last = s->line_num;
+    s->line_number_last_pc = 0;
+  }
+
+  /* initialize the 'home_object' variable if needed */
+  if (s->home_object_var_idx >= 0) {
+    dbuf_putc(&bc_out, OP_special_object);
+    dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_HOME_OBJECT);
+    put_short_code(&bc_out, OP_put_loc, s->home_object_var_idx);
+  }
+  /* initialize the 'this.active_func' variable if needed */
+  if (s->this_active_func_var_idx >= 0) {
+    dbuf_putc(&bc_out, OP_special_object);
+    dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_THIS_FUNC);
+    put_short_code(&bc_out, OP_put_loc, s->this_active_func_var_idx);
+  }
+  /* initialize the 'new.target' variable if needed */
+  if (s->new_target_var_idx >= 0) {
+    dbuf_putc(&bc_out, OP_special_object);
+    dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_NEW_TARGET);
+    put_short_code(&bc_out, OP_put_loc, s->new_target_var_idx);
+  }
+  /* initialize the 'this' variable if needed. In a derived class
+     constructor, this is initially uninitialized. */
+  if (s->this_var_idx >= 0) {
+    if (s->is_derived_class_constructor) {
+      dbuf_putc(&bc_out, OP_set_loc_uninitialized);
+      dbuf_put_u16(&bc_out, s->this_var_idx);
+    } else {
+      dbuf_putc(&bc_out, OP_push_this);
+      put_short_code(&bc_out, OP_put_loc, s->this_var_idx);
+    }
+  }
+  /* initialize the 'arguments' variable if needed */
+  if (s->arguments_var_idx >= 0) {
+    if ((s->js_mode & JS_MODE_STRICT) || !s->has_simple_parameter_list) {
+      dbuf_putc(&bc_out, OP_special_object);
+      dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_ARGUMENTS);
+    } else {
+      dbuf_putc(&bc_out, OP_special_object);
+      dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS);
+    }
+    if (s->arguments_arg_idx >= 0)
+      put_short_code(&bc_out, OP_set_loc, s->arguments_arg_idx);
+    put_short_code(&bc_out, OP_put_loc, s->arguments_var_idx);
+  }
+  /* initialize a reference to the current function if needed */
+  if (s->func_var_idx >= 0) {
+    dbuf_putc(&bc_out, OP_special_object);
+    dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_THIS_FUNC);
+    put_short_code(&bc_out, OP_put_loc, s->func_var_idx);
+  }
+  /* initialize the variable environment object if needed */
+  if (s->var_object_idx >= 0) {
+    dbuf_putc(&bc_out, OP_special_object);
+    dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
+    put_short_code(&bc_out, OP_put_loc, s->var_object_idx);
+  }
+  if (s->arg_var_object_idx >= 0) {
+    dbuf_putc(&bc_out, OP_special_object);
+    dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
+    put_short_code(&bc_out, OP_put_loc, s->arg_var_object_idx);
+  }
+
+  for (pos = 0; pos < bc_len; pos = pos_next) {
+    int val;
+    op = bc_buf[pos];
+    len = opcode_info[op].size;
+    pos_next = pos + len;
+    switch(op) {
+      case OP_line_num:
+        /* line number info (for debug). We put it in a separate
+           compressed table to reduce memory usage and get better
+           performance */
+        line_num = get_u32(bc_buf + pos + 1);
+        break;
+
+      case OP_label:
+      {
+        label = get_u32(bc_buf + pos + 1);
+        assert(label >= 0 && label < s->label_count);
+        ls = &label_slots[label];
+        assert(ls->addr == -1);
+        ls->addr = bc_out.size;
+        /* resolve the relocation entries */
+        for(re = ls->first_reloc; re != NULL; re = re_next) {
+          int diff = ls->addr - re->addr;
+          re_next = re->next;
+          switch (re->size) {
+            case 4:
+              put_u32(bc_out.buf + re->addr, diff);
+              break;
+            case 2:
+              assert(diff == (int16_t)diff);
+              put_u16(bc_out.buf + re->addr, diff);
+              break;
+            case 1:
+              assert(diff == (int8_t)diff);
+              put_u8(bc_out.buf + re->addr, diff);
+              break;
+          }
+          js_free(ctx, re);
+        }
+        ls->first_reloc = NULL;
+      }
+      break;
+
+      case OP_call:
+      case OP_call_method:
+      {
+        /* detect and transform tail calls */
+        int argc;
+        argc = get_u16(bc_buf + pos + 1);
+        if (code_match(&cc, pos_next, OP_return, -1)) {
+          if (cc.line_num >= 0) line_num = cc.line_num;
+          add_pc2line_info(s, bc_out.size, line_num);
+          put_short_code(&bc_out, op + 1, argc);
+          pos_next = skip_dead_code(s, bc_buf, bc_len, cc.pos, &line_num);
+          break;
+        }
+        add_pc2line_info(s, bc_out.size, line_num);
+        put_short_code(&bc_out, op, argc);
+        break;
+      }
+        goto no_change;
+
+      case OP_return:
+      case OP_return_undef:
+      case OP_return_async:
+      case OP_throw:
+      case OP_throw_error:
+        pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
+        goto no_change;
+
+      case OP_goto:
+        label = get_u32(bc_buf + pos + 1);
+      has_goto:
+        if (OPTIMIZE) {
+          int line1 = -1;
+          /* Use custom matcher because multiple labels can follow */
+          label = find_jump_target(s, label, &op1, &line1);
+          if (code_has_label(&cc, pos_next, label)) {
+            /* jump to next instruction: remove jump */
+            update_label(s, label, -1);
+            break;
+          }
+          if (op1 == OP_return || op1 == OP_return_undef || op1 == OP_throw) {
+            /* jump to return/throw: remove jump, append return/throw */
+            /* updating the line number obfuscates assembly listing */
+            //if (line1 >= 0) line_num = line1;
+            update_label(s, label, -1);
+            add_pc2line_info(s, bc_out.size, line_num);
+            dbuf_putc(&bc_out, op1);
+            pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
+            break;
+          }
+          /* XXX: should duplicate single instructions followed by goto or return */
+          /* For example, can match one of these followed by return:
+             push_i32 / push_const / push_atom_value / get_var /
+             undefined / null / push_false / push_true / get_ref_value /
+             get_loc / get_arg / get_var_ref
+           */
+        }
+        goto has_label;
+
+      case OP_gosub:
+        label = get_u32(bc_buf + pos + 1);
+        if (0 && OPTIMIZE) {
+          label = find_jump_target(s, label, &op1, NULL);
+          if (op1 == OP_ret) {
+            update_label(s, label, -1);
+            /* empty finally clause: remove gosub */
+            break;
+          }
+        }
+        goto has_label;
+
+      case OP_catch:
+        label = get_u32(bc_buf + pos + 1);
+        goto has_label;
+
+      case OP_if_true:
+      case OP_if_false:
+        label = get_u32(bc_buf + pos + 1);
+        if (OPTIMIZE) {
+          label = find_jump_target(s, label, &op1, NULL);
+          /* transform if_false/if_true(l1) label(l1) -> drop label(l1) */
+          if (code_has_label(&cc, pos_next, label)) {
+            update_label(s, label, -1);
+            dbuf_putc(&bc_out, OP_drop);
+            break;
+          }
+          /* transform if_false(l1) goto(l2) label(l1) -> if_false(l2) label(l1) */
+          if (code_match(&cc, pos_next, OP_goto, -1)) {
+            int pos1 = cc.pos;
+            int line1 = cc.line_num;
+            if (code_has_label(&cc, pos1, label)) {
+              if (line1 >= 0) line_num = line1;
+              pos_next = pos1;
+              update_label(s, label, -1);
+              label = cc.label;
+              op ^= OP_if_true ^ OP_if_false;
+            }
+          }
+        }
+      has_label:
+        add_pc2line_info(s, bc_out.size, line_num);
+        if (op == OP_goto) {
+          pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
+        }
+        assert(label >= 0 && label < s->label_count);
+        ls = &label_slots[label];
+#if SHORT_OPCODES
+        jp = &s->jump_slots[s->jump_count++];
+        jp->op = op;
+        jp->size = 4;
+        jp->pos = bc_out.size + 1;
+        jp->label = label;
+
+        if (ls->addr == -1) {
+          int diff = ls->pos2 - pos - 1;
+          if (diff < 128 && (op == OP_if_false || op == OP_if_true || op == OP_goto)) {
+            jp->size = 1;
+            jp->op = OP_if_false8 + (op - OP_if_false);
+            dbuf_putc(&bc_out, OP_if_false8 + (op - OP_if_false));
+            dbuf_putc(&bc_out, 0);
+            if (!add_reloc(ctx, ls, bc_out.size - 1, 1))
+              goto fail;
+            break;
+          }
+          if (diff < 32768 && op == OP_goto) {
+            jp->size = 2;
+            jp->op = OP_goto16;
+            dbuf_putc(&bc_out, OP_goto16);
+            dbuf_put_u16(&bc_out, 0);
+            if (!add_reloc(ctx, ls, bc_out.size - 2, 2))
+              goto fail;
+            break;
+          }
+        } else {
+          int diff = ls->addr - bc_out.size - 1;
+          if (diff == (int8_t)diff && (op == OP_if_false || op == OP_if_true || op == OP_goto)) {
+            jp->size = 1;
+            jp->op = OP_if_false8 + (op - OP_if_false);
+            dbuf_putc(&bc_out, OP_if_false8 + (op - OP_if_false));
+            dbuf_putc(&bc_out, diff);
+            break;
+          }
+          if (diff == (int16_t)diff && op == OP_goto) {
+            jp->size = 2;
+            jp->op = OP_goto16;
+            dbuf_putc(&bc_out, OP_goto16);
+            dbuf_put_u16(&bc_out, diff);
+            break;
+          }
+        }
+#endif
+        dbuf_putc(&bc_out, op);
+        dbuf_put_u32(&bc_out, ls->addr - bc_out.size);
+        if (ls->addr == -1) {
+          /* unresolved yet: create a new relocation entry */
+          if (!add_reloc(ctx, ls, bc_out.size - 4, 4))
+            goto fail;
+        }
+        break;
+      case OP_with_get_var:
+      case OP_with_put_var:
+      case OP_with_delete_var:
+      case OP_with_make_ref:
+      case OP_with_get_ref:
+      case OP_with_get_ref_undef:
+      {
+        JSAtom atom;
+        int is_with;
+
+        atom = get_u32(bc_buf + pos + 1);
+        label = get_u32(bc_buf + pos + 5);
+        is_with = bc_buf[pos + 9];
+        if (OPTIMIZE) {
+          label = find_jump_target(s, label, &op1, NULL);
+        }
+        assert(label >= 0 && label < s->label_count);
+        ls = &label_slots[label];
+        add_pc2line_info(s, bc_out.size, line_num);
+#if SHORT_OPCODES
+        jp = &s->jump_slots[s->jump_count++];
+        jp->op = op;
+        jp->size = 4;
+        jp->pos = bc_out.size + 5;
+        jp->label = label;
+#endif
+        dbuf_putc(&bc_out, op);
+        dbuf_put_u32(&bc_out, atom);
+        dbuf_put_u32(&bc_out, ls->addr - bc_out.size);
+        if (ls->addr == -1) {
+          /* unresolved yet: create a new relocation entry */
+          if (!add_reloc(ctx, ls, bc_out.size - 4, 4))
+            goto fail;
+        }
+        dbuf_putc(&bc_out, is_with);
+      }
+      break;
+
+      case OP_drop:
+        if (OPTIMIZE) {
+          /* remove useless drops before return */
+          if (code_match(&cc, pos_next, OP_return_undef, -1)) {
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            break;
+          }
+        }
+        goto no_change;
+
+      case OP_null:
+#if SHORT_OPCODES
+        if (OPTIMIZE) {
+          /* transform null strict_eq into is_null */
+          if (code_match(&cc, pos_next, OP_strict_eq, -1)) {
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            add_pc2line_info(s, bc_out.size, line_num);
+            dbuf_putc(&bc_out, OP_is_null);
+            pos_next = cc.pos;
+            break;
+          }
+          /* transform null strict_neq if_false/if_true -> is_null if_true/if_false */
+          if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) {
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            add_pc2line_info(s, bc_out.size, line_num);
+            dbuf_putc(&bc_out, OP_is_null);
+            pos_next = cc.pos;
+            label = cc.label;
+            op = cc.op ^ OP_if_false ^ OP_if_true;
+            goto has_label;
+          }
+        }
+#endif
+        /* fall thru */
+      case OP_push_false:
+      case OP_push_true:
+        if (OPTIMIZE) {
+          val = (op == OP_push_true);
+          if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
+          has_constant_test:
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            if (val == cc.op - OP_if_false) {
+              /* transform null if_false(l1) -> goto l1 */
+              /* transform false if_false(l1) -> goto l1 */
+              /* transform true if_true(l1) -> goto l1 */
+              pos_next = cc.pos;
+              op = OP_goto;
+              label = cc.label;
+              goto has_goto;
+            } else {
+              /* transform null if_true(l1) -> nop */
+              /* transform false if_true(l1) -> nop */
+              /* transform true if_false(l1) -> nop */
+              pos_next = cc.pos;
+              update_label(s, cc.label, -1);
+              break;
+            }
+          }
+        }
+        goto no_change;
+
+      case OP_push_i32:
+        if (OPTIMIZE) {
+          /* transform i32(val) neg -> i32(-val) */
+          val = get_i32(bc_buf + pos + 1);
+          if ((val != INT32_MIN && val != 0)
+              &&  code_match(&cc, pos_next, OP_neg, -1)) {
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            if (code_match(&cc, cc.pos, OP_drop, -1)) {
+              if (cc.line_num >= 0) line_num = cc.line_num;
+            } else {
+              add_pc2line_info(s, bc_out.size, line_num);
+              push_short_int(&bc_out, -val);
+            }
+            pos_next = cc.pos;
+            break;
+          }
+          /* remove push/drop pairs generated by the parser */
+          if (code_match(&cc, pos_next, OP_drop, -1)) {
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            pos_next = cc.pos;
+            break;
+          }
+          /* Optimize constant tests: `if (0)`, `if (1)`, `if (!0)`... */
+          if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
+            val = (val != 0);
+            goto has_constant_test;
+          }
+          add_pc2line_info(s, bc_out.size, line_num);
+          push_short_int(&bc_out, val);
+          break;
+        }
+        goto no_change;
+
+#if SHORT_OPCODES
+      case OP_push_const:
+      case OP_fclosure:
+        if (OPTIMIZE) {
+          int idx = get_u32(bc_buf + pos + 1);
+          if (idx < 256) {
+            add_pc2line_info(s, bc_out.size, line_num);
+            dbuf_putc(&bc_out, OP_push_const8 + op - OP_push_const);
+            dbuf_putc(&bc_out, idx);
+            break;
+          }
+        }
+        goto no_change;
+
+      case OP_get_field:
+        if (OPTIMIZE) {
+          JSAtom atom = get_u32(bc_buf + pos + 1);
+          if (atom == JS_ATOM_length) {
+            JS_FreeAtom(ctx, atom);
+            add_pc2line_info(s, bc_out.size, line_num);
+            dbuf_putc(&bc_out, OP_get_length);
+            break;
+          }
+        }
+        goto no_change;
+#endif
+      case OP_push_atom_value:
+        if (OPTIMIZE) {
+          JSAtom atom = get_u32(bc_buf + pos + 1);
+          /* remove push/drop pairs generated by the parser */
+          if (code_match(&cc, pos_next, OP_drop, -1)) {
+            JS_FreeAtom(ctx, atom);
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            pos_next = cc.pos;
+            break;
+          }
+#if SHORT_OPCODES
+          if (atom == JS_ATOM_empty_string) {
+            JS_FreeAtom(ctx, atom);
+            add_pc2line_info(s, bc_out.size, line_num);
+            dbuf_putc(&bc_out, OP_push_empty_string);
+            break;
+          }
+#endif
+        }
+        goto no_change;
+
+      case OP_to_propkey:
+      case OP_to_propkey2:
+        if (OPTIMIZE) {
+          /* remove redundant to_propkey/to_propkey2 opcodes when storing simple data */
+          if (code_match(&cc, pos_next, M3(OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_put_array_el, -1)
+              ||  code_match(&cc, pos_next, M3(OP_push_i32, OP_push_const, OP_push_atom_value), OP_put_array_el, -1)
+              ||  code_match(&cc, pos_next, M4(OP_undefined, OP_null, OP_push_true, OP_push_false), OP_put_array_el, -1)) {
+            break;
+          }
+        }
+        goto no_change;
+
+      case OP_undefined:
+        if (OPTIMIZE) {
+          /* remove push/drop pairs generated by the parser */
+          if (code_match(&cc, pos_next, OP_drop, -1)) {
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            pos_next = cc.pos;
+            break;
+          }
+          /* transform undefined return -> return_undefined */
+          if (code_match(&cc, pos_next, OP_return, -1)) {
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            add_pc2line_info(s, bc_out.size, line_num);
+            dbuf_putc(&bc_out, OP_return_undef);
+            pos_next = cc.pos;
+            break;
+          }
+          /* transform undefined if_true(l1)/if_false(l1) -> nop/goto(l1) */
+          if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
+            val = 0;
+            goto has_constant_test;
+          }
+#if SHORT_OPCODES
+          /* transform undefined strict_eq -> is_undefined */
+          if (code_match(&cc, pos_next, OP_strict_eq, -1)) {
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            add_pc2line_info(s, bc_out.size, line_num);
+            dbuf_putc(&bc_out, OP_is_undefined);
+            pos_next = cc.pos;
+            break;
+          }
+          /* transform undefined strict_neq if_false/if_true -> is_undefined if_true/if_false */
+          if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) {
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            add_pc2line_info(s, bc_out.size, line_num);
+            dbuf_putc(&bc_out, OP_is_undefined);
+            pos_next = cc.pos;
+            label = cc.label;
+            op = cc.op ^ OP_if_false ^ OP_if_true;
+            goto has_label;
+          }
+#endif
+        }
+        goto no_change;
+
+      case OP_insert2:
+        if (OPTIMIZE) {
+          /* Transformation:
+             insert2 put_field(a) drop -> put_field(a)
+             insert2 put_var_strict(a) drop -> put_var_strict(a)
+          */
+          if (code_match(&cc, pos_next, M2(OP_put_field, OP_put_var_strict), OP_drop, -1)) {
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            add_pc2line_info(s, bc_out.size, line_num);
+            dbuf_putc(&bc_out, cc.op);
+            dbuf_put_u32(&bc_out, cc.atom);
+            pos_next = cc.pos;
+            break;
+          }
+        }
+        goto no_change;
+
+      case OP_dup:
+        if (OPTIMIZE) {
+          /* Transformation: dup put_x(n) drop -> put_x(n) */
+          int op1, line2 = -1;
+          /* Transformation: dup put_x(n) -> set_x(n) */
+          if (code_match(&cc, pos_next, M3(OP_put_loc, OP_put_arg, OP_put_var_ref), -1, -1)) {
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            op1 = cc.op + 1;  /* put_x -> set_x */
+            pos_next = cc.pos;
+            if (code_match(&cc, cc.pos, OP_drop, -1)) {
+              if (cc.line_num >= 0) line_num = cc.line_num;
+              op1 -= 1; /* set_x drop -> put_x */
+              pos_next = cc.pos;
+              if (code_match(&cc, cc.pos, op1 - 1, cc.idx, -1)) {
+                line2 = cc.line_num; /* delay line number update */
+                op1 += 1;   /* put_x(n) get_x(n) -> set_x(n) */
+                pos_next = cc.pos;
+              }
+            }
+            add_pc2line_info(s, bc_out.size, line_num);
+            put_short_code(&bc_out, op1, cc.idx);
+            if (line2 >= 0) line_num = line2;
+            break;
+          }
+        }
+        goto no_change;
+
+      case OP_get_loc:
+        if (OPTIMIZE) {
+          /* transformation:
+             get_loc(n) post_dec put_loc(n) drop -> dec_loc(n)
+             get_loc(n) post_inc put_loc(n) drop -> inc_loc(n)
+             get_loc(n) dec dup put_loc(n) drop -> dec_loc(n)
+             get_loc(n) inc dup put_loc(n) drop -> inc_loc(n)
+           */
+          int idx;
+          idx = get_u16(bc_buf + pos + 1);
+          if (idx >= 256)
+            goto no_change;
+          if (code_match(&cc, pos_next, M2(OP_post_dec, OP_post_inc), OP_put_loc, idx, OP_drop, -1) ||
+              code_match(&cc, pos_next, M2(OP_dec, OP_inc), OP_dup, OP_put_loc, idx, OP_drop, -1)) {
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            add_pc2line_info(s, bc_out.size, line_num);
+            dbuf_putc(&bc_out, (cc.op == OP_inc || cc.op == OP_post_inc) ? OP_inc_loc : OP_dec_loc);
+            dbuf_putc(&bc_out, idx);
+            pos_next = cc.pos;
+            break;
+          }
+          /* transformation:
+             get_loc(n) push_atom_value(x) add dup put_loc(n) drop -> push_atom_value(x) add_loc(n)
+           */
+          if (code_match(&cc, pos_next, OP_push_atom_value, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            add_pc2line_info(s, bc_out.size, line_num);
+#if SHORT_OPCODES
+            if (cc.atom == JS_ATOM_empty_string) {
+              JS_FreeAtom(ctx, cc.atom);
+              dbuf_putc(&bc_out, OP_push_empty_string);
+            } else
+#endif
+            {
+              dbuf_putc(&bc_out, OP_push_atom_value);
+              dbuf_put_u32(&bc_out, cc.atom);
+            }
+            dbuf_putc(&bc_out, OP_add_loc);
+            dbuf_putc(&bc_out, idx);
+            pos_next = cc.pos;
+            break;
+          }
+          /* transformation:
+             get_loc(n) push_i32(x) add dup put_loc(n) drop -> push_i32(x) add_loc(n)
+           */
+          if (code_match(&cc, pos_next, OP_push_i32, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            add_pc2line_info(s, bc_out.size, line_num);
+            push_short_int(&bc_out, cc.label);
+            dbuf_putc(&bc_out, OP_add_loc);
+            dbuf_putc(&bc_out, idx);
+            pos_next = cc.pos;
+            break;
+          }
+          /* transformation: XXX: also do these:
+             get_loc(n) get_loc(x) add dup put_loc(n) drop -> get_loc(x) add_loc(n)
+             get_loc(n) get_arg(x) add dup put_loc(n) drop -> get_arg(x) add_loc(n)
+             get_loc(n) get_var_ref(x) add dup put_loc(n) drop -> get_var_ref(x) add_loc(n)
+           */
+          if (code_match(&cc, pos_next, M3(OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            add_pc2line_info(s, bc_out.size, line_num);
+            put_short_code(&bc_out, cc.op, cc.idx);
+            dbuf_putc(&bc_out, OP_add_loc);
+            dbuf_putc(&bc_out, idx);
+            pos_next = cc.pos;
+            break;
+          }
+          add_pc2line_info(s, bc_out.size, line_num);
+          put_short_code(&bc_out, op, idx);
+          break;
+        }
+        goto no_change;
+#if SHORT_OPCODES
+      case OP_get_arg:
+      case OP_get_var_ref:
+        if (OPTIMIZE) {
+          int idx;
+          idx = get_u16(bc_buf + pos + 1);
+          add_pc2line_info(s, bc_out.size, line_num);
+          put_short_code(&bc_out, op, idx);
+          break;
+        }
+        goto no_change;
+#endif
+      case OP_put_loc:
+      case OP_put_arg:
+      case OP_put_var_ref:
+        if (OPTIMIZE) {
+          /* transformation: put_x(n) get_x(n) -> set_x(n) */
+          int idx;
+          idx = get_u16(bc_buf + pos + 1);
+          if (code_match(&cc, pos_next, op - 1, idx, -1)) {
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            add_pc2line_info(s, bc_out.size, line_num);
+            put_short_code(&bc_out, op + 1, idx);
+            pos_next = cc.pos;
+            break;
+          }
+          add_pc2line_info(s, bc_out.size, line_num);
+          put_short_code(&bc_out, op, idx);
+          break;
+        }
+        goto no_change;
+
+      case OP_post_inc:
+      case OP_post_dec:
+        if (OPTIMIZE) {
+          /* transformation:
+             post_inc put_x drop -> inc put_x
+             post_inc perm3 put_field drop -> inc put_field
+             post_inc perm3 put_var_strict drop -> inc put_var_strict
+             post_inc perm4 put_array_el drop -> inc put_array_el
+           */
+          int op1, idx;
+          if (code_match(&cc, pos_next, M3(OP_put_loc, OP_put_arg, OP_put_var_ref), -1, OP_drop, -1)) {
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            op1 = cc.op;
+            idx = cc.idx;
+            pos_next = cc.pos;
+            if (code_match(&cc, cc.pos, op1 - 1, idx, -1)) {
+              if (cc.line_num >= 0) line_num = cc.line_num;
+              op1 += 1;   /* put_x(n) get_x(n) -> set_x(n) */
+              pos_next = cc.pos;
+            }
+            add_pc2line_info(s, bc_out.size, line_num);
+            dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
+            put_short_code(&bc_out, op1, idx);
+            break;
+          }
+          if (code_match(&cc, pos_next, OP_perm3, M2(OP_put_field, OP_put_var_strict), OP_drop, -1)) {
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            add_pc2line_info(s, bc_out.size, line_num);
+            dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
+            dbuf_putc(&bc_out, cc.op);
+            dbuf_put_u32(&bc_out, cc.atom);
+            pos_next = cc.pos;
+            break;
+          }
+          if (code_match(&cc, pos_next, OP_perm4, OP_put_array_el, OP_drop, -1)) {
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            add_pc2line_info(s, bc_out.size, line_num);
+            dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
+            dbuf_putc(&bc_out, OP_put_array_el);
+            pos_next = cc.pos;
+            break;
+          }
+        }
+        goto no_change;
+
+#if SHORT_OPCODES
+      case OP_typeof:
+        if (OPTIMIZE) {
+          /* simplify typeof tests */
+          if (code_match(&cc, pos_next, OP_push_atom_value, M4(OP_strict_eq, OP_strict_neq, OP_eq, OP_neq), -1)) {
+            if (cc.line_num >= 0) line_num = cc.line_num;
+            int op1 = (cc.op == OP_strict_eq || cc.op == OP_eq) ? OP_strict_eq : OP_strict_neq;
+            int op2 = -1;
+            switch (cc.atom) {
+              case JS_ATOM_undefined:
+                op2 = OP_typeof_is_undefined;
+                break;
+              case JS_ATOM_function:
+                op2 = OP_typeof_is_function;
+                break;
+            }
+            if (op2 >= 0) {
+              /* transform typeof(s) == "<type>" into is_<type> */
+              if (op1 == OP_strict_eq) {
+                add_pc2line_info(s, bc_out.size, line_num);
+                dbuf_putc(&bc_out, op2);
+                JS_FreeAtom(ctx, cc.atom);
+                pos_next = cc.pos;
+                break;
+              }
+              if (op1 == OP_strict_neq && code_match(&cc, cc.pos, OP_if_false, -1)) {
+                /* transform typeof(s) != "<type>" if_false into is_<type> if_true */
+                if (cc.line_num >= 0) line_num = cc.line_num;
+                add_pc2line_info(s, bc_out.size, line_num);
+                dbuf_putc(&bc_out, op2);
+                JS_FreeAtom(ctx, cc.atom);
+                pos_next = cc.pos;
+                label = cc.label;
+                op = OP_if_true;
+                goto has_label;
+              }
+            }
+          }
+        }
+        goto no_change;
+#endif
+
+      default:
+      no_change:
+        add_pc2line_info(s, bc_out.size, line_num);
+        dbuf_put(&bc_out, bc_buf + pos, len);
+        break;
+    }
+  }
+
+  /* check that there were no missing labels */
+  for(i = 0; i < s->label_count; i++) {
+    assert(label_slots[i].first_reloc == NULL);
+  }
+#if SHORT_OPCODES
+  if (OPTIMIZE) {
+    /* more jump optimizations */
+    int patch_offsets = 0;
+    for (i = 0, jp = s->jump_slots; i < s->jump_count; i++, jp++) {
+      LabelSlot *ls;
+      JumpSlot *jp1;
+      int j, pos, diff, delta;
+
+      delta = 3;
+      switch (op = jp->op) {
+        case OP_goto16:
+          delta = 1;
+          /* fall thru */
+        case OP_if_false:
+        case OP_if_true:
+        case OP_goto:
+          pos = jp->pos;
+          diff = s->label_slots[jp->label].addr - pos;
+          if (diff >= -128 && diff <= 127 + delta) {
+            //put_u8(bc_out.buf + pos, diff);
+            jp->size = 1;
+            if (op == OP_goto16) {
+              bc_out.buf[pos - 1] = jp->op = OP_goto8;
+            } else {
+              bc_out.buf[pos - 1] = jp->op = OP_if_false8 + (op - OP_if_false);
+            }
+            goto shrink;
+          } else
+              if (diff == (int16_t)diff && op == OP_goto) {
+            //put_u16(bc_out.buf + pos, diff);
+            jp->size = 2;
+            delta = 2;
+            bc_out.buf[pos - 1] = jp->op = OP_goto16;
+          shrink:
+            /* XXX: should reduce complexity, using 2 finger copy scheme */
+            memmove(bc_out.buf + pos + jp->size, bc_out.buf + pos + jp->size + delta,
+                    bc_out.size - pos - jp->size - delta);
+            bc_out.size -= delta;
+            patch_offsets++;
+            for (j = 0, ls = s->label_slots; j < s->label_count; j++, ls++) {
+              if (ls->addr > pos)
+                ls->addr -= delta;
+            }
+            for (j = i + 1, jp1 = jp + 1; j < s->jump_count; j++, jp1++) {
+              if (jp1->pos > pos)
+                jp1->pos -= delta;
+            }
+            for (j = 0; j < s->line_number_count; j++) {
+              if (s->line_number_slots[j].pc > pos)
+                s->line_number_slots[j].pc -= delta;
+            }
+            continue;
+          }
+          break;
+      }
+    }
+    if (patch_offsets) {
+      JumpSlot *jp1;
+      int j;
+      for (j = 0, jp1 = s->jump_slots; j < s->jump_count; j++, jp1++) {
+        int diff1 = s->label_slots[jp1->label].addr - jp1->pos;
+        switch (jp1->size) {
+          case 1:
+            put_u8(bc_out.buf + jp1->pos, diff1);
+            break;
+          case 2:
+            put_u16(bc_out.buf + jp1->pos, diff1);
+            break;
+          case 4:
+            put_u32(bc_out.buf + jp1->pos, diff1);
+            break;
+        }
+      }
+    }
+  }
+  js_free(ctx, s->jump_slots);
+  s->jump_slots = NULL;
+#endif
+  js_free(ctx, s->label_slots);
+  s->label_slots = NULL;
+  /* XXX: should delay until copying to runtime bytecode function */
+  compute_pc2line_info(s);
+  js_free(ctx, s->line_number_slots);
+  s->line_number_slots = NULL;
+  /* set the new byte code */
+  dbuf_free(&s->byte_code);
+  s->byte_code = bc_out;
+  s->use_short_opcodes = TRUE;
+  if (dbuf_error(&s->byte_code)) {
+    JS_ThrowOutOfMemory(ctx);
+    return -1;
+  }
+  return 0;
+fail:
+  /* XXX: not safe */
+  dbuf_free(&bc_out);
+  return -1;
+}
+
+/* compute the maximum stack size needed by the function */
+
+typedef struct StackSizeState {
+  int bc_len;
+  int stack_len_max;
+  uint16_t *stack_level_tab;
+  int *pc_stack;
+  int pc_stack_len;
+  int pc_stack_size;
+} StackSizeState;
+
+/* 'op' is only used for error indication */
+static __exception int ss_check(JSContext *ctx, StackSizeState *s,
+                                int pos, int op, int stack_len)
+{
+  if ((unsigned)pos >= s->bc_len) {
+    JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
+    return -1;
+  }
+  if (stack_len > s->stack_len_max) {
+    s->stack_len_max = stack_len;
+    if (s->stack_len_max > JS_STACK_SIZE_MAX) {
+      JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
+      return -1;
+    }
+  }
+  if (s->stack_level_tab[pos] != 0xffff) {
+    /* already explored: check that the stack size is consistent */
+    if (s->stack_level_tab[pos] != stack_len) {
+      JS_ThrowInternalError(ctx, "unconsistent stack size: %d %d (pc=%d)",
+                            s->stack_level_tab[pos], stack_len, pos);
+      return -1;
+    } else {
+      return 0;
+    }
+  }
+
+  /* mark as explored and store the stack size */
+  s->stack_level_tab[pos] = stack_len;
+
+  /* queue the new PC to explore */
+  if (js_resize_array(ctx, (void **)&s->pc_stack, sizeof(s->pc_stack[0]),
+                      &s->pc_stack_size, s->pc_stack_len + 1))
+    return -1;
+  s->pc_stack[s->pc_stack_len++] = pos;
+  return 0;
+}
+
+static __exception int compute_stack_size(JSContext *ctx,
+                                          JSFunctionDef *fd,
+                                          int *pstack_size)
+{
+  StackSizeState s_s, *s = &s_s;
+  int i, diff, n_pop, pos_next, stack_len, pos, op;
+  const JSOpCode *oi;
+  const uint8_t *bc_buf;
+
+  bc_buf = fd->byte_code.buf;
+  s->bc_len = fd->byte_code.size;
+  /* bc_len > 0 */
+  s->stack_level_tab = js_malloc(ctx, sizeof(s->stack_level_tab[0]) *
+                                          s->bc_len);
+  if (!s->stack_level_tab)
+    return -1;
+  for(i = 0; i < s->bc_len; i++)
+    s->stack_level_tab[i] = 0xffff;
+  s->stack_len_max = 0;
+  s->pc_stack = NULL;
+  s->pc_stack_len = 0;
+  s->pc_stack_size = 0;
+
+  /* breadth-first graph exploration */
+  if (ss_check(ctx, s, 0, OP_invalid, 0))
+    goto fail;
+
+  while (s->pc_stack_len > 0) {
+    pos = s->pc_stack[--s->pc_stack_len];
+    stack_len = s->stack_level_tab[pos];
+    op = bc_buf[pos];
+    if (op == 0 || op >= OP_COUNT) {
+      JS_ThrowInternalError(ctx, "invalid opcode (op=%d, pc=%d)", op, pos);
+      goto fail;
+    }
+    oi = &short_opcode_info(op);
+    pos_next = pos + oi->size;
+    if (pos_next > s->bc_len) {
+      JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
+      goto fail;
+    }
+    n_pop = oi->n_pop;
+    /* call pops a variable number of arguments */
+    if (oi->fmt == OP_FMT_npop || oi->fmt == OP_FMT_npop_u16) {
+      n_pop += get_u16(bc_buf + pos + 1);
+    } else {
+#if SHORT_OPCODES
+      if (oi->fmt == OP_FMT_npopx) {
+        n_pop += op - OP_call0;
+      }
+#endif
+    }
+
+    if (stack_len < n_pop) {
+      JS_ThrowInternalError(ctx, "stack underflow (op=%d, pc=%d)", op, pos);
+      goto fail;
+    }
+    stack_len += oi->n_push - n_pop;
+    if (stack_len > s->stack_len_max) {
+      s->stack_len_max = stack_len;
+      if (s->stack_len_max > JS_STACK_SIZE_MAX) {
+        JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
+        goto fail;
+      }
+    }
+    switch(op) {
+      case OP_tail_call:
+      case OP_tail_call_method:
+      case OP_return:
+      case OP_return_undef:
+      case OP_return_async:
+      case OP_throw:
+      case OP_throw_error:
+      case OP_ret:
+        goto done_insn;
+      case OP_goto:
+        diff = get_u32(bc_buf + pos + 1);
+        pos_next = pos + 1 + diff;
+        break;
+#if SHORT_OPCODES
+      case OP_goto16:
+        diff = (int16_t)get_u16(bc_buf + pos + 1);
+        pos_next = pos + 1 + diff;
+        break;
+      case OP_goto8:
+        diff = (int8_t)bc_buf[pos + 1];
+        pos_next = pos + 1 + diff;
+        break;
+      case OP_if_true8:
+      case OP_if_false8:
+        diff = (int8_t)bc_buf[pos + 1];
+        if (ss_check(ctx, s, pos + 1 + diff, op, stack_len))
+          goto fail;
+        break;
+#endif
+      case OP_if_true:
+      case OP_if_false:
+      case OP_catch:
+        diff = get_u32(bc_buf + pos + 1);
+        if (ss_check(ctx, s, pos + 1 + diff, op, stack_len))
+          goto fail;
+        break;
+      case OP_gosub:
+        diff = get_u32(bc_buf + pos + 1);
+        if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1))
+          goto fail;
+        break;
+      case OP_with_get_var:
+      case OP_with_delete_var:
+        diff = get_u32(bc_buf + pos + 5);
+        if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1))
+          goto fail;
+        break;
+      case OP_with_make_ref:
+      case OP_with_get_ref:
+      case OP_with_get_ref_undef:
+        diff = get_u32(bc_buf + pos + 5);
+        if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2))
+          goto fail;
+        break;
+      case OP_with_put_var:
+        diff = get_u32(bc_buf + pos + 5);
+        if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1))
+          goto fail;
+        break;
+
+      default:
+        break;
+    }
+    if (ss_check(ctx, s, pos_next, op, stack_len))
+      goto fail;
+  done_insn: ;
+  }
+  js_free(ctx, s->stack_level_tab);
+  js_free(ctx, s->pc_stack);
+  *pstack_size = s->stack_len_max;
+  return 0;
+fail:
+  js_free(ctx, s->stack_level_tab);
+  js_free(ctx, s->pc_stack);
+  *pstack_size = 0;
+  return -1;
+}
+
+static int add_module_variables(JSContext *ctx, JSFunctionDef *fd)
+{
+  int i, idx;
+  JSModuleDef *m = fd->module;
+  JSExportEntry *me;
+  JSGlobalVar *hf;
+
+  /* The imported global variables were added as closure variables
+     in js_parse_import(). We add here the module global
+     variables. */
+
+  for(i = 0; i < fd->global_var_count; i++) {
+    hf = &fd->global_vars[i];
+    if (add_closure_var(ctx, fd, TRUE, FALSE, i, hf->var_name, hf->is_const,
+                        hf->is_lexical, FALSE) < 0)
+      return -1;
+  }
+
+  /* resolve the variable names of the local exports */
+  for(i = 0; i < m->export_entries_count; i++) {
+    me = &m->export_entries[i];
+    if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
+      idx = find_closure_var(ctx, fd, me->local_name);
+      if (idx < 0) {
+        JS_ThrowSyntaxErrorAtom(ctx, "exported variable '%s' does not exist",
+                                me->local_name);
+        return -1;
+      }
+      me->u.local.var_idx = idx;
+    }
+  }
+  return 0;
+}
+
+/* create a function object from a function definition. The function
+   definition is freed. All the child functions are also created. It
+   must be done this way to resolve all the variables. */
+static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
+{
+  JSValue func_obj;
+  JSFunctionBytecode *b;
+  struct list_head *el, *el1;
+  int stack_size, scope, idx;
+  int function_size, byte_code_offset, cpool_offset;
+  int closure_var_offset, vardefs_offset;
+
+  /* recompute scope linkage */
+  for (scope = 0; scope < fd->scope_count; scope++) {
+    fd->scopes[scope].first = -1;
+  }
+  if (fd->has_parameter_expressions) {
+    /* special end of variable list marker for the argument scope */
+    fd->scopes[ARG_SCOPE_INDEX].first = ARG_SCOPE_END;
+  }
+  for (idx = 0; idx < fd->var_count; idx++) {
+    JSVarDef *vd = &fd->vars[idx];
+    vd->scope_next = fd->scopes[vd->scope_level].first;
+    fd->scopes[vd->scope_level].first = idx;
+  }
+  for (scope = 2; scope < fd->scope_count; scope++) {
+    JSVarScope *sd = &fd->scopes[scope];
+    if (sd->first < 0)
+      sd->first = fd->scopes[sd->parent].first;
+  }
+  for (idx = 0; idx < fd->var_count; idx++) {
+    JSVarDef *vd = &fd->vars[idx];
+    if (vd->scope_next < 0 && vd->scope_level > 1) {
+      scope = fd->scopes[vd->scope_level].parent;
+      vd->scope_next = fd->scopes[scope].first;
+    }
+  }
+
+  /* if the function contains an eval call, the closure variables
+     are used to compile the eval and they must be ordered by scope,
+     so it is necessary to create the closure variables before any
+     other variable lookup is done. */
+  if (fd->has_eval_call)
+    add_eval_variables(ctx, fd);
+
+  /* add the module global variables in the closure */
+  if (fd->module) {
+    if (add_module_variables(ctx, fd))
+      goto fail;
+  }
+
+  /* first create all the child functions */
+  list_for_each_safe(el, el1, &fd->child_list) {
+    JSFunctionDef *fd1;
+    int cpool_idx;
+
+    fd1 = list_entry(el, JSFunctionDef, link);
+    cpool_idx = fd1->parent_cpool_idx;
+    func_obj = js_create_function(ctx, fd1);
+    if (JS_IsException(func_obj))
+      goto fail;
+    /* save it in the constant pool */
+    assert(cpool_idx >= 0);
+    fd->cpool[cpool_idx] = func_obj;
+  }
+
+#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 4)
+  if (!(fd->js_mode & JS_MODE_STRIP)) {
+    printf("pass 1\n");
+    dump_byte_code(ctx, 1, fd->byte_code.buf, fd->byte_code.size,
+                   fd->args, fd->arg_count, fd->vars, fd->var_count,
+                   fd->closure_var, fd->closure_var_count,
+                   fd->cpool, fd->cpool_count, fd->source, fd->line_num,
+                   fd->label_slots, NULL);
+    printf("\n");
+  }
+#endif
+
+  if (resolve_variables(ctx, fd))
+    goto fail;
+
+#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 2)
+  if (!(fd->js_mode & JS_MODE_STRIP)) {
+    printf("pass 2\n");
+    dump_byte_code(ctx, 2, fd->byte_code.buf, fd->byte_code.size,
+                   fd->args, fd->arg_count, fd->vars, fd->var_count,
+                   fd->closure_var, fd->closure_var_count,
+                   fd->cpool, fd->cpool_count, fd->source, fd->line_num,
+                   fd->label_slots, NULL);
+    printf("\n");
+  }
+#endif
+
+  if (resolve_labels(ctx, fd))
+    goto fail;
+
+  if (compute_stack_size(ctx, fd, &stack_size) < 0)
+    goto fail;
+
+  if (fd->js_mode & JS_MODE_STRIP) {
+    function_size = offsetof(JSFunctionBytecode, debug);
+  } else {
+    function_size = sizeof(*b);
+  }
+  cpool_offset = function_size;
+  function_size += fd->cpool_count * sizeof(*fd->cpool);
+  vardefs_offset = function_size;
+  if (!(fd->js_mode & JS_MODE_STRIP) || fd->has_eval_call) {
+    function_size += (fd->arg_count + fd->var_count) * sizeof(*b->vardefs);
+  }
+  closure_var_offset = function_size;
+  function_size += fd->closure_var_count * sizeof(*fd->closure_var);
+  byte_code_offset = function_size;
+  function_size += fd->byte_code.size;
+
+  b = js_mallocz(ctx, function_size);
+  if (!b)
+    goto fail;
+  b->header.ref_count = 1;
+
+  b->byte_code_buf = (void *)((uint8_t*)b + byte_code_offset);
+  b->byte_code_len = fd->byte_code.size;
+  memcpy(b->byte_code_buf, fd->byte_code.buf, fd->byte_code.size);
+  js_free(ctx, fd->byte_code.buf);
+  fd->byte_code.buf = NULL;
+
+  b->func_name = fd->func_name;
+  if (fd->arg_count + fd->var_count > 0) {
+    if ((fd->js_mode & JS_MODE_STRIP) && !fd->has_eval_call) {
+      /* Strip variable definitions not needed at runtime */
+      int i;
+      for(i = 0; i < fd->var_count; i++) {
+        JS_FreeAtom(ctx, fd->vars[i].var_name);
+      }
+      for(i = 0; i < fd->arg_count; i++) {
+        JS_FreeAtom(ctx, fd->args[i].var_name);
+      }
+      for(i = 0; i < fd->closure_var_count; i++) {
+        JS_FreeAtom(ctx, fd->closure_var[i].var_name);
+        fd->closure_var[i].var_name = JS_ATOM_NULL;
+      }
+    } else {
+      b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
+      memcpy(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0]));
+      memcpy(b->vardefs + fd->arg_count, fd->vars, fd->var_count * sizeof(fd->vars[0]));
+    }
+    b->var_count = fd->var_count;
+    b->arg_count = fd->arg_count;
+    b->defined_arg_count = fd->defined_arg_count;
+    js_free(ctx, fd->args);
+    js_free(ctx, fd->vars);
+  }
+  b->cpool_count = fd->cpool_count;
+  if (b->cpool_count) {
+    b->cpool = (void *)((uint8_t*)b + cpool_offset);
+    memcpy(b->cpool, fd->cpool, b->cpool_count * sizeof(*b->cpool));
+  }
+  js_free(ctx, fd->cpool);
+  fd->cpool = NULL;
+
+  b->stack_size = stack_size;
+
+  if (fd->js_mode & JS_MODE_STRIP) {
+    JS_FreeAtom(ctx, fd->filename);
+    dbuf_free(&fd->pc2line);    // probably useless
+  } else {
+    /* XXX: source and pc2line info should be packed at the end of the
+       JSFunctionBytecode structure, avoiding allocation overhead
+     */
+    b->has_debug = 1;
+    b->debug.filename = fd->filename;
+    b->debug.line_num = fd->line_num;
+
+    //DynBuf pc2line;
+    //compute_pc2line_info(fd, &pc2line);
+    //js_free(ctx, fd->line_number_slots)
+    b->debug.pc2line_buf = js_realloc(ctx, fd->pc2line.buf, fd->pc2line.size);
+    if (!b->debug.pc2line_buf)
+      b->debug.pc2line_buf = fd->pc2line.buf;
+    b->debug.pc2line_len = fd->pc2line.size;
+    b->debug.source = fd->source;
+    b->debug.source_len = fd->source_len;
+  }
+  if (fd->scopes != fd->def_scope_array)
+    js_free(ctx, fd->scopes);
+
+  b->closure_var_count = fd->closure_var_count;
+  if (b->closure_var_count) {
+    b->closure_var = (void *)((uint8_t*)b + closure_var_offset);
+    memcpy(b->closure_var, fd->closure_var, b->closure_var_count * sizeof(*b->closure_var));
+  }
+  js_free(ctx, fd->closure_var);
+  fd->closure_var = NULL;
+
+  b->has_prototype = fd->has_prototype;
+  b->has_simple_parameter_list = fd->has_simple_parameter_list;
+  b->js_mode = fd->js_mode;
+  b->is_derived_class_constructor = fd->is_derived_class_constructor;
+  b->func_kind = fd->func_kind;
+  b->need_home_object = (fd->home_object_var_idx >= 0 ||
+                         fd->need_home_object);
+  b->new_target_allowed = fd->new_target_allowed;
+  b->super_call_allowed = fd->super_call_allowed;
+  b->super_allowed = fd->super_allowed;
+  b->arguments_allowed = fd->arguments_allowed;
+  b->backtrace_barrier = fd->backtrace_barrier;
+  b->realm = JS_DupContext(ctx);
+
+  add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
+
+#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 1)
+  if (!(fd->js_mode & JS_MODE_STRIP)) {
+    js_dump_function_bytecode(ctx, b);
+  }
+#endif
+
+  if (fd->parent) {
+    /* remove from parent list */
+    list_del(&fd->link);
+  }
+
+  js_free(ctx, fd);
+  return JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);
+fail:
+  js_free_function_def(ctx, fd);
+  return JS_EXCEPTION;
+}
+
+static __exception int js_parse_directives(JSParseState *s)
+{
+  char str[20];
+  JSParsePos pos;
+  BOOL has_semi;
+
+  if (s->token.val != TOK_STRING)
+    return 0;
+
+  js_parse_get_pos(s, &pos);
+
+  while(s->token.val == TOK_STRING) {
+    /* Copy actual source string representation */
+    snprintf(str, sizeof str, "%.*s",
+             (int)(s->buf_ptr - s->token.ptr - 2), s->token.ptr + 1);
+
+    if (next_token(s))
+      return -1;
+
+    has_semi = FALSE;
+    switch (s->token.val) {
+      case ';':
+        if (next_token(s))
+          return -1;
+        has_semi = TRUE;
+        break;
+      case '}':
+      case TOK_EOF:
+        has_semi = TRUE;
+        break;
+      case TOK_NUMBER:
+      case TOK_STRING:
+      case TOK_TEMPLATE:
+      case TOK_IDENT:
+      case TOK_REGEXP:
+      case TOK_DEC:
+      case TOK_INC:
+      case TOK_NULL:
+      case TOK_FALSE:
+      case TOK_TRUE:
+      case TOK_IF:
+      case TOK_RETURN:
+      case TOK_VAR:
+      case TOK_THIS:
+      case TOK_DELETE:
+      case TOK_TYPEOF:
+      case TOK_NEW:
+      case TOK_DO:
+      case TOK_WHILE:
+      case TOK_FOR:
+      case TOK_SWITCH:
+      case TOK_THROW:
+      case TOK_TRY:
+      case TOK_FUNCTION:
+      case TOK_DEBUGGER:
+      case TOK_WITH:
+      case TOK_CLASS:
+      case TOK_CONST:
+      case TOK_ENUM:
+      case TOK_EXPORT:
+      case TOK_IMPORT:
+      case TOK_SUPER:
+      case TOK_INTERFACE:
+      case TOK_LET:
+      case TOK_PACKAGE:
+      case TOK_PRIVATE:
+      case TOK_PROTECTED:
+      case TOK_PUBLIC:
+      case TOK_STATIC:
+        /* automatic insertion of ';' */
+        if (s->got_lf)
+          has_semi = TRUE;
+        break;
+      default:
+        break;
+    }
+    if (!has_semi)
+      break;
+    if (!strcmp(str, "use strict")) {
+      s->cur_func->has_use_strict = TRUE;
+      s->cur_func->js_mode |= JS_MODE_STRICT;
+    }
+#if !defined(DUMP_BYTECODE) || !(DUMP_BYTECODE & 8)
+    else if (!strcmp(str, "use strip")) {
+      s->cur_func->js_mode |= JS_MODE_STRIP;
+    }
+#endif
+#ifdef CONFIG_BIGNUM
+    else if (s->ctx->bignum_ext && !strcmp(str, "use math")) {
+      s->cur_func->js_mode |= JS_MODE_MATH;
+    }
+#endif
+  }
+  return js_parse_seek_token(s, &pos);
+}
+
+static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd,
+                                         JSAtom func_name)
+{
+  JSAtom name;
+  int i, idx;
+
+  if (fd->js_mode & JS_MODE_STRICT) {
+    if (!fd->has_simple_parameter_list && fd->has_use_strict) {
+      return js_parse_error(s, "\"use strict\" not allowed in function with default or destructuring parameter");
+    }
+    if (func_name == JS_ATOM_eval || func_name == JS_ATOM_arguments) {
+      return js_parse_error(s, "invalid function name in strict code");
+    }
+    for (idx = 0; idx < fd->arg_count; idx++) {
+      name = fd->args[idx].var_name;
+
+      if (name == JS_ATOM_eval || name == JS_ATOM_arguments) {
+        return js_parse_error(s, "invalid argument name in strict code");
+      }
+    }
+  }
+  /* check async_generator case */
+  if ((fd->js_mode & JS_MODE_STRICT)
+      ||  !fd->has_simple_parameter_list
+      ||  (fd->func_type == JS_PARSE_FUNC_METHOD && fd->func_kind == JS_FUNC_ASYNC)
+      ||  fd->func_type == JS_PARSE_FUNC_ARROW
+      ||  fd->func_type == JS_PARSE_FUNC_METHOD) {
+    for (idx = 0; idx < fd->arg_count; idx++) {
+      name = fd->args[idx].var_name;
+      if (name != JS_ATOM_NULL) {
+        for (i = 0; i < idx; i++) {
+          if (fd->args[i].var_name == name)
+            goto duplicate;
+        }
+        /* Check if argument name duplicates a destructuring parameter */
+        /* XXX: should have a flag for such variables */
+        for (i = 0; i < fd->var_count; i++) {
+          if (fd->vars[i].var_name == name &&
+              fd->vars[i].scope_level == 0)
+            goto duplicate;
+        }
+      }
+    }
+  }
+  return 0;
+
+duplicate:
+  return js_parse_error(s, "duplicate argument names not allowed in this context");
+}
+
+/* create a function to initialize class fields */
+static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s)
+{
+  JSFunctionDef *fd;
+
+  fd = js_new_function_def(s->ctx, s->cur_func, FALSE, FALSE,
+                           s->filename, 0);
+  if (!fd)
+    return NULL;
+  fd->func_name = JS_ATOM_NULL;
+  fd->has_prototype = FALSE;
+  fd->has_home_object = TRUE;
+
+  fd->has_arguments_binding = FALSE;
+  fd->has_this_binding = TRUE;
+  fd->is_derived_class_constructor = FALSE;
+  fd->new_target_allowed = TRUE;
+  fd->super_call_allowed = FALSE;
+  fd->super_allowed = fd->has_home_object;
+  fd->arguments_allowed = FALSE;
+
+  fd->func_kind = JS_FUNC_NORMAL;
+  fd->func_type = JS_PARSE_FUNC_METHOD;
+  return fd;
+}
+
+/* func_name must be JS_ATOM_NULL for JS_PARSE_FUNC_STATEMENT and
+   JS_PARSE_FUNC_EXPR, JS_PARSE_FUNC_ARROW and JS_PARSE_FUNC_VAR */
+static __exception int js_parse_function_decl2(JSParseState *s,
+                                               JSParseFunctionEnum func_type,
+                                               JSFunctionKindEnum func_kind,
+                                               JSAtom func_name,
+                                               const uint8_t *ptr,
+                                               int function_line_num,
+                                               JSParseExportEnum export_flag,
+                                               JSFunctionDef **pfd)
+{
+  JSContext *ctx = s->ctx;
+  JSFunctionDef *fd = s->cur_func;
+  BOOL is_expr;
+  int func_idx, lexical_func_idx = -1;
+  BOOL has_opt_arg;
+  BOOL create_func_var = FALSE;
+
+  is_expr = (func_type != JS_PARSE_FUNC_STATEMENT &&
+             func_type != JS_PARSE_FUNC_VAR);
+
+  if (func_type == JS_PARSE_FUNC_STATEMENT ||
+      func_type == JS_PARSE_FUNC_VAR ||
+      func_type == JS_PARSE_FUNC_EXPR) {
+    if (func_kind == JS_FUNC_NORMAL &&
+        token_is_pseudo_keyword(s, JS_ATOM_async) &&
+        peek_token(s, TRUE) != '\n') {
+      if (next_token(s))
+        return -1;
+      func_kind = JS_FUNC_ASYNC;
+    }
+    if (next_token(s))
+      return -1;
+    if (s->token.val == '*') {
+      if (next_token(s))
+        return -1;
+      func_kind |= JS_FUNC_GENERATOR;
+    }
+
+    if (s->token.val == TOK_IDENT) {
+      if (s->token.u.ident.is_reserved ||
+          (s->token.u.ident.atom == JS_ATOM_yield &&
+           func_type == JS_PARSE_FUNC_EXPR &&
+           (func_kind & JS_FUNC_GENERATOR)) ||
+          (s->token.u.ident.atom == JS_ATOM_await &&
+           func_type == JS_PARSE_FUNC_EXPR &&
+           (func_kind & JS_FUNC_ASYNC))) {
+        return js_parse_error_reserved_identifier(s);
+      }
+    }
+    if (s->token.val == TOK_IDENT ||
+        (((s->token.val == TOK_YIELD && !(fd->js_mode & JS_MODE_STRICT)) ||
+          (s->token.val == TOK_AWAIT && !s->is_module)) &&
+         func_type == JS_PARSE_FUNC_EXPR)) {
+      func_name = JS_DupAtom(ctx, s->token.u.ident.atom);
+      if (next_token(s)) {
+        JS_FreeAtom(ctx, func_name);
+        return -1;
+      }
+    } else {
+      if (func_type != JS_PARSE_FUNC_EXPR &&
+          export_flag != JS_PARSE_EXPORT_DEFAULT) {
+        return js_parse_error(s, "function name expected");
+      }
+    }
+  } else if (func_type != JS_PARSE_FUNC_ARROW) {
+    func_name = JS_DupAtom(ctx, func_name);
+  }
+
+  if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_MODULE &&
+      (func_type == JS_PARSE_FUNC_STATEMENT || func_type == JS_PARSE_FUNC_VAR)) {
+    JSGlobalVar *hf;
+    hf = find_global_var(fd, func_name);
+    /* XXX: should check scope chain */
+    if (hf && hf->scope_level == fd->scope_level) {
+      js_parse_error(s, "invalid redefinition of global identifier in module code");
+      JS_FreeAtom(ctx, func_name);
+      return -1;
+    }
+  }
+
+  if (func_type == JS_PARSE_FUNC_VAR) {
+    if (!(fd->js_mode & JS_MODE_STRICT)
+        && func_kind == JS_FUNC_NORMAL
+        &&  find_lexical_decl(ctx, fd, func_name, fd->scope_first, FALSE) < 0
+        &&  !((func_idx = find_var(ctx, fd, func_name)) >= 0 && (func_idx & ARGUMENT_VAR_OFFSET))
+        &&  !(func_name == JS_ATOM_arguments && fd->has_arguments_binding)) {
+      create_func_var = TRUE;
+    }
+    /* Create the lexical name here so that the function closure
+       contains it */
+    if (fd->is_eval &&
+        (fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
+         fd->eval_type == JS_EVAL_TYPE_MODULE) &&
+        fd->scope_level == fd->body_scope) {
+      /* avoid creating a lexical variable in the global
+         scope. XXX: check annex B */
+      JSGlobalVar *hf;
+      hf = find_global_var(fd, func_name);
+      /* XXX: should check scope chain */
+      if (hf && hf->scope_level == fd->scope_level) {
+        js_parse_error(s, "invalid redefinition of global identifier");
+        JS_FreeAtom(ctx, func_name);
+        return -1;
+      }
+    } else {
+      /* Always create a lexical name, fail if at the same scope as
+         existing name */
+      /* Lexical variable will be initialized upon entering scope */
+      lexical_func_idx = define_var(s, fd, func_name,
+                                    func_kind != JS_FUNC_NORMAL ?
+                                                                JS_VAR_DEF_NEW_FUNCTION_DECL :
+                                                                JS_VAR_DEF_FUNCTION_DECL);
+      if (lexical_func_idx < 0) {
+        JS_FreeAtom(ctx, func_name);
+        return -1;
+      }
+    }
+  }
+
+  fd = js_new_function_def(ctx, fd, FALSE, is_expr,
+                           s->filename, function_line_num);
+  if (!fd) {
+    JS_FreeAtom(ctx, func_name);
+    return -1;
+  }
+  if (pfd)
+    *pfd = fd;
+  s->cur_func = fd;
+  fd->func_name = func_name;
+  /* XXX: test !fd->is_generator is always false */
+  fd->has_prototype = (func_type == JS_PARSE_FUNC_STATEMENT ||
+                       func_type == JS_PARSE_FUNC_VAR ||
+                       func_type == JS_PARSE_FUNC_EXPR) &&
+                      func_kind == JS_FUNC_NORMAL;
+  fd->has_home_object = (func_type == JS_PARSE_FUNC_METHOD ||
+                         func_type == JS_PARSE_FUNC_GETTER ||
+                         func_type == JS_PARSE_FUNC_SETTER ||
+                         func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR ||
+                         func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);
+  fd->has_arguments_binding = (func_type != JS_PARSE_FUNC_ARROW);
+  fd->has_this_binding = fd->has_arguments_binding;
+  fd->is_derived_class_constructor = (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);
+  if (func_type == JS_PARSE_FUNC_ARROW) {
+    fd->new_target_allowed = fd->parent->new_target_allowed;
+    fd->super_call_allowed = fd->parent->super_call_allowed;
+    fd->super_allowed = fd->parent->super_allowed;
+    fd->arguments_allowed = fd->parent->arguments_allowed;
+  } else {
+    fd->new_target_allowed = TRUE;
+    fd->super_call_allowed = fd->is_derived_class_constructor;
+    fd->super_allowed = fd->has_home_object;
+    fd->arguments_allowed = TRUE;
+  }
+
+  /* fd->in_function_body == FALSE prevents yield/await during the parsing
+     of the arguments in generator/async functions. They are parsed as
+     regular identifiers for other function kinds. */
+  fd->func_kind = func_kind;
+  fd->func_type = func_type;
+
+  if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR ||
+      func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR) {
+    /* error if not invoked as a constructor */
+    emit_op(s, OP_check_ctor);
+  }
+
+  if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) {
+    emit_class_field_init(s);
+  }
+
+  /* parse arguments */
+  fd->has_simple_parameter_list = TRUE;
+  fd->has_parameter_expressions = FALSE;
+  has_opt_arg = FALSE;
+  if (func_type == JS_PARSE_FUNC_ARROW && s->token.val == TOK_IDENT) {
+    JSAtom name;
+    if (s->token.u.ident.is_reserved) {
+      js_parse_error_reserved_identifier(s);
+      goto fail;
+    }
+    name = s->token.u.ident.atom;
+    if (add_arg(ctx, fd, name) < 0)
+      goto fail;
+    fd->defined_arg_count = 1;
+  } else {
+    if (s->token.val == '(') {
+      int skip_bits;
+      /* if there is an '=' inside the parameter list, we
+         consider there is a parameter expression inside */
+      js_parse_skip_parens_token(s, &skip_bits, FALSE);
+      if (skip_bits & SKIP_HAS_ASSIGNMENT)
+        fd->has_parameter_expressions = TRUE;
+      if (next_token(s))
+        goto fail;
+    } else {
+      if (js_parse_expect(s, '('))
+        goto fail;
+    }
+
+    if (fd->has_parameter_expressions) {
+      fd->scope_level = -1; /* force no parent scope */
+      if (push_scope(s) < 0)
+        return -1;
+    }
+
+    while (s->token.val != ')') {
+      JSAtom name;
+      BOOL rest = FALSE;
+      int idx, has_initializer;
+
+      if (s->token.val == TOK_ELLIPSIS) {
+        fd->has_simple_parameter_list = FALSE;
+        rest = TRUE;
+        if (next_token(s))
+          goto fail;
+      }
+      if (s->token.val == '[' || s->token.val == '{') {
+        fd->has_simple_parameter_list = FALSE;
+        if (rest) {
+          emit_op(s, OP_rest);
+          emit_u16(s, fd->arg_count);
+        } else {
+          /* unnamed arg for destructuring */
+          idx = add_arg(ctx, fd, JS_ATOM_NULL);
+          emit_op(s, OP_get_arg);
+          emit_u16(s, idx);
+        }
+        has_initializer = js_parse_destructuring_element(s, fd->has_parameter_expressions ? TOK_LET : TOK_VAR, 1, TRUE, -1, TRUE);
+        if (has_initializer < 0)
+          goto fail;
+        if (has_initializer)
+          has_opt_arg = TRUE;
+        if (!has_opt_arg)
+          fd->defined_arg_count++;
+      } else if (s->token.val == TOK_IDENT) {
+        if (s->token.u.ident.is_reserved) {
+          js_parse_error_reserved_identifier(s);
+          goto fail;
+        }
+        name = s->token.u.ident.atom;
+        if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) {
+          js_parse_error_reserved_identifier(s);
+          goto fail;
+        }
+        if (fd->has_parameter_expressions) {
+          if (define_var(s, fd, name, JS_VAR_DEF_LET) < 0)
+            goto fail;
+        }
+        /* XXX: could avoid allocating an argument if rest is true */
+        idx = add_arg(ctx, fd, name);
+        if (idx < 0)
+          goto fail;
+        if (next_token(s))
+          goto fail;
+        if (rest) {
+          emit_op(s, OP_rest);
+          emit_u16(s, idx);
+          if (fd->has_parameter_expressions) {
+            emit_op(s, OP_dup);
+            emit_op(s, OP_scope_put_var_init);
+            emit_atom(s, name);
+            emit_u16(s, fd->scope_level);
+          }
+          emit_op(s, OP_put_arg);
+          emit_u16(s, idx);
+          fd->has_simple_parameter_list = FALSE;
+          has_opt_arg = TRUE;
+        } else if (s->token.val == '=') {
+          int label;
+
+          fd->has_simple_parameter_list = FALSE;
+          has_opt_arg = TRUE;
+
+          if (next_token(s))
+            goto fail;
+
+          label = new_label(s);
+          emit_op(s, OP_get_arg);
+          emit_u16(s, idx);
+          emit_op(s, OP_dup);
+          emit_op(s, OP_undefined);
+          emit_op(s, OP_strict_eq);
+          emit_goto(s, OP_if_false, label);
+          emit_op(s, OP_drop);
+          if (js_parse_assign_expr(s))
+            goto fail;
+          set_object_name(s, name);
+          emit_op(s, OP_dup);
+          emit_op(s, OP_put_arg);
+          emit_u16(s, idx);
+          emit_label(s, label);
+          emit_op(s, OP_scope_put_var_init);
+          emit_atom(s, name);
+          emit_u16(s, fd->scope_level);
+        } else {
+          if (!has_opt_arg) {
+            fd->defined_arg_count++;
+          }
+          if (fd->has_parameter_expressions) {
+            /* copy the argument to the argument scope */
+            emit_op(s, OP_get_arg);
+            emit_u16(s, idx);
+            emit_op(s, OP_scope_put_var_init);
+            emit_atom(s, name);
+            emit_u16(s, fd->scope_level);
+          }
+        }
+      } else {
+        js_parse_error(s, "missing formal parameter");
+        goto fail;
+      }
+      if (rest && s->token.val != ')') {
+        js_parse_expect(s, ')');
+        goto fail;
+      }
+      if (s->token.val == ')')
+        break;
+      if (js_parse_expect(s, ','))
+        goto fail;
+    }
+    if ((func_type == JS_PARSE_FUNC_GETTER && fd->arg_count != 0) ||
+        (func_type == JS_PARSE_FUNC_SETTER && fd->arg_count != 1)) {
+      js_parse_error(s, "invalid number of arguments for getter or setter");
+      goto fail;
+    }
+  }
+
+  if (fd->has_parameter_expressions) {
+    int idx;
+
+    /* Copy the variables in the argument scope to the variable
+       scope (see FunctionDeclarationInstantiation() in spec). The
+       normal arguments are already present, so no need to copy
+       them. */
+    idx = fd->scopes[fd->scope_level].first;
+    while (idx >= 0) {
+      JSVarDef *vd = &fd->vars[idx];
+      if (vd->scope_level != fd->scope_level)
+        break;
+      if (find_var(ctx, fd, vd->var_name) < 0) {
+        if (add_var(ctx, fd, vd->var_name) < 0)
+          goto fail;
+        vd = &fd->vars[idx]; /* fd->vars may have been reallocated */
+        emit_op(s, OP_scope_get_var);
+        emit_atom(s, vd->var_name);
+        emit_u16(s, fd->scope_level);
+        emit_op(s, OP_scope_put_var);
+        emit_atom(s, vd->var_name);
+        emit_u16(s, 0);
+      }
+      idx = vd->scope_next;
+    }
+
+    /* the argument scope has no parent, hence we don't use pop_scope(s) */
+    emit_op(s, OP_leave_scope);
+    emit_u16(s, fd->scope_level);
+
+    /* set the variable scope as the current scope */
+    fd->scope_level = 0;
+    fd->scope_first = fd->scopes[fd->scope_level].first;
+  }
+
+  if (next_token(s))
+    goto fail;
+
+  /* generator function: yield after the parameters are evaluated */
+  if (func_kind == JS_FUNC_GENERATOR ||
+      func_kind == JS_FUNC_ASYNC_GENERATOR)
+    emit_op(s, OP_initial_yield);
+
+  /* in generators, yield expression is forbidden during the parsing
+     of the arguments */
+  fd->in_function_body = TRUE;
+  push_scope(s);  /* enter body scope */
+  fd->body_scope = fd->scope_level;
+
+  if (s->token.val == TOK_ARROW) {
+    if (next_token(s))
+      goto fail;
+
+    if (s->token.val != '{') {
+      if (js_parse_function_check_names(s, fd, func_name))
+        goto fail;
+
+      if (js_parse_assign_expr(s))
+        goto fail;
+
+      if (func_kind != JS_FUNC_NORMAL)
+        emit_op(s, OP_return_async);
+      else
+        emit_op(s, OP_return);
+
+      if (!(fd->js_mode & JS_MODE_STRIP)) {
+        /* save the function source code */
+        /* the end of the function source code is after the last
+           token of the function source stored into s->last_ptr */
+        fd->source_len = s->last_ptr - ptr;
+        fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len);
+        if (!fd->source)
+          goto fail;
+      }
+      goto done;
+    }
+  }
+
+  if (js_parse_expect(s, '{'))
+    goto fail;
+
+  if (js_parse_directives(s))
+    goto fail;
+
+  /* in strict_mode, check function and argument names */
+  if (js_parse_function_check_names(s, fd, func_name))
+    goto fail;
+
+  while (s->token.val != '}') {
+    if (js_parse_source_element(s))
+      goto fail;
+  }
+  if (!(fd->js_mode & JS_MODE_STRIP)) {
+    /* save the function source code */
+    fd->source_len = s->buf_ptr - ptr;
+    fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len);
+    if (!fd->source)
+      goto fail;
+  }
+
+  if (next_token(s)) {
+    /* consume the '}' */
+    goto fail;
+  }
+
+  /* in case there is no return, add one */
+  if (js_is_live_code(s)) {
+    emit_return(s, FALSE);
+  }
+done:
+  s->cur_func = fd->parent;
+
+  /* create the function object */
+  {
+    int idx;
+    JSAtom func_name = fd->func_name;
+
+    /* the real object will be set at the end of the compilation */
+    idx = cpool_add(s, JS_NULL);
+    fd->parent_cpool_idx = idx;
+
+    if (is_expr) {
+      /* for constructors, no code needs to be generated here */
+      if (func_type != JS_PARSE_FUNC_CLASS_CONSTRUCTOR &&
+          func_type != JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR) {
+        /* OP_fclosure creates the function object from the bytecode
+           and adds the scope information */
+        emit_op(s, OP_fclosure);
+        emit_u32(s, idx);
+        if (func_name == JS_ATOM_NULL) {
+          emit_op(s, OP_set_name);
+          emit_u32(s, JS_ATOM_NULL);
+        }
+      }
+    } else if (func_type == JS_PARSE_FUNC_VAR) {
+      emit_op(s, OP_fclosure);
+      emit_u32(s, idx);
+      if (create_func_var) {
+        if (s->cur_func->is_global_var) {
+          JSGlobalVar *hf;
+          /* the global variable must be defined at the start of the
+             function */
+          hf = add_global_var(ctx, s->cur_func, func_name);
+          if (!hf)
+            goto fail;
+          /* it is considered as defined at the top level
+             (needed for annex B.3.3.4 and B.3.3.5
+             checks) */
+          hf->scope_level = 0;
+          hf->force_init = ((s->cur_func->js_mode & JS_MODE_STRICT) != 0);
+          /* store directly into global var, bypass lexical scope */
+          emit_op(s, OP_dup);
+          emit_op(s, OP_scope_put_var);
+          emit_atom(s, func_name);
+          emit_u16(s, 0);
+        } else {
+          /* do not call define_var to bypass lexical scope check */
+          func_idx = find_var(ctx, s->cur_func, func_name);
+          if (func_idx < 0) {
+            func_idx = add_var(ctx, s->cur_func, func_name);
+            if (func_idx < 0)
+              goto fail;
+          }
+          /* store directly into local var, bypass lexical catch scope */
+          emit_op(s, OP_dup);
+          emit_op(s, OP_scope_put_var);
+          emit_atom(s, func_name);
+          emit_u16(s, 0);
+        }
+      }
+      if (lexical_func_idx >= 0) {
+        /* lexical variable will be initialized upon entering scope */
+        s->cur_func->vars[lexical_func_idx].func_pool_idx = idx;
+        emit_op(s, OP_drop);
+      } else {
+        /* store function object into its lexical name */
+        /* XXX: could use OP_put_loc directly */
+        emit_op(s, OP_scope_put_var_init);
+        emit_atom(s, func_name);
+        emit_u16(s, s->cur_func->scope_level);
+      }
+    } else {
+      if (!s->cur_func->is_global_var) {
+        int var_idx = define_var(s, s->cur_func, func_name, JS_VAR_DEF_VAR);
+
+        if (var_idx < 0)
+          goto fail;
+        /* the variable will be assigned at the top of the function */
+        if (var_idx & ARGUMENT_VAR_OFFSET) {
+          s->cur_func->args[var_idx - ARGUMENT_VAR_OFFSET].func_pool_idx = idx;
+        } else {
+          s->cur_func->vars[var_idx].func_pool_idx = idx;
+        }
+      } else {
+        JSAtom func_var_name;
+        JSGlobalVar *hf;
+        if (func_name == JS_ATOM_NULL)
+          func_var_name = JS_ATOM__default_; /* export default */
+        else
+          func_var_name = func_name;
+        /* the variable will be assigned at the top of the function */
+        hf = add_global_var(ctx, s->cur_func, func_var_name);
+        if (!hf)
+          goto fail;
+        hf->cpool_idx = idx;
+        if (export_flag != JS_PARSE_EXPORT_NONE) {
+          if (!add_export_entry(s, s->cur_func->module, func_var_name,
+                                export_flag == JS_PARSE_EXPORT_NAMED ? func_var_name : JS_ATOM_default, JS_EXPORT_TYPE_LOCAL))
+            goto fail;
+        }
+      }
+    }
+  }
+  return 0;
+fail:
+  s->cur_func = fd->parent;
+  js_free_function_def(ctx, fd);
+  if (pfd)
+    *pfd = NULL;
+  return -1;
+}
+
+static __exception int js_parse_function_decl(JSParseState *s,
+                                              JSParseFunctionEnum func_type,
+                                              JSFunctionKindEnum func_kind,
+                                              JSAtom func_name,
+                                              const uint8_t *ptr,
+                                              int function_line_num)
+{
+  return js_parse_function_decl2(s, func_type, func_kind, func_name, ptr,
+                                 function_line_num, JS_PARSE_EXPORT_NONE,
+                                 NULL);
+}
+
+static __exception int js_parse_program(JSParseState *s)
+{
+  JSFunctionDef *fd = s->cur_func;
+  int idx;
+
+  if (next_token(s))
+    return -1;
+
+  if (js_parse_directives(s))
+    return -1;
+
+  fd->is_global_var = (fd->eval_type == JS_EVAL_TYPE_GLOBAL) ||
+                      (fd->eval_type == JS_EVAL_TYPE_MODULE) ||
+                      !(fd->js_mode & JS_MODE_STRICT);
+
+  if (!s->is_module) {
+    /* hidden variable for the return value */
+    fd->eval_ret_idx = idx = add_var(s->ctx, fd, JS_ATOM__ret_);
+    if (idx < 0)
+      return -1;
+  }
+
+  while (s->token.val != TOK_EOF) {
+    if (js_parse_source_element(s))
+      return -1;
+  }
+
+  if (!s->is_module) {
+    /* return the value of the hidden variable eval_ret_idx  */
+    emit_op(s, OP_get_loc);
+    emit_u16(s, fd->eval_ret_idx);
+
+    emit_op(s, OP_return);
+  } else {
+    emit_op(s, OP_return_undef);
+  }
+
+  return 0;
+}
+
+void js_parse_init(JSContext *ctx, JSParseState *s,
+                          const char *input, size_t input_len,
+                          const char *filename)
+{
+  memset(s, 0, sizeof(*s));
+  s->ctx = ctx;
+  s->filename = filename;
+  s->line_num = 1;
+  s->buf_ptr = (const uint8_t *)input;
+  s->buf_end = s->buf_ptr + input_len;
+  s->token.val = ' ';
+  s->token.line_num = 1;
+}
+
+
+void skip_shebang(JSParseState *s)
+{
+  const uint8_t *p = s->buf_ptr;
+  int c;
+
+  if (p[0] == '#' && p[1] == '!') {
+    p += 2;
+    while (p < s->buf_end) {
+      if (*p == '\n' || *p == '\r') {
+        break;
+      } else if (*p >= 0x80) {
+        c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
+        if (c == CP_LS || c == CP_PS) {
+          break;
+        } else if (c == -1) {
+          p++; /* skip invalid UTF-8 */
+        }
+      } else {
+        p++;
+      }
+    }
+    s->buf_ptr = p;
+  }
+}
+
+/* 'input' must be zero terminated i.e. input[input_len] = '\0'. */
+JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
+                                 const char *input, size_t input_len,
+                                 const char *filename, int flags, int scope_idx)
+{
+  JSParseState s1, *s = &s1;
+  int err, js_mode, eval_type;
+  JSValue fun_obj, ret_val;
+  JSStackFrame *sf;
+  JSVarRef **var_refs;
+  JSFunctionBytecode *b;
+  JSFunctionDef *fd;
+  JSModuleDef *m;
+
+  js_parse_init(ctx, s, input, input_len, filename);
+  skip_shebang(s);
+
+  eval_type = flags & JS_EVAL_TYPE_MASK;
+  m = NULL;
+  if (eval_type == JS_EVAL_TYPE_DIRECT) {
+    JSObject *p;
+    sf = ctx->rt->current_stack_frame;
+    assert(sf != NULL);
+    assert(JS_VALUE_GET_TAG(sf->cur_func) == JS_TAG_OBJECT);
+    p = JS_VALUE_GET_OBJ(sf->cur_func);
+    assert(js_class_has_bytecode(p->class_id));
+    b = p->u.func.function_bytecode;
+    var_refs = p->u.func.var_refs;
+    js_mode = b->js_mode;
+  } else {
+    sf = NULL;
+    b = NULL;
+    var_refs = NULL;
+    js_mode = 0;
+    if (flags & JS_EVAL_FLAG_STRICT)
+      js_mode |= JS_MODE_STRICT;
+    if (flags & JS_EVAL_FLAG_STRIP)
+      js_mode |= JS_MODE_STRIP;
+    if (eval_type == JS_EVAL_TYPE_MODULE) {
+      JSAtom module_name = JS_NewAtom(ctx, filename);
+      if (module_name == JS_ATOM_NULL)
+        return JS_EXCEPTION;
+      m = js_new_module_def(ctx, module_name);
+      if (!m)
+        return JS_EXCEPTION;
+      js_mode |= JS_MODE_STRICT;
+    }
+  }
+  fd = js_new_function_def(ctx, NULL, TRUE, FALSE, filename, 1);
+  if (!fd)
+    goto fail1;
+  s->cur_func = fd;
+  fd->eval_type = eval_type;
+  fd->has_this_binding = (eval_type != JS_EVAL_TYPE_DIRECT);
+  fd->backtrace_barrier = ((flags & JS_EVAL_FLAG_BACKTRACE_BARRIER) != 0);
+  if (eval_type == JS_EVAL_TYPE_DIRECT) {
+    fd->new_target_allowed = b->new_target_allowed;
+    fd->super_call_allowed = b->super_call_allowed;
+    fd->super_allowed = b->super_allowed;
+    fd->arguments_allowed = b->arguments_allowed;
+  } else {
+    fd->new_target_allowed = FALSE;
+    fd->super_call_allowed = FALSE;
+    fd->super_allowed = FALSE;
+    fd->arguments_allowed = TRUE;
+  }
+  fd->js_mode = js_mode;
+  fd->func_name = JS_DupAtom(ctx, JS_ATOM__eval_);
+  if (b) {
+    if (add_closure_variables(ctx, fd, b, scope_idx))
+      goto fail;
+  }
+  fd->module = m;
+  s->is_module = (m != NULL);
+  s->allow_html_comments = !s->is_module;
+
+  push_scope(s); /* body scope */
+  fd->body_scope = fd->scope_level;
+
+  err = js_parse_program(s);
+  if (err) {
+  fail:
+    free_token(s, &s->token);
+    js_free_function_def(ctx, fd);
+    goto fail1;
+  }
+
+  /* create the function object and all the enclosed functions */
+  fun_obj = js_create_function(ctx, fd);
+  if (JS_IsException(fun_obj))
+    goto fail1;
+  /* Could add a flag to avoid resolution if necessary */
+  if (m) {
+    m->func_obj = fun_obj;
+    if (js_resolve_module(ctx, m) < 0)
+      goto fail1;
+    fun_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
+  }
+  if (flags & JS_EVAL_FLAG_COMPILE_ONLY) {
+    ret_val = fun_obj;
+  } else {
+    ret_val = JS_EvalFunctionInternal(ctx, fun_obj, this_obj, var_refs, sf);
+  }
+  return ret_val;
+fail1:
+  /* XXX: should free all the unresolved dependencies */
+  if (m)
+    js_free_module_def(ctx, m);
+  return JS_EXCEPTION;
+}
diff --git a/src/core/parser.h b/src/core/parser.h
new file mode 100644
index 000000000..63d9f0460
--- /dev/null
+++ b/src/core/parser.h
@@ -0,0 +1,424 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_PARSER_H
+#define QUICKJS_PARSER_H
+
+#include "quickjs/cutils.h"
+#include "quickjs/list.h"
+#include "types.h"
+
+/* JS parser */
+
+enum {
+  TOK_NUMBER = -128,
+  TOK_STRING,
+  TOK_TEMPLATE,
+  TOK_IDENT,
+  TOK_REGEXP,
+  /* warning: order matters (see js_parse_assign_expr) */
+  TOK_MUL_ASSIGN,
+  TOK_DIV_ASSIGN,
+  TOK_MOD_ASSIGN,
+  TOK_PLUS_ASSIGN,
+  TOK_MINUS_ASSIGN,
+  TOK_SHL_ASSIGN,
+  TOK_SAR_ASSIGN,
+  TOK_SHR_ASSIGN,
+  TOK_AND_ASSIGN,
+  TOK_XOR_ASSIGN,
+  TOK_OR_ASSIGN,
+#ifdef CONFIG_BIGNUM
+  TOK_MATH_POW_ASSIGN,
+#endif
+  TOK_POW_ASSIGN,
+  TOK_LAND_ASSIGN,
+  TOK_LOR_ASSIGN,
+  TOK_DOUBLE_QUESTION_MARK_ASSIGN,
+  TOK_DEC,
+  TOK_INC,
+  TOK_SHL,
+  TOK_SAR,
+  TOK_SHR,
+  TOK_LT,
+  TOK_LTE,
+  TOK_GT,
+  TOK_GTE,
+  TOK_EQ,
+  TOK_STRICT_EQ,
+  TOK_NEQ,
+  TOK_STRICT_NEQ,
+  TOK_LAND,
+  TOK_LOR,
+#ifdef CONFIG_BIGNUM
+  TOK_MATH_POW,
+#endif
+  TOK_POW,
+  TOK_ARROW,
+  TOK_ELLIPSIS,
+  TOK_DOUBLE_QUESTION_MARK,
+  TOK_QUESTION_MARK_DOT,
+  TOK_ERROR,
+  TOK_PRIVATE_NAME,
+  TOK_EOF,
+  /* keywords: WARNING: same order as atoms */
+  TOK_NULL, /* must be first */
+  TOK_FALSE,
+  TOK_TRUE,
+  TOK_IF,
+  TOK_ELSE,
+  TOK_RETURN,
+  TOK_VAR,
+  TOK_THIS,
+  TOK_DELETE,
+  TOK_VOID,
+  TOK_TYPEOF,
+  TOK_NEW,
+  TOK_IN,
+  TOK_INSTANCEOF,
+  TOK_DO,
+  TOK_WHILE,
+  TOK_FOR,
+  TOK_BREAK,
+  TOK_CONTINUE,
+  TOK_SWITCH,
+  TOK_CASE,
+  TOK_DEFAULT,
+  TOK_THROW,
+  TOK_TRY,
+  TOK_CATCH,
+  TOK_FINALLY,
+  TOK_FUNCTION,
+  TOK_DEBUGGER,
+  TOK_WITH,
+  /* FutureReservedWord */
+  TOK_CLASS,
+  TOK_CONST,
+  TOK_ENUM,
+  TOK_EXPORT,
+  TOK_EXTENDS,
+  TOK_IMPORT,
+  TOK_SUPER,
+  /* FutureReservedWords when parsing strict mode code */
+  TOK_IMPLEMENTS,
+  TOK_INTERFACE,
+  TOK_LET,
+  TOK_PACKAGE,
+  TOK_PRIVATE,
+  TOK_PROTECTED,
+  TOK_PUBLIC,
+  TOK_STATIC,
+  TOK_YIELD,
+  TOK_AWAIT, /* must be last */
+  TOK_OF,    /* only used for js_parse_skip_parens_token() */
+};
+
+#define TOK_FIRST_KEYWORD TOK_NULL
+#define TOK_LAST_KEYWORD TOK_AWAIT
+
+/* unicode code points */
+#define CP_NBSP 0x00a0
+#define CP_BOM 0xfeff
+
+#define CP_LS 0x2028
+#define CP_PS 0x2029
+
+typedef struct BlockEnv {
+  struct BlockEnv* prev;
+  JSAtom label_name; /* JS_ATOM_NULL if none */
+  int label_break;   /* -1 if none */
+  int label_cont;    /* -1 if none */
+  int drop_count;    /* number of stack elements to drop */
+  int label_finally; /* -1 if none */
+  int scope_level;
+  int has_iterator;
+} BlockEnv;
+
+typedef struct JSGlobalVar {
+  int cpool_idx;          /* if >= 0, index in the constant pool for hoisted
+                                               function defintion*/
+  uint8_t force_init : 1; /* force initialization to undefined */
+  uint8_t is_lexical : 1; /* global let/const definition */
+  uint8_t is_const : 1;   /* const definition */
+  int scope_level;        /* scope of definition */
+  JSAtom var_name;        /* variable name */
+} JSGlobalVar;
+
+typedef struct RelocEntry {
+  struct RelocEntry* next;
+  uint32_t addr; /* address to patch */
+  int size;      /* address size: 1, 2 or 4 bytes */
+} RelocEntry;
+
+typedef struct JumpSlot {
+  int op;
+  int size;
+  int pos;
+  int label;
+} JumpSlot;
+
+typedef struct LabelSlot {
+  int ref_count;
+  int pos;  /* phase 1 address, -1 means not resolved yet */
+  int pos2; /* phase 2 address, -1 means not resolved yet */
+  int addr; /* phase 3 address, -1 means not resolved yet */
+  RelocEntry* first_reloc;
+} LabelSlot;
+
+typedef struct LineNumberSlot {
+  uint32_t pc;
+  int line_num;
+} LineNumberSlot;
+
+typedef enum JSParseFunctionEnum {
+  JS_PARSE_FUNC_STATEMENT,
+  JS_PARSE_FUNC_VAR,
+  JS_PARSE_FUNC_EXPR,
+  JS_PARSE_FUNC_ARROW,
+  JS_PARSE_FUNC_GETTER,
+  JS_PARSE_FUNC_SETTER,
+  JS_PARSE_FUNC_METHOD,
+  JS_PARSE_FUNC_CLASS_CONSTRUCTOR,
+  JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR,
+} JSParseFunctionEnum;
+
+typedef enum JSParseExportEnum {
+  JS_PARSE_EXPORT_NONE,
+  JS_PARSE_EXPORT_NAMED,
+  JS_PARSE_EXPORT_DEFAULT,
+} JSParseExportEnum;
+
+typedef struct JSFunctionDef {
+  JSContext* ctx;
+  struct JSFunctionDef* parent;
+  int parent_cpool_idx;        /* index in the constant pool of the parent
+                                                or -1 if none */
+  int parent_scope_level;      /* scope level in parent at point of definition */
+  struct list_head child_list; /* list of JSFunctionDef.link */
+  struct list_head link;
+
+  BOOL is_eval;         /* TRUE if eval code */
+  int eval_type;        /* only valid if is_eval = TRUE */
+  BOOL is_global_var;   /* TRUE if variables are not defined locally:
+                               eval global, eval module or non strict eval */
+  BOOL is_func_expr;    /* TRUE if function expression */
+  BOOL has_home_object; /* TRUE if the home object is available */
+  BOOL has_prototype;   /* true if a prototype field is necessary */
+  BOOL has_simple_parameter_list;
+  BOOL has_parameter_expressions; /* if true, an argument scope is created */
+  BOOL has_use_strict;            /* to reject directive in special cases */
+  BOOL has_eval_call;             /* true if the function contains a call to eval() */
+  BOOL has_arguments_binding;     /* true if the 'arguments' binding is
+                                             available in the function */
+  BOOL has_this_binding;          /* true if the 'this' and new.target binding are
+                                                       available in the function */
+  BOOL new_target_allowed;        /* true if the 'new.target' does not
+                                                   throw a syntax error */
+  BOOL super_call_allowed;        /* true if super() is allowed */
+  BOOL super_allowed;             /* true if super. or super[] is allowed */
+  BOOL arguments_allowed;         /* true if the 'arguments' identifier is allowed */
+  BOOL is_derived_class_constructor;
+  BOOL in_function_body;
+  BOOL backtrace_barrier;
+  JSFunctionKindEnum func_kind : 8;
+  JSParseFunctionEnum func_type : 8;
+  uint8_t js_mode;  /* bitmap of JS_MODE_x */
+  JSAtom func_name; /* JS_ATOM_NULL if no name */
+
+  JSVarDef* vars;
+  int var_size; /* allocated size for vars[] */
+  int var_count;
+  JSVarDef* args;
+  int arg_size;  /* allocated size for args[] */
+  int arg_count; /* number of arguments */
+  int defined_arg_count;
+  int var_object_idx;           /* -1 if none */
+  int arg_var_object_idx;       /* -1 if none (var object for the argument scope) */
+  int arguments_var_idx;        /* -1 if none */
+  int arguments_arg_idx;        /* argument variable definition in argument scope,
+                                                 -1 if none */
+  int func_var_idx;             /* variable containing the current function (-1
+                                                           if none, only used if is_func_expr is true) */
+  int eval_ret_idx;             /* variable containing the return value of the eval, -1 if none */
+  int this_var_idx;             /* variable containg the 'this' value, -1 if none */
+  int new_target_var_idx;       /* variable containg the 'new.target' value, -1 if none */
+  int this_active_func_var_idx; /* variable containg the 'this.active_func' value, -1 if none */
+  int home_object_var_idx;
+  BOOL need_home_object;
+
+  int scope_level; /* index into fd->scopes if the current lexical scope */
+  int scope_first; /* index into vd->vars of first lexically scoped variable */
+  int scope_size;  /* allocated size of fd->scopes array */
+  int scope_count; /* number of entries used in the fd->scopes array */
+  JSVarScope* scopes;
+  JSVarScope def_scope_array[4];
+  int body_scope; /* scope of the body of the function or eval */
+
+  int global_var_count;
+  int global_var_size;
+  JSGlobalVar* global_vars;
+
+  DynBuf byte_code;
+  int last_opcode_pos; /* -1 if no last opcode */
+  int last_opcode_line_num;
+  BOOL use_short_opcodes; /* true if short opcodes are used in byte_code */
+
+  LabelSlot* label_slots;
+  int label_size; /* allocated size for label_slots[] */
+  int label_count;
+  BlockEnv* top_break; /* break/continue label stack */
+
+  /* constant pool (strings, functions, numbers) */
+  JSValue* cpool;
+  int cpool_count;
+  int cpool_size;
+
+  /* list of variables in the closure */
+  int closure_var_count;
+  int closure_var_size;
+  JSClosureVar* closure_var;
+
+  JumpSlot* jump_slots;
+  int jump_size;
+  int jump_count;
+
+  LineNumberSlot* line_number_slots;
+  int line_number_size;
+  int line_number_count;
+  int line_number_last;
+  int line_number_last_pc;
+
+  /* pc2line table */
+  JSAtom filename;
+  int line_num;
+  DynBuf pc2line;
+
+  char* source; /* raw source, utf-8 encoded */
+  int source_len;
+
+  JSModuleDef* module; /* != NULL when parsing a module */
+} JSFunctionDef;
+
+typedef struct JSToken {
+  int val;
+  int line_num; /* line number of token start */
+  const uint8_t* ptr;
+  union {
+    struct {
+      JSValue str;
+      int sep;
+    } str;
+    struct {
+      JSValue val;
+#ifdef CONFIG_BIGNUM
+      slimb_t exponent; /* may be != 0 only if val is a float */
+#endif
+    } num;
+    struct {
+      JSAtom atom;
+      BOOL has_escape;
+      BOOL is_reserved;
+    } ident;
+    struct {
+      JSValue body;
+      JSValue flags;
+    } regexp;
+  } u;
+} JSToken;
+
+typedef struct JSParseState {
+  JSContext *ctx;
+  int last_line_num;  /* line number of last token */
+  int line_num;       /* line number of current offset */
+  const char *filename;
+  JSToken token;
+  BOOL got_lf; /* true if got line feed before the current token */
+  const uint8_t *last_ptr;
+  const uint8_t *buf_ptr;
+  const uint8_t *buf_end;
+
+  /* current function code */
+  JSFunctionDef *cur_func;
+  BOOL is_module; /* parsing a module */
+  BOOL allow_html_comments;
+  BOOL ext_json; /* true if accepting JSON superset */
+} JSParseState;
+
+typedef struct JSOpCode {
+#ifdef DUMP_BYTECODE
+  const char *name;
+#endif
+  uint8_t size; /* in bytes */
+  /* the opcodes remove n_pop items from the top of the stack, then
+     pushes n_push items */
+  uint8_t n_pop;
+  uint8_t n_push;
+  uint8_t fmt;
+} JSOpCode;
+
+static const JSOpCode opcode_info[OP_COUNT + (OP_TEMP_END - OP_TEMP_START)] = {
+#define FMT(f)
+#ifdef DUMP_BYTECODE
+#define DEF(id, size, n_pop, n_push, f) { #id, size, n_pop, n_push, OP_FMT_ ## f },
+#else
+#define DEF(id, size, n_pop, n_push, f) { size, n_pop, n_push, OP_FMT_ ## f },
+#endif
+#include "quickjs/quickjs-opcode.h"
+#undef DEF
+#undef FMT
+};
+
+#if SHORT_OPCODES
+/* After the final compilation pass, short opcodes are used. Their
+   opcodes overlap with the temporary opcodes which cannot appear in
+   the final bytecode. Their description is after the temporary
+   opcodes in opcode_info[]. */
+#define short_opcode_info(op)           \
+    opcode_info[(op) >= OP_TEMP_START ? \
+                (op) + (OP_TEMP_END - OP_TEMP_START) : (op)]
+#else
+#define short_opcode_info(op) opcode_info[op]
+#endif
+
+JSExportEntry* add_export_entry2(JSContext* ctx, JSParseState* s, JSModuleDef* m, JSAtom local_name, JSAtom export_name, JSExportTypeEnum export_type);
+
+__exception int json_next_token(JSParseState *s);
+void free_token(JSParseState *s, JSToken *token);
+
+JSFunctionDef* js_new_function_def(JSContext* ctx, JSFunctionDef* parent, BOOL is_eval, BOOL is_func_expr, const char* filename, int line_num);
+void js_parse_init(JSContext* ctx, JSParseState* s, const char* input, size_t input_len, const char* filename);
+int __attribute__((format(printf, 2, 3))) js_parse_error(JSParseState *s, const char *fmt, ...);
+void skip_shebang(JSParseState* s);
+
+JSValue js_module_ns_autoinit(JSContext* ctx, JSObject* p, JSAtom atom, void* opaque);
+void js_free_module_def(JSContext* ctx, JSModuleDef* m);
+JSValue js_import_meta(JSContext* ctx);
+
+/* 'input' must be zero terminated i.e. input[input_len] = '\0'. */
+JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
+                                 const char *input, size_t input_len,
+                                 const char *filename, int flags, int scope_idx);
+
+#endif
\ No newline at end of file
diff --git a/src/core/runtime.c b/src/core/runtime.c
new file mode 100644
index 000000000..5602a6e4a
--- /dev/null
+++ b/src/core/runtime.c
@@ -0,0 +1,3059 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "runtime.h"
+#include "builtins/js-array.h"
+#include "builtins/js-function.h"
+#include "builtins/js-object.h"
+#include "builtins/js-proxy.h"
+#include "builtins/js-string.h"
+#include "exception.h"
+#include "function.h"
+#include "malloc.h"
+#include "string.h"
+
+#if CONFIG_BIGNUM
+#include "quickjs/libbf.h"
+#endif
+
+#include "builtins/js-big-num.h"
+#include "builtins/js-boolean.h"
+#include "builtins/js-closures.h"
+#include "builtins/js-date.h"
+#include "builtins/js-generator.h"
+#include "builtins/js-math.h"
+#include "builtins/js-number.h"
+#include "builtins/js-operator.h"
+#include "builtins/js-reflect.h"
+#include "builtins/js-symbol.h"
+#include "convertion.h"
+#include "gc.h"
+#include "module.h"
+#include "object.h"
+#include "parser.h"
+#include "shape.h"
+
+static const JSClassExoticMethods js_arguments_exotic_methods = {
+    .define_own_property = js_arguments_define_own_property,
+};
+
+void dbuf_put_leb128(DynBuf* s, uint32_t v) {
+  uint32_t a;
+  for (;;) {
+    a = v & 0x7f;
+    v >>= 7;
+    if (v != 0) {
+      dbuf_putc(s, a | 0x80);
+    } else {
+      dbuf_putc(s, a);
+      break;
+    }
+  }
+}
+
+
+
+void dbuf_put_sleb128(DynBuf* s, int32_t v1) {
+  uint32_t v = v1;
+  dbuf_put_leb128(s, (2 * v) ^ -(v >> 31));
+}
+
+int get_leb128(uint32_t* pval, const uint8_t* buf, const uint8_t* buf_end) {
+  const uint8_t* ptr = buf;
+  uint32_t v, a, i;
+  v = 0;
+  for (i = 0; i < 5; i++) {
+    if (unlikely(ptr >= buf_end))
+      break;
+    a = *ptr++;
+    v |= (a & 0x7f) << (i * 7);
+    if (!(a & 0x80)) {
+      *pval = v;
+      return ptr - buf;
+    }
+  }
+  *pval = 0;
+  return -1;
+}
+
+int get_sleb128(int32_t* pval, const uint8_t* buf, const uint8_t* buf_end) {
+  int ret;
+  uint32_t val;
+  ret = get_leb128(&val, buf, buf_end);
+  if (ret < 0) {
+    *pval = 0;
+    return -1;
+  }
+  *pval = (val >> 1) ^ -(val & 1);
+  return ret;
+}
+
+int find_line_num(JSContext* ctx, JSFunctionBytecode* b, uint32_t pc_value) {
+  const uint8_t *p_end, *p;
+  int new_line_num, line_num, pc, v, ret;
+  unsigned int op;
+
+  if (!b->has_debug || !b->debug.pc2line_buf) {
+    /* function was stripped */
+    return -1;
+  }
+
+  p = b->debug.pc2line_buf;
+  p_end = p + b->debug.pc2line_len;
+  pc = 0;
+  line_num = b->debug.line_num;
+  while (p < p_end) {
+    op = *p++;
+    if (op == 0) {
+      uint32_t val;
+      ret = get_leb128(&val, p, p_end);
+      if (ret < 0)
+        goto fail;
+      pc += val;
+      p += ret;
+      ret = get_sleb128(&v, p, p_end);
+      if (ret < 0) {
+      fail:
+        /* should never happen */
+        return b->debug.line_num;
+      }
+      p += ret;
+      new_line_num = line_num + v;
+    } else {
+      op -= PC2LINE_OP_FIRST;
+      pc += (op / PC2LINE_RANGE);
+      new_line_num = line_num + (op % PC2LINE_RANGE) + PC2LINE_BASE;
+    }
+    if (pc_value < pc)
+      return line_num;
+    line_num = new_line_num;
+  }
+  return line_num;
+}
+
+int js_update_property_flags(JSContext* ctx, JSObject* p, JSShapeProperty** pprs, int flags) {
+  if (flags != (*pprs)->flags) {
+    if (js_shape_prepare_update(ctx, p, pprs))
+      return -1;
+    (*pprs)->flags = flags;
+  }
+  return 0;
+}
+
+BOOL js_class_has_bytecode(JSClassID class_id) {
+  return (class_id == JS_CLASS_BYTECODE_FUNCTION || class_id == JS_CLASS_GENERATOR_FUNCTION || class_id == JS_CLASS_ASYNC_FUNCTION || class_id == JS_CLASS_ASYNC_GENERATOR_FUNCTION);
+}
+
+/* JSClass support */
+
+JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT;
+/* a new class ID is allocated if *pclass_id != 0 */
+JSClassID JS_NewClassID(JSClassID* pclass_id) {
+  JSClassID class_id;
+  /* XXX: make it thread safe */
+  class_id = *pclass_id;
+  if (class_id == 0) {
+    class_id = js_class_id_alloc++;
+    *pclass_id = class_id;
+  }
+  return class_id;
+}
+
+BOOL JS_IsRegisteredClass(JSRuntime* rt, JSClassID class_id) {
+  return (class_id < rt->class_count && rt->class_array[class_id].class_id != 0);
+}
+
+/* create a new object internal class. Return -1 if error, 0 if
+   OK. The finalizer can be NULL if none is needed. */
+static int JS_NewClass1(JSRuntime* rt, JSClassID class_id, const JSClassDef* class_def, JSAtom name) {
+  int new_size, i;
+  JSClass *cl, *new_class_array;
+  struct list_head* el;
+
+  if (class_id >= (1 << 16))
+    return -1;
+  if (class_id < rt->class_count && rt->class_array[class_id].class_id != 0)
+    return -1;
+
+  if (class_id >= rt->class_count) {
+    new_size = max_int(JS_CLASS_INIT_COUNT, max_int(class_id + 1, rt->class_count * 3 / 2));
+
+    /* reallocate the context class prototype array, if any */
+    list_for_each(el, &rt->context_list) {
+      JSContext* ctx = list_entry(el, JSContext, link);
+      JSValue* new_tab;
+      new_tab = js_realloc_rt(rt, ctx->class_proto, sizeof(ctx->class_proto[0]) * new_size);
+      if (!new_tab)
+        return -1;
+      for (i = rt->class_count; i < new_size; i++)
+        new_tab[i] = JS_NULL;
+      ctx->class_proto = new_tab;
+    }
+    /* reallocate the class array */
+    new_class_array = js_realloc_rt(rt, rt->class_array, sizeof(JSClass) * new_size);
+    if (!new_class_array)
+      return -1;
+    memset(new_class_array + rt->class_count, 0, (new_size - rt->class_count) * sizeof(JSClass));
+    rt->class_array = new_class_array;
+    rt->class_count = new_size;
+  }
+  cl = &rt->class_array[class_id];
+  cl->class_id = class_id;
+  cl->class_name = JS_DupAtomRT(rt, name);
+  cl->finalizer = class_def->finalizer;
+  cl->gc_mark = class_def->gc_mark;
+  cl->call = class_def->call;
+  cl->exotic = class_def->exotic;
+  return 0;
+}
+
+int JS_NewClass(JSRuntime* rt, JSClassID class_id, const JSClassDef* class_def) {
+  int ret, len;
+  JSAtom name;
+
+  len = strlen(class_def->class_name);
+  name = __JS_FindAtom(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
+  if (name == JS_ATOM_NULL) {
+    name = __JS_NewAtomInit(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
+    if (name == JS_ATOM_NULL)
+      return -1;
+  }
+  ret = JS_NewClass1(rt, class_id, class_def, name);
+  JS_FreeAtomRT(rt, name);
+  return ret;
+}
+
+/* return -1 (exception) or TRUE/FALSE */
+int JS_SetPrototypeInternal(JSContext* ctx, JSValueConst obj, JSValueConst proto_val, BOOL throw_flag) {
+  JSObject *proto, *p, *p1;
+  JSShape* sh;
+
+  if (throw_flag) {
+    if (JS_VALUE_GET_TAG(obj) == JS_TAG_NULL || JS_VALUE_GET_TAG(obj) == JS_TAG_UNDEFINED)
+      goto not_obj;
+  } else {
+    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
+      goto not_obj;
+  }
+  p = JS_VALUE_GET_OBJ(obj);
+  if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT) {
+    if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_NULL) {
+    not_obj:
+      JS_ThrowTypeErrorNotAnObject(ctx);
+      return -1;
+    }
+    proto = NULL;
+  } else {
+    proto = JS_VALUE_GET_OBJ(proto_val);
+  }
+
+  if (throw_flag && JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
+    return TRUE;
+
+  if (unlikely(p->class_id == JS_CLASS_PROXY))
+    return js_proxy_setPrototypeOf(ctx, obj, proto_val, throw_flag);
+  sh = p->shape;
+  if (sh->proto == proto)
+    return TRUE;
+  if (!p->extensible) {
+    if (throw_flag) {
+      JS_ThrowTypeError(ctx, "object is not extensible");
+      return -1;
+    } else {
+      return FALSE;
+    }
+  }
+  if (proto) {
+    /* check if there is a cycle */
+    p1 = proto;
+    do {
+      if (p1 == p) {
+        if (throw_flag) {
+          JS_ThrowTypeError(ctx, "circular prototype chain");
+          return -1;
+        } else {
+          return FALSE;
+        }
+      }
+      /* Note: for Proxy objects, proto is NULL */
+      p1 = p1->shape->proto;
+    } while (p1 != NULL);
+    JS_DupValue(ctx, proto_val);
+  }
+
+  if (js_shape_prepare_update(ctx, p, NULL))
+    return -1;
+  sh = p->shape;
+  if (sh->proto)
+    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
+  sh->proto = proto;
+  return TRUE;
+}
+
+/* return -1 (exception) or TRUE/FALSE */
+int JS_SetPrototype(JSContext* ctx, JSValueConst obj, JSValueConst proto_val) {
+  return JS_SetPrototypeInternal(ctx, obj, proto_val, TRUE);
+}
+
+/* Only works for primitive types, otherwise return JS_NULL. */
+JSValueConst JS_GetPrototypePrimitive(JSContext* ctx, JSValueConst val) {
+  switch (JS_VALUE_GET_NORM_TAG(val)) {
+#ifdef CONFIG_BIGNUM
+    case JS_TAG_BIG_INT:
+      val = ctx->class_proto[JS_CLASS_BIG_INT];
+      break;
+    case JS_TAG_BIG_FLOAT:
+      val = ctx->class_proto[JS_CLASS_BIG_FLOAT];
+      break;
+    case JS_TAG_BIG_DECIMAL:
+      val = ctx->class_proto[JS_CLASS_BIG_DECIMAL];
+      break;
+#endif
+    case JS_TAG_INT:
+    case JS_TAG_FLOAT64:
+      val = ctx->class_proto[JS_CLASS_NUMBER];
+      break;
+    case JS_TAG_BOOL:
+      val = ctx->class_proto[JS_CLASS_BOOLEAN];
+      break;
+    case JS_TAG_STRING:
+      val = ctx->class_proto[JS_CLASS_STRING];
+      break;
+    case JS_TAG_SYMBOL:
+      val = ctx->class_proto[JS_CLASS_SYMBOL];
+      break;
+    case JS_TAG_OBJECT:
+    case JS_TAG_NULL:
+    case JS_TAG_UNDEFINED:
+    default:
+      val = JS_NULL;
+      break;
+  }
+  return val;
+}
+
+/* Return an Object, JS_NULL or JS_EXCEPTION in case of Proxy object. */
+JSValue JS_GetPrototype(JSContext* ctx, JSValueConst obj) {
+  JSValue val;
+  if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
+    JSObject* p;
+    p = JS_VALUE_GET_OBJ(obj);
+    if (unlikely(p->class_id == JS_CLASS_PROXY)) {
+      val = js_proxy_getPrototypeOf(ctx, obj);
+    } else {
+      p = p->shape->proto;
+      if (!p)
+        val = JS_NULL;
+      else
+        val = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+    }
+  } else {
+    val = JS_DupValue(ctx, JS_GetPrototypePrimitive(ctx, obj));
+  }
+  return val;
+}
+
+JSValue JS_GetGlobalVar(JSContext* ctx, JSAtom prop, BOOL throw_ref_error) {
+  JSObject* p;
+  JSShapeProperty* prs;
+  JSProperty* pr;
+
+  /* no exotic behavior is possible in global_var_obj */
+  p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
+  prs = find_own_property(&pr, p, prop);
+  if (prs) {
+    /* XXX: should handle JS_PROP_TMASK properties */
+    if (unlikely(JS_IsUninitialized(pr->u.value)))
+      return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
+    return JS_DupValue(ctx, pr->u.value);
+  }
+  return JS_GetPropertyInternal(ctx, ctx->global_obj, prop, ctx->global_obj, throw_ref_error);
+}
+
+/* construct a reference to a global variable */
+int JS_GetGlobalVarRef(JSContext* ctx, JSAtom prop, JSValue* sp) {
+  JSObject* p;
+  JSShapeProperty* prs;
+  JSProperty* pr;
+
+  /* no exotic behavior is possible in global_var_obj */
+  p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
+  prs = find_own_property(&pr, p, prop);
+  if (prs) {
+    /* XXX: should handle JS_PROP_AUTOINIT properties? */
+    /* XXX: conformance: do these tests in
+       OP_put_var_ref/OP_get_var_ref ? */
+    if (unlikely(JS_IsUninitialized(pr->u.value))) {
+      JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
+      return -1;
+    }
+    if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) {
+      return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop);
+    }
+    sp[0] = JS_DupValue(ctx, ctx->global_var_obj);
+  } else {
+    int ret;
+    ret = JS_HasProperty(ctx, ctx->global_obj, prop);
+    if (ret < 0)
+      return -1;
+    if (ret) {
+      sp[0] = JS_DupValue(ctx, ctx->global_obj);
+    } else {
+      sp[0] = JS_UNDEFINED;
+    }
+  }
+  sp[1] = JS_AtomToValue(ctx, prop);
+  return 0;
+}
+
+/* use for strict variable access: test if the variable exists */
+int JS_CheckGlobalVar(JSContext* ctx, JSAtom prop) {
+  JSObject* p;
+  JSShapeProperty* prs;
+  int ret;
+
+  /* no exotic behavior is possible in global_var_obj */
+  p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
+  prs = find_own_property1(p, prop);
+  if (prs) {
+    ret = TRUE;
+  } else {
+    ret = JS_HasProperty(ctx, ctx->global_obj, prop);
+    if (ret < 0)
+      return -1;
+  }
+  return ret;
+}
+
+/* flag = 0: normal variable write
+   flag = 1: initialize lexical variable
+   flag = 2: normal variable write, strict check was done before
+*/
+int JS_SetGlobalVar(JSContext* ctx, JSAtom prop, JSValue val, int flag) {
+  JSObject* p;
+  JSShapeProperty* prs;
+  JSProperty* pr;
+  int flags;
+
+  /* no exotic behavior is possible in global_var_obj */
+  p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
+  prs = find_own_property(&pr, p, prop);
+  if (prs) {
+    /* XXX: should handle JS_PROP_AUTOINIT properties? */
+    if (flag != 1) {
+      if (unlikely(JS_IsUninitialized(pr->u.value))) {
+        JS_FreeValue(ctx, val);
+        JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
+        return -1;
+      }
+      if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) {
+        JS_FreeValue(ctx, val);
+        return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop);
+      }
+    }
+    set_value(ctx, &pr->u.value, val);
+    return 0;
+  }
+  flags = JS_PROP_THROW_STRICT;
+  if (is_strict_mode(ctx))
+    flags |= JS_PROP_NO_ADD;
+  return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, flags);
+}
+
+/* return -1, FALSE or TRUE. return FALSE if not configurable or
+   invalid object. return -1 in case of exception.
+   flags can be 0, JS_PROP_THROW or JS_PROP_THROW_STRICT */
+int JS_DeleteProperty(JSContext* ctx, JSValueConst obj, JSAtom prop, int flags) {
+  JSValue obj1;
+  JSObject* p;
+  int res;
+
+  obj1 = JS_ToObject(ctx, obj);
+  if (JS_IsException(obj1))
+    return -1;
+  p = JS_VALUE_GET_OBJ(obj1);
+  res = delete_property(ctx, p, prop);
+  JS_FreeValue(ctx, obj1);
+  if (res != FALSE)
+    return res;
+  if ((flags & JS_PROP_THROW) || ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
+    JS_ThrowTypeError(ctx, "could not delete property");
+    return -1;
+  }
+  return FALSE;
+}
+
+int JS_DeletePropertyInt64(JSContext* ctx, JSValueConst obj, int64_t idx, int flags) {
+  JSAtom prop;
+  int res;
+
+  if ((uint64_t)idx <= JS_ATOM_MAX_INT) {
+    /* fast path for fast arrays */
+    return JS_DeleteProperty(ctx, obj, __JS_AtomFromUInt32(idx), flags);
+  }
+  prop = JS_NewAtomInt64(ctx, idx);
+  if (prop == JS_ATOM_NULL)
+    return -1;
+  res = JS_DeleteProperty(ctx, obj, prop, flags);
+  JS_FreeAtom(ctx, prop);
+  return res;
+}
+
+JSValue JS_GetPrototypeFree(JSContext* ctx, JSValue obj) {
+  JSValue obj1;
+  obj1 = JS_GetPrototype(ctx, obj);
+  JS_FreeValue(ctx, obj);
+  return obj1;
+}
+
+JSValue JS_ThrowSyntaxErrorVarRedeclaration(JSContext* ctx, JSAtom prop) {
+  return JS_ThrowSyntaxErrorAtom(ctx, "redeclaration of '%s'", prop);
+}
+
+/* flags is 0, DEFINE_GLOBAL_LEX_VAR or DEFINE_GLOBAL_FUNC_VAR */
+/* XXX: could support exotic global object. */
+int JS_CheckDefineGlobalVar(JSContext* ctx, JSAtom prop, int flags) {
+  JSObject* p;
+  JSShapeProperty* prs;
+
+  p = JS_VALUE_GET_OBJ(ctx->global_obj);
+  prs = find_own_property1(p, prop);
+  /* XXX: should handle JS_PROP_AUTOINIT */
+  if (flags & DEFINE_GLOBAL_LEX_VAR) {
+    if (prs && !(prs->flags & JS_PROP_CONFIGURABLE))
+      goto fail_redeclaration;
+  } else {
+    if (!prs && !p->extensible)
+      goto define_error;
+    if (flags & DEFINE_GLOBAL_FUNC_VAR) {
+      if (prs) {
+        if (!(prs->flags & JS_PROP_CONFIGURABLE) &&
+            ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET || ((prs->flags & (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)) != (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)))) {
+        define_error:
+          JS_ThrowTypeErrorAtom(ctx, "cannot define variable '%s'", prop);
+          return -1;
+        }
+      }
+    }
+  }
+  /* check if there already is a lexical declaration */
+  p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
+  prs = find_own_property1(p, prop);
+  if (prs) {
+  fail_redeclaration:
+    JS_ThrowSyntaxErrorVarRedeclaration(ctx, prop);
+    return -1;
+  }
+  return 0;
+}
+
+/* def_flags is (0, DEFINE_GLOBAL_LEX_VAR) |
+   JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE */
+/* XXX: could support exotic global object. */
+int JS_DefineGlobalVar(JSContext* ctx, JSAtom prop, int def_flags) {
+  JSObject* p;
+  JSShapeProperty* prs;
+  JSProperty* pr;
+  JSValue val;
+  int flags;
+
+  if (def_flags & DEFINE_GLOBAL_LEX_VAR) {
+    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
+    flags = JS_PROP_ENUMERABLE | (def_flags & JS_PROP_WRITABLE) | JS_PROP_CONFIGURABLE;
+    val = JS_UNINITIALIZED;
+  } else {
+    p = JS_VALUE_GET_OBJ(ctx->global_obj);
+    flags = JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | (def_flags & JS_PROP_CONFIGURABLE);
+    val = JS_UNDEFINED;
+  }
+  prs = find_own_property1(p, prop);
+  if (prs)
+    return 0;
+  if (!p->extensible)
+    return 0;
+  pr = add_property(ctx, p, prop, flags);
+  if (unlikely(!pr))
+    return -1;
+  pr->u.value = val;
+  return 0;
+}
+
+/* 'def_flags' is 0 or JS_PROP_CONFIGURABLE. */
+/* XXX: could support exotic global object. */
+int JS_DefineGlobalFunction(JSContext* ctx, JSAtom prop, JSValueConst func, int def_flags) {
+  JSObject* p;
+  JSShapeProperty* prs;
+  int flags;
+
+  p = JS_VALUE_GET_OBJ(ctx->global_obj);
+  prs = find_own_property1(p, prop);
+  flags = JS_PROP_HAS_VALUE | JS_PROP_THROW;
+  if (!prs || (prs->flags & JS_PROP_CONFIGURABLE)) {
+    flags |= JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | def_flags | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE;
+  }
+  if (JS_DefineProperty(ctx, ctx->global_obj, prop, func, JS_UNDEFINED, JS_UNDEFINED, flags) < 0)
+    return -1;
+  return 0;
+}
+
+BOOL JS_IsFunction(JSContext* ctx, JSValueConst val) {
+  JSObject* p;
+  if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
+    return FALSE;
+  p = JS_VALUE_GET_OBJ(val);
+  switch (p->class_id) {
+    case JS_CLASS_BYTECODE_FUNCTION:
+      return TRUE;
+    case JS_CLASS_PROXY:
+      return p->u.proxy_data->is_func;
+    default:
+      return (ctx->rt->class_array[p->class_id].call != NULL);
+  }
+}
+
+BOOL JS_SetConstructorBit(JSContext* ctx, JSValueConst func_obj, BOOL val) {
+  JSObject* p;
+  if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
+    return FALSE;
+  p = JS_VALUE_GET_OBJ(func_obj);
+  p->is_constructor = val;
+  return TRUE;
+}
+
+void JS_SetOpaque(JSValue obj, void* opaque) {
+  JSObject* p;
+  if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
+    p = JS_VALUE_GET_OBJ(obj);
+    p->u.opaque = opaque;
+  }
+}
+
+/* return NULL if not an object of class class_id */
+void* JS_GetOpaque(JSValueConst obj, JSClassID class_id) {
+  JSObject* p;
+  if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
+    return NULL;
+  p = JS_VALUE_GET_OBJ(obj);
+  if (p->class_id != class_id)
+    return NULL;
+  return p->u.opaque;
+}
+
+void* JS_GetOpaque2(JSContext* ctx, JSValueConst obj, JSClassID class_id) {
+  void* p = JS_GetOpaque(obj, class_id);
+  if (unlikely(!p)) {
+    JS_ThrowTypeErrorInvalidClass(ctx, class_id);
+  }
+  return p;
+}
+
+JSValue JS_GetGlobalObject(JSContext *ctx)
+{
+  return JS_DupValue(ctx, ctx->global_obj);
+}
+
+JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,
+                            int length, int magic, int data_len,
+                            JSValueConst *data)
+{
+  JSCFunctionDataRecord *s;
+  JSValue func_obj;
+  int i;
+
+  func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
+                                    JS_CLASS_C_FUNCTION_DATA);
+  if (JS_IsException(func_obj))
+    return func_obj;
+  s = js_malloc(ctx, sizeof(*s) + data_len * sizeof(JSValue));
+  if (!s) {
+    JS_FreeValue(ctx, func_obj);
+    return JS_EXCEPTION;
+  }
+  s->func = func;
+  s->length = length;
+  s->data_len = data_len;
+  s->magic = magic;
+  for(i = 0; i < data_len; i++)
+    s->data[i] = JS_DupValue(ctx, data[i]);
+  JS_SetOpaque(func_obj, s);
+  js_function_set_properties(ctx, func_obj,
+                             JS_ATOM_empty_string, length);
+  return func_obj;
+}
+
+/* compute the property flags. For each flag: (JS_PROP_HAS_x forces
+   it, otherwise def_flags is used)
+   Note: makes assumption about the bit pattern of the flags
+*/
+int get_prop_flags(int flags, int def_flags) {
+  int mask;
+  mask = (flags >> JS_PROP_HAS_SHIFT) & JS_PROP_C_W_E;
+  return (flags & mask) | (def_flags & ~mask);
+}
+
+
+/* set the array length and remove the array elements if necessary. */
+int set_array_length(JSContext *ctx, JSObject *p, JSValue val,
+                            int flags)
+{
+  uint32_t len, idx, cur_len;
+  int i, ret;
+
+  /* Note: this call can reallocate the properties of 'p' */
+  ret = JS_ToArrayLengthFree(ctx, &len, val, FALSE);
+  if (ret)
+    return -1;
+  /* JS_ToArrayLengthFree() must be done before the read-only test */
+  if (unlikely(!(p->shape->prop[0].flags & JS_PROP_WRITABLE)))
+    return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
+
+  if (likely(p->fast_array)) {
+    uint32_t old_len = p->u.array.count;
+    if (len < old_len) {
+      for(i = len; i < old_len; i++) {
+        JS_FreeValue(ctx, p->u.array.u.values[i]);
+      }
+      p->u.array.count = len;
+    }
+    p->prop[0].u.value = JS_NewUint32(ctx, len);
+  } else {
+    /* Note: length is always a uint32 because the object is an
+       array */
+    JS_ToUint32(ctx, &cur_len, p->prop[0].u.value);
+    if (len < cur_len) {
+      uint32_t d;
+      JSShape *sh;
+      JSShapeProperty *pr;
+
+      d = cur_len - len;
+      sh = p->shape;
+      if (d <= sh->prop_count) {
+        JSAtom atom;
+
+        /* faster to iterate */
+        while (cur_len > len) {
+          atom = JS_NewAtomUInt32(ctx, cur_len - 1);
+          ret = delete_property(ctx, p, atom);
+          JS_FreeAtom(ctx, atom);
+          if (unlikely(!ret)) {
+            /* unlikely case: property is not
+               configurable */
+            break;
+          }
+          cur_len--;
+        }
+      } else {
+        /* faster to iterate thru all the properties. Need two
+           passes in case one of the property is not
+           configurable */
+        cur_len = len;
+        for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count;
+             i++, pr++) {
+          if (pr->atom != JS_ATOM_NULL &&
+              JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) {
+            if (idx >= cur_len &&
+                !(pr->flags & JS_PROP_CONFIGURABLE)) {
+              cur_len = idx + 1;
+            }
+          }
+        }
+
+        for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count;
+             i++, pr++) {
+          if (pr->atom != JS_ATOM_NULL &&
+              JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) {
+            if (idx >= cur_len) {
+              /* remove the property */
+              delete_property(ctx, p, pr->atom);
+              /* WARNING: the shape may have been modified */
+              sh = p->shape;
+              pr = get_shape_prop(sh) + i;
+            }
+          }
+        }
+      }
+    } else {
+      cur_len = len;
+    }
+    set_value(ctx, &p->prop[0].u.value, JS_NewUint32(ctx, cur_len));
+    if (unlikely(cur_len > len)) {
+      return JS_ThrowTypeErrorOrFalse(ctx, flags, "not configurable");
+    }
+  }
+  return TRUE;
+}
+
+/* WARNING: 'p' must be a typed array. Works even if the array buffer
+   is detached */
+uint32_t typed_array_get_length(JSContext* ctx, JSObject* p) {
+  JSTypedArray* ta = p->u.typed_array;
+  int size_log2 = typed_array_size_log2(p->class_id);
+  return ta->length >> size_log2;
+}
+
+/* Preconditions: 'p' must be of class JS_CLASS_ARRAY, p->fast_array =
+   TRUE and p->extensible = TRUE */
+int add_fast_array_element(JSContext* ctx, JSObject* p, JSValue val, int flags) {
+  uint32_t new_len, array_len;
+  /* extend the array by one */
+  /* XXX: convert to slow array if new_len > 2^31-1 elements */
+  new_len = p->u.array.count + 1;
+  /* update the length if necessary. We assume that if the length is
+     not an integer, then if it >= 2^31.  */
+  if (likely(JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT)) {
+    array_len = JS_VALUE_GET_INT(p->prop[0].u.value);
+    if (new_len > array_len) {
+      if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE))) {
+        JS_FreeValue(ctx, val);
+        return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
+      }
+      p->prop[0].u.value = JS_NewInt32(ctx, new_len);
+    }
+  }
+  if (unlikely(new_len > p->u.array.u1.size)) {
+    if (expand_fast_array(ctx, p, new_len)) {
+      JS_FreeValue(ctx, val);
+      return -1;
+    }
+  }
+  p->u.array.u.values[new_len - 1] = val;
+  p->u.array.count = new_len;
+  return TRUE;
+}
+
+int JS_CreateProperty(JSContext* ctx, JSObject* p, JSAtom prop, JSValueConst val, JSValueConst getter, JSValueConst setter, int flags) {
+  JSProperty* pr;
+  int ret, prop_flags;
+
+  /* add a new property or modify an existing exotic one */
+  if (p->is_exotic) {
+    if (p->class_id == JS_CLASS_ARRAY) {
+      uint32_t idx, len;
+
+      if (p->fast_array) {
+        if (__JS_AtomIsTaggedInt(prop)) {
+          idx = __JS_AtomToUInt32(prop);
+          if (idx == p->u.array.count) {
+            if (!p->extensible)
+              goto not_extensible;
+            if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET))
+              goto convert_to_array;
+            prop_flags = get_prop_flags(flags, 0);
+            if (prop_flags != JS_PROP_C_W_E)
+              goto convert_to_array;
+            return add_fast_array_element(ctx, p, JS_DupValue(ctx, val), flags);
+          } else {
+            goto convert_to_array;
+          }
+        } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) {
+          /* convert the fast array to normal array */
+        convert_to_array:
+          if (convert_fast_array_to_array(ctx, p))
+            return -1;
+          goto generic_array;
+        }
+      } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) {
+        JSProperty* plen;
+        JSShapeProperty* pslen;
+      generic_array:
+        /* update the length field */
+        plen = &p->prop[0];
+        JS_ToUint32(ctx, &len, plen->u.value);
+        if ((idx + 1) > len) {
+          pslen = get_shape_prop(p->shape);
+          if (unlikely(!(pslen->flags & JS_PROP_WRITABLE)))
+            return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
+          /* XXX: should update the length after defining
+             the property */
+          len = idx + 1;
+          set_value(ctx, &plen->u.value, JS_NewUint32(ctx, len));
+        }
+      }
+    } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
+      ret = JS_AtomIsNumericIndex(ctx, prop);
+      if (ret != 0) {
+        if (ret < 0)
+          return -1;
+        return JS_ThrowTypeErrorOrFalse(ctx, flags, "cannot create numeric index in typed array");
+      }
+    } else if (!(flags & JS_PROP_NO_EXOTIC)) {
+      const JSClassExoticMethods* em = ctx->rt->class_array[p->class_id].exotic;
+      if (em) {
+        if (em->define_own_property) {
+          return em->define_own_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), prop, val, getter, setter, flags);
+        }
+        ret = JS_IsExtensible(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+        if (ret < 0)
+          return -1;
+        if (!ret)
+          goto not_extensible;
+      }
+    }
+  }
+
+  if (!p->extensible) {
+  not_extensible:
+    return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible");
+  }
+
+  if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
+    prop_flags = (flags & (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) | JS_PROP_GETSET;
+  } else {
+    prop_flags = flags & JS_PROP_C_W_E;
+  }
+  pr = add_property(ctx, p, prop, prop_flags);
+  if (unlikely(!pr))
+    return -1;
+  if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
+    pr->u.getset.getter = NULL;
+    if ((flags & JS_PROP_HAS_GET) && JS_IsFunction(ctx, getter)) {
+      pr->u.getset.getter = JS_VALUE_GET_OBJ(JS_DupValue(ctx, getter));
+    }
+    pr->u.getset.setter = NULL;
+    if ((flags & JS_PROP_HAS_SET) && JS_IsFunction(ctx, setter)) {
+      pr->u.getset.setter = JS_VALUE_GET_OBJ(JS_DupValue(ctx, setter));
+    }
+  } else {
+    if (flags & JS_PROP_HAS_VALUE) {
+      pr->u.value = JS_DupValue(ctx, val);
+    } else {
+      pr->u.value = JS_UNDEFINED;
+    }
+  }
+  return TRUE;
+}
+
+/* return TRUE, FALSE or (-1) in case of exception */
+int JS_OrdinaryIsInstanceOf(JSContext* ctx, JSValueConst val, JSValueConst obj) {
+  JSValue obj_proto;
+  JSObject* proto;
+  const JSObject *p, *proto1;
+  BOOL ret;
+
+  if (!JS_IsFunction(ctx, obj))
+    return FALSE;
+  p = JS_VALUE_GET_OBJ(obj);
+  if (p->class_id == JS_CLASS_BOUND_FUNCTION) {
+    JSBoundFunction* s = p->u.bound_function;
+    return JS_IsInstanceOf(ctx, val, s->func_obj);
+  }
+
+  /* Only explicitly boxed values are instances of constructors */
+  if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
+    return FALSE;
+  obj_proto = JS_GetProperty(ctx, obj, JS_ATOM_prototype);
+  if (JS_VALUE_GET_TAG(obj_proto) != JS_TAG_OBJECT) {
+    if (!JS_IsException(obj_proto))
+      JS_ThrowTypeError(ctx, "operand 'prototype' property is not an object");
+    ret = -1;
+    goto done;
+  }
+  proto = JS_VALUE_GET_OBJ(obj_proto);
+  p = JS_VALUE_GET_OBJ(val);
+  for (;;) {
+    proto1 = p->shape->proto;
+    if (!proto1) {
+      /* slow case if proxy in the prototype chain */
+      if (unlikely(p->class_id == JS_CLASS_PROXY)) {
+        JSValue obj1;
+        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, (JSObject*)p));
+        for (;;) {
+          obj1 = JS_GetPrototypeFree(ctx, obj1);
+          if (JS_IsException(obj1)) {
+            ret = -1;
+            break;
+          }
+          if (JS_IsNull(obj1)) {
+            ret = FALSE;
+            break;
+          }
+          if (proto == JS_VALUE_GET_OBJ(obj1)) {
+            JS_FreeValue(ctx, obj1);
+            ret = TRUE;
+            break;
+          }
+          /* must check for timeout to avoid infinite loop */
+          if (js_poll_interrupts(ctx)) {
+            JS_FreeValue(ctx, obj1);
+            ret = -1;
+            break;
+          }
+        }
+      } else {
+        ret = FALSE;
+      }
+      break;
+    }
+    p = proto1;
+    if (proto == p) {
+      ret = TRUE;
+      break;
+    }
+  }
+done:
+  JS_FreeValue(ctx, obj_proto);
+  return ret;
+}
+
+JSContext* js_autoinit_get_realm(JSProperty* pr) {
+  return (JSContext*)(pr->u.init.realm_and_id & ~3);
+}
+
+JSAutoInitIDEnum js_autoinit_get_id(JSProperty* pr) {
+  return pr->u.init.realm_and_id & 3;
+}
+
+void js_autoinit_free(JSRuntime* rt, JSProperty* pr) {
+  JS_FreeContext(js_autoinit_get_realm(pr));
+}
+
+void js_autoinit_mark(JSRuntime* rt, JSProperty* pr, JS_MarkFunc* mark_func) {
+  mark_func(rt, &js_autoinit_get_realm(pr)->header);
+}
+
+/* return TRUE, FALSE or (-1) in case of exception */
+int JS_IsInstanceOf(JSContext* ctx, JSValueConst val, JSValueConst obj) {
+  JSValue method;
+
+  if (!JS_IsObject(obj))
+    goto fail;
+  method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_hasInstance);
+  if (JS_IsException(method))
+    return -1;
+  if (!JS_IsNull(method) && !JS_IsUndefined(method)) {
+    JSValue ret;
+    ret = JS_CallFree(ctx, method, obj, 1, &val);
+    return JS_ToBoolFree(ctx, ret);
+  }
+
+  /* legacy case */
+  if (!JS_IsFunction(ctx, obj)) {
+  fail:
+    JS_ThrowTypeError(ctx, "invalid 'instanceof' right operand");
+    return -1;
+  }
+  return JS_OrdinaryIsInstanceOf(ctx, val, obj);
+}
+
+/* in order to avoid executing arbitrary code during the stack trace
+   generation, we only look at simple 'name' properties containing a
+   string. */
+const char* get_func_name(JSContext* ctx, JSValueConst func) {
+  JSProperty* pr;
+  JSShapeProperty* prs;
+  JSValueConst val;
+
+  if (JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)
+    return NULL;
+  prs = find_own_property(&pr, JS_VALUE_GET_OBJ(func), JS_ATOM_name);
+  if (!prs)
+    return NULL;
+  if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
+    return NULL;
+  val = pr->u.value;
+  if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
+    return NULL;
+  return JS_ToCString(ctx, val);
+}
+
+/* if filename != NULL, an additional level is added with the filename
+   and line number information (used for parse error). */
+void build_backtrace(JSContext* ctx, JSValueConst error_obj, const char* filename, int line_num, int backtrace_flags) {
+  JSStackFrame* sf;
+  JSValue str;
+  DynBuf dbuf;
+  const char* func_name_str;
+  const char* str1;
+  JSObject* p;
+  BOOL backtrace_barrier;
+
+  js_dbuf_init(ctx, &dbuf);
+  if (filename) {
+    dbuf_printf(&dbuf, "    at %s", filename);
+    if (line_num != -1)
+      dbuf_printf(&dbuf, ":%d", line_num);
+    dbuf_putc(&dbuf, '\n');
+    str = JS_NewString(ctx, filename);
+    JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_fileName, str, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+    JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_lineNumber, JS_NewInt32(ctx, line_num), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+    if (backtrace_flags & JS_BACKTRACE_FLAG_SINGLE_LEVEL)
+      goto done;
+  }
+  for (sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) {
+    if (backtrace_flags & JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL) {
+      backtrace_flags &= ~JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL;
+      continue;
+    }
+    func_name_str = get_func_name(ctx, sf->cur_func);
+    if (!func_name_str || func_name_str[0] == '\0')
+      str1 = "<anonymous>";
+    else
+      str1 = func_name_str;
+    dbuf_printf(&dbuf, "    at %s", str1);
+    JS_FreeCString(ctx, func_name_str);
+
+    p = JS_VALUE_GET_OBJ(sf->cur_func);
+    backtrace_barrier = FALSE;
+    if (js_class_has_bytecode(p->class_id)) {
+      JSFunctionBytecode* b;
+      const char* atom_str;
+      int line_num1;
+
+      b = p->u.func.function_bytecode;
+      backtrace_barrier = b->backtrace_barrier;
+      if (b->has_debug) {
+        line_num1 = find_line_num(ctx, b, sf->cur_pc - b->byte_code_buf - 1);
+        atom_str = JS_AtomToCString(ctx, b->debug.filename);
+        dbuf_printf(&dbuf, " (%s", atom_str ? atom_str : "<null>");
+        JS_FreeCString(ctx, atom_str);
+        if (line_num1 != -1)
+          dbuf_printf(&dbuf, ":%d", line_num1);
+        dbuf_putc(&dbuf, ')');
+      }
+    } else {
+      dbuf_printf(&dbuf, " (native)");
+    }
+    dbuf_putc(&dbuf, '\n');
+    /* stop backtrace if JS_EVAL_FLAG_BACKTRACE_BARRIER was used */
+    if (backtrace_barrier)
+      break;
+  }
+done:
+  dbuf_putc(&dbuf, '\0');
+  if (dbuf_error(&dbuf))
+    str = JS_NULL;
+  else
+    str = JS_NewString(ctx, (char*)dbuf.buf);
+  dbuf_free(&dbuf);
+  JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_stack, str, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+}
+
+/* Note: it is important that no exception is returned by this function */
+BOOL is_backtrace_needed(JSContext* ctx, JSValueConst obj) {
+  JSObject* p;
+  if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
+    return FALSE;
+  p = JS_VALUE_GET_OBJ(obj);
+  if (p->class_id != JS_CLASS_ERROR)
+    return FALSE;
+  if (find_own_property1(p, JS_ATOM_stack))
+    return FALSE;
+  return TRUE;
+}
+
+no_inline __exception int __js_poll_interrupts(JSContext* ctx) {
+  JSRuntime* rt = ctx->rt;
+  ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT;
+  if (rt->interrupt_handler) {
+    if (rt->interrupt_handler(rt, rt->interrupt_opaque)) {
+      /* XXX: should set a specific flag to avoid catching */
+      JS_ThrowInternalError(ctx, "interrupted");
+      JS_SetUncatchableError(ctx, ctx->rt->current_exception, TRUE);
+      return -1;
+    }
+  }
+  return 0;
+}
+
+int check_function(JSContext* ctx, JSValueConst obj) {
+  if (likely(JS_IsFunction(ctx, obj)))
+    return 0;
+  JS_ThrowTypeError(ctx, "not a function");
+  return -1;
+}
+
+int check_exception_free(JSContext* ctx, JSValue obj) {
+  JS_FreeValue(ctx, obj);
+  return JS_IsException(obj);
+}
+
+JSAtom find_atom(JSContext* ctx, const char* name) {
+  JSAtom atom;
+  int len;
+
+  if (*name == '[') {
+    name++;
+    len = strlen(name) - 1;
+    /* We assume 8 bit non null strings, which is the case for these
+       symbols */
+    for (atom = JS_ATOM_Symbol_toPrimitive; atom <= JS_ATOM_Symbol_asyncIterator; atom++) {
+      JSAtomStruct* p = ctx->rt->atom_array[atom];
+      JSString* str = p;
+      if (str->len == len && !memcmp(str->u.str8, name, len))
+        return JS_DupAtom(ctx, atom);
+    }
+    abort();
+  } else {
+    atom = JS_NewAtom(ctx, name);
+  }
+  return atom;
+}
+
+JSValue JS_InstantiateFunctionListItem2(JSContext* ctx, JSObject* p, JSAtom atom, void* opaque) {
+  const JSCFunctionListEntry* e = opaque;
+  JSValue val;
+
+  switch (e->def_type) {
+    case JS_DEF_CFUNC:
+      val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic, e->name, e->u.func.length, e->u.func.cproto, e->magic);
+      break;
+    case JS_DEF_PROP_STRING:
+      val = JS_NewAtomString(ctx, e->u.str);
+      break;
+    case JS_DEF_OBJECT:
+      val = JS_NewObject(ctx);
+      JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len);
+      break;
+    default:
+      abort();
+  }
+  return val;
+}
+
+int JS_InstantiateFunctionListItem(JSContext* ctx, JSValueConst obj, JSAtom atom, const JSCFunctionListEntry* e) {
+  JSValue val;
+  int prop_flags = e->prop_flags;
+
+  switch (e->def_type) {
+    case JS_DEF_ALIAS: /* using autoinit for aliases is not safe */
+    {
+      JSAtom atom1 = find_atom(ctx, e->u.alias.name);
+      switch (e->u.alias.base) {
+        case -1:
+          val = JS_GetProperty(ctx, obj, atom1);
+          break;
+        case 0:
+          val = JS_GetProperty(ctx, ctx->global_obj, atom1);
+          break;
+        case 1:
+          val = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], atom1);
+          break;
+        default:
+          abort();
+      }
+      JS_FreeAtom(ctx, atom1);
+      if (atom == JS_ATOM_Symbol_toPrimitive) {
+        /* Symbol.toPrimitive functions are not writable */
+        prop_flags = JS_PROP_CONFIGURABLE;
+      } else if (atom == JS_ATOM_Symbol_hasInstance) {
+        /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */
+        prop_flags = 0;
+      }
+    } break;
+    case JS_DEF_CFUNC:
+      if (atom == JS_ATOM_Symbol_toPrimitive) {
+        /* Symbol.toPrimitive functions are not writable */
+        prop_flags = JS_PROP_CONFIGURABLE;
+      } else if (atom == JS_ATOM_Symbol_hasInstance) {
+        /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */
+        prop_flags = 0;
+      }
+      JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP, (void*)e, prop_flags);
+      return 0;
+    case JS_DEF_CGETSET: /* XXX: use autoinit again ? */
+    case JS_DEF_CGETSET_MAGIC: {
+      JSValue getter, setter;
+      char buf[64];
+
+      getter = JS_UNDEFINED;
+      if (e->u.getset.get.generic) {
+        snprintf(buf, sizeof(buf), "get %s", e->name);
+        getter = JS_NewCFunction2(ctx, e->u.getset.get.generic, buf, 0, e->def_type == JS_DEF_CGETSET_MAGIC ? JS_CFUNC_getter_magic : JS_CFUNC_getter, e->magic);
+      }
+      setter = JS_UNDEFINED;
+      if (e->u.getset.set.generic) {
+        snprintf(buf, sizeof(buf), "set %s", e->name);
+        setter = JS_NewCFunction2(ctx, e->u.getset.set.generic, buf, 1, e->def_type == JS_DEF_CGETSET_MAGIC ? JS_CFUNC_setter_magic : JS_CFUNC_setter, e->magic);
+      }
+      JS_DefinePropertyGetSet(ctx, obj, atom, getter, setter, prop_flags);
+      return 0;
+    } break;
+    case JS_DEF_PROP_INT32:
+      val = JS_NewInt32(ctx, e->u.i32);
+      break;
+    case JS_DEF_PROP_INT64:
+      val = JS_NewInt64(ctx, e->u.i64);
+      break;
+    case JS_DEF_PROP_DOUBLE:
+      val = __JS_NewFloat64(ctx, e->u.f64);
+      break;
+    case JS_DEF_PROP_UNDEFINED:
+      val = JS_UNDEFINED;
+      break;
+    case JS_DEF_PROP_STRING:
+    case JS_DEF_OBJECT:
+      JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP, (void*)e, prop_flags);
+      return 0;
+    default:
+      abort();
+  }
+  JS_DefinePropertyValue(ctx, obj, atom, val, prop_flags);
+  return 0;
+}
+
+void JS_SetPropertyFunctionList(JSContext* ctx, JSValueConst obj, const JSCFunctionListEntry* tab, int len) {
+  int i;
+
+  for (i = 0; i < len; i++) {
+    const JSCFunctionListEntry* e = &tab[i];
+    JSAtom atom = find_atom(ctx, e->name);
+    JS_InstantiateFunctionListItem(ctx, obj, atom, e);
+    JS_FreeAtom(ctx, atom);
+  }
+}
+
+int JS_AddModuleExportList(JSContext* ctx, JSModuleDef* m, const JSCFunctionListEntry* tab, int len) {
+  int i;
+  for (i = 0; i < len; i++) {
+    if (JS_AddModuleExport(ctx, m, tab[i].name))
+      return -1;
+  }
+  return 0;
+}
+
+int JS_SetModuleExportList(JSContext* ctx, JSModuleDef* m, const JSCFunctionListEntry* tab, int len) {
+  int i;
+  JSValue val;
+
+  for (i = 0; i < len; i++) {
+    const JSCFunctionListEntry* e = &tab[i];
+    switch (e->def_type) {
+      case JS_DEF_CFUNC:
+        val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic, e->name, e->u.func.length, e->u.func.cproto, e->magic);
+        break;
+      case JS_DEF_PROP_STRING:
+        val = JS_NewString(ctx, e->u.str);
+        break;
+      case JS_DEF_PROP_INT32:
+        val = JS_NewInt32(ctx, e->u.i32);
+        break;
+      case JS_DEF_PROP_INT64:
+        val = JS_NewInt64(ctx, e->u.i64);
+        break;
+      case JS_DEF_PROP_DOUBLE:
+        val = __JS_NewFloat64(ctx, e->u.f64);
+        break;
+      case JS_DEF_OBJECT:
+        val = JS_NewObject(ctx);
+        JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len);
+        break;
+      default:
+        abort();
+    }
+    if (JS_SetModuleExport(ctx, m, e->name, val))
+      return -1;
+  }
+  return 0;
+}
+
+/* Note: 'func_obj' is not necessarily a constructor */
+void JS_SetConstructor2(JSContext* ctx, JSValueConst func_obj, JSValueConst proto, int proto_flags, int ctor_flags) {
+  JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype, JS_DupValue(ctx, proto), proto_flags);
+  JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor, JS_DupValue(ctx, func_obj), ctor_flags);
+  set_cycle_flag(ctx, func_obj);
+  set_cycle_flag(ctx, proto);
+}
+
+void JS_SetConstructor(JSContext* ctx, JSValueConst func_obj, JSValueConst proto) {
+  JS_SetConstructor2(ctx, func_obj, proto, 0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+}
+
+JSValue iterator_to_array(JSContext* ctx, JSValueConst items) {
+  JSValue iter, next_method = JS_UNDEFINED;
+  JSValue v, r = JS_UNDEFINED;
+  int64_t k;
+  BOOL done;
+
+  iter = JS_GetIterator(ctx, items, FALSE);
+  if (JS_IsException(iter))
+    goto exception;
+  next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
+  if (JS_IsException(next_method))
+    goto exception;
+  r = JS_NewArray(ctx);
+  if (JS_IsException(r))
+    goto exception;
+  for (k = 0;; k++) {
+    v = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
+    if (JS_IsException(v))
+      goto exception_close;
+    if (done)
+      break;
+    if (JS_DefinePropertyValueInt64(ctx, r, k, v, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
+      goto exception_close;
+  }
+done:
+  JS_FreeValue(ctx, next_method);
+  JS_FreeValue(ctx, iter);
+  return r;
+exception_close:
+  JS_IteratorClose(ctx, iter, TRUE);
+exception:
+  JS_FreeValue(ctx, r);
+  r = JS_EXCEPTION;
+  goto done;
+}
+
+/* only valid inside C functions */
+JSValueConst JS_GetActiveFunction(JSContext* ctx) {
+  return ctx->rt->current_stack_frame->cur_func;
+}
+
+JSValue js_error_constructor(JSContext* ctx, JSValueConst new_target, int argc, JSValueConst* argv, int magic) {
+  JSValue obj, msg, proto;
+  JSValueConst message;
+
+  if (JS_IsUndefined(new_target))
+    new_target = JS_GetActiveFunction(ctx);
+  proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);
+  if (JS_IsException(proto))
+    return proto;
+  if (!JS_IsObject(proto)) {
+    JSContext* realm;
+    JSValueConst proto1;
+
+    JS_FreeValue(ctx, proto);
+    realm = JS_GetFunctionRealm(ctx, new_target);
+    if (!realm)
+      return JS_EXCEPTION;
+    if (magic < 0) {
+      proto1 = realm->class_proto[JS_CLASS_ERROR];
+    } else {
+      proto1 = realm->native_error_proto[magic];
+    }
+    proto = JS_DupValue(ctx, proto1);
+  }
+  obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_ERROR);
+  JS_FreeValue(ctx, proto);
+  if (JS_IsException(obj))
+    return obj;
+  if (magic == JS_AGGREGATE_ERROR) {
+    message = argv[1];
+  } else {
+    message = argv[0];
+  }
+
+  if (!JS_IsUndefined(message)) {
+    msg = JS_ToString(ctx, message);
+    if (unlikely(JS_IsException(msg)))
+      goto exception;
+    JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, msg, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+  }
+
+  if (magic == JS_AGGREGATE_ERROR) {
+    JSValue error_list = iterator_to_array(ctx, argv[0]);
+    if (JS_IsException(error_list))
+      goto exception;
+    JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, error_list, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+  }
+
+  /* skip the Error() function in the backtrace */
+  build_backtrace(ctx, obj, NULL, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL);
+  return obj;
+exception:
+  JS_FreeValue(ctx, obj);
+  return JS_EXCEPTION;
+}
+
+JSValue js_aggregate_error_constructor(JSContext* ctx, JSValueConst errors) {
+  JSValue obj;
+
+  obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[JS_AGGREGATE_ERROR], JS_CLASS_ERROR);
+  if (JS_IsException(obj))
+    return obj;
+  JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, JS_DupValue(ctx, errors), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+  return obj;
+}
+
+JSValue js_error_toString(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue name, msg;
+
+  if (!JS_IsObject(this_val))
+    return JS_ThrowTypeErrorNotAnObject(ctx);
+  name = JS_GetProperty(ctx, this_val, JS_ATOM_name);
+  if (JS_IsUndefined(name))
+    name = JS_AtomToString(ctx, JS_ATOM_Error);
+  else
+    name = JS_ToStringFree(ctx, name);
+  if (JS_IsException(name))
+    return JS_EXCEPTION;
+
+  msg = JS_GetProperty(ctx, this_val, JS_ATOM_message);
+  if (JS_IsUndefined(msg))
+    msg = JS_AtomToString(ctx, JS_ATOM_empty_string);
+  else
+    msg = JS_ToStringFree(ctx, msg);
+  if (JS_IsException(msg)) {
+    JS_FreeValue(ctx, name);
+    return JS_EXCEPTION;
+  }
+  if (!JS_IsEmptyString(name) && !JS_IsEmptyString(msg))
+    name = JS_ConcatString3(ctx, "", name, ": ");
+  return JS_ConcatString(ctx, name, msg);
+}
+
+static const JSCFunctionListEntry js_error_proto_funcs[] = {
+    JS_CFUNC_DEF("toString", 0, js_error_toString),
+    JS_PROP_STRING_DEF("name", "Error", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE),
+    JS_PROP_STRING_DEF("message", "", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE),
+};
+
+void JS_NewGlobalCConstructor2(JSContext* ctx, JSValue func_obj, const char* name, JSValueConst proto) {
+  JS_DefinePropertyValueStr(ctx, ctx->global_obj, name, JS_DupValue(ctx, func_obj), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+  JS_SetConstructor(ctx, func_obj, proto);
+  JS_FreeValue(ctx, func_obj);
+}
+
+JSValueConst JS_NewGlobalCConstructor(JSContext* ctx, const char* name, JSCFunction* func, int length, JSValueConst proto) {
+  JSValue func_obj;
+  func_obj = JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_constructor_or_func, 0);
+  JS_NewGlobalCConstructor2(ctx, func_obj, name, proto);
+  return func_obj;
+}
+
+JSValueConst JS_NewGlobalCConstructorOnly(JSContext* ctx, const char* name, JSCFunction* func, int length, JSValueConst proto) {
+  JSValue func_obj;
+  func_obj = JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_constructor, 0);
+  JS_NewGlobalCConstructor2(ctx, func_obj, name, proto);
+  return func_obj;
+}
+
+void* JS_GetRuntimeOpaque(JSRuntime* rt) {
+  return rt->user_opaque;
+}
+
+void JS_SetRuntimeOpaque(JSRuntime* rt, void* opaque) {
+  rt->user_opaque = opaque;
+}
+
+void JS_SetMemoryLimit(JSRuntime* rt, size_t limit) {
+  rt->malloc_state.malloc_limit = limit;
+}
+
+void JS_SetInterruptHandler(JSRuntime* rt, JSInterruptHandler* cb, void* opaque) {
+  rt->interrupt_handler = cb;
+  rt->interrupt_opaque = opaque;
+}
+
+void JS_SetCanBlock(JSRuntime* rt, BOOL can_block) {
+  rt->can_block = can_block;
+}
+
+void JS_SetSharedArrayBufferFunctions(JSRuntime* rt, const JSSharedArrayBufferFunctions* sf) {
+  rt->sab_funcs = *sf;
+}
+
+/* return 0 if OK, < 0 if exception */
+int JS_EnqueueJob(JSContext* ctx, JSJobFunc* job_func, int argc, JSValueConst* argv) {
+  JSRuntime* rt = ctx->rt;
+  JSJobEntry* e;
+  int i;
+
+  e = js_malloc(ctx, sizeof(*e) + argc * sizeof(JSValue));
+  if (!e)
+    return -1;
+  e->ctx = ctx;
+  e->job_func = job_func;
+  e->argc = argc;
+  for (i = 0; i < argc; i++) {
+    e->argv[i] = JS_DupValue(ctx, argv[i]);
+  }
+  list_add_tail(&e->link, &rt->job_list);
+  return 0;
+}
+
+BOOL JS_IsJobPending(JSRuntime* rt) {
+  return !list_empty(&rt->job_list);
+}
+
+/* return < 0 if exception, 0 if no job pending, 1 if a job was
+   executed successfully. the context of the job is stored in '*pctx' */
+int JS_ExecutePendingJob(JSRuntime* rt, JSContext** pctx) {
+  JSContext* ctx;
+  JSJobEntry* e;
+  JSValue res;
+  int i, ret;
+
+  if (list_empty(&rt->job_list)) {
+    *pctx = NULL;
+    return 0;
+  }
+
+  /* get the first pending job and execute it */
+  e = list_entry(rt->job_list.next, JSJobEntry, link);
+  list_del(&e->link);
+  ctx = e->ctx;
+  res = e->job_func(e->ctx, e->argc, (JSValueConst*)e->argv);
+  for (i = 0; i < e->argc; i++)
+    JS_FreeValue(ctx, e->argv[i]);
+  if (JS_IsException(res))
+    ret = -1;
+  else
+    ret = 1;
+  JS_FreeValue(ctx, res);
+  js_free(ctx, e);
+  *pctx = ctx;
+  return ret;
+}
+
+void JS_SetClassProto(JSContext* ctx, JSClassID class_id, JSValue obj) {
+  JSRuntime* rt = ctx->rt;
+  assert(class_id < rt->class_count);
+  set_value(ctx, &ctx->class_proto[class_id], obj);
+}
+
+JSValue JS_GetClassProto(JSContext* ctx, JSClassID class_id) {
+  JSRuntime* rt = ctx->rt;
+  assert(class_id < rt->class_count);
+  return JS_DupValue(ctx, ctx->class_proto[class_id]);
+}
+
+static JSObject* get_proto_obj(JSValueConst proto_val) {
+  if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT)
+    return NULL;
+  else
+    return JS_VALUE_GET_OBJ(proto_val);
+}
+
+JSValue JS_NewArray(JSContext* ctx) {
+  return JS_NewObjectFromShape(ctx, js_dup_shape(ctx->array_shape), JS_CLASS_ARRAY);
+}
+
+/* WARNING: proto must be an object or JS_NULL */
+JSValue JS_NewObjectProtoClass(JSContext* ctx, JSValueConst proto_val, JSClassID class_id) {
+  JSShape* sh;
+  JSObject* proto;
+
+  proto = get_proto_obj(proto_val);
+  sh = find_hashed_shape_proto(ctx->rt, proto);
+  if (likely(sh)) {
+    sh = js_dup_shape(sh);
+  } else {
+    sh = js_new_shape(ctx, proto);
+    if (!sh)
+      return JS_EXCEPTION;
+  }
+  return JS_NewObjectFromShape(ctx, sh, class_id);
+}
+
+JSValue js_global_eval(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  return JS_EvalObject(ctx, ctx->global_obj, argv[0], JS_EVAL_TYPE_INDIRECT, -1);
+}
+
+JSValue js_global_isNaN(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  double d;
+
+  /* XXX: does this work for bigfloat? */
+  if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
+    return JS_EXCEPTION;
+  return JS_NewBool(ctx, isnan(d));
+}
+
+JSValue js_global_isFinite(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  BOOL res;
+  double d;
+  if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
+    return JS_EXCEPTION;
+  res = isfinite(d);
+  return JS_NewBool(ctx, res);
+}
+
+static const char* const native_error_name[JS_NATIVE_ERROR_COUNT] = {
+    "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", "URIError", "InternalError", "AggregateError",
+};
+
+/* URI handling */
+
+int string_get_hex(JSString* p, int k, int n) {
+  int c = 0, h;
+  while (n-- > 0) {
+    if ((h = from_hex(string_get(p, k++))) < 0)
+      return -1;
+    c = (c << 4) | h;
+  }
+  return c;
+}
+
+static int isURIReserved(int c) {
+  return c < 0x100 && memchr(";/?:@&=+$,#", c, sizeof(";/?:@&=+$,#") - 1) != NULL;
+}
+
+static int __attribute__((format(printf, 2, 3))) js_throw_URIError(JSContext* ctx, const char* fmt, ...) {
+  va_list ap;
+
+  va_start(ap, fmt);
+  JS_ThrowError(ctx, JS_URI_ERROR, fmt, ap);
+  va_end(ap);
+  return -1;
+}
+
+static int hex_decode(JSContext* ctx, JSString* p, int k) {
+  int c;
+
+  if (k >= p->len || string_get(p, k) != '%')
+    return js_throw_URIError(ctx, "expecting %%");
+  if (k + 2 >= p->len || (c = string_get_hex(p, k + 1, 2)) < 0)
+    return js_throw_URIError(ctx, "expecting hex digit");
+
+  return c;
+}
+
+static JSValue js_global_decodeURI(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int isComponent) {
+  JSValue str;
+  StringBuffer b_s, *b = &b_s;
+  JSString* p;
+  int k, c, c1, n, c_min;
+
+  str = JS_ToString(ctx, argv[0]);
+  if (JS_IsException(str))
+    return str;
+
+  string_buffer_init(ctx, b, 0);
+
+  p = JS_VALUE_GET_STRING(str);
+  for (k = 0; k < p->len;) {
+    c = string_get(p, k);
+    if (c == '%') {
+      c = hex_decode(ctx, p, k);
+      if (c < 0)
+        goto fail;
+      k += 3;
+      if (c < 0x80) {
+        if (!isComponent && isURIReserved(c)) {
+          c = '%';
+          k -= 2;
+        }
+      } else {
+        /* Decode URI-encoded UTF-8 sequence */
+        if (c >= 0xc0 && c <= 0xdf) {
+          n = 1;
+          c_min = 0x80;
+          c &= 0x1f;
+        } else if (c >= 0xe0 && c <= 0xef) {
+          n = 2;
+          c_min = 0x800;
+          c &= 0xf;
+        } else if (c >= 0xf0 && c <= 0xf7) {
+          n = 3;
+          c_min = 0x10000;
+          c &= 0x7;
+        } else {
+          n = 0;
+          c_min = 1;
+          c = 0;
+        }
+        while (n-- > 0) {
+          c1 = hex_decode(ctx, p, k);
+          if (c1 < 0)
+            goto fail;
+          k += 3;
+          if ((c1 & 0xc0) != 0x80) {
+            c = 0;
+            break;
+          }
+          c = (c << 6) | (c1 & 0x3f);
+        }
+        if (c < c_min || c > 0x10FFFF || (c >= 0xd800 && c < 0xe000)) {
+          js_throw_URIError(ctx, "malformed UTF-8");
+          goto fail;
+        }
+      }
+    } else {
+      k++;
+    }
+    string_buffer_putc(b, c);
+  }
+  JS_FreeValue(ctx, str);
+  return string_buffer_end(b);
+
+fail:
+  JS_FreeValue(ctx, str);
+  string_buffer_free(b);
+  return JS_EXCEPTION;
+}
+
+static int isUnescaped(int c) {
+  static char const unescaped_chars[] =
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+      "abcdefghijklmnopqrstuvwxyz"
+      "0123456789"
+      "@*_+-./";
+  return c < 0x100 && memchr(unescaped_chars, c, sizeof(unescaped_chars) - 1);
+}
+
+static int isURIUnescaped(int c, int isComponent) {
+  return c < 0x100 &&
+         ((c >= 0x61 && c <= 0x7a) || (c >= 0x41 && c <= 0x5a) || (c >= 0x30 && c <= 0x39) || memchr("-_.!~*'()", c, sizeof("-_.!~*'()") - 1) != NULL || (!isComponent && isURIReserved(c)));
+}
+
+static int encodeURI_hex(StringBuffer* b, int c) {
+  uint8_t buf[6];
+  int n = 0;
+  const char* hex = "0123456789ABCDEF";
+
+  buf[n++] = '%';
+  if (c >= 256) {
+    buf[n++] = 'u';
+    buf[n++] = hex[(c >> 12) & 15];
+    buf[n++] = hex[(c >> 8) & 15];
+  }
+  buf[n++] = hex[(c >> 4) & 15];
+  buf[n++] = hex[(c >> 0) & 15];
+  return string_buffer_write8(b, buf, n);
+}
+
+static JSValue js_global_encodeURI(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv, int isComponent) {
+  JSValue str;
+  StringBuffer b_s, *b = &b_s;
+  JSString* p;
+  int k, c, c1;
+
+  str = JS_ToString(ctx, argv[0]);
+  if (JS_IsException(str))
+    return str;
+
+  p = JS_VALUE_GET_STRING(str);
+  string_buffer_init(ctx, b, p->len);
+  for (k = 0; k < p->len;) {
+    c = string_get(p, k);
+    k++;
+    if (isURIUnescaped(c, isComponent)) {
+      string_buffer_putc16(b, c);
+    } else {
+      if (c >= 0xdc00 && c <= 0xdfff) {
+        js_throw_URIError(ctx, "invalid character");
+        goto fail;
+      } else if (c >= 0xd800 && c <= 0xdbff) {
+        if (k >= p->len) {
+          js_throw_URIError(ctx, "expecting surrogate pair");
+          goto fail;
+        }
+        c1 = string_get(p, k);
+        k++;
+        if (c1 < 0xdc00 || c1 > 0xdfff) {
+          js_throw_URIError(ctx, "expecting surrogate pair");
+          goto fail;
+        }
+        c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
+      }
+      if (c < 0x80) {
+        encodeURI_hex(b, c);
+      } else {
+        /* XXX: use C UTF-8 conversion ? */
+        if (c < 0x800) {
+          encodeURI_hex(b, (c >> 6) | 0xc0);
+        } else {
+          if (c < 0x10000) {
+            encodeURI_hex(b, (c >> 12) | 0xe0);
+          } else {
+            encodeURI_hex(b, (c >> 18) | 0xf0);
+            encodeURI_hex(b, ((c >> 12) & 0x3f) | 0x80);
+          }
+          encodeURI_hex(b, ((c >> 6) & 0x3f) | 0x80);
+        }
+        encodeURI_hex(b, (c & 0x3f) | 0x80);
+      }
+    }
+  }
+  JS_FreeValue(ctx, str);
+  return string_buffer_end(b);
+
+fail:
+  JS_FreeValue(ctx, str);
+  string_buffer_free(b);
+  return JS_EXCEPTION;
+}
+
+static JSValue js_global_escape(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue str;
+  StringBuffer b_s, *b = &b_s;
+  JSString* p;
+  int i, len, c;
+
+  str = JS_ToString(ctx, argv[0]);
+  if (JS_IsException(str))
+    return str;
+
+  p = JS_VALUE_GET_STRING(str);
+  string_buffer_init(ctx, b, p->len);
+  for (i = 0, len = p->len; i < len; i++) {
+    c = string_get(p, i);
+    if (isUnescaped(c)) {
+      string_buffer_putc16(b, c);
+    } else {
+      encodeURI_hex(b, c);
+    }
+  }
+  JS_FreeValue(ctx, str);
+  return string_buffer_end(b);
+}
+
+static JSValue js_global_unescape(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv) {
+  JSValue str;
+  StringBuffer b_s, *b = &b_s;
+  JSString* p;
+  int i, len, c, n;
+
+  str = JS_ToString(ctx, argv[0]);
+  if (JS_IsException(str))
+    return str;
+
+  string_buffer_init(ctx, b, 0);
+  p = JS_VALUE_GET_STRING(str);
+  for (i = 0, len = p->len; i < len; i++) {
+    c = string_get(p, i);
+    if (c == '%') {
+      if (i + 6 <= len && string_get(p, i + 1) == 'u' && (n = string_get_hex(p, i + 2, 4)) >= 0) {
+        c = n;
+        i += 6 - 1;
+      } else if (i + 3 <= len && (n = string_get_hex(p, i + 1, 2)) >= 0) {
+        c = n;
+        i += 3 - 1;
+      }
+    }
+    string_buffer_putc16(b, c);
+  }
+  JS_FreeValue(ctx, str);
+  return string_buffer_end(b);
+}
+
+/* Minimum amount of objects to be able to compile code and display
+   error messages. No JSAtom should be allocated by this function. */
+static void JS_AddIntrinsicBasicObjects(JSContext* ctx) {
+  JSValue proto;
+  int i;
+
+  ctx->class_proto[JS_CLASS_OBJECT] = JS_NewObjectProto(ctx, JS_NULL);
+  ctx->function_proto = JS_NewCFunction3(ctx, js_function_proto, "", 0, JS_CFUNC_generic, 0, ctx->class_proto[JS_CLASS_OBJECT]);
+  ctx->class_proto[JS_CLASS_BYTECODE_FUNCTION] = JS_DupValue(ctx, ctx->function_proto);
+  ctx->class_proto[JS_CLASS_ERROR] = JS_NewObject(ctx);
+#if 0
+    /* these are auto-initialized from js_error_proto_funcs,
+       but delaying might be a problem */
+    JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ERROR], JS_ATOM_name,
+                           JS_AtomToString(ctx, JS_ATOM_Error),
+                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+    JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ERROR], JS_ATOM_message,
+                           JS_AtomToString(ctx, JS_ATOM_empty_string),
+                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+#endif
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ERROR], js_error_proto_funcs, countof(js_error_proto_funcs));
+
+  for (i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
+    proto = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ERROR]);
+    JS_DefinePropertyValue(ctx, proto, JS_ATOM_name, JS_NewAtomString(ctx, native_error_name[i]), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+    JS_DefinePropertyValue(ctx, proto, JS_ATOM_message, JS_AtomToString(ctx, JS_ATOM_empty_string), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+    ctx->native_error_proto[i] = proto;
+  }
+
+  /* the array prototype is an array */
+  ctx->class_proto[JS_CLASS_ARRAY] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_ARRAY);
+
+  ctx->array_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_ARRAY]), JS_PROP_INITIAL_HASH_SIZE, 1);
+  add_shape_property(ctx, &ctx->array_shape, NULL, JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_LENGTH);
+
+  /* XXX: could test it on first context creation to ensure that no
+     new atoms are created in JS_AddIntrinsicBasicObjects(). It is
+     necessary to avoid useless renumbering of atoms after
+     JS_EvalBinary() if it is done just after
+     JS_AddIntrinsicBasicObjects(). */
+  //    assert(ctx->rt->atom_count == JS_ATOM_END);
+}
+
+/* Objects */
+static const JSCFunctionListEntry js_object_funcs[] = {
+    JS_CFUNC_DEF("create", 2, js_object_create),
+    JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 0),
+    JS_CFUNC_DEF("setPrototypeOf", 2, js_object_setPrototypeOf),
+    JS_CFUNC_MAGIC_DEF("defineProperty", 3, js_object_defineProperty, 0),
+    JS_CFUNC_DEF("defineProperties", 2, js_object_defineProperties),
+    JS_CFUNC_DEF("getOwnPropertyNames", 1, js_object_getOwnPropertyNames),
+    JS_CFUNC_DEF("getOwnPropertySymbols", 1, js_object_getOwnPropertySymbols),
+    JS_CFUNC_MAGIC_DEF("keys", 1, js_object_keys, JS_ITERATOR_KIND_KEY),
+    JS_CFUNC_MAGIC_DEF("values", 1, js_object_keys, JS_ITERATOR_KIND_VALUE),
+    JS_CFUNC_MAGIC_DEF("entries", 1, js_object_keys, JS_ITERATOR_KIND_KEY_AND_VALUE),
+    JS_CFUNC_MAGIC_DEF("isExtensible", 1, js_object_isExtensible, 0),
+    JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 0),
+    JS_CFUNC_MAGIC_DEF("getOwnPropertyDescriptor", 2, js_object_getOwnPropertyDescriptor, 0),
+    JS_CFUNC_DEF("getOwnPropertyDescriptors", 1, js_object_getOwnPropertyDescriptors),
+    JS_CFUNC_DEF("is", 2, js_object_is),
+    JS_CFUNC_DEF("assign", 2, js_object_assign),
+    JS_CFUNC_MAGIC_DEF("seal", 1, js_object_seal, 0),
+    JS_CFUNC_MAGIC_DEF("freeze", 1, js_object_seal, 1),
+    JS_CFUNC_MAGIC_DEF("isSealed", 1, js_object_isSealed, 0),
+    JS_CFUNC_MAGIC_DEF("isFrozen", 1, js_object_isSealed, 1),
+    JS_CFUNC_DEF("__getClass", 1, js_object___getClass),
+    // JS_CFUNC_DEF("__isObject", 1, js_object___isObject ),
+    // JS_CFUNC_DEF("__isConstructor", 1, js_object___isConstructor ),
+    // JS_CFUNC_DEF("__toObject", 1, js_object___toObject ),
+    // JS_CFUNC_DEF("__setOwnProperty", 3, js_object___setOwnProperty ),
+    // JS_CFUNC_DEF("__toPrimitive", 2, js_object___toPrimitive ),
+    // JS_CFUNC_DEF("__toPropertyKey", 1, js_object___toPropertyKey ),
+    // JS_CFUNC_DEF("__speciesConstructor", 2, js_object___speciesConstructor ),
+    // JS_CFUNC_DEF("__isSameValueZero", 2, js_object___isSameValueZero ),
+    // JS_CFUNC_DEF("__getObjectData", 1, js_object___getObjectData ),
+    // JS_CFUNC_DEF("__setObjectData", 2, js_object___setObjectData ),
+    JS_CFUNC_DEF("fromEntries", 1, js_object_fromEntries),
+};
+
+static const JSCFunctionListEntry js_object_proto_funcs[] = {
+    JS_CFUNC_DEF("toString", 0, js_object_toString),
+    JS_CFUNC_DEF("toLocaleString", 0, js_object_toLocaleString),
+    JS_CFUNC_DEF("valueOf", 0, js_object_valueOf),
+    JS_CFUNC_DEF("hasOwnProperty", 1, js_object_hasOwnProperty),
+    JS_CFUNC_DEF("isPrototypeOf", 1, js_object_isPrototypeOf),
+    JS_CFUNC_DEF("propertyIsEnumerable", 1, js_object_propertyIsEnumerable),
+    JS_CGETSET_DEF("__proto__", js_object_get___proto__, js_object_set___proto__),
+    JS_CFUNC_MAGIC_DEF("__defineGetter__", 2, js_object___defineGetter__, 0),
+    JS_CFUNC_MAGIC_DEF("__defineSetter__", 2, js_object___defineGetter__, 1),
+    JS_CFUNC_MAGIC_DEF("__lookupGetter__", 1, js_object___lookupGetter__, 0),
+    JS_CFUNC_MAGIC_DEF("__lookupSetter__", 1, js_object___lookupGetter__, 1),
+};
+
+/* Function class */
+
+static const JSCFunctionListEntry js_function_proto_funcs[] = {
+    JS_CFUNC_DEF("call", 1, js_function_call),
+    JS_CFUNC_MAGIC_DEF("apply", 2, js_function_apply, 0),
+    JS_CFUNC_DEF("bind", 1, js_function_bind),
+    JS_CFUNC_DEF("toString", 0, js_function_toString),
+    JS_CFUNC_DEF("[Symbol.hasInstance]", 1, js_function_hasInstance),
+    JS_CGETSET_DEF("fileName", js_function_proto_fileName, NULL),
+    JS_CGETSET_DEF("lineNumber", js_function_proto_lineNumber, NULL),
+};
+
+/* Array */
+static const JSCFunctionListEntry js_array_proto_funcs[] = {
+    JS_CFUNC_DEF("concat", 1, js_array_concat),
+    JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every),
+    JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some),
+    JS_CFUNC_MAGIC_DEF("forEach", 1, js_array_every, special_forEach),
+    JS_CFUNC_MAGIC_DEF("map", 1, js_array_every, special_map),
+    JS_CFUNC_MAGIC_DEF("filter", 1, js_array_every, special_filter),
+    JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce),
+    JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight),
+    JS_CFUNC_DEF("fill", 1, js_array_fill),
+    JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, 0),
+    JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, 1),
+    JS_CFUNC_DEF("indexOf", 1, js_array_indexOf),
+    JS_CFUNC_DEF("lastIndexOf", 1, js_array_lastIndexOf),
+    JS_CFUNC_DEF("includes", 1, js_array_includes),
+    JS_CFUNC_MAGIC_DEF("join", 1, js_array_join, 0),
+    JS_CFUNC_DEF("toString", 0, js_array_toString),
+    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_array_join, 1),
+    JS_CFUNC_MAGIC_DEF("pop", 0, js_array_pop, 0),
+    JS_CFUNC_MAGIC_DEF("push", 1, js_array_push, 0),
+    JS_CFUNC_MAGIC_DEF("shift", 0, js_array_pop, 1),
+    JS_CFUNC_MAGIC_DEF("unshift", 1, js_array_push, 1),
+    JS_CFUNC_DEF("reverse", 0, js_array_reverse),
+    JS_CFUNC_DEF("sort", 1, js_array_sort),
+    JS_CFUNC_MAGIC_DEF("slice", 2, js_array_slice, 0),
+    JS_CFUNC_MAGIC_DEF("splice", 2, js_array_slice, 1),
+    JS_CFUNC_DEF("copyWithin", 2, js_array_copyWithin),
+    JS_CFUNC_MAGIC_DEF("flatMap", 1, js_array_flatten, 1),
+    JS_CFUNC_MAGIC_DEF("flat", 0, js_array_flatten, 0),
+    JS_CFUNC_MAGIC_DEF("values", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE),
+    JS_ALIAS_DEF("[Symbol.iterator]", "values"),
+    JS_CFUNC_MAGIC_DEF("keys", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY),
+    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE),
+};
+
+static const JSCFunctionListEntry js_array_funcs[] = {
+    JS_CFUNC_DEF("isArray", 1, js_array_isArray),
+    JS_CFUNC_DEF("from", 1, js_array_from),
+    JS_CFUNC_DEF("of", 0, js_array_of),
+    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL),
+};
+
+static const JSCFunctionListEntry js_iterator_proto_funcs[] = {
+    JS_CFUNC_DEF("[Symbol.iterator]", 0, js_iterator_proto_iterator),
+};
+
+static const JSCFunctionListEntry js_array_iterator_proto_funcs[] = {
+    JS_ITERATOR_NEXT_DEF("next", 0, js_array_iterator_next, 0),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Array Iterator", JS_PROP_CONFIGURABLE),
+};
+
+/* Number */
+static const JSCFunctionListEntry js_number_funcs[] = {
+    /* global ParseInt and parseFloat should be defined already or delayed */
+    JS_ALIAS_BASE_DEF("parseInt", "parseInt", 0),
+    JS_ALIAS_BASE_DEF("parseFloat", "parseFloat", 0),
+    JS_CFUNC_DEF("isNaN", 1, js_number_isNaN),
+    JS_CFUNC_DEF("isFinite", 1, js_number_isFinite),
+    JS_CFUNC_DEF("isInteger", 1, js_number_isInteger),
+    JS_CFUNC_DEF("isSafeInteger", 1, js_number_isSafeInteger),
+    JS_PROP_DOUBLE_DEF("MAX_VALUE", 1.7976931348623157e+308, 0),
+    JS_PROP_DOUBLE_DEF("MIN_VALUE", 5e-324, 0),
+    JS_PROP_DOUBLE_DEF("NaN", NAN, 0),
+    JS_PROP_DOUBLE_DEF("NEGATIVE_INFINITY", -INFINITY, 0),
+    JS_PROP_DOUBLE_DEF("POSITIVE_INFINITY", INFINITY, 0),
+    JS_PROP_DOUBLE_DEF("EPSILON", 2.220446049250313e-16, 0),        /* ES6 */
+    JS_PROP_DOUBLE_DEF("MAX_SAFE_INTEGER", 9007199254740991.0, 0),  /* ES6 */
+    JS_PROP_DOUBLE_DEF("MIN_SAFE_INTEGER", -9007199254740991.0, 0), /* ES6 */
+                                                                    // JS_CFUNC_DEF("__toInteger", 1, js_number___toInteger ),
+                                                                    // JS_CFUNC_DEF("__toLength", 1, js_number___toLength ),
+};
+static const JSCFunctionListEntry js_number_proto_funcs[] = {
+    JS_CFUNC_DEF("toExponential", 1, js_number_toExponential),      JS_CFUNC_DEF("toFixed", 1, js_number_toFixed),
+    JS_CFUNC_DEF("toPrecision", 1, js_number_toPrecision),          JS_CFUNC_MAGIC_DEF("toString", 1, js_number_toString, 0),
+    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_number_toString, 1), JS_CFUNC_DEF("valueOf", 0, js_number_valueOf),
+};
+
+/* global object */
+static const JSCFunctionListEntry js_global_funcs[] = {
+    JS_CFUNC_DEF("parseInt", 2, js_parseInt), JS_CFUNC_DEF("parseFloat", 1, js_parseFloat), JS_CFUNC_DEF("isNaN", 1, js_global_isNaN), JS_CFUNC_DEF("isFinite", 1, js_global_isFinite),
+    JS_CFUNC_MAGIC_DEF("decodeURI", 1, js_global_decodeURI, 0), JS_CFUNC_MAGIC_DEF("decodeURIComponent", 1, js_global_decodeURI, 1), JS_CFUNC_MAGIC_DEF("encodeURI", 1, js_global_encodeURI, 0),
+    JS_CFUNC_MAGIC_DEF("encodeURIComponent", 1, js_global_encodeURI, 1), JS_CFUNC_DEF("escape", 1, js_global_escape), JS_CFUNC_DEF("unescape", 1, js_global_unescape),
+    JS_PROP_DOUBLE_DEF("Infinity", 1.0 / 0.0, 0), JS_PROP_DOUBLE_DEF("NaN", NAN, 0), JS_PROP_UNDEFINED_DEF("undefined", 0),
+
+    /* for the 'Date' implementation */
+    JS_CFUNC_DEF("__date_clock", 0, js___date_clock),
+    // JS_CFUNC_DEF("__date_now", 0, js___date_now ),
+    // JS_CFUNC_DEF("__date_getTimezoneOffset", 1, js___date_getTimezoneOffset ),
+    // JS_CFUNC_DEF("__date_create", 3, js___date_create ),
+};
+
+/* Boolean */
+static const JSCFunctionListEntry js_boolean_proto_funcs[] = {
+    JS_CFUNC_DEF("toString", 0, js_boolean_toString),
+    JS_CFUNC_DEF("valueOf", 0, js_boolean_valueOf),
+};
+
+/* String */
+static const JSCFunctionListEntry js_string_funcs[] = {
+    JS_CFUNC_DEF("fromCharCode", 1, js_string_fromCharCode), JS_CFUNC_DEF("fromCodePoint", 1, js_string_fromCodePoint), JS_CFUNC_DEF("raw", 1, js_string_raw),
+    // JS_CFUNC_DEF("__toString", 1, js_string___toString ),
+    // JS_CFUNC_DEF("__isSpace", 1, js_string___isSpace ),
+    // JS_CFUNC_DEF("__toStringCheckObject", 1, js_string___toStringCheckObject ),
+    // JS_CFUNC_DEF("__advanceStringIndex", 3, js_string___advanceStringIndex ),
+    // JS_CFUNC_DEF("__GetSubstitution", 6, js_string___GetSubstitution ),
+};
+
+static const JSCFunctionListEntry js_string_proto_funcs[] = {
+    JS_PROP_INT32_DEF("length", 0, JS_PROP_CONFIGURABLE),
+    JS_CFUNC_DEF("charCodeAt", 1, js_string_charCodeAt),
+    JS_CFUNC_DEF("charAt", 1, js_string_charAt),
+    JS_CFUNC_DEF("concat", 1, js_string_concat),
+    JS_CFUNC_DEF("codePointAt", 1, js_string_codePointAt),
+    JS_CFUNC_MAGIC_DEF("indexOf", 1, js_string_indexOf, 0),
+    JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_string_indexOf, 1),
+    JS_CFUNC_MAGIC_DEF("includes", 1, js_string_includes, 0),
+    JS_CFUNC_MAGIC_DEF("endsWith", 1, js_string_includes, 2),
+    JS_CFUNC_MAGIC_DEF("startsWith", 1, js_string_includes, 1),
+    JS_CFUNC_MAGIC_DEF("match", 1, js_string_match, JS_ATOM_Symbol_match),
+    JS_CFUNC_MAGIC_DEF("matchAll", 1, js_string_match, JS_ATOM_Symbol_matchAll),
+    JS_CFUNC_MAGIC_DEF("search", 1, js_string_match, JS_ATOM_Symbol_search),
+    JS_CFUNC_DEF("split", 2, js_string_split),
+    JS_CFUNC_DEF("substring", 2, js_string_substring),
+    JS_CFUNC_DEF("substr", 2, js_string_substr),
+    JS_CFUNC_DEF("slice", 2, js_string_slice),
+    JS_CFUNC_DEF("repeat", 1, js_string_repeat),
+    JS_CFUNC_MAGIC_DEF("replace", 2, js_string_replace, 0),
+    JS_CFUNC_MAGIC_DEF("replaceAll", 2, js_string_replace, 1),
+    JS_CFUNC_MAGIC_DEF("padEnd", 1, js_string_pad, 1),
+    JS_CFUNC_MAGIC_DEF("padStart", 1, js_string_pad, 0),
+    JS_CFUNC_MAGIC_DEF("trim", 0, js_string_trim, 3),
+    JS_CFUNC_MAGIC_DEF("trimEnd", 0, js_string_trim, 2),
+    JS_ALIAS_DEF("trimRight", "trimEnd"),
+    JS_CFUNC_MAGIC_DEF("trimStart", 0, js_string_trim, 1),
+    JS_ALIAS_DEF("trimLeft", "trimStart"),
+    JS_CFUNC_DEF("toString", 0, js_string_toString),
+    JS_CFUNC_DEF("valueOf", 0, js_string_toString),
+    JS_CFUNC_DEF("__quote", 1, js_string___quote),
+    JS_CFUNC_DEF("localeCompare", 1, js_string_localeCompare),
+    JS_CFUNC_MAGIC_DEF("toLowerCase", 0, js_string_toLowerCase, 1),
+    JS_CFUNC_MAGIC_DEF("toUpperCase", 0, js_string_toLowerCase, 0),
+    JS_CFUNC_MAGIC_DEF("toLocaleLowerCase", 0, js_string_toLowerCase, 1),
+    JS_CFUNC_MAGIC_DEF("toLocaleUpperCase", 0, js_string_toLowerCase, 0),
+    JS_CFUNC_MAGIC_DEF("[Symbol.iterator]", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE | 4),
+    /* ES6 Annex B 2.3.2 etc. */
+    JS_CFUNC_MAGIC_DEF("anchor", 1, js_string_CreateHTML, magic_string_anchor),
+    JS_CFUNC_MAGIC_DEF("big", 0, js_string_CreateHTML, magic_string_big),
+    JS_CFUNC_MAGIC_DEF("blink", 0, js_string_CreateHTML, magic_string_blink),
+    JS_CFUNC_MAGIC_DEF("bold", 0, js_string_CreateHTML, magic_string_bold),
+    JS_CFUNC_MAGIC_DEF("fixed", 0, js_string_CreateHTML, magic_string_fixed),
+    JS_CFUNC_MAGIC_DEF("fontcolor", 1, js_string_CreateHTML, magic_string_fontcolor),
+    JS_CFUNC_MAGIC_DEF("fontsize", 1, js_string_CreateHTML, magic_string_fontsize),
+    JS_CFUNC_MAGIC_DEF("italics", 0, js_string_CreateHTML, magic_string_italics),
+    JS_CFUNC_MAGIC_DEF("link", 1, js_string_CreateHTML, magic_string_link),
+    JS_CFUNC_MAGIC_DEF("small", 0, js_string_CreateHTML, magic_string_small),
+    JS_CFUNC_MAGIC_DEF("strike", 0, js_string_CreateHTML, magic_string_strike),
+    JS_CFUNC_MAGIC_DEF("sub", 0, js_string_CreateHTML, magic_string_sub),
+    JS_CFUNC_MAGIC_DEF("sup", 0, js_string_CreateHTML, magic_string_sup),
+};
+
+static const JSCFunctionListEntry js_string_iterator_proto_funcs[] = {
+    JS_ITERATOR_NEXT_DEF("next", 0, js_string_iterator_next, 0),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "String Iterator", JS_PROP_CONFIGURABLE),
+};
+
+#ifdef CONFIG_ALL_UNICODE
+static const JSCFunctionListEntry js_string_proto_normalize[] = {
+    JS_CFUNC_DEF("normalize", 0, js_string_normalize),
+};
+#endif
+
+/* Math */
+static const JSCFunctionListEntry js_math_funcs[] = {
+    JS_CFUNC_MAGIC_DEF("min", 2, js_math_min_max, 0),
+    JS_CFUNC_MAGIC_DEF("max", 2, js_math_min_max, 1),
+    JS_CFUNC_SPECIAL_DEF("abs", 1, f_f, fabs),
+    JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, floor),
+    JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, ceil),
+    JS_CFUNC_SPECIAL_DEF("round", 1, f_f, js_math_round),
+    JS_CFUNC_SPECIAL_DEF("sqrt", 1, f_f, sqrt),
+
+    JS_CFUNC_SPECIAL_DEF("acos", 1, f_f, acos),
+    JS_CFUNC_SPECIAL_DEF("asin", 1, f_f, asin),
+    JS_CFUNC_SPECIAL_DEF("atan", 1, f_f, atan),
+    JS_CFUNC_SPECIAL_DEF("atan2", 2, f_f_f, atan2),
+    JS_CFUNC_SPECIAL_DEF("cos", 1, f_f, cos),
+    JS_CFUNC_SPECIAL_DEF("exp", 1, f_f, exp),
+    JS_CFUNC_SPECIAL_DEF("log", 1, f_f, log),
+    JS_CFUNC_SPECIAL_DEF("pow", 2, f_f_f, js_pow),
+    JS_CFUNC_SPECIAL_DEF("sin", 1, f_f, sin),
+    JS_CFUNC_SPECIAL_DEF("tan", 1, f_f, tan),
+    /* ES6 */
+    JS_CFUNC_SPECIAL_DEF("trunc", 1, f_f, trunc),
+    JS_CFUNC_SPECIAL_DEF("sign", 1, f_f, js_math_sign),
+    JS_CFUNC_SPECIAL_DEF("cosh", 1, f_f, cosh),
+    JS_CFUNC_SPECIAL_DEF("sinh", 1, f_f, sinh),
+    JS_CFUNC_SPECIAL_DEF("tanh", 1, f_f, tanh),
+    JS_CFUNC_SPECIAL_DEF("acosh", 1, f_f, acosh),
+    JS_CFUNC_SPECIAL_DEF("asinh", 1, f_f, asinh),
+    JS_CFUNC_SPECIAL_DEF("atanh", 1, f_f, atanh),
+    JS_CFUNC_SPECIAL_DEF("expm1", 1, f_f, expm1),
+    JS_CFUNC_SPECIAL_DEF("log1p", 1, f_f, log1p),
+    JS_CFUNC_SPECIAL_DEF("log2", 1, f_f, log2),
+    JS_CFUNC_SPECIAL_DEF("log10", 1, f_f, log10),
+    JS_CFUNC_SPECIAL_DEF("cbrt", 1, f_f, cbrt),
+    JS_CFUNC_DEF("hypot", 2, js_math_hypot),
+    JS_CFUNC_DEF("random", 0, js_math_random),
+    JS_CFUNC_SPECIAL_DEF("fround", 1, f_f, js_math_fround),
+    JS_CFUNC_DEF("imul", 2, js_math_imul),
+    JS_CFUNC_DEF("clz32", 1, js_math_clz32),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Math", JS_PROP_CONFIGURABLE),
+    JS_PROP_DOUBLE_DEF("E", 2.718281828459045, 0),
+    JS_PROP_DOUBLE_DEF("LN10", 2.302585092994046, 0),
+    JS_PROP_DOUBLE_DEF("LN2", 0.6931471805599453, 0),
+    JS_PROP_DOUBLE_DEF("LOG2E", 1.4426950408889634, 0),
+    JS_PROP_DOUBLE_DEF("LOG10E", 0.4342944819032518, 0),
+    JS_PROP_DOUBLE_DEF("PI", 3.141592653589793, 0),
+    JS_PROP_DOUBLE_DEF("SQRT1_2", 0.7071067811865476, 0),
+    JS_PROP_DOUBLE_DEF("SQRT2", 1.4142135623730951, 0),
+};
+
+static const JSCFunctionListEntry js_math_obj[] = {
+    JS_OBJECT_DEF("Math", js_math_funcs, countof(js_math_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE),
+};
+
+/* Reflect */
+static const JSCFunctionListEntry js_reflect_funcs[] = {
+    JS_CFUNC_DEF("apply", 3, js_reflect_apply),
+    JS_CFUNC_DEF("construct", 2, js_reflect_construct),
+    JS_CFUNC_MAGIC_DEF("defineProperty", 3, js_object_defineProperty, 1),
+    JS_CFUNC_DEF("deleteProperty", 2, js_reflect_deleteProperty),
+    JS_CFUNC_DEF("get", 2, js_reflect_get),
+    JS_CFUNC_MAGIC_DEF("getOwnPropertyDescriptor", 2, js_object_getOwnPropertyDescriptor, 1),
+    JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 1),
+    JS_CFUNC_DEF("has", 2, js_reflect_has),
+    JS_CFUNC_MAGIC_DEF("isExtensible", 1, js_object_isExtensible, 1),
+    JS_CFUNC_DEF("ownKeys", 1, js_reflect_ownKeys),
+    JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 1),
+    JS_CFUNC_DEF("set", 3, js_reflect_set),
+    JS_CFUNC_DEF("setPrototypeOf", 2, js_reflect_setPrototypeOf),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Reflect", JS_PROP_CONFIGURABLE),
+};
+
+static const JSCFunctionListEntry js_reflect_obj[] = {
+    JS_OBJECT_DEF("Reflect", js_reflect_funcs, countof(js_reflect_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE),
+};
+
+/* Symbol */
+static const JSCFunctionListEntry js_symbol_proto_funcs[] = {
+    JS_CFUNC_DEF("toString", 0, js_symbol_toString),
+    JS_CFUNC_DEF("valueOf", 0, js_symbol_valueOf),
+    // XXX: should have writable: false
+    JS_CFUNC_DEF("[Symbol.toPrimitive]", 1, js_symbol_valueOf),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Symbol", JS_PROP_CONFIGURABLE),
+    JS_CGETSET_DEF("description", js_symbol_get_description, NULL),
+};
+
+static const JSCFunctionListEntry js_symbol_funcs[] = {
+    JS_CFUNC_DEF("for", 1, js_symbol_for),
+    JS_CFUNC_DEF("keyFor", 1, js_symbol_keyFor),
+};
+
+/* Generator */
+static const JSCFunctionListEntry js_generator_function_proto_funcs[] = {
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "GeneratorFunction", JS_PROP_CONFIGURABLE),
+};
+
+static const JSCFunctionListEntry js_generator_proto_funcs[] = {
+    JS_ITERATOR_NEXT_DEF("next", 1, js_generator_next, GEN_MAGIC_NEXT),
+    JS_ITERATOR_NEXT_DEF("return", 1, js_generator_next, GEN_MAGIC_RETURN),
+    JS_ITERATOR_NEXT_DEF("throw", 1, js_generator_next, GEN_MAGIC_THROW),
+    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Generator", JS_PROP_CONFIGURABLE),
+};
+
+void JS_AddIntrinsicStringNormalize(JSContext* ctx) {
+#ifdef CONFIG_ALL_UNICODE
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING], js_string_proto_normalize, countof(js_string_proto_normalize));
+#endif
+}
+
+void JS_AddIntrinsicBaseObjects(JSContext* ctx) {
+  int i;
+  JSValueConst obj, number_obj;
+  JSValue obj1;
+
+  ctx->throw_type_error = JS_NewCFunction(ctx, js_throw_type_error, NULL, 0);
+
+  /* add caller and arguments properties to throw a TypeError */
+  obj1 = JS_NewCFunction(ctx, js_function_proto_caller, NULL, 0);
+  JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_caller, JS_UNDEFINED, obj1, ctx->throw_type_error, JS_PROP_HAS_GET | JS_PROP_HAS_SET | JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE);
+  JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_arguments, JS_UNDEFINED, obj1, ctx->throw_type_error, JS_PROP_HAS_GET | JS_PROP_HAS_SET | JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE);
+  JS_FreeValue(ctx, obj1);
+  JS_FreeValue(ctx, js_object_seal(ctx, JS_UNDEFINED, 1, (JSValueConst*)&ctx->throw_type_error, 1));
+
+  ctx->global_obj = JS_NewObject(ctx);
+  ctx->global_var_obj = JS_NewObjectProto(ctx, JS_NULL);
+
+  /* Object */
+  obj = JS_NewGlobalCConstructor(ctx, "Object", js_object_constructor, 1, ctx->class_proto[JS_CLASS_OBJECT]);
+  JS_SetPropertyFunctionList(ctx, obj, js_object_funcs, countof(js_object_funcs));
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_OBJECT], js_object_proto_funcs, countof(js_object_proto_funcs));
+
+  /* Function */
+  JS_SetPropertyFunctionList(ctx, ctx->function_proto, js_function_proto_funcs, countof(js_function_proto_funcs));
+  ctx->function_ctor = JS_NewCFunctionMagic(ctx, js_function_constructor, "Function", 1, JS_CFUNC_constructor_or_func_magic, JS_FUNC_NORMAL);
+  JS_NewGlobalCConstructor2(ctx, JS_DupValue(ctx, ctx->function_ctor), "Function", ctx->function_proto);
+
+  /* Error */
+  obj1 = JS_NewCFunctionMagic(ctx, js_error_constructor, "Error", 1, JS_CFUNC_constructor_or_func_magic, -1);
+  JS_NewGlobalCConstructor2(ctx, obj1, "Error", ctx->class_proto[JS_CLASS_ERROR]);
+
+  for (i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
+    JSValue func_obj;
+    int n_args;
+    n_args = 1 + (i == JS_AGGREGATE_ERROR);
+    func_obj = JS_NewCFunction3(ctx, (JSCFunction*)js_error_constructor, native_error_name[i], n_args, JS_CFUNC_constructor_or_func_magic, i, obj1);
+    JS_NewGlobalCConstructor2(ctx, func_obj, native_error_name[i], ctx->native_error_proto[i]);
+  }
+
+  /* Iterator prototype */
+  ctx->iterator_proto = JS_NewObject(ctx);
+  JS_SetPropertyFunctionList(ctx, ctx->iterator_proto, js_iterator_proto_funcs, countof(js_iterator_proto_funcs));
+
+  /* Array */
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY], js_array_proto_funcs, countof(js_array_proto_funcs));
+
+  obj = JS_NewGlobalCConstructor(ctx, "Array", js_array_constructor, 1, ctx->class_proto[JS_CLASS_ARRAY]);
+  ctx->array_ctor = JS_DupValue(ctx, obj);
+  JS_SetPropertyFunctionList(ctx, obj, js_array_funcs, countof(js_array_funcs));
+
+  /* XXX: create auto_initializer */
+  {
+    /* initialize Array.prototype[Symbol.unscopables] */
+    char const unscopables[] =
+        "copyWithin"
+        "\0"
+        "entries"
+        "\0"
+        "fill"
+        "\0"
+        "find"
+        "\0"
+        "findIndex"
+        "\0"
+        "flat"
+        "\0"
+        "flatMap"
+        "\0"
+        "includes"
+        "\0"
+        "keys"
+        "\0"
+        "values"
+        "\0";
+    const char* p = unscopables;
+    obj1 = JS_NewObjectProto(ctx, JS_NULL);
+    for (p = unscopables; *p; p += strlen(p) + 1) {
+      JS_DefinePropertyValueStr(ctx, obj1, p, JS_TRUE, JS_PROP_C_W_E);
+    }
+    JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_Symbol_unscopables, obj1, JS_PROP_CONFIGURABLE);
+  }
+
+  /* needed to initialize arguments[Symbol.iterator] */
+  ctx->array_proto_values = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_values);
+
+  ctx->class_proto[JS_CLASS_ARRAY_ITERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto);
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY_ITERATOR], js_array_iterator_proto_funcs, countof(js_array_iterator_proto_funcs));
+
+  /* parseFloat and parseInteger must be defined before Number
+     because of the Number.parseFloat and Number.parseInteger
+     aliases */
+  JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_global_funcs, countof(js_global_funcs));
+
+  /* Number */
+  ctx->class_proto[JS_CLASS_NUMBER] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_NUMBER);
+  JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_NUMBER], JS_NewInt32(ctx, 0));
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_NUMBER], js_number_proto_funcs, countof(js_number_proto_funcs));
+  number_obj = JS_NewGlobalCConstructor(ctx, "Number", js_number_constructor, 1, ctx->class_proto[JS_CLASS_NUMBER]);
+  JS_SetPropertyFunctionList(ctx, number_obj, js_number_funcs, countof(js_number_funcs));
+
+  /* Boolean */
+  ctx->class_proto[JS_CLASS_BOOLEAN] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_BOOLEAN);
+  JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], JS_NewBool(ctx, FALSE));
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], js_boolean_proto_funcs, countof(js_boolean_proto_funcs));
+  JS_NewGlobalCConstructor(ctx, "Boolean", js_boolean_constructor, 1, ctx->class_proto[JS_CLASS_BOOLEAN]);
+
+  /* String */
+  ctx->class_proto[JS_CLASS_STRING] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_STRING);
+  JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_STRING], JS_AtomToString(ctx, JS_ATOM_empty_string));
+  obj = JS_NewGlobalCConstructor(ctx, "String", js_string_constructor, 1, ctx->class_proto[JS_CLASS_STRING]);
+  JS_SetPropertyFunctionList(ctx, obj, js_string_funcs, countof(js_string_funcs));
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING], js_string_proto_funcs, countof(js_string_proto_funcs));
+
+  ctx->class_proto[JS_CLASS_STRING_ITERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto);
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING_ITERATOR], js_string_iterator_proto_funcs, countof(js_string_iterator_proto_funcs));
+
+  /* Math: create as autoinit object */
+  js_random_init(ctx);
+  JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_math_obj, countof(js_math_obj));
+
+  /* ES6 Reflect: create as autoinit object */
+  JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_reflect_obj, countof(js_reflect_obj));
+
+  /* ES6 Symbol */
+  ctx->class_proto[JS_CLASS_SYMBOL] = JS_NewObject(ctx);
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_SYMBOL], js_symbol_proto_funcs, countof(js_symbol_proto_funcs));
+  obj = JS_NewGlobalCConstructor(ctx, "Symbol", js_symbol_constructor, 0, ctx->class_proto[JS_CLASS_SYMBOL]);
+  JS_SetPropertyFunctionList(ctx, obj, js_symbol_funcs, countof(js_symbol_funcs));
+  for (i = JS_ATOM_Symbol_toPrimitive; i <= JS_ATOM_Symbol_asyncIterator; i++) {
+    char buf[ATOM_GET_STR_BUF_SIZE];
+    const char *str, *p;
+    str = JS_AtomGetStr(ctx, buf, sizeof(buf), i);
+    /* skip "Symbol." */
+    p = strchr(str, '.');
+    if (p)
+      str = p + 1;
+    JS_DefinePropertyValueStr(ctx, obj, str, JS_AtomToValue(ctx, i), 0);
+  }
+
+  /* ES6 Generator */
+  ctx->class_proto[JS_CLASS_GENERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto);
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_GENERATOR], js_generator_proto_funcs, countof(js_generator_proto_funcs));
+
+  ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION] = JS_NewObjectProto(ctx, ctx->function_proto);
+  obj1 = JS_NewCFunctionMagic(ctx, js_function_constructor, "GeneratorFunction", 1, JS_CFUNC_constructor_or_func_magic, JS_FUNC_GENERATOR);
+  JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION], js_generator_function_proto_funcs, countof(js_generator_function_proto_funcs));
+  JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION], ctx->class_proto[JS_CLASS_GENERATOR], JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE);
+  JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION], 0, JS_PROP_CONFIGURABLE);
+  JS_FreeValue(ctx, obj1);
+
+  /* global properties */
+  ctx->eval_obj = JS_NewCFunction(ctx, js_global_eval, "eval", 1);
+  JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_eval, JS_DupValue(ctx, ctx->eval_obj), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+
+  JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_globalThis, JS_DupValue(ctx, ctx->global_obj), JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
+}
+
+void JS_SetRuntimeInfo(JSRuntime* rt, const char* s) {
+  if (rt)
+    rt->rt_info = s;
+}
+
+void JS_FreeRuntime(JSRuntime* rt) {
+  struct list_head *el, *el1;
+  int i;
+
+  JS_FreeValueRT(rt, rt->current_exception);
+
+  list_for_each_safe(el, el1, &rt->job_list) {
+    JSJobEntry* e = list_entry(el, JSJobEntry, link);
+    for (i = 0; i < e->argc; i++)
+      JS_FreeValueRT(rt, e->argv[i]);
+    js_free_rt(rt, e);
+  }
+  init_list_head(&rt->job_list);
+
+  JS_RunGC(rt);
+
+#ifdef DUMP_LEAKS
+  /* leaking objects */
+  {
+    BOOL header_done;
+    JSGCObjectHeader* p;
+    int count;
+
+    /* remove the internal refcounts to display only the object
+       referenced externally */
+    list_for_each(el, &rt->gc_obj_list) {
+      p = list_entry(el, JSGCObjectHeader, link);
+      p->mark = 0;
+    }
+    gc_decref(rt);
+
+    header_done = FALSE;
+    list_for_each(el, &rt->gc_obj_list) {
+      p = list_entry(el, JSGCObjectHeader, link);
+      if (p->ref_count != 0) {
+        if (!header_done) {
+          printf("Object leaks:\n");
+          JS_DumpObjectHeader(rt);
+          header_done = TRUE;
+        }
+        JS_DumpGCObject(rt, p);
+      }
+    }
+
+    count = 0;
+    list_for_each(el, &rt->gc_obj_list) {
+      p = list_entry(el, JSGCObjectHeader, link);
+      if (p->ref_count == 0) {
+        count++;
+      }
+    }
+    if (count != 0)
+      printf("Secondary object leaks: %d\n", count);
+  }
+#endif
+  assert(list_empty(&rt->gc_obj_list));
+
+  /* free the classes */
+  for (i = 0; i < rt->class_count; i++) {
+    JSClass* cl = &rt->class_array[i];
+    if (cl->class_id != 0) {
+      JS_FreeAtomRT(rt, cl->class_name);
+    }
+  }
+  js_free_rt(rt, rt->class_array);
+
+#ifdef CONFIG_BIGNUM
+  bf_context_end(&rt->bf_ctx);
+#endif
+
+#ifdef DUMP_LEAKS
+  /* only the atoms defined in JS_InitAtoms() should be left */
+  {
+    BOOL header_done = FALSE;
+
+    for (i = 0; i < rt->atom_size; i++) {
+      JSAtomStruct* p = rt->atom_array[i];
+      if (!atom_is_free(p) /* && p->str*/) {
+        if (i >= JS_ATOM_END || p->header.ref_count != 1) {
+          if (!header_done) {
+            header_done = TRUE;
+            if (rt->rt_info) {
+              printf("%s:1: atom leakage:", rt->rt_info);
+            } else {
+              printf(
+                  "Atom leaks:\n"
+                  "    %6s %6s %s\n",
+                  "ID", "REFCNT", "NAME");
+            }
+          }
+          if (rt->rt_info) {
+            printf(" ");
+          } else {
+            printf("    %6u %6u ", i, p->header.ref_count);
+          }
+          switch (p->atom_type) {
+            case JS_ATOM_TYPE_STRING:
+              JS_DumpString(rt, p);
+              break;
+            case JS_ATOM_TYPE_GLOBAL_SYMBOL:
+              printf("Symbol.for(");
+              JS_DumpString(rt, p);
+              printf(")");
+              break;
+            case JS_ATOM_TYPE_SYMBOL:
+              if (p->hash == JS_ATOM_HASH_SYMBOL) {
+                printf("Symbol(");
+                JS_DumpString(rt, p);
+                printf(")");
+              } else {
+                printf("Private(");
+                JS_DumpString(rt, p);
+                printf(")");
+              }
+              break;
+          }
+          if (rt->rt_info) {
+            printf(":%u", p->header.ref_count);
+          } else {
+            printf("\n");
+          }
+        }
+      }
+    }
+    if (rt->rt_info && header_done)
+      printf("\n");
+  }
+#endif
+
+  /* free the atoms */
+  for (i = 0; i < rt->atom_size; i++) {
+    JSAtomStruct* p = rt->atom_array[i];
+    if (!atom_is_free(p)) {
+#ifdef DUMP_LEAKS
+      list_del(&p->link);
+#endif
+      js_free_rt(rt, p);
+    }
+  }
+  js_free_rt(rt, rt->atom_array);
+  js_free_rt(rt, rt->atom_hash);
+  js_free_rt(rt, rt->shape_hash);
+#ifdef DUMP_LEAKS
+  if (!list_empty(&rt->string_list)) {
+    if (rt->rt_info) {
+      printf("%s:1: string leakage:", rt->rt_info);
+    } else {
+      printf(
+          "String leaks:\n"
+          "    %6s %s\n",
+          "REFCNT", "VALUE");
+    }
+    list_for_each_safe(el, el1, &rt->string_list) {
+      JSString* str = list_entry(el, JSString, link);
+      if (rt->rt_info) {
+        printf(" ");
+      } else {
+        printf("    %6u ", str->header.ref_count);
+      }
+      JS_DumpString(rt, str);
+      if (rt->rt_info) {
+        printf(":%u", str->header.ref_count);
+      } else {
+        printf("\n");
+      }
+      list_del(&str->link);
+      js_free_rt(rt, str);
+    }
+    if (rt->rt_info)
+      printf("\n");
+  }
+  {
+    JSMallocState* s = &rt->malloc_state;
+    if (s->malloc_count > 1) {
+      if (rt->rt_info)
+        printf("%s:1: ", rt->rt_info);
+      printf("Memory leak: %" PRIu64 " bytes lost in %" PRIu64 " block%s\n", (uint64_t)(s->malloc_size - sizeof(JSRuntime)), (uint64_t)(s->malloc_count - 1), &"s"[s->malloc_count == 2]);
+    }
+  }
+#endif
+
+  {
+    JSMallocState ms = rt->malloc_state;
+    rt->mf.js_free(&ms, rt);
+  }
+}
+
+JSContext* JS_NewContextRaw(JSRuntime* rt) {
+  JSContext* ctx;
+  int i;
+
+  ctx = js_mallocz_rt(rt, sizeof(JSContext));
+  if (!ctx)
+    return NULL;
+  ctx->header.ref_count = 1;
+  add_gc_object(rt, &ctx->header, JS_GC_OBJ_TYPE_JS_CONTEXT);
+
+  ctx->class_proto = js_malloc_rt(rt, sizeof(ctx->class_proto[0]) * rt->class_count);
+  if (!ctx->class_proto) {
+    js_free_rt(rt, ctx);
+    return NULL;
+  }
+  ctx->rt = rt;
+  list_add_tail(&ctx->link, &rt->context_list);
+#ifdef CONFIG_BIGNUM
+  ctx->bf_ctx = &rt->bf_ctx;
+  ctx->fp_env.prec = 113;
+  ctx->fp_env.flags = bf_set_exp_bits(15) | BF_RNDN | BF_FLAG_SUBNORMAL;
+#endif
+  for (i = 0; i < rt->class_count; i++)
+    ctx->class_proto[i] = JS_NULL;
+  ctx->array_ctor = JS_NULL;
+  ctx->regexp_ctor = JS_NULL;
+  ctx->promise_ctor = JS_NULL;
+  init_list_head(&ctx->loaded_modules);
+
+  JS_AddIntrinsicBasicObjects(ctx);
+  return ctx;
+}
+
+JSContext* JS_NewContext(JSRuntime* rt) {
+  JSContext* ctx;
+
+  ctx = JS_NewContextRaw(rt);
+  if (!ctx)
+    return NULL;
+
+  JS_AddIntrinsicBaseObjects(ctx);
+  JS_AddIntrinsicDate(ctx);
+  JS_AddIntrinsicEval(ctx);
+  JS_AddIntrinsicStringNormalize(ctx);
+  JS_AddIntrinsicRegExp(ctx);
+  JS_AddIntrinsicJSON(ctx);
+  JS_AddIntrinsicProxy(ctx);
+  JS_AddIntrinsicMapSet(ctx);
+  JS_AddIntrinsicTypedArrays(ctx);
+  JS_AddIntrinsicPromise(ctx);
+#ifdef CONFIG_BIGNUM
+  JS_AddIntrinsicBigInt(ctx);
+#endif
+  return ctx;
+}
+
+void* JS_GetContextOpaque(JSContext* ctx) {
+  return ctx->user_opaque;
+}
+
+void JS_SetContextOpaque(JSContext* ctx, void* opaque) {
+  ctx->user_opaque = opaque;
+}
+
+void JS_SetIsHTMLDDA(JSContext* ctx, JSValueConst obj) {
+  JSObject* p;
+  if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
+    return;
+  p = JS_VALUE_GET_OBJ(obj);
+  p->is_HTMLDDA = TRUE;
+}
+
+void JS_FreeContext(JSContext* ctx) {
+  JSRuntime* rt = ctx->rt;
+  int i;
+
+  if (--ctx->header.ref_count > 0)
+    return;
+  assert(ctx->header.ref_count == 0);
+
+#ifdef DUMP_ATOMS
+  JS_DumpAtoms(ctx->rt);
+#endif
+#ifdef DUMP_SHAPES
+  JS_DumpShapes(ctx->rt);
+#endif
+#ifdef DUMP_OBJECTS
+  {
+    struct list_head* el;
+    JSGCObjectHeader* p;
+    printf("JSObjects: {\n");
+    JS_DumpObjectHeader(ctx->rt);
+    list_for_each(el, &rt->gc_obj_list) {
+      p = list_entry(el, JSGCObjectHeader, link);
+      JS_DumpGCObject(rt, p);
+    }
+    printf("}\n");
+  }
+#endif
+#ifdef DUMP_MEM
+  {
+    JSMemoryUsage stats;
+    JS_ComputeMemoryUsage(rt, &stats);
+    JS_DumpMemoryUsage(stdout, &stats, rt);
+  }
+#endif
+
+  js_free_modules(ctx, JS_FREE_MODULE_ALL);
+
+  JS_FreeValue(ctx, ctx->global_obj);
+  JS_FreeValue(ctx, ctx->global_var_obj);
+
+  JS_FreeValue(ctx, ctx->throw_type_error);
+  JS_FreeValue(ctx, ctx->eval_obj);
+
+  JS_FreeValue(ctx, ctx->array_proto_values);
+  for (i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
+    JS_FreeValue(ctx, ctx->native_error_proto[i]);
+  }
+  for (i = 0; i < rt->class_count; i++) {
+    JS_FreeValue(ctx, ctx->class_proto[i]);
+  }
+  js_free_rt(rt, ctx->class_proto);
+  JS_FreeValue(ctx, ctx->iterator_proto);
+  JS_FreeValue(ctx, ctx->async_iterator_proto);
+  JS_FreeValue(ctx, ctx->promise_ctor);
+  JS_FreeValue(ctx, ctx->array_ctor);
+  JS_FreeValue(ctx, ctx->regexp_ctor);
+  JS_FreeValue(ctx, ctx->function_ctor);
+  JS_FreeValue(ctx, ctx->function_proto);
+
+  js_free_shape_null(ctx->rt, ctx->array_shape);
+
+  list_del(&ctx->link);
+  remove_gc_object(&ctx->header);
+  js_free_rt(ctx->rt, ctx);
+}
+
+JSRuntime* JS_GetRuntime(JSContext* ctx) {
+  return ctx->rt;
+}
+
+static void update_stack_limit(JSRuntime* rt) {
+  if (rt->stack_size == 0) {
+    rt->stack_limit = 0; /* no limit */
+  } else {
+    rt->stack_limit = rt->stack_top - rt->stack_size;
+  }
+}
+
+void JS_SetMaxStackSize(JSRuntime* rt, size_t stack_size) {
+  rt->stack_size = stack_size;
+  update_stack_limit(rt);
+}
+
+void JS_UpdateStackTop(JSRuntime* rt) {
+  rt->stack_top = js_get_stack_pointer();
+  update_stack_limit(rt);
+}
+
+#ifdef CONFIG_BIGNUM
+static JSValue JS_ThrowUnsupportedOperation(JSContext* ctx) {
+  return JS_ThrowTypeError(ctx, "unsupported operation");
+}
+
+static JSValue invalid_to_string(JSContext* ctx, JSValueConst val) {
+  return JS_ThrowUnsupportedOperation(ctx);
+}
+
+static JSValue invalid_from_string(JSContext* ctx, const char* buf, int radix, int flags, slimb_t* pexponent) {
+  return JS_NAN;
+}
+
+static int invalid_unary_arith(JSContext* ctx, JSValue* pres, OPCodeEnum op, JSValue op1) {
+  JS_FreeValue(ctx, op1);
+  JS_ThrowUnsupportedOperation(ctx);
+  return -1;
+}
+
+static int invalid_binary_arith(JSContext* ctx, OPCodeEnum op, JSValue* pres, JSValue op1, JSValue op2) {
+  JS_FreeValue(ctx, op1);
+  JS_FreeValue(ctx, op2);
+  JS_ThrowUnsupportedOperation(ctx);
+  return -1;
+}
+
+static JSValue invalid_mul_pow10_to_float64(JSContext* ctx, const bf_t* a, int64_t exponent) {
+  return JS_ThrowUnsupportedOperation(ctx);
+}
+
+static int invalid_mul_pow10(JSContext* ctx, JSValue* sp) {
+  JS_ThrowUnsupportedOperation(ctx);
+  return -1;
+}
+
+static void set_dummy_numeric_ops(JSNumericOperations* ops) {
+  ops->to_string = invalid_to_string;
+  ops->from_string = invalid_from_string;
+  ops->unary_arith = invalid_unary_arith;
+  ops->binary_arith = invalid_binary_arith;
+  ops->mul_pow10_to_float64 = invalid_mul_pow10_to_float64;
+  ops->mul_pow10 = invalid_mul_pow10;
+}
+
+#endif /* CONFIG_BIGNUM */
+
+int init_class_range(JSRuntime* rt, JSClassShortDef const* tab, int start, int count) {
+  JSClassDef cm_s, *cm = &cm_s;
+  int i, class_id;
+
+  for (i = 0; i < count; i++) {
+    class_id = i + start;
+    memset(cm, 0, sizeof(*cm));
+    cm->finalizer = tab[i].finalizer;
+    cm->gc_mark = tab[i].gc_mark;
+    if (JS_NewClass1(rt, class_id, cm, tab[i].class_name) < 0)
+      return -1;
+  }
+  return 0;
+}
+
+JSRuntime* JS_NewRuntime2(const JSMallocFunctions* mf, void* opaque) {
+  JSRuntime* rt;
+  JSMallocState ms;
+
+  memset(&ms, 0, sizeof(ms));
+  ms.opaque = opaque;
+  ms.malloc_limit = -1;
+
+  rt = mf->js_malloc(&ms, sizeof(JSRuntime));
+  if (!rt)
+    return NULL;
+  memset(rt, 0, sizeof(*rt));
+  rt->mf = *mf;
+  if (!rt->mf.js_malloc_usable_size) {
+    /* use dummy function if none provided */
+    rt->mf.js_malloc_usable_size = js_malloc_usable_size_unknown;
+  }
+  rt->malloc_state = ms;
+  rt->malloc_gc_threshold = 256 * 1024;
+
+#ifdef CONFIG_BIGNUM
+  bf_context_init(&rt->bf_ctx, js_bf_realloc, rt);
+  set_dummy_numeric_ops(&rt->bigint_ops);
+  set_dummy_numeric_ops(&rt->bigfloat_ops);
+  set_dummy_numeric_ops(&rt->bigdecimal_ops);
+#endif
+
+  init_list_head(&rt->context_list);
+  init_list_head(&rt->gc_obj_list);
+  init_list_head(&rt->gc_zero_ref_count_list);
+  rt->gc_phase = JS_GC_PHASE_NONE;
+
+#ifdef DUMP_LEAKS
+  init_list_head(&rt->string_list);
+#endif
+  init_list_head(&rt->job_list);
+
+  if (JS_InitAtoms(rt))
+    goto fail;
+
+  /* create the object, array and function classes */
+  if (init_class_range(rt, js_std_class_def, JS_CLASS_OBJECT, countof(js_std_class_def)) < 0)
+    goto fail;
+  rt->class_array[JS_CLASS_ARGUMENTS].exotic = &js_arguments_exotic_methods;
+  rt->class_array[JS_CLASS_STRING].exotic = &js_string_exotic_methods;
+  rt->class_array[JS_CLASS_MODULE_NS].exotic = &js_module_ns_exotic_methods;
+
+  rt->class_array[JS_CLASS_C_FUNCTION].call = js_call_c_function;
+  rt->class_array[JS_CLASS_C_FUNCTION_DATA].call = js_c_function_data_call;
+  rt->class_array[JS_CLASS_BOUND_FUNCTION].call = js_call_bound_function;
+  rt->class_array[JS_CLASS_GENERATOR_FUNCTION].call = js_generator_function_call;
+  if (init_shape_hash(rt))
+    goto fail;
+
+  rt->stack_size = JS_DEFAULT_STACK_SIZE;
+  JS_UpdateStackTop(rt);
+
+  rt->current_exception = JS_NULL;
+
+  return rt;
+fail:
+  JS_FreeRuntime(rt);
+  return NULL;
+}
+
+/* eval */
+
+void JS_AddIntrinsicEval(JSContext* ctx) {
+  ctx->eval_internal = __JS_EvalInternal;
+}
+
+static const JSMallocFunctions def_malloc_funcs = {
+    js_def_malloc,
+    js_def_free,
+    js_def_realloc,
+#if defined(__APPLE__)
+    malloc_size,
+#elif defined(_WIN32)
+    (size_t(*)(const void*))_msize,
+#elif defined(EMSCRIPTEN)
+    NULL,
+#elif defined(__linux__)
+    (size_t(*)(const void*))malloc_usable_size,
+#else
+    /* change this to `NULL,` if compilation fails */
+    malloc_usable_size,
+#endif
+};
+
+JSRuntime* JS_NewRuntime(void) {
+  return JS_NewRuntime2(&def_malloc_funcs, NULL);
+}
+
+/* the indirection is needed to make 'eval' optional */
+JSValue JS_EvalInternal(JSContext* ctx, JSValueConst this_obj, const char* input, size_t input_len, const char* filename, int flags, int scope_idx) {
+  if (unlikely(!ctx->eval_internal)) {
+    return JS_ThrowTypeError(ctx, "eval is not supported");
+  }
+  return ctx->eval_internal(ctx, this_obj, input, input_len, filename, flags, scope_idx);
+}
+
+JSValue JS_EvalObject(JSContext* ctx, JSValueConst this_obj, JSValueConst val, int flags, int scope_idx) {
+  JSValue ret;
+  const char* str;
+  size_t len;
+
+  if (!JS_IsString(val))
+    return JS_DupValue(ctx, val);
+  str = JS_ToCStringLen(ctx, &len, val);
+  if (!str)
+    return JS_EXCEPTION;
+  ret = JS_EvalInternal(ctx, this_obj, str, len, "<input>", flags, scope_idx);
+  JS_FreeCString(ctx, str);
+  return ret;
+}
+
+JSValue JS_EvalThis(JSContext* ctx, JSValueConst this_obj, const char* input, size_t input_len, const char* filename, int eval_flags) {
+  int eval_type = eval_flags & JS_EVAL_TYPE_MASK;
+  JSValue ret;
+
+  assert(eval_type == JS_EVAL_TYPE_GLOBAL || eval_type == JS_EVAL_TYPE_MODULE);
+  ret = JS_EvalInternal(ctx, this_obj, input, input_len, filename, eval_flags, -1);
+  return ret;
+}
+
+JSValue JS_Eval(JSContext* ctx, const char* input, size_t input_len, const char* filename, int eval_flags) {
+  return JS_EvalThis(ctx, ctx->global_obj, input, input_len, filename, eval_flags);
+}
+
+JSValue JS_EvalFunctionInternal(JSContext* ctx, JSValue fun_obj, JSValueConst this_obj, JSVarRef** var_refs, JSStackFrame* sf) {
+  JSValue ret_val;
+  uint32_t tag;
+
+  tag = JS_VALUE_GET_TAG(fun_obj);
+  if (tag == JS_TAG_FUNCTION_BYTECODE) {
+    fun_obj = js_closure(ctx, fun_obj, var_refs, sf);
+    ret_val = JS_CallFree(ctx, fun_obj, this_obj, 0, NULL);
+  } else if (tag == JS_TAG_MODULE) {
+    JSModuleDef* m;
+    m = JS_VALUE_GET_PTR(fun_obj);
+    /* the module refcount should be >= 2 */
+    JS_FreeValue(ctx, fun_obj);
+    if (js_create_module_function(ctx, m) < 0)
+      goto fail;
+    if (js_link_module(ctx, m) < 0)
+      goto fail;
+    ret_val = js_evaluate_module(ctx, m);
+    if (JS_IsException(ret_val)) {
+    fail:
+      js_free_modules(ctx, JS_FREE_MODULE_NOT_EVALUATED);
+      return JS_EXCEPTION;
+    }
+  } else {
+    JS_FreeValue(ctx, fun_obj);
+    ret_val = JS_ThrowTypeError(ctx, "bytecode function expected");
+  }
+  return ret_val;
+}
+
+JSValue JS_EvalFunction(JSContext* ctx, JSValue fun_obj) {
+  return JS_EvalFunctionInternal(ctx, fun_obj, ctx->global_obj, NULL, NULL);
+}
\ No newline at end of file
diff --git a/src/core/runtime.h b/src/core/runtime.h
new file mode 100644
index 000000000..597f21053
--- /dev/null
+++ b/src/core/runtime.h
@@ -0,0 +1,251 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_RUNTIME_H
+#define QUICKJS_RUNTIME_H
+
+#include "quickjs/quickjs.h"
+#include "quickjs/cutils.h"
+#include "quickjs/list.h"
+#include "types.h"
+#include "builtins/js-array.h"
+#include "builtins/js-function.h"
+#include "builtins/js-object.h"
+#include "builtins/js-operator.h"
+#include "builtins/js-regexp.h"
+#include "function.h"
+#include "gc.h"
+
+#if CONFIG_BIGNUM
+#include "builtins/js-big-num.h"
+#endif
+
+#define JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL (1 << 0)
+/* only taken into account if filename is provided */
+#define JS_BACKTRACE_FLAG_SINGLE_LEVEL (1 << 1)
+
+#define DEFINE_GLOBAL_LEX_VAR (1 << 7)
+#define DEFINE_GLOBAL_FUNC_VAR (1 << 6)
+
+typedef struct JSClassShortDef {
+  JSAtom class_name;
+  JSClassFinalizer* finalizer;
+  JSClassGCMark* gc_mark;
+} JSClassShortDef;
+
+static const JSClassExoticMethods js_arguments_exotic_methods;
+static const JSClassExoticMethods js_string_exotic_methods;
+static const JSClassExoticMethods js_proxy_exotic_methods;
+static const JSClassExoticMethods js_module_ns_exotic_methods;
+
+static JSClassShortDef const js_std_class_def[] = {
+    {JS_ATOM_Object, NULL, NULL},                                                           /* JS_CLASS_OBJECT */
+    {JS_ATOM_Array, js_array_finalizer, js_array_mark},                                     /* JS_CLASS_ARRAY */
+    {JS_ATOM_Error, NULL, NULL},                                                            /* JS_CLASS_ERROR */
+    {JS_ATOM_Number, js_object_data_finalizer, js_object_data_mark},                        /* JS_CLASS_NUMBER */
+    {JS_ATOM_String, js_object_data_finalizer, js_object_data_mark},                        /* JS_CLASS_STRING */
+    {JS_ATOM_Boolean, js_object_data_finalizer, js_object_data_mark},                       /* JS_CLASS_BOOLEAN */
+    {JS_ATOM_Symbol, js_object_data_finalizer, js_object_data_mark},                        /* JS_CLASS_SYMBOL */
+    {JS_ATOM_Arguments, js_array_finalizer, js_array_mark},                                 /* JS_CLASS_ARGUMENTS */
+    {JS_ATOM_Arguments, NULL, NULL},                                                        /* JS_CLASS_MAPPED_ARGUMENTS */
+    {JS_ATOM_Date, js_object_data_finalizer, js_object_data_mark},                          /* JS_CLASS_DATE */
+    {JS_ATOM_Object, NULL, NULL},                                                           /* JS_CLASS_MODULE_NS */
+    {JS_ATOM_Function, js_c_function_finalizer, js_c_function_mark},                        /* JS_CLASS_C_FUNCTION */
+    {JS_ATOM_Function, js_bytecode_function_finalizer, js_bytecode_function_mark},          /* JS_CLASS_BYTECODE_FUNCTION */
+    {JS_ATOM_Function, js_bound_function_finalizer, js_bound_function_mark},                /* JS_CLASS_BOUND_FUNCTION */
+    {JS_ATOM_Function, js_c_function_data_finalizer, js_c_function_data_mark},              /* JS_CLASS_C_FUNCTION_DATA */
+    {JS_ATOM_GeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark}, /* JS_CLASS_GENERATOR_FUNCTION */
+    {JS_ATOM_ForInIterator, js_for_in_iterator_finalizer, js_for_in_iterator_mark},         /* JS_CLASS_FOR_IN_ITERATOR */
+    {JS_ATOM_RegExp, js_regexp_finalizer, NULL},                                            /* JS_CLASS_REGEXP */
+    {JS_ATOM_ArrayBuffer, js_array_buffer_finalizer, NULL},                                 /* JS_CLASS_ARRAY_BUFFER */
+    {JS_ATOM_SharedArrayBuffer, js_array_buffer_finalizer, NULL},                           /* JS_CLASS_SHARED_ARRAY_BUFFER */
+    {JS_ATOM_Uint8ClampedArray, js_typed_array_finalizer, js_typed_array_mark},             /* JS_CLASS_UINT8C_ARRAY */
+    {JS_ATOM_Int8Array, js_typed_array_finalizer, js_typed_array_mark},                     /* JS_CLASS_INT8_ARRAY */
+    {JS_ATOM_Uint8Array, js_typed_array_finalizer, js_typed_array_mark},                    /* JS_CLASS_UINT8_ARRAY */
+    {JS_ATOM_Int16Array, js_typed_array_finalizer, js_typed_array_mark},                    /* JS_CLASS_INT16_ARRAY */
+    {JS_ATOM_Uint16Array, js_typed_array_finalizer, js_typed_array_mark},                   /* JS_CLASS_UINT16_ARRAY */
+    {JS_ATOM_Int32Array, js_typed_array_finalizer, js_typed_array_mark},                    /* JS_CLASS_INT32_ARRAY */
+    {JS_ATOM_Uint32Array, js_typed_array_finalizer, js_typed_array_mark},                   /* JS_CLASS_UINT32_ARRAY */
+#ifdef CONFIG_BIGNUM
+    {JS_ATOM_BigInt64Array, js_typed_array_finalizer, js_typed_array_mark},  /* JS_CLASS_BIG_INT64_ARRAY */
+    {JS_ATOM_BigUint64Array, js_typed_array_finalizer, js_typed_array_mark}, /* JS_CLASS_BIG_UINT64_ARRAY */
+#endif
+    {JS_ATOM_Float32Array, js_typed_array_finalizer, js_typed_array_mark}, /* JS_CLASS_FLOAT32_ARRAY */
+    {JS_ATOM_Float64Array, js_typed_array_finalizer, js_typed_array_mark}, /* JS_CLASS_FLOAT64_ARRAY */
+    {JS_ATOM_DataView, js_typed_array_finalizer, js_typed_array_mark},     /* JS_CLASS_DATAVIEW */
+#ifdef CONFIG_BIGNUM
+    {JS_ATOM_BigInt, js_object_data_finalizer, js_object_data_mark},        /* JS_CLASS_BIG_INT */
+    {JS_ATOM_BigFloat, js_object_data_finalizer, js_object_data_mark},      /* JS_CLASS_BIG_FLOAT */
+    {JS_ATOM_BigFloatEnv, js_float_env_finalizer, NULL},                    /* JS_CLASS_FLOAT_ENV */
+    {JS_ATOM_BigDecimal, js_object_data_finalizer, js_object_data_mark},    /* JS_CLASS_BIG_DECIMAL */
+    {JS_ATOM_OperatorSet, js_operator_set_finalizer, js_operator_set_mark}, /* JS_CLASS_OPERATOR_SET */
+#endif
+    {JS_ATOM_Map, js_map_finalizer, js_map_mark},                                                          /* JS_CLASS_MAP */
+    {JS_ATOM_Set, js_map_finalizer, js_map_mark},                                                          /* JS_CLASS_SET */
+    {JS_ATOM_WeakMap, js_map_finalizer, js_map_mark},                                                      /* JS_CLASS_WEAKMAP */
+    {JS_ATOM_WeakSet, js_map_finalizer, js_map_mark},                                                      /* JS_CLASS_WEAKSET */
+    {JS_ATOM_Map_Iterator, js_map_iterator_finalizer, js_map_iterator_mark},                               /* JS_CLASS_MAP_ITERATOR */
+    {JS_ATOM_Set_Iterator, js_map_iterator_finalizer, js_map_iterator_mark},                               /* JS_CLASS_SET_ITERATOR */
+    {JS_ATOM_Array_Iterator, js_array_iterator_finalizer, js_array_iterator_mark},                         /* JS_CLASS_ARRAY_ITERATOR */
+    {JS_ATOM_String_Iterator, js_array_iterator_finalizer, js_array_iterator_mark},                        /* JS_CLASS_STRING_ITERATOR */
+    {JS_ATOM_RegExp_String_Iterator, js_regexp_string_iterator_finalizer, js_regexp_string_iterator_mark}, /* JS_CLASS_REGEXP_STRING_ITERATOR */
+    {JS_ATOM_Generator, js_generator_finalizer, js_generator_mark},                                        /* JS_CLASS_GENERATOR */
+};
+
+static inline BOOL is_strict_mode(JSContext* ctx) {
+  JSStackFrame* sf = ctx->rt->current_stack_frame;
+  return (sf && (sf->js_mode & JS_MODE_STRICT));
+};
+
+#ifdef CONFIG_BIGNUM
+static inline BOOL is_math_mode(JSContext* ctx) {
+  JSStackFrame* sf = ctx->rt->current_stack_frame;
+  return (sf && (sf->js_mode & JS_MODE_MATH));
+}
+#endif
+
+int js_update_property_flags(JSContext* ctx, JSObject* p, JSShapeProperty** pprs, int flags);
+BOOL js_class_has_bytecode(JSClassID class_id);
+
+/* set the new value and free the old value after (freeing the value
+   can reallocate the object data) */
+static inline void set_value(JSContext* ctx, JSValue* pval, JSValue new_val) {
+  JSValue old_val;
+  old_val = *pval;
+  *pval = new_val;
+  JS_FreeValue(ctx, old_val);
+}
+
+void dbuf_put_leb128(DynBuf* s, uint32_t v);
+void dbuf_put_sleb128(DynBuf* s, int32_t v1);
+int get_leb128(uint32_t* pval, const uint8_t* buf, const uint8_t* buf_end);
+int get_sleb128(int32_t* pval, const uint8_t* buf, const uint8_t* buf_end);
+int find_line_num(JSContext* ctx, JSFunctionBytecode* b, uint32_t pc_value);
+
+/* in order to avoid executing arbitrary code during the stack trace
+   generation, we only look at simple 'name' properties containing a
+   string. */
+const char* get_func_name(JSContext* ctx, JSValueConst func);
+
+/* if filename != NULL, an additional level is added with the filename
+   and line number information (used for parse error). */
+void build_backtrace(JSContext* ctx, JSValueConst error_obj, const char* filename, int line_num, int backtrace_flags);
+BOOL is_backtrace_needed(JSContext* ctx, JSValueConst obj);
+
+/* return -1 (exception) or TRUE/FALSE */
+int JS_SetPrototypeInternal(JSContext* ctx, JSValueConst obj, JSValueConst proto_val, BOOL throw_flag);
+/* Only works for primitive types, otherwise return JS_NULL. */
+JSValueConst JS_GetPrototypePrimitive(JSContext* ctx, JSValueConst val);
+int JS_DeletePropertyInt64(JSContext* ctx, JSValueConst obj, int64_t idx, int flags);
+JSValue JS_GetPrototypeFree(JSContext* ctx, JSValue obj);
+
+JSValue JS_ThrowSyntaxErrorVarRedeclaration(JSContext* ctx, JSAtom prop);
+int JS_CheckDefineGlobalVar(JSContext* ctx, JSAtom prop, int flags);
+int JS_DefineGlobalVar(JSContext* ctx, JSAtom prop, int def_flags);
+int JS_DefineGlobalFunction(JSContext* ctx, JSAtom prop, JSValueConst func, int def_flags);
+
+JSValue JS_GetGlobalVar(JSContext* ctx, JSAtom prop, BOOL throw_ref_error);
+/* construct a reference to a global variable */
+int JS_GetGlobalVarRef(JSContext* ctx, JSAtom prop, JSValue* sp);
+/* use for strict variable access: test if the variable exists */
+int JS_CheckGlobalVar(JSContext* ctx, JSAtom prop);
+/* flag = 0: normal variable write
+   flag = 1: initialize lexical variable
+   flag = 2: normal variable write, strict check was done before
+*/
+int JS_SetGlobalVar(JSContext* ctx, JSAtom prop, JSValue val, int flag);
+
+void JS_SetIsHTMLDDA(JSContext* ctx, JSValueConst obj);
+static inline BOOL JS_IsHTMLDDA(JSContext* ctx, JSValueConst obj) {
+  JSObject* p;
+  if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
+    return FALSE;
+  p = JS_VALUE_GET_OBJ(obj);
+  return p->is_HTMLDDA;
+};
+
+/* compute the property flags. For each flag: (JS_PROP_HAS_x forces
+   it, otherwise def_flags is used)
+   Note: makes assumption about the bit pattern of the flags
+*/
+int get_prop_flags(int flags, int def_flags);
+
+/* set the array length and remove the array elements if necessary. */
+int set_array_length(JSContext* ctx, JSObject* p, JSValue val, int flags);
+/* WARNING: 'p' must be a typed array. Works even if the array buffer
+   is detached */
+uint32_t typed_array_get_length(JSContext* ctx, JSObject* p);
+/* Preconditions: 'p' must be of class JS_CLASS_ARRAY, p->fast_array =
+   TRUE and p->extensible = TRUE */
+int add_fast_array_element(JSContext* ctx, JSObject* p, JSValue val, int flags);
+
+int JS_CreateProperty(JSContext* ctx, JSObject* p, JSAtom prop, JSValueConst val, JSValueConst getter, JSValueConst setter, int flags);
+
+/* return TRUE, FALSE or (-1) in case of exception */
+int JS_OrdinaryIsInstanceOf(JSContext* ctx, JSValueConst val, JSValueConst obj);
+
+JSContext* js_autoinit_get_realm(JSProperty* pr);
+JSAutoInitIDEnum js_autoinit_get_id(JSProperty* pr);
+void js_autoinit_free(JSRuntime* rt, JSProperty* pr);
+void js_autoinit_mark(JSRuntime* rt, JSProperty* pr, JS_MarkFunc* mark_func);
+
+no_inline __exception int __js_poll_interrupts(JSContext* ctx);
+static inline __exception int js_poll_interrupts(JSContext* ctx) {
+  if (unlikely(--ctx->interrupt_counter <= 0)) {
+    return __js_poll_interrupts(ctx);
+  } else {
+    return 0;
+  }
+}
+
+int check_function(JSContext* ctx, JSValueConst obj);
+JSValue JS_EvalObject(JSContext* ctx, JSValueConst this_obj, JSValueConst val, int flags, int scope_idx);
+int check_exception_free(JSContext* ctx, JSValue obj);
+JSAtom find_atom(JSContext* ctx, const char* name);
+JSValue JS_InstantiateFunctionListItem2(JSContext* ctx, JSObject* p, JSAtom atom, void* opaque);
+int JS_InstantiateFunctionListItem(JSContext* ctx, JSValueConst obj, JSAtom atom, const JSCFunctionListEntry* e);
+/* Note: 'func_obj' is not necessarily a constructor */
+void JS_SetConstructor2(JSContext* ctx, JSValueConst func_obj, JSValueConst proto, int proto_flags, int ctor_flags);
+
+JSValueConst JS_NewGlobalCConstructor(JSContext* ctx, const char* name, JSCFunction* func, int length, JSValueConst proto);
+
+JSValue iterator_to_array(JSContext* ctx, JSValueConst items);
+/* only valid inside C functions */
+JSValueConst JS_GetActiveFunction(JSContext* ctx);
+JSValue js_error_constructor(JSContext* ctx, JSValueConst new_target, int argc, JSValueConst* argv, int magic);
+JSValue js_aggregate_error_constructor(JSContext* ctx, JSValueConst errors);
+JSValue js_error_toString(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+void JS_NewGlobalCConstructor2(JSContext* ctx, JSValue func_obj, const char* name, JSValueConst proto);
+JSValueConst JS_NewGlobalCConstructorOnly(JSContext* ctx, const char* name, JSCFunction* func, int length, JSValueConst proto);
+JSValue js_global_eval(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_global_isNaN(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+JSValue js_global_isFinite(JSContext* ctx, JSValueConst this_val, int argc, JSValueConst* argv);
+int string_get_hex(JSString* p, int k, int n);
+int init_class_range(JSRuntime* rt, JSClassShortDef const* tab, int start, int count);
+/* the indirection is needed to make 'eval' optional */
+JSValue JS_EvalInternal(JSContext* ctx, JSValueConst this_obj, const char* input, size_t input_len, const char* filename, int flags, int scope_idx);
+JSValue JS_EvalFunctionInternal(JSContext* ctx, JSValue fun_obj, JSValueConst this_obj, JSVarRef** var_refs, JSStackFrame* sf);
+
+#endif
diff --git a/src/core/shape.c b/src/core/shape.c
new file mode 100644
index 000000000..5e79d4d91
--- /dev/null
+++ b/src/core/shape.c
@@ -0,0 +1,587 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shape.h"
+#include "gc.h"
+#include "malloc.h"
+#include "object.h"
+#include "string.h"
+
+/* Shape support */
+
+
+int init_shape_hash(JSRuntime* rt) {
+  rt->shape_hash_bits = 4; /* 16 shapes */
+  rt->shape_hash_size = 1 << rt->shape_hash_bits;
+  rt->shape_hash_count = 0;
+  rt->shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) * rt->shape_hash_size);
+  if (!rt->shape_hash)
+    return -1;
+  return 0;
+}
+
+/* same magic hash multiplier as the Linux kernel */
+uint32_t shape_hash(uint32_t h, uint32_t val) {
+  return (h + val) * 0x9e370001;
+}
+
+/* truncate the shape hash to 'hash_bits' bits */
+uint32_t get_shape_hash(uint32_t h, int hash_bits) {
+  return h >> (32 - hash_bits);
+}
+
+uint32_t shape_initial_hash(JSObject* proto) {
+  uint32_t h;
+  h = shape_hash(1, (uintptr_t)proto);
+  if (sizeof(proto) > 4)
+    h = shape_hash(h, (uint64_t)(uintptr_t)proto >> 32);
+  return h;
+}
+
+int resize_shape_hash(JSRuntime* rt, int new_shape_hash_bits) {
+  int new_shape_hash_size, i;
+  uint32_t h;
+  JSShape **new_shape_hash, *sh, *sh_next;
+
+  new_shape_hash_size = 1 << new_shape_hash_bits;
+  new_shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) * new_shape_hash_size);
+  if (!new_shape_hash)
+    return -1;
+  for (i = 0; i < rt->shape_hash_size; i++) {
+    for (sh = rt->shape_hash[i]; sh != NULL; sh = sh_next) {
+      sh_next = sh->shape_hash_next;
+      h = get_shape_hash(sh->hash, new_shape_hash_bits);
+      sh->shape_hash_next = new_shape_hash[h];
+      new_shape_hash[h] = sh;
+    }
+  }
+  js_free_rt(rt, rt->shape_hash);
+  rt->shape_hash_bits = new_shape_hash_bits;
+  rt->shape_hash_size = new_shape_hash_size;
+  rt->shape_hash = new_shape_hash;
+  return 0;
+}
+
+void js_shape_hash_link(JSRuntime* rt, JSShape* sh) {
+  uint32_t h;
+  h = get_shape_hash(sh->hash, rt->shape_hash_bits);
+  sh->shape_hash_next = rt->shape_hash[h];
+  rt->shape_hash[h] = sh;
+  rt->shape_hash_count++;
+}
+
+void js_shape_hash_unlink(JSRuntime* rt, JSShape* sh) {
+  uint32_t h;
+  JSShape** psh;
+
+  h = get_shape_hash(sh->hash, rt->shape_hash_bits);
+  psh = &rt->shape_hash[h];
+  while (*psh != sh)
+    psh = &(*psh)->shape_hash_next;
+  *psh = sh->shape_hash_next;
+  rt->shape_hash_count--;
+}
+
+/* create a new empty shape with prototype 'proto' */
+no_inline JSShape* js_new_shape2(JSContext* ctx, JSObject* proto, int hash_size, int prop_size) {
+  JSRuntime* rt = ctx->rt;
+  void* sh_alloc;
+  JSShape* sh;
+
+  /* resize the shape hash table if necessary */
+  if (2 * (rt->shape_hash_count + 1) > rt->shape_hash_size) {
+    resize_shape_hash(rt, rt->shape_hash_bits + 1);
+  }
+
+  sh_alloc = js_malloc(ctx, get_shape_size(hash_size, prop_size));
+  if (!sh_alloc)
+    return NULL;
+  sh = get_shape_from_alloc(sh_alloc, hash_size);
+  sh->header.ref_count = 1;
+  add_gc_object(rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);
+  if (proto)
+    JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, proto));
+  sh->proto = proto;
+  memset(prop_hash_end(sh) - hash_size, 0, sizeof(prop_hash_end(sh)[0]) * hash_size);
+  sh->prop_hash_mask = hash_size - 1;
+  sh->prop_size = prop_size;
+  sh->prop_count = 0;
+  sh->deleted_prop_count = 0;
+
+  /* insert in the hash table */
+  sh->hash = shape_initial_hash(proto);
+  sh->is_hashed = TRUE;
+  sh->has_small_array_index = FALSE;
+  js_shape_hash_link(ctx->rt, sh);
+  return sh;
+}
+
+JSShape* js_new_shape(JSContext* ctx, JSObject* proto) {
+  return js_new_shape2(ctx, proto, JS_PROP_INITIAL_HASH_SIZE, JS_PROP_INITIAL_SIZE);
+}
+
+/* The shape is cloned. The new shape is not inserted in the shape
+   hash table */
+JSShape* js_clone_shape(JSContext* ctx, JSShape* sh1) {
+  JSShape* sh;
+  void *sh_alloc, *sh_alloc1;
+  size_t size;
+  JSShapeProperty* pr;
+  uint32_t i, hash_size;
+
+  hash_size = sh1->prop_hash_mask + 1;
+  size = get_shape_size(hash_size, sh1->prop_size);
+  sh_alloc = js_malloc(ctx, size);
+  if (!sh_alloc)
+    return NULL;
+  sh_alloc1 = get_alloc_from_shape(sh1);
+  memcpy(sh_alloc, sh_alloc1, size);
+  sh = get_shape_from_alloc(sh_alloc, hash_size);
+  sh->header.ref_count = 1;
+  add_gc_object(ctx->rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);
+  sh->is_hashed = FALSE;
+  if (sh->proto) {
+    JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
+  }
+  for (i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {
+    JS_DupAtom(ctx, pr->atom);
+  }
+  return sh;
+}
+
+JSShape* js_dup_shape(JSShape* sh) {
+  sh->header.ref_count++;
+  return sh;
+}
+
+void js_free_shape0(JSRuntime* rt, JSShape* sh) {
+  uint32_t i;
+  JSShapeProperty* pr;
+
+  assert(sh->header.ref_count == 0);
+  if (sh->is_hashed)
+    js_shape_hash_unlink(rt, sh);
+  if (sh->proto != NULL) {
+    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
+  }
+  pr = get_shape_prop(sh);
+  for (i = 0; i < sh->prop_count; i++) {
+    JS_FreeAtomRT(rt, pr->atom);
+    pr++;
+  }
+  remove_gc_object(&sh->header);
+  js_free_rt(rt, get_alloc_from_shape(sh));
+}
+
+void js_free_shape(JSRuntime* rt, JSShape* sh) {
+  if (unlikely(--sh->header.ref_count <= 0)) {
+    js_free_shape0(rt, sh);
+  }
+}
+
+void js_free_shape_null(JSRuntime* rt, JSShape* sh) {
+  if (sh)
+    js_free_shape(rt, sh);
+}
+
+/* make space to hold at least 'count' properties */
+no_inline int resize_properties(JSContext* ctx, JSShape** psh, JSObject* p, uint32_t count) {
+  JSShape* sh;
+  uint32_t new_size, new_hash_size, new_hash_mask, i;
+  JSShapeProperty* pr;
+  void* sh_alloc;
+  intptr_t h;
+
+  sh = *psh;
+  new_size = max_int(count, sh->prop_size * 3 / 2);
+  /* Reallocate prop array first to avoid crash or size inconsistency
+     in case of memory allocation failure */
+  if (p) {
+    JSProperty* new_prop;
+    new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size);
+    if (unlikely(!new_prop))
+      return -1;
+    p->prop = new_prop;
+  }
+  new_hash_size = sh->prop_hash_mask + 1;
+  while (new_hash_size < new_size)
+    new_hash_size = 2 * new_hash_size;
+  if (new_hash_size != (sh->prop_hash_mask + 1)) {
+    JSShape* old_sh;
+    /* resize the hash table and the properties */
+    old_sh = sh;
+    sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
+    if (!sh_alloc)
+      return -1;
+    sh = get_shape_from_alloc(sh_alloc, new_hash_size);
+    list_del(&old_sh->header.link);
+    /* copy all the fields and the properties */
+    memcpy(sh, old_sh, sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count);
+    list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
+    new_hash_mask = new_hash_size - 1;
+    sh->prop_hash_mask = new_hash_mask;
+    memset(prop_hash_end(sh) - new_hash_size, 0, sizeof(prop_hash_end(sh)[0]) * new_hash_size);
+    for (i = 0, pr = sh->prop; i < sh->prop_count; i++, pr++) {
+      if (pr->atom != JS_ATOM_NULL) {
+        h = ((uintptr_t)pr->atom & new_hash_mask);
+        pr->hash_next = prop_hash_end(sh)[-h - 1];
+        prop_hash_end(sh)[-h - 1] = i + 1;
+      }
+    }
+    js_free(ctx, get_alloc_from_shape(old_sh));
+  } else {
+    /* only resize the properties */
+    list_del(&sh->header.link);
+    sh_alloc = js_realloc(ctx, get_alloc_from_shape(sh), get_shape_size(new_hash_size, new_size));
+    if (unlikely(!sh_alloc)) {
+      /* insert again in the GC list */
+      list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
+      return -1;
+    }
+    sh = get_shape_from_alloc(sh_alloc, new_hash_size);
+    list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
+  }
+  *psh = sh;
+  sh->prop_size = new_size;
+  return 0;
+}
+
+/* remove the deleted properties. */
+int compact_properties(JSContext* ctx, JSObject* p) {
+  JSShape *sh, *old_sh;
+  void* sh_alloc;
+  intptr_t h;
+  uint32_t new_hash_size, i, j, new_hash_mask, new_size;
+  JSShapeProperty *old_pr, *pr;
+  JSProperty *prop, *new_prop;
+
+  sh = p->shape;
+  assert(!sh->is_hashed);
+
+  new_size = max_int(JS_PROP_INITIAL_SIZE, sh->prop_count - sh->deleted_prop_count);
+  assert(new_size <= sh->prop_size);
+
+  new_hash_size = sh->prop_hash_mask + 1;
+  while ((new_hash_size / 2) >= new_size)
+    new_hash_size = new_hash_size / 2;
+  new_hash_mask = new_hash_size - 1;
+
+  /* resize the hash table and the properties */
+  old_sh = sh;
+  sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
+  if (!sh_alloc)
+    return -1;
+  sh = get_shape_from_alloc(sh_alloc, new_hash_size);
+  list_del(&old_sh->header.link);
+  memcpy(sh, old_sh, sizeof(JSShape));
+  list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
+
+  memset(prop_hash_end(sh) - new_hash_size, 0, sizeof(prop_hash_end(sh)[0]) * new_hash_size);
+
+  j = 0;
+  old_pr = old_sh->prop;
+  pr = sh->prop;
+  prop = p->prop;
+  for (i = 0; i < sh->prop_count; i++) {
+    if (old_pr->atom != JS_ATOM_NULL) {
+      pr->atom = old_pr->atom;
+      pr->flags = old_pr->flags;
+      h = ((uintptr_t)old_pr->atom & new_hash_mask);
+      pr->hash_next = prop_hash_end(sh)[-h - 1];
+      prop_hash_end(sh)[-h - 1] = j + 1;
+      prop[j] = prop[i];
+      j++;
+      pr++;
+    }
+    old_pr++;
+  }
+  assert(j == (sh->prop_count - sh->deleted_prop_count));
+  sh->prop_hash_mask = new_hash_mask;
+  sh->prop_size = new_size;
+  sh->deleted_prop_count = 0;
+  sh->prop_count = j;
+
+  p->shape = sh;
+  js_free(ctx, get_alloc_from_shape(old_sh));
+
+  /* reduce the size of the object properties */
+  new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size);
+  if (new_prop)
+    p->prop = new_prop;
+  return 0;
+}
+
+int add_shape_property(JSContext* ctx, JSShape** psh, JSObject* p, JSAtom atom, int prop_flags) {
+  JSRuntime* rt = ctx->rt;
+  JSShape* sh = *psh;
+  JSShapeProperty *pr, *prop;
+  uint32_t hash_mask, new_shape_hash = 0;
+  intptr_t h;
+
+  /* update the shape hash */
+  if (sh->is_hashed) {
+    js_shape_hash_unlink(rt, sh);
+    new_shape_hash = shape_hash(shape_hash(sh->hash, atom), prop_flags);
+  }
+
+  if (unlikely(sh->prop_count >= sh->prop_size)) {
+    if (resize_properties(ctx, psh, p, sh->prop_count + 1)) {
+      /* in case of error, reinsert in the hash table.
+         sh is still valid if resize_properties() failed */
+      if (sh->is_hashed)
+        js_shape_hash_link(rt, sh);
+      return -1;
+    }
+    sh = *psh;
+  }
+  if (sh->is_hashed) {
+    sh->hash = new_shape_hash;
+    js_shape_hash_link(rt, sh);
+  }
+  /* Initialize the new shape property.
+     The object property at p->prop[sh->prop_count] is uninitialized */
+  prop = get_shape_prop(sh);
+  pr = &prop[sh->prop_count++];
+  pr->atom = JS_DupAtom(ctx, atom);
+  pr->flags = prop_flags;
+  sh->has_small_array_index |= __JS_AtomIsTaggedInt(atom);
+  /* add in hash table */
+  hash_mask = sh->prop_hash_mask;
+  h = atom & hash_mask;
+  pr->hash_next = prop_hash_end(sh)[-h - 1];
+  prop_hash_end(sh)[-h - 1] = sh->prop_count;
+  return 0;
+}
+
+/* find a hashed empty shape matching the prototype. Return NULL if
+   not found */
+JSShape* find_hashed_shape_proto(JSRuntime* rt, JSObject* proto) {
+  JSShape* sh1;
+  uint32_t h, h1;
+
+  h = shape_initial_hash(proto);
+  h1 = get_shape_hash(h, rt->shape_hash_bits);
+  for (sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) {
+    if (sh1->hash == h && sh1->proto == proto && sh1->prop_count == 0) {
+      return sh1;
+    }
+  }
+  return NULL;
+}
+
+/* find a hashed shape matching sh + (prop, prop_flags). Return NULL if
+   not found */
+JSShape* find_hashed_shape_prop(JSRuntime* rt, JSShape* sh, JSAtom atom, int prop_flags) {
+  JSShape* sh1;
+  uint32_t h, h1, i, n;
+
+  h = sh->hash;
+  h = shape_hash(h, atom);
+  h = shape_hash(h, prop_flags);
+  h1 = get_shape_hash(h, rt->shape_hash_bits);
+  for (sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) {
+    /* we test the hash first so that the rest is done only if the
+       shapes really match */
+    if (sh1->hash == h && sh1->proto == sh->proto && sh1->prop_count == ((n = sh->prop_count) + 1)) {
+      for (i = 0; i < n; i++) {
+        if (unlikely(sh1->prop[i].atom != sh->prop[i].atom) || unlikely(sh1->prop[i].flags != sh->prop[i].flags))
+          goto next;
+      }
+      if (unlikely(sh1->prop[n].atom != atom) || unlikely(sh1->prop[n].flags != prop_flags))
+        goto next;
+      return sh1;
+    }
+  next:;
+  }
+  return NULL;
+}
+
+__maybe_unused void JS_DumpShape(JSRuntime* rt, int i, JSShape* sh) {
+  char atom_buf[ATOM_GET_STR_BUF_SIZE];
+  int j;
+
+  /* XXX: should output readable class prototype */
+  printf("%5d %3d%c %14p %5d %5d", i, sh->header.ref_count, " *"[sh->is_hashed], (void*)sh -> proto, sh -> prop_size,
+         sh -> prop_count);
+  for (j = 0; j < sh->prop_count; j++) {
+    printf(" %s", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf), sh->prop[j].atom));
+  }
+  printf("\n");
+}
+
+__maybe_unused void JS_DumpShapes(JSRuntime* rt) {
+  int i;
+  JSShape* sh;
+  struct list_head* el;
+  JSObject* p;
+  JSGCObjectHeader* gp;
+
+  printf("JSShapes: {\n");
+  printf("%5s %4s %14s %5s %5s %s\n", "SLOT", "REFS", "PROTO", "SIZE", "COUNT", "PROPS");
+  for (i = 0; i < rt->shape_hash_size; i++) {
+    for (sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) {
+      JS_DumpShape(rt, i, sh);
+      assert(sh->is_hashed);
+    }
+  }
+  /* dump non-hashed shapes */
+  list_for_each(el, &rt->gc_obj_list) {
+    gp = list_entry(el, JSGCObjectHeader, link);
+    if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
+      p = (JSObject*)gp;
+      if (!p->shape->is_hashed) {
+        JS_DumpShape(rt, -1, p->shape);
+      }
+    }
+  }
+  printf("}\n");
+}
+
+JSValue JS_NewObjectFromShape(JSContext* ctx, JSShape* sh, JSClassID class_id) {
+  JSObject* p;
+
+  js_trigger_gc(ctx->rt, sizeof(JSObject));
+  p = js_malloc(ctx, sizeof(JSObject));
+  if (unlikely(!p))
+    goto fail;
+  p->class_id = class_id;
+  p->extensible = TRUE;
+  p->free_mark = 0;
+  p->is_exotic = 0;
+  p->fast_array = 0;
+  p->is_constructor = 0;
+  p->is_uncatchable_error = 0;
+  p->tmp_mark = 0;
+  p->is_HTMLDDA = 0;
+  p->first_weak_ref = NULL;
+  p->u.opaque = NULL;
+  p->shape = sh;
+  p->prop = js_malloc(ctx, sizeof(JSProperty) * sh->prop_size);
+  if (unlikely(!p->prop)) {
+    js_free(ctx, p);
+  fail:
+    js_free_shape(ctx->rt, sh);
+    return JS_EXCEPTION;
+  }
+
+  switch (class_id) {
+    case JS_CLASS_OBJECT:
+      break;
+    case JS_CLASS_ARRAY: {
+      JSProperty* pr;
+      p->is_exotic = 1;
+      p->fast_array = 1;
+      p->u.array.u.values = NULL;
+      p->u.array.count = 0;
+      p->u.array.u1.size = 0;
+      /* the length property is always the first one */
+      if (likely(sh == ctx->array_shape)) {
+        pr = &p->prop[0];
+      } else {
+        /* only used for the first array */
+        /* cannot fail */
+        pr = add_property(ctx, p, JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_LENGTH);
+      }
+      pr->u.value = JS_NewInt32(ctx, 0);
+    } break;
+    case JS_CLASS_C_FUNCTION:
+      p->prop[0].u.value = JS_UNDEFINED;
+      break;
+    case JS_CLASS_ARGUMENTS:
+    case JS_CLASS_UINT8C_ARRAY:
+    case JS_CLASS_INT8_ARRAY:
+    case JS_CLASS_UINT8_ARRAY:
+    case JS_CLASS_INT16_ARRAY:
+    case JS_CLASS_UINT16_ARRAY:
+    case JS_CLASS_INT32_ARRAY:
+    case JS_CLASS_UINT32_ARRAY:
+#ifdef CONFIG_BIGNUM
+    case JS_CLASS_BIG_INT64_ARRAY:
+    case JS_CLASS_BIG_UINT64_ARRAY:
+#endif
+    case JS_CLASS_FLOAT32_ARRAY:
+    case JS_CLASS_FLOAT64_ARRAY:
+      p->is_exotic = 1;
+      p->fast_array = 1;
+      p->u.array.u.ptr = NULL;
+      p->u.array.count = 0;
+      break;
+    case JS_CLASS_DATAVIEW:
+      p->u.array.u.ptr = NULL;
+      p->u.array.count = 0;
+      break;
+    case JS_CLASS_NUMBER:
+    case JS_CLASS_STRING:
+    case JS_CLASS_BOOLEAN:
+    case JS_CLASS_SYMBOL:
+    case JS_CLASS_DATE:
+#ifdef CONFIG_BIGNUM
+    case JS_CLASS_BIG_INT:
+    case JS_CLASS_BIG_FLOAT:
+    case JS_CLASS_BIG_DECIMAL:
+#endif
+      p->u.object_data = JS_UNDEFINED;
+      goto set_exotic;
+    case JS_CLASS_REGEXP:
+      p->u.regexp.pattern = NULL;
+      p->u.regexp.bytecode = NULL;
+      goto set_exotic;
+    default:
+    set_exotic:
+      if (ctx->rt->class_array[class_id].exotic) {
+        p->is_exotic = 1;
+      }
+      break;
+  }
+  p->header.ref_count = 1;
+  add_gc_object(ctx->rt, &p->header, JS_GC_OBJ_TYPE_JS_OBJECT);
+  return JS_MKPTR(JS_TAG_OBJECT, p);
+}
+
+/* ensure that the shape can be safely modified */
+int js_shape_prepare_update(JSContext* ctx, JSObject* p, JSShapeProperty** pprs) {
+  JSShape* sh;
+  uint32_t idx = 0; /* prevent warning */
+
+  sh = p->shape;
+  if (sh->is_hashed) {
+    if (sh->header.ref_count != 1) {
+      if (pprs)
+        idx = *pprs - get_shape_prop(sh);
+      /* clone the shape (the resulting one is no longer hashed) */
+      sh = js_clone_shape(ctx, sh);
+      if (!sh)
+        return -1;
+      js_free_shape(ctx->rt, p->shape);
+      p->shape = sh;
+      if (pprs)
+        *pprs = get_shape_prop(sh) + idx;
+    } else {
+      js_shape_hash_unlink(ctx->rt, sh);
+      sh->is_hashed = FALSE;
+    }
+  }
+  return 0;
+}
\ No newline at end of file
diff --git a/src/core/shape.h b/src/core/shape.h
new file mode 100644
index 000000000..e82921252
--- /dev/null
+++ b/src/core/shape.h
@@ -0,0 +1,91 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_SHAPE_H
+#define QUICKJS_SHAPE_H
+
+#include "quickjs/quickjs.h"
+#include "quickjs/cutils.h"
+#include "types.h"
+
+
+static inline size_t get_shape_size(size_t hash_size, size_t prop_size) {
+  return hash_size * sizeof(uint32_t) + sizeof(JSShape) + prop_size * sizeof(JSShapeProperty);
+}
+
+static inline JSShape* get_shape_from_alloc(void* sh_alloc, size_t hash_size) {
+  return (JSShape*)(void*)((uint32_t*)sh_alloc + hash_size);
+}
+
+static inline uint32_t* prop_hash_end(JSShape* sh) {
+  return (uint32_t*)sh;
+}
+
+static inline void* get_alloc_from_shape(JSShape* sh) {
+  return prop_hash_end(sh) - ((intptr_t)sh->prop_hash_mask + 1);
+}
+
+static inline JSShapeProperty* get_shape_prop(JSShape* sh) {
+  return sh->prop;
+}
+
+int init_shape_hash(JSRuntime* rt);
+/* same magic hash multiplier as the Linux kernel */
+uint32_t shape_hash(uint32_t h, uint32_t val);
+/* truncate the shape hash to 'hash_bits' bits */
+uint32_t get_shape_hash(uint32_t h, int hash_bits);
+uint32_t shape_initial_hash(JSObject* proto);
+int resize_shape_hash(JSRuntime* rt, int new_shape_hash_bits);
+void js_shape_hash_link(JSRuntime* rt, JSShape* sh);
+void js_shape_hash_unlink(JSRuntime* rt, JSShape* sh);
+/* create a new empty shape with prototype 'proto' */
+no_inline JSShape* js_new_shape2(JSContext* ctx, JSObject* proto, int hash_size, int prop_size);
+JSShape* js_new_shape(JSContext* ctx, JSObject* proto);
+
+/* The shape is cloned. The new shape is not inserted in the shape
+   hash table */
+JSShape* js_clone_shape(JSContext* ctx, JSShape* sh1);
+JSShape* js_dup_shape(JSShape* sh);
+void js_free_shape0(JSRuntime* rt, JSShape* sh);
+void js_free_shape(JSRuntime* rt, JSShape* sh);
+void js_free_shape_null(JSRuntime* rt, JSShape* sh);
+/* make space to hold at least 'count' properties */
+no_inline int resize_properties(JSContext* ctx, JSShape** psh, JSObject* p, uint32_t count);
+/* remove the deleted properties. */
+int compact_properties(JSContext* ctx, JSObject* p);
+int add_shape_property(JSContext* ctx, JSShape** psh, JSObject* p, JSAtom atom, int prop_flags);
+/* find a hashed empty shape matching the prototype. Return NULL if
+   not found */
+JSShape* find_hashed_shape_proto(JSRuntime* rt, JSObject* proto);
+/* find a hashed shape matching sh + (prop, prop_flags). Return NULL if
+   not found */
+JSShape* find_hashed_shape_prop(JSRuntime* rt, JSShape* sh, JSAtom atom, int prop_flags);;
+__maybe_unused void JS_DumpShape(JSRuntime* rt, int i, JSShape* sh);
+__maybe_unused void JS_DumpShapes(JSRuntime* rt);
+JSValue JS_NewObjectFromShape(JSContext* ctx, JSShape* sh, JSClassID class_id);
+/* ensure that the shape can be safely modified */
+int js_shape_prepare_update(JSContext* ctx, JSObject* p, JSShapeProperty** pprs);
+
+#endif
diff --git a/src/core/string.c b/src/core/string.c
new file mode 100644
index 000000000..cb5720ba4
--- /dev/null
+++ b/src/core/string.c
@@ -0,0 +1,1631 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "string.h"
+#include "convertion.h"
+#include "exception.h"
+#include "quickjs/cutils.h"
+#include "quickjs/list.h"
+
+/* Note: the string contents are uninitialized */
+JSString* js_alloc_string_rt(JSRuntime* rt, int max_len, int is_wide_char) {
+  JSString* str;
+  str = js_malloc_rt(rt, sizeof(JSString) + (max_len << is_wide_char) + 1 - is_wide_char);
+  if (unlikely(!str))
+    return NULL;
+  str->header.ref_count = 1;
+  str->is_wide_char = is_wide_char;
+  str->len = max_len;
+  str->atom_type = 0;
+  str->hash = 0;      /* optional but costless */
+  str->hash_next = 0; /* optional */
+#ifdef DUMP_LEAKS
+  list_add_tail(&str->link, &rt->string_list);
+#endif
+  return str;
+}
+
+JSString* js_alloc_string(JSContext* ctx, int max_len, int is_wide_char) {
+  JSString* p;
+  p = js_alloc_string_rt(ctx->rt, max_len, is_wide_char);
+  if (unlikely(!p)) {
+    JS_ThrowOutOfMemory(ctx);
+    return NULL;
+  }
+  return p;
+}
+
+
+int JS_ResizeAtomHash(JSRuntime* rt, int new_hash_size) {
+  JSAtomStruct* p;
+  uint32_t new_hash_mask, h, i, hash_next1, j, *new_hash;
+
+  assert((new_hash_size & (new_hash_size - 1)) == 0); /* power of two */
+  new_hash_mask = new_hash_size - 1;
+  new_hash = js_mallocz_rt(rt, sizeof(rt->atom_hash[0]) * new_hash_size);
+  if (!new_hash)
+    return -1;
+  for (i = 0; i < rt->atom_hash_size; i++) {
+    h = rt->atom_hash[i];
+    while (h != 0) {
+      p = rt->atom_array[h];
+      hash_next1 = p->hash_next;
+      /* add in new hash table */
+      j = p->hash & new_hash_mask;
+      p->hash_next = new_hash[j];
+      new_hash[j] = h;
+      h = hash_next1;
+    }
+  }
+  js_free_rt(rt, rt->atom_hash);
+  rt->atom_hash = new_hash;
+  rt->atom_hash_size = new_hash_size;
+  rt->atom_count_resize = JS_ATOM_COUNT_RESIZE(new_hash_size);
+  //    JS_DumpAtoms(rt);
+  return 0;
+}
+
+int JS_InitAtoms(JSRuntime* rt) {
+  int i, len, atom_type;
+  const char* p;
+
+  rt->atom_hash_size = 0;
+  rt->atom_hash = NULL;
+  rt->atom_count = 0;
+  rt->atom_size = 0;
+  rt->atom_free_index = 0;
+  if (JS_ResizeAtomHash(rt, 1024)) /* there are at least 195 predefined atoms */
+    return -1;
+
+  p = js_atom_init;
+
+  for (i = 1; i < JS_ATOM_END; i++) {
+    if (i == JS_ATOM_Private_brand)
+      atom_type = JS_ATOM_TYPE_PRIVATE;
+    else if (i >= JS_ATOM_Symbol_toPrimitive && i <= JS_ATOM_Symbol_asyncIterator)
+      atom_type = JS_ATOM_TYPE_SYMBOL;
+    else
+      atom_type = JS_ATOM_TYPE_STRING;
+    len = strlen(p);
+    if (__JS_NewAtomInit(rt, p, len, atom_type) == JS_ATOM_NULL)
+      return -1;
+    p = p + len + 1;
+  }
+  return 0;
+}
+
+
+uint32_t hash_string(const JSString* str, uint32_t h) {
+  if (str->is_wide_char)
+    h = hash_string16(str->u.str16, str->len, h);
+  else
+    h = hash_string8(str->u.str8, str->len, h);
+  return h;
+}
+
+__maybe_unused void JS_DumpString(JSRuntime* rt, const JSString* p) {
+  int i, c, sep;
+
+  if (p == NULL) {
+    printf("<null>");
+    return;
+  }
+  printf("%d", p->header.ref_count);
+  sep = (p->header.ref_count == 1) ? '\"' : '\'';
+  putchar(sep);
+  for (i = 0; i < p->len; i++) {
+    if (p->is_wide_char)
+      c = p->u.str16[i];
+    else
+      c = p->u.str8[i];
+    if (c == sep || c == '\\') {
+      putchar('\\');
+      putchar(c);
+    } else if (c >= ' ' && c <= 126) {
+      putchar(c);
+    } else if (c == '\n') {
+      putchar('\\');
+      putchar('n');
+    } else {
+      printf("\\u%04x", c);
+    }
+  }
+  putchar(sep);
+}
+
+__maybe_unused void JS_DumpAtoms(JSRuntime* rt) {
+  JSAtomStruct* p;
+  int h, i;
+  /* This only dumps hashed atoms, not JS_ATOM_TYPE_SYMBOL atoms */
+  printf("JSAtom count=%d size=%d hash_size=%d:\n", rt->atom_count, rt->atom_size, rt->atom_hash_size);
+  printf("JSAtom hash table: {\n");
+  for (i = 0; i < rt->atom_hash_size; i++) {
+    h = rt->atom_hash[i];
+    if (h) {
+      printf("  %d:", i);
+      while (h) {
+        p = rt->atom_array[h];
+        printf(" ");
+        JS_DumpString(rt, p);
+        h = p->hash_next;
+      }
+      printf("\n");
+    }
+  }
+  printf("}\n");
+  printf("JSAtom table: {\n");
+  for (i = 0; i < rt->atom_size; i++) {
+    p = rt->atom_array[i];
+    if (!atom_is_free(p)) {
+      printf("  %d: { %d %08x ", i, p->atom_type, p->hash);
+      if (!(p->len == 0 && p->is_wide_char != 0))
+        JS_DumpString(rt, p);
+      printf(" %d }\n", p->hash_next);
+    }
+  }
+  printf("}\n");
+}
+
+JSAtom JS_DupAtomRT(JSRuntime* rt, JSAtom v) {
+  JSAtomStruct* p;
+
+  if (!__JS_AtomIsConst(v)) {
+    p = rt->atom_array[v];
+    p->header.ref_count++;
+  }
+  return v;
+}
+
+JSAtom JS_DupAtom(JSContext* ctx, JSAtom v) {
+  JSRuntime* rt;
+  JSAtomStruct* p;
+
+  if (!__JS_AtomIsConst(v)) {
+    rt = ctx->rt;
+    p = rt->atom_array[v];
+    p->header.ref_count++;
+  }
+  return v;
+}
+
+JSAtomKindEnum JS_AtomGetKind(JSContext* ctx, JSAtom v) {
+  JSRuntime* rt;
+  JSAtomStruct* p;
+
+  rt = ctx->rt;
+  if (__JS_AtomIsTaggedInt(v))
+    return JS_ATOM_KIND_STRING;
+  p = rt->atom_array[v];
+  switch (p->atom_type) {
+    case JS_ATOM_TYPE_STRING:
+      return JS_ATOM_KIND_STRING;
+    case JS_ATOM_TYPE_GLOBAL_SYMBOL:
+      return JS_ATOM_KIND_SYMBOL;
+    case JS_ATOM_TYPE_SYMBOL:
+      switch (p->hash) {
+        case JS_ATOM_HASH_SYMBOL:
+          return JS_ATOM_KIND_SYMBOL;
+        case JS_ATOM_HASH_PRIVATE:
+          return JS_ATOM_KIND_PRIVATE;
+        default:
+          abort();
+      }
+    default:
+      abort();
+  }
+}
+
+BOOL JS_AtomIsString(JSContext* ctx, JSAtom v) {
+  return JS_AtomGetKind(ctx, v) == JS_ATOM_KIND_STRING;
+}
+
+JSAtom js_get_atom_index(JSRuntime* rt, JSAtomStruct* p) {
+  uint32_t i = p->hash_next; /* atom_index */
+  if (p->atom_type != JS_ATOM_TYPE_SYMBOL) {
+    JSAtomStruct* p1;
+
+    i = rt->atom_hash[p->hash & (rt->atom_hash_size - 1)];
+    p1 = rt->atom_array[i];
+    while (p1 != p) {
+      assert(i != 0);
+      i = p1->hash_next;
+      p1 = rt->atom_array[i];
+    }
+  }
+  return i;
+}
+
+int memcmp16_8(const uint16_t* src1, const uint8_t* src2, int len) {
+  int c, i;
+  for (i = 0; i < len; i++) {
+    c = src1[i] - src2[i];
+    if (c != 0)
+      return c;
+  }
+  return 0;
+}
+
+int memcmp16(const uint16_t* src1, const uint16_t* src2, int len) {
+  int c, i;
+  for (i = 0; i < len; i++) {
+    c = src1[i] - src2[i];
+    if (c != 0)
+      return c;
+  }
+  return 0;
+}
+
+int js_string_memcmp(const JSString* p1, const JSString* p2, int len) {
+  int res;
+
+  if (likely(!p1->is_wide_char)) {
+    if (likely(!p2->is_wide_char))
+      res = memcmp(p1->u.str8, p2->u.str8, len);
+    else
+      res = -memcmp16_8(p2->u.str16, p1->u.str8, len);
+  } else {
+    if (!p2->is_wide_char)
+      res = memcmp16_8(p1->u.str16, p2->u.str8, len);
+    else
+      res = memcmp16(p1->u.str16, p2->u.str16, len);
+  }
+  return res;
+}
+
+/* return < 0, 0 or > 0 */
+int js_string_compare(JSContext* ctx, const JSString* p1, const JSString* p2) {
+  int res, len;
+  len = min_int(p1->len, p2->len);
+  res = js_string_memcmp(p1, p2, len);
+  if (res == 0) {
+    if (p1->len == p2->len)
+      res = 0;
+    else if (p1->len < p2->len)
+      res = -1;
+    else
+      res = 1;
+  }
+  return res;
+}
+
+void copy_str16(uint16_t* dst, const JSString* p, int offset, int len) {
+  if (p->is_wide_char) {
+    memcpy(dst, p->u.str16 + offset, len * 2);
+  } else {
+    const uint8_t* src1 = p->u.str8 + offset;
+    int i;
+
+    for (i = 0; i < len; i++)
+      dst[i] = src1[i];
+  }
+}
+
+JSValue JS_ConcatString1(JSContext* ctx, const JSString* p1, const JSString* p2) {
+  JSString* p;
+  uint32_t len;
+  int is_wide_char;
+
+  len = p1->len + p2->len;
+  if (len > JS_STRING_LEN_MAX)
+    return JS_ThrowInternalError(ctx, "string too long");
+  is_wide_char = p1->is_wide_char | p2->is_wide_char;
+  p = js_alloc_string(ctx, len, is_wide_char);
+  if (!p)
+    return JS_EXCEPTION;
+  if (!is_wide_char) {
+    memcpy(p->u.str8, p1->u.str8, p1->len);
+    memcpy(p->u.str8 + p1->len, p2->u.str8, p2->len);
+    p->u.str8[len] = '\0';
+  } else {
+    copy_str16(p->u.str16, p1, 0, p1->len);
+    copy_str16(p->u.str16 + p1->len, p2, 0, p2->len);
+  }
+  return JS_MKPTR(JS_TAG_STRING, p);
+}
+
+/* string case (internal). Return JS_ATOM_NULL if error. 'str' is
+   freed. */
+JSAtom __JS_NewAtom(JSRuntime* rt, JSString* str, int atom_type) {
+  uint32_t h, h1, i;
+  JSAtomStruct* p;
+  int len;
+
+#if 0
+    printf("__JS_NewAtom: ");  JS_DumpString(rt, str); printf("\n");
+#endif
+  if (atom_type < JS_ATOM_TYPE_SYMBOL) {
+    /* str is not NULL */
+    if (str->atom_type == atom_type) {
+      /* str is the atom, return its index */
+      i = js_get_atom_index(rt, str);
+      /* reduce string refcount and increase atom's unless constant */
+      if (__JS_AtomIsConst(i))
+        str->header.ref_count--;
+      return i;
+    }
+    /* try and locate an already registered atom */
+    len = str->len;
+    /* only in extreme case will str has zero hash, we accept extra hash calc in that case. */
+    h = str->hash != 0 ? str->hash : hash_string(str, atom_type);
+    h &= JS_ATOM_HASH_MASK;
+    h1 = h & (rt->atom_hash_size - 1);
+    i = rt->atom_hash[h1];
+    while (i != 0) {
+      p = rt->atom_array[i];
+      if (p->hash == h && p->atom_type == atom_type && p->len == len && js_string_memcmp(p, str, len) == 0) {
+        if (!__JS_AtomIsConst(i))
+          p->header.ref_count++;
+        goto done;
+      }
+      i = p->hash_next;
+    }
+  } else {
+    h1 = 0; /* avoid warning */
+    if (atom_type == JS_ATOM_TYPE_SYMBOL) {
+      h = JS_ATOM_HASH_SYMBOL;
+    } else {
+      h = JS_ATOM_HASH_PRIVATE;
+      atom_type = JS_ATOM_TYPE_SYMBOL;
+    }
+  }
+
+  if (rt->atom_free_index == 0) {
+    /* allow new atom entries */
+    uint32_t new_size, start;
+    JSAtomStruct** new_array;
+
+    /* alloc new with size progression 3/2:
+       4 6 9 13 19 28 42 63 94 141 211 316 474 711 1066 1599 2398 3597 5395 8092
+       preallocating space for predefined atoms (at least 195).
+     */
+    new_size = max_int(1066, rt->atom_size * 3 / 2);
+    if (new_size > JS_ATOM_MAX)
+      goto fail;
+    /* XXX: should use realloc2 to use slack space */
+    new_array = js_realloc_rt(rt, rt->atom_array, sizeof(*new_array) * new_size);
+    if (!new_array)
+      goto fail;
+    /* Note: the atom 0 is not used */
+    start = rt->atom_size;
+    if (start == 0) {
+      /* JS_ATOM_NULL entry */
+      p = js_mallocz_rt(rt, sizeof(JSAtomStruct));
+      if (!p) {
+        js_free_rt(rt, new_array);
+        goto fail;
+      }
+      p->header.ref_count = 1; /* not refcounted */
+      p->atom_type = JS_ATOM_TYPE_SYMBOL;
+#ifdef DUMP_LEAKS
+      list_add_tail(&p->link, &rt->string_list);
+#endif
+      new_array[0] = p;
+      rt->atom_count++;
+      start = 1;
+    }
+    rt->atom_size = new_size;
+    rt->atom_array = new_array;
+    rt->atom_free_index = start;
+    for (i = start; i < new_size; i++) {
+      uint32_t next;
+      if (i == (new_size - 1))
+        next = 0;
+      else
+        next = i + 1;
+      rt->atom_array[i] = atom_set_free(next);
+    }
+  }
+
+  if (str) {
+    if (str->atom_type == 0) {
+      p = str;
+      p->atom_type = atom_type;
+    } else {
+      p = js_malloc_rt(rt, sizeof(JSString) + (str->len << str->is_wide_char) + 1 - str->is_wide_char);
+      if (unlikely(!p))
+        goto fail;
+      p->header.ref_count = 1;
+      p->is_wide_char = str->is_wide_char;
+      p->len = str->len;
+#ifdef DUMP_LEAKS
+      list_add_tail(&p->link, &rt->string_list);
+#endif
+      memcpy(p->u.str8, str->u.str8, (str->len << str->is_wide_char) + 1 - str->is_wide_char);
+      js_free_string(rt, str);
+    }
+  } else {
+    p = js_malloc_rt(rt, sizeof(JSAtomStruct)); /* empty wide string */
+    if (!p)
+      return JS_ATOM_NULL;
+    p->header.ref_count = 1;
+    p->is_wide_char = 1; /* Hack to represent NULL as a JSString */
+    p->len = 0;
+#ifdef DUMP_LEAKS
+    list_add_tail(&p->link, &rt->string_list);
+#endif
+  }
+
+  /* use an already free entry */
+  i = rt->atom_free_index;
+  rt->atom_free_index = atom_get_free(rt->atom_array[i]);
+  rt->atom_array[i] = p;
+
+  p->hash = h;
+  p->hash_next = i; /* atom_index */
+  p->atom_type = atom_type;
+
+  rt->atom_count++;
+
+  if (atom_type != JS_ATOM_TYPE_SYMBOL) {
+    p->hash_next = rt->atom_hash[h1];
+    rt->atom_hash[h1] = i;
+    if (unlikely(rt->atom_count >= rt->atom_count_resize))
+      JS_ResizeAtomHash(rt, rt->atom_hash_size * 2);
+  }
+
+  //    JS_DumpAtoms(rt);
+  return i;
+
+fail:
+  i = JS_ATOM_NULL;
+done:
+  if (str)
+    js_free_string(rt, str);
+  return i;
+}
+
+/* only works with zero terminated 8 bit strings */
+JSAtom __JS_NewAtomInit(JSRuntime* rt, const char* str, int len, int atom_type) {
+  JSString* p;
+  p = js_alloc_string_rt(rt, len, 0);
+  if (!p)
+    return JS_ATOM_NULL;
+  memcpy(p->u.str8, str, len);
+  p->u.str8[len] = '\0';
+  return __JS_NewAtom(rt, p, atom_type);
+}
+
+JSAtom __JS_FindAtom(JSRuntime* rt, const char* str, size_t len, int atom_type) {
+  uint32_t h, h1, i;
+  JSAtomStruct* p;
+
+  h = hash_string8((const uint8_t*)str, len, JS_ATOM_TYPE_STRING);
+  h &= JS_ATOM_HASH_MASK;
+  h1 = h & (rt->atom_hash_size - 1);
+  i = rt->atom_hash[h1];
+  while (i != 0) {
+    p = rt->atom_array[i];
+    if (p->hash == h && p->atom_type == JS_ATOM_TYPE_STRING && p->len == len && p->is_wide_char == 0 && memcmp(p->u.str8, str, len) == 0) {
+      if (!__JS_AtomIsConst(i))
+        p->header.ref_count++;
+      return i;
+    }
+    i = p->hash_next;
+  }
+  return JS_ATOM_NULL;
+}
+
+void JS_FreeAtomStruct(JSRuntime* rt, JSAtomStruct* p) {
+#if 0 /* JS_ATOM_NULL is not refcounted: __JS_AtomIsConst() includes 0 */
+    if (unlikely(i == JS_ATOM_NULL)) {
+        p->header.ref_count = INT32_MAX / 2;
+        return;
+    }
+#endif
+  uint32_t i = p->hash_next; /* atom_index */
+  if (p->atom_type != JS_ATOM_TYPE_SYMBOL) {
+    JSAtomStruct *p0, *p1;
+    uint32_t h0;
+
+    h0 = p->hash & (rt->atom_hash_size - 1);
+    i = rt->atom_hash[h0];
+    p1 = rt->atom_array[i];
+    if (p1 == p) {
+      rt->atom_hash[h0] = p1->hash_next;
+    } else {
+      for (;;) {
+        assert(i != 0);
+        p0 = p1;
+        i = p1->hash_next;
+        p1 = rt->atom_array[i];
+        if (p1 == p) {
+          p0->hash_next = p1->hash_next;
+          break;
+        }
+      }
+    }
+  }
+  /* insert in free atom list */
+  rt->atom_array[i] = atom_set_free(rt->atom_free_index);
+  rt->atom_free_index = i;
+  /* free the string structure */
+#ifdef DUMP_LEAKS
+  list_del(&p->link);
+#endif
+  js_free_rt(rt, p);
+  rt->atom_count--;
+  assert(rt->atom_count >= 0);
+}
+
+void __JS_FreeAtom(JSRuntime* rt, uint32_t i) {
+  JSAtomStruct* p;
+
+  p = rt->atom_array[i];
+  if (--p->header.ref_count > 0)
+    return;
+  JS_FreeAtomStruct(rt, p);
+}
+
+/* Warning: 'p' is freed */
+JSAtom JS_NewAtomStr(JSContext* ctx, JSString* p) {
+  JSRuntime* rt = ctx->rt;
+  uint32_t n;
+  if (is_num_string(&n, p)) {
+    if (n <= JS_ATOM_MAX_INT) {
+      js_free_string(rt, p);
+      return __JS_AtomFromUInt32(n);
+    }
+  }
+  /* XXX: should generate an exception */
+  return __JS_NewAtom(rt, p, JS_ATOM_TYPE_STRING);
+}
+
+JSAtom JS_NewAtomLen(JSContext* ctx, const char* str, size_t len) {
+  JSValue val;
+
+  if (len == 0 || !is_digit(*str)) {
+    JSAtom atom = __JS_FindAtom(ctx->rt, str, len, JS_ATOM_TYPE_STRING);
+    if (atom)
+      return atom;
+  }
+  val = JS_NewStringLen(ctx, str, len);
+  if (JS_IsException(val))
+    return JS_ATOM_NULL;
+  return JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(val));
+}
+
+JSAtom JS_NewAtom(JSContext* ctx, const char* str) {
+  return JS_NewAtomLen(ctx, str, strlen(str));
+}
+
+JSAtom JS_NewAtomUInt32(JSContext* ctx, uint32_t n) {
+  if (n <= JS_ATOM_MAX_INT) {
+    return __JS_AtomFromUInt32(n);
+  } else {
+    char buf[11];
+    JSValue val;
+    snprintf(buf, sizeof(buf), "%u", n);
+    val = JS_NewString(ctx, buf);
+    if (JS_IsException(val))
+      return JS_ATOM_NULL;
+    return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val), JS_ATOM_TYPE_STRING);
+  }
+}
+
+JSAtom JS_NewAtomInt64(JSContext* ctx, int64_t n) {
+  if ((uint64_t)n <= JS_ATOM_MAX_INT) {
+    return __JS_AtomFromUInt32((uint32_t)n);
+  } else {
+    char buf[24];
+    JSValue val;
+    snprintf(buf, sizeof(buf), "%" PRId64, n);
+    val = JS_NewString(ctx, buf);
+    if (JS_IsException(val))
+      return JS_ATOM_NULL;
+    return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val), JS_ATOM_TYPE_STRING);
+  }
+}
+
+/* Should only be used for debug. */
+const char* JS_AtomGetStrRT(JSRuntime* rt, char* buf, int buf_size, JSAtom atom) {
+  if (__JS_AtomIsTaggedInt(atom)) {
+    snprintf(buf, buf_size, "%u", __JS_AtomToUInt32(atom));
+  } else {
+    JSAtomStruct* p;
+    assert(atom < rt->atom_size);
+    if (atom == JS_ATOM_NULL) {
+      snprintf(buf, buf_size, "<null>");
+    } else {
+      int i, c;
+      char* q;
+      JSString* str;
+
+      q = buf;
+      p = rt->atom_array[atom];
+      assert(!atom_is_free(p));
+      str = p;
+      if (str) {
+        if (!str->is_wide_char) {
+          /* special case ASCII strings */
+          c = 0;
+          for (i = 0; i < str->len; i++) {
+            c |= str->u.str8[i];
+          }
+          if (c < 0x80)
+            return (const char*)str->u.str8;
+        }
+        for (i = 0; i < str->len; i++) {
+          if (str->is_wide_char)
+            c = str->u.str16[i];
+          else
+            c = str->u.str8[i];
+          if ((q - buf) >= buf_size - UTF8_CHAR_LEN_MAX)
+            break;
+          if (c < 128) {
+            *q++ = c;
+          } else {
+            q += unicode_to_utf8((uint8_t*)q, c);
+          }
+        }
+      }
+      *q = '\0';
+    }
+  }
+  return buf;
+}
+
+const char* JS_AtomGetStr(JSContext* ctx, char* buf, int buf_size, JSAtom atom) {
+  return JS_AtomGetStrRT(ctx->rt, buf, buf_size, atom);
+}
+
+JSValue __JS_AtomToValue(JSContext* ctx, JSAtom atom, BOOL force_string) {
+  char buf[ATOM_GET_STR_BUF_SIZE];
+
+  if (__JS_AtomIsTaggedInt(atom)) {
+    snprintf(buf, sizeof(buf), "%u", __JS_AtomToUInt32(atom));
+    return JS_NewString(ctx, buf);
+  } else {
+    JSRuntime* rt = ctx->rt;
+    JSAtomStruct* p;
+    assert(atom < rt->atom_size);
+    p = rt->atom_array[atom];
+    if (p->atom_type == JS_ATOM_TYPE_STRING) {
+      goto ret_string;
+    } else if (force_string) {
+      if (p->len == 0 && p->is_wide_char != 0) {
+        /* no description string */
+        p = rt->atom_array[JS_ATOM_empty_string];
+      }
+    ret_string:
+      return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
+    } else {
+      return JS_DupValue(ctx, JS_MKPTR(JS_TAG_SYMBOL, p));
+    }
+  }
+}
+
+JSValue JS_AtomToValue(JSContext* ctx, JSAtom atom) {
+  return __JS_AtomToValue(ctx, atom, FALSE);
+}
+
+JSValue JS_AtomToString(JSContext* ctx, JSAtom atom) {
+  return __JS_AtomToValue(ctx, atom, TRUE);
+}
+
+/* val must be a symbol */
+JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val)
+{
+  JSAtomStruct *p = JS_VALUE_GET_PTR(val);
+  return js_get_atom_index(ctx->rt, p);
+}
+
+/* return JS_ATOM_NULL in case of exception */
+JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val)
+{
+  JSAtom atom;
+  uint32_t tag;
+  tag = JS_VALUE_GET_TAG(val);
+  if (tag == JS_TAG_INT &&
+      (uint32_t)JS_VALUE_GET_INT(val) <= JS_ATOM_MAX_INT) {
+    /* fast path for integer values */
+    atom = __JS_AtomFromUInt32(JS_VALUE_GET_INT(val));
+  } else if (tag == JS_TAG_SYMBOL) {
+    JSAtomStruct *p = JS_VALUE_GET_PTR(val);
+    atom = JS_DupAtom(ctx, js_get_atom_index(ctx->rt, p));
+  } else {
+    JSValue str;
+    str = JS_ToPropertyKey(ctx, val);
+    if (JS_IsException(str))
+      return JS_ATOM_NULL;
+    if (JS_VALUE_GET_TAG(str) == JS_TAG_SYMBOL) {
+      atom = js_symbol_to_atom(ctx, str);
+    } else {
+      atom = JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(str));
+    }
+  }
+  return atom;
+}
+
+/* return TRUE if the atom is an array index (i.e. 0 <= index <=
+   2^32-2 and return its value */
+BOOL JS_AtomIsArrayIndex(JSContext* ctx, uint32_t* pval, JSAtom atom) {
+  if (__JS_AtomIsTaggedInt(atom)) {
+    *pval = __JS_AtomToUInt32(atom);
+    return TRUE;
+  } else {
+    JSRuntime* rt = ctx->rt;
+    JSAtomStruct* p;
+    uint32_t val;
+
+    assert(atom < rt->atom_size);
+    p = rt->atom_array[atom];
+    if (p->atom_type == JS_ATOM_TYPE_STRING && is_num_string(&val, p) && val != -1) {
+      *pval = val;
+      return TRUE;
+    } else {
+      *pval = 0;
+      return FALSE;
+    }
+  }
+}
+
+/* This test must be fast if atom is not a numeric index (e.g. a
+   method name). Return JS_UNDEFINED if not a numeric
+   index. JS_EXCEPTION can also be returned. */
+JSValue JS_AtomIsNumericIndex1(JSContext* ctx, JSAtom atom) {
+  JSRuntime* rt = ctx->rt;
+  JSAtomStruct* p1;
+  JSString* p;
+  int c, len, ret;
+  JSValue num, str;
+
+  if (__JS_AtomIsTaggedInt(atom))
+    return JS_NewInt32(ctx, __JS_AtomToUInt32(atom));
+  assert(atom < rt->atom_size);
+  p1 = rt->atom_array[atom];
+  if (p1->atom_type != JS_ATOM_TYPE_STRING)
+    return JS_UNDEFINED;
+  p = p1;
+  len = p->len;
+  if (p->is_wide_char) {
+    const uint16_t *r = p->u.str16, *r_end = p->u.str16 + len;
+    if (r >= r_end)
+      return JS_UNDEFINED;
+    c = *r;
+    if (c == '-') {
+      if (r >= r_end)
+        return JS_UNDEFINED;
+      r++;
+      c = *r;
+      /* -0 case is specific */
+      if (c == '0' && len == 2)
+        goto minus_zero;
+    }
+    /* XXX: should test NaN, but the tests do not check it */
+    if (!is_num(c)) {
+      /* XXX: String should be normalized, therefore 8-bit only */
+      const uint16_t nfinity16[7] = {'n', 'f', 'i', 'n', 'i', 't', 'y'};
+      if (!(c == 'I' && (r_end - r) == 8 && !memcmp(r + 1, nfinity16, sizeof(nfinity16))))
+        return JS_UNDEFINED;
+    }
+  } else {
+    const uint8_t *r = p->u.str8, *r_end = p->u.str8 + len;
+    if (r >= r_end)
+      return JS_UNDEFINED;
+    c = *r;
+    if (c == '-') {
+      if (r >= r_end)
+        return JS_UNDEFINED;
+      r++;
+      c = *r;
+      /* -0 case is specific */
+      if (c == '0' && len == 2) {
+      minus_zero:
+        return __JS_NewFloat64(ctx, -0.0);
+      }
+    }
+    if (!is_num(c)) {
+      if (!(c == 'I' && (r_end - r) == 8 && !memcmp(r + 1, "nfinity", 7)))
+        return JS_UNDEFINED;
+    }
+  }
+  /* XXX: bignum: would be better to only accept integer to avoid
+     relying on current floating point precision */
+  /* this is ECMA CanonicalNumericIndexString primitive */
+  num = JS_ToNumber(ctx, JS_MKPTR(JS_TAG_STRING, p));
+  if (JS_IsException(num))
+    return num;
+  str = JS_ToString(ctx, num);
+  if (JS_IsException(str)) {
+    JS_FreeValue(ctx, num);
+    return str;
+  }
+  ret = js_string_compare(ctx, p, JS_VALUE_GET_STRING(str));
+  JS_FreeValue(ctx, str);
+  if (ret == 0) {
+    return num;
+  } else {
+    JS_FreeValue(ctx, num);
+    return JS_UNDEFINED;
+  }
+}
+
+/* return -1 if exception or TRUE/FALSE */
+int JS_AtomIsNumericIndex(JSContext* ctx, JSAtom atom) {
+  JSValue num;
+  num = JS_AtomIsNumericIndex1(ctx, atom);
+  if (likely(JS_IsUndefined(num)))
+    return FALSE;
+  if (JS_IsException(num))
+    return -1;
+  JS_FreeValue(ctx, num);
+  return TRUE;
+}
+
+void JS_FreeAtom(JSContext* ctx, JSAtom v) {
+  if (!__JS_AtomIsConst(v))
+    __JS_FreeAtom(ctx->rt, v);
+}
+
+void JS_FreeAtomRT(JSRuntime* rt, JSAtom v) {
+  if (!__JS_AtomIsConst(v))
+    __JS_FreeAtom(rt, v);
+}
+
+/* return TRUE if 'v' is a symbol with a string description */
+BOOL JS_AtomSymbolHasDescription(JSContext* ctx, JSAtom v) {
+  JSRuntime* rt;
+  JSAtomStruct* p;
+
+  rt = ctx->rt;
+  if (__JS_AtomIsTaggedInt(v))
+    return FALSE;
+  p = rt->atom_array[v];
+  return (((p->atom_type == JS_ATOM_TYPE_SYMBOL && p->hash == JS_ATOM_HASH_SYMBOL) || p->atom_type == JS_ATOM_TYPE_GLOBAL_SYMBOL) && !(p->len == 0 && p->is_wide_char != 0));
+}
+
+__maybe_unused void print_atom(JSContext* ctx, JSAtom atom) {
+  char buf[ATOM_GET_STR_BUF_SIZE];
+  const char* p;
+  int i;
+
+  /* XXX: should handle embedded null characters */
+  /* XXX: should move encoding code to JS_AtomGetStr */
+  p = JS_AtomGetStr(ctx, buf, sizeof(buf), atom);
+  for (i = 0; p[i]; i++) {
+    int c = (unsigned char)p[i];
+    if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_' || c == '$') || (c >= '0' && c <= '9' && i > 0)))
+      break;
+  }
+  if (i > 0 && p[i] == '\0') {
+    printf("%s", p);
+  } else {
+    putchar('"');
+    printf("%.*s", i, p);
+    for (; p[i]; i++) {
+      int c = (unsigned char)p[i];
+      if (c == '\"' || c == '\\') {
+        putchar('\\');
+        putchar(c);
+      } else if (c >= ' ' && c <= 126) {
+        putchar(c);
+      } else if (c == '\n') {
+        putchar('\\');
+        putchar('n');
+      } else {
+        printf("\\u%04x", c);
+      }
+    }
+    putchar('\"');
+  }
+}
+
+/* free with JS_FreeCString() */
+const char* JS_AtomToCString(JSContext* ctx, JSAtom atom) {
+  JSValue str;
+  const char* cstr;
+
+  str = JS_AtomToString(ctx, atom);
+  if (JS_IsException(str))
+    return NULL;
+  cstr = JS_ToCString(ctx, str);
+  JS_FreeValue(ctx, str);
+  return cstr;
+}
+
+/* return a string atom containing name concatenated with str1 */
+JSAtom js_atom_concat_str(JSContext* ctx, JSAtom name, const char* str1) {
+  JSValue str;
+  JSAtom atom;
+  const char* cstr;
+  char* cstr2;
+  size_t len, len1;
+
+  str = JS_AtomToString(ctx, name);
+  if (JS_IsException(str))
+    return JS_ATOM_NULL;
+  cstr = JS_ToCStringLen(ctx, &len, str);
+  if (!cstr)
+    goto fail;
+  len1 = strlen(str1);
+  cstr2 = js_malloc(ctx, len + len1 + 1);
+  if (!cstr2)
+    goto fail;
+  memcpy(cstr2, cstr, len);
+  memcpy(cstr2 + len, str1, len1);
+  cstr2[len + len1] = '\0';
+  atom = JS_NewAtomLen(ctx, cstr2, len + len1);
+  js_free(ctx, cstr2);
+  JS_FreeCString(ctx, cstr);
+  JS_FreeValue(ctx, str);
+  return atom;
+fail:
+  JS_FreeCString(ctx, cstr);
+  JS_FreeValue(ctx, str);
+  return JS_ATOM_NULL;
+}
+
+JSAtom js_atom_concat_num(JSContext* ctx, JSAtom name, uint32_t n) {
+  char buf[16];
+  snprintf(buf, sizeof(buf), "%u", n);
+  return js_atom_concat_str(ctx, name, buf);
+}
+
+/* 'p' is freed */
+JSValue JS_NewSymbol(JSContext* ctx, JSString* p, int atom_type) {
+  JSRuntime* rt = ctx->rt;
+  JSAtom atom;
+  atom = __JS_NewAtom(rt, p, atom_type);
+  if (atom == JS_ATOM_NULL)
+    return JS_ThrowOutOfMemory(ctx);
+  return JS_MKPTR(JS_TAG_SYMBOL, rt->atom_array[atom]);
+}
+
+/* descr must be a non-numeric string atom */
+JSValue JS_NewSymbolFromAtom(JSContext* ctx, JSAtom descr, int atom_type) {
+  JSRuntime* rt = ctx->rt;
+  JSString* p;
+
+  assert(!__JS_AtomIsTaggedInt(descr));
+  assert(descr < rt->atom_size);
+  p = rt->atom_array[descr];
+  JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
+  return JS_NewSymbol(ctx, p, atom_type);
+}
+
+/* It is valid to call string_buffer_end() and all string_buffer functions even
+   if string_buffer_init() or another string_buffer function returns an error.
+   If the error_status is set, string_buffer_end() returns JS_EXCEPTION.
+ */
+int string_buffer_init2(JSContext* ctx, StringBuffer* s, int size, int is_wide) {
+  s->ctx = ctx;
+  s->size = size;
+  s->len = 0;
+  s->is_wide_char = is_wide;
+  s->error_status = 0;
+  s->str = js_alloc_string(ctx, size, is_wide);
+  if (unlikely(!s->str)) {
+    s->size = 0;
+    return s->error_status = -1;
+  }
+#ifdef DUMP_LEAKS
+  /* the StringBuffer may reallocate the JSString, only link it at the end */
+  list_del(&s->str->link);
+#endif
+  return 0;
+}
+
+
+
+void string_buffer_free(StringBuffer* s) {
+  js_free(s->ctx, s->str);
+  s->str = NULL;
+}
+
+int string_buffer_set_error(StringBuffer* s) {
+  js_free(s->ctx, s->str);
+  s->str = NULL;
+  s->size = 0;
+  s->len = 0;
+  return s->error_status = -1;
+}
+
+no_inline int string_buffer_widen(StringBuffer* s, int size) {
+  JSString* str;
+  size_t slack;
+  int i;
+
+  if (s->error_status)
+    return -1;
+
+  str = js_realloc2(s->ctx, s->str, sizeof(JSString) + (size << 1), &slack);
+  if (!str)
+    return string_buffer_set_error(s);
+  size += slack >> 1;
+  for (i = s->len; i-- > 0;) {
+    str->u.str16[i] = str->u.str8[i];
+  }
+  s->is_wide_char = 1;
+  s->size = size;
+  s->str = str;
+  return 0;
+}
+
+no_inline int string_buffer_realloc(StringBuffer* s, int new_len, int c) {
+  JSString* new_str;
+  int new_size;
+  size_t new_size_bytes, slack;
+
+  if (s->error_status)
+    return -1;
+
+  if (new_len > JS_STRING_LEN_MAX) {
+    JS_ThrowInternalError(s->ctx, "string too long");
+    return string_buffer_set_error(s);
+  }
+  new_size = min_int(max_int(new_len, s->size * 3 / 2), JS_STRING_LEN_MAX);
+  if (!s->is_wide_char && c >= 0x100) {
+    return string_buffer_widen(s, new_size);
+  }
+  new_size_bytes = sizeof(JSString) + (new_size << s->is_wide_char) + 1 - s->is_wide_char;
+  new_str = js_realloc2(s->ctx, s->str, new_size_bytes, &slack);
+  if (!new_str)
+    return string_buffer_set_error(s);
+  new_size = min_int(new_size + (slack >> s->is_wide_char), JS_STRING_LEN_MAX);
+  s->size = new_size;
+  s->str = new_str;
+  return 0;
+}
+
+no_inline int string_buffer_putc_slow(StringBuffer* s, uint32_t c) {
+  if (unlikely(s->len >= s->size)) {
+    if (string_buffer_realloc(s, s->len + 1, c))
+      return -1;
+  }
+  if (s->is_wide_char) {
+    s->str->u.str16[s->len++] = c;
+  } else if (c < 0x100) {
+    s->str->u.str8[s->len++] = c;
+  } else {
+    if (string_buffer_widen(s, s->size))
+      return -1;
+    s->str->u.str16[s->len++] = c;
+  }
+  return 0;
+}
+
+/* 0 <= c <= 0xff */
+int string_buffer_putc8(StringBuffer* s, uint32_t c) {
+  if (unlikely(s->len >= s->size)) {
+    if (string_buffer_realloc(s, s->len + 1, c))
+      return -1;
+  }
+  if (s->is_wide_char) {
+    s->str->u.str16[s->len++] = c;
+  } else {
+    s->str->u.str8[s->len++] = c;
+  }
+  return 0;
+}
+
+/* 0 <= c <= 0xffff */
+int string_buffer_putc16(StringBuffer* s, uint32_t c) {
+  if (likely(s->len < s->size)) {
+    if (s->is_wide_char) {
+      s->str->u.str16[s->len++] = c;
+      return 0;
+    } else if (c < 0x100) {
+      s->str->u.str8[s->len++] = c;
+      return 0;
+    }
+  }
+  return string_buffer_putc_slow(s, c);
+}
+
+/* 0 <= c <= 0x10ffff */
+int string_buffer_putc(StringBuffer* s, uint32_t c) {
+  if (unlikely(c >= 0x10000)) {
+    /* surrogate pair */
+    c -= 0x10000;
+    if (string_buffer_putc16(s, (c >> 10) + 0xd800))
+      return -1;
+    c = (c & 0x3ff) + 0xdc00;
+  }
+  return string_buffer_putc16(s, c);
+}
+
+int string_get(const JSString* p, int idx) {
+  return p->is_wide_char ? p->u.str16[idx] : p->u.str8[idx];
+}
+
+int string_getc(const JSString* p, int* pidx) {
+  int idx, c, c1;
+  idx = *pidx;
+  if (p->is_wide_char) {
+    c = p->u.str16[idx++];
+    if (c >= 0xd800 && c < 0xdc00 && idx < p->len) {
+      c1 = p->u.str16[idx];
+      if (c1 >= 0xdc00 && c1 < 0xe000) {
+        c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
+        idx++;
+      }
+    }
+  } else {
+    c = p->u.str8[idx++];
+  }
+  *pidx = idx;
+  return c;
+}
+
+int string_buffer_write8(StringBuffer* s, const uint8_t* p, int len) {
+  int i;
+
+  if (s->len + len > s->size) {
+    if (string_buffer_realloc(s, s->len + len, 0))
+      return -1;
+  }
+  if (s->is_wide_char) {
+    for (i = 0; i < len; i++) {
+      s->str->u.str16[s->len + i] = p[i];
+    }
+    s->len += len;
+  } else {
+    memcpy(&s->str->u.str8[s->len], p, len);
+    s->len += len;
+  }
+  return 0;
+}
+
+int string_buffer_write16(StringBuffer* s, const uint16_t* p, int len) {
+  int c = 0, i;
+
+  for (i = 0; i < len; i++) {
+    c |= p[i];
+  }
+  if (s->len + len > s->size) {
+    if (string_buffer_realloc(s, s->len + len, c))
+      return -1;
+  } else if (!s->is_wide_char && c >= 0x100) {
+    if (string_buffer_widen(s, s->size))
+      return -1;
+  }
+  if (s->is_wide_char) {
+    memcpy(&s->str->u.str16[s->len], p, len << 1);
+    s->len += len;
+  } else {
+    for (i = 0; i < len; i++) {
+      s->str->u.str8[s->len + i] = p[i];
+    }
+    s->len += len;
+  }
+  return 0;
+}
+
+/* appending an ASCII string */
+int string_buffer_puts8(StringBuffer* s, const char* str) {
+  return string_buffer_write8(s, (const uint8_t*)str, strlen(str));
+}
+
+int string_buffer_concat(StringBuffer* s, const JSString* p, uint32_t from, uint32_t to) {
+  if (to <= from)
+    return 0;
+  if (p->is_wide_char)
+    return string_buffer_write16(s, p->u.str16 + from, to - from);
+  else
+    return string_buffer_write8(s, p->u.str8 + from, to - from);
+}
+
+int string_buffer_concat_value(StringBuffer* s, JSValueConst v) {
+  JSString* p;
+  JSValue v1;
+  int res;
+
+  if (s->error_status) {
+    /* prevent exception overload */
+    return -1;
+  }
+  if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) {
+    v1 = JS_ToString(s->ctx, v);
+    if (JS_IsException(v1))
+      return string_buffer_set_error(s);
+    p = JS_VALUE_GET_STRING(v1);
+    res = string_buffer_concat(s, p, 0, p->len);
+    JS_FreeValue(s->ctx, v1);
+    return res;
+  }
+  p = JS_VALUE_GET_STRING(v);
+  return string_buffer_concat(s, p, 0, p->len);
+}
+
+int string_buffer_concat_value_free(StringBuffer* s, JSValue v) {
+  JSString* p;
+  int res;
+
+  if (s->error_status) {
+    /* prevent exception overload */
+    JS_FreeValue(s->ctx, v);
+    return -1;
+  }
+  if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) {
+    v = JS_ToStringFree(s->ctx, v);
+    if (JS_IsException(v))
+      return string_buffer_set_error(s);
+  }
+  p = JS_VALUE_GET_STRING(v);
+  res = string_buffer_concat(s, p, 0, p->len);
+  JS_FreeValue(s->ctx, v);
+  return res;
+}
+
+int string_buffer_fill(StringBuffer* s, int c, int count) {
+  /* XXX: optimize */
+  if (s->len + count > s->size) {
+    if (string_buffer_realloc(s, s->len + count, c))
+      return -1;
+  }
+  while (count-- > 0) {
+    if (string_buffer_putc16(s, c))
+      return -1;
+  }
+  return 0;
+}
+
+JSValue string_buffer_end(StringBuffer* s) {
+  JSString* str;
+  str = s->str;
+  if (s->error_status)
+    return JS_EXCEPTION;
+  if (s->len == 0) {
+    js_free(s->ctx, str);
+    s->str = NULL;
+    return JS_AtomToString(s->ctx, JS_ATOM_empty_string);
+  }
+  if (s->len < s->size) {
+    /* smaller size so js_realloc should not fail, but OK if it does */
+    /* XXX: should add some slack to avoid unnecessary calls */
+    /* XXX: might need to use malloc+free to ensure smaller size */
+    str = js_realloc_rt(s->ctx->rt, str, sizeof(JSString) + (s->len << s->is_wide_char) + 1 - s->is_wide_char);
+    if (str == NULL)
+      str = s->str;
+    s->str = str;
+  }
+  if (!s->is_wide_char)
+    str->u.str8[s->len] = 0;
+#ifdef DUMP_LEAKS
+  list_add_tail(&str->link, &s->ctx->rt->string_list);
+#endif
+  str->is_wide_char = s->is_wide_char;
+  str->len = s->len;
+  s->str = NULL;
+  return JS_MKPTR(JS_TAG_STRING, str);
+}
+
+JSValue js_new_string8(JSContext* ctx, const uint8_t* buf, int len) {
+  JSString* str;
+
+  if (len <= 0) {
+    return JS_AtomToString(ctx, JS_ATOM_empty_string);
+  }
+  str = js_alloc_string(ctx, len, 0);
+  if (!str)
+    return JS_EXCEPTION;
+  memcpy(str->u.str8, buf, len);
+  str->u.str8[len] = '\0';
+  return JS_MKPTR(JS_TAG_STRING, str);
+}
+
+JSValue js_new_string16(JSContext* ctx, const uint16_t* buf, int len) {
+  JSString* str;
+  str = js_alloc_string(ctx, len, 1);
+  if (!str)
+    return JS_EXCEPTION;
+  memcpy(str->u.str16, buf, len * 2);
+  return JS_MKPTR(JS_TAG_STRING, str);
+}
+
+JSValue js_new_string_char(JSContext* ctx, uint16_t c) {
+  if (c < 0x100) {
+    uint8_t ch8 = c;
+    return js_new_string8(ctx, &ch8, 1);
+  } else {
+    uint16_t ch16 = c;
+    return js_new_string16(ctx, &ch16, 1);
+  }
+}
+
+JSValue js_sub_string(JSContext* ctx, JSString* p, int start, int end) {
+  int len = end - start;
+  if (start == 0 && end == p->len) {
+    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
+  }
+  if (p->is_wide_char && len > 0) {
+    JSString* str;
+    int i;
+    uint16_t c = 0;
+    for (i = start; i < end; i++) {
+      c |= p->u.str16[i];
+    }
+    if (c > 0xFF)
+      return js_new_string16(ctx, p->u.str16 + start, len);
+
+    str = js_alloc_string(ctx, len, 0);
+    if (!str)
+      return JS_EXCEPTION;
+    for (i = 0; i < len; i++) {
+      str->u.str8[i] = p->u.str16[start + i];
+    }
+    str->u.str8[len] = '\0';
+    return JS_MKPTR(JS_TAG_STRING, str);
+  } else {
+    return js_new_string8(ctx, p->u.str8 + start, len);
+  }
+}
+
+/* create a string from a UTF-8 buffer */
+JSValue JS_NewStringLen(JSContext* ctx, const char* buf, size_t buf_len) {
+  const uint8_t *p, *p_end, *p_start, *p_next;
+  uint32_t c;
+  StringBuffer b_s, *b = &b_s;
+  size_t len1;
+
+  p_start = (const uint8_t*)buf;
+  p_end = p_start + buf_len;
+  p = p_start;
+  while (p < p_end && * p < 128)
+    p++;
+  len1 = p - p_start;
+  if (len1 > JS_STRING_LEN_MAX)
+    return JS_ThrowInternalError(ctx, "string too long");
+  if (p == p_end) {
+    /* ASCII string */
+    return js_new_string8(ctx, (const uint8_t*)buf, buf_len);
+  } else {
+    if (string_buffer_init(ctx, b, buf_len))
+      goto fail;
+    string_buffer_write8(b, p_start, len1);
+    while (p < p_end) {
+      if (*p < 128) {
+        string_buffer_putc8(b, *p++);
+      } else {
+        /* parse utf-8 sequence, return 0xFFFFFFFF for error */
+        c = unicode_from_utf8(p, p_end - p, &p_next);
+        if (c < 0x10000) {
+          p = p_next;
+        } else if (c <= 0x10FFFF) {
+          p = p_next;
+          /* surrogate pair */
+          c -= 0x10000;
+          string_buffer_putc16(b, (c >> 10) + 0xd800);
+          c = (c & 0x3ff) + 0xdc00;
+        } else {
+          /* invalid char */
+          c = 0xfffd;
+          /* skip the invalid chars */
+          /* XXX: seems incorrect. Why not just use c = *p++; ? */
+          while (p < p_end && (*p >= 0x80 && *p < 0xc0))
+            p++;
+          if (p < p_end) {
+            p++;
+            while (p < p_end && (*p >= 0x80 && *p < 0xc0))
+              p++;
+          }
+        }
+        string_buffer_putc16(b, c);
+      }
+    }
+  }
+  return string_buffer_end(b);
+
+fail:
+  string_buffer_free(b);
+  return JS_EXCEPTION;
+}
+
+JSValue JS_ConcatString3(JSContext* ctx, const char* str1, JSValue str2, const char* str3) {
+  StringBuffer b_s, *b = &b_s;
+  int len1, len3;
+  JSString* p;
+
+  if (unlikely(JS_VALUE_GET_TAG(str2) != JS_TAG_STRING)) {
+    str2 = JS_ToStringFree(ctx, str2);
+    if (JS_IsException(str2))
+      goto fail;
+  }
+  p = JS_VALUE_GET_STRING(str2);
+  len1 = strlen(str1);
+  len3 = strlen(str3);
+
+  if (string_buffer_init2(ctx, b, len1 + p->len + len3, p->is_wide_char))
+    goto fail;
+
+  string_buffer_write8(b, (const uint8_t*)str1, len1);
+  string_buffer_concat(b, p, 0, p->len);
+  string_buffer_write8(b, (const uint8_t*)str3, len3);
+
+  JS_FreeValue(ctx, str2);
+  return string_buffer_end(b);
+
+fail:
+  JS_FreeValue(ctx, str2);
+  return JS_EXCEPTION;
+}
+
+JSValue JS_NewString(JSContext* ctx, const char* str) {
+  return JS_NewStringLen(ctx, str, strlen(str));
+}
+
+JSValue JS_NewAtomString(JSContext* ctx, const char* str) {
+  JSAtom atom = JS_NewAtom(ctx, str);
+  if (atom == JS_ATOM_NULL)
+    return JS_EXCEPTION;
+  JSValue val = JS_AtomToString(ctx, atom);
+  JS_FreeAtom(ctx, atom);
+  return val;
+}
+
+/* return (NULL, 0) if exception. */
+/* return pointer into a JSString with a live ref_count */
+/* cesu8 determines if non-BMP1 codepoints are encoded as 1 or 2 utf-8 sequences */
+const char* JS_ToCStringLen2(JSContext* ctx, size_t* plen, JSValueConst val1, BOOL cesu8) {
+  JSValue val;
+  JSString *str, *str_new;
+  int pos, len, c, c1;
+  uint8_t* q;
+
+  if (JS_VALUE_GET_TAG(val1) != JS_TAG_STRING) {
+    val = JS_ToString(ctx, val1);
+    if (JS_IsException(val))
+      goto fail;
+  } else {
+    val = JS_DupValue(ctx, val1);
+  }
+
+  str = JS_VALUE_GET_STRING(val);
+  len = str->len;
+  if (!str->is_wide_char) {
+    const uint8_t* src = str->u.str8;
+    int count;
+
+    /* count the number of non-ASCII characters */
+    /* Scanning the whole string is required for ASCII strings,
+       and computing the number of non-ASCII bytes is less expensive
+       than testing each byte, hence this method is faster for ASCII
+       strings, which is the most common case.
+     */
+    count = 0;
+    for (pos = 0; pos < len; pos++) {
+      count += src[pos] >> 7;
+    }
+    if (count == 0) {
+      if (plen)
+        *plen = len;
+      return (const char*)src;
+    }
+    str_new = js_alloc_string(ctx, len + count, 0);
+    if (!str_new)
+      goto fail;
+    q = str_new->u.str8;
+    for (pos = 0; pos < len; pos++) {
+      c = src[pos];
+      if (c < 0x80) {
+        *q++ = c;
+      } else {
+        *q++ = (c >> 6) | 0xc0;
+        *q++ = (c & 0x3f) | 0x80;
+      }
+    }
+  } else {
+    const uint16_t* src = str->u.str16;
+    /* Allocate 3 bytes per 16 bit code point. Surrogate pairs may
+       produce 4 bytes but use 2 code points.
+     */
+    str_new = js_alloc_string(ctx, len * 3, 0);
+    if (!str_new)
+      goto fail;
+    q = str_new->u.str8;
+    pos = 0;
+    while (pos < len) {
+      c = src[pos++];
+      if (c < 0x80) {
+        *q++ = c;
+      } else {
+        if (c >= 0xd800 && c < 0xdc00) {
+          if (pos < len && !cesu8) {
+            c1 = src[pos];
+            if (c1 >= 0xdc00 && c1 < 0xe000) {
+              pos++;
+              /* surrogate pair */
+              c = (((c & 0x3ff) << 10) | (c1 & 0x3ff)) + 0x10000;
+            } else {
+              /* Keep unmatched surrogate code points */
+              /* c = 0xfffd; */ /* error */
+            }
+          } else {
+            /* Keep unmatched surrogate code points */
+            /* c = 0xfffd; */ /* error */
+          }
+        }
+        q += unicode_to_utf8(q, c);
+      }
+    }
+  }
+
+  *q = '\0';
+  str_new->len = q - str_new->u.str8;
+  JS_FreeValue(ctx, val);
+  if (plen)
+    *plen = str_new->len;
+  return (const char*)str_new->u.str8;
+fail:
+  if (plen)
+    *plen = 0;
+  return NULL;
+}
+
+void JS_FreeCString(JSContext* ctx, const char* ptr) {
+  JSString* p;
+  if (!ptr)
+    return;
+  /* purposely removing constness */
+  p = (JSString*)(void*)(ptr - offsetof(JSString, u));
+  JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
+}
+
+/* op1 and op2 are converted to strings. For convience, op1 or op2 =
+   JS_EXCEPTION are accepted and return JS_EXCEPTION.  */
+JSValue JS_ConcatString(JSContext* ctx, JSValue op1, JSValue op2) {
+  JSValue ret;
+  JSString *p1, *p2;
+
+  if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_STRING)) {
+    op1 = JS_ToStringFree(ctx, op1);
+    if (JS_IsException(op1)) {
+      JS_FreeValue(ctx, op2);
+      return JS_EXCEPTION;
+    }
+  }
+  if (unlikely(JS_VALUE_GET_TAG(op2) != JS_TAG_STRING)) {
+    op2 = JS_ToStringFree(ctx, op2);
+    if (JS_IsException(op2)) {
+      JS_FreeValue(ctx, op1);
+      return JS_EXCEPTION;
+    }
+  }
+  p1 = JS_VALUE_GET_STRING(op1);
+  p2 = JS_VALUE_GET_STRING(op2);
+
+  /* XXX: could also check if p1 is empty */
+  if (p2->len == 0) {
+    goto ret_op1;
+  }
+  if (p1->header.ref_count == 1 && p1->is_wide_char == p2->is_wide_char && js_malloc_usable_size(ctx, p1) >= sizeof(*p1) + ((p1->len + p2->len) << p2->is_wide_char) + 1 - p1->is_wide_char) {
+    /* Concatenate in place in available space at the end of p1 */
+    if (p1->is_wide_char) {
+      memcpy(p1->u.str16 + p1->len, p2->u.str16, p2->len << 1);
+      p1->len += p2->len;
+    } else {
+      memcpy(p1->u.str8 + p1->len, p2->u.str8, p2->len);
+      p1->len += p2->len;
+      p1->u.str8[p1->len] = '\0';
+    }
+  ret_op1:
+    JS_FreeValue(ctx, op2);
+    return op1;
+  }
+  ret = JS_ConcatString1(ctx, p1, p2);
+  JS_FreeValue(ctx, op1);
+  JS_FreeValue(ctx, op2);
+  return ret;
+}
\ No newline at end of file
diff --git a/src/core/string.h b/src/core/string.h
new file mode 100644
index 000000000..b09fdc4a1
--- /dev/null
+++ b/src/core/string.h
@@ -0,0 +1,263 @@
+/*
+ * QuickJS Javascript Engine
+ *
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_STRING_H
+#define QUICKJS_STRING_H
+
+#include "quickjs/quickjs.h"
+#include "quickjs/cutils.h"
+#include "types.h"
+
+#define ATOM_GET_STR_BUF_SIZE 64
+
+#define JS_ATOM_TAG_INT (1U << 31)
+#define JS_ATOM_MAX_INT (JS_ATOM_TAG_INT - 1)
+#define JS_ATOM_MAX ((1U << 30) - 1)
+
+/* return the max count from the hash size */
+#define JS_ATOM_COUNT_RESIZE(n) ((n)*2)
+
+typedef struct StringBuffer {
+  JSContext* ctx;
+  JSString* str;
+  int len;
+  int size;
+  int is_wide_char;
+  int error_status;
+} StringBuffer;
+
+static inline uint32_t atom_get_free(const JSAtomStruct* p) {
+  return (uintptr_t)p >> 1;
+}
+
+static inline int is_digit(int c) {
+  return c >= '0' && c <= '9';
+}
+
+static inline BOOL atom_is_free(const JSAtomStruct* p) {
+  return (uintptr_t)p & 1;
+}
+
+static inline JSAtomStruct* atom_set_free(uint32_t v) {
+  return (JSAtomStruct*)(((uintptr_t)v << 1) | 1);
+}
+
+
+JSString* js_alloc_string(JSContext* ctx, int max_len, int is_wide_char);
+/* Note: the string contents are uninitialized */
+JSString* js_alloc_string_rt(JSRuntime* rt, int max_len, int is_wide_char);
+
+int JS_InitAtoms(JSRuntime* rt);
+JSAtom __JS_NewAtomInit(JSRuntime* rt, const char* str, int len, int atom_type);
+JSAtom __JS_FindAtom(JSRuntime* rt, const char* str, size_t len, int atom_type);
+void JS_FreeAtomStruct(JSRuntime* rt, JSAtomStruct* p);
+void __JS_FreeAtom(JSRuntime* rt, uint32_t i);
+JSAtom JS_NewAtomInt64(JSContext* ctx, int64_t n);
+/* Should only be used for debug. */
+const char* JS_AtomGetStrRT(JSRuntime* rt, char* buf, int buf_size, JSAtom atom);
+const char* JS_AtomGetStr(JSContext* ctx, char* buf, int buf_size, JSAtom atom);
+JSValue __JS_AtomToValue(JSContext* ctx, JSAtom atom, BOOL force_string);
+/* val must be a symbol */
+JSAtom js_symbol_to_atom(JSContext* ctx, JSValue val);
+/* return TRUE if the atom is an array index (i.e. 0 <= index <=
+   2^32-2 and return its value */
+BOOL JS_AtomIsArrayIndex(JSContext* ctx, uint32_t* pval, JSAtom atom);
+/* This test must be fast if atom is not a numeric index (e.g. a
+   method name). Return JS_UNDEFINED if not a numeric
+   index. JS_EXCEPTION can also be returned. */
+JSValue JS_AtomIsNumericIndex1(JSContext* ctx, JSAtom atom);
+/* return -1 if exception or TRUE/FALSE */
+int JS_AtomIsNumericIndex(JSContext* ctx, JSAtom atom);
+/* Warning: 'p' is freed */
+JSAtom JS_NewAtomStr(JSContext* ctx, JSString* p);
+__maybe_unused void JS_DumpAtoms(JSRuntime* rt);
+JSAtom JS_DupAtomRT(JSRuntime* rt, JSAtom v);
+JSAtomKindEnum JS_AtomGetKind(JSContext* ctx, JSAtom v);
+BOOL JS_AtomIsString(JSContext* ctx, JSAtom v);
+JSAtom js_get_atom_index(JSRuntime* rt, JSAtomStruct* p);
+int memcmp16_8(const uint16_t* src1, const uint8_t* src2, int len);
+int memcmp16(const uint16_t* src1, const uint16_t* src2, int len);
+int js_string_memcmp(const JSString* p1, const JSString* p2, int len);
+/* return < 0, 0 or > 0 */
+int js_string_compare(JSContext* ctx, const JSString* p1, const JSString* p2);
+void copy_str16(uint16_t* dst, const JSString* p, int offset, int len);
+JSValue JS_ConcatString1(JSContext* ctx, const JSString* p1, const JSString* p2);
+
+__maybe_unused void JS_DumpString(JSRuntime* rt, const JSString* p);
+
+/* same as JS_FreeValueRT() but faster */
+static inline void js_free_string(JSRuntime* rt, JSString* str) {
+  if (--str->header.ref_count <= 0) {
+    if (str->atom_type) {
+      JS_FreeAtomStruct(rt, str);
+    } else {
+#ifdef DUMP_LEAKS
+      list_del(&str->link);
+#endif
+      js_free_rt(rt, str);
+    }
+  }
+}
+int JS_ResizeAtomHash(JSRuntime* rt, int new_hash_size);
+static inline BOOL __JS_AtomIsTaggedInt(JSAtom v) {
+  return (v & JS_ATOM_TAG_INT) != 0;
+}
+static inline BOOL __JS_AtomIsConst(JSAtom v) {
+#if defined(DUMP_LEAKS) && DUMP_LEAKS > 1
+  return (int32_t)v <= 0;
+#else
+  return (int32_t)v < JS_ATOM_END;
+#endif
+}
+
+static inline JSAtom __JS_AtomFromUInt32(uint32_t v) {
+  return v | JS_ATOM_TAG_INT;
+}
+
+static inline uint32_t __JS_AtomToUInt32(JSAtom atom) {
+  return atom & ~JS_ATOM_TAG_INT;
+}
+
+static inline int is_num(int c) {
+  return c >= '0' && c <= '9';
+}
+
+/* return TRUE if the string is a number n with 0 <= n <= 2^32-1 */
+static inline BOOL is_num_string(uint32_t* pval, const JSString* p) {
+  uint32_t n;
+  uint64_t n64;
+  int c, i, len;
+
+  len = p->len;
+  if (len == 0 || len > 10)
+    return FALSE;
+  if (p->is_wide_char)
+    c = p->u.str16[0];
+  else
+    c = p->u.str8[0];
+  if (is_num(c)) {
+    if (c == '0') {
+      if (len != 1)
+        return FALSE;
+      n = 0;
+    } else {
+      n = c - '0';
+      for (i = 1; i < len; i++) {
+        if (p->is_wide_char)
+          c = p->u.str16[i];
+        else
+          c = p->u.str8[i];
+        if (!is_num(c))
+          return FALSE;
+        n64 = (uint64_t)n * 10 + (c - '0');
+        if ((n64 >> 32) != 0)
+          return FALSE;
+        n = n64;
+      }
+    }
+    *pval = n;
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+/* XXX: could use faster version ? */
+static inline uint32_t hash_string8(const uint8_t* str, size_t len, uint32_t h) {
+  size_t i;
+
+  for (i = 0; i < len; i++)
+    h = h * 263 + str[i];
+  return h;
+}
+
+static inline uint32_t hash_string16(const uint16_t* str, size_t len, uint32_t h) {
+  size_t i;
+
+  for (i = 0; i < len; i++)
+    h = h * 263 + str[i];
+  return h;
+}
+uint32_t hash_string(const JSString* str, uint32_t h);
+int string_buffer_init2(JSContext* ctx, StringBuffer* s, int size, int is_wide);
+
+static inline int string_buffer_init(JSContext* ctx, StringBuffer* s, int size) {
+  return string_buffer_init2(ctx, s, size, 0);
+}
+void string_buffer_free(StringBuffer* s);
+int string_buffer_set_error(StringBuffer* s);
+no_inline int string_buffer_widen(StringBuffer* s, int size);
+no_inline int string_buffer_realloc(StringBuffer* s, int new_len, int c);
+no_inline int string_buffer_putc_slow(StringBuffer* s, uint32_t c);
+/* 0 <= c <= 0xff */
+int string_buffer_putc8(StringBuffer* s, uint32_t c);
+/* 0 <= c <= 0xffff */
+int string_buffer_putc16(StringBuffer* s, uint32_t c);
+/* 0 <= c <= 0x10ffff */
+int string_buffer_putc(StringBuffer* s, uint32_t c);
+int string_get(const JSString* p, int idx);
+int string_getc(const JSString* p, int* pidx);
+int string_buffer_write8(StringBuffer* s, const uint8_t* p, int len);
+int string_buffer_write16(StringBuffer* s, const uint16_t* p, int len);
+/* appending an ASCII string */
+int string_buffer_puts8(StringBuffer* s, const char* str);
+int string_buffer_concat(StringBuffer* s, const JSString* p, uint32_t from, uint32_t to);
+int string_buffer_concat_value(StringBuffer* s, JSValueConst v);
+int string_buffer_concat_value_free(StringBuffer* s, JSValue v);
+int string_buffer_fill(StringBuffer* s, int c, int count);
+JSValue string_buffer_end(StringBuffer* s);
+
+JSValue js_new_string8(JSContext* ctx, const uint8_t* buf, int len);
+JSValue js_new_string16(JSContext* ctx, const uint16_t* buf, int len);
+JSValue js_new_string_char(JSContext* ctx, uint16_t c);
+JSValue js_sub_string(JSContext* ctx, JSString* p, int start, int end);
+JSValue JS_ConcatString3(JSContext* ctx, const char* str1, JSValue str2, const char* str3);
+/* op1 and op2 are converted to strings. For convience, op1 or op2 =
+   JS_EXCEPTION are accepted and return JS_EXCEPTION.  */
+JSValue JS_ConcatString(JSContext* ctx, JSValue op1, JSValue op2);
+
+/* return a string atom containing name concatenated with str1 */
+JSAtom js_atom_concat_str(JSContext* ctx, JSAtom name, const char* str1);
+JSAtom js_atom_concat_num(JSContext* ctx, JSAtom name, uint32_t n);
+static inline BOOL JS_IsEmptyString(JSValueConst v) {
+  return JS_VALUE_GET_TAG(v) == JS_TAG_STRING && JS_VALUE_GET_STRING(v)->len == 0;
+}
+
+/* return TRUE if 'v' is a symbol with a string description */
+BOOL JS_AtomSymbolHasDescription(JSContext* ctx, JSAtom v);
+__maybe_unused void print_atom(JSContext* ctx, JSAtom atom);
+
+/* 'p' is freed */
+JSValue JS_NewSymbol(JSContext* ctx, JSString* p, int atom_type);
+/* descr must be a non-numeric string atom */
+JSValue JS_NewSymbolFromAtom(JSContext* ctx, JSAtom descr, int atom_type);
+
+/* It is valid to call string_buffer_end() and all string_buffer functions even
+   if string_buffer_init() or another string_buffer function returns an error.
+   If the error_status is set, string_buffer_end() returns JS_EXCEPTION.
+ */
+int string_buffer_init2(JSContext* ctx, StringBuffer* s, int size, int is_wide);
+
+#endif
diff --git a/src/core/types.h b/src/core/types.h
new file mode 100644
index 000000000..a9316e659
--- /dev/null
+++ b/src/core/types.h
@@ -0,0 +1,946 @@
+/*
+* QuickJS Javascript Engine
+*
+* Copyright (c) 2017-2021 Fabrice Bellard
+* Copyright (c) 2017-2021 Charlie Gordon
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+ */
+
+#ifndef QUICKJS_TYPES_H
+#define QUICKJS_TYPES_H
+
+#include "quickjs/quickjs.h"
+#include "quickjs/list.h"
+#include "quickjs/cutils.h"
+#include "base.h"
+
+#if CONFIG_BIGNUM
+#include "quickjs/libbf.h"
+#endif
+
+enum {
+    /* classid tag        */    /* union usage   | properties */
+    JS_CLASS_OBJECT = 1,        /* must be first */
+    JS_CLASS_ARRAY,             /* u.array       | length */
+    JS_CLASS_ERROR,
+    JS_CLASS_NUMBER,            /* u.object_data */
+    JS_CLASS_STRING,            /* u.object_data */
+    JS_CLASS_BOOLEAN,           /* u.object_data */
+    JS_CLASS_SYMBOL,            /* u.object_data */
+    JS_CLASS_ARGUMENTS,         /* u.array       | length */
+    JS_CLASS_MAPPED_ARGUMENTS,  /*               | length */
+    JS_CLASS_DATE,              /* u.object_data */
+    JS_CLASS_MODULE_NS,
+    JS_CLASS_C_FUNCTION,        /* u.cfunc */
+    JS_CLASS_BYTECODE_FUNCTION, /* u.func */
+    JS_CLASS_BOUND_FUNCTION,    /* u.bound_function */
+    JS_CLASS_C_FUNCTION_DATA,   /* u.c_function_data_record */
+    JS_CLASS_GENERATOR_FUNCTION, /* u.func */
+    JS_CLASS_FOR_IN_ITERATOR,   /* u.for_in_iterator */
+    JS_CLASS_REGEXP,            /* u.regexp */
+    JS_CLASS_ARRAY_BUFFER,      /* u.array_buffer */
+    JS_CLASS_SHARED_ARRAY_BUFFER, /* u.array_buffer */
+    JS_CLASS_UINT8C_ARRAY,      /* u.array (typed_array) */
+    JS_CLASS_INT8_ARRAY,        /* u.array (typed_array) */
+    JS_CLASS_UINT8_ARRAY,       /* u.array (typed_array) */
+    JS_CLASS_INT16_ARRAY,       /* u.array (typed_array) */
+    JS_CLASS_UINT16_ARRAY,      /* u.array (typed_array) */
+    JS_CLASS_INT32_ARRAY,       /* u.array (typed_array) */
+    JS_CLASS_UINT32_ARRAY,      /* u.array (typed_array) */
+#ifdef CONFIG_BIGNUM
+    JS_CLASS_BIG_INT64_ARRAY,   /* u.array (typed_array) */
+    JS_CLASS_BIG_UINT64_ARRAY,  /* u.array (typed_array) */
+#endif
+    JS_CLASS_FLOAT32_ARRAY,     /* u.array (typed_array) */
+    JS_CLASS_FLOAT64_ARRAY,     /* u.array (typed_array) */
+    JS_CLASS_DATAVIEW,          /* u.typed_array */
+#ifdef CONFIG_BIGNUM
+    JS_CLASS_BIG_INT,           /* u.object_data */
+    JS_CLASS_BIG_FLOAT,         /* u.object_data */
+    JS_CLASS_FLOAT_ENV,         /* u.float_env */
+    JS_CLASS_BIG_DECIMAL,       /* u.object_data */
+    JS_CLASS_OPERATOR_SET,      /* u.operator_set */
+#endif
+    JS_CLASS_MAP,               /* u.map_state */
+    JS_CLASS_SET,               /* u.map_state */
+    JS_CLASS_WEAKMAP,           /* u.map_state */
+    JS_CLASS_WEAKSET,           /* u.map_state */
+    JS_CLASS_MAP_ITERATOR,      /* u.map_iterator_data */
+    JS_CLASS_SET_ITERATOR,      /* u.map_iterator_data */
+    JS_CLASS_ARRAY_ITERATOR,    /* u.array_iterator_data */
+    JS_CLASS_STRING_ITERATOR,   /* u.array_iterator_data */
+    JS_CLASS_REGEXP_STRING_ITERATOR,   /* u.regexp_string_iterator_data */
+    JS_CLASS_GENERATOR,         /* u.generator_data */
+    JS_CLASS_PROXY,             /* u.proxy_data */
+    JS_CLASS_PROMISE,           /* u.promise_data */
+    JS_CLASS_PROMISE_RESOLVE_FUNCTION,  /* u.promise_function_data */
+    JS_CLASS_PROMISE_REJECT_FUNCTION,   /* u.promise_function_data */
+    JS_CLASS_ASYNC_FUNCTION,            /* u.func */
+    JS_CLASS_ASYNC_FUNCTION_RESOLVE,    /* u.async_function_data */
+    JS_CLASS_ASYNC_FUNCTION_REJECT,     /* u.async_function_data */
+    JS_CLASS_ASYNC_FROM_SYNC_ITERATOR,  /* u.async_from_sync_iterator_data */
+    JS_CLASS_ASYNC_GENERATOR_FUNCTION,  /* u.func */
+    JS_CLASS_ASYNC_GENERATOR,   /* u.async_generator_data */
+
+    JS_CLASS_INIT_COUNT, /* last entry for predefined classes */
+};
+
+/* number of typed array types */
+#define JS_TYPED_ARRAY_COUNT  (JS_CLASS_FLOAT64_ARRAY - JS_CLASS_UINT8C_ARRAY + 1)
+static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT];
+#define typed_array_size_log2(classid)  (typed_array_size_log2[(classid)- JS_CLASS_UINT8C_ARRAY])
+
+typedef enum JSErrorEnum {
+    JS_EVAL_ERROR,
+    JS_RANGE_ERROR,
+    JS_REFERENCE_ERROR,
+    JS_SYNTAX_ERROR,
+    JS_TYPE_ERROR,
+    JS_URI_ERROR,
+    JS_INTERNAL_ERROR,
+    JS_AGGREGATE_ERROR,
+
+    JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */
+} JSErrorEnum;
+
+#define JS_MAX_LOCAL_VARS 65536
+#define JS_STACK_SIZE_MAX 65534
+#define JS_STRING_LEN_MAX ((1 << 30) - 1)
+
+#define __exception __attribute__((warn_unused_result))
+
+typedef struct JSShape JSShape;
+typedef struct JSString JSString;
+typedef struct JSString JSAtomStruct;
+
+typedef enum {
+    JS_GC_PHASE_NONE,
+    JS_GC_PHASE_DECREF,
+    JS_GC_PHASE_REMOVE_CYCLES,
+} JSGCPhaseEnum;
+
+typedef enum OPCodeEnum OPCodeEnum;
+
+#ifdef CONFIG_BIGNUM
+/* function pointers are used for numeric operations so that it is
+   possible to remove some numeric types */
+typedef struct {
+    JSValue (*to_string)(JSContext *ctx, JSValueConst val);
+    JSValue (*from_string)(JSContext *ctx, const char *buf,
+                           int radix, int flags, slimb_t *pexponent);
+    int (*unary_arith)(JSContext *ctx,
+                       JSValue *pres, OPCodeEnum op, JSValue op1);
+    int (*binary_arith)(JSContext *ctx, OPCodeEnum op,
+                        JSValue *pres, JSValue op1, JSValue op2);
+    int (*compare)(JSContext *ctx, OPCodeEnum op,
+                   JSValue op1, JSValue op2);
+    /* only for bigfloat: */
+    JSValue (*mul_pow10_to_float64)(JSContext *ctx, const bf_t *a,
+                                    int64_t exponent);
+    int (*mul_pow10)(JSContext *ctx, JSValue *sp);
+} JSNumericOperations;
+#endif
+
+struct JSRuntime {
+    JSMallocFunctions mf;
+    JSMallocState malloc_state;
+    const char *rt_info;
+
+    int atom_hash_size; /* power of two */
+    int atom_count;
+    int atom_size;
+    int atom_count_resize; /* resize hash table at this count */
+    uint32_t *atom_hash;
+    JSAtomStruct **atom_array;
+    int atom_free_index; /* 0 = none */
+
+    int class_count;    /* size of class_array */
+    JSClass *class_array;
+
+    struct list_head context_list; /* list of JSContext.link */
+    /* list of JSGCObjectHeader.link. List of allocated GC objects (used
+       by the garbage collector) */
+    struct list_head gc_obj_list;
+    /* list of JSGCObjectHeader.link. Used during JS_FreeValueRT() */
+    struct list_head gc_zero_ref_count_list;
+    struct list_head tmp_obj_list; /* used during GC */
+    JSGCPhaseEnum gc_phase : 8;
+    size_t malloc_gc_threshold;
+#ifdef DUMP_LEAKS
+    struct list_head string_list; /* list of JSString.link */
+#endif
+    /* stack limitation */
+    uintptr_t stack_size; /* in bytes, 0 if no limit */
+    uintptr_t stack_top;
+    uintptr_t stack_limit; /* lower stack limit */
+
+    JSValue current_exception;
+    /* true if inside an out of memory error, to avoid recursing */
+    BOOL in_out_of_memory : 8;
+
+    struct JSStackFrame *current_stack_frame;
+
+    JSInterruptHandler *interrupt_handler;
+    void *interrupt_opaque;
+
+    JSHostPromiseRejectionTracker *host_promise_rejection_tracker;
+    void *host_promise_rejection_tracker_opaque;
+
+    struct list_head job_list; /* list of JSJobEntry.link */
+
+    JSModuleNormalizeFunc *module_normalize_func;
+    JSModuleLoaderFunc *module_loader_func;
+    void *module_loader_opaque;
+
+    BOOL can_block : 8; /* TRUE if Atomics.wait can block */
+    /* used to allocate, free and clone SharedArrayBuffers */
+    JSSharedArrayBufferFunctions sab_funcs;
+
+    /* Shape hash table */
+    int shape_hash_bits;
+    int shape_hash_size;
+    int shape_hash_count; /* number of hashed shapes */
+    JSShape **shape_hash;
+#ifdef CONFIG_BIGNUM
+    bf_context_t bf_ctx;
+    JSNumericOperations bigint_ops;
+    JSNumericOperations bigfloat_ops;
+    JSNumericOperations bigdecimal_ops;
+    uint32_t operator_count;
+#endif
+    void *user_opaque;
+};
+
+struct JSClass {
+    uint32_t class_id; /* 0 means free entry */
+    JSAtom class_name;
+    JSClassFinalizer *finalizer;
+    JSClassGCMark *gc_mark;
+    JSClassCall *call;
+    /* pointers for exotic behavior, can be NULL if none are present */
+    const JSClassExoticMethods *exotic;
+};
+
+#define JS_MODE_STRICT (1 << 0)
+#define JS_MODE_STRIP  (1 << 1)
+#define JS_MODE_MATH   (1 << 2)
+
+typedef struct JSStackFrame {
+    struct JSStackFrame *prev_frame; /* NULL if first stack frame */
+    JSValue cur_func; /* current function, JS_UNDEFINED if the frame is detached */
+    JSValue *arg_buf; /* arguments */
+    JSValue *var_buf; /* variables */
+    struct list_head var_ref_list; /* list of JSVarRef.link */
+    const uint8_t *cur_pc; /* only used in bytecode functions : PC of the
+                        instruction after the call */
+    int arg_count;
+    int js_mode; /* 0 or JS_MODE_MATH for C functions */
+    /* only used in generators. Current stack pointer value. NULL if
+       the function is running. */
+    JSValue *cur_sp;
+} JSStackFrame;
+
+typedef enum {
+    JS_GC_OBJ_TYPE_JS_OBJECT,
+    JS_GC_OBJ_TYPE_FUNCTION_BYTECODE,
+    JS_GC_OBJ_TYPE_SHAPE,
+    JS_GC_OBJ_TYPE_VAR_REF,
+    JS_GC_OBJ_TYPE_ASYNC_FUNCTION,
+    JS_GC_OBJ_TYPE_JS_CONTEXT,
+} JSGCObjectTypeEnum;
+
+/* header for GC objects. GC objects are C data structures with a
+   reference count that can reference other GC objects. JS Objects are
+   a particular type of GC object. */
+struct JSGCObjectHeader {
+    int ref_count; /* must come first, 32-bit */
+    JSGCObjectTypeEnum gc_obj_type : 4;
+    uint8_t mark : 4; /* used by the GC */
+    uint8_t dummy1; /* not used by the GC */
+    uint16_t dummy2; /* not used by the GC */
+    struct list_head link;
+};
+
+typedef struct JSVarRef {
+    union {
+        JSGCObjectHeader header; /* must come first */
+        struct {
+            int __gc_ref_count; /* corresponds to header.ref_count */
+            uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
+
+            /* 0 : the JSVarRef is on the stack. header.link is an element
+               of JSStackFrame.var_ref_list.
+               1 : the JSVarRef is detached. header.link has the normal meanning
+            */
+            uint8_t is_detached : 1;
+            uint8_t is_arg : 1;
+            uint16_t var_idx; /* index of the corresponding function variable on
+                                 the stack */
+        };
+    };
+    JSValue *pvalue; /* pointer to the value, either on the stack or
+                        to 'value' */
+    JSValue value; /* used when the variable is no longer on the stack */
+} JSVarRef;
+
+#ifdef CONFIG_BIGNUM
+typedef struct JSFloatEnv {
+    limb_t prec;
+    bf_flags_t flags;
+    unsigned int status;
+} JSFloatEnv;
+
+/* the same structure is used for big integers and big floats. Big
+   integers are never infinite or NaNs */
+typedef struct JSBigFloat {
+    JSRefCountHeader header; /* must come first, 32-bit */
+    bf_t num;
+} JSBigFloat;
+
+typedef struct JSBigDecimal {
+    JSRefCountHeader header; /* must come first, 32-bit */
+    bfdec_t num;
+} JSBigDecimal;
+#endif
+
+typedef enum {
+    JS_AUTOINIT_ID_PROTOTYPE,
+    JS_AUTOINIT_ID_MODULE_NS,
+    JS_AUTOINIT_ID_PROP,
+} JSAutoInitIDEnum;
+
+typedef enum JSStrictEqModeEnum {
+  JS_EQ_STRICT,
+  JS_EQ_SAME_VALUE,
+  JS_EQ_SAME_VALUE_ZERO,
+} JSStrictEqModeEnum;
+
+/* must be large enough to have a negligible runtime cost and small
+   enough to call the interrupt callback often. */
+#define JS_INTERRUPT_COUNTER_INIT 10000
+
+struct JSContext {
+    JSGCObjectHeader header; /* must come first */
+    JSRuntime *rt;
+    struct list_head link;
+
+    uint16_t binary_object_count;
+    int binary_object_size;
+
+    JSShape *array_shape;   /* initial shape for Array objects */
+
+    JSValue *class_proto;
+    JSValue function_proto;
+    JSValue function_ctor;
+    JSValue array_ctor;
+    JSValue regexp_ctor;
+    JSValue promise_ctor;
+    JSValue native_error_proto[JS_NATIVE_ERROR_COUNT];
+    JSValue iterator_proto;
+    JSValue async_iterator_proto;
+    JSValue array_proto_values;
+    JSValue throw_type_error;
+    JSValue eval_obj;
+
+    JSValue global_obj; /* global object */
+    JSValue global_var_obj; /* contains the global let/const definitions */
+
+    uint64_t random_state;
+#ifdef CONFIG_BIGNUM
+    bf_context_t *bf_ctx;   /* points to rt->bf_ctx, shared by all contexts */
+    JSFloatEnv fp_env; /* global FP environment */
+    BOOL bignum_ext : 8; /* enable math mode */
+    BOOL allow_operator_overloading : 8;
+#endif
+    /* when the counter reaches zero, JSRutime.interrupt_handler is called */
+    int interrupt_counter;
+    BOOL is_error_property_enabled;
+
+    struct list_head loaded_modules; /* list of JSModuleDef.link */
+
+    /* if NULL, RegExp compilation is not supported */
+    JSValue (*compile_regexp)(JSContext *ctx, JSValueConst pattern,
+                              JSValueConst flags);
+    /* if NULL, eval is not supported */
+    JSValue (*eval_internal)(JSContext *ctx, JSValueConst this_obj,
+                             const char *input, size_t input_len,
+                             const char *filename, int flags, int scope_idx);
+    void *user_opaque;
+};
+
+typedef union JSFloat64Union {
+    double d;
+    uint64_t u64;
+    uint32_t u32[2];
+} JSFloat64Union;
+
+enum {
+    JS_ATOM_TYPE_STRING = 1,
+    JS_ATOM_TYPE_GLOBAL_SYMBOL,
+    JS_ATOM_TYPE_SYMBOL,
+    JS_ATOM_TYPE_PRIVATE,
+};
+
+enum {
+    JS_ATOM_HASH_SYMBOL,
+    JS_ATOM_HASH_PRIVATE,
+};
+
+typedef enum {
+    JS_ATOM_KIND_STRING,
+    JS_ATOM_KIND_SYMBOL,
+    JS_ATOM_KIND_PRIVATE,
+} JSAtomKindEnum;
+
+#define JS_ATOM_HASH_MASK  ((1 << 30) - 1)
+
+struct JSString {
+    JSRefCountHeader header; /* must come first, 32-bit */
+    uint32_t len : 31;
+    uint8_t is_wide_char : 1; /* 0 = 8 bits, 1 = 16 bits characters */
+    /* for JS_ATOM_TYPE_SYMBOL: hash = 0, atom_type = 3,
+       for JS_ATOM_TYPE_PRIVATE: hash = 1, atom_type = 3
+       XXX: could change encoding to have one more bit in hash */
+    uint32_t hash : 30;
+    uint8_t atom_type : 2; /* != 0 if atom, JS_ATOM_TYPE_x */
+    uint32_t hash_next; /* atom_index for JS_ATOM_TYPE_SYMBOL */
+#ifdef DUMP_LEAKS
+    struct list_head link; /* string list */
+#endif
+    union {
+        uint8_t str8[0]; /* 8 bit strings will get an extra null terminator */
+        uint16_t str16[0];
+    } u;
+};
+
+typedef struct JSClosureVar {
+    uint8_t is_local : 1;
+    uint8_t is_arg : 1;
+    uint8_t is_const : 1;
+    uint8_t is_lexical : 1;
+    uint8_t var_kind : 4; /* see JSVarKindEnum */
+    /* 8 bits available */
+    uint16_t var_idx; /* is_local = TRUE: index to a normal variable of the
+                    parent function. otherwise: index to a closure
+                    variable of the parent function */
+    JSAtom var_name;
+} JSClosureVar;
+
+#define ARG_SCOPE_INDEX 1
+#define ARG_SCOPE_END (-2)
+
+typedef struct JSVarScope {
+    int parent;  /* index into fd->scopes of the enclosing scope */
+    int first;   /* index into fd->vars of the last variable in this scope */
+} JSVarScope;
+
+typedef enum {
+    /* XXX: add more variable kinds here instead of using bit fields */
+    JS_VAR_NORMAL,
+    JS_VAR_FUNCTION_DECL, /* lexical var with function declaration */
+    JS_VAR_NEW_FUNCTION_DECL, /* lexical var with async/generator
+                                 function declaration */
+    JS_VAR_CATCH,
+    JS_VAR_FUNCTION_NAME, /* function expression name */
+    JS_VAR_PRIVATE_FIELD,
+    JS_VAR_PRIVATE_METHOD,
+    JS_VAR_PRIVATE_GETTER,
+    JS_VAR_PRIVATE_SETTER, /* must come after JS_VAR_PRIVATE_GETTER */
+    JS_VAR_PRIVATE_GETTER_SETTER, /* must come after JS_VAR_PRIVATE_SETTER */
+} JSVarKindEnum;
+
+/* XXX: could use a different structure in bytecode functions to save
+   memory */
+typedef struct JSVarDef {
+    JSAtom var_name;
+    /* index into fd->scopes of this variable lexical scope */
+    int scope_level;
+    /* during compilation:
+        - if scope_level = 0: scope in which the variable is defined
+        - if scope_level != 0: index into fd->vars of the next
+          variable in the same or enclosing lexical scope
+       in a bytecode function:
+       index into fd->vars of the next
+       variable in the same or enclosing lexical scope
+    */
+    int scope_next;
+    uint8_t is_const : 1;
+    uint8_t is_lexical : 1;
+    uint8_t is_captured : 1;
+    uint8_t var_kind : 4; /* see JSVarKindEnum */
+    /* only used during compilation: function pool index for lexical
+       variables with var_kind =
+       JS_VAR_FUNCTION_DECL/JS_VAR_NEW_FUNCTION_DECL or scope level of
+       the definition of the 'var' variables (they have scope_level =
+       0) */
+    int func_pool_idx : 24; /* only used during compilation : index in
+                               the constant pool for hoisted function
+                               definition */
+} JSVarDef;
+
+/* for the encoding of the pc2line table */
+#define PC2LINE_BASE     (-1)
+#define PC2LINE_RANGE    5
+#define PC2LINE_OP_FIRST 1
+#define PC2LINE_DIFF_PC_MAX ((255 - PC2LINE_OP_FIRST) / PC2LINE_RANGE)
+
+typedef enum JSFunctionKindEnum {
+    JS_FUNC_NORMAL = 0,
+    JS_FUNC_GENERATOR = (1 << 0),
+    JS_FUNC_ASYNC = (1 << 1),
+    JS_FUNC_ASYNC_GENERATOR = (JS_FUNC_GENERATOR | JS_FUNC_ASYNC),
+} JSFunctionKindEnum;
+
+typedef struct JSFunctionBytecode {
+    JSGCObjectHeader header; /* must come first */
+    uint8_t js_mode;
+    uint8_t has_prototype : 1; /* true if a prototype field is necessary */
+    uint8_t has_simple_parameter_list : 1;
+    uint8_t is_derived_class_constructor : 1;
+    /* true if home_object needs to be initialized */
+    uint8_t need_home_object : 1;
+    uint8_t func_kind : 2;
+    uint8_t new_target_allowed : 1;
+    uint8_t super_call_allowed : 1;
+    uint8_t super_allowed : 1;
+    uint8_t arguments_allowed : 1;
+    uint8_t has_debug : 1;
+    uint8_t backtrace_barrier : 1; /* stop backtrace on this function */
+    uint8_t read_only_bytecode : 1;
+    /* XXX: 4 bits available */
+    uint8_t *byte_code_buf; /* (self pointer) */
+    int byte_code_len;
+    JSAtom func_name;
+    JSVarDef *vardefs; /* arguments + local variables (arg_count + var_count) (self pointer) */
+    JSClosureVar *closure_var; /* list of variables in the closure (self pointer) */
+    uint16_t arg_count;
+    uint16_t var_count;
+    uint16_t defined_arg_count; /* for length function property */
+    uint16_t stack_size; /* maximum stack size */
+    JSContext *realm; /* function realm */
+    JSValue *cpool; /* constant pool (self pointer) */
+    int cpool_count;
+    int closure_var_count;
+    struct {
+        /* debug info, move to separate structure to save memory? */
+        JSAtom filename;
+        int line_num;
+        int source_len;
+        int pc2line_len;
+        uint8_t *pc2line_buf;
+        char *source;
+    } debug;
+} JSFunctionBytecode;
+
+typedef struct JSBoundFunction {
+    JSValue func_obj;
+    JSValue this_val;
+    int argc;
+    JSValue argv[0];
+} JSBoundFunction;
+
+typedef enum JSIteratorKindEnum {
+    JS_ITERATOR_KIND_KEY,
+    JS_ITERATOR_KIND_VALUE,
+    JS_ITERATOR_KIND_KEY_AND_VALUE,
+} JSIteratorKindEnum;
+
+typedef struct JSForInIterator {
+    JSValue obj;
+    BOOL is_array;
+    uint32_t array_length;
+    uint32_t idx;
+} JSForInIterator;
+
+typedef struct JSRegExp {
+    JSString *pattern;
+    JSString *bytecode; /* also contains the flags */
+} JSRegExp;
+
+typedef struct JSProxyData {
+    JSValue target;
+    JSValue handler;
+    uint8_t is_func;
+    uint8_t is_revoked;
+} JSProxyData;
+
+typedef struct JSArrayBuffer {
+    int byte_length; /* 0 if detached */
+    uint8_t detached;
+    uint8_t shared; /* if shared, the array buffer cannot be detached */
+    uint8_t *data; /* NULL if detached */
+    struct list_head array_list;
+    void *opaque;
+    JSFreeArrayBufferDataFunc *free_func;
+} JSArrayBuffer;
+
+typedef struct JSTypedArray {
+    struct list_head link; /* link to arraybuffer */
+    JSObject *obj; /* back pointer to the TypedArray/DataView object */
+    JSObject *buffer; /* based array buffer */
+    uint32_t offset; /* offset in the array buffer */
+    uint32_t length; /* length in the array buffer */
+} JSTypedArray;
+
+typedef struct JSAsyncFunctionState {
+    JSValue this_val; /* 'this' generator argument */
+    int argc; /* number of function arguments */
+    BOOL throw_flag; /* used to throw an exception in JS_CallInternal() */
+    JSStackFrame frame;
+} JSAsyncFunctionState;
+
+/* XXX: could use an object instead to avoid the
+   JS_TAG_ASYNC_FUNCTION tag for the GC */
+typedef struct JSAsyncFunctionData {
+    JSGCObjectHeader header; /* must come first */
+    JSValue resolving_funcs[2];
+    BOOL is_active; /* true if the async function state is valid */
+    JSAsyncFunctionState func_state;
+} JSAsyncFunctionData;
+
+typedef enum {
+   /* binary operators */
+   JS_OVOP_ADD,
+   JS_OVOP_SUB,
+   JS_OVOP_MUL,
+   JS_OVOP_DIV,
+   JS_OVOP_MOD,
+   JS_OVOP_POW,
+   JS_OVOP_OR,
+   JS_OVOP_AND,
+   JS_OVOP_XOR,
+   JS_OVOP_SHL,
+   JS_OVOP_SAR,
+   JS_OVOP_SHR,
+   JS_OVOP_EQ,
+   JS_OVOP_LESS,
+
+   JS_OVOP_BINARY_COUNT,
+   /* unary operators */
+   JS_OVOP_POS = JS_OVOP_BINARY_COUNT,
+   JS_OVOP_NEG,
+   JS_OVOP_INC,
+   JS_OVOP_DEC,
+   JS_OVOP_NOT,
+
+   JS_OVOP_COUNT,
+} JSOverloadableOperatorEnum;
+
+typedef struct {
+    uint32_t operator_index;
+    JSObject *ops[JS_OVOP_BINARY_COUNT]; /* self operators */
+} JSBinaryOperatorDefEntry;
+
+typedef struct {
+    int count;
+    JSBinaryOperatorDefEntry *tab;
+} JSBinaryOperatorDef;
+
+typedef struct {
+    uint32_t operator_counter;
+    BOOL is_primitive; /* OperatorSet for a primitive type */
+    /* NULL if no operator is defined */
+    JSObject *self_ops[JS_OVOP_COUNT]; /* self operators */
+    JSBinaryOperatorDef left;
+    JSBinaryOperatorDef right;
+} JSOperatorSetData;
+
+typedef struct JSReqModuleEntry {
+    JSAtom module_name;
+    JSModuleDef *module; /* used using resolution */
+} JSReqModuleEntry;
+
+typedef enum JSExportTypeEnum {
+    JS_EXPORT_TYPE_LOCAL,
+    JS_EXPORT_TYPE_INDIRECT,
+} JSExportTypeEnum;
+
+typedef struct JSExportEntry {
+    union {
+        struct {
+            int var_idx; /* closure variable index */
+            JSVarRef *var_ref; /* if != NULL, reference to the variable */
+        } local; /* for local export */
+        int req_module_idx; /* module for indirect export */
+    } u;
+    JSExportTypeEnum export_type;
+    JSAtom local_name; /* '*' if export ns from. not used for local
+                          export after compilation */
+    JSAtom export_name; /* exported variable name */
+} JSExportEntry;
+
+typedef struct JSStarExportEntry {
+    int req_module_idx; /* in req_module_entries */
+} JSStarExportEntry;
+
+typedef struct JSImportEntry {
+    int var_idx; /* closure variable index */
+    JSAtom import_name;
+    int req_module_idx; /* in req_module_entries */
+} JSImportEntry;
+
+struct JSModuleDef {
+    JSRefCountHeader header; /* must come first, 32-bit */
+    JSAtom module_name;
+    struct list_head link;
+
+    JSReqModuleEntry *req_module_entries;
+    int req_module_entries_count;
+    int req_module_entries_size;
+
+    JSExportEntry *export_entries;
+    int export_entries_count;
+    int export_entries_size;
+
+    JSStarExportEntry *star_export_entries;
+    int star_export_entries_count;
+    int star_export_entries_size;
+
+    JSImportEntry *import_entries;
+    int import_entries_count;
+    int import_entries_size;
+
+    JSValue module_ns;
+    JSValue func_obj; /* only used for JS modules */
+    JSModuleInitFunc *init_func; /* only used for C modules */
+    BOOL resolved : 8;
+    BOOL func_created : 8;
+    BOOL instantiated : 8;
+    BOOL evaluated : 8;
+    BOOL eval_mark : 8; /* temporary use during js_evaluate_module() */
+    /* true if evaluation yielded an exception. It is saved in
+       eval_exception */
+    BOOL eval_has_exception : 8;
+    JSValue eval_exception;
+    JSValue meta_obj; /* for import.meta */
+};
+
+typedef struct JSJobEntry {
+    struct list_head link;
+    JSContext *ctx;
+    JSJobFunc *job_func;
+    int argc;
+    JSValue argv[0];
+} JSJobEntry;
+
+typedef struct JSProperty {
+    union {
+        JSValue value;      /* JS_PROP_NORMAL */
+        struct {            /* JS_PROP_GETSET */
+            JSObject *getter; /* NULL if undefined */
+            JSObject *setter; /* NULL if undefined */
+        } getset;
+        JSVarRef *var_ref;  /* JS_PROP_VARREF */
+        struct {            /* JS_PROP_AUTOINIT */
+            /* in order to use only 2 pointers, we compress the realm
+               and the init function pointer */
+            uintptr_t realm_and_id; /* realm and init_id (JS_AUTOINIT_ID_x)
+                                       in the 2 low bits */
+            void *opaque;
+        } init;
+    } u;
+} JSProperty;
+
+#define JS_PROP_INITIAL_SIZE 2
+#define JS_PROP_INITIAL_HASH_SIZE 4 /* must be a power of two */
+#define JS_ARRAY_INITIAL_SIZE 2
+
+typedef struct JSShapeProperty {
+    uint32_t hash_next : 26; /* 0 if last in list */
+    uint32_t flags : 6;   /* JS_PROP_XXX */
+    JSAtom atom; /* JS_ATOM_NULL = free property entry */
+} JSShapeProperty;
+
+struct JSShape {
+    /* hash table of size hash_mask + 1 before the start of the
+       structure (see prop_hash_end()). */
+    JSGCObjectHeader header;
+    /* true if the shape is inserted in the shape hash table. If not,
+       JSShape.hash is not valid */
+    uint8_t is_hashed;
+    /* If true, the shape may have small array index properties 'n' with 0
+       <= n <= 2^31-1. If false, the shape is guaranteed not to have
+       small array index properties */
+    uint8_t has_small_array_index;
+    uint32_t hash; /* current hash value */
+    uint32_t prop_hash_mask;
+    int prop_size; /* allocated properties */
+    int prop_count; /* include deleted properties */
+    int deleted_prop_count;
+    JSShape *shape_hash_next; /* in JSRuntime.shape_hash[h] list */
+    JSObject *proto;
+    JSShapeProperty prop[0]; /* prop_size elements */
+};
+
+struct JSObject {
+    union {
+        JSGCObjectHeader header;
+        struct {
+            int __gc_ref_count; /* corresponds to header.ref_count */
+            uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
+
+            uint8_t extensible : 1;
+            uint8_t free_mark : 1; /* only used when freeing objects with cycles */
+            uint8_t is_exotic : 1; /* TRUE if object has exotic property handlers */
+            uint8_t fast_array : 1; /* TRUE if u.array is used for get/put (for JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS and typed arrays) */
+            uint8_t is_constructor : 1; /* TRUE if object is a constructor function */
+            uint8_t is_uncatchable_error : 1; /* if TRUE, error is not catchable */
+            uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */
+            uint8_t is_HTMLDDA : 1; /* specific annex B IsHtmlDDA behavior */
+            uint16_t class_id; /* see JS_CLASS_x */
+        };
+    };
+    /* byte offsets: 16/24 */
+    JSShape *shape; /* prototype and property names + flag */
+    JSProperty *prop; /* array of properties */
+    /* byte offsets: 24/40 */
+    struct JSMapRecord *first_weak_ref; /* XXX: use a bit and an external hash table? */
+    /* byte offsets: 28/48 */
+    union {
+        void *opaque;
+        struct JSBoundFunction *bound_function; /* JS_CLASS_BOUND_FUNCTION */
+        struct JSCFunctionDataRecord *c_function_data_record; /* JS_CLASS_C_FUNCTION_DATA */
+        struct JSForInIterator *for_in_iterator; /* JS_CLASS_FOR_IN_ITERATOR */
+        struct JSArrayBuffer *array_buffer; /* JS_CLASS_ARRAY_BUFFER, JS_CLASS_SHARED_ARRAY_BUFFER */
+        struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_DATAVIEW */
+#ifdef CONFIG_BIGNUM
+        struct JSFloatEnv *float_env; /* JS_CLASS_FLOAT_ENV */
+        struct JSOperatorSetData *operator_set; /* JS_CLASS_OPERATOR_SET */
+#endif
+        struct JSMapState *map_state;   /* JS_CLASS_MAP..JS_CLASS_WEAKSET */
+        struct JSMapIteratorData *map_iterator_data; /* JS_CLASS_MAP_ITERATOR, JS_CLASS_SET_ITERATOR */
+        struct JSArrayIteratorData *array_iterator_data; /* JS_CLASS_ARRAY_ITERATOR, JS_CLASS_STRING_ITERATOR */
+        struct JSRegExpStringIteratorData *regexp_string_iterator_data; /* JS_CLASS_REGEXP_STRING_ITERATOR */
+        struct JSGeneratorData *generator_data; /* JS_CLASS_GENERATOR */
+        struct JSProxyData *proxy_data; /* JS_CLASS_PROXY */
+        struct JSPromiseData *promise_data; /* JS_CLASS_PROMISE */
+        struct JSPromiseFunctionData *promise_function_data; /* JS_CLASS_PROMISE_RESOLVE_FUNCTION, JS_CLASS_PROMISE_REJECT_FUNCTION */
+        struct JSAsyncFunctionData *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */
+        struct JSAsyncFromSyncIteratorData *async_from_sync_iterator_data; /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */
+        struct JSAsyncGeneratorData *async_generator_data; /* JS_CLASS_ASYNC_GENERATOR */
+        struct { /* JS_CLASS_BYTECODE_FUNCTION: 12/24 bytes */
+            /* also used by JS_CLASS_GENERATOR_FUNCTION, JS_CLASS_ASYNC_FUNCTION and JS_CLASS_ASYNC_GENERATOR_FUNCTION */
+            struct JSFunctionBytecode *function_bytecode;
+            JSVarRef **var_refs;
+            JSObject *home_object; /* for 'super' access */
+        } func;
+        struct { /* JS_CLASS_C_FUNCTION: 12/20 bytes */
+            JSContext *realm;
+            JSCFunctionType c_function;
+            uint8_t length;
+            uint8_t cproto;
+            int16_t magic;
+        } cfunc;
+        /* array part for fast arrays and typed arrays */
+        struct { /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS, JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
+            union {
+                uint32_t size;          /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */
+                struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
+            } u1;
+            union {
+                JSValue *values;        /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */
+                void *ptr;              /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
+                int8_t *int8_ptr;       /* JS_CLASS_INT8_ARRAY */
+                uint8_t *uint8_ptr;     /* JS_CLASS_UINT8_ARRAY, JS_CLASS_UINT8C_ARRAY */
+                int16_t *int16_ptr;     /* JS_CLASS_INT16_ARRAY */
+                uint16_t *uint16_ptr;   /* JS_CLASS_UINT16_ARRAY */
+                int32_t *int32_ptr;     /* JS_CLASS_INT32_ARRAY */
+                uint32_t *uint32_ptr;   /* JS_CLASS_UINT32_ARRAY */
+                int64_t *int64_ptr;     /* JS_CLASS_INT64_ARRAY */
+                uint64_t *uint64_ptr;   /* JS_CLASS_UINT64_ARRAY */
+                float *float_ptr;       /* JS_CLASS_FLOAT32_ARRAY */
+                double *double_ptr;     /* JS_CLASS_FLOAT64_ARRAY */
+            } u;
+            uint32_t count; /* <= 2^31-1. 0 for a detached typed array */
+        } array;    /* 12/20 bytes */
+        JSRegExp regexp;    /* JS_CLASS_REGEXP: 8/16 bytes */
+        JSValue object_data;    /* for JS_SetObjectData(): 8/16/16 bytes */
+    } u;
+    /* byte sizes: 40/48/72 */
+};
+
+enum {
+  __JS_ATOM_NULL = JS_ATOM_NULL,
+#define DEF(name, str) JS_ATOM_ ## name,
+#include "quickjs/quickjs-atom.h"
+#undef DEF
+  JS_ATOM_END,
+};
+#define JS_ATOM_LAST_KEYWORD JS_ATOM_super
+#define JS_ATOM_LAST_STRICT_KEYWORD JS_ATOM_yield
+
+static const char js_atom_init[] =
+#define DEF(name, str) str "\0"
+#include "quickjs/quickjs-atom.h"
+#undef DEF
+    ;
+
+typedef enum OPCodeFormat {
+#define FMT(f) OP_FMT_ ## f,
+#define DEF(id, size, n_pop, n_push, f)
+#include "quickjs/quickjs-opcode.h"
+#undef DEF
+#undef FMT
+} OPCodeFormat;
+
+enum OPCodeEnum {
+#define FMT(f)
+#define DEF(id, size, n_pop, n_push, f) OP_ ## id,
+#define def(id, size, n_pop, n_push, f)
+#include "quickjs/quickjs-opcode.h"
+#undef def
+#undef DEF
+#undef FMT
+    OP_COUNT, /* excluding temporary opcodes */
+    /* temporary opcodes : overlap with the short opcodes */
+    OP_TEMP_START = OP_nop + 1,
+    OP___dummy = OP_TEMP_START - 1,
+#define FMT(f)
+#define DEF(id, size, n_pop, n_push, f)
+#define def(id, size, n_pop, n_push, f) OP_ ## id,
+#include "quickjs/quickjs-opcode.h"
+#undef def
+#undef DEF
+#undef FMT
+    OP_TEMP_END,
+};
+
+#define ATOD_INT_ONLY        (1 << 0)
+/* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */
+#define ATOD_ACCEPT_BIN_OCT  (1 << 2)
+/* accept O prefix as octal if radix == 0 and properly formed (Annex B) */
+#define ATOD_ACCEPT_LEGACY_OCTAL  (1 << 4)
+/* accept _ between digits as a digit separator */
+#define ATOD_ACCEPT_UNDERSCORES  (1 << 5)
+/* allow a suffix to override the type */
+#define ATOD_ACCEPT_SUFFIX    (1 << 6)
+/* default type */
+#define ATOD_TYPE_MASK        (3 << 7)
+#define ATOD_TYPE_FLOAT64     (0 << 7)
+#define ATOD_TYPE_BIG_INT     (1 << 7)
+#define ATOD_TYPE_BIG_FLOAT   (2 << 7)
+#define ATOD_TYPE_BIG_DECIMAL (3 << 7)
+/* assume bigint mode: floats are parsed as integers if no decimal
+   point nor exponent */
+#define ATOD_MODE_BIGINT      (1 << 9)
+/* accept -0x1 */
+#define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10)
+
+#endif
diff --git a/cutils.c b/src/cutils.c
similarity index 99%
rename from cutils.c
rename to src/cutils.c
index a02fb7688..ff4e7c458 100644
--- a/cutils.c
+++ b/src/cutils.c
@@ -27,7 +27,7 @@
 #include <stdarg.h>
 #include <string.h>
 
-#include "cutils.h"
+#include "quickjs/cutils.h"
 
 void pstrcpy(char *buf, int buf_size, const char *str)
 {
diff --git a/libbf.c b/src/libbf.c
similarity index 99%
rename from libbf.c
rename to src/libbf.c
index fe1628e79..81e752035 100644
--- a/libbf.c
+++ b/src/libbf.c
@@ -1,6 +1,6 @@
 /*
  * Tiny arbitrary precision floating point library
- * 
+ *
  * Copyright (c) 2017-2021 Fabrice Bellard
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -21,19 +21,20 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#include <stdlib.h>
-#include <stdio.h>
+#include <assert.h>
 #include <inttypes.h>
 #include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 
 #ifdef __AVX2__
 #include <immintrin.h>
 #endif
 
-#include "cutils.h"
-#include "libbf.h"
+#include "core/convertion.h"
+#include "quickjs/cutils.h"
+#include "quickjs/libbf.h"
 
 /* enable it to check the multiplication result */
 //#define USE_MUL_CHECK
@@ -2817,18 +2818,6 @@ int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix,
     return ret;
 }
 
-static inline int to_digit(int c)
-{
-    if (c >= '0' && c <= '9')
-        return c - '0';
-    else if (c >= 'A' && c <= 'Z')
-        return c - 'A' + 10;
-    else if (c >= 'a' && c <= 'z')
-        return c - 'a' + 10;
-    else
-        return 36;
-}
-
 /* add a limb at 'pos' and decrement pos. new space is created if
    needed. Return 0 if OK, -1 if memory error */
 static int bf_add_limb(bf_t *a, slimb_t *ppos, limb_t v)
diff --git a/libregexp.c b/src/libregexp.c
similarity index 99%
rename from libregexp.c
rename to src/libregexp.c
index 379bfc7a9..c944a358d 100644
--- a/libregexp.c
+++ b/src/libregexp.c
@@ -28,8 +28,8 @@
 #include <string.h>
 #include <assert.h>
 
-#include "cutils.h"
-#include "libregexp.h"
+#include "quickjs/cutils.h"
+#include "quickjs/libregexp.h"
 
 /*
   TODO:
@@ -49,7 +49,7 @@
 
 typedef enum {
 #define DEF(id, size) REOP_ ## id,
-#include "libregexp-opcode.h"
+#include "quickjs/libregexp-opcode.h"
 #undef DEF
     REOP_COUNT,
 } REOPCodeEnum;
@@ -96,7 +96,7 @@ static const REOpCode reopcode_info[REOP_COUNT] = {
 #else
 #define DEF(id, size) { size },
 #endif
-#include "libregexp-opcode.h"
+#include "quickjs/libregexp-opcode.h"
 #undef DEF
 };
 
diff --git a/libunicode.c b/src/libunicode.c
similarity index 99%
rename from libunicode.c
rename to src/libunicode.c
index 63c12a077..50c4e79be 100644
--- a/libunicode.c
+++ b/src/libunicode.c
@@ -27,9 +27,9 @@
 #include <string.h>
 #include <assert.h>
 
-#include "cutils.h"
-#include "libunicode.h"
-#include "libunicode-table.h"
+#include "quickjs/cutils.h"
+#include "quickjs/libunicode.h"
+#include "quickjs/libunicode-table.h"
 
 enum {
     RUN_TYPE_U,
diff --git a/test262.conf b/test262.conf
index bb66cf4f1..6fbb5793a 100644
--- a/test262.conf
+++ b/test262.conf
@@ -51,7 +51,6 @@ testdir=test262/test
 AggregateError
 align-detached-buffer-semantics-with-web-reality
 arbitrary-module-namespace-names=skip
-array-find-from-last=skip
 Array.prototype.at=skip
 Array.prototype.flat
 Array.prototype.flatMap
@@ -67,10 +66,8 @@ BigInt
 caller
 class
 class-fields-private
-class-fields-private-in=skip
 class-fields-public
 class-methods-private
-class-static-block=skip
 class-static-fields-public
 class-static-fields-private
 class-static-methods-private
@@ -92,7 +89,6 @@ default-parameters
 destructuring-assignment
 destructuring-binding
 dynamic-import
-error-cause=skip
 export-star-as-namespace-from-module
 FinalizationGroup=skip
 FinalizationRegistry=skip
@@ -106,12 +102,10 @@ globalThis
 hashbang
 host-gc-required=skip
 import.meta
-import-assertions=skip
 Int16Array
 Int32Array
 Int8Array
 IsHTMLDDA
-json-modules=skip
 json-superset
 legacy-regexp=skip
 let
@@ -122,7 +116,6 @@ numeric-separator-literal
 object-rest
 object-spread
 Object.fromEntries
-Object.hasOwn
 Object.is
 optional-catch-binding
 optional-chaining
@@ -141,10 +134,8 @@ regexp-lookbehind
 regexp-match-indices=skip
 regexp-named-groups
 regexp-unicode-property-escapes
-resizable-arraybuffer=skip
 rest-parameters
 Set
-ShadowRealm=skip
 SharedArrayBuffer
 string-trimming
 String.fromCodePoint
@@ -173,7 +164,6 @@ Symbol.toStringTag
 Symbol.unscopables
 tail-call-optimization=skip
 template
-Temporal=skip
 top-level-await=skip
 TypedArray
 TypedArray.prototype.at=skip
diff --git a/unicode_download.sh b/unicode_download.sh
index 2ed328954..87bb2956c 100755
--- a/unicode_download.sh
+++ b/unicode_download.sh
@@ -1,7 +1,7 @@
 #!/bin/sh
 set -e
 
-url="ftp://ftp.unicode.org/Public/14.0.0/ucd"
+url="ftp://ftp.unicode.org/Public/13.0.0/ucd"
 emoji_url="${url}/emoji/emoji-data.txt"
 
 files="CaseFolding.txt DerivedNormalizationProps.txt PropList.txt \
@@ -11,9 +11,9 @@ PropertyValueAliases.txt"
 
 mkdir -p unicode
 
-for f in $files; do
-    g="${url}/${f}"
-    wget $g -O unicode/$f
-done
+#for f in $files; do
+#    g="${url}/${f}"
+#    wget $g -O unicode/$f
+#done
     
 wget $emoji_url -O unicode/emoji-data.txt
diff --git a/unicode_gen_def.h b/unicode_gen_def.h
index 55f6790a2..47b0e391b 100644
--- a/unicode_gen_def.h
+++ b/unicode_gen_def.h
@@ -72,7 +72,6 @@ DEF(Coptic, "Copt,Qaac")
 DEF(Cuneiform, "Xsux")
 DEF(Cypriot, "Cprt")
 DEF(Cyrillic, "Cyrl")
-DEF(Cypro_Minoan, "Cpmn")
 DEF(Deseret, "Dsrt")
 DEF(Devanagari, "Deva")
 DEF(Dives_Akuru, "Diak")
@@ -155,7 +154,6 @@ DEF(Old_Persian, "Xpeo")
 DEF(Old_Sogdian, "Sogo")
 DEF(Old_South_Arabian, "Sarb")
 DEF(Old_Turkic, "Orkh")
-DEF(Old_Uyghur, "Ougr")
 DEF(Oriya, "Orya")
 DEF(Osage, "Osge")
 DEF(Osmanya, "Osma")
@@ -194,11 +192,8 @@ DEF(Thai, "Thai")
 DEF(Tibetan, "Tibt")
 DEF(Tifinagh, "Tfng")
 DEF(Tirhuta, "Tirh")
-DEF(Tangsa, "Tnsa")
-DEF(Toto, "Toto")
 DEF(Ugaritic, "Ugar")
 DEF(Vai, "Vaii")
-DEF(Vithkuqi, "Vith")
 DEF(Wancho, "Wcho")
 DEF(Warang_Citi, "Wara")
 DEF(Yezidi, "Yezi")