quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

quickjs.c (2029740B)


      1 /*
      2  * QuickJS Javascript Engine
      3  *
      4  * Copyright (c) 2017-2025 Fabrice Bellard
      5  * Copyright (c) 2017-2025 Charlie Gordon
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a copy
      8  * of this software and associated documentation files (the "Software"), to deal
      9  * in the Software without restriction, including without limitation the rights
     10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     11  * copies of the Software, and to permit persons to whom the Software is
     12  * furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included in
     15  * all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     23  * THE SOFTWARE.
     24  */
     25 #include <stdlib.h>
     26 #include <stdio.h>
     27 #include <stdarg.h>
     28 #include <inttypes.h>
     29 #include <string.h>
     30 #include <assert.h>
     31 #include <sys/time.h>
     32 #include <time.h>
     33 #include <fenv.h>
     34 #include <math.h>
     35 #if defined(__APPLE__)
     36 #include <malloc/malloc.h>
     37 #elif defined(__linux__) || defined(__GLIBC__)
     38 #include <malloc.h>
     39 #elif defined(__FreeBSD__)
     40 #include <malloc_np.h>
     41 #endif
     42 
     43 #include "cutils.h"
     44 #include "list.h"
     45 #include "quickjs.h"
     46 #include "libregexp.h"
     47 #include "libunicode.h"
     48 #include "dtoa.h"
     49 
     50 #define OPTIMIZE         1
     51 #define SHORT_OPCODES    1
     52 #if defined(__EMSCRIPTEN__)
     53 #define DIRECT_DISPATCH  0
     54 #else
     55 #define DIRECT_DISPATCH  1
     56 #endif
     57 
     58 #if defined(__APPLE__)
     59 #define MALLOC_OVERHEAD  0
     60 #else
     61 #define MALLOC_OVERHEAD  8
     62 #endif
     63 
     64 #if !defined(_WIN32)
     65 /* define it if printf uses the RNDN rounding mode instead of RNDNA */
     66 #define CONFIG_PRINTF_RNDN
     67 #endif
     68 
     69 /* define to include Atomics.* operations which depend on the OS
     70    threads */
     71 #if !defined(__EMSCRIPTEN__)
     72 #define CONFIG_ATOMICS
     73 #endif
     74 
     75 #if !defined(__EMSCRIPTEN__)
     76 /* enable stack limitation */
     77 #define CONFIG_STACK_CHECK
     78 #endif
     79 
     80 
     81 /* dump object free */
     82 //#define DUMP_FREE
     83 //#define DUMP_CLOSURE
     84 /* dump the bytecode of the compiled functions: combination of bits
     85    1: dump pass 3 final byte code
     86    2: dump pass 2 code
     87    4: dump pass 1 code
     88    8: dump stdlib functions
     89   16: dump bytecode in hex
     90   32: dump line number table
     91   64: dump compute_stack_size
     92  */
     93 //#define DUMP_BYTECODE  (1)
     94 /* dump the occurence of the automatic GC */
     95 //#define DUMP_GC
     96 /* dump objects freed by the garbage collector */
     97 //#define DUMP_GC_FREE
     98 /* dump objects leaking when freeing the runtime */
     99 //#define DUMP_LEAKS  1
    100 /* dump memory usage before running the garbage collector */
    101 //#define DUMP_MEM
    102 //#define DUMP_OBJECTS    /* dump objects in JS_FreeContext */
    103 //#define DUMP_ATOMS      /* dump atoms in JS_FreeContext */
    104 //#define DUMP_SHAPES     /* dump shapes in JS_FreeContext */
    105 //#define DUMP_MODULE_RESOLVE
    106 //#define DUMP_MODULE_EXEC
    107 //#define DUMP_PROMISE
    108 //#define DUMP_READ_OBJECT
    109 //#define DUMP_ROPE_REBALANCE
    110 /* add asm labels to each opcode so that it is easier to see the generated code */
    111 //#define OPCODE_ASM_LABEL
    112 
    113 /* test the GC by forcing it before each object allocation */
    114 //#define FORCE_GC_AT_MALLOC
    115 
    116 /* use function call trampolines for better output in profiling tools */
    117 //#define PERF_TRAMPOLINE
    118 
    119 #ifdef CONFIG_ATOMICS
    120 #include <pthread.h>
    121 #include <stdatomic.h>
    122 #include <errno.h>
    123 #endif
    124 
    125 enum {
    126     /* classid tag        */    /* union usage   | properties */
    127     JS_CLASS_OBJECT = 1,        /* must be first */
    128     JS_CLASS_ARRAY,             /* u.array       | length */
    129     JS_CLASS_ERROR,
    130     JS_CLASS_NUMBER,            /* u.object_data */
    131     JS_CLASS_STRING,            /* u.object_data */
    132     JS_CLASS_BOOLEAN,           /* u.object_data */
    133     JS_CLASS_SYMBOL,            /* u.object_data */
    134     JS_CLASS_ARGUMENTS,         /* u.array       | length */
    135     JS_CLASS_MAPPED_ARGUMENTS,  /* u.array       | length */
    136     JS_CLASS_DATE,              /* u.object_data */
    137     JS_CLASS_MODULE_NS,
    138     JS_CLASS_C_FUNCTION,        /* u.cfunc */
    139     JS_CLASS_BYTECODE_FUNCTION, /* u.func */
    140     JS_CLASS_BOUND_FUNCTION,    /* u.bound_function */
    141     JS_CLASS_C_FUNCTION_DATA,   /* u.c_function_data_record */
    142     JS_CLASS_GENERATOR_FUNCTION, /* u.func */
    143     JS_CLASS_FOR_IN_ITERATOR,   /* u.for_in_iterator */
    144     JS_CLASS_REGEXP,            /* u.regexp */
    145     JS_CLASS_ARRAY_BUFFER,      /* u.array_buffer */
    146     JS_CLASS_SHARED_ARRAY_BUFFER, /* u.array_buffer */
    147     JS_CLASS_UINT8C_ARRAY,      /* u.array (typed_array) */
    148     JS_CLASS_INT8_ARRAY,        /* u.array (typed_array) */
    149     JS_CLASS_UINT8_ARRAY,       /* u.array (typed_array) */
    150     JS_CLASS_INT16_ARRAY,       /* u.array (typed_array) */
    151     JS_CLASS_UINT16_ARRAY,      /* u.array (typed_array) */
    152     JS_CLASS_INT32_ARRAY,       /* u.array (typed_array) */
    153     JS_CLASS_UINT32_ARRAY,      /* u.array (typed_array) */
    154     JS_CLASS_BIG_INT64_ARRAY,   /* u.array (typed_array) */
    155     JS_CLASS_BIG_UINT64_ARRAY,  /* u.array (typed_array) */
    156     JS_CLASS_FLOAT16_ARRAY,     /* u.array (typed_array) */
    157     JS_CLASS_FLOAT32_ARRAY,     /* u.array (typed_array) */
    158     JS_CLASS_FLOAT64_ARRAY,     /* u.array (typed_array) */
    159     JS_CLASS_DATAVIEW,          /* u.typed_array */
    160     JS_CLASS_BIG_INT,           /* u.object_data */
    161     JS_CLASS_MAP,               /* u.map_state */
    162     JS_CLASS_SET,               /* u.map_state */
    163     JS_CLASS_WEAKMAP,           /* u.map_state */
    164     JS_CLASS_WEAKSET,           /* u.map_state */
    165     JS_CLASS_ITERATOR,          /* u.map_iterator_data */
    166     JS_CLASS_ITERATOR_CONCAT,   /* u.iterator_concat_data */
    167     JS_CLASS_ITERATOR_HELPER,   /* u.iterator_helper_data */
    168     JS_CLASS_ITERATOR_WRAP,     /* u.iterator_wrap_data */
    169     JS_CLASS_MAP_ITERATOR,      /* u.map_iterator_data */
    170     JS_CLASS_SET_ITERATOR,      /* u.map_iterator_data */
    171     JS_CLASS_ARRAY_ITERATOR,    /* u.array_iterator_data */
    172     JS_CLASS_STRING_ITERATOR,   /* u.array_iterator_data */
    173     JS_CLASS_REGEXP_STRING_ITERATOR,   /* u.regexp_string_iterator_data */
    174     JS_CLASS_GENERATOR,         /* u.generator_data */
    175     JS_CLASS_GLOBAL_OBJECT,     /* u.global_object */
    176     JS_CLASS_RAWJSON,
    177     JS_CLASS_PROXY,             /* u.proxy_data */
    178     JS_CLASS_PROMISE,           /* u.promise_data */
    179     JS_CLASS_PROMISE_RESOLVE_FUNCTION,  /* u.promise_function_data */
    180     JS_CLASS_PROMISE_REJECT_FUNCTION,   /* u.promise_function_data */
    181     JS_CLASS_ASYNC_FUNCTION,            /* u.func */
    182     JS_CLASS_ASYNC_FUNCTION_RESOLVE,    /* u.async_function_data */
    183     JS_CLASS_ASYNC_FUNCTION_REJECT,     /* u.async_function_data */
    184     JS_CLASS_ASYNC_FROM_SYNC_ITERATOR,  /* u.async_from_sync_iterator_data */
    185     JS_CLASS_ASYNC_GENERATOR_FUNCTION,  /* u.func */
    186     JS_CLASS_ASYNC_GENERATOR,   /* u.async_generator_data */
    187     JS_CLASS_WEAK_REF,
    188     JS_CLASS_FINALIZATION_REGISTRY,
    189     
    190     JS_CLASS_INIT_COUNT, /* last entry for predefined classes */
    191 };
    192 
    193 /* number of typed array types */
    194 #define JS_TYPED_ARRAY_COUNT  (JS_CLASS_FLOAT64_ARRAY - JS_CLASS_UINT8C_ARRAY + 1)
    195 static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT];
    196 #define typed_array_size_log2(classid)  (typed_array_size_log2[(classid)- JS_CLASS_UINT8C_ARRAY])
    197 
    198 typedef enum JSErrorEnum {
    199     JS_EVAL_ERROR,
    200     JS_RANGE_ERROR,
    201     JS_REFERENCE_ERROR,
    202     JS_SYNTAX_ERROR,
    203     JS_TYPE_ERROR,
    204     JS_URI_ERROR,
    205     JS_INTERNAL_ERROR,
    206     JS_AGGREGATE_ERROR,
    207 
    208     JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */
    209 } JSErrorEnum;
    210 
    211 /* the variable and scope indexes must fit on 16 bits. The (-1) and
    212    ARG_SCOPE_END values are reserved. */
    213 #define JS_MAX_LOCAL_VARS 65534
    214 #define JS_STACK_SIZE_MAX 65534
    215 #define JS_STRING_LEN_MAX ((1 << 30) - 1)
    216 
    217 /* strings <= this length are not concatenated using ropes. if too
    218    small, the rope memory overhead becomes high. */
    219 #define JS_STRING_ROPE_SHORT_LEN  512
    220 /* specific threshold for initial rope use */
    221 #define JS_STRING_ROPE_SHORT2_LEN 8192
    222 /* rope depth at which we rebalance */
    223 #define JS_STRING_ROPE_MAX_DEPTH 60
    224 
    225 #define __exception __attribute__((warn_unused_result))
    226 
    227 typedef struct JSShape JSShape;
    228 typedef struct JSString JSString;
    229 typedef struct JSString JSAtomStruct;
    230 typedef struct JSObject JSObject;
    231 
    232 #define JS_VALUE_GET_OBJ(v) ((JSObject *)JS_VALUE_GET_PTR(v))
    233 #define JS_VALUE_GET_STRING(v) ((JSString *)JS_VALUE_GET_PTR(v))
    234 #define JS_VALUE_GET_STRING_ROPE(v) ((JSStringRope *)JS_VALUE_GET_PTR(v))
    235 
    236 typedef enum {
    237     JS_GC_PHASE_NONE,
    238     JS_GC_PHASE_DECREF,
    239     JS_GC_PHASE_REMOVE_CYCLES,
    240 } JSGCPhaseEnum;
    241 
    242 typedef enum OPCodeEnum OPCodeEnum;
    243 
    244 /* JS malloc */
    245 
    246 #define JS_MALLOC_ALIGN 8
    247 #define JS_MALLOC_ARENA_SIZE 4096
    248 #define JS_MALLOC_BLOCK_SIZE_COUNT 31
    249 #define JS_MALLOC_MIN_SMALL_SIZE 16
    250 #define JS_MALLOC_MAX_SMALL_SIZE 512
    251 #if defined(__SANITIZE_ADDRESS__)
    252 /* use the host malloc() for all allocations */
    253 #define JS_MALLOC_LARGE_BLOCKS_ONLY 1
    254 #else
    255 #define JS_MALLOC_LARGE_BLOCKS_ONLY 0
    256 #endif
    257 
    258 /* allow iteration among the allocated blocks. Currently not used. May
    259    be used to suppress the memory overhead of JSGCObjectHeader */
    260 //#define JS_MALLOC_USE_ITER
    261 
    262 #define FREE_NIL 0xffff
    263 
    264 /* 8 byte header */
    265 /* Notes: 
    266    - the header is necessary at least to recover a pointer to
    267      JSMallocArena because we don't want to enforce a page
    268      alignment on the system malloc().
    269    - could store the block offset instead of (block_idx,
    270    block_size_idx), but it would require a division to recover the block
    271    index.
    272 */
    273 typedef struct JSMallocBlockHeader {
    274     union {
    275         uint16_t block_idx; /* FREE_NIL if large block */
    276         uint16_t free_next; /* FREE_NIL if none */
    277     } u;
    278     uint8_t block_size_idx;
    279     uint8_t gc_obj_type : 7;
    280     uint8_t mark : 1;
    281     int ref_count;
    282     __attribute__((aligned(JS_MALLOC_ALIGN))) uint8_t user_data[];
    283 } JSMallocBlockHeader;
    284 
    285 typedef struct JSMallocLargeBlockHeader {
    286 #ifdef JS_MALLOC_USE_ITER    
    287     struct list_head link;
    288 #endif
    289     JSMallocBlockHeader header;
    290 } JSMallocLargeBlockHeader;
    291 
    292 typedef struct {
    293     struct list_head free_link;
    294     struct list_head link;
    295     uint8_t block_size_idx;
    296     uint16_t n_used_blocks; /* number of allocated blocks */
    297     uint16_t n_blocks; /* total number of blocks */
    298     uint16_t first_free_block; /* FREE_NIL if none */
    299 #ifdef JS_MALLOC_USE_ITER    
    300     /* bit set to 1 for allocated block */
    301     uint32_t bitmap[((JS_MALLOC_ARENA_SIZE / JS_MALLOC_MIN_SMALL_SIZE) + 31) / 32]; 
    302 #endif
    303     /* n_blocks memory blocks of identical size */
    304     __attribute__((aligned(JS_MALLOC_ALIGN))) uint8_t blocks[];
    305 } JSMallocArena;
    306 
    307 typedef struct {
    308     struct list_head arena_list[JS_MALLOC_BLOCK_SIZE_COUNT]; /* list of JSMallocArena.link (all arenas) */
    309     struct list_head free_arena_list[JS_MALLOC_BLOCK_SIZE_COUNT]; /* list of JSMallocArena.free_link (arenas where n_used_blocks < n_blocks) */
    310 #ifdef JS_MALLOC_USE_ITER
    311     struct list_head large_block_list; /* list of JSMallocLargeBlockHeader.link */
    312 #endif
    313     __attribute__((aligned(JS_MALLOC_ALIGN))) uint8_t zero_size_block[sizeof(JSMallocBlockHeader)];
    314 
    315     /* callbacks to the host malloc */
    316     JSMallocFunctions mf;
    317     JSMallocState malloc_state;
    318 } JSMallocContext;
    319 
    320 /* end JS Malloc */
    321 
    322 struct JSRuntime {
    323     JSMallocContext malloc_ctx;
    324     const char *rt_info;
    325 
    326     int atom_hash_size; /* power of two */
    327     int atom_count;
    328     int atom_size;
    329     int atom_count_resize; /* resize hash table at this count */
    330     uint32_t *atom_hash;
    331     JSAtomStruct **atom_array;
    332     int atom_free_index; /* 0 = none */
    333 
    334     int class_count;    /* size of class_array */
    335     JSClass *class_array;
    336 
    337     struct list_head context_list; /* list of JSContext.link */
    338     /* list of JSGCObjectHeader.link. List of allocated GC objects (used
    339        by the garbage collector) */
    340     struct list_head gc_obj_list;
    341     /* list of JSGCObjectHeader.link. Used during JS_FreeValueRT() */
    342     struct list_head gc_zero_ref_count_list;
    343     struct list_head tmp_obj_list; /* used during GC */
    344     JSGCPhaseEnum gc_phase : 8;
    345     size_t malloc_gc_threshold;
    346     struct list_head weakref_list; /* list of JSWeakRefHeader.link */
    347 #ifdef DUMP_LEAKS
    348     struct list_head string_list; /* list of JSString.link */
    349 #endif
    350     /* stack limitation */
    351     uintptr_t stack_size; /* in bytes, 0 if no limit */
    352     uintptr_t stack_top;
    353     uintptr_t stack_limit; /* lower stack limit */
    354 
    355     JSValue current_exception;
    356     /* true if the current exception cannot be catched */
    357     BOOL current_exception_is_uncatchable : 8;
    358     /* true if inside an out of memory error, to avoid recursing */
    359     BOOL in_out_of_memory : 8;
    360 
    361     struct JSStackFrame *current_stack_frame;
    362 
    363     JSInterruptHandler *interrupt_handler;
    364     void *interrupt_opaque;
    365 
    366     JSHostPromiseRejectionTracker *host_promise_rejection_tracker;
    367     void *host_promise_rejection_tracker_opaque;
    368 
    369     struct list_head job_list; /* list of JSJobEntry.link */
    370 
    371     JSModuleNormalizeFunc *module_normalize_func;
    372     BOOL module_loader_has_attr;
    373     union {
    374         JSModuleLoaderFunc *module_loader_func;
    375         JSModuleLoaderFunc2 *module_loader_func2;
    376     } u;
    377     JSModuleCheckSupportedImportAttributes *module_check_attrs;
    378     void *module_loader_opaque;
    379     /* timestamp for internal use in module evaluation */
    380     int64_t module_async_evaluation_next_timestamp;
    381 
    382     BOOL can_block : 8; /* TRUE if Atomics.wait can block */
    383     /* used to allocate, free and clone SharedArrayBuffers */
    384     JSSharedArrayBufferFunctions sab_funcs;
    385     /* see JS_SetStripInfo() */
    386     uint8_t strip_flags;
    387     
    388     /* Shape hash table */
    389     int shape_hash_bits;
    390     int shape_hash_size;
    391     int shape_hash_count; /* number of hashed shapes */
    392     JSShape **shape_hash;
    393     void *user_opaque;
    394 };
    395 
    396 struct JSClass {
    397     uint32_t class_id; /* 0 means free entry */
    398     JSAtom class_name;
    399     JSClassFinalizer *finalizer;
    400     JSClassGCMark *gc_mark;
    401     JSClassCall *call;
    402     /* pointers for exotic behavior, can be NULL if none are present */
    403     const JSClassExoticMethods *exotic;
    404 };
    405 
    406 #define JS_MODE_STRICT (1 << 0)
    407 #define JS_MODE_ASYNC  (1 << 2) /* async function */
    408 #define JS_MODE_BACKTRACE_BARRIER (1 << 3) /* stop backtrace before this frame */
    409 
    410 typedef struct JSStackFrame {
    411     struct JSStackFrame *prev_frame; /* NULL if first stack frame */
    412     JSValue cur_func; /* current function, JS_UNDEFINED if the frame is detached */
    413     JSValue *arg_buf; /* arguments */
    414     JSValue *var_buf; /* variables */
    415     struct JSVarRef **var_refs; /* references to arguments or local variables */ 
    416     const uint8_t *cur_pc; /* only used in bytecode functions : PC of the
    417                         instruction after the call */
    418     int arg_count;
    419     int js_mode; /* not supported for C functions */
    420     /* only used in generators. Current stack pointer value. NULL if
    421        the function is running. */
    422     JSValue *cur_sp;
    423 } JSStackFrame;
    424 
    425 typedef enum {
    426     JS_GC_OBJ_TYPE_JS_OBJECT,
    427     JS_GC_OBJ_TYPE_FUNCTION_BYTECODE,
    428     JS_GC_OBJ_TYPE_SHAPE,
    429     JS_GC_OBJ_TYPE_VAR_REF,
    430     JS_GC_OBJ_TYPE_ASYNC_FUNCTION,
    431     JS_GC_OBJ_TYPE_JS_CONTEXT,
    432     JS_GC_OBJ_TYPE_MODULE,
    433 } JSGCObjectTypeEnum;
    434 
    435 /* header for GC objects. GC objects are C data structures with a
    436    reference count that can reference other GC objects. JS Objects are
    437    a particular type of GC object. */
    438 struct JSGCObjectHeader {
    439     struct list_head link;
    440 };
    441 
    442 typedef enum {
    443     JS_WEAKREF_TYPE_MAP,
    444     JS_WEAKREF_TYPE_WEAKREF,
    445     JS_WEAKREF_TYPE_FINREC,
    446 } JSWeakRefHeaderTypeEnum;
    447 
    448 typedef struct {
    449     struct list_head link;
    450     JSWeakRefHeaderTypeEnum weakref_type;
    451 } JSWeakRefHeader;
    452 
    453 typedef struct JSVarRef {
    454     JSGCObjectHeader header; /* must come first */
    455     uint8_t is_detached;
    456     uint8_t is_lexical; /* only used with global variables */
    457     uint8_t is_const; /* only used with global variables */
    458     JSValue *pvalue; /* pointer to the value, either on the stack or
    459                         to 'value' */
    460     union {
    461         JSValue value; /* used when is_detached = TRUE */
    462         struct {
    463             uint16_t var_ref_idx; /* index in JSStackFrame.var_refs[] */
    464             JSStackFrame *stack_frame;
    465         }; /* used when is_detached = FALSE */
    466     };
    467 } JSVarRef;
    468 
    469 /* bigint */
    470 
    471 #if JS_LIMB_BITS == 32
    472 
    473 typedef int32_t js_slimb_t;
    474 typedef uint32_t js_limb_t;
    475 typedef int64_t js_sdlimb_t;
    476 typedef uint64_t js_dlimb_t;
    477 
    478 #define JS_LIMB_DIGITS 9
    479 
    480 #else
    481 
    482 typedef __int128 int128_t;
    483 typedef unsigned __int128 uint128_t;
    484 typedef int64_t js_slimb_t;
    485 typedef uint64_t js_limb_t;
    486 typedef int128_t js_sdlimb_t;
    487 typedef uint128_t js_dlimb_t;
    488 
    489 #define JS_LIMB_DIGITS 19
    490 
    491 #endif
    492 
    493 typedef struct JSBigInt {
    494     uint32_t len; /* number of limbs, >= 1 */
    495     js_limb_t tab[]; /* two's complement representation, always
    496                         normalized so that 'len' is the minimum
    497                         possible length >= 1 */
    498 } JSBigInt;
    499 
    500 /* this bigint structure can hold a 64 bit integer */
    501 typedef struct {
    502     js_limb_t big_int_buf[sizeof(JSBigInt) / sizeof(js_limb_t)]; /* for JSBigInt */
    503     /* must come just after */
    504     js_limb_t tab[(64 + JS_LIMB_BITS - 1) / JS_LIMB_BITS];
    505 } JSBigIntBuf;
    506     
    507 typedef enum {
    508     JS_AUTOINIT_ID_PROTOTYPE,
    509     JS_AUTOINIT_ID_MODULE_NS,
    510     JS_AUTOINIT_ID_PROP,
    511 } JSAutoInitIDEnum;
    512 
    513 /* must be large enough to have a negligible runtime cost and small
    514    enough to call the interrupt callback often. */
    515 #define JS_INTERRUPT_COUNTER_INIT 10000
    516 
    517 struct JSContext {
    518     JSGCObjectHeader header; /* must come first */
    519     JSRuntime *rt;
    520     struct list_head link;
    521 
    522     uint16_t binary_object_count;
    523     int binary_object_size;
    524     
    525     JSShape *array_shape;   /* initial shape for Array objects */
    526     JSShape *arguments_shape;  /* shape for arguments objects */
    527     JSShape *mapped_arguments_shape;  /* shape for mapped arguments objects */
    528     JSShape *regexp_shape;  /* shape for regexp objects */
    529     JSShape *regexp_result_shape;  /* shape for regexp result objects */
    530 
    531     JSValue *class_proto;
    532     JSValue function_proto;
    533     JSValue function_ctor;
    534     JSValue array_ctor;
    535     JSValue regexp_ctor;
    536     JSValue promise_ctor;
    537     JSValue native_error_proto[JS_NATIVE_ERROR_COUNT];
    538     JSValue iterator_ctor;
    539     JSValue async_iterator_proto;
    540     JSValue array_proto_values;
    541     JSValue throw_type_error;
    542     JSValue eval_obj;
    543 
    544     JSValue global_obj; /* global object */
    545     JSValue global_var_obj; /* contains the global let/const definitions */
    546 
    547     uint64_t random_state;
    548 
    549     /* when the counter reaches zero, JSRutime.interrupt_handler is called */
    550     int interrupt_counter;
    551 
    552     struct list_head loaded_modules; /* list of JSModuleDef.link */
    553 
    554     /* if NULL, RegExp compilation is not supported */
    555     JSValue (*compile_regexp)(JSContext *ctx, JSValueConst pattern,
    556                               JSValueConst flags);
    557     /* if NULL, eval is not supported */
    558     JSValue (*eval_internal)(JSContext *ctx, JSValueConst this_obj,
    559                              const char *input, size_t input_len,
    560                              const char *filename, int flags, int scope_idx);
    561     void *user_opaque;
    562 };
    563 
    564 typedef union JSFloat64Union {
    565     double d;
    566     uint64_t u64;
    567     uint32_t u32[2];
    568 } JSFloat64Union;
    569 
    570 enum {
    571     JS_ATOM_TYPE_STRING = 1,
    572     JS_ATOM_TYPE_GLOBAL_SYMBOL,
    573     JS_ATOM_TYPE_SYMBOL,
    574     JS_ATOM_TYPE_PRIVATE,
    575 };
    576 
    577 typedef enum {
    578     JS_ATOM_KIND_STRING,
    579     JS_ATOM_KIND_SYMBOL,
    580     JS_ATOM_KIND_PRIVATE,
    581 } JSAtomKindEnum;
    582 
    583 #define JS_ATOM_HASH_MASK  ((1 << 30) - 1)
    584 #define JS_ATOM_HASH_PRIVATE JS_ATOM_HASH_MASK
    585 
    586 struct JSString {
    587     uint32_t len : 31;
    588     uint8_t is_wide_char : 1; /* 0 = 8 bits, 1 = 16 bits characters */
    589     /* for JS_ATOM_TYPE_SYMBOL: hash = weakref_count, atom_type = 3,
    590        for JS_ATOM_TYPE_PRIVATE: hash = JS_ATOM_HASH_PRIVATE, atom_type = 3
    591        XXX: could change encoding to have one more bit in hash */
    592     uint32_t hash : 30;
    593     uint8_t atom_type : 2; /* != 0 if atom, JS_ATOM_TYPE_x */
    594     uint32_t hash_next; /* atom_index for JS_ATOM_TYPE_SYMBOL */
    595 #ifdef DUMP_LEAKS
    596     struct list_head link; /* string list */
    597 #endif
    598     union {
    599         uint8_t str8[0]; /* 8 bit strings will get an extra null terminator */
    600         uint16_t str16[0];
    601     } u;
    602 };
    603 
    604 typedef struct JSStringRope {
    605     uint32_t len;
    606     uint8_t is_wide_char; /* 0 = 8 bits, 1 = 16 bits characters */
    607     uint8_t depth; /* max depth of the rope tree */
    608     /* XXX: could reduce memory usage by using a direct pointer with
    609        bit 0 to select rope or string */
    610     JSValue left;
    611     JSValue right; /* might be the empty string */
    612 } JSStringRope;
    613 
    614 typedef enum {
    615     JS_CLOSURE_LOCAL, /* 'var_idx' is the index of a local variable in the parent function */
    616     JS_CLOSURE_ARG, /* 'var_idx' is the index of a argument variable in the parent function */
    617     JS_CLOSURE_REF, /* 'var_idx' is the index of a closure variable in the parent function */
    618     JS_CLOSURE_GLOBAL_REF, /* 'var_idx' in the index of a closure
    619                               variable in the parent function
    620                               referencing a global variable */
    621     JS_CLOSURE_GLOBAL_DECL, /* global variable declaration (eval code only) */
    622     JS_CLOSURE_GLOBAL, /* global variable (eval code only) */
    623     JS_CLOSURE_MODULE_DECL, /* definition of a module variable (eval code only) */
    624     JS_CLOSURE_MODULE_IMPORT, /* definition of a module import (eval code only) */ 
    625 } JSClosureTypeEnum;
    626 
    627 typedef struct JSClosureVar {
    628     JSClosureTypeEnum closure_type : 3;
    629     uint8_t is_lexical : 1; /* lexical variable */
    630     uint8_t is_const : 1; /* const variable (is_lexical = 1 if is_const = 1 */
    631     uint8_t var_kind : 4; /* see JSVarKindEnum */
    632     uint16_t var_idx; /* is_local = TRUE: index to a normal variable of the
    633                     parent function. otherwise: index to a closure
    634                     variable of the parent function */
    635     JSAtom var_name;
    636 } JSClosureVar;
    637 
    638 #define ARG_SCOPE_INDEX 1
    639 #define ARG_SCOPE_END (-2)
    640 
    641 typedef enum {
    642     /* XXX: add more variable kinds here instead of using bit fields */
    643     JS_VAR_NORMAL,
    644     JS_VAR_FUNCTION_DECL, /* lexical var with function declaration */
    645     JS_VAR_NEW_FUNCTION_DECL, /* lexical var with async/generator
    646                                  function declaration */
    647     JS_VAR_CATCH,
    648     JS_VAR_FUNCTION_NAME, /* function expression name */
    649     JS_VAR_PRIVATE_FIELD,
    650     JS_VAR_PRIVATE_METHOD,
    651     JS_VAR_PRIVATE_GETTER,
    652     JS_VAR_PRIVATE_SETTER, /* must come after JS_VAR_PRIVATE_GETTER */
    653     JS_VAR_PRIVATE_GETTER_SETTER, /* must come after JS_VAR_PRIVATE_SETTER */
    654     JS_VAR_GLOBAL_FUNCTION_DECL, /* global function definition, only in JSVarDef */
    655 } JSVarKindEnum;
    656 
    657 typedef struct JSBytecodeVarDef {
    658     JSAtom var_name;
    659     /* index into JSFunctionBytecode.vars of the next variable in the same or
    660        enclosing lexical scope
    661     */
    662     int scope_next; /* XXX: store on 16 bits */
    663     uint8_t is_const : 1;
    664     uint8_t is_lexical : 1;
    665     uint8_t is_captured : 1; /* XXX: could remove and use a var_ref_idx value */
    666     uint8_t has_scope: 1; /* true if JSVarDef.scope_level != 0 */
    667     uint8_t var_kind : 4; /* see JSVarKindEnum */
    668     /* If is_captured = TRUE, provides, the index of the corresponding
    669        JSVarRef on stack. It would be more compact to have a separate
    670        table with the corresponding inverted table but it requires
    671        more modifications in the code. */
    672     uint16_t var_ref_idx;
    673 } JSBytecodeVarDef;
    674 
    675 /* for the encoding of the pc2line table */
    676 #define PC2LINE_BASE     (-1)
    677 #define PC2LINE_RANGE    5
    678 #define PC2LINE_OP_FIRST 1
    679 #define PC2LINE_DIFF_PC_MAX ((255 - PC2LINE_OP_FIRST) / PC2LINE_RANGE)
    680 
    681 typedef enum JSFunctionKindEnum {
    682     JS_FUNC_NORMAL = 0,
    683     JS_FUNC_GENERATOR = (1 << 0),
    684     JS_FUNC_ASYNC = (1 << 1),
    685     JS_FUNC_ASYNC_GENERATOR = (JS_FUNC_GENERATOR | JS_FUNC_ASYNC),
    686 } JSFunctionKindEnum;
    687 
    688 typedef struct JSFunctionBytecode {
    689     JSGCObjectHeader header; /* must come first */
    690     uint8_t js_mode;
    691     uint8_t has_prototype : 1; /* true if a prototype field is necessary */
    692     uint8_t has_simple_parameter_list : 1;
    693     uint8_t is_derived_class_constructor : 1;
    694     /* true if home_object needs to be initialized */
    695     uint8_t need_home_object : 1;
    696     uint8_t func_kind : 2;
    697     uint8_t new_target_allowed : 1;
    698     uint8_t super_call_allowed : 1;
    699     uint8_t super_allowed : 1;
    700     uint8_t arguments_allowed : 1;
    701     uint8_t has_debug : 1;
    702     uint8_t read_only_bytecode : 1;
    703     uint8_t is_direct_or_indirect_eval : 1; /* used by JS_GetScriptOrModuleName() */
    704     /* XXX: 10 bits available */
    705     uint8_t *byte_code_buf; /* (self pointer) */
    706     int byte_code_len;
    707     JSAtom func_name;
    708     JSBytecodeVarDef *vardefs; /* arguments + local variables (arg_count + var_count) (self pointer) */
    709     JSClosureVar *closure_var; /* list of variables in the closure (self pointer) */
    710     uint16_t arg_count;
    711     uint16_t var_count;
    712     uint16_t defined_arg_count; /* for length function property */
    713     uint16_t stack_size; /* maximum stack size */
    714     uint16_t var_ref_count; /* number of local variable references */
    715     JSContext *realm; /* function realm */
    716     JSValue *cpool; /* constant pool (self pointer) */
    717     int cpool_count;
    718     int closure_var_count;
    719     void *perf_trampoline;
    720     struct {
    721         /* debug info, move to separate structure to save memory? */
    722         JSAtom filename;
    723         int source_len; 
    724         int pc2line_len;
    725         uint8_t *pc2line_buf;
    726         char *source;
    727     } debug;
    728 } JSFunctionBytecode;
    729 
    730 typedef struct JSBoundFunction {
    731     JSValue func_obj;
    732     JSValue this_val;
    733     int argc;
    734     JSValue argv[0];
    735 } JSBoundFunction;
    736 
    737 typedef enum JSIteratorKindEnum {
    738     JS_ITERATOR_KIND_KEY,
    739     JS_ITERATOR_KIND_VALUE,
    740     JS_ITERATOR_KIND_KEY_AND_VALUE,
    741 } JSIteratorKindEnum;
    742 
    743 typedef struct JSForInIterator {
    744     JSValue obj;
    745     uint32_t idx;
    746     uint32_t atom_count;
    747     uint8_t in_prototype_chain;
    748     uint8_t is_array;
    749     JSPropertyEnum *tab_atom; /* is_array = FALSE */
    750 } JSForInIterator;
    751 
    752 typedef struct JSRegExp {
    753     JSString *pattern;
    754     JSString *bytecode; /* also contains the flags */
    755 } JSRegExp;
    756 
    757 typedef struct JSProxyData {
    758     JSValue target;
    759     JSValue handler;
    760     uint8_t is_func;
    761     uint8_t is_revoked;
    762 } JSProxyData;
    763 
    764 typedef struct JSArrayBuffer {
    765     int byte_length; /* 0 if detached */
    766     int max_byte_length; /* -1 if not resizable; >= byte_length otherwise */
    767     uint8_t detached;
    768     uint8_t shared; /* if shared, the array buffer cannot be detached */
    769     uint8_t *data; /* NULL if detached */
    770     struct list_head array_list;
    771     void *opaque;
    772     JSFreeArrayBufferDataFunc *free_func;
    773 } JSArrayBuffer;
    774 
    775 typedef struct JSTypedArray {
    776     struct list_head link; /* link to arraybuffer */
    777     JSObject *obj; /* back pointer to the TypedArray/DataView object */
    778     JSObject *buffer; /* based array buffer */
    779     uint32_t offset; /* byte offset in the array buffer */
    780     uint32_t length; /* byte length in the array buffer */
    781     BOOL track_rab; /* auto-track length of backing array buffer */
    782 } JSTypedArray;
    783 
    784 typedef struct JSGlobalObject {
    785     JSValue uninitialized_vars; /* hidden object containing the list of uninitialized variables */
    786 } JSGlobalObject;
    787 
    788 typedef struct JSAsyncFunctionState {
    789     JSGCObjectHeader header;
    790     JSValue this_val; /* 'this' argument */
    791     int argc; /* number of function arguments */
    792     BOOL throw_flag; /* used to throw an exception in JS_CallInternal() */
    793     BOOL is_completed; /* TRUE if the function has returned. The stack
    794                           frame is no longer valid */
    795     JSValue resolving_funcs[2]; /* only used in JS async functions */
    796     JSStackFrame frame;
    797     /* arg_buf, var_buf, stack_buf and var_refs follow */
    798 } JSAsyncFunctionState;
    799 
    800 typedef enum {
    801    /* binary operators */
    802    JS_OVOP_ADD,
    803    JS_OVOP_SUB,
    804    JS_OVOP_MUL,
    805    JS_OVOP_DIV,
    806    JS_OVOP_MOD,
    807    JS_OVOP_POW,
    808    JS_OVOP_OR,
    809    JS_OVOP_AND,
    810    JS_OVOP_XOR,
    811    JS_OVOP_SHL,
    812    JS_OVOP_SAR,
    813    JS_OVOP_SHR,
    814    JS_OVOP_EQ,
    815    JS_OVOP_LESS,
    816 
    817    JS_OVOP_BINARY_COUNT,
    818    /* unary operators */
    819    JS_OVOP_POS = JS_OVOP_BINARY_COUNT,
    820    JS_OVOP_NEG,
    821    JS_OVOP_INC,
    822    JS_OVOP_DEC,
    823    JS_OVOP_NOT,
    824 
    825    JS_OVOP_COUNT,
    826 } JSOverloadableOperatorEnum;
    827 
    828 typedef struct {
    829     uint32_t operator_index;
    830     JSObject *ops[JS_OVOP_BINARY_COUNT]; /* self operators */
    831 } JSBinaryOperatorDefEntry;
    832 
    833 typedef struct {
    834     int count;
    835     JSBinaryOperatorDefEntry *tab;
    836 } JSBinaryOperatorDef;
    837 
    838 typedef struct {
    839     uint32_t operator_counter;
    840     BOOL is_primitive; /* OperatorSet for a primitive type */
    841     /* NULL if no operator is defined */
    842     JSObject *self_ops[JS_OVOP_COUNT]; /* self operators */
    843     JSBinaryOperatorDef left;
    844     JSBinaryOperatorDef right;
    845 } JSOperatorSetData;
    846 
    847 typedef struct JSReqModuleEntry {
    848     JSAtom module_name;
    849     JSModuleDef *module; /* used using resolution */
    850     JSValue attributes; /* JS_UNDEFINED or an object contains the attributes as key/value */
    851 } JSReqModuleEntry;
    852 
    853 typedef enum JSExportTypeEnum {
    854     JS_EXPORT_TYPE_LOCAL,
    855     JS_EXPORT_TYPE_INDIRECT,
    856 } JSExportTypeEnum;
    857 
    858 typedef struct JSExportEntry {
    859     union {
    860         struct {
    861             int var_idx; /* closure variable index */
    862             JSVarRef *var_ref; /* if != NULL, reference to the variable */
    863         } local; /* for local export */
    864         int req_module_idx; /* module for indirect export */
    865     } u;
    866     JSExportTypeEnum export_type;
    867     JSAtom local_name; /* '*' if export ns from. not used for local
    868                           export after compilation */
    869     JSAtom export_name; /* exported variable name */
    870 } JSExportEntry;
    871 
    872 typedef struct JSStarExportEntry {
    873     int req_module_idx; /* in req_module_entries */
    874 } JSStarExportEntry;
    875 
    876 typedef struct JSImportEntry {
    877     int var_idx; /* closure variable index */
    878     BOOL is_star; /* import_name = '*' is a valid import name, so need a flag */
    879     JSAtom import_name;
    880     int req_module_idx; /* in req_module_entries */
    881 } JSImportEntry;
    882 
    883 typedef enum {
    884     JS_MODULE_STATUS_UNLINKED,
    885     JS_MODULE_STATUS_LINKING,
    886     JS_MODULE_STATUS_LINKED,
    887     JS_MODULE_STATUS_EVALUATING,
    888     JS_MODULE_STATUS_EVALUATING_ASYNC,
    889     JS_MODULE_STATUS_EVALUATED,
    890 } JSModuleStatus;
    891 
    892 struct JSModuleDef {
    893     JSGCObjectHeader header; /* must come first */
    894     JSAtom module_name;
    895     struct list_head link;
    896 
    897     JSReqModuleEntry *req_module_entries;
    898     int req_module_entries_count;
    899     int req_module_entries_size;
    900 
    901     JSExportEntry *export_entries;
    902     int export_entries_count;
    903     int export_entries_size;
    904 
    905     JSStarExportEntry *star_export_entries;
    906     int star_export_entries_count;
    907     int star_export_entries_size;
    908 
    909     JSImportEntry *import_entries;
    910     int import_entries_count;
    911     int import_entries_size;
    912 
    913     JSValue module_ns;
    914     JSValue func_obj; /* only used for JS modules */
    915     JSModuleInitFunc *init_func; /* only used for C modules */
    916     BOOL has_tla : 8; /* true if func_obj contains await */
    917     BOOL resolved : 8;
    918     BOOL func_created : 8;
    919     JSModuleStatus status : 8;
    920     /* temp use during js_module_link() & js_module_evaluate() */
    921     int dfs_index, dfs_ancestor_index;
    922     JSModuleDef *stack_prev;
    923     /* temp use during js_module_evaluate() */
    924     JSModuleDef **async_parent_modules;
    925     int async_parent_modules_count;
    926     int async_parent_modules_size;
    927     int pending_async_dependencies;
    928     BOOL async_evaluation; /* true: async_evaluation_timestamp corresponds to [[AsyncEvaluationOrder]] 
    929                               false: [[AsyncEvaluationOrder]] is UNSET or DONE */
    930     int64_t async_evaluation_timestamp;
    931     JSModuleDef *cycle_root;
    932     JSValue promise; /* corresponds to spec field: capability */
    933     JSValue resolving_funcs[2]; /* corresponds to spec field: capability */
    934 
    935     /* true if evaluation yielded an exception. It is saved in
    936        eval_exception */
    937     BOOL eval_has_exception : 8;
    938     JSValue eval_exception;
    939     JSValue meta_obj; /* for import.meta */
    940     JSValue private_value; /* private value for C modules */
    941 };
    942 
    943 typedef struct JSJobEntry {
    944     struct list_head link;
    945     JSContext *realm;
    946     JSJobFunc *job_func;
    947     int argc;
    948     JSValue argv[0];
    949 } JSJobEntry;
    950 
    951 typedef struct JSProperty {
    952     union {
    953         JSValue value;      /* JS_PROP_NORMAL */
    954         struct {            /* JS_PROP_GETSET */
    955             JSObject *getter; /* NULL if undefined */
    956             JSObject *setter; /* NULL if undefined */
    957         } getset;
    958         JSVarRef *var_ref;  /* JS_PROP_VARREF */
    959         struct {            /* JS_PROP_AUTOINIT */
    960             /* in order to use only 2 pointers, we compress the realm
    961                and the init function pointer */
    962             uintptr_t realm_and_id; /* realm and init_id (JS_AUTOINIT_ID_x)
    963                                        in the 2 low bits */
    964             void *opaque;
    965         } init;
    966     } u;
    967 } JSProperty;
    968 
    969 #define JS_PROP_INITIAL_SIZE 2
    970 #define JS_PROP_INITIAL_HASH_SIZE 4 /* must be a power of two */
    971 
    972 typedef struct JSShapeProperty {
    973     uint32_t hash_next : 26; /* 0 if last in list */
    974     uint32_t flags : 6;   /* JS_PROP_XXX */
    975     JSAtom atom; /* JS_ATOM_NULL = free property entry */
    976 } JSShapeProperty;
    977 
    978 struct JSShape {
    979     JSGCObjectHeader header;
    980     /* true if the shape is inserted in the shape hash table. If not,
    981        JSShape.hash is not valid */
    982     uint8_t is_hashed;
    983     uint32_t hash; /* current hash value */
    984     uint32_t prop_hash_mask; /* >= 2 */
    985     int prop_size; /* allocated properties */
    986     int prop_count; /* include deleted properties */
    987     int deleted_prop_count;
    988     JSShape *shape_hash_next; /* in JSRuntime.shape_hash[h] list */
    989     JSObject *proto;
    990     uint32_t hash_table[]; /* prop_hash_mask + 1 elements */
    991     /* followed by JSShapeProperty prop[prop_size]; */
    992 };
    993 
    994 struct JSObject {
    995     JSGCObjectHeader header;
    996     /* TRUE if the array prototype is "normal":
    997        - no small index properties which are get/set or non writable
    998        - its prototype is Object.prototype
    999        - Object.prototype has no small index properties which are get/set or non writable
   1000        - the prototype of Object.prototype is null (always true as it is immutable)
   1001     */
   1002     uint8_t is_std_array_prototype : 1;
   1003     
   1004     uint8_t extensible : 1;
   1005     uint8_t free_mark : 1; /* only used when freeing objects with cycles */
   1006     uint8_t is_exotic : 1; /* TRUE if object has exotic property handlers */
   1007     uint8_t fast_array : 1; /* TRUE if u.array is used for get/put (for JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS, JS_CLASS_MAPPED_ARGUMENTS and typed arrays) */
   1008     uint8_t is_constructor : 1; /* TRUE if object is a constructor function */
   1009     uint8_t has_immutable_prototype : 1; /* cannot modify the prototype */
   1010     uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */
   1011     uint8_t is_HTMLDDA : 1; /* specific annex B IsHtmlDDA behavior */
   1012     uint16_t class_id; /* see JS_CLASS_x */
   1013     /* count the number of weak references to this object. The object
   1014        structure is freed only if header.ref_count = 0 and
   1015        weakref_count = 0 */
   1016     uint32_t weakref_count; 
   1017     JSShape *shape; /* prototype and property names + flag */
   1018     JSProperty *prop; /* array of properties */
   1019     union {
   1020         void *opaque;
   1021         struct JSBoundFunction *bound_function; /* JS_CLASS_BOUND_FUNCTION */
   1022         struct JSCFunctionDataRecord *c_function_data_record; /* JS_CLASS_C_FUNCTION_DATA */
   1023         struct JSForInIterator *for_in_iterator; /* JS_CLASS_FOR_IN_ITERATOR */
   1024         struct JSArrayBuffer *array_buffer; /* JS_CLASS_ARRAY_BUFFER, JS_CLASS_SHARED_ARRAY_BUFFER */
   1025         struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_DATAVIEW */
   1026         struct JSMapState *map_state;   /* JS_CLASS_MAP..JS_CLASS_WEAKSET */
   1027         struct JSMapIteratorData *map_iterator_data; /* JS_CLASS_MAP_ITERATOR, JS_CLASS_SET_ITERATOR */
   1028         struct JSArrayIteratorData *array_iterator_data; /* JS_CLASS_ARRAY_ITERATOR, JS_CLASS_STRING_ITERATOR */
   1029         struct JSRegExpStringIteratorData *regexp_string_iterator_data; /* JS_CLASS_REGEXP_STRING_ITERATOR */
   1030         struct JSGeneratorData *generator_data; /* JS_CLASS_GENERATOR */
   1031         struct JSIteratorConcatData *iterator_concat_data; /* JS_CLASS_ITERATOR_CONCAT */
   1032         struct JSIteratorHelperData *iterator_helper_data; /* JS_CLASS_ITERATOR_HELPER */
   1033         struct JSIteratorWrapData *iterator_wrap_data; /* JS_CLASS_ITERATOR_WRAP */
   1034         struct JSProxyData *proxy_data; /* JS_CLASS_PROXY */
   1035         struct JSPromiseData *promise_data; /* JS_CLASS_PROMISE */
   1036         struct JSPromiseFunctionData *promise_function_data; /* JS_CLASS_PROMISE_RESOLVE_FUNCTION, JS_CLASS_PROMISE_REJECT_FUNCTION */
   1037         struct JSAsyncFunctionState *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */
   1038         struct JSAsyncFromSyncIteratorData *async_from_sync_iterator_data; /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */
   1039         struct JSAsyncGeneratorData *async_generator_data; /* JS_CLASS_ASYNC_GENERATOR */
   1040         struct { /* JS_CLASS_BYTECODE_FUNCTION: 12/24 bytes */
   1041             /* also used by JS_CLASS_GENERATOR_FUNCTION, JS_CLASS_ASYNC_FUNCTION and JS_CLASS_ASYNC_GENERATOR_FUNCTION */
   1042             struct JSFunctionBytecode *function_bytecode;
   1043             JSVarRef **var_refs;
   1044             JSObject *home_object; /* for 'super' access */
   1045         } func;
   1046         struct { /* JS_CLASS_C_FUNCTION: 12/20 bytes */
   1047             JSContext *realm;
   1048             JSCFunctionType c_function;
   1049             uint8_t length;
   1050             uint8_t cproto;
   1051             int16_t magic;
   1052         } cfunc;
   1053         /* array part for fast arrays and typed arrays */
   1054         struct { /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS, JS_CLASS_MAPPED_ARGUMENTS, JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
   1055             union {
   1056                 uint32_t size;          /* JS_CLASS_ARRAY */
   1057                 struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
   1058             } u1;
   1059             union {
   1060                 JSValue *values;        /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */
   1061                 JSVarRef **var_refs;     /* JS_CLASS_MAPPED_ARGUMENTS */
   1062                 void *ptr;              /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
   1063                 int8_t *int8_ptr;       /* JS_CLASS_INT8_ARRAY */
   1064                 uint8_t *uint8_ptr;     /* JS_CLASS_UINT8_ARRAY, JS_CLASS_UINT8C_ARRAY */
   1065                 int16_t *int16_ptr;     /* JS_CLASS_INT16_ARRAY */
   1066                 uint16_t *uint16_ptr;   /* JS_CLASS_UINT16_ARRAY */
   1067                 int32_t *int32_ptr;     /* JS_CLASS_INT32_ARRAY */
   1068                 uint32_t *uint32_ptr;   /* JS_CLASS_UINT32_ARRAY */
   1069                 int64_t *int64_ptr;     /* JS_CLASS_INT64_ARRAY */
   1070                 uint64_t *uint64_ptr;   /* JS_CLASS_UINT64_ARRAY */
   1071                 uint16_t *fp16_ptr;     /* JS_CLASS_FLOAT16_ARRAY */
   1072                 float *float_ptr;       /* JS_CLASS_FLOAT32_ARRAY */
   1073                 double *double_ptr;     /* JS_CLASS_FLOAT64_ARRAY */
   1074             } u;
   1075             uint32_t count; /* <= 2^31-1. 0 for a detached typed array */
   1076         } array;    /* 12/20 bytes */
   1077         JSRegExp regexp;    /* JS_CLASS_REGEXP: 8/16 bytes */
   1078         JSValue object_data;    /* for JS_SetObjectData(): 8/16/16 bytes */
   1079         JSGlobalObject global_object;
   1080     } u;
   1081 };
   1082 
   1083 typedef struct JSMapRecord {
   1084     int ref_count; /* used during enumeration to avoid freeing the record */
   1085     BOOL empty : 8; /* TRUE if the record is deleted */
   1086     struct list_head link;
   1087     struct JSMapRecord *hash_next;
   1088     JSValue key;
   1089     JSValue value;
   1090 } JSMapRecord;
   1091 
   1092 typedef struct JSMapState {
   1093     BOOL is_weak; /* TRUE if WeakSet/WeakMap */
   1094     struct list_head records; /* list of JSMapRecord.link */
   1095     uint32_t record_count;
   1096     JSMapRecord **hash_table;
   1097     int hash_bits;
   1098     uint32_t hash_size; /* = 2 ^ hash_bits */
   1099     uint32_t record_count_threshold; /* count at which a hash table
   1100                                         resize is needed */
   1101     JSWeakRefHeader weakref_header; /* only used if is_weak = TRUE */
   1102 } JSMapState;
   1103 
   1104 enum {
   1105     __JS_ATOM_NULL = JS_ATOM_NULL,
   1106 #define DEF(name, str) JS_ATOM_ ## name,
   1107 #include "quickjs-atom.h"
   1108 #undef DEF
   1109     JS_ATOM_END,
   1110 };
   1111 #define JS_ATOM_LAST_KEYWORD JS_ATOM_super
   1112 #define JS_ATOM_LAST_STRICT_KEYWORD JS_ATOM_yield
   1113 
   1114 static const char js_atom_init[] =
   1115 #define DEF(name, str) str "\0"
   1116 #include "quickjs-atom.h"
   1117 #undef DEF
   1118 ;
   1119 
   1120 typedef enum OPCodeFormat {
   1121 #define FMT(f) OP_FMT_ ## f,
   1122 #define DEF(id, size, n_pop, n_push, f)
   1123 #include "quickjs-opcode.h"
   1124 #undef DEF
   1125 #undef FMT
   1126 } OPCodeFormat;
   1127 
   1128 enum OPCodeEnum {
   1129 #define FMT(f)
   1130 #define DEF(id, size, n_pop, n_push, f) OP_ ## id,
   1131 #define def(id, size, n_pop, n_push, f)
   1132 #include "quickjs-opcode.h"
   1133 #undef def
   1134 #undef DEF
   1135 #undef FMT
   1136     OP_COUNT, /* excluding temporary opcodes */
   1137     /* temporary opcodes : overlap with the short opcodes */
   1138     OP_TEMP_START = OP_nop + 1,
   1139     OP___dummy = OP_TEMP_START - 1,
   1140 #define FMT(f)
   1141 #define DEF(id, size, n_pop, n_push, f)
   1142 #define def(id, size, n_pop, n_push, f) OP_ ## id,
   1143 #include "quickjs-opcode.h"
   1144 #undef def
   1145 #undef DEF
   1146 #undef FMT
   1147     OP_TEMP_END,
   1148 };
   1149 
   1150 static int JS_InitAtoms(JSRuntime *rt);
   1151 static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
   1152                                int atom_type);
   1153 static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p);
   1154 static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b);
   1155 static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
   1156                                   JSValueConst this_obj,
   1157                                   int argc, JSValueConst *argv, int flags);
   1158 static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj,
   1159                                       JSValueConst this_obj,
   1160                                       int argc, JSValueConst *argv, int flags);
   1161 static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
   1162                                JSValueConst this_obj, JSValueConst new_target,
   1163                                int argc, JSValue *argv, int flags);
   1164 static JSValue JS_CallConstructorInternal(JSContext *ctx,
   1165                                           JSValueConst func_obj,
   1166                                           JSValueConst new_target,
   1167                                           int argc, JSValue *argv, int flags);
   1168 static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj,
   1169                            int argc, JSValueConst *argv);
   1170 static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
   1171                              int argc, JSValueConst *argv);
   1172 static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
   1173                                             JSValue val, BOOL is_array_ctor);
   1174 static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
   1175                              JSValueConst val, int flags, int scope_idx);
   1176 JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...);
   1177 static __maybe_unused void JS_DumpAtoms(JSRuntime *rt);
   1178 static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p);
   1179 static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt);
   1180 static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p);
   1181 static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p);
   1182 static __maybe_unused void JS_DumpAtom(JSContext *ctx, const char *str, JSAtom atom);
   1183 static __maybe_unused void JS_DumpValueRT(JSRuntime *rt, const char *str, JSValueConst val);
   1184 static __maybe_unused void JS_DumpValue(JSContext *ctx, const char *str, JSValueConst val);
   1185 static __maybe_unused void JS_DumpShapes(JSRuntime *rt);
   1186 static void js_dump_value_write(void *opaque, const char *buf, size_t len);
   1187 static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
   1188                                  int argc, JSValueConst *argv, int magic);
   1189 static void js_array_finalizer(JSRuntime *rt, JSValue val);
   1190 static void js_array_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
   1191 static void js_mapped_arguments_finalizer(JSRuntime *rt, JSValue val);
   1192 static void js_mapped_arguments_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
   1193 static void js_object_data_finalizer(JSRuntime *rt, JSValue val);
   1194 static void js_object_data_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
   1195 static void js_c_function_finalizer(JSRuntime *rt, JSValue val);
   1196 static void js_c_function_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
   1197 static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val);
   1198 static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
   1199                                 JS_MarkFunc *mark_func);
   1200 static void js_bound_function_finalizer(JSRuntime *rt, JSValue val);
   1201 static void js_bound_function_mark(JSRuntime *rt, JSValueConst val,
   1202                                 JS_MarkFunc *mark_func);
   1203 static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val);
   1204 static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val,
   1205                                 JS_MarkFunc *mark_func);
   1206 static void js_regexp_finalizer(JSRuntime *rt, JSValue val);
   1207 static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val);
   1208 static void js_typed_array_finalizer(JSRuntime *rt, JSValue val);
   1209 static void js_typed_array_mark(JSRuntime *rt, JSValueConst val,
   1210                                 JS_MarkFunc *mark_func);
   1211 static void js_proxy_finalizer(JSRuntime *rt, JSValue val);
   1212 static void js_proxy_mark(JSRuntime *rt, JSValueConst val,
   1213                                 JS_MarkFunc *mark_func);
   1214 static void js_map_finalizer(JSRuntime *rt, JSValue val);
   1215 static void js_map_mark(JSRuntime *rt, JSValueConst val,
   1216                                 JS_MarkFunc *mark_func);
   1217 static void js_map_iterator_finalizer(JSRuntime *rt, JSValue val);
   1218 static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val,
   1219                                 JS_MarkFunc *mark_func);
   1220 static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val);
   1221 static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val,
   1222                                 JS_MarkFunc *mark_func);
   1223 static void js_iterator_concat_finalizer(JSRuntime *rt, JSValue val);
   1224 static void js_iterator_concat_mark(JSRuntime *rt, JSValueConst val,
   1225                                     JS_MarkFunc *mark_func);
   1226 static void js_iterator_helper_finalizer(JSRuntime *rt, JSValue val);
   1227 static void js_iterator_helper_mark(JSRuntime *rt, JSValueConst val,
   1228                                     JS_MarkFunc *mark_func);
   1229 static void js_iterator_wrap_finalizer(JSRuntime *rt, JSValue val);
   1230 static void js_iterator_wrap_mark(JSRuntime *rt, JSValueConst val,
   1231                                   JS_MarkFunc *mark_func);
   1232 static void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val);
   1233 static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val,
   1234                                 JS_MarkFunc *mark_func);
   1235 static void js_generator_finalizer(JSRuntime *rt, JSValue obj);
   1236 static void js_generator_mark(JSRuntime *rt, JSValueConst val,
   1237                                 JS_MarkFunc *mark_func);
   1238 static void js_global_object_finalizer(JSRuntime *rt, JSValue obj);
   1239 static void js_global_object_mark(JSRuntime *rt, JSValueConst val,
   1240                                   JS_MarkFunc *mark_func);
   1241 static void js_promise_finalizer(JSRuntime *rt, JSValue val);
   1242 static void js_promise_mark(JSRuntime *rt, JSValueConst val,
   1243                                 JS_MarkFunc *mark_func);
   1244 static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val);
   1245 static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
   1246                                 JS_MarkFunc *mark_func);
   1247 
   1248 #define HINT_STRING  0
   1249 #define HINT_NUMBER  1
   1250 #define HINT_NONE    2
   1251 #define HINT_FORCE_ORDINARY (1 << 4) // don't try Symbol.toPrimitive
   1252 static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint);
   1253 static JSValue JS_ToStringFree(JSContext *ctx, JSValue val);
   1254 static int JS_ToBoolFree(JSContext *ctx, JSValue val);
   1255 static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val);
   1256 static int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val);
   1257 static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val);
   1258 static JSValue js_new_string8_len(JSContext *ctx, const char *buf, int len);
   1259 static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
   1260                                  JSValueConst flags);
   1261 static JSValue JS_NewRegexp(JSContext *ctx, JSValue pattern, JSValue bc);
   1262 static void gc_decref(JSRuntime *rt);
   1263 static int JS_NewClass1(JSRuntime *rt, JSClassID class_id,
   1264                         const JSClassDef *class_def, JSAtom name);
   1265 
   1266 typedef enum JSStrictEqModeEnum {
   1267     JS_EQ_STRICT,
   1268     JS_EQ_SAME_VALUE,
   1269     JS_EQ_SAME_VALUE_ZERO,
   1270 } JSStrictEqModeEnum;
   1271 
   1272 static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
   1273                           JSStrictEqModeEnum eq_mode);
   1274 static BOOL js_strict_eq(JSContext *ctx, JSValueConst op1, JSValueConst op2);
   1275 static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2);
   1276 static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2);
   1277 static JSValue JS_ToObject(JSContext *ctx, JSValueConst val);
   1278 static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val);
   1279 static JSProperty *add_property(JSContext *ctx,
   1280                                 JSObject *p, JSAtom prop, int prop_flags);
   1281 static void free_property(JSRuntime *rt, JSProperty *pr, int prop_flags);
   1282 static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val);
   1283 JSValue JS_ThrowOutOfMemory(JSContext *ctx);
   1284 static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx);
   1285 
   1286 static int js_resolve_proxy(JSContext *ctx, JSValueConst *pval, int throw_exception);
   1287 static int JS_CreateProperty(JSContext *ctx, JSObject *p,
   1288                              JSAtom prop, JSValueConst val,
   1289                              JSValueConst getter, JSValueConst setter,
   1290                              int flags);
   1291 static int js_string_memcmp(const JSString *p1, int pos1, const JSString *p2,
   1292                             int pos2, int len);
   1293 static JSValue js_array_buffer_constructor3(JSContext *ctx,
   1294                                             JSValueConst new_target,
   1295                                             uint64_t len, uint64_t *max_len,
   1296                                             JSClassID class_id,
   1297                                             uint8_t *buf,
   1298                                             JSFreeArrayBufferDataFunc *free_func,
   1299                                             void *opaque, BOOL alloc_flag);
   1300 static void js_array_buffer_free(JSRuntime *rt, void *opaque, void *ptr);
   1301 static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj);
   1302 static BOOL array_buffer_is_resizable(const JSArrayBuffer *abuf);
   1303 static JSValue js_typed_array_constructor(JSContext *ctx,
   1304                                           JSValueConst this_val,
   1305                                           int argc, JSValueConst *argv,
   1306                                           int classid);
   1307 static JSValue js_typed_array_constructor_ta(JSContext *ctx,
   1308                                              JSValueConst new_target,
   1309                                              JSValueConst src_obj,
   1310                                              int classid, uint32_t len);
   1311 static BOOL typed_array_is_oob(JSObject *p);
   1312 static int js_typed_array_get_length_unsafe(JSContext *ctx, JSValueConst obj);
   1313 static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx);
   1314 static JSValue JS_ThrowTypeErrorArrayBufferOOB(JSContext *ctx);
   1315 static JSVarRef *js_create_var_ref(JSContext *ctx, BOOL is_lexical);
   1316 static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx,
   1317                              BOOL is_arg);
   1318 static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s);
   1319 static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s);
   1320 static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
   1321                                           JSValueConst this_obj,
   1322                                           int argc, JSValueConst *argv,
   1323                                           int flags);
   1324 static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val);
   1325 static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,
   1326                                            JS_MarkFunc *mark_func);
   1327 static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
   1328                                const char *input, size_t input_len,
   1329                                const char *filename, int flags, int scope_idx);
   1330 static void js_free_module_def(JSRuntime *rt, JSModuleDef *m);
   1331 static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
   1332                                JS_MarkFunc *mark_func);
   1333 static JSValue js_import_meta(JSContext *ctx);
   1334 static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier, JSValueConst options);
   1335 static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref);
   1336 static JSValue js_new_promise_capability(JSContext *ctx,
   1337                                          JSValue *resolving_funcs,
   1338                                          JSValueConst ctor);
   1339 static __exception int perform_promise_then(JSContext *ctx,
   1340                                             JSValueConst promise,
   1341                                             JSValueConst *resolve_reject,
   1342                                             JSValueConst *cap_resolving_funcs);
   1343 static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
   1344                                   int argc, JSValueConst *argv, int magic);
   1345 static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val,
   1346                                int argc, JSValueConst *argv);
   1347 static BOOL js_string_eq(JSContext *ctx,
   1348                          const JSString *p1, const JSString *p2);
   1349 static int js_string_compare(JSContext *ctx,
   1350                              const JSString *p1, const JSString *p2);
   1351 static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val);
   1352 static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
   1353                                JSValue prop, JSValue val, int flags);
   1354 static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val);
   1355 static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val);
   1356 static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val);
   1357 static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc,
   1358                                      JSObject *p, JSAtom prop);
   1359 static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc);
   1360 static int JS_AddIntrinsicBasicObjects(JSContext *ctx);
   1361 static void js_free_shape(JSRuntime *rt, JSShape *sh);
   1362 static void js_free_shape_null(JSRuntime *rt, JSShape *sh);
   1363 static int js_shape_prepare_update(JSContext *ctx, JSObject *p,
   1364                                    JSShapeProperty **pprs);
   1365 static int init_shape_hash(JSRuntime *rt);
   1366 static __exception int js_get_length32(JSContext *ctx, uint32_t *pres,
   1367                                        JSValueConst obj);
   1368 static __exception int js_get_length64(JSContext *ctx, int64_t *pres,
   1369                                        JSValueConst obj);
   1370 static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len);
   1371 static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
   1372                                JSValueConst array_arg);
   1373 static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj,
   1374                               JSValue **arrpp, uint32_t *countp);
   1375 static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx,
   1376                                               JSValueConst sync_iter);
   1377 static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val);
   1378 static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val,
   1379                                     JS_MarkFunc *mark_func);
   1380 static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj,
   1381                                        JSValueConst this_val,
   1382                                        int argc, JSValueConst *argv, int flags);
   1383 static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val);
   1384 static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
   1385                           JSGCObjectTypeEnum type);
   1386 static void remove_gc_object(JSGCObjectHeader *h);
   1387 static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
   1388 static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
   1389                                  void *opaque);
   1390 static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,
   1391                                                JSAtom atom, void *opaque);
   1392 static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val,
   1393                                  int argc, JSValueConst *argv, int is_map);
   1394 static void map_delete_weakrefs(JSRuntime *rt, JSWeakRefHeader *wh);
   1395 static void weakref_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh);
   1396 static void finrec_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh);
   1397 static void JS_RunGCInternal(JSRuntime *rt, BOOL remove_weak_objects);
   1398 static JSValue js_array_from_iterator(JSContext *ctx, uint32_t *plen,
   1399                                       JSValueConst obj, JSValueConst method);
   1400 static int js_string_find_invalid_codepoint(JSString *p);
   1401 static JSValue js_regexp_toString(JSContext *ctx, JSValueConst this_val,
   1402                                   int argc, JSValueConst *argv);
   1403 static JSValue get_date_string(JSContext *ctx, JSValueConst this_val,
   1404                                int argc, JSValueConst *argv, int magic);
   1405 static JSValue js_error_toString(JSContext *ctx, JSValueConst this_val,
   1406                                  int argc, JSValueConst *argv);
   1407 static JSVarRef *js_global_object_find_uninitialized_var(JSContext *ctx, JSObject *p,
   1408                                                          JSAtom atom, BOOL is_lexical);
   1409 static int typed_array_init(JSContext *ctx, JSValueConst obj,
   1410                             JSValue buffer, uint64_t offset, uint64_t len,
   1411                             BOOL track_rab);
   1412 
   1413 
   1414 static const JSClassExoticMethods js_arguments_exotic_methods;
   1415 static const JSClassExoticMethods js_string_exotic_methods;
   1416 static const JSClassExoticMethods js_proxy_exotic_methods;
   1417 static const JSClassExoticMethods js_module_ns_exotic_methods;
   1418 static JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT;
   1419 
   1420 /* JS malloc */
   1421 
   1422 /* max overhead for size >= 64: 12.5% */
   1423 static const uint16_t js_malloc_block_sizes[JS_MALLOC_BLOCK_SIZE_COUNT] = {
   1424     16,
   1425     24,
   1426     32,
   1427     40,
   1428     48,
   1429     56,
   1430     64,
   1431     72,
   1432     80,
   1433     88,
   1434     96,
   1435     104,
   1436     112,
   1437     120,
   1438     128,
   1439     144,
   1440     160,
   1441     176,
   1442     192,
   1443     208,
   1444     224,
   1445     240,
   1446     256,
   1447     288,
   1448     320,
   1449     352,
   1450     384,
   1451     416,
   1452     448,
   1453     480,
   1454     512,
   1455 };
   1456 
   1457 static int get_block_size_index(size_t size)
   1458 {
   1459     if (size <= 16) {
   1460         return 0;
   1461     } else if (size <= 128) {
   1462         return (size + 7) / 8 - 2;
   1463     } else if (size <= 256) {
   1464         return (size + 15) / 16 + 6;
   1465     } else if (size <= 512) {
   1466         return (size + 31) / 32 + 14;
   1467     } else {
   1468         return JS_MALLOC_BLOCK_SIZE_COUNT;
   1469     }
   1470 }
   1471 
   1472 static JSMallocBlockHeader *get_zero_size_block(JSMallocContext *s)
   1473 {
   1474     return (JSMallocBlockHeader *)s->zero_size_block;
   1475 }
   1476 
   1477 static void js_malloc_init(JSMallocContext *s)
   1478 {
   1479     int i;
   1480     memset(s, 0, sizeof(*s));
   1481     get_zero_size_block(s)->u.block_idx = FREE_NIL;
   1482     for(i = 0; i < JS_MALLOC_BLOCK_SIZE_COUNT; i++) {
   1483         init_list_head(&s->arena_list[i]);
   1484         init_list_head(&s->free_arena_list[i]);
   1485     }
   1486 #ifdef JS_MALLOC_USE_ITER
   1487     init_list_head(&s->large_block_list);
   1488 #endif
   1489 }
   1490 
   1491 static void *get_arena_block(JSMallocArena *ar, unsigned int idx, unsigned int block_size)
   1492 {
   1493     return ar->blocks + idx * block_size;
   1494 }
   1495 
   1496 static inline JSMallocBlockHeader *js_rc(void *ptr)
   1497 {
   1498     return container_of(ptr, JSMallocBlockHeader, user_data);
   1499 }
   1500 
   1501 static no_inline JSMallocArena *js_malloc_new_arena(JSMallocContext *s, int block_size_idx)
   1502 {
   1503     JSMallocBlockHeader *b;
   1504     JSMallocArena *ar;
   1505     int n_blocks, block_size, i;
   1506 
   1507     block_size = js_malloc_block_sizes[block_size_idx];
   1508     n_blocks = (JS_MALLOC_ARENA_SIZE - sizeof(JSMallocArena)) / block_size;
   1509     ar = s->mf.js_malloc(&s->malloc_state, sizeof(JSMallocArena) + n_blocks * block_size);
   1510     if (!ar)
   1511         return NULL;
   1512 
   1513     ar->block_size_idx = block_size_idx;
   1514     ar->n_blocks = n_blocks;
   1515     ar->n_used_blocks = 0;
   1516     ar->first_free_block = 0;
   1517 #ifdef JS_MALLOC_USE_ITER
   1518     {
   1519         int n_bitmap_words = (n_blocks + 31) / 32;
   1520         for(i = 0; i < n_bitmap_words; i++)
   1521             ar->bitmap[i] = 0;
   1522     }
   1523 #endif
   1524     for(i = 0; i < n_blocks - 1; i++) {
   1525         b = get_arena_block(ar, i, block_size);
   1526         b->u.free_next = i + 1;
   1527         b->block_size_idx = block_size_idx;
   1528     }
   1529     b = get_arena_block(ar, n_blocks - 1, block_size);
   1530     b->u.free_next = FREE_NIL;
   1531     b->block_size_idx = block_size_idx;
   1532     
   1533     /* add to the head */
   1534     list_add(&ar->link, &s->arena_list[block_size_idx]);
   1535     list_add(&ar->free_link, &s->free_arena_list[block_size_idx]);
   1536     return ar;
   1537 }
   1538 
   1539 static no_inline void *js_malloc_large(JSMallocContext *s, size_t size)
   1540 {
   1541     JSMallocLargeBlockHeader *b;
   1542     b = s->mf.js_malloc(&s->malloc_state, sizeof(JSMallocLargeBlockHeader) + size);
   1543     if (!b)
   1544         return NULL;
   1545     b->header.u.block_idx = FREE_NIL;
   1546     b->header.block_size_idx = 0xff; /* fail safe */
   1547 #ifdef JS_MALLOC_USE_ITER
   1548     list_add_tail(&b->link, &s->large_block_list);
   1549 #endif
   1550     return b->header.user_data;
   1551 }
   1552 
   1553 static void *__js_malloc(JSMallocContext *s, size_t size)
   1554 {
   1555     size_t total_size;
   1556     if (unlikely(size == 0)) {
   1557         JSMallocBlockHeader *b = get_zero_size_block(s);
   1558         return b->user_data;
   1559     } else {
   1560         total_size = ((size + JS_MALLOC_ALIGN - 1) & ~(JS_MALLOC_ALIGN - 1)) +
   1561             sizeof(JSMallocBlockHeader);
   1562         if (!JS_MALLOC_LARGE_BLOCKS_ONLY &&
   1563             total_size <= JS_MALLOC_MAX_SMALL_SIZE) {
   1564             int block_size_idx;
   1565             unsigned int block_idx, block_size;
   1566             JSMallocBlockHeader *b;
   1567             JSMallocArena *ar;
   1568             struct list_head *el, *head;
   1569             
   1570             block_size_idx = get_block_size_index(total_size);
   1571             block_size = js_malloc_block_sizes[block_size_idx];
   1572             head = &s->free_arena_list[block_size_idx];
   1573             el = head->next;
   1574             if (unlikely(el == head)) {
   1575                 ar = js_malloc_new_arena(s, block_size_idx);
   1576                 if (!ar)
   1577                     return NULL;
   1578             } else {
   1579                 ar = list_entry(el, JSMallocArena, free_link);
   1580             }
   1581             block_idx = ar->first_free_block;
   1582             b = get_arena_block(ar, ar->first_free_block, block_size);
   1583             ar->first_free_block = b->u.free_next;
   1584             b->u.block_idx = block_idx;
   1585             ar->n_used_blocks++;
   1586             if (unlikely(ar->n_used_blocks == ar->n_blocks)) {
   1587                 list_del(&ar->free_link);
   1588             }
   1589 #ifdef JS_MALLOC_USE_ITER
   1590             ar->bitmap[block_idx / 32] |= 1 << (block_idx % 32);
   1591 #endif
   1592             return b->user_data;
   1593         } else {
   1594             return js_malloc_large(s, size);
   1595         }
   1596     }
   1597 }
   1598 
   1599 static void __js_free(JSMallocContext *s, void *ptr)
   1600 {
   1601     JSMallocBlockHeader *b;
   1602 
   1603     if (!ptr)
   1604         return;
   1605     b = container_of(ptr, JSMallocBlockHeader, user_data);
   1606     if (unlikely(b->u.block_idx == FREE_NIL)) {
   1607         /* large or zero size block */
   1608         if (b == get_zero_size_block(s)) {
   1609             /* nothing to do */
   1610         } else {
   1611             JSMallocLargeBlockHeader *lb = container_of(ptr, JSMallocLargeBlockHeader, header.user_data);
   1612 #ifdef JS_MALLOC_USE_ITER
   1613             list_del(&lb->link);
   1614 #endif
   1615             s->mf.js_free(&s->malloc_state, lb);
   1616         }
   1617     } else {
   1618         unsigned int block_idx = b->u.block_idx;
   1619         unsigned int block_size_idx = b->block_size_idx;
   1620         unsigned int block_size = js_malloc_block_sizes[block_size_idx];
   1621         JSMallocArena *ar = (JSMallocArena *)((uint8_t *)b - block_size * block_idx - sizeof(JSMallocArena));
   1622         b->u.free_next = ar->first_free_block;
   1623         ar->first_free_block = block_idx;
   1624 #ifdef JS_MALLOC_USE_ITER
   1625         ar->bitmap[block_idx / 32] &= ~(1 << (block_idx % 32));
   1626 #endif
   1627         /* add back to the free list if needed */
   1628         if (unlikely(ar->n_used_blocks == ar->n_blocks)) {
   1629             list_add(&ar->free_link, &s->free_arena_list[block_size_idx]);
   1630         }
   1631         ar->n_used_blocks--;
   1632         if (unlikely(ar->n_used_blocks == 0)) {
   1633             list_del(&ar->link);
   1634             list_del(&ar->free_link);
   1635             s->mf.js_free(&s->malloc_state, ar);
   1636         }
   1637     }
   1638 }
   1639 
   1640 static void *__js_realloc(JSMallocContext *s, void *ptr, size_t size)
   1641 {
   1642     JSMallocBlockHeader *b;
   1643     if (ptr == NULL) {
   1644         return __js_malloc(s, size);
   1645     } else if (size == 0) {
   1646         __js_free(s, ptr);
   1647         return NULL;
   1648     }
   1649     b = container_of(ptr, JSMallocBlockHeader, user_data);
   1650     if (b->u.block_idx == FREE_NIL) {
   1651         if (b == get_zero_size_block(s)) {
   1652             return __js_malloc(s, size);
   1653         } else {
   1654             JSMallocLargeBlockHeader *lb, *new_lb;
   1655             lb = container_of(ptr, JSMallocLargeBlockHeader, header.user_data);
   1656 #ifdef JS_MALLOC_USE_ITER
   1657             list_del(&lb->link);
   1658 #endif
   1659             new_lb = s->mf.js_realloc(&s->malloc_state, lb, sizeof(JSMallocLargeBlockHeader) + size);
   1660             if (!new_lb) {
   1661 #ifdef JS_MALLOC_USE_ITER
   1662                 /* add again in the list */
   1663                 list_add_tail(&lb->link, &s->large_block_list);
   1664 #endif
   1665                 return NULL;
   1666             }
   1667             new_lb->header.u.block_idx = FREE_NIL;
   1668             new_lb->header.block_size_idx = 0xff; /* fail safe */
   1669 #ifdef JS_MALLOC_USE_ITER
   1670             list_add_tail(&new_lb->link, &s->large_block_list);
   1671 #endif
   1672             return new_lb->header.user_data;
   1673         }
   1674     } else {
   1675         unsigned int block_size_idx = b->block_size_idx;
   1676         size_t block_size = js_malloc_block_sizes[block_size_idx];
   1677         size_t total_size, old_size;
   1678         void *new_ptr;
   1679         JSMallocBlockHeader *new_b;
   1680 
   1681         total_size = ((size + JS_MALLOC_ALIGN - 1) & ~(JS_MALLOC_ALIGN - 1)) +
   1682             sizeof(JSMallocBlockHeader);
   1683         if (total_size <= block_size)
   1684             return ptr;
   1685         new_ptr = __js_malloc(s, size);
   1686         if (!new_ptr)
   1687             return NULL;
   1688         new_b = container_of(new_ptr, JSMallocBlockHeader, user_data);
   1689         /* copy the GC data */
   1690         new_b->gc_obj_type = b->gc_obj_type;
   1691         new_b->mark = b->mark;
   1692         new_b->ref_count = b->ref_count;
   1693         /* copy the data */
   1694         old_size = block_size - sizeof(JSMallocBlockHeader);
   1695         if (size > old_size)
   1696             size = old_size;
   1697         memcpy(new_ptr, ptr, size);
   1698         __js_free(s, ptr);
   1699         return new_ptr;
   1700     }
   1701 }
   1702 
   1703 static size_t __js_malloc_usable_size(JSMallocContext *s, const char *ptr)
   1704 {
   1705     JSMallocBlockHeader *b;
   1706     if (!ptr)
   1707         return 0;
   1708     b = container_of(ptr, JSMallocBlockHeader, user_data);
   1709     if (b->u.block_idx == FREE_NIL) {
   1710         if (b == get_zero_size_block(s)) {
   1711             return 0;
   1712         } else {
   1713             JSMallocLargeBlockHeader *lb;
   1714             size_t size;
   1715             lb = container_of(ptr, JSMallocLargeBlockHeader, header.user_data);
   1716             if (s->mf.js_malloc_usable_size) {
   1717                 size = s->mf.js_malloc_usable_size(lb);
   1718                 if (size != 0)
   1719                     size -= sizeof(JSMallocLargeBlockHeader);
   1720                 return size;
   1721             } else {
   1722                 return 0;
   1723             }
   1724         }
   1725     } else {
   1726         size_t block_size = js_malloc_block_sizes[b->block_size_idx];
   1727         return block_size - sizeof(*b);
   1728     }
   1729 }
   1730 
   1731 static __maybe_unused void js_malloc_dump_arenas(JSMallocContext *s)
   1732 {
   1733     struct list_head *el;
   1734     int block_size_idx;
   1735 
   1736     printf("%20s %10s %10s\n", "PTR", "BLK_SIZE", "ALLOC");
   1737     for(block_size_idx = 0; block_size_idx < JS_MALLOC_BLOCK_SIZE_COUNT; block_size_idx++) {
   1738         int block_size = js_malloc_block_sizes[block_size_idx];
   1739         list_for_each(el, &s->arena_list[block_size_idx]) {
   1740             JSMallocArena *ar = list_entry(el, JSMallocArena, link);
   1741             printf("%20p %10u %9.1f%%\n",
   1742                    ar, block_size,
   1743                    (double)ar->n_used_blocks / ar->n_blocks * 100);
   1744         }
   1745     }
   1746 }
   1747 
   1748 #ifdef JS_MALLOC_USE_ITER
   1749 typedef void JSMallocIterFunc(void *opaque, void *ptr);
   1750 
   1751 /* iterate thru allocated blocks. The allocated block list should not
   1752    be modified while iterating. */
   1753 static __maybe_unused void js_malloc_iter(JSMallocContext *s, JSMallocIterFunc *iter_func, void *iter_opaque)
   1754 {
   1755     struct list_head *el;
   1756     int block_size_idx;
   1757     int i, j, n_words;
   1758     uint32_t bmp;
   1759     
   1760     for(block_size_idx = 0; block_size_idx < JS_MALLOC_BLOCK_SIZE_COUNT; block_size_idx++) {
   1761         unsigned int block_size = js_malloc_block_sizes[block_size_idx];
   1762         list_for_each(el, &s->arena_list[block_size_idx]) {
   1763             JSMallocArena *ar = list_entry(el, JSMallocArena, link);
   1764             n_words = (ar->n_blocks + 31) / 32;
   1765             for(i = 0; i < n_words; i++) {
   1766                 bmp = ar->bitmap[i];
   1767                 while (bmp != 0) {
   1768                     j = ctz32(bmp);
   1769                     bmp &= ~(1 << j);
   1770                     iter_func(iter_opaque, get_arena_block(ar, i * 32+ j, block_size));
   1771                 }
   1772             }
   1773         }
   1774     }
   1775     list_for_each(el, &s->large_block_list) {
   1776         JSMallocLargeBlockHeader *lb = list_entry(el, JSMallocLargeBlockHeader, link);
   1777         iter_func(iter_opaque, lb->header.user_data);
   1778     }
   1779 }
   1780 #endif
   1781 
   1782 /* end JS malloc */
   1783 
   1784 static void js_trigger_gc(JSRuntime *rt, size_t size)
   1785 {
   1786     BOOL force_gc;
   1787 #ifdef FORCE_GC_AT_MALLOC
   1788     force_gc = TRUE;
   1789 #else
   1790     force_gc = ((rt->malloc_ctx.malloc_state.malloc_size + size) >
   1791                 rt->malloc_gc_threshold);
   1792 #endif
   1793     if (force_gc) {
   1794 #ifdef DUMP_GC
   1795         printf("GC: size=%" PRIu64 "\n",
   1796                (uint64_t)rt->malloc_ctx.malloc_state.malloc_size);
   1797 #endif
   1798         JS_RunGC(rt);
   1799         rt->malloc_gc_threshold = rt->malloc_ctx.malloc_state.malloc_size +
   1800             (rt->malloc_ctx.malloc_state.malloc_size >> 1);
   1801     }
   1802 }
   1803 
   1804 void *js_malloc_rt(JSRuntime *rt, size_t size)
   1805 {
   1806     return __js_malloc(&rt->malloc_ctx, size);
   1807 }
   1808 
   1809 void js_free_rt(JSRuntime *rt, void *ptr)
   1810 {
   1811     __js_free(&rt->malloc_ctx, ptr);
   1812 }
   1813 
   1814 void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size)
   1815 {
   1816     return __js_realloc(&rt->malloc_ctx, ptr, size);
   1817 }
   1818 
   1819 size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr)
   1820 {
   1821     return __js_malloc_usable_size(&rt->malloc_ctx, ptr);
   1822 }
   1823 
   1824 void *js_mallocz_rt(JSRuntime *rt, size_t size)
   1825 {
   1826     void *ptr;
   1827     ptr = js_malloc_rt(rt, size);
   1828     if (unlikely(!ptr))
   1829         return NULL;
   1830     return memset(ptr, 0, size);
   1831 }
   1832 
   1833 /* Throw out of memory in case of error */
   1834 void *js_malloc(JSContext *ctx, size_t size)
   1835 {
   1836     void *ptr;
   1837     ptr = js_malloc_rt(ctx->rt, size);
   1838     if (unlikely(!ptr)) {
   1839         JS_ThrowOutOfMemory(ctx);
   1840         return NULL;
   1841     }
   1842     return ptr;
   1843 }
   1844 
   1845 /* Throw out of memory in case of error */
   1846 void *js_mallocz(JSContext *ctx, size_t size)
   1847 {
   1848     void *ptr;
   1849     ptr = js_mallocz_rt(ctx->rt, size);
   1850     if (unlikely(!ptr)) {
   1851         JS_ThrowOutOfMemory(ctx);
   1852         return NULL;
   1853     }
   1854     return ptr;
   1855 }
   1856 
   1857 void js_free(JSContext *ctx, void *ptr)
   1858 {
   1859     js_free_rt(ctx->rt, ptr);
   1860 }
   1861 
   1862 /* Throw out of memory in case of error */
   1863 void *js_realloc(JSContext *ctx, void *ptr, size_t size)
   1864 {
   1865     void *ret;
   1866     ret = js_realloc_rt(ctx->rt, ptr, size);
   1867     if (unlikely(!ret && size != 0)) {
   1868         JS_ThrowOutOfMemory(ctx);
   1869         return NULL;
   1870     }
   1871     return ret;
   1872 }
   1873 
   1874 /* store extra allocated size in *pslack if successful */
   1875 void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack)
   1876 {
   1877     void *ret;
   1878     ret = js_realloc_rt(ctx->rt, ptr, size);
   1879     if (unlikely(!ret && size != 0)) {
   1880         JS_ThrowOutOfMemory(ctx);
   1881         return NULL;
   1882     }
   1883     if (pslack) {
   1884         size_t new_size = js_malloc_usable_size_rt(ctx->rt, ret);
   1885         *pslack = (new_size > size) ? new_size - size : 0;
   1886     }
   1887     return ret;
   1888 }
   1889 
   1890 size_t js_malloc_usable_size(JSContext *ctx, const void *ptr)
   1891 {
   1892     return js_malloc_usable_size_rt(ctx->rt, ptr);
   1893 }
   1894 
   1895 /* Throw out of memory exception in case of error */
   1896 char *js_strndup(JSContext *ctx, const char *s, size_t n)
   1897 {
   1898     char *ptr;
   1899     ptr = js_malloc(ctx, n + 1);
   1900     if (ptr) {
   1901         memcpy(ptr, s, n);
   1902         ptr[n] = '\0';
   1903     }
   1904     return ptr;
   1905 }
   1906 
   1907 char *js_strdup(JSContext *ctx, const char *str)
   1908 {
   1909     return js_strndup(ctx, str, strlen(str));
   1910 }
   1911 
   1912 static no_inline int js_realloc_array(JSContext *ctx, void **parray,
   1913                                       int elem_size, int *psize, int req_size)
   1914 {
   1915     int new_size;
   1916     size_t slack;
   1917     void *new_array;
   1918     /* XXX: potential arithmetic overflow */
   1919     new_size = max_int(req_size, *psize * 3 / 2);
   1920     new_array = js_realloc2(ctx, *parray, new_size * elem_size, &slack);
   1921     if (!new_array)
   1922         return -1;
   1923     new_size += slack / elem_size;
   1924     *psize = new_size;
   1925     *parray = new_array;
   1926     return 0;
   1927 }
   1928 
   1929 /* resize the array and update its size if req_size > *psize */
   1930 static inline int js_resize_array(JSContext *ctx, void **parray, int elem_size,
   1931                                   int *psize, int req_size)
   1932 {
   1933     if (unlikely(req_size > *psize))
   1934         return js_realloc_array(ctx, parray, elem_size, psize, req_size);
   1935     else
   1936         return 0;
   1937 }
   1938 
   1939 static void *js_realloc_rt_opaque(void *opaque, void *ptr, size_t size)
   1940 {
   1941     return js_realloc_rt(opaque, ptr, size);
   1942 }
   1943 
   1944 static inline void js_dbuf_init(JSContext *ctx, DynBuf *s)
   1945 {
   1946     dbuf_init2(s, ctx->rt, js_realloc_rt_opaque);
   1947 }
   1948 
   1949 static void *js_realloc_bytecode_rt(void *opaque, void *ptr, size_t size)
   1950 {
   1951     JSRuntime *rt = opaque;
   1952     if (size > (INT32_MAX / 2)) {
   1953         /* the bytecode cannot be larger than 2G. Leave some slack to 
   1954            avoid some overflows. */
   1955         return NULL;
   1956     } else {
   1957         return js_realloc_rt(rt, ptr, size);
   1958     }
   1959 }
   1960 
   1961 static inline void js_dbuf_bytecode_init(JSContext *ctx, DynBuf *s)
   1962 {
   1963     dbuf_init2(s, ctx->rt, js_realloc_bytecode_rt);
   1964 }
   1965 
   1966 static inline int is_digit(int c) {
   1967     return c >= '0' && c <= '9';
   1968 }
   1969 
   1970 static inline int string_get(const JSString *p, int idx) {
   1971     return p->is_wide_char ? p->u.str16[idx] : p->u.str8[idx];
   1972 }
   1973 
   1974 typedef struct JSClassShortDef {
   1975     JSAtom class_name;
   1976     JSClassFinalizer *finalizer;
   1977     JSClassGCMark *gc_mark;
   1978 } JSClassShortDef;
   1979 
   1980 static JSClassShortDef const js_std_class_def[] = {
   1981     { JS_ATOM_Object, NULL, NULL },                             /* JS_CLASS_OBJECT */
   1982     { JS_ATOM_Array, js_array_finalizer, js_array_mark },       /* JS_CLASS_ARRAY */
   1983     { JS_ATOM_Error, NULL, NULL }, /* JS_CLASS_ERROR */
   1984     { JS_ATOM_Number, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_NUMBER */
   1985     { JS_ATOM_String, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_STRING */
   1986     { JS_ATOM_Boolean, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BOOLEAN */
   1987     { JS_ATOM_Symbol, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_SYMBOL */
   1988     { JS_ATOM_Arguments, js_array_finalizer, js_array_mark },   /* JS_CLASS_ARGUMENTS */
   1989     { JS_ATOM_Arguments, js_mapped_arguments_finalizer, js_mapped_arguments_mark }, /* JS_CLASS_MAPPED_ARGUMENTS */
   1990     { JS_ATOM_Date, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_DATE */
   1991     { JS_ATOM_Object, NULL, NULL },                             /* JS_CLASS_MODULE_NS */
   1992     { JS_ATOM_Function, js_c_function_finalizer, js_c_function_mark }, /* JS_CLASS_C_FUNCTION */
   1993     { JS_ATOM_Function, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_BYTECODE_FUNCTION */
   1994     { JS_ATOM_Function, js_bound_function_finalizer, js_bound_function_mark }, /* JS_CLASS_BOUND_FUNCTION */
   1995     { JS_ATOM_Function, js_c_function_data_finalizer, js_c_function_data_mark }, /* JS_CLASS_C_FUNCTION_DATA */
   1996     { JS_ATOM_GeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_GENERATOR_FUNCTION */
   1997     { JS_ATOM_ForInIterator, js_for_in_iterator_finalizer, js_for_in_iterator_mark },      /* JS_CLASS_FOR_IN_ITERATOR */
   1998     { JS_ATOM_RegExp, js_regexp_finalizer, NULL },                              /* JS_CLASS_REGEXP */
   1999     { JS_ATOM_ArrayBuffer, js_array_buffer_finalizer, NULL },                   /* JS_CLASS_ARRAY_BUFFER */
   2000     { JS_ATOM_SharedArrayBuffer, js_array_buffer_finalizer, NULL },             /* JS_CLASS_SHARED_ARRAY_BUFFER */
   2001     { JS_ATOM_Uint8ClampedArray, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT8C_ARRAY */
   2002     { JS_ATOM_Int8Array, js_typed_array_finalizer, js_typed_array_mark },       /* JS_CLASS_INT8_ARRAY */
   2003     { JS_ATOM_Uint8Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_UINT8_ARRAY */
   2004     { JS_ATOM_Int16Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_INT16_ARRAY */
   2005     { JS_ATOM_Uint16Array, js_typed_array_finalizer, js_typed_array_mark },     /* JS_CLASS_UINT16_ARRAY */
   2006     { JS_ATOM_Int32Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_INT32_ARRAY */
   2007     { JS_ATOM_Uint32Array, js_typed_array_finalizer, js_typed_array_mark },     /* JS_CLASS_UINT32_ARRAY */
   2008     { JS_ATOM_BigInt64Array, js_typed_array_finalizer, js_typed_array_mark },   /* JS_CLASS_BIG_INT64_ARRAY */
   2009     { JS_ATOM_BigUint64Array, js_typed_array_finalizer, js_typed_array_mark },  /* JS_CLASS_BIG_UINT64_ARRAY */
   2010     { JS_ATOM_Float16Array, js_typed_array_finalizer, js_typed_array_mark },    /* JS_CLASS_FLOAT16_ARRAY */
   2011     { JS_ATOM_Float32Array, js_typed_array_finalizer, js_typed_array_mark },    /* JS_CLASS_FLOAT32_ARRAY */
   2012     { JS_ATOM_Float64Array, js_typed_array_finalizer, js_typed_array_mark },    /* JS_CLASS_FLOAT64_ARRAY */
   2013     { JS_ATOM_DataView, js_typed_array_finalizer, js_typed_array_mark },        /* JS_CLASS_DATAVIEW */
   2014     { JS_ATOM_BigInt, js_object_data_finalizer, js_object_data_mark },      /* JS_CLASS_BIG_INT */
   2015     { JS_ATOM_Map, js_map_finalizer, js_map_mark },             /* JS_CLASS_MAP */
   2016     { JS_ATOM_Set, js_map_finalizer, js_map_mark },             /* JS_CLASS_SET */
   2017     { JS_ATOM_WeakMap, js_map_finalizer, js_map_mark },         /* JS_CLASS_WEAKMAP */
   2018     { JS_ATOM_WeakSet, js_map_finalizer, js_map_mark },         /* JS_CLASS_WEAKSET */
   2019     { JS_ATOM_Iterator, NULL, NULL },                           /* JS_CLASS_ITERATOR */
   2020     { JS_ATOM_IteratorConcat, js_iterator_concat_finalizer, js_iterator_concat_mark }, /* JS_CLASS_ITERATOR_CONCAT */
   2021     { JS_ATOM_IteratorHelper, js_iterator_helper_finalizer, js_iterator_helper_mark }, /* JS_CLASS_ITERATOR_HELPER */
   2022     { JS_ATOM_IteratorWrap, js_iterator_wrap_finalizer, js_iterator_wrap_mark }, /* JS_CLASS_ITERATOR_WRAP */
   2023     { JS_ATOM_Map_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_MAP_ITERATOR */
   2024     { JS_ATOM_Set_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_SET_ITERATOR */
   2025     { JS_ATOM_Array_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_ARRAY_ITERATOR */
   2026     { JS_ATOM_String_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_STRING_ITERATOR */
   2027     { JS_ATOM_RegExp_String_Iterator, js_regexp_string_iterator_finalizer, js_regexp_string_iterator_mark }, /* JS_CLASS_REGEXP_STRING_ITERATOR */
   2028     { JS_ATOM_Generator, js_generator_finalizer, js_generator_mark }, /* JS_CLASS_GENERATOR */
   2029     { JS_ATOM_Object, js_global_object_finalizer, js_global_object_mark }, /* JS_CLASS_GLOBAL_OBJECT */
   2030     { JS_ATOM_Object, NULL, NULL }, /* JS_CLASS_RAWJSON */
   2031 };
   2032 
   2033 static int init_class_range(JSRuntime *rt, JSClassShortDef const *tab,
   2034                             int start, int count)
   2035 {
   2036     JSClassDef cm_s, *cm = &cm_s;
   2037     int i, class_id;
   2038 
   2039     for(i = 0; i < count; i++) {
   2040         class_id = i + start;
   2041         memset(cm, 0, sizeof(*cm));
   2042         cm->finalizer = tab[i].finalizer;
   2043         cm->gc_mark = tab[i].gc_mark;
   2044         if (JS_NewClass1(rt, class_id, cm, tab[i].class_name) < 0)
   2045             return -1;
   2046     }
   2047     return 0;
   2048 }
   2049 
   2050 #if !defined(CONFIG_STACK_CHECK)
   2051 /* no stack limitation */
   2052 static inline uintptr_t js_get_stack_pointer(void)
   2053 {
   2054     return 0;
   2055 }
   2056 
   2057 static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
   2058 {
   2059     return FALSE;
   2060 }
   2061 #else
   2062 /* Note: OS and CPU dependent */
   2063 static inline uintptr_t js_get_stack_pointer(void)
   2064 {
   2065     return (uintptr_t)__builtin_frame_address(0);
   2066 }
   2067 
   2068 static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
   2069 {
   2070     uintptr_t sp;
   2071     sp = js_get_stack_pointer() - alloca_size;
   2072     return unlikely(sp < rt->stack_limit);
   2073 }
   2074 #endif
   2075 
   2076 JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
   2077 {
   2078     JSRuntime *rt;
   2079     JSMallocState ms;
   2080 
   2081     memset(&ms, 0, sizeof(ms));
   2082     ms.opaque = opaque;
   2083     ms.malloc_limit = -1;
   2084 
   2085     rt = mf->js_malloc(&ms, sizeof(JSRuntime));
   2086     if (!rt)
   2087         return NULL;
   2088     memset(rt, 0, sizeof(*rt));
   2089     js_malloc_init(&rt->malloc_ctx);
   2090     rt->malloc_ctx.mf = *mf;
   2091     rt->malloc_ctx.malloc_state = ms;
   2092     rt->malloc_gc_threshold = 256 * 1024;
   2093 
   2094     init_list_head(&rt->context_list);
   2095     init_list_head(&rt->gc_obj_list);
   2096     init_list_head(&rt->gc_zero_ref_count_list);
   2097     rt->gc_phase = JS_GC_PHASE_NONE;
   2098     init_list_head(&rt->weakref_list);
   2099 
   2100 #ifdef DUMP_LEAKS
   2101     init_list_head(&rt->string_list);
   2102 #endif
   2103     init_list_head(&rt->job_list);
   2104 
   2105     if (JS_InitAtoms(rt))
   2106         goto fail;
   2107 
   2108     /* create the object, array and function classes */
   2109     if (init_class_range(rt, js_std_class_def, JS_CLASS_OBJECT,
   2110                          countof(js_std_class_def)) < 0)
   2111         goto fail;
   2112     rt->class_array[JS_CLASS_ARGUMENTS].exotic = &js_arguments_exotic_methods;
   2113     rt->class_array[JS_CLASS_MAPPED_ARGUMENTS].exotic = &js_arguments_exotic_methods;
   2114     rt->class_array[JS_CLASS_STRING].exotic = &js_string_exotic_methods;
   2115     rt->class_array[JS_CLASS_MODULE_NS].exotic = &js_module_ns_exotic_methods;
   2116 
   2117     rt->class_array[JS_CLASS_C_FUNCTION].call = js_call_c_function;
   2118     rt->class_array[JS_CLASS_C_FUNCTION_DATA].call = js_c_function_data_call;
   2119     rt->class_array[JS_CLASS_BOUND_FUNCTION].call = js_call_bound_function;
   2120     rt->class_array[JS_CLASS_GENERATOR_FUNCTION].call = js_generator_function_call;
   2121     if (init_shape_hash(rt))
   2122         goto fail;
   2123 
   2124     rt->stack_size = JS_DEFAULT_STACK_SIZE;
   2125     JS_UpdateStackTop(rt);
   2126 
   2127     rt->current_exception = JS_UNINITIALIZED;
   2128 
   2129     return rt;
   2130  fail:
   2131     JS_FreeRuntime(rt);
   2132     return NULL;
   2133 }
   2134 
   2135 void *JS_GetRuntimeOpaque(JSRuntime *rt)
   2136 {
   2137     return rt->user_opaque;
   2138 }
   2139 
   2140 void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque)
   2141 {
   2142     rt->user_opaque = opaque;
   2143 }
   2144 
   2145 /* default memory allocation functions with memory limitation */
   2146 static size_t js_def_malloc_usable_size(const void *ptr)
   2147 {
   2148 #if defined(__APPLE__)
   2149     return malloc_size(ptr);
   2150 #elif defined(_WIN32)
   2151     return _msize((void *)ptr);
   2152 #elif defined(__EMSCRIPTEN__)
   2153     return 0;
   2154 #elif defined(__linux__) || defined(__GLIBC__)
   2155     return malloc_usable_size((void *)ptr);
   2156 #else
   2157     /* change this to `return 0;` if compilation fails */
   2158     return malloc_usable_size((void *)ptr);
   2159 #endif
   2160 }
   2161 
   2162 static void *js_def_malloc(JSMallocState *s, size_t size)
   2163 {
   2164     void *ptr;
   2165 
   2166     /* Do not allocate zero bytes: behavior is platform dependent */
   2167     assert(size != 0);
   2168 
   2169     if (unlikely(s->malloc_size + size > s->malloc_limit))
   2170         return NULL;
   2171 
   2172     ptr = malloc(size);
   2173     if (!ptr)
   2174         return NULL;
   2175 
   2176     s->malloc_count++;
   2177     s->malloc_size += js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
   2178     return ptr;
   2179 }
   2180 
   2181 static void js_def_free(JSMallocState *s, void *ptr)
   2182 {
   2183     if (!ptr)
   2184         return;
   2185 
   2186     s->malloc_count--;
   2187     s->malloc_size -= js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
   2188     free(ptr);
   2189 }
   2190 
   2191 static void *js_def_realloc(JSMallocState *s, void *ptr, size_t size)
   2192 {
   2193     size_t old_size;
   2194 
   2195     if (!ptr) {
   2196         if (size == 0)
   2197             return NULL;
   2198         return js_def_malloc(s, size);
   2199     }
   2200     old_size = js_def_malloc_usable_size(ptr);
   2201     if (size == 0) {
   2202         s->malloc_count--;
   2203         s->malloc_size -= old_size + MALLOC_OVERHEAD;
   2204         free(ptr);
   2205         return NULL;
   2206     }
   2207     if (s->malloc_size + size - old_size > s->malloc_limit)
   2208         return NULL;
   2209 
   2210     ptr = realloc(ptr, size);
   2211     if (!ptr)
   2212         return NULL;
   2213 
   2214     s->malloc_size += js_def_malloc_usable_size(ptr) - old_size;
   2215     return ptr;
   2216 }
   2217 
   2218 static const JSMallocFunctions def_malloc_funcs = {
   2219     js_def_malloc,
   2220     js_def_free,
   2221     js_def_realloc,
   2222     js_def_malloc_usable_size,
   2223 };
   2224 
   2225 JSRuntime *JS_NewRuntime(void)
   2226 {
   2227     return JS_NewRuntime2(&def_malloc_funcs, NULL);
   2228 }
   2229 
   2230 void JS_SetMemoryLimit(JSRuntime *rt, size_t limit)
   2231 {
   2232     rt->malloc_ctx.malloc_state.malloc_limit = limit;
   2233 }
   2234 
   2235 /* use -1 to disable automatic GC */
   2236 void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold)
   2237 {
   2238     rt->malloc_gc_threshold = gc_threshold;
   2239 }
   2240 
   2241 #define malloc(s) malloc_is_forbidden(s)
   2242 #define free(p) free_is_forbidden(p)
   2243 #define realloc(p,s) realloc_is_forbidden(p,s)
   2244 
   2245 void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque)
   2246 {
   2247     rt->interrupt_handler = cb;
   2248     rt->interrupt_opaque = opaque;
   2249 }
   2250 
   2251 void JS_SetCanBlock(JSRuntime *rt, BOOL can_block)
   2252 {
   2253     rt->can_block = can_block;
   2254 }
   2255 
   2256 void JS_SetSharedArrayBufferFunctions(JSRuntime *rt,
   2257                                       const JSSharedArrayBufferFunctions *sf)
   2258 {
   2259     rt->sab_funcs = *sf;
   2260 }
   2261 
   2262 void JS_SetStripInfo(JSRuntime *rt, int flags)
   2263 {
   2264     rt->strip_flags = flags;
   2265 }
   2266 
   2267 int JS_GetStripInfo(JSRuntime *rt)
   2268 {
   2269     return rt->strip_flags;
   2270 }
   2271 
   2272 static int JS_EnqueueJob2(JSContext *ctx, JSJobFunc *job_func,
   2273                           int argc, JSValueConst *argv, BOOL no_exception)
   2274 {
   2275     JSRuntime *rt = ctx->rt;
   2276     JSJobEntry *e;
   2277     int i;
   2278 
   2279     if (no_exception)
   2280         e = js_malloc_rt(ctx->rt, sizeof(*e) + argc * sizeof(JSValue));
   2281     else
   2282         e = js_malloc(ctx, sizeof(*e) + argc * sizeof(JSValue));
   2283     if (!e)
   2284         return -1;
   2285     e->realm = JS_DupContext(ctx);
   2286     e->job_func = job_func;
   2287     e->argc = argc;
   2288     for(i = 0; i < argc; i++) {
   2289         e->argv[i] = JS_DupValue(ctx, argv[i]);
   2290     }
   2291     list_add_tail(&e->link, &rt->job_list);
   2292     return 0;
   2293 }
   2294 
   2295 /* return 0 if OK, < 0 if exception */
   2296 int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func,
   2297                   int argc, JSValueConst *argv)
   2298 {
   2299     return JS_EnqueueJob2(ctx, job_func, argc, argv, FALSE);
   2300 }
   2301 
   2302 BOOL JS_IsJobPending(JSRuntime *rt)
   2303 {
   2304     return !list_empty(&rt->job_list);
   2305 }
   2306 
   2307 /* return < 0 if exception, 0 if no job pending, 1 if a job was
   2308    executed successfully. The context of the job is stored in '*pctx'
   2309    if pctx != NULL. It may be NULL if the context was already
   2310    destroyed or if no job was pending. The 'pctx' parameter is now
   2311    absolete. */
   2312 int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx)
   2313 {
   2314     JSContext *ctx;
   2315     JSJobEntry *e;
   2316     JSValue res;
   2317     int i, ret;
   2318 
   2319     if (list_empty(&rt->job_list)) {
   2320         if (pctx)
   2321             *pctx = NULL;
   2322         return 0;
   2323     }
   2324 
   2325     /* get the first pending job and execute it */
   2326     e = list_entry(rt->job_list.next, JSJobEntry, link);
   2327     list_del(&e->link);
   2328     ctx = e->realm;
   2329     res = e->job_func(ctx, e->argc, (JSValueConst *)e->argv);
   2330     for(i = 0; i < e->argc; i++)
   2331         JS_FreeValue(ctx, e->argv[i]);
   2332     if (JS_IsException(res))
   2333         ret = -1;
   2334     else
   2335         ret = 1;
   2336     JS_FreeValue(ctx, res);
   2337     js_free(ctx, e);
   2338     if (pctx) {
   2339         if (js_rc(ctx)->ref_count > 1)
   2340             *pctx = ctx;
   2341         else
   2342             *pctx = NULL;
   2343     }
   2344     JS_FreeContext(ctx);
   2345     return ret;
   2346 }
   2347 
   2348 static inline uint32_t atom_get_free(const JSAtomStruct *p)
   2349 {
   2350     return (uintptr_t)p >> 1;
   2351 }
   2352 
   2353 static inline BOOL atom_is_free(const JSAtomStruct *p)
   2354 {
   2355     return (uintptr_t)p & 1;
   2356 }
   2357 
   2358 static inline JSAtomStruct *atom_set_free(uint32_t v)
   2359 {
   2360     return (JSAtomStruct *)(((uintptr_t)v << 1) | 1);
   2361 }
   2362 
   2363 /* Note: the string contents are uninitialized */
   2364 static JSString *js_alloc_string_rt(JSRuntime *rt, int max_len, int is_wide_char)
   2365 {
   2366     JSString *str;
   2367     str = js_malloc_rt(rt, sizeof(JSString) + (max_len << is_wide_char) + 1 - is_wide_char);
   2368     if (unlikely(!str))
   2369         return NULL;
   2370     js_rc(str)->ref_count = 1;
   2371     str->is_wide_char = is_wide_char;
   2372     str->len = max_len;
   2373     str->atom_type = 0;
   2374     str->hash = 0;          /* optional but costless */
   2375     str->hash_next = 0;     /* optional */
   2376 #ifdef DUMP_LEAKS
   2377     list_add_tail(&str->link, &rt->string_list);
   2378 #endif
   2379     return str;
   2380 }
   2381 
   2382 static JSString *js_alloc_string(JSContext *ctx, int max_len, int is_wide_char)
   2383 {
   2384     JSString *p;
   2385     p = js_alloc_string_rt(ctx->rt, max_len, is_wide_char);
   2386     if (unlikely(!p)) {
   2387         JS_ThrowOutOfMemory(ctx);
   2388         return NULL;
   2389     }
   2390     return p;
   2391 }
   2392 
   2393 /* same as JS_FreeValueRT() but faster */
   2394 static inline void js_free_string(JSRuntime *rt, JSString *str)
   2395 {
   2396     if (--js_rc(str)->ref_count <= 0) {
   2397         if (str->atom_type) {
   2398             JS_FreeAtomStruct(rt, str);
   2399         } else {
   2400 #ifdef DUMP_LEAKS
   2401             list_del(&str->link);
   2402 #endif
   2403             js_free_rt(rt, str);
   2404         }
   2405     }
   2406 }
   2407 
   2408 void JS_SetRuntimeInfo(JSRuntime *rt, const char *s)
   2409 {
   2410     if (rt)
   2411         rt->rt_info = s;
   2412 }
   2413 
   2414 void JS_FreeRuntime(JSRuntime *rt)
   2415 {
   2416     struct list_head *el, *el1;
   2417     int i;
   2418 
   2419     JS_FreeValueRT(rt, rt->current_exception);
   2420 
   2421     list_for_each_safe(el, el1, &rt->job_list) {
   2422         JSJobEntry *e = list_entry(el, JSJobEntry, link);
   2423         for(i = 0; i < e->argc; i++)
   2424             JS_FreeValueRT(rt, e->argv[i]);
   2425         JS_FreeContext(e->realm);
   2426         js_free_rt(rt, e);
   2427     }
   2428     init_list_head(&rt->job_list);
   2429 
   2430     /* don't remove the weak objects to avoid create new jobs with
   2431        FinalizationRegistry */
   2432     JS_RunGCInternal(rt, FALSE);
   2433 
   2434 #ifdef DUMP_LEAKS
   2435     /* leaking objects */
   2436     {
   2437         BOOL header_done;
   2438         JSGCObjectHeader *p;
   2439         int count;
   2440 
   2441         /* remove the internal refcounts to display only the object
   2442            referenced externally */
   2443         list_for_each(el, &rt->gc_obj_list) {
   2444             p = list_entry(el, JSGCObjectHeader, link);
   2445             js_rc(p)->mark = 0;
   2446         }
   2447         gc_decref(rt);
   2448 
   2449         header_done = FALSE;
   2450         list_for_each(el, &rt->gc_obj_list) {
   2451             p = list_entry(el, JSGCObjectHeader, link);
   2452             if (js_rc(p)->ref_count != 0) {
   2453                 if (!header_done) {
   2454                     printf("Object leaks:\n");
   2455                     JS_DumpObjectHeader(rt);
   2456                     header_done = TRUE;
   2457                 }
   2458                 JS_DumpGCObject(rt, p);
   2459             }
   2460         }
   2461 
   2462         count = 0;
   2463         list_for_each(el, &rt->gc_obj_list) {
   2464             p = list_entry(el, JSGCObjectHeader, link);
   2465             if (js_rc(p)->ref_count == 0) {
   2466                 count++;
   2467             }
   2468         }
   2469         if (count != 0)
   2470             printf("Secondary object leaks: %d\n", count);
   2471     }
   2472 #endif
   2473     assert(list_empty(&rt->gc_obj_list));
   2474     assert(list_empty(&rt->weakref_list));
   2475 
   2476     /* free the classes */
   2477     for(i = 0; i < rt->class_count; i++) {
   2478         JSClass *cl = &rt->class_array[i];
   2479         if (cl->class_id != 0) {
   2480             JS_FreeAtomRT(rt, cl->class_name);
   2481         }
   2482     }
   2483     js_free_rt(rt, rt->class_array);
   2484 
   2485 #ifdef DUMP_LEAKS
   2486     /* only the atoms defined in JS_InitAtoms() should be left */
   2487     {
   2488         BOOL header_done = FALSE;
   2489 
   2490         for(i = 0; i < rt->atom_size; i++) {
   2491             JSAtomStruct *p = rt->atom_array[i];
   2492             if (!atom_is_free(p) /* && p->str*/) {
   2493                 if (i >= JS_ATOM_END || js_rc(p)->ref_count != 1) {
   2494                     if (!header_done) {
   2495                         header_done = TRUE;
   2496                         if (rt->rt_info) {
   2497                             printf("%s:1: atom leakage:", rt->rt_info);
   2498                         } else {
   2499                             printf("Atom leaks:\n"
   2500                                    "    %6s %6s %s\n",
   2501                                    "ID", "REFCNT", "NAME");
   2502                         }
   2503                     }
   2504                     if (rt->rt_info) {
   2505                         printf(" ");
   2506                     } else {
   2507                         printf("    %6u %6u ", i, js_rc(p)->ref_count);
   2508                     }
   2509                     switch (p->atom_type) {
   2510                     case JS_ATOM_TYPE_STRING:
   2511                         JS_DumpString(rt, p);
   2512                         break;
   2513                     case JS_ATOM_TYPE_GLOBAL_SYMBOL:
   2514                         printf("Symbol.for(");
   2515                         JS_DumpString(rt, p);
   2516                         printf(")");
   2517                         break;
   2518                     case JS_ATOM_TYPE_SYMBOL:
   2519                         if (p->hash != JS_ATOM_HASH_PRIVATE) {
   2520                             printf("Symbol(");
   2521                             JS_DumpString(rt, p);
   2522                             printf(")");
   2523                         } else {
   2524                             printf("Private(");
   2525                             JS_DumpString(rt, p);
   2526                             printf(")");
   2527                         }
   2528                         break;
   2529                     }
   2530                     if (rt->rt_info) {
   2531                         printf(":%u", js_rc(p)->ref_count);
   2532                     } else {
   2533                         printf("\n");
   2534                     }
   2535                 }
   2536             }
   2537         }
   2538         if (rt->rt_info && header_done)
   2539             printf("\n");
   2540     }
   2541 #endif
   2542 
   2543     /* free the atoms */
   2544     for(i = 0; i < rt->atom_size; i++) {
   2545         JSAtomStruct *p = rt->atom_array[i];
   2546         if (!atom_is_free(p)) {
   2547 #ifdef DUMP_LEAKS
   2548             list_del(&p->link);
   2549 #endif
   2550             js_free_rt(rt, p);
   2551         }
   2552     }
   2553     js_free_rt(rt, rt->atom_array);
   2554     js_free_rt(rt, rt->atom_hash);
   2555     js_free_rt(rt, rt->shape_hash);
   2556 #ifdef DUMP_LEAKS
   2557     if (!list_empty(&rt->string_list)) {
   2558         if (rt->rt_info) {
   2559             printf("%s:1: string leakage:", rt->rt_info);
   2560         } else {
   2561             printf("String leaks:\n"
   2562                    "    %6s %s\n",
   2563                    "REFCNT", "VALUE");
   2564         }
   2565         list_for_each_safe(el, el1, &rt->string_list) {
   2566             JSString *str = list_entry(el, JSString, link);
   2567             if (rt->rt_info) {
   2568                 printf(" ");
   2569             } else {
   2570                 printf("    %6u ", js_rc(str)->ref_count);
   2571             }
   2572             JS_DumpString(rt, str);
   2573             if (rt->rt_info) {
   2574                 printf(":%u", js_rc(str)->ref_count);
   2575             } else {
   2576                 printf("\n");
   2577             }
   2578             list_del(&str->link);
   2579             js_free_rt(rt, str);
   2580         }
   2581         if (rt->rt_info)
   2582             printf("\n");
   2583     }
   2584     {
   2585         JSMallocState *s = &rt->malloc_ctx.malloc_state;
   2586         if (s->malloc_count > 1) {
   2587             if (rt->rt_info)
   2588                 printf("%s:1: ", rt->rt_info);
   2589             printf("Memory leak: %"PRIu64" bytes lost in %"PRIu64" block%s\n",
   2590                    (uint64_t)(s->malloc_size - sizeof(JSRuntime)),
   2591                    (uint64_t)(s->malloc_count - 1), &"s"[s->malloc_count == 2]);
   2592         }
   2593     }
   2594 #endif
   2595 
   2596     {
   2597         JSMallocState ms = rt->malloc_ctx.malloc_state;
   2598         rt->malloc_ctx.mf.js_free(&ms, rt);
   2599     }
   2600 }
   2601 
   2602 JSContext *JS_NewContextRaw(JSRuntime *rt)
   2603 {
   2604     JSContext *ctx;
   2605     int i;
   2606 
   2607     ctx = js_mallocz_rt(rt, sizeof(JSContext));
   2608     if (!ctx)
   2609         return NULL;
   2610     js_rc(ctx)->ref_count = 1;
   2611     add_gc_object(rt, &ctx->header, JS_GC_OBJ_TYPE_JS_CONTEXT);
   2612 
   2613     ctx->class_proto = js_malloc_rt(rt, sizeof(ctx->class_proto[0]) *
   2614                                     rt->class_count);
   2615     if (!ctx->class_proto) {
   2616         js_free_rt(rt, ctx);
   2617         return NULL;
   2618     }
   2619     ctx->rt = rt;
   2620     list_add_tail(&ctx->link, &rt->context_list);
   2621     for(i = 0; i < rt->class_count; i++)
   2622         ctx->class_proto[i] = JS_NULL;
   2623     ctx->array_ctor = JS_NULL;
   2624     ctx->iterator_ctor = JS_NULL;
   2625     ctx->regexp_ctor = JS_NULL;
   2626     ctx->promise_ctor = JS_NULL;
   2627     init_list_head(&ctx->loaded_modules);
   2628 
   2629     if (JS_AddIntrinsicBasicObjects(ctx)) {
   2630         JS_FreeContext(ctx);
   2631         return NULL;
   2632     }
   2633     return ctx;
   2634 }
   2635 
   2636 JSContext *JS_NewContext(JSRuntime *rt)
   2637 {
   2638     JSContext *ctx;
   2639 
   2640     ctx = JS_NewContextRaw(rt);
   2641     if (!ctx)
   2642         return NULL;
   2643 
   2644     if (JS_AddIntrinsicBaseObjects(ctx) ||
   2645         JS_AddIntrinsicDate(ctx) ||
   2646         JS_AddIntrinsicEval(ctx) ||
   2647         JS_AddIntrinsicStringNormalize(ctx) ||
   2648         JS_AddIntrinsicRegExp(ctx) ||
   2649         JS_AddIntrinsicJSON(ctx) ||
   2650         JS_AddIntrinsicProxy(ctx) ||
   2651         JS_AddIntrinsicMapSet(ctx) ||
   2652         JS_AddIntrinsicTypedArrays(ctx) ||
   2653         JS_AddIntrinsicPromise(ctx) ||
   2654         JS_AddIntrinsicWeakRef(ctx)) {
   2655         JS_FreeContext(ctx);
   2656         return NULL;
   2657     }
   2658     return ctx;
   2659 }
   2660 
   2661 void *JS_GetContextOpaque(JSContext *ctx)
   2662 {
   2663     return ctx->user_opaque;
   2664 }
   2665 
   2666 void JS_SetContextOpaque(JSContext *ctx, void *opaque)
   2667 {
   2668     ctx->user_opaque = opaque;
   2669 }
   2670 
   2671 /* set the new value and free the old value after (freeing the value
   2672    can reallocate the object data) */
   2673 static inline void set_value(JSContext *ctx, JSValue *pval, JSValue new_val)
   2674 {
   2675     JSValue old_val;
   2676     old_val = *pval;
   2677     *pval = new_val;
   2678     JS_FreeValue(ctx, old_val);
   2679 }
   2680 
   2681 void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj)
   2682 {
   2683     JSRuntime *rt = ctx->rt;
   2684     assert(class_id < rt->class_count);
   2685     set_value(ctx, &ctx->class_proto[class_id], obj);
   2686 }
   2687 
   2688 JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id)
   2689 {
   2690     JSRuntime *rt = ctx->rt;
   2691     assert(class_id < rt->class_count);
   2692     return JS_DupValue(ctx, ctx->class_proto[class_id]);
   2693 }
   2694 
   2695 typedef enum JSFreeModuleEnum {
   2696     JS_FREE_MODULE_ALL,
   2697     JS_FREE_MODULE_NOT_RESOLVED,
   2698 } JSFreeModuleEnum;
   2699 
   2700 /* XXX: would be more efficient with separate module lists */
   2701 static void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag)
   2702 {
   2703     struct list_head *el, *el1;
   2704     list_for_each_safe(el, el1, &ctx->loaded_modules) {
   2705         JSModuleDef *m = list_entry(el, JSModuleDef, link);
   2706         if (flag == JS_FREE_MODULE_ALL ||
   2707             (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved)) {
   2708             /* warning: the module may be referenced elsewhere. It
   2709                could be simpler to use an array instead of a list for
   2710                'ctx->loaded_modules' */
   2711             list_del(&m->link);
   2712             m->link.prev = NULL;
   2713             m->link.next = NULL;
   2714             JS_FreeValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
   2715         }
   2716     }
   2717 }
   2718 
   2719 JSContext *JS_DupContext(JSContext *ctx)
   2720 {
   2721     js_rc(ctx)->ref_count++;
   2722     return ctx;
   2723 }
   2724 
   2725 /* used by the GC */
   2726 static void JS_MarkContext(JSRuntime *rt, JSContext *ctx,
   2727                            JS_MarkFunc *mark_func)
   2728 {
   2729     int i;
   2730     struct list_head *el;
   2731 
   2732     list_for_each(el, &ctx->loaded_modules) {
   2733         JSModuleDef *m = list_entry(el, JSModuleDef, link);
   2734         JS_MarkValue(rt, JS_MKPTR(JS_TAG_MODULE, m), mark_func);
   2735     }
   2736 
   2737     JS_MarkValue(rt, ctx->global_obj, mark_func);
   2738     JS_MarkValue(rt, ctx->global_var_obj, mark_func);
   2739 
   2740     JS_MarkValue(rt, ctx->throw_type_error, mark_func);
   2741     JS_MarkValue(rt, ctx->eval_obj, mark_func);
   2742 
   2743     JS_MarkValue(rt, ctx->array_proto_values, mark_func);
   2744     for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
   2745         JS_MarkValue(rt, ctx->native_error_proto[i], mark_func);
   2746     }
   2747     for(i = 0; i < rt->class_count; i++) {
   2748         JS_MarkValue(rt, ctx->class_proto[i], mark_func);
   2749     }
   2750     JS_MarkValue(rt, ctx->iterator_ctor, mark_func);
   2751     JS_MarkValue(rt, ctx->async_iterator_proto, mark_func);
   2752     JS_MarkValue(rt, ctx->promise_ctor, mark_func);
   2753     JS_MarkValue(rt, ctx->array_ctor, mark_func);
   2754     JS_MarkValue(rt, ctx->regexp_ctor, mark_func);
   2755     JS_MarkValue(rt, ctx->function_ctor, mark_func);
   2756     JS_MarkValue(rt, ctx->function_proto, mark_func);
   2757 
   2758     if (ctx->array_shape)
   2759         mark_func(rt, &ctx->array_shape->header);
   2760 
   2761     if (ctx->arguments_shape)
   2762         mark_func(rt, &ctx->arguments_shape->header);
   2763 
   2764     if (ctx->mapped_arguments_shape)
   2765         mark_func(rt, &ctx->mapped_arguments_shape->header);
   2766 
   2767     if (ctx->regexp_shape)
   2768         mark_func(rt, &ctx->regexp_shape->header);
   2769 
   2770     if (ctx->regexp_result_shape)
   2771         mark_func(rt, &ctx->regexp_result_shape->header);
   2772 }
   2773 
   2774 void JS_FreeContext(JSContext *ctx)
   2775 {
   2776     JSRuntime *rt = ctx->rt;
   2777     int i;
   2778 
   2779     if (--js_rc(ctx)->ref_count > 0)
   2780         return;
   2781     assert(js_rc(ctx)->ref_count == 0);
   2782 
   2783 #ifdef DUMP_ATOMS
   2784     JS_DumpAtoms(ctx->rt);
   2785 #endif
   2786 #ifdef DUMP_SHAPES
   2787     JS_DumpShapes(ctx->rt);
   2788 #endif
   2789 #ifdef DUMP_OBJECTS
   2790     {
   2791         struct list_head *el;
   2792         JSGCObjectHeader *p;
   2793         printf("JSObjects: {\n");
   2794         JS_DumpObjectHeader(ctx->rt);
   2795         list_for_each(el, &rt->gc_obj_list) {
   2796             p = list_entry(el, JSGCObjectHeader, link);
   2797             JS_DumpGCObject(rt, p);
   2798         }
   2799         printf("}\n");
   2800     }
   2801 #endif
   2802 #ifdef DUMP_MEM
   2803     {
   2804         JSMemoryUsage stats;
   2805         JS_ComputeMemoryUsage(rt, &stats);
   2806         JS_DumpMemoryUsage(stdout, &stats, rt);
   2807     }
   2808 #endif
   2809 
   2810     js_free_modules(ctx, JS_FREE_MODULE_ALL);
   2811 
   2812     JS_FreeValue(ctx, ctx->global_obj);
   2813     JS_FreeValue(ctx, ctx->global_var_obj);
   2814 
   2815     JS_FreeValue(ctx, ctx->throw_type_error);
   2816     JS_FreeValue(ctx, ctx->eval_obj);
   2817 
   2818     JS_FreeValue(ctx, ctx->array_proto_values);
   2819     for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
   2820         JS_FreeValue(ctx, ctx->native_error_proto[i]);
   2821     }
   2822     for(i = 0; i < rt->class_count; i++) {
   2823         JS_FreeValue(ctx, ctx->class_proto[i]);
   2824     }
   2825     js_free_rt(rt, ctx->class_proto);
   2826     JS_FreeValue(ctx, ctx->iterator_ctor);
   2827     JS_FreeValue(ctx, ctx->async_iterator_proto);
   2828     JS_FreeValue(ctx, ctx->promise_ctor);
   2829     JS_FreeValue(ctx, ctx->array_ctor);
   2830     JS_FreeValue(ctx, ctx->regexp_ctor);
   2831     JS_FreeValue(ctx, ctx->function_ctor);
   2832     JS_FreeValue(ctx, ctx->function_proto);
   2833 
   2834     js_free_shape_null(ctx->rt, ctx->array_shape);
   2835     js_free_shape_null(ctx->rt, ctx->arguments_shape);
   2836     js_free_shape_null(ctx->rt, ctx->mapped_arguments_shape);
   2837     js_free_shape_null(ctx->rt, ctx->regexp_shape);
   2838     js_free_shape_null(ctx->rt, ctx->regexp_result_shape);
   2839 
   2840     list_del(&ctx->link);
   2841     remove_gc_object(&ctx->header);
   2842     js_free_rt(ctx->rt, ctx);
   2843 }
   2844 
   2845 JSRuntime *JS_GetRuntime(JSContext *ctx)
   2846 {
   2847     return ctx->rt;
   2848 }
   2849 
   2850 static void update_stack_limit(JSRuntime *rt)
   2851 {
   2852     if (rt->stack_size == 0) {
   2853         rt->stack_limit = 0; /* no limit */
   2854     } else {
   2855         rt->stack_limit = rt->stack_top - rt->stack_size;
   2856     }
   2857 }
   2858 
   2859 void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size)
   2860 {
   2861     rt->stack_size = stack_size;
   2862     update_stack_limit(rt);
   2863 }
   2864 
   2865 void JS_UpdateStackTop(JSRuntime *rt)
   2866 {
   2867     rt->stack_top = js_get_stack_pointer();
   2868     update_stack_limit(rt);
   2869 }
   2870 
   2871 static inline BOOL is_strict_mode(JSContext *ctx)
   2872 {
   2873     JSStackFrame *sf = ctx->rt->current_stack_frame;
   2874     return (sf && (sf->js_mode & JS_MODE_STRICT));
   2875 }
   2876 
   2877 /* JSAtom support */
   2878 
   2879 #define JS_ATOM_TAG_INT (1U << 31)
   2880 #define JS_ATOM_MAX_INT (JS_ATOM_TAG_INT - 1)
   2881 #define JS_ATOM_MAX     ((1U << 30) - 1)
   2882 
   2883 /* return the max count from the hash size */
   2884 #define JS_ATOM_COUNT_RESIZE(n) ((n) * 2)
   2885 
   2886 static inline BOOL __JS_AtomIsConst(JSAtom v)
   2887 {
   2888 #if defined(DUMP_LEAKS) && DUMP_LEAKS > 1
   2889         return (int32_t)v <= 0;
   2890 #else
   2891         return (int32_t)v < JS_ATOM_END;
   2892 #endif
   2893 }
   2894 
   2895 static inline BOOL __JS_AtomIsTaggedInt(JSAtom v)
   2896 {
   2897     return (v & JS_ATOM_TAG_INT) != 0;
   2898 }
   2899 
   2900 static inline JSAtom __JS_AtomFromUInt32(uint32_t v)
   2901 {
   2902     return v | JS_ATOM_TAG_INT;
   2903 }
   2904 
   2905 static inline uint32_t __JS_AtomToUInt32(JSAtom atom)
   2906 {
   2907     return atom & ~JS_ATOM_TAG_INT;
   2908 }
   2909 
   2910 static inline int is_num(int c)
   2911 {
   2912     return c >= '0' && c <= '9';
   2913 }
   2914 
   2915 /* return TRUE if the string is a number n with 0 <= n <= 2^32-1 */
   2916 static inline BOOL is_num_string(uint32_t *pval, const JSString *p)
   2917 {
   2918     uint32_t n;
   2919     uint64_t n64;
   2920     int c, i, len;
   2921 
   2922     len = p->len;
   2923     if (len == 0 || len > 10)
   2924         return FALSE;
   2925     c = string_get(p, 0);
   2926     if (is_num(c)) {
   2927         if (c == '0') {
   2928             if (len != 1)
   2929                 return FALSE;
   2930             n = 0;
   2931         } else {
   2932             n = c - '0';
   2933             for(i = 1; i < len; i++) {
   2934                 c = string_get(p, i);
   2935                 if (!is_num(c))
   2936                     return FALSE;
   2937                 n64 = (uint64_t)n * 10 + (c - '0');
   2938                 if ((n64 >> 32) != 0)
   2939                     return FALSE;
   2940                 n = n64;
   2941             }
   2942         }
   2943         *pval = n;
   2944         return TRUE;
   2945     } else {
   2946         return FALSE;
   2947     }
   2948 }
   2949 
   2950 /* XXX: could use faster version ? */
   2951 static inline uint32_t hash_string8(const uint8_t *str, size_t len, uint32_t h)
   2952 {
   2953     size_t i;
   2954 
   2955     for(i = 0; i < len; i++)
   2956         h = h * 263 + str[i];
   2957     return h;
   2958 }
   2959 
   2960 static inline uint32_t hash_string16(const uint16_t *str,
   2961                                      size_t len, uint32_t h)
   2962 {
   2963     size_t i;
   2964 
   2965     for(i = 0; i < len; i++)
   2966         h = h * 263 + str[i];
   2967     return h;
   2968 }
   2969 
   2970 static uint32_t hash_string(const JSString *str, uint32_t h)
   2971 {
   2972     if (str->is_wide_char)
   2973         h = hash_string16(str->u.str16, str->len, h);
   2974     else
   2975         h = hash_string8(str->u.str8, str->len, h);
   2976     return h;
   2977 }
   2978 
   2979 static uint32_t hash_string_rope(JSValueConst val, uint32_t h)
   2980 {
   2981     if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
   2982         return hash_string(JS_VALUE_GET_STRING(val), h);
   2983     } else {
   2984         JSStringRope *r = JS_VALUE_GET_STRING_ROPE(val);
   2985         h = hash_string_rope(r->left, h);
   2986         return hash_string_rope(r->right, h);
   2987     }
   2988 }
   2989 
   2990 static __maybe_unused void JS_DumpChar(FILE *fo, int c, int sep)
   2991 {
   2992     if (c == sep || c == '\\') {
   2993         fputc('\\', fo);
   2994         fputc(c, fo);
   2995     } else if (c >= ' ' && c <= 126) {
   2996         fputc(c, fo);
   2997     } else if (c == '\n') {
   2998         fputc('\\', fo);
   2999         fputc('n', fo);
   3000     } else {
   3001         fprintf(fo, "\\u%04x", c);
   3002     }
   3003 }
   3004 
   3005 static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p)
   3006 {
   3007     int i, sep;
   3008 
   3009     if (p == NULL) {
   3010         printf("<null>");
   3011         return;
   3012     }
   3013     printf("%d", js_rc((void *)p)->ref_count);
   3014     sep = (js_rc((void *)p)->ref_count == 1) ? '\"' : '\'';
   3015     putchar(sep);
   3016     for(i = 0; i < p->len; i++) {
   3017         JS_DumpChar(stdout, string_get(p, i), sep);
   3018     }
   3019     putchar(sep);
   3020 }
   3021 
   3022 static __maybe_unused void JS_DumpAtoms(JSRuntime *rt)
   3023 {
   3024     JSAtomStruct *p;
   3025     int h, i;
   3026     /* This only dumps hashed atoms, not JS_ATOM_TYPE_SYMBOL atoms */
   3027     printf("JSAtom count=%d size=%d hash_size=%d:\n",
   3028            rt->atom_count, rt->atom_size, rt->atom_hash_size);
   3029     printf("JSAtom hash table: {\n");
   3030     for(i = 0; i < rt->atom_hash_size; i++) {
   3031         h = rt->atom_hash[i];
   3032         if (h) {
   3033             printf("  %d:", i);
   3034             while (h) {
   3035                 p = rt->atom_array[h];
   3036                 printf(" ");
   3037                 JS_DumpString(rt, p);
   3038                 h = p->hash_next;
   3039             }
   3040             printf("\n");
   3041         }
   3042     }
   3043     printf("}\n");
   3044     printf("JSAtom table: {\n");
   3045     for(i = 0; i < rt->atom_size; i++) {
   3046         p = rt->atom_array[i];
   3047         if (!atom_is_free(p)) {
   3048             printf("  %d: { %d %08x ", i, p->atom_type, p->hash);
   3049             if (!(p->len == 0 && p->is_wide_char != 0))
   3050                 JS_DumpString(rt, p);
   3051             printf(" %d }\n", p->hash_next);
   3052         }
   3053     }
   3054     printf("}\n");
   3055 }
   3056 
   3057 static int JS_ResizeAtomHash(JSRuntime *rt, int new_hash_size)
   3058 {
   3059     JSAtomStruct *p;
   3060     uint32_t new_hash_mask, h, i, hash_next1, j, *new_hash;
   3061 
   3062     assert((new_hash_size & (new_hash_size - 1)) == 0); /* power of two */
   3063     new_hash_mask = new_hash_size - 1;
   3064     new_hash = js_mallocz_rt(rt, sizeof(rt->atom_hash[0]) * new_hash_size);
   3065     if (!new_hash)
   3066         return -1;
   3067     for(i = 0; i < rt->atom_hash_size; i++) {
   3068         h = rt->atom_hash[i];
   3069         while (h != 0) {
   3070             p = rt->atom_array[h];
   3071             hash_next1 = p->hash_next;
   3072             /* add in new hash table */
   3073             j = p->hash & new_hash_mask;
   3074             p->hash_next = new_hash[j];
   3075             new_hash[j] = h;
   3076             h = hash_next1;
   3077         }
   3078     }
   3079     js_free_rt(rt, rt->atom_hash);
   3080     rt->atom_hash = new_hash;
   3081     rt->atom_hash_size = new_hash_size;
   3082     rt->atom_count_resize = JS_ATOM_COUNT_RESIZE(new_hash_size);
   3083     //    JS_DumpAtoms(rt);
   3084     return 0;
   3085 }
   3086 
   3087 static int JS_InitAtoms(JSRuntime *rt)
   3088 {
   3089     int i, len, atom_type;
   3090     const char *p;
   3091 
   3092     rt->atom_hash_size = 0;
   3093     rt->atom_hash = NULL;
   3094     rt->atom_count = 0;
   3095     rt->atom_size = 0;
   3096     rt->atom_free_index = 0;
   3097     if (JS_ResizeAtomHash(rt, 512))     /* there are at least 504 predefined atoms */
   3098         return -1;
   3099 
   3100     p = js_atom_init;
   3101     for(i = 1; i < JS_ATOM_END; i++) {
   3102         if (i == JS_ATOM_Private_brand)
   3103             atom_type = JS_ATOM_TYPE_PRIVATE;
   3104         else if (i >= JS_ATOM_Symbol_toPrimitive)
   3105             atom_type = JS_ATOM_TYPE_SYMBOL;
   3106         else
   3107             atom_type = JS_ATOM_TYPE_STRING;
   3108         len = strlen(p);
   3109         if (__JS_NewAtomInit(rt, p, len, atom_type) == JS_ATOM_NULL)
   3110             return -1;
   3111         p = p + len + 1;
   3112     }
   3113     return 0;
   3114 }
   3115 
   3116 static JSAtom JS_DupAtomRT(JSRuntime *rt, JSAtom v)
   3117 {
   3118     JSAtomStruct *p;
   3119 
   3120     if (!__JS_AtomIsConst(v)) {
   3121         p = rt->atom_array[v];
   3122         js_rc(p)->ref_count++;
   3123     }
   3124     return v;
   3125 }
   3126 
   3127 JSAtom JS_DupAtom(JSContext *ctx, JSAtom v)
   3128 {
   3129     JSRuntime *rt;
   3130     JSAtomStruct *p;
   3131 
   3132     if (!__JS_AtomIsConst(v)) {
   3133         rt = ctx->rt;
   3134         p = rt->atom_array[v];
   3135         js_rc(p)->ref_count++;
   3136     }
   3137     return v;
   3138 }
   3139 
   3140 static JSAtomKindEnum JS_AtomGetKind(JSContext *ctx, JSAtom v)
   3141 {
   3142     JSRuntime *rt;
   3143     JSAtomStruct *p;
   3144 
   3145     rt = ctx->rt;
   3146     if (__JS_AtomIsTaggedInt(v))
   3147         return JS_ATOM_KIND_STRING;
   3148     p = rt->atom_array[v];
   3149     switch(p->atom_type) {
   3150     case JS_ATOM_TYPE_STRING:
   3151         return JS_ATOM_KIND_STRING;
   3152     case JS_ATOM_TYPE_GLOBAL_SYMBOL:
   3153         return JS_ATOM_KIND_SYMBOL;
   3154     case JS_ATOM_TYPE_SYMBOL:
   3155         if (p->hash == JS_ATOM_HASH_PRIVATE)
   3156             return JS_ATOM_KIND_PRIVATE;
   3157         else
   3158             return JS_ATOM_KIND_SYMBOL;
   3159     default:
   3160         abort();
   3161     }
   3162 }
   3163 
   3164 static BOOL JS_AtomIsString(JSContext *ctx, JSAtom v)
   3165 {
   3166     return JS_AtomGetKind(ctx, v) == JS_ATOM_KIND_STRING;
   3167 }
   3168 
   3169 static JSAtom js_get_atom_index(JSRuntime *rt, JSAtomStruct *p)
   3170 {
   3171     uint32_t i = p->hash_next;  /* atom_index */
   3172     if (p->atom_type != JS_ATOM_TYPE_SYMBOL) {
   3173         JSAtomStruct *p1;
   3174 
   3175         i = rt->atom_hash[p->hash & (rt->atom_hash_size - 1)];
   3176         p1 = rt->atom_array[i];
   3177         while (p1 != p) {
   3178             assert(i != 0);
   3179             i = p1->hash_next;
   3180             p1 = rt->atom_array[i];
   3181         }
   3182     }
   3183     return i;
   3184 }
   3185 
   3186 /* string case (internal). Return JS_ATOM_NULL if error. 'str' is
   3187    freed. */
   3188 static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type)
   3189 {
   3190     uint32_t h, h1, i;
   3191     JSAtomStruct *p;
   3192     int len;
   3193 
   3194 #if 0
   3195     printf("__JS_NewAtom: ");  JS_DumpString(rt, str); printf("\n");
   3196 #endif
   3197     if (atom_type < JS_ATOM_TYPE_SYMBOL) {
   3198         /* str is not NULL */
   3199         if (str->atom_type == atom_type) {
   3200             /* str is the atom, return its index */
   3201             i = js_get_atom_index(rt, str);
   3202             /* reduce string refcount and increase atom's unless constant */
   3203             if (__JS_AtomIsConst(i))
   3204                 js_rc(str)->ref_count--;
   3205             return i;
   3206         }
   3207         /* try and locate an already registered atom */
   3208         len = str->len;
   3209         h = hash_string(str, atom_type);
   3210         h &= JS_ATOM_HASH_MASK;
   3211         h1 = h & (rt->atom_hash_size - 1);
   3212         i = rt->atom_hash[h1];
   3213         while (i != 0) {
   3214             p = rt->atom_array[i];
   3215             if (p->hash == h &&
   3216                 p->atom_type == atom_type &&
   3217                 p->len == len &&
   3218                 js_string_memcmp(p, 0, str, 0, len) == 0) {
   3219                 if (!__JS_AtomIsConst(i))
   3220                     js_rc(p)->ref_count++;
   3221                 goto done;
   3222             }
   3223             i = p->hash_next;
   3224         }
   3225     } else {
   3226         h1 = 0; /* avoid warning */
   3227         if (atom_type == JS_ATOM_TYPE_SYMBOL) {
   3228             h = 0;
   3229         } else {
   3230             h = JS_ATOM_HASH_PRIVATE;
   3231             atom_type = JS_ATOM_TYPE_SYMBOL;
   3232         }
   3233     }
   3234 
   3235     if (rt->atom_free_index == 0) {
   3236         /* allow new atom entries */
   3237         uint32_t new_size, start;
   3238         JSAtomStruct **new_array;
   3239 
   3240         /* alloc new with size progression 3/2:
   3241            4 6 9 13 19 28 42 63 94 141 211 316 474 711 1066 1599 2398 3597 5395 8092
   3242            preallocating space for predefined atoms (at least 504).
   3243          */
   3244         new_size = max_int(711, rt->atom_size * 3 / 2);
   3245         if (new_size > JS_ATOM_MAX)
   3246             goto fail;
   3247         /* XXX: should use realloc2 to use slack space */
   3248         new_array = js_realloc_rt(rt, rt->atom_array, sizeof(*new_array) * new_size);
   3249         if (!new_array)
   3250             goto fail;
   3251         /* Note: the atom 0 is not used */
   3252         start = rt->atom_size;
   3253         if (start == 0) {
   3254             /* JS_ATOM_NULL entry */
   3255             p = js_mallocz_rt(rt, sizeof(JSAtomStruct));
   3256             if (!p) {
   3257                 js_free_rt(rt, new_array);
   3258                 goto fail;
   3259             }
   3260             js_rc(p)->ref_count = 1;  /* not refcounted */
   3261             p->atom_type = JS_ATOM_TYPE_SYMBOL;
   3262 #ifdef DUMP_LEAKS
   3263             list_add_tail(&p->link, &rt->string_list);
   3264 #endif
   3265             new_array[0] = p;
   3266             rt->atom_count++;
   3267             start = 1;
   3268         }
   3269         rt->atom_size = new_size;
   3270         rt->atom_array = new_array;
   3271         rt->atom_free_index = start;
   3272         for(i = start; i < new_size; i++) {
   3273             uint32_t next;
   3274             if (i == (new_size - 1))
   3275                 next = 0;
   3276             else
   3277                 next = i + 1;
   3278             rt->atom_array[i] = atom_set_free(next);
   3279         }
   3280     }
   3281 
   3282     if (str) {
   3283         if (str->atom_type == 0) {
   3284             p = str;
   3285             p->atom_type = atom_type;
   3286         } else {
   3287             p = js_malloc_rt(rt, sizeof(JSString) +
   3288                              (str->len << str->is_wide_char) +
   3289                              1 - str->is_wide_char);
   3290             if (unlikely(!p))
   3291                 goto fail;
   3292             js_rc(p)->ref_count = 1;
   3293             p->is_wide_char = str->is_wide_char;
   3294             p->len = str->len;
   3295 #ifdef DUMP_LEAKS
   3296             list_add_tail(&p->link, &rt->string_list);
   3297 #endif
   3298             memcpy(p->u.str8, str->u.str8, (str->len << str->is_wide_char) +
   3299                    1 - str->is_wide_char);
   3300             js_free_string(rt, str);
   3301         }
   3302     } else {
   3303         p = js_malloc_rt(rt, sizeof(JSAtomStruct)); /* empty wide string */
   3304         if (!p)
   3305             return JS_ATOM_NULL;
   3306         js_rc(p)->ref_count = 1;
   3307         p->is_wide_char = 1;    /* Hack to represent NULL as a JSString */
   3308         p->len = 0;
   3309 #ifdef DUMP_LEAKS
   3310         list_add_tail(&p->link, &rt->string_list);
   3311 #endif
   3312     }
   3313 
   3314     /* use an already free entry */
   3315     i = rt->atom_free_index;
   3316     rt->atom_free_index = atom_get_free(rt->atom_array[i]);
   3317     rt->atom_array[i] = p;
   3318 
   3319     p->hash = h;
   3320     p->hash_next = i;   /* atom_index */
   3321     p->atom_type = atom_type;
   3322 
   3323     rt->atom_count++;
   3324 
   3325     if (atom_type != JS_ATOM_TYPE_SYMBOL) {
   3326         p->hash_next = rt->atom_hash[h1];
   3327         rt->atom_hash[h1] = i;
   3328         if (unlikely(rt->atom_count >= rt->atom_count_resize))
   3329             JS_ResizeAtomHash(rt, rt->atom_hash_size * 2);
   3330     }
   3331 
   3332     //    JS_DumpAtoms(rt);
   3333     return i;
   3334 
   3335  fail:
   3336     i = JS_ATOM_NULL;
   3337  done:
   3338     if (str)
   3339         js_free_string(rt, str);
   3340     return i;
   3341 }
   3342 
   3343 /* only works with zero terminated 8 bit strings */
   3344 static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
   3345                                int atom_type)
   3346 {
   3347     JSString *p;
   3348     p = js_alloc_string_rt(rt, len, 0);
   3349     if (!p)
   3350         return JS_ATOM_NULL;
   3351     memcpy(p->u.str8, str, len);
   3352     p->u.str8[len] = '\0';
   3353     return __JS_NewAtom(rt, p, atom_type);
   3354 }
   3355 
   3356 /* Warning: str must be ASCII only */
   3357 static JSAtom __JS_FindAtom(JSRuntime *rt, const char *str, size_t len,
   3358                             int atom_type)
   3359 {
   3360     uint32_t h, h1, i;
   3361     JSAtomStruct *p;
   3362 
   3363     h = hash_string8((const uint8_t *)str, len, JS_ATOM_TYPE_STRING);
   3364     h &= JS_ATOM_HASH_MASK;
   3365     h1 = h & (rt->atom_hash_size - 1);
   3366     i = rt->atom_hash[h1];
   3367     while (i != 0) {
   3368         p = rt->atom_array[i];
   3369         if (p->hash == h &&
   3370             p->atom_type == JS_ATOM_TYPE_STRING &&
   3371             p->len == len &&
   3372             p->is_wide_char == 0 &&
   3373             memcmp(p->u.str8, str, len) == 0) {
   3374             if (!__JS_AtomIsConst(i))
   3375                 js_rc(p)->ref_count++;
   3376             return i;
   3377         }
   3378         i = p->hash_next;
   3379     }
   3380     return JS_ATOM_NULL;
   3381 }
   3382 
   3383 static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p)
   3384 {
   3385 #if 0   /* JS_ATOM_NULL is not refcounted: __JS_AtomIsConst() includes 0 */
   3386     if (unlikely(i == JS_ATOM_NULL)) {
   3387         js_rc(p)->ref_count = INT32_MAX / 2;
   3388         return;
   3389     }
   3390 #endif
   3391     uint32_t i = p->hash_next;  /* atom_index */
   3392     if (p->atom_type != JS_ATOM_TYPE_SYMBOL) {
   3393         JSAtomStruct *p0, *p1;
   3394         uint32_t h0;
   3395 
   3396         h0 = p->hash & (rt->atom_hash_size - 1);
   3397         i = rt->atom_hash[h0];
   3398         p1 = rt->atom_array[i];
   3399         if (p1 == p) {
   3400             rt->atom_hash[h0] = p1->hash_next;
   3401         } else {
   3402             for(;;) {
   3403                 assert(i != 0);
   3404                 p0 = p1;
   3405                 i = p1->hash_next;
   3406                 p1 = rt->atom_array[i];
   3407                 if (p1 == p) {
   3408                     p0->hash_next = p1->hash_next;
   3409                     break;
   3410                 }
   3411             }
   3412         }
   3413     }
   3414     /* insert in free atom list */
   3415     rt->atom_array[i] = atom_set_free(rt->atom_free_index);
   3416     rt->atom_free_index = i;
   3417     /* free the string structure */
   3418 #ifdef DUMP_LEAKS
   3419     list_del(&p->link);
   3420 #endif
   3421     if (p->atom_type == JS_ATOM_TYPE_SYMBOL &&
   3422         p->hash != JS_ATOM_HASH_PRIVATE && p->hash != 0) {
   3423         /* live weak references are still present on this object: keep
   3424            it */
   3425     } else {
   3426         js_free_rt(rt, p);
   3427     }
   3428     rt->atom_count--;
   3429     assert(rt->atom_count >= 0);
   3430 }
   3431 
   3432 static void __JS_FreeAtom(JSRuntime *rt, uint32_t i)
   3433 {
   3434     JSAtomStruct *p;
   3435 
   3436     p = rt->atom_array[i];
   3437     if (--js_rc(p)->ref_count > 0)
   3438         return;
   3439     JS_FreeAtomStruct(rt, p);
   3440 }
   3441 
   3442 /* Warning: 'p' is freed */
   3443 static JSAtom JS_NewAtomStr(JSContext *ctx, JSString *p)
   3444 {
   3445     JSRuntime *rt = ctx->rt;
   3446     uint32_t n;
   3447     if (is_num_string(&n, p)) {
   3448         if (n <= JS_ATOM_MAX_INT) {
   3449             js_free_string(rt, p);
   3450             return __JS_AtomFromUInt32(n);
   3451         }
   3452     }
   3453     /* XXX: should generate an exception */
   3454     return __JS_NewAtom(rt, p, JS_ATOM_TYPE_STRING);
   3455 }
   3456 
   3457 /* XXX: optimize */
   3458 static size_t count_ascii(const uint8_t *buf, size_t len)
   3459 {
   3460     const uint8_t *p, *p_end;
   3461     p = buf;
   3462     p_end = buf + len;
   3463     while (p < p_end && *p < 128)
   3464         p++;
   3465     return p - buf;
   3466 }
   3467 
   3468 /* str is UTF-8 encoded */
   3469 JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len)
   3470 {
   3471     JSValue val;
   3472 
   3473     if (len == 0 ||
   3474         (!is_digit(*str) &&
   3475          count_ascii((const uint8_t *)str, len) == len)) {
   3476         JSAtom atom = __JS_FindAtom(ctx->rt, str, len, JS_ATOM_TYPE_STRING);
   3477         if (atom)
   3478             return atom;
   3479     }
   3480     val = JS_NewStringLen(ctx, str, len);
   3481     if (JS_IsException(val))
   3482         return JS_ATOM_NULL;
   3483     return JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(val));
   3484 }
   3485 
   3486 JSAtom JS_NewAtom(JSContext *ctx, const char *str)
   3487 {
   3488     return JS_NewAtomLen(ctx, str, strlen(str));
   3489 }
   3490 
   3491 JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n)
   3492 {
   3493     if (n <= JS_ATOM_MAX_INT) {
   3494         return __JS_AtomFromUInt32(n);
   3495     } else {
   3496         char buf[11];
   3497         JSValue val;
   3498         size_t len;
   3499         len = u32toa(buf, n);
   3500         val = js_new_string8_len(ctx, buf, len);
   3501         if (JS_IsException(val))
   3502             return JS_ATOM_NULL;
   3503         return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),
   3504                             JS_ATOM_TYPE_STRING);
   3505     }
   3506 }
   3507 
   3508 static JSAtom JS_NewAtomInt64(JSContext *ctx, int64_t n)
   3509 {
   3510     if ((uint64_t)n <= JS_ATOM_MAX_INT) {
   3511         return __JS_AtomFromUInt32((uint32_t)n);
   3512     } else {
   3513         char buf[24];
   3514         JSValue val;
   3515         size_t len;
   3516         len = i64toa(buf, n);
   3517         val = js_new_string8_len(ctx, buf, len);
   3518         if (JS_IsException(val))
   3519             return JS_ATOM_NULL;
   3520         return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),
   3521                             JS_ATOM_TYPE_STRING);
   3522     }
   3523 }
   3524 
   3525 /* 'p' is freed */
   3526 static JSValue JS_NewSymbol(JSContext *ctx, JSString *p, int atom_type)
   3527 {
   3528     JSRuntime *rt = ctx->rt;
   3529     JSAtom atom;
   3530     atom = __JS_NewAtom(rt, p, atom_type);
   3531     if (atom == JS_ATOM_NULL)
   3532         return JS_ThrowOutOfMemory(ctx);
   3533     return JS_MKPTR(JS_TAG_SYMBOL, rt->atom_array[atom]);
   3534 }
   3535 
   3536 /* descr must be a non-numeric string atom */
   3537 static JSValue JS_NewSymbolFromAtom(JSContext *ctx, JSAtom descr,
   3538                                     int atom_type)
   3539 {
   3540     JSRuntime *rt = ctx->rt;
   3541     JSString *p;
   3542 
   3543     assert(!__JS_AtomIsTaggedInt(descr));
   3544     assert(descr < rt->atom_size);
   3545     p = rt->atom_array[descr];
   3546     JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
   3547     return JS_NewSymbol(ctx, p, atom_type);
   3548 }
   3549 
   3550 #define ATOM_GET_STR_BUF_SIZE 64
   3551 
   3552 /* Should only be used for debug. */
   3553 static const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size,
   3554                                    JSAtom atom)
   3555 {
   3556     if (__JS_AtomIsTaggedInt(atom)) {
   3557         snprintf(buf, buf_size, "%u", __JS_AtomToUInt32(atom));
   3558     } else {
   3559         JSAtomStruct *p;
   3560         assert(atom < rt->atom_size);
   3561         if (atom == JS_ATOM_NULL) {
   3562             snprintf(buf, buf_size, "<null>");
   3563         } else {
   3564             int i, c;
   3565             char *q;
   3566             JSString *str;
   3567 
   3568             q = buf;
   3569             p = rt->atom_array[atom];
   3570             assert(!atom_is_free(p));
   3571             str = p;
   3572             if (str) {
   3573                 if (!str->is_wide_char) {
   3574                     /* special case ASCII strings */
   3575                     c = 0;
   3576                     for(i = 0; i < str->len; i++) {
   3577                         c |= str->u.str8[i];
   3578                     }
   3579                     if (c < 0x80)
   3580                         return (const char *)str->u.str8;
   3581                 }
   3582                 for(i = 0; i < str->len; i++) {
   3583                     c = string_get(str, i);
   3584                     if ((q - buf) >= buf_size - UTF8_CHAR_LEN_MAX)
   3585                         break;
   3586                     if (c < 128) {
   3587                         *q++ = c;
   3588                     } else {
   3589                         q += unicode_to_utf8((uint8_t *)q, c);
   3590                     }
   3591                 }
   3592             }
   3593             *q = '\0';
   3594         }
   3595     }
   3596     return buf;
   3597 }
   3598 
   3599 static const char *JS_AtomGetStr(JSContext *ctx, char *buf, int buf_size, JSAtom atom)
   3600 {
   3601     return JS_AtomGetStrRT(ctx->rt, buf, buf_size, atom);
   3602 }
   3603 
   3604 static JSValue __JS_AtomToValue(JSContext *ctx, JSAtom atom, BOOL force_string)
   3605 {
   3606     char buf[ATOM_GET_STR_BUF_SIZE];
   3607 
   3608     if (__JS_AtomIsTaggedInt(atom)) {
   3609         size_t len = u32toa(buf, __JS_AtomToUInt32(atom));
   3610         return js_new_string8_len(ctx, buf, len);
   3611     } else {
   3612         JSRuntime *rt = ctx->rt;
   3613         JSAtomStruct *p;
   3614         assert(atom < rt->atom_size);
   3615         p = rt->atom_array[atom];
   3616         if (p->atom_type == JS_ATOM_TYPE_STRING) {
   3617             goto ret_string;
   3618         } else if (force_string) {
   3619             if (p->len == 0 && p->is_wide_char != 0) {
   3620                 /* no description string */
   3621                 p = rt->atom_array[JS_ATOM_empty_string];
   3622             }
   3623         ret_string:
   3624             return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
   3625         } else {
   3626             return JS_DupValue(ctx, JS_MKPTR(JS_TAG_SYMBOL, p));
   3627         }
   3628     }
   3629 }
   3630 
   3631 JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom)
   3632 {
   3633     return __JS_AtomToValue(ctx, atom, FALSE);
   3634 }
   3635 
   3636 JSValue JS_AtomToString(JSContext *ctx, JSAtom atom)
   3637 {
   3638     return __JS_AtomToValue(ctx, atom, TRUE);
   3639 }
   3640 
   3641 /* return TRUE if the atom is an array index (i.e. 0 <= index <=
   3642    2^32-2 and return its value */
   3643 static BOOL JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom)
   3644 {
   3645     if (__JS_AtomIsTaggedInt(atom)) {
   3646         *pval = __JS_AtomToUInt32(atom);
   3647         return TRUE;
   3648     } else {
   3649         JSRuntime *rt = ctx->rt;
   3650         JSAtomStruct *p;
   3651         uint32_t val;
   3652 
   3653         assert(atom < rt->atom_size);
   3654         p = rt->atom_array[atom];
   3655         if (p->atom_type == JS_ATOM_TYPE_STRING &&
   3656             is_num_string(&val, p) && val != -1) {
   3657             *pval = val;
   3658             return TRUE;
   3659         } else {
   3660             *pval = 0;
   3661             return FALSE;
   3662         }
   3663     }
   3664 }
   3665 
   3666 /* This test must be fast if atom is not a numeric index (e.g. a
   3667    method name). Return JS_UNDEFINED if not a numeric
   3668    index. JS_EXCEPTION can also be returned. */
   3669 static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom)
   3670 {
   3671     JSRuntime *rt = ctx->rt;
   3672     JSAtomStruct *p1;
   3673     JSString *p;
   3674     int c, ret;
   3675     JSValue num, str;
   3676 
   3677     if (__JS_AtomIsTaggedInt(atom))
   3678         return JS_NewInt32(ctx, __JS_AtomToUInt32(atom));
   3679     assert(atom < rt->atom_size);
   3680     p1 = rt->atom_array[atom];
   3681     if (p1->atom_type != JS_ATOM_TYPE_STRING)
   3682         return JS_UNDEFINED;
   3683     switch(atom) {
   3684     case JS_ATOM_minus_zero:
   3685         return __JS_NewFloat64(ctx, -0.0);
   3686     case JS_ATOM_Infinity:
   3687         return __JS_NewFloat64(ctx, INFINITY);
   3688     case JS_ATOM_minus_Infinity:
   3689         return __JS_NewFloat64(ctx, -INFINITY);
   3690     case JS_ATOM_NaN:
   3691         return __JS_NewFloat64(ctx, NAN);
   3692     default:
   3693         break;
   3694     }
   3695     p = p1;
   3696     if (p->len == 0)
   3697         return JS_UNDEFINED;
   3698     c = string_get(p, 0);
   3699     if (!is_num(c) && c != '-')
   3700         return JS_UNDEFINED;
   3701     /* this is ECMA CanonicalNumericIndexString primitive */
   3702     num = JS_ToNumber(ctx, JS_MKPTR(JS_TAG_STRING, p));
   3703     if (JS_IsException(num))
   3704         return num;
   3705     str = JS_ToString(ctx, num);
   3706     if (JS_IsException(str)) {
   3707         JS_FreeValue(ctx, num);
   3708         return str;
   3709     }
   3710     ret = js_string_eq(ctx, p, JS_VALUE_GET_STRING(str));
   3711     JS_FreeValue(ctx, str);
   3712     if (ret) {
   3713         return num;
   3714     } else {
   3715         JS_FreeValue(ctx, num);
   3716         return JS_UNDEFINED;
   3717     }
   3718 }
   3719 
   3720 /* return -1 if exception or TRUE/FALSE */
   3721 static int JS_AtomIsNumericIndex(JSContext *ctx, JSAtom atom)
   3722 {
   3723     JSValue num;
   3724     num = JS_AtomIsNumericIndex1(ctx, atom);
   3725     if (likely(JS_IsUndefined(num)))
   3726         return FALSE;
   3727     if (JS_IsException(num))
   3728         return -1;
   3729     JS_FreeValue(ctx, num);
   3730     return TRUE;
   3731 }
   3732 
   3733 void JS_FreeAtom(JSContext *ctx, JSAtom v)
   3734 {
   3735     if (!__JS_AtomIsConst(v))
   3736         __JS_FreeAtom(ctx->rt, v);
   3737 }
   3738 
   3739 void JS_FreeAtomRT(JSRuntime *rt, JSAtom v)
   3740 {
   3741     if (!__JS_AtomIsConst(v))
   3742         __JS_FreeAtom(rt, v);
   3743 }
   3744 
   3745 /* return TRUE if 'v' is a symbol with a string description */
   3746 static BOOL JS_AtomSymbolHasDescription(JSContext *ctx, JSAtom v)
   3747 {
   3748     JSRuntime *rt;
   3749     JSAtomStruct *p;
   3750 
   3751     rt = ctx->rt;
   3752     if (__JS_AtomIsTaggedInt(v))
   3753         return FALSE;
   3754     p = rt->atom_array[v];
   3755     return (((p->atom_type == JS_ATOM_TYPE_SYMBOL &&
   3756               p->hash != JS_ATOM_HASH_PRIVATE) ||
   3757              p->atom_type == JS_ATOM_TYPE_GLOBAL_SYMBOL) &&
   3758             !(p->len == 0 && p->is_wide_char != 0));
   3759 }
   3760 
   3761 /* free with JS_FreeCString() */
   3762 const char *JS_AtomToCStringLen(JSContext *ctx, size_t *plen, JSAtom atom)
   3763 {
   3764     JSValue str;
   3765     const char *cstr;
   3766 
   3767     str = JS_AtomToString(ctx, atom);
   3768     if (JS_IsException(str)) {
   3769         if (plen)
   3770             *plen = 0;
   3771         return NULL;
   3772     }
   3773     cstr = JS_ToCStringLen(ctx, plen, str);
   3774     JS_FreeValue(ctx, str);
   3775     return cstr;
   3776 }
   3777 
   3778 /* return a string atom containing name concatenated with str1 */
   3779 static JSAtom js_atom_concat_str(JSContext *ctx, JSAtom name, const char *str1)
   3780 {
   3781     JSValue str;
   3782     JSAtom atom;
   3783     const char *cstr;
   3784     char *cstr2;
   3785     size_t len, len1;
   3786 
   3787     str = JS_AtomToString(ctx, name);
   3788     if (JS_IsException(str))
   3789         return JS_ATOM_NULL;
   3790     cstr = JS_ToCStringLen(ctx, &len, str);
   3791     if (!cstr)
   3792         goto fail;
   3793     len1 = strlen(str1);
   3794     cstr2 = js_malloc(ctx, len + len1 + 1);
   3795     if (!cstr2)
   3796         goto fail;
   3797     memcpy(cstr2, cstr, len);
   3798     memcpy(cstr2 + len, str1, len1);
   3799     cstr2[len + len1] = '\0';
   3800     atom = JS_NewAtomLen(ctx, cstr2, len + len1);
   3801     js_free(ctx, cstr2);
   3802     JS_FreeCString(ctx, cstr);
   3803     JS_FreeValue(ctx, str);
   3804     return atom;
   3805  fail:
   3806     JS_FreeCString(ctx, cstr);
   3807     JS_FreeValue(ctx, str);
   3808     return JS_ATOM_NULL;
   3809 }
   3810 
   3811 static JSAtom js_atom_concat_num(JSContext *ctx, JSAtom name, uint32_t n)
   3812 {
   3813     char buf[16];
   3814     size_t len;
   3815     len = u32toa(buf, n);
   3816     buf[len] = '\0';
   3817     return js_atom_concat_str(ctx, name, buf);
   3818 }
   3819 
   3820 static inline BOOL JS_IsEmptyString(JSValueConst v)
   3821 {
   3822     return JS_VALUE_GET_TAG(v) == JS_TAG_STRING && JS_VALUE_GET_STRING(v)->len == 0;
   3823 }
   3824 
   3825 /* JSClass support */
   3826 
   3827 #ifdef CONFIG_ATOMICS
   3828 static pthread_mutex_t js_class_id_mutex = PTHREAD_MUTEX_INITIALIZER;
   3829 #endif
   3830 
   3831 /* a new class ID is allocated if *pclass_id != 0 */
   3832 JSClassID JS_NewClassID(JSClassID *pclass_id)
   3833 {
   3834     JSClassID class_id;
   3835 #ifdef CONFIG_ATOMICS
   3836     pthread_mutex_lock(&js_class_id_mutex);
   3837 #endif
   3838     class_id = *pclass_id;
   3839     if (class_id == 0) {
   3840         class_id = js_class_id_alloc++;
   3841         *pclass_id = class_id;
   3842     }
   3843 #ifdef CONFIG_ATOMICS
   3844     pthread_mutex_unlock(&js_class_id_mutex);
   3845 #endif
   3846     return class_id;
   3847 }
   3848 
   3849 JSClassID JS_GetClassID(JSValue v)
   3850 {
   3851     JSObject *p;
   3852     if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT)
   3853         return JS_INVALID_CLASS_ID;
   3854     p = JS_VALUE_GET_OBJ(v);
   3855     return p->class_id;
   3856 }
   3857 
   3858 BOOL JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id)
   3859 {
   3860     return (class_id < rt->class_count &&
   3861             rt->class_array[class_id].class_id != 0);
   3862 }
   3863 
   3864 /* create a new object internal class. Return -1 if error, 0 if
   3865    OK. The finalizer can be NULL if none is needed. */
   3866 static int JS_NewClass1(JSRuntime *rt, JSClassID class_id,
   3867                         const JSClassDef *class_def, JSAtom name)
   3868 {
   3869     int new_size, i;
   3870     JSClass *cl, *new_class_array;
   3871     struct list_head *el;
   3872 
   3873     if (class_id >= (1 << 16))
   3874         return -1;
   3875     if (class_id < rt->class_count &&
   3876         rt->class_array[class_id].class_id != 0)
   3877         return -1;
   3878 
   3879     if (class_id >= rt->class_count) {
   3880         new_size = max_int(JS_CLASS_INIT_COUNT,
   3881                            max_int(class_id + 1, rt->class_count * 3 / 2));
   3882 
   3883         /* reallocate the context class prototype array, if any */
   3884         list_for_each(el, &rt->context_list) {
   3885             JSContext *ctx = list_entry(el, JSContext, link);
   3886             JSValue *new_tab;
   3887             new_tab = js_realloc_rt(rt, ctx->class_proto,
   3888                                     sizeof(ctx->class_proto[0]) * new_size);
   3889             if (!new_tab)
   3890                 return -1;
   3891             for(i = rt->class_count; i < new_size; i++)
   3892                 new_tab[i] = JS_NULL;
   3893             ctx->class_proto = new_tab;
   3894         }
   3895         /* reallocate the class array */
   3896         new_class_array = js_realloc_rt(rt, rt->class_array,
   3897                                         sizeof(JSClass) * new_size);
   3898         if (!new_class_array)
   3899             return -1;
   3900         memset(new_class_array + rt->class_count, 0,
   3901                (new_size - rt->class_count) * sizeof(JSClass));
   3902         rt->class_array = new_class_array;
   3903         rt->class_count = new_size;
   3904     }
   3905     cl = &rt->class_array[class_id];
   3906     cl->class_id = class_id;
   3907     cl->class_name = JS_DupAtomRT(rt, name);
   3908     cl->finalizer = class_def->finalizer;
   3909     cl->gc_mark = class_def->gc_mark;
   3910     cl->call = class_def->call;
   3911     cl->exotic = class_def->exotic;
   3912     return 0;
   3913 }
   3914 
   3915 int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def)
   3916 {
   3917     int ret, len;
   3918     JSAtom name;
   3919 
   3920     len = strlen(class_def->class_name);
   3921     name = __JS_FindAtom(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
   3922     if (name == JS_ATOM_NULL) {
   3923         name = __JS_NewAtomInit(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
   3924         if (name == JS_ATOM_NULL)
   3925             return -1;
   3926     }
   3927     ret = JS_NewClass1(rt, class_id, class_def, name);
   3928     JS_FreeAtomRT(rt, name);
   3929     return ret;
   3930 }
   3931 
   3932 static JSValue js_new_string8_len(JSContext *ctx, const char *buf, int len)
   3933 {
   3934     JSString *str;
   3935 
   3936     if (len <= 0) {
   3937         return JS_AtomToString(ctx, JS_ATOM_empty_string);
   3938     }
   3939     str = js_alloc_string(ctx, len, 0);
   3940     if (!str)
   3941         return JS_EXCEPTION;
   3942     memcpy(str->u.str8, buf, len);
   3943     str->u.str8[len] = '\0';
   3944     return JS_MKPTR(JS_TAG_STRING, str);
   3945 }
   3946 
   3947 static JSValue js_new_string8(JSContext *ctx, const char *buf)
   3948 {
   3949     return js_new_string8_len(ctx, buf, strlen(buf));
   3950 }
   3951 
   3952 static JSValue js_new_string16_len(JSContext *ctx, const uint16_t *buf, int len)
   3953 {
   3954     JSString *str;
   3955     str = js_alloc_string(ctx, len, 1);
   3956     if (!str)
   3957         return JS_EXCEPTION;
   3958     memcpy(str->u.str16, buf, len * 2);
   3959     return JS_MKPTR(JS_TAG_STRING, str);
   3960 }
   3961 
   3962 static JSValue js_new_string_char(JSContext *ctx, uint16_t c)
   3963 {
   3964     if (c < 0x100) {
   3965         uint8_t ch8 = c;
   3966         return js_new_string8_len(ctx, (const char *)&ch8, 1);
   3967     } else {
   3968         uint16_t ch16 = c;
   3969         return js_new_string16_len(ctx, &ch16, 1);
   3970     }
   3971 }
   3972 
   3973 static JSValue js_sub_string(JSContext *ctx, JSString *p, int start, int end)
   3974 {
   3975     int len = end - start;
   3976     if (start == 0 && end == p->len) {
   3977         return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
   3978     }
   3979     if (p->is_wide_char && len > 0) {
   3980         JSString *str;
   3981         int i;
   3982         uint16_t c = 0;
   3983         for (i = start; i < end; i++) {
   3984             c |= p->u.str16[i];
   3985         }
   3986         if (c > 0xFF)
   3987             return js_new_string16_len(ctx, p->u.str16 + start, len);
   3988 
   3989         str = js_alloc_string(ctx, len, 0);
   3990         if (!str)
   3991             return JS_EXCEPTION;
   3992         for (i = 0; i < len; i++) {
   3993             str->u.str8[i] = p->u.str16[start + i];
   3994         }
   3995         str->u.str8[len] = '\0';
   3996         return JS_MKPTR(JS_TAG_STRING, str);
   3997     } else {
   3998         return js_new_string8_len(ctx, (const char *)(p->u.str8 + start), len);
   3999     }
   4000 }
   4001 
   4002 typedef struct StringBuffer {
   4003     JSContext *ctx;
   4004     JSString *str;
   4005     int len;
   4006     int size;
   4007     int is_wide_char;
   4008     int error_status;
   4009 } StringBuffer;
   4010 
   4011 /* It is valid to call string_buffer_end() and all string_buffer functions even
   4012    if string_buffer_init() or another string_buffer function returns an error.
   4013    If the error_status is set, string_buffer_end() returns JS_EXCEPTION.
   4014  */
   4015 static int string_buffer_init2(JSContext *ctx, StringBuffer *s, int size,
   4016                                int is_wide)
   4017 {
   4018     s->ctx = ctx;
   4019     s->size = size;
   4020     s->len = 0;
   4021     s->is_wide_char = is_wide;
   4022     s->error_status = 0;
   4023     s->str = js_alloc_string(ctx, size, is_wide);
   4024     if (unlikely(!s->str)) {
   4025         s->size = 0;
   4026         return s->error_status = -1;
   4027     }
   4028 #ifdef DUMP_LEAKS
   4029     /* the StringBuffer may reallocate the JSString, only link it at the end */
   4030     list_del(&s->str->link);
   4031 #endif
   4032     return 0;
   4033 }
   4034 
   4035 static inline int string_buffer_init(JSContext *ctx, StringBuffer *s, int size)
   4036 {
   4037     return string_buffer_init2(ctx, s, size, 0);
   4038 }
   4039 
   4040 static void string_buffer_free(StringBuffer *s)
   4041 {
   4042     js_free(s->ctx, s->str);
   4043     s->str = NULL;
   4044 }
   4045 
   4046 static int string_buffer_set_error(StringBuffer *s)
   4047 {
   4048     js_free(s->ctx, s->str);
   4049     s->str = NULL;
   4050     s->size = 0;
   4051     s->len = 0;
   4052     return s->error_status = -1;
   4053 }
   4054 
   4055 static no_inline int string_buffer_widen(StringBuffer *s, int size)
   4056 {
   4057     JSString *str;
   4058     size_t slack;
   4059     int i;
   4060 
   4061     if (s->error_status)
   4062         return -1;
   4063 
   4064     str = js_realloc2(s->ctx, s->str, sizeof(JSString) + (size << 1), &slack);
   4065     if (!str)
   4066         return string_buffer_set_error(s);
   4067     size += slack >> 1;
   4068     for(i = s->len; i-- > 0;) {
   4069         str->u.str16[i] = str->u.str8[i];
   4070     }
   4071     s->is_wide_char = 1;
   4072     s->size = size;
   4073     s->str = str;
   4074     return 0;
   4075 }
   4076 
   4077 static no_inline int string_buffer_realloc(StringBuffer *s, int new_len, int c)
   4078 {
   4079     JSString *new_str;
   4080     int new_size;
   4081     size_t new_size_bytes, slack;
   4082 
   4083     if (s->error_status)
   4084         return -1;
   4085 
   4086     if (new_len > JS_STRING_LEN_MAX) {
   4087         JS_ThrowInternalError(s->ctx, "string too long");
   4088         return string_buffer_set_error(s);
   4089     }
   4090     new_size = min_int(max_int(new_len, s->size * 3 / 2), JS_STRING_LEN_MAX);
   4091     if (!s->is_wide_char && c >= 0x100) {
   4092         return string_buffer_widen(s, new_size);
   4093     }
   4094     new_size_bytes = sizeof(JSString) + (new_size << s->is_wide_char) + 1 - s->is_wide_char;
   4095     new_str = js_realloc2(s->ctx, s->str, new_size_bytes, &slack);
   4096     if (!new_str)
   4097         return string_buffer_set_error(s);
   4098     new_size = min_int(new_size + (slack >> s->is_wide_char), JS_STRING_LEN_MAX);
   4099     s->size = new_size;
   4100     s->str = new_str;
   4101     return 0;
   4102 }
   4103 
   4104 static no_inline int string_buffer_putc16_slow(StringBuffer *s, uint32_t c)
   4105 {
   4106     if (unlikely(s->len >= s->size)) {
   4107         if (string_buffer_realloc(s, s->len + 1, c))
   4108             return -1;
   4109     }
   4110     if (s->is_wide_char) {
   4111         s->str->u.str16[s->len++] = c;
   4112     } else if (c < 0x100) {
   4113         s->str->u.str8[s->len++] = c;
   4114     } else {
   4115         if (string_buffer_widen(s, s->size))
   4116             return -1;
   4117         s->str->u.str16[s->len++] = c;
   4118     }
   4119     return 0;
   4120 }
   4121 
   4122 /* 0 <= c <= 0xff */
   4123 static int string_buffer_putc8(StringBuffer *s, uint32_t c)
   4124 {
   4125     if (unlikely(s->len >= s->size)) {
   4126         if (string_buffer_realloc(s, s->len + 1, c))
   4127             return -1;
   4128     }
   4129     if (s->is_wide_char) {
   4130         s->str->u.str16[s->len++] = c;
   4131     } else {
   4132         s->str->u.str8[s->len++] = c;
   4133     }
   4134     return 0;
   4135 }
   4136 
   4137 /* 0 <= c <= 0xffff */
   4138 static int string_buffer_putc16(StringBuffer *s, uint32_t c)
   4139 {
   4140     if (likely(s->len < s->size)) {
   4141         if (s->is_wide_char) {
   4142             s->str->u.str16[s->len++] = c;
   4143             return 0;
   4144         } else if (c < 0x100) {
   4145             s->str->u.str8[s->len++] = c;
   4146             return 0;
   4147         }
   4148     }
   4149     return string_buffer_putc16_slow(s, c);
   4150 }
   4151 
   4152 static int string_buffer_putc_slow(StringBuffer *s, uint32_t c)
   4153 {
   4154     if (unlikely(c >= 0x10000)) {
   4155         /* surrogate pair */
   4156         if (string_buffer_putc16(s, get_hi_surrogate(c)))
   4157             return -1;
   4158         c = get_lo_surrogate(c);
   4159     }
   4160     return string_buffer_putc16(s, c);
   4161 }
   4162 
   4163 /* 0 <= c <= 0x10ffff */
   4164 static inline int string_buffer_putc(StringBuffer *s, uint32_t c)
   4165 {
   4166     if (likely(s->len < s->size)) {
   4167         if (s->is_wide_char) {
   4168             if (c < 0x10000) {
   4169                 s->str->u.str16[s->len++] = c;
   4170                 return 0;
   4171             } else if (likely((s->len + 1) < s->size)) {
   4172                 s->str->u.str16[s->len++] = get_hi_surrogate(c);
   4173                 s->str->u.str16[s->len++] = get_lo_surrogate(c);
   4174                 return 0;
   4175             }
   4176         } else if (c < 0x100) {
   4177             s->str->u.str8[s->len++] = c;
   4178             return 0;
   4179         }
   4180     }
   4181     return string_buffer_putc_slow(s, c);
   4182 }
   4183 
   4184 static int string_getc(const JSString *p, int *pidx)
   4185 {
   4186     int idx, c, c1;
   4187     idx = *pidx;
   4188     if (p->is_wide_char) {
   4189         c = p->u.str16[idx++];
   4190         if (is_hi_surrogate(c) && idx < p->len) {
   4191             c1 = p->u.str16[idx];
   4192             if (is_lo_surrogate(c1)) {
   4193                 c = from_surrogate(c, c1);
   4194                 idx++;
   4195             }
   4196         }
   4197     } else {
   4198         c = p->u.str8[idx++];
   4199     }
   4200     *pidx = idx;
   4201     return c;
   4202 }
   4203 
   4204 static int string_buffer_write8(StringBuffer *s, const uint8_t *p, int len)
   4205 {
   4206     int i;
   4207 
   4208     if (s->len + len > s->size) {
   4209         if (string_buffer_realloc(s, s->len + len, 0))
   4210             return -1;
   4211     }
   4212     if (s->is_wide_char) {
   4213         for (i = 0; i < len; i++) {
   4214             s->str->u.str16[s->len + i] = p[i];
   4215         }
   4216         s->len += len;
   4217     } else {
   4218         memcpy(&s->str->u.str8[s->len], p, len);
   4219         s->len += len;
   4220     }
   4221     return 0;
   4222 }
   4223 
   4224 static int string_buffer_write16(StringBuffer *s, const uint16_t *p, int len)
   4225 {
   4226     int c = 0, i;
   4227 
   4228     for (i = 0; i < len; i++) {
   4229         c |= p[i];
   4230     }
   4231     if (s->len + len > s->size) {
   4232         if (string_buffer_realloc(s, s->len + len, c))
   4233             return -1;
   4234     } else if (!s->is_wide_char && c >= 0x100) {
   4235         if (string_buffer_widen(s, s->size))
   4236             return -1;
   4237     }
   4238     if (s->is_wide_char) {
   4239         memcpy(&s->str->u.str16[s->len], p, len << 1);
   4240         s->len += len;
   4241     } else {
   4242         for (i = 0; i < len; i++) {
   4243             s->str->u.str8[s->len + i] = p[i];
   4244         }
   4245         s->len += len;
   4246     }
   4247     return 0;
   4248 }
   4249 
   4250 /* appending an ASCII string */
   4251 static int string_buffer_puts8(StringBuffer *s, const char *str)
   4252 {
   4253     return string_buffer_write8(s, (const uint8_t *)str, strlen(str));
   4254 }
   4255 
   4256 static int string_buffer_concat(StringBuffer *s, const JSString *p,
   4257                                 uint32_t from, uint32_t to)
   4258 {
   4259     if (to <= from)
   4260         return 0;
   4261     if (p->is_wide_char)
   4262         return string_buffer_write16(s, p->u.str16 + from, to - from);
   4263     else
   4264         return string_buffer_write8(s, p->u.str8 + from, to - from);
   4265 }
   4266 
   4267 static int string_buffer_concat_value(StringBuffer *s, JSValueConst v)
   4268 {
   4269     JSString *p;
   4270     JSValue v1;
   4271     int res;
   4272 
   4273     if (s->error_status) {
   4274         /* prevent exception overload */
   4275         return -1;
   4276     }
   4277     if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) {
   4278         if (JS_VALUE_GET_TAG(v) == JS_TAG_STRING_ROPE) {
   4279             JSStringRope *r = JS_VALUE_GET_STRING_ROPE(v);
   4280             /* recursion is acceptable because the rope depth is bounded */
   4281             if (string_buffer_concat_value(s, r->left))
   4282                 return -1;
   4283             return string_buffer_concat_value(s, r->right);
   4284         } else {
   4285             v1 = JS_ToString(s->ctx, v);
   4286             if (JS_IsException(v1))
   4287                 return string_buffer_set_error(s);
   4288             p = JS_VALUE_GET_STRING(v1);
   4289             res = string_buffer_concat(s, p, 0, p->len);
   4290             JS_FreeValue(s->ctx, v1);
   4291             return res;
   4292         }
   4293     }
   4294     p = JS_VALUE_GET_STRING(v);
   4295     return string_buffer_concat(s, p, 0, p->len);
   4296 }
   4297 
   4298 static int string_buffer_concat_value_free(StringBuffer *s, JSValue v)
   4299 {
   4300     JSString *p;
   4301     int res;
   4302 
   4303     if (s->error_status) {
   4304         /* prevent exception overload */
   4305         JS_FreeValue(s->ctx, v);
   4306         return -1;
   4307     }
   4308     if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) {
   4309         v = JS_ToStringFree(s->ctx, v);
   4310         if (JS_IsException(v))
   4311             return string_buffer_set_error(s);
   4312     }
   4313     p = JS_VALUE_GET_STRING(v);
   4314     res = string_buffer_concat(s, p, 0, p->len);
   4315     JS_FreeValue(s->ctx, v);
   4316     return res;
   4317 }
   4318 
   4319 static int string_buffer_fill(StringBuffer *s, int c, int count)
   4320 {
   4321     /* XXX: optimize */
   4322     if (s->len + count > s->size) {
   4323         if (string_buffer_realloc(s, s->len + count, c))
   4324             return -1;
   4325     }
   4326     while (count-- > 0) {
   4327         if (string_buffer_putc16(s, c))
   4328             return -1;
   4329     }
   4330     return 0;
   4331 }
   4332 
   4333 static JSValue string_buffer_end(StringBuffer *s)
   4334 {
   4335     JSString *str;
   4336     str = s->str;
   4337     if (s->error_status)
   4338         return JS_EXCEPTION;
   4339     if (s->len == 0) {
   4340         js_free(s->ctx, str);
   4341         s->str = NULL;
   4342         return JS_AtomToString(s->ctx, JS_ATOM_empty_string);
   4343     }
   4344     if (s->len < s->size) {
   4345         /* smaller size so js_realloc should not fail, but OK if it does */
   4346         /* XXX: should add some slack to avoid unnecessary calls */
   4347         /* XXX: might need to use malloc+free to ensure smaller size */
   4348         str = js_realloc_rt(s->ctx->rt, str, sizeof(JSString) +
   4349                             (s->len << s->is_wide_char) + 1 - s->is_wide_char);
   4350         if (str == NULL)
   4351             str = s->str;
   4352         s->str = str;
   4353     }
   4354     if (!s->is_wide_char)
   4355         str->u.str8[s->len] = 0;
   4356 #ifdef DUMP_LEAKS
   4357     list_add_tail(&str->link, &s->ctx->rt->string_list);
   4358 #endif
   4359     str->is_wide_char = s->is_wide_char;
   4360     str->len = s->len;
   4361     s->str = NULL;
   4362     return JS_MKPTR(JS_TAG_STRING, str);
   4363 }
   4364 
   4365 /* create a string from a UTF-8 buffer */
   4366 JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len)
   4367 {
   4368     const uint8_t *p, *p_end, *p_start, *p_next;
   4369     uint32_t c;
   4370     StringBuffer b_s, *b = &b_s;
   4371     size_t len1;
   4372 
   4373     p_start = (const uint8_t *)buf;
   4374     p_end = p_start + buf_len;
   4375     len1 = count_ascii(p_start, buf_len);
   4376     p = p_start + len1;
   4377     if (len1 > JS_STRING_LEN_MAX)
   4378         return JS_ThrowInternalError(ctx, "string too long");
   4379     if (p == p_end) {
   4380         /* ASCII string */
   4381         return js_new_string8_len(ctx, buf, buf_len);
   4382     } else {
   4383         if (string_buffer_init(ctx, b, buf_len))
   4384             goto fail;
   4385         string_buffer_write8(b, p_start, len1);
   4386         while (p < p_end) {
   4387             if (*p < 128) {
   4388                 string_buffer_putc8(b, *p++);
   4389             } else {
   4390                 /* parse utf-8 sequence, return 0xFFFFFFFF for error */
   4391                 c = unicode_from_utf8(p, p_end - p, &p_next);
   4392                 if (c < 0x10000) {
   4393                     p = p_next;
   4394                 } else if (c <= 0x10FFFF) {
   4395                     p = p_next;
   4396                     /* surrogate pair */
   4397                     string_buffer_putc16(b, get_hi_surrogate(c));
   4398                     c = get_lo_surrogate(c);
   4399                 } else {
   4400                     /* invalid char */
   4401                     c = 0xfffd;
   4402                     /* skip the invalid chars */
   4403                     /* XXX: seems incorrect. Why not just use c = *p++; ? */
   4404                     while (p < p_end && (*p >= 0x80 && *p < 0xc0))
   4405                         p++;
   4406                     if (p < p_end) {
   4407                         p++;
   4408                         while (p < p_end && (*p >= 0x80 && *p < 0xc0))
   4409                             p++;
   4410                     }
   4411                 }
   4412                 string_buffer_putc16(b, c);
   4413             }
   4414         }
   4415     }
   4416     return string_buffer_end(b);
   4417 
   4418  fail:
   4419     string_buffer_free(b);
   4420     return JS_EXCEPTION;
   4421 }
   4422 
   4423 static JSValue JS_ConcatString3(JSContext *ctx, const char *str1,
   4424                                 JSValue str2, const char *str3)
   4425 {
   4426     StringBuffer b_s, *b = &b_s;
   4427     int len1, len3;
   4428     JSString *p;
   4429 
   4430     if (unlikely(JS_VALUE_GET_TAG(str2) != JS_TAG_STRING)) {
   4431         str2 = JS_ToStringFree(ctx, str2);
   4432         if (JS_IsException(str2))
   4433             goto fail;
   4434     }
   4435     p = JS_VALUE_GET_STRING(str2);
   4436     len1 = strlen(str1);
   4437     len3 = strlen(str3);
   4438 
   4439     if (string_buffer_init2(ctx, b, len1 + p->len + len3, p->is_wide_char))
   4440         goto fail;
   4441 
   4442     string_buffer_write8(b, (const uint8_t *)str1, len1);
   4443     string_buffer_concat(b, p, 0, p->len);
   4444     string_buffer_write8(b, (const uint8_t *)str3, len3);
   4445 
   4446     JS_FreeValue(ctx, str2);
   4447     return string_buffer_end(b);
   4448 
   4449  fail:
   4450     JS_FreeValue(ctx, str2);
   4451     return JS_EXCEPTION;
   4452 }
   4453 
   4454 JSValue JS_NewAtomString(JSContext *ctx, const char *str)
   4455 {
   4456     JSAtom atom = JS_NewAtom(ctx, str);
   4457     if (atom == JS_ATOM_NULL)
   4458         return JS_EXCEPTION;
   4459     JSValue val = JS_AtomToString(ctx, atom);
   4460     JS_FreeAtom(ctx, atom);
   4461     return val;
   4462 }
   4463 
   4464 /* return (NULL, 0) if exception. */
   4465 /* return pointer into a JSString with a live ref_count */
   4466 /* cesu8 determines if non-BMP1 codepoints are encoded as 1 or 2 utf-8 sequences */
   4467 const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, BOOL cesu8)
   4468 {
   4469     JSValue val;
   4470     JSString *str, *str_new;
   4471     int pos, len, c, c1;
   4472     uint8_t *q;
   4473 
   4474     if (JS_VALUE_GET_TAG(val1) != JS_TAG_STRING) {
   4475         val = JS_ToString(ctx, val1);
   4476         if (JS_IsException(val))
   4477             goto fail;
   4478     } else {
   4479         val = JS_DupValue(ctx, val1);
   4480     }
   4481 
   4482     str = JS_VALUE_GET_STRING(val);
   4483     len = str->len;
   4484     if (!str->is_wide_char) {
   4485         const uint8_t *src = str->u.str8;
   4486         int count;
   4487 
   4488         /* count the number of non-ASCII characters */
   4489         /* Scanning the whole string is required for ASCII strings,
   4490            and computing the number of non-ASCII bytes is less expensive
   4491            than testing each byte, hence this method is faster for ASCII
   4492            strings, which is the most common case.
   4493          */
   4494         count = 0;
   4495         for (pos = 0; pos < len; pos++) {
   4496             count += src[pos] >> 7;
   4497         }
   4498         if (count == 0) {
   4499             if (plen)
   4500                 *plen = len;
   4501             return (const char *)src;
   4502         }
   4503         str_new = js_alloc_string(ctx, len + count, 0);
   4504         if (!str_new)
   4505             goto fail;
   4506         q = str_new->u.str8;
   4507         for (pos = 0; pos < len; pos++) {
   4508             c = src[pos];
   4509             if (c < 0x80) {
   4510                 *q++ = c;
   4511             } else {
   4512                 *q++ = (c >> 6) | 0xc0;
   4513                 *q++ = (c & 0x3f) | 0x80;
   4514             }
   4515         }
   4516     } else {
   4517         const uint16_t *src = str->u.str16;
   4518         /* Allocate 3 bytes per 16 bit code point. Surrogate pairs may
   4519            produce 4 bytes but use 2 code points.
   4520          */
   4521         str_new = js_alloc_string(ctx, len * 3, 0);
   4522         if (!str_new)
   4523             goto fail;
   4524         q = str_new->u.str8;
   4525         pos = 0;
   4526         while (pos < len) {
   4527             c = src[pos++];
   4528             if (c < 0x80) {
   4529                 *q++ = c;
   4530             } else {
   4531                 if (is_hi_surrogate(c)) {
   4532                     if (pos < len && !cesu8) {
   4533                         c1 = src[pos];
   4534                         if (is_lo_surrogate(c1)) {
   4535                             pos++;
   4536                             c = from_surrogate(c, c1);
   4537                         } else {
   4538                             /* Keep unmatched surrogate code points */
   4539                             /* c = 0xfffd; */ /* error */
   4540                         }
   4541                     } else {
   4542                         /* Keep unmatched surrogate code points */
   4543                         /* c = 0xfffd; */ /* error */
   4544                     }
   4545                 }
   4546                 q += unicode_to_utf8(q, c);
   4547             }
   4548         }
   4549     }
   4550 
   4551     *q = '\0';
   4552     str_new->len = q - str_new->u.str8;
   4553     JS_FreeValue(ctx, val);
   4554     if (plen)
   4555         *plen = str_new->len;
   4556     return (const char *)str_new->u.str8;
   4557  fail:
   4558     if (plen)
   4559         *plen = 0;
   4560     return NULL;
   4561 }
   4562 
   4563 void JS_FreeCString(JSContext *ctx, const char *ptr)
   4564 {
   4565     JSString *p;
   4566     if (!ptr)
   4567         return;
   4568     /* purposely removing constness */
   4569     p = container_of(ptr, JSString, u);
   4570     JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
   4571 }
   4572 
   4573 static int memcmp16_8(const uint16_t *src1, const uint8_t *src2, int len)
   4574 {
   4575     int c, i;
   4576     for(i = 0; i < len; i++) {
   4577         c = src1[i] - src2[i];
   4578         if (c != 0)
   4579             return c;
   4580     }
   4581     return 0;
   4582 }
   4583 
   4584 static int memcmp16(const uint16_t *src1, const uint16_t *src2, int len)
   4585 {
   4586     int c, i;
   4587     for(i = 0; i < len; i++) {
   4588         c = src1[i] - src2[i];
   4589         if (c != 0)
   4590             return c;
   4591     }
   4592     return 0;
   4593 }
   4594 
   4595 static int js_string_memcmp(const JSString *p1, int pos1, const JSString *p2,
   4596                             int pos2, int len)
   4597 {
   4598     int res;
   4599 
   4600     if (likely(!p1->is_wide_char)) {
   4601         if (likely(!p2->is_wide_char))
   4602             res = memcmp(p1->u.str8 + pos1, p2->u.str8 + pos2, len);
   4603         else
   4604             res = -memcmp16_8(p2->u.str16 + pos2, p1->u.str8 + pos1, len);
   4605     } else {
   4606         if (!p2->is_wide_char)
   4607             res = memcmp16_8(p1->u.str16 + pos1, p2->u.str8 + pos2, len);
   4608         else
   4609             res = memcmp16(p1->u.str16 + pos1, p2->u.str16 + pos2, len);
   4610     }
   4611     return res;
   4612 }
   4613 
   4614 static BOOL js_string_eq(JSContext *ctx,
   4615                          const JSString *p1, const JSString *p2)
   4616 {
   4617     if (p1->len != p2->len)
   4618         return FALSE;
   4619     if (p1 == p2)
   4620         return TRUE;
   4621     return js_string_memcmp(p1, 0, p2, 0, p1->len) == 0;
   4622 }
   4623 
   4624 /* return < 0, 0 or > 0 */
   4625 static int js_string_compare(JSContext *ctx,
   4626                              const JSString *p1, const JSString *p2)
   4627 {
   4628     int res, len;
   4629     len = min_int(p1->len, p2->len);
   4630     res = js_string_memcmp(p1, 0, p2, 0, len);
   4631     if (res == 0) {
   4632         if (p1->len == p2->len)
   4633             res = 0;
   4634         else if (p1->len < p2->len)
   4635             res = -1;
   4636         else
   4637             res = 1;
   4638     }
   4639     return res;
   4640 }
   4641 
   4642 static void copy_str16(uint16_t *dst, const JSString *p, int offset, int len)
   4643 {
   4644     if (p->is_wide_char) {
   4645         memcpy(dst, p->u.str16 + offset, len * 2);
   4646     } else {
   4647         const uint8_t *src1 = p->u.str8 + offset;
   4648         int i;
   4649 
   4650         for(i = 0; i < len; i++)
   4651             dst[i] = src1[i];
   4652     }
   4653 }
   4654 
   4655 static JSValue JS_ConcatString1(JSContext *ctx,
   4656                                 const JSString *p1, const JSString *p2)
   4657 {
   4658     JSString *p;
   4659     uint32_t len;
   4660     int is_wide_char;
   4661 
   4662     len = p1->len + p2->len;
   4663     if (len > JS_STRING_LEN_MAX)
   4664         return JS_ThrowInternalError(ctx, "string too long");
   4665     is_wide_char = p1->is_wide_char | p2->is_wide_char;
   4666     p = js_alloc_string(ctx, len, is_wide_char);
   4667     if (!p)
   4668         return JS_EXCEPTION;
   4669     if (!is_wide_char) {
   4670         memcpy(p->u.str8, p1->u.str8, p1->len);
   4671         memcpy(p->u.str8 + p1->len, p2->u.str8, p2->len);
   4672         p->u.str8[len] = '\0';
   4673     } else {
   4674         copy_str16(p->u.str16, p1, 0, p1->len);
   4675         copy_str16(p->u.str16 + p1->len, p2, 0, p2->len);
   4676     }
   4677     return JS_MKPTR(JS_TAG_STRING, p);
   4678 }
   4679 
   4680 static BOOL JS_ConcatStringInPlace(JSContext *ctx, JSString *p1, JSValueConst op2) {
   4681     if (JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {
   4682         JSString *p2 = JS_VALUE_GET_STRING(op2);
   4683         size_t size1;
   4684 
   4685         if (p2->len == 0)
   4686             return TRUE;
   4687         if (js_rc(p1)->ref_count != 1)
   4688             return FALSE;
   4689         size1 = js_malloc_usable_size(ctx, p1);
   4690         if (p1->is_wide_char) {
   4691             if (size1 >= sizeof(*p1) + ((p1->len + p2->len) << 1)) {
   4692                 if (p2->is_wide_char) {
   4693                     memcpy(p1->u.str16 + p1->len, p2->u.str16, p2->len << 1);
   4694                     p1->len += p2->len;
   4695                     return TRUE;
   4696                 } else {
   4697                     size_t i;
   4698                     for (i = 0; i < p2->len; i++) {
   4699                         p1->u.str16[p1->len++] = p2->u.str8[i];
   4700                     }
   4701                     return TRUE;
   4702                 }
   4703             }
   4704         } else if (!p2->is_wide_char) {
   4705             if (size1 >= sizeof(*p1) + p1->len + p2->len + 1) {
   4706                 memcpy(p1->u.str8 + p1->len, p2->u.str8, p2->len);
   4707                 p1->len += p2->len;
   4708                 p1->u.str8[p1->len] = '\0';
   4709                 return TRUE;
   4710             }
   4711         }
   4712     }
   4713     return FALSE;
   4714 }
   4715 
   4716 static JSValue JS_ConcatString2(JSContext *ctx, JSValue op1, JSValue op2)
   4717 {
   4718     JSValue ret;
   4719     JSString *p1, *p2;
   4720     p1 = JS_VALUE_GET_STRING(op1);
   4721     if (JS_ConcatStringInPlace(ctx, p1, op2)) {
   4722         JS_FreeValue(ctx, op2);
   4723         return op1;
   4724     }
   4725     p2 = JS_VALUE_GET_STRING(op2);
   4726     ret = JS_ConcatString1(ctx, p1, p2);
   4727     JS_FreeValue(ctx, op1);
   4728     JS_FreeValue(ctx, op2);
   4729     return ret;
   4730 }
   4731 
   4732 /* Return the character at position 'idx'. 'val' must be a string or rope */
   4733 static int string_rope_get(JSValueConst val, uint32_t idx)
   4734 {
   4735     if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
   4736         return string_get(JS_VALUE_GET_STRING(val), idx);
   4737     } else {
   4738         JSStringRope *r = JS_VALUE_GET_STRING_ROPE(val);
   4739         uint32_t len;
   4740         if (JS_VALUE_GET_TAG(r->left) == JS_TAG_STRING)
   4741             len = JS_VALUE_GET_STRING(r->left)->len;
   4742         else
   4743             len = JS_VALUE_GET_STRING_ROPE(r->left)->len;
   4744         if (idx < len)
   4745             return string_rope_get(r->left, idx);
   4746         else
   4747             return string_rope_get(r->right, idx - len);
   4748     }
   4749 }
   4750 
   4751 typedef struct {
   4752     JSValueConst stack[JS_STRING_ROPE_MAX_DEPTH];
   4753     int stack_len;
   4754 } JSStringRopeIter;
   4755 
   4756 static void string_rope_iter_init(JSStringRopeIter *s, JSValueConst val)
   4757 {
   4758     s->stack_len = 0;
   4759     s->stack[s->stack_len++] = val;
   4760 }
   4761 
   4762 /* iterate thru a rope and return the strings in order */
   4763 static JSString *string_rope_iter_next(JSStringRopeIter *s)
   4764 {
   4765     JSValueConst val;
   4766     JSStringRope *r;
   4767 
   4768     if (s->stack_len == 0)
   4769         return NULL;
   4770     val = s->stack[--s->stack_len];
   4771     for(;;) {
   4772         if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING)
   4773             return JS_VALUE_GET_STRING(val);
   4774         r = JS_VALUE_GET_STRING_ROPE(val);
   4775         assert(s->stack_len < JS_STRING_ROPE_MAX_DEPTH);
   4776         s->stack[s->stack_len++] = r->right;
   4777         val = r->left;
   4778     }
   4779 }
   4780 
   4781 static uint32_t string_rope_get_len(JSValueConst val)
   4782 {
   4783     if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING)
   4784         return JS_VALUE_GET_STRING(val)->len;
   4785     else
   4786         return JS_VALUE_GET_STRING_ROPE(val)->len;
   4787 }
   4788 
   4789 static int js_string_rope_compare(JSContext *ctx, JSValueConst op1,
   4790                                   JSValueConst op2, BOOL eq_only)
   4791 {
   4792     uint32_t len1, len2, len, pos1, pos2, l;
   4793     int res;
   4794     JSStringRopeIter it1, it2;
   4795     JSString *p1, *p2;
   4796     
   4797     len1 = string_rope_get_len(op1);
   4798     len2 = string_rope_get_len(op2);
   4799     /* no need to go further for equality test if
   4800        different length */
   4801     if (eq_only && len1 != len2)
   4802         return 1; 
   4803     len = min_uint32(len1, len2);
   4804     string_rope_iter_init(&it1, op1);
   4805     string_rope_iter_init(&it2, op2);
   4806     p1 = string_rope_iter_next(&it1);
   4807     p2 = string_rope_iter_next(&it2);
   4808     pos1 = 0;
   4809     pos2 = 0;
   4810     while (len != 0) {
   4811         l = min_uint32(p1->len - pos1, p2->len - pos2);
   4812         l = min_uint32(l, len);
   4813         res = js_string_memcmp(p1, pos1, p2, pos2, l);
   4814         if (res != 0)
   4815             return res;
   4816         len -= l;
   4817         pos1 += l;
   4818         if (pos1 >= p1->len) {
   4819             p1 = string_rope_iter_next(&it1);
   4820             pos1 = 0;
   4821         }
   4822         pos2 += l;
   4823         if (pos2 >= p2->len) {
   4824             p2 = string_rope_iter_next(&it2);
   4825             pos2 = 0;
   4826         }
   4827     }
   4828 
   4829     if (len1 == len2)
   4830         res = 0;
   4831     else if (len1 < len2)
   4832         res = -1;
   4833     else
   4834         res = 1;
   4835     return res;
   4836 }
   4837 
   4838 /* 'rope' must be a rope. return a string and modify the rope so that
   4839    it won't need to be linearized again. */
   4840 static JSValue js_linearize_string_rope(JSContext *ctx, JSValue rope)
   4841 {
   4842     StringBuffer b_s, *b = &b_s;
   4843     JSStringRope *r;
   4844     JSValue ret;
   4845     
   4846     r = JS_VALUE_GET_STRING_ROPE(rope);
   4847 
   4848     /* check whether it is already linearized */
   4849     if (JS_VALUE_GET_TAG(r->right) == JS_TAG_STRING &&
   4850         JS_VALUE_GET_STRING(r->right)->len == 0) {
   4851         ret = JS_DupValue(ctx, r->left);
   4852         JS_FreeValue(ctx, rope);
   4853         return ret;
   4854     }
   4855     if (string_buffer_init2(ctx, b, r->len, r->is_wide_char))
   4856         goto fail;
   4857     if (string_buffer_concat_value(b, rope))
   4858         goto fail;
   4859     ret = string_buffer_end(b);
   4860     if (js_rc(r)->ref_count > 1) {
   4861         /* update the rope so that it won't need to be linearized again */
   4862         JS_FreeValue(ctx, r->left);
   4863         JS_FreeValue(ctx, r->right);
   4864         r->left = JS_DupValue(ctx, ret);
   4865         r->right = JS_AtomToString(ctx, JS_ATOM_empty_string);
   4866     }
   4867     JS_FreeValue(ctx, rope);
   4868     return ret;
   4869  fail:
   4870     JS_FreeValue(ctx, rope);
   4871     return JS_EXCEPTION;
   4872 }
   4873 
   4874 static JSValue js_rebalancee_string_rope(JSContext *ctx, JSValueConst rope);
   4875 
   4876 /* op1 and op2 must be strings or string ropes */
   4877 static JSValue js_new_string_rope(JSContext *ctx, JSValue op1, JSValue op2)
   4878 {
   4879     uint32_t len;
   4880     int is_wide_char, depth;
   4881     JSStringRope *r;
   4882     JSValue res;
   4883     
   4884     if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING) {
   4885         JSString *p1 = JS_VALUE_GET_STRING(op1);
   4886         len = p1->len;
   4887         is_wide_char = p1->is_wide_char;
   4888         depth = 0;
   4889     } else {
   4890         JSStringRope *r1 = JS_VALUE_GET_STRING_ROPE(op1);
   4891         len = r1->len;
   4892         is_wide_char = r1->is_wide_char;
   4893         depth = r1->depth;
   4894     }
   4895 
   4896     if (JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {
   4897         JSString *p2 = JS_VALUE_GET_STRING(op2);
   4898         len += p2->len;
   4899         is_wide_char |= p2->is_wide_char;
   4900     } else {
   4901         JSStringRope *r2 = JS_VALUE_GET_STRING_ROPE(op2);
   4902         len += r2->len;
   4903         is_wide_char |= r2->is_wide_char;
   4904         depth = max_int(depth, r2->depth);
   4905     }
   4906     if (len > JS_STRING_LEN_MAX) {
   4907         JS_ThrowInternalError(ctx, "string too long");
   4908         goto fail;
   4909     }
   4910     r = js_malloc(ctx, sizeof(*r));
   4911     if (!r)
   4912         goto fail;
   4913     js_rc(r)->ref_count = 1;
   4914     r->len = len;
   4915     r->is_wide_char = is_wide_char;
   4916     r->depth = depth + 1;
   4917     r->left = op1;
   4918     r->right = op2;
   4919     res = JS_MKPTR(JS_TAG_STRING_ROPE, r);
   4920     if (r->depth > JS_STRING_ROPE_MAX_DEPTH) {
   4921         JSValue res2;
   4922 #ifdef DUMP_ROPE_REBALANCE
   4923         printf("rebalance: initial depth=%d\n", r->depth);
   4924 #endif
   4925         res2 = js_rebalancee_string_rope(ctx, res);
   4926 #ifdef DUMP_ROPE_REBALANCE
   4927         if (JS_VALUE_GET_TAG(res2) == JS_TAG_STRING_ROPE) 
   4928             printf("rebalance: final depth=%d\n", JS_VALUE_GET_STRING_ROPE(res2)->depth);
   4929 #endif
   4930         JS_FreeValue(ctx, res);
   4931         return res2;
   4932     } else {
   4933         return res;
   4934     }
   4935  fail:
   4936     JS_FreeValue(ctx, op1);
   4937     JS_FreeValue(ctx, op2);
   4938     return JS_EXCEPTION;
   4939 }
   4940 
   4941 #define ROPE_N_BUCKETS 44
   4942 
   4943 /* Fibonacii numbers starting from F_2 */
   4944 static const uint32_t rope_bucket_len[ROPE_N_BUCKETS] = {
   4945           1,          2,          3,          5,
   4946           8,         13,         21,         34,
   4947          55,         89,        144,        233,
   4948         377,        610,        987,       1597,
   4949        2584,       4181,       6765,      10946,
   4950       17711,      28657,      46368,      75025,
   4951      121393,     196418,     317811,     514229,
   4952      832040,    1346269,    2178309,    3524578,
   4953     5702887,    9227465,   14930352,   24157817,
   4954    39088169,   63245986,  102334155,  165580141,
   4955   267914296,  433494437,  701408733, 1134903170, /* > JS_STRING_LEN_MAX */
   4956 };
   4957 
   4958 static int js_rebalancee_string_rope_rec(JSContext *ctx, JSValue *buckets,
   4959                                           JSValueConst val)
   4960 {
   4961     if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
   4962         JSString *p = JS_VALUE_GET_STRING(val);
   4963         uint32_t len, i;
   4964         JSValue a, b;
   4965         
   4966         len = p->len;
   4967         if (len == 0)
   4968             return 0; /* nothing to do */
   4969         /* find the bucket i so that rope_bucket_len[i] <= len <
   4970            rope_bucket_len[i + 1] and concatenate the ropes in the
   4971            buckets before */
   4972         a = JS_NULL;
   4973         i = 0;
   4974         while (len >= rope_bucket_len[i + 1]) {
   4975             b = buckets[i];
   4976             if (!JS_IsNull(b)) {
   4977                 buckets[i] = JS_NULL;
   4978                 if (JS_IsNull(a)) {
   4979                     a = b;
   4980                 } else {
   4981                     a = js_new_string_rope(ctx, b, a);
   4982                     if (JS_IsException(a))
   4983                         return -1;
   4984                 }
   4985             }
   4986             i++;
   4987         }
   4988         if (!JS_IsNull(a)) {
   4989             a = js_new_string_rope(ctx, a, JS_DupValue(ctx, val));
   4990             if (JS_IsException(a))
   4991                 return -1;
   4992         } else {
   4993             a = JS_DupValue(ctx, val);
   4994         }
   4995         while (!JS_IsNull(buckets[i])) {
   4996             a = js_new_string_rope(ctx, buckets[i], a);
   4997             buckets[i] = JS_NULL;
   4998             if (JS_IsException(a))
   4999                 return -1;
   5000             i++;
   5001         }
   5002         buckets[i] = a;
   5003     } else {
   5004         JSStringRope *r = JS_VALUE_GET_STRING_ROPE(val);
   5005         js_rebalancee_string_rope_rec(ctx, buckets, r->left);
   5006         js_rebalancee_string_rope_rec(ctx, buckets, r->right);
   5007     }
   5008     return 0;
   5009 }
   5010 
   5011 /* Return a new rope which is balanced. Algorithm from "Ropes: an
   5012    Alternative to Strings", Hans-J. Boehm, Russ Atkinson and Michael
   5013    Plass. */
   5014 static JSValue js_rebalancee_string_rope(JSContext *ctx, JSValueConst rope)
   5015 {
   5016     JSValue buckets[ROPE_N_BUCKETS], a, b;
   5017     int i;
   5018     
   5019     for(i = 0; i < ROPE_N_BUCKETS; i++)
   5020         buckets[i] = JS_NULL;
   5021     if (js_rebalancee_string_rope_rec(ctx, buckets, rope))
   5022         goto fail;
   5023     a = JS_NULL;
   5024     for(i = 0; i < ROPE_N_BUCKETS; i++) {
   5025         b = buckets[i];
   5026         if (!JS_IsNull(b)) {
   5027             buckets[i] = JS_NULL;
   5028             if (JS_IsNull(a)) {
   5029                 a = b;
   5030             } else {
   5031                 a = js_new_string_rope(ctx, b, a);
   5032                 if (JS_IsException(a))
   5033                     goto fail;
   5034             }
   5035         }
   5036     }
   5037     /* fail safe */
   5038     if (JS_IsNull(a))
   5039         return JS_AtomToString(ctx, JS_ATOM_empty_string);
   5040     else
   5041         return a;
   5042  fail:
   5043     for(i = 0; i < ROPE_N_BUCKETS; i++) {
   5044         JS_FreeValue(ctx, buckets[i]);
   5045     }
   5046     return JS_EXCEPTION;
   5047 }
   5048 
   5049 /* op1 and op2 are converted to strings. For convenience, op1 or op2 =
   5050    JS_EXCEPTION are accepted and return JS_EXCEPTION.  */
   5051 static JSValue JS_ConcatString(JSContext *ctx, JSValue op1, JSValue op2)
   5052 {
   5053     JSString *p1, *p2;
   5054 
   5055     if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_STRING &&
   5056                  JS_VALUE_GET_TAG(op1) != JS_TAG_STRING_ROPE)) {
   5057         op1 = JS_ToStringFree(ctx, op1);
   5058         if (JS_IsException(op1)) {
   5059             JS_FreeValue(ctx, op2);
   5060             return JS_EXCEPTION;
   5061         }
   5062     }
   5063     if (unlikely(JS_VALUE_GET_TAG(op2) != JS_TAG_STRING &&
   5064                  JS_VALUE_GET_TAG(op2) != JS_TAG_STRING_ROPE)) {
   5065         op2 = JS_ToStringFree(ctx, op2);
   5066         if (JS_IsException(op2)) {
   5067             JS_FreeValue(ctx, op1);
   5068             return JS_EXCEPTION;
   5069         }
   5070     }
   5071 
   5072     /* normal concatenation for short strings */
   5073     if (JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {
   5074         p2 = JS_VALUE_GET_STRING(op2);
   5075         if (p2->len == 0) {
   5076             JS_FreeValue(ctx, op2);
   5077             return op1;
   5078         }
   5079         if (p2->len <= JS_STRING_ROPE_SHORT_LEN) {
   5080             if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING) {
   5081                 p1 = JS_VALUE_GET_STRING(op1);
   5082                 if (p1->len <= JS_STRING_ROPE_SHORT2_LEN) {
   5083                     return JS_ConcatString2(ctx, op1, op2);
   5084                 } else {
   5085                     return js_new_string_rope(ctx, op1, op2);
   5086                 }
   5087             } else {
   5088                 JSStringRope *r1;
   5089                 r1 = JS_VALUE_GET_STRING_ROPE(op1);
   5090                 if (JS_VALUE_GET_TAG(r1->right) == JS_TAG_STRING &&
   5091                     JS_VALUE_GET_STRING(r1->right)->len <= JS_STRING_ROPE_SHORT_LEN) {
   5092                     JSValue val, ret;
   5093                     val = JS_ConcatString2(ctx, JS_DupValue(ctx, r1->right), op2);
   5094                     if (JS_IsException(val)) {
   5095                         JS_FreeValue(ctx, op1);
   5096                         return JS_EXCEPTION;
   5097                     }
   5098                     ret = js_new_string_rope(ctx, JS_DupValue(ctx, r1->left), val);
   5099                     JS_FreeValue(ctx, op1);
   5100                     return ret;
   5101                 }
   5102             }
   5103         }
   5104     } else if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING) {
   5105         JSStringRope *r2;
   5106         p1 = JS_VALUE_GET_STRING(op1);
   5107         if (p1->len == 0) {
   5108             JS_FreeValue(ctx, op1);
   5109             return op2;
   5110         }
   5111         r2 = JS_VALUE_GET_STRING_ROPE(op2);
   5112         if (JS_VALUE_GET_TAG(r2->left) == JS_TAG_STRING &&
   5113             JS_VALUE_GET_STRING(r2->left)->len <= JS_STRING_ROPE_SHORT_LEN) {
   5114             JSValue val, ret;
   5115             val = JS_ConcatString2(ctx, op1, JS_DupValue(ctx, r2->left));
   5116             if (JS_IsException(val)) {
   5117                 JS_FreeValue(ctx, op2);
   5118                 return JS_EXCEPTION;
   5119             }
   5120             ret = js_new_string_rope(ctx, val, JS_DupValue(ctx, r2->right));
   5121             JS_FreeValue(ctx, op2);
   5122             return ret;
   5123         }
   5124     }
   5125     return js_new_string_rope(ctx, op1, op2);
   5126 }
   5127 
   5128 /* Shape support */
   5129 
   5130 static inline size_t get_shape_size(size_t hash_size, size_t prop_size)
   5131 {
   5132     return sizeof(JSShape) + hash_size * sizeof(uint32_t) +
   5133         prop_size * sizeof(JSShapeProperty);
   5134 }
   5135 
   5136 static inline JSShapeProperty *get_shape_prop(JSShape *sh)
   5137 {
   5138     return (JSShapeProperty *)((uint32_t *)(sh + 1) + sh->prop_hash_mask + 1);
   5139 }
   5140 
   5141 static int init_shape_hash(JSRuntime *rt)
   5142 {
   5143     rt->shape_hash_bits = 4;   /* 16 shapes */
   5144     rt->shape_hash_size = 1 << rt->shape_hash_bits;
   5145     rt->shape_hash_count = 0;
   5146     rt->shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) *
   5147                                    rt->shape_hash_size);
   5148     if (!rt->shape_hash)
   5149         return -1;
   5150     return 0;
   5151 }
   5152 
   5153 /* same magic hash multiplier as the Linux kernel */
   5154 static uint32_t shape_hash(uint32_t h, uint32_t val)
   5155 {
   5156     return (h + val) * 0x9e370001;
   5157 }
   5158 
   5159 /* truncate the shape hash to 'hash_bits' bits */
   5160 static uint32_t get_shape_hash(uint32_t h, int hash_bits)
   5161 {
   5162     return h >> (32 - hash_bits);
   5163 }
   5164 
   5165 static uint32_t shape_initial_hash(JSObject *proto)
   5166 {
   5167     uint32_t h;
   5168     h = shape_hash(1, (uintptr_t)proto);
   5169     if (sizeof(proto) > 4)
   5170         h = shape_hash(h, (uint64_t)(uintptr_t)proto >> 32);
   5171     return h;
   5172 }
   5173 
   5174 static int resize_shape_hash(JSRuntime *rt, int new_shape_hash_bits)
   5175 {
   5176     int new_shape_hash_size, i;
   5177     uint32_t h;
   5178     JSShape **new_shape_hash, *sh, *sh_next;
   5179 
   5180     new_shape_hash_size = 1 << new_shape_hash_bits;
   5181     new_shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) *
   5182                                    new_shape_hash_size);
   5183     if (!new_shape_hash)
   5184         return -1;
   5185     for(i = 0; i < rt->shape_hash_size; i++) {
   5186         for(sh = rt->shape_hash[i]; sh != NULL; sh = sh_next) {
   5187             sh_next = sh->shape_hash_next;
   5188             h = get_shape_hash(sh->hash, new_shape_hash_bits);
   5189             sh->shape_hash_next = new_shape_hash[h];
   5190             new_shape_hash[h] = sh;
   5191         }
   5192     }
   5193     js_free_rt(rt, rt->shape_hash);
   5194     rt->shape_hash_bits = new_shape_hash_bits;
   5195     rt->shape_hash_size = new_shape_hash_size;
   5196     rt->shape_hash = new_shape_hash;
   5197     return 0;
   5198 }
   5199 
   5200 static void js_shape_hash_link(JSRuntime *rt, JSShape *sh)
   5201 {
   5202     uint32_t h;
   5203     h = get_shape_hash(sh->hash, rt->shape_hash_bits);
   5204     sh->shape_hash_next = rt->shape_hash[h];
   5205     rt->shape_hash[h] = sh;
   5206     rt->shape_hash_count++;
   5207 }
   5208 
   5209 static void js_shape_hash_unlink(JSRuntime *rt, JSShape *sh)
   5210 {
   5211     uint32_t h;
   5212     JSShape **psh;
   5213 
   5214     h = get_shape_hash(sh->hash, rt->shape_hash_bits);
   5215     psh = &rt->shape_hash[h];
   5216     while (*psh != sh)
   5217         psh = &(*psh)->shape_hash_next;
   5218     *psh = sh->shape_hash_next;
   5219     rt->shape_hash_count--;
   5220 }
   5221 
   5222 /* create a new empty shape with prototype 'proto'. It is not hashed */
   5223 static inline JSShape *js_new_shape_nohash(JSContext *ctx, JSObject *proto,
   5224                                            int hash_size, int prop_size)
   5225 {
   5226     JSRuntime *rt = ctx->rt;
   5227     JSShape *sh;
   5228 
   5229     sh = js_malloc(ctx, get_shape_size(hash_size, prop_size));
   5230     if (!sh)
   5231         return NULL;
   5232     js_rc(sh)->ref_count = 1;
   5233     add_gc_object(rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);
   5234     if (proto)
   5235         JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, proto));
   5236     sh->proto = proto;
   5237     memset(sh->hash_table, 0, sizeof(sh->hash_table[0]) * hash_size);
   5238     sh->prop_hash_mask = hash_size - 1;
   5239     sh->prop_size = prop_size;
   5240     sh->prop_count = 0;
   5241     sh->deleted_prop_count = 0;
   5242     sh->is_hashed = FALSE;
   5243     return sh;
   5244 }
   5245 
   5246 /* create a new empty shape with prototype 'proto' */
   5247 static no_inline JSShape *js_new_shape2(JSContext *ctx, JSObject *proto,
   5248                                         int hash_size, int prop_size)
   5249 {
   5250     JSRuntime *rt = ctx->rt;
   5251     JSShape *sh;
   5252 
   5253     /* resize the shape hash table if necessary */
   5254     if (2 * (rt->shape_hash_count + 1) > rt->shape_hash_size) {
   5255         resize_shape_hash(rt, rt->shape_hash_bits + 1);
   5256     }
   5257 
   5258     sh = js_new_shape_nohash(ctx, proto, hash_size, prop_size);
   5259     if (!sh)
   5260         return NULL;
   5261     
   5262     /* insert in the hash table */
   5263     sh->hash = shape_initial_hash(proto);
   5264     sh->is_hashed = TRUE;
   5265     js_shape_hash_link(ctx->rt, sh);
   5266     return sh;
   5267 }
   5268 
   5269 static JSShape *js_new_shape(JSContext *ctx, JSObject *proto)
   5270 {
   5271     return js_new_shape2(ctx, proto, JS_PROP_INITIAL_HASH_SIZE,
   5272                          JS_PROP_INITIAL_SIZE);
   5273 }
   5274 
   5275 /* The shape is cloned. The new shape is not inserted in the shape
   5276    hash table */
   5277 static JSShape *js_clone_shape(JSContext *ctx, JSShape *sh1)
   5278 {
   5279     JSShape *sh;
   5280     size_t size;
   5281     JSShapeProperty *pr;
   5282     uint32_t i, hash_size;
   5283 
   5284     hash_size = sh1->prop_hash_mask + 1;
   5285     size = get_shape_size(hash_size, sh1->prop_size);
   5286     sh = js_malloc(ctx, size);
   5287     if (!sh)
   5288         return NULL;
   5289     memcpy(&sh->header + 1, &sh1->header + 1,
   5290            size - sizeof(JSGCObjectHeader));
   5291     js_rc(sh)->ref_count = 1;
   5292     add_gc_object(ctx->rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);
   5293     sh->is_hashed = FALSE;
   5294     if (sh->proto) {
   5295         JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
   5296     }
   5297     for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {
   5298         JS_DupAtom(ctx, pr->atom);
   5299     }
   5300     return sh;
   5301 }
   5302 
   5303 static JSShape *js_dup_shape(JSShape *sh)
   5304 {
   5305     js_rc(sh)->ref_count++;
   5306     return sh;
   5307 }
   5308 
   5309 static void js_free_shape0(JSRuntime *rt, JSShape *sh)
   5310 {
   5311     uint32_t i;
   5312     JSShapeProperty *pr;
   5313 
   5314     assert(js_rc(sh)->ref_count == 0);
   5315     if (sh->is_hashed)
   5316         js_shape_hash_unlink(rt, sh);
   5317     if (sh->proto != NULL) {
   5318         JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
   5319     }
   5320     pr = get_shape_prop(sh);
   5321     for(i = 0; i < sh->prop_count; i++) {
   5322         JS_FreeAtomRT(rt, pr->atom);
   5323         pr++;
   5324     }
   5325     remove_gc_object(&sh->header);
   5326     js_free_rt(rt, sh);
   5327 }
   5328 
   5329 static void js_free_shape(JSRuntime *rt, JSShape *sh)
   5330 {
   5331     if (unlikely(--js_rc(sh)->ref_count <= 0)) {
   5332         js_free_shape0(rt, sh);
   5333     }
   5334 }
   5335 
   5336 static void js_free_shape_null(JSRuntime *rt, JSShape *sh)
   5337 {
   5338     if (sh)
   5339         js_free_shape(rt, sh);
   5340 }
   5341 
   5342 /* make space to hold at least 'count' properties */
   5343 static no_inline int resize_properties(JSContext *ctx, JSShape **psh,
   5344                                        JSObject *p, uint32_t count)
   5345 {
   5346     JSShape *sh;
   5347     uint32_t new_size, new_hash_size, new_hash_mask, i;
   5348     JSShapeProperty *pr;
   5349     intptr_t h;
   5350     JSShape *old_sh;
   5351 
   5352     sh = *psh;
   5353     new_size = max_int(count, sh->prop_size * 3 / 2);
   5354     /* Reallocate prop array first to avoid crash or size inconsistency
   5355        in case of memory allocation failure */
   5356     if (p) {
   5357         JSProperty *new_prop;
   5358         new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size);
   5359         if (unlikely(!new_prop))
   5360             return -1;
   5361         p->prop = new_prop;
   5362     }
   5363     new_hash_size = sh->prop_hash_mask + 1;
   5364     while (new_hash_size < new_size)
   5365         new_hash_size = 2 * new_hash_size;
   5366     /* resize the property shapes. Using js_realloc() is not possible in
   5367        case the GC runs during the allocation */
   5368     old_sh = sh;
   5369     sh = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
   5370     if (!sh)
   5371         return -1;
   5372     remove_gc_object(&old_sh->header);
   5373 
   5374     js_rc(sh)->ref_count = 1;
   5375     add_gc_object(ctx->rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);
   5376 
   5377     memcpy(&sh->header + 1, &old_sh->header + 1,
   5378            sizeof(JSShape) - sizeof(JSGCObjectHeader));
   5379     
   5380     if (new_hash_size != (sh->prop_hash_mask + 1)) {
   5381         /* resize the hash table and the properties */
   5382         new_hash_mask = new_hash_size - 1;
   5383         sh->prop_hash_mask = new_hash_mask;
   5384         memset(sh->hash_table, 0,
   5385                sizeof(sh->hash_table[0]) * new_hash_size);
   5386         memcpy(get_shape_prop(sh), get_shape_prop(old_sh),
   5387                sizeof(JSShapeProperty) * old_sh->prop_count);
   5388         for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {
   5389             if (pr->atom != JS_ATOM_NULL) {
   5390                 h = ((uintptr_t)pr->atom & new_hash_mask);
   5391                 pr->hash_next = sh->hash_table[h];
   5392                 sh->hash_table[h] = i + 1;
   5393             }
   5394         }
   5395     } else {
   5396         /* just copy the previous hash table and the properties */
   5397         memcpy(sh->hash_table, old_sh->hash_table,
   5398                sizeof(sh->hash_table[0]) * new_hash_size);
   5399 
   5400         memcpy(get_shape_prop(sh), get_shape_prop(old_sh),
   5401                sizeof(JSShapeProperty) * old_sh->prop_count);
   5402     }
   5403     js_free(ctx, old_sh);
   5404     *psh = sh;
   5405     sh->prop_size = new_size;
   5406     return 0;
   5407 }
   5408 
   5409 /* remove the deleted properties. */
   5410 static int compact_properties(JSContext *ctx, JSObject *p)
   5411 {
   5412     JSShape *sh, *old_sh;
   5413     intptr_t h;
   5414     uint32_t new_hash_size, i, j, new_hash_mask, new_size;
   5415     JSShapeProperty *old_pr, *pr;
   5416     JSProperty *prop, *new_prop;
   5417 
   5418     sh = p->shape;
   5419     assert(!sh->is_hashed);
   5420 
   5421     new_size = max_int(JS_PROP_INITIAL_SIZE,
   5422                        sh->prop_count - sh->deleted_prop_count);
   5423     assert(new_size <= sh->prop_size);
   5424 
   5425     new_hash_size = sh->prop_hash_mask + 1;
   5426     while ((new_hash_size / 2) >= new_size)
   5427         new_hash_size = new_hash_size / 2;
   5428     new_hash_mask = new_hash_size - 1;
   5429 
   5430     /* resize the hash table and the properties */
   5431     old_sh = sh;
   5432     sh = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
   5433     if (!sh)
   5434         return -1;
   5435     remove_gc_object(&old_sh->header);
   5436 
   5437     js_rc(sh)->ref_count = 1;
   5438     add_gc_object(ctx->rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);
   5439 
   5440     memcpy(&sh->header + 1, &old_sh->header + 1,
   5441            sizeof(JSShape) - sizeof(JSGCObjectHeader));
   5442 
   5443     memset(sh->hash_table, 0, sizeof(sh->hash_table[0]) * new_hash_size);
   5444     sh->prop_hash_mask = new_hash_mask;
   5445 
   5446     j = 0;
   5447     old_pr = get_shape_prop(old_sh);
   5448     pr = get_shape_prop(sh);
   5449     prop = p->prop;
   5450     for(i = 0; i < sh->prop_count; i++) {
   5451         if (old_pr->atom != JS_ATOM_NULL) {
   5452             pr->atom = old_pr->atom;
   5453             pr->flags = old_pr->flags;
   5454             h = ((uintptr_t)old_pr->atom & new_hash_mask);
   5455             pr->hash_next = sh->hash_table[h];
   5456             sh->hash_table[h] = j + 1;
   5457             prop[j] = prop[i];
   5458             j++;
   5459             pr++;
   5460         }
   5461         old_pr++;
   5462     }
   5463     assert(j == (sh->prop_count - sh->deleted_prop_count));
   5464     sh->prop_size = new_size;
   5465     sh->deleted_prop_count = 0;
   5466     sh->prop_count = j;
   5467 
   5468     p->shape = sh;
   5469     js_free(ctx, old_sh);
   5470 
   5471     /* reduce the size of the object properties */
   5472     new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size);
   5473     if (new_prop)
   5474         p->prop = new_prop;
   5475     return 0;
   5476 }
   5477 
   5478 static int add_shape_property(JSContext *ctx, JSShape **psh,
   5479                               JSObject *p, JSAtom atom, int prop_flags)
   5480 {
   5481     JSRuntime *rt = ctx->rt;
   5482     JSShape *sh = *psh;
   5483     JSShapeProperty *pr, *prop;
   5484     uint32_t hash_mask, new_shape_hash = 0;
   5485     intptr_t h;
   5486 
   5487     /* update the shape hash */
   5488     if (sh->is_hashed) {
   5489         js_shape_hash_unlink(rt, sh);
   5490         new_shape_hash = shape_hash(shape_hash(sh->hash, atom), prop_flags);
   5491     }
   5492 
   5493     if (unlikely(sh->prop_count >= sh->prop_size)) {
   5494         if (resize_properties(ctx, psh, p, sh->prop_count + 1)) {
   5495             /* in case of error, reinsert in the hash table.
   5496                sh is still valid if resize_properties() failed */
   5497             if (sh->is_hashed)
   5498                 js_shape_hash_link(rt, sh);
   5499             return -1;
   5500         }
   5501         sh = *psh;
   5502     }
   5503     if (sh->is_hashed) {
   5504         sh->hash = new_shape_hash;
   5505         js_shape_hash_link(rt, sh);
   5506     }
   5507     /* Initialize the new shape property.
   5508        The object property at p->prop[sh->prop_count] is uninitialized */
   5509     prop = get_shape_prop(sh);
   5510     pr = &prop[sh->prop_count++];
   5511     pr->atom = JS_DupAtom(ctx, atom);
   5512     pr->flags = prop_flags;
   5513     /* add in hash table */
   5514     hash_mask = sh->prop_hash_mask;
   5515     h = atom & hash_mask;
   5516     pr->hash_next = sh->hash_table[h];
   5517     sh->hash_table[h] = sh->prop_count;
   5518     return 0;
   5519 }
   5520 
   5521 /* find a hashed empty shape matching the prototype. Return NULL if
   5522    not found */
   5523 static JSShape *find_hashed_shape_proto(JSRuntime *rt, JSObject *proto)
   5524 {
   5525     JSShape *sh1;
   5526     uint32_t h, h1;
   5527 
   5528     h = shape_initial_hash(proto);
   5529     h1 = get_shape_hash(h, rt->shape_hash_bits);
   5530     for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) {
   5531         if (sh1->hash == h &&
   5532             sh1->proto == proto &&
   5533             sh1->prop_count == 0) {
   5534             return sh1;
   5535         }
   5536     }
   5537     return NULL;
   5538 }
   5539 
   5540 /* find a hashed shape matching sh + (prop, prop_flags). Return NULL if
   5541    not found */
   5542 static JSShape *find_hashed_shape_prop(JSRuntime *rt, JSShape *sh,
   5543                                        JSAtom atom, int prop_flags)
   5544 {
   5545     JSShape *sh1;
   5546     uint32_t h, h1, i, n;
   5547 
   5548     h = sh->hash;
   5549     h = shape_hash(h, atom);
   5550     h = shape_hash(h, prop_flags);
   5551     h1 = get_shape_hash(h, rt->shape_hash_bits);
   5552     for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) {
   5553         /* we test the hash first so that the rest is done only if the
   5554            shapes really match */
   5555         if (sh1->hash == h &&
   5556             sh1->proto == sh->proto &&
   5557             sh1->prop_count == ((n = sh->prop_count) + 1)) {
   5558             JSShapeProperty *prop = get_shape_prop(sh);
   5559             JSShapeProperty *prop1 = get_shape_prop(sh1);
   5560             for(i = 0; i < n; i++) {
   5561                 if (unlikely(prop1[i].atom != prop[i].atom) ||
   5562                     unlikely(prop1[i].flags != prop[i].flags))
   5563                     goto next;
   5564             }
   5565             if (unlikely(prop1[n].atom != atom) ||
   5566                 unlikely(prop1[n].flags != prop_flags))
   5567                 goto next;
   5568             return sh1;
   5569         }
   5570     next: ;
   5571     }
   5572     return NULL;
   5573 }
   5574 
   5575 static __maybe_unused void JS_DumpShape(JSRuntime *rt, int i, JSShape *sh)
   5576 {
   5577     char atom_buf[ATOM_GET_STR_BUF_SIZE];
   5578     int j;
   5579 
   5580     /* XXX: should output readable class prototype */
   5581     printf("%5d %3d%c %14p %5d %5d", i,
   5582            js_rc(sh)->ref_count, " *"[sh->is_hashed],
   5583            (void *)sh->proto, sh->prop_size, sh->prop_count);
   5584     for(j = 0; j < sh->prop_count; j++) {
   5585         printf(" %s", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf),
   5586                                       get_shape_prop(sh)[j].atom));
   5587     }
   5588     printf("\n");
   5589 }
   5590 
   5591 static __maybe_unused void JS_DumpShapes(JSRuntime *rt)
   5592 {
   5593     int i;
   5594     JSShape *sh;
   5595     struct list_head *el;
   5596     JSObject *p;
   5597     JSGCObjectHeader *gp;
   5598 
   5599     printf("JSShapes: {\n");
   5600     printf("%5s %4s %14s %5s %5s %s\n", "SLOT", "REFS", "PROTO", "SIZE", "COUNT", "PROPS");
   5601     for(i = 0; i < rt->shape_hash_size; i++) {
   5602         for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) {
   5603             JS_DumpShape(rt, i, sh);
   5604             assert(sh->is_hashed);
   5605         }
   5606     }
   5607     /* dump non-hashed shapes */
   5608     list_for_each(el, &rt->gc_obj_list) {
   5609         gp = list_entry(el, JSGCObjectHeader, link);
   5610         if (js_rc(gp)->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
   5611             p = (JSObject *)gp;
   5612             if (!p->shape->is_hashed) {
   5613                 JS_DumpShape(rt, -1, p->shape);
   5614             }
   5615         }
   5616     }
   5617     printf("}\n");
   5618 }
   5619 
   5620 /* 'props[]' is used to initialized the object properties. The number
   5621    of elements depends on the shape. */
   5622 static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID class_id,
   5623                                      JSProperty *props)
   5624 {
   5625     JSObject *p;
   5626     int i;
   5627     
   5628     js_trigger_gc(ctx->rt, sizeof(JSObject));
   5629     p = js_malloc(ctx, sizeof(JSObject));
   5630     if (unlikely(!p))
   5631         goto fail;
   5632     p->class_id = class_id;
   5633     p->is_std_array_prototype = 0;
   5634     p->extensible = TRUE;
   5635     p->free_mark = 0;
   5636     p->is_exotic = 0;
   5637     p->fast_array = 0;
   5638     p->is_constructor = 0;
   5639     p->has_immutable_prototype = 0;
   5640     p->tmp_mark = 0;
   5641     p->is_HTMLDDA = 0;
   5642     p->weakref_count = 0;
   5643     p->u.opaque = NULL;
   5644     p->shape = sh;
   5645     p->prop = js_malloc(ctx, sizeof(JSProperty) * sh->prop_size);
   5646     if (unlikely(!p->prop)) {
   5647         js_free(ctx, p);
   5648     fail:
   5649         if (props) {
   5650             JSShapeProperty *prs = get_shape_prop(sh);
   5651             for(i = 0; i < sh->prop_count; i++) {
   5652                 free_property(ctx->rt, &props[i], prs->flags);
   5653                 prs++;
   5654             }
   5655         }
   5656         js_free_shape(ctx->rt, sh);
   5657         return JS_EXCEPTION;
   5658     }
   5659 
   5660     switch(class_id) {
   5661     case JS_CLASS_OBJECT:
   5662         break;
   5663     case JS_CLASS_ARRAY:
   5664         {
   5665             JSProperty *pr;
   5666             p->is_exotic = 1;
   5667             p->fast_array = 1;
   5668             p->u.array.u.values = NULL;
   5669             p->u.array.count = 0;
   5670             p->u.array.u1.size = 0;
   5671             if (!props) {
   5672                 /* XXX: remove */
   5673                 /* the length property is always the first one */
   5674                 if (likely(sh == ctx->array_shape)) {
   5675                     pr = &p->prop[0];
   5676                 } else {
   5677                     /* only used for the first array */
   5678                     /* cannot fail */
   5679                     pr = add_property(ctx, p, JS_ATOM_length,
   5680                                       JS_PROP_WRITABLE | JS_PROP_LENGTH);
   5681                 }
   5682                 pr->u.value = JS_NewInt32(ctx, 0);
   5683             }
   5684         }
   5685         break;
   5686     case JS_CLASS_C_FUNCTION:
   5687         p->prop[0].u.value = JS_UNDEFINED;
   5688         break;
   5689     case JS_CLASS_ARGUMENTS:
   5690     case JS_CLASS_MAPPED_ARGUMENTS:
   5691     case JS_CLASS_UINT8C_ARRAY:
   5692     case JS_CLASS_INT8_ARRAY:
   5693     case JS_CLASS_UINT8_ARRAY:
   5694     case JS_CLASS_INT16_ARRAY:
   5695     case JS_CLASS_UINT16_ARRAY:
   5696     case JS_CLASS_INT32_ARRAY:
   5697     case JS_CLASS_UINT32_ARRAY:
   5698     case JS_CLASS_BIG_INT64_ARRAY:
   5699     case JS_CLASS_BIG_UINT64_ARRAY:
   5700     case JS_CLASS_FLOAT16_ARRAY:
   5701     case JS_CLASS_FLOAT32_ARRAY:
   5702     case JS_CLASS_FLOAT64_ARRAY:
   5703         p->is_exotic = 1;
   5704         p->fast_array = 1;
   5705         p->u.array.u.ptr = NULL;
   5706         p->u.array.count = 0;
   5707         break;
   5708     case JS_CLASS_DATAVIEW:
   5709         p->u.array.u.ptr = NULL;
   5710         p->u.array.count = 0;
   5711         break;
   5712     case JS_CLASS_NUMBER:
   5713     case JS_CLASS_STRING:
   5714     case JS_CLASS_BOOLEAN:
   5715     case JS_CLASS_SYMBOL:
   5716     case JS_CLASS_DATE:
   5717     case JS_CLASS_BIG_INT:
   5718         p->u.object_data = JS_UNDEFINED;
   5719         goto set_exotic;
   5720     case JS_CLASS_REGEXP:
   5721         p->u.regexp.pattern = NULL;
   5722         p->u.regexp.bytecode = NULL;
   5723         break;
   5724     case JS_CLASS_GLOBAL_OBJECT:
   5725         p->u.global_object.uninitialized_vars = JS_UNDEFINED;
   5726         break;
   5727     default:
   5728     set_exotic:
   5729         if (ctx->rt->class_array[class_id].exotic) {
   5730             p->is_exotic = 1;
   5731         }
   5732         break;
   5733     }
   5734     js_rc(p)->ref_count = 1;
   5735     add_gc_object(ctx->rt, &p->header, JS_GC_OBJ_TYPE_JS_OBJECT);
   5736     if (props) {
   5737         for(i = 0; i < sh->prop_count; i++)
   5738             p->prop[i] = props[i];
   5739     }
   5740     return JS_MKPTR(JS_TAG_OBJECT, p);
   5741 }
   5742 
   5743 static JSObject *get_proto_obj(JSValueConst proto_val)
   5744 {
   5745     if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT)
   5746         return NULL;
   5747     else
   5748         return JS_VALUE_GET_OBJ(proto_val);
   5749 }
   5750 
   5751 /* WARNING: proto must be an object or JS_NULL */
   5752 JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto_val,
   5753                                JSClassID class_id)
   5754 {
   5755     JSShape *sh;
   5756     JSObject *proto;
   5757 
   5758     proto = get_proto_obj(proto_val);
   5759     sh = find_hashed_shape_proto(ctx->rt, proto);
   5760     if (likely(sh)) {
   5761         sh = js_dup_shape(sh);
   5762     } else {
   5763         sh = js_new_shape(ctx, proto);
   5764         if (!sh)
   5765             return JS_EXCEPTION;
   5766     }
   5767     return JS_NewObjectFromShape(ctx, sh, class_id, NULL);
   5768 }
   5769 
   5770 /* WARNING: the shape is not hashed. It is used for objects where
   5771    factorizing the shape is not relevant (prototypes, constructors) */
   5772 static JSValue JS_NewObjectProtoClassAlloc(JSContext *ctx, JSValueConst proto_val,
   5773                                            JSClassID class_id, int n_alloc_props)
   5774 {
   5775     JSShape *sh;
   5776     JSObject *proto;
   5777     int hash_size, hash_bits;
   5778     
   5779     if (n_alloc_props <= JS_PROP_INITIAL_SIZE) {
   5780         n_alloc_props = JS_PROP_INITIAL_SIZE;
   5781         hash_size = JS_PROP_INITIAL_HASH_SIZE;
   5782     } else {
   5783         hash_bits = 32 - clz32(n_alloc_props - 1); /* ceil(log2(radix)) */
   5784         hash_size = 1 << hash_bits;
   5785     }
   5786     proto = get_proto_obj(proto_val);
   5787     sh = js_new_shape_nohash(ctx, proto, hash_size, n_alloc_props);
   5788     if (!sh)
   5789         return JS_EXCEPTION;
   5790     return JS_NewObjectFromShape(ctx, sh, class_id, NULL);
   5791 }
   5792 
   5793 #if 0
   5794 static JSValue JS_GetObjectData(JSContext *ctx, JSValueConst obj)
   5795 {
   5796     JSObject *p;
   5797 
   5798     if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
   5799         p = JS_VALUE_GET_OBJ(obj);
   5800         switch(p->class_id) {
   5801         case JS_CLASS_NUMBER:
   5802         case JS_CLASS_STRING:
   5803         case JS_CLASS_BOOLEAN:
   5804         case JS_CLASS_SYMBOL:
   5805         case JS_CLASS_DATE:
   5806         case JS_CLASS_BIG_INT:
   5807             return JS_DupValue(ctx, p->u.object_data);
   5808         }
   5809     }
   5810     return JS_UNDEFINED;
   5811 }
   5812 #endif
   5813 
   5814 static int JS_SetObjectData(JSContext *ctx, JSValueConst obj, JSValue val)
   5815 {
   5816     JSObject *p;
   5817 
   5818     if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
   5819         p = JS_VALUE_GET_OBJ(obj);
   5820         switch(p->class_id) {
   5821         case JS_CLASS_NUMBER:
   5822         case JS_CLASS_STRING:
   5823         case JS_CLASS_BOOLEAN:
   5824         case JS_CLASS_SYMBOL:
   5825         case JS_CLASS_DATE:
   5826         case JS_CLASS_BIG_INT:
   5827             JS_FreeValue(ctx, p->u.object_data);
   5828             p->u.object_data = val; /* for JS_CLASS_STRING, 'val' must
   5829                                        be JS_TAG_STRING (and not a
   5830                                        rope) */
   5831             return 0;
   5832         }
   5833     }
   5834     JS_FreeValue(ctx, val);
   5835     if (!JS_IsException(obj))
   5836         JS_ThrowTypeError(ctx, "invalid object type");
   5837     return -1;
   5838 }
   5839 
   5840 JSValue JS_NewObjectClass(JSContext *ctx, int class_id)
   5841 {
   5842     return JS_NewObjectProtoClass(ctx, ctx->class_proto[class_id], class_id);
   5843 }
   5844 
   5845 JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto)
   5846 {
   5847     return JS_NewObjectProtoClass(ctx, proto, JS_CLASS_OBJECT);
   5848 }
   5849 
   5850 JSValue JS_NewArray(JSContext *ctx)
   5851 {
   5852     return JS_NewObjectFromShape(ctx, js_dup_shape(ctx->array_shape),
   5853                                  JS_CLASS_ARRAY, NULL);
   5854 }
   5855 
   5856 JSValue JS_NewObject(JSContext *ctx)
   5857 {
   5858     /* inline JS_NewObjectClass(ctx, JS_CLASS_OBJECT); */
   5859     return JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_OBJECT);
   5860 }
   5861 
   5862 static void js_function_set_properties(JSContext *ctx, JSValueConst func_obj,
   5863                                        JSAtom name, int len)
   5864 {
   5865     /* ES6 feature non compatible with ES5.1: length is configurable */
   5866     JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length, JS_NewInt32(ctx, len),
   5867                            JS_PROP_CONFIGURABLE);
   5868     JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name,
   5869                            JS_AtomToString(ctx, name), JS_PROP_CONFIGURABLE);
   5870 }
   5871 
   5872 static BOOL js_class_has_bytecode(JSClassID class_id)
   5873 {
   5874     return (class_id == JS_CLASS_BYTECODE_FUNCTION ||
   5875             class_id == JS_CLASS_GENERATOR_FUNCTION ||
   5876             class_id == JS_CLASS_ASYNC_FUNCTION ||
   5877             class_id == JS_CLASS_ASYNC_GENERATOR_FUNCTION);
   5878 }
   5879 
   5880 /* return NULL without exception if not a function or no bytecode */
   5881 static JSFunctionBytecode *JS_GetFunctionBytecode(JSValueConst val)
   5882 {
   5883     JSObject *p;
   5884     if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
   5885         return NULL;
   5886     p = JS_VALUE_GET_OBJ(val);
   5887     if (!js_class_has_bytecode(p->class_id))
   5888         return NULL;
   5889     return p->u.func.function_bytecode;
   5890 }
   5891 
   5892 static void js_method_set_home_object(JSContext *ctx, JSValueConst func_obj,
   5893                                       JSValueConst home_obj)
   5894 {
   5895     JSObject *p, *p1;
   5896     JSFunctionBytecode *b;
   5897 
   5898     if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
   5899         return;
   5900     p = JS_VALUE_GET_OBJ(func_obj);
   5901     if (!js_class_has_bytecode(p->class_id))
   5902         return;
   5903     b = p->u.func.function_bytecode;
   5904     if (b->need_home_object) {
   5905         p1 = p->u.func.home_object;
   5906         if (p1) {
   5907             JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
   5908         }
   5909         if (JS_VALUE_GET_TAG(home_obj) == JS_TAG_OBJECT)
   5910             p1 = JS_VALUE_GET_OBJ(JS_DupValue(ctx, home_obj));
   5911         else
   5912             p1 = NULL;
   5913         p->u.func.home_object = p1;
   5914     }
   5915 }
   5916 
   5917 static JSValue js_get_function_name(JSContext *ctx, JSAtom name)
   5918 {
   5919     JSValue name_str;
   5920 
   5921     name_str = JS_AtomToString(ctx, name);
   5922     if (JS_AtomSymbolHasDescription(ctx, name)) {
   5923         name_str = JS_ConcatString3(ctx, "[", name_str, "]");
   5924     }
   5925     return name_str;
   5926 }
   5927 
   5928 /* Modify the name of a method according to the atom and
   5929    'flags'. 'flags' is a bitmask of JS_PROP_HAS_GET and
   5930    JS_PROP_HAS_SET. Also set the home object of the method.
   5931    Return < 0 if exception. */
   5932 static int js_method_set_properties(JSContext *ctx, JSValueConst func_obj,
   5933                                     JSAtom name, int flags, JSValueConst home_obj)
   5934 {
   5935     JSValue name_str;
   5936 
   5937     name_str = js_get_function_name(ctx, name);
   5938     if (flags & JS_PROP_HAS_GET) {
   5939         name_str = JS_ConcatString3(ctx, "get ", name_str, "");
   5940     } else if (flags & JS_PROP_HAS_SET) {
   5941         name_str = JS_ConcatString3(ctx, "set ", name_str, "");
   5942     }
   5943     if (JS_IsException(name_str))
   5944         return -1;
   5945     if (JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name_str,
   5946                                JS_PROP_CONFIGURABLE) < 0)
   5947         return -1;
   5948     js_method_set_home_object(ctx, func_obj, home_obj);
   5949     return 0;
   5950 }
   5951 
   5952 /* Note: at least 'length' arguments will be readable in 'argv' */
   5953 static JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func,
   5954                                 const char *name,
   5955                                 int length, JSCFunctionEnum cproto, int magic,
   5956                                 JSValueConst proto_val, int n_fields)
   5957 {
   5958     JSValue func_obj;
   5959     JSObject *p;
   5960     JSAtom name_atom;
   5961 
   5962     if (n_fields > 0) {
   5963         func_obj = JS_NewObjectProtoClassAlloc(ctx, proto_val, JS_CLASS_C_FUNCTION, n_fields);
   5964     } else {
   5965         func_obj = JS_NewObjectProtoClass(ctx, proto_val, JS_CLASS_C_FUNCTION);
   5966     }
   5967     if (JS_IsException(func_obj))
   5968         return func_obj;
   5969     p = JS_VALUE_GET_OBJ(func_obj);
   5970     p->u.cfunc.realm = JS_DupContext(ctx);
   5971     p->u.cfunc.c_function.generic = func;
   5972     p->u.cfunc.length = length;
   5973     p->u.cfunc.cproto = cproto;
   5974     p->u.cfunc.magic = magic;
   5975     p->is_constructor = (cproto == JS_CFUNC_constructor ||
   5976                          cproto == JS_CFUNC_constructor_magic ||
   5977                          cproto == JS_CFUNC_constructor_or_func ||
   5978                          cproto == JS_CFUNC_constructor_or_func_magic);
   5979     if (!name)
   5980         name = "";
   5981     name_atom = JS_NewAtom(ctx, name);
   5982     if (name_atom == JS_ATOM_NULL) {
   5983         JS_FreeValue(ctx, func_obj);
   5984         return JS_EXCEPTION;
   5985     }
   5986     js_function_set_properties(ctx, func_obj, name_atom, length);
   5987     JS_FreeAtom(ctx, name_atom);
   5988     return func_obj;
   5989 }
   5990 
   5991 /* Note: at least 'length' arguments will be readable in 'argv' */
   5992 JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func,
   5993                          const char *name,
   5994                          int length, JSCFunctionEnum cproto, int magic)
   5995 {
   5996     return JS_NewCFunction3(ctx, func, name, length, cproto, magic,
   5997                             ctx->function_proto, 0);
   5998 }
   5999 
   6000 typedef struct JSCFunctionDataRecord {
   6001     JSCFunctionData *func;
   6002     uint8_t length;
   6003     uint8_t data_len;
   6004     uint16_t magic;
   6005     JSValue data[0];
   6006 } JSCFunctionDataRecord;
   6007 
   6008 static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val)
   6009 {
   6010     JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA);
   6011     int i;
   6012 
   6013     if (s) {
   6014         for(i = 0; i < s->data_len; i++) {
   6015             JS_FreeValueRT(rt, s->data[i]);
   6016         }
   6017         js_free_rt(rt, s);
   6018     }
   6019 }
   6020 
   6021 static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val,
   6022                                     JS_MarkFunc *mark_func)
   6023 {
   6024     JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA);
   6025     int i;
   6026 
   6027     if (s) {
   6028         for(i = 0; i < s->data_len; i++) {
   6029             JS_MarkValue(rt, s->data[i], mark_func);
   6030         }
   6031     }
   6032 }
   6033 
   6034 static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj,
   6035                                        JSValueConst this_val,
   6036                                        int argc, JSValueConst *argv, int flags)
   6037 {
   6038     JSCFunctionDataRecord *s = JS_GetOpaque(func_obj, JS_CLASS_C_FUNCTION_DATA);
   6039     JSValueConst *arg_buf;
   6040     int i;
   6041 
   6042     /* XXX: could add the function on the stack for debug */
   6043     if (unlikely(argc < s->length)) {
   6044         arg_buf = alloca(sizeof(arg_buf[0]) * s->length);
   6045         for(i = 0; i < argc; i++)
   6046             arg_buf[i] = argv[i];
   6047         for(i = argc; i < s->length; i++)
   6048             arg_buf[i] = JS_UNDEFINED;
   6049     } else {
   6050         arg_buf = argv;
   6051     }
   6052 
   6053     return s->func(ctx, this_val, argc, arg_buf, s->magic, s->data);
   6054 }
   6055 
   6056 JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,
   6057                             int length, int magic, int data_len,
   6058                             JSValueConst *data)
   6059 {
   6060     JSCFunctionDataRecord *s;
   6061     JSValue func_obj;
   6062     int i;
   6063 
   6064     func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
   6065                                       JS_CLASS_C_FUNCTION_DATA);
   6066     if (JS_IsException(func_obj))
   6067         return func_obj;
   6068     s = js_malloc(ctx, sizeof(*s) + data_len * sizeof(JSValue));
   6069     if (!s) {
   6070         JS_FreeValue(ctx, func_obj);
   6071         return JS_EXCEPTION;
   6072     }
   6073     s->func = func;
   6074     s->length = length;
   6075     s->data_len = data_len;
   6076     s->magic = magic;
   6077     for(i = 0; i < data_len; i++)
   6078         s->data[i] = JS_DupValue(ctx, data[i]);
   6079     JS_SetOpaque(func_obj, s);
   6080     js_function_set_properties(ctx, func_obj,
   6081                                JS_ATOM_empty_string, length);
   6082     return func_obj;
   6083 }
   6084 
   6085 static JSContext *js_autoinit_get_realm(JSProperty *pr)
   6086 {
   6087     return (JSContext *)(pr->u.init.realm_and_id & ~3);
   6088 }
   6089 
   6090 static JSAutoInitIDEnum js_autoinit_get_id(JSProperty *pr)
   6091 {
   6092     return pr->u.init.realm_and_id & 3;
   6093 }
   6094 
   6095 static void js_autoinit_free(JSRuntime *rt, JSProperty *pr)
   6096 {
   6097     JS_FreeContext(js_autoinit_get_realm(pr));
   6098 }
   6099 
   6100 static void js_autoinit_mark(JSRuntime *rt, JSProperty *pr,
   6101                              JS_MarkFunc *mark_func)
   6102 {
   6103     mark_func(rt, &js_autoinit_get_realm(pr)->header);
   6104 }
   6105 
   6106 static void free_property(JSRuntime *rt, JSProperty *pr, int prop_flags)
   6107 {
   6108     if (unlikely(prop_flags & JS_PROP_TMASK)) {
   6109         if ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
   6110             if (pr->u.getset.getter)
   6111                 JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
   6112             if (pr->u.getset.setter)
   6113                 JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
   6114         } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
   6115             free_var_ref(rt, pr->u.var_ref);
   6116         } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
   6117             js_autoinit_free(rt, pr);
   6118         }
   6119     } else {
   6120         JS_FreeValueRT(rt, pr->u.value);
   6121     }
   6122 }
   6123 
   6124 static force_inline JSShapeProperty *find_own_property1(JSObject *p,
   6125                                                         JSAtom atom)
   6126 {
   6127     JSShape *sh;
   6128     JSShapeProperty *pr, *prop;
   6129     intptr_t h;
   6130     sh = p->shape;
   6131     h = (uintptr_t)atom & sh->prop_hash_mask;
   6132     h = sh->hash_table[h];
   6133     prop = get_shape_prop(sh);
   6134     while (h) {
   6135         pr = &prop[h - 1];
   6136         if (likely(pr->atom == atom)) {
   6137             return pr;
   6138         }
   6139         h = pr->hash_next;
   6140     }
   6141     return NULL;
   6142 }
   6143 
   6144 static force_inline JSShapeProperty *find_own_property(JSProperty **ppr,
   6145                                                        JSObject *p,
   6146                                                        JSAtom atom)
   6147 {
   6148     JSShape *sh;
   6149     JSShapeProperty *pr, *prop;
   6150     intptr_t h;
   6151     sh = p->shape;
   6152     h = (uintptr_t)atom & sh->prop_hash_mask;
   6153     h = sh->hash_table[h];
   6154     prop = get_shape_prop(sh);
   6155     while (h) {
   6156         pr = &prop[h - 1];
   6157         if (likely(pr->atom == atom)) {
   6158             *ppr = &p->prop[h - 1];
   6159             /* the compiler should be able to assume that pr != NULL here */
   6160             return pr;
   6161         }
   6162         h = pr->hash_next;
   6163     }
   6164     *ppr = NULL;
   6165     return NULL;
   6166 }
   6167 
   6168 /* indicate that the object may be part of a function prototype cycle */
   6169 static void set_cycle_flag(JSContext *ctx, JSValueConst obj)
   6170 {
   6171 }
   6172 
   6173 static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref)
   6174 {
   6175     if (var_ref) {
   6176         assert(js_rc(var_ref)->ref_count > 0);
   6177         if (--js_rc(var_ref)->ref_count == 0) {
   6178             if (var_ref->is_detached) {
   6179                 JS_FreeValueRT(rt, var_ref->value);
   6180             } else {
   6181                 JSStackFrame *sf = var_ref->stack_frame;
   6182                 assert(sf->var_refs[var_ref->var_ref_idx] == var_ref);
   6183                 sf->var_refs[var_ref->var_ref_idx] = NULL;
   6184                 if (sf->js_mode & JS_MODE_ASYNC) {
   6185                     JSAsyncFunctionState *async_func = container_of(sf, JSAsyncFunctionState, frame);
   6186                     async_func_free(rt, async_func);
   6187                 }
   6188             }
   6189             remove_gc_object(&var_ref->header);
   6190             js_free_rt(rt, var_ref);
   6191         }
   6192     }
   6193 }
   6194 
   6195 static void js_array_finalizer(JSRuntime *rt, JSValue val)
   6196 {
   6197     JSObject *p = JS_VALUE_GET_OBJ(val);
   6198     int i;
   6199 
   6200     for(i = 0; i < p->u.array.count; i++) {
   6201         JS_FreeValueRT(rt, p->u.array.u.values[i]);
   6202     }
   6203     js_free_rt(rt, p->u.array.u.values);
   6204 }
   6205 
   6206 static void js_array_mark(JSRuntime *rt, JSValueConst val,
   6207                           JS_MarkFunc *mark_func)
   6208 {
   6209     JSObject *p = JS_VALUE_GET_OBJ(val);
   6210     int i;
   6211 
   6212     for(i = 0; i < p->u.array.count; i++) {
   6213         JS_MarkValue(rt, p->u.array.u.values[i], mark_func);
   6214     }
   6215 }
   6216 
   6217 static void js_object_data_finalizer(JSRuntime *rt, JSValue val)
   6218 {
   6219     JSObject *p = JS_VALUE_GET_OBJ(val);
   6220     JS_FreeValueRT(rt, p->u.object_data);
   6221     p->u.object_data = JS_UNDEFINED;
   6222 }
   6223 
   6224 static void js_object_data_mark(JSRuntime *rt, JSValueConst val,
   6225                                 JS_MarkFunc *mark_func)
   6226 {
   6227     JSObject *p = JS_VALUE_GET_OBJ(val);
   6228     JS_MarkValue(rt, p->u.object_data, mark_func);
   6229 }
   6230 
   6231 static void js_c_function_finalizer(JSRuntime *rt, JSValue val)
   6232 {
   6233     JSObject *p = JS_VALUE_GET_OBJ(val);
   6234 
   6235     if (p->u.cfunc.realm)
   6236         JS_FreeContext(p->u.cfunc.realm);
   6237 }
   6238 
   6239 static void js_c_function_mark(JSRuntime *rt, JSValueConst val,
   6240                                JS_MarkFunc *mark_func)
   6241 {
   6242     JSObject *p = JS_VALUE_GET_OBJ(val);
   6243 
   6244     if (p->u.cfunc.realm)
   6245         mark_func(rt, &p->u.cfunc.realm->header);
   6246 }
   6247 
   6248 static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val)
   6249 {
   6250     JSObject *p1, *p = JS_VALUE_GET_OBJ(val);
   6251     JSFunctionBytecode *b;
   6252     JSVarRef **var_refs;
   6253     int i;
   6254 
   6255     p1 = p->u.func.home_object;
   6256     if (p1) {
   6257         JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, p1));
   6258     }
   6259     b = p->u.func.function_bytecode;
   6260     if (b) {
   6261         var_refs = p->u.func.var_refs;
   6262         if (var_refs) {
   6263             for(i = 0; i < b->closure_var_count; i++)
   6264                 free_var_ref(rt, var_refs[i]);
   6265             js_free_rt(rt, var_refs);
   6266         }
   6267         JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b));
   6268     }
   6269 }
   6270 
   6271 static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
   6272                                       JS_MarkFunc *mark_func)
   6273 {
   6274     JSObject *p = JS_VALUE_GET_OBJ(val);
   6275     JSVarRef **var_refs = p->u.func.var_refs;
   6276     JSFunctionBytecode *b = p->u.func.function_bytecode;
   6277     int i;
   6278 
   6279     if (p->u.func.home_object) {
   6280         JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object),
   6281                      mark_func);
   6282     }
   6283     if (b) {
   6284         if (var_refs) {
   6285             for(i = 0; i < b->closure_var_count; i++) {
   6286                 JSVarRef *var_ref = var_refs[i];
   6287                 if (var_ref) {
   6288                     mark_func(rt, &var_ref->header);
   6289                 }
   6290             }
   6291         }
   6292         /* must mark the function bytecode because template objects may be
   6293            part of a cycle */
   6294         JS_MarkValue(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b), mark_func);
   6295     }
   6296 }
   6297 
   6298 static void js_bound_function_finalizer(JSRuntime *rt, JSValue val)
   6299 {
   6300     JSObject *p = JS_VALUE_GET_OBJ(val);
   6301     JSBoundFunction *bf = p->u.bound_function;
   6302     int i;
   6303 
   6304     JS_FreeValueRT(rt, bf->func_obj);
   6305     JS_FreeValueRT(rt, bf->this_val);
   6306     for(i = 0; i < bf->argc; i++) {
   6307         JS_FreeValueRT(rt, bf->argv[i]);
   6308     }
   6309     js_free_rt(rt, bf);
   6310 }
   6311 
   6312 static void js_bound_function_mark(JSRuntime *rt, JSValueConst val,
   6313                                 JS_MarkFunc *mark_func)
   6314 {
   6315     JSObject *p = JS_VALUE_GET_OBJ(val);
   6316     JSBoundFunction *bf = p->u.bound_function;
   6317     int i;
   6318 
   6319     JS_MarkValue(rt, bf->func_obj, mark_func);
   6320     JS_MarkValue(rt, bf->this_val, mark_func);
   6321     for(i = 0; i < bf->argc; i++)
   6322         JS_MarkValue(rt, bf->argv[i], mark_func);
   6323 }
   6324 
   6325 static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val)
   6326 {
   6327     JSObject *p = JS_VALUE_GET_OBJ(val);
   6328     JSForInIterator *it = p->u.for_in_iterator;
   6329     int i;
   6330 
   6331     JS_FreeValueRT(rt, it->obj);
   6332     if (!it->is_array) {
   6333         for(i = 0; i < it->atom_count; i++) {
   6334             JS_FreeAtomRT(rt, it->tab_atom[i].atom);
   6335         }
   6336         js_free_rt(rt, it->tab_atom);
   6337     }
   6338     js_free_rt(rt, it);
   6339 }
   6340 
   6341 static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val,
   6342                                 JS_MarkFunc *mark_func)
   6343 {
   6344     JSObject *p = JS_VALUE_GET_OBJ(val);
   6345     JSForInIterator *it = p->u.for_in_iterator;
   6346     JS_MarkValue(rt, it->obj, mark_func);
   6347 }
   6348 
   6349 static void free_object(JSRuntime *rt, JSObject *p)
   6350 {
   6351     int i;
   6352     JSClassFinalizer *finalizer;
   6353     JSShape *sh;
   6354     JSShapeProperty *pr;
   6355 
   6356     p->free_mark = 1; /* used to tell the object is invalid when
   6357                          freeing cycles */
   6358     /* free all the fields */
   6359     sh = p->shape;
   6360     pr = get_shape_prop(sh);
   6361     for(i = 0; i < sh->prop_count; i++) {
   6362         free_property(rt, &p->prop[i], pr->flags);
   6363         pr++;
   6364     }
   6365     js_free_rt(rt, p->prop);
   6366     /* as an optimization we destroy the shape immediately without
   6367        putting it in gc_zero_ref_count_list */
   6368     js_free_shape(rt, sh);
   6369 
   6370     /* fail safe */
   6371     p->shape = NULL;
   6372     p->prop = NULL;
   6373 
   6374     finalizer = rt->class_array[p->class_id].finalizer;
   6375     if (finalizer)
   6376         (*finalizer)(rt, JS_MKPTR(JS_TAG_OBJECT, p));
   6377 
   6378     /* fail safe */
   6379     p->class_id = 0;
   6380     p->u.opaque = NULL;
   6381     p->u.func.var_refs = NULL;
   6382     p->u.func.home_object = NULL;
   6383 
   6384     remove_gc_object(&p->header);
   6385     if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES) {
   6386         if (js_rc(p)->ref_count == 0 && p->weakref_count == 0) {
   6387             js_free_rt(rt, p);
   6388         } else {
   6389             /* keep the object structure because there are may be
   6390                references to it */
   6391             list_add_tail(&p->header.link, &rt->gc_zero_ref_count_list);
   6392         }
   6393     } else {
   6394         /* keep the object structure in case there are weak references to it */
   6395         if (p->weakref_count == 0) {
   6396             js_free_rt(rt, p);
   6397         } else {
   6398             js_rc(p)->mark = 0; /* reset the mark so that the weakref can be freed */
   6399         }
   6400     }
   6401 }
   6402 
   6403 static void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp)
   6404 {
   6405     switch(js_rc(gp)->gc_obj_type) {
   6406     case JS_GC_OBJ_TYPE_JS_OBJECT:
   6407         free_object(rt, (JSObject *)gp);
   6408         break;
   6409     case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
   6410         free_function_bytecode(rt, (JSFunctionBytecode *)gp);
   6411         break;
   6412     case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
   6413         __async_func_free(rt, (JSAsyncFunctionState *)gp);
   6414         break;
   6415     case JS_GC_OBJ_TYPE_MODULE:
   6416         js_free_module_def(rt, (JSModuleDef *)gp);
   6417         break;
   6418     default:
   6419         abort();
   6420     }
   6421 }
   6422 
   6423 static void free_zero_refcount(JSRuntime *rt)
   6424 {
   6425     struct list_head *el;
   6426     JSGCObjectHeader *p;
   6427 
   6428     rt->gc_phase = JS_GC_PHASE_DECREF;
   6429     for(;;) {
   6430         el = rt->gc_zero_ref_count_list.next;
   6431         if (el == &rt->gc_zero_ref_count_list)
   6432             break;
   6433         p = list_entry(el, JSGCObjectHeader, link);
   6434         assert(js_rc(p)->ref_count == 0);
   6435         free_gc_object(rt, p);
   6436     }
   6437     rt->gc_phase = JS_GC_PHASE_NONE;
   6438 }
   6439 
   6440 /* called with the ref_count of 'v' reaches zero. */
   6441 void __JS_FreeValueRT(JSRuntime *rt, JSValue v)
   6442 {
   6443     uint32_t tag = JS_VALUE_GET_TAG(v);
   6444 
   6445 #ifdef DUMP_FREE
   6446     {
   6447         printf("Freeing ");
   6448         if (tag == JS_TAG_OBJECT) {
   6449             JS_DumpObject(rt, JS_VALUE_GET_OBJ(v));
   6450         } else {
   6451             JS_DumpValueShort(rt, v);
   6452             printf("\n");
   6453         }
   6454     }
   6455 #endif
   6456 
   6457     switch(tag) {
   6458     case JS_TAG_STRING:
   6459         {
   6460             JSString *p = JS_VALUE_GET_STRING(v);
   6461             if (p->atom_type) {
   6462                 JS_FreeAtomStruct(rt, p);
   6463             } else {
   6464 #ifdef DUMP_LEAKS
   6465                 list_del(&p->link);
   6466 #endif
   6467                 js_free_rt(rt, p);
   6468             }
   6469         }
   6470         break;
   6471     case JS_TAG_STRING_ROPE:
   6472         /* Note: recursion is acceptable because the rope depth is bounded */
   6473         {
   6474             JSStringRope *p = JS_VALUE_GET_STRING_ROPE(v);
   6475             JS_FreeValueRT(rt, p->left);
   6476             JS_FreeValueRT(rt, p->right);
   6477             js_free_rt(rt, p);
   6478         }
   6479         break;
   6480     case JS_TAG_OBJECT:
   6481     case JS_TAG_FUNCTION_BYTECODE:
   6482     case JS_TAG_MODULE:
   6483         {
   6484             JSGCObjectHeader *p = JS_VALUE_GET_PTR(v);
   6485             if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {
   6486                 list_del(&p->link);
   6487                 list_add(&p->link, &rt->gc_zero_ref_count_list);
   6488                 js_rc(p)->mark = 1; /* indicate that the object is about to be freed */
   6489                 if (rt->gc_phase == JS_GC_PHASE_NONE) {
   6490                     free_zero_refcount(rt);
   6491                 }
   6492             }
   6493         }
   6494         break;
   6495     case JS_TAG_BIG_INT:
   6496         {
   6497             JSBigInt *p = JS_VALUE_GET_PTR(v);
   6498             js_free_rt(rt, p);
   6499         }
   6500         break;
   6501     case JS_TAG_SYMBOL:
   6502         {
   6503             JSAtomStruct *p = JS_VALUE_GET_PTR(v);
   6504             JS_FreeAtomStruct(rt, p);
   6505         }
   6506         break;
   6507     default:
   6508         abort();
   6509     }
   6510 }
   6511 
   6512 void __JS_FreeValue(JSContext *ctx, JSValue v)
   6513 {
   6514     __JS_FreeValueRT(ctx->rt, v);
   6515 }
   6516 
   6517 /* garbage collection */
   6518 
   6519 static void gc_remove_weak_objects(JSRuntime *rt)
   6520 {
   6521     struct list_head *el;
   6522 
   6523     /* add the freed objects to rt->gc_zero_ref_count_list so that
   6524        rt->weakref_list is not modified while we traverse it */
   6525     rt->gc_phase = JS_GC_PHASE_DECREF; 
   6526         
   6527     list_for_each(el, &rt->weakref_list) {
   6528         JSWeakRefHeader *wh = list_entry(el, JSWeakRefHeader, link);
   6529         switch(wh->weakref_type) {
   6530         case JS_WEAKREF_TYPE_MAP:
   6531             map_delete_weakrefs(rt, wh);
   6532             break;
   6533         case JS_WEAKREF_TYPE_WEAKREF:
   6534             weakref_delete_weakref(rt, wh);
   6535             break;
   6536         case JS_WEAKREF_TYPE_FINREC:
   6537             finrec_delete_weakref(rt, wh);
   6538             break;
   6539         default:
   6540             abort();
   6541         }
   6542     }
   6543 
   6544     rt->gc_phase = JS_GC_PHASE_NONE;
   6545     /* free the freed objects here. */
   6546     free_zero_refcount(rt);
   6547 }
   6548 
   6549 static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
   6550                           JSGCObjectTypeEnum type)
   6551 {
   6552     js_rc(h)->mark = 0;
   6553     js_rc(h)->gc_obj_type = type;
   6554     list_add_tail(&h->link, &rt->gc_obj_list);
   6555 }
   6556 
   6557 static void remove_gc_object(JSGCObjectHeader *h)
   6558 {
   6559     list_del(&h->link);
   6560 }
   6561 
   6562 void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
   6563 {
   6564     if (JS_VALUE_HAS_REF_COUNT(val)) {
   6565         switch(JS_VALUE_GET_TAG(val)) {
   6566         case JS_TAG_OBJECT:
   6567         case JS_TAG_FUNCTION_BYTECODE:
   6568         case JS_TAG_MODULE:
   6569             mark_func(rt, JS_VALUE_GET_PTR(val));
   6570             break;
   6571         default:
   6572             break;
   6573         }
   6574     }
   6575 }
   6576 
   6577 static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp,
   6578                           JS_MarkFunc *mark_func)
   6579 {
   6580     switch(js_rc(gp)->gc_obj_type) {
   6581     case JS_GC_OBJ_TYPE_JS_OBJECT:
   6582         {
   6583             JSObject *p = (JSObject *)gp;
   6584             JSShapeProperty *prs;
   6585             JSShape *sh;
   6586             int i;
   6587             sh = p->shape;
   6588             mark_func(rt, &sh->header);
   6589             /* mark all the fields */
   6590             prs = get_shape_prop(sh);
   6591             for(i = 0; i < sh->prop_count; i++) {
   6592                 JSProperty *pr = &p->prop[i];
   6593                 if (prs->atom != JS_ATOM_NULL) {
   6594                     if (prs->flags & JS_PROP_TMASK) {
   6595                         if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
   6596                             if (pr->u.getset.getter)
   6597                                 mark_func(rt, &pr->u.getset.getter->header);
   6598                             if (pr->u.getset.setter)
   6599                                 mark_func(rt, &pr->u.getset.setter->header);
   6600                         } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
   6601                             /* Note: the tag does not matter
   6602                                provided it is a GC object */
   6603                             mark_func(rt, &pr->u.var_ref->header);
   6604                         } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
   6605                             js_autoinit_mark(rt, pr, mark_func);
   6606                         }
   6607                     } else {
   6608                         JS_MarkValue(rt, pr->u.value, mark_func);
   6609                     }
   6610                 }
   6611                 prs++;
   6612             }
   6613 
   6614             if (p->class_id != JS_CLASS_OBJECT) {
   6615                 JSClassGCMark *gc_mark;
   6616                 gc_mark = rt->class_array[p->class_id].gc_mark;
   6617                 if (gc_mark)
   6618                     gc_mark(rt, JS_MKPTR(JS_TAG_OBJECT, p), mark_func);
   6619             }
   6620         }
   6621         break;
   6622     case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
   6623         /* the template objects can be part of a cycle */
   6624         {
   6625             JSFunctionBytecode *b = (JSFunctionBytecode *)gp;
   6626             int i;
   6627             for(i = 0; i < b->cpool_count; i++) {
   6628                 JS_MarkValue(rt, b->cpool[i], mark_func);
   6629             }
   6630             if (b->realm)
   6631                 mark_func(rt, &b->realm->header);
   6632         }
   6633         break;
   6634     case JS_GC_OBJ_TYPE_VAR_REF:
   6635         {
   6636             JSVarRef *var_ref = (JSVarRef *)gp;
   6637             if (var_ref->is_detached) {
   6638                 JS_MarkValue(rt, *var_ref->pvalue, mark_func);
   6639             } else {
   6640                 JSStackFrame *sf = var_ref->stack_frame;
   6641                 if (sf->js_mode & JS_MODE_ASYNC) {
   6642                     JSAsyncFunctionState *async_func = container_of(sf, JSAsyncFunctionState, frame);
   6643                     mark_func(rt, &async_func->header);
   6644                 }
   6645             }
   6646         }
   6647         break;
   6648     case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
   6649         {
   6650             JSAsyncFunctionState *s = (JSAsyncFunctionState *)gp;
   6651             JSStackFrame *sf = &s->frame;
   6652             JSValue *sp;
   6653 
   6654             if (!s->is_completed) {
   6655                 JS_MarkValue(rt, sf->cur_func, mark_func);
   6656                 JS_MarkValue(rt, s->this_val, mark_func);
   6657                 /* sf->cur_sp = NULL if the function is running */
   6658                 if (sf->cur_sp) {
   6659                     /* if the function is running, cur_sp is not known so we
   6660                        cannot mark the stack. Marking the variables is not needed
   6661                        because a running function cannot be part of a removable
   6662                        cycle */
   6663                     for(sp = sf->arg_buf; sp < sf->cur_sp; sp++)
   6664                         JS_MarkValue(rt, *sp, mark_func);
   6665                 }
   6666             }
   6667             JS_MarkValue(rt, s->resolving_funcs[0], mark_func);
   6668             JS_MarkValue(rt, s->resolving_funcs[1], mark_func);
   6669         }
   6670         break;
   6671     case JS_GC_OBJ_TYPE_SHAPE:
   6672         {
   6673             JSShape *sh = (JSShape *)gp;
   6674             if (sh->proto != NULL) {
   6675                 mark_func(rt, &sh->proto->header);
   6676             }
   6677         }
   6678         break;
   6679     case JS_GC_OBJ_TYPE_JS_CONTEXT:
   6680         {
   6681             JSContext *ctx = (JSContext *)gp;
   6682             JS_MarkContext(rt, ctx, mark_func);
   6683         }
   6684         break;
   6685     case JS_GC_OBJ_TYPE_MODULE:
   6686         {
   6687             JSModuleDef *m = (JSModuleDef *)gp;
   6688             js_mark_module_def(rt, m, mark_func);
   6689         }
   6690         break;
   6691     default:
   6692         abort();
   6693     }
   6694 }
   6695 
   6696 static void gc_decref_child(JSRuntime *rt, JSGCObjectHeader *p)
   6697 {
   6698     assert(js_rc(p)->ref_count > 0);
   6699     js_rc(p)->ref_count--;
   6700     if (js_rc(p)->ref_count == 0 && js_rc(p)->mark == 1) {
   6701         list_del(&p->link);
   6702         list_add_tail(&p->link, &rt->tmp_obj_list);
   6703     }
   6704 }
   6705 
   6706 static void gc_decref(JSRuntime *rt)
   6707 {
   6708     struct list_head *el, *el1;
   6709     JSGCObjectHeader *p;
   6710 
   6711     init_list_head(&rt->tmp_obj_list);
   6712 
   6713     /* decrement the refcount of all the children of all the GC
   6714        objects and move the GC objects with zero refcount to
   6715        tmp_obj_list */
   6716     list_for_each_safe(el, el1, &rt->gc_obj_list) {
   6717         p = list_entry(el, JSGCObjectHeader, link);
   6718         assert(js_rc(p)->mark == 0);
   6719         mark_children(rt, p, gc_decref_child);
   6720         js_rc(p)->mark = 1;
   6721         if (js_rc(p)->ref_count == 0) {
   6722             list_del(&p->link);
   6723             list_add_tail(&p->link, &rt->tmp_obj_list);
   6724         }
   6725     }
   6726 }
   6727 
   6728 static void gc_scan_incref_child(JSRuntime *rt, JSGCObjectHeader *p)
   6729 {
   6730     js_rc(p)->ref_count++;
   6731     if (js_rc(p)->ref_count == 1) {
   6732         /* ref_count was 0: remove from tmp_obj_list and add at the
   6733            end of gc_obj_list */
   6734         list_del(&p->link);
   6735         list_add_tail(&p->link, &rt->gc_obj_list);
   6736         js_rc(p)->mark = 0; /* reset the mark for the next GC call */
   6737     }
   6738 }
   6739 
   6740 static void gc_scan_incref_child2(JSRuntime *rt, JSGCObjectHeader *p)
   6741 {
   6742     js_rc(p)->ref_count++;
   6743 }
   6744 
   6745 static void gc_scan(JSRuntime *rt)
   6746 {
   6747     struct list_head *el;
   6748     JSGCObjectHeader *p;
   6749 
   6750     /* keep the objects with a refcount > 0 and their children. */
   6751     list_for_each(el, &rt->gc_obj_list) {
   6752         p = list_entry(el, JSGCObjectHeader, link);
   6753         assert(js_rc(p)->ref_count > 0);
   6754         js_rc(p)->mark = 0; /* reset the mark for the next GC call */
   6755         mark_children(rt, p, gc_scan_incref_child);
   6756     }
   6757 
   6758     /* restore the refcount of the objects to be deleted. */
   6759     list_for_each(el, &rt->tmp_obj_list) {
   6760         p = list_entry(el, JSGCObjectHeader, link);
   6761         mark_children(rt, p, gc_scan_incref_child2);
   6762     }
   6763 }
   6764 
   6765 static void gc_free_cycles(JSRuntime *rt)
   6766 {
   6767     struct list_head *el, *el1;
   6768     JSGCObjectHeader *p;
   6769 #ifdef DUMP_GC_FREE
   6770     BOOL header_done = FALSE;
   6771 #endif
   6772 
   6773     rt->gc_phase = JS_GC_PHASE_REMOVE_CYCLES;
   6774 
   6775     for(;;) {
   6776         el = rt->tmp_obj_list.next;
   6777         if (el == &rt->tmp_obj_list)
   6778             break;
   6779         p = list_entry(el, JSGCObjectHeader, link);
   6780         /* Only need to free the GC object associated with JS values
   6781            or async functions. The rest will be automatically removed
   6782            because they must be referenced by them. */
   6783         switch(js_rc(p)->gc_obj_type) {
   6784         case JS_GC_OBJ_TYPE_JS_OBJECT:
   6785         case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
   6786         case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
   6787         case JS_GC_OBJ_TYPE_MODULE:
   6788 #ifdef DUMP_GC_FREE
   6789             if (!header_done) {
   6790                 printf("Freeing cycles:\n");
   6791                 JS_DumpObjectHeader(rt);
   6792                 header_done = TRUE;
   6793             }
   6794             JS_DumpGCObject(rt, p);
   6795 #endif
   6796             free_gc_object(rt, p);
   6797             break;
   6798         default:
   6799             list_del(&p->link);
   6800             list_add_tail(&p->link, &rt->gc_zero_ref_count_list);
   6801             break;
   6802         }
   6803     }
   6804     rt->gc_phase = JS_GC_PHASE_NONE;
   6805 
   6806     list_for_each_safe(el, el1, &rt->gc_zero_ref_count_list) {
   6807         p = list_entry(el, JSGCObjectHeader, link);
   6808         assert(js_rc(p)->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT ||
   6809                js_rc(p)->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE ||
   6810                js_rc(p)->gc_obj_type == JS_GC_OBJ_TYPE_ASYNC_FUNCTION ||
   6811                js_rc(p)->gc_obj_type == JS_GC_OBJ_TYPE_MODULE);
   6812         if (js_rc(p)->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT &&
   6813             ((JSObject *)p)->weakref_count != 0) {
   6814             /* keep the object because there are weak references to it */
   6815             js_rc(p)->mark = 0;
   6816         } else {
   6817             js_free_rt(rt, p);
   6818         }
   6819     }
   6820 
   6821     init_list_head(&rt->gc_zero_ref_count_list);
   6822 }
   6823 
   6824 static void JS_RunGCInternal(JSRuntime *rt, BOOL remove_weak_objects)
   6825 {
   6826     if (remove_weak_objects) {
   6827         /* free the weakly referenced object or symbol structures, delete
   6828            the associated Map/Set entries and queue the finalization
   6829            registry callbacks. */
   6830         gc_remove_weak_objects(rt);
   6831     }
   6832     
   6833     /* decrement the reference of the children of each object. mark =
   6834        1 after this pass. */
   6835     gc_decref(rt);
   6836 
   6837     /* keep the GC objects with a non zero refcount and their childs */
   6838     gc_scan(rt);
   6839 
   6840     /* free the GC objects in a cycle */
   6841     gc_free_cycles(rt);
   6842 }
   6843 
   6844 void JS_RunGC(JSRuntime *rt)
   6845 {
   6846     JS_RunGCInternal(rt, TRUE);
   6847 }
   6848 
   6849 /* Return false if not an object or if the object has already been
   6850    freed (zombie objects are visible in finalizers when freeing
   6851    cycles). */
   6852 BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj)
   6853 {
   6854     JSObject *p;
   6855     if (!JS_IsObject(obj))
   6856         return FALSE;
   6857     p = JS_VALUE_GET_OBJ(obj);
   6858     return !p->free_mark;
   6859 }
   6860 
   6861 /* Compute memory used by various object types */
   6862 /* XXX: poor man's approach to handling multiply referenced objects */
   6863 typedef struct JSMemoryUsage_helper {
   6864     double memory_used_count;
   6865     double str_count;
   6866     double str_size;
   6867     int64_t js_func_count;
   6868     double js_func_size;
   6869     int64_t js_func_code_size;
   6870     int64_t js_func_pc2line_count;
   6871     int64_t js_func_pc2line_size;
   6872 } JSMemoryUsage_helper;
   6873 
   6874 static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp);
   6875 
   6876 static void compute_jsstring_size(JSString *str, JSMemoryUsage_helper *hp)
   6877 {
   6878     if (!str->atom_type) {  /* atoms are handled separately */
   6879         double s_ref_count = js_rc(str)->ref_count;
   6880         hp->str_count += 1 / s_ref_count;
   6881         hp->str_size += ((sizeof(*str) + (str->len << str->is_wide_char) +
   6882                           1 - str->is_wide_char) / s_ref_count);
   6883     }
   6884 }
   6885 
   6886 static void compute_bytecode_size(JSFunctionBytecode *b, JSMemoryUsage_helper *hp)
   6887 {
   6888     int memory_used_count, js_func_size, i;
   6889 
   6890     memory_used_count = 0;
   6891     js_func_size = offsetof(JSFunctionBytecode, debug);
   6892     if (b->vardefs) {
   6893         js_func_size += (b->arg_count + b->var_count) * sizeof(*b->vardefs);
   6894     }
   6895     if (b->cpool) {
   6896         js_func_size += b->cpool_count * sizeof(*b->cpool);
   6897         for (i = 0; i < b->cpool_count; i++) {
   6898             JSValueConst val = b->cpool[i];
   6899             compute_value_size(val, hp);
   6900         }
   6901     }
   6902     if (b->closure_var) {
   6903         js_func_size += b->closure_var_count * sizeof(*b->closure_var);
   6904     }
   6905     if (!b->read_only_bytecode && b->byte_code_buf) {
   6906         hp->js_func_code_size += b->byte_code_len;
   6907     }
   6908     if (b->has_debug) {
   6909         js_func_size += sizeof(*b) - offsetof(JSFunctionBytecode, debug);
   6910         if (b->debug.source) {
   6911             memory_used_count++;
   6912             js_func_size += b->debug.source_len + 1;
   6913         }
   6914         if (b->debug.pc2line_len) {
   6915             memory_used_count++;
   6916             hp->js_func_pc2line_count += 1;
   6917             hp->js_func_pc2line_size += b->debug.pc2line_len;
   6918         }
   6919     }
   6920     hp->js_func_size += js_func_size;
   6921     hp->js_func_count += 1;
   6922     hp->memory_used_count += memory_used_count;
   6923 }
   6924 
   6925 static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp)
   6926 {
   6927     switch(JS_VALUE_GET_TAG(val)) {
   6928     case JS_TAG_STRING:
   6929         compute_jsstring_size(JS_VALUE_GET_STRING(val), hp);
   6930         break;
   6931     case JS_TAG_BIG_INT:
   6932         /* should track JSBigInt usage */
   6933         break;
   6934     }
   6935 }
   6936 
   6937 void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
   6938 {
   6939     struct list_head *el, *el1;
   6940     int i;
   6941     JSMemoryUsage_helper mem = { 0 }, *hp = &mem;
   6942 
   6943     memset(s, 0, sizeof(*s));
   6944     s->malloc_count = rt->malloc_ctx.malloc_state.malloc_count;
   6945     s->malloc_size = rt->malloc_ctx.malloc_state.malloc_size;
   6946     s->malloc_limit = rt->malloc_ctx.malloc_state.malloc_limit;
   6947 
   6948     s->memory_used_count = 2; /* rt + rt->class_array */
   6949     s->memory_used_size = sizeof(JSRuntime) + sizeof(JSValue) * rt->class_count;
   6950 
   6951     list_for_each(el, &rt->context_list) {
   6952         JSContext *ctx = list_entry(el, JSContext, link);
   6953         JSShape *sh = ctx->array_shape;
   6954         s->memory_used_count += 2; /* ctx + ctx->class_proto */
   6955         s->memory_used_size += sizeof(JSContext) +
   6956             sizeof(JSValue) * rt->class_count;
   6957         s->binary_object_count += ctx->binary_object_count;
   6958         s->binary_object_size += ctx->binary_object_size;
   6959 
   6960         /* the hashed shapes are counted separately */
   6961         if (sh && !sh->is_hashed) {
   6962             int hash_size = sh->prop_hash_mask + 1;
   6963             s->shape_count++;
   6964             s->shape_size += get_shape_size(hash_size, sh->prop_size);
   6965         }
   6966         list_for_each(el1, &ctx->loaded_modules) {
   6967             JSModuleDef *m = list_entry(el1, JSModuleDef, link);
   6968             s->memory_used_count += 1;
   6969             s->memory_used_size += sizeof(*m);
   6970             if (m->req_module_entries) {
   6971                 s->memory_used_count += 1;
   6972                 s->memory_used_size += m->req_module_entries_count * sizeof(*m->req_module_entries);
   6973             }
   6974             if (m->export_entries) {
   6975                 s->memory_used_count += 1;
   6976                 s->memory_used_size += m->export_entries_count * sizeof(*m->export_entries);
   6977                 for (i = 0; i < m->export_entries_count; i++) {
   6978                     JSExportEntry *me = &m->export_entries[i];
   6979                     if (me->export_type == JS_EXPORT_TYPE_LOCAL && me->u.local.var_ref) {
   6980                         /* potential multiple count */
   6981                         s->memory_used_count += 1;
   6982                         compute_value_size(me->u.local.var_ref->value, hp);
   6983                     }
   6984                 }
   6985             }
   6986             if (m->star_export_entries) {
   6987                 s->memory_used_count += 1;
   6988                 s->memory_used_size += m->star_export_entries_count * sizeof(*m->star_export_entries);
   6989             }
   6990             if (m->import_entries) {
   6991                 s->memory_used_count += 1;
   6992                 s->memory_used_size += m->import_entries_count * sizeof(*m->import_entries);
   6993             }
   6994             compute_value_size(m->module_ns, hp);
   6995             compute_value_size(m->func_obj, hp);
   6996         }
   6997     }
   6998 
   6999     list_for_each(el, &rt->gc_obj_list) {
   7000         JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link);
   7001         JSObject *p;
   7002         JSShape *sh;
   7003         JSShapeProperty *prs;
   7004 
   7005         /* XXX: could count the other GC object types too */
   7006         if (js_rc(gp)->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE) {
   7007             compute_bytecode_size((JSFunctionBytecode *)gp, hp);
   7008             continue;
   7009         } else if (js_rc(gp)->gc_obj_type != JS_GC_OBJ_TYPE_JS_OBJECT) {
   7010             continue;
   7011         }
   7012         p = (JSObject *)gp;
   7013         sh = p->shape;
   7014         s->obj_count++;
   7015         if (p->prop) {
   7016             s->memory_used_count++;
   7017             s->prop_size += sh->prop_size * sizeof(*p->prop);
   7018             s->prop_count += sh->prop_count;
   7019             prs = get_shape_prop(sh);
   7020             for(i = 0; i < sh->prop_count; i++) {
   7021                 JSProperty *pr = &p->prop[i];
   7022                 if (prs->atom != JS_ATOM_NULL && !(prs->flags & JS_PROP_TMASK)) {
   7023                     compute_value_size(pr->u.value, hp);
   7024                 }
   7025                 prs++;
   7026             }
   7027         }
   7028         /* the hashed shapes are counted separately */
   7029         if (!sh->is_hashed) {
   7030             int hash_size = sh->prop_hash_mask + 1;
   7031             s->shape_count++;
   7032             s->shape_size += get_shape_size(hash_size, sh->prop_size);
   7033         }
   7034 
   7035         switch(p->class_id) {
   7036         case JS_CLASS_ARRAY:             /* u.array | length */
   7037         case JS_CLASS_ARGUMENTS:         /* u.array | length */
   7038             s->array_count++;
   7039             if (p->fast_array) {
   7040                 s->fast_array_count++;
   7041                 if (p->u.array.u.values) {
   7042                     s->memory_used_count++;
   7043                     s->memory_used_size += p->u.array.count *
   7044                         sizeof(*p->u.array.u.values);
   7045                     s->fast_array_elements += p->u.array.count;
   7046                     for (i = 0; i < p->u.array.count; i++) {
   7047                         compute_value_size(p->u.array.u.values[i], hp);
   7048                     }
   7049                 }
   7050             }
   7051             break;
   7052         case JS_CLASS_MAPPED_ARGUMENTS:         /* u.array | length */
   7053             if (p->fast_array) {
   7054                 s->fast_array_count++;
   7055                 if (p->u.array.u.values) {
   7056                     s->memory_used_count++;
   7057                     s->memory_used_size += p->u.array.count *
   7058                         sizeof(*p->u.array.u.var_refs);
   7059                     s->fast_array_elements += p->u.array.count;
   7060                     for (i = 0; i < p->u.array.count; i++) {
   7061                         compute_value_size(*p->u.array.u.var_refs[i]->pvalue, hp);
   7062                     }
   7063                 }
   7064             }
   7065             break;
   7066         case JS_CLASS_NUMBER:            /* u.object_data */
   7067         case JS_CLASS_STRING:            /* u.object_data */
   7068         case JS_CLASS_BOOLEAN:           /* u.object_data */
   7069         case JS_CLASS_SYMBOL:            /* u.object_data */
   7070         case JS_CLASS_DATE:              /* u.object_data */
   7071         case JS_CLASS_BIG_INT:           /* u.object_data */
   7072             compute_value_size(p->u.object_data, hp);
   7073             break;
   7074         case JS_CLASS_C_FUNCTION:        /* u.cfunc */
   7075             s->c_func_count++;
   7076             break;
   7077         case JS_CLASS_BYTECODE_FUNCTION: /* u.func */
   7078             {
   7079                 JSFunctionBytecode *b = p->u.func.function_bytecode;
   7080                 JSVarRef **var_refs = p->u.func.var_refs;
   7081                 /* home_object: object will be accounted for in list scan */
   7082                 if (var_refs) {
   7083                     s->memory_used_count++;
   7084                     s->js_func_size += b->closure_var_count * sizeof(*var_refs);
   7085                     for (i = 0; i < b->closure_var_count; i++) {
   7086                         if (var_refs[i]) {
   7087                             double ref_count = js_rc(var_refs[i])->ref_count;
   7088                             s->memory_used_count += 1 / ref_count;
   7089                             s->js_func_size += sizeof(*var_refs[i]) / ref_count;
   7090                             /* handle non object closed values */
   7091                             if (var_refs[i]->pvalue == &var_refs[i]->value) {
   7092                                 /* potential multiple count */
   7093                                 compute_value_size(var_refs[i]->value, hp);
   7094                             }
   7095                         }
   7096                     }
   7097                 }
   7098             }
   7099             break;
   7100         case JS_CLASS_BOUND_FUNCTION:    /* u.bound_function */
   7101             {
   7102                 JSBoundFunction *bf = p->u.bound_function;
   7103                 /* func_obj and this_val are objects */
   7104                 for (i = 0; i < bf->argc; i++) {
   7105                     compute_value_size(bf->argv[i], hp);
   7106                 }
   7107                 s->memory_used_count += 1;
   7108                 s->memory_used_size += sizeof(*bf) + bf->argc * sizeof(*bf->argv);
   7109             }
   7110             break;
   7111         case JS_CLASS_C_FUNCTION_DATA:   /* u.c_function_data_record */
   7112             {
   7113                 JSCFunctionDataRecord *fd = p->u.c_function_data_record;
   7114                 if (fd) {
   7115                     for (i = 0; i < fd->data_len; i++) {
   7116                         compute_value_size(fd->data[i], hp);
   7117                     }
   7118                     s->memory_used_count += 1;
   7119                     s->memory_used_size += sizeof(*fd) + fd->data_len * sizeof(*fd->data);
   7120                 }
   7121             }
   7122             break;
   7123         case JS_CLASS_REGEXP:            /* u.regexp */
   7124             compute_jsstring_size(p->u.regexp.pattern, hp);
   7125             compute_jsstring_size(p->u.regexp.bytecode, hp);
   7126             break;
   7127 
   7128         case JS_CLASS_FOR_IN_ITERATOR:   /* u.for_in_iterator */
   7129             {
   7130                 JSForInIterator *it = p->u.for_in_iterator;
   7131                 if (it) {
   7132                     compute_value_size(it->obj, hp);
   7133                     s->memory_used_count += 1;
   7134                     s->memory_used_size += sizeof(*it);
   7135                 }
   7136             }
   7137             break;
   7138         case JS_CLASS_ARRAY_BUFFER:      /* u.array_buffer */
   7139         case JS_CLASS_SHARED_ARRAY_BUFFER: /* u.array_buffer */
   7140             {
   7141                 JSArrayBuffer *abuf = p->u.array_buffer;
   7142                 if (abuf) {
   7143                     s->memory_used_count += 1;
   7144                     s->memory_used_size += sizeof(*abuf);
   7145                     if (abuf->data) {
   7146                         s->memory_used_count += 1;
   7147                         s->memory_used_size += abuf->byte_length;
   7148                     }
   7149                 }
   7150             }
   7151             break;
   7152         case JS_CLASS_GENERATOR:         /* u.generator_data */
   7153         case JS_CLASS_UINT8C_ARRAY:      /* u.typed_array / u.array */
   7154         case JS_CLASS_INT8_ARRAY:        /* u.typed_array / u.array */
   7155         case JS_CLASS_UINT8_ARRAY:       /* u.typed_array / u.array */
   7156         case JS_CLASS_INT16_ARRAY:       /* u.typed_array / u.array */
   7157         case JS_CLASS_UINT16_ARRAY:      /* u.typed_array / u.array */
   7158         case JS_CLASS_INT32_ARRAY:       /* u.typed_array / u.array */
   7159         case JS_CLASS_UINT32_ARRAY:      /* u.typed_array / u.array */
   7160         case JS_CLASS_BIG_INT64_ARRAY:   /* u.typed_array / u.array */
   7161         case JS_CLASS_BIG_UINT64_ARRAY:  /* u.typed_array / u.array */
   7162         case JS_CLASS_FLOAT16_ARRAY:     /* u.typed_array / u.array */
   7163         case JS_CLASS_FLOAT32_ARRAY:     /* u.typed_array / u.array */
   7164         case JS_CLASS_FLOAT64_ARRAY:     /* u.typed_array / u.array */
   7165         case JS_CLASS_DATAVIEW:          /* u.typed_array */
   7166         case JS_CLASS_MAP:               /* u.map_state */
   7167         case JS_CLASS_SET:               /* u.map_state */
   7168         case JS_CLASS_WEAKMAP:           /* u.map_state */
   7169         case JS_CLASS_WEAKSET:           /* u.map_state */
   7170         case JS_CLASS_MAP_ITERATOR:      /* u.map_iterator_data */
   7171         case JS_CLASS_SET_ITERATOR:      /* u.map_iterator_data */
   7172         case JS_CLASS_ARRAY_ITERATOR:    /* u.array_iterator_data */
   7173         case JS_CLASS_STRING_ITERATOR:   /* u.array_iterator_data */
   7174         case JS_CLASS_PROXY:             /* u.proxy_data */
   7175         case JS_CLASS_PROMISE:           /* u.promise_data */
   7176         case JS_CLASS_PROMISE_RESOLVE_FUNCTION:  /* u.promise_function_data */
   7177         case JS_CLASS_PROMISE_REJECT_FUNCTION:   /* u.promise_function_data */
   7178         case JS_CLASS_ASYNC_FUNCTION_RESOLVE:    /* u.async_function_data */
   7179         case JS_CLASS_ASYNC_FUNCTION_REJECT:     /* u.async_function_data */
   7180         case JS_CLASS_ASYNC_FROM_SYNC_ITERATOR:  /* u.async_from_sync_iterator_data */
   7181         case JS_CLASS_ASYNC_GENERATOR:   /* u.async_generator_data */
   7182             /* TODO */
   7183         default:
   7184             /* XXX: class definition should have an opaque block size */
   7185             if (p->u.opaque) {
   7186                 s->memory_used_count += 1;
   7187             }
   7188             break;
   7189         }
   7190     }
   7191     s->obj_size += s->obj_count * sizeof(JSObject);
   7192 
   7193     /* hashed shapes */
   7194     s->memory_used_count++; /* rt->shape_hash */
   7195     s->memory_used_size += sizeof(rt->shape_hash[0]) * rt->shape_hash_size;
   7196     for(i = 0; i < rt->shape_hash_size; i++) {
   7197         JSShape *sh;
   7198         for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) {
   7199             int hash_size = sh->prop_hash_mask + 1;
   7200             s->shape_count++;
   7201             s->shape_size += get_shape_size(hash_size, sh->prop_size);
   7202         }
   7203     }
   7204 
   7205     /* atoms */
   7206     s->memory_used_count += 2; /* rt->atom_array, rt->atom_hash */
   7207     s->atom_count = rt->atom_count;
   7208     s->atom_size = sizeof(rt->atom_array[0]) * rt->atom_size +
   7209         sizeof(rt->atom_hash[0]) * rt->atom_hash_size;
   7210     for(i = 0; i < rt->atom_size; i++) {
   7211         JSAtomStruct *p = rt->atom_array[i];
   7212         if (!atom_is_free(p)) {
   7213             s->atom_size += (sizeof(*p) + (p->len << p->is_wide_char) +
   7214                              1 - p->is_wide_char);
   7215         }
   7216     }
   7217     s->str_count = round(mem.str_count);
   7218     s->str_size = round(mem.str_size);
   7219     s->js_func_count = mem.js_func_count;
   7220     s->js_func_size = round(mem.js_func_size);
   7221     s->js_func_code_size = mem.js_func_code_size;
   7222     s->js_func_pc2line_count = mem.js_func_pc2line_count;
   7223     s->js_func_pc2line_size = mem.js_func_pc2line_size;
   7224     s->memory_used_count += round(mem.memory_used_count) +
   7225         s->atom_count + s->str_count +
   7226         s->obj_count + s->shape_count +
   7227         s->js_func_count + s->js_func_pc2line_count;
   7228     s->memory_used_size += s->atom_size + s->str_size +
   7229         s->obj_size + s->prop_size + s->shape_size +
   7230         s->js_func_size + s->js_func_code_size + s->js_func_pc2line_size;
   7231 }
   7232 
   7233 void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt)
   7234 {
   7235     fprintf(fp, "QuickJS memory usage -- " CONFIG_VERSION " version, %d-bit, malloc limit: %"PRId64"\n\n",
   7236             (int)sizeof(void *) * 8, s->malloc_limit);
   7237 #if 1
   7238     if (rt) {
   7239         static const struct {
   7240             const char *name;
   7241             size_t size;
   7242         } object_types[] = {
   7243             { "JSRuntime", sizeof(JSRuntime) },
   7244             { "JSContext", sizeof(JSContext) },
   7245             { "JSObject", sizeof(JSObject) },
   7246             { "JSString", sizeof(JSString) },
   7247             { "JSFunctionBytecode", sizeof(JSFunctionBytecode) },
   7248         };
   7249         int i, usage_size_ok = 0;
   7250         for(i = 0; i < countof(object_types); i++) {
   7251             unsigned int size = object_types[i].size;
   7252             void *p = js_malloc_rt(rt, size);
   7253             if (p) {
   7254                 unsigned int size1 = js_malloc_usable_size_rt(rt, p);
   7255                 if (size1 >= size) {
   7256                     usage_size_ok = 1;
   7257                     fprintf(fp, "  %3u + %-2u  %s\n",
   7258                             size, size1 - size, object_types[i].name);
   7259                 }
   7260                 js_free_rt(rt, p);
   7261             }
   7262         }
   7263         if (!usage_size_ok) {
   7264             fprintf(fp, "  malloc_usable_size unavailable\n");
   7265         }
   7266         {
   7267             int obj_classes[JS_CLASS_INIT_COUNT + 1] = { 0 };
   7268             int class_id;
   7269             struct list_head *el;
   7270             list_for_each(el, &rt->gc_obj_list) {
   7271                 JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link);
   7272                 JSObject *p;
   7273                 if (js_rc(gp)->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
   7274                     p = (JSObject *)gp;
   7275                     obj_classes[min_uint32(p->class_id, JS_CLASS_INIT_COUNT)]++;
   7276                 }
   7277             }
   7278             fprintf(fp, "\n" "JSObject classes\n");
   7279             if (obj_classes[0])
   7280                 fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[0], 0, "none");
   7281             for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) {
   7282                 if (obj_classes[class_id] && class_id < rt->class_count) {
   7283                     char buf[ATOM_GET_STR_BUF_SIZE];
   7284                     fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[class_id], class_id,
   7285                             JS_AtomGetStrRT(rt, buf, sizeof(buf), rt->class_array[class_id].class_name));
   7286                 }
   7287             }
   7288             if (obj_classes[JS_CLASS_INIT_COUNT])
   7289                 fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[JS_CLASS_INIT_COUNT], 0, "other");
   7290         }
   7291         fprintf(fp, "\n");
   7292     }
   7293 #endif
   7294     fprintf(fp, "%-20s %8s %8s\n", "NAME", "COUNT", "SIZE");
   7295 
   7296     if (s->malloc_count) {
   7297         fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per block)\n",
   7298                 "memory allocated", s->malloc_count, s->malloc_size,
   7299                 (double)s->malloc_size / s->malloc_count);
   7300         fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%d overhead, %0.1f average slack)\n",
   7301                 "memory used", s->memory_used_count, s->memory_used_size,
   7302                 MALLOC_OVERHEAD, ((double)(s->malloc_size - s->memory_used_size) /
   7303                                   s->memory_used_count));
   7304     }
   7305     if (s->atom_count) {
   7306         fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per atom)\n",
   7307                 "atoms", s->atom_count, s->atom_size,
   7308                 (double)s->atom_size / s->atom_count);
   7309     }
   7310     if (s->str_count) {
   7311         fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per string)\n",
   7312                 "strings", s->str_count, s->str_size,
   7313                 (double)s->str_size / s->str_count);
   7314     }
   7315     if (s->obj_count) {
   7316         fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per object)\n",
   7317                 "objects", s->obj_count, s->obj_size,
   7318                 (double)s->obj_size / s->obj_count);
   7319         fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per object)\n",
   7320                 "  properties", s->prop_count, s->prop_size,
   7321                 (double)s->prop_count / s->obj_count);
   7322         fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per shape)\n",
   7323                 "  shapes", s->shape_count, s->shape_size,
   7324                 (double)s->shape_size / s->shape_count);
   7325     }
   7326     if (s->js_func_count) {
   7327         fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n",
   7328                 "bytecode functions", s->js_func_count, s->js_func_size);
   7329         fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per function)\n",
   7330                 "  bytecode", s->js_func_count, s->js_func_code_size,
   7331                 (double)s->js_func_code_size / s->js_func_count);
   7332         if (s->js_func_pc2line_count) {
   7333             fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per function)\n",
   7334                     "  pc2line", s->js_func_pc2line_count,
   7335                     s->js_func_pc2line_size,
   7336                     (double)s->js_func_pc2line_size / s->js_func_pc2line_count);
   7337         }
   7338     }
   7339     if (s->c_func_count) {
   7340         fprintf(fp, "%-20s %8"PRId64"\n", "C functions", s->c_func_count);
   7341     }
   7342     if (s->array_count) {
   7343         fprintf(fp, "%-20s %8"PRId64"\n", "arrays", s->array_count);
   7344         if (s->fast_array_count) {
   7345             fprintf(fp, "%-20s %8"PRId64"\n", "  fast arrays", s->fast_array_count);
   7346             fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per fast array)\n",
   7347                     "  elements", s->fast_array_elements,
   7348                     s->fast_array_elements * (int)sizeof(JSValue),
   7349                     (double)s->fast_array_elements / s->fast_array_count);
   7350         }
   7351     }
   7352     if (s->binary_object_count) {
   7353         fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n",
   7354                 "binary objects", s->binary_object_count, s->binary_object_size);
   7355     }
   7356 }
   7357 
   7358 JSValue JS_GetGlobalObject(JSContext *ctx)
   7359 {
   7360     return JS_DupValue(ctx, ctx->global_obj);
   7361 }
   7362 
   7363 /* WARNING: obj is freed */
   7364 JSValue JS_Throw(JSContext *ctx, JSValue obj)
   7365 {
   7366     JSRuntime *rt = ctx->rt;
   7367     JS_FreeValue(ctx, rt->current_exception);
   7368     rt->current_exception = obj;
   7369     rt->current_exception_is_uncatchable = FALSE;
   7370     return JS_EXCEPTION;
   7371 }
   7372 
   7373 /* return the pending exception (cannot be called twice). */
   7374 JSValue JS_GetException(JSContext *ctx)
   7375 {
   7376     JSValue val;
   7377     JSRuntime *rt = ctx->rt;
   7378     val = rt->current_exception;
   7379     rt->current_exception = JS_UNINITIALIZED;
   7380     return val;
   7381 }
   7382 
   7383 JS_BOOL JS_HasException(JSContext *ctx)
   7384 {
   7385     return !JS_IsUninitialized(ctx->rt->current_exception);
   7386 }
   7387 
   7388 static void dbuf_put_leb128(DynBuf *s, uint32_t v)
   7389 {
   7390     uint32_t a;
   7391     for(;;) {
   7392         a = v & 0x7f;
   7393         v >>= 7;
   7394         if (v != 0) {
   7395             dbuf_putc(s, a | 0x80);
   7396         } else {
   7397             dbuf_putc(s, a);
   7398             break;
   7399         }
   7400     }
   7401 }
   7402 
   7403 static void dbuf_put_sleb128(DynBuf *s, int32_t v1)
   7404 {
   7405     uint32_t v = v1;
   7406     dbuf_put_leb128(s, (2 * v) ^ -(v >> 31));
   7407 }
   7408 
   7409 static int get_leb128(uint32_t *pval, const uint8_t *buf,
   7410                       const uint8_t *buf_end)
   7411 {
   7412     const uint8_t *ptr = buf;
   7413     uint32_t v, a, i;
   7414     v = 0;
   7415     for(i = 0; i < 5; i++) {
   7416         if (unlikely(ptr >= buf_end))
   7417             break;
   7418         a = *ptr++;
   7419         v |= (a & 0x7f) << (i * 7);
   7420         if (!(a & 0x80)) {
   7421             *pval = v;
   7422             return ptr - buf;
   7423         }
   7424     }
   7425     *pval = 0;
   7426     return -1;
   7427 }
   7428 
   7429 static int get_sleb128(int32_t *pval, const uint8_t *buf,
   7430                        const uint8_t *buf_end)
   7431 {
   7432     int ret;
   7433     uint32_t val;
   7434     ret = get_leb128(&val, buf, buf_end);
   7435     if (ret < 0) {
   7436         *pval = 0;
   7437         return -1;
   7438     }
   7439     *pval = (val >> 1) ^ -(val & 1);
   7440     return ret;
   7441 }
   7442 
   7443 /* use pc_value = -1 to get the position of the function definition */
   7444 static int find_line_num(JSContext *ctx, JSFunctionBytecode *b,
   7445                          uint32_t pc_value, int *pcol_num)
   7446 {
   7447     const uint8_t *p_end, *p;
   7448     int new_line_num, line_num, pc, v, ret, new_col_num, col_num;
   7449     uint32_t val;
   7450     unsigned int op;
   7451 
   7452     if (!b->has_debug || !b->debug.pc2line_buf)
   7453         goto fail; /* function was stripped */
   7454 
   7455     p = b->debug.pc2line_buf;
   7456     p_end = p + b->debug.pc2line_len;
   7457 
   7458     /* get the function line and column numbers */
   7459     ret = get_leb128(&val, p, p_end);
   7460     if (ret < 0)
   7461         goto fail;
   7462     p += ret;
   7463     line_num = val + 1;
   7464 
   7465     ret = get_leb128(&val, p, p_end);
   7466     if (ret < 0)
   7467         goto fail;
   7468     p += ret;
   7469     col_num = val + 1;
   7470 
   7471     if (pc_value != -1) {
   7472         pc = 0;
   7473         while (p < p_end) {
   7474             op = *p++;
   7475             if (op == 0) {
   7476                 ret = get_leb128(&val, p, p_end);
   7477                 if (ret < 0)
   7478                     goto fail;
   7479                 pc += val;
   7480                 p += ret;
   7481                 ret = get_sleb128(&v, p, p_end);
   7482                 if (ret < 0)
   7483                     goto fail;
   7484                 p += ret;
   7485                 new_line_num = line_num + v;
   7486             } else {
   7487                 op -= PC2LINE_OP_FIRST;
   7488                 pc += (op / PC2LINE_RANGE);
   7489                 new_line_num = line_num + (op % PC2LINE_RANGE) + PC2LINE_BASE;
   7490             }
   7491             ret = get_sleb128(&v, p, p_end);
   7492             if (ret < 0)
   7493                 goto fail;
   7494             p += ret;
   7495             new_col_num = col_num + v;
   7496             
   7497             if (pc_value < pc)
   7498                 goto done;
   7499             line_num = new_line_num;
   7500             col_num = new_col_num;
   7501         }
   7502     }
   7503  done:
   7504     *pcol_num = col_num;
   7505     return line_num;
   7506  fail:
   7507     *pcol_num = 0;
   7508     return 0;
   7509 }
   7510 
   7511 /* return a string property without executing arbitrary JS code (used
   7512    when dumping the stack trace or in debug print). */
   7513 static const char *get_prop_string(JSContext *ctx, JSValueConst obj, JSAtom prop)
   7514 {
   7515     JSObject *p;
   7516     JSProperty *pr;
   7517     JSShapeProperty *prs;
   7518     JSValueConst val;
   7519 
   7520     if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
   7521         return NULL;
   7522     p = JS_VALUE_GET_OBJ(obj);
   7523     prs = find_own_property(&pr, p, prop);
   7524     if (!prs) {
   7525         /* we look at one level in the prototype to handle the 'name'
   7526            field of the Error objects */
   7527         p = p->shape->proto;
   7528         if (!p)
   7529             return NULL;
   7530         prs = find_own_property(&pr, p, prop);
   7531         if (!prs)
   7532             return NULL;
   7533     }
   7534     
   7535     if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
   7536         return NULL;
   7537     val = pr->u.value;
   7538     if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
   7539         return NULL;
   7540     return JS_ToCString(ctx, val);
   7541 }
   7542 
   7543 #define JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL (1 << 0)
   7544 
   7545 /* if filename != NULL, an additional level is added with the filename
   7546    and line number information (used for parse error). */
   7547 static void build_backtrace(JSContext *ctx, JSValueConst error_obj,
   7548                             const char *filename, int line_num, int col_num,
   7549                             int backtrace_flags)
   7550 {
   7551     JSStackFrame *sf;
   7552     JSValue str;
   7553     DynBuf dbuf;
   7554     const char *func_name_str;
   7555     const char *str1;
   7556     JSObject *p;
   7557 
   7558     if (!JS_IsObject(error_obj))
   7559         return; /* protection in the out of memory case */
   7560     
   7561     js_dbuf_init(ctx, &dbuf);
   7562     if (filename) {
   7563         dbuf_printf(&dbuf, "    at %s", filename);
   7564         if (line_num != -1)
   7565             dbuf_printf(&dbuf, ":%d:%d", line_num, col_num);
   7566         dbuf_putc(&dbuf, '\n');
   7567         str = JS_NewString(ctx, filename);
   7568         if (JS_IsException(str))
   7569             return;
   7570         /* Note: SpiderMonkey does that, could update once there is a standard */
   7571         if (JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_fileName, str,
   7572                                    JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0 ||
   7573             JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_lineNumber, JS_NewInt32(ctx, line_num),
   7574                                    JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0 ||
   7575             JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_columnNumber, JS_NewInt32(ctx, col_num),
   7576                                    JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0) {
   7577             return;
   7578         }
   7579     }
   7580     for(sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) {
   7581         if (sf->js_mode & JS_MODE_BACKTRACE_BARRIER)
   7582             break;
   7583         if (backtrace_flags & JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL) {
   7584             backtrace_flags &= ~JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL;
   7585             continue;
   7586         }
   7587         func_name_str = get_prop_string(ctx, sf->cur_func, JS_ATOM_name);
   7588         if (!func_name_str || func_name_str[0] == '\0')
   7589             str1 = "<anonymous>";
   7590         else
   7591             str1 = func_name_str;
   7592         dbuf_printf(&dbuf, "    at %s", str1);
   7593         JS_FreeCString(ctx, func_name_str);
   7594 
   7595         p = JS_VALUE_GET_OBJ(sf->cur_func);
   7596         if (js_class_has_bytecode(p->class_id)) {
   7597             JSFunctionBytecode *b;
   7598             const char *atom_str;
   7599             int line_num1, col_num1;
   7600 
   7601             b = p->u.func.function_bytecode;
   7602             if (b->has_debug) {
   7603                 line_num1 = find_line_num(ctx, b,
   7604                                           sf->cur_pc - b->byte_code_buf - 1, &col_num1);
   7605                 atom_str = JS_AtomToCString(ctx, b->debug.filename);
   7606                 dbuf_printf(&dbuf, " (%s",
   7607                             atom_str ? atom_str : "<null>");
   7608                 JS_FreeCString(ctx, atom_str);
   7609                 if (line_num1 != 0)
   7610                     dbuf_printf(&dbuf, ":%d:%d", line_num1, col_num1);
   7611                 dbuf_putc(&dbuf, ')');
   7612             }
   7613         } else {
   7614             dbuf_printf(&dbuf, " (native)");
   7615         }
   7616         dbuf_putc(&dbuf, '\n');
   7617     }
   7618     dbuf_putc(&dbuf, '\0');
   7619     if (dbuf_error(&dbuf))
   7620         str = JS_NULL;
   7621     else
   7622         str = JS_NewString(ctx, (char *)dbuf.buf);
   7623     dbuf_free(&dbuf);
   7624     JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_stack, str,
   7625                            JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
   7626 }
   7627 
   7628 /* Note: it is important that no exception is returned by this function */
   7629 static BOOL is_backtrace_needed(JSContext *ctx, JSValueConst obj)
   7630 {
   7631     JSObject *p;
   7632     if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
   7633         return FALSE;
   7634     p = JS_VALUE_GET_OBJ(obj);
   7635     if (p->class_id != JS_CLASS_ERROR)
   7636         return FALSE;
   7637     if (find_own_property1(p, JS_ATOM_stack))
   7638         return FALSE;
   7639     return TRUE;
   7640 }
   7641 
   7642 JSValue JS_NewError(JSContext *ctx)
   7643 {
   7644     return JS_NewObjectClass(ctx, JS_CLASS_ERROR);
   7645 }
   7646 
   7647 static JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num,
   7648                               const char *fmt, va_list ap, BOOL add_backtrace)
   7649 {
   7650     char buf[256];
   7651     JSValue obj, ret;
   7652 
   7653     vsnprintf(buf, sizeof(buf), fmt, ap);
   7654     obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[error_num],
   7655                                  JS_CLASS_ERROR);
   7656     if (unlikely(JS_IsException(obj))) {
   7657         /* out of memory: throw JS_NULL to avoid recursing */
   7658         obj = JS_NULL;
   7659     } else {
   7660         JS_DefinePropertyValue(ctx, obj, JS_ATOM_message,
   7661                                JS_NewString(ctx, buf),
   7662                                JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
   7663         if (add_backtrace) {
   7664             build_backtrace(ctx, obj, NULL, 0, 0, 0);
   7665         }
   7666     }
   7667     ret = JS_Throw(ctx, obj);
   7668     return ret;
   7669 }
   7670 
   7671 static JSValue JS_ThrowError(JSContext *ctx, JSErrorEnum error_num,
   7672                              const char *fmt, va_list ap)
   7673 {
   7674     JSRuntime *rt = ctx->rt;
   7675     JSStackFrame *sf;
   7676     BOOL add_backtrace;
   7677 
   7678     /* the backtrace is added later if called from a bytecode function */
   7679     sf = rt->current_stack_frame;
   7680     add_backtrace = !rt->in_out_of_memory &&
   7681         (!sf || (JS_GetFunctionBytecode(sf->cur_func) == NULL));
   7682     return JS_ThrowError2(ctx, error_num, fmt, ap, add_backtrace);
   7683 }
   7684 
   7685 JSValue __attribute__((format(printf, 2, 3))) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...)
   7686 {
   7687     JSValue val;
   7688     va_list ap;
   7689 
   7690     va_start(ap, fmt);
   7691     val = JS_ThrowError(ctx, JS_SYNTAX_ERROR, fmt, ap);
   7692     va_end(ap);
   7693     return val;
   7694 }
   7695 
   7696 JSValue __attribute__((format(printf, 2, 3))) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...)
   7697 {
   7698     JSValue val;
   7699     va_list ap;
   7700 
   7701     va_start(ap, fmt);
   7702     val = JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);
   7703     va_end(ap);
   7704     return val;
   7705 }
   7706 
   7707 static int __attribute__((format(printf, 3, 4))) JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, const char *fmt, ...)
   7708 {
   7709     va_list ap;
   7710 
   7711     if ((flags & JS_PROP_THROW) ||
   7712         ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
   7713         va_start(ap, fmt);
   7714         JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);
   7715         va_end(ap);
   7716         return -1;
   7717     } else {
   7718         return FALSE;
   7719     }
   7720 }
   7721 
   7722 /* never use it directly */
   7723 static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowTypeErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
   7724 {
   7725     char buf[ATOM_GET_STR_BUF_SIZE];
   7726     return JS_ThrowTypeError(ctx, fmt,
   7727                              JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
   7728 }
   7729 
   7730 /* never use it directly */
   7731 static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowSyntaxErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
   7732 {
   7733     char buf[ATOM_GET_STR_BUF_SIZE];
   7734     return JS_ThrowSyntaxError(ctx, fmt,
   7735                              JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
   7736 }
   7737 
   7738 /* %s is replaced by 'atom'. The macro is used so that gcc can check
   7739     the format string. */
   7740 #define JS_ThrowTypeErrorAtom(ctx, fmt, atom) __JS_ThrowTypeErrorAtom(ctx, atom, fmt, "")
   7741 #define JS_ThrowSyntaxErrorAtom(ctx, fmt, atom) __JS_ThrowSyntaxErrorAtom(ctx, atom, fmt, "")
   7742 
   7743 static int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int flags, JSAtom atom)
   7744 {
   7745     if ((flags & JS_PROP_THROW) ||
   7746         ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
   7747         JS_ThrowTypeErrorAtom(ctx, "'%s' is read-only", atom);
   7748         return -1;
   7749     } else {
   7750         return FALSE;
   7751     }
   7752 }
   7753 
   7754 JSValue __attribute__((format(printf, 2, 3))) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...)
   7755 {
   7756     JSValue val;
   7757     va_list ap;
   7758 
   7759     va_start(ap, fmt);
   7760     val = JS_ThrowError(ctx, JS_REFERENCE_ERROR, fmt, ap);
   7761     va_end(ap);
   7762     return val;
   7763 }
   7764 
   7765 JSValue __attribute__((format(printf, 2, 3))) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...)
   7766 {
   7767     JSValue val;
   7768     va_list ap;
   7769 
   7770     va_start(ap, fmt);
   7771     val = JS_ThrowError(ctx, JS_RANGE_ERROR, fmt, ap);
   7772     va_end(ap);
   7773     return val;
   7774 }
   7775 
   7776 JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...)
   7777 {
   7778     JSValue val;
   7779     va_list ap;
   7780 
   7781     va_start(ap, fmt);
   7782     val = JS_ThrowError(ctx, JS_INTERNAL_ERROR, fmt, ap);
   7783     va_end(ap);
   7784     return val;
   7785 }
   7786 
   7787 JSValue JS_ThrowOutOfMemory(JSContext *ctx)
   7788 {
   7789     JSRuntime *rt = ctx->rt;
   7790     if (!rt->in_out_of_memory) {
   7791         rt->in_out_of_memory = TRUE;
   7792         JS_ThrowInternalError(ctx, "out of memory");
   7793         rt->in_out_of_memory = FALSE;
   7794     }
   7795     return JS_EXCEPTION;
   7796 }
   7797 
   7798 static JSValue JS_ThrowStackOverflow(JSContext *ctx)
   7799 {
   7800     return JS_ThrowInternalError(ctx, "stack overflow");
   7801 }
   7802 
   7803 static JSValue JS_ThrowTypeErrorNotAnObject(JSContext *ctx)
   7804 {
   7805     return JS_ThrowTypeError(ctx, "not an object");
   7806 }
   7807 
   7808 static JSValue JS_ThrowTypeErrorNotAConstructor(JSContext *ctx,
   7809                                                 JSValueConst func_obj)
   7810 {
   7811     const char *name;
   7812     if (!JS_IsFunction(ctx, func_obj))
   7813         goto fail;
   7814     name = get_prop_string(ctx, func_obj, JS_ATOM_name);
   7815     if (!name) {
   7816     fail:
   7817         return JS_ThrowTypeError(ctx, "not a constructor");
   7818     }
   7819     JS_ThrowTypeError(ctx, "%s is not a constructor", name);
   7820     JS_FreeCString(ctx, name);
   7821     return JS_EXCEPTION;
   7822 }
   7823 
   7824 static JSValue JS_ThrowTypeErrorNotASymbol(JSContext *ctx)
   7825 {
   7826     return JS_ThrowTypeError(ctx, "not a symbol");
   7827 }
   7828 
   7829 static JSValue JS_ThrowReferenceErrorNotDefined(JSContext *ctx, JSAtom name)
   7830 {
   7831     char buf[ATOM_GET_STR_BUF_SIZE];
   7832     return JS_ThrowReferenceError(ctx, "'%s' is not defined",
   7833                                   JS_AtomGetStr(ctx, buf, sizeof(buf), name));
   7834 }
   7835 
   7836 static JSValue JS_ThrowReferenceErrorUninitialized(JSContext *ctx, JSAtom name)
   7837 {
   7838     char buf[ATOM_GET_STR_BUF_SIZE];
   7839     return JS_ThrowReferenceError(ctx, "%s is not initialized",
   7840                                   name == JS_ATOM_NULL ? "lexical variable" :
   7841                                   JS_AtomGetStr(ctx, buf, sizeof(buf), name));
   7842 }
   7843 
   7844 static JSValue JS_ThrowReferenceErrorUninitialized2(JSContext *ctx,
   7845                                                     JSFunctionBytecode *b,
   7846                                                     int idx, BOOL is_ref)
   7847 {
   7848     JSAtom atom = JS_ATOM_NULL;
   7849     if (is_ref) {
   7850         atom = b->closure_var[idx].var_name;
   7851     } else {
   7852         /* not present if the function is stripped and contains no eval() */
   7853         if (b->vardefs)
   7854             atom = b->vardefs[b->arg_count + idx].var_name;
   7855     }
   7856     return JS_ThrowReferenceErrorUninitialized(ctx, atom);
   7857 }
   7858 
   7859 static JSValue JS_ThrowTypeErrorInvalidClass(JSContext *ctx, int class_id)
   7860 {
   7861     JSRuntime *rt = ctx->rt;
   7862     JSAtom name;
   7863     name = rt->class_array[class_id].class_name;
   7864     return JS_ThrowTypeErrorAtom(ctx, "%s object expected", name);
   7865 }
   7866 
   7867 static void JS_ThrowInterrupted(JSContext *ctx)
   7868 {
   7869     JS_ThrowInternalError(ctx, "interrupted");
   7870     JS_SetUncatchableException(ctx, TRUE);
   7871 }
   7872 
   7873 static no_inline __exception int __js_poll_interrupts(JSContext *ctx)
   7874 {
   7875     JSRuntime *rt = ctx->rt;
   7876     ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT;
   7877     if (rt->interrupt_handler) {
   7878         if (rt->interrupt_handler(rt, rt->interrupt_opaque)) {
   7879             JS_ThrowInterrupted(ctx);
   7880             return -1;
   7881         }
   7882     }
   7883     return 0;
   7884 }
   7885 
   7886 static inline __exception int js_poll_interrupts(JSContext *ctx)
   7887 {
   7888     if (unlikely(--ctx->interrupt_counter <= 0)) {
   7889         return __js_poll_interrupts(ctx);
   7890     } else {
   7891         return 0;
   7892     }
   7893 }
   7894 
   7895 static void JS_SetImmutablePrototype(JSContext *ctx, JSValueConst obj)
   7896 {
   7897     JSObject *p;
   7898     if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
   7899         return;
   7900     p = JS_VALUE_GET_OBJ(obj);
   7901     p->has_immutable_prototype = TRUE;
   7902 }
   7903 
   7904 /* Return -1 (exception) or TRUE/FALSE. 'throw_flag' = FALSE indicates
   7905    that it is called from Reflect.setPrototypeOf(). */
   7906 static int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj,
   7907                                    JSValueConst proto_val,
   7908                                    BOOL throw_flag)
   7909 {
   7910     JSObject *proto, *p, *p1;
   7911     JSShape *sh;
   7912 
   7913     if (throw_flag) {
   7914         if (JS_VALUE_GET_TAG(obj) == JS_TAG_NULL ||
   7915             JS_VALUE_GET_TAG(obj) == JS_TAG_UNDEFINED)
   7916             goto not_obj;
   7917     } else {
   7918         if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
   7919             goto not_obj;
   7920     }
   7921     p = JS_VALUE_GET_OBJ(obj);
   7922     if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT) {
   7923         if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_NULL) {
   7924         not_obj:
   7925             JS_ThrowTypeErrorNotAnObject(ctx);
   7926             return -1;
   7927         }
   7928         proto = NULL;
   7929     } else {
   7930         proto = JS_VALUE_GET_OBJ(proto_val);
   7931     }
   7932 
   7933     if (throw_flag && JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
   7934         return TRUE;
   7935 
   7936     if (unlikely(p->is_exotic)) {
   7937         const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
   7938         int ret;
   7939         if (em && em->set_prototype) {
   7940             ret = em->set_prototype(ctx, obj, proto_val);
   7941             if (ret == 0 && throw_flag) {
   7942                 JS_ThrowTypeError(ctx, "proxy: bad prototype");
   7943                 return -1;
   7944             } else {
   7945                 return ret;
   7946             }
   7947         }
   7948     }
   7949 
   7950     sh = p->shape;
   7951     if (sh->proto == proto)
   7952         return TRUE;
   7953     if (unlikely(p->has_immutable_prototype)) {
   7954         if (throw_flag) {
   7955             JS_ThrowTypeError(ctx, "prototype is immutable");
   7956             return -1;
   7957         } else {
   7958             return FALSE;
   7959         }
   7960     }
   7961     if (unlikely(!p->extensible)) {
   7962         if (throw_flag) {
   7963             JS_ThrowTypeError(ctx, "object is not extensible");
   7964             return -1;
   7965         } else {
   7966             return FALSE;
   7967         }
   7968     }
   7969     if (proto) {
   7970         /* check if there is a cycle */
   7971         p1 = proto;
   7972         do {
   7973             if (p1 == p) {
   7974                 if (throw_flag) {
   7975                     JS_ThrowTypeError(ctx, "circular prototype chain");
   7976                     return -1;
   7977                 } else {
   7978                     return FALSE;
   7979                 }
   7980             }
   7981             /* Note: for Proxy objects, proto is NULL */
   7982             p1 = p1->shape->proto;
   7983         } while (p1 != NULL);
   7984         JS_DupValue(ctx, proto_val);
   7985     }
   7986 
   7987     if (js_shape_prepare_update(ctx, p, NULL))
   7988         return -1;
   7989     sh = p->shape;
   7990     if (sh->proto)
   7991         JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
   7992     sh->proto = proto;
   7993     p->is_std_array_prototype = FALSE; 
   7994     return TRUE;
   7995 }
   7996 
   7997 /* return -1 (exception) or TRUE/FALSE */
   7998 int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val)
   7999 {
   8000     return JS_SetPrototypeInternal(ctx, obj, proto_val, TRUE);
   8001 }
   8002 
   8003 /* Only works for primitive types, otherwise return JS_NULL. */
   8004 static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val)
   8005 {
   8006     switch(JS_VALUE_GET_NORM_TAG(val)) {
   8007     case JS_TAG_SHORT_BIG_INT:
   8008     case JS_TAG_BIG_INT:
   8009         val = ctx->class_proto[JS_CLASS_BIG_INT];
   8010         break;
   8011     case JS_TAG_INT:
   8012     case JS_TAG_FLOAT64:
   8013         val = ctx->class_proto[JS_CLASS_NUMBER];
   8014         break;
   8015     case JS_TAG_BOOL:
   8016         val = ctx->class_proto[JS_CLASS_BOOLEAN];
   8017         break;
   8018     case JS_TAG_STRING:
   8019     case JS_TAG_STRING_ROPE:
   8020         val = ctx->class_proto[JS_CLASS_STRING];
   8021         break;
   8022     case JS_TAG_SYMBOL:
   8023         val = ctx->class_proto[JS_CLASS_SYMBOL];
   8024         break;
   8025     case JS_TAG_OBJECT:
   8026     case JS_TAG_NULL:
   8027     case JS_TAG_UNDEFINED:
   8028     default:
   8029         val = JS_NULL;
   8030         break;
   8031     }
   8032     return val;
   8033 }
   8034 
   8035 /* Return an Object, JS_NULL or JS_EXCEPTION in case of exotic object. */
   8036 JSValue JS_GetPrototype(JSContext *ctx, JSValueConst obj)
   8037 {
   8038     JSValue val;
   8039     if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
   8040         JSObject *p;
   8041         p = JS_VALUE_GET_OBJ(obj);
   8042         if (unlikely(p->is_exotic)) {
   8043             const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
   8044             if (em && em->get_prototype) {
   8045                 return em->get_prototype(ctx, obj);
   8046             }
   8047         }
   8048         p = p->shape->proto;
   8049         if (!p)
   8050             val = JS_NULL;
   8051         else
   8052             val = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
   8053     } else {
   8054         val = JS_DupValue(ctx, JS_GetPrototypePrimitive(ctx, obj));
   8055     }
   8056     return val;
   8057 }
   8058 
   8059 static JSValue JS_GetPrototypeFree(JSContext *ctx, JSValue obj)
   8060 {
   8061     JSValue obj1;
   8062     obj1 = JS_GetPrototype(ctx, obj);
   8063     JS_FreeValue(ctx, obj);
   8064     return obj1;
   8065 }
   8066 
   8067 /* return TRUE, FALSE or (-1) in case of exception */
   8068 static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val,
   8069                                    JSValueConst obj)
   8070 {
   8071     JSValue obj_proto;
   8072     JSObject *proto;
   8073     const JSObject *p, *proto1;
   8074     BOOL ret;
   8075 
   8076     if (!JS_IsFunction(ctx, obj))
   8077         return FALSE;
   8078     p = JS_VALUE_GET_OBJ(obj);
   8079     if (p->class_id == JS_CLASS_BOUND_FUNCTION) {
   8080         JSBoundFunction *s = p->u.bound_function;
   8081         return JS_IsInstanceOf(ctx, val, s->func_obj);
   8082     }
   8083 
   8084     /* Only explicitly boxed values are instances of constructors */
   8085     if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
   8086         return FALSE;
   8087     obj_proto = JS_GetProperty(ctx, obj, JS_ATOM_prototype);
   8088     if (JS_VALUE_GET_TAG(obj_proto) != JS_TAG_OBJECT) {
   8089         if (!JS_IsException(obj_proto))
   8090             JS_ThrowTypeError(ctx, "operand 'prototype' property is not an object");
   8091         ret = -1;
   8092         goto done;
   8093     }
   8094     proto = JS_VALUE_GET_OBJ(obj_proto);
   8095     p = JS_VALUE_GET_OBJ(val);
   8096     for(;;) {
   8097         proto1 = p->shape->proto;
   8098         if (!proto1) {
   8099             /* slow case if exotic object in the prototype chain */
   8100             if (unlikely(p->is_exotic && !p->fast_array)) {
   8101                 JSValue obj1;
   8102                 obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, (JSObject *)p));
   8103                 for(;;) {
   8104                     obj1 = JS_GetPrototypeFree(ctx, obj1);
   8105                     if (JS_IsException(obj1)) {
   8106                         ret = -1;
   8107                         break;
   8108                     }
   8109                     if (JS_IsNull(obj1)) {
   8110                         ret = FALSE;
   8111                         break;
   8112                     }
   8113                     if (proto == JS_VALUE_GET_OBJ(obj1)) {
   8114                         JS_FreeValue(ctx, obj1);
   8115                         ret = TRUE;
   8116                         break;
   8117                     }
   8118                     /* must check for timeout to avoid infinite loop */
   8119                     if (js_poll_interrupts(ctx)) {
   8120                         JS_FreeValue(ctx, obj1);
   8121                         ret = -1;
   8122                         break;
   8123                     }
   8124                 }
   8125             } else {
   8126                 ret = FALSE;
   8127             }
   8128             break;
   8129         }
   8130         p = proto1;
   8131         if (proto == p) {
   8132             ret = TRUE;
   8133             break;
   8134         }
   8135     }
   8136 done:
   8137     JS_FreeValue(ctx, obj_proto);
   8138     return ret;
   8139 }
   8140 
   8141 /* return TRUE, FALSE or (-1) in case of exception */
   8142 int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj)
   8143 {
   8144     JSValue method;
   8145 
   8146     if (!JS_IsObject(obj))
   8147         goto fail;
   8148     method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_hasInstance);
   8149     if (JS_IsException(method))
   8150         return -1;
   8151     if (!JS_IsNull(method) && !JS_IsUndefined(method)) {
   8152         JSValue ret;
   8153         ret = JS_CallFree(ctx, method, obj, 1, &val);
   8154         return JS_ToBoolFree(ctx, ret);
   8155     }
   8156 
   8157     /* legacy case */
   8158     if (!JS_IsFunction(ctx, obj)) {
   8159     fail:
   8160         JS_ThrowTypeError(ctx, "invalid 'instanceof' right operand");
   8161         return -1;
   8162     }
   8163     return JS_OrdinaryIsInstanceOf(ctx, val, obj);
   8164 }
   8165 
   8166 /* return the value associated to the autoinit property or an exception */
   8167 typedef JSValue JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
   8168 
   8169 static JSAutoInitFunc *js_autoinit_func_table[] = {
   8170     js_instantiate_prototype, /* JS_AUTOINIT_ID_PROTOTYPE */
   8171     js_module_ns_autoinit, /* JS_AUTOINIT_ID_MODULE_NS */
   8172     JS_InstantiateFunctionListItem2, /* JS_AUTOINIT_ID_PROP */
   8173 };
   8174 
   8175 /* warning: 'prs' is reallocated after it */
   8176 static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop,
   8177                                JSProperty *pr, JSShapeProperty *prs)
   8178 {
   8179     JSValue val;
   8180     JSContext *realm;
   8181     JSAutoInitFunc *func;
   8182     JSAutoInitIDEnum id;
   8183     
   8184     if (js_shape_prepare_update(ctx, p, &prs))
   8185         return -1;
   8186 
   8187     realm = js_autoinit_get_realm(pr);
   8188     id = js_autoinit_get_id(pr);
   8189     func = js_autoinit_func_table[id];
   8190     /* 'func' shall not modify the object properties 'pr' */
   8191     val = func(realm, p, prop, pr->u.init.opaque);
   8192     js_autoinit_free(ctx->rt, pr);
   8193     prs->flags &= ~JS_PROP_TMASK;
   8194     pr->u.value = JS_UNDEFINED;
   8195     if (JS_IsException(val))
   8196         return -1;
   8197     if (id == JS_AUTOINIT_ID_MODULE_NS &&
   8198         JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
   8199         /* WARNING: a varref is returned as a string  ! */
   8200         prs->flags |= JS_PROP_VARREF;
   8201         pr->u.var_ref = JS_VALUE_GET_PTR(val);
   8202         js_rc(pr->u.var_ref)->ref_count++;
   8203     } else if (p->class_id == JS_CLASS_GLOBAL_OBJECT) {
   8204         JSVarRef *var_ref;
   8205         /* in the global object we use references */
   8206         var_ref = js_create_var_ref(ctx, FALSE);
   8207         if (!var_ref)
   8208             return -1;
   8209         prs->flags |= JS_PROP_VARREF;
   8210         pr->u.var_ref = var_ref;
   8211         var_ref->value = val; 
   8212         var_ref->is_const = !(prs->flags & JS_PROP_WRITABLE);
   8213     } else {
   8214         pr->u.value = val;
   8215     }
   8216     return 0;
   8217 }
   8218 
   8219 JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
   8220                                JSAtom prop, JSValueConst this_obj,
   8221                                BOOL throw_ref_error)
   8222 {
   8223     JSObject *p;
   8224     JSProperty *pr;
   8225     JSShapeProperty *prs;
   8226     uint32_t tag;
   8227 
   8228     tag = JS_VALUE_GET_TAG(obj);
   8229     if (unlikely(tag != JS_TAG_OBJECT)) {
   8230         switch(tag) {
   8231         case JS_TAG_NULL:
   8232             return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of null", prop);
   8233         case JS_TAG_UNDEFINED:
   8234             return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of undefined", prop);
   8235         case JS_TAG_EXCEPTION:
   8236             return JS_EXCEPTION;
   8237         case JS_TAG_STRING:
   8238             {
   8239                 JSString *p1 = JS_VALUE_GET_STRING(obj);
   8240                 if (__JS_AtomIsTaggedInt(prop)) {
   8241                     uint32_t idx;
   8242                     idx = __JS_AtomToUInt32(prop);
   8243                     if (idx < p1->len) {
   8244                         return js_new_string_char(ctx, string_get(p1, idx));
   8245                     }
   8246                 } else if (prop == JS_ATOM_length) {
   8247                     return JS_NewInt32(ctx, p1->len);
   8248                 }
   8249             }
   8250             break;
   8251         case JS_TAG_STRING_ROPE:
   8252             {
   8253                 JSStringRope *p1 = JS_VALUE_GET_STRING_ROPE(obj);
   8254                 if (__JS_AtomIsTaggedInt(prop)) {
   8255                     uint32_t idx;
   8256                     idx = __JS_AtomToUInt32(prop);
   8257                     if (idx < p1->len) {
   8258                         return js_new_string_char(ctx, string_rope_get(obj, idx));
   8259                     }
   8260                 } else if (prop == JS_ATOM_length) {
   8261                     return JS_NewInt32(ctx, p1->len);
   8262                 }
   8263             }
   8264             break;
   8265         default:
   8266             break;
   8267         }
   8268         /* cannot raise an exception */
   8269         p = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj));
   8270         if (!p)
   8271             return JS_UNDEFINED;
   8272     } else {
   8273         p = JS_VALUE_GET_OBJ(obj);
   8274     }
   8275 
   8276     for(;;) {
   8277         prs = find_own_property(&pr, p, prop);
   8278         if (prs) {
   8279             /* found */
   8280             if (unlikely(prs->flags & JS_PROP_TMASK)) {
   8281                 if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
   8282                     if (unlikely(!pr->u.getset.getter)) {
   8283                         return JS_UNDEFINED;
   8284                     } else {
   8285                         JSValue func = JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter);
   8286                         /* Note: the field could be removed in the getter */
   8287                         func = JS_DupValue(ctx, func);
   8288                         return JS_CallFree(ctx, func, this_obj, 0, NULL);
   8289                     }
   8290                 } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
   8291                     JSValue val = *pr->u.var_ref->pvalue;
   8292                     if (unlikely(JS_IsUninitialized(val)))
   8293                         return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
   8294                     return JS_DupValue(ctx, val);
   8295                 } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
   8296                     /* Instantiate property and retry */
   8297                     if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
   8298                         return JS_EXCEPTION;
   8299                     continue;
   8300                 }
   8301             } else {
   8302                 return JS_DupValue(ctx, pr->u.value);
   8303             }
   8304         }
   8305         if (unlikely(p->is_exotic)) {
   8306             /* exotic behaviors */
   8307             if (p->fast_array) {
   8308                 if (__JS_AtomIsTaggedInt(prop)) {
   8309                     uint32_t idx = __JS_AtomToUInt32(prop);
   8310                     if (idx < p->u.array.count) {
   8311                         /* we avoid duplicating the code */
   8312                         return JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
   8313                     } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
   8314                                p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
   8315                         return JS_UNDEFINED;
   8316                     }
   8317                 } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
   8318                            p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
   8319                     int ret;
   8320                     ret = JS_AtomIsNumericIndex(ctx, prop);
   8321                     if (ret != 0) {
   8322                         if (ret < 0)
   8323                             return JS_EXCEPTION;
   8324                         return JS_UNDEFINED;
   8325                     }
   8326                 }
   8327             } else {
   8328                 const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
   8329                 if (em) {
   8330                     if (em->get_property) {
   8331                         JSValue obj1, retval;
   8332                         /* XXX: should pass throw_ref_error */
   8333                         /* Note: if 'p' is a prototype, it can be
   8334                            freed in the called function */
   8335                         obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
   8336                         retval = em->get_property(ctx, obj1, prop, this_obj);
   8337                         JS_FreeValue(ctx, obj1);
   8338                         return retval;
   8339                     }
   8340                     if (em->get_own_property) {
   8341                         JSPropertyDescriptor desc;
   8342                         int ret;
   8343                         JSValue obj1;
   8344 
   8345                         /* Note: if 'p' is a prototype, it can be
   8346                            freed in the called function */
   8347                         obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
   8348                         ret = em->get_own_property(ctx, &desc, obj1, prop);
   8349                         JS_FreeValue(ctx, obj1);
   8350                         if (ret < 0)
   8351                             return JS_EXCEPTION;
   8352                         if (ret) {
   8353                             if (desc.flags & JS_PROP_GETSET) {
   8354                                 JS_FreeValue(ctx, desc.setter);
   8355                                 return JS_CallFree(ctx, desc.getter, this_obj, 0, NULL);
   8356                             } else {
   8357                                 return desc.value;
   8358                             }
   8359                         }
   8360                     }
   8361                 }
   8362             }
   8363         }
   8364         p = p->shape->proto;
   8365         if (!p)
   8366             break;
   8367     }
   8368     if (unlikely(throw_ref_error)) {
   8369         return JS_ThrowReferenceErrorNotDefined(ctx, prop);
   8370     } else {
   8371         return JS_UNDEFINED;
   8372     }
   8373 }
   8374 
   8375 static JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom)
   8376 {
   8377     return JS_ThrowTypeErrorAtom(ctx, "private class field '%s' does not exist",
   8378                                  atom);
   8379 }
   8380 
   8381 /* Private fields can be added even on non extensible objects or
   8382    Proxies */
   8383 static int JS_DefinePrivateField(JSContext *ctx, JSValueConst obj,
   8384                                  JSValueConst name, JSValue val)
   8385 {
   8386     JSObject *p;
   8387     JSShapeProperty *prs;
   8388     JSProperty *pr;
   8389     JSAtom prop;
   8390 
   8391     if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
   8392         JS_ThrowTypeErrorNotAnObject(ctx);
   8393         goto fail;
   8394     }
   8395     /* safety check */
   8396     if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) {
   8397         JS_ThrowTypeErrorNotASymbol(ctx);
   8398         goto fail;
   8399     }
   8400     prop = js_symbol_to_atom(ctx, (JSValue)name);
   8401     p = JS_VALUE_GET_OBJ(obj);
   8402     prs = find_own_property(&pr, p, prop);
   8403     if (prs) {
   8404         JS_ThrowTypeErrorAtom(ctx, "private class field '%s' already exists",
   8405                               prop);
   8406         goto fail;
   8407     }
   8408     pr = add_property(ctx, p, prop, JS_PROP_C_W_E);
   8409     if (unlikely(!pr)) {
   8410     fail:
   8411         JS_FreeValue(ctx, val);
   8412         return -1;
   8413     }
   8414     pr->u.value = val;
   8415     return 0;
   8416 }
   8417 
   8418 static JSValue JS_GetPrivateField(JSContext *ctx, JSValueConst obj,
   8419                                   JSValueConst name)
   8420 {
   8421     JSObject *p;
   8422     JSShapeProperty *prs;
   8423     JSProperty *pr;
   8424     JSAtom prop;
   8425 
   8426     if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
   8427         return JS_ThrowTypeErrorNotAnObject(ctx);
   8428     /* safety check */
   8429     if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL))
   8430         return JS_ThrowTypeErrorNotASymbol(ctx);
   8431     prop = js_symbol_to_atom(ctx, (JSValue)name);
   8432     p = JS_VALUE_GET_OBJ(obj);
   8433     prs = find_own_property(&pr, p, prop);
   8434     if (!prs) {
   8435         JS_ThrowTypeErrorPrivateNotFound(ctx, prop);
   8436         return JS_EXCEPTION;
   8437     }
   8438     return JS_DupValue(ctx, pr->u.value);
   8439 }
   8440 
   8441 static int JS_SetPrivateField(JSContext *ctx, JSValueConst obj,
   8442                               JSValueConst name, JSValue val)
   8443 {
   8444     JSObject *p;
   8445     JSShapeProperty *prs;
   8446     JSProperty *pr;
   8447     JSAtom prop;
   8448 
   8449     if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
   8450         JS_ThrowTypeErrorNotAnObject(ctx);
   8451         goto fail;
   8452     }
   8453     /* safety check */
   8454     if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) {
   8455         JS_ThrowTypeErrorNotASymbol(ctx);
   8456         goto fail;
   8457     }
   8458     prop = js_symbol_to_atom(ctx, (JSValue)name);
   8459     p = JS_VALUE_GET_OBJ(obj);
   8460     prs = find_own_property(&pr, p, prop);
   8461     if (!prs) {
   8462         JS_ThrowTypeErrorPrivateNotFound(ctx, prop);
   8463     fail:
   8464         JS_FreeValue(ctx, val);
   8465         return -1;
   8466     }
   8467     set_value(ctx, &pr->u.value, val);
   8468     return 0;
   8469 }
   8470 
   8471 /* add a private brand field to 'home_obj' if not already present and
   8472    if obj is != null add a private brand to it */
   8473 static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj)
   8474 {
   8475     JSObject *p, *p1;
   8476     JSShapeProperty *prs;
   8477     JSProperty *pr;
   8478     JSValue brand;
   8479     JSAtom brand_atom;
   8480 
   8481     if (unlikely(JS_VALUE_GET_TAG(home_obj) != JS_TAG_OBJECT)) {
   8482         JS_ThrowTypeErrorNotAnObject(ctx);
   8483         return -1;
   8484     }
   8485     p = JS_VALUE_GET_OBJ(home_obj);
   8486     prs = find_own_property(&pr, p, JS_ATOM_Private_brand);
   8487     if (!prs) {
   8488         /* if the brand is not present, add it */
   8489         brand = JS_NewSymbolFromAtom(ctx, JS_ATOM_brand, JS_ATOM_TYPE_PRIVATE);
   8490         if (JS_IsException(brand))
   8491             return -1;
   8492         pr = add_property(ctx, p, JS_ATOM_Private_brand, JS_PROP_C_W_E);
   8493         if (!pr) {
   8494             JS_FreeValue(ctx, brand);
   8495             return -1;
   8496         }
   8497         pr->u.value = JS_DupValue(ctx, brand);
   8498     } else {
   8499         brand = JS_DupValue(ctx, pr->u.value);
   8500     }
   8501     brand_atom = js_symbol_to_atom(ctx, brand);
   8502 
   8503     if (JS_IsObject(obj)) {
   8504         p1 = JS_VALUE_GET_OBJ(obj);
   8505         prs = find_own_property(&pr, p1, brand_atom);
   8506         if (unlikely(prs)) {
   8507             JS_FreeAtom(ctx, brand_atom);
   8508             JS_ThrowTypeError(ctx, "private method is already present");
   8509             return -1;
   8510         }
   8511         pr = add_property(ctx, p1, brand_atom, JS_PROP_C_W_E);
   8512         JS_FreeAtom(ctx, brand_atom);
   8513         if (!pr)
   8514             return -1;
   8515         pr->u.value = JS_UNDEFINED;
   8516     } else {
   8517         JS_FreeAtom(ctx, brand_atom);
   8518     }
   8519     return 0;
   8520 }
   8521 
   8522 /* return a boolean telling if the brand of the home object of 'func'
   8523    is present on 'obj' or -1 in case of exception */
   8524 static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func)
   8525 {
   8526     JSObject *p, *p1, *home_obj;
   8527     JSShapeProperty *prs;
   8528     JSProperty *pr;
   8529     JSValueConst brand;
   8530 
   8531     /* get the home object of 'func' */
   8532     if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT))
   8533         goto not_obj;
   8534     p1 = JS_VALUE_GET_OBJ(func);
   8535     if (!js_class_has_bytecode(p1->class_id))
   8536         goto not_obj;
   8537     home_obj = p1->u.func.home_object;
   8538     if (!home_obj)
   8539         goto not_obj;
   8540     prs = find_own_property(&pr, home_obj, JS_ATOM_Private_brand);
   8541     if (!prs) {
   8542         JS_ThrowTypeError(ctx, "expecting <brand> private field");
   8543         return -1;
   8544     }
   8545     brand = pr->u.value;
   8546     /* safety check */
   8547     if (unlikely(JS_VALUE_GET_TAG(brand) != JS_TAG_SYMBOL))
   8548         goto not_obj;
   8549 
   8550     /* get the brand array of 'obj' */
   8551     if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
   8552     not_obj:
   8553         JS_ThrowTypeErrorNotAnObject(ctx);
   8554         return -1;
   8555     }
   8556     p = JS_VALUE_GET_OBJ(obj);
   8557     prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, (JSValue)brand));
   8558     return (prs != NULL);
   8559 }
   8560 
   8561 static uint32_t js_string_obj_get_length(JSContext *ctx,
   8562                                          JSValueConst obj)
   8563 {
   8564     JSObject *p;
   8565     uint32_t len = 0;
   8566 
   8567     /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
   8568     p = JS_VALUE_GET_OBJ(obj);
   8569     if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
   8570         JSString *p1 = JS_VALUE_GET_STRING(p->u.object_data);
   8571         len = p1->len;
   8572     }
   8573     return len;
   8574 }
   8575 
   8576 static int num_keys_cmp(const void *p1, const void *p2, void *opaque)
   8577 {
   8578     JSContext *ctx = opaque;
   8579     JSAtom atom1 = ((const JSPropertyEnum *)p1)->atom;
   8580     JSAtom atom2 = ((const JSPropertyEnum *)p2)->atom;
   8581     uint32_t v1, v2;
   8582     BOOL atom1_is_integer, atom2_is_integer;
   8583 
   8584     atom1_is_integer = JS_AtomIsArrayIndex(ctx, &v1, atom1);
   8585     atom2_is_integer = JS_AtomIsArrayIndex(ctx, &v2, atom2);
   8586     assert(atom1_is_integer && atom2_is_integer);
   8587     if (v1 < v2)
   8588         return -1;
   8589     else if (v1 == v2)
   8590         return 0;
   8591     else
   8592         return 1;
   8593 }
   8594 
   8595 void JS_FreePropertyEnum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len)
   8596 {
   8597     uint32_t i;
   8598     if (tab) {
   8599         for(i = 0; i < len; i++)
   8600             JS_FreeAtom(ctx, tab[i].atom);
   8601         js_free(ctx, tab);
   8602     }
   8603 }
   8604 
   8605 /* return < 0 in case if exception, 0 if OK. ptab and its atoms must
   8606    be freed by the user. */
   8607 static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
   8608                                                       JSPropertyEnum **ptab,
   8609                                                       uint32_t *plen,
   8610                                                       JSObject *p, int flags)
   8611 {
   8612     int i, j;
   8613     JSShape *sh;
   8614     JSShapeProperty *prs;
   8615     JSPropertyEnum *tab_atom, *tab_exotic;
   8616     JSAtom atom;
   8617     uint32_t num_keys_count, str_keys_count, sym_keys_count, atom_count;
   8618     uint32_t num_index, str_index, sym_index, exotic_count, exotic_keys_count;
   8619     BOOL is_enumerable, num_sorted;
   8620     uint32_t num_key;
   8621     JSAtomKindEnum kind;
   8622 
   8623     /* clear pointer for consistency in case of failure */
   8624     *ptab = NULL;
   8625     *plen = 0;
   8626 
   8627     /* compute the number of returned properties */
   8628     num_keys_count = 0;
   8629     str_keys_count = 0;
   8630     sym_keys_count = 0;
   8631     exotic_keys_count = 0;
   8632     exotic_count = 0;
   8633     tab_exotic = NULL;
   8634     sh = p->shape;
   8635     for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
   8636         atom = prs->atom;
   8637         if (atom != JS_ATOM_NULL) {
   8638             is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0);
   8639             kind = JS_AtomGetKind(ctx, atom);
   8640             if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
   8641                 ((flags >> kind) & 1) != 0) {
   8642                 /* need to raise an exception in case of the module
   8643                    name space (implicit GetOwnProperty) */
   8644                 if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) &&
   8645                     (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY))) {
   8646                     JSVarRef *var_ref = p->prop[i].u.var_ref;
   8647                     if (unlikely(JS_IsUninitialized(*var_ref->pvalue))) {
   8648                         JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
   8649                         return -1;
   8650                     }
   8651                 }
   8652                 if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
   8653                     num_keys_count++;
   8654                 } else if (kind == JS_ATOM_KIND_STRING) {
   8655                     str_keys_count++;
   8656                 } else {
   8657                     sym_keys_count++;
   8658                 }
   8659             }
   8660         }
   8661     }
   8662 
   8663     if (p->is_exotic) {
   8664         if (p->fast_array) {
   8665             if (flags & JS_GPN_STRING_MASK) {
   8666                 num_keys_count += p->u.array.count;
   8667             }
   8668         } else if (p->class_id == JS_CLASS_STRING) {
   8669             if (flags & JS_GPN_STRING_MASK) {
   8670                 num_keys_count += js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
   8671             }
   8672         } else {
   8673             const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
   8674             if (em && em->get_own_property_names) {
   8675                 if (em->get_own_property_names(ctx, &tab_exotic, &exotic_count,
   8676                                                JS_MKPTR(JS_TAG_OBJECT, p)))
   8677                     return -1;
   8678                 for(i = 0; i < exotic_count; i++) {
   8679                     atom = tab_exotic[i].atom;
   8680                     kind = JS_AtomGetKind(ctx, atom);
   8681                     if (((flags >> kind) & 1) != 0) {
   8682                         is_enumerable = FALSE;
   8683                         if (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY)) {
   8684                             JSPropertyDescriptor desc;
   8685                             int res;
   8686                             /* set the "is_enumerable" field if necessary */
   8687                             res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
   8688                             if (res < 0) {
   8689                                 JS_FreePropertyEnum(ctx, tab_exotic, exotic_count);
   8690                                 return -1;
   8691                             }
   8692                             if (res) {
   8693                                 is_enumerable =
   8694                                     ((desc.flags & JS_PROP_ENUMERABLE) != 0);
   8695                                 js_free_desc(ctx, &desc);
   8696                             }
   8697                             tab_exotic[i].is_enumerable = is_enumerable;
   8698                         }
   8699                         if (!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) {
   8700                             exotic_keys_count++;
   8701                         }
   8702                     }
   8703                 }
   8704             }
   8705         }
   8706     }
   8707 
   8708     /* fill them */
   8709 
   8710     atom_count = num_keys_count + str_keys_count;
   8711     if (atom_count < str_keys_count)
   8712         goto add_overflow;
   8713     atom_count += sym_keys_count;
   8714     if (atom_count < sym_keys_count)
   8715         goto add_overflow;
   8716     atom_count += exotic_keys_count;
   8717     if (atom_count < exotic_keys_count || atom_count > INT32_MAX) {
   8718     add_overflow:
   8719         JS_ThrowOutOfMemory(ctx);
   8720         JS_FreePropertyEnum(ctx, tab_exotic, exotic_count);
   8721         return -1;
   8722     }
   8723     /* XXX: need generic way to test for js_malloc(ctx, a * b) overflow */
   8724     
   8725     /* avoid allocating 0 bytes */
   8726     tab_atom = js_malloc(ctx, sizeof(tab_atom[0]) * max_int(atom_count, 1));
   8727     if (!tab_atom) {
   8728         JS_FreePropertyEnum(ctx, tab_exotic, exotic_count);
   8729         return -1;
   8730     }
   8731 
   8732     num_index = 0;
   8733     str_index = num_keys_count;
   8734     sym_index = str_index + str_keys_count;
   8735 
   8736     num_sorted = TRUE;
   8737     sh = p->shape;
   8738     for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
   8739         atom = prs->atom;
   8740         if (atom != JS_ATOM_NULL) {
   8741             is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0);
   8742             kind = JS_AtomGetKind(ctx, atom);
   8743             if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
   8744                 ((flags >> kind) & 1) != 0) {
   8745                 if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
   8746                     j = num_index++;
   8747                     num_sorted = FALSE;
   8748                 } else if (kind == JS_ATOM_KIND_STRING) {
   8749                     j = str_index++;
   8750                 } else {
   8751                     j = sym_index++;
   8752                 }
   8753                 tab_atom[j].atom = JS_DupAtom(ctx, atom);
   8754                 tab_atom[j].is_enumerable = is_enumerable;
   8755             }
   8756         }
   8757     }
   8758 
   8759     if (p->is_exotic) {
   8760         int len;
   8761         if (p->fast_array) {
   8762             if (flags & JS_GPN_STRING_MASK) {
   8763                 len = p->u.array.count;
   8764                 goto add_array_keys;
   8765             }
   8766         } else if (p->class_id == JS_CLASS_STRING) {
   8767             if (flags & JS_GPN_STRING_MASK) {
   8768                 len = js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
   8769             add_array_keys:
   8770                 for(i = 0; i < len; i++) {
   8771                     tab_atom[num_index].atom = __JS_AtomFromUInt32(i);
   8772                     if (tab_atom[num_index].atom == JS_ATOM_NULL) {
   8773                         JS_FreePropertyEnum(ctx, tab_atom, num_index);
   8774                         return -1;
   8775                     }
   8776                     tab_atom[num_index].is_enumerable = TRUE;
   8777                     num_index++;
   8778                 }
   8779             }
   8780         } else {
   8781             /* Note: exotic keys are not reordered and comes after the object own properties. */
   8782             for(i = 0; i < exotic_count; i++) {
   8783                 atom = tab_exotic[i].atom;
   8784                 is_enumerable = tab_exotic[i].is_enumerable;
   8785                 kind = JS_AtomGetKind(ctx, atom);
   8786                 if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
   8787                     ((flags >> kind) & 1) != 0) {
   8788                     tab_atom[sym_index].atom = atom;
   8789                     tab_atom[sym_index].is_enumerable = is_enumerable;
   8790                     sym_index++;
   8791                 } else {
   8792                     JS_FreeAtom(ctx, atom);
   8793                 }
   8794             }
   8795             js_free(ctx, tab_exotic);
   8796         }
   8797     }
   8798 
   8799     assert(num_index == num_keys_count);
   8800     assert(str_index == num_keys_count + str_keys_count);
   8801     assert(sym_index == atom_count);
   8802 
   8803     if (num_keys_count != 0 && !num_sorted) {
   8804         rqsort(tab_atom, num_keys_count, sizeof(tab_atom[0]), num_keys_cmp,
   8805                ctx);
   8806     }
   8807     *ptab = tab_atom;
   8808     *plen = atom_count;
   8809     return 0;
   8810 }
   8811 
   8812 int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab,
   8813                            uint32_t *plen, JSValueConst obj, int flags)
   8814 {
   8815     if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
   8816         JS_ThrowTypeErrorNotAnObject(ctx);
   8817         return -1;
   8818     }
   8819     return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen,
   8820                                           JS_VALUE_GET_OBJ(obj), flags);
   8821 }
   8822 
   8823 /* Return -1 if exception,
   8824    FALSE if the property does not exist, TRUE if it exists. If TRUE is
   8825    returned, the property descriptor 'desc' is filled present. */
   8826 static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc,
   8827                                      JSObject *p, JSAtom prop)
   8828 {
   8829     JSShapeProperty *prs;
   8830     JSProperty *pr;
   8831 
   8832 retry:
   8833     prs = find_own_property(&pr, p, prop);
   8834     if (prs) {
   8835         if (desc) {
   8836             desc->flags = prs->flags & JS_PROP_C_W_E;
   8837             desc->getter = JS_UNDEFINED;
   8838             desc->setter = JS_UNDEFINED;
   8839             desc->value = JS_UNDEFINED;
   8840             if (unlikely(prs->flags & JS_PROP_TMASK)) {
   8841                 if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
   8842                     desc->flags |= JS_PROP_GETSET;
   8843                     if (pr->u.getset.getter)
   8844                         desc->getter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
   8845                     if (pr->u.getset.setter)
   8846                         desc->setter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
   8847                 } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
   8848                     JSValue val = *pr->u.var_ref->pvalue;
   8849                     if (unlikely(JS_IsUninitialized(val))) {
   8850                         JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
   8851                         return -1;
   8852                     }
   8853                     desc->value = JS_DupValue(ctx, val);
   8854                 } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
   8855                     /* Instantiate property and retry */
   8856                     if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
   8857                         return -1;
   8858                     goto retry;
   8859                 }
   8860             } else {
   8861                 desc->value = JS_DupValue(ctx, pr->u.value);
   8862             }
   8863         } else {
   8864             /* for consistency, send the exception even if desc is NULL */
   8865             if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF)) {
   8866                 if (unlikely(JS_IsUninitialized(*pr->u.var_ref->pvalue))) {
   8867                     JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
   8868                     return -1;
   8869                 }
   8870             } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
   8871                 /* nothing to do: delay instantiation until actual value and/or attributes are read */
   8872             }
   8873         }
   8874         return TRUE;
   8875     }
   8876     if (p->is_exotic) {
   8877         if (p->fast_array) {
   8878             /* specific case for fast arrays */
   8879             if (__JS_AtomIsTaggedInt(prop)) {
   8880                 uint32_t idx;
   8881                 idx = __JS_AtomToUInt32(prop);
   8882                 if (idx < p->u.array.count) {
   8883                     if (desc) {
   8884                         desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE |
   8885                             JS_PROP_CONFIGURABLE;
   8886                         desc->getter = JS_UNDEFINED;
   8887                         desc->setter = JS_UNDEFINED;
   8888                         desc->value = JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
   8889                     }
   8890                     return TRUE;
   8891                 }
   8892             }
   8893         } else {
   8894             const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
   8895             if (em && em->get_own_property) {
   8896                 return em->get_own_property(ctx, desc,
   8897                                             JS_MKPTR(JS_TAG_OBJECT, p), prop);
   8898             }
   8899         }
   8900     }
   8901     return FALSE;
   8902 }
   8903 
   8904 int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc,
   8905                       JSValueConst obj, JSAtom prop)
   8906 {
   8907     if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
   8908         JS_ThrowTypeErrorNotAnObject(ctx);
   8909         return -1;
   8910     }
   8911     return JS_GetOwnPropertyInternal(ctx, desc, JS_VALUE_GET_OBJ(obj), prop);
   8912 }
   8913 
   8914 /* return -1 if exception (exotic object only) or TRUE/FALSE */
   8915 int JS_IsExtensible(JSContext *ctx, JSValueConst obj)
   8916 {
   8917     JSObject *p;
   8918 
   8919     if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
   8920         return FALSE;
   8921     p = JS_VALUE_GET_OBJ(obj);
   8922     if (unlikely(p->is_exotic)) {
   8923         const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
   8924         if (em && em->is_extensible) {
   8925             return em->is_extensible(ctx, obj);
   8926         }
   8927     }
   8928     return p->extensible;
   8929 }
   8930 
   8931 /* return -1 if exception (exotic object only) or TRUE/FALSE */
   8932 int JS_PreventExtensions(JSContext *ctx, JSValueConst obj)
   8933 {
   8934     JSObject *p;
   8935 
   8936     if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
   8937         return FALSE;
   8938     p = JS_VALUE_GET_OBJ(obj);
   8939     if (unlikely(p->is_exotic)) {
   8940         if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
   8941             p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
   8942             JSTypedArray *ta;
   8943             JSArrayBuffer *abuf;
   8944             /* resizable type arrays return FALSE */
   8945             ta = p->u.typed_array;
   8946             abuf = ta->buffer->u.array_buffer;
   8947             if (ta->track_rab ||
   8948                 (array_buffer_is_resizable(abuf) && !abuf->shared))
   8949                 return FALSE;
   8950         } else {
   8951             const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
   8952             if (em && em->prevent_extensions) {
   8953                 return em->prevent_extensions(ctx, obj);
   8954             }
   8955         }
   8956     }
   8957     p->extensible = FALSE;
   8958     return TRUE;
   8959 }
   8960 
   8961 /* return -1 if exception otherwise TRUE or FALSE */
   8962 int JS_HasPropertyStr(JSContext *ctx, JSValueConst obj, const char *propname)
   8963 {
   8964     JSAtom atom;
   8965     int ret;
   8966     atom = JS_NewAtom(ctx, propname);
   8967     if (atom == JS_ATOM_NULL) {
   8968         return -1;
   8969     }
   8970     ret = JS_HasProperty(ctx, obj, atom);
   8971     JS_FreeAtom(ctx, atom);
   8972     return ret;
   8973 }
   8974 
   8975 /* return -1 if exception otherwise TRUE or FALSE */
   8976 int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop)
   8977 {
   8978     JSObject *p;
   8979     int ret;
   8980     JSValue obj1;
   8981 
   8982     if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
   8983         return FALSE;
   8984     p = JS_VALUE_GET_OBJ(obj);
   8985     for(;;) {
   8986         if (p->is_exotic) {
   8987             const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
   8988             if (em && em->has_property) {
   8989                 /* has_property can free the prototype */
   8990                 obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
   8991                 ret = em->has_property(ctx, obj1, prop);
   8992                 JS_FreeValue(ctx, obj1);
   8993                 return ret;
   8994             }
   8995         }
   8996         /* JS_GetOwnPropertyInternal can free the prototype */
   8997         JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
   8998         ret = JS_GetOwnPropertyInternal(ctx, NULL, p, prop);
   8999         JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
   9000         if (ret != 0)
   9001             return ret;
   9002         if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
   9003             p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
   9004             ret = JS_AtomIsNumericIndex(ctx, prop);
   9005             if (ret != 0) {
   9006                 if (ret < 0)
   9007                     return -1;
   9008                 return FALSE;
   9009             }
   9010         }
   9011         p = p->shape->proto;
   9012         if (!p)
   9013             break;
   9014     }
   9015     return FALSE;
   9016 }
   9017 
   9018 /* val must be a symbol */
   9019 static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val)
   9020 {
   9021     JSAtomStruct *p = JS_VALUE_GET_PTR(val);
   9022     return js_get_atom_index(ctx->rt, p);
   9023 }
   9024 
   9025 /* return JS_ATOM_NULL in case of exception */
   9026 JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val)
   9027 {
   9028     JSAtom atom;
   9029     uint32_t tag;
   9030     tag = JS_VALUE_GET_TAG(val);
   9031     if (tag == JS_TAG_INT &&
   9032         (uint32_t)JS_VALUE_GET_INT(val) <= JS_ATOM_MAX_INT) {
   9033         /* fast path for integer values */
   9034         atom = __JS_AtomFromUInt32(JS_VALUE_GET_INT(val));
   9035     } else if (tag == JS_TAG_SYMBOL) {
   9036         JSAtomStruct *p = JS_VALUE_GET_PTR(val);
   9037         atom = JS_DupAtom(ctx, js_get_atom_index(ctx->rt, p));
   9038     } else {
   9039         JSValue str;
   9040         str = JS_ToPropertyKey(ctx, val);
   9041         if (JS_IsException(str))
   9042             return JS_ATOM_NULL;
   9043         if (JS_VALUE_GET_TAG(str) == JS_TAG_SYMBOL) {
   9044             atom = js_symbol_to_atom(ctx, str);
   9045         } else {
   9046             atom = JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(str));
   9047         }
   9048     }
   9049     return atom;
   9050 }
   9051 
   9052 static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,
   9053                                    JSValue prop)
   9054 {
   9055     JSAtom atom;
   9056     JSValue ret;
   9057 
   9058     if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT &&
   9059                JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {
   9060         JSObject *p;
   9061         uint32_t idx;
   9062         /* fast path for array access */
   9063         p = JS_VALUE_GET_OBJ(this_obj);
   9064         idx = JS_VALUE_GET_INT(prop);
   9065         switch(p->class_id) {
   9066         case JS_CLASS_ARRAY:
   9067         case JS_CLASS_ARGUMENTS:
   9068             if (unlikely(idx >= p->u.array.count)) goto slow_path;
   9069             return JS_DupValue(ctx, p->u.array.u.values[idx]);
   9070         case JS_CLASS_MAPPED_ARGUMENTS:
   9071             if (unlikely(idx >= p->u.array.count)) goto slow_path;
   9072             return JS_DupValue(ctx, *p->u.array.u.var_refs[idx]->pvalue);
   9073         case JS_CLASS_INT8_ARRAY:
   9074             if (unlikely(idx >= p->u.array.count)) goto slow_path;
   9075             return JS_NewInt32(ctx, p->u.array.u.int8_ptr[idx]);
   9076         case JS_CLASS_UINT8C_ARRAY:
   9077         case JS_CLASS_UINT8_ARRAY:
   9078             if (unlikely(idx >= p->u.array.count)) goto slow_path;
   9079             return JS_NewInt32(ctx, p->u.array.u.uint8_ptr[idx]);
   9080         case JS_CLASS_INT16_ARRAY:
   9081             if (unlikely(idx >= p->u.array.count)) goto slow_path;
   9082             return JS_NewInt32(ctx, p->u.array.u.int16_ptr[idx]);
   9083         case JS_CLASS_UINT16_ARRAY:
   9084             if (unlikely(idx >= p->u.array.count)) goto slow_path;
   9085             return JS_NewInt32(ctx, p->u.array.u.uint16_ptr[idx]);
   9086         case JS_CLASS_INT32_ARRAY:
   9087             if (unlikely(idx >= p->u.array.count)) goto slow_path;
   9088             return JS_NewInt32(ctx, p->u.array.u.int32_ptr[idx]);
   9089         case JS_CLASS_UINT32_ARRAY:
   9090             if (unlikely(idx >= p->u.array.count)) goto slow_path;
   9091             return JS_NewUint32(ctx, p->u.array.u.uint32_ptr[idx]);
   9092         case JS_CLASS_BIG_INT64_ARRAY:
   9093             if (unlikely(idx >= p->u.array.count)) goto slow_path;
   9094             return JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]);
   9095         case JS_CLASS_BIG_UINT64_ARRAY:
   9096             if (unlikely(idx >= p->u.array.count)) goto slow_path;
   9097             return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]);
   9098         case JS_CLASS_FLOAT16_ARRAY:
   9099             if (unlikely(idx >= p->u.array.count)) goto slow_path;
   9100             return __JS_NewFloat64(ctx, fromfp16(p->u.array.u.fp16_ptr[idx]));
   9101         case JS_CLASS_FLOAT32_ARRAY:
   9102             if (unlikely(idx >= p->u.array.count)) goto slow_path;
   9103             return __JS_NewFloat64(ctx, p->u.array.u.float_ptr[idx]);
   9104         case JS_CLASS_FLOAT64_ARRAY:
   9105             if (unlikely(idx >= p->u.array.count)) goto slow_path;
   9106             return __JS_NewFloat64(ctx, p->u.array.u.double_ptr[idx]);
   9107         default:
   9108             goto slow_path;
   9109         }
   9110     } else {
   9111     slow_path:
   9112         /* ToObject() must be done before ToPropertyKey() */
   9113         if (JS_IsNull(this_obj) || JS_IsUndefined(this_obj)) {
   9114             JS_FreeValue(ctx, prop);
   9115             return JS_ThrowTypeError(ctx, "cannot read property of %s", JS_IsNull(this_obj) ? "null" : "undefined");
   9116         }
   9117         atom = JS_ValueToAtom(ctx, prop);
   9118         JS_FreeValue(ctx, prop);
   9119         if (unlikely(atom == JS_ATOM_NULL))
   9120             return JS_EXCEPTION;
   9121         ret = JS_GetProperty(ctx, this_obj, atom);
   9122         JS_FreeAtom(ctx, atom);
   9123         return ret;
   9124     }
   9125 }
   9126 
   9127 JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
   9128                              uint32_t idx)
   9129 {
   9130     return JS_GetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx));
   9131 }
   9132 
   9133 /* Check if an object has a generalized numeric property. Return value:
   9134    -1 for exception,
   9135    TRUE if property exists, stored into *pval,
   9136    FALSE if proprty does not exist.
   9137  */
   9138 static int JS_TryGetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, JSValue *pval)
   9139 {
   9140     JSValue val = JS_UNDEFINED;
   9141     JSAtom prop;
   9142     int present;
   9143 
   9144     if (likely((uint64_t)idx <= JS_ATOM_MAX_INT)) {
   9145         /* fast path */
   9146         present = JS_HasProperty(ctx, obj, __JS_AtomFromUInt32(idx));
   9147         if (present > 0) {
   9148             val = JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx));
   9149             if (unlikely(JS_IsException(val)))
   9150                 present = -1;
   9151         }
   9152     } else {
   9153         prop = JS_NewAtomInt64(ctx, idx);
   9154         present = -1;
   9155         if (likely(prop != JS_ATOM_NULL)) {
   9156             present = JS_HasProperty(ctx, obj, prop);
   9157             if (present > 0) {
   9158                 val = JS_GetProperty(ctx, obj, prop);
   9159                 if (unlikely(JS_IsException(val)))
   9160                     present = -1;
   9161             }
   9162             JS_FreeAtom(ctx, prop);
   9163         }
   9164     }
   9165     *pval = val;
   9166     return present;
   9167 }
   9168 
   9169 static JSValue JS_GetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx)
   9170 {
   9171     JSAtom prop;
   9172     JSValue val;
   9173 
   9174     if ((uint64_t)idx <= INT32_MAX) {
   9175         /* fast path for fast arrays */
   9176         return JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx));
   9177     }
   9178     prop = JS_NewAtomInt64(ctx, idx);
   9179     if (prop == JS_ATOM_NULL)
   9180         return JS_EXCEPTION;
   9181 
   9182     val = JS_GetProperty(ctx, obj, prop);
   9183     JS_FreeAtom(ctx, prop);
   9184     return val;
   9185 }
   9186 
   9187 JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj,
   9188                           const char *prop)
   9189 {
   9190     JSAtom atom;
   9191     JSValue ret;
   9192     atom = JS_NewAtom(ctx, prop);
   9193     if (atom == JS_ATOM_NULL)
   9194         return JS_EXCEPTION;
   9195     ret = JS_GetProperty(ctx, this_obj, atom);
   9196     JS_FreeAtom(ctx, atom);
   9197     return ret;
   9198 }
   9199 
   9200 /* Note: the property value is not initialized. Return NULL if memory
   9201    error. */
   9202 static JSProperty *add_property(JSContext *ctx,
   9203                                 JSObject *p, JSAtom prop, int prop_flags)
   9204 {
   9205     JSShape *sh, *new_sh;
   9206 
   9207     if (unlikely(__JS_AtomIsTaggedInt(prop))) {
   9208         /* update is_std_array_prototype */
   9209         if (unlikely(p->is_std_array_prototype)) {
   9210             p->is_std_array_prototype = FALSE;
   9211         } else if (unlikely(p->has_immutable_prototype)) {
   9212             struct list_head *el;
   9213             
   9214             /* modifying Object.prototype : reset the corresponding is_std_array_prototype */
   9215             list_for_each(el, &ctx->rt->context_list) {
   9216                 JSContext *ctx1 = list_entry(el, JSContext, link);
   9217                 if (JS_IsObject(ctx1->class_proto[JS_CLASS_OBJECT]) && 
   9218                     JS_VALUE_GET_OBJ(ctx1->class_proto[JS_CLASS_OBJECT]) == p) {
   9219                     if (JS_IsObject(ctx1->class_proto[JS_CLASS_ARRAY])) {
   9220                         JSObject *p1 = JS_VALUE_GET_OBJ(ctx1->class_proto[JS_CLASS_ARRAY]);
   9221                         p1->is_std_array_prototype = FALSE;
   9222                     }
   9223                     break;
   9224                 }
   9225             }
   9226         }
   9227     }
   9228     sh = p->shape;
   9229     if (sh->is_hashed) {
   9230         /* try to find an existing shape */
   9231         new_sh = find_hashed_shape_prop(ctx->rt, sh, prop, prop_flags);
   9232         if (new_sh) {
   9233             /* matching shape found: use it */
   9234             /*  the property array may need to be resized */
   9235             if (new_sh->prop_size != sh->prop_size) {
   9236                 JSProperty *new_prop;
   9237                 new_prop = js_realloc(ctx, p->prop, sizeof(p->prop[0]) *
   9238                                       new_sh->prop_size);
   9239                 if (!new_prop)
   9240                     return NULL;
   9241                 p->prop = new_prop;
   9242             }
   9243             p->shape = js_dup_shape(new_sh);
   9244             js_free_shape(ctx->rt, sh);
   9245             return &p->prop[new_sh->prop_count - 1];
   9246         } else if (js_rc(sh)->ref_count != 1) {
   9247             /* if the shape is shared, clone it */
   9248             new_sh = js_clone_shape(ctx, sh);
   9249             if (!new_sh)
   9250                 return NULL;
   9251             /* hash the cloned shape */
   9252             new_sh->is_hashed = TRUE;
   9253             js_shape_hash_link(ctx->rt, new_sh);
   9254             js_free_shape(ctx->rt, p->shape);
   9255             p->shape = new_sh;
   9256         }
   9257     }
   9258     assert(js_rc(p->shape)->ref_count == 1);
   9259     if (add_shape_property(ctx, &p->shape, p, prop, prop_flags))
   9260         return NULL;
   9261     return &p->prop[p->shape->prop_count - 1];
   9262 }
   9263 
   9264 /* can be called on JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS or
   9265    JS_CLASS_MAPPED_ARGUMENTS objects. return < 0 if memory alloc
   9266    error. */
   9267 static no_inline __exception int convert_fast_array_to_array(JSContext *ctx,
   9268                                                              JSObject *p)
   9269 {
   9270     JSProperty *pr;
   9271     JSShape *sh;
   9272     uint32_t i, len, new_count;
   9273 
   9274     if (js_shape_prepare_update(ctx, p, NULL))
   9275         return -1;
   9276     len = p->u.array.count;
   9277     /* resize the properties once to simplify the error handling */
   9278     sh = p->shape;
   9279     new_count = sh->prop_count + len;
   9280     if (new_count > sh->prop_size) {
   9281         if (resize_properties(ctx, &p->shape, p, new_count))
   9282             return -1;
   9283     }
   9284 
   9285     if (p->class_id == JS_CLASS_MAPPED_ARGUMENTS) {
   9286         JSVarRef **tab = p->u.array.u.var_refs;
   9287         for(i = 0; i < len; i++) {
   9288             /* add_property cannot fail here but
   9289                __JS_AtomFromUInt32(i) fails for i > INT32_MAX */
   9290             pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E | JS_PROP_VARREF);
   9291             pr->u.var_ref = *tab++;
   9292         }
   9293     } else {
   9294         JSValue *tab = p->u.array.u.values;
   9295         for(i = 0; i < len; i++) {
   9296             /* add_property cannot fail here but
   9297                __JS_AtomFromUInt32(i) fails for i > INT32_MAX */
   9298             pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E);
   9299             pr->u.value = *tab++;
   9300         }
   9301     }
   9302     js_free(ctx, p->u.array.u.values);
   9303     p->u.array.count = 0;
   9304     p->u.array.u.values = NULL; /* fail safe */
   9305     p->u.array.u1.size = 0;
   9306     p->fast_array = 0;
   9307     p->is_std_array_prototype = FALSE;
   9308     return 0;
   9309 }
   9310 
   9311 static int remove_global_object_property(JSContext *ctx, JSObject *p,
   9312                                          JSShapeProperty *prs, JSProperty *pr)
   9313 {
   9314     JSVarRef *var_ref;
   9315     JSObject *p1;
   9316     JSProperty *pr1;
   9317     
   9318     var_ref = pr->u.var_ref;
   9319     if (js_rc(var_ref)->ref_count == 1)
   9320         return 0;
   9321     p1 = JS_VALUE_GET_OBJ(p->u.global_object.uninitialized_vars);
   9322     pr1 = add_property(ctx, p1, prs->atom, JS_PROP_C_W_E | JS_PROP_VARREF);
   9323     if (!pr1)
   9324         return -1;
   9325     pr1->u.var_ref = var_ref;
   9326     js_rc(var_ref)->ref_count++;
   9327     JS_FreeValue(ctx, var_ref->value);
   9328     var_ref->is_lexical = FALSE;
   9329     var_ref->is_const = FALSE;
   9330     var_ref->value = JS_UNINITIALIZED;
   9331     return 0;
   9332 }
   9333 
   9334 static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom)
   9335 {
   9336     JSShape *sh;
   9337     JSShapeProperty *pr, *lpr, *prop;
   9338     JSProperty *pr1;
   9339     uint32_t lpr_idx;
   9340     intptr_t h, h1;
   9341 
   9342  redo:
   9343     sh = p->shape;
   9344     h1 = atom & sh->prop_hash_mask;
   9345     h = sh->hash_table[h1];
   9346     prop = get_shape_prop(sh);
   9347     lpr = NULL;
   9348     lpr_idx = 0;   /* prevent warning */
   9349     while (h != 0) {
   9350         pr = &prop[h - 1];
   9351         if (likely(pr->atom == atom)) {
   9352             /* found ! */
   9353             if (!(pr->flags & JS_PROP_CONFIGURABLE))
   9354                 return FALSE;
   9355             /* realloc the shape if needed */
   9356             if (lpr)
   9357                 lpr_idx = lpr - get_shape_prop(sh);
   9358             if (js_shape_prepare_update(ctx, p, &pr))
   9359                 return -1;
   9360             sh = p->shape;
   9361             /* remove property */
   9362             if (lpr) {
   9363                 lpr = get_shape_prop(sh) + lpr_idx;
   9364                 lpr->hash_next = pr->hash_next;
   9365             } else {
   9366                 sh->hash_table[h1] = pr->hash_next;
   9367             }
   9368             sh->deleted_prop_count++;
   9369             /* free the entry */
   9370             pr1 = &p->prop[h - 1];
   9371             if (unlikely(p->class_id == JS_CLASS_GLOBAL_OBJECT)) {
   9372                 if ((pr->flags & JS_PROP_TMASK) == JS_PROP_VARREF)
   9373                     if (remove_global_object_property(ctx, p, pr, pr1))
   9374                         return -1;
   9375             }
   9376             free_property(ctx->rt, pr1, pr->flags);
   9377             JS_FreeAtom(ctx, pr->atom);
   9378             /* put default values */
   9379             pr->flags = 0;
   9380             pr->atom = JS_ATOM_NULL;
   9381             pr1->u.value = JS_UNDEFINED;
   9382 
   9383             /* compact the properties if too many deleted properties */
   9384             if (sh->deleted_prop_count >= 8 &&
   9385                 sh->deleted_prop_count >= ((unsigned)sh->prop_count / 2)) {
   9386                 compact_properties(ctx, p);
   9387             }
   9388             return TRUE;
   9389         }
   9390         lpr = pr;
   9391         h = pr->hash_next;
   9392     }
   9393 
   9394     if (p->is_exotic) {
   9395         if (p->fast_array) {
   9396             uint32_t idx;
   9397             if (JS_AtomIsArrayIndex(ctx, &idx, atom) &&
   9398                 idx < p->u.array.count) {
   9399                 if (p->class_id == JS_CLASS_ARRAY ||
   9400                     p->class_id == JS_CLASS_ARGUMENTS ||
   9401                     p->class_id == JS_CLASS_MAPPED_ARGUMENTS) {
   9402                     /* Special case deleting the last element of a fast Array */
   9403                     if (idx == p->u.array.count - 1) {
   9404                         if (p->class_id == JS_CLASS_MAPPED_ARGUMENTS) {
   9405                             free_var_ref(ctx->rt, p->u.array.u.var_refs[idx]);
   9406                         } else {
   9407                             JS_FreeValue(ctx, p->u.array.u.values[idx]);
   9408                         }
   9409                         p->u.array.count = idx;
   9410                         return TRUE;
   9411                     }
   9412                     if (convert_fast_array_to_array(ctx, p))
   9413                         return -1;
   9414                     goto redo;
   9415                 } else {
   9416                     return FALSE;
   9417                 }
   9418             }
   9419         } else {
   9420             const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
   9421             if (em && em->delete_property) {
   9422                 return em->delete_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), atom);
   9423             }
   9424         }
   9425     }
   9426     /* not found */
   9427     return TRUE;
   9428 }
   9429 
   9430 static int call_setter(JSContext *ctx, JSObject *setter,
   9431                        JSValueConst this_obj, JSValue val, int flags)
   9432 {
   9433     JSValue ret, func;
   9434     if (likely(setter)) {
   9435         func = JS_MKPTR(JS_TAG_OBJECT, setter);
   9436         /* Note: the field could be removed in the setter */
   9437         func = JS_DupValue(ctx, func);
   9438         ret = JS_CallFree(ctx, func, this_obj, 1, (JSValueConst *)&val);
   9439         JS_FreeValue(ctx, val);
   9440         if (JS_IsException(ret))
   9441             return -1;
   9442         JS_FreeValue(ctx, ret);
   9443         return TRUE;
   9444     } else {
   9445         JS_FreeValue(ctx, val);
   9446         if ((flags & JS_PROP_THROW) ||
   9447             ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
   9448             JS_ThrowTypeError(ctx, "no setter for property");
   9449             return -1;
   9450         }
   9451         return FALSE;
   9452     }
   9453 }
   9454 
   9455 /* set the array length and remove the array elements if necessary. */
   9456 static int set_array_length(JSContext *ctx, JSObject *p, JSValue val,
   9457                             int flags)
   9458 {
   9459     uint32_t len, idx, cur_len;
   9460     int i, ret;
   9461 
   9462     /* Note: this call can reallocate the properties of 'p' */
   9463     ret = JS_ToArrayLengthFree(ctx, &len, val, FALSE);
   9464     if (ret)
   9465         return -1;
   9466     /* JS_ToArrayLengthFree() must be done before the read-only test */
   9467     if (unlikely(!(get_shape_prop(p->shape)[0].flags & JS_PROP_WRITABLE)))
   9468         return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
   9469 
   9470     if (likely(p->fast_array)) {
   9471         uint32_t old_len = p->u.array.count;
   9472         if (len < old_len) {
   9473             for(i = len; i < old_len; i++) {
   9474                 JS_FreeValue(ctx, p->u.array.u.values[i]);
   9475             }
   9476             p->u.array.count = len;
   9477         }
   9478         p->prop[0].u.value = JS_NewUint32(ctx, len);
   9479     } else {
   9480         /* Note: length is always a uint32 because the object is an
   9481            array */
   9482         JS_ToUint32(ctx, &cur_len, p->prop[0].u.value);
   9483         if (len < cur_len) {
   9484             uint32_t d;
   9485             JSShape *sh;
   9486             JSShapeProperty *pr;
   9487 
   9488             d = cur_len - len;
   9489             sh = p->shape;
   9490             if (d <= sh->prop_count) {
   9491                 JSAtom atom;
   9492 
   9493                 /* faster to iterate */
   9494                 while (cur_len > len) {
   9495                     atom = JS_NewAtomUInt32(ctx, cur_len - 1);
   9496                     ret = delete_property(ctx, p, atom);
   9497                     JS_FreeAtom(ctx, atom);
   9498                     if (unlikely(!ret)) {
   9499                         /* unlikely case: property is not
   9500                            configurable */
   9501                         break;
   9502                     }
   9503                     cur_len--;
   9504                 }
   9505             } else {
   9506                 /* faster to iterate thru all the properties. Need two
   9507                    passes in case one of the property is not
   9508                    configurable */
   9509                 cur_len = len;
   9510                 for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count;
   9511                     i++, pr++) {
   9512                     if (pr->atom != JS_ATOM_NULL &&
   9513                         JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) {
   9514                         if (idx >= cur_len &&
   9515                             !(pr->flags & JS_PROP_CONFIGURABLE)) {
   9516                             cur_len = idx + 1;
   9517                         }
   9518                     }
   9519                 }
   9520 
   9521                 for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count;
   9522                     i++, pr++) {
   9523                     if (pr->atom != JS_ATOM_NULL &&
   9524                         JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) {
   9525                         if (idx >= cur_len) {
   9526                             /* remove the property */
   9527                             delete_property(ctx, p, pr->atom);
   9528                             /* WARNING: the shape may have been modified */
   9529                             sh = p->shape;
   9530                             pr = get_shape_prop(sh) + i;
   9531                         }
   9532                     }
   9533                 }
   9534             }
   9535         } else {
   9536             cur_len = len;
   9537         }
   9538         set_value(ctx, &p->prop[0].u.value, JS_NewUint32(ctx, cur_len));
   9539         if (unlikely(cur_len > len)) {
   9540             return JS_ThrowTypeErrorOrFalse(ctx, flags, "not configurable");
   9541         }
   9542     }
   9543     return TRUE;
   9544 }
   9545 
   9546 /* return -1 if exception */
   9547 static int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len)
   9548 {
   9549     uint32_t new_size;
   9550     size_t slack;
   9551     JSValue *new_array_prop;
   9552     /* XXX: potential arithmetic overflow */
   9553     new_size = max_int(new_len, p->u.array.u1.size * 3 / 2);
   9554     new_array_prop = js_realloc2(ctx, p->u.array.u.values, sizeof(JSValue) * new_size, &slack);
   9555     if (!new_array_prop)
   9556         return -1;
   9557     new_size += slack / sizeof(*new_array_prop);
   9558     p->u.array.u.values = new_array_prop;
   9559     p->u.array.u1.size = new_size;
   9560     return 0;
   9561 }
   9562 
   9563 /* Preconditions: 'p' must be of class JS_CLASS_ARRAY, p->fast_array =
   9564    TRUE and p->extensible = TRUE */
   9565 static inline int add_fast_array_element(JSContext *ctx, JSObject *p,
   9566                                          JSValue val, int flags)
   9567 {
   9568     uint32_t new_len, array_len;
   9569     /* extend the array by one */
   9570     /* XXX: convert to slow array if new_len > 2^31-1 elements */
   9571     new_len = p->u.array.count + 1;
   9572     /* update the length if necessary. We assume that if the length is
   9573        not an integer, then if it >= 2^31.  */
   9574     if (likely(JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT)) {
   9575         array_len = JS_VALUE_GET_INT(p->prop[0].u.value);
   9576         if (new_len > array_len) {
   9577             if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE))) {
   9578                 JS_FreeValue(ctx, val);
   9579                 return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
   9580             }
   9581             p->prop[0].u.value = JS_NewInt32(ctx, new_len);
   9582         }
   9583     }
   9584     if (unlikely(new_len > p->u.array.u1.size)) {
   9585         if (expand_fast_array(ctx, p, new_len)) {
   9586             JS_FreeValue(ctx, val);
   9587             return -1;
   9588         }
   9589     }
   9590     p->u.array.u.values[new_len - 1] = val;
   9591     p->u.array.count = new_len;
   9592     return TRUE;
   9593 }
   9594 
   9595 /* Allocate a new fast array initialized to JS_UNDEFINED. Its maximum
   9596    size is 2^31-1 elements. For convenience, 'len' is a 64 bit
   9597    integer. */
   9598 static JSValue js_allocate_fast_array(JSContext *ctx, int64_t len)
   9599 {
   9600     JSValue arr;
   9601     JSObject *p;
   9602     int i;
   9603     
   9604     if (len > INT32_MAX)
   9605         return JS_ThrowRangeError(ctx, "invalid array length");
   9606     arr = JS_NewArray(ctx);
   9607     if (JS_IsException(arr))
   9608         return arr;
   9609     if (len > 0) {
   9610         p = JS_VALUE_GET_OBJ(arr);
   9611         if (expand_fast_array(ctx, p, len) < 0) {
   9612             JS_FreeValue(ctx, arr);
   9613             return JS_EXCEPTION;
   9614         }
   9615         p->u.array.count = len;
   9616         for(i = 0; i < len; i++) 
   9617             p->u.array.u.values[i] = JS_UNDEFINED;
   9618         /* update the 'length' field */
   9619         set_value(ctx, &p->prop[0].u.value, JS_NewInt32(ctx, len));
   9620     }
   9621     return arr;
   9622 }
   9623 
   9624 static JSValue js_create_array(JSContext *ctx, int len, JSValueConst *tab)
   9625 {
   9626     JSValue obj;
   9627     JSObject *p;
   9628     int i;
   9629 
   9630     obj = JS_NewArray(ctx);
   9631     if (JS_IsException(obj))
   9632         return JS_EXCEPTION;
   9633     if (len > 0) {
   9634         p = JS_VALUE_GET_OBJ(obj);
   9635         if (expand_fast_array(ctx, p, len) < 0) {
   9636             JS_FreeValue(ctx, obj);
   9637             return JS_EXCEPTION;
   9638         }
   9639         p->u.array.count = len;
   9640         for(i = 0; i < len; i++) 
   9641             p->u.array.u.values[i] = JS_DupValue(ctx, tab[i]);
   9642         /* update the 'length' field */
   9643         set_value(ctx, &p->prop[0].u.value, JS_NewInt32(ctx, len));
   9644     }
   9645     return obj;
   9646 }
   9647 
   9648 static JSValue js_create_array_free(JSContext *ctx, int len, JSValue *tab)
   9649 {
   9650     JSValue obj;
   9651     JSObject *p;
   9652     int i;
   9653 
   9654     obj = JS_NewArray(ctx);
   9655     if (JS_IsException(obj))
   9656         goto fail;
   9657     if (len > 0) {
   9658         p = JS_VALUE_GET_OBJ(obj);
   9659         if (expand_fast_array(ctx, p, len) < 0) {
   9660             JS_FreeValue(ctx, obj);
   9661         fail:
   9662             for(i = 0; i < len; i++)
   9663                 JS_FreeValue(ctx, tab[i]);
   9664             return JS_EXCEPTION;
   9665         }
   9666         p->u.array.count = len;
   9667         for(i = 0; i < len; i++) 
   9668             p->u.array.u.values[i] = tab[i];
   9669         /* update the 'length' field */
   9670         set_value(ctx, &p->prop[0].u.value, JS_NewInt32(ctx, len));
   9671     }
   9672     return obj;
   9673 }
   9674 
   9675 static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc)
   9676 {
   9677     JS_FreeValue(ctx, desc->getter);
   9678     JS_FreeValue(ctx, desc->setter);
   9679     JS_FreeValue(ctx, desc->value);
   9680 }
   9681 
   9682 /* return -1 in case of exception or TRUE or FALSE. Warning: 'val' is
   9683    freed by the function. 'flags' is a bitmask of JS_PROP_THROW and
   9684    JS_PROP_THROW_STRICT. 'this_obj' is the receiver. If obj !=
   9685    this_obj, then obj must be an object (Reflect.set case). */
   9686 int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj,
   9687                            JSAtom prop, JSValue val, JSValueConst this_obj, int flags)
   9688 {
   9689     JSObject *p, *p1;
   9690     JSShapeProperty *prs;
   9691     JSProperty *pr;
   9692     uint32_t tag;
   9693     JSPropertyDescriptor desc;
   9694     int ret;
   9695 #if 0
   9696     printf("JS_SetPropertyInternal: "); print_atom(ctx, prop); printf("\n");
   9697 #endif
   9698     tag = JS_VALUE_GET_TAG(this_obj);
   9699     if (unlikely(tag != JS_TAG_OBJECT)) {
   9700         if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
   9701             p = NULL;
   9702             p1 = JS_VALUE_GET_OBJ(obj);
   9703             goto prototype_lookup;
   9704         } else {
   9705             switch(tag) {
   9706             case JS_TAG_NULL:
   9707                 JS_FreeValue(ctx, val);
   9708                 JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop);
   9709                 return -1;
   9710             case JS_TAG_UNDEFINED:
   9711                 JS_FreeValue(ctx, val);
   9712                 JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop);
   9713                 return -1;
   9714             default:
   9715                 /* even on a primitive type we can have setters on the prototype */
   9716                 p = NULL;
   9717                 p1 = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj));
   9718                 goto prototype_lookup;
   9719             }
   9720         }
   9721     } else {
   9722         p = JS_VALUE_GET_OBJ(this_obj);
   9723         p1 = JS_VALUE_GET_OBJ(obj);
   9724         if (unlikely(p != p1))
   9725             goto retry2;
   9726     }
   9727 
   9728     /* fast path if obj == this_obj */
   9729  retry:
   9730     prs = find_own_property(&pr, p1, prop);
   9731     if (prs) {
   9732         if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE |
   9733                                   JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) {
   9734             /* fast case */
   9735             set_value(ctx, &pr->u.value, val);
   9736             return TRUE;
   9737         } else if (prs->flags & JS_PROP_LENGTH) {
   9738             assert(p->class_id == JS_CLASS_ARRAY);
   9739             assert(prop == JS_ATOM_length);
   9740             return set_array_length(ctx, p, val, flags);
   9741         } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
   9742             return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);
   9743         } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
   9744             /* XXX: already use var_ref->is_const. Cannot simplify use the
   9745                writable flag for JS_CLASS_MODULE_NS. */
   9746             if (p->class_id == JS_CLASS_MODULE_NS || pr->u.var_ref->is_const)
   9747                 goto read_only_prop;
   9748             set_value(ctx, pr->u.var_ref->pvalue, val);
   9749             return TRUE;
   9750         } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
   9751             /* Instantiate property and retry (potentially useless) */
   9752             if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) {
   9753                 JS_FreeValue(ctx, val);
   9754                 return -1;
   9755             }
   9756             goto retry;
   9757         } else {
   9758             goto read_only_prop;
   9759         }
   9760     }
   9761 
   9762     for(;;) {
   9763         if (p1->is_exotic) {
   9764             if (p1->fast_array) {
   9765                 if (__JS_AtomIsTaggedInt(prop)) {
   9766                     uint32_t idx = __JS_AtomToUInt32(prop);
   9767                     if (idx < p1->u.array.count) {
   9768                         if (unlikely(p == p1))
   9769                             return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val, flags);
   9770                         else
   9771                             break;
   9772                     } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY &&
   9773                                p1->class_id <= JS_CLASS_FLOAT64_ARRAY) {
   9774                         goto typed_array_oob;
   9775                     }
   9776                 } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY &&
   9777                            p1->class_id <= JS_CLASS_FLOAT64_ARRAY) {
   9778                     ret = JS_AtomIsNumericIndex(ctx, prop);
   9779                     if (ret != 0) {
   9780                         if (ret < 0) {
   9781                             JS_FreeValue(ctx, val);
   9782                             return -1;
   9783                         }
   9784                     typed_array_oob:
   9785                         if (p == p1) {
   9786                             /* must convert the argument even if out of bound access */
   9787                             if (p1->class_id == JS_CLASS_BIG_INT64_ARRAY ||
   9788                                 p1->class_id == JS_CLASS_BIG_UINT64_ARRAY) {
   9789                                 int64_t v;
   9790                                 if (JS_ToBigInt64Free(ctx, &v, val))
   9791                                     return -1;
   9792                             } else {
   9793                                 val = JS_ToNumberFree(ctx, val);
   9794                                 JS_FreeValue(ctx, val);
   9795                                 if (JS_IsException(val))
   9796                                     return -1;
   9797                             }
   9798                         } else {
   9799                             JS_FreeValue(ctx, val);
   9800                         }
   9801                         return TRUE;
   9802                     }
   9803                 }
   9804             } else {
   9805                 const JSClassExoticMethods *em = ctx->rt->class_array[p1->class_id].exotic;
   9806                 if (em) {
   9807                     JSValue obj1;
   9808                     if (em->set_property) {
   9809                         /* set_property can free the prototype */
   9810                         obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
   9811                         ret = em->set_property(ctx, obj1, prop,
   9812                                                val, this_obj, flags);
   9813                         JS_FreeValue(ctx, obj1);
   9814                         JS_FreeValue(ctx, val);
   9815                         return ret;
   9816                     }
   9817                     if (em->get_own_property) {
   9818                         /* get_own_property can free the prototype */
   9819                         obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
   9820                         ret = em->get_own_property(ctx, &desc,
   9821                                                    obj1, prop);
   9822                         JS_FreeValue(ctx, obj1);
   9823                         if (ret < 0) {
   9824                             JS_FreeValue(ctx, val);
   9825                             return ret;
   9826                         }
   9827                         if (ret) {
   9828                             if (desc.flags & JS_PROP_GETSET) {
   9829                                 JSObject *setter;
   9830                                 if (JS_IsUndefined(desc.setter))
   9831                                     setter = NULL;
   9832                                 else
   9833                                     setter = JS_VALUE_GET_OBJ(desc.setter);
   9834                                 ret = call_setter(ctx, setter, this_obj, val, flags);
   9835                                 JS_FreeValue(ctx, desc.getter);
   9836                                 JS_FreeValue(ctx, desc.setter);
   9837                                 return ret;
   9838                             } else {
   9839                                 JS_FreeValue(ctx, desc.value);
   9840                                 if (!(desc.flags & JS_PROP_WRITABLE))
   9841                                     goto read_only_prop;
   9842                                 if (likely(p == p1)) {
   9843                                     ret = JS_DefineProperty(ctx, this_obj, prop, val,
   9844                                                             JS_UNDEFINED, JS_UNDEFINED,
   9845                                                             JS_PROP_HAS_VALUE);
   9846                                     JS_FreeValue(ctx, val);
   9847                                     return ret;
   9848                                 } else {
   9849                                     break;
   9850                                 }
   9851                             }
   9852                         }
   9853                     }
   9854                 }
   9855             }
   9856         }
   9857         p1 = p1->shape->proto;
   9858     prototype_lookup:
   9859         if (!p1)
   9860             break;
   9861 
   9862     retry2:
   9863         prs = find_own_property(&pr, p1, prop);
   9864         if (prs) {
   9865             if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
   9866                 return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);
   9867             } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
   9868                 /* Instantiate property and retry (potentially useless) */
   9869                 if (JS_AutoInitProperty(ctx, p1, prop, pr, prs))
   9870                     return -1;
   9871                 goto retry2;
   9872             } else if (!(prs->flags & JS_PROP_WRITABLE)) {
   9873                 goto read_only_prop;
   9874             } else {
   9875                 break;
   9876             }
   9877         }
   9878     }
   9879 
   9880     if (unlikely(!p)) {
   9881         JS_FreeValue(ctx, val);
   9882         return JS_ThrowTypeErrorOrFalse(ctx, flags, "not an object");
   9883     }
   9884 
   9885     if (unlikely(!p->extensible)) {
   9886         JS_FreeValue(ctx, val);
   9887         return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible");
   9888     }
   9889 
   9890     if (likely(p == JS_VALUE_GET_OBJ(obj))) {
   9891         if (p->is_exotic) {
   9892             if (p->class_id == JS_CLASS_ARRAY && p->fast_array &&
   9893                 __JS_AtomIsTaggedInt(prop)) {
   9894                 uint32_t idx = __JS_AtomToUInt32(prop);
   9895                 if (idx == p->u.array.count) {
   9896                     /* fast case */
   9897                     return add_fast_array_element(ctx, p, val, flags);
   9898                 } else {
   9899                     goto generic_create_prop;
   9900                 }
   9901             } else {
   9902                 goto generic_create_prop;
   9903             }
   9904         } else {
   9905             if (unlikely(p->class_id == JS_CLASS_GLOBAL_OBJECT))
   9906                 goto generic_create_prop;
   9907             pr = add_property(ctx, p, prop, JS_PROP_C_W_E);
   9908             if (unlikely(!pr)) {
   9909                 JS_FreeValue(ctx, val);
   9910                 return -1;
   9911             }
   9912             pr->u.value = val;
   9913             return TRUE;
   9914         }
   9915     } else {
   9916         /* generic case: modify the property in this_obj if it already exists */
   9917         ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
   9918         if (ret < 0) {
   9919             JS_FreeValue(ctx, val);
   9920             return ret;
   9921         }
   9922         if (ret) {
   9923             if (desc.flags & JS_PROP_GETSET) {
   9924                 JS_FreeValue(ctx, desc.getter);
   9925                 JS_FreeValue(ctx, desc.setter);
   9926                 JS_FreeValue(ctx, val);
   9927                 return JS_ThrowTypeErrorOrFalse(ctx, flags, "setter is forbidden");
   9928             } else {
   9929                 JS_FreeValue(ctx, desc.value);
   9930                 if (!(desc.flags & JS_PROP_WRITABLE) ||
   9931                     p->class_id == JS_CLASS_MODULE_NS) {
   9932                 read_only_prop:
   9933                     JS_FreeValue(ctx, val);
   9934                     return JS_ThrowTypeErrorReadOnly(ctx, flags, prop);
   9935                 }
   9936             }
   9937             ret = JS_DefineProperty(ctx, this_obj, prop, val,
   9938                                     JS_UNDEFINED, JS_UNDEFINED,
   9939                                     JS_PROP_HAS_VALUE);
   9940             JS_FreeValue(ctx, val);
   9941             return ret;
   9942         } else {
   9943         generic_create_prop:
   9944             ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED,
   9945                                     flags |
   9946                                     JS_PROP_HAS_VALUE |
   9947                                     JS_PROP_HAS_ENUMERABLE |
   9948                                     JS_PROP_HAS_WRITABLE |
   9949                                     JS_PROP_HAS_CONFIGURABLE |
   9950                                     JS_PROP_C_W_E);
   9951             JS_FreeValue(ctx, val);
   9952             return ret;
   9953         }
   9954     }
   9955 }
   9956 
   9957 /* return true if an element can be added to a fast array without further tests */
   9958 static force_inline BOOL can_extend_fast_array(JSObject *p)
   9959 {
   9960     JSObject *proto;
   9961     if (!p->extensible)
   9962         return FALSE;
   9963     proto = p->shape->proto;
   9964     if (!proto)
   9965         return TRUE;
   9966     return proto->is_std_array_prototype;
   9967 }
   9968 
   9969 /* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */
   9970 static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
   9971                                JSValue prop, JSValue val, int flags)
   9972 {
   9973     if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT &&
   9974                JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {
   9975         JSObject *p;
   9976         uint32_t idx;
   9977         double d;
   9978         int32_t v;
   9979 
   9980         /* fast path for array access */
   9981         p = JS_VALUE_GET_OBJ(this_obj);
   9982         idx = JS_VALUE_GET_INT(prop);
   9983         switch(p->class_id) {
   9984         case JS_CLASS_ARRAY:
   9985             if (unlikely(idx >= (uint32_t)p->u.array.count)) {
   9986                 /* fast path to add an element to the array */
   9987                 if (unlikely(idx != (uint32_t)p->u.array.count ||
   9988                              !p->fast_array ||
   9989                              !can_extend_fast_array(p))) {
   9990                     goto slow_path;
   9991                 }
   9992                 /* add element */
   9993                 return add_fast_array_element(ctx, p, val, flags);
   9994             }
   9995             set_value(ctx, &p->u.array.u.values[idx], val);
   9996             break;
   9997         case JS_CLASS_ARGUMENTS:
   9998             if (unlikely(idx >= (uint32_t)p->u.array.count))
   9999                 goto slow_path;
  10000             set_value(ctx, &p->u.array.u.values[idx], val);
  10001             break;
  10002         case JS_CLASS_MAPPED_ARGUMENTS:
  10003             if (unlikely(idx >= (uint32_t)p->u.array.count))
  10004                 goto slow_path;
  10005             set_value(ctx, p->u.array.u.var_refs[idx]->pvalue, val);
  10006             break;
  10007         case JS_CLASS_UINT8C_ARRAY:
  10008             if (JS_ToUint8ClampFree(ctx, &v, val))
  10009                 return -1;
  10010             /* Note: the conversion can detach the typed array, so the
  10011                array bound check must be done after */
  10012             if (unlikely(idx >= (uint32_t)p->u.array.count))
  10013                 goto ta_out_of_bound;
  10014             p->u.array.u.uint8_ptr[idx] = v;
  10015             break;
  10016         case JS_CLASS_INT8_ARRAY:
  10017         case JS_CLASS_UINT8_ARRAY:
  10018             if (JS_ToInt32Free(ctx, &v, val))
  10019                 return -1;
  10020             if (unlikely(idx >= (uint32_t)p->u.array.count))
  10021                 goto ta_out_of_bound;
  10022             p->u.array.u.uint8_ptr[idx] = v;
  10023             break;
  10024         case JS_CLASS_INT16_ARRAY:
  10025         case JS_CLASS_UINT16_ARRAY:
  10026             if (JS_ToInt32Free(ctx, &v, val))
  10027                 return -1;
  10028             if (unlikely(idx >= (uint32_t)p->u.array.count))
  10029                 goto ta_out_of_bound;
  10030             p->u.array.u.uint16_ptr[idx] = v;
  10031             break;
  10032         case JS_CLASS_INT32_ARRAY:
  10033         case JS_CLASS_UINT32_ARRAY:
  10034             if (JS_ToInt32Free(ctx, &v, val))
  10035                 return -1;
  10036             if (unlikely(idx >= (uint32_t)p->u.array.count))
  10037                 goto ta_out_of_bound;
  10038             p->u.array.u.uint32_ptr[idx] = v;
  10039             break;
  10040         case JS_CLASS_BIG_INT64_ARRAY:
  10041         case JS_CLASS_BIG_UINT64_ARRAY:
  10042             /* XXX: need specific conversion function */
  10043             {
  10044                 int64_t v;
  10045                 if (JS_ToBigInt64Free(ctx, &v, val))
  10046                     return -1;
  10047                 if (unlikely(idx >= (uint32_t)p->u.array.count))
  10048                     goto ta_out_of_bound;
  10049                 p->u.array.u.uint64_ptr[idx] = v;
  10050             }
  10051             break;
  10052         case JS_CLASS_FLOAT16_ARRAY:
  10053             if (JS_ToFloat64Free(ctx, &d, val))
  10054                 return -1;
  10055             if (unlikely(idx >= (uint32_t)p->u.array.count))
  10056                 goto ta_out_of_bound;
  10057             p->u.array.u.fp16_ptr[idx] = tofp16(d);
  10058             break;
  10059         case JS_CLASS_FLOAT32_ARRAY:
  10060             if (JS_ToFloat64Free(ctx, &d, val))
  10061                 return -1;
  10062             if (unlikely(idx >= (uint32_t)p->u.array.count))
  10063                 goto ta_out_of_bound;
  10064             p->u.array.u.float_ptr[idx] = d;
  10065             break;
  10066         case JS_CLASS_FLOAT64_ARRAY:
  10067             if (JS_ToFloat64Free(ctx, &d, val))
  10068                 return -1;
  10069             if (unlikely(idx >= (uint32_t)p->u.array.count)) {
  10070             ta_out_of_bound:
  10071                 return TRUE;
  10072             }
  10073             p->u.array.u.double_ptr[idx] = d;
  10074             break;
  10075         default:
  10076             goto slow_path;
  10077         }
  10078         return TRUE;
  10079     } else {
  10080         JSAtom atom;
  10081         int ret;
  10082     slow_path:
  10083         atom = JS_ValueToAtom(ctx, prop);
  10084         JS_FreeValue(ctx, prop);
  10085         if (unlikely(atom == JS_ATOM_NULL)) {
  10086             JS_FreeValue(ctx, val);
  10087             return -1;
  10088         }
  10089         ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, flags);
  10090         JS_FreeAtom(ctx, atom);
  10091         return ret;
  10092     }
  10093 }
  10094 
  10095 int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
  10096                          uint32_t idx, JSValue val)
  10097 {
  10098     return JS_SetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx), val,
  10099                                JS_PROP_THROW);
  10100 }
  10101 
  10102 int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj,
  10103                         int64_t idx, JSValue val)
  10104 {
  10105     JSAtom prop;
  10106     int res;
  10107 
  10108     if ((uint64_t)idx <= INT32_MAX) {
  10109         /* fast path for fast arrays */
  10110         return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val,
  10111                                    JS_PROP_THROW);
  10112     }
  10113     prop = JS_NewAtomInt64(ctx, idx);
  10114     if (prop == JS_ATOM_NULL) {
  10115         JS_FreeValue(ctx, val);
  10116         return -1;
  10117     }
  10118     res = JS_SetProperty(ctx, this_obj, prop, val);
  10119     JS_FreeAtom(ctx, prop);
  10120     return res;
  10121 }
  10122 
  10123 int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj,
  10124                       const char *prop, JSValue val)
  10125 {
  10126     JSAtom atom;
  10127     int ret;
  10128     atom = JS_NewAtom(ctx, prop);
  10129     if (atom == JS_ATOM_NULL) {
  10130         JS_FreeValue(ctx, val);
  10131         return -1;
  10132     }
  10133     ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, JS_PROP_THROW);
  10134     JS_FreeAtom(ctx, atom);
  10135     return ret;
  10136 }
  10137 
  10138 /* compute the property flags. For each flag: (JS_PROP_HAS_x forces
  10139    it, otherwise def_flags is used)
  10140    Note: makes assumption about the bit pattern of the flags
  10141 */
  10142 static int get_prop_flags(int flags, int def_flags)
  10143 {
  10144     int mask;
  10145     mask = (flags >> JS_PROP_HAS_SHIFT) & JS_PROP_C_W_E;
  10146     return (flags & mask) | (def_flags & ~mask);
  10147 }
  10148 
  10149 static int JS_CreateProperty(JSContext *ctx, JSObject *p,
  10150                              JSAtom prop, JSValueConst val,
  10151                              JSValueConst getter, JSValueConst setter,
  10152                              int flags)
  10153 {
  10154     JSProperty *pr;
  10155     int ret, prop_flags;
  10156     JSVarRef *var_ref;
  10157     JSObject *delete_obj;
  10158     
  10159     /* add a new property or modify an existing exotic one */
  10160     if (p->is_exotic) {
  10161         if (p->class_id == JS_CLASS_ARRAY) {
  10162             uint32_t idx, len;
  10163 
  10164             if (p->fast_array) {
  10165                 if (__JS_AtomIsTaggedInt(prop)) {
  10166                     idx = __JS_AtomToUInt32(prop);
  10167                     if (idx == p->u.array.count) {
  10168                         if (!p->extensible)
  10169                             goto not_extensible;
  10170                         if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET))
  10171                             goto convert_to_array;
  10172                         prop_flags = get_prop_flags(flags, 0);
  10173                         if (prop_flags != JS_PROP_C_W_E)
  10174                             goto convert_to_array;
  10175                         return add_fast_array_element(ctx, p,
  10176                                                       JS_DupValue(ctx, val), flags);
  10177                     } else {
  10178                         goto convert_to_array;
  10179                     }
  10180                 } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) {
  10181                     /* convert the fast array to normal array */
  10182                 convert_to_array:
  10183                     if (convert_fast_array_to_array(ctx, p))
  10184                         return -1;
  10185                     goto generic_array;
  10186                 }
  10187             } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) {
  10188                 JSProperty *plen;
  10189                 JSShapeProperty *pslen;
  10190             generic_array:
  10191                 /* update the length field */
  10192                 plen = &p->prop[0];
  10193                 JS_ToUint32(ctx, &len, plen->u.value);
  10194                 if ((idx + 1) > len) {
  10195                     pslen = get_shape_prop(p->shape);
  10196                     if (unlikely(!(pslen->flags & JS_PROP_WRITABLE)))
  10197                         return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
  10198                     /* XXX: should update the length after defining
  10199                        the property */
  10200                     len = idx + 1;
  10201                     set_value(ctx, &plen->u.value, JS_NewUint32(ctx, len));
  10202                 }
  10203             }
  10204         } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
  10205                    p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
  10206             ret = JS_AtomIsNumericIndex(ctx, prop);
  10207             if (ret != 0) {
  10208                 if (ret < 0)
  10209                     return -1;
  10210                 return JS_ThrowTypeErrorOrFalse(ctx, flags, "cannot create numeric index in typed array");
  10211             }
  10212         } else if (!(flags & JS_PROP_NO_EXOTIC)) {
  10213             const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
  10214             if (em) {
  10215                 if (em->define_own_property) {
  10216                     return em->define_own_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p),
  10217                                                    prop, val, getter, setter, flags);
  10218                 }
  10219                 ret = JS_IsExtensible(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
  10220                 if (ret < 0)
  10221                     return -1;
  10222                 if (!ret)
  10223                     goto not_extensible;
  10224             }
  10225         }
  10226     }
  10227 
  10228     if (!p->extensible) {
  10229     not_extensible:
  10230         return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible");
  10231     }
  10232 
  10233     var_ref = NULL;
  10234     delete_obj = NULL;
  10235     if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
  10236         prop_flags = (flags & (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) |
  10237             JS_PROP_GETSET;
  10238     } else {
  10239         prop_flags = flags & JS_PROP_C_W_E;
  10240         if (p->class_id == JS_CLASS_GLOBAL_OBJECT) {
  10241             JSObject *p1 = JS_VALUE_GET_OBJ(p->u.global_object.uninitialized_vars);
  10242             JSShapeProperty *prs1;
  10243             JSProperty *pr1;
  10244             prs1 = find_own_property(&pr1, p1, prop);
  10245             if (prs1) {
  10246                 delete_obj = p1;
  10247                 var_ref = pr1->u.var_ref;
  10248                 js_rc(var_ref)->ref_count++;
  10249             } else {
  10250                 var_ref = js_create_var_ref(ctx, FALSE);
  10251                 if (!var_ref)
  10252                     return -1;
  10253             }
  10254             var_ref->is_const = !(prop_flags & JS_PROP_WRITABLE);
  10255             prop_flags |= JS_PROP_VARREF;
  10256         }
  10257     }
  10258     pr = add_property(ctx, p, prop, prop_flags);
  10259     if (unlikely(!pr)) {
  10260         if (var_ref)
  10261             free_var_ref(ctx->rt, var_ref);
  10262         return -1;
  10263     }
  10264     if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
  10265         pr->u.getset.getter = NULL;
  10266         if ((flags & JS_PROP_HAS_GET) && JS_IsFunction(ctx, getter)) {
  10267             pr->u.getset.getter =
  10268                 JS_VALUE_GET_OBJ(JS_DupValue(ctx, getter));
  10269         }
  10270         pr->u.getset.setter = NULL;
  10271         if ((flags & JS_PROP_HAS_SET) && JS_IsFunction(ctx, setter)) {
  10272             pr->u.getset.setter =
  10273                 JS_VALUE_GET_OBJ(JS_DupValue(ctx, setter));
  10274         }
  10275     } else if (p->class_id == JS_CLASS_GLOBAL_OBJECT) {
  10276         if (delete_obj)
  10277             delete_property(ctx, delete_obj, prop);
  10278         pr->u.var_ref = var_ref;
  10279         if (flags & JS_PROP_HAS_VALUE) {
  10280             *var_ref->pvalue = JS_DupValue(ctx, val);
  10281         } else {
  10282             *var_ref->pvalue = JS_UNDEFINED;
  10283         }
  10284     } else {
  10285         if (flags & JS_PROP_HAS_VALUE) {
  10286             pr->u.value = JS_DupValue(ctx, val);
  10287         } else {
  10288             pr->u.value = JS_UNDEFINED;
  10289         }
  10290     }
  10291     return TRUE;
  10292 }
  10293 
  10294 /* return FALSE if not OK */
  10295 static BOOL check_define_prop_flags(int prop_flags, int flags)
  10296 {
  10297     BOOL has_accessor, is_getset;
  10298 
  10299     if (!(prop_flags & JS_PROP_CONFIGURABLE)) {
  10300         if ((flags & (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) ==
  10301             (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) {
  10302             return FALSE;
  10303         }
  10304         if ((flags & JS_PROP_HAS_ENUMERABLE) &&
  10305             (flags & JS_PROP_ENUMERABLE) != (prop_flags & JS_PROP_ENUMERABLE))
  10306             return FALSE;
  10307         if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE |
  10308                      JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
  10309             has_accessor = ((flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) != 0);
  10310             is_getset = ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET);
  10311             if (has_accessor != is_getset)
  10312                 return FALSE;
  10313             if (!is_getset && !(prop_flags & JS_PROP_WRITABLE)) {
  10314                 /* not writable: cannot set the writable bit */
  10315                 if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
  10316                     (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE))
  10317                     return FALSE;
  10318             }
  10319         }
  10320     }
  10321     return TRUE;
  10322 }
  10323 
  10324 /* ensure that the shape can be safely modified */
  10325 static int js_shape_prepare_update(JSContext *ctx, JSObject *p,
  10326                                    JSShapeProperty **pprs)
  10327 {
  10328     JSShape *sh;
  10329     uint32_t idx = 0;    /* prevent warning */
  10330 
  10331     sh = p->shape;
  10332     if (sh->is_hashed) {
  10333         if (js_rc(sh)->ref_count != 1) {
  10334             if (pprs)
  10335                 idx = *pprs - get_shape_prop(sh);
  10336             /* clone the shape (the resulting one is no longer hashed) */
  10337             sh = js_clone_shape(ctx, sh);
  10338             if (!sh)
  10339                 return -1;
  10340             js_free_shape(ctx->rt, p->shape);
  10341             p->shape = sh;
  10342             if (pprs)
  10343                 *pprs = get_shape_prop(sh) + idx;
  10344         } else {
  10345             js_shape_hash_unlink(ctx->rt, sh);
  10346             sh->is_hashed = FALSE;
  10347         }
  10348     }
  10349     return 0;
  10350 }
  10351 
  10352 static int js_update_property_flags(JSContext *ctx, JSObject *p,
  10353                                     JSShapeProperty **pprs, int flags)
  10354 {
  10355     if (flags != (*pprs)->flags) {
  10356         if (js_shape_prepare_update(ctx, p, pprs))
  10357             return -1;
  10358         (*pprs)->flags = flags;
  10359     }
  10360     return 0;
  10361 }
  10362 
  10363 /* allowed flags:
  10364    JS_PROP_CONFIGURABLE, JS_PROP_WRITABLE, JS_PROP_ENUMERABLE
  10365    JS_PROP_HAS_GET, JS_PROP_HAS_SET, JS_PROP_HAS_VALUE,
  10366    JS_PROP_HAS_CONFIGURABLE, JS_PROP_HAS_WRITABLE, JS_PROP_HAS_ENUMERABLE,
  10367    JS_PROP_THROW, JS_PROP_NO_EXOTIC.
  10368    If JS_PROP_THROW is set, return an exception instead of FALSE.
  10369    if JS_PROP_NO_EXOTIC is set, do not call the exotic
  10370    define_own_property callback.
  10371    return -1 (exception), FALSE or TRUE.
  10372 */
  10373 int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
  10374                       JSAtom prop, JSValueConst val,
  10375                       JSValueConst getter, JSValueConst setter, int flags)
  10376 {
  10377     JSObject *p;
  10378     JSShapeProperty *prs;
  10379     JSProperty *pr;
  10380     int mask, res;
  10381 
  10382     if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT) {
  10383         JS_ThrowTypeErrorNotAnObject(ctx);
  10384         return -1;
  10385     }
  10386     p = JS_VALUE_GET_OBJ(this_obj);
  10387 
  10388  redo_prop_update:
  10389     prs = find_own_property(&pr, p, prop);
  10390     if (prs) {
  10391         /* the range of the Array length property is always tested before */
  10392         if ((prs->flags & JS_PROP_LENGTH) && (flags & JS_PROP_HAS_VALUE)) {
  10393             uint32_t array_length;
  10394             if (JS_ToArrayLengthFree(ctx, &array_length,
  10395                                      JS_DupValue(ctx, val), FALSE)) {
  10396                 return -1;
  10397             }
  10398             /* this code relies on the fact that Uint32 are never allocated */
  10399             val = (JSValueConst)JS_NewUint32(ctx, array_length);
  10400             /* prs may have been modified */
  10401             prs = find_own_property(&pr, p, prop);
  10402             assert(prs != NULL);
  10403         }
  10404         /* property already exists */
  10405         if (!check_define_prop_flags(prs->flags, flags)) {
  10406         not_configurable:
  10407             return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
  10408         }
  10409 
  10410         if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
  10411             /* Instantiate property and retry */
  10412             if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
  10413                 return -1;
  10414             goto redo_prop_update;
  10415         }
  10416 
  10417         if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE |
  10418                      JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
  10419             if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
  10420                 JSObject *new_getter, *new_setter;
  10421 
  10422                 if (JS_IsFunction(ctx, getter)) {
  10423                     new_getter = JS_VALUE_GET_OBJ(getter);
  10424                 } else {
  10425                     new_getter = NULL;
  10426                 }
  10427                 if (JS_IsFunction(ctx, setter)) {
  10428                     new_setter = JS_VALUE_GET_OBJ(setter);
  10429                 } else {
  10430                     new_setter = NULL;
  10431                 }
  10432 
  10433                 if ((prs->flags & JS_PROP_TMASK) != JS_PROP_GETSET) {
  10434                     if (js_shape_prepare_update(ctx, p, &prs))
  10435                         return -1;
  10436                     /* convert to getset */
  10437                     if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
  10438                         if (unlikely(p->class_id == JS_CLASS_GLOBAL_OBJECT)) {
  10439                             if (remove_global_object_property(ctx, p, prs, pr))
  10440                                 return -1;
  10441                         }
  10442                         free_var_ref(ctx->rt, pr->u.var_ref);
  10443                     } else {
  10444                         JS_FreeValue(ctx, pr->u.value);
  10445                     }
  10446                     prs->flags = (prs->flags &
  10447                                   (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) |
  10448                         JS_PROP_GETSET;
  10449                     pr->u.getset.getter = NULL;
  10450                     pr->u.getset.setter = NULL;
  10451                 } else {
  10452                     if (!(prs->flags & JS_PROP_CONFIGURABLE)) {
  10453                         if ((flags & JS_PROP_HAS_GET) &&
  10454                             new_getter != pr->u.getset.getter) {
  10455                             goto not_configurable;
  10456                         }
  10457                         if ((flags & JS_PROP_HAS_SET) &&
  10458                             new_setter != pr->u.getset.setter) {
  10459                             goto not_configurable;
  10460                         }
  10461                     }
  10462                 }
  10463                 if (flags & JS_PROP_HAS_GET) {
  10464                     if (pr->u.getset.getter)
  10465                         JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
  10466                     if (new_getter)
  10467                         JS_DupValue(ctx, getter);
  10468                     pr->u.getset.getter = new_getter;
  10469                 }
  10470                 if (flags & JS_PROP_HAS_SET) {
  10471                     if (pr->u.getset.setter)
  10472                         JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
  10473                     if (new_setter)
  10474                         JS_DupValue(ctx, setter);
  10475                     pr->u.getset.setter = new_setter;
  10476                 }
  10477             } else {
  10478                 if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
  10479                     /* convert to data descriptor */
  10480                     JSVarRef *var_ref;
  10481                     if (unlikely(p->class_id == JS_CLASS_GLOBAL_OBJECT)) {
  10482                         var_ref = js_global_object_find_uninitialized_var(ctx, p, prop, FALSE);
  10483                         if (!var_ref)
  10484                             return -1;
  10485                     } else {
  10486                         var_ref = NULL;
  10487                     }
  10488                     if (js_shape_prepare_update(ctx, p, &prs)) {
  10489                         if (var_ref)
  10490                             free_var_ref(ctx->rt, var_ref);
  10491                         return -1;
  10492                     }
  10493                     if (pr->u.getset.getter)
  10494                         JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
  10495                     if (pr->u.getset.setter)
  10496                         JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
  10497                     if (var_ref) {
  10498                         prs->flags = (prs->flags & ~JS_PROP_TMASK) |
  10499                             JS_PROP_VARREF | JS_PROP_WRITABLE;
  10500                         pr->u.var_ref = var_ref;
  10501                     } else {
  10502                         prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
  10503                         pr->u.value = JS_UNDEFINED;
  10504                     }
  10505                 } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
  10506                     /* Note: JS_PROP_VARREF is always writable */
  10507                 } else {
  10508                     if ((prs->flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 &&
  10509                         (flags & JS_PROP_HAS_VALUE)) {
  10510                         if (!js_same_value(ctx, val, pr->u.value)) {
  10511                             goto not_configurable;
  10512                         } else {
  10513                             return TRUE;
  10514                         }
  10515                     }
  10516                 }
  10517                 if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
  10518                     if (flags & JS_PROP_HAS_VALUE) {
  10519                         if (p->class_id == JS_CLASS_MODULE_NS) {
  10520                             /* JS_PROP_WRITABLE is always true for variable
  10521                                references, but they are write protected in module name
  10522                                spaces. */
  10523                             if (!js_same_value(ctx, val, *pr->u.var_ref->pvalue))
  10524                                 goto not_configurable;
  10525                         } else {
  10526                             /* update the reference */
  10527                             set_value(ctx, pr->u.var_ref->pvalue,
  10528                                       JS_DupValue(ctx, val));
  10529                         }
  10530                     }
  10531                     if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) {
  10532                         JSValue val1;
  10533                         if (p->class_id == JS_CLASS_MODULE_NS) {
  10534                             return JS_ThrowTypeErrorOrFalse(ctx, flags, "module namespace properties have writable = false");
  10535                         }
  10536                         if (js_shape_prepare_update(ctx, p, &prs))
  10537                             return -1;
  10538                         if (p->class_id == JS_CLASS_GLOBAL_OBJECT) {
  10539                             pr->u.var_ref->is_const = TRUE; /* mark as read-only */
  10540                             prs->flags &= ~JS_PROP_WRITABLE;
  10541                         } else {
  10542                             /* if writable is set to false, no longer a
  10543                                reference (for mapped arguments) */
  10544                             val1 = JS_DupValue(ctx, *pr->u.var_ref->pvalue);
  10545                             free_var_ref(ctx->rt, pr->u.var_ref);
  10546                             pr->u.value = val1;
  10547                             prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
  10548                         }
  10549                     }
  10550                 } else if (prs->flags & JS_PROP_LENGTH) {
  10551                     if (flags & JS_PROP_HAS_VALUE) {
  10552                         /* Note: no JS code is executable because
  10553                            'val' is guaranted to be a Uint32 */
  10554                         res = set_array_length(ctx, p, JS_DupValue(ctx, val),
  10555                                                flags);
  10556                     } else {
  10557                         res = TRUE;
  10558                     }
  10559                     /* still need to reset the writable flag if
  10560                        needed.  The JS_PROP_LENGTH is kept because the
  10561                        Uint32 test is still done if the length
  10562                        property is read-only. */
  10563                     if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
  10564                         JS_PROP_HAS_WRITABLE) {
  10565                         prs = get_shape_prop(p->shape);
  10566                         if (js_update_property_flags(ctx, p, &prs,
  10567                                                      prs->flags & ~JS_PROP_WRITABLE))
  10568                             return -1;
  10569                     }
  10570                     return res;
  10571                 } else {
  10572                     if (flags & JS_PROP_HAS_VALUE) {
  10573                         JS_FreeValue(ctx, pr->u.value);
  10574                         pr->u.value = JS_DupValue(ctx, val);
  10575                     }
  10576                     if (flags & JS_PROP_HAS_WRITABLE) {
  10577                         if (js_update_property_flags(ctx, p, &prs,
  10578                                                      (prs->flags & ~JS_PROP_WRITABLE) |
  10579                                                      (flags & JS_PROP_WRITABLE)))
  10580                             return -1;
  10581                     }
  10582                 }
  10583             }
  10584         }
  10585         mask = 0;
  10586         if (flags & JS_PROP_HAS_CONFIGURABLE)
  10587             mask |= JS_PROP_CONFIGURABLE;
  10588         if (flags & JS_PROP_HAS_ENUMERABLE)
  10589             mask |= JS_PROP_ENUMERABLE;
  10590         if (js_update_property_flags(ctx, p, &prs,
  10591                                      (prs->flags & ~mask) | (flags & mask)))
  10592             return -1;
  10593         return TRUE;
  10594     }
  10595 
  10596     /* handle modification of fast array elements */
  10597     if (p->fast_array) {
  10598         uint32_t idx;
  10599         uint32_t prop_flags;
  10600         if (p->class_id == JS_CLASS_ARRAY) {
  10601             if (__JS_AtomIsTaggedInt(prop)) {
  10602                 idx = __JS_AtomToUInt32(prop);
  10603                 if (idx < p->u.array.count) {
  10604                     prop_flags = get_prop_flags(flags, JS_PROP_C_W_E);
  10605                     if (prop_flags != JS_PROP_C_W_E)
  10606                         goto convert_to_slow_array;
  10607                     if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
  10608                     convert_to_slow_array:
  10609                         if (convert_fast_array_to_array(ctx, p))
  10610                             return -1;
  10611                         else
  10612                             goto redo_prop_update;
  10613                     }
  10614                     if (flags & JS_PROP_HAS_VALUE) {
  10615                         set_value(ctx, &p->u.array.u.values[idx], JS_DupValue(ctx, val));
  10616                     }
  10617                     return TRUE;
  10618                 }
  10619             }
  10620         } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
  10621                    p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
  10622             JSValue num;
  10623             int ret;
  10624 
  10625             if (!__JS_AtomIsTaggedInt(prop)) {
  10626                 /* slow path with to handle all numeric indexes */
  10627                 num = JS_AtomIsNumericIndex1(ctx, prop);
  10628                 if (JS_IsUndefined(num))
  10629                     goto typed_array_done;
  10630                 if (JS_IsException(num))
  10631                     return -1;
  10632                 ret = JS_NumberIsInteger(ctx, num);
  10633                 if (ret < 0) {
  10634                     JS_FreeValue(ctx, num);
  10635                     return -1;
  10636                 }
  10637                 if (!ret) {
  10638                     JS_FreeValue(ctx, num);
  10639                     return JS_ThrowTypeErrorOrFalse(ctx, flags, "non integer index in typed array");
  10640                 }
  10641                 ret = JS_NumberIsNegativeOrMinusZero(ctx, num);
  10642                 JS_FreeValue(ctx, num);
  10643                 if (ret) {
  10644                     return JS_ThrowTypeErrorOrFalse(ctx, flags, "negative index in typed array");
  10645                 }
  10646                 if (!__JS_AtomIsTaggedInt(prop))
  10647                     goto typed_array_oob;
  10648             }
  10649             idx = __JS_AtomToUInt32(prop);
  10650             /* if the typed array is detached, p->u.array.count = 0 */
  10651             if (idx >= p->u.array.count) {
  10652             typed_array_oob:
  10653                 return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound index in typed array");
  10654             }
  10655             prop_flags = get_prop_flags(flags, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
  10656             if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET) ||
  10657                 prop_flags != (JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE)) {
  10658                 return JS_ThrowTypeErrorOrFalse(ctx, flags, "invalid descriptor flags");
  10659             }
  10660             if (flags & JS_PROP_HAS_VALUE) {
  10661                 return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), JS_DupValue(ctx, val), flags);
  10662             }
  10663             return TRUE;
  10664         typed_array_done: ;
  10665         }
  10666     }
  10667 
  10668     return JS_CreateProperty(ctx, p, prop, val, getter, setter, flags);
  10669 }
  10670 
  10671 static int JS_DefineAutoInitProperty(JSContext *ctx, JSValueConst this_obj,
  10672                                      JSAtom prop, JSAutoInitIDEnum id,
  10673                                      void *opaque, int flags)
  10674 {
  10675     JSObject *p;
  10676     JSProperty *pr;
  10677 
  10678     if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT)
  10679         return FALSE;
  10680 
  10681     p = JS_VALUE_GET_OBJ(this_obj);
  10682 
  10683     if (find_own_property(&pr, p, prop)) {
  10684         /* property already exists */
  10685         abort();
  10686         return FALSE;
  10687     }
  10688 
  10689     /* Specialized CreateProperty */
  10690     pr = add_property(ctx, p, prop, (flags & JS_PROP_C_W_E) | JS_PROP_AUTOINIT);
  10691     if (unlikely(!pr))
  10692         return -1;
  10693     pr->u.init.realm_and_id = (uintptr_t)JS_DupContext(ctx);
  10694     assert((pr->u.init.realm_and_id & 3) == 0);
  10695     assert(id <= 3);
  10696     pr->u.init.realm_and_id |= id;
  10697     pr->u.init.opaque = opaque;
  10698     return TRUE;
  10699 }
  10700 
  10701 /* shortcut to add or redefine a new property value */
  10702 int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj,
  10703                            JSAtom prop, JSValue val, int flags)
  10704 {
  10705     int ret;
  10706     ret = JS_DefineProperty(ctx, this_obj, prop, val, JS_UNDEFINED, JS_UNDEFINED,
  10707                             flags | JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE);
  10708     JS_FreeValue(ctx, val);
  10709     return ret;
  10710 }
  10711 
  10712 int JS_DefinePropertyValueValue(JSContext *ctx, JSValueConst this_obj,
  10713                                 JSValue prop, JSValue val, int flags)
  10714 {
  10715     JSAtom atom;
  10716     int ret;
  10717     atom = JS_ValueToAtom(ctx, prop);
  10718     JS_FreeValue(ctx, prop);
  10719     if (unlikely(atom == JS_ATOM_NULL)) {
  10720         JS_FreeValue(ctx, val);
  10721         return -1;
  10722     }
  10723     ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
  10724     JS_FreeAtom(ctx, atom);
  10725     return ret;
  10726 }
  10727 
  10728 int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj,
  10729                                  uint32_t idx, JSValue val, int flags)
  10730 {
  10731     return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewUint32(ctx, idx),
  10732                                        val, flags);
  10733 }
  10734 
  10735 int JS_DefinePropertyValueInt64(JSContext *ctx, JSValueConst this_obj,
  10736                                 int64_t idx, JSValue val, int flags)
  10737 {
  10738     return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx),
  10739                                        val, flags);
  10740 }
  10741 
  10742 int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj,
  10743                               const char *prop, JSValue val, int flags)
  10744 {
  10745     JSAtom atom;
  10746     int ret;
  10747     atom = JS_NewAtom(ctx, prop);
  10748     if (atom == JS_ATOM_NULL) {
  10749         JS_FreeValue(ctx, val);
  10750         return -1;
  10751     }
  10752     ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
  10753     JS_FreeAtom(ctx, atom);
  10754     return ret;
  10755 }
  10756 
  10757 /* shortcut to add getter & setter */
  10758 int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj,
  10759                             JSAtom prop, JSValue getter, JSValue setter,
  10760                             int flags)
  10761 {
  10762     int ret;
  10763     ret = JS_DefineProperty(ctx, this_obj, prop, JS_UNDEFINED, getter, setter,
  10764                             flags | JS_PROP_HAS_GET | JS_PROP_HAS_SET |
  10765                             JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE);
  10766     JS_FreeValue(ctx, getter);
  10767     JS_FreeValue(ctx, setter);
  10768     return ret;
  10769 }
  10770 
  10771 static int JS_CreateDataPropertyUint32(JSContext *ctx, JSValueConst this_obj,
  10772                                        int64_t idx, JSValue val, int flags)
  10773 {
  10774     return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx),
  10775                                        val, flags | JS_PROP_CONFIGURABLE |
  10776                                        JS_PROP_ENUMERABLE | JS_PROP_WRITABLE);
  10777 }
  10778 
  10779 
  10780 /* return TRUE if 'obj' has a non empty 'name' string */
  10781 static BOOL js_object_has_name(JSContext *ctx, JSValueConst obj)
  10782 {
  10783     JSProperty *pr;
  10784     JSShapeProperty *prs;
  10785     JSValueConst val;
  10786     JSString *p;
  10787 
  10788     prs = find_own_property(&pr, JS_VALUE_GET_OBJ(obj), JS_ATOM_name);
  10789     if (!prs)
  10790         return FALSE;
  10791     if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
  10792         return TRUE;
  10793     val = pr->u.value;
  10794     if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
  10795         return TRUE;
  10796     p = JS_VALUE_GET_STRING(val);
  10797     return (p->len != 0);
  10798 }
  10799 
  10800 static int JS_DefineObjectName(JSContext *ctx, JSValueConst obj,
  10801                                JSAtom name, int flags)
  10802 {
  10803     if (name != JS_ATOM_NULL
  10804     &&  JS_IsObject(obj)
  10805     &&  !js_object_has_name(ctx, obj)
  10806     &&  JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, JS_AtomToString(ctx, name), flags) < 0) {
  10807         return -1;
  10808     }
  10809     return 0;
  10810 }
  10811 
  10812 static int JS_DefineObjectNameComputed(JSContext *ctx, JSValueConst obj,
  10813                                        JSValueConst str, int flags)
  10814 {
  10815     if (JS_IsObject(obj) &&
  10816         !js_object_has_name(ctx, obj)) {
  10817         JSAtom prop;
  10818         JSValue name_str;
  10819         prop = JS_ValueToAtom(ctx, str);
  10820         if (prop == JS_ATOM_NULL)
  10821             return -1;
  10822         name_str = js_get_function_name(ctx, prop);
  10823         JS_FreeAtom(ctx, prop);
  10824         if (JS_IsException(name_str))
  10825             return -1;
  10826         if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, name_str, flags) < 0)
  10827             return -1;
  10828     }
  10829     return 0;
  10830 }
  10831 
  10832 #define DEFINE_GLOBAL_LEX_VAR (1 << 7)
  10833 #define DEFINE_GLOBAL_FUNC_VAR (1 << 6)
  10834 
  10835 static JSValue JS_ThrowSyntaxErrorVarRedeclaration(JSContext *ctx, JSAtom prop)
  10836 {
  10837     return JS_ThrowSyntaxErrorAtom(ctx, "redeclaration of '%s'", prop);
  10838 }
  10839 
  10840 /* flags is 0, DEFINE_GLOBAL_LEX_VAR or DEFINE_GLOBAL_FUNC_VAR */
  10841 /* XXX: could support exotic global object. */
  10842 static int JS_CheckDefineGlobalVar(JSContext *ctx, JSAtom prop, int flags)
  10843 {
  10844     JSObject *p;
  10845     JSShapeProperty *prs;
  10846 
  10847     p = JS_VALUE_GET_OBJ(ctx->global_obj);
  10848     prs = find_own_property1(p, prop);
  10849     /* XXX: should handle JS_PROP_AUTOINIT */
  10850     if (flags & DEFINE_GLOBAL_LEX_VAR) {
  10851         if (prs && !(prs->flags & JS_PROP_CONFIGURABLE))
  10852             goto fail_redeclaration;
  10853     } else {
  10854         if (!prs && !p->extensible)
  10855             goto define_error;
  10856         if (flags & DEFINE_GLOBAL_FUNC_VAR) {
  10857             if (prs) {
  10858                 if (!(prs->flags & JS_PROP_CONFIGURABLE) &&
  10859                     ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET ||
  10860                      ((prs->flags & (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)) !=
  10861                       (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)))) {
  10862                 define_error:
  10863                     JS_ThrowTypeErrorAtom(ctx, "cannot define variable '%s'",
  10864                                           prop);
  10865                     return -1;
  10866                 }
  10867             }
  10868         }
  10869     }
  10870     /* check if there already is a lexical declaration */
  10871     p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
  10872     prs = find_own_property1(p, prop);
  10873     if (prs) {
  10874     fail_redeclaration:
  10875         JS_ThrowSyntaxErrorVarRedeclaration(ctx, prop);
  10876         return -1;
  10877     }
  10878     return 0;
  10879 }
  10880 
  10881 /* construct a reference to a global variable */
  10882 static int JS_GetGlobalVarRef(JSContext *ctx, JSAtom prop, JSValue *sp)
  10883 {
  10884     JSObject *p;
  10885     JSShapeProperty *prs;
  10886     JSProperty *pr;
  10887 
  10888     /* no exotic behavior is possible in global_var_obj */
  10889     p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
  10890     prs = find_own_property(&pr, p, prop);
  10891     if (prs) {
  10892         /* XXX: conformance: do these tests in
  10893            OP_put_var_ref/OP_get_var_ref ? */
  10894         if (unlikely(JS_IsUninitialized(*pr->u.var_ref->pvalue))) {
  10895             JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
  10896             return -1;
  10897         }
  10898         if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) {
  10899             return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop);
  10900         }
  10901         sp[0] = JS_DupValue(ctx, ctx->global_var_obj);
  10902     } else {
  10903         int ret;
  10904         ret = JS_HasProperty(ctx, ctx->global_obj, prop);
  10905         if (ret < 0)
  10906             return -1;
  10907         if (ret) {
  10908             sp[0] = JS_DupValue(ctx, ctx->global_obj);
  10909         } else {
  10910             sp[0] = JS_UNDEFINED;
  10911         }
  10912     }
  10913     sp[1] = JS_AtomToValue(ctx, prop);
  10914     return 0;
  10915 }
  10916 
  10917 /* return -1, FALSE or TRUE */
  10918 static int JS_DeleteGlobalVar(JSContext *ctx, JSAtom prop)
  10919 {
  10920     JSObject *p;
  10921     JSShapeProperty *prs;
  10922     JSProperty *pr;
  10923     int ret;
  10924 
  10925     /* 9.1.1.4.7 DeleteBinding ( N ) */
  10926     p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
  10927     prs = find_own_property(&pr, p, prop);
  10928     if (prs)
  10929         return FALSE; /* lexical variables cannot be deleted */
  10930     ret = JS_HasProperty(ctx, ctx->global_obj, prop);
  10931     if (ret < 0)
  10932         return -1;
  10933     if (ret) {
  10934         return JS_DeleteProperty(ctx, ctx->global_obj, prop, 0);
  10935     } else {
  10936         return TRUE;
  10937     }
  10938 }
  10939 
  10940 /* return -1, FALSE or TRUE. return FALSE if not configurable or
  10941    invalid object. return -1 in case of exception.
  10942    flags can be 0, JS_PROP_THROW or JS_PROP_THROW_STRICT */
  10943 int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags)
  10944 {
  10945     JSValue obj1;
  10946     JSObject *p;
  10947     int res;
  10948 
  10949     obj1 = JS_ToObject(ctx, obj);
  10950     if (JS_IsException(obj1))
  10951         return -1;
  10952     p = JS_VALUE_GET_OBJ(obj1);
  10953     res = delete_property(ctx, p, prop);
  10954     JS_FreeValue(ctx, obj1);
  10955     if (res != FALSE)
  10956         return res;
  10957     if ((flags & JS_PROP_THROW) ||
  10958         ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
  10959         JS_ThrowTypeError(ctx, "could not delete property");
  10960         return -1;
  10961     }
  10962     return FALSE;
  10963 }
  10964 
  10965 int JS_DeletePropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, int flags)
  10966 {
  10967     JSAtom prop;
  10968     int res;
  10969 
  10970     if ((uint64_t)idx <= JS_ATOM_MAX_INT) {
  10971         /* fast path for fast arrays */
  10972         return JS_DeleteProperty(ctx, obj, __JS_AtomFromUInt32(idx), flags);
  10973     }
  10974     prop = JS_NewAtomInt64(ctx, idx);
  10975     if (prop == JS_ATOM_NULL)
  10976         return -1;
  10977     res = JS_DeleteProperty(ctx, obj, prop, flags);
  10978     JS_FreeAtom(ctx, prop);
  10979     return res;
  10980 }
  10981 
  10982 BOOL JS_IsFunction(JSContext *ctx, JSValueConst val)
  10983 {
  10984     JSObject *p;
  10985     if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
  10986         return FALSE;
  10987     p = JS_VALUE_GET_OBJ(val);
  10988     switch(p->class_id) {
  10989     case JS_CLASS_BYTECODE_FUNCTION:
  10990         return TRUE;
  10991     case JS_CLASS_PROXY:
  10992         return p->u.proxy_data->is_func;
  10993     default:
  10994         return (ctx->rt->class_array[p->class_id].call != NULL);
  10995     }
  10996 }
  10997 
  10998 BOOL JS_IsCFunction(JSContext *ctx, JSValueConst val, JSCFunction *func, int magic)
  10999 {
  11000     JSObject *p;
  11001     if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
  11002         return FALSE;
  11003     p = JS_VALUE_GET_OBJ(val);
  11004     if (p->class_id == JS_CLASS_C_FUNCTION)
  11005         return (p->u.cfunc.c_function.generic == func && p->u.cfunc.magic == magic);
  11006     else
  11007         return FALSE;
  11008 }
  11009 
  11010 BOOL JS_IsConstructor(JSContext *ctx, JSValueConst val)
  11011 {
  11012     JSObject *p;
  11013     if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
  11014         return FALSE;
  11015     p = JS_VALUE_GET_OBJ(val);
  11016     return p->is_constructor;
  11017 }
  11018 
  11019 BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, BOOL val)
  11020 {
  11021     JSObject *p;
  11022     if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
  11023         return FALSE;
  11024     p = JS_VALUE_GET_OBJ(func_obj);
  11025     p->is_constructor = val;
  11026     return TRUE;
  11027 }
  11028 
  11029 BOOL JS_IsError(JSContext *ctx, JSValueConst val)
  11030 {
  11031     JSObject *p;
  11032     if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
  11033         return FALSE;
  11034     p = JS_VALUE_GET_OBJ(val);
  11035     return (p->class_id == JS_CLASS_ERROR);
  11036 }
  11037 
  11038 /* must be called after JS_Throw() */
  11039 void JS_SetUncatchableException(JSContext *ctx, BOOL flag)
  11040 {
  11041     ctx->rt->current_exception_is_uncatchable = flag;
  11042 }
  11043 
  11044 void JS_SetOpaque(JSValue obj, void *opaque)
  11045 {
  11046    JSObject *p;
  11047     if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
  11048         p = JS_VALUE_GET_OBJ(obj);
  11049         p->u.opaque = opaque;
  11050     }
  11051 }
  11052 
  11053 /* return NULL if not an object of class class_id */
  11054 void *JS_GetOpaque(JSValueConst obj, JSClassID class_id)
  11055 {
  11056     JSObject *p;
  11057     if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
  11058         return NULL;
  11059     p = JS_VALUE_GET_OBJ(obj);
  11060     if (p->class_id != class_id)
  11061         return NULL;
  11062     return p->u.opaque;
  11063 }
  11064 
  11065 void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id)
  11066 {
  11067     void *p = JS_GetOpaque(obj, class_id);
  11068     if (unlikely(!p)) {
  11069         JS_ThrowTypeErrorInvalidClass(ctx, class_id);
  11070     }
  11071     return p;
  11072 }
  11073 
  11074 void *JS_GetAnyOpaque(JSValueConst obj, JSClassID *class_id)
  11075 {
  11076     JSObject *p;
  11077     if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
  11078         *class_id = 0;
  11079         return NULL;
  11080     }
  11081     p = JS_VALUE_GET_OBJ(obj);
  11082     *class_id = p->class_id;
  11083     return p->u.opaque;
  11084 }
  11085 
  11086 static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint)
  11087 {
  11088     int i;
  11089     BOOL force_ordinary;
  11090 
  11091     JSAtom method_name;
  11092     JSValue method, ret;
  11093     if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
  11094         return val;
  11095     force_ordinary = hint & HINT_FORCE_ORDINARY;
  11096     hint &= ~HINT_FORCE_ORDINARY;
  11097     if (!force_ordinary) {
  11098         method = JS_GetProperty(ctx, val, JS_ATOM_Symbol_toPrimitive);
  11099         if (JS_IsException(method))
  11100             goto exception;
  11101         /* ECMA says *If exoticToPrim is not undefined* but tests in
  11102            test262 use null as a non callable converter */
  11103         if (!JS_IsUndefined(method) && !JS_IsNull(method)) {
  11104             JSAtom atom;
  11105             JSValue arg;
  11106             switch(hint) {
  11107             case HINT_STRING:
  11108                 atom = JS_ATOM_string;
  11109                 break;
  11110             case HINT_NUMBER:
  11111                 atom = JS_ATOM_number;
  11112                 break;
  11113             default:
  11114             case HINT_NONE:
  11115                 atom = JS_ATOM_default;
  11116                 break;
  11117             }
  11118             arg = JS_AtomToString(ctx, atom);
  11119             ret = JS_CallFree(ctx, method, val, 1, (JSValueConst *)&arg);
  11120             JS_FreeValue(ctx, arg);
  11121             if (JS_IsException(ret))
  11122                 goto exception;
  11123             JS_FreeValue(ctx, val);
  11124             if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT)
  11125                 return ret;
  11126             JS_FreeValue(ctx, ret);
  11127             return JS_ThrowTypeError(ctx, "toPrimitive");
  11128         }
  11129     }
  11130     if (hint != HINT_STRING)
  11131         hint = HINT_NUMBER;
  11132     for(i = 0; i < 2; i++) {
  11133         if ((i ^ hint) == 0) {
  11134             method_name = JS_ATOM_toString;
  11135         } else {
  11136             method_name = JS_ATOM_valueOf;
  11137         }
  11138         method = JS_GetProperty(ctx, val, method_name);
  11139         if (JS_IsException(method))
  11140             goto exception;
  11141         if (JS_IsFunction(ctx, method)) {
  11142             ret = JS_CallFree(ctx, method, val, 0, NULL);
  11143             if (JS_IsException(ret))
  11144                 goto exception;
  11145             if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
  11146                 JS_FreeValue(ctx, val);
  11147                 return ret;
  11148             }
  11149             JS_FreeValue(ctx, ret);
  11150         } else {
  11151             JS_FreeValue(ctx, method);
  11152         }
  11153     }
  11154     JS_ThrowTypeError(ctx, "toPrimitive");
  11155 exception:
  11156     JS_FreeValue(ctx, val);
  11157     return JS_EXCEPTION;
  11158 }
  11159 
  11160 static JSValue JS_ToPrimitive(JSContext *ctx, JSValueConst val, int hint)
  11161 {
  11162     return JS_ToPrimitiveFree(ctx, JS_DupValue(ctx, val), hint);
  11163 }
  11164 
  11165 void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj)
  11166 {
  11167     JSObject *p;
  11168     if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
  11169         return;
  11170     p = JS_VALUE_GET_OBJ(obj);
  11171     p->is_HTMLDDA = TRUE;
  11172 }
  11173 
  11174 static inline BOOL JS_IsHTMLDDA(JSContext *ctx, JSValueConst obj)
  11175 {
  11176     JSObject *p;
  11177     if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
  11178         return FALSE;
  11179     p = JS_VALUE_GET_OBJ(obj);
  11180     return p->is_HTMLDDA;
  11181 }
  11182 
  11183 static int JS_ToBoolFree(JSContext *ctx, JSValue val)
  11184 {
  11185     uint32_t tag = JS_VALUE_GET_TAG(val);
  11186     switch(tag) {
  11187     case JS_TAG_INT:
  11188         return JS_VALUE_GET_INT(val) != 0;
  11189     case JS_TAG_BOOL:
  11190     case JS_TAG_NULL:
  11191     case JS_TAG_UNDEFINED:
  11192         return JS_VALUE_GET_INT(val);
  11193     case JS_TAG_EXCEPTION:
  11194         return -1;
  11195     case JS_TAG_STRING:
  11196         {
  11197             BOOL ret = JS_VALUE_GET_STRING(val)->len != 0;
  11198             JS_FreeValue(ctx, val);
  11199             return ret;
  11200         }
  11201     case JS_TAG_STRING_ROPE:
  11202         {
  11203             BOOL ret = JS_VALUE_GET_STRING_ROPE(val)->len != 0;
  11204             JS_FreeValue(ctx, val);
  11205             return ret;
  11206         }
  11207     case JS_TAG_SHORT_BIG_INT:
  11208         return JS_VALUE_GET_SHORT_BIG_INT(val) != 0;
  11209     case JS_TAG_BIG_INT:
  11210         {
  11211             JSBigInt *p = JS_VALUE_GET_PTR(val);
  11212             BOOL ret;
  11213             int i;
  11214             
  11215             /* fail safe: we assume it is not necessarily
  11216                normalized. Beginning from the MSB ensures that the
  11217                test is fast. */
  11218             ret = FALSE;
  11219             for(i = p->len - 1; i >= 0; i--) {
  11220                 if (p->tab[i] != 0) {
  11221                     ret = TRUE;
  11222                     break;
  11223                 }
  11224             }
  11225             JS_FreeValue(ctx, val);
  11226             return ret;
  11227         }
  11228     case JS_TAG_OBJECT:
  11229         {
  11230             JSObject *p = JS_VALUE_GET_OBJ(val);
  11231             BOOL ret;
  11232             ret = !p->is_HTMLDDA;
  11233             JS_FreeValue(ctx, val);
  11234             return ret;
  11235         }
  11236         break;
  11237     default:
  11238         if (JS_TAG_IS_FLOAT64(tag)) {
  11239             double d = JS_VALUE_GET_FLOAT64(val);
  11240             return !isnan(d) && d != 0;
  11241         } else {
  11242             JS_FreeValue(ctx, val);
  11243             return TRUE;
  11244         }
  11245     }
  11246 }
  11247 
  11248 int JS_ToBool(JSContext *ctx, JSValueConst val)
  11249 {
  11250     return JS_ToBoolFree(ctx, JS_DupValue(ctx, val));
  11251 }
  11252 
  11253 static int skip_spaces(const char *pc)
  11254 {
  11255     const uint8_t *p, *p_next, *p_start;
  11256     uint32_t c;
  11257 
  11258     p = p_start = (const uint8_t *)pc;
  11259     for (;;) {
  11260         c = *p;
  11261         if (c < 128) {
  11262             if (!((c >= 0x09 && c <= 0x0d) || (c == 0x20)))
  11263                 break;
  11264             p++;
  11265         } else {
  11266             c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
  11267             if (!lre_is_space(c))
  11268                 break;
  11269             p = p_next;
  11270         }
  11271     }
  11272     return p - p_start;
  11273 }
  11274 
  11275 static inline int to_digit(int c)
  11276 {
  11277     if (c >= '0' && c <= '9')
  11278         return c - '0';
  11279     else if (c >= 'A' && c <= 'Z')
  11280         return c - 'A' + 10;
  11281     else if (c >= 'a' && c <= 'z')
  11282         return c - 'a' + 10;
  11283     else
  11284         return 36;
  11285 }
  11286 
  11287 /* bigint support */
  11288 
  11289 #define JS_BIGINT_MAX_SIZE ((1024 * 1024) / JS_LIMB_BITS) /* in limbs */
  11290 
  11291 /* it is currently assumed that JS_SHORT_BIG_INT_BITS = JS_LIMB_BITS */
  11292 #if JS_SHORT_BIG_INT_BITS == 32
  11293 #define JS_SHORT_BIG_INT_MIN INT32_MIN
  11294 #define JS_SHORT_BIG_INT_MAX INT32_MAX
  11295 #elif JS_SHORT_BIG_INT_BITS == 64
  11296 #define JS_SHORT_BIG_INT_MIN INT64_MIN
  11297 #define JS_SHORT_BIG_INT_MAX INT64_MAX
  11298 #else
  11299 #error unsupported
  11300 #endif
  11301 
  11302 #define ADDC(res, carry_out, op1, op2, carry_in)        \
  11303 do {                                                    \
  11304     js_limb_t __v, __a, __k, __k1;                      \
  11305     __v = (op1);                                        \
  11306     __a = __v + (op2);                                  \
  11307     __k1 = __a < __v;                                   \
  11308     __k = (carry_in);                                   \
  11309     __a = __a + __k;                                    \
  11310     carry_out = (__a < __k) | __k1;                     \
  11311     res = __a;                                          \
  11312 } while (0)
  11313 
  11314 #if JS_LIMB_BITS == 32
  11315 /* a != 0 */
  11316 static inline js_limb_t js_limb_clz(js_limb_t a)
  11317 {
  11318     return clz32(a);
  11319 }
  11320 #else
  11321 static inline js_limb_t js_limb_clz(js_limb_t a)
  11322 {
  11323     return clz64(a);
  11324 }
  11325 #endif
  11326 
  11327 /* handle a = 0 too */
  11328 static inline js_limb_t js_limb_safe_clz(js_limb_t a)
  11329 {
  11330     if (a == 0)
  11331         return JS_LIMB_BITS;
  11332     else
  11333         return js_limb_clz(a);
  11334 }
  11335 
  11336 static js_limb_t mp_add(js_limb_t *res, const js_limb_t *op1, const js_limb_t *op2,
  11337                      js_limb_t n, js_limb_t carry)
  11338 {
  11339     int i;
  11340     for(i = 0;i < n; i++) {
  11341         ADDC(res[i], carry, op1[i], op2[i], carry);
  11342     }
  11343     return carry;
  11344 }
  11345 
  11346 static js_limb_t mp_sub(js_limb_t *res, const js_limb_t *op1, const js_limb_t *op2,
  11347                         int n, js_limb_t carry)
  11348 {
  11349     int i;
  11350     js_limb_t k, a, v, k1;
  11351 
  11352     k = carry;
  11353     for(i=0;i<n;i++) {
  11354         v = op1[i];
  11355         a = v - op2[i];
  11356         k1 = a > v;
  11357         v = a - k;
  11358         k = (v > a) | k1;
  11359         res[i] = v;
  11360     }
  11361     return k;
  11362 }
  11363 
  11364 /* compute 0 - op2. carry = 0 or 1. */
  11365 static js_limb_t mp_neg(js_limb_t *res, const js_limb_t *op2, int n)
  11366 {
  11367     int i;
  11368     js_limb_t v, carry;
  11369 
  11370     carry = 1;
  11371     for(i=0;i<n;i++) {
  11372         v = ~op2[i] + carry;
  11373         carry = v < carry;
  11374         res[i] = v;
  11375     }
  11376     return carry;
  11377 }
  11378 
  11379 /* tabr[] = taba[] * b + l. Return the high carry */
  11380 static js_limb_t mp_mul1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,
  11381                       js_limb_t b, js_limb_t l)
  11382 {
  11383     js_limb_t i;
  11384     js_dlimb_t t;
  11385 
  11386     for(i = 0; i < n; i++) {
  11387         t = (js_dlimb_t)taba[i] * (js_dlimb_t)b + l;
  11388         tabr[i] = t;
  11389         l = t >> JS_LIMB_BITS;
  11390     }
  11391     return l;
  11392 }
  11393 
  11394 static js_limb_t mp_div1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,
  11395                       js_limb_t b, js_limb_t r)
  11396 {
  11397     js_slimb_t i;
  11398     js_dlimb_t a1;
  11399     for(i = n - 1; i >= 0; i--) {
  11400         a1 = ((js_dlimb_t)r << JS_LIMB_BITS) | taba[i];
  11401         tabr[i] = a1 / b;
  11402         r = a1 % b;
  11403     }
  11404     return r;
  11405 }
  11406 
  11407 /* tabr[] += taba[] * b, return the high word. */
  11408 static js_limb_t mp_add_mul1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,
  11409                           js_limb_t b)
  11410 {
  11411     js_limb_t i, l;
  11412     js_dlimb_t t;
  11413 
  11414     l = 0;
  11415     for(i = 0; i < n; i++) {
  11416         t = (js_dlimb_t)taba[i] * (js_dlimb_t)b + l + tabr[i];
  11417         tabr[i] = t;
  11418         l = t >> JS_LIMB_BITS;
  11419     }
  11420     return l;
  11421 }
  11422 
  11423 /* size of the result : op1_size + op2_size. */
  11424 static void mp_mul_basecase(js_limb_t *result,
  11425                             const js_limb_t *op1, js_limb_t op1_size,
  11426                             const js_limb_t *op2, js_limb_t op2_size)
  11427 {
  11428     int i;
  11429     js_limb_t r;
  11430     
  11431     result[op1_size] = mp_mul1(result, op1, op1_size, op2[0], 0);
  11432     for(i=1;i<op2_size;i++) {
  11433         r = mp_add_mul1(result + i, op1, op1_size, op2[i]);
  11434         result[i + op1_size] = r;
  11435     }
  11436 }
  11437 
  11438 /* tabr[] -= taba[] * b. Return the value to substract to the high
  11439    word. */
  11440 static js_limb_t mp_sub_mul1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,
  11441                           js_limb_t b)
  11442 {
  11443     js_limb_t i, l;
  11444     js_dlimb_t t;
  11445 
  11446     l = 0;
  11447     for(i = 0; i < n; i++) {
  11448         t = tabr[i] - (js_dlimb_t)taba[i] * (js_dlimb_t)b - l;
  11449         tabr[i] = t;
  11450         l = -(t >> JS_LIMB_BITS);
  11451     }
  11452     return l;
  11453 }
  11454 
  11455 /* WARNING: d must be >= 2^(JS_LIMB_BITS-1) */
  11456 static inline js_limb_t udiv1norm_init(js_limb_t d)
  11457 {
  11458     js_limb_t a0, a1;
  11459     a1 = -d - 1;
  11460     a0 = -1;
  11461     return (((js_dlimb_t)a1 << JS_LIMB_BITS) | a0) / d;
  11462 }
  11463 
  11464 /* return the quotient and the remainder in '*pr'of 'a1*2^JS_LIMB_BITS+a0
  11465    / d' with 0 <= a1 < d. */
  11466 static inline js_limb_t udiv1norm(js_limb_t *pr, js_limb_t a1, js_limb_t a0,
  11467                                 js_limb_t d, js_limb_t d_inv)
  11468 {
  11469     js_limb_t n1m, n_adj, q, r, ah;
  11470     js_dlimb_t a;
  11471     n1m = ((js_slimb_t)a0 >> (JS_LIMB_BITS - 1));
  11472     n_adj = a0 + (n1m & d);
  11473     a = (js_dlimb_t)d_inv * (a1 - n1m) + n_adj;
  11474     q = (a >> JS_LIMB_BITS) + a1;
  11475     /* compute a - q * r and update q so that the remainder is\
  11476        between 0 and d - 1 */
  11477     a = ((js_dlimb_t)a1 << JS_LIMB_BITS) | a0;
  11478     a = a - (js_dlimb_t)q * d - d;
  11479     ah = a >> JS_LIMB_BITS;
  11480     q += 1 + ah;
  11481     r = (js_limb_t)a + (ah & d);
  11482     *pr = r;
  11483     return q;
  11484 }
  11485 
  11486 #define UDIV1NORM_THRESHOLD 3
  11487 
  11488 /* b must be >= 1 << (JS_LIMB_BITS - 1) */
  11489 static js_limb_t mp_div1norm(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,
  11490                           js_limb_t b, js_limb_t r)
  11491 {
  11492     js_slimb_t i;
  11493 
  11494     if (n >= UDIV1NORM_THRESHOLD) {
  11495         js_limb_t b_inv;
  11496         b_inv = udiv1norm_init(b);
  11497         for(i = n - 1; i >= 0; i--) {
  11498             tabr[i] = udiv1norm(&r, r, taba[i], b, b_inv);
  11499         }
  11500     } else {
  11501         js_dlimb_t a1;
  11502         for(i = n - 1; i >= 0; i--) {
  11503             a1 = ((js_dlimb_t)r << JS_LIMB_BITS) | taba[i];
  11504             tabr[i] = a1 / b;
  11505             r = a1 % b;
  11506         }
  11507     }
  11508     return r;
  11509 }
  11510 
  11511 /* base case division: divides taba[0..na-1] by tabb[0..nb-1]. tabb[nb
  11512    - 1] must be >= 1 << (JS_LIMB_BITS - 1). na - nb must be >= 0. 'taba'
  11513    is modified and contains the remainder (nb limbs). tabq[0..na-nb]
  11514    contains the quotient with tabq[na - nb] <= 1. */
  11515 static void mp_divnorm(js_limb_t *tabq, js_limb_t *taba, js_limb_t na,
  11516                        const js_limb_t *tabb, js_limb_t nb)
  11517 {
  11518     js_limb_t r, a, c, q, v, b1, b1_inv, n, dummy_r;
  11519     int i, j;
  11520 
  11521     b1 = tabb[nb - 1];
  11522     if (nb == 1) {
  11523         taba[0] = mp_div1norm(tabq, taba, na, b1, 0);
  11524         return;
  11525     }
  11526     n = na - nb;
  11527 
  11528     if (n >= UDIV1NORM_THRESHOLD)
  11529         b1_inv = udiv1norm_init(b1);
  11530     else
  11531         b1_inv = 0;
  11532 
  11533     /* first iteration: the quotient is only 0 or 1 */
  11534     q = 1;
  11535     for(j = nb - 1; j >= 0; j--) {
  11536         if (taba[n + j] != tabb[j]) {
  11537             if (taba[n + j] < tabb[j])
  11538                 q = 0;
  11539             break;
  11540         }
  11541     }
  11542     tabq[n] = q;
  11543     if (q) {
  11544         mp_sub(taba + n, taba + n, tabb, nb, 0);
  11545     }
  11546 
  11547     for(i = n - 1; i >= 0; i--) {
  11548         if (unlikely(taba[i + nb] >= b1)) {
  11549             q = -1;
  11550         } else if (b1_inv) {
  11551             q = udiv1norm(&dummy_r, taba[i + nb], taba[i + nb - 1], b1, b1_inv);
  11552         } else {
  11553             js_dlimb_t al;
  11554             al = ((js_dlimb_t)taba[i + nb] << JS_LIMB_BITS) | taba[i + nb - 1];
  11555             q = al / b1;
  11556             r = al % b1;
  11557         }
  11558         r = mp_sub_mul1(taba + i, tabb, nb, q);
  11559 
  11560         v = taba[i + nb];
  11561         a = v - r;
  11562         c = (a > v);
  11563         taba[i + nb] = a;
  11564 
  11565         if (c != 0) {
  11566             /* negative result */
  11567             for(;;) {
  11568                 q--;
  11569                 c = mp_add(taba + i, taba + i, tabb, nb, 0);
  11570                 /* propagate carry and test if positive result */
  11571                 if (c != 0) {
  11572                     if (++taba[i + nb] == 0) {
  11573                         break;
  11574                     }
  11575                 }
  11576             }
  11577         }
  11578         tabq[i] = q;
  11579     }
  11580 }
  11581 
  11582 /* 1 <= shift <= JS_LIMB_BITS - 1 */
  11583 static js_limb_t mp_shl(js_limb_t *tabr, const js_limb_t *taba, int n,
  11584                         int shift)
  11585 {
  11586     int i;
  11587     js_limb_t l, v;
  11588     l = 0;
  11589     for(i = 0; i < n; i++) {
  11590         v = taba[i];
  11591         tabr[i] = (v << shift) | l;
  11592         l = v >> (JS_LIMB_BITS - shift);
  11593     }
  11594     return l;
  11595 }
  11596 
  11597 /* r = (a + high*B^n) >> shift. Return the remainder r (0 <= r < 2^shift). 
  11598    1 <= shift <= LIMB_BITS - 1 */
  11599 static js_limb_t mp_shr(js_limb_t *tab_r, const js_limb_t *tab, int n,
  11600                         int shift, js_limb_t high)
  11601 {
  11602     int i;
  11603     js_limb_t l, a;
  11604 
  11605     l = high;
  11606     for(i = n - 1; i >= 0; i--) {
  11607         a = tab[i];
  11608         tab_r[i] = (a >> shift) | (l << (JS_LIMB_BITS - shift));
  11609         l = a;
  11610     }
  11611     return l & (((js_limb_t)1 << shift) - 1);
  11612 }
  11613 
  11614 static JSBigInt *js_bigint_new(JSContext *ctx, int len)
  11615 {
  11616     JSBigInt *r;
  11617     if (len > JS_BIGINT_MAX_SIZE) {
  11618         JS_ThrowRangeError(ctx, "BigInt is too large to allocate");
  11619         return NULL;
  11620     }
  11621     r = js_malloc(ctx, sizeof(JSBigInt) + len * sizeof(js_limb_t));
  11622     if (!r)
  11623         return NULL;
  11624     js_rc(r)->ref_count = 1;
  11625     r->len = len;
  11626     return r;
  11627 }
  11628 
  11629 static JSBigInt *js_bigint_set_si(JSBigIntBuf *buf, js_slimb_t a)
  11630 {
  11631     JSBigInt *r = (JSBigInt *)buf->big_int_buf;
  11632     r->len = 1;
  11633     r->tab[0] = a;
  11634     return r;
  11635 }
  11636 
  11637 static JSBigInt *js_bigint_set_si64(JSBigIntBuf *buf, int64_t a)
  11638 {
  11639 #if JS_LIMB_BITS == 64
  11640     return js_bigint_set_si(buf, a);
  11641 #else
  11642     JSBigInt *r = (JSBigInt *)buf->big_int_buf;
  11643     if (a >= INT32_MIN && a <= INT32_MAX) {
  11644         r->len = 1;
  11645         r->tab[0] = a;
  11646     } else {
  11647         r->len = 2;
  11648         r->tab[0] = a;
  11649         r->tab[1] = a >> JS_LIMB_BITS;
  11650     }
  11651     return r;
  11652 #endif
  11653 }
  11654 
  11655 /* val must be a short big int */
  11656 static JSBigInt *js_bigint_set_short(JSBigIntBuf *buf, JSValueConst val)
  11657 {
  11658     return js_bigint_set_si(buf, JS_VALUE_GET_SHORT_BIG_INT(val));
  11659 }
  11660 
  11661 static __maybe_unused void js_bigint_dump1(JSContext *ctx, const char *str,
  11662                                            const js_limb_t *tab, int len)
  11663 {
  11664     int i;
  11665     printf("%s: ", str);
  11666     for(i = len - 1; i >= 0; i--) {
  11667 #if JS_LIMB_BITS == 32
  11668         printf(" %08x", tab[i]);
  11669 #else
  11670         printf(" %016" PRIx64, tab[i]);
  11671 #endif
  11672     }
  11673     printf("\n");
  11674 }
  11675 
  11676 static __maybe_unused void js_bigint_dump(JSContext *ctx, const char *str,
  11677                                           const JSBigInt *p)
  11678 {
  11679     js_bigint_dump1(ctx, str, p->tab, p->len);
  11680 }
  11681 
  11682 static JSBigInt *js_bigint_new_si(JSContext *ctx, js_slimb_t a)
  11683 {
  11684     JSBigInt *r;
  11685     r = js_bigint_new(ctx, 1);
  11686     if (!r)
  11687         return NULL;
  11688     r->tab[0] = a;
  11689     return r;
  11690 }
  11691 
  11692 static JSBigInt *js_bigint_new_si64(JSContext *ctx, int64_t a)
  11693 {
  11694 #if JS_LIMB_BITS == 64
  11695     return js_bigint_new_si(ctx, a);
  11696 #else
  11697     if (a >= INT32_MIN && a <= INT32_MAX) {
  11698         return js_bigint_new_si(ctx, a);
  11699     } else {
  11700         JSBigInt *r;
  11701         r = js_bigint_new(ctx, 2);
  11702         if (!r)
  11703             return NULL;
  11704         r->tab[0] = a;
  11705         r->tab[1] = a >> 32;
  11706         return r;
  11707     }
  11708 #endif
  11709 }
  11710 
  11711 static JSBigInt *js_bigint_new_ui64(JSContext *ctx, uint64_t a)
  11712 {
  11713     if (a <= INT64_MAX) {
  11714         return js_bigint_new_si64(ctx, a);
  11715     } else {
  11716         JSBigInt *r;
  11717         r = js_bigint_new(ctx, (65 + JS_LIMB_BITS - 1) / JS_LIMB_BITS);
  11718         if (!r)
  11719             return NULL;
  11720 #if JS_LIMB_BITS == 64
  11721         r->tab[0] = a;
  11722         r->tab[1] = 0;
  11723 #else
  11724         r->tab[0] = a;
  11725         r->tab[1] = a >> 32;
  11726         r->tab[2] = 0;
  11727 #endif
  11728         return r;
  11729     }
  11730 }
  11731 
  11732 static JSBigInt *js_bigint_new_di(JSContext *ctx, js_sdlimb_t a)
  11733 {
  11734     JSBigInt *r;
  11735     if (a == (js_slimb_t)a) {
  11736         r = js_bigint_new(ctx, 1);
  11737         if (!r)
  11738             return NULL;
  11739         r->tab[0] = a;
  11740     } else {
  11741         r = js_bigint_new(ctx, 2);
  11742         if (!r)
  11743             return NULL;
  11744         r->tab[0] = a;
  11745         r->tab[1] = a >> JS_LIMB_BITS;
  11746     }
  11747     return r;
  11748 }
  11749 
  11750 /* Remove redundant high order limbs. Warning: 'a' may be
  11751    reallocated. Can never fail.
  11752 */
  11753 static JSBigInt *js_bigint_normalize1(JSContext *ctx, JSBigInt *a, int l)
  11754 {
  11755     js_limb_t v;
  11756 
  11757     assert(js_rc(a)->ref_count == 1);
  11758     while (l > 1) {
  11759         v = a->tab[l - 1];
  11760         if ((v != 0 && v != -1) ||
  11761             (v & 1) != (a->tab[l - 2] >> (JS_LIMB_BITS - 1))) {
  11762             break;
  11763         }
  11764         l--;
  11765     }
  11766     if (l != a->len) {
  11767         JSBigInt *a1;
  11768         /* realloc to reduce the size */
  11769         a->len = l;
  11770         a1 = js_realloc(ctx, a, sizeof(JSBigInt) + l * sizeof(js_limb_t));
  11771         if (a1)
  11772             a = a1;
  11773     }
  11774     return a;
  11775 }
  11776 
  11777 static JSBigInt *js_bigint_normalize(JSContext *ctx, JSBigInt *a)
  11778 {
  11779     return js_bigint_normalize1(ctx, a, a->len);
  11780 }
  11781 
  11782 /* return 0 or 1 depending on the sign */
  11783 static inline int js_bigint_sign(const JSBigInt *a)
  11784 {
  11785     return a->tab[a->len - 1] >> (JS_LIMB_BITS - 1);
  11786 }
  11787 
  11788 static js_slimb_t js_bigint_get_si_sat(const JSBigInt *a)
  11789 {
  11790     if (a->len == 1) {
  11791         return a->tab[0];
  11792     } else {
  11793 #if JS_LIMB_BITS == 32
  11794         if (js_bigint_sign(a))
  11795             return INT32_MIN;
  11796         else
  11797             return INT32_MAX;
  11798 #else
  11799         if (js_bigint_sign(a))
  11800             return INT64_MIN;
  11801         else
  11802             return INT64_MAX;
  11803 #endif
  11804     }
  11805 }
  11806 
  11807 /* add the op1 limb */
  11808 static JSBigInt *js_bigint_extend(JSContext *ctx, JSBigInt *r,
  11809                                   js_limb_t op1)
  11810 {
  11811     int n2 = r->len;
  11812     if ((op1 != 0 && op1 != -1) ||
  11813         (op1 & 1) != r->tab[n2 - 1] >> (JS_LIMB_BITS - 1)) {
  11814         JSBigInt *r1;
  11815         r1 = js_realloc(ctx, r,
  11816                         sizeof(JSBigInt) + (n2 + 1) * sizeof(js_limb_t));
  11817         if (!r1) {
  11818             js_free(ctx, r);
  11819             return NULL;
  11820         }
  11821         r = r1;
  11822         r->len = n2 + 1;
  11823         r->tab[n2] = op1;
  11824     } else {
  11825         /* otherwise still need to normalize the result */
  11826         r = js_bigint_normalize(ctx, r);
  11827     }
  11828     return r;
  11829 }
  11830 
  11831 /* return NULL in case of error. Compute a + b (b_neg = 0) or a - b
  11832    (b_neg = 1) */
  11833 /* XXX: optimize */
  11834 static JSBigInt *js_bigint_add(JSContext *ctx, const JSBigInt *a,
  11835                                const JSBigInt *b, int b_neg)
  11836 {
  11837     JSBigInt *r;
  11838     int n1, n2, i;
  11839     js_limb_t carry, op1, op2, a_sign, b_sign;
  11840     
  11841     n2 = max_int(a->len, b->len);
  11842     n1 = min_int(a->len, b->len);
  11843     r = js_bigint_new(ctx, n2);
  11844     if (!r)
  11845         return NULL;
  11846     /* XXX: optimize */
  11847     /* common part */
  11848     carry = b_neg;
  11849     for(i = 0; i < n1; i++) {
  11850         op1 = a->tab[i];
  11851         op2 = b->tab[i] ^ (-b_neg);
  11852         ADDC(r->tab[i], carry, op1, op2, carry);
  11853     }
  11854     a_sign = -js_bigint_sign(a);
  11855     b_sign = (-js_bigint_sign(b)) ^ (-b_neg);
  11856     /* part with sign extension of one operand  */
  11857     if (a->len > b->len) {
  11858         for(i = n1; i < n2; i++) {
  11859             op1 = a->tab[i];
  11860             ADDC(r->tab[i], carry, op1, b_sign, carry);
  11861         }
  11862     } else if (a->len < b->len) {
  11863         for(i = n1; i < n2; i++) {
  11864             op2 = b->tab[i] ^ (-b_neg);
  11865             ADDC(r->tab[i], carry, a_sign, op2, carry);
  11866         }
  11867     }
  11868 
  11869     /* part with sign extension for both operands. Extend the result
  11870        if necessary */
  11871     return js_bigint_extend(ctx, r, a_sign + b_sign + carry);
  11872 }
  11873 
  11874 /* XXX: optimize */
  11875 static JSBigInt *js_bigint_neg(JSContext *ctx, const JSBigInt *a)
  11876 {
  11877     JSBigIntBuf buf;
  11878     JSBigInt *b;
  11879     b = js_bigint_set_si(&buf, 0);
  11880     return js_bigint_add(ctx, b, a, 1);
  11881 }
  11882 
  11883 static JSBigInt *js_bigint_mul(JSContext *ctx, const JSBigInt *a,
  11884                                const JSBigInt *b)
  11885 {
  11886     JSBigInt *r;
  11887     
  11888     r = js_bigint_new(ctx, a->len + b->len);
  11889     if (!r)
  11890         return NULL;
  11891     mp_mul_basecase(r->tab, a->tab, a->len, b->tab, b->len);
  11892     /* correct the result if negative operands (no overflow is
  11893        possible) */
  11894     if (js_bigint_sign(a))
  11895         mp_sub(r->tab + a->len, r->tab + a->len, b->tab, b->len, 0);
  11896     if (js_bigint_sign(b))
  11897         mp_sub(r->tab + b->len, r->tab + b->len, a->tab, a->len, 0);
  11898     return js_bigint_normalize(ctx, r);
  11899 }
  11900 
  11901 /* return the division or the remainder. 'b' must be != 0. return NULL
  11902    in case of exception (division by zero or memory error) */
  11903 static JSBigInt *js_bigint_divrem(JSContext *ctx, const JSBigInt *a,
  11904                                   const JSBigInt *b, BOOL is_rem)
  11905 {
  11906     JSBigInt *r, *q;
  11907     js_limb_t *tabb, h;
  11908     int na, nb, a_sign, b_sign, shift;
  11909     
  11910     if (b->len == 1 && b->tab[0] == 0) {
  11911         JS_ThrowRangeError(ctx, "BigInt division by zero");
  11912         return NULL;
  11913     }
  11914     
  11915     a_sign = js_bigint_sign(a);
  11916     b_sign = js_bigint_sign(b);
  11917     na = a->len;
  11918     nb = b->len;
  11919 
  11920     r = js_bigint_new(ctx, na + 2); 
  11921     if (!r)
  11922         return NULL;
  11923     if (a_sign) {
  11924         mp_neg(r->tab, a->tab, na);
  11925     } else {
  11926         memcpy(r->tab, a->tab, na * sizeof(a->tab[0]));
  11927     }
  11928     /* normalize */
  11929     while (na > 1 && r->tab[na - 1] == 0)
  11930         na--;
  11931 
  11932     tabb = js_malloc(ctx, nb * sizeof(tabb[0]));
  11933     if (!tabb) {
  11934         js_free(ctx, r);
  11935         return NULL;
  11936     }
  11937     if (b_sign) {
  11938         mp_neg(tabb, b->tab, nb);
  11939     } else {
  11940         memcpy(tabb, b->tab, nb * sizeof(tabb[0]));
  11941     }
  11942     /* normalize */
  11943     while (nb > 1 && tabb[nb - 1] == 0)
  11944         nb--;
  11945 
  11946     /* trivial case if 'a' is small */
  11947     if (na < nb) {
  11948         js_free(ctx, r);
  11949         js_free(ctx, tabb);
  11950         if (is_rem) {
  11951             /* r = a */
  11952             r = js_bigint_new(ctx, a->len);
  11953             if (!r)
  11954                 return NULL;
  11955             memcpy(r->tab, a->tab, a->len * sizeof(a->tab[0])); 
  11956             return r;
  11957         } else {
  11958             /* q = 0 */
  11959             return js_bigint_new_si(ctx, 0);
  11960         }
  11961     }
  11962 
  11963     /* normalize 'b' */
  11964     shift = js_limb_clz(tabb[nb - 1]);
  11965     if (shift != 0) {
  11966         mp_shl(tabb, tabb, nb, shift);
  11967         h = mp_shl(r->tab, r->tab, na, shift);
  11968         if (h != 0)
  11969             r->tab[na++] = h;
  11970     }
  11971 
  11972     q = js_bigint_new(ctx, na - nb + 2); /* one more limb for the sign */
  11973     if (!q) {
  11974         js_free(ctx, r);
  11975         js_free(ctx, tabb);
  11976         return NULL;
  11977     }
  11978 
  11979     //    js_bigint_dump1(ctx, "a", r->tab, na);
  11980     //    js_bigint_dump1(ctx, "b", tabb, nb);
  11981     mp_divnorm(q->tab, r->tab, na, tabb, nb);
  11982     js_free(ctx, tabb);
  11983 
  11984     if (is_rem) {
  11985         js_free(ctx, q);
  11986         if (shift != 0)
  11987             mp_shr(r->tab, r->tab, nb, shift, 0);
  11988         r->tab[nb++] = 0;
  11989         if (a_sign)
  11990             mp_neg(r->tab, r->tab, nb);
  11991         r = js_bigint_normalize1(ctx, r, nb);
  11992         return r;
  11993     } else {
  11994         js_free(ctx, r);
  11995         q->tab[na - nb + 1] = 0;
  11996         if (a_sign ^ b_sign) {
  11997             mp_neg(q->tab, q->tab, q->len);
  11998         }
  11999         q = js_bigint_normalize(ctx, q);
  12000         return q;
  12001     }
  12002 }
  12003 
  12004 /* and, or, xor */
  12005 static JSBigInt *js_bigint_logic(JSContext *ctx, const JSBigInt *a,
  12006                                  const JSBigInt *b, OPCodeEnum op)
  12007 {
  12008     JSBigInt *r;
  12009     js_limb_t b_sign;
  12010     int a_len, b_len, i;
  12011 
  12012     if (a->len < b->len) {
  12013         const JSBigInt *tmp;
  12014         tmp = a;
  12015         a = b;
  12016         b = tmp;
  12017     }
  12018     /* a_len >= b_len */
  12019     a_len = a->len;
  12020     b_len = b->len;
  12021     b_sign = -js_bigint_sign(b);
  12022 
  12023     r = js_bigint_new(ctx, a_len);
  12024     if (!r)
  12025         return NULL;
  12026     switch(op) {
  12027     case OP_or:
  12028         for(i = 0; i < b_len; i++) {
  12029             r->tab[i] = a->tab[i] | b->tab[i];
  12030         }
  12031         for(i = b_len; i < a_len; i++) {
  12032             r->tab[i] = a->tab[i] | b_sign;
  12033         }
  12034         break;
  12035     case OP_and:
  12036         for(i = 0; i < b_len; i++) {
  12037             r->tab[i] = a->tab[i] & b->tab[i];
  12038         }
  12039         for(i = b_len; i < a_len; i++) {
  12040             r->tab[i] = a->tab[i] & b_sign;
  12041         }
  12042         break;
  12043     case OP_xor:
  12044         for(i = 0; i < b_len; i++) {
  12045             r->tab[i] = a->tab[i] ^ b->tab[i];
  12046         }
  12047         for(i = b_len; i < a_len; i++) {
  12048             r->tab[i] = a->tab[i] ^ b_sign;
  12049         }
  12050         break;
  12051     default:
  12052         abort();
  12053     }
  12054     return js_bigint_normalize(ctx, r);
  12055 }
  12056 
  12057 static JSBigInt *js_bigint_not(JSContext *ctx, const JSBigInt *a)
  12058 {
  12059     JSBigInt *r;
  12060     int i;
  12061     
  12062     r = js_bigint_new(ctx, a->len);
  12063     if (!r)
  12064         return NULL;
  12065     for(i = 0; i < a->len; i++) {
  12066         r->tab[i] = ~a->tab[i];
  12067     }
  12068     /* no normalization is needed */
  12069     return r;
  12070 }
  12071 
  12072 static JSBigInt *js_bigint_shl(JSContext *ctx, const JSBigInt *a,
  12073                                unsigned int shift1)
  12074 {
  12075     int d, i, shift;
  12076     JSBigInt *r;
  12077     js_limb_t l;
  12078 
  12079     if (a->len == 1 && a->tab[0] == 0)
  12080         return js_bigint_new_si(ctx, 0); /* zero case */
  12081     d = shift1 / JS_LIMB_BITS;
  12082     shift = shift1 % JS_LIMB_BITS;
  12083     r = js_bigint_new(ctx, a->len + d);
  12084     if (!r)
  12085         return NULL;
  12086     for(i = 0; i < d; i++)
  12087         r->tab[i] = 0;
  12088     if (shift == 0) {
  12089         for(i = 0; i < a->len; i++) {
  12090             r->tab[i + d] = a->tab[i];
  12091         }
  12092     } else {
  12093         l = mp_shl(r->tab + d, a->tab, a->len, shift);
  12094         if (js_bigint_sign(a))
  12095             l |= (js_limb_t)(-1) << shift;
  12096         r = js_bigint_extend(ctx, r, l);
  12097     }
  12098     return r;
  12099 }
  12100 
  12101 static JSBigInt *js_bigint_shr(JSContext *ctx, const JSBigInt *a,
  12102                                unsigned int shift1)
  12103 {
  12104     int d, i, shift, a_sign, n1;
  12105     JSBigInt *r;
  12106 
  12107     d = shift1 / JS_LIMB_BITS;
  12108     shift = shift1 % JS_LIMB_BITS;
  12109     a_sign = js_bigint_sign(a);
  12110     if (d >= a->len)
  12111         return js_bigint_new_si(ctx, -a_sign);
  12112     n1 = a->len - d;
  12113     r = js_bigint_new(ctx, n1);
  12114     if (!r)
  12115         return NULL;
  12116     if (shift == 0) {
  12117         for(i = 0; i < n1; i++) {
  12118             r->tab[i] = a->tab[i + d];
  12119         }
  12120         /* no normalization is needed */
  12121     } else {
  12122         mp_shr(r->tab, a->tab + d, n1, shift, -a_sign);
  12123         r = js_bigint_normalize(ctx, r);
  12124     }
  12125     return r;
  12126 }
  12127 
  12128 static JSBigInt *js_bigint_pow(JSContext *ctx, const JSBigInt *a, JSBigInt *b)
  12129 {
  12130     uint32_t e;
  12131     int n_bits, i;
  12132     JSBigInt *r, *r1;
  12133     
  12134     /* b must be >= 0 */
  12135     if (js_bigint_sign(b)) {
  12136         JS_ThrowRangeError(ctx, "BigInt negative exponent");
  12137         return NULL;
  12138     }
  12139     if (b->len == 1 && b->tab[0] == 0) {
  12140         /* a^0 = 1 */
  12141         return js_bigint_new_si(ctx, 1);
  12142     } else if (a->len == 1) {
  12143         js_limb_t v;
  12144         BOOL is_neg;
  12145 
  12146         v = a->tab[0];
  12147         if (v <= 1)
  12148             return js_bigint_new_si(ctx, v);
  12149         else if (v == -1)
  12150             return js_bigint_new_si(ctx, 1 - 2 * (b->tab[0] & 1));
  12151         is_neg = (js_slimb_t)v < 0;
  12152         if (is_neg)
  12153             v = -v;
  12154         if ((v & (v - 1)) == 0) {
  12155             uint64_t e1;
  12156             int n;
  12157             /* v = 2^n */
  12158             n = JS_LIMB_BITS - 1 - js_limb_clz(v);
  12159             if (b->len > 1)
  12160                 goto overflow;
  12161             if (b->tab[0] > INT32_MAX)
  12162                 goto overflow;
  12163             e = b->tab[0];
  12164             e1 = (uint64_t)e * n;
  12165             if (e1 > JS_BIGINT_MAX_SIZE * JS_LIMB_BITS)
  12166                 goto overflow;
  12167             e = e1;
  12168             if (is_neg)
  12169                 is_neg = b->tab[0] & 1;
  12170             r = js_bigint_new(ctx,
  12171                               (e + JS_LIMB_BITS + 1 - is_neg) / JS_LIMB_BITS);
  12172             if (!r)
  12173                 return NULL;
  12174             memset(r->tab, 0, sizeof(r->tab[0]) * r->len);
  12175             r->tab[e / JS_LIMB_BITS] =
  12176                 (js_limb_t)(1 - 2 * is_neg) << (e % JS_LIMB_BITS);
  12177             return r;
  12178         }
  12179     }
  12180     if (b->len > 1)
  12181         goto overflow;
  12182     if (b->tab[0] > INT32_MAX)
  12183         goto overflow;
  12184     e = b->tab[0];
  12185     n_bits = 32 - clz32(e);
  12186 
  12187     r = js_bigint_new(ctx, a->len);
  12188     if (!r)
  12189         return NULL;
  12190     memcpy(r->tab, a->tab, a->len * sizeof(a->tab[0]));
  12191     for(i = n_bits - 2; i >= 0; i--) {
  12192         r1 = js_bigint_mul(ctx, r, r);
  12193         if (!r1)
  12194             return NULL;
  12195         js_free(ctx, r);
  12196         r = r1;
  12197         if ((e >> i) & 1) {
  12198             r1 = js_bigint_mul(ctx, r, a);
  12199             if (!r1)
  12200                 return NULL;
  12201             js_free(ctx, r);
  12202             r = r1;
  12203         }
  12204     }
  12205     return r;
  12206  overflow:
  12207     JS_ThrowRangeError(ctx, "BigInt is too large");
  12208     return NULL;
  12209 }
  12210 
  12211 /* return (mant, exp) so that abs(a) ~ mant*2^(exp - (limb_bits -
  12212    1). a must be != 0. */
  12213 static uint64_t js_bigint_get_mant_exp(JSContext *ctx,
  12214                                        int *pexp, const JSBigInt *a)
  12215 {
  12216     js_limb_t t[4 - JS_LIMB_BITS / 32], carry, v, low_bits;
  12217     int n1, n2, sgn, shift, i, j, e;
  12218     uint64_t a1, a0;
  12219 
  12220     n2 = 4 - JS_LIMB_BITS / 32;
  12221     n1 = a->len - n2;
  12222     sgn = js_bigint_sign(a);
  12223 
  12224     /* low_bits != 0 if there are a non zero low bit in abs(a) */
  12225     low_bits = 0;
  12226     carry = sgn;
  12227     for(i = 0; i < n1; i++) {
  12228         v = (a->tab[i] ^ (-sgn)) + carry;
  12229         carry = v < carry;
  12230         low_bits |= v;
  12231     }
  12232     /* get the n2 high limbs of abs(a) */
  12233     for(j = 0; j < n2; j++) {
  12234         i = j + n1;
  12235         if (i < 0) {
  12236             v = 0;
  12237         } else {
  12238             v = (a->tab[i] ^ (-sgn)) + carry;
  12239             carry = v < carry;
  12240         }
  12241         t[j] = v;
  12242     }
  12243     
  12244 #if JS_LIMB_BITS == 32
  12245     a1 = ((uint64_t)t[2] << 32) | t[1];
  12246     a0 = (uint64_t)t[0] << 32;
  12247 #else
  12248     a1 = t[1];
  12249     a0 = t[0];
  12250 #endif
  12251     a0 |= (low_bits != 0);
  12252     /* normalize */
  12253     if (a1 == 0) {
  12254         /* JS_LIMB_BITS = 64 bit only */
  12255         shift = 64;
  12256         a1 = a0;
  12257         a0 = 0;
  12258     } else {
  12259         shift = clz64(a1);
  12260         if (shift != 0) {
  12261             a1 = (a1 << shift) | (a0 >> (64 - shift));
  12262             a0 <<= shift;
  12263         }
  12264     }
  12265     a1 |= (a0 != 0); /* keep the bits for the final rounding */
  12266     /* compute the exponent */
  12267     e = a->len * JS_LIMB_BITS - shift - 1;
  12268     *pexp = e;
  12269     return a1;
  12270 }
  12271 
  12272 /* shift left with round to nearest, ties to even. n >= 1 */
  12273 static uint64_t shr_rndn(uint64_t a, int n)
  12274 {
  12275     uint64_t addend = ((a >> n) & 1) + ((1 << (n - 1)) - 1);
  12276     return (a + addend) >> n;
  12277 }
  12278 
  12279 /* convert to float64 with round to nearest, ties to even. Return
  12280    +/-infinity if too large. */
  12281 static double js_bigint_to_float64(JSContext *ctx, const JSBigInt *a)
  12282 {
  12283     int sgn, e;
  12284     uint64_t mant;
  12285 
  12286     if (a->len == 1) {
  12287         /* fast case, including zero */
  12288         return (double)(js_slimb_t)a->tab[0];
  12289     }
  12290 
  12291     sgn = js_bigint_sign(a);
  12292     mant = js_bigint_get_mant_exp(ctx, &e, a);
  12293     if (e > 1023) {
  12294         /* overflow: return infinity */
  12295         mant = 0;
  12296         e = 1024;
  12297     } else {
  12298         mant = (mant >> 1) | (mant & 1); /* avoid overflow in rounding */
  12299         mant = shr_rndn(mant, 10);
  12300         /* rounding can cause an overflow */
  12301         if (mant >= ((uint64_t)1 << 53)) {
  12302             mant >>= 1;
  12303             e++;
  12304         }
  12305         mant &= (((uint64_t)1 << 52) - 1);
  12306     }
  12307     return uint64_as_float64(((uint64_t)sgn << 63) |
  12308                              ((uint64_t)(e + 1023) << 52) |
  12309                              mant);
  12310 }
  12311 
  12312 /* return (1, NULL) if not an integer, (2, NULL) if NaN or Infinity,
  12313    (0, n) if an integer, (0, NULL) in case of memory error */
  12314 static JSBigInt *js_bigint_from_float64(JSContext *ctx, int *pres, double a1)
  12315 {
  12316     uint64_t a = float64_as_uint64(a1);
  12317     int sgn, e, shift;
  12318     uint64_t mant;
  12319     JSBigIntBuf buf;
  12320     JSBigInt *r;
  12321     
  12322     sgn = a >> 63;
  12323     e = (a >> 52) & ((1 << 11) - 1);
  12324     mant = a & (((uint64_t)1 << 52) - 1);
  12325     if (e == 2047) {
  12326         /* NaN, Infinity */
  12327         *pres = 2;
  12328         return NULL;
  12329     }
  12330     if (e == 0 && mant == 0) {
  12331         /* zero */
  12332         *pres = 0;
  12333         return js_bigint_new_si(ctx, 0);
  12334     }
  12335     e -= 1023;
  12336     /* 0 < a < 1 : not an integer */
  12337     if (e < 0)
  12338         goto not_an_integer;
  12339     mant |= (uint64_t)1 << 52;
  12340     if (e < 52) {
  12341         shift = 52 - e;
  12342         /* check that there is no fractional part */
  12343         if (mant & (((uint64_t)1 << shift) - 1)) {
  12344         not_an_integer:
  12345             *pres = 1;
  12346             return NULL;
  12347         }
  12348         mant >>= shift;
  12349         e = 0;
  12350     } else {
  12351         e -= 52;
  12352     }
  12353     if (sgn)
  12354         mant = -mant;
  12355     /* the integer is mant*2^e */
  12356     r = js_bigint_set_si64(&buf, (int64_t)mant);
  12357     *pres = 0;
  12358     return js_bigint_shl(ctx, r, e);
  12359 }
  12360 
  12361 /* return -1, 0, 1 or (2) (unordered) */
  12362 static int js_bigint_float64_cmp(JSContext *ctx, const JSBigInt *a,
  12363                                  double b)
  12364 {
  12365     int b_sign, a_sign, e, f;
  12366     uint64_t mant, b1, a_mant;
  12367     
  12368     b1 = float64_as_uint64(b);
  12369     b_sign = b1 >> 63;
  12370     e = (b1 >> 52) & ((1 << 11) - 1);
  12371     mant = b1 & (((uint64_t)1 << 52) - 1);
  12372     a_sign = js_bigint_sign(a);
  12373     if (e == 2047) {
  12374         if (mant != 0) {
  12375             /* NaN */
  12376             return 2;
  12377         } else {
  12378             /* +/- infinity */
  12379             return 2 * b_sign - 1;
  12380         }
  12381     } else if (e == 0 && mant == 0) {
  12382         /* b = +/-0 */
  12383         if (a->len == 1 && a->tab[0] == 0)
  12384             return 0;
  12385         else
  12386             return 1 - 2 * a_sign;
  12387     } else if (a->len == 1 && a->tab[0] == 0) {
  12388         /* a = 0, b != 0 */
  12389         return 2 * b_sign - 1;
  12390     } else if (a_sign != b_sign) {
  12391         return 1 - 2 * a_sign;
  12392     } else {
  12393         e -= 1023;
  12394         /* Note: handling denormals is not necessary because we
  12395            compare to integers hence f >= 0 */
  12396         /* compute f so that 2^f <= abs(a) < 2^(f+1) */
  12397         a_mant = js_bigint_get_mant_exp(ctx, &f, a);
  12398         if (f != e) {
  12399             if (f < e)
  12400                 return -1;
  12401             else
  12402                 return 1;
  12403         } else {
  12404             mant = (mant | ((uint64_t)1 << 52)) << 11; /* align to a_mant */
  12405             if (a_mant < mant)
  12406                 return 2 * a_sign - 1;
  12407             else if (a_mant > mant)
  12408                 return 1 - 2 * a_sign;
  12409             else
  12410                 return 0;
  12411         }
  12412     }
  12413 }
  12414 
  12415 /* return -1, 0 or 1 */
  12416 static int js_bigint_cmp(JSContext *ctx, const JSBigInt *a,
  12417                          const JSBigInt *b)
  12418 {
  12419     int a_sign, b_sign, res, i;
  12420     a_sign = js_bigint_sign(a);
  12421     b_sign = js_bigint_sign(b);
  12422     if (a_sign != b_sign) {
  12423         res = 1 - 2 * a_sign;
  12424     } else {
  12425         /* we assume the numbers are normalized */
  12426         if (a->len != b->len) {
  12427             if (a->len < b->len)
  12428                 res = 2 * a_sign - 1;
  12429             else
  12430                 res = 1 - 2 * a_sign;
  12431         } else {
  12432             res = 0;
  12433             for(i = a->len -1; i >= 0; i--) {
  12434                 if (a->tab[i] != b->tab[i]) {
  12435                     if (a->tab[i] < b->tab[i])
  12436                         res = -1;
  12437                     else
  12438                         res = 1;
  12439                     break;
  12440                 }
  12441             }
  12442         }
  12443     }
  12444     return res;
  12445 }
  12446 
  12447 /* contains 10^i */
  12448 static const js_limb_t js_pow_dec[JS_LIMB_DIGITS + 1] = {
  12449     1U,
  12450     10U,
  12451     100U,
  12452     1000U,
  12453     10000U,
  12454     100000U,
  12455     1000000U,
  12456     10000000U,
  12457     100000000U,
  12458     1000000000U,
  12459 #if JS_LIMB_BITS == 64
  12460     10000000000U,
  12461     100000000000U,
  12462     1000000000000U,
  12463     10000000000000U,
  12464     100000000000000U,
  12465     1000000000000000U,
  12466     10000000000000000U,
  12467     100000000000000000U,
  12468     1000000000000000000U,
  12469     10000000000000000000U,
  12470 #endif
  12471 };
  12472 
  12473 /* syntax: [-]digits in base radix. Return NULL if memory error. radix
  12474    = 10, 2, 8 or 16. */
  12475 static JSBigInt *js_bigint_from_string(JSContext *ctx,
  12476                                        const char *str, int radix)
  12477 {
  12478     const char *p = str;
  12479     size_t n_digits1;
  12480     int is_neg, n_digits, n_limbs, len, log2_radix, n_bits, i;
  12481     JSBigInt *r;
  12482     js_limb_t v, c, h;
  12483     
  12484     is_neg = 0;
  12485     if (*p == '-') {
  12486         is_neg = 1;
  12487         p++;
  12488     }
  12489     while (*p == '0')
  12490         p++;
  12491     n_digits1 = strlen(p);
  12492     /* the real check for overflox is done js_bigint_new(). Here
  12493        we just avoid integer overflow */
  12494     if (n_digits1 > JS_BIGINT_MAX_SIZE * JS_LIMB_BITS) {
  12495         JS_ThrowRangeError(ctx, "BigInt is too large to allocate");
  12496         return NULL;
  12497     }
  12498     n_digits = n_digits1;
  12499     log2_radix = 32 - clz32(radix - 1); /* ceil(log2(radix)) */
  12500     /* compute the maximum number of limbs */
  12501     if (radix == 10) {
  12502         n_bits = (n_digits * 27 + 7) / 8; /* >= ceil(n_digits * log2(10)) */
  12503     } else {
  12504         n_bits = n_digits * log2_radix;
  12505     }
  12506     /* we add one extra bit for the sign */
  12507     n_limbs = max_int(1, n_bits / JS_LIMB_BITS + 1);
  12508     r = js_bigint_new(ctx, n_limbs);
  12509     if (!r)
  12510         return NULL;
  12511     if (radix == 10) {
  12512         int digits_per_limb = JS_LIMB_DIGITS;
  12513         len = 1;
  12514         r->tab[0] = 0;
  12515         for(;;) {
  12516             /* XXX: slow */
  12517             v = 0;
  12518             for(i = 0; i < digits_per_limb; i++) {
  12519                 c = to_digit(*p);
  12520                 if (c >= radix)
  12521                     break;
  12522                 p++;
  12523                 v = v * 10 + c;
  12524             }
  12525             if (i == 0)
  12526                 break;
  12527             if (len == 1 && r->tab[0] == 0) {
  12528                 r->tab[0] = v;
  12529             } else {
  12530                 h = mp_mul1(r->tab, r->tab, len, js_pow_dec[i], v);
  12531                 if (h != 0) {
  12532                     r->tab[len++] = h;
  12533                 }
  12534             }
  12535         }
  12536         /* add one extra limb to have the correct sign*/
  12537         if ((r->tab[len - 1] >> (JS_LIMB_BITS - 1)) != 0)
  12538             r->tab[len++] = 0;
  12539         r->len = len;
  12540     } else {
  12541         unsigned int bit_pos, shift, pos;
  12542         
  12543         /* power of two base: no multiplication is needed */
  12544         r->len = n_limbs;
  12545         memset(r->tab, 0, sizeof(r->tab[0]) * n_limbs);
  12546         for(i = 0; i < n_digits; i++) {
  12547             c = to_digit(p[n_digits - 1 - i]);
  12548             assert(c < radix);
  12549             bit_pos = i * log2_radix;
  12550             shift = bit_pos & (JS_LIMB_BITS - 1);
  12551             pos = bit_pos / JS_LIMB_BITS;
  12552             r->tab[pos] |= c << shift;
  12553             /* if log2_radix does not divide JS_LIMB_BITS, needed an
  12554                additional op */
  12555             if (shift + log2_radix > JS_LIMB_BITS) {
  12556                 r->tab[pos + 1] |= c >> (JS_LIMB_BITS - shift);
  12557             }
  12558         }
  12559     }
  12560     r = js_bigint_normalize(ctx, r);
  12561     /* XXX: could do it in place */
  12562     if (is_neg) {
  12563         JSBigInt *r1;
  12564         r1 = js_bigint_neg(ctx, r);
  12565         js_free(ctx, r);
  12566         r = r1;
  12567     }
  12568     return r;
  12569 }
  12570 
  12571 /* 2 <= base <= 36 */
  12572 static char const digits[36] = {
  12573   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b',
  12574   'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
  12575   'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
  12576 };
  12577 
  12578 /* special version going backwards */
  12579 /* XXX: use dtoa.c */
  12580 static char *js_u64toa(char *q, int64_t n, unsigned int base)
  12581 {
  12582     int digit;
  12583     if (base == 10) {
  12584         /* division by known base uses multiplication */
  12585         do {
  12586             digit = (uint64_t)n % 10;
  12587             n = (uint64_t)n / 10;
  12588             *--q = '0' + digit;
  12589         } while (n != 0);
  12590     } else {
  12591         do {
  12592             digit = (uint64_t)n % base;
  12593             n = (uint64_t)n / base;
  12594             *--q = digits[digit];
  12595         } while (n != 0);
  12596     }
  12597     return q;
  12598 }
  12599 
  12600 /* len >= 1. 2 <= radix <= 36 */
  12601 static char *limb_to_a(char *q, js_limb_t n, unsigned int radix, int len)
  12602 {
  12603     int digit, i;
  12604 
  12605     if (radix == 10) {
  12606         /* specific case with constant divisor */
  12607         /* XXX: optimize */
  12608         for(i = 0; i < len; i++) {
  12609             digit = (js_limb_t)n % 10;
  12610             n = (js_limb_t)n / 10;
  12611             *--q = digit + '0';
  12612         }
  12613     } else {
  12614         for(i = 0; i < len; i++) {
  12615             digit = (js_limb_t)n % radix;
  12616             n = (js_limb_t)n / radix;
  12617             *--q = digits[digit];
  12618         }
  12619     }
  12620     return q;
  12621 }
  12622 
  12623 #define JS_RADIX_MAX 36
  12624 
  12625 static const uint8_t digits_per_limb_table[JS_RADIX_MAX - 1] = {
  12626 #if JS_LIMB_BITS == 32
  12627 32,20,16,13,12,11,10,10, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  12628 #else
  12629 64,40,32,27,24,22,21,20,19,18,17,17,16,16,16,15,15,15,14,14,14,14,13,13,13,13,13,13,13,12,12,12,12,12,12,
  12630 #endif
  12631 };
  12632 
  12633 static const js_limb_t radix_base_table[JS_RADIX_MAX - 1] = {
  12634 #if JS_LIMB_BITS == 32
  12635  0x00000000, 0xcfd41b91, 0x00000000, 0x48c27395,
  12636  0x81bf1000, 0x75db9c97, 0x40000000, 0xcfd41b91,
  12637  0x3b9aca00, 0x8c8b6d2b, 0x19a10000, 0x309f1021,
  12638  0x57f6c100, 0x98c29b81, 0x00000000, 0x18754571,
  12639  0x247dbc80, 0x3547667b, 0x4c4b4000, 0x6b5a6e1d,
  12640  0x94ace180, 0xcaf18367, 0x0b640000, 0x0e8d4a51,
  12641  0x1269ae40, 0x17179149, 0x1cb91000, 0x23744899,
  12642  0x2b73a840, 0x34e63b41, 0x40000000, 0x4cfa3cc1,
  12643  0x5c13d840, 0x6d91b519, 0x81bf1000,
  12644 #else
  12645  0x0000000000000000, 0xa8b8b452291fe821, 0x0000000000000000, 0x6765c793fa10079d,
  12646  0x41c21cb8e1000000, 0x3642798750226111, 0x8000000000000000, 0xa8b8b452291fe821,
  12647  0x8ac7230489e80000, 0x4d28cb56c33fa539, 0x1eca170c00000000, 0x780c7372621bd74d,
  12648  0x1e39a5057d810000, 0x5b27ac993df97701, 0x0000000000000000, 0x27b95e997e21d9f1,
  12649  0x5da0e1e53c5c8000, 0xd2ae3299c1c4aedb, 0x16bcc41e90000000, 0x2d04b7fdd9c0ef49,
  12650  0x5658597bcaa24000, 0xa0e2073737609371, 0x0c29e98000000000, 0x14adf4b7320334b9,
  12651  0x226ed36478bfa000, 0x383d9170b85ff80b, 0x5a3c23e39c000000, 0x8e65137388122bcd,
  12652  0xdd41bb36d259e000, 0x0aee5720ee830681, 0x1000000000000000, 0x172588ad4f5f0981,
  12653  0x211e44f7d02c1000, 0x2ee56725f06e5c71, 0x41c21cb8e1000000,
  12654 #endif
  12655 };
  12656 
  12657 static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix)
  12658 {
  12659     if (JS_VALUE_GET_TAG(val) == JS_TAG_SHORT_BIG_INT) {
  12660         char buf[66];
  12661         int len;
  12662         len = i64toa_radix(buf, JS_VALUE_GET_SHORT_BIG_INT(val), radix);
  12663         return js_new_string8_len(ctx, buf, len);
  12664     } else {
  12665         JSBigInt *r, *tmp = NULL;
  12666         char *buf, *q, *buf_end;
  12667         int is_neg, n_bits, log2_radix, n_digits;
  12668         BOOL is_binary_radix;
  12669         JSValue res;
  12670         
  12671         assert(JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT);
  12672         r = JS_VALUE_GET_PTR(val);
  12673         if (r->len == 1 && r->tab[0] == 0) {
  12674             /* '0' case */
  12675             return js_new_string8_len(ctx, "0", 1);
  12676         }
  12677         is_binary_radix = ((radix & (radix - 1)) == 0);
  12678         is_neg = js_bigint_sign(r);
  12679         if (is_neg) {
  12680             tmp = js_bigint_neg(ctx, r);
  12681             if (!tmp)
  12682                 return JS_EXCEPTION;
  12683             r = tmp;
  12684         } else if (!is_binary_radix) {
  12685             /* need to modify 'r' */
  12686             tmp = js_bigint_new(ctx, r->len);
  12687             if (!tmp)
  12688                 return JS_EXCEPTION;
  12689             memcpy(tmp->tab, r->tab, r->len * sizeof(r->tab[0]));
  12690             r = tmp;
  12691         }
  12692         log2_radix = 31 - clz32(radix); /* floor(log2(radix)) */
  12693         n_bits = r->len * JS_LIMB_BITS - js_limb_safe_clz(r->tab[r->len - 1]);
  12694         /* n_digits is exact only if radix is a power of
  12695            two. Otherwise it is >= the exact number of digits */
  12696         n_digits = (n_bits + log2_radix - 1) / log2_radix;
  12697         /* XXX: could directly build the JSString */
  12698         buf = js_malloc(ctx, n_digits + is_neg + 1);
  12699         if (!buf) {
  12700             js_free(ctx, tmp);
  12701             return JS_EXCEPTION;
  12702         }
  12703         q = buf + n_digits + is_neg + 1;
  12704         *--q = '\0';
  12705         buf_end = q;
  12706         if (!is_binary_radix) {
  12707             int len;
  12708             js_limb_t radix_base, v;
  12709             radix_base = radix_base_table[radix - 2];
  12710             len = r->len;
  12711             for(;;) {
  12712                 /* remove leading zero limbs */
  12713                 while (len > 1 && r->tab[len - 1] == 0)
  12714                     len--;
  12715                 if (len == 1 && r->tab[0] < radix_base) {
  12716                     v = r->tab[0];
  12717                     if (v != 0) {
  12718                         q = js_u64toa(q, v, radix);
  12719                     }
  12720                     break;
  12721                 } else {
  12722                     v = mp_div1(r->tab, r->tab, len, radix_base, 0);
  12723                     q = limb_to_a(q, v, radix, digits_per_limb_table[radix - 2]);
  12724                 }
  12725             }
  12726         } else {
  12727             int i, shift;
  12728             unsigned int bit_pos, pos, c;
  12729 
  12730             /* radix is a power of two */
  12731             for(i = 0; i < n_digits; i++) {
  12732                 bit_pos = i * log2_radix;
  12733                 pos = bit_pos / JS_LIMB_BITS;
  12734                 shift = bit_pos % JS_LIMB_BITS;
  12735                 c = r->tab[pos] >> shift;
  12736                 if ((shift + log2_radix) > JS_LIMB_BITS &&
  12737                     (pos + 1) < r->len) {
  12738                     c |= r->tab[pos + 1] << (JS_LIMB_BITS - shift);
  12739                 }
  12740                 c &= (radix - 1);
  12741                 *--q = digits[c];
  12742             }
  12743         }
  12744         if (is_neg)
  12745             *--q = '-';
  12746         js_free(ctx, tmp);
  12747         res = js_new_string8_len(ctx, q, buf_end - q);
  12748         js_free(ctx, buf);
  12749         return res;
  12750     }
  12751 }
  12752 
  12753 /* if possible transform a BigInt to short big and free it, otherwise
  12754    return a normal bigint */
  12755 static JSValue JS_CompactBigInt(JSContext *ctx, JSBigInt *p)
  12756 {
  12757     JSValue res;
  12758     if (p->len == 1) {
  12759         res = __JS_NewShortBigInt(ctx, (js_slimb_t)p->tab[0]);
  12760         js_free(ctx, p);
  12761         return res;
  12762     } else {
  12763         return JS_MKPTR(JS_TAG_BIG_INT, p);
  12764     }
  12765 }
  12766 
  12767 #define ATOD_INT_ONLY        (1 << 0)
  12768 /* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */
  12769 #define ATOD_ACCEPT_BIN_OCT  (1 << 2)
  12770 /* accept O prefix as octal if radix == 0 and properly formed (Annex B) */
  12771 #define ATOD_ACCEPT_LEGACY_OCTAL  (1 << 4)
  12772 /* accept _ between digits as a digit separator */
  12773 #define ATOD_ACCEPT_UNDERSCORES  (1 << 5)
  12774 /* allow a suffix to override the type */
  12775 #define ATOD_ACCEPT_SUFFIX    (1 << 6)
  12776 /* default type */
  12777 #define ATOD_TYPE_MASK        (3 << 7)
  12778 #define ATOD_TYPE_FLOAT64     (0 << 7)
  12779 #define ATOD_TYPE_BIG_INT     (1 << 7)
  12780 /* accept -0x1 */
  12781 #define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10)
  12782 
  12783 /* return an exception in case of memory error. Return JS_NAN if
  12784    invalid syntax */
  12785 /* XXX: directly use js_atod() */
  12786 static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
  12787                        int radix, int flags)
  12788 {
  12789     const char *p, *p_start;
  12790     int sep, is_neg;
  12791     BOOL is_float, has_legacy_octal;
  12792     int atod_type = flags & ATOD_TYPE_MASK;
  12793     char buf1[64], *buf;
  12794     int i, j, len;
  12795     BOOL buf_allocated = FALSE;
  12796     JSValue val;
  12797     JSATODTempMem atod_mem;
  12798     
  12799     /* optional separator between digits */
  12800     sep = (flags & ATOD_ACCEPT_UNDERSCORES) ? '_' : 256;
  12801     has_legacy_octal = FALSE;
  12802 
  12803     p = str;
  12804     p_start = p;
  12805     is_neg = 0;
  12806     if (p[0] == '+') {
  12807         p++;
  12808         p_start++;
  12809         if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN))
  12810             goto no_radix_prefix;
  12811     } else if (p[0] == '-') {
  12812         p++;
  12813         p_start++;
  12814         is_neg = 1;
  12815         if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN))
  12816             goto no_radix_prefix;
  12817     }
  12818     if (p[0] == '0') {
  12819         if ((p[1] == 'x' || p[1] == 'X') &&
  12820             (radix == 0 || radix == 16)) {
  12821             p += 2;
  12822             radix = 16;
  12823         } else if ((p[1] == 'o' || p[1] == 'O') &&
  12824                    radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) {
  12825             p += 2;
  12826             radix = 8;
  12827         } else if ((p[1] == 'b' || p[1] == 'B') &&
  12828                    radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) {
  12829             p += 2;
  12830             radix = 2;
  12831         } else if ((p[1] >= '0' && p[1] <= '9') &&
  12832                    radix == 0 && (flags & ATOD_ACCEPT_LEGACY_OCTAL)) {
  12833             int i;
  12834             has_legacy_octal = TRUE;
  12835             sep = 256;
  12836             for (i = 1; (p[i] >= '0' && p[i] <= '7'); i++)
  12837                 continue;
  12838             if (p[i] == '8' || p[i] == '9')
  12839                 goto no_prefix;
  12840             p += 1;
  12841             radix = 8;
  12842         } else {
  12843             goto no_prefix;
  12844         }
  12845         /* there must be a digit after the prefix */
  12846         if (to_digit((uint8_t)*p) >= radix)
  12847             goto fail;
  12848     no_prefix: ;
  12849     } else {
  12850  no_radix_prefix:
  12851         if (!(flags & ATOD_INT_ONLY) &&
  12852             (atod_type == ATOD_TYPE_FLOAT64) &&
  12853             strstart(p, "Infinity", &p)) {
  12854             double d = 1.0 / 0.0;
  12855             if (is_neg)
  12856                 d = -d;
  12857             val = JS_NewFloat64(ctx, d);
  12858             goto done;
  12859         }
  12860     }
  12861     if (radix == 0)
  12862         radix = 10;
  12863     is_float = FALSE;
  12864     p_start = p;
  12865     while (to_digit((uint8_t)*p) < radix
  12866            ||  (*p == sep && (radix != 10 ||
  12867                               p != p_start + 1 || p[-1] != '0') &&
  12868                 to_digit((uint8_t)p[1]) < radix)) {
  12869         p++;
  12870     }
  12871     if (!(flags & ATOD_INT_ONLY) && radix == 10) {
  12872         if (*p == '.' && (p > p_start || to_digit((uint8_t)p[1]) < radix)) {
  12873             is_float = TRUE;
  12874             p++;
  12875             if (*p == sep)
  12876                 goto fail;
  12877             while (to_digit((uint8_t)*p) < radix ||
  12878                    (*p == sep && to_digit((uint8_t)p[1]) < radix))
  12879                 p++;
  12880         }
  12881         if (p > p_start && (*p == 'e' || *p == 'E')) {
  12882             const char *p1 = p + 1;
  12883             is_float = TRUE;
  12884             if (*p1 == '+') {
  12885                 p1++;
  12886             } else if (*p1 == '-') {
  12887                 p1++;
  12888             }
  12889             if (is_digit((uint8_t)*p1)) {
  12890                 p = p1 + 1;
  12891                 while (is_digit((uint8_t)*p) || (*p == sep && is_digit((uint8_t)p[1])))
  12892                     p++;
  12893             }
  12894         }
  12895     }
  12896     if (p == p_start)
  12897         goto fail;
  12898 
  12899     buf = buf1;
  12900     buf_allocated = FALSE;
  12901     len = p - p_start;
  12902     if (unlikely((len + 2) > sizeof(buf1))) {
  12903         buf = js_malloc_rt(ctx->rt, len + 2); /* no exception raised */
  12904         if (!buf)
  12905             goto mem_error;
  12906         buf_allocated = TRUE;
  12907     }
  12908     /* remove the separators and the radix prefixes */
  12909     j = 0;
  12910     if (is_neg)
  12911         buf[j++] = '-';
  12912     for (i = 0; i < len; i++) {
  12913         if (p_start[i] != '_')
  12914             buf[j++] = p_start[i];
  12915     }
  12916     buf[j] = '\0';
  12917 
  12918     if ((flags & ATOD_ACCEPT_SUFFIX) && *p == 'n') {
  12919         p++;
  12920         atod_type = ATOD_TYPE_BIG_INT;
  12921     }
  12922 
  12923     switch(atod_type) {
  12924     case ATOD_TYPE_FLOAT64:
  12925         {
  12926             double d;
  12927             d = js_atod(buf, NULL, radix, is_float ? 0 : JS_ATOD_INT_ONLY,
  12928                         &atod_mem);
  12929             /* return int or float64 */
  12930             val = JS_NewFloat64(ctx, d);
  12931         }
  12932         break;
  12933     case ATOD_TYPE_BIG_INT:
  12934         {
  12935             JSBigInt *r;
  12936             if (has_legacy_octal || is_float)
  12937                 goto fail;
  12938             r = js_bigint_from_string(ctx, buf, radix);
  12939             if (!r) {
  12940                 val = JS_EXCEPTION;
  12941                 goto done;
  12942             }
  12943             val = JS_CompactBigInt(ctx, r);
  12944         }
  12945         break;
  12946     default:
  12947         abort();
  12948     }
  12949 
  12950 done:
  12951     if (buf_allocated)
  12952         js_free_rt(ctx->rt, buf);
  12953     if (pp)
  12954         *pp = p;
  12955     return val;
  12956  fail:
  12957     val = JS_NAN;
  12958     goto done;
  12959  mem_error:
  12960     val = JS_ThrowOutOfMemory(ctx);
  12961     goto done;
  12962 }
  12963 
  12964 typedef enum JSToNumberHintEnum {
  12965     TON_FLAG_NUMBER,
  12966     TON_FLAG_NUMERIC,
  12967 } JSToNumberHintEnum;
  12968 
  12969 static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val,
  12970                                    JSToNumberHintEnum flag)
  12971 {
  12972     uint32_t tag;
  12973     JSValue ret;
  12974 
  12975  redo:
  12976     tag = JS_VALUE_GET_NORM_TAG(val);
  12977     switch(tag) {
  12978     case JS_TAG_BIG_INT:
  12979     case JS_TAG_SHORT_BIG_INT:
  12980         if (flag != TON_FLAG_NUMERIC) {
  12981             JS_FreeValue(ctx, val);
  12982             return JS_ThrowTypeError(ctx, "cannot convert bigint to number");
  12983         }
  12984         ret = val;
  12985         break;
  12986     case JS_TAG_FLOAT64:
  12987     case JS_TAG_INT:
  12988     case JS_TAG_EXCEPTION:
  12989         ret = val;
  12990         break;
  12991     case JS_TAG_BOOL:
  12992     case JS_TAG_NULL:
  12993         ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));
  12994         break;
  12995     case JS_TAG_UNDEFINED:
  12996         ret = JS_NAN;
  12997         break;
  12998     case JS_TAG_OBJECT:
  12999         val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
  13000         if (JS_IsException(val))
  13001             return JS_EXCEPTION;
  13002         goto redo;
  13003     case JS_TAG_STRING:
  13004     case JS_TAG_STRING_ROPE:
  13005         {
  13006             const char *str;
  13007             const char *p;
  13008             size_t len;
  13009 
  13010             str = JS_ToCStringLen(ctx, &len, val);
  13011             JS_FreeValue(ctx, val);
  13012             if (!str)
  13013                 return JS_EXCEPTION;
  13014             p = str;
  13015             p += skip_spaces(p);
  13016             if ((p - str) == len) {
  13017                 ret = JS_NewInt32(ctx, 0);
  13018             } else {
  13019                 int flags = ATOD_ACCEPT_BIN_OCT;
  13020                 ret = js_atof(ctx, p, &p, 0, flags);
  13021                 if (!JS_IsException(ret)) {
  13022                     p += skip_spaces(p);
  13023                     if ((p - str) != len) {
  13024                         JS_FreeValue(ctx, ret);
  13025                         ret = JS_NAN;
  13026                     }
  13027                 }
  13028             }
  13029             JS_FreeCString(ctx, str);
  13030         }
  13031         break;
  13032     case JS_TAG_SYMBOL:
  13033         JS_FreeValue(ctx, val);
  13034         return JS_ThrowTypeError(ctx, "cannot convert symbol to number");
  13035     default:
  13036         JS_FreeValue(ctx, val);
  13037         ret = JS_NAN;
  13038         break;
  13039     }
  13040     return ret;
  13041 }
  13042 
  13043 static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val)
  13044 {
  13045     return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMBER);
  13046 }
  13047 
  13048 static JSValue JS_ToNumericFree(JSContext *ctx, JSValue val)
  13049 {
  13050     return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC);
  13051 }
  13052 
  13053 static JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val)
  13054 {
  13055     return JS_ToNumericFree(ctx, JS_DupValue(ctx, val));
  13056 }
  13057 
  13058 static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres,
  13059                                           JSValue val)
  13060 {
  13061     double d;
  13062     uint32_t tag;
  13063     
  13064     val = JS_ToNumberFree(ctx, val);
  13065     if (JS_IsException(val))
  13066         goto fail;
  13067     tag = JS_VALUE_GET_NORM_TAG(val);
  13068     switch(tag) {
  13069     case JS_TAG_INT:
  13070         d = JS_VALUE_GET_INT(val);
  13071         break;
  13072     case JS_TAG_FLOAT64:
  13073         d = JS_VALUE_GET_FLOAT64(val);
  13074         break;
  13075     default:
  13076         abort();
  13077     }
  13078     *pres = d;
  13079     return 0;
  13080  fail:
  13081     *pres = JS_FLOAT64_NAN;
  13082     return -1;
  13083 }
  13084 
  13085 static inline int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val)
  13086 {
  13087     uint32_t tag;
  13088 
  13089     tag = JS_VALUE_GET_TAG(val);
  13090     if (tag <= JS_TAG_NULL) {
  13091         *pres = JS_VALUE_GET_INT(val);
  13092         return 0;
  13093     } else if (JS_TAG_IS_FLOAT64(tag)) {
  13094         *pres = JS_VALUE_GET_FLOAT64(val);
  13095         return 0;
  13096     } else {
  13097         return __JS_ToFloat64Free(ctx, pres, val);
  13098     }
  13099 }
  13100 
  13101 int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val)
  13102 {
  13103     return JS_ToFloat64Free(ctx, pres, JS_DupValue(ctx, val));
  13104 }
  13105 
  13106 static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val)
  13107 {
  13108     return JS_ToNumberFree(ctx, JS_DupValue(ctx, val));
  13109 }
  13110 
  13111 /* same as JS_ToNumber() but return 0 in case of NaN/Undefined */
  13112 static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
  13113 {
  13114     uint32_t tag;
  13115     JSValue ret;
  13116 
  13117  redo:
  13118     tag = JS_VALUE_GET_NORM_TAG(val);
  13119     switch(tag) {
  13120     case JS_TAG_INT:
  13121     case JS_TAG_BOOL:
  13122     case JS_TAG_NULL:
  13123     case JS_TAG_UNDEFINED:
  13124         ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));
  13125         break;
  13126     case JS_TAG_FLOAT64:
  13127         {
  13128             double d = JS_VALUE_GET_FLOAT64(val);
  13129             if (isnan(d)) {
  13130                 ret = JS_NewInt32(ctx, 0);
  13131             } else {
  13132                 /* convert -0 to +0 */
  13133                 d = trunc(d) + 0.0;
  13134                 ret = JS_NewFloat64(ctx, d);
  13135             }
  13136         }
  13137         break;
  13138     default:
  13139         val = JS_ToNumberFree(ctx, val);
  13140         if (JS_IsException(val))
  13141             return val;
  13142         goto redo;
  13143     }
  13144     return ret;
  13145 }
  13146 
  13147 /* Note: the integer value is satured to 32 bits */
  13148 static int JS_ToInt32SatFree(JSContext *ctx, int *pres, JSValue val)
  13149 {
  13150     uint32_t tag;
  13151     int ret;
  13152 
  13153  redo:
  13154     tag = JS_VALUE_GET_NORM_TAG(val);
  13155     switch(tag) {
  13156     case JS_TAG_INT:
  13157     case JS_TAG_BOOL:
  13158     case JS_TAG_NULL:
  13159     case JS_TAG_UNDEFINED:
  13160         ret = JS_VALUE_GET_INT(val);
  13161         break;
  13162     case JS_TAG_EXCEPTION:
  13163         *pres = 0;
  13164         return -1;
  13165     case JS_TAG_FLOAT64:
  13166         {
  13167             double d = JS_VALUE_GET_FLOAT64(val);
  13168             if (isnan(d)) {
  13169                 ret = 0;
  13170             } else {
  13171                 if (d < INT32_MIN)
  13172                     ret = INT32_MIN;
  13173                 else if (d > INT32_MAX)
  13174                     ret = INT32_MAX;
  13175                 else
  13176                     ret = (int)d;
  13177             }
  13178         }
  13179         break;
  13180     default:
  13181         val = JS_ToNumberFree(ctx, val);
  13182         if (JS_IsException(val)) {
  13183             *pres = 0;
  13184             return -1;
  13185         }
  13186         goto redo;
  13187     }
  13188     *pres = ret;
  13189     return 0;
  13190 }
  13191 
  13192 int JS_ToInt32Sat(JSContext *ctx, int *pres, JSValueConst val)
  13193 {
  13194     return JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val));
  13195 }
  13196 
  13197 int JS_ToInt32Clamp(JSContext *ctx, int *pres, JSValueConst val,
  13198                     int min, int max, int min_offset)
  13199 {
  13200     int res = JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val));
  13201     if (res == 0) {
  13202         if (*pres < min) {
  13203             *pres += min_offset;
  13204             if (*pres < min)
  13205                 *pres = min;
  13206         } else {
  13207             if (*pres > max)
  13208                 *pres = max;
  13209         }
  13210     }
  13211     return res;
  13212 }
  13213 
  13214 static int JS_ToInt64SatFree(JSContext *ctx, int64_t *pres, JSValue val)
  13215 {
  13216     uint32_t tag;
  13217 
  13218  redo:
  13219     tag = JS_VALUE_GET_NORM_TAG(val);
  13220     switch(tag) {
  13221     case JS_TAG_INT:
  13222     case JS_TAG_BOOL:
  13223     case JS_TAG_NULL:
  13224     case JS_TAG_UNDEFINED:
  13225         *pres = JS_VALUE_GET_INT(val);
  13226         return 0;
  13227     case JS_TAG_EXCEPTION:
  13228         *pres = 0;
  13229         return -1;
  13230     case JS_TAG_FLOAT64:
  13231         {
  13232             double d = JS_VALUE_GET_FLOAT64(val);
  13233             if (isnan(d)) {
  13234                 *pres = 0;
  13235             } else {
  13236                 if (d < INT64_MIN)
  13237                     *pres = INT64_MIN;
  13238                 else if (d >= 0x1p63) /* must use INT64_MAX + 1 because INT64_MAX cannot be exactly represented as a double */
  13239                     *pres = INT64_MAX;
  13240                 else
  13241                     *pres = (int64_t)d;
  13242             }
  13243         }
  13244         return 0;
  13245     default:
  13246         val = JS_ToNumberFree(ctx, val);
  13247         if (JS_IsException(val)) {
  13248             *pres = 0;
  13249             return -1;
  13250         }
  13251         goto redo;
  13252     }
  13253 }
  13254 
  13255 int JS_ToInt64Sat(JSContext *ctx, int64_t *pres, JSValueConst val)
  13256 {
  13257     return JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val));
  13258 }
  13259 
  13260 int JS_ToInt64Clamp(JSContext *ctx, int64_t *pres, JSValueConst val,
  13261                     int64_t min, int64_t max, int64_t neg_offset)
  13262 {
  13263     int res = JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val));
  13264     if (res == 0) {
  13265         if (*pres < 0)
  13266             *pres += neg_offset;
  13267         if (*pres < min)
  13268             *pres = min;
  13269         else if (*pres > max)
  13270             *pres = max;
  13271     }
  13272     return res;
  13273 }
  13274 
  13275 /* Same as JS_ToInt32Free() but with a 64 bit result. Return (<0, 0)
  13276    in case of exception */
  13277 static int JS_ToInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
  13278 {
  13279     uint32_t tag;
  13280     int64_t ret;
  13281 
  13282  redo:
  13283     tag = JS_VALUE_GET_NORM_TAG(val);
  13284     switch(tag) {
  13285     case JS_TAG_INT:
  13286     case JS_TAG_BOOL:
  13287     case JS_TAG_NULL:
  13288     case JS_TAG_UNDEFINED:
  13289         ret = JS_VALUE_GET_INT(val);
  13290         break;
  13291     case JS_TAG_FLOAT64:
  13292         {
  13293             JSFloat64Union u;
  13294             double d;
  13295             int e;
  13296             d = JS_VALUE_GET_FLOAT64(val);
  13297             u.d = d;
  13298             /* we avoid doing fmod(x, 2^64) */
  13299             e = (u.u64 >> 52) & 0x7ff;
  13300             if (likely(e <= (1023 + 62))) {
  13301                 /* fast case */
  13302                 ret = (int64_t)d;
  13303             } else if (e <= (1023 + 62 + 53)) {
  13304                 uint64_t v;
  13305                 /* remainder modulo 2^64 */
  13306                 v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);
  13307                 ret = v << ((e - 1023) - 52);
  13308                 /* take the sign into account */
  13309                 if (u.u64 >> 63)
  13310                     ret = -ret;
  13311             } else {
  13312                 ret = 0; /* also handles NaN and +inf */
  13313             }
  13314         }
  13315         break;
  13316     default:
  13317         val = JS_ToNumberFree(ctx, val);
  13318         if (JS_IsException(val)) {
  13319             *pres = 0;
  13320             return -1;
  13321         }
  13322         goto redo;
  13323     }
  13324     *pres = ret;
  13325     return 0;
  13326 }
  13327 
  13328 int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
  13329 {
  13330     return JS_ToInt64Free(ctx, pres, JS_DupValue(ctx, val));
  13331 }
  13332 
  13333 int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val)
  13334 {
  13335     if (JS_IsBigInt(ctx, val))
  13336         return JS_ToBigInt64(ctx, pres, val);
  13337     else
  13338         return JS_ToInt64(ctx, pres, val);
  13339 }
  13340 
  13341 /* return (<0, 0) in case of exception */
  13342 static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val)
  13343 {
  13344     uint32_t tag;
  13345     int32_t ret;
  13346 
  13347  redo:
  13348     tag = JS_VALUE_GET_NORM_TAG(val);
  13349     switch(tag) {
  13350     case JS_TAG_INT:
  13351     case JS_TAG_BOOL:
  13352     case JS_TAG_NULL:
  13353     case JS_TAG_UNDEFINED:
  13354         ret = JS_VALUE_GET_INT(val);
  13355         break;
  13356     case JS_TAG_FLOAT64:
  13357         {
  13358             JSFloat64Union u;
  13359             double d;
  13360             int e;
  13361             d = JS_VALUE_GET_FLOAT64(val);
  13362             u.d = d;
  13363             /* we avoid doing fmod(x, 2^32) */
  13364             e = (u.u64 >> 52) & 0x7ff;
  13365             if (likely(e <= (1023 + 30))) {
  13366                 /* fast case */
  13367                 ret = (int32_t)d;
  13368             } else if (e <= (1023 + 30 + 53)) {
  13369                 uint64_t v;
  13370                 /* remainder modulo 2^32 */
  13371                 v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);
  13372                 v = v << ((e - 1023) - 52 + 32);
  13373                 ret = v >> 32;
  13374                 /* take the sign into account */
  13375                 if (u.u64 >> 63)
  13376                     ret = -ret;
  13377             } else {
  13378                 ret = 0; /* also handles NaN and +inf */
  13379             }
  13380         }
  13381         break;
  13382     default:
  13383         val = JS_ToNumberFree(ctx, val);
  13384         if (JS_IsException(val)) {
  13385             *pres = 0;
  13386             return -1;
  13387         }
  13388         goto redo;
  13389     }
  13390     *pres = ret;
  13391     return 0;
  13392 }
  13393 
  13394 int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val)
  13395 {
  13396     return JS_ToInt32Free(ctx, pres, JS_DupValue(ctx, val));
  13397 }
  13398 
  13399 static inline int JS_ToUint32Free(JSContext *ctx, uint32_t *pres, JSValue val)
  13400 {
  13401     return JS_ToInt32Free(ctx, (int32_t *)pres, val);
  13402 }
  13403 
  13404 static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val)
  13405 {
  13406     uint32_t tag;
  13407     int res;
  13408 
  13409  redo:
  13410     tag = JS_VALUE_GET_NORM_TAG(val);
  13411     switch(tag) {
  13412     case JS_TAG_INT:
  13413     case JS_TAG_BOOL:
  13414     case JS_TAG_NULL:
  13415     case JS_TAG_UNDEFINED:
  13416         res = JS_VALUE_GET_INT(val);
  13417         res = max_int(0, min_int(255, res));
  13418         break;
  13419     case JS_TAG_FLOAT64:
  13420         {
  13421             double d = JS_VALUE_GET_FLOAT64(val);
  13422             if (isnan(d)) {
  13423                 res = 0;
  13424             } else {
  13425                 if (d < 0)
  13426                     res = 0;
  13427                 else if (d > 255)
  13428                     res = 255;
  13429                 else
  13430                     res = lrint(d);
  13431             }
  13432         }
  13433         break;
  13434     default:
  13435         val = JS_ToNumberFree(ctx, val);
  13436         if (JS_IsException(val)) {
  13437             *pres = 0;
  13438             return -1;
  13439         }
  13440         goto redo;
  13441     }
  13442     *pres = res;
  13443     return 0;
  13444 }
  13445 
  13446 static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
  13447                                             JSValue val, BOOL is_array_ctor)
  13448 {
  13449     uint32_t tag, len;
  13450 
  13451     tag = JS_VALUE_GET_TAG(val);
  13452     switch(tag) {
  13453     case JS_TAG_INT:
  13454     case JS_TAG_BOOL:
  13455     case JS_TAG_NULL:
  13456         {
  13457             int v;
  13458             v = JS_VALUE_GET_INT(val);
  13459             if (v < 0)
  13460                 goto fail;
  13461             len = v;
  13462         }
  13463         break;
  13464     default:
  13465         if (JS_TAG_IS_FLOAT64(tag)) {
  13466             double d;
  13467             d = JS_VALUE_GET_FLOAT64(val);
  13468             if (!(d >= 0 && d <= UINT32_MAX))
  13469                 goto fail;
  13470             len = (uint32_t)d;
  13471             if (len != d)
  13472                 goto fail;
  13473         } else {
  13474             uint32_t len1;
  13475 
  13476             if (is_array_ctor) {
  13477                 val = JS_ToNumberFree(ctx, val);
  13478                 if (JS_IsException(val))
  13479                     return -1;
  13480                 /* cannot recurse because val is a number */
  13481                 if (JS_ToArrayLengthFree(ctx, &len, val, TRUE))
  13482                     return -1;
  13483             } else {
  13484                 /* legacy behavior: must do the conversion twice and compare */
  13485                 if (JS_ToUint32(ctx, &len, val)) {
  13486                     JS_FreeValue(ctx, val);
  13487                     return -1;
  13488                 }
  13489                 val = JS_ToNumberFree(ctx, val);
  13490                 if (JS_IsException(val))
  13491                     return -1;
  13492                 /* cannot recurse because val is a number */
  13493                 if (JS_ToArrayLengthFree(ctx, &len1, val, FALSE))
  13494                     return -1;
  13495                 if (len1 != len) {
  13496                 fail:
  13497                     JS_ThrowRangeError(ctx, "invalid array length");
  13498                     return -1;
  13499                 }
  13500             }
  13501         }
  13502         break;
  13503     }
  13504     *plen = len;
  13505     return 0;
  13506 }
  13507 
  13508 #define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1)
  13509 
  13510 static BOOL is_safe_integer(double d)
  13511 {
  13512     return isfinite(d) && floor(d) == d &&
  13513         fabs(d) <= (double)MAX_SAFE_INTEGER;
  13514 }
  13515 
  13516 int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val)
  13517 {
  13518     int64_t v;
  13519     if (JS_ToInt64Sat(ctx, &v, val))
  13520         return -1;
  13521     if (v < 0 || v > MAX_SAFE_INTEGER) {
  13522         JS_ThrowRangeError(ctx, "invalid array index");
  13523         *plen = 0;
  13524         return -1;
  13525     }
  13526     *plen = v;
  13527     return 0;
  13528 }
  13529 
  13530 /* convert a value to a length between 0 and MAX_SAFE_INTEGER.
  13531    return -1 for exception */
  13532 static __exception int JS_ToLengthFree(JSContext *ctx, int64_t *plen,
  13533                                        JSValue val)
  13534 {
  13535     int res = JS_ToInt64Clamp(ctx, plen, val, 0, MAX_SAFE_INTEGER, 0);
  13536     JS_FreeValue(ctx, val);
  13537     return res;
  13538 }
  13539 
  13540 /* Note: can return an exception */
  13541 static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val)
  13542 {
  13543     double d;
  13544     if (!JS_IsNumber(val))
  13545         return FALSE;
  13546     if (unlikely(JS_ToFloat64(ctx, &d, val)))
  13547         return -1;
  13548     return isfinite(d) && floor(d) == d;
  13549 }
  13550 
  13551 static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val)
  13552 {
  13553     uint32_t tag;
  13554 
  13555     tag = JS_VALUE_GET_NORM_TAG(val);
  13556     switch(tag) {
  13557     case JS_TAG_INT:
  13558         {
  13559             int v;
  13560             v = JS_VALUE_GET_INT(val);
  13561             return (v < 0);
  13562         }
  13563     case JS_TAG_FLOAT64:
  13564         {
  13565             JSFloat64Union u;
  13566             u.d = JS_VALUE_GET_FLOAT64(val);
  13567             return (u.u64 >> 63);
  13568         }
  13569     case JS_TAG_SHORT_BIG_INT:
  13570         return (JS_VALUE_GET_SHORT_BIG_INT(val) < 0);
  13571     case JS_TAG_BIG_INT:
  13572         {
  13573             JSBigInt *p = JS_VALUE_GET_PTR(val);
  13574             return js_bigint_sign(p);
  13575         }
  13576     default:
  13577         return FALSE;
  13578     }
  13579 }
  13580 
  13581 static JSValue js_bigint_to_string(JSContext *ctx, JSValueConst val)
  13582 {
  13583     return js_bigint_to_string1(ctx, val, 10);
  13584 }
  13585 
  13586 static JSValue js_dtoa2(JSContext *ctx,
  13587                         double d, int radix, int n_digits, int flags)
  13588 {
  13589     char static_buf[128], *buf, *tmp_buf;
  13590     int len, len_max;
  13591     JSValue res;
  13592     JSDTOATempMem dtoa_mem;
  13593     len_max = js_dtoa_max_len(d, radix, n_digits, flags);
  13594     
  13595     /* longer buffer may be used if radix != 10 */
  13596     if (len_max > sizeof(static_buf) - 1) {
  13597         tmp_buf = js_malloc(ctx, len_max + 1);
  13598         if (!tmp_buf)
  13599             return JS_EXCEPTION;
  13600         buf = tmp_buf;
  13601     } else {
  13602         tmp_buf = NULL;
  13603         buf = static_buf;
  13604     }
  13605     len = js_dtoa(buf, d, radix, n_digits, flags, &dtoa_mem);
  13606     res = js_new_string8_len(ctx, buf, len);
  13607     js_free(ctx, tmp_buf);
  13608     return res;
  13609 }
  13610 
  13611 static JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToPropertyKey)
  13612 {
  13613     uint32_t tag;
  13614     char buf[32];
  13615 
  13616     tag = JS_VALUE_GET_NORM_TAG(val);
  13617     switch(tag) {
  13618     case JS_TAG_STRING:
  13619         return JS_DupValue(ctx, val);
  13620     case JS_TAG_STRING_ROPE:
  13621         return js_linearize_string_rope(ctx, JS_DupValue(ctx, val));
  13622     case JS_TAG_INT:
  13623         {
  13624             size_t len;
  13625             len = i32toa(buf, JS_VALUE_GET_INT(val));
  13626             return js_new_string8_len(ctx, buf, len);
  13627         }
  13628         break;
  13629     case JS_TAG_BOOL:
  13630         return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ?
  13631                           JS_ATOM_true : JS_ATOM_false);
  13632     case JS_TAG_NULL:
  13633         return JS_AtomToString(ctx, JS_ATOM_null);
  13634     case JS_TAG_UNDEFINED:
  13635         return JS_AtomToString(ctx, JS_ATOM_undefined);
  13636     case JS_TAG_EXCEPTION:
  13637         return JS_EXCEPTION;
  13638     case JS_TAG_OBJECT:
  13639         {
  13640             JSValue val1, ret;
  13641             val1 = JS_ToPrimitive(ctx, val, HINT_STRING);
  13642             if (JS_IsException(val1))
  13643                 return val1;
  13644             ret = JS_ToStringInternal(ctx, val1, is_ToPropertyKey);
  13645             JS_FreeValue(ctx, val1);
  13646             return ret;
  13647         }
  13648         break;
  13649     case JS_TAG_FUNCTION_BYTECODE:
  13650         return js_new_string8(ctx, "[function bytecode]");
  13651     case JS_TAG_SYMBOL:
  13652         if (is_ToPropertyKey) {
  13653             return JS_DupValue(ctx, val);
  13654         } else {
  13655             return JS_ThrowTypeError(ctx, "cannot convert symbol to string");
  13656         }
  13657     case JS_TAG_FLOAT64:
  13658         return js_dtoa2(ctx, JS_VALUE_GET_FLOAT64(val), 10, 0,
  13659                         JS_DTOA_FORMAT_FREE);
  13660     case JS_TAG_SHORT_BIG_INT:
  13661     case JS_TAG_BIG_INT:
  13662         return js_bigint_to_string(ctx, val);
  13663     default:
  13664         return js_new_string8(ctx, "[unsupported type]");
  13665     }
  13666 }
  13667 
  13668 JSValue JS_ToString(JSContext *ctx, JSValueConst val)
  13669 {
  13670     return JS_ToStringInternal(ctx, val, FALSE);
  13671 }
  13672 
  13673 static JSValue JS_ToStringFree(JSContext *ctx, JSValue val)
  13674 {
  13675     JSValue ret;
  13676     ret = JS_ToString(ctx, val);
  13677     JS_FreeValue(ctx, val);
  13678     return ret;
  13679 }
  13680 
  13681 static JSValue JS_ToLocaleStringFree(JSContext *ctx, JSValue val)
  13682 {
  13683     if (JS_IsUndefined(val) || JS_IsNull(val))
  13684         return JS_ToStringFree(ctx, val);
  13685     return JS_InvokeFree(ctx, val, JS_ATOM_toLocaleString, 0, NULL);
  13686 }
  13687 
  13688 JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val)
  13689 {
  13690     return JS_ToStringInternal(ctx, val, TRUE);
  13691 }
  13692 
  13693 static JSValue JS_ToStringCheckObject(JSContext *ctx, JSValueConst val)
  13694 {
  13695     uint32_t tag = JS_VALUE_GET_TAG(val);
  13696     if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)
  13697         return JS_ThrowTypeError(ctx, "null or undefined are forbidden");
  13698     return JS_ToString(ctx, val);
  13699 }
  13700 
  13701 #define JS_PRINT_MAX_DEPTH 8
  13702 
  13703 typedef struct {
  13704     JSRuntime *rt;
  13705     JSContext *ctx; /* may be NULL */
  13706     JSPrintValueOptions options;
  13707     JSPrintValueWrite *write_func;
  13708     void *write_opaque;
  13709     int level;
  13710     JSObject *print_stack[JS_PRINT_MAX_DEPTH]; /* level values */
  13711 } JSPrintValueState;
  13712 
  13713 static void js_print_value(JSPrintValueState *s, JSValueConst val);
  13714 
  13715 static void js_putc(JSPrintValueState *s, char c)
  13716 {
  13717     s->write_func(s->write_opaque, &c, 1);
  13718 }
  13719 
  13720 static void js_puts(JSPrintValueState *s, const char *str)
  13721 {
  13722     s->write_func(s->write_opaque, str, strlen(str));
  13723 }
  13724 
  13725 static void __attribute__((format(printf, 2, 3))) js_printf(JSPrintValueState *s, const char *fmt, ...)
  13726 {
  13727     va_list ap;
  13728     char buf[256];
  13729     
  13730     va_start(ap, fmt);
  13731     vsnprintf(buf, sizeof(buf), fmt, ap);
  13732     va_end(ap);
  13733     s->write_func(s->write_opaque, buf, strlen(buf));
  13734 }
  13735 
  13736 static void js_print_float64(JSPrintValueState *s, double d)
  13737 {
  13738     JSDTOATempMem dtoa_mem;
  13739     char buf[32];
  13740     int len;
  13741     len = js_dtoa(buf, d, 10, 0, JS_DTOA_FORMAT_FREE | JS_DTOA_MINUS_ZERO, &dtoa_mem);
  13742     s->write_func(s->write_opaque, buf, len);
  13743 }
  13744 
  13745 static uint32_t js_string_get_length(JSValueConst val)
  13746 {
  13747     if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
  13748         JSString *p = JS_VALUE_GET_STRING(val);
  13749         return p->len;
  13750     } else if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING_ROPE) {
  13751         JSStringRope *r = JS_VALUE_GET_PTR(val);
  13752         return r->len;
  13753     } else {
  13754         return 0;
  13755     }
  13756 }
  13757 
  13758 /* pretty print the first 'len' characters of 'p' */
  13759 static void js_print_string1(JSPrintValueState *s, JSString *p, int len, int sep)
  13760 {
  13761     uint8_t buf[UTF8_CHAR_LEN_MAX];
  13762     int l, i, c, c1;
  13763 
  13764     for(i = 0; i < len; i++) {
  13765         c = string_get(p, i);
  13766         switch(c) {
  13767         case '\t':
  13768             c = 't';
  13769             goto quote;
  13770         case '\r':
  13771             c = 'r';
  13772             goto quote;
  13773         case '\n':
  13774             c = 'n';
  13775             goto quote;
  13776         case '\b':
  13777             c = 'b';
  13778             goto quote;
  13779         case '\f':
  13780             c = 'f';
  13781             goto quote;
  13782         case '\\':
  13783         quote:
  13784             js_putc(s, '\\');
  13785             js_putc(s, c);
  13786             break;
  13787         default:
  13788             if (c == sep)
  13789                 goto quote;
  13790             if (c >= 32 && c <= 126) {
  13791                 js_putc(s, c);
  13792             } else if (c < 32 || 
  13793                        (c >= 0x7f && c <= 0x9f)) {
  13794             escape:
  13795                 js_printf(s, "\\u%04x", c);
  13796             } else {
  13797                 if (is_hi_surrogate(c)) {
  13798                     if ((i + 1) >= len)
  13799                         goto escape;
  13800                     c1 = string_get(p, i + 1);
  13801                     if (!is_lo_surrogate(c1))
  13802                         goto escape;
  13803                     i++;
  13804                     c = from_surrogate(c, c1);
  13805                 } else if (is_lo_surrogate(c)) {
  13806                     goto escape;
  13807                 }
  13808                 l = unicode_to_utf8(buf, c);
  13809                 s->write_func(s->write_opaque, (char *)buf, l);
  13810             }
  13811             break;
  13812         }
  13813     }
  13814 }
  13815 
  13816 static void js_print_string_rec(JSPrintValueState *s, JSValueConst val,
  13817                                 int sep, uint32_t pos)
  13818 {
  13819     if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
  13820         JSString *p = JS_VALUE_GET_STRING(val);
  13821         uint32_t len;
  13822         if (pos < s->options.max_string_length) {
  13823             len = min_uint32(p->len, s->options.max_string_length - pos);
  13824             js_print_string1(s, p, len, sep);
  13825         }
  13826     } else if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING_ROPE) {
  13827         JSStringRope *r = JS_VALUE_GET_PTR(val);
  13828         js_print_string_rec(s, r->left, sep, pos);
  13829         js_print_string_rec(s, r->right, sep, pos + js_string_get_length(r->left));
  13830     } else {
  13831         js_printf(s, "<invalid string tag %d>", (int)JS_VALUE_GET_TAG(val));
  13832     }
  13833 }
  13834 
  13835 static void js_print_string(JSPrintValueState *s, JSValueConst val)
  13836 {
  13837     int sep;
  13838     if (s->options.raw_dump && JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
  13839         JSString *p = JS_VALUE_GET_STRING(val);
  13840         js_printf(s, "%d", js_rc(p)->ref_count);
  13841         sep = (js_rc(p)->ref_count == 1) ? '\"' : '\'';
  13842     } else {
  13843         sep = '\"';
  13844     }
  13845     js_putc(s, sep);
  13846     js_print_string_rec(s, val, sep, 0);
  13847     js_putc(s, sep);
  13848     if (js_string_get_length(val) > s->options.max_string_length) {
  13849         uint32_t n = js_string_get_length(val) - s->options.max_string_length;
  13850         js_printf(s, "... %u more character%s", n, n > 1 ? "s" : "");
  13851     }
  13852 }
  13853 
  13854 static void js_print_raw_string(JSPrintValueState *s, JSValueConst val)
  13855 {
  13856     const char *cstr;
  13857     size_t len;
  13858     cstr = JS_ToCStringLen(s->ctx, &len, val);
  13859     if (cstr) {
  13860         s->write_func(s->write_opaque, cstr, len);
  13861         JS_FreeCString(s->ctx, cstr);
  13862     }
  13863 }
  13864 
  13865 static BOOL is_ascii_ident(const JSString *p)
  13866 {
  13867     int i, c;
  13868 
  13869     if (p->len == 0)
  13870         return FALSE;
  13871     for(i = 0; i < p->len; i++) {
  13872         c = string_get(p, i);
  13873         if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
  13874               (c == '_' || c == '$') || (c >= '0' && c <= '9' && i > 0)))
  13875             return FALSE;
  13876     }
  13877     return TRUE;
  13878 }
  13879 
  13880 static void js_print_atom(JSPrintValueState *s, JSAtom atom)
  13881 {
  13882     int i;
  13883     if (__JS_AtomIsTaggedInt(atom)) {
  13884         js_printf(s, "%u", __JS_AtomToUInt32(atom));
  13885     } else if (atom == JS_ATOM_NULL) {
  13886         js_puts(s, "<null>");
  13887     } else {
  13888         assert(atom < s->rt->atom_size);
  13889         JSString *p;
  13890         p = s->rt->atom_array[atom];
  13891         if (is_ascii_ident(p)) {
  13892             for(i = 0; i < p->len; i++) {
  13893                 js_putc(s, string_get(p, i));
  13894             }
  13895         } else {
  13896             js_putc(s, '"');
  13897             js_print_string1(s, p, p->len, '\"');
  13898             js_putc(s, '"');
  13899         }
  13900     }
  13901 }
  13902 
  13903 /* return 0 if invalid length */
  13904 static uint32_t js_print_array_get_length(JSObject *p)
  13905 {
  13906     JSProperty *pr;
  13907     JSShapeProperty *prs;
  13908     JSValueConst val;
  13909 
  13910     prs = find_own_property(&pr, p, JS_ATOM_length);
  13911     if (!prs)
  13912         return 0;
  13913     if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
  13914         return 0;
  13915     val = pr->u.value;
  13916     switch(JS_VALUE_GET_NORM_TAG(val)) {
  13917     case JS_TAG_INT:
  13918         return JS_VALUE_GET_INT(val);
  13919     case JS_TAG_FLOAT64:
  13920         return (uint32_t)JS_VALUE_GET_FLOAT64(val);
  13921     default:
  13922         return 0;
  13923     }
  13924 }
  13925 
  13926 static void js_print_comma(JSPrintValueState *s, int *pcomma_state)
  13927 {
  13928     switch(*pcomma_state) {
  13929     case 0:
  13930         break;
  13931     case 1:
  13932         js_printf(s, ", ");
  13933         break;
  13934     case 2:
  13935         js_printf(s, " { ");
  13936         break;
  13937     }
  13938     *pcomma_state = 1;
  13939 }
  13940 
  13941 static void js_print_more_items(JSPrintValueState *s, int *pcomma_state,
  13942                                 uint32_t n)
  13943 {
  13944     js_print_comma(s, pcomma_state);
  13945     js_printf(s, "... %u more item%s", n, n > 1 ? "s" : "");
  13946 }
  13947 
  13948 /* similar to js_regexp_toString() but without side effect */
  13949 static void js_print_regexp(JSPrintValueState *s, JSObject *p1)
  13950 {
  13951     JSRegExp *re = &p1->u.regexp;
  13952     JSString *p;
  13953     int i, n, c, c2, bra, flags;
  13954     static const char regexp_flags[] = { 'g', 'i', 'm', 's', 'u', 'y', 'd', 'v' };
  13955 
  13956     if (!re->pattern || !re->bytecode) {
  13957         /* the regexp fields are zeroed at init */
  13958         js_puts(s, "[uninitialized_regexp]");
  13959         return;
  13960     }
  13961     p = re->pattern;
  13962     js_putc(s, '/');
  13963     if (p->len == 0) {
  13964         js_puts(s, "(?:)");
  13965     } else {
  13966         bra = 0;
  13967         for (i = 0, n = p->len; i < n;) {
  13968             c2 = -1;
  13969             switch (c = string_get(p, i++)) {
  13970             case '\\':
  13971                 if (i < n)
  13972                     c2 = string_get(p, i++);
  13973                 break;
  13974             case ']':
  13975                 bra = 0;
  13976                 break;
  13977             case '[':
  13978                 if (!bra) {
  13979                     if (i < n && string_get(p, i) == ']')
  13980                         c2 = string_get(p, i++);
  13981                     bra = 1;
  13982                 }
  13983                 break;
  13984             case '\n':
  13985                 c = '\\';
  13986                 c2 = 'n';
  13987                 break;
  13988             case '\r':
  13989                 c = '\\';
  13990                 c2 = 'r';
  13991                 break;
  13992             case '/':
  13993                 if (!bra) {
  13994                     c = '\\';
  13995                     c2 = '/';
  13996                 }
  13997                 break;
  13998             }
  13999             js_putc(s, c);
  14000             if (c2 >= 0)
  14001                 js_putc(s, c2);
  14002         }
  14003     }
  14004     js_putc(s, '/');
  14005 
  14006     flags = lre_get_flags(re->bytecode->u.str8);
  14007     for(i = 0; i < countof(regexp_flags); i++) {
  14008         if ((flags >> i) & 1) {
  14009             js_putc(s, regexp_flags[i]);
  14010         }
  14011     }
  14012 }
  14013 
  14014 /* similar to js_error_toString() but without side effect */
  14015 static void js_print_error(JSPrintValueState *s, JSObject *p)
  14016 {
  14017     const char *str;
  14018     size_t len;
  14019 
  14020     str = get_prop_string(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), JS_ATOM_name);
  14021     if (!str) {
  14022         js_puts(s, "Error");
  14023     } else {
  14024         js_puts(s, str);
  14025         JS_FreeCString(s->ctx, str);
  14026     }
  14027     
  14028     str = get_prop_string(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), JS_ATOM_message);
  14029     if (str && str[0] != '\0') {
  14030         js_puts(s, ": ");
  14031         js_puts(s, str);
  14032     }
  14033     JS_FreeCString(s->ctx, str);
  14034 
  14035     /* dump the stack if present */
  14036     str = get_prop_string(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), JS_ATOM_stack);
  14037     if (str) {
  14038         js_putc(s, '\n');
  14039         
  14040         /* XXX: should remove the last '\n' in stack as
  14041            v8. SpiderMonkey does not do it */
  14042         len = strlen(str);
  14043         if (len > 0 && str[len - 1] == '\n')
  14044             len--;
  14045         s->write_func(s->write_opaque, str, len);
  14046         
  14047         JS_FreeCString(s->ctx, str);
  14048     }
  14049 }
  14050 
  14051 static void js_print_object(JSPrintValueState *s, JSObject *p)
  14052 {
  14053     JSRuntime *rt = s->rt;
  14054     JSShape *sh;
  14055     JSShapeProperty *prs;
  14056     JSProperty *pr;
  14057     int comma_state;
  14058     BOOL is_array;
  14059     uint32_t i;
  14060     
  14061     comma_state = 0;
  14062     is_array = FALSE;
  14063     if (p->class_id == JS_CLASS_ARRAY) {
  14064         is_array = TRUE;
  14065         js_printf(s, "[ ");
  14066         /* XXX: print array like properties even if not fast array */
  14067         if (p->fast_array) {
  14068             uint32_t len, n, len1;
  14069             len = js_print_array_get_length(p);
  14070 
  14071             len1 = min_uint32(p->u.array.count, s->options.max_item_count);
  14072             for(i = 0; i < len1; i++) {
  14073                 js_print_comma(s, &comma_state);
  14074                 js_print_value(s, p->u.array.u.values[i]);
  14075             }
  14076             if (len1 < p->u.array.count)
  14077                 js_print_more_items(s, &comma_state, p->u.array.count - len1);
  14078             if (p->u.array.count < len) {
  14079                 n = len - p->u.array.count;
  14080                 js_print_comma(s, &comma_state);
  14081                 js_printf(s, "<%u empty item%s>", n, n > 1 ? "s" : "");
  14082             }
  14083         }
  14084     } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
  14085         uint32_t size = 1 << typed_array_size_log2(p->class_id);
  14086         uint32_t len1;
  14087         int64_t v;
  14088 
  14089         js_print_atom(s, rt->class_array[p->class_id].class_name);
  14090         js_printf(s, "(%u) [ ", p->u.array.count);
  14091         
  14092         is_array = TRUE;
  14093         len1 = min_uint32(p->u.array.count, s->options.max_item_count);
  14094         for(i = 0; i < len1; i++) {
  14095             const uint8_t *ptr = p->u.array.u.uint8_ptr + i * size;
  14096             js_print_comma(s, &comma_state);
  14097             switch(p->class_id) {
  14098             case JS_CLASS_UINT8C_ARRAY:
  14099             case JS_CLASS_UINT8_ARRAY:
  14100                 v = *ptr;
  14101                 goto ta_int64;
  14102             case JS_CLASS_INT8_ARRAY:
  14103                 v = *(int8_t *)ptr;
  14104                 goto ta_int64;
  14105             case JS_CLASS_INT16_ARRAY:
  14106                 v = *(int16_t *)ptr;
  14107                 goto ta_int64;
  14108             case JS_CLASS_UINT16_ARRAY:
  14109                 v = *(uint16_t *)ptr;
  14110                 goto ta_int64;
  14111             case JS_CLASS_INT32_ARRAY:
  14112                 v = *(int32_t *)ptr;
  14113                 goto ta_int64;
  14114             case JS_CLASS_UINT32_ARRAY:
  14115                 v = *(uint32_t *)ptr;
  14116                 goto ta_int64;
  14117             case JS_CLASS_BIG_INT64_ARRAY:
  14118                 v = *(int64_t *)ptr;
  14119             ta_int64:
  14120                 js_printf(s, "%" PRId64, v);
  14121                 break;
  14122             case JS_CLASS_BIG_UINT64_ARRAY:
  14123                 js_printf(s, "%" PRIu64, *(uint64_t *)ptr);
  14124                 break;
  14125             case JS_CLASS_FLOAT16_ARRAY:
  14126                 js_print_float64(s, fromfp16(*(uint16_t *)ptr));
  14127                 break;
  14128             case JS_CLASS_FLOAT32_ARRAY:
  14129                 js_print_float64(s, *(float *)ptr);
  14130                 break;
  14131             case JS_CLASS_FLOAT64_ARRAY:
  14132                 js_print_float64(s, *(double *)ptr);
  14133                 break;
  14134             }
  14135         }
  14136         if (len1 < p->u.array.count)
  14137             js_print_more_items(s, &comma_state, p->u.array.count - len1);
  14138     } else if (p->class_id == JS_CLASS_BYTECODE_FUNCTION ||
  14139                (rt->class_array[p->class_id].call != NULL &&
  14140                 p->class_id != JS_CLASS_PROXY)) {
  14141         js_printf(s, "[Function");
  14142         /* XXX: allow dump without ctx */
  14143         if (!s->options.raw_dump && s->ctx) {
  14144             const char *func_name_str;
  14145             js_putc(s, ' ');
  14146             func_name_str = get_prop_string(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), JS_ATOM_name);
  14147             if (!func_name_str || func_name_str[0] == '\0')
  14148                 js_puts(s, "(anonymous)");
  14149             else
  14150                 js_puts(s, func_name_str);
  14151             JS_FreeCString(s->ctx, func_name_str);
  14152         }
  14153         js_printf(s, "]");
  14154         comma_state = 2;
  14155     } else if (p->class_id == JS_CLASS_MAP || p->class_id == JS_CLASS_SET) {
  14156         JSMapState *ms = p->u.opaque;
  14157         struct list_head *el;
  14158         
  14159         if (!ms)
  14160             goto default_obj;
  14161         js_print_atom(s, rt->class_array[p->class_id].class_name);
  14162         js_printf(s, "(%u) { ", ms->record_count);
  14163         i = 0;
  14164         list_for_each(el, &ms->records) {
  14165             JSMapRecord *mr = list_entry(el, JSMapRecord, link);
  14166             js_print_comma(s, &comma_state);
  14167             if (mr->empty)
  14168                 continue;
  14169             js_print_value(s, mr->key);
  14170             if (p->class_id == JS_CLASS_MAP) {
  14171                 js_printf(s, " => ");
  14172                 js_print_value(s, mr->value);
  14173             }
  14174             i++;
  14175             if (i >= s->options.max_item_count)
  14176                 break;
  14177         }
  14178         if (i < ms->record_count)
  14179             js_print_more_items(s, &comma_state, ms->record_count - i);
  14180     } else if (p->class_id == JS_CLASS_REGEXP && s->ctx) {
  14181         js_print_regexp(s, p);
  14182         comma_state = 2;
  14183     } else if (p->class_id == JS_CLASS_DATE && s->ctx) {
  14184         /* get_date_string() has no side effect */
  14185         JSValue str = get_date_string(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), 0, NULL, 0x23); /* toISOString() */
  14186         if (JS_IsException(str))
  14187             goto default_obj;
  14188         js_print_raw_string(s, str);
  14189         JS_FreeValueRT(s->rt, str);
  14190         comma_state = 2;
  14191     } else if (p->class_id == JS_CLASS_ERROR && s->ctx) {
  14192         js_print_error(s, p);
  14193         comma_state = 2;
  14194     } else {
  14195         default_obj:
  14196         if (p->class_id != JS_CLASS_OBJECT) {
  14197             js_print_atom(s, rt->class_array[p->class_id].class_name);
  14198             js_printf(s, " ");
  14199         }
  14200         js_printf(s, "{ ");
  14201     }
  14202     
  14203     sh = p->shape; /* the shape can be NULL while freeing an object */
  14204     if (sh) {
  14205         uint32_t j;
  14206         
  14207         j = 0;
  14208         for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
  14209             if (prs->atom != JS_ATOM_NULL) {
  14210                 if (!(prs->flags & JS_PROP_ENUMERABLE) &&
  14211                     !s->options.show_hidden) {
  14212                     continue;
  14213                 }
  14214                 if (j < s->options.max_item_count) {
  14215                     pr = &p->prop[i];
  14216                     js_print_comma(s, &comma_state);
  14217                     js_print_atom(s, prs->atom);
  14218                     js_printf(s, ": ");
  14219                     
  14220                     /* XXX: autoinit property */
  14221                     if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
  14222                         if (s->options.raw_dump) {
  14223                             js_printf(s, "[Getter %p Setter %p]",
  14224                                     pr->u.getset.getter, pr->u.getset.setter);
  14225                         } else {
  14226                             if (pr->u.getset.getter && pr->u.getset.setter) {
  14227                                 js_printf(s, "[Getter/Setter]");
  14228                             } else if (pr->u.getset.setter) {
  14229                                 js_printf(s, "[Setter]");
  14230                             } else {
  14231                                 js_printf(s, "[Getter]");
  14232                             }
  14233                         }
  14234                     } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
  14235                         if (s->options.raw_dump) {
  14236                             js_printf(s, "[varref %p]", (void *)pr->u.var_ref);
  14237                         } else {
  14238                             js_print_value(s, *pr->u.var_ref->pvalue);
  14239                         }
  14240                     } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
  14241                         if (s->options.raw_dump) {
  14242                             js_printf(s, "[autoinit %p %d %p]",
  14243                                     (void *)js_autoinit_get_realm(pr),
  14244                                     js_autoinit_get_id(pr),
  14245                                     (void *)pr->u.init.opaque);
  14246                         } else {
  14247                             /* XXX: could autoinit but need to restart
  14248                                the iteration */
  14249                             js_printf(s, "[autoinit]");
  14250                         }
  14251                     } else {
  14252                         js_print_value(s, pr->u.value);
  14253                     }
  14254                 }
  14255                 j++;
  14256             }
  14257         }
  14258         if (j > s->options.max_item_count)
  14259             js_print_more_items(s, &comma_state, j - s->options.max_item_count);
  14260     }
  14261     if (s->options.raw_dump && js_class_has_bytecode(p->class_id)) {
  14262         JSFunctionBytecode *b = p->u.func.function_bytecode;
  14263         if (b->closure_var_count) {
  14264             JSVarRef **var_refs;
  14265             var_refs = p->u.func.var_refs;
  14266             
  14267             js_print_comma(s, &comma_state);
  14268             js_printf(s, "[[Closure]]: [");
  14269             for(i = 0; i < b->closure_var_count; i++) {
  14270                 if (i != 0)
  14271                     js_printf(s, ", ");
  14272                 js_print_value(s, var_refs[i]->value);
  14273             }
  14274             js_printf(s, " ]");
  14275         }
  14276         if (p->u.func.home_object) {
  14277             js_print_comma(s, &comma_state);
  14278             js_printf(s, "[[HomeObject]]: ");
  14279             js_print_value(s, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object));
  14280         }
  14281     }
  14282 
  14283     if (!is_array) {
  14284         if (comma_state != 2) {
  14285             js_printf(s, " }");
  14286         }
  14287     } else {
  14288         js_printf(s, " ]");
  14289     }
  14290 }
  14291 
  14292 static int js_print_stack_index(JSPrintValueState *s, JSObject *p)
  14293 {
  14294     int i;
  14295     for(i = 0; i < s->level; i++)
  14296         if (s->print_stack[i] == p)
  14297             return i;
  14298     return -1;
  14299 }
  14300 
  14301 static void js_print_value(JSPrintValueState *s, JSValueConst val)
  14302 {
  14303     uint32_t tag = JS_VALUE_GET_NORM_TAG(val);
  14304     const char *str;
  14305 
  14306     switch(tag) {
  14307     case JS_TAG_INT:
  14308         js_printf(s, "%d", JS_VALUE_GET_INT(val));
  14309         break;
  14310     case JS_TAG_BOOL:
  14311         if (JS_VALUE_GET_BOOL(val))
  14312             str = "true";
  14313         else
  14314             str = "false";
  14315         goto print_str;
  14316     case JS_TAG_NULL:
  14317         str = "null";
  14318         goto print_str;
  14319     case JS_TAG_EXCEPTION:
  14320         str = "exception";
  14321         goto print_str;
  14322     case JS_TAG_UNINITIALIZED:
  14323         str = "uninitialized";
  14324         goto print_str;
  14325     case JS_TAG_UNDEFINED:
  14326         str = "undefined";
  14327     print_str:
  14328         js_puts(s, str);
  14329         break;
  14330     case JS_TAG_FLOAT64:
  14331         js_print_float64(s, JS_VALUE_GET_FLOAT64(val));
  14332         break;
  14333     case JS_TAG_SHORT_BIG_INT:
  14334         js_printf(s, "%" PRId64 "n", (int64_t)JS_VALUE_GET_SHORT_BIG_INT(val));
  14335         break;
  14336     case JS_TAG_BIG_INT:
  14337         if (!s->options.raw_dump && s->ctx) {
  14338             JSValue str = js_bigint_to_string(s->ctx, val);
  14339             if (JS_IsException(str))
  14340                 goto raw_bigint;
  14341             js_print_raw_string(s, str);
  14342             js_putc(s, 'n');
  14343             JS_FreeValueRT(s->rt, str);
  14344         } else {
  14345             JSBigInt *p;
  14346             int sgn, i;
  14347         raw_bigint:
  14348             p = JS_VALUE_GET_PTR(val);
  14349             /* In order to avoid allocations we just dump the limbs */
  14350             sgn = js_bigint_sign(p);
  14351             if (sgn)
  14352                 js_printf(s, "BigInt.asIntN(%d,", p->len * JS_LIMB_BITS);
  14353             js_printf(s, "0x");
  14354             for(i = p->len - 1; i >= 0; i--) {
  14355                 if (i != p->len - 1)
  14356                     js_putc(s, '_');
  14357 #if JS_LIMB_BITS == 32
  14358                 js_printf(s, "%08x", p->tab[i]);
  14359 #else
  14360                 js_printf(s, "%016" PRIx64, p->tab[i]);
  14361 #endif
  14362             }
  14363             js_putc(s, 'n');
  14364             if (sgn)
  14365                 js_putc(s, ')');
  14366         }
  14367         break;
  14368     case JS_TAG_STRING:
  14369     case JS_TAG_STRING_ROPE:
  14370         if (s->options.raw_dump && tag == JS_TAG_STRING_ROPE) {
  14371             JSStringRope *r = JS_VALUE_GET_STRING_ROPE(val);
  14372             js_printf(s, "[rope len=%d depth=%d]", r->len, r->depth);
  14373         } else {
  14374             js_print_string(s, val);
  14375         }
  14376         break;
  14377     case JS_TAG_FUNCTION_BYTECODE:
  14378         {
  14379             JSFunctionBytecode *b = JS_VALUE_GET_PTR(val);
  14380             js_puts(s, "[bytecode ");
  14381             js_print_atom(s, b->func_name);
  14382             js_putc(s, ']');
  14383         }
  14384         break;
  14385     case JS_TAG_OBJECT:
  14386         {
  14387             JSObject *p = JS_VALUE_GET_OBJ(val);
  14388             int idx;
  14389             idx = js_print_stack_index(s, p);
  14390             if (idx >= 0) {
  14391                 js_printf(s, "[circular %d]", idx);
  14392             } else if (s->level < s->options.max_depth) {
  14393                 s->print_stack[s->level++] = p;
  14394                 js_print_object(s, JS_VALUE_GET_OBJ(val));
  14395                 s->level--;
  14396             } else {
  14397                 JSAtom atom = s->rt->class_array[p->class_id].class_name;
  14398                 js_putc(s, '[');
  14399                 js_print_atom(s, atom);
  14400                 if (s->options.raw_dump) {
  14401                     js_printf(s, " %p", (void *)p);
  14402                 }
  14403                 js_putc(s, ']');
  14404             }
  14405         }
  14406         break;
  14407     case JS_TAG_SYMBOL:
  14408         {
  14409             JSAtomStruct *p = JS_VALUE_GET_PTR(val);
  14410             js_puts(s, "Symbol(");
  14411             js_print_atom(s, js_get_atom_index(s->rt, p));
  14412             js_putc(s, ')');
  14413         }
  14414         break;
  14415     case JS_TAG_MODULE:
  14416         js_puts(s, "[module]");
  14417         break;
  14418     default:
  14419         js_printf(s, "[unknown tag %d]", tag);
  14420         break;
  14421     }
  14422 }
  14423 
  14424 void JS_PrintValueSetDefaultOptions(JSPrintValueOptions *options)
  14425 {
  14426     memset(options, 0, sizeof(*options));
  14427     options->max_depth = 2;
  14428     options->max_string_length = 1000;
  14429     options->max_item_count = 100;
  14430 }
  14431 
  14432 static void JS_PrintValueInternal(JSRuntime *rt, JSContext *ctx, 
  14433                                   JSPrintValueWrite *write_func, void *write_opaque,
  14434                                   JSValueConst val, const JSPrintValueOptions *options)
  14435 {
  14436     JSPrintValueState ss, *s = &ss;
  14437     if (options)
  14438         s->options = *options;
  14439     else
  14440         JS_PrintValueSetDefaultOptions(&s->options);
  14441     if (s->options.max_depth <= 0)
  14442         s->options.max_depth = JS_PRINT_MAX_DEPTH;
  14443     else
  14444         s->options.max_depth = min_int(s->options.max_depth, JS_PRINT_MAX_DEPTH);
  14445     if (s->options.max_string_length == 0)
  14446         s->options.max_string_length = UINT32_MAX;
  14447     if (s->options.max_item_count == 0)
  14448         s->options.max_item_count = UINT32_MAX;
  14449     s->rt = rt;
  14450     s->ctx = ctx;
  14451     s->write_func = write_func;
  14452     s->write_opaque = write_opaque;
  14453     s->level = 0;
  14454     js_print_value(s, val);
  14455 }
  14456 
  14457 void JS_PrintValueRT(JSRuntime *rt, JSPrintValueWrite *write_func, void *write_opaque,
  14458                      JSValueConst val, const JSPrintValueOptions *options)
  14459 {
  14460     JS_PrintValueInternal(rt, NULL, write_func, write_opaque, val, options);
  14461 }
  14462 
  14463 void JS_PrintValue(JSContext *ctx, JSPrintValueWrite *write_func, void *write_opaque,
  14464                    JSValueConst val, const JSPrintValueOptions *options)
  14465 {
  14466     JS_PrintValueInternal(ctx->rt, ctx, write_func, write_opaque, val, options);
  14467 }
  14468 
  14469 static void js_dump_value_write(void *opaque, const char *buf, size_t len)
  14470 {
  14471     FILE *fo = opaque;
  14472     fwrite(buf, 1, len, fo);
  14473 }
  14474 
  14475 static __maybe_unused void print_atom(JSContext *ctx, JSAtom atom)
  14476 {
  14477     JSPrintValueState ss, *s = &ss;
  14478     memset(s, 0, sizeof(*s));
  14479     s->rt = ctx->rt;
  14480     s->ctx = ctx;
  14481     s->write_func = js_dump_value_write;
  14482     s->write_opaque = stdout;
  14483     js_print_atom(s, atom);
  14484 }
  14485 
  14486 static __maybe_unused void JS_DumpAtom(JSContext *ctx, const char *str, JSAtom atom)
  14487 {
  14488     printf("%s=", str);
  14489     print_atom(ctx, atom);
  14490     printf("\n");
  14491 }
  14492 
  14493 static __maybe_unused void JS_DumpValue(JSContext *ctx, const char *str, JSValueConst val)
  14494 {
  14495     printf("%s=", str);
  14496     JS_PrintValue(ctx, js_dump_value_write, stdout, val, NULL);
  14497     printf("\n");
  14498 }
  14499 
  14500 static __maybe_unused void JS_DumpValueRT(JSRuntime *rt, const char *str, JSValueConst val)
  14501 {
  14502     printf("%s=", str);
  14503     JS_PrintValueRT(rt, js_dump_value_write, stdout, val, NULL);
  14504     printf("\n");
  14505 }
  14506 
  14507 static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt)
  14508 {
  14509     printf("%14s %4s %4s %14s %s\n",
  14510            "ADDRESS", "REFS", "SHRF", "PROTO", "CONTENT");
  14511 }
  14512 
  14513 /* for debug only: dump an object without side effect */
  14514 static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
  14515 {
  14516     JSShape *sh;
  14517     JSPrintValueOptions options;
  14518     
  14519     /* XXX: should encode atoms with special characters */
  14520     sh = p->shape; /* the shape can be NULL while freeing an object */
  14521     printf("%14p %4d ",
  14522            (void *)p,
  14523            js_rc(p)->ref_count);
  14524     if (sh) {
  14525         printf("%3d%c %14p ",
  14526                js_rc(sh)->ref_count,
  14527                " *"[sh->is_hashed],
  14528                (void *)sh->proto);
  14529     } else {
  14530         printf("%3s  %14s ", "-", "-");
  14531     }
  14532 
  14533     JS_PrintValueSetDefaultOptions(&options);
  14534     options.max_depth = 1;
  14535     options.show_hidden = TRUE;
  14536     options.raw_dump = TRUE;
  14537     JS_PrintValueRT(rt, js_dump_value_write, stdout, JS_MKPTR(JS_TAG_OBJECT, p), &options);
  14538 
  14539     printf("\n");
  14540 }
  14541 
  14542 static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p)
  14543 {
  14544     if (js_rc(p)->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
  14545         JS_DumpObject(rt, (JSObject *)p);
  14546     } else {
  14547         printf("%14p %4d ",
  14548                (void *)p,
  14549                js_rc(p)->ref_count);
  14550         switch(js_rc(p)->gc_obj_type) {
  14551         case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
  14552             printf("[function bytecode]");
  14553             break;
  14554         case JS_GC_OBJ_TYPE_SHAPE:
  14555             printf("[shape]");
  14556             break;
  14557         case JS_GC_OBJ_TYPE_VAR_REF:
  14558             printf("[var_ref]");
  14559             break;
  14560         case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
  14561             printf("[async_function]");
  14562             break;
  14563         case JS_GC_OBJ_TYPE_JS_CONTEXT:
  14564             printf("[js_context]");
  14565             break;
  14566         case JS_GC_OBJ_TYPE_MODULE:
  14567             printf("[module]");
  14568             break;
  14569         default:
  14570             printf("[unknown %d]", js_rc(p)->gc_obj_type);
  14571             break;
  14572         }
  14573         printf("\n");
  14574     }
  14575 }
  14576 
  14577 /* return -1 if exception (proxy case) or TRUE/FALSE */
  14578 // TODO: should take flags to make proxy resolution and exceptions optional
  14579 int JS_IsArray(JSContext *ctx, JSValueConst val)
  14580 {
  14581     if (js_resolve_proxy(ctx, &val, TRUE))
  14582         return -1;
  14583     if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {
  14584         JSObject *p = JS_VALUE_GET_OBJ(val);
  14585         return p->class_id == JS_CLASS_ARRAY;
  14586     } else {
  14587         return FALSE;
  14588     }
  14589 }
  14590 
  14591 static double js_pow(double a, double b)
  14592 {
  14593     if (unlikely(!isfinite(b)) && fabs(a) == 1) {
  14594         /* not compatible with IEEE 754 */
  14595         return JS_FLOAT64_NAN;
  14596     } else {
  14597         return pow(a, b);
  14598     }
  14599 }
  14600 
  14601 JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)
  14602 {
  14603 #if JS_SHORT_BIG_INT_BITS == 64
  14604     return __JS_NewShortBigInt(ctx, v);
  14605 #else
  14606     if (v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX) {
  14607         return __JS_NewShortBigInt(ctx, v);
  14608     } else {
  14609         JSBigInt *p;
  14610         p = js_bigint_new_si64(ctx, v);
  14611         if (!p)
  14612             return JS_EXCEPTION;
  14613         return JS_MKPTR(JS_TAG_BIG_INT, p);
  14614     }
  14615 #endif
  14616 }
  14617 
  14618 JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
  14619 {
  14620     if (v <= JS_SHORT_BIG_INT_MAX) {
  14621         return __JS_NewShortBigInt(ctx, v);
  14622     } else {
  14623         JSBigInt *p;
  14624         p = js_bigint_new_ui64(ctx, v);
  14625         if (!p)
  14626             return JS_EXCEPTION;
  14627         return JS_MKPTR(JS_TAG_BIG_INT, p);
  14628     }
  14629 }
  14630 
  14631 /* return NaN if bad bigint literal */
  14632 static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val)
  14633 {
  14634     const char *str, *p;
  14635     size_t len;
  14636     int flags;
  14637 
  14638     str = JS_ToCStringLen(ctx, &len, val);
  14639     JS_FreeValue(ctx, val);
  14640     if (!str)
  14641         return JS_EXCEPTION;
  14642     p = str;
  14643     p += skip_spaces(p);
  14644     if ((p - str) == len) {
  14645         val = JS_NewBigInt64(ctx, 0);
  14646     } else {
  14647         flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT;
  14648         val = js_atof(ctx, p, &p, 0, flags);
  14649         p += skip_spaces(p);
  14650         if (!JS_IsException(val)) {
  14651             if ((p - str) != len) {
  14652                 JS_FreeValue(ctx, val);
  14653                 val = JS_NAN;
  14654             }
  14655         }
  14656     }
  14657     JS_FreeCString(ctx, str);
  14658     return val;
  14659 }
  14660 
  14661 static JSValue JS_StringToBigIntErr(JSContext *ctx, JSValue val)
  14662 {
  14663     val = JS_StringToBigInt(ctx, val);
  14664     if (JS_VALUE_IS_NAN(val))
  14665         return JS_ThrowSyntaxError(ctx, "invalid bigint literal");
  14666     return val;
  14667 }
  14668 
  14669 /* JS Numbers are not allowed */
  14670 static JSValue JS_ToBigIntFree(JSContext *ctx, JSValue val)
  14671 {
  14672     uint32_t tag;
  14673 
  14674  redo:
  14675     tag = JS_VALUE_GET_NORM_TAG(val);
  14676     switch(tag) {
  14677     case JS_TAG_SHORT_BIG_INT:
  14678     case JS_TAG_BIG_INT:
  14679         break;
  14680     case JS_TAG_INT:
  14681     case JS_TAG_NULL:
  14682     case JS_TAG_UNDEFINED:
  14683     case JS_TAG_FLOAT64:
  14684         goto fail;
  14685     case JS_TAG_BOOL:
  14686         val = __JS_NewShortBigInt(ctx, JS_VALUE_GET_INT(val));
  14687         break;
  14688     case JS_TAG_STRING:
  14689     case JS_TAG_STRING_ROPE:
  14690         val = JS_StringToBigIntErr(ctx, val);
  14691         if (JS_IsException(val))
  14692             return val;
  14693         goto redo;
  14694     case JS_TAG_OBJECT:
  14695         val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
  14696         if (JS_IsException(val))
  14697             return val;
  14698         goto redo;
  14699     default:
  14700     fail:
  14701         JS_FreeValue(ctx, val);
  14702         return JS_ThrowTypeError(ctx, "cannot convert to bigint");
  14703     }
  14704     return val;
  14705 }
  14706 
  14707 static JSValue JS_ToBigInt(JSContext *ctx, JSValueConst val)
  14708 {
  14709     return JS_ToBigIntFree(ctx, JS_DupValue(ctx, val));
  14710 }
  14711 
  14712 /* XXX: merge with JS_ToInt64Free with a specific flag ? */
  14713 static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
  14714 {
  14715     uint64_t res;
  14716 
  14717     val = JS_ToBigIntFree(ctx, val);
  14718     if (JS_IsException(val)) {
  14719         *pres = 0;
  14720         return -1;
  14721     }
  14722     if (JS_VALUE_GET_TAG(val) == JS_TAG_SHORT_BIG_INT) {
  14723         res = JS_VALUE_GET_SHORT_BIG_INT(val);
  14724     } else {
  14725         JSBigInt *p = JS_VALUE_GET_PTR(val);
  14726         /* return the value mod 2^64 */
  14727         res = p->tab[0];
  14728 #if JS_LIMB_BITS == 32
  14729         if (p->len >= 2)
  14730             res |= (uint64_t)p->tab[1] << 32;
  14731 #endif
  14732         JS_FreeValue(ctx, val);
  14733     }
  14734     *pres = res;
  14735     return 0;
  14736 }
  14737 
  14738 int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
  14739 {
  14740     return JS_ToBigInt64Free(ctx, pres, JS_DupValue(ctx, val));
  14741 }
  14742 
  14743 static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
  14744                                                      JSValue *sp,
  14745                                                      OPCodeEnum op)
  14746 {
  14747     JSValue op1;
  14748     int v;
  14749     uint32_t tag;
  14750     JSBigIntBuf buf1;
  14751     JSBigInt *p1;
  14752 
  14753     op1 = sp[-1];
  14754     /* fast path for float64 */
  14755     if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)))
  14756         goto handle_float64;
  14757     op1 = JS_ToNumericFree(ctx, op1);
  14758     if (JS_IsException(op1))
  14759         goto exception;
  14760     tag = JS_VALUE_GET_TAG(op1);
  14761     switch(tag) {
  14762     case JS_TAG_INT:
  14763         {
  14764             int64_t v64;
  14765             v64 = JS_VALUE_GET_INT(op1);
  14766             switch(op) {
  14767             case OP_inc:
  14768             case OP_dec:
  14769                 v = 2 * (op - OP_dec) - 1;
  14770                 v64 += v;
  14771                 break;
  14772             case OP_plus:
  14773                 break;
  14774             case OP_neg:
  14775                 if (v64 == 0) {
  14776                     sp[-1] = __JS_NewFloat64(ctx, -0.0);
  14777                     return 0;
  14778                 } else {
  14779                     v64 = -v64;
  14780                 }
  14781                 break;
  14782             default:
  14783                 abort();
  14784             }
  14785             sp[-1] = JS_NewInt64(ctx, v64);
  14786         }
  14787         break;
  14788     case JS_TAG_SHORT_BIG_INT:
  14789         {
  14790             int64_t v;
  14791             v = JS_VALUE_GET_SHORT_BIG_INT(op1);
  14792             switch(op) {
  14793             case OP_plus:
  14794                 JS_ThrowTypeError(ctx, "bigint argument with unary +");
  14795                 goto exception;
  14796             case OP_inc:
  14797                 if (v == JS_SHORT_BIG_INT_MAX)
  14798                     goto bigint_slow_case;
  14799                 sp[-1] = __JS_NewShortBigInt(ctx, v + 1);
  14800                 break;
  14801             case OP_dec:
  14802                 if (v == JS_SHORT_BIG_INT_MIN)
  14803                     goto bigint_slow_case;
  14804                 sp[-1] = __JS_NewShortBigInt(ctx, v - 1);
  14805                 break;
  14806             case OP_neg:
  14807                 v = JS_VALUE_GET_SHORT_BIG_INT(op1);
  14808                 if (v == JS_SHORT_BIG_INT_MIN) {
  14809                 bigint_slow_case:
  14810                     p1 = js_bigint_set_short(&buf1, op1);
  14811                     goto bigint_slow_case1;
  14812                 }
  14813                 sp[-1] = __JS_NewShortBigInt(ctx, -v);
  14814                 break;
  14815             default:
  14816                 abort();
  14817             }
  14818         }
  14819         break;
  14820     case JS_TAG_BIG_INT:
  14821         {
  14822             JSBigInt *r;
  14823             p1 = JS_VALUE_GET_PTR(op1);
  14824         bigint_slow_case1:
  14825             switch(op) {
  14826             case OP_plus:
  14827                 JS_ThrowTypeError(ctx, "bigint argument with unary +");
  14828                 JS_FreeValue(ctx, op1);
  14829                 goto exception;
  14830             case OP_inc:
  14831             case OP_dec:
  14832                 {
  14833                     JSBigIntBuf buf2;
  14834                     JSBigInt *p2;
  14835                     p2 = js_bigint_set_si(&buf2, 2 * (op - OP_dec) - 1);
  14836                     r = js_bigint_add(ctx, p1, p2, 0);
  14837                 }
  14838                 break;
  14839             case OP_neg:
  14840                 r = js_bigint_neg(ctx, p1);
  14841                 break;
  14842             case OP_not:
  14843                 r = js_bigint_not(ctx, p1);
  14844                 break;
  14845             default:
  14846                 abort();
  14847             }
  14848             JS_FreeValue(ctx, op1);
  14849             if (!r)
  14850                 goto exception;
  14851             sp[-1] = JS_CompactBigInt(ctx, r);
  14852         }
  14853         break;
  14854     default:
  14855     handle_float64:
  14856         {
  14857             double d;
  14858             d = JS_VALUE_GET_FLOAT64(op1);
  14859             switch(op) {
  14860             case OP_inc:
  14861             case OP_dec:
  14862                 v = 2 * (op - OP_dec) - 1;
  14863                 d += v;
  14864                 break;
  14865             case OP_plus:
  14866                 break;
  14867             case OP_neg:
  14868                 d = -d;
  14869                 break;
  14870             default:
  14871                 abort();
  14872             }
  14873             sp[-1] = __JS_NewFloat64(ctx, d);
  14874         }
  14875         break;
  14876     }
  14877     return 0;
  14878  exception:
  14879     sp[-1] = JS_UNDEFINED;
  14880     return -1;
  14881 }
  14882 
  14883 static __exception int js_post_inc_slow(JSContext *ctx,
  14884                                         JSValue *sp, OPCodeEnum op)
  14885 {
  14886     JSValue op1;
  14887 
  14888     /* XXX: allow custom operators */
  14889     op1 = sp[-1];
  14890     op1 = JS_ToNumericFree(ctx, op1);
  14891     if (JS_IsException(op1)) {
  14892         sp[-1] = JS_UNDEFINED;
  14893         return -1;
  14894     }
  14895     sp[-1] = op1;
  14896     sp[0] = JS_DupValue(ctx, op1);
  14897     return js_unary_arith_slow(ctx, sp + 1, op - OP_post_dec + OP_dec);
  14898 }
  14899 
  14900 static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
  14901 {
  14902     JSValue op1;
  14903 
  14904     op1 = sp[-1];
  14905     op1 = JS_ToNumericFree(ctx, op1);
  14906     if (JS_IsException(op1))
  14907         goto exception;
  14908     if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT) {
  14909         sp[-1] = __JS_NewShortBigInt(ctx, ~JS_VALUE_GET_SHORT_BIG_INT(op1));
  14910     } else if (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) {
  14911         JSBigInt *r;
  14912         r = js_bigint_not(ctx, JS_VALUE_GET_PTR(op1));
  14913         JS_FreeValue(ctx, op1);
  14914         if (!r)
  14915             goto exception;
  14916         sp[-1] = JS_CompactBigInt(ctx, r);
  14917     } else {
  14918         int32_t v1;
  14919         if (unlikely(JS_ToInt32Free(ctx, &v1, op1)))
  14920             goto exception;
  14921         sp[-1] = JS_NewInt32(ctx, ~v1);
  14922     }
  14923     return 0;
  14924  exception:
  14925     sp[-1] = JS_UNDEFINED;
  14926     return -1;
  14927 }
  14928 
  14929 static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
  14930                                                       OPCodeEnum op)
  14931 {
  14932     JSValue op1, op2;
  14933     uint32_t tag1, tag2;
  14934     double d1, d2;
  14935 
  14936     op1 = sp[-2];
  14937     op2 = sp[-1];
  14938     tag1 = JS_VALUE_GET_NORM_TAG(op1);
  14939     tag2 = JS_VALUE_GET_NORM_TAG(op2);
  14940     /* fast path for float operations */
  14941     if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) {
  14942         d1 = JS_VALUE_GET_FLOAT64(op1);
  14943         d2 = JS_VALUE_GET_FLOAT64(op2);
  14944         goto handle_float64;
  14945     }
  14946     /* fast path for short big int operations */
  14947     if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) {
  14948         js_slimb_t v1, v2;
  14949         js_sdlimb_t v;
  14950         v1 = JS_VALUE_GET_SHORT_BIG_INT(op1);
  14951         v2 = JS_VALUE_GET_SHORT_BIG_INT(op2);
  14952         switch(op) {
  14953         case OP_sub:
  14954             v = (js_sdlimb_t)v1 - (js_sdlimb_t)v2;
  14955             break;
  14956         case OP_mul:
  14957             v = (js_sdlimb_t)v1 * (js_sdlimb_t)v2;
  14958             break;
  14959         case OP_div:
  14960             if (v2 == 0 ||
  14961                 ((js_limb_t)v1 == (js_limb_t)1 << (JS_LIMB_BITS - 1) &&
  14962                  v2 == -1)) {
  14963                 goto slow_big_int;
  14964             }
  14965             sp[-2] = __JS_NewShortBigInt(ctx, v1 / v2);
  14966             return 0;
  14967         case OP_mod:
  14968             if (v2 == 0 ||
  14969                 ((js_limb_t)v1 == (js_limb_t)1 << (JS_LIMB_BITS - 1) &&
  14970                  v2 == -1)) {
  14971                 goto slow_big_int;
  14972             }
  14973             sp[-2] = __JS_NewShortBigInt(ctx, v1 % v2);
  14974             return 0;
  14975         case OP_pow:
  14976             goto slow_big_int;
  14977         default:
  14978             abort();
  14979         }
  14980         if (likely(v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX)) {
  14981             sp[-2] = __JS_NewShortBigInt(ctx, v);
  14982         } else {
  14983             JSBigInt *r = js_bigint_new_di(ctx, v);
  14984             if (!r)
  14985                 goto exception;
  14986             sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r);
  14987         }
  14988         return 0;
  14989     }
  14990     op1 = JS_ToNumericFree(ctx, op1);
  14991     if (JS_IsException(op1)) {
  14992         JS_FreeValue(ctx, op2);
  14993         goto exception;
  14994     }
  14995     op2 = JS_ToNumericFree(ctx, op2);
  14996     if (JS_IsException(op2)) {
  14997         JS_FreeValue(ctx, op1);
  14998         goto exception;
  14999     }
  15000     tag1 = JS_VALUE_GET_NORM_TAG(op1);
  15001     tag2 = JS_VALUE_GET_NORM_TAG(op2);
  15002 
  15003     if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
  15004         int32_t v1, v2;
  15005         int64_t v;
  15006         v1 = JS_VALUE_GET_INT(op1);
  15007         v2 = JS_VALUE_GET_INT(op2);
  15008         switch(op) {
  15009         case OP_sub:
  15010             v = (int64_t)v1 - (int64_t)v2;
  15011             break;
  15012         case OP_mul:
  15013             v = (int64_t)v1 * (int64_t)v2;
  15014             if (v == 0 && (v1 | v2) < 0) {
  15015                 sp[-2] = __JS_NewFloat64(ctx, -0.0);
  15016                 return 0;
  15017             }
  15018             break;
  15019         case OP_div:
  15020             sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2);
  15021             return 0;
  15022         case OP_mod:
  15023             if (v1 < 0 || v2 <= 0) {
  15024                 sp[-2] = JS_NewFloat64(ctx, fmod(v1, v2));
  15025                 return 0;
  15026             } else {
  15027                 v = (int64_t)v1 % (int64_t)v2;
  15028             }
  15029             break;
  15030         case OP_pow:
  15031             sp[-2] = JS_NewFloat64(ctx, js_pow(v1, v2));
  15032             return 0;
  15033         default:
  15034             abort();
  15035         }
  15036         sp[-2] = JS_NewInt64(ctx, v);
  15037     } else if ((tag1 == JS_TAG_SHORT_BIG_INT || tag1 == JS_TAG_BIG_INT) &&
  15038                (tag2 == JS_TAG_SHORT_BIG_INT || tag2 == JS_TAG_BIG_INT)) {
  15039         JSBigInt *p1, *p2, *r;
  15040         JSBigIntBuf buf1, buf2;
  15041     slow_big_int:
  15042         /* bigint result */
  15043         if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT)
  15044             p1 = js_bigint_set_short(&buf1, op1);
  15045         else
  15046             p1 = JS_VALUE_GET_PTR(op1);
  15047         if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT)
  15048             p2 = js_bigint_set_short(&buf2, op2);
  15049         else
  15050             p2 = JS_VALUE_GET_PTR(op2);
  15051         switch(op) {
  15052         case OP_add:
  15053             r = js_bigint_add(ctx, p1, p2, 0);
  15054             break;
  15055         case OP_sub:
  15056             r = js_bigint_add(ctx, p1, p2, 1);
  15057             break;
  15058         case OP_mul:
  15059             r = js_bigint_mul(ctx, p1, p2);
  15060             break;
  15061         case OP_div:
  15062             r = js_bigint_divrem(ctx, p1, p2, FALSE);
  15063             break;
  15064         case OP_mod:
  15065             r = js_bigint_divrem(ctx, p1, p2, TRUE);
  15066             break;
  15067         case OP_pow:
  15068             r = js_bigint_pow(ctx, p1, p2);
  15069             break;
  15070         default:
  15071             abort();
  15072         }
  15073         JS_FreeValue(ctx, op1);
  15074         JS_FreeValue(ctx, op2);
  15075         if (!r)
  15076             goto exception;
  15077         sp[-2] = JS_CompactBigInt(ctx, r);
  15078     } else {
  15079         double dr;
  15080         /* float64 result */
  15081         if (JS_ToFloat64Free(ctx, &d1, op1)) {
  15082             JS_FreeValue(ctx, op2);
  15083             goto exception;
  15084         }
  15085         if (JS_ToFloat64Free(ctx, &d2, op2))
  15086             goto exception;
  15087     handle_float64:
  15088         switch(op) {
  15089         case OP_sub:
  15090             dr = d1 - d2;
  15091             break;
  15092         case OP_mul:
  15093             dr = d1 * d2;
  15094             break;
  15095         case OP_div:
  15096             dr = d1 / d2;
  15097             break;
  15098         case OP_mod:
  15099             dr = fmod(d1, d2);
  15100             break;
  15101         case OP_pow:
  15102             dr = js_pow(d1, d2);
  15103             break;
  15104         default:
  15105             abort();
  15106         }
  15107         sp[-2] = __JS_NewFloat64(ctx, dr);
  15108     }
  15109     return 0;
  15110  exception:
  15111     sp[-2] = JS_UNDEFINED;
  15112     sp[-1] = JS_UNDEFINED;
  15113     return -1;
  15114 }
  15115 
  15116 static inline BOOL tag_is_string(uint32_t tag)
  15117 {
  15118     return tag == JS_TAG_STRING || tag == JS_TAG_STRING_ROPE;
  15119 }
  15120 
  15121 static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
  15122 {
  15123     JSValue op1, op2;
  15124     uint32_t tag1, tag2;
  15125 
  15126     op1 = sp[-2];
  15127     op2 = sp[-1];
  15128 
  15129     tag1 = JS_VALUE_GET_NORM_TAG(op1);
  15130     tag2 = JS_VALUE_GET_NORM_TAG(op2);
  15131     /* fast path for float64 */
  15132     if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) {
  15133         double d1, d2;
  15134         d1 = JS_VALUE_GET_FLOAT64(op1);
  15135         d2 = JS_VALUE_GET_FLOAT64(op2);
  15136         sp[-2] = __JS_NewFloat64(ctx, d1 + d2);
  15137         return 0;
  15138     }
  15139     /* fast path for short bigint */
  15140     if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) {
  15141         js_slimb_t v1, v2;
  15142         js_sdlimb_t v;
  15143         v1 = JS_VALUE_GET_SHORT_BIG_INT(op1);
  15144         v2 = JS_VALUE_GET_SHORT_BIG_INT(op2);
  15145         v = (js_sdlimb_t)v1 + (js_sdlimb_t)v2;
  15146         if (likely(v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX)) {
  15147             sp[-2] = __JS_NewShortBigInt(ctx, v);
  15148         } else {
  15149             JSBigInt *r = js_bigint_new_di(ctx, v);
  15150             if (!r)
  15151                 goto exception;
  15152             sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r);
  15153         }
  15154         return 0;
  15155     }
  15156     
  15157     if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) {
  15158         op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
  15159         if (JS_IsException(op1)) {
  15160             JS_FreeValue(ctx, op2);
  15161             goto exception;
  15162         }
  15163 
  15164         op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
  15165         if (JS_IsException(op2)) {
  15166             JS_FreeValue(ctx, op1);
  15167             goto exception;
  15168         }
  15169         tag1 = JS_VALUE_GET_NORM_TAG(op1);
  15170         tag2 = JS_VALUE_GET_NORM_TAG(op2);
  15171     }
  15172 
  15173     if (tag_is_string(tag1) || tag_is_string(tag2)) {
  15174         sp[-2] = JS_ConcatString(ctx, op1, op2);
  15175         if (JS_IsException(sp[-2]))
  15176             goto exception;
  15177         return 0;
  15178     }
  15179 
  15180     op1 = JS_ToNumericFree(ctx, op1);
  15181     if (JS_IsException(op1)) {
  15182         JS_FreeValue(ctx, op2);
  15183         goto exception;
  15184     }
  15185     op2 = JS_ToNumericFree(ctx, op2);
  15186     if (JS_IsException(op2)) {
  15187         JS_FreeValue(ctx, op1);
  15188         goto exception;
  15189     }
  15190     tag1 = JS_VALUE_GET_NORM_TAG(op1);
  15191     tag2 = JS_VALUE_GET_NORM_TAG(op2);
  15192 
  15193     if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
  15194         int32_t v1, v2;
  15195         int64_t v;
  15196         v1 = JS_VALUE_GET_INT(op1);
  15197         v2 = JS_VALUE_GET_INT(op2);
  15198         v = (int64_t)v1 + (int64_t)v2;
  15199         sp[-2] = JS_NewInt64(ctx, v);
  15200     } else if ((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) &&
  15201                (tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT)) {
  15202         JSBigInt *p1, *p2, *r;
  15203         JSBigIntBuf buf1, buf2;
  15204         /* bigint result */
  15205         if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT)
  15206             p1 = js_bigint_set_short(&buf1, op1);
  15207         else
  15208             p1 = JS_VALUE_GET_PTR(op1);
  15209         if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT)
  15210             p2 = js_bigint_set_short(&buf2, op2);
  15211         else
  15212             p2 = JS_VALUE_GET_PTR(op2);
  15213         r = js_bigint_add(ctx, p1, p2, 0);
  15214         JS_FreeValue(ctx, op1);
  15215         JS_FreeValue(ctx, op2);
  15216         if (!r)
  15217             goto exception;
  15218         sp[-2] = JS_CompactBigInt(ctx, r);
  15219     } else {
  15220         double d1, d2;
  15221         /* float64 result */
  15222         if (JS_ToFloat64Free(ctx, &d1, op1)) {
  15223             JS_FreeValue(ctx, op2);
  15224             goto exception;
  15225         }
  15226         if (JS_ToFloat64Free(ctx, &d2, op2))
  15227             goto exception;
  15228         sp[-2] = __JS_NewFloat64(ctx, d1 + d2);
  15229     }
  15230     return 0;
  15231  exception:
  15232     sp[-2] = JS_UNDEFINED;
  15233     sp[-1] = JS_UNDEFINED;
  15234     return -1;
  15235 }
  15236 
  15237 static no_inline __exception int js_binary_logic_slow(JSContext *ctx,
  15238                                                       JSValue *sp,
  15239                                                       OPCodeEnum op)
  15240 {
  15241     JSValue op1, op2;
  15242     uint32_t tag1, tag2;
  15243     uint32_t v1, v2, r;
  15244 
  15245     op1 = sp[-2];
  15246     op2 = sp[-1];
  15247     tag1 = JS_VALUE_GET_NORM_TAG(op1);
  15248     tag2 = JS_VALUE_GET_NORM_TAG(op2);
  15249 
  15250     if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) {
  15251         js_slimb_t v1, v2, v;
  15252         js_sdlimb_t vd;
  15253         v1 = JS_VALUE_GET_SHORT_BIG_INT(op1);
  15254         v2 = JS_VALUE_GET_SHORT_BIG_INT(op2);
  15255         /* bigint fast path */
  15256         switch(op) {
  15257         case OP_and:
  15258             v = v1 & v2;
  15259             break;
  15260         case OP_or:
  15261             v = v1 | v2;
  15262             break;
  15263         case OP_xor:
  15264             v = v1 ^ v2;
  15265             break;
  15266         case OP_sar:
  15267             if (v2 > (JS_LIMB_BITS - 1)) {
  15268                 goto slow_big_int;
  15269             } else if (v2 < 0) {
  15270                 if (v2 < -(JS_LIMB_BITS - 1))
  15271                     goto slow_big_int;
  15272                 v2 = -v2;
  15273                 goto bigint_shl;
  15274             }
  15275         bigint_sar:
  15276             v = v1 >> v2;
  15277             break;
  15278         case OP_shl:
  15279             if (v2 > (JS_LIMB_BITS - 1)) {
  15280                 goto slow_big_int;
  15281             } else if (v2 < 0) {
  15282                 if (v2 < -(JS_LIMB_BITS - 1))
  15283                     goto slow_big_int;
  15284                 v2 = -v2;
  15285                 goto bigint_sar;
  15286             }
  15287         bigint_shl:
  15288             vd = (js_dlimb_t)v1 << v2;
  15289             if (likely(vd >= JS_SHORT_BIG_INT_MIN &&
  15290                        vd <= JS_SHORT_BIG_INT_MAX)) {
  15291                 v = vd;
  15292             } else {
  15293                 JSBigInt *r = js_bigint_new_di(ctx, vd);
  15294                 if (!r)
  15295                     goto exception;
  15296                 sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r);
  15297                 return 0;
  15298             }
  15299             break;
  15300         default:
  15301             abort();
  15302         }
  15303         sp[-2] = __JS_NewShortBigInt(ctx, v);
  15304         return 0;
  15305     }
  15306     op1 = JS_ToNumericFree(ctx, op1);
  15307     if (JS_IsException(op1)) {
  15308         JS_FreeValue(ctx, op2);
  15309         goto exception;
  15310     }
  15311     op2 = JS_ToNumericFree(ctx, op2);
  15312     if (JS_IsException(op2)) {
  15313         JS_FreeValue(ctx, op1);
  15314         goto exception;
  15315     }
  15316 
  15317     tag1 = JS_VALUE_GET_TAG(op1);
  15318     tag2 = JS_VALUE_GET_TAG(op2);
  15319     if ((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) &&
  15320         (tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT)) {
  15321         JSBigInt *p1, *p2, *r;
  15322         JSBigIntBuf buf1, buf2;
  15323     slow_big_int:
  15324         if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT)
  15325             p1 = js_bigint_set_short(&buf1, op1);
  15326         else
  15327             p1 = JS_VALUE_GET_PTR(op1);
  15328         if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT)
  15329             p2 = js_bigint_set_short(&buf2, op2);
  15330         else
  15331             p2 = JS_VALUE_GET_PTR(op2);
  15332         switch(op) {
  15333         case OP_and:
  15334         case OP_or:
  15335         case OP_xor:
  15336             r = js_bigint_logic(ctx, p1, p2, op);
  15337             break;
  15338         case OP_shl:
  15339         case OP_sar:
  15340             {
  15341                 js_slimb_t shift;
  15342                 shift = js_bigint_get_si_sat(p2);
  15343                 if (shift > INT32_MAX)
  15344                     shift = INT32_MAX;
  15345                 else if (shift < -INT32_MAX)
  15346                     shift = -INT32_MAX;
  15347                 if (op == OP_sar)
  15348                     shift = -shift;
  15349                 if (shift >= 0)
  15350                     r = js_bigint_shl(ctx, p1, shift);
  15351                 else
  15352                     r = js_bigint_shr(ctx, p1, -shift);
  15353             }
  15354             break;
  15355         default:
  15356             abort();
  15357         }
  15358         JS_FreeValue(ctx, op1);
  15359         JS_FreeValue(ctx, op2);
  15360         if (!r)
  15361             goto exception;
  15362         sp[-2] = JS_CompactBigInt(ctx, r);
  15363     } else {
  15364         if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {
  15365             JS_FreeValue(ctx, op2);
  15366             goto exception;
  15367         }
  15368         if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2)))
  15369             goto exception;
  15370         switch(op) {
  15371         case OP_shl:
  15372             r = v1 << (v2 & 0x1f);
  15373             break;
  15374         case OP_sar:
  15375             r = (int)v1 >> (v2 & 0x1f);
  15376             break;
  15377         case OP_and:
  15378             r = v1 & v2;
  15379             break;
  15380         case OP_or:
  15381             r = v1 | v2;
  15382             break;
  15383         case OP_xor:
  15384             r = v1 ^ v2;
  15385             break;
  15386         default:
  15387             abort();
  15388         }
  15389         sp[-2] = JS_NewInt32(ctx, r);
  15390     }
  15391     return 0;
  15392  exception:
  15393     sp[-2] = JS_UNDEFINED;
  15394     sp[-1] = JS_UNDEFINED;
  15395     return -1;
  15396 }
  15397 
  15398 /* op1 must be a bigint or int. */
  15399 static JSBigInt *JS_ToBigIntBuf(JSContext *ctx, JSBigIntBuf *buf1,
  15400                                 JSValue op1)
  15401 {
  15402     JSBigInt *p1;
  15403     
  15404     switch(JS_VALUE_GET_TAG(op1)) {
  15405     case JS_TAG_INT:
  15406         p1 = js_bigint_set_si(buf1, JS_VALUE_GET_INT(op1));
  15407         break;
  15408     case JS_TAG_SHORT_BIG_INT:
  15409         p1 = js_bigint_set_short(buf1, op1);
  15410         break;
  15411     case JS_TAG_BIG_INT:
  15412         p1 = JS_VALUE_GET_PTR(op1);
  15413         break;
  15414     default:
  15415         abort();
  15416     }
  15417     return p1;
  15418 }
  15419 
  15420 /* op1 and op2 must be numeric types and at least one must be a
  15421    bigint. No exception is generated. */
  15422 static int js_compare_bigint(JSContext *ctx, OPCodeEnum op,
  15423                              JSValue op1, JSValue op2)
  15424 {
  15425     int res, val, tag1, tag2;
  15426     JSBigIntBuf buf1, buf2;
  15427     JSBigInt *p1, *p2;
  15428     
  15429     tag1 = JS_VALUE_GET_NORM_TAG(op1);
  15430     tag2 = JS_VALUE_GET_NORM_TAG(op2);
  15431     if ((tag1 == JS_TAG_SHORT_BIG_INT || tag1 == JS_TAG_INT) &&
  15432         (tag2 == JS_TAG_SHORT_BIG_INT || tag2 == JS_TAG_INT)) {
  15433         /* fast path */
  15434         js_slimb_t v1, v2;
  15435         if (tag1 == JS_TAG_INT)
  15436             v1 = JS_VALUE_GET_INT(op1);
  15437         else
  15438             v1 = JS_VALUE_GET_SHORT_BIG_INT(op1);
  15439         if (tag2 == JS_TAG_INT)
  15440             v2 = JS_VALUE_GET_INT(op2);
  15441         else
  15442             v2 = JS_VALUE_GET_SHORT_BIG_INT(op2);
  15443         val = (v1 > v2) - (v1 < v2);
  15444     } else {
  15445         if (tag1 == JS_TAG_FLOAT64) {
  15446             p2 = JS_ToBigIntBuf(ctx, &buf2, op2);
  15447             val = js_bigint_float64_cmp(ctx, p2, JS_VALUE_GET_FLOAT64(op1));
  15448             if (val == 2)
  15449                 goto unordered;
  15450             val = -val;
  15451         } else if (tag2 == JS_TAG_FLOAT64) {
  15452             p1 = JS_ToBigIntBuf(ctx, &buf1, op1);
  15453             val = js_bigint_float64_cmp(ctx, p1, JS_VALUE_GET_FLOAT64(op2));
  15454             if (val == 2) {
  15455             unordered:
  15456                 JS_FreeValue(ctx, op1);
  15457                 JS_FreeValue(ctx, op2);
  15458                 return FALSE;
  15459             }
  15460         } else {
  15461             p1 = JS_ToBigIntBuf(ctx, &buf1, op1);
  15462             p2 = JS_ToBigIntBuf(ctx, &buf2, op2);
  15463             val = js_bigint_cmp(ctx, p1, p2);
  15464         }
  15465         JS_FreeValue(ctx, op1);
  15466         JS_FreeValue(ctx, op2);
  15467     }
  15468 
  15469     switch(op) {
  15470     case OP_lt:
  15471         res = val < 0;
  15472         break;
  15473     case OP_lte:
  15474         res = val <= 0;
  15475         break;
  15476     case OP_gt:
  15477         res = val > 0;
  15478         break;
  15479     case OP_gte:
  15480         res = val >= 0;
  15481         break;
  15482     case OP_eq:
  15483         res = val == 0;
  15484         break;
  15485     default:
  15486         abort();
  15487     }
  15488     return res;
  15489 }
  15490 
  15491 static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
  15492                                         OPCodeEnum op)
  15493 {
  15494     JSValue op1, op2;
  15495     int res;
  15496     uint32_t tag1, tag2;
  15497 
  15498     op1 = sp[-2];
  15499     op2 = sp[-1];
  15500     tag1 = JS_VALUE_GET_NORM_TAG(op1);
  15501     tag2 = JS_VALUE_GET_NORM_TAG(op2);
  15502     op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER);
  15503     if (JS_IsException(op1)) {
  15504         JS_FreeValue(ctx, op2);
  15505         goto exception;
  15506     }
  15507     op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER);
  15508     if (JS_IsException(op2)) {
  15509         JS_FreeValue(ctx, op1);
  15510         goto exception;
  15511     }
  15512     tag1 = JS_VALUE_GET_NORM_TAG(op1);
  15513     tag2 = JS_VALUE_GET_NORM_TAG(op2);
  15514 
  15515     if (tag_is_string(tag1) && tag_is_string(tag2)) {
  15516         if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) {
  15517             res = js_string_compare(ctx, JS_VALUE_GET_STRING(op1),
  15518                                     JS_VALUE_GET_STRING(op2));
  15519         } else {
  15520             res = js_string_rope_compare(ctx, op1, op2, FALSE);
  15521         }
  15522         switch(op) {
  15523         case OP_lt:
  15524             res = (res < 0);
  15525             break;
  15526         case OP_lte:
  15527             res = (res <= 0);
  15528             break;
  15529         case OP_gt:
  15530             res = (res > 0);
  15531             break;
  15532         default:
  15533         case OP_gte:
  15534             res = (res >= 0);
  15535             break;
  15536         }
  15537         JS_FreeValue(ctx, op1);
  15538         JS_FreeValue(ctx, op2);
  15539     } else if ((tag1 <= JS_TAG_NULL || tag1 == JS_TAG_FLOAT64) &&
  15540                (tag2 <= JS_TAG_NULL || tag2 == JS_TAG_FLOAT64)) {
  15541         /* fast path for float64/int */
  15542         goto float64_compare;
  15543     } else {
  15544         if ((((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) &&
  15545               tag_is_string(tag2)) ||
  15546              ((tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) &&
  15547               tag_is_string(tag1)))) {
  15548             if (tag_is_string(tag1)) {
  15549                 op1 = JS_StringToBigInt(ctx, op1);
  15550                 if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT &&
  15551                     JS_VALUE_GET_TAG(op1) != JS_TAG_SHORT_BIG_INT)
  15552                     goto invalid_bigint_string;
  15553             }
  15554             if (tag_is_string(tag2)) {
  15555                 op2 = JS_StringToBigInt(ctx, op2);
  15556                 if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT &&
  15557                     JS_VALUE_GET_TAG(op2) != JS_TAG_SHORT_BIG_INT) {
  15558                 invalid_bigint_string:
  15559                     JS_FreeValue(ctx, op1);
  15560                     JS_FreeValue(ctx, op2);
  15561                     res = FALSE;
  15562                     goto done;
  15563                 }
  15564             }
  15565         } else {
  15566             op1 = JS_ToNumericFree(ctx, op1);
  15567             if (JS_IsException(op1)) {
  15568                 JS_FreeValue(ctx, op2);
  15569                 goto exception;
  15570             }
  15571             op2 = JS_ToNumericFree(ctx, op2);
  15572             if (JS_IsException(op2)) {
  15573                 JS_FreeValue(ctx, op1);
  15574                 goto exception;
  15575             }
  15576         }
  15577 
  15578         tag1 = JS_VALUE_GET_NORM_TAG(op1);
  15579         tag2 = JS_VALUE_GET_NORM_TAG(op2);
  15580 
  15581         if (tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT ||
  15582             tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) {
  15583             res = js_compare_bigint(ctx, op, op1, op2);
  15584         } else {
  15585             double d1, d2;
  15586 
  15587         float64_compare:
  15588             /* can use floating point comparison */
  15589             if (tag1 == JS_TAG_FLOAT64) {
  15590                 d1 = JS_VALUE_GET_FLOAT64(op1);
  15591             } else {
  15592                 d1 = JS_VALUE_GET_INT(op1);
  15593             }
  15594             if (tag2 == JS_TAG_FLOAT64) {
  15595                 d2 = JS_VALUE_GET_FLOAT64(op2);
  15596             } else {
  15597                 d2 = JS_VALUE_GET_INT(op2);
  15598             }
  15599             switch(op) {
  15600             case OP_lt:
  15601                 res = (d1 < d2); /* if NaN return false */
  15602                 break;
  15603             case OP_lte:
  15604                 res = (d1 <= d2); /* if NaN return false */
  15605                 break;
  15606             case OP_gt:
  15607                 res = (d1 > d2); /* if NaN return false */
  15608                 break;
  15609             default:
  15610             case OP_gte:
  15611                 res = (d1 >= d2); /* if NaN return false */
  15612                 break;
  15613             }
  15614         }
  15615     }
  15616  done:
  15617     sp[-2] = JS_NewBool(ctx, res);
  15618     return 0;
  15619  exception:
  15620     sp[-2] = JS_UNDEFINED;
  15621     sp[-1] = JS_UNDEFINED;
  15622     return -1;
  15623 }
  15624 
  15625 static BOOL tag_is_number(uint32_t tag)
  15626 {
  15627     return (tag == JS_TAG_INT || 
  15628             tag == JS_TAG_FLOAT64 ||
  15629             tag == JS_TAG_BIG_INT || tag == JS_TAG_SHORT_BIG_INT);
  15630 }
  15631 
  15632 static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
  15633                                             BOOL is_neq)
  15634 {
  15635     JSValue op1, op2;
  15636     int res;
  15637     uint32_t tag1, tag2;
  15638 
  15639     op1 = sp[-2];
  15640     op2 = sp[-1];
  15641  redo:
  15642     tag1 = JS_VALUE_GET_NORM_TAG(op1);
  15643     tag2 = JS_VALUE_GET_NORM_TAG(op2);
  15644     if (tag_is_number(tag1) && tag_is_number(tag2)) {
  15645         if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
  15646             res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);
  15647         } else if ((tag1 == JS_TAG_FLOAT64 &&
  15648                     (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64)) ||
  15649                    (tag2 == JS_TAG_FLOAT64 &&
  15650                     (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64))) {
  15651             double d1, d2;
  15652             if (tag1 == JS_TAG_FLOAT64) {
  15653                 d1 = JS_VALUE_GET_FLOAT64(op1);
  15654             } else {
  15655                 d1 = JS_VALUE_GET_INT(op1);
  15656             }
  15657             if (tag2 == JS_TAG_FLOAT64) {
  15658                 d2 = JS_VALUE_GET_FLOAT64(op2);
  15659             } else {
  15660                 d2 = JS_VALUE_GET_INT(op2);
  15661             }
  15662             res = (d1 == d2);
  15663         } else {
  15664             res = js_compare_bigint(ctx, OP_eq, op1, op2);
  15665         }
  15666     } else if (tag1 == tag2) {
  15667         res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
  15668     } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) ||
  15669                (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) {
  15670         res = TRUE;
  15671     } else if (tag_is_string(tag1) && tag_is_string(tag2)) {
  15672         /* needed when comparing strings and ropes */
  15673         res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
  15674     } else if ((tag_is_string(tag1) && tag_is_number(tag2)) ||
  15675                (tag_is_string(tag2) && tag_is_number(tag1))) {
  15676 
  15677         if (tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT ||
  15678             tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) {
  15679             if (tag_is_string(tag1)) {
  15680                 op1 = JS_StringToBigInt(ctx, op1);
  15681                 if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT &&
  15682                     JS_VALUE_GET_TAG(op1) != JS_TAG_SHORT_BIG_INT)
  15683                     goto invalid_bigint_string;
  15684             }
  15685             if (tag_is_string(tag2)) {
  15686                 op2 = JS_StringToBigInt(ctx, op2);
  15687                 if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT &&
  15688                     JS_VALUE_GET_TAG(op2) != JS_TAG_SHORT_BIG_INT ) {
  15689                 invalid_bigint_string:
  15690                     JS_FreeValue(ctx, op1);
  15691                     JS_FreeValue(ctx, op2);
  15692                     res = FALSE;
  15693                     goto done;
  15694                 }
  15695             }
  15696         } else {
  15697             op1 = JS_ToNumericFree(ctx, op1);
  15698             if (JS_IsException(op1)) {
  15699                 JS_FreeValue(ctx, op2);
  15700                 goto exception;
  15701             }
  15702             op2 = JS_ToNumericFree(ctx, op2);
  15703             if (JS_IsException(op2)) {
  15704                 JS_FreeValue(ctx, op1);
  15705                 goto exception;
  15706             }
  15707         }
  15708         res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
  15709     } else if (tag1 == JS_TAG_BOOL) {
  15710         op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1));
  15711         goto redo;
  15712     } else if (tag2 == JS_TAG_BOOL) {
  15713         op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2));
  15714         goto redo;
  15715     } else if ((tag1 == JS_TAG_OBJECT &&
  15716                 (tag_is_number(tag2) || tag_is_string(tag2) || tag2 == JS_TAG_SYMBOL)) ||
  15717                (tag2 == JS_TAG_OBJECT &&
  15718                 (tag_is_number(tag1) || tag_is_string(tag1) || tag1 == JS_TAG_SYMBOL))) {
  15719         op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
  15720         if (JS_IsException(op1)) {
  15721             JS_FreeValue(ctx, op2);
  15722             goto exception;
  15723         }
  15724         op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
  15725         if (JS_IsException(op2)) {
  15726             JS_FreeValue(ctx, op1);
  15727             goto exception;
  15728         }
  15729         goto redo;
  15730     } else {
  15731         /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */
  15732         if ((JS_IsHTMLDDA(ctx, op1) &&
  15733              (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) ||
  15734             (JS_IsHTMLDDA(ctx, op2) &&
  15735              (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) {
  15736             res = TRUE;
  15737         } else {
  15738             res = FALSE;
  15739         }
  15740         JS_FreeValue(ctx, op1);
  15741         JS_FreeValue(ctx, op2);
  15742     }
  15743  done:
  15744     sp[-2] = JS_NewBool(ctx, res ^ is_neq);
  15745     return 0;
  15746  exception:
  15747     sp[-2] = JS_UNDEFINED;
  15748     sp[-1] = JS_UNDEFINED;
  15749     return -1;
  15750 }
  15751 
  15752 static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp)
  15753 {
  15754     JSValue op1, op2;
  15755     uint32_t v1, v2, r;
  15756 
  15757     op1 = sp[-2];
  15758     op2 = sp[-1];
  15759     op1 = JS_ToNumericFree(ctx, op1);
  15760     if (JS_IsException(op1)) {
  15761         JS_FreeValue(ctx, op2);
  15762         goto exception;
  15763     }
  15764     op2 = JS_ToNumericFree(ctx, op2);
  15765     if (JS_IsException(op2)) {
  15766         JS_FreeValue(ctx, op1);
  15767         goto exception;
  15768     }
  15769     if (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT ||
  15770         JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT ||
  15771         JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_INT ||
  15772         JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT) {
  15773         JS_ThrowTypeError(ctx, "bigint operands are forbidden for >>>");
  15774         JS_FreeValue(ctx, op1);
  15775         JS_FreeValue(ctx, op2);
  15776         goto exception;
  15777     }
  15778     /* cannot give an exception */
  15779     JS_ToUint32Free(ctx, &v1, op1);
  15780     JS_ToUint32Free(ctx, &v2, op2);
  15781     r = v1 >> (v2 & 0x1f);
  15782     sp[-2] = JS_NewUint32(ctx, r);
  15783     return 0;
  15784  exception:
  15785     sp[-2] = JS_UNDEFINED;
  15786     sp[-1] = JS_UNDEFINED;
  15787     return -1;
  15788 }
  15789 
  15790 /* XXX: Should take JSValueConst arguments */
  15791 static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
  15792                           JSStrictEqModeEnum eq_mode)
  15793 {
  15794     BOOL res;
  15795     int tag1, tag2;
  15796     double d1, d2;
  15797 
  15798     tag1 = JS_VALUE_GET_NORM_TAG(op1);
  15799     tag2 = JS_VALUE_GET_NORM_TAG(op2);
  15800     switch(tag1) {
  15801     case JS_TAG_BOOL:
  15802         if (tag1 != tag2) {
  15803             res = FALSE;
  15804         } else {
  15805             res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);
  15806             goto done_no_free;
  15807         }
  15808         break;
  15809     case JS_TAG_NULL:
  15810     case JS_TAG_UNDEFINED:
  15811         res = (tag1 == tag2);
  15812         break;
  15813     case JS_TAG_STRING:
  15814     case JS_TAG_STRING_ROPE:
  15815         {
  15816             if (!tag_is_string(tag2)) {
  15817                 res = FALSE;
  15818             } else if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) {
  15819                 res = js_string_eq(ctx, JS_VALUE_GET_STRING(op1),
  15820                                    JS_VALUE_GET_STRING(op2));
  15821             } else {
  15822                 res = (js_string_rope_compare(ctx, op1, op2, TRUE) == 0);
  15823             }
  15824         }
  15825         break;
  15826     case JS_TAG_SYMBOL:
  15827         {
  15828             JSAtomStruct *p1, *p2;
  15829             if (tag1 != tag2) {
  15830                 res = FALSE;
  15831             } else {
  15832                 p1 = JS_VALUE_GET_PTR(op1);
  15833                 p2 = JS_VALUE_GET_PTR(op2);
  15834                 res = (p1 == p2);
  15835             }
  15836         }
  15837         break;
  15838     case JS_TAG_OBJECT:
  15839         if (tag1 != tag2)
  15840             res = FALSE;
  15841         else
  15842             res = JS_VALUE_GET_OBJ(op1) == JS_VALUE_GET_OBJ(op2);
  15843         break;
  15844     case JS_TAG_INT:
  15845         d1 = JS_VALUE_GET_INT(op1);
  15846         if (tag2 == JS_TAG_INT) {
  15847             d2 = JS_VALUE_GET_INT(op2);
  15848             goto number_test;
  15849         } else if (tag2 == JS_TAG_FLOAT64) {
  15850             d2 = JS_VALUE_GET_FLOAT64(op2);
  15851             goto number_test;
  15852         } else {
  15853             res = FALSE;
  15854         }
  15855         break;
  15856     case JS_TAG_FLOAT64:
  15857         d1 = JS_VALUE_GET_FLOAT64(op1);
  15858         if (tag2 == JS_TAG_FLOAT64) {
  15859             d2 = JS_VALUE_GET_FLOAT64(op2);
  15860         } else if (tag2 == JS_TAG_INT) {
  15861             d2 = JS_VALUE_GET_INT(op2);
  15862         } else {
  15863             res = FALSE;
  15864             break;
  15865         }
  15866     number_test:
  15867         if (unlikely(eq_mode >= JS_EQ_SAME_VALUE)) {
  15868             JSFloat64Union u1, u2;
  15869             /* NaN is not always normalized, so this test is necessary */
  15870             if (isnan(d1) || isnan(d2)) {
  15871                 res = isnan(d1) == isnan(d2);
  15872             } else if (eq_mode == JS_EQ_SAME_VALUE_ZERO) {
  15873                 res = (d1 == d2); /* +0 == -0 */
  15874             } else {
  15875                 u1.d = d1;
  15876                 u2.d = d2;
  15877                 res = (u1.u64 == u2.u64); /* +0 != -0 */
  15878             }
  15879         } else {
  15880             res = (d1 == d2); /* if NaN return false and +0 == -0 */
  15881         }
  15882         goto done_no_free;
  15883     case JS_TAG_SHORT_BIG_INT:
  15884     case JS_TAG_BIG_INT:
  15885         {
  15886             JSBigIntBuf buf1, buf2;
  15887             JSBigInt *p1, *p2;
  15888 
  15889             if (tag2 != JS_TAG_SHORT_BIG_INT &&
  15890                 tag2 != JS_TAG_BIG_INT) {
  15891                 res = FALSE;
  15892                 break;
  15893             }
  15894             
  15895             if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT)
  15896                 p1 = js_bigint_set_short(&buf1, op1);
  15897             else
  15898                 p1 = JS_VALUE_GET_PTR(op1);
  15899             if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT)
  15900                 p2 = js_bigint_set_short(&buf2, op2);
  15901             else
  15902                 p2 = JS_VALUE_GET_PTR(op2);
  15903             res = (js_bigint_cmp(ctx, p1, p2) == 0);
  15904         }
  15905         break;
  15906     default:
  15907         res = FALSE;
  15908         break;
  15909     }
  15910     JS_FreeValue(ctx, op1);
  15911     JS_FreeValue(ctx, op2);
  15912  done_no_free:
  15913     return res;
  15914 }
  15915 
  15916 static BOOL js_strict_eq(JSContext *ctx, JSValueConst op1, JSValueConst op2)
  15917 {
  15918     return js_strict_eq2(ctx,
  15919                          JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),
  15920                          JS_EQ_STRICT);
  15921 }
  15922 
  15923 BOOL JS_StrictEq(JSContext *ctx, JSValueConst op1, JSValueConst op2)
  15924 {
  15925     return js_strict_eq(ctx, op1, op2);
  15926 }
  15927 
  15928 static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2)
  15929 {
  15930     return js_strict_eq2(ctx,
  15931                          JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),
  15932                          JS_EQ_SAME_VALUE);
  15933 }
  15934 
  15935 BOOL JS_SameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2)
  15936 {
  15937     return js_same_value(ctx, op1, op2);
  15938 }
  15939 
  15940 static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2)
  15941 {
  15942     return js_strict_eq2(ctx,
  15943                          JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),
  15944                          JS_EQ_SAME_VALUE_ZERO);
  15945 }
  15946 
  15947 BOOL JS_SameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2)
  15948 {
  15949     return js_same_value_zero(ctx, op1, op2);
  15950 }
  15951 
  15952 static no_inline int js_strict_eq_slow(JSContext *ctx, JSValue *sp,
  15953                                        BOOL is_neq)
  15954 {
  15955     BOOL res;
  15956     res = js_strict_eq2(ctx, sp[-2], sp[-1], JS_EQ_STRICT);
  15957     sp[-2] = JS_NewBool(ctx, res ^ is_neq);
  15958     return 0;
  15959 }
  15960 
  15961 static __exception int js_operator_in(JSContext *ctx, JSValue *sp)
  15962 {
  15963     JSValue op1, op2;
  15964     JSAtom atom;
  15965     int ret;
  15966 
  15967     op1 = sp[-2];
  15968     op2 = sp[-1];
  15969 
  15970     if (JS_VALUE_GET_TAG(op2) != JS_TAG_OBJECT) {
  15971         JS_ThrowTypeError(ctx, "invalid 'in' operand");
  15972         return -1;
  15973     }
  15974     atom = JS_ValueToAtom(ctx, op1);
  15975     if (unlikely(atom == JS_ATOM_NULL))
  15976         return -1;
  15977     ret = JS_HasProperty(ctx, op2, atom);
  15978     JS_FreeAtom(ctx, atom);
  15979     if (ret < 0)
  15980         return -1;
  15981     JS_FreeValue(ctx, op1);
  15982     JS_FreeValue(ctx, op2);
  15983     sp[-2] = JS_NewBool(ctx, ret);
  15984     return 0;
  15985 }
  15986 
  15987 static __exception int js_operator_private_in(JSContext *ctx, JSValue *sp)
  15988 {
  15989     JSValue op1, op2;
  15990     int ret;
  15991 
  15992     op1 = sp[-2]; /* object */
  15993     op2 = sp[-1]; /* field name or method function */
  15994 
  15995     if (JS_VALUE_GET_TAG(op1) != JS_TAG_OBJECT) {
  15996         JS_ThrowTypeError(ctx, "invalid 'in' operand");
  15997         return -1;
  15998     }
  15999     if (JS_IsObject(op2)) {
  16000         /* method: use the brand */
  16001         ret = JS_CheckBrand(ctx, op1, op2);
  16002         if (ret < 0)
  16003             return -1;
  16004     } else {
  16005         JSAtom atom;
  16006         JSObject *p;
  16007         JSShapeProperty *prs;
  16008         JSProperty *pr;
  16009         /* field */
  16010         atom = JS_ValueToAtom(ctx, op2);
  16011         if (unlikely(atom == JS_ATOM_NULL))
  16012             return -1;
  16013         p = JS_VALUE_GET_OBJ(op1);
  16014         prs = find_own_property(&pr, p, atom);
  16015         JS_FreeAtom(ctx, atom);
  16016         ret = (prs != NULL);
  16017     }
  16018     JS_FreeValue(ctx, op1);
  16019     JS_FreeValue(ctx, op2);
  16020     sp[-2] = JS_NewBool(ctx, ret);
  16021     return 0;
  16022 }
  16023 
  16024 static __exception int js_has_unscopable(JSContext *ctx, JSValueConst obj,
  16025                                          JSAtom atom)
  16026 {
  16027     JSValue arr, val;
  16028     int ret;
  16029 
  16030     arr = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_unscopables);
  16031     if (JS_IsException(arr))
  16032         return -1;
  16033     ret = 0;
  16034     if (JS_IsObject(arr)) {
  16035         val = JS_GetProperty(ctx, arr, atom);
  16036         ret = JS_ToBoolFree(ctx, val);
  16037     }
  16038     JS_FreeValue(ctx, arr);
  16039     return ret;
  16040 }
  16041 
  16042 static __exception int js_operator_instanceof(JSContext *ctx, JSValue *sp)
  16043 {
  16044     JSValue op1, op2;
  16045     BOOL ret;
  16046 
  16047     op1 = sp[-2];
  16048     op2 = sp[-1];
  16049     ret = JS_IsInstanceOf(ctx, op1, op2);
  16050     if (ret < 0)
  16051         return ret;
  16052     JS_FreeValue(ctx, op1);
  16053     JS_FreeValue(ctx, op2);
  16054     sp[-2] = JS_NewBool(ctx, ret);
  16055     return 0;
  16056 }
  16057 
  16058 static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1)
  16059 {
  16060     JSAtom atom;
  16061     uint32_t tag;
  16062 
  16063     tag = JS_VALUE_GET_NORM_TAG(op1);
  16064     switch(tag) {
  16065     case JS_TAG_SHORT_BIG_INT:
  16066     case JS_TAG_BIG_INT:
  16067         atom = JS_ATOM_bigint;
  16068         break;
  16069     case JS_TAG_INT:
  16070     case JS_TAG_FLOAT64:
  16071         atom = JS_ATOM_number;
  16072         break;
  16073     case JS_TAG_UNDEFINED:
  16074         atom = JS_ATOM_undefined;
  16075         break;
  16076     case JS_TAG_BOOL:
  16077         atom = JS_ATOM_boolean;
  16078         break;
  16079     case JS_TAG_STRING:
  16080     case JS_TAG_STRING_ROPE:
  16081         atom = JS_ATOM_string;
  16082         break;
  16083     case JS_TAG_OBJECT:
  16084         {
  16085             JSObject *p;
  16086             p = JS_VALUE_GET_OBJ(op1);
  16087             if (unlikely(p->is_HTMLDDA))
  16088                 atom = JS_ATOM_undefined;
  16089             else if (JS_IsFunction(ctx, op1))
  16090                 atom = JS_ATOM_function;
  16091             else
  16092                 goto obj_type;
  16093         }
  16094         break;
  16095     case JS_TAG_NULL:
  16096     obj_type:
  16097         atom = JS_ATOM_object;
  16098         break;
  16099     case JS_TAG_SYMBOL:
  16100         atom = JS_ATOM_symbol;
  16101         break;
  16102     default:
  16103         atom = JS_ATOM_unknown;
  16104         break;
  16105     }
  16106     return atom;
  16107 }
  16108 
  16109 static __exception int js_operator_delete(JSContext *ctx, JSValue *sp)
  16110 {
  16111     JSValue op1, op2;
  16112     JSAtom atom;
  16113     int ret;
  16114 
  16115     op1 = sp[-2];
  16116     op2 = sp[-1];
  16117     atom = JS_ValueToAtom(ctx, op2);
  16118     if (unlikely(atom == JS_ATOM_NULL))
  16119         return -1;
  16120     ret = JS_DeleteProperty(ctx, op1, atom, JS_PROP_THROW_STRICT);
  16121     JS_FreeAtom(ctx, atom);
  16122     if (unlikely(ret < 0))
  16123         return -1;
  16124     JS_FreeValue(ctx, op1);
  16125     JS_FreeValue(ctx, op2);
  16126     sp[-2] = JS_NewBool(ctx, ret);
  16127     return 0;
  16128 }
  16129 
  16130 /* XXX: not 100% compatible, but mozilla seems to use a similar
  16131    implementation to ensure that caller in non strict mode does not
  16132    throw (ES5 compatibility) */
  16133 static JSValue js_throw_type_error(JSContext *ctx, JSValueConst this_val,
  16134                                    int argc, JSValueConst *argv)
  16135 {
  16136     JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
  16137     if (!b || (b->js_mode & JS_MODE_STRICT) || !b->has_prototype || argc >= 1) {
  16138         return JS_ThrowTypeError(ctx, "invalid property access");
  16139     }
  16140     return JS_UNDEFINED;
  16141 }
  16142 
  16143 static JSValue js_function_proto_fileName(JSContext *ctx,
  16144                                           JSValueConst this_val)
  16145 {
  16146     JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
  16147     if (b && b->has_debug) {
  16148         return JS_AtomToString(ctx, b->debug.filename);
  16149     }
  16150     return JS_UNDEFINED;
  16151 }
  16152 
  16153 static JSValue js_function_proto_lineNumber(JSContext *ctx,
  16154                                             JSValueConst this_val, int is_col)
  16155 {
  16156     JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
  16157     if (b && b->has_debug) {
  16158         int line_num, col_num;
  16159         line_num = find_line_num(ctx, b, -1, &col_num);
  16160         if (is_col)
  16161             return JS_NewInt32(ctx, col_num);
  16162         else
  16163             return JS_NewInt32(ctx, line_num);
  16164     }
  16165     return JS_UNDEFINED;
  16166 }
  16167 
  16168 static int js_arguments_define_own_property(JSContext *ctx,
  16169                                             JSValueConst this_obj,
  16170                                             JSAtom prop, JSValueConst val,
  16171                                             JSValueConst getter, JSValueConst setter, int flags)
  16172 {
  16173     JSObject *p;
  16174     uint32_t idx;
  16175     p = JS_VALUE_GET_OBJ(this_obj);
  16176     /* convert to normal array when redefining an existing numeric field */
  16177     if (p->fast_array && JS_AtomIsArrayIndex(ctx, &idx, prop) &&
  16178         idx < p->u.array.count) {
  16179         if (convert_fast_array_to_array(ctx, p))
  16180             return -1;
  16181     }
  16182     /* run the default define own property */
  16183     return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter,
  16184                              flags | JS_PROP_NO_EXOTIC);
  16185 }
  16186 
  16187 static const JSClassExoticMethods js_arguments_exotic_methods = {
  16188     .define_own_property = js_arguments_define_own_property,
  16189 };
  16190 
  16191 static JSValue js_build_arguments(JSContext *ctx, int argc, JSValueConst *argv)
  16192 {
  16193     JSValue val, *tab;
  16194     JSProperty props[3];
  16195     JSObject *p;
  16196     int i;
  16197 
  16198     props[0].u.value = JS_NewInt32(ctx, argc); /* length */
  16199     props[1].u.value = JS_DupValue(ctx, ctx->array_proto_values); /* Symbol.iterator */
  16200     props[2].u.getset.getter = JS_VALUE_GET_OBJ(JS_DupValue(ctx, ctx->throw_type_error)); /* callee */
  16201     props[2].u.getset.setter = JS_VALUE_GET_OBJ(JS_DupValue(ctx, ctx->throw_type_error)); /* callee */
  16202     
  16203     val = JS_NewObjectFromShape(ctx, js_dup_shape(ctx->arguments_shape),
  16204                                 JS_CLASS_ARGUMENTS, props);
  16205     if (JS_IsException(val))
  16206         return val;
  16207     p = JS_VALUE_GET_OBJ(val);
  16208 
  16209     /* initialize the fast array part */
  16210     tab = NULL;
  16211     if (argc > 0) {
  16212         tab = js_malloc(ctx, sizeof(tab[0]) * argc);
  16213         if (!tab)
  16214             goto fail;
  16215         for(i = 0; i < argc; i++) {
  16216             tab[i] = JS_DupValue(ctx, argv[i]);
  16217         }
  16218     }
  16219     p->u.array.u.values = tab;
  16220     p->u.array.count = argc;
  16221     return val;
  16222  fail:
  16223     JS_FreeValue(ctx, val);
  16224     return JS_EXCEPTION;
  16225 }
  16226 
  16227 #define GLOBAL_VAR_OFFSET 0x40000000
  16228 #define ARGUMENT_VAR_OFFSET 0x20000000
  16229 
  16230 static void js_mapped_arguments_finalizer(JSRuntime *rt, JSValue val)
  16231 {
  16232     JSObject *p = JS_VALUE_GET_OBJ(val);
  16233     JSVarRef **var_refs = p->u.array.u.var_refs;
  16234     int i;
  16235     for(i = 0; i < p->u.array.count; i++)
  16236         free_var_ref(rt, var_refs[i]);
  16237     js_free_rt(rt, var_refs);
  16238 }
  16239 
  16240 static void js_mapped_arguments_mark(JSRuntime *rt, JSValueConst val,
  16241                                      JS_MarkFunc *mark_func)
  16242 {
  16243     JSObject *p = JS_VALUE_GET_OBJ(val);
  16244     JSVarRef **var_refs = p->u.array.u.var_refs;
  16245     int i;
  16246     
  16247     for(i = 0; i < p->u.array.count; i++)
  16248         mark_func(rt, &var_refs[i]->header);
  16249 }
  16250 
  16251 /* legacy arguments object: add references to the function arguments */
  16252 static JSValue js_build_mapped_arguments(JSContext *ctx, int argc,
  16253                                          JSValueConst *argv,
  16254                                          JSStackFrame *sf, int arg_count)
  16255 {
  16256     JSValue val;
  16257     JSProperty props[3];
  16258     JSVarRef **tab, *var_ref;
  16259     JSObject *p;
  16260     int i, j;
  16261 
  16262     props[0].u.value = JS_NewInt32(ctx, argc); /* length */
  16263     props[1].u.value = JS_DupValue(ctx, ctx->array_proto_values); /* Symbol.iterator */
  16264     props[2].u.value = JS_DupValue(ctx, ctx->rt->current_stack_frame->cur_func); /* callee */
  16265     
  16266     val = JS_NewObjectFromShape(ctx, js_dup_shape(ctx->mapped_arguments_shape),
  16267                                 JS_CLASS_MAPPED_ARGUMENTS, props);
  16268     if (JS_IsException(val))
  16269         return val;
  16270     p = JS_VALUE_GET_OBJ(val);
  16271 
  16272     /* initialize the fast array part */
  16273     tab = NULL;
  16274     if (argc > 0) {
  16275         tab = js_malloc(ctx, sizeof(tab[0]) * argc);
  16276         if (!tab)
  16277             goto fail;
  16278         for(i = 0; i < arg_count; i++) {
  16279             var_ref = get_var_ref(ctx, sf, i, TRUE);
  16280             if (!var_ref)
  16281                 goto fail1;
  16282             tab[i] = var_ref;
  16283         }
  16284         for(i = arg_count; i < argc; i++) {
  16285             var_ref = js_create_var_ref(ctx, FALSE);
  16286             if (!var_ref) {
  16287             fail1:
  16288                 for(j = 0; j < i; j++)
  16289                     free_var_ref(ctx->rt, tab[j]);
  16290                 js_free(ctx, tab);
  16291                 goto fail;
  16292             }
  16293             var_ref->value = JS_DupValue(ctx, argv[i]);
  16294             tab[i] = var_ref;
  16295         }
  16296     }
  16297     p->u.array.u.var_refs = tab;
  16298     p->u.array.count = argc;
  16299     return val;
  16300  fail:
  16301     JS_FreeValue(ctx, val);
  16302     return JS_EXCEPTION;
  16303 }
  16304 
  16305 static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
  16306 {
  16307     JSObject *p, *p1;
  16308     JSPropertyEnum *tab_atom;
  16309     int i;
  16310     JSValue enum_obj;
  16311     JSForInIterator *it;
  16312     uint32_t tag, tab_atom_count;
  16313 
  16314     tag = JS_VALUE_GET_TAG(obj);
  16315     if (tag != JS_TAG_OBJECT && tag != JS_TAG_NULL && tag != JS_TAG_UNDEFINED) {
  16316         obj = JS_ToObjectFree(ctx, obj);
  16317     }
  16318 
  16319     it = js_malloc(ctx, sizeof(*it));
  16320     if (!it) {
  16321         JS_FreeValue(ctx, obj);
  16322         return JS_EXCEPTION;
  16323     }
  16324     enum_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_FOR_IN_ITERATOR);
  16325     if (JS_IsException(enum_obj)) {
  16326         js_free(ctx, it);
  16327         JS_FreeValue(ctx, obj);
  16328         return JS_EXCEPTION;
  16329     }
  16330     it->is_array = FALSE;
  16331     it->obj = obj;
  16332     it->idx = 0;
  16333     it->tab_atom = NULL;
  16334     it->atom_count = 0;
  16335     it->in_prototype_chain = FALSE;
  16336     p1 = JS_VALUE_GET_OBJ(enum_obj);
  16337     p1->u.for_in_iterator = it;
  16338 
  16339     if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)
  16340         return enum_obj;
  16341 
  16342     p = JS_VALUE_GET_OBJ(obj);
  16343     if (p->fast_array) {
  16344         JSShape *sh;
  16345         JSShapeProperty *prs;
  16346         /* check that there are no enumerable normal fields */
  16347         sh = p->shape;
  16348         for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
  16349             if (prs->flags & JS_PROP_ENUMERABLE)
  16350                 goto normal_case;
  16351         }
  16352         /* for fast arrays, we only store the number of elements */
  16353         it->is_array = TRUE;
  16354         it->atom_count = p->u.array.count;
  16355     } else {
  16356     normal_case:
  16357         if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
  16358                                            JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
  16359             JS_FreeValue(ctx, enum_obj);
  16360             return JS_EXCEPTION;
  16361         }
  16362         it->tab_atom = tab_atom;
  16363         it->atom_count = tab_atom_count;
  16364     }
  16365     return enum_obj;
  16366 }
  16367 
  16368 /* obj -> enum_obj */
  16369 static __exception int js_for_in_start(JSContext *ctx, JSValue *sp)
  16370 {
  16371     sp[-1] = build_for_in_iterator(ctx, sp[-1]);
  16372     if (JS_IsException(sp[-1]))
  16373         return -1;
  16374     return 0;
  16375 }
  16376 
  16377 /* return -1 if exception, 0 if slow case, 1 if the enumeration is finished */
  16378 static __exception int js_for_in_prepare_prototype_chain_enum(JSContext *ctx,
  16379                                                               JSValueConst enum_obj)
  16380 {
  16381     JSObject *p;
  16382     JSForInIterator *it;
  16383     JSPropertyEnum *tab_atom;
  16384     uint32_t tab_atom_count, i;
  16385     JSValue obj1;
  16386 
  16387     p = JS_VALUE_GET_OBJ(enum_obj);
  16388     it = p->u.for_in_iterator;
  16389 
  16390     /* check if there are enumerable properties in the prototype chain (fast path) */
  16391     obj1 = JS_DupValue(ctx, it->obj);
  16392     for(;;) {
  16393         obj1 = JS_GetPrototypeFree(ctx, obj1);
  16394         if (JS_IsNull(obj1))
  16395             break;
  16396         if (JS_IsException(obj1))
  16397             goto fail;
  16398         if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
  16399                                            JS_VALUE_GET_OBJ(obj1),
  16400                                            JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) {
  16401             JS_FreeValue(ctx, obj1);
  16402             goto fail;
  16403         }
  16404         JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count);
  16405         if (tab_atom_count != 0) {
  16406             JS_FreeValue(ctx, obj1);
  16407             goto slow_path;
  16408         }
  16409         /* must check for timeout to avoid infinite loop */
  16410         if (js_poll_interrupts(ctx)) {
  16411             JS_FreeValue(ctx, obj1);
  16412             goto fail;
  16413         }
  16414     }
  16415     JS_FreeValue(ctx, obj1);
  16416     return 1;
  16417 
  16418  slow_path:
  16419     /* add the visited properties, even if they are not enumerable */
  16420     if (it->is_array) {
  16421         if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
  16422                                            JS_VALUE_GET_OBJ(it->obj),
  16423                                            JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
  16424             goto fail;
  16425         }
  16426         it->is_array = FALSE;
  16427         it->tab_atom = tab_atom;
  16428         it->atom_count = tab_atom_count;
  16429     }
  16430 
  16431     for(i = 0; i < it->atom_count; i++) {
  16432         if (JS_DefinePropertyValue(ctx, enum_obj, it->tab_atom[i].atom, JS_NULL, JS_PROP_ENUMERABLE) < 0)
  16433             goto fail;
  16434     }
  16435     return 0;
  16436  fail:
  16437     return -1;
  16438 }
  16439 
  16440 /* enum_obj -> enum_obj value done */
  16441 static __exception int js_for_in_next(JSContext *ctx, JSValue *sp)
  16442 {
  16443     JSValueConst enum_obj;
  16444     JSObject *p;
  16445     JSAtom prop;
  16446     JSForInIterator *it;
  16447     JSPropertyEnum *tab_atom;
  16448     uint32_t tab_atom_count;
  16449     int ret;
  16450 
  16451     enum_obj = sp[-1];
  16452     /* fail safe */
  16453     if (JS_VALUE_GET_TAG(enum_obj) != JS_TAG_OBJECT)
  16454         goto done;
  16455     p = JS_VALUE_GET_OBJ(enum_obj);
  16456     if (p->class_id != JS_CLASS_FOR_IN_ITERATOR)
  16457         goto done;
  16458     it = p->u.for_in_iterator;
  16459 
  16460     for(;;) {
  16461         if (it->idx >= it->atom_count) {
  16462             if (JS_IsNull(it->obj) || JS_IsUndefined(it->obj))
  16463                 goto done; /* not an object */
  16464             /* no more property in the current object: look in the prototype */
  16465             if (!it->in_prototype_chain) {
  16466                 ret = js_for_in_prepare_prototype_chain_enum(ctx, enum_obj);
  16467                 if (ret < 0)
  16468                     return -1;
  16469                 if (ret)
  16470                     goto done;
  16471                 it->in_prototype_chain = TRUE;
  16472             }
  16473             it->obj = JS_GetPrototypeFree(ctx, it->obj);
  16474             if (JS_IsException(it->obj))
  16475                 return -1;
  16476             if (JS_IsNull(it->obj))
  16477                 goto done; /* no more prototype */
  16478 
  16479             /* must check for timeout to avoid infinite loop */
  16480             if (js_poll_interrupts(ctx))
  16481                 return -1;
  16482 
  16483             if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
  16484                                                JS_VALUE_GET_OBJ(it->obj),
  16485                                                JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
  16486                 return -1;
  16487             }
  16488             JS_FreePropertyEnum(ctx, it->tab_atom, it->atom_count);
  16489             it->tab_atom = tab_atom;
  16490             it->atom_count = tab_atom_count;
  16491             it->idx = 0;
  16492         } else {
  16493             if (it->is_array) {
  16494                 prop = __JS_AtomFromUInt32(it->idx);
  16495                 it->idx++;
  16496             } else {
  16497                 BOOL is_enumerable;
  16498                 prop = it->tab_atom[it->idx].atom;
  16499                 is_enumerable = it->tab_atom[it->idx].is_enumerable;
  16500                 it->idx++;
  16501                 if (it->in_prototype_chain) {
  16502                     /* slow case: we are in the prototype chain */
  16503                     ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(enum_obj), prop);
  16504                     if (ret < 0)
  16505                         return ret;
  16506                     if (ret)
  16507                         continue; /* already visited */
  16508                     /* add to the visited property list */
  16509                     if (JS_DefinePropertyValue(ctx, enum_obj, prop, JS_NULL,
  16510                                                JS_PROP_ENUMERABLE) < 0)
  16511                         return -1;
  16512                 }
  16513                 if (!is_enumerable)
  16514                     continue;
  16515             }
  16516             /* check if the property was deleted */
  16517             ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(it->obj), prop);
  16518             if (ret < 0)
  16519                 return ret;
  16520             if (ret)
  16521                 break;
  16522         }
  16523     }
  16524     /* return the property */
  16525     sp[0] = JS_AtomToValue(ctx, prop);
  16526     sp[1] = JS_FALSE;
  16527     return 0;
  16528  done:
  16529     /* return the end */
  16530     sp[0] = JS_UNDEFINED;
  16531     sp[1] = JS_TRUE;
  16532     return 0;
  16533 }
  16534 
  16535 static JSValue JS_GetIterator2(JSContext *ctx, JSValueConst obj,
  16536                                JSValueConst method)
  16537 {
  16538     JSValue enum_obj;
  16539 
  16540     enum_obj = JS_Call(ctx, method, obj, 0, NULL);
  16541     if (JS_IsException(enum_obj))
  16542         return enum_obj;
  16543     if (!JS_IsObject(enum_obj)) {
  16544         JS_FreeValue(ctx, enum_obj);
  16545         return JS_ThrowTypeErrorNotAnObject(ctx);
  16546     }
  16547     return enum_obj;
  16548 }
  16549 
  16550 static JSValue JS_GetIterator(JSContext *ctx, JSValueConst obj, BOOL is_async)
  16551 {
  16552     JSValue method, ret, sync_iter;
  16553 
  16554     if (is_async) {
  16555         method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_asyncIterator);
  16556         if (JS_IsException(method))
  16557             return method;
  16558         if (JS_IsUndefined(method) || JS_IsNull(method)) {
  16559             method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
  16560             if (JS_IsException(method))
  16561                 return method;
  16562             sync_iter = JS_GetIterator2(ctx, obj, method);
  16563             JS_FreeValue(ctx, method);
  16564             if (JS_IsException(sync_iter))
  16565                 return sync_iter;
  16566             ret = JS_CreateAsyncFromSyncIterator(ctx, sync_iter);
  16567             JS_FreeValue(ctx, sync_iter);
  16568             return ret;
  16569         }
  16570     } else {
  16571         method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
  16572         if (JS_IsException(method))
  16573             return method;
  16574     }
  16575     if (!JS_IsFunction(ctx, method)) {
  16576         JS_FreeValue(ctx, method);
  16577         return JS_ThrowTypeError(ctx, "value is not iterable");
  16578     }
  16579     ret = JS_GetIterator2(ctx, obj, method);
  16580     JS_FreeValue(ctx, method);
  16581     return ret;
  16582 }
  16583 
  16584 /* return *pdone = 2 if the iterator object is not parsed */
  16585 static JSValue JS_IteratorNext2(JSContext *ctx, JSValueConst enum_obj,
  16586                                 JSValueConst method,
  16587                                 int argc, JSValueConst *argv, int *pdone)
  16588 {
  16589     JSValue obj;
  16590 
  16591     /* fast path for the built-in iterators (avoid creating the
  16592        intermediate result object) */
  16593     if (JS_IsObject(method)) {
  16594         JSObject *p = JS_VALUE_GET_OBJ(method);
  16595         if (p->class_id == JS_CLASS_C_FUNCTION &&
  16596             p->u.cfunc.cproto == JS_CFUNC_iterator_next) {
  16597             JSCFunctionType func;
  16598             JSValueConst args[1];
  16599 
  16600             /* in case the function expects one argument */
  16601             if (argc == 0) {
  16602                 args[0] = JS_UNDEFINED;
  16603                 argv = args;
  16604             }
  16605             func = p->u.cfunc.c_function;
  16606             return func.iterator_next(ctx, enum_obj, argc, argv,
  16607                                       pdone, p->u.cfunc.magic);
  16608         }
  16609     }
  16610     obj = JS_Call(ctx, method, enum_obj, argc, argv);
  16611     if (JS_IsException(obj))
  16612         goto fail;
  16613     if (!JS_IsObject(obj)) {
  16614         JS_FreeValue(ctx, obj);
  16615         JS_ThrowTypeError(ctx, "iterator must return an object");
  16616         goto fail;
  16617     }
  16618     *pdone = 2;
  16619     return obj;
  16620  fail:
  16621     *pdone = FALSE;
  16622     return JS_EXCEPTION;
  16623 }
  16624 
  16625 /* Note: always return JS_UNDEFINED when *pdone = TRUE. */
  16626 static JSValue JS_IteratorNext(JSContext *ctx, JSValueConst enum_obj,
  16627                                JSValueConst method,
  16628                                int argc, JSValueConst *argv, BOOL *pdone)
  16629 {
  16630     JSValue obj, value, done_val;
  16631     int done;
  16632 
  16633     obj = JS_IteratorNext2(ctx, enum_obj, method, argc, argv, &done);
  16634     if (JS_IsException(obj))
  16635         goto fail;
  16636     if (likely(done == 0)) {
  16637         *pdone = FALSE;
  16638         return obj;
  16639     } else if (done != 2) {
  16640         JS_FreeValue(ctx, obj);
  16641         *pdone = TRUE;
  16642         return JS_UNDEFINED;
  16643     } else {
  16644         done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);
  16645         if (JS_IsException(done_val))
  16646             goto fail;
  16647         *pdone = JS_ToBoolFree(ctx, done_val);
  16648         value = JS_UNDEFINED;
  16649         if (!*pdone) {
  16650             value = JS_GetProperty(ctx, obj, JS_ATOM_value);
  16651         }
  16652         JS_FreeValue(ctx, obj);
  16653         return value;
  16654     }
  16655  fail:
  16656     JS_FreeValue(ctx, obj);
  16657     *pdone = FALSE;
  16658     return JS_EXCEPTION;
  16659 }
  16660 
  16661 /* return < 0 in case of exception */
  16662 static int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj,
  16663                             BOOL is_exception_pending)
  16664 {
  16665     JSValue method, ret, ex_obj;
  16666     int res;
  16667 
  16668     if (is_exception_pending) {
  16669         ex_obj = ctx->rt->current_exception;
  16670         ctx->rt->current_exception = JS_UNINITIALIZED;
  16671         res = -1;
  16672     } else {
  16673         ex_obj = JS_UNDEFINED;
  16674         res = 0;
  16675     }
  16676     method = JS_GetProperty(ctx, enum_obj, JS_ATOM_return);
  16677     if (JS_IsException(method)) {
  16678         res = -1;
  16679         goto done;
  16680     }
  16681     if (JS_IsUndefined(method) || JS_IsNull(method)) {
  16682         goto done;
  16683     }
  16684     ret = JS_CallFree(ctx, method, enum_obj, 0, NULL);
  16685     if (!is_exception_pending) {
  16686         if (JS_IsException(ret)) {
  16687             res = -1;
  16688         } else if (!JS_IsObject(ret)) {
  16689             JS_ThrowTypeErrorNotAnObject(ctx);
  16690             res = -1;
  16691         }
  16692     }
  16693     JS_FreeValue(ctx, ret);
  16694  done:
  16695     if (is_exception_pending) {
  16696         JS_Throw(ctx, ex_obj);
  16697     }
  16698     return res;
  16699 }
  16700 
  16701 /* obj -> enum_rec (3 slots) */
  16702 static __exception int js_for_of_start(JSContext *ctx, JSValue *sp,
  16703                                        BOOL is_async)
  16704 {
  16705     JSValue op1, obj, method;
  16706     op1 = sp[-1];
  16707     obj = JS_GetIterator(ctx, op1, is_async);
  16708     if (JS_IsException(obj))
  16709         return -1;
  16710     JS_FreeValue(ctx, op1);
  16711     sp[-1] = obj;
  16712     method = JS_GetProperty(ctx, obj, JS_ATOM_next);
  16713     if (JS_IsException(method))
  16714         return -1;
  16715     sp[0] = method;
  16716     return 0;
  16717 }
  16718 
  16719 /* enum_rec [objs] -> enum_rec [objs] value done. There are 'offset'
  16720    objs. If 'done' is true or in case of exception, 'enum_rec' is set
  16721    to undefined. If 'done' is true, 'value' is always set to
  16722    undefined. */
  16723 static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset)
  16724 {
  16725     JSValue value = JS_UNDEFINED;
  16726     int done = 1;
  16727 
  16728     if (likely(!JS_IsUndefined(sp[offset]))) {
  16729         value = JS_IteratorNext(ctx, sp[offset], sp[offset + 1], 0, NULL, &done);
  16730         if (JS_IsException(value))
  16731             done = -1;
  16732         if (done) {
  16733             /* value is JS_UNDEFINED or JS_EXCEPTION */
  16734             /* replace the iteration object with undefined */
  16735             JS_FreeValue(ctx, sp[offset]);
  16736             sp[offset] = JS_UNDEFINED;
  16737             if (done < 0) {
  16738                 return -1;
  16739             } else {
  16740                 JS_FreeValue(ctx, value);
  16741                 value = JS_UNDEFINED;
  16742             }
  16743         }
  16744     }
  16745     sp[0] = value;
  16746     sp[1] = JS_NewBool(ctx, done);
  16747     return 0;
  16748 }
  16749 
  16750 static __exception int js_for_await_of_next(JSContext *ctx, JSValue *sp)
  16751 {
  16752     JSValue obj, iter, next;
  16753 
  16754     sp[-1] = JS_UNDEFINED; /* disable the catch offset so that
  16755                               exceptions do not close the iterator */
  16756     iter = sp[-3];
  16757     next = sp[-2];
  16758     obj = JS_Call(ctx, next, iter, 0, NULL);
  16759     if (JS_IsException(obj))
  16760         return -1;
  16761     sp[0] = obj;
  16762     return 0;
  16763 }
  16764 
  16765 static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValueConst obj,
  16766                                            BOOL *pdone)
  16767 {
  16768     JSValue done_val, value;
  16769     BOOL done;
  16770     done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);
  16771     if (JS_IsException(done_val))
  16772         goto fail;
  16773     done = JS_ToBoolFree(ctx, done_val);
  16774     value = JS_GetProperty(ctx, obj, JS_ATOM_value);
  16775     if (JS_IsException(value))
  16776         goto fail;
  16777     *pdone = done;
  16778     return value;
  16779  fail:
  16780     *pdone = FALSE;
  16781     return JS_EXCEPTION;
  16782 }
  16783 
  16784 static __exception int js_iterator_get_value_done(JSContext *ctx, JSValue *sp)
  16785 {
  16786     JSValue obj, value;
  16787     BOOL done;
  16788     obj = sp[-1];
  16789     if (!JS_IsObject(obj)) {
  16790         JS_ThrowTypeError(ctx, "iterator must return an object");
  16791         return -1;
  16792     }
  16793     value = JS_IteratorGetCompleteValue(ctx, obj, &done);
  16794     if (JS_IsException(value))
  16795         return -1;
  16796     JS_FreeValue(ctx, obj);
  16797     /* put again the catch offset so that exceptions close the
  16798        iterator */
  16799     sp[-2] = JS_NewCatchOffset(ctx, 0); 
  16800     sp[-1] = value;
  16801     sp[0] = JS_NewBool(ctx, done);
  16802     return 0;
  16803 }
  16804 
  16805 static JSValue js_create_iterator_result(JSContext *ctx,
  16806                                          JSValue val,
  16807                                          BOOL done)
  16808 {
  16809     JSValue obj;
  16810     obj = JS_NewObject(ctx);
  16811     if (JS_IsException(obj)) {
  16812         JS_FreeValue(ctx, val);
  16813         return obj;
  16814     }
  16815     if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_value,
  16816                                val, JS_PROP_C_W_E) < 0) {
  16817         goto fail;
  16818     }
  16819     if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_done,
  16820                                JS_NewBool(ctx, done), JS_PROP_C_W_E) < 0) {
  16821     fail:
  16822         JS_FreeValue(ctx, obj);
  16823         return JS_EXCEPTION;
  16824     }
  16825     return obj;
  16826 }
  16827 
  16828 static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val,
  16829                                       int argc, JSValueConst *argv,
  16830                                       BOOL *pdone, int magic);
  16831 
  16832 static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val,
  16833                                         int argc, JSValueConst *argv, int magic);
  16834 
  16835 static BOOL js_is_fast_array(JSContext *ctx, JSValueConst obj)
  16836 {
  16837     /* Try and handle fast arrays explicitly */
  16838     if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
  16839         JSObject *p = JS_VALUE_GET_OBJ(obj);
  16840         if (p->class_id == JS_CLASS_ARRAY && p->fast_array) {
  16841             return TRUE;
  16842         }
  16843     }
  16844     return FALSE;
  16845 }
  16846 
  16847 /* Access an Array's internal JSValue array if available */
  16848 static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj,
  16849                               JSValue **arrpp, uint32_t *countp)
  16850 {
  16851     /* Try and handle fast arrays explicitly */
  16852     if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
  16853         JSObject *p = JS_VALUE_GET_OBJ(obj);
  16854         if (p->class_id == JS_CLASS_ARRAY && p->fast_array) {
  16855             *countp = p->u.array.count;
  16856             *arrpp = p->u.array.u.values;
  16857             return TRUE;
  16858         }
  16859     }
  16860     return FALSE;
  16861 }
  16862 
  16863 static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp)
  16864 {
  16865     JSValue iterator, enumobj, method, value;
  16866     int is_array_iterator;
  16867     JSValue *arrp;
  16868     uint32_t i, count32, pos;
  16869     JSCFunctionType ft;
  16870 
  16871     if (JS_VALUE_GET_TAG(sp[-2]) != JS_TAG_INT) {
  16872         JS_ThrowInternalError(ctx, "invalid index for append");
  16873         return -1;
  16874     }
  16875 
  16876     pos = JS_VALUE_GET_INT(sp[-2]);
  16877 
  16878     /* XXX: further optimisations:
  16879        - use ctx->array_proto_values?
  16880        - check if array_iterator_prototype next method is built-in and
  16881          avoid constructing actual iterator object?
  16882        - build this into js_for_of_start and use in all `for (x of o)` loops
  16883      */
  16884     iterator = JS_GetProperty(ctx, sp[-1], JS_ATOM_Symbol_iterator);
  16885     if (JS_IsException(iterator))
  16886         return -1;
  16887     ft.generic_magic = js_create_array_iterator;
  16888     is_array_iterator = JS_IsCFunction(ctx, iterator, ft.generic,
  16889                                        JS_ITERATOR_KIND_VALUE);
  16890     JS_FreeValue(ctx, iterator);
  16891 
  16892     enumobj = JS_GetIterator(ctx, sp[-1], FALSE);
  16893     if (JS_IsException(enumobj))
  16894         return -1;
  16895     method = JS_GetProperty(ctx, enumobj, JS_ATOM_next);
  16896     if (JS_IsException(method)) {
  16897         JS_FreeValue(ctx, enumobj);
  16898         return -1;
  16899     }
  16900 
  16901     ft.iterator_next = js_array_iterator_next;
  16902     if (is_array_iterator
  16903     &&  JS_IsCFunction(ctx, method, ft.generic, 0)
  16904     &&  js_get_fast_array(ctx, sp[-1], &arrp, &count32)) {
  16905         uint32_t len;
  16906         if (js_get_length32(ctx, &len, sp[-1]))
  16907             goto exception;
  16908         /* if len > count32, the elements >= count32 might be read in
  16909            the prototypes and might have side effects */
  16910         if (len != count32)
  16911             goto general_case;
  16912         /* Handle fast arrays explicitly */
  16913         for (i = 0; i < count32; i++) {
  16914             if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++,
  16915                                              JS_DupValue(ctx, arrp[i]), JS_PROP_C_W_E) < 0)
  16916                 goto exception;
  16917         }
  16918     } else {
  16919     general_case:
  16920         for (;;) {
  16921             BOOL done;
  16922             value = JS_IteratorNext(ctx, enumobj, method, 0, NULL, &done);
  16923             if (JS_IsException(value))
  16924                 goto exception;
  16925             if (done) {
  16926                 /* value is JS_UNDEFINED */
  16927                 break;
  16928             }
  16929             if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, value, JS_PROP_C_W_E) < 0)
  16930                 goto exception;
  16931         }
  16932     }
  16933     /* Note: could raise an error if too many elements */
  16934     sp[-2] = JS_NewInt32(ctx, pos);
  16935     JS_FreeValue(ctx, enumobj);
  16936     JS_FreeValue(ctx, method);
  16937     return 0;
  16938 
  16939 exception:
  16940     JS_IteratorClose(ctx, enumobj, TRUE);
  16941     JS_FreeValue(ctx, enumobj);
  16942     JS_FreeValue(ctx, method);
  16943     return -1;
  16944 }
  16945 
  16946 static __exception int JS_CopyDataProperties(JSContext *ctx,
  16947                                              JSValueConst target,
  16948                                              JSValueConst source,
  16949                                              JSValueConst excluded,
  16950                                              BOOL setprop)
  16951 {
  16952     JSPropertyEnum *tab_atom;
  16953     JSValue val;
  16954     uint32_t i, tab_atom_count;
  16955     JSObject *p;
  16956     JSObject *pexcl = NULL;
  16957     int ret, gpn_flags;
  16958     JSPropertyDescriptor desc;
  16959     BOOL is_enumerable;
  16960 
  16961     if (JS_VALUE_GET_TAG(source) != JS_TAG_OBJECT)
  16962         return 0;
  16963 
  16964     if (JS_VALUE_GET_TAG(excluded) == JS_TAG_OBJECT)
  16965         pexcl = JS_VALUE_GET_OBJ(excluded);
  16966 
  16967     p = JS_VALUE_GET_OBJ(source);
  16968 
  16969     gpn_flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK | JS_GPN_ENUM_ONLY;
  16970     if (p->is_exotic) {
  16971         const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
  16972         /* cannot use JS_GPN_ENUM_ONLY with e.g. proxies because it
  16973            introduces a visible change */
  16974         if (em && em->get_own_property_names) {
  16975             gpn_flags &= ~JS_GPN_ENUM_ONLY;
  16976         }
  16977     }
  16978     if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
  16979                                        gpn_flags))
  16980         return -1;
  16981 
  16982     for (i = 0; i < tab_atom_count; i++) {
  16983         if (pexcl) {
  16984             ret = JS_GetOwnPropertyInternal(ctx, NULL, pexcl, tab_atom[i].atom);
  16985             if (ret) {
  16986                 if (ret < 0)
  16987                     goto exception;
  16988                 continue;
  16989             }
  16990         }
  16991         if (!(gpn_flags & JS_GPN_ENUM_ONLY)) {
  16992             /* test if the property is enumerable */
  16993             ret = JS_GetOwnPropertyInternal(ctx, &desc, p, tab_atom[i].atom);
  16994             if (ret < 0)
  16995                 goto exception;
  16996             if (!ret)
  16997                 continue;
  16998             is_enumerable = (desc.flags & JS_PROP_ENUMERABLE) != 0;
  16999             js_free_desc(ctx, &desc);
  17000             if (!is_enumerable)
  17001                 continue;
  17002         }
  17003         val = JS_GetProperty(ctx, source, tab_atom[i].atom);
  17004         if (JS_IsException(val))
  17005             goto exception;
  17006         if (setprop)
  17007             ret = JS_SetProperty(ctx, target, tab_atom[i].atom, val);
  17008         else
  17009             ret = JS_DefinePropertyValue(ctx, target, tab_atom[i].atom, val,
  17010                                          JS_PROP_C_W_E);
  17011         if (ret < 0)
  17012             goto exception;
  17013     }
  17014     JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count);
  17015     return 0;
  17016  exception:
  17017     JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count);
  17018     return -1;
  17019 }
  17020 
  17021 /* only valid inside C functions */
  17022 static JSValueConst JS_GetActiveFunction(JSContext *ctx)
  17023 {
  17024     return ctx->rt->current_stack_frame->cur_func;
  17025 }
  17026 
  17027 static JSVarRef *js_create_var_ref(JSContext *ctx, BOOL is_lexical)
  17028 {
  17029     JSVarRef *var_ref;
  17030     var_ref = js_malloc(ctx, sizeof(JSVarRef));
  17031     if (!var_ref)
  17032         return NULL;
  17033     js_rc(var_ref)->ref_count = 1;
  17034     if (is_lexical)
  17035         var_ref->value = JS_UNINITIALIZED;
  17036     else
  17037         var_ref->value = JS_UNDEFINED;
  17038     var_ref->pvalue = &var_ref->value;
  17039     var_ref->is_detached = TRUE;
  17040     var_ref->is_lexical = FALSE;
  17041     var_ref->is_const = FALSE;
  17042     add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
  17043     return var_ref;
  17044 }
  17045 
  17046 static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx,
  17047                              BOOL is_arg)
  17048 {
  17049     JSObject *p;
  17050     JSFunctionBytecode *b;
  17051     JSVarRef *var_ref;
  17052     JSValue *pvalue;
  17053     int var_ref_idx;
  17054     JSBytecodeVarDef *vd;
  17055     
  17056     p = JS_VALUE_GET_OBJ(sf->cur_func);
  17057     b = p->u.func.function_bytecode;
  17058     
  17059     if (is_arg) {
  17060         vd = &b->vardefs[var_idx];
  17061         pvalue = &sf->arg_buf[var_idx];
  17062     } else {
  17063         vd = &b->vardefs[b->arg_count + var_idx];
  17064         pvalue = &sf->var_buf[var_idx];
  17065     }
  17066     assert(vd->is_captured);
  17067     var_ref_idx = vd->var_ref_idx;
  17068     assert(var_ref_idx < b->var_ref_count);
  17069     var_ref = sf->var_refs[var_ref_idx];
  17070     if (var_ref) {
  17071         /* reference to the already created local variable */
  17072         assert(var_ref->pvalue == pvalue);
  17073         js_rc(var_ref)->ref_count++;
  17074         return var_ref;
  17075     }
  17076 
  17077     /* create a new one */
  17078     var_ref = js_malloc(ctx, sizeof(JSVarRef));
  17079     if (!var_ref)
  17080         return NULL;
  17081     js_rc(var_ref)->ref_count = 1;
  17082     add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
  17083     var_ref->is_detached = FALSE;
  17084     var_ref->is_lexical = FALSE;
  17085     var_ref->is_const = FALSE;
  17086     var_ref->var_ref_idx = var_ref_idx;
  17087     var_ref->stack_frame = sf;
  17088     sf->var_refs[var_ref_idx] = var_ref;
  17089     if (sf->js_mode & JS_MODE_ASYNC) {
  17090         JSAsyncFunctionState *async_func = container_of(sf, JSAsyncFunctionState, frame);
  17091         /* The stack frame is detached and may be destroyed at any
  17092            time so its reference count must be increased. Calling
  17093            close_var_refs() when destroying the stack frame is not
  17094            possible because it would change the graph between the GC
  17095            objects. Another solution could be to temporarily detach
  17096            the JSVarRef of async functions during the GC. It would
  17097            have the advantage of allowing the release of unused stack
  17098            frames in a cycle. */
  17099         js_rc(async_func)->ref_count++;
  17100     }
  17101     var_ref->pvalue = pvalue;
  17102     return var_ref;
  17103 }
  17104 
  17105 static void js_global_object_finalizer(JSRuntime *rt, JSValue obj)
  17106 {
  17107     JSObject *p = JS_VALUE_GET_OBJ(obj);
  17108     JS_FreeValueRT(rt, p->u.global_object.uninitialized_vars);
  17109 }
  17110 
  17111 static void js_global_object_mark(JSRuntime *rt, JSValueConst val,
  17112                                   JS_MarkFunc *mark_func)
  17113 {
  17114     JSObject *p = JS_VALUE_GET_OBJ(val);
  17115     JS_MarkValue(rt, p->u.global_object.uninitialized_vars, mark_func);
  17116 }
  17117 
  17118 static JSVarRef *js_global_object_get_uninitialized_var(JSContext *ctx, JSObject *p1, 
  17119                                                         JSAtom atom)
  17120 {
  17121     JSObject *p = JS_VALUE_GET_OBJ(p1->u.global_object.uninitialized_vars);
  17122     JSShapeProperty *prs;
  17123     JSProperty *pr;
  17124     JSVarRef *var_ref;
  17125     
  17126     prs = find_own_property(&pr, p, atom);
  17127     if (prs) {
  17128         assert((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF);
  17129         var_ref = pr->u.var_ref;
  17130         js_rc(var_ref)->ref_count++;
  17131         return var_ref;
  17132     }
  17133 
  17134     var_ref = js_create_var_ref(ctx, TRUE);
  17135     if (!var_ref)
  17136         return NULL;
  17137     pr = add_property(ctx, p, atom, JS_PROP_C_W_E | JS_PROP_VARREF);
  17138     if (unlikely(!pr)) {
  17139         free_var_ref(ctx->rt, var_ref);
  17140         return NULL;
  17141     }
  17142     pr->u.var_ref = var_ref;
  17143     js_rc(var_ref)->ref_count++;
  17144     return var_ref;
  17145 }
  17146 
  17147 /* return a new variable reference. Get it from the uninitialized
  17148    variables if it is present. Return NULL in case of memory error. */
  17149 static JSVarRef *js_global_object_find_uninitialized_var(JSContext *ctx, JSObject *p,
  17150                                                          JSAtom atom, BOOL is_lexical)
  17151 {
  17152     JSObject *p1;
  17153     JSShapeProperty *prs;
  17154     JSProperty *pr;
  17155     JSVarRef *var_ref;
  17156     
  17157     p1 = JS_VALUE_GET_OBJ(p->u.global_object.uninitialized_vars);
  17158     prs = find_own_property(&pr, p1, atom);
  17159     if (prs) {
  17160         assert((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF);
  17161         var_ref = pr->u.var_ref;
  17162         js_rc(var_ref)->ref_count++;
  17163         delete_property(ctx, p1, atom);
  17164         if (!is_lexical)
  17165             var_ref->value = JS_UNDEFINED;
  17166     } else {
  17167         var_ref = js_create_var_ref(ctx, is_lexical);
  17168         if (!var_ref)
  17169             return NULL;
  17170     }
  17171     return var_ref;
  17172 }
  17173 
  17174 static JSVarRef *js_closure_define_global_var(JSContext *ctx, JSClosureVar *cv,
  17175                                               BOOL is_direct_or_indirect_eval)
  17176 {
  17177     JSObject *p, *p1;
  17178     JSShapeProperty *prs;
  17179     int flags;
  17180     JSProperty *pr;
  17181     JSVarRef *var_ref;
  17182     
  17183     if (cv->is_lexical) {
  17184         p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
  17185         flags = JS_PROP_ENUMERABLE | JS_PROP_CONFIGURABLE;
  17186         if (!cv->is_const)
  17187             flags |= JS_PROP_WRITABLE;
  17188 
  17189         prs = find_own_property(&pr, p, cv->var_name);
  17190         if (prs) {
  17191             assert((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF);
  17192             var_ref = pr->u.var_ref;
  17193             js_rc(var_ref)->ref_count++;
  17194             return var_ref;
  17195         }
  17196 
  17197         /* if there is a corresponding global variable, reuse its
  17198            reference and create a new one for the global variable */
  17199         p1 = JS_VALUE_GET_OBJ(ctx->global_obj);
  17200         prs = find_own_property(&pr, p1, cv->var_name);
  17201         if (prs && (prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
  17202             JSVarRef *var_ref1;
  17203             var_ref1 = js_create_var_ref(ctx, FALSE);
  17204             if (!var_ref1)
  17205                 return NULL;
  17206             var_ref = pr->u.var_ref;
  17207             var_ref1->value = var_ref->value;
  17208             var_ref->value = JS_UNINITIALIZED;
  17209             pr->u.var_ref = var_ref1;
  17210             goto add_var_ref;
  17211         }
  17212     } else {
  17213         p = JS_VALUE_GET_OBJ(ctx->global_obj);
  17214         flags = JS_PROP_ENUMERABLE | JS_PROP_WRITABLE;
  17215         if (is_direct_or_indirect_eval)
  17216             flags |= JS_PROP_CONFIGURABLE;
  17217 
  17218     retry:
  17219         prs = find_own_property(&pr, p, cv->var_name);
  17220         if (prs) {
  17221             if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT)) {
  17222                 if (JS_AutoInitProperty(ctx, p, cv->var_name, pr, prs))
  17223                     return NULL;
  17224                 goto retry;
  17225             } else if ((prs->flags & JS_PROP_TMASK) != JS_PROP_VARREF) {
  17226                 var_ref = js_global_object_get_uninitialized_var(ctx, p, cv->var_name);
  17227                 if (!var_ref)
  17228                     return NULL;
  17229             } else {
  17230                 var_ref = pr->u.var_ref;
  17231                 js_rc(var_ref)->ref_count++;
  17232             }
  17233             if (cv->var_kind == JS_VAR_GLOBAL_FUNCTION_DECL &&
  17234                 (prs->flags & JS_PROP_CONFIGURABLE)) {
  17235                 /* update the property flags if possible when
  17236                    declaring a global function */
  17237                 if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
  17238                     free_property(ctx->rt, pr, prs->flags);
  17239                     prs->flags = flags | JS_PROP_VARREF;
  17240                     pr->u.var_ref = var_ref;
  17241                     js_rc(var_ref)->ref_count++;
  17242                 } else {
  17243                     assert((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF);
  17244                     prs->flags = (prs->flags & ~JS_PROP_C_W_E) | flags;
  17245                 }
  17246                 var_ref->is_const = FALSE;
  17247             }
  17248             return var_ref;
  17249         }
  17250         
  17251         if (!p->extensible) {
  17252             return js_global_object_get_uninitialized_var(ctx, p, cv->var_name);
  17253         }
  17254     }
  17255     
  17256     /* if there is a corresponding uninitialized variable, use it */
  17257     p1 = JS_VALUE_GET_OBJ(ctx->global_obj);
  17258     var_ref = js_global_object_find_uninitialized_var(ctx, p1, cv->var_name, cv->is_lexical);
  17259     if (!var_ref)
  17260         return NULL;
  17261  add_var_ref:
  17262     if (cv->is_lexical) {
  17263         var_ref->is_lexical = TRUE;
  17264         var_ref->is_const = cv->is_const;
  17265     }
  17266 
  17267     pr = add_property(ctx, p, cv->var_name, flags | JS_PROP_VARREF);
  17268     if (unlikely(!pr)) {
  17269         free_var_ref(ctx->rt, var_ref);
  17270         return NULL;
  17271     }
  17272     pr->u.var_ref = var_ref;
  17273     js_rc(var_ref)->ref_count++;
  17274     return var_ref;
  17275 }
  17276 
  17277 static JSVarRef *js_closure_global_var(JSContext *ctx, JSClosureVar *cv)
  17278 {
  17279     JSObject *p;
  17280     JSShapeProperty *prs;
  17281     JSProperty *pr;
  17282     JSVarRef *var_ref;
  17283     
  17284     p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
  17285     prs = find_own_property(&pr, p, cv->var_name);
  17286     if (prs) {
  17287         assert((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF);
  17288         var_ref = pr->u.var_ref;
  17289         js_rc(var_ref)->ref_count++;
  17290         return var_ref;
  17291     }
  17292     p = JS_VALUE_GET_OBJ(ctx->global_obj);
  17293  redo:
  17294     prs = find_own_property(&pr, p, cv->var_name);
  17295     if (prs) {
  17296         if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT)) {
  17297             /* Instantiate property and retry */
  17298             if (JS_AutoInitProperty(ctx, p, cv->var_name, pr, prs))
  17299                 return NULL;
  17300             goto redo;
  17301         }
  17302         if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
  17303             var_ref = pr->u.var_ref;
  17304             js_rc(var_ref)->ref_count++;
  17305             return var_ref;
  17306         }
  17307     }
  17308     return js_global_object_get_uninitialized_var(ctx, p, cv->var_name);
  17309 }
  17310 
  17311 static JSValue js_closure2(JSContext *ctx, JSValue func_obj,
  17312                            JSFunctionBytecode *b,
  17313                            JSVarRef **cur_var_refs,
  17314                            JSStackFrame *sf,
  17315                            BOOL is_eval, JSModuleDef *m)
  17316 {
  17317     JSObject *p;
  17318     JSVarRef **var_refs;
  17319     int i;
  17320 
  17321     p = JS_VALUE_GET_OBJ(func_obj);
  17322     p->u.func.function_bytecode = b;
  17323     p->u.func.home_object = NULL;
  17324     p->u.func.var_refs = NULL;
  17325     if (b->closure_var_count) {
  17326         var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count);
  17327         if (!var_refs)
  17328             goto fail;
  17329         p->u.func.var_refs = var_refs;
  17330         if (is_eval) {
  17331             /* first pass to check the global variable definitions */
  17332             for(i = 0; i < b->closure_var_count; i++) {
  17333                 JSClosureVar *cv = &b->closure_var[i];
  17334                 if (cv->closure_type == JS_CLOSURE_GLOBAL_DECL) {
  17335                     int flags;
  17336                     flags = 0;
  17337                     if (cv->is_lexical)
  17338                         flags |= DEFINE_GLOBAL_LEX_VAR;
  17339                     if (cv->var_kind == JS_VAR_GLOBAL_FUNCTION_DECL)
  17340                         flags |= DEFINE_GLOBAL_FUNC_VAR;
  17341                     if (JS_CheckDefineGlobalVar(ctx, cv->var_name, flags))
  17342                         goto fail;
  17343                 }
  17344             }
  17345         }
  17346         for(i = 0; i < b->closure_var_count; i++) {
  17347             JSClosureVar *cv = &b->closure_var[i];
  17348             JSVarRef *var_ref;
  17349             switch(cv->closure_type) {
  17350             case JS_CLOSURE_MODULE_IMPORT:
  17351                 /* imported from other modules */
  17352                 continue;
  17353             case JS_CLOSURE_MODULE_DECL:
  17354                 var_ref = js_create_var_ref(ctx, cv->is_lexical);
  17355                 break;
  17356             case JS_CLOSURE_GLOBAL_DECL:
  17357                 var_ref = js_closure_define_global_var(ctx, cv, b->is_direct_or_indirect_eval);
  17358                 break;
  17359             case JS_CLOSURE_GLOBAL:
  17360                 var_ref = js_closure_global_var(ctx, cv);
  17361                 break;
  17362             case JS_CLOSURE_LOCAL:
  17363                 /* reuse the existing variable reference if it already exists */
  17364                 var_ref = get_var_ref(ctx, sf, cv->var_idx, FALSE);
  17365                 break;
  17366             case JS_CLOSURE_ARG:
  17367                 /* reuse the existing variable reference if it already exists */
  17368                 var_ref = get_var_ref(ctx, sf, cv->var_idx, TRUE);
  17369                 break;
  17370             case JS_CLOSURE_REF:
  17371             case JS_CLOSURE_GLOBAL_REF:
  17372                 var_ref = cur_var_refs[cv->var_idx];
  17373                 js_rc(var_ref)->ref_count++;
  17374                 break;
  17375             default:
  17376                 abort();
  17377             }
  17378             if (!var_ref)
  17379                 goto fail;
  17380             var_refs[i] = var_ref;
  17381         }
  17382     }
  17383     return func_obj;
  17384  fail:
  17385     /* bfunc is freed when func_obj is freed */
  17386     JS_FreeValue(ctx, func_obj);
  17387     return JS_EXCEPTION;
  17388 }
  17389 
  17390 static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque)
  17391 {
  17392     JSValue obj, this_val;
  17393     int ret;
  17394 
  17395     this_val = JS_MKPTR(JS_TAG_OBJECT, p);
  17396     obj = JS_NewObject(ctx);
  17397     if (JS_IsException(obj))
  17398         return JS_EXCEPTION;
  17399     set_cycle_flag(ctx, obj);
  17400     set_cycle_flag(ctx, this_val);
  17401     ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_constructor,
  17402                                  JS_DupValue(ctx, this_val),
  17403                                  JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
  17404     if (ret < 0) {
  17405         JS_FreeValue(ctx, obj);
  17406         return JS_EXCEPTION;
  17407     }
  17408     return obj;
  17409 }
  17410 
  17411 static const uint16_t func_kind_to_class_id[] = {
  17412     [JS_FUNC_NORMAL] = JS_CLASS_BYTECODE_FUNCTION,
  17413     [JS_FUNC_GENERATOR] = JS_CLASS_GENERATOR_FUNCTION,
  17414     [JS_FUNC_ASYNC] = JS_CLASS_ASYNC_FUNCTION,
  17415     [JS_FUNC_ASYNC_GENERATOR] = JS_CLASS_ASYNC_GENERATOR_FUNCTION,
  17416 };
  17417 
  17418 static JSValue js_closure(JSContext *ctx, JSValue bfunc,
  17419                           JSVarRef **cur_var_refs,
  17420                           JSStackFrame *sf, BOOL is_eval)
  17421 {
  17422     JSFunctionBytecode *b;
  17423     JSValue func_obj;
  17424     JSAtom name_atom;
  17425 
  17426     b = JS_VALUE_GET_PTR(bfunc);
  17427     func_obj = JS_NewObjectClass(ctx, func_kind_to_class_id[b->func_kind]);
  17428     if (JS_IsException(func_obj)) {
  17429         JS_FreeValue(ctx, bfunc);
  17430         return JS_EXCEPTION;
  17431     }
  17432     func_obj = js_closure2(ctx, func_obj, b, cur_var_refs, sf, is_eval, NULL);
  17433     if (JS_IsException(func_obj)) {
  17434         /* bfunc has been freed */
  17435         goto fail;
  17436     }
  17437     name_atom = b->func_name;
  17438     if (name_atom == JS_ATOM_NULL)
  17439         name_atom = JS_ATOM_empty_string;
  17440     js_function_set_properties(ctx, func_obj, name_atom,
  17441                                b->defined_arg_count);
  17442 
  17443     if (b->func_kind & JS_FUNC_GENERATOR) {
  17444         JSValue proto;
  17445         int proto_class_id;
  17446         /* generators have a prototype field which is used as
  17447            prototype for the generator object */
  17448         if (b->func_kind == JS_FUNC_ASYNC_GENERATOR)
  17449             proto_class_id = JS_CLASS_ASYNC_GENERATOR;
  17450         else
  17451             proto_class_id = JS_CLASS_GENERATOR;
  17452         proto = JS_NewObjectProto(ctx, ctx->class_proto[proto_class_id]);
  17453         if (JS_IsException(proto))
  17454             goto fail;
  17455         JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype, proto,
  17456                                JS_PROP_WRITABLE);
  17457     } else if (b->has_prototype) {
  17458         /* add the 'prototype' property: delay instantiation to avoid
  17459            creating cycles for every javascript function. The prototype
  17460            object is created on the fly when first accessed */
  17461         JS_SetConstructorBit(ctx, func_obj, TRUE);
  17462         JS_DefineAutoInitProperty(ctx, func_obj, JS_ATOM_prototype,
  17463                                   JS_AUTOINIT_ID_PROTOTYPE, NULL,
  17464                                   JS_PROP_WRITABLE);
  17465     }
  17466     return func_obj;
  17467  fail:
  17468     /* bfunc is freed when func_obj is freed */
  17469     JS_FreeValue(ctx, func_obj);
  17470     return JS_EXCEPTION;
  17471 }
  17472 
  17473 #define JS_DEFINE_CLASS_HAS_HERITAGE     (1 << 0)
  17474 
  17475 static int js_op_define_class(JSContext *ctx, JSValue *sp,
  17476                               JSAtom class_name, int class_flags,
  17477                               JSVarRef **cur_var_refs,
  17478                               JSStackFrame *sf, BOOL is_computed_name)
  17479 {
  17480     JSValue bfunc, parent_class, proto = JS_UNDEFINED;
  17481     JSValue ctor = JS_UNDEFINED, parent_proto = JS_UNDEFINED;
  17482     JSFunctionBytecode *b;
  17483 
  17484     parent_class = sp[-2];
  17485     bfunc = sp[-1];
  17486 
  17487     if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE) {
  17488         if (JS_IsNull(parent_class)) {
  17489             parent_proto = JS_NULL;
  17490             parent_class = JS_DupValue(ctx, ctx->function_proto);
  17491         } else {
  17492             if (!JS_IsConstructor(ctx, parent_class)) {
  17493                 JS_ThrowTypeError(ctx, "parent class must be constructor");
  17494                 goto fail;
  17495             }
  17496             parent_proto = JS_GetProperty(ctx, parent_class, JS_ATOM_prototype);
  17497             if (JS_IsException(parent_proto))
  17498                 goto fail;
  17499             if (!JS_IsNull(parent_proto) && !JS_IsObject(parent_proto)) {
  17500                 JS_ThrowTypeError(ctx, "parent prototype must be an object or null");
  17501                 goto fail;
  17502             }
  17503         }
  17504     } else {
  17505         /* parent_class is JS_UNDEFINED in this case */
  17506         parent_proto = JS_DupValue(ctx, ctx->class_proto[JS_CLASS_OBJECT]);
  17507         parent_class = JS_DupValue(ctx, ctx->function_proto);
  17508     }
  17509     proto = JS_NewObjectProto(ctx, parent_proto);
  17510     if (JS_IsException(proto))
  17511         goto fail;
  17512 
  17513     b = JS_VALUE_GET_PTR(bfunc);
  17514     assert(b->func_kind == JS_FUNC_NORMAL);
  17515     ctor = JS_NewObjectProtoClass(ctx, parent_class,
  17516                                   JS_CLASS_BYTECODE_FUNCTION);
  17517     if (JS_IsException(ctor))
  17518         goto fail;
  17519     ctor = js_closure2(ctx, ctor, b, cur_var_refs, sf, FALSE, NULL);
  17520     bfunc = JS_UNDEFINED;
  17521     if (JS_IsException(ctor))
  17522         goto fail;
  17523     js_method_set_home_object(ctx, ctor, proto);
  17524     JS_SetConstructorBit(ctx, ctor, TRUE);
  17525 
  17526     JS_DefinePropertyValue(ctx, ctor, JS_ATOM_length,
  17527                            JS_NewInt32(ctx, b->defined_arg_count),
  17528                            JS_PROP_CONFIGURABLE);
  17529 
  17530     if (is_computed_name) {
  17531         if (JS_DefineObjectNameComputed(ctx, ctor, sp[-3],
  17532                                         JS_PROP_CONFIGURABLE) < 0)
  17533             goto fail;
  17534     } else {
  17535         if (JS_DefineObjectName(ctx, ctor, class_name, JS_PROP_CONFIGURABLE) < 0)
  17536             goto fail;
  17537     }
  17538 
  17539     /* the constructor property must be first. It can be overriden by
  17540        computed property names */
  17541     if (JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor,
  17542                                JS_DupValue(ctx, ctor),
  17543                                JS_PROP_CONFIGURABLE |
  17544                                JS_PROP_WRITABLE | JS_PROP_THROW) < 0)
  17545         goto fail;
  17546     /* set the prototype property */
  17547     if (JS_DefinePropertyValue(ctx, ctor, JS_ATOM_prototype,
  17548                                JS_DupValue(ctx, proto), JS_PROP_THROW) < 0)
  17549         goto fail;
  17550     set_cycle_flag(ctx, ctor);
  17551     set_cycle_flag(ctx, proto);
  17552 
  17553     JS_FreeValue(ctx, parent_proto);
  17554     JS_FreeValue(ctx, parent_class);
  17555 
  17556     sp[-2] = ctor;
  17557     sp[-1] = proto;
  17558     return 0;
  17559  fail:
  17560     JS_FreeValue(ctx, parent_class);
  17561     JS_FreeValue(ctx, parent_proto);
  17562     JS_FreeValue(ctx, bfunc);
  17563     JS_FreeValue(ctx, proto);
  17564     JS_FreeValue(ctx, ctor);
  17565     sp[-2] = JS_UNDEFINED;
  17566     sp[-1] = JS_UNDEFINED;
  17567     return -1;
  17568 }
  17569 
  17570 static void close_var_ref(JSRuntime *rt, JSStackFrame *sf, JSVarRef *var_ref)
  17571 {
  17572     if (sf->js_mode & JS_MODE_ASYNC) {
  17573         JSAsyncFunctionState *async_func = container_of(sf, JSAsyncFunctionState, frame);
  17574         async_func_free(rt, async_func);
  17575     }
  17576     var_ref->value = JS_DupValueRT(rt, *var_ref->pvalue);
  17577     var_ref->pvalue = &var_ref->value;
  17578     /* the reference is no longer to a local variable */
  17579     var_ref->is_detached = TRUE;
  17580 }
  17581 
  17582 static void close_var_refs(JSRuntime *rt, JSFunctionBytecode *b, JSStackFrame *sf)
  17583 {
  17584     JSVarRef *var_ref;
  17585     int i;
  17586 
  17587     for(i = 0; i < b->var_ref_count; i++) {
  17588         var_ref = sf->var_refs[i];
  17589         if (var_ref)
  17590             close_var_ref(rt, sf, var_ref);
  17591     }
  17592 }
  17593 
  17594 static void close_lexical_var(JSContext *ctx, JSFunctionBytecode *b,
  17595                               JSStackFrame *sf, int var_idx)
  17596 {
  17597     JSVarRef *var_ref;
  17598     int var_ref_idx;
  17599     
  17600     var_ref_idx = b->vardefs[b->arg_count + var_idx].var_ref_idx;
  17601     var_ref = sf->var_refs[var_ref_idx];
  17602     if (var_ref) {
  17603         close_var_ref(ctx->rt, sf, var_ref);
  17604         sf->var_refs[var_ref_idx] = NULL;
  17605     }
  17606 }
  17607 
  17608 #define JS_CALL_FLAG_COPY_ARGV   (1 << 1)
  17609 #define JS_CALL_FLAG_GENERATOR   (1 << 2)
  17610 
  17611 static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
  17612                                   JSValueConst this_obj,
  17613                                   int argc, JSValueConst *argv, int flags)
  17614 {
  17615     JSRuntime *rt = ctx->rt;
  17616     JSCFunctionType func;
  17617     JSObject *p;
  17618     JSStackFrame sf_s, *sf = &sf_s, *prev_sf;
  17619     JSValue ret_val;
  17620     JSValueConst *arg_buf;
  17621     int arg_count, i;
  17622     JSCFunctionEnum cproto;
  17623 
  17624     p = JS_VALUE_GET_OBJ(func_obj);
  17625     cproto = p->u.cfunc.cproto;
  17626     arg_count = p->u.cfunc.length;
  17627 
  17628     /* better to always check stack overflow */
  17629     if (js_check_stack_overflow(rt, sizeof(arg_buf[0]) * arg_count))
  17630         return JS_ThrowStackOverflow(ctx);
  17631 
  17632     prev_sf = rt->current_stack_frame;
  17633     sf->prev_frame = prev_sf;
  17634     rt->current_stack_frame = sf;
  17635     ctx = p->u.cfunc.realm; /* change the current realm */
  17636     sf->js_mode = 0;
  17637     sf->cur_func = (JSValue)func_obj;
  17638     sf->arg_count = argc;
  17639     arg_buf = argv;
  17640 
  17641     if (unlikely(argc < arg_count)) {
  17642         /* ensure that at least argc_count arguments are readable */
  17643         arg_buf = alloca(sizeof(arg_buf[0]) * arg_count);
  17644         for(i = 0; i < argc; i++)
  17645             arg_buf[i] = argv[i];
  17646         for(i = argc; i < arg_count; i++)
  17647             arg_buf[i] = JS_UNDEFINED;
  17648         sf->arg_count = arg_count;
  17649     }
  17650     sf->arg_buf = (JSValue*)arg_buf;
  17651 
  17652     func = p->u.cfunc.c_function;
  17653     switch(cproto) {
  17654     case JS_CFUNC_constructor:
  17655     case JS_CFUNC_constructor_or_func:
  17656         if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) {
  17657             if (cproto == JS_CFUNC_constructor) {
  17658             not_a_constructor:
  17659                 ret_val = JS_ThrowTypeError(ctx, "must be called with new");
  17660                 break;
  17661             } else {
  17662                 this_obj = JS_UNDEFINED;
  17663             }
  17664         }
  17665         /* here this_obj is new_target */
  17666         /* fall thru */
  17667     case JS_CFUNC_generic:
  17668         ret_val = func.generic(ctx, this_obj, argc, arg_buf);
  17669         break;
  17670     case JS_CFUNC_constructor_magic:
  17671     case JS_CFUNC_constructor_or_func_magic:
  17672         if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) {
  17673             if (cproto == JS_CFUNC_constructor_magic) {
  17674                 goto not_a_constructor;
  17675             } else {
  17676                 this_obj = JS_UNDEFINED;
  17677             }
  17678         }
  17679         /* fall thru */
  17680     case JS_CFUNC_generic_magic:
  17681         ret_val = func.generic_magic(ctx, this_obj, argc, arg_buf,
  17682                                      p->u.cfunc.magic);
  17683         break;
  17684     case JS_CFUNC_getter:
  17685         ret_val = func.getter(ctx, this_obj);
  17686         break;
  17687     case JS_CFUNC_setter:
  17688         ret_val = func.setter(ctx, this_obj, arg_buf[0]);
  17689         break;
  17690     case JS_CFUNC_getter_magic:
  17691         ret_val = func.getter_magic(ctx, this_obj, p->u.cfunc.magic);
  17692         break;
  17693     case JS_CFUNC_setter_magic:
  17694         ret_val = func.setter_magic(ctx, this_obj, arg_buf[0], p->u.cfunc.magic);
  17695         break;
  17696     case JS_CFUNC_f_f:
  17697         {
  17698             double d1;
  17699 
  17700             if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) {
  17701                 ret_val = JS_EXCEPTION;
  17702                 break;
  17703             }
  17704             ret_val = JS_NewFloat64(ctx, func.f_f(d1));
  17705         }
  17706         break;
  17707     case JS_CFUNC_f_f_f:
  17708         {
  17709             double d1, d2;
  17710 
  17711             if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) {
  17712                 ret_val = JS_EXCEPTION;
  17713                 break;
  17714             }
  17715             if (unlikely(JS_ToFloat64(ctx, &d2, arg_buf[1]))) {
  17716                 ret_val = JS_EXCEPTION;
  17717                 break;
  17718             }
  17719             ret_val = JS_NewFloat64(ctx, func.f_f_f(d1, d2));
  17720         }
  17721         break;
  17722     case JS_CFUNC_iterator_next:
  17723         {
  17724             int done;
  17725             ret_val = func.iterator_next(ctx, this_obj, argc, arg_buf,
  17726                                          &done, p->u.cfunc.magic);
  17727             if (!JS_IsException(ret_val) && done != 2) {
  17728                 ret_val = js_create_iterator_result(ctx, ret_val, done);
  17729             }
  17730         }
  17731         break;
  17732     default:
  17733         abort();
  17734     }
  17735 
  17736     rt->current_stack_frame = sf->prev_frame;
  17737     return ret_val;
  17738 }
  17739 
  17740 static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj,
  17741                                       JSValueConst this_obj,
  17742                                       int argc, JSValueConst *argv, int flags)
  17743 {
  17744     JSObject *p;
  17745     JSBoundFunction *bf;
  17746     JSValueConst *arg_buf, new_target;
  17747     int arg_count, i;
  17748 
  17749     p = JS_VALUE_GET_OBJ(func_obj);
  17750     bf = p->u.bound_function;
  17751     arg_count = bf->argc + argc;
  17752     if (js_check_stack_overflow(ctx->rt, sizeof(JSValue) * arg_count))
  17753         return JS_ThrowStackOverflow(ctx);
  17754     arg_buf = alloca(sizeof(JSValue) * arg_count);
  17755     for(i = 0; i < bf->argc; i++) {
  17756         arg_buf[i] = bf->argv[i];
  17757     }
  17758     for(i = 0; i < argc; i++) {
  17759         arg_buf[bf->argc + i] = argv[i];
  17760     }
  17761     if (flags & JS_CALL_FLAG_CONSTRUCTOR) {
  17762         new_target = this_obj;
  17763         if (js_same_value(ctx, func_obj, new_target))
  17764             new_target = bf->func_obj;
  17765         return JS_CallConstructor2(ctx, bf->func_obj, new_target,
  17766                                    arg_count, arg_buf);
  17767     } else {
  17768         return JS_Call(ctx, bf->func_obj, bf->this_val,
  17769                        arg_count, arg_buf);
  17770     }
  17771 }
  17772 
  17773 /* argument of OP_special_object */
  17774 typedef enum {
  17775     OP_SPECIAL_OBJECT_ARGUMENTS,
  17776     OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS,
  17777     OP_SPECIAL_OBJECT_THIS_FUNC,
  17778     OP_SPECIAL_OBJECT_NEW_TARGET,
  17779     OP_SPECIAL_OBJECT_HOME_OBJECT,
  17780     OP_SPECIAL_OBJECT_VAR_OBJECT,
  17781     OP_SPECIAL_OBJECT_IMPORT_META,
  17782 } OPSpecialObjectEnum;
  17783 
  17784 #define FUNC_RET_AWAIT         0
  17785 #define FUNC_RET_YIELD         1
  17786 #define FUNC_RET_YIELD_STAR    2
  17787 #define FUNC_RET_INITIAL_YIELD 3
  17788 
  17789 #ifdef OPCODE_ASM_LABEL
  17790 #pragma GCC diagnostic push
  17791 #pragma GCC diagnostic ignored "-Wunused-label"
  17792 #endif
  17793 
  17794 /* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */
  17795 static JSValue __JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
  17796                                JSValueConst this_obj, JSValueConst new_target,
  17797                                int argc, JSValue *argv, int flags)
  17798 {
  17799     JSRuntime *rt = caller_ctx->rt;
  17800     JSContext *ctx;
  17801     JSObject *p;
  17802     JSFunctionBytecode *b;
  17803     JSStackFrame sf_s, *sf = &sf_s;
  17804     const uint8_t *pc;
  17805     int opcode, arg_allocated_size, i;
  17806     JSValue *local_buf, *stack_buf, *var_buf, *arg_buf, *sp, ret_val, *pval;
  17807     JSVarRef **var_refs;
  17808     size_t alloca_size;
  17809 
  17810 #if !DIRECT_DISPATCH
  17811 #define SWITCH(pc)      switch (opcode = *pc++)
  17812 #define CASE(op)        case op
  17813 #define DEFAULT         default
  17814 #define BREAK           break
  17815 #else
  17816     static const void * const dispatch_table[256] = {
  17817 #define DEF(id, size, n_pop, n_push, f) && case_OP_ ## id,
  17818 #if SHORT_OPCODES
  17819 #define def(id, size, n_pop, n_push, f)
  17820 #else
  17821 #define def(id, size, n_pop, n_push, f) && case_default,
  17822 #endif
  17823 #include "quickjs-opcode.h"
  17824         [ OP_COUNT ... 255 ] = &&case_default
  17825     };
  17826 #define SWITCH(pc)      goto *dispatch_table[opcode = *pc++];
  17827 #ifdef OPCODE_ASM_LABEL
  17828 #define CASE(op)        case_ ## op: asm volatile("label_" #op ":\n.globl label_" #op); dummy_case_ ## op
  17829 #else
  17830 #define CASE(op)        case_ ## op
  17831 #endif
  17832 #define DEFAULT         case_default
  17833 #define BREAK           SWITCH(pc)
  17834 #endif
  17835 
  17836     if (js_poll_interrupts(caller_ctx))
  17837         return JS_EXCEPTION;
  17838     if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)) {
  17839         if (flags & JS_CALL_FLAG_GENERATOR) {
  17840             JSAsyncFunctionState *s = JS_VALUE_GET_PTR(func_obj);
  17841             /* func_obj get contains a pointer to JSFuncAsyncState */
  17842             /* the stack frame is already allocated */
  17843             sf = &s->frame;
  17844             p = JS_VALUE_GET_OBJ(sf->cur_func);
  17845             b = p->u.func.function_bytecode;
  17846             ctx = b->realm;
  17847             var_refs = p->u.func.var_refs;
  17848             local_buf = arg_buf = sf->arg_buf;
  17849             var_buf = sf->var_buf;
  17850             stack_buf = sf->var_buf + b->var_count;
  17851             sp = sf->cur_sp;
  17852             sf->cur_sp = NULL; /* cur_sp is NULL if the function is running */
  17853             pc = sf->cur_pc;
  17854             sf->prev_frame = rt->current_stack_frame;
  17855             rt->current_stack_frame = sf;
  17856             if (s->throw_flag)
  17857                 goto exception;
  17858             else
  17859                 goto restart;
  17860         } else {
  17861             goto not_a_function;
  17862         }
  17863     }
  17864     p = JS_VALUE_GET_OBJ(func_obj);
  17865     if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {
  17866         JSClassCall *call_func;
  17867         call_func = rt->class_array[p->class_id].call;
  17868         if (!call_func) {
  17869         not_a_function:
  17870             return JS_ThrowTypeError(caller_ctx, "not a function");
  17871         }
  17872         return call_func(caller_ctx, func_obj, this_obj, argc,
  17873                          (JSValueConst *)argv, flags);
  17874     }
  17875     b = p->u.func.function_bytecode;
  17876 
  17877     if (unlikely(argc < b->arg_count || (flags & JS_CALL_FLAG_COPY_ARGV))) {
  17878         arg_allocated_size = b->arg_count;
  17879     } else {
  17880         arg_allocated_size = 0;
  17881     }
  17882 
  17883     alloca_size = sizeof(JSValue) * (arg_allocated_size + b->var_count +
  17884                                      b->stack_size) +
  17885         sizeof(JSVarRef *) * b->var_ref_count;
  17886     if (js_check_stack_overflow(rt, alloca_size))
  17887         return JS_ThrowStackOverflow(caller_ctx);
  17888 
  17889     sf->js_mode = b->js_mode;
  17890     arg_buf = argv;
  17891     sf->arg_count = argc;
  17892     sf->cur_func = (JSValue)func_obj;
  17893     var_refs = p->u.func.var_refs;
  17894 
  17895     local_buf = alloca(alloca_size);
  17896     if (unlikely(arg_allocated_size)) {
  17897         int n = min_int(argc, b->arg_count);
  17898         arg_buf = local_buf;
  17899         for(i = 0; i < n; i++)
  17900             arg_buf[i] = JS_DupValue(caller_ctx, argv[i]);
  17901         for(; i < b->arg_count; i++)
  17902             arg_buf[i] = JS_UNDEFINED;
  17903         sf->arg_count = b->arg_count;
  17904     }
  17905     var_buf = local_buf + arg_allocated_size;
  17906     sf->var_buf = var_buf;
  17907     sf->arg_buf = arg_buf;
  17908 
  17909     for(i = 0; i < b->var_count; i++)
  17910         var_buf[i] = JS_UNDEFINED;
  17911 
  17912     stack_buf = var_buf + b->var_count;
  17913     sf->var_refs = (JSVarRef **)(stack_buf + b->stack_size);
  17914     for(i = 0; i < b->var_ref_count; i++)
  17915         sf->var_refs[i] = NULL;
  17916     sp = stack_buf;
  17917     pc = b->byte_code_buf;
  17918     sf->prev_frame = rt->current_stack_frame;
  17919     rt->current_stack_frame = sf;
  17920     ctx = b->realm; /* set the current realm */
  17921 
  17922  restart:
  17923     for(;;) {
  17924         int call_argc;
  17925         JSValue *call_argv;
  17926 
  17927         SWITCH(pc) {
  17928         CASE(OP_push_i32):
  17929             *sp++ = JS_NewInt32(ctx, get_u32(pc));
  17930             pc += 4;
  17931             BREAK;
  17932         CASE(OP_push_bigint_i32):
  17933             *sp++ = __JS_NewShortBigInt(ctx, (int)get_u32(pc));
  17934             pc += 4;
  17935             BREAK;
  17936         CASE(OP_push_const):
  17937             *sp++ = JS_DupValue(ctx, b->cpool[get_u32(pc)]);
  17938             pc += 4;
  17939             BREAK;
  17940 #if SHORT_OPCODES
  17941         CASE(OP_push_minus1):
  17942         CASE(OP_push_0):
  17943         CASE(OP_push_1):
  17944         CASE(OP_push_2):
  17945         CASE(OP_push_3):
  17946         CASE(OP_push_4):
  17947         CASE(OP_push_5):
  17948         CASE(OP_push_6):
  17949         CASE(OP_push_7):
  17950             *sp++ = JS_NewInt32(ctx, opcode - OP_push_0);
  17951             BREAK;
  17952         CASE(OP_push_i8):
  17953             *sp++ = JS_NewInt32(ctx, get_i8(pc));
  17954             pc += 1;
  17955             BREAK;
  17956         CASE(OP_push_i16):
  17957             *sp++ = JS_NewInt32(ctx, get_i16(pc));
  17958             pc += 2;
  17959             BREAK;
  17960         CASE(OP_push_const8):
  17961             *sp++ = JS_DupValue(ctx, b->cpool[*pc++]);
  17962             BREAK;
  17963         CASE(OP_fclosure8):
  17964             *sp++ = js_closure(ctx, JS_DupValue(ctx, b->cpool[*pc++]), var_refs, sf, FALSE);
  17965             if (unlikely(JS_IsException(sp[-1])))
  17966                 goto exception;
  17967             BREAK;
  17968         CASE(OP_push_empty_string):
  17969             *sp++ = JS_AtomToString(ctx, JS_ATOM_empty_string);
  17970             BREAK;
  17971 #endif
  17972         CASE(OP_push_atom_value):
  17973             *sp++ = JS_AtomToValue(ctx, get_u32(pc));
  17974             pc += 4;
  17975             BREAK;
  17976         CASE(OP_undefined):
  17977             *sp++ = JS_UNDEFINED;
  17978             BREAK;
  17979         CASE(OP_null):
  17980             *sp++ = JS_NULL;
  17981             BREAK;
  17982         CASE(OP_push_this):
  17983             /* OP_push_this is only called at the start of a function */
  17984             {
  17985                 JSValue val;
  17986                 if (!(b->js_mode & JS_MODE_STRICT)) {
  17987                     uint32_t tag = JS_VALUE_GET_TAG(this_obj);
  17988                     if (likely(tag == JS_TAG_OBJECT))
  17989                         goto normal_this;
  17990                     if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) {
  17991                         val = JS_DupValue(ctx, ctx->global_obj);
  17992                     } else {
  17993                         val = JS_ToObject(ctx, this_obj);
  17994                         if (JS_IsException(val))
  17995                             goto exception;
  17996                     }
  17997                 } else {
  17998                 normal_this:
  17999                     val = JS_DupValue(ctx, this_obj);
  18000                 }
  18001                 *sp++ = val;
  18002             }
  18003             BREAK;
  18004         CASE(OP_push_false):
  18005             *sp++ = JS_FALSE;
  18006             BREAK;
  18007         CASE(OP_push_true):
  18008             *sp++ = JS_TRUE;
  18009             BREAK;
  18010         CASE(OP_object):
  18011             *sp++ = JS_NewObject(ctx);
  18012             if (unlikely(JS_IsException(sp[-1])))
  18013                 goto exception;
  18014             BREAK;
  18015         CASE(OP_special_object):
  18016             {
  18017                 int arg = *pc++;
  18018                 switch(arg) {
  18019                 case OP_SPECIAL_OBJECT_ARGUMENTS:
  18020                     *sp++ = js_build_arguments(ctx, argc, (JSValueConst *)argv);
  18021                     if (unlikely(JS_IsException(sp[-1])))
  18022                         goto exception;
  18023                     break;
  18024                 case OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS:
  18025                     *sp++ = js_build_mapped_arguments(ctx, argc, (JSValueConst *)argv,
  18026                                                       sf, min_int(argc, b->arg_count));
  18027                     if (unlikely(JS_IsException(sp[-1])))
  18028                         goto exception;
  18029                     break;
  18030                 case OP_SPECIAL_OBJECT_THIS_FUNC:
  18031                     *sp++ = JS_DupValue(ctx, sf->cur_func);
  18032                     break;
  18033                 case OP_SPECIAL_OBJECT_NEW_TARGET:
  18034                     *sp++ = JS_DupValue(ctx, new_target);
  18035                     break;
  18036                 case OP_SPECIAL_OBJECT_HOME_OBJECT:
  18037                     {
  18038                         JSObject *p1;
  18039                         p1 = p->u.func.home_object;
  18040                         if (unlikely(!p1))
  18041                             *sp++ = JS_UNDEFINED;
  18042                         else
  18043                             *sp++ = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
  18044                     }
  18045                     break;
  18046                 case OP_SPECIAL_OBJECT_VAR_OBJECT:
  18047                     *sp++ = JS_NewObjectProto(ctx, JS_NULL);
  18048                     if (unlikely(JS_IsException(sp[-1])))
  18049                         goto exception;
  18050                     break;
  18051                 case OP_SPECIAL_OBJECT_IMPORT_META:
  18052                     *sp++ = js_import_meta(ctx);
  18053                     if (unlikely(JS_IsException(sp[-1])))
  18054                         goto exception;
  18055                     break;
  18056                 default:
  18057                     abort();
  18058                 }
  18059             }
  18060             BREAK;
  18061         CASE(OP_rest):
  18062             {
  18063                 int first = get_u16(pc);
  18064                 pc += 2;
  18065                 first = min_int(first, argc);
  18066                 *sp++ = js_create_array(ctx, argc - first, (JSValueConst *)(argv + first));
  18067                 if (unlikely(JS_IsException(sp[-1])))
  18068                     goto exception;
  18069             }
  18070             BREAK;
  18071 
  18072         CASE(OP_drop):
  18073             JS_FreeValue(ctx, sp[-1]);
  18074             sp--;
  18075             BREAK;
  18076         CASE(OP_nip):
  18077             JS_FreeValue(ctx, sp[-2]);
  18078             sp[-2] = sp[-1];
  18079             sp--;
  18080             BREAK;
  18081         CASE(OP_nip1): /* a b c -> b c */
  18082             JS_FreeValue(ctx, sp[-3]);
  18083             sp[-3] = sp[-2];
  18084             sp[-2] = sp[-1];
  18085             sp--;
  18086             BREAK;
  18087         CASE(OP_dup):
  18088             sp[0] = JS_DupValue(ctx, sp[-1]);
  18089             sp++;
  18090             BREAK;
  18091         CASE(OP_dup2): /* a b -> a b a b */
  18092             sp[0] = JS_DupValue(ctx, sp[-2]);
  18093             sp[1] = JS_DupValue(ctx, sp[-1]);
  18094             sp += 2;
  18095             BREAK;
  18096         CASE(OP_dup3): /* a b c -> a b c a b c */
  18097             sp[0] = JS_DupValue(ctx, sp[-3]);
  18098             sp[1] = JS_DupValue(ctx, sp[-2]);
  18099             sp[2] = JS_DupValue(ctx, sp[-1]);
  18100             sp += 3;
  18101             BREAK;
  18102         CASE(OP_dup1): /* a b -> a a b */
  18103             sp[0] = sp[-1];
  18104             sp[-1] = JS_DupValue(ctx, sp[-2]);
  18105             sp++;
  18106             BREAK;
  18107         CASE(OP_insert2): /* obj a -> a obj a (dup_x1) */
  18108             sp[0] = sp[-1];
  18109             sp[-1] = sp[-2];
  18110             sp[-2] = JS_DupValue(ctx, sp[0]);
  18111             sp++;
  18112             BREAK;
  18113         CASE(OP_insert3): /* obj prop a -> a obj prop a (dup_x2) */
  18114             sp[0] = sp[-1];
  18115             sp[-1] = sp[-2];
  18116             sp[-2] = sp[-3];
  18117             sp[-3] = JS_DupValue(ctx, sp[0]);
  18118             sp++;
  18119             BREAK;
  18120         CASE(OP_insert4): /* this obj prop a -> a this obj prop a */
  18121             sp[0] = sp[-1];
  18122             sp[-1] = sp[-2];
  18123             sp[-2] = sp[-3];
  18124             sp[-3] = sp[-4];
  18125             sp[-4] = JS_DupValue(ctx, sp[0]);
  18126             sp++;
  18127             BREAK;
  18128         CASE(OP_perm3): /* obj a b -> a obj b (213) */
  18129             {
  18130                 JSValue tmp;
  18131                 tmp = sp[-2];
  18132                 sp[-2] = sp[-3];
  18133                 sp[-3] = tmp;
  18134             }
  18135             BREAK;
  18136         CASE(OP_rot3l): /* x a b -> a b x (231) */
  18137             {
  18138                 JSValue tmp;
  18139                 tmp = sp[-3];
  18140                 sp[-3] = sp[-2];
  18141                 sp[-2] = sp[-1];
  18142                 sp[-1] = tmp;
  18143             }
  18144             BREAK;
  18145         CASE(OP_rot4l): /* x a b c -> a b c x */
  18146             {
  18147                 JSValue tmp;
  18148                 tmp = sp[-4];
  18149                 sp[-4] = sp[-3];
  18150                 sp[-3] = sp[-2];
  18151                 sp[-2] = sp[-1];
  18152                 sp[-1] = tmp;
  18153             }
  18154             BREAK;
  18155         CASE(OP_rot5l): /* x a b c d -> a b c d x */
  18156             {
  18157                 JSValue tmp;
  18158                 tmp = sp[-5];
  18159                 sp[-5] = sp[-4];
  18160                 sp[-4] = sp[-3];
  18161                 sp[-3] = sp[-2];
  18162                 sp[-2] = sp[-1];
  18163                 sp[-1] = tmp;
  18164             }
  18165             BREAK;
  18166         CASE(OP_rot3r): /* a b x -> x a b (312) */
  18167             {
  18168                 JSValue tmp;
  18169                 tmp = sp[-1];
  18170                 sp[-1] = sp[-2];
  18171                 sp[-2] = sp[-3];
  18172                 sp[-3] = tmp;
  18173             }
  18174             BREAK;
  18175         CASE(OP_perm4): /* obj prop a b -> a obj prop b */
  18176             {
  18177                 JSValue tmp;
  18178                 tmp = sp[-2];
  18179                 sp[-2] = sp[-3];
  18180                 sp[-3] = sp[-4];
  18181                 sp[-4] = tmp;
  18182             }
  18183             BREAK;
  18184         CASE(OP_perm5): /* this obj prop a b -> a this obj prop b */
  18185             {
  18186                 JSValue tmp;
  18187                 tmp = sp[-2];
  18188                 sp[-2] = sp[-3];
  18189                 sp[-3] = sp[-4];
  18190                 sp[-4] = sp[-5];
  18191                 sp[-5] = tmp;
  18192             }
  18193             BREAK;
  18194         CASE(OP_swap): /* a b -> b a */
  18195             {
  18196                 JSValue tmp;
  18197                 tmp = sp[-2];
  18198                 sp[-2] = sp[-1];
  18199                 sp[-1] = tmp;
  18200             }
  18201             BREAK;
  18202         CASE(OP_swap2): /* a b c d -> c d a b */
  18203             {
  18204                 JSValue tmp1, tmp2;
  18205                 tmp1 = sp[-4];
  18206                 tmp2 = sp[-3];
  18207                 sp[-4] = sp[-2];
  18208                 sp[-3] = sp[-1];
  18209                 sp[-2] = tmp1;
  18210                 sp[-1] = tmp2;
  18211             }
  18212             BREAK;
  18213 
  18214         CASE(OP_fclosure):
  18215             {
  18216                 JSValue bfunc = JS_DupValue(ctx, b->cpool[get_u32(pc)]);
  18217                 pc += 4;
  18218                 *sp++ = js_closure(ctx, bfunc, var_refs, sf, FALSE);
  18219                 if (unlikely(JS_IsException(sp[-1])))
  18220                     goto exception;
  18221             }
  18222             BREAK;
  18223 #if SHORT_OPCODES
  18224         CASE(OP_call0):
  18225         CASE(OP_call1):
  18226         CASE(OP_call2):
  18227         CASE(OP_call3):
  18228             call_argc = opcode - OP_call0;
  18229             goto has_call_argc;
  18230 #endif
  18231         CASE(OP_call):
  18232         CASE(OP_tail_call):
  18233             {
  18234                 call_argc = get_u16(pc);
  18235                 pc += 2;
  18236                 goto has_call_argc;
  18237             has_call_argc:
  18238                 call_argv = sp - call_argc;
  18239                 sf->cur_pc = pc;
  18240                 ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED,
  18241                                           JS_UNDEFINED, call_argc, call_argv, 0);
  18242                 if (unlikely(JS_IsException(ret_val)))
  18243                     goto exception;
  18244                 if (opcode == OP_tail_call)
  18245                     goto done;
  18246                 for(i = -1; i < call_argc; i++)
  18247                     JS_FreeValue(ctx, call_argv[i]);
  18248                 sp -= call_argc + 1;
  18249                 *sp++ = ret_val;
  18250             }
  18251             BREAK;
  18252         CASE(OP_call_constructor):
  18253             {
  18254                 call_argc = get_u16(pc);
  18255                 pc += 2;
  18256                 call_argv = sp - call_argc;
  18257                 sf->cur_pc = pc;
  18258                 ret_val = JS_CallConstructorInternal(ctx, call_argv[-2],
  18259                                                      call_argv[-1],
  18260                                                      call_argc, call_argv, 0);
  18261                 if (unlikely(JS_IsException(ret_val)))
  18262                     goto exception;
  18263                 for(i = -2; i < call_argc; i++)
  18264                     JS_FreeValue(ctx, call_argv[i]);
  18265                 sp -= call_argc + 2;
  18266                 *sp++ = ret_val;
  18267             }
  18268             BREAK;
  18269         CASE(OP_call_method):
  18270         CASE(OP_tail_call_method):
  18271             {
  18272                 call_argc = get_u16(pc);
  18273                 pc += 2;
  18274                 call_argv = sp - call_argc;
  18275                 sf->cur_pc = pc;
  18276                 ret_val = JS_CallInternal(ctx, call_argv[-1], call_argv[-2],
  18277                                           JS_UNDEFINED, call_argc, call_argv, 0);
  18278                 if (unlikely(JS_IsException(ret_val)))
  18279                     goto exception;
  18280                 if (opcode == OP_tail_call_method)
  18281                     goto done;
  18282                 for(i = -2; i < call_argc; i++)
  18283                     JS_FreeValue(ctx, call_argv[i]);
  18284                 sp -= call_argc + 2;
  18285                 *sp++ = ret_val;
  18286             }
  18287             BREAK;
  18288         CASE(OP_array_from):
  18289             call_argc = get_u16(pc);
  18290             pc += 2;
  18291             ret_val = js_create_array_free(ctx, call_argc, sp - call_argc);
  18292             sp -= call_argc;
  18293             if (unlikely(JS_IsException(ret_val)))
  18294                 goto exception;
  18295             *sp++ = ret_val;
  18296             BREAK;
  18297 
  18298         CASE(OP_apply):
  18299             {
  18300                 int magic;
  18301                 magic = get_u16(pc);
  18302                 pc += 2;
  18303                 sf->cur_pc = pc;
  18304 
  18305                 ret_val = js_function_apply(ctx, sp[-3], 2, (JSValueConst *)&sp[-2], magic);
  18306                 if (unlikely(JS_IsException(ret_val)))
  18307                     goto exception;
  18308                 JS_FreeValue(ctx, sp[-3]);
  18309                 JS_FreeValue(ctx, sp[-2]);
  18310                 JS_FreeValue(ctx, sp[-1]);
  18311                 sp -= 3;
  18312                 *sp++ = ret_val;
  18313             }
  18314             BREAK;
  18315         CASE(OP_return):
  18316             ret_val = *--sp;
  18317             goto done;
  18318         CASE(OP_return_undef):
  18319             ret_val = JS_UNDEFINED;
  18320             goto done;
  18321 
  18322         CASE(OP_check_ctor_return):
  18323             /* return TRUE if 'this' should be returned */
  18324             if (!JS_IsObject(sp[-1])) {
  18325                 if (!JS_IsUndefined(sp[-1])) {
  18326                     JS_ThrowTypeError(caller_ctx, "derived class constructor must return an object or undefined");
  18327                     goto exception;
  18328                 }
  18329                 sp[0] = JS_TRUE;
  18330             } else {
  18331                 sp[0] = JS_FALSE;
  18332             }
  18333             sp++;
  18334             BREAK;
  18335         CASE(OP_check_ctor):
  18336             if (JS_IsUndefined(new_target)) {
  18337             non_ctor_call:
  18338                 JS_ThrowTypeError(ctx, "class constructors must be invoked with 'new'");
  18339                 goto exception;
  18340             }
  18341             BREAK;
  18342         CASE(OP_init_ctor):
  18343             {
  18344                 JSValue super, ret;
  18345                 sf->cur_pc = pc;
  18346                 if (JS_IsUndefined(new_target))
  18347                     goto non_ctor_call;
  18348                 super = JS_GetPrototype(ctx, func_obj);
  18349                 if (JS_IsException(super))
  18350                     goto exception;
  18351                 ret = JS_CallConstructor2(ctx, super, new_target, argc, (JSValueConst *)argv);
  18352                 JS_FreeValue(ctx, super);
  18353                 if (JS_IsException(ret))
  18354                     goto exception;
  18355                 *sp++ = ret;
  18356             }
  18357             BREAK;
  18358         CASE(OP_check_brand):
  18359             {
  18360                 int ret = JS_CheckBrand(ctx, sp[-2], sp[-1]);
  18361                 if (ret < 0)
  18362                     goto exception;
  18363                 if (!ret) {
  18364                     JS_ThrowTypeError(ctx, "invalid brand on object");
  18365                     goto exception;
  18366                 }
  18367             }
  18368             BREAK;
  18369         CASE(OP_add_brand):
  18370             if (JS_AddBrand(ctx, sp[-2], sp[-1]) < 0)
  18371                 goto exception;
  18372             JS_FreeValue(ctx, sp[-2]);
  18373             JS_FreeValue(ctx, sp[-1]);
  18374             sp -= 2;
  18375             BREAK;
  18376 
  18377         CASE(OP_throw):
  18378             JS_Throw(ctx, *--sp);
  18379             goto exception;
  18380 
  18381         CASE(OP_throw_error):
  18382 #define JS_THROW_VAR_RO             0
  18383 #define JS_THROW_VAR_REDECL         1
  18384 #define JS_THROW_VAR_UNINITIALIZED  2
  18385 #define JS_THROW_ERROR_DELETE_SUPER   3
  18386 #define JS_THROW_ERROR_ITERATOR_THROW 4
  18387             {
  18388                 JSAtom atom;
  18389                 int type;
  18390                 atom = get_u32(pc);
  18391                 type = pc[4];
  18392                 pc += 5;
  18393                 if (type == JS_THROW_VAR_RO)
  18394                     JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, atom);
  18395                 else
  18396                 if (type == JS_THROW_VAR_REDECL)
  18397                     JS_ThrowSyntaxErrorVarRedeclaration(ctx, atom);
  18398                 else
  18399                 if (type == JS_THROW_VAR_UNINITIALIZED)
  18400                     JS_ThrowReferenceErrorUninitialized(ctx, atom);
  18401                 else
  18402                 if (type == JS_THROW_ERROR_DELETE_SUPER)
  18403                     JS_ThrowReferenceError(ctx, "unsupported reference to 'super'");
  18404                 else
  18405                 if (type == JS_THROW_ERROR_ITERATOR_THROW)
  18406                     JS_ThrowTypeError(ctx, "iterator does not have a throw method");
  18407                 else
  18408                     JS_ThrowInternalError(ctx, "invalid throw var type %d", type);
  18409             }
  18410             goto exception;
  18411 
  18412         CASE(OP_eval):
  18413             {
  18414                 JSValueConst obj;
  18415                 int scope_idx;
  18416                 call_argc = get_u16(pc);
  18417                 scope_idx = get_u16(pc + 2) + ARG_SCOPE_END;
  18418                 pc += 4;
  18419                 call_argv = sp - call_argc;
  18420                 sf->cur_pc = pc;
  18421                 if (js_same_value(ctx, call_argv[-1], ctx->eval_obj)) {
  18422                     if (call_argc >= 1)
  18423                         obj = call_argv[0];
  18424                     else
  18425                         obj = JS_UNDEFINED;
  18426                     ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj,
  18427                                             JS_EVAL_TYPE_DIRECT, scope_idx);
  18428                 } else {
  18429                     ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED,
  18430                                               JS_UNDEFINED, call_argc, call_argv, 0);
  18431                 }
  18432                 if (unlikely(JS_IsException(ret_val)))
  18433                     goto exception;
  18434                 for(i = -1; i < call_argc; i++)
  18435                     JS_FreeValue(ctx, call_argv[i]);
  18436                 sp -= call_argc + 1;
  18437                 *sp++ = ret_val;
  18438             }
  18439             BREAK;
  18440             /* could merge with OP_apply */
  18441         CASE(OP_apply_eval):
  18442             {
  18443                 int scope_idx;
  18444                 uint32_t len;
  18445                 JSValue *tab;
  18446                 JSValueConst obj;
  18447 
  18448                 scope_idx = get_u16(pc) + ARG_SCOPE_END;
  18449                 pc += 2;
  18450                 sf->cur_pc = pc;
  18451                 tab = build_arg_list(ctx, &len, sp[-1]);
  18452                 if (!tab)
  18453                     goto exception;
  18454                 if (js_same_value(ctx, sp[-2], ctx->eval_obj)) {
  18455                     if (len >= 1)
  18456                         obj = tab[0];
  18457                     else
  18458                         obj = JS_UNDEFINED;
  18459                     ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj,
  18460                                             JS_EVAL_TYPE_DIRECT, scope_idx);
  18461                 } else {
  18462                     ret_val = JS_Call(ctx, sp[-2], JS_UNDEFINED, len,
  18463                                       (JSValueConst *)tab);
  18464                 }
  18465                 free_arg_list(ctx, tab, len);
  18466                 if (unlikely(JS_IsException(ret_val)))
  18467                     goto exception;
  18468                 JS_FreeValue(ctx, sp[-2]);
  18469                 JS_FreeValue(ctx, sp[-1]);
  18470                 sp -= 2;
  18471                 *sp++ = ret_val;
  18472             }
  18473             BREAK;
  18474 
  18475         CASE(OP_regexp):
  18476             {
  18477                 sp[-2] = JS_NewRegexp(ctx, sp[-2], sp[-1]);
  18478                 sp--;
  18479                 if (JS_IsException(sp[-1]))
  18480                     goto exception;
  18481             }
  18482             BREAK;
  18483 
  18484         CASE(OP_get_super):
  18485             {
  18486                 JSValue proto;
  18487                 sf->cur_pc = pc;
  18488                 proto = JS_GetPrototype(ctx, sp[-1]);
  18489                 if (JS_IsException(proto))
  18490                     goto exception;
  18491                 JS_FreeValue(ctx, sp[-1]);
  18492                 sp[-1] = proto;
  18493             }
  18494             BREAK;
  18495 
  18496         CASE(OP_import):
  18497             {
  18498                 JSValue val;
  18499                 sf->cur_pc = pc;
  18500                 val = js_dynamic_import(ctx, sp[-2], sp[-1]);
  18501                 if (JS_IsException(val))
  18502                     goto exception;
  18503                 JS_FreeValue(ctx, sp[-2]);
  18504                 JS_FreeValue(ctx, sp[-1]);
  18505                 sp--;
  18506                 sp[-1] = val;
  18507             }
  18508             BREAK;
  18509 
  18510         CASE(OP_get_var_undef):
  18511         CASE(OP_get_var):
  18512             {
  18513                 int idx;
  18514                 JSValue val;
  18515                 idx = get_u16(pc);
  18516                 pc += 2;
  18517                 val = *var_refs[idx]->pvalue;
  18518                 if (unlikely(JS_IsUninitialized(val))) {
  18519                     JSClosureVar *cv = &b->closure_var[idx];
  18520                     if (cv->is_lexical) {
  18521                         JS_ThrowReferenceErrorUninitialized(ctx, cv->var_name);
  18522                         goto exception;
  18523                     } else {
  18524                         sf->cur_pc = pc;
  18525                         sp[0] = JS_GetPropertyInternal(ctx, ctx->global_obj,
  18526                                                        cv->var_name,
  18527                                                        ctx->global_obj,
  18528                                                        opcode - OP_get_var_undef);
  18529                         if (JS_IsException(sp[0]))
  18530                             goto exception;
  18531                     }
  18532                 } else {
  18533                     sp[0] = JS_DupValue(ctx, val);
  18534                 }
  18535                 sp++;
  18536             }
  18537             BREAK;
  18538 
  18539         CASE(OP_put_var):
  18540         CASE(OP_put_var_init):
  18541             {
  18542                 int idx, ret;
  18543                 JSVarRef *var_ref;
  18544                 idx = get_u16(pc);
  18545                 pc += 2;
  18546                 var_ref = var_refs[idx];
  18547                 if (unlikely(JS_IsUninitialized(*var_ref->pvalue) ||
  18548                              var_ref->is_const)) {
  18549                     JSClosureVar *cv = &b->closure_var[idx];
  18550                     if (var_ref->is_lexical) {
  18551                         if (opcode == OP_put_var_init)
  18552                             goto put_var_ok;
  18553                         if (JS_IsUninitialized(*var_ref->pvalue))
  18554                             JS_ThrowReferenceErrorUninitialized(ctx, cv->var_name);
  18555                         else
  18556                             JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, cv->var_name);
  18557                         goto exception;
  18558                     } else {
  18559                         sf->cur_pc = pc;
  18560                         ret = JS_HasProperty(ctx, ctx->global_obj, cv->var_name);
  18561                         if (ret < 0)
  18562                             goto exception;
  18563                         if (ret == 0 && is_strict_mode(ctx)) {
  18564                             JS_ThrowReferenceErrorNotDefined(ctx, cv->var_name);
  18565                             goto exception;
  18566                         }
  18567                         ret = JS_SetPropertyInternal(ctx, ctx->global_obj, cv->var_name, sp[-1],
  18568                                                      ctx->global_obj, JS_PROP_THROW_STRICT);
  18569                         sp--;
  18570                         if (ret < 0)
  18571                             goto exception;
  18572                     }
  18573                 } else {
  18574                 put_var_ok:
  18575                    set_value(ctx, var_ref->pvalue, sp[-1]);
  18576                    sp--;
  18577                 }
  18578             }
  18579             BREAK;
  18580         CASE(OP_get_loc):
  18581             {
  18582                 int idx;
  18583                 idx = get_u16(pc);
  18584                 pc += 2;
  18585                 sp[0] = JS_DupValue(ctx, var_buf[idx]);
  18586                 sp++;
  18587             }
  18588             BREAK;
  18589         CASE(OP_put_loc):
  18590             {
  18591                 int idx;
  18592                 idx = get_u16(pc);
  18593                 pc += 2;
  18594                 set_value(ctx, &var_buf[idx], sp[-1]);
  18595                 sp--;
  18596             }
  18597             BREAK;
  18598         CASE(OP_set_loc):
  18599             {
  18600                 int idx;
  18601                 idx = get_u16(pc);
  18602                 pc += 2;
  18603                 set_value(ctx, &var_buf[idx], JS_DupValue(ctx, sp[-1]));
  18604             }
  18605             BREAK;
  18606         CASE(OP_get_arg):
  18607             {
  18608                 int idx;
  18609                 idx = get_u16(pc);
  18610                 pc += 2;
  18611                 sp[0] = JS_DupValue(ctx, arg_buf[idx]);
  18612                 sp++;
  18613             }
  18614             BREAK;
  18615         CASE(OP_put_arg):
  18616             {
  18617                 int idx;
  18618                 idx = get_u16(pc);
  18619                 pc += 2;
  18620                 set_value(ctx, &arg_buf[idx], sp[-1]);
  18621                 sp--;
  18622             }
  18623             BREAK;
  18624         CASE(OP_set_arg):
  18625             {
  18626                 int idx;
  18627                 idx = get_u16(pc);
  18628                 pc += 2;
  18629                 set_value(ctx, &arg_buf[idx], JS_DupValue(ctx, sp[-1]));
  18630             }
  18631             BREAK;
  18632 
  18633 #if SHORT_OPCODES
  18634         CASE(OP_get_loc8): *sp++ = JS_DupValue(ctx, var_buf[*pc++]); BREAK;
  18635         CASE(OP_put_loc8): set_value(ctx, &var_buf[*pc++], *--sp); BREAK;
  18636         CASE(OP_set_loc8): set_value(ctx, &var_buf[*pc++], JS_DupValue(ctx, sp[-1])); BREAK;
  18637 
  18638         CASE(OP_get_loc0): *sp++ = JS_DupValue(ctx, var_buf[0]); BREAK;
  18639         CASE(OP_get_loc1): *sp++ = JS_DupValue(ctx, var_buf[1]); BREAK;
  18640         CASE(OP_get_loc2): *sp++ = JS_DupValue(ctx, var_buf[2]); BREAK;
  18641         CASE(OP_get_loc3): *sp++ = JS_DupValue(ctx, var_buf[3]); BREAK;
  18642         CASE(OP_put_loc0): set_value(ctx, &var_buf[0], *--sp); BREAK;
  18643         CASE(OP_put_loc1): set_value(ctx, &var_buf[1], *--sp); BREAK;
  18644         CASE(OP_put_loc2): set_value(ctx, &var_buf[2], *--sp); BREAK;
  18645         CASE(OP_put_loc3): set_value(ctx, &var_buf[3], *--sp); BREAK;
  18646         CASE(OP_set_loc0): set_value(ctx, &var_buf[0], JS_DupValue(ctx, sp[-1])); BREAK;
  18647         CASE(OP_set_loc1): set_value(ctx, &var_buf[1], JS_DupValue(ctx, sp[-1])); BREAK;
  18648         CASE(OP_set_loc2): set_value(ctx, &var_buf[2], JS_DupValue(ctx, sp[-1])); BREAK;
  18649         CASE(OP_set_loc3): set_value(ctx, &var_buf[3], JS_DupValue(ctx, sp[-1])); BREAK;
  18650         CASE(OP_get_arg0): *sp++ = JS_DupValue(ctx, arg_buf[0]); BREAK;
  18651         CASE(OP_get_arg1): *sp++ = JS_DupValue(ctx, arg_buf[1]); BREAK;
  18652         CASE(OP_get_arg2): *sp++ = JS_DupValue(ctx, arg_buf[2]); BREAK;
  18653         CASE(OP_get_arg3): *sp++ = JS_DupValue(ctx, arg_buf[3]); BREAK;
  18654         CASE(OP_put_arg0): set_value(ctx, &arg_buf[0], *--sp); BREAK;
  18655         CASE(OP_put_arg1): set_value(ctx, &arg_buf[1], *--sp); BREAK;
  18656         CASE(OP_put_arg2): set_value(ctx, &arg_buf[2], *--sp); BREAK;
  18657         CASE(OP_put_arg3): set_value(ctx, &arg_buf[3], *--sp); BREAK;
  18658         CASE(OP_set_arg0): set_value(ctx, &arg_buf[0], JS_DupValue(ctx, sp[-1])); BREAK;
  18659         CASE(OP_set_arg1): set_value(ctx, &arg_buf[1], JS_DupValue(ctx, sp[-1])); BREAK;
  18660         CASE(OP_set_arg2): set_value(ctx, &arg_buf[2], JS_DupValue(ctx, sp[-1])); BREAK;
  18661         CASE(OP_set_arg3): set_value(ctx, &arg_buf[3], JS_DupValue(ctx, sp[-1])); BREAK;
  18662         CASE(OP_get_var_ref0): *sp++ = JS_DupValue(ctx, *var_refs[0]->pvalue); BREAK;
  18663         CASE(OP_get_var_ref1): *sp++ = JS_DupValue(ctx, *var_refs[1]->pvalue); BREAK;
  18664         CASE(OP_get_var_ref2): *sp++ = JS_DupValue(ctx, *var_refs[2]->pvalue); BREAK;
  18665         CASE(OP_get_var_ref3): *sp++ = JS_DupValue(ctx, *var_refs[3]->pvalue); BREAK;
  18666         CASE(OP_put_var_ref0): set_value(ctx, var_refs[0]->pvalue, *--sp); BREAK;
  18667         CASE(OP_put_var_ref1): set_value(ctx, var_refs[1]->pvalue, *--sp); BREAK;
  18668         CASE(OP_put_var_ref2): set_value(ctx, var_refs[2]->pvalue, *--sp); BREAK;
  18669         CASE(OP_put_var_ref3): set_value(ctx, var_refs[3]->pvalue, *--sp); BREAK;
  18670         CASE(OP_set_var_ref0): set_value(ctx, var_refs[0]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
  18671         CASE(OP_set_var_ref1): set_value(ctx, var_refs[1]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
  18672         CASE(OP_set_var_ref2): set_value(ctx, var_refs[2]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
  18673         CASE(OP_set_var_ref3): set_value(ctx, var_refs[3]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
  18674 #endif
  18675 
  18676         CASE(OP_get_var_ref):
  18677             {
  18678                 int idx;
  18679                 JSValue val;
  18680                 idx = get_u16(pc);
  18681                 pc += 2;
  18682                 val = *var_refs[idx]->pvalue;
  18683                 sp[0] = JS_DupValue(ctx, val);
  18684                 sp++;
  18685             }
  18686             BREAK;
  18687         CASE(OP_put_var_ref):
  18688             {
  18689                 int idx;
  18690                 idx = get_u16(pc);
  18691                 pc += 2;
  18692                 set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
  18693                 sp--;
  18694             }
  18695             BREAK;
  18696         CASE(OP_set_var_ref):
  18697             {
  18698                 int idx;
  18699                 idx = get_u16(pc);
  18700                 pc += 2;
  18701                 set_value(ctx, var_refs[idx]->pvalue, JS_DupValue(ctx, sp[-1]));
  18702             }
  18703             BREAK;
  18704         CASE(OP_get_var_ref_check):
  18705             {
  18706                 int idx;
  18707                 JSValue val;
  18708                 idx = get_u16(pc);
  18709                 pc += 2;
  18710                 val = *var_refs[idx]->pvalue;
  18711                 if (unlikely(JS_IsUninitialized(val))) {
  18712                     JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
  18713                     goto exception;
  18714                 }
  18715                 sp[0] = JS_DupValue(ctx, val);
  18716                 sp++;
  18717             }
  18718             BREAK;
  18719         CASE(OP_put_var_ref_check):
  18720             {
  18721                 int idx;
  18722                 idx = get_u16(pc);
  18723                 pc += 2;
  18724                 if (unlikely(JS_IsUninitialized(*var_refs[idx]->pvalue))) {
  18725                     JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
  18726                     goto exception;
  18727                 }
  18728                 set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
  18729                 sp--;
  18730             }
  18731             BREAK;
  18732         CASE(OP_put_var_ref_check_init):
  18733             {
  18734                 int idx;
  18735                 idx = get_u16(pc);
  18736                 pc += 2;
  18737                 if (unlikely(!JS_IsUninitialized(*var_refs[idx]->pvalue))) {
  18738                     JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
  18739                     goto exception;
  18740                 }
  18741                 set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
  18742                 sp--;
  18743             }
  18744             BREAK;
  18745         CASE(OP_set_loc_uninitialized):
  18746             {
  18747                 int idx;
  18748                 idx = get_u16(pc);
  18749                 pc += 2;
  18750                 set_value(ctx, &var_buf[idx], JS_UNINITIALIZED);
  18751             }
  18752             BREAK;
  18753         CASE(OP_get_loc_check):
  18754             {
  18755                 int idx;
  18756                 idx = get_u16(pc);
  18757                 pc += 2;
  18758                 if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
  18759                     JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);
  18760                     goto exception;
  18761                 }
  18762                 sp[0] = JS_DupValue(ctx, var_buf[idx]);
  18763                 sp++;
  18764             }
  18765             BREAK;
  18766         CASE(OP_get_loc_checkthis):
  18767             {
  18768                 int idx;
  18769                 idx = get_u16(pc);
  18770                 pc += 2;
  18771                 if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
  18772                     JS_ThrowReferenceErrorUninitialized2(caller_ctx, b, idx, FALSE);
  18773                     goto exception;
  18774                 }
  18775                 sp[0] = JS_DupValue(ctx, var_buf[idx]);
  18776                 sp++;
  18777             }
  18778             BREAK;
  18779         CASE(OP_put_loc_check):
  18780             {
  18781                 int idx;
  18782                 idx = get_u16(pc);
  18783                 pc += 2;
  18784                 if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
  18785                     JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);
  18786                     goto exception;
  18787                 }
  18788                 set_value(ctx, &var_buf[idx], sp[-1]);
  18789                 sp--;
  18790             }
  18791             BREAK;
  18792         CASE(OP_set_loc_check):
  18793             {
  18794                 int idx;
  18795                 idx = get_u16(pc);
  18796                 pc += 2;
  18797                 if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
  18798                     JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);
  18799                     goto exception;
  18800                 }
  18801                 set_value(ctx, &var_buf[idx], JS_DupValue(ctx, sp[-1]));
  18802             }
  18803             BREAK;
  18804         CASE(OP_put_loc_check_init):
  18805             {
  18806                 int idx;
  18807                 idx = get_u16(pc);
  18808                 pc += 2;
  18809                 if (unlikely(!JS_IsUninitialized(var_buf[idx]))) {
  18810                     JS_ThrowReferenceError(ctx, "'this' can be initialized only once");
  18811                     goto exception;
  18812                 }
  18813                 set_value(ctx, &var_buf[idx], sp[-1]);
  18814                 sp--;
  18815             }
  18816             BREAK;
  18817         CASE(OP_close_loc):
  18818             {
  18819                 int idx;
  18820                 idx = get_u16(pc);
  18821                 pc += 2;
  18822                 close_lexical_var(ctx, b, sf, idx);
  18823             }
  18824             BREAK;
  18825 
  18826         CASE(OP_make_loc_ref):
  18827         CASE(OP_make_arg_ref):
  18828         CASE(OP_make_var_ref_ref):
  18829             {
  18830                 JSVarRef *var_ref;
  18831                 JSProperty *pr;
  18832                 JSAtom atom;
  18833                 int idx;
  18834                 atom = get_u32(pc);
  18835                 idx = get_u16(pc + 4);
  18836                 pc += 6;
  18837                 *sp++ = JS_NewObjectProto(ctx, JS_NULL);
  18838                 if (unlikely(JS_IsException(sp[-1])))
  18839                     goto exception;
  18840                 if (opcode == OP_make_var_ref_ref) {
  18841                     var_ref = var_refs[idx];
  18842                     js_rc(var_ref)->ref_count++;
  18843                 } else {
  18844                     var_ref = get_var_ref(ctx, sf, idx, opcode == OP_make_arg_ref);
  18845                     if (!var_ref)
  18846                         goto exception;
  18847                 }
  18848                 pr = add_property(ctx, JS_VALUE_GET_OBJ(sp[-1]), atom,
  18849                                   JS_PROP_WRITABLE | JS_PROP_VARREF);
  18850                 if (!pr) {
  18851                     free_var_ref(rt, var_ref);
  18852                     goto exception;
  18853                 }
  18854                 pr->u.var_ref = var_ref;
  18855                 *sp++ = JS_AtomToValue(ctx, atom);
  18856             }
  18857             BREAK;
  18858         CASE(OP_make_var_ref):
  18859             {
  18860                 JSAtom atom;
  18861                 atom = get_u32(pc);
  18862                 pc += 4;
  18863                 sf->cur_pc = pc;
  18864 
  18865                 if (JS_GetGlobalVarRef(ctx, atom, sp))
  18866                     goto exception;
  18867                 sp += 2;
  18868             }
  18869             BREAK;
  18870 
  18871         CASE(OP_goto):
  18872             pc += (int32_t)get_u32(pc);
  18873             if (unlikely(js_poll_interrupts(ctx)))
  18874                 goto exception;
  18875             BREAK;
  18876 #if SHORT_OPCODES
  18877         CASE(OP_goto16):
  18878             pc += (int16_t)get_u16(pc);
  18879             if (unlikely(js_poll_interrupts(ctx)))
  18880                 goto exception;
  18881             BREAK;
  18882         CASE(OP_goto8):
  18883             pc += (int8_t)pc[0];
  18884             if (unlikely(js_poll_interrupts(ctx)))
  18885                 goto exception;
  18886             BREAK;
  18887 #endif
  18888         CASE(OP_if_true):
  18889             {
  18890                 int res;
  18891                 JSValue op1;
  18892 
  18893                 op1 = sp[-1];
  18894                 pc += 4;
  18895                 if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
  18896                     res = JS_VALUE_GET_INT(op1);
  18897                 } else {
  18898                     res = JS_ToBoolFree(ctx, op1);
  18899                 }
  18900                 sp--;
  18901                 if (res) {
  18902                     pc += (int32_t)get_u32(pc - 4) - 4;
  18903                 }
  18904                 if (unlikely(js_poll_interrupts(ctx)))
  18905                     goto exception;
  18906             }
  18907             BREAK;
  18908         CASE(OP_if_false):
  18909             {
  18910                 int res;
  18911                 JSValue op1;
  18912 
  18913                 op1 = sp[-1];
  18914                 pc += 4;
  18915                 /* quick and dirty test for JS_TAG_INT, JS_TAG_BOOL, JS_TAG_NULL and JS_TAG_UNDEFINED */
  18916                 if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
  18917                     res = JS_VALUE_GET_INT(op1);
  18918                 } else {
  18919                     res = JS_ToBoolFree(ctx, op1);
  18920                 }
  18921                 sp--;
  18922                 if (!res) {
  18923                     pc += (int32_t)get_u32(pc - 4) - 4;
  18924                 }
  18925                 if (unlikely(js_poll_interrupts(ctx)))
  18926                     goto exception;
  18927             }
  18928             BREAK;
  18929 #if SHORT_OPCODES
  18930         CASE(OP_if_true8):
  18931             {
  18932                 int res;
  18933                 JSValue op1;
  18934 
  18935                 op1 = sp[-1];
  18936                 pc += 1;
  18937                 if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
  18938                     res = JS_VALUE_GET_INT(op1);
  18939                 } else {
  18940                     res = JS_ToBoolFree(ctx, op1);
  18941                 }
  18942                 sp--;
  18943                 if (res) {
  18944                     pc += (int8_t)pc[-1] - 1;
  18945                 }
  18946                 if (unlikely(js_poll_interrupts(ctx)))
  18947                     goto exception;
  18948             }
  18949             BREAK;
  18950         CASE(OP_if_false8):
  18951             {
  18952                 int res;
  18953                 JSValue op1;
  18954 
  18955                 op1 = sp[-1];
  18956                 pc += 1;
  18957                 if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
  18958                     res = JS_VALUE_GET_INT(op1);
  18959                 } else {
  18960                     res = JS_ToBoolFree(ctx, op1);
  18961                 }
  18962                 sp--;
  18963                 if (!res) {
  18964                     pc += (int8_t)pc[-1] - 1;
  18965                 }
  18966                 if (unlikely(js_poll_interrupts(ctx)))
  18967                     goto exception;
  18968             }
  18969             BREAK;
  18970 #endif
  18971         CASE(OP_catch):
  18972             {
  18973                 int32_t diff;
  18974                 diff = get_u32(pc);
  18975                 sp[0] = JS_NewCatchOffset(ctx, pc + diff - b->byte_code_buf);
  18976                 sp++;
  18977                 pc += 4;
  18978             }
  18979             BREAK;
  18980         CASE(OP_gosub):
  18981             {
  18982                 int32_t diff;
  18983                 diff = get_u32(pc);
  18984                 /* XXX: should have a different tag to avoid security flaw */
  18985                 sp[0] = JS_NewInt32(ctx, pc + 4 - b->byte_code_buf);
  18986                 sp++;
  18987                 pc += diff;
  18988             }
  18989             BREAK;
  18990         CASE(OP_ret):
  18991             {
  18992                 JSValue op1;
  18993                 uint32_t pos;
  18994                 op1 = sp[-1];
  18995                 if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_INT))
  18996                     goto ret_fail;
  18997                 pos = JS_VALUE_GET_INT(op1);
  18998                 if (unlikely(pos >= b->byte_code_len)) {
  18999                 ret_fail:
  19000                     JS_ThrowInternalError(ctx, "invalid ret value");
  19001                     goto exception;
  19002                 }
  19003                 sp--;
  19004                 pc = b->byte_code_buf + pos;
  19005             }
  19006             BREAK;
  19007 
  19008         CASE(OP_for_in_start):
  19009             sf->cur_pc = pc;
  19010             if (js_for_in_start(ctx, sp))
  19011                 goto exception;
  19012             BREAK;
  19013         CASE(OP_for_in_next):
  19014             sf->cur_pc = pc;
  19015             if (js_for_in_next(ctx, sp))
  19016                 goto exception;
  19017             sp += 2;
  19018             BREAK;
  19019         CASE(OP_for_of_start):
  19020             sf->cur_pc = pc;
  19021             if (js_for_of_start(ctx, sp, FALSE))
  19022                 goto exception;
  19023             sp += 1;
  19024             *sp++ = JS_NewCatchOffset(ctx, 0);
  19025             BREAK;
  19026         CASE(OP_for_of_next):
  19027             {
  19028                 int offset = -3 - pc[0];
  19029                 pc += 1;
  19030                 sf->cur_pc = pc;
  19031                 if (js_for_of_next(ctx, sp, offset))
  19032                     goto exception;
  19033                 sp += 2;
  19034             }
  19035             BREAK;
  19036         CASE(OP_for_await_of_next):
  19037             sf->cur_pc = pc;
  19038             if (js_for_await_of_next(ctx, sp))
  19039                 goto exception;
  19040             sp++;
  19041             BREAK;
  19042         CASE(OP_for_await_of_start):
  19043             sf->cur_pc = pc;
  19044             if (js_for_of_start(ctx, sp, TRUE))
  19045                 goto exception;
  19046             sp += 1;
  19047             *sp++ = JS_NewCatchOffset(ctx, 0);
  19048             BREAK;
  19049         CASE(OP_iterator_get_value_done):
  19050             sf->cur_pc = pc;
  19051             if (js_iterator_get_value_done(ctx, sp))
  19052                 goto exception;
  19053             sp += 1;
  19054             BREAK;
  19055         CASE(OP_iterator_check_object):
  19056             if (unlikely(!JS_IsObject(sp[-1]))) {
  19057                 JS_ThrowTypeError(ctx, "iterator must return an object");
  19058                 goto exception;
  19059             }
  19060             BREAK;
  19061 
  19062         CASE(OP_iterator_close):
  19063             /* iter_obj next catch_offset -> */
  19064             sp--; /* drop the catch offset to avoid getting caught by exception */
  19065             JS_FreeValue(ctx, sp[-1]); /* drop the next method */
  19066             sp--;
  19067             if (!JS_IsUndefined(sp[-1])) {
  19068                 sf->cur_pc = pc;
  19069                 if (JS_IteratorClose(ctx, sp[-1], FALSE))
  19070                     goto exception;
  19071                 JS_FreeValue(ctx, sp[-1]);
  19072             }
  19073             sp--;
  19074             BREAK;
  19075         CASE(OP_nip_catch):
  19076             {
  19077                 JSValue ret_val;
  19078                 /* catch_offset ... ret_val -> ret_eval */
  19079                 ret_val = *--sp;
  19080                 while (sp > stack_buf &&
  19081                        JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_CATCH_OFFSET) {
  19082                     JS_FreeValue(ctx, *--sp);
  19083                 }
  19084                 if (unlikely(sp == stack_buf)) {
  19085                     JS_ThrowInternalError(ctx, "nip_catch");
  19086                     JS_FreeValue(ctx, ret_val);
  19087                     goto exception;
  19088                 }
  19089                 sp[-1] = ret_val;
  19090             }
  19091             BREAK;
  19092 
  19093         CASE(OP_iterator_next):
  19094             /* stack: iter_obj next catch_offset val */
  19095             {
  19096                 JSValue ret;
  19097                 sf->cur_pc = pc;
  19098                 ret = JS_Call(ctx, sp[-3], sp[-4],
  19099                               1, (JSValueConst *)(sp - 1));
  19100                 if (JS_IsException(ret))
  19101                     goto exception;
  19102                 JS_FreeValue(ctx, sp[-1]);
  19103                 sp[-1] = ret;
  19104             }
  19105             BREAK;
  19106 
  19107         CASE(OP_iterator_call):
  19108             /* stack: iter_obj next catch_offset val */
  19109             {
  19110                 JSValue method, ret;
  19111                 BOOL ret_flag;
  19112                 int flags;
  19113                 flags = *pc++;
  19114                 sf->cur_pc = pc;
  19115                 method = JS_GetProperty(ctx, sp[-4], (flags & 1) ?
  19116                                         JS_ATOM_throw : JS_ATOM_return);
  19117                 if (JS_IsException(method))
  19118                     goto exception;
  19119                 if (JS_IsUndefined(method) || JS_IsNull(method)) {
  19120                     ret_flag = TRUE;
  19121                 } else {
  19122                     if (flags & 2) {
  19123                         /* no argument */
  19124                         ret = JS_CallFree(ctx, method, sp[-4],
  19125                                           0, NULL);
  19126                     } else {
  19127                         ret = JS_CallFree(ctx, method, sp[-4],
  19128                                           1, (JSValueConst *)(sp - 1));
  19129                     }
  19130                     if (JS_IsException(ret))
  19131                         goto exception;
  19132                     JS_FreeValue(ctx, sp[-1]);
  19133                     sp[-1] = ret;
  19134                     ret_flag = FALSE;
  19135                 }
  19136                 sp[0] = JS_NewBool(ctx, ret_flag);
  19137                 sp += 1;
  19138             }
  19139             BREAK;
  19140 
  19141         CASE(OP_lnot):
  19142             {
  19143                 int res;
  19144                 JSValue op1;
  19145 
  19146                 op1 = sp[-1];
  19147                 if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
  19148                     res = JS_VALUE_GET_INT(op1) != 0;
  19149                 } else {
  19150                     res = JS_ToBoolFree(ctx, op1);
  19151                 }
  19152                 sp[-1] = JS_NewBool(ctx, !res);
  19153             }
  19154             BREAK;
  19155 
  19156 #define GET_FIELD_INLINE(name, keep, is_length)                         \
  19157             {                                                           \
  19158                 JSValue val, obj;                                       \
  19159                 JSAtom atom;                                            \
  19160                 JSObject *p;                                            \
  19161                 JSProperty *pr;                                         \
  19162                 JSShapeProperty *prs;                                   \
  19163                                                                         \
  19164                 if (is_length) {                                        \
  19165                     atom = JS_ATOM_length;                              \
  19166                 } else {                                                \
  19167                     atom = get_u32(pc);                                 \
  19168                     pc += 4;                                            \
  19169                 }                                                       \
  19170                                                                         \
  19171                 obj = sp[-1];                                           \
  19172                 if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT)) {   \
  19173                     p = JS_VALUE_GET_OBJ(obj);                          \
  19174                     for(;;) {                                           \
  19175                         prs = find_own_property(&pr, p, atom);          \
  19176                         if (prs) {                                      \
  19177                             /* found */                                 \
  19178                             if (unlikely(prs->flags & JS_PROP_TMASK))   \
  19179                                     goto name ## _slow_path;            \
  19180                             val = JS_DupValue(ctx, pr->u.value);        \
  19181                             break;                                      \
  19182                         }                                               \
  19183                         if (unlikely(p->is_exotic)) {                   \
  19184                             /* XXX: should avoid the slow path for arrays \
  19185                                and typed arrays by ensuring that 'prop' is \
  19186                                not numeric */                           \
  19187                             obj = JS_MKPTR(JS_TAG_OBJECT, p);           \
  19188                             goto name ## _slow_path;                    \
  19189                         }                                               \
  19190                         p = p->shape->proto;                            \
  19191                         if (!p) {                                       \
  19192                             val = JS_UNDEFINED;                         \
  19193                             break;                                      \
  19194                         }                                               \
  19195                     }                                                   \
  19196                 } else {                                                \
  19197                 name ## _slow_path:                                     \
  19198                     sf->cur_pc = pc;                                    \
  19199                     val = JS_GetPropertyInternal(ctx, obj, atom, sp[-1], 0); \
  19200                     if (unlikely(JS_IsException(val)))                  \
  19201                         goto exception;                                 \
  19202                 }                                                       \
  19203                 if (keep) {                                             \
  19204                     *sp++ = val;                                        \
  19205                 } else {                                                \
  19206                     JS_FreeValue(ctx, sp[-1]);                          \
  19207                     sp[-1] = val;                                       \
  19208                 }                                                       \
  19209             }
  19210 
  19211             
  19212         CASE(OP_get_field):
  19213             GET_FIELD_INLINE(get_field, 0, 0);
  19214             BREAK;
  19215 
  19216         CASE(OP_get_field2):
  19217             GET_FIELD_INLINE(get_field2, 1, 0);
  19218             BREAK;
  19219 
  19220 #if SHORT_OPCODES
  19221         CASE(OP_get_length):
  19222             GET_FIELD_INLINE(get_length, 0, 1);
  19223             BREAK;
  19224 #endif
  19225             
  19226         CASE(OP_put_field):
  19227             {
  19228                 int ret;
  19229                 JSValue obj;
  19230                 JSAtom atom;
  19231                 JSObject *p;
  19232                 JSProperty *pr;
  19233                 JSShapeProperty *prs;
  19234 
  19235                 atom = get_u32(pc);
  19236                 pc += 4;
  19237 
  19238                 obj = sp[-2];
  19239                 if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT)) {
  19240                     p = JS_VALUE_GET_OBJ(obj);
  19241                     prs = find_own_property(&pr, p, atom);
  19242                     if (!prs)
  19243                         goto put_field_slow_path;
  19244                     if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE |
  19245                                               JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) {
  19246                         /* fast path */
  19247                         set_value(ctx, &pr->u.value, sp[-1]);
  19248                     } else {
  19249                         goto put_field_slow_path;
  19250                     }
  19251                     JS_FreeValue(ctx, obj);
  19252                     sp -= 2;
  19253                 } else {
  19254                 put_field_slow_path:
  19255                     sf->cur_pc = pc;
  19256                     ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-1], obj,
  19257                                                  JS_PROP_THROW_STRICT);
  19258                     JS_FreeValue(ctx, obj);
  19259                     sp -= 2;
  19260                     if (unlikely(ret < 0))
  19261                         goto exception;
  19262                 }
  19263                 
  19264             }
  19265             BREAK;
  19266 
  19267         CASE(OP_private_symbol):
  19268             {
  19269                 JSAtom atom;
  19270                 JSValue val;
  19271 
  19272                 atom = get_u32(pc);
  19273                 pc += 4;
  19274                 val = JS_NewSymbolFromAtom(ctx, atom, JS_ATOM_TYPE_PRIVATE);
  19275                 if (JS_IsException(val))
  19276                     goto exception;
  19277                 *sp++ = val;
  19278             }
  19279             BREAK;
  19280 
  19281         CASE(OP_get_private_field):
  19282             {
  19283                 JSValue val;
  19284 
  19285                 val = JS_GetPrivateField(ctx, sp[-2], sp[-1]);
  19286                 JS_FreeValue(ctx, sp[-1]);
  19287                 JS_FreeValue(ctx, sp[-2]);
  19288                 sp[-2] = val;
  19289                 sp--;
  19290                 if (unlikely(JS_IsException(val)))
  19291                     goto exception;
  19292             }
  19293             BREAK;
  19294 
  19295         CASE(OP_put_private_field):
  19296             {
  19297                 int ret;
  19298                 ret = JS_SetPrivateField(ctx, sp[-3], sp[-1], sp[-2]);
  19299                 JS_FreeValue(ctx, sp[-3]);
  19300                 JS_FreeValue(ctx, sp[-1]);
  19301                 sp -= 3;
  19302                 if (unlikely(ret < 0))
  19303                     goto exception;
  19304             }
  19305             BREAK;
  19306 
  19307         CASE(OP_define_private_field):
  19308             {
  19309                 int ret;
  19310                 ret = JS_DefinePrivateField(ctx, sp[-3], sp[-2], sp[-1]);
  19311                 JS_FreeValue(ctx, sp[-2]);
  19312                 sp -= 2;
  19313                 if (unlikely(ret < 0))
  19314                     goto exception;
  19315             }
  19316             BREAK;
  19317 
  19318         CASE(OP_define_field):
  19319             {
  19320                 int ret;
  19321                 JSAtom atom;
  19322                 atom = get_u32(pc);
  19323                 pc += 4;
  19324 
  19325                 ret = JS_DefinePropertyValue(ctx, sp[-2], atom, sp[-1],
  19326                                              JS_PROP_C_W_E | JS_PROP_THROW);
  19327                 sp--;
  19328                 if (unlikely(ret < 0))
  19329                     goto exception;
  19330             }
  19331             BREAK;
  19332 
  19333         CASE(OP_set_name):
  19334             {
  19335                 int ret;
  19336                 JSAtom atom;
  19337                 atom = get_u32(pc);
  19338                 pc += 4;
  19339 
  19340                 ret = JS_DefineObjectName(ctx, sp[-1], atom, JS_PROP_CONFIGURABLE);
  19341                 if (unlikely(ret < 0))
  19342                     goto exception;
  19343             }
  19344             BREAK;
  19345         CASE(OP_set_name_computed):
  19346             {
  19347                 int ret;
  19348                 ret = JS_DefineObjectNameComputed(ctx, sp[-1], sp[-2], JS_PROP_CONFIGURABLE);
  19349                 if (unlikely(ret < 0))
  19350                     goto exception;
  19351             }
  19352             BREAK;
  19353         CASE(OP_set_proto):
  19354             {
  19355                 JSValue proto;
  19356                 sf->cur_pc = pc;
  19357                 proto = sp[-1];
  19358                 if (JS_IsObject(proto) || JS_IsNull(proto)) {
  19359                     if (JS_SetPrototypeInternal(ctx, sp[-2], proto, TRUE) < 0)
  19360                         goto exception;
  19361                 }
  19362                 JS_FreeValue(ctx, proto);
  19363                 sp--;
  19364             }
  19365             BREAK;
  19366         CASE(OP_set_home_object):
  19367             js_method_set_home_object(ctx, sp[-1], sp[-2]);
  19368             BREAK;
  19369         CASE(OP_define_method):
  19370         CASE(OP_define_method_computed):
  19371             {
  19372                 JSValue getter, setter, value;
  19373                 JSValueConst obj;
  19374                 JSAtom atom;
  19375                 int flags, ret, op_flags;
  19376                 BOOL is_computed;
  19377 #define OP_DEFINE_METHOD_METHOD 0
  19378 #define OP_DEFINE_METHOD_GETTER 1
  19379 #define OP_DEFINE_METHOD_SETTER 2
  19380 #define OP_DEFINE_METHOD_ENUMERABLE 4
  19381 
  19382                 is_computed = (opcode == OP_define_method_computed);
  19383                 if (is_computed) {
  19384                     atom = JS_ValueToAtom(ctx, sp[-2]);
  19385                     if (unlikely(atom == JS_ATOM_NULL))
  19386                         goto exception;
  19387                     opcode += OP_define_method - OP_define_method_computed;
  19388                 } else {
  19389                     atom = get_u32(pc);
  19390                     pc += 4;
  19391                 }
  19392                 op_flags = *pc++;
  19393 
  19394                 obj = sp[-2 - is_computed];
  19395                 flags = JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE |
  19396                     JS_PROP_HAS_ENUMERABLE | JS_PROP_THROW;
  19397                 if (op_flags & OP_DEFINE_METHOD_ENUMERABLE)
  19398                     flags |= JS_PROP_ENUMERABLE;
  19399                 op_flags &= 3;
  19400                 value = JS_UNDEFINED;
  19401                 getter = JS_UNDEFINED;
  19402                 setter = JS_UNDEFINED;
  19403                 if (op_flags == OP_DEFINE_METHOD_METHOD) {
  19404                     value = sp[-1];
  19405                     flags |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE;
  19406                 } else if (op_flags == OP_DEFINE_METHOD_GETTER) {
  19407                     getter = sp[-1];
  19408                     flags |= JS_PROP_HAS_GET;
  19409                 } else {
  19410                     setter = sp[-1];
  19411                     flags |= JS_PROP_HAS_SET;
  19412                 }
  19413                 ret = js_method_set_properties(ctx, sp[-1], atom, flags, obj);
  19414                 if (ret >= 0) {
  19415                     ret = JS_DefineProperty(ctx, obj, atom, value,
  19416                                             getter, setter, flags);
  19417                 }
  19418                 JS_FreeValue(ctx, sp[-1]);
  19419                 if (is_computed) {
  19420                     JS_FreeAtom(ctx, atom);
  19421                     JS_FreeValue(ctx, sp[-2]);
  19422                 }
  19423                 sp -= 1 + is_computed;
  19424                 if (unlikely(ret < 0))
  19425                     goto exception;
  19426             }
  19427             BREAK;
  19428 
  19429         CASE(OP_define_class):
  19430         CASE(OP_define_class_computed):
  19431             {
  19432                 int class_flags;
  19433                 JSAtom atom;
  19434 
  19435                 atom = get_u32(pc);
  19436                 class_flags = pc[4];
  19437                 pc += 5;
  19438                 if (js_op_define_class(ctx, sp, atom, class_flags,
  19439                                        var_refs, sf,
  19440                                        (opcode == OP_define_class_computed)) < 0)
  19441                     goto exception;
  19442             }
  19443             BREAK;
  19444 
  19445 #define GET_ARRAY_EL_INLINE(name, keep)                                 \
  19446             {                                                           \
  19447                 JSValue val, obj, prop;                                 \
  19448                 JSObject *p;                                            \
  19449                 uint32_t idx;                                           \
  19450                                                                         \
  19451                 obj = sp[-2];                                           \
  19452                 prop = sp[-1];                                          \
  19453                 if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT &&    \
  19454                            JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {     \
  19455                     p = JS_VALUE_GET_OBJ(obj);                          \
  19456                     idx = JS_VALUE_GET_INT(prop);                       \
  19457                     if (unlikely(p->class_id != JS_CLASS_ARRAY))        \
  19458                         goto name ## _slow_path;                        \
  19459                     if (unlikely(idx >= p->u.array.count))              \
  19460                         goto name ## _slow_path;                        \
  19461                     val = JS_DupValue(ctx, p->u.array.u.values[idx]);   \
  19462                 } else {                                                \
  19463                     name ## _slow_path:                                 \
  19464                     sf->cur_pc = pc;                                    \
  19465                     val = JS_GetPropertyValue(ctx, obj, prop);          \
  19466                     if (unlikely(JS_IsException(val))) {                \
  19467                         if (keep)                                       \
  19468                             sp[-1] = JS_UNDEFINED;                      \
  19469                         else                                            \
  19470                             sp--;                                       \
  19471                         goto exception;                                 \
  19472                     }                                                   \
  19473                 }                                                       \
  19474                 if (keep) {                                             \
  19475                     sp[-1] = val;                                       \
  19476                 } else {                                                \
  19477                     JS_FreeValue(ctx, obj);                             \
  19478                     sp[-2] = val;                                       \
  19479                     sp--;                                               \
  19480                 }                                                       \
  19481             }
  19482             
  19483         CASE(OP_get_array_el):
  19484             GET_ARRAY_EL_INLINE(get_array_el, 0);
  19485             BREAK;
  19486 
  19487         CASE(OP_get_array_el2):
  19488             GET_ARRAY_EL_INLINE(get_array_el2, 1);
  19489             BREAK;
  19490 
  19491         CASE(OP_get_array_el3):
  19492             {
  19493                 JSValue val;
  19494                 JSObject *p;
  19495                 uint32_t idx;
  19496 
  19497                 if (likely(JS_VALUE_GET_TAG(sp[-2]) == JS_TAG_OBJECT &&
  19498                            JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_INT)) {
  19499                     p = JS_VALUE_GET_OBJ(sp[-2]);
  19500                     idx = JS_VALUE_GET_INT(sp[-1]);
  19501                     if (unlikely(p->class_id != JS_CLASS_ARRAY))
  19502                         goto get_array_el3_slow_path;
  19503                     if (unlikely(idx >= p->u.array.count))
  19504                         goto get_array_el3_slow_path;
  19505                     val = JS_DupValue(ctx, p->u.array.u.values[idx]);
  19506                 } else {
  19507                 get_array_el3_slow_path:
  19508                     switch (JS_VALUE_GET_TAG(sp[-1])) {
  19509                     case JS_TAG_INT:
  19510                     case JS_TAG_STRING:
  19511                     case JS_TAG_SYMBOL:
  19512                         /* undefined and null are tested in JS_GetPropertyValue() */
  19513                         break;
  19514                     default:
  19515                         /* must be tested before JS_ToPropertyKey */
  19516                         if (unlikely(JS_IsUndefined(sp[-2]) || JS_IsNull(sp[-2]))) {
  19517                             JS_ThrowTypeError(ctx, "value has no property");
  19518                             goto exception;
  19519                         }
  19520                         sf->cur_pc = pc;
  19521                         ret_val = JS_ToPropertyKey(ctx, sp[-1]);
  19522                         if (JS_IsException(ret_val))
  19523                             goto exception;
  19524                         JS_FreeValue(ctx, sp[-1]);
  19525                         sp[-1] = ret_val;
  19526                         break;
  19527                     }
  19528                     sf->cur_pc = pc;
  19529                     val = JS_GetPropertyValue(ctx, sp[-2], JS_DupValue(ctx, sp[-1]));
  19530                     if (unlikely(JS_IsException(val)))
  19531                         goto exception;
  19532                 }
  19533                 *sp++ = val;
  19534             }
  19535             BREAK;
  19536             
  19537         CASE(OP_get_ref_value):
  19538             {
  19539                 JSValue val;
  19540                 JSAtom atom;
  19541                 int ret;
  19542                 
  19543                 sf->cur_pc = pc;
  19544                 atom = JS_ValueToAtom(ctx, sp[-1]);
  19545                 if (atom == JS_ATOM_NULL)
  19546                     goto exception;
  19547                 if (unlikely(JS_IsUndefined(sp[-2]))) {
  19548                     JS_ThrowReferenceErrorNotDefined(ctx, atom);
  19549                     JS_FreeAtom(ctx, atom);
  19550                     goto exception;
  19551                 }
  19552                 ret = JS_HasProperty(ctx, sp[-2], atom);
  19553                 if (unlikely(ret <= 0)) {
  19554                     if (ret < 0) {
  19555                         JS_FreeAtom(ctx, atom);
  19556                         goto exception;
  19557                     }
  19558                     if (is_strict_mode(ctx)) {
  19559                         JS_ThrowReferenceErrorNotDefined(ctx, atom);
  19560                         JS_FreeAtom(ctx, atom);
  19561                         goto exception;
  19562                     } 
  19563                     val = JS_UNDEFINED;
  19564                 } else {
  19565                     val = JS_GetProperty(ctx, sp[-2], atom);
  19566                 }
  19567                 JS_FreeAtom(ctx, atom);
  19568                 if (unlikely(JS_IsException(val)))
  19569                     goto exception;
  19570                 sp[0] = val;
  19571                 sp++;
  19572             }
  19573             BREAK;
  19574 
  19575         CASE(OP_get_super_value):
  19576             {
  19577                 JSValue val;
  19578                 JSAtom atom;
  19579                 sf->cur_pc = pc;
  19580                 atom = JS_ValueToAtom(ctx, sp[-1]);
  19581                 if (unlikely(atom == JS_ATOM_NULL))
  19582                     goto exception;
  19583                 val = JS_GetPropertyInternal(ctx, sp[-2], atom, sp[-3], FALSE);
  19584                 JS_FreeAtom(ctx, atom);
  19585                 if (unlikely(JS_IsException(val)))
  19586                     goto exception;
  19587                 JS_FreeValue(ctx, sp[-1]);
  19588                 JS_FreeValue(ctx, sp[-2]);
  19589                 JS_FreeValue(ctx, sp[-3]);
  19590                 sp[-3] = val;
  19591                 sp -= 2;
  19592             }
  19593             BREAK;
  19594 
  19595         CASE(OP_put_array_el):
  19596             {
  19597                 int ret;
  19598                 JSObject *p;
  19599                 uint32_t idx;
  19600 
  19601                 if (likely(JS_VALUE_GET_TAG(sp[-3]) == JS_TAG_OBJECT &&
  19602                            JS_VALUE_GET_TAG(sp[-2]) == JS_TAG_INT)) {
  19603                     p = JS_VALUE_GET_OBJ(sp[-3]);
  19604                     idx = JS_VALUE_GET_INT(sp[-2]);
  19605                     if (unlikely(p->class_id != JS_CLASS_ARRAY))
  19606                         goto put_array_el_slow_path;
  19607                     if (unlikely(idx >= (uint32_t)p->u.array.count)) {
  19608                         uint32_t new_len, array_len;
  19609                         if (unlikely(idx != (uint32_t)p->u.array.count ||
  19610                                      !p->fast_array ||
  19611                                      !can_extend_fast_array(p))) {
  19612                             goto put_array_el_slow_path;
  19613                         }
  19614                         if (likely(JS_VALUE_GET_TAG(p->prop[0].u.value) != JS_TAG_INT))
  19615                             goto put_array_el_slow_path;
  19616                         /* cannot overflow otherwise the length would not be an integer */
  19617                         new_len = idx + 1;
  19618                         if (unlikely(new_len > p->u.array.u1.size))
  19619                             goto put_array_el_slow_path;
  19620                         array_len = JS_VALUE_GET_INT(p->prop[0].u.value);
  19621                         if (new_len > array_len) {
  19622                             if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE)))
  19623                                 goto put_array_el_slow_path;
  19624                             p->prop[0].u.value = JS_NewInt32(ctx, new_len);
  19625                         }
  19626                         p->u.array.count = new_len;
  19627                         p->u.array.u.values[idx] = sp[-1];
  19628                     } else {
  19629                         set_value(ctx, &p->u.array.u.values[idx], sp[-1]);
  19630                     }
  19631                     JS_FreeValue(ctx, sp[-3]);
  19632                     sp -= 3;
  19633                 } else {
  19634                 put_array_el_slow_path:
  19635                     sf->cur_pc = pc;
  19636                     ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT);
  19637                     JS_FreeValue(ctx, sp[-3]);
  19638                     sp -= 3;
  19639                     if (unlikely(ret < 0))
  19640                         goto exception;
  19641                 }
  19642             }
  19643             BREAK;
  19644 
  19645         CASE(OP_put_ref_value):
  19646             {
  19647                 int ret;
  19648                 JSAtom atom;
  19649                 sf->cur_pc = pc;
  19650                 atom = JS_ValueToAtom(ctx, sp[-2]);
  19651                 if (unlikely(atom == JS_ATOM_NULL))
  19652                     goto exception;
  19653                 if (unlikely(JS_IsUndefined(sp[-3]))) {
  19654                     if (is_strict_mode(ctx)) {
  19655                         JS_ThrowReferenceErrorNotDefined(ctx, atom);
  19656                         JS_FreeAtom(ctx, atom);
  19657                         goto exception;
  19658                     } else {
  19659                         sp[-3] = JS_DupValue(ctx, ctx->global_obj);
  19660                     }
  19661                 }
  19662                 ret = JS_HasProperty(ctx, sp[-3], atom);
  19663                 if (unlikely(ret <= 0)) {
  19664                     if (unlikely(ret < 0)) {
  19665                         JS_FreeAtom(ctx, atom);
  19666                         goto exception;
  19667                     }
  19668                     if (is_strict_mode(ctx)) {
  19669                         JS_ThrowReferenceErrorNotDefined(ctx, atom);
  19670                         JS_FreeAtom(ctx, atom);
  19671                         goto exception;
  19672                     }
  19673                 }
  19674                 ret = JS_SetPropertyInternal(ctx, sp[-3], atom, sp[-1], sp[-3], JS_PROP_THROW_STRICT);
  19675                 JS_FreeAtom(ctx, atom);
  19676                 JS_FreeValue(ctx, sp[-2]);
  19677                 JS_FreeValue(ctx, sp[-3]);
  19678                 sp -= 3;
  19679                 if (unlikely(ret < 0))
  19680                     goto exception;
  19681             }
  19682             BREAK;
  19683 
  19684         CASE(OP_put_super_value):
  19685             {
  19686                 int ret;
  19687                 JSAtom atom;
  19688                 sf->cur_pc = pc;
  19689                 if (JS_VALUE_GET_TAG(sp[-3]) != JS_TAG_OBJECT) {
  19690                     JS_ThrowTypeErrorNotAnObject(ctx);
  19691                     goto exception;
  19692                 }
  19693                 atom = JS_ValueToAtom(ctx, sp[-2]);
  19694                 if (unlikely(atom == JS_ATOM_NULL))
  19695                     goto exception;
  19696                 ret = JS_SetPropertyInternal(ctx, sp[-3], atom, sp[-1], sp[-4],
  19697                                              JS_PROP_THROW_STRICT);
  19698                 JS_FreeAtom(ctx, atom);
  19699                 JS_FreeValue(ctx, sp[-4]);
  19700                 JS_FreeValue(ctx, sp[-3]);
  19701                 JS_FreeValue(ctx, sp[-2]);
  19702                 sp -= 4;
  19703                 if (ret < 0)
  19704                     goto exception;
  19705             }
  19706             BREAK;
  19707 
  19708         CASE(OP_define_array_el):
  19709             {
  19710                 int ret;
  19711                 ret = JS_DefinePropertyValueValue(ctx, sp[-3], JS_DupValue(ctx, sp[-2]), sp[-1],
  19712                                                   JS_PROP_C_W_E | JS_PROP_THROW);
  19713                 sp -= 1;
  19714                 if (unlikely(ret < 0))
  19715                     goto exception;
  19716             }
  19717             BREAK;
  19718 
  19719         CASE(OP_append):    /* array pos enumobj -- array pos */
  19720             {
  19721                 sf->cur_pc = pc;
  19722                 if (js_append_enumerate(ctx, sp))
  19723                     goto exception;
  19724                 JS_FreeValue(ctx, *--sp);
  19725             }
  19726             BREAK;
  19727 
  19728         CASE(OP_copy_data_properties):    /* target source excludeList */
  19729             {
  19730                 /* stack offsets (-1 based):
  19731                    2 bits for target,
  19732                    3 bits for source,
  19733                    2 bits for exclusionList */
  19734                 int mask;
  19735 
  19736                 mask = *pc++;
  19737                 sf->cur_pc = pc;
  19738                 if (JS_CopyDataProperties(ctx, sp[-1 - (mask & 3)],
  19739                                           sp[-1 - ((mask >> 2) & 7)],
  19740                                           sp[-1 - ((mask >> 5) & 7)], 0))
  19741                     goto exception;
  19742             }
  19743             BREAK;
  19744 
  19745         CASE(OP_add):
  19746             {
  19747                 JSValue op1, op2;
  19748                 op1 = sp[-2];
  19749                 op2 = sp[-1];
  19750                 if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
  19751                     int64_t r;
  19752                     r = (int64_t)JS_VALUE_GET_INT(op1) + JS_VALUE_GET_INT(op2);
  19753                     if (unlikely((int)r != r)) {
  19754                         sp[-2] = __JS_NewFloat64(ctx, (double)r);
  19755                     } else {
  19756                         sp[-2] = JS_NewInt32(ctx, r);
  19757                     }
  19758                     sp--;
  19759                 } else if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)) ||
  19760                            JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op2))) {
  19761                     double d1, d2;
  19762                     if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1))) {
  19763                         d1 = JS_VALUE_GET_FLOAT64(op1);
  19764                     } else if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
  19765                         d1 = JS_VALUE_GET_INT(op1);
  19766                     } else {
  19767                         goto add_slow_case;
  19768                     }
  19769                     if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op2))) {
  19770                         d2 = JS_VALUE_GET_FLOAT64(op2);
  19771                     } else if (JS_VALUE_GET_TAG(op2) == JS_TAG_INT) {
  19772                         d2 = JS_VALUE_GET_INT(op2);
  19773                     } else {
  19774                         goto add_slow_case;
  19775                     }
  19776                     sp[-2] = __JS_NewFloat64(ctx, d1 + d2);
  19777                     sp--;
  19778                 } else if (JS_IsString(op1) && JS_IsString(op2)) {
  19779                     sp[-2] = JS_ConcatString(ctx, op1, op2);
  19780                     sp--;
  19781                     if (JS_IsException(sp[-1]))
  19782                         goto exception;
  19783                 } else {
  19784                 add_slow_case:
  19785                     sf->cur_pc = pc;
  19786                     if (js_add_slow(ctx, sp))
  19787                         goto exception;
  19788                     sp--;
  19789                 }
  19790             }
  19791             BREAK;
  19792         CASE(OP_add_loc):
  19793             {
  19794                 JSValue op2;
  19795                 JSValue *pv;
  19796                 int idx;
  19797                 idx = *pc;
  19798                 pc += 1;
  19799 
  19800                 op2 = sp[-1];
  19801                 pv = &var_buf[idx];
  19802                 if (likely(JS_VALUE_IS_BOTH_INT(*pv, op2))) {
  19803                     int64_t r;
  19804                     r = (int64_t)JS_VALUE_GET_INT(*pv) + JS_VALUE_GET_INT(op2);
  19805                     if (unlikely((int)r != r)) {
  19806                         *pv = __JS_NewFloat64(ctx, (double)r);
  19807                     } else {
  19808                         *pv = JS_NewInt32(ctx, r);
  19809                     }
  19810                     sp--;
  19811                 } else if (JS_VALUE_IS_BOTH_FLOAT(*pv, op2)) {
  19812                     *pv = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(*pv) +
  19813                                                JS_VALUE_GET_FLOAT64(op2));
  19814                     sp--;
  19815                 } else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING &&
  19816                            JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {
  19817                     sp--;
  19818                     sf->cur_pc = pc;
  19819                     if (JS_ConcatStringInPlace(ctx, JS_VALUE_GET_STRING(*pv), op2)) {
  19820                         JS_FreeValue(ctx, op2);
  19821                     } else {
  19822                         op2 = JS_ConcatString(ctx, JS_DupValue(ctx, *pv), op2);
  19823                         if (JS_IsException(op2))
  19824                             goto exception;
  19825                         set_value(ctx, pv, op2);
  19826                     }
  19827                 } else {
  19828                     JSValue ops[2];
  19829                     /* In case of exception, js_add_slow frees ops[0]
  19830                        and ops[1], so we must duplicate *pv */
  19831                     sf->cur_pc = pc;
  19832                     ops[0] = JS_DupValue(ctx, *pv);
  19833                     ops[1] = op2;
  19834                     sp--;
  19835                     if (js_add_slow(ctx, ops + 2))
  19836                         goto exception;
  19837                     set_value(ctx, pv, ops[0]);
  19838                 }
  19839             }
  19840             BREAK;
  19841         CASE(OP_sub):
  19842             {
  19843                 JSValue op1, op2;
  19844                 op1 = sp[-2];
  19845                 op2 = sp[-1];
  19846                 if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
  19847                     int64_t r;
  19848                     r = (int64_t)JS_VALUE_GET_INT(op1) - JS_VALUE_GET_INT(op2);
  19849                     if (unlikely((int)r != r)) {
  19850                         sp[-2] = __JS_NewFloat64(ctx, (double)r);
  19851                     } else {
  19852                         sp[-2] = JS_NewInt32(ctx, r);
  19853                     }
  19854                     sp--;
  19855                 } else if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)) ||
  19856                            JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op2))) {
  19857                     double d1, d2;
  19858                     if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1))) {
  19859                         d1 = JS_VALUE_GET_FLOAT64(op1);
  19860                     } else if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
  19861                         d1 = JS_VALUE_GET_INT(op1);
  19862                     } else {
  19863                         goto binary_arith_slow;
  19864                     }
  19865                     if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op2))) {
  19866                         d2 = JS_VALUE_GET_FLOAT64(op2);
  19867                     } else if (JS_VALUE_GET_TAG(op2) == JS_TAG_INT) {
  19868                         d2 = JS_VALUE_GET_INT(op2);
  19869                     } else {
  19870                         goto binary_arith_slow;
  19871                     }
  19872                     sp[-2] = __JS_NewFloat64(ctx, d1 - d2);
  19873                     sp--;
  19874                 } else {
  19875                     goto binary_arith_slow;
  19876                 }
  19877             }
  19878             BREAK;
  19879         CASE(OP_mul):
  19880             {
  19881                 JSValue op1, op2;
  19882                 double d;
  19883                 op1 = sp[-2];
  19884                 op2 = sp[-1];
  19885                 if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
  19886                     int32_t v1, v2;
  19887                     int64_t r;
  19888                     v1 = JS_VALUE_GET_INT(op1);
  19889                     v2 = JS_VALUE_GET_INT(op2);
  19890                     r = (int64_t)v1 * v2;
  19891                     if (unlikely((int)r != r)) {
  19892                         d = (double)r;
  19893                         goto mul_fp_res;
  19894                     }
  19895                     /* need to test zero case for -0 result */
  19896                     if (unlikely(r == 0 && (v1 | v2) < 0)) {
  19897                         d = -0.0;
  19898                         goto mul_fp_res;
  19899                     }
  19900                     sp[-2] = JS_NewInt32(ctx, r);
  19901                     sp--;
  19902                 } else if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)) ||
  19903                            JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op2))) {
  19904                     double d1, d2;
  19905                     if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1))) {
  19906                         d1 = JS_VALUE_GET_FLOAT64(op1);
  19907                     } else if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
  19908                         d1 = JS_VALUE_GET_INT(op1);
  19909                     } else {
  19910                         goto binary_arith_slow;
  19911                     }
  19912                     if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op2))) {
  19913                         d2 = JS_VALUE_GET_FLOAT64(op2);
  19914                     } else if (JS_VALUE_GET_TAG(op2) == JS_TAG_INT) {
  19915                         d2 = JS_VALUE_GET_INT(op2);
  19916                     } else {
  19917                         goto binary_arith_slow;
  19918                     }
  19919                     d = d1 * d2;
  19920                 mul_fp_res:
  19921                     sp[-2] = __JS_NewFloat64(ctx, d);
  19922                     sp--;
  19923                 } else {
  19924                     goto binary_arith_slow;
  19925                 }
  19926             }
  19927             BREAK;
  19928         CASE(OP_div):
  19929             {
  19930                 JSValue op1, op2;
  19931                 op1 = sp[-2];
  19932                 op2 = sp[-1];
  19933                 if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
  19934                     int v1, v2;
  19935                     v1 = JS_VALUE_GET_INT(op1);
  19936                     v2 = JS_VALUE_GET_INT(op2);
  19937                     sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2);
  19938                     sp--;
  19939                 } else {
  19940                     goto binary_arith_slow;
  19941                 }
  19942             }
  19943             BREAK;
  19944         CASE(OP_mod):
  19945             {
  19946                 JSValue op1, op2;
  19947                 op1 = sp[-2];
  19948                 op2 = sp[-1];
  19949                 if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
  19950                     int v1, v2, r;
  19951                     v1 = JS_VALUE_GET_INT(op1);
  19952                     v2 = JS_VALUE_GET_INT(op2);
  19953                     /* We must avoid v2 = 0, v1 = INT32_MIN and v2 =
  19954                        -1 and the cases where the result is -0. */
  19955                     if (unlikely(v1 < 0 || v2 <= 0))
  19956                         goto binary_arith_slow;
  19957                     r = v1 % v2;
  19958                     sp[-2] = JS_NewInt32(ctx, r);
  19959                     sp--;
  19960                 } else {
  19961                     goto binary_arith_slow;
  19962                 }
  19963             }
  19964             BREAK;
  19965         CASE(OP_pow):
  19966         binary_arith_slow:
  19967             sf->cur_pc = pc;
  19968             if (js_binary_arith_slow(ctx, sp, opcode))
  19969                 goto exception;
  19970             sp--;
  19971             BREAK;
  19972 
  19973         CASE(OP_plus):
  19974             {
  19975                 JSValue op1;
  19976                 uint32_t tag;
  19977                 op1 = sp[-1];
  19978                 tag = JS_VALUE_GET_TAG(op1);
  19979                 if (tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag)) {
  19980                 } else if (tag == JS_TAG_NULL || tag == JS_TAG_BOOL) {
  19981                     sp[-1] = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1));
  19982                 } else {
  19983                     sf->cur_pc = pc;
  19984                     if (js_unary_arith_slow(ctx, sp, opcode))
  19985                         goto exception;
  19986                 }
  19987             }
  19988             BREAK;
  19989         CASE(OP_neg):
  19990             {
  19991                 JSValue op1;
  19992                 uint32_t tag;
  19993                 int val;
  19994                 double d;
  19995                 op1 = sp[-1];
  19996                 tag = JS_VALUE_GET_TAG(op1);
  19997                 if (tag == JS_TAG_INT ||
  19998                     tag == JS_TAG_BOOL ||
  19999                     tag == JS_TAG_NULL) {
  20000                     val = JS_VALUE_GET_INT(op1);
  20001                     /* Note: -0 cannot be expressed as integer */
  20002                     if (unlikely(val == 0)) {
  20003                         d = -0.0;
  20004                         goto neg_fp_res;
  20005                     }
  20006                     if (unlikely(val == INT32_MIN)) {
  20007                         d = -(double)val;
  20008                         goto neg_fp_res;
  20009                     }
  20010                     sp[-1] = JS_NewInt32(ctx, -val);
  20011                 } else if (JS_TAG_IS_FLOAT64(tag)) {
  20012                     d = -JS_VALUE_GET_FLOAT64(op1);
  20013                 neg_fp_res:
  20014                     sp[-1] = __JS_NewFloat64(ctx, d);
  20015                 } else {
  20016                     sf->cur_pc = pc;
  20017                     if (js_unary_arith_slow(ctx, sp, opcode))
  20018                         goto exception;
  20019                 }
  20020             }
  20021             BREAK;
  20022         CASE(OP_inc):
  20023             {
  20024                 JSValue op1;
  20025                 int val;
  20026                 op1 = sp[-1];
  20027                 if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
  20028                     val = JS_VALUE_GET_INT(op1);
  20029                     if (unlikely(val == INT32_MAX))
  20030                         goto inc_slow;
  20031                     sp[-1] = JS_NewInt32(ctx, val + 1);
  20032                 } else {
  20033                 inc_slow:
  20034                     sf->cur_pc = pc;
  20035                     if (js_unary_arith_slow(ctx, sp, opcode))
  20036                         goto exception;
  20037                 }
  20038             }
  20039             BREAK;
  20040         CASE(OP_dec):
  20041             {
  20042                 JSValue op1;
  20043                 int val;
  20044                 op1 = sp[-1];
  20045                 if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
  20046                     val = JS_VALUE_GET_INT(op1);
  20047                     if (unlikely(val == INT32_MIN))
  20048                         goto dec_slow;
  20049                     sp[-1] = JS_NewInt32(ctx, val - 1);
  20050                 } else {
  20051                 dec_slow:
  20052                     sf->cur_pc = pc;
  20053                     if (js_unary_arith_slow(ctx, sp, opcode))
  20054                         goto exception;
  20055                 }
  20056             }
  20057             BREAK;
  20058         CASE(OP_post_inc):
  20059             {
  20060                 JSValue op1;
  20061                 int val;
  20062                 op1 = sp[-1];
  20063                 if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
  20064                     val = JS_VALUE_GET_INT(op1);
  20065                     if (unlikely(val == INT32_MAX))
  20066                         goto post_inc_slow;
  20067                     sp[0] = JS_NewInt32(ctx, val + 1);
  20068                 } else {
  20069                 post_inc_slow:
  20070                     sf->cur_pc = pc;
  20071                     if (js_post_inc_slow(ctx, sp, opcode))
  20072                         goto exception;
  20073                 }
  20074                 sp++;
  20075             }
  20076             BREAK;
  20077         CASE(OP_post_dec):
  20078             {
  20079                 JSValue op1;
  20080                 int val;
  20081                 op1 = sp[-1];
  20082                 if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
  20083                     val = JS_VALUE_GET_INT(op1);
  20084                     if (unlikely(val == INT32_MIN))
  20085                         goto post_dec_slow;
  20086                     sp[0] = JS_NewInt32(ctx, val - 1);
  20087                 } else {
  20088                 post_dec_slow:
  20089                     sf->cur_pc = pc;
  20090                     if (js_post_inc_slow(ctx, sp, opcode))
  20091                         goto exception;
  20092                 }
  20093                 sp++;
  20094             }
  20095             BREAK;
  20096         CASE(OP_inc_loc):
  20097             {
  20098                 JSValue op1;
  20099                 int val;
  20100                 int idx;
  20101                 idx = *pc;
  20102                 pc += 1;
  20103 
  20104                 op1 = var_buf[idx];
  20105                 if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
  20106                     val = JS_VALUE_GET_INT(op1);
  20107                     if (unlikely(val == INT32_MAX))
  20108                         goto inc_loc_slow;
  20109                     var_buf[idx] = JS_NewInt32(ctx, val + 1);
  20110                 } else {
  20111                 inc_loc_slow:
  20112                     sf->cur_pc = pc;
  20113                     /* must duplicate otherwise the variable value may
  20114                        be destroyed before JS code accesses it */
  20115                     op1 = JS_DupValue(ctx, op1);
  20116                     if (js_unary_arith_slow(ctx, &op1 + 1, OP_inc))
  20117                         goto exception;
  20118                     set_value(ctx, &var_buf[idx], op1);
  20119                 }
  20120             }
  20121             BREAK;
  20122         CASE(OP_dec_loc):
  20123             {
  20124                 JSValue op1;
  20125                 int val;
  20126                 int idx;
  20127                 idx = *pc;
  20128                 pc += 1;
  20129 
  20130                 op1 = var_buf[idx];
  20131                 if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
  20132                     val = JS_VALUE_GET_INT(op1);
  20133                     if (unlikely(val == INT32_MIN))
  20134                         goto dec_loc_slow;
  20135                     var_buf[idx] = JS_NewInt32(ctx, val - 1);
  20136                 } else {
  20137                 dec_loc_slow:
  20138                     sf->cur_pc = pc;
  20139                     /* must duplicate otherwise the variable value may
  20140                        be destroyed before JS code accesses it */
  20141                     op1 = JS_DupValue(ctx, op1);
  20142                     if (js_unary_arith_slow(ctx, &op1 + 1, OP_dec))
  20143                         goto exception;
  20144                     set_value(ctx, &var_buf[idx], op1);
  20145                 }
  20146             }
  20147             BREAK;
  20148         CASE(OP_not):
  20149             {
  20150                 JSValue op1;
  20151                 op1 = sp[-1];
  20152                 if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
  20153                     sp[-1] = JS_NewInt32(ctx, ~JS_VALUE_GET_INT(op1));
  20154                 } else {
  20155                     sf->cur_pc = pc;
  20156                     if (js_not_slow(ctx, sp))
  20157                         goto exception;
  20158                 }
  20159             }
  20160             BREAK;
  20161 
  20162         CASE(OP_shl):
  20163             {
  20164                 JSValue op1, op2;
  20165                 op1 = sp[-2];
  20166                 op2 = sp[-1];
  20167                 if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
  20168                     uint32_t v1, v2;
  20169                     v1 = JS_VALUE_GET_INT(op1);
  20170                     v2 = JS_VALUE_GET_INT(op2);
  20171                     v2 &= 0x1f;
  20172                     sp[-2] = JS_NewInt32(ctx, v1 << v2);
  20173                     sp--;
  20174                 } else {
  20175                     sf->cur_pc = pc;
  20176                     if (js_binary_logic_slow(ctx, sp, opcode))
  20177                         goto exception;
  20178                     sp--;
  20179                 }
  20180             }
  20181             BREAK;
  20182         CASE(OP_shr):
  20183             {
  20184                 JSValue op1, op2;
  20185                 op1 = sp[-2];
  20186                 op2 = sp[-1];
  20187                 if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
  20188                     uint32_t v2;
  20189                     v2 = JS_VALUE_GET_INT(op2);
  20190                     v2 &= 0x1f;
  20191                     sp[-2] = JS_NewUint32(ctx,
  20192                                           (uint32_t)JS_VALUE_GET_INT(op1) >>
  20193                                           v2);
  20194                     sp--;
  20195                 } else {
  20196                     sf->cur_pc = pc;
  20197                     if (js_shr_slow(ctx, sp))
  20198                         goto exception;
  20199                     sp--;
  20200                 }
  20201             }
  20202             BREAK;
  20203         CASE(OP_sar):
  20204             {
  20205                 JSValue op1, op2;
  20206                 op1 = sp[-2];
  20207                 op2 = sp[-1];
  20208                 if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
  20209                     uint32_t v2;
  20210                     v2 = JS_VALUE_GET_INT(op2);
  20211                     v2 &= 0x1f;
  20212                     sp[-2] = JS_NewInt32(ctx,
  20213                                           (int)JS_VALUE_GET_INT(op1) >> v2);
  20214                     sp--;
  20215                 } else {
  20216                     sf->cur_pc = pc;
  20217                     if (js_binary_logic_slow(ctx, sp, opcode))
  20218                         goto exception;
  20219                     sp--;
  20220                 }
  20221             }
  20222             BREAK;
  20223         CASE(OP_and):
  20224             {
  20225                 JSValue op1, op2;
  20226                 op1 = sp[-2];
  20227                 op2 = sp[-1];
  20228                 if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
  20229                     sp[-2] = JS_NewInt32(ctx,
  20230                                          JS_VALUE_GET_INT(op1) &
  20231                                          JS_VALUE_GET_INT(op2));
  20232                     sp--;
  20233                 } else {
  20234                     sf->cur_pc = pc;
  20235                     if (js_binary_logic_slow(ctx, sp, opcode))
  20236                         goto exception;
  20237                     sp--;
  20238                 }
  20239             }
  20240             BREAK;
  20241         CASE(OP_or):
  20242             {
  20243                 JSValue op1, op2;
  20244                 op1 = sp[-2];
  20245                 op2 = sp[-1];
  20246                 if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
  20247                     sp[-2] = JS_NewInt32(ctx,
  20248                                          JS_VALUE_GET_INT(op1) |
  20249                                          JS_VALUE_GET_INT(op2));
  20250                     sp--;
  20251                 } else {
  20252                     sf->cur_pc = pc;
  20253                     if (js_binary_logic_slow(ctx, sp, opcode))
  20254                         goto exception;
  20255                     sp--;
  20256                 }
  20257             }
  20258             BREAK;
  20259         CASE(OP_xor):
  20260             {
  20261                 JSValue op1, op2;
  20262                 op1 = sp[-2];
  20263                 op2 = sp[-1];
  20264                 if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
  20265                     sp[-2] = JS_NewInt32(ctx,
  20266                                          JS_VALUE_GET_INT(op1) ^
  20267                                          JS_VALUE_GET_INT(op2));
  20268                     sp--;
  20269                 } else {
  20270                     sf->cur_pc = pc;
  20271                     if (js_binary_logic_slow(ctx, sp, opcode))
  20272                         goto exception;
  20273                     sp--;
  20274                 }
  20275             }
  20276             BREAK;
  20277 
  20278 
  20279 #define OP_CMP(opcode, binary_op, slow_call)              \
  20280             CASE(opcode):                                 \
  20281                 {                                         \
  20282                 JSValue op1, op2;                         \
  20283                 op1 = sp[-2];                             \
  20284                 op2 = sp[-1];                                   \
  20285                 if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {           \
  20286                     sp[-2] = JS_NewBool(ctx, JS_VALUE_GET_INT(op1) binary_op JS_VALUE_GET_INT(op2)); \
  20287                     sp--;                                               \
  20288                 } else {                                                \
  20289                     sf->cur_pc = pc;                                    \
  20290                     if (slow_call)                                      \
  20291                         goto exception;                                 \
  20292                     sp--;                                               \
  20293                 }                                                       \
  20294                 }                                                       \
  20295             BREAK
  20296 
  20297             OP_CMP(OP_lt, <, js_relational_slow(ctx, sp, opcode));
  20298             OP_CMP(OP_lte, <=, js_relational_slow(ctx, sp, opcode));
  20299             OP_CMP(OP_gt, >, js_relational_slow(ctx, sp, opcode));
  20300             OP_CMP(OP_gte, >=, js_relational_slow(ctx, sp, opcode));
  20301             OP_CMP(OP_eq, ==, js_eq_slow(ctx, sp, 0));
  20302             OP_CMP(OP_neq, !=, js_eq_slow(ctx, sp, 1));
  20303             OP_CMP(OP_strict_eq, ==, js_strict_eq_slow(ctx, sp, 0));
  20304             OP_CMP(OP_strict_neq, !=, js_strict_eq_slow(ctx, sp, 1));
  20305 
  20306         CASE(OP_in):
  20307             sf->cur_pc = pc;
  20308             if (js_operator_in(ctx, sp))
  20309                 goto exception;
  20310             sp--;
  20311             BREAK;
  20312         CASE(OP_private_in):
  20313             sf->cur_pc = pc;
  20314             if (js_operator_private_in(ctx, sp))
  20315                 goto exception;
  20316             sp--;
  20317             BREAK;
  20318         CASE(OP_instanceof):
  20319             sf->cur_pc = pc;
  20320             if (js_operator_instanceof(ctx, sp))
  20321                 goto exception;
  20322             sp--;
  20323             BREAK;
  20324         CASE(OP_typeof):
  20325             {
  20326                 JSValue op1;
  20327                 JSAtom atom;
  20328 
  20329                 op1 = sp[-1];
  20330                 atom = js_operator_typeof(ctx, op1);
  20331                 JS_FreeValue(ctx, op1);
  20332                 sp[-1] = JS_AtomToString(ctx, atom);
  20333             }
  20334             BREAK;
  20335         CASE(OP_delete):
  20336             sf->cur_pc = pc;
  20337             if (js_operator_delete(ctx, sp))
  20338                 goto exception;
  20339             sp--;
  20340             BREAK;
  20341         CASE(OP_delete_var):
  20342             {
  20343                 JSAtom atom;
  20344                 int ret;
  20345 
  20346                 atom = get_u32(pc);
  20347                 pc += 4;
  20348                 sf->cur_pc = pc;
  20349 
  20350                 ret = JS_DeleteGlobalVar(ctx, atom);
  20351                 if (unlikely(ret < 0))
  20352                     goto exception;
  20353                 *sp++ = JS_NewBool(ctx, ret);
  20354             }
  20355             BREAK;
  20356 
  20357         CASE(OP_to_object):
  20358             if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_OBJECT) {
  20359                 sf->cur_pc = pc;
  20360                 ret_val = JS_ToObject(ctx, sp[-1]);
  20361                 if (JS_IsException(ret_val))
  20362                     goto exception;
  20363                 JS_FreeValue(ctx, sp[-1]);
  20364                 sp[-1] = ret_val;
  20365             }
  20366             BREAK;
  20367 
  20368         CASE(OP_to_propkey):
  20369             switch (JS_VALUE_GET_TAG(sp[-1])) {
  20370             case JS_TAG_INT:
  20371             case JS_TAG_STRING:
  20372             case JS_TAG_SYMBOL:
  20373                 break;
  20374             default:
  20375                 sf->cur_pc = pc;
  20376                 ret_val = JS_ToPropertyKey(ctx, sp[-1]);
  20377                 if (JS_IsException(ret_val))
  20378                     goto exception;
  20379                 JS_FreeValue(ctx, sp[-1]);
  20380                 sp[-1] = ret_val;
  20381                 break;
  20382             }
  20383             BREAK;
  20384 
  20385 #if 0
  20386         CASE(OP_to_string):
  20387             if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_STRING) {
  20388                 ret_val = JS_ToString(ctx, sp[-1]);
  20389                 if (JS_IsException(ret_val))
  20390                     goto exception;
  20391                 JS_FreeValue(ctx, sp[-1]);
  20392                 sp[-1] = ret_val;
  20393             }
  20394             BREAK;
  20395 #endif
  20396         CASE(OP_with_get_var):
  20397         CASE(OP_with_put_var):
  20398         CASE(OP_with_delete_var):
  20399         CASE(OP_with_make_ref):
  20400         CASE(OP_with_get_ref):
  20401             {
  20402                 JSAtom atom;
  20403                 int32_t diff;
  20404                 JSValue obj, val;
  20405                 int ret, is_with;
  20406                 atom = get_u32(pc);
  20407                 diff = get_u32(pc + 4);
  20408                 is_with = pc[8];
  20409                 pc += 9;
  20410                 sf->cur_pc = pc;
  20411 
  20412                 obj = sp[-1];
  20413                 ret = JS_HasProperty(ctx, obj, atom);
  20414                 if (unlikely(ret < 0))
  20415                     goto exception;
  20416                 if (ret) {
  20417                     if (is_with) {
  20418                         ret = js_has_unscopable(ctx, obj, atom);
  20419                         if (unlikely(ret < 0))
  20420                             goto exception;
  20421                         if (ret)
  20422                             goto no_with;
  20423                     }
  20424                     switch (opcode) {
  20425                     case OP_with_get_var:
  20426                         /* in Object Environment Records, GetBindingValue() calls HasProperty() */
  20427                         ret = JS_HasProperty(ctx, obj, atom);
  20428                         if (unlikely(ret <= 0)) {
  20429                             if (ret < 0)
  20430                                 goto exception;
  20431                             if (is_strict_mode(ctx)) {
  20432                                 JS_ThrowReferenceErrorNotDefined(ctx, atom);
  20433                                 goto exception;
  20434                             } 
  20435                             val = JS_UNDEFINED;
  20436                         } else {
  20437                             val = JS_GetProperty(ctx, obj, atom);
  20438                             if (unlikely(JS_IsException(val)))
  20439                                 goto exception;
  20440                         }
  20441                         set_value(ctx, &sp[-1], val);
  20442                         break;
  20443                     case OP_with_put_var: /* used e.g. in for in/of */
  20444                         /* in Object Environment Records, SetMutableBinding() calls HasProperty() */
  20445                         ret = JS_HasProperty(ctx, obj, atom);
  20446                         if (unlikely(ret <= 0)) {
  20447                             if (ret < 0)
  20448                                 goto exception;
  20449                             if (is_strict_mode(ctx)) {
  20450                                 JS_ThrowReferenceErrorNotDefined(ctx, atom);
  20451                                 goto exception;
  20452                             } 
  20453                         }
  20454                         ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2], obj,
  20455                                                      JS_PROP_THROW_STRICT);
  20456                         JS_FreeValue(ctx, sp[-1]);
  20457                         sp -= 2;
  20458                         if (unlikely(ret < 0))
  20459                             goto exception;
  20460                         break;
  20461                     case OP_with_delete_var:
  20462                         ret = JS_DeleteProperty(ctx, obj, atom, 0);
  20463                         if (unlikely(ret < 0))
  20464                             goto exception;
  20465                         JS_FreeValue(ctx, sp[-1]);
  20466                         sp[-1] = JS_NewBool(ctx, ret);
  20467                         break;
  20468                     case OP_with_make_ref:
  20469                         /* produce a pair object/propname on the stack */
  20470                         *sp++ = JS_AtomToValue(ctx, atom);
  20471                         break;
  20472                     case OP_with_get_ref:
  20473                         /* produce a pair object/method on the stack */
  20474                         /* in Object Environment Records, GetBindingValue() calls HasProperty() */
  20475                         ret = JS_HasProperty(ctx, obj, atom);
  20476                         if (unlikely(ret < 0))
  20477                             goto exception;
  20478                         if (!ret) {
  20479                             val = JS_UNDEFINED;
  20480                         } else {
  20481                             val = JS_GetProperty(ctx, obj, atom);
  20482                             if (unlikely(JS_IsException(val)))
  20483                                 goto exception;
  20484                         }
  20485                         *sp++ = val;
  20486                         break;
  20487                     }
  20488                     pc += diff - 5;
  20489                 } else {
  20490                 no_with:
  20491                     /* if not jumping, drop the object argument */
  20492                     JS_FreeValue(ctx, sp[-1]);
  20493                     sp--;
  20494                 }
  20495             }
  20496             BREAK;
  20497 
  20498         CASE(OP_await):
  20499             ret_val = JS_NewInt32(ctx, FUNC_RET_AWAIT);
  20500             goto done_generator;
  20501         CASE(OP_yield):
  20502             ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD);
  20503             goto done_generator;
  20504         CASE(OP_yield_star):
  20505         CASE(OP_async_yield_star):
  20506             ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD_STAR);
  20507             goto done_generator;
  20508         CASE(OP_return_async):
  20509             ret_val = JS_UNDEFINED;
  20510             goto done_generator;
  20511         CASE(OP_initial_yield):
  20512             ret_val = JS_NewInt32(ctx, FUNC_RET_INITIAL_YIELD);
  20513             goto done_generator;
  20514 
  20515         CASE(OP_nop):
  20516             BREAK;
  20517         CASE(OP_is_undefined_or_null):
  20518             if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED ||
  20519                 JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) {
  20520                 goto set_true;
  20521             } else {
  20522                 goto free_and_set_false;
  20523             }
  20524 #if SHORT_OPCODES
  20525         CASE(OP_is_undefined):
  20526             if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED) {
  20527                 goto set_true;
  20528             } else {
  20529                 goto free_and_set_false;
  20530             }
  20531         CASE(OP_is_null):
  20532             if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) {
  20533                 goto set_true;
  20534             } else {
  20535                 goto free_and_set_false;
  20536             }
  20537             /* XXX: could merge to a single opcode */
  20538         CASE(OP_typeof_is_undefined):
  20539             /* different from OP_is_undefined because of isHTMLDDA */
  20540             if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_undefined) {
  20541                 goto free_and_set_true;
  20542             } else {
  20543                 goto free_and_set_false;
  20544             }
  20545         CASE(OP_typeof_is_function):
  20546             if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_function) {
  20547                 goto free_and_set_true;
  20548             } else {
  20549                 goto free_and_set_false;
  20550             }
  20551         free_and_set_true:
  20552             JS_FreeValue(ctx, sp[-1]);
  20553 #endif
  20554         set_true:
  20555             sp[-1] = JS_TRUE;
  20556             BREAK;
  20557         free_and_set_false:
  20558             JS_FreeValue(ctx, sp[-1]);
  20559             sp[-1] = JS_FALSE;
  20560             BREAK;
  20561         CASE(OP_invalid):
  20562         DEFAULT:
  20563             JS_ThrowInternalError(ctx, "invalid opcode: pc=%u opcode=0x%02x",
  20564                                   (int)(pc - b->byte_code_buf - 1), opcode);
  20565             goto exception;
  20566         }
  20567     }
  20568  exception:
  20569     if (is_backtrace_needed(ctx, rt->current_exception)) {
  20570         /* add the backtrace information now (it is not done
  20571            before if the exception happens in a bytecode
  20572            operation */
  20573         sf->cur_pc = pc;
  20574         build_backtrace(ctx, rt->current_exception, NULL, 0, 0, 0);
  20575     }
  20576     if (!rt->current_exception_is_uncatchable) {
  20577         while (sp > stack_buf) {
  20578             JSValue val = *--sp;
  20579             JS_FreeValue(ctx, val);
  20580             if (JS_VALUE_GET_TAG(val) == JS_TAG_CATCH_OFFSET) {
  20581                 int pos = JS_VALUE_GET_INT(val);
  20582                 if (pos == 0) {
  20583                     /* enumerator: close it with a throw */
  20584                     JS_FreeValue(ctx, sp[-1]); /* drop the next method */
  20585                     sp--;
  20586                     JS_IteratorClose(ctx, sp[-1], TRUE);
  20587                 } else {
  20588                     *sp++ = rt->current_exception;
  20589                     rt->current_exception = JS_UNINITIALIZED;
  20590                     pc = b->byte_code_buf + pos;
  20591                     goto restart;
  20592                 }
  20593             }
  20594         }
  20595     }
  20596     ret_val = JS_EXCEPTION;
  20597     /* the local variables are freed by the caller in the generator
  20598        case. Hence the label 'done' should never be reached in a
  20599        generator function. */
  20600     if (b->func_kind != JS_FUNC_NORMAL) {
  20601     done_generator:
  20602         sf->cur_pc = pc;
  20603         sf->cur_sp = sp;
  20604     } else {
  20605     done:
  20606         if (unlikely(b->var_ref_count != 0)) {
  20607             /* variable references reference the stack: must close them */
  20608             close_var_refs(rt, b, sf);
  20609         }
  20610         /* free the local variables and stack */
  20611         for(pval = local_buf; pval < sp; pval++) {
  20612             JS_FreeValue(ctx, *pval);
  20613         }
  20614     }
  20615     rt->current_stack_frame = sf->prev_frame;
  20616     return ret_val;
  20617 }
  20618 
  20619 #ifdef PERF_TRAMPOLINE
  20620 
  20621 #include <sys/mman.h>
  20622 #include <fcntl.h>
  20623 #include <unistd.h>
  20624 
  20625 static FILE *
  20626 perf_map_get_file(void)
  20627 {
  20628     static FILE *perf_map_file = NULL;
  20629     if (perf_map_file) {
  20630         return perf_map_file;
  20631     }
  20632     char filename[100];
  20633     pid_t pid = getpid();
  20634     // Location and file name of perf map is hard-coded in perf tool.
  20635     // Use exclusive create flag wit nofollow to prevent symlink attacks.
  20636     int flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC;
  20637     snprintf(filename, sizeof(filename) - 1, "/tmp/perf-%jd.map",
  20638              (intmax_t)pid);
  20639     int fd = open(filename, flags, 0600);
  20640     if (fd == -1) {
  20641         return NULL;
  20642     }
  20643     perf_map_file = fdopen(fd, "w");
  20644     if (!perf_map_file) {
  20645         close(fd);
  20646         return NULL;
  20647     }
  20648     return perf_map_file;
  20649 }
  20650 
  20651 static void
  20652 perf_map_write_entry(JSContext *ctx, const void *code_addr, unsigned int code_size, JSFunctionBytecode *b)
  20653 {
  20654     FILE *method_file = perf_map_get_file();
  20655     const char *atom_entry = NULL;
  20656     const char *atom_filename = NULL;
  20657     const char *filename = NULL;
  20658     int line = 0;
  20659     if (b->has_debug) {
  20660       int col;
  20661       line = find_line_num(ctx, b, -1, &col);
  20662     }
  20663     if (b->func_name != JS_ATOM_NULL) {
  20664       atom_entry = JS_AtomToCString(ctx, b->func_name);
  20665     }
  20666     if (b->has_debug && b->debug.filename != JS_ATOM_NULL) {
  20667       atom_filename = JS_AtomToCString(ctx, b->debug.filename);
  20668     }
  20669     if (NULL == atom_filename) {
  20670       filename = "<unknown>";
  20671     } else {
  20672       filename = atom_filename;
  20673     }
  20674     if (NULL == atom_entry) {
  20675       fprintf(method_file, "%p %x js@%s:%u\n", code_addr, code_size, filename, line);
  20676     } else {
  20677       fprintf(method_file, "%p %x js::%s@%s:%u\n", code_addr, code_size, atom_entry, filename, line);
  20678     }
  20679     fflush(method_file);
  20680     JS_FreeCString(ctx, atom_entry);
  20681     JS_FreeCString(ctx, atom_filename);
  20682 }
  20683 
  20684 typedef struct {
  20685   JSContext *caller_ctx;
  20686   JSValueConst func_obj;
  20687   JSValueConst this_obj;
  20688   JSValueConst new_target;
  20689   int argc;
  20690   JSValue *argv;
  20691   int flags;
  20692 } CallInternalArgs;
  20693 
  20694 typedef JSValue CallFn(CallInternalArgs *args);
  20695 typedef JSValue TrampolineFn(CallInternalArgs *args, CallFn fn);
  20696 
  20697 /**
  20698  * For x86-64:
  20699  * push %rbp; mov %rsp,%rbp; call *%rsi; pop %rbp; ret;
  20700 */
  20701 char perf_trampoline_code[] = {0x55, 0x48, 0x89, 0xe5, 0xff, 0xd6, 0x5d, 0xc3};
  20702 
  20703 void *compile_trampoline()
  20704 {
  20705   size_t mem_size = 4096 * 16;
  20706   char *memory =
  20707         mmap(NULL,  // address
  20708              mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
  20709              -1,  // fd (not used here)
  20710              0);  // offset (not used here)
  20711   memcpy(memory, perf_trampoline_code, 8);
  20712   mprotect(memory, mem_size, PROT_READ | PROT_EXEC);
  20713   return memory;
  20714 }
  20715 
  20716 static JSValue fallback_trampoline(CallInternalArgs *ci_args, CallFn fn)
  20717 {
  20718   JSValue value;
  20719   value = fn(ci_args);
  20720   return value;
  20721 }
  20722 
  20723 static JSValue JS_CallInternalStruct(CallInternalArgs *ci_args)
  20724 {
  20725     return __JS_CallInternal(ci_args->caller_ctx, ci_args->func_obj,
  20726                            ci_args->this_obj, ci_args->new_target,
  20727                            ci_args->argc, ci_args->argv, ci_args->flags);
  20728 }
  20729 
  20730 static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
  20731                                JSValueConst this_obj, JSValueConst new_target,
  20732                                int argc, JSValue *argv, int flags)
  20733 {
  20734     CallInternalArgs ci_args;
  20735     JSObject *p;
  20736     JSFunctionBytecode *b = NULL;
  20737 
  20738     ci_args.caller_ctx = caller_ctx;
  20739     ci_args.func_obj = func_obj;
  20740     ci_args.this_obj = this_obj;
  20741     ci_args.new_target = new_target;
  20742     ci_args.argc = argc;
  20743     ci_args.argv = argv;
  20744     ci_args.flags = flags;
  20745 
  20746     if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)) {
  20747         if (flags & JS_CALL_FLAG_GENERATOR) {
  20748             JSAsyncFunctionState *s = JS_VALUE_GET_PTR(func_obj);
  20749             JSStackFrame *sf;
  20750             /* func_obj get contains a pointer to JSFuncAsyncState */
  20751             /* the stack frame is already allocated */
  20752             sf = &s->frame;
  20753             p = JS_VALUE_GET_OBJ(sf->cur_func);
  20754             b = p->u.func.function_bytecode;
  20755         }
  20756     } else {
  20757       p = JS_VALUE_GET_OBJ(func_obj);
  20758       if (p->class_id == JS_CLASS_BYTECODE_FUNCTION) {
  20759         b = p->u.func.function_bytecode;
  20760       }
  20761     }
  20762 
  20763     if (b) {
  20764       TrampolineFn *fn;
  20765       if (!b->perf_trampoline) {
  20766         b->perf_trampoline = compile_trampoline();
  20767         if (b->perf_trampoline) {
  20768           perf_map_write_entry(caller_ctx, b->perf_trampoline, 8, b);
  20769         }
  20770       }
  20771       fn = b->perf_trampoline;
  20772       if (fn) {
  20773         return fn(&ci_args, JS_CallInternalStruct);
  20774       }
  20775     }
  20776 
  20777     return fallback_trampoline(&ci_args, JS_CallInternalStruct);
  20778     //return __JS_CallInternal(caller_ctx, func_obj, this_obj, new_target, argc, argv, flags);
  20779 }
  20780 
  20781 #else
  20782 
  20783 static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
  20784                                JSValueConst this_obj, JSValueConst new_target,
  20785                                int argc, JSValue *argv, int flags)
  20786 {
  20787   return __JS_CallInternal(caller_ctx, func_obj, this_obj, new_target, argc, argv, flags);
  20788 }
  20789 
  20790 #endif /* PERF_TRAMPOLINE */
  20791 
  20792 #ifdef OPCODE_ASM_LABEL
  20793 #pragma GCC diagnostic pop
  20794 #endif
  20795 
  20796 JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj,
  20797                 int argc, JSValueConst *argv)
  20798 {
  20799     return JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED,
  20800                            argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV);
  20801 }
  20802 
  20803 static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj,
  20804                            int argc, JSValueConst *argv)
  20805 {
  20806     JSValue res = JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED,
  20807                                   argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV);
  20808     JS_FreeValue(ctx, func_obj);
  20809     return res;
  20810 }
  20811 
  20812 /* warning: the refcount of the context is not incremented. Return
  20813    NULL in case of exception (case of revoked proxy only) */
  20814 static JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValueConst func_obj)
  20815 {
  20816     JSObject *p;
  20817     JSContext *realm;
  20818 
  20819     if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
  20820         return ctx;
  20821     p = JS_VALUE_GET_OBJ(func_obj);
  20822     switch(p->class_id) {
  20823     case JS_CLASS_C_FUNCTION:
  20824         realm = p->u.cfunc.realm;
  20825         break;
  20826     case JS_CLASS_BYTECODE_FUNCTION:
  20827     case JS_CLASS_GENERATOR_FUNCTION:
  20828     case JS_CLASS_ASYNC_FUNCTION:
  20829     case JS_CLASS_ASYNC_GENERATOR_FUNCTION:
  20830         {
  20831             JSFunctionBytecode *b;
  20832             b = p->u.func.function_bytecode;
  20833             realm = b->realm;
  20834         }
  20835         break;
  20836     case JS_CLASS_PROXY:
  20837         {
  20838             JSProxyData *s = p->u.opaque;
  20839             if (!s)
  20840                 return ctx;
  20841             if (s->is_revoked) {
  20842                 JS_ThrowTypeErrorRevokedProxy(ctx);
  20843                 return NULL;
  20844             } else {
  20845                 realm = JS_GetFunctionRealm(ctx, s->target);
  20846             }
  20847         }
  20848         break;
  20849     case JS_CLASS_BOUND_FUNCTION:
  20850         {
  20851             JSBoundFunction *bf = p->u.bound_function;
  20852             realm = JS_GetFunctionRealm(ctx, bf->func_obj);
  20853         }
  20854         break;
  20855     default:
  20856         realm = ctx;
  20857         break;
  20858     }
  20859     return realm;
  20860 }
  20861 
  20862 static JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor,
  20863                                    int class_id)
  20864 {
  20865     JSValue proto, obj;
  20866     JSContext *realm;
  20867 
  20868     if (JS_IsUndefined(ctor)) {
  20869         proto = JS_DupValue(ctx, ctx->class_proto[class_id]);
  20870     } else {
  20871         proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);
  20872         if (JS_IsException(proto))
  20873             return proto;
  20874         if (!JS_IsObject(proto)) {
  20875             JS_FreeValue(ctx, proto);
  20876             realm = JS_GetFunctionRealm(ctx, ctor);
  20877             if (!realm)
  20878                 return JS_EXCEPTION;
  20879             proto = JS_DupValue(ctx, realm->class_proto[class_id]);
  20880         }
  20881     }
  20882     obj = JS_NewObjectProtoClass(ctx, proto, class_id);
  20883     JS_FreeValue(ctx, proto);
  20884     return obj;
  20885 }
  20886 
  20887 /* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */
  20888 static JSValue JS_CallConstructorInternal(JSContext *ctx,
  20889                                           JSValueConst func_obj,
  20890                                           JSValueConst new_target,
  20891                                           int argc, JSValue *argv, int flags)
  20892 {
  20893     JSObject *p;
  20894     JSFunctionBytecode *b;
  20895 
  20896     if (js_poll_interrupts(ctx))
  20897         return JS_EXCEPTION;
  20898     flags |= JS_CALL_FLAG_CONSTRUCTOR;
  20899     if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT))
  20900         goto not_a_function;
  20901     p = JS_VALUE_GET_OBJ(func_obj);
  20902     if (unlikely(!p->is_constructor))
  20903         return JS_ThrowTypeErrorNotAConstructor(ctx, func_obj);
  20904     if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {
  20905         JSClassCall *call_func;
  20906         call_func = ctx->rt->class_array[p->class_id].call;
  20907         if (!call_func) {
  20908         not_a_function:
  20909             return JS_ThrowTypeError(ctx, "not a function");
  20910         }
  20911         return call_func(ctx, func_obj, new_target, argc,
  20912                          (JSValueConst *)argv, flags);
  20913     }
  20914 
  20915     b = p->u.func.function_bytecode;
  20916     if (b->is_derived_class_constructor) {
  20917         return JS_CallInternal(ctx, func_obj, JS_UNDEFINED, new_target, argc, argv, flags);
  20918     } else {
  20919         JSValue obj, ret;
  20920         /* legacy constructor behavior */
  20921         obj = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
  20922         if (JS_IsException(obj))
  20923             return JS_EXCEPTION;
  20924         ret = JS_CallInternal(ctx, func_obj, obj, new_target, argc, argv, flags);
  20925         if (JS_VALUE_GET_TAG(ret) == JS_TAG_OBJECT ||
  20926             JS_IsException(ret)) {
  20927             JS_FreeValue(ctx, obj);
  20928             return ret;
  20929         } else {
  20930             JS_FreeValue(ctx, ret);
  20931             return obj;
  20932         }
  20933     }
  20934 }
  20935 
  20936 JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj,
  20937                             JSValueConst new_target,
  20938                             int argc, JSValueConst *argv)
  20939 {
  20940     return JS_CallConstructorInternal(ctx, func_obj, new_target,
  20941                                       argc, (JSValue *)argv,
  20942                                       JS_CALL_FLAG_COPY_ARGV);
  20943 }
  20944 
  20945 JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj,
  20946                            int argc, JSValueConst *argv)
  20947 {
  20948     return JS_CallConstructorInternal(ctx, func_obj, func_obj,
  20949                                       argc, (JSValue *)argv,
  20950                                       JS_CALL_FLAG_COPY_ARGV);
  20951 }
  20952 
  20953 JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom,
  20954                   int argc, JSValueConst *argv)
  20955 {
  20956     JSValue func_obj;
  20957     func_obj = JS_GetProperty(ctx, this_val, atom);
  20958     if (JS_IsException(func_obj))
  20959         return func_obj;
  20960     return JS_CallFree(ctx, func_obj, this_val, argc, argv);
  20961 }
  20962 
  20963 static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
  20964                              int argc, JSValueConst *argv)
  20965 {
  20966     JSValue res = JS_Invoke(ctx, this_val, atom, argc, argv);
  20967     JS_FreeValue(ctx, this_val);
  20968     return res;
  20969 }
  20970 
  20971 /* JSAsyncFunctionState (used by generator and async functions) */
  20972 static JSAsyncFunctionState *async_func_init(JSContext *ctx,
  20973                                              JSValueConst func_obj, JSValueConst this_obj,
  20974                                              int argc, JSValueConst *argv)
  20975 {
  20976     JSAsyncFunctionState *s;
  20977     JSObject *p;
  20978     JSFunctionBytecode *b;
  20979     JSStackFrame *sf;
  20980     int i, arg_buf_len, n;
  20981 
  20982     p = JS_VALUE_GET_OBJ(func_obj);
  20983     b = p->u.func.function_bytecode;
  20984     arg_buf_len = max_int(b->arg_count, argc);
  20985     s = js_malloc(ctx, sizeof(*s) + sizeof(JSValue) * (arg_buf_len + b->var_count + b->stack_size) + sizeof(JSVarRef *) * b->var_ref_count);
  20986     if (!s)
  20987         return NULL;
  20988     memset(s, 0, sizeof(*s));
  20989     js_rc(s)->ref_count = 1;
  20990     add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION);
  20991 
  20992     sf = &s->frame;
  20993     sf->js_mode = b->js_mode | JS_MODE_ASYNC;
  20994     sf->cur_pc = b->byte_code_buf;
  20995     sf->arg_buf = (JSValue *)(s + 1);
  20996     sf->cur_func = JS_DupValue(ctx, func_obj);
  20997     s->this_val = JS_DupValue(ctx, this_obj);
  20998     s->argc = argc;
  20999     sf->arg_count = arg_buf_len;
  21000     sf->var_buf = sf->arg_buf + arg_buf_len;
  21001     sf->cur_sp = sf->var_buf + b->var_count;
  21002     sf->var_refs = (JSVarRef **)(sf->cur_sp + b->stack_size);
  21003     for(i = 0; i < b->var_ref_count; i++)
  21004         sf->var_refs[i] = NULL;
  21005     for(i = 0; i < argc; i++)
  21006         sf->arg_buf[i] = JS_DupValue(ctx, argv[i]);
  21007     n = arg_buf_len + b->var_count;
  21008     for(i = argc; i < n; i++)
  21009         sf->arg_buf[i] = JS_UNDEFINED;
  21010     s->resolving_funcs[0] = JS_UNDEFINED;
  21011     s->resolving_funcs[1] = JS_UNDEFINED;
  21012     s->is_completed = FALSE;
  21013     return s;
  21014 }
  21015 
  21016 static void async_func_free_frame(JSRuntime *rt, JSAsyncFunctionState *s)
  21017 {
  21018     JSStackFrame *sf = &s->frame;
  21019     JSValue *sp;
  21020 
  21021     /* cannot free the function if it is running */
  21022     assert(sf->cur_sp != NULL);
  21023     for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) {
  21024         JS_FreeValueRT(rt, *sp);
  21025     }
  21026     JS_FreeValueRT(rt, sf->cur_func);
  21027     JS_FreeValueRT(rt, s->this_val);
  21028 }
  21029 
  21030 static JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s)
  21031 {
  21032     JSRuntime *rt = ctx->rt;
  21033     JSStackFrame *sf = &s->frame;
  21034     JSValue func_obj, ret;
  21035 
  21036     assert(!s->is_completed);
  21037     if (js_check_stack_overflow(ctx->rt, 0)) {
  21038         ret = JS_ThrowStackOverflow(ctx);
  21039     } else {
  21040         /* the tag does not matter provided it is not an object */
  21041         func_obj = JS_MKPTR(JS_TAG_INT, s);
  21042         ret = JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED,
  21043                               s->argc, sf->arg_buf, JS_CALL_FLAG_GENERATOR);
  21044     }
  21045     if (JS_IsException(ret) || JS_IsUndefined(ret)) {
  21046         JSObject *p;
  21047         JSFunctionBytecode *b;
  21048         
  21049         p = JS_VALUE_GET_OBJ(sf->cur_func);
  21050         b = p->u.func.function_bytecode;
  21051         
  21052         if (JS_IsUndefined(ret)) {
  21053             ret = sf->cur_sp[-1];
  21054             sf->cur_sp[-1] = JS_UNDEFINED;
  21055         }
  21056         /* end of execution */
  21057         s->is_completed = TRUE;
  21058 
  21059         /* close the closure variables. */
  21060         close_var_refs(rt, b, sf);
  21061         
  21062         async_func_free_frame(rt, s);
  21063     }
  21064     return ret;
  21065 }
  21066 
  21067 static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
  21068 {
  21069     /* cannot close the closure variables here because it would
  21070        potentially modify the object graph */
  21071     if (!s->is_completed) {
  21072         async_func_free_frame(rt, s);
  21073     }
  21074 
  21075     JS_FreeValueRT(rt, s->resolving_funcs[0]);
  21076     JS_FreeValueRT(rt, s->resolving_funcs[1]);
  21077 
  21078     remove_gc_object(&s->header);
  21079     if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && js_rc(s)->ref_count != 0) {
  21080         list_add_tail(&s->header.link, &rt->gc_zero_ref_count_list);
  21081     } else {
  21082         js_free_rt(rt, s);
  21083     }
  21084 }
  21085 
  21086 static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
  21087 {
  21088     if (--js_rc(s)->ref_count == 0) {
  21089         if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {
  21090             list_del(&s->header.link);
  21091             list_add(&s->header.link, &rt->gc_zero_ref_count_list);
  21092             if (rt->gc_phase == JS_GC_PHASE_NONE) {
  21093                 free_zero_refcount(rt);
  21094             }
  21095         }
  21096     }
  21097 }
  21098 
  21099 /* Generators */
  21100 
  21101 typedef enum JSGeneratorStateEnum {
  21102     JS_GENERATOR_STATE_SUSPENDED_START,
  21103     JS_GENERATOR_STATE_SUSPENDED_YIELD,
  21104     JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR,
  21105     JS_GENERATOR_STATE_EXECUTING,
  21106     JS_GENERATOR_STATE_COMPLETED,
  21107 } JSGeneratorStateEnum;
  21108 
  21109 typedef struct JSGeneratorData {
  21110     JSGeneratorStateEnum state;
  21111     JSAsyncFunctionState *func_state;
  21112 } JSGeneratorData;
  21113 
  21114 static void free_generator_stack_rt(JSRuntime *rt, JSGeneratorData *s)
  21115 {
  21116     if (s->state == JS_GENERATOR_STATE_COMPLETED)
  21117         return;
  21118     if (s->func_state) {
  21119         async_func_free(rt, s->func_state);
  21120         s->func_state = NULL;
  21121     }
  21122     s->state = JS_GENERATOR_STATE_COMPLETED;
  21123 }
  21124 
  21125 static void js_generator_finalizer(JSRuntime *rt, JSValue obj)
  21126 {
  21127     JSGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_GENERATOR);
  21128 
  21129     if (s) {
  21130         free_generator_stack_rt(rt, s);
  21131         js_free_rt(rt, s);
  21132     }
  21133 }
  21134 
  21135 static void free_generator_stack(JSContext *ctx, JSGeneratorData *s)
  21136 {
  21137     free_generator_stack_rt(ctx->rt, s);
  21138 }
  21139 
  21140 static void js_generator_mark(JSRuntime *rt, JSValueConst val,
  21141                               JS_MarkFunc *mark_func)
  21142 {
  21143     JSObject *p = JS_VALUE_GET_OBJ(val);
  21144     JSGeneratorData *s = p->u.generator_data;
  21145 
  21146     if (!s || !s->func_state)
  21147         return;
  21148     mark_func(rt, &s->func_state->header);
  21149 }
  21150 
  21151 /* XXX: use enum */
  21152 #define GEN_MAGIC_NEXT   0
  21153 #define GEN_MAGIC_RETURN 1
  21154 #define GEN_MAGIC_THROW  2
  21155 
  21156 static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
  21157                                  int argc, JSValueConst *argv,
  21158                                  BOOL *pdone, int magic)
  21159 {
  21160     JSGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_GENERATOR);
  21161     JSStackFrame *sf;
  21162     JSValue ret, func_ret;
  21163 
  21164     *pdone = TRUE;
  21165     if (!s)
  21166         return JS_ThrowTypeError(ctx, "not a generator");
  21167     switch(s->state) {
  21168     default:
  21169     case JS_GENERATOR_STATE_SUSPENDED_START:
  21170         sf = &s->func_state->frame;
  21171         if (magic == GEN_MAGIC_NEXT) {
  21172             goto exec_no_arg;
  21173         } else {
  21174             free_generator_stack(ctx, s);
  21175             goto done;
  21176         }
  21177         break;
  21178     case JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
  21179     case JS_GENERATOR_STATE_SUSPENDED_YIELD:
  21180         sf = &s->func_state->frame;
  21181         /* cur_sp[-1] was set to JS_UNDEFINED in the previous call */
  21182         ret = JS_DupValue(ctx, argv[0]);
  21183         if (magic == GEN_MAGIC_THROW &&
  21184             s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) {
  21185             JS_Throw(ctx, ret);
  21186             s->func_state->throw_flag = TRUE;
  21187         } else {
  21188             sf->cur_sp[-1] = ret;
  21189             sf->cur_sp[0] = JS_NewInt32(ctx, magic);
  21190             sf->cur_sp++;
  21191         exec_no_arg:
  21192             s->func_state->throw_flag = FALSE;
  21193         }
  21194         s->state = JS_GENERATOR_STATE_EXECUTING;
  21195         func_ret = async_func_resume(ctx, s->func_state);
  21196         s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD;
  21197         if (s->func_state->is_completed) {
  21198             /* finalize the execution in case of exception or normal return */
  21199             free_generator_stack(ctx, s);
  21200             return func_ret;
  21201         } else {
  21202             assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT);
  21203             /* get the returned yield value at the top of the stack */
  21204             ret = sf->cur_sp[-1];
  21205             sf->cur_sp[-1] = JS_UNDEFINED;
  21206             if (JS_VALUE_GET_INT(func_ret) == FUNC_RET_YIELD_STAR) {
  21207                 s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
  21208                 /* return (value, done) object */
  21209                 *pdone = 2;
  21210             } else {
  21211                 *pdone = FALSE;
  21212             }
  21213         }
  21214         break;
  21215     case JS_GENERATOR_STATE_COMPLETED:
  21216     done:
  21217         /* execution is finished */
  21218         switch(magic) {
  21219         default:
  21220         case GEN_MAGIC_NEXT:
  21221             ret = JS_UNDEFINED;
  21222             break;
  21223         case GEN_MAGIC_RETURN:
  21224             ret = JS_DupValue(ctx, argv[0]);
  21225             break;
  21226         case GEN_MAGIC_THROW:
  21227             ret = JS_Throw(ctx, JS_DupValue(ctx, argv[0]));
  21228             break;
  21229         }
  21230         break;
  21231     case JS_GENERATOR_STATE_EXECUTING:
  21232         ret = JS_ThrowTypeError(ctx, "cannot invoke a running generator");
  21233         break;
  21234     }
  21235     return ret;
  21236 }
  21237 
  21238 static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
  21239                                           JSValueConst this_obj,
  21240                                           int argc, JSValueConst *argv,
  21241                                           int flags)
  21242 {
  21243     JSValue obj, func_ret;
  21244     JSGeneratorData *s;
  21245 
  21246     s = js_mallocz(ctx, sizeof(*s));
  21247     if (!s)
  21248         return JS_EXCEPTION;
  21249     s->state = JS_GENERATOR_STATE_SUSPENDED_START;
  21250     s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv);
  21251     if (!s->func_state) {
  21252         s->state = JS_GENERATOR_STATE_COMPLETED;
  21253         goto fail;
  21254     }
  21255 
  21256     /* execute the function up to 'OP_initial_yield' */
  21257     func_ret = async_func_resume(ctx, s->func_state);
  21258     if (JS_IsException(func_ret))
  21259         goto fail;
  21260     JS_FreeValue(ctx, func_ret);
  21261 
  21262     obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_GENERATOR);
  21263     if (JS_IsException(obj))
  21264         goto fail;
  21265     JS_SetOpaque(obj, s);
  21266     return obj;
  21267  fail:
  21268     free_generator_stack_rt(ctx->rt, s);
  21269     js_free(ctx, s);
  21270     return JS_EXCEPTION;
  21271 }
  21272 
  21273 /* AsyncFunction */
  21274 
  21275 static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val)
  21276 {
  21277     JSObject *p = JS_VALUE_GET_OBJ(val);
  21278     JSAsyncFunctionState *s = p->u.async_function_data;
  21279     if (s) {
  21280         async_func_free(rt, s);
  21281     }
  21282 }
  21283 
  21284 static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,
  21285                                            JS_MarkFunc *mark_func)
  21286 {
  21287     JSObject *p = JS_VALUE_GET_OBJ(val);
  21288     JSAsyncFunctionState *s = p->u.async_function_data;
  21289     if (s) {
  21290         mark_func(rt, &s->header);
  21291     }
  21292 }
  21293 
  21294 static int js_async_function_resolve_create(JSContext *ctx,
  21295                                             JSAsyncFunctionState *s,
  21296                                             JSValue *resolving_funcs)
  21297 {
  21298     int i;
  21299     JSObject *p;
  21300 
  21301     for(i = 0; i < 2; i++) {
  21302         resolving_funcs[i] =
  21303             JS_NewObjectProtoClass(ctx, ctx->function_proto,
  21304                                    JS_CLASS_ASYNC_FUNCTION_RESOLVE + i);
  21305         if (JS_IsException(resolving_funcs[i])) {
  21306             if (i == 1)
  21307                 JS_FreeValue(ctx, resolving_funcs[0]);
  21308             return -1;
  21309         }
  21310         p = JS_VALUE_GET_OBJ(resolving_funcs[i]);
  21311         js_rc(s)->ref_count++;
  21312         p->u.async_function_data = s;
  21313     }
  21314     return 0;
  21315 }
  21316 
  21317 static void js_async_function_resume(JSContext *ctx, JSAsyncFunctionState *s)
  21318 {
  21319     JSValue func_ret, ret2;
  21320 
  21321     func_ret = async_func_resume(ctx, s);
  21322     if (s->is_completed) {
  21323         if (JS_IsException(func_ret)) {
  21324             JSValue error;
  21325         fail:
  21326             error = JS_GetException(ctx);
  21327             ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED,
  21328                            1, (JSValueConst *)&error);
  21329             JS_FreeValue(ctx, error);
  21330             JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
  21331         } else {
  21332             /* normal return */
  21333             ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED,
  21334                            1, (JSValueConst *)&func_ret);
  21335             JS_FreeValue(ctx, func_ret);
  21336             JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
  21337         }
  21338     } else {
  21339         JSValue value, promise, resolving_funcs[2], resolving_funcs1[2];
  21340         int i, res;
  21341 
  21342         value = s->frame.cur_sp[-1];
  21343         s->frame.cur_sp[-1] = JS_UNDEFINED;
  21344 
  21345         /* await */
  21346         JS_FreeValue(ctx, func_ret); /* not used */
  21347         promise = js_promise_resolve(ctx, ctx->promise_ctor,
  21348                                      1, (JSValueConst *)&value, 0);
  21349         JS_FreeValue(ctx, value);
  21350         if (JS_IsException(promise))
  21351             goto fail;
  21352         if (js_async_function_resolve_create(ctx, s, resolving_funcs)) {
  21353             JS_FreeValue(ctx, promise);
  21354             goto fail;
  21355         }
  21356 
  21357         /* Note: no need to create 'thrownawayCapability' as in
  21358            the spec */
  21359         for(i = 0; i < 2; i++)
  21360             resolving_funcs1[i] = JS_UNDEFINED;
  21361         res = perform_promise_then(ctx, promise,
  21362                                    (JSValueConst *)resolving_funcs,
  21363                                    (JSValueConst *)resolving_funcs1);
  21364         JS_FreeValue(ctx, promise);
  21365         for(i = 0; i < 2; i++)
  21366             JS_FreeValue(ctx, resolving_funcs[i]);
  21367         if (res)
  21368             goto fail;
  21369     }
  21370 }
  21371 
  21372 static JSValue js_async_function_resolve_call(JSContext *ctx,
  21373                                               JSValueConst func_obj,
  21374                                               JSValueConst this_obj,
  21375                                               int argc, JSValueConst *argv,
  21376                                               int flags)
  21377 {
  21378     JSObject *p = JS_VALUE_GET_OBJ(func_obj);
  21379     JSAsyncFunctionState *s = p->u.async_function_data;
  21380     BOOL is_reject = p->class_id - JS_CLASS_ASYNC_FUNCTION_RESOLVE;
  21381     JSValueConst arg;
  21382 
  21383     if (argc > 0)
  21384         arg = argv[0];
  21385     else
  21386         arg = JS_UNDEFINED;
  21387     s->throw_flag = is_reject;
  21388     if (is_reject) {
  21389         JS_Throw(ctx, JS_DupValue(ctx, arg));
  21390     } else {
  21391         /* return value of await */
  21392         s->frame.cur_sp[-1] = JS_DupValue(ctx, arg);
  21393     }
  21394     js_async_function_resume(ctx, s);
  21395     return JS_UNDEFINED;
  21396 }
  21397 
  21398 static JSValue js_async_function_call(JSContext *ctx, JSValueConst func_obj,
  21399                                       JSValueConst this_obj,
  21400                                       int argc, JSValueConst *argv, int flags)
  21401 {
  21402     JSValue promise;
  21403     JSAsyncFunctionState *s;
  21404 
  21405     s = async_func_init(ctx, func_obj, this_obj, argc, argv);
  21406     if (!s)
  21407         return JS_EXCEPTION;
  21408 
  21409     promise = JS_NewPromiseCapability(ctx, s->resolving_funcs);
  21410     if (JS_IsException(promise)) {
  21411         async_func_free(ctx->rt, s);
  21412         return JS_EXCEPTION;
  21413     }
  21414 
  21415     js_async_function_resume(ctx, s);
  21416 
  21417     async_func_free(ctx->rt, s);
  21418 
  21419     return promise;
  21420 }
  21421 
  21422 /* AsyncGenerator */
  21423 
  21424 typedef enum JSAsyncGeneratorStateEnum {
  21425     JS_ASYNC_GENERATOR_STATE_SUSPENDED_START,
  21426     JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD,
  21427     JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR,
  21428     JS_ASYNC_GENERATOR_STATE_EXECUTING,
  21429     JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN,
  21430     JS_ASYNC_GENERATOR_STATE_COMPLETED,
  21431 } JSAsyncGeneratorStateEnum;
  21432 
  21433 typedef struct JSAsyncGeneratorRequest {
  21434     struct list_head link;
  21435     /* completion */
  21436     int completion_type; /* GEN_MAGIC_x */
  21437     JSValue result;
  21438     /* promise capability */
  21439     JSValue promise;
  21440     JSValue resolving_funcs[2];
  21441 } JSAsyncGeneratorRequest;
  21442 
  21443 typedef struct JSAsyncGeneratorData {
  21444     JSObject *generator; /* back pointer to the object (const) */
  21445     JSAsyncGeneratorStateEnum state;
  21446     /* func_state is NULL is state AWAITING_RETURN and COMPLETED */
  21447     JSAsyncFunctionState *func_state;
  21448     struct list_head queue; /* list of JSAsyncGeneratorRequest.link */
  21449 } JSAsyncGeneratorData;
  21450 
  21451 static void js_async_generator_free(JSRuntime *rt,
  21452                                     JSAsyncGeneratorData *s)
  21453 {
  21454     struct list_head *el, *el1;
  21455     JSAsyncGeneratorRequest *req;
  21456 
  21457     list_for_each_safe(el, el1, &s->queue) {
  21458         req = list_entry(el, JSAsyncGeneratorRequest, link);
  21459         JS_FreeValueRT(rt, req->result);
  21460         JS_FreeValueRT(rt, req->promise);
  21461         JS_FreeValueRT(rt, req->resolving_funcs[0]);
  21462         JS_FreeValueRT(rt, req->resolving_funcs[1]);
  21463         js_free_rt(rt, req);
  21464     }
  21465     if (s->func_state)
  21466         async_func_free(rt, s->func_state);
  21467     js_free_rt(rt, s);
  21468 }
  21469 
  21470 static void js_async_generator_finalizer(JSRuntime *rt, JSValue obj)
  21471 {
  21472     JSAsyncGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_ASYNC_GENERATOR);
  21473 
  21474     if (s) {
  21475         js_async_generator_free(rt, s);
  21476     }
  21477 }
  21478 
  21479 static void js_async_generator_mark(JSRuntime *rt, JSValueConst val,
  21480                                     JS_MarkFunc *mark_func)
  21481 {
  21482     JSAsyncGeneratorData *s = JS_GetOpaque(val, JS_CLASS_ASYNC_GENERATOR);
  21483     struct list_head *el;
  21484     JSAsyncGeneratorRequest *req;
  21485     if (s) {
  21486         list_for_each(el, &s->queue) {
  21487             req = list_entry(el, JSAsyncGeneratorRequest, link);
  21488             JS_MarkValue(rt, req->result, mark_func);
  21489             JS_MarkValue(rt, req->promise, mark_func);
  21490             JS_MarkValue(rt, req->resolving_funcs[0], mark_func);
  21491             JS_MarkValue(rt, req->resolving_funcs[1], mark_func);
  21492         }
  21493         if (s->func_state) {
  21494             mark_func(rt, &s->func_state->header);
  21495         }
  21496     }
  21497 }
  21498 
  21499 static JSValue js_async_generator_resolve_function(JSContext *ctx,
  21500                                           JSValueConst this_obj,
  21501                                           int argc, JSValueConst *argv,
  21502                                           int magic, JSValue *func_data);
  21503 
  21504 static int js_async_generator_resolve_function_create(JSContext *ctx,
  21505                                                       JSValueConst generator,
  21506                                                       JSValue *resolving_funcs,
  21507                                                       BOOL is_resume_next)
  21508 {
  21509     int i;
  21510     JSValue func;
  21511 
  21512     for(i = 0; i < 2; i++) {
  21513         func = JS_NewCFunctionData(ctx, js_async_generator_resolve_function, 1,
  21514                                    i + is_resume_next * 2, 1, &generator);
  21515         if (JS_IsException(func)) {
  21516             if (i == 1)
  21517                 JS_FreeValue(ctx, resolving_funcs[0]);
  21518             return -1;
  21519         }
  21520         resolving_funcs[i] = func;
  21521     }
  21522     return 0;
  21523 }
  21524 
  21525 static int js_async_generator_await(JSContext *ctx,
  21526                                     JSAsyncGeneratorData *s,
  21527                                     JSValueConst value)
  21528 {
  21529     JSValue promise, resolving_funcs[2], resolving_funcs1[2];
  21530     int i, res;
  21531 
  21532     promise = js_promise_resolve(ctx, ctx->promise_ctor,
  21533                                  1, &value, 0);
  21534     if (JS_IsException(promise))
  21535         goto fail;
  21536 
  21537     if (js_async_generator_resolve_function_create(ctx, JS_MKPTR(JS_TAG_OBJECT, s->generator),
  21538                                                    resolving_funcs, FALSE)) {
  21539         JS_FreeValue(ctx, promise);
  21540         goto fail;
  21541     }
  21542 
  21543     /* Note: no need to create 'thrownawayCapability' as in
  21544        the spec */
  21545     for(i = 0; i < 2; i++)
  21546         resolving_funcs1[i] = JS_UNDEFINED;
  21547     res = perform_promise_then(ctx, promise,
  21548                                (JSValueConst *)resolving_funcs,
  21549                                (JSValueConst *)resolving_funcs1);
  21550     JS_FreeValue(ctx, promise);
  21551     for(i = 0; i < 2; i++)
  21552         JS_FreeValue(ctx, resolving_funcs[i]);
  21553     if (res)
  21554         goto fail;
  21555     return 0;
  21556  fail:
  21557     return -1;
  21558 }
  21559 
  21560 static void js_async_generator_resolve_or_reject(JSContext *ctx,
  21561                                                  JSAsyncGeneratorData *s,
  21562                                                  JSValueConst result,
  21563                                                  int is_reject)
  21564 {
  21565     JSAsyncGeneratorRequest *next;
  21566     JSValue ret;
  21567 
  21568     next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link);
  21569     list_del(&next->link);
  21570     ret = JS_Call(ctx, next->resolving_funcs[is_reject], JS_UNDEFINED, 1,
  21571                   &result);
  21572     JS_FreeValue(ctx, ret);
  21573     JS_FreeValue(ctx, next->result);
  21574     JS_FreeValue(ctx, next->promise);
  21575     JS_FreeValue(ctx, next->resolving_funcs[0]);
  21576     JS_FreeValue(ctx, next->resolving_funcs[1]);
  21577     js_free(ctx, next);
  21578 }
  21579 
  21580 static void js_async_generator_resolve(JSContext *ctx,
  21581                                        JSAsyncGeneratorData *s,
  21582                                        JSValueConst value,
  21583                                        BOOL done)
  21584 {
  21585     JSValue result;
  21586     result = js_create_iterator_result(ctx, JS_DupValue(ctx, value), done);
  21587     /* XXX: better exception handling ? */
  21588     js_async_generator_resolve_or_reject(ctx, s, result, 0);
  21589     JS_FreeValue(ctx, result);
  21590  }
  21591 
  21592 static void js_async_generator_reject(JSContext *ctx,
  21593                                        JSAsyncGeneratorData *s,
  21594                                        JSValueConst exception)
  21595 {
  21596     js_async_generator_resolve_or_reject(ctx, s, exception, 1);
  21597 }
  21598 
  21599 static void js_async_generator_complete(JSContext *ctx,
  21600                                         JSAsyncGeneratorData *s)
  21601 {
  21602     if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED) {
  21603         s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
  21604         async_func_free(ctx->rt, s->func_state);
  21605         s->func_state = NULL;
  21606     }
  21607 }
  21608 
  21609 static int js_async_generator_completed_return(JSContext *ctx,
  21610                                                JSAsyncGeneratorData *s,
  21611                                                JSValueConst value)
  21612 {
  21613     JSValue promise, resolving_funcs[2], resolving_funcs1[2];
  21614     int res;
  21615 
  21616     // Can fail looking up JS_ATOM_constructor when is_reject==0.
  21617     promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, &value,
  21618                                  /*is_reject*/0);
  21619     // A poisoned .constructor property is observable and the resulting
  21620     // exception should be delivered to the catch handler.
  21621     if (JS_IsException(promise)) {
  21622         JSValue err = JS_GetException(ctx);
  21623         promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, (JSValueConst *)&err,
  21624                                      /*is_reject*/1);
  21625         JS_FreeValue(ctx, err);
  21626         if (JS_IsException(promise))
  21627             return -1;
  21628     }
  21629     if (js_async_generator_resolve_function_create(ctx,
  21630                                                    JS_MKPTR(JS_TAG_OBJECT, s->generator),
  21631                                                    resolving_funcs1,
  21632                                                    TRUE)) {
  21633         JS_FreeValue(ctx, promise);
  21634         return -1;
  21635     }
  21636     resolving_funcs[0] = JS_UNDEFINED;
  21637     resolving_funcs[1] = JS_UNDEFINED;
  21638     res = perform_promise_then(ctx, promise,
  21639                                (JSValueConst *)resolving_funcs1,
  21640                                (JSValueConst *)resolving_funcs);
  21641     JS_FreeValue(ctx, resolving_funcs1[0]);
  21642     JS_FreeValue(ctx, resolving_funcs1[1]);
  21643     JS_FreeValue(ctx, promise);
  21644     return res;
  21645 }
  21646 
  21647 static void js_async_generator_resume_next(JSContext *ctx,
  21648                                            JSAsyncGeneratorData *s)
  21649 {
  21650     JSAsyncGeneratorRequest *next;
  21651     JSValue func_ret, value;
  21652 
  21653     for(;;) {
  21654         if (list_empty(&s->queue))
  21655             break;
  21656         next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link);
  21657         switch(s->state) {
  21658         case JS_ASYNC_GENERATOR_STATE_EXECUTING:
  21659             /* only happens when restarting execution after await() */
  21660             goto resume_exec;
  21661         case JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN:
  21662             goto done;
  21663         case JS_ASYNC_GENERATOR_STATE_SUSPENDED_START:
  21664             if (next->completion_type == GEN_MAGIC_NEXT) {
  21665                 goto exec_no_arg;
  21666             } else {
  21667                 js_async_generator_complete(ctx, s);
  21668             }
  21669             break;
  21670         case JS_ASYNC_GENERATOR_STATE_COMPLETED:
  21671             if (next->completion_type == GEN_MAGIC_NEXT) {
  21672                 js_async_generator_resolve(ctx, s, JS_UNDEFINED, TRUE);
  21673             } else if (next->completion_type == GEN_MAGIC_RETURN) {
  21674                 s->state = JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN;
  21675                 js_async_generator_completed_return(ctx, s, next->result);
  21676             } else {
  21677                 js_async_generator_reject(ctx, s, next->result);
  21678             }
  21679             goto done;
  21680         case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD:
  21681         case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
  21682             value = JS_DupValue(ctx, next->result);
  21683             if (next->completion_type == GEN_MAGIC_THROW &&
  21684                 s->state == JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD) {
  21685                 JS_Throw(ctx, value);
  21686                 s->func_state->throw_flag = TRUE;
  21687             } else {
  21688                 /* 'yield' returns a value. 'yield *' also returns a value
  21689                    in case the 'throw' method is called */
  21690                 s->func_state->frame.cur_sp[-1] = value;
  21691                 s->func_state->frame.cur_sp[0] =
  21692                     JS_NewInt32(ctx, next->completion_type);
  21693                 s->func_state->frame.cur_sp++;
  21694             exec_no_arg:
  21695                 s->func_state->throw_flag = FALSE;
  21696             }
  21697             s->state = JS_ASYNC_GENERATOR_STATE_EXECUTING;
  21698         resume_exec:
  21699             func_ret = async_func_resume(ctx, s->func_state);
  21700             if (s->func_state->is_completed) {
  21701                 if (JS_IsException(func_ret)) {
  21702                     value = JS_GetException(ctx);
  21703                     js_async_generator_complete(ctx, s);
  21704                     js_async_generator_reject(ctx, s, value);
  21705                     JS_FreeValue(ctx, value);
  21706                 } else {
  21707                     /* end of function */
  21708                     js_async_generator_complete(ctx, s);
  21709                     js_async_generator_resolve(ctx, s, func_ret, TRUE);
  21710                     JS_FreeValue(ctx, func_ret);
  21711                 }
  21712             } else {
  21713                 int func_ret_code, ret;
  21714                 assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT);
  21715                 func_ret_code = JS_VALUE_GET_INT(func_ret);
  21716                 value = s->func_state->frame.cur_sp[-1];
  21717                 s->func_state->frame.cur_sp[-1] = JS_UNDEFINED;
  21718                 switch(func_ret_code) {
  21719                 case FUNC_RET_YIELD:
  21720                 case FUNC_RET_YIELD_STAR:
  21721                     if (func_ret_code == FUNC_RET_YIELD_STAR)
  21722                         s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
  21723                     else
  21724                         s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD;
  21725                     js_async_generator_resolve(ctx, s, value, FALSE);
  21726                     JS_FreeValue(ctx, value);
  21727                     break;
  21728                 case FUNC_RET_AWAIT:
  21729                     ret = js_async_generator_await(ctx, s, value);
  21730                     JS_FreeValue(ctx, value);
  21731                     if (ret < 0) {
  21732                         /* exception: throw it */
  21733                         s->func_state->throw_flag = TRUE;
  21734                         goto resume_exec;
  21735                     }
  21736                     goto done;
  21737                 default:
  21738                     abort();
  21739                 }
  21740             }
  21741             break;
  21742         default:
  21743             abort();
  21744         }
  21745     }
  21746  done: ;
  21747 }
  21748 
  21749 static JSValue js_async_generator_resolve_function(JSContext *ctx,
  21750                                                    JSValueConst this_obj,
  21751                                                    int argc, JSValueConst *argv,
  21752                                                    int magic, JSValue *func_data)
  21753 {
  21754     BOOL is_reject = magic & 1;
  21755     JSAsyncGeneratorData *s = JS_GetOpaque(func_data[0], JS_CLASS_ASYNC_GENERATOR);
  21756     JSValueConst arg = argv[0];
  21757 
  21758     /* XXX: what if s == NULL */
  21759 
  21760     if (magic >= 2) {
  21761         /* resume next case in AWAITING_RETURN state */
  21762         assert(s->state == JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN ||
  21763                s->state == JS_ASYNC_GENERATOR_STATE_COMPLETED);
  21764         s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
  21765         if (is_reject) {
  21766             js_async_generator_reject(ctx, s, arg);
  21767         } else {
  21768             js_async_generator_resolve(ctx, s, arg, TRUE);
  21769         }
  21770     } else if (s->state == JS_ASYNC_GENERATOR_STATE_EXECUTING) {
  21771         /* restart function execution after await() */
  21772         s->func_state->throw_flag = is_reject;
  21773         if (is_reject) {
  21774             JS_Throw(ctx, JS_DupValue(ctx, arg));
  21775         } else {
  21776             /* return value of await */
  21777             s->func_state->frame.cur_sp[-1] = JS_DupValue(ctx, arg);
  21778         }
  21779         js_async_generator_resume_next(ctx, s);
  21780     }
  21781     return JS_UNDEFINED;
  21782 }
  21783 
  21784 /* magic = GEN_MAGIC_x */
  21785 static JSValue js_async_generator_next(JSContext *ctx, JSValueConst this_val,
  21786                                        int argc, JSValueConst *argv,
  21787                                        int magic)
  21788 {
  21789     JSAsyncGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_GENERATOR);
  21790     JSValue promise, resolving_funcs[2];
  21791     JSAsyncGeneratorRequest *req;
  21792 
  21793     promise = JS_NewPromiseCapability(ctx, resolving_funcs);
  21794     if (JS_IsException(promise))
  21795         return JS_EXCEPTION;
  21796     if (!s) {
  21797         JSValue err, res2;
  21798         JS_ThrowTypeError(ctx, "not an AsyncGenerator object");
  21799         err = JS_GetException(ctx);
  21800         res2 = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
  21801                        1, (JSValueConst *)&err);
  21802         JS_FreeValue(ctx, err);
  21803         JS_FreeValue(ctx, res2);
  21804         JS_FreeValue(ctx, resolving_funcs[0]);
  21805         JS_FreeValue(ctx, resolving_funcs[1]);
  21806         return promise;
  21807     }
  21808     req = js_mallocz(ctx, sizeof(*req));
  21809     if (!req)
  21810         goto fail;
  21811     req->completion_type = magic;
  21812     req->result = JS_DupValue(ctx, argv[0]);
  21813     req->promise = JS_DupValue(ctx, promise);
  21814     req->resolving_funcs[0] = resolving_funcs[0];
  21815     req->resolving_funcs[1] = resolving_funcs[1];
  21816     list_add_tail(&req->link, &s->queue);
  21817     if (s->state != JS_ASYNC_GENERATOR_STATE_EXECUTING) {
  21818         js_async_generator_resume_next(ctx, s);
  21819     }
  21820     return promise;
  21821  fail:
  21822     JS_FreeValue(ctx, resolving_funcs[0]);
  21823     JS_FreeValue(ctx, resolving_funcs[1]);
  21824     JS_FreeValue(ctx, promise);
  21825     return JS_EXCEPTION;
  21826 }
  21827 
  21828 static JSValue js_async_generator_function_call(JSContext *ctx, JSValueConst func_obj,
  21829                                                 JSValueConst this_obj,
  21830                                                 int argc, JSValueConst *argv,
  21831                                                 int flags)
  21832 {
  21833     JSValue obj, func_ret;
  21834     JSAsyncGeneratorData *s;
  21835 
  21836     s = js_mallocz(ctx, sizeof(*s));
  21837     if (!s)
  21838         return JS_EXCEPTION;
  21839     s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_START;
  21840     init_list_head(&s->queue);
  21841     s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv);
  21842     if (!s->func_state)
  21843         goto fail;
  21844     /* execute the function up to 'OP_initial_yield' (no yield nor
  21845        await are possible) */
  21846     func_ret = async_func_resume(ctx, s->func_state);
  21847     if (JS_IsException(func_ret))
  21848         goto fail;
  21849     JS_FreeValue(ctx, func_ret);
  21850 
  21851     obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_ASYNC_GENERATOR);
  21852     if (JS_IsException(obj))
  21853         goto fail;
  21854     s->generator = JS_VALUE_GET_OBJ(obj);
  21855     JS_SetOpaque(obj, s);
  21856     return obj;
  21857  fail:
  21858     js_async_generator_free(ctx->rt, s);
  21859     return JS_EXCEPTION;
  21860 }
  21861 
  21862 /* JS parser */
  21863 
  21864 enum {
  21865     TOK_NUMBER = -128,
  21866     TOK_STRING,
  21867     TOK_TEMPLATE,
  21868     TOK_IDENT,
  21869     TOK_REGEXP,
  21870     /* warning: order matters (see js_parse_assign_expr) */
  21871     TOK_MUL_ASSIGN,
  21872     TOK_DIV_ASSIGN,
  21873     TOK_MOD_ASSIGN,
  21874     TOK_PLUS_ASSIGN,
  21875     TOK_MINUS_ASSIGN,
  21876     TOK_SHL_ASSIGN,
  21877     TOK_SAR_ASSIGN,
  21878     TOK_SHR_ASSIGN,
  21879     TOK_AND_ASSIGN,
  21880     TOK_XOR_ASSIGN,
  21881     TOK_OR_ASSIGN,
  21882     TOK_POW_ASSIGN,
  21883     TOK_LAND_ASSIGN,
  21884     TOK_LOR_ASSIGN,
  21885     TOK_DOUBLE_QUESTION_MARK_ASSIGN,
  21886     TOK_DEC,
  21887     TOK_INC,
  21888     TOK_SHL,
  21889     TOK_SAR,
  21890     TOK_SHR,
  21891     TOK_LT,
  21892     TOK_LTE,
  21893     TOK_GT,
  21894     TOK_GTE,
  21895     TOK_EQ,
  21896     TOK_STRICT_EQ,
  21897     TOK_NEQ,
  21898     TOK_STRICT_NEQ,
  21899     TOK_LAND,
  21900     TOK_LOR,
  21901     TOK_POW,
  21902     TOK_ARROW,
  21903     TOK_ELLIPSIS,
  21904     TOK_DOUBLE_QUESTION_MARK,
  21905     TOK_QUESTION_MARK_DOT,
  21906     TOK_ERROR,
  21907     TOK_PRIVATE_NAME,
  21908     TOK_EOF,
  21909     /* keywords: WARNING: same order as atoms */
  21910     TOK_NULL, /* must be first */
  21911     TOK_FALSE,
  21912     TOK_TRUE,
  21913     TOK_IF,
  21914     TOK_ELSE,
  21915     TOK_RETURN,
  21916     TOK_VAR,
  21917     TOK_THIS,
  21918     TOK_DELETE,
  21919     TOK_VOID,
  21920     TOK_TYPEOF,
  21921     TOK_NEW,
  21922     TOK_IN,
  21923     TOK_INSTANCEOF,
  21924     TOK_DO,
  21925     TOK_WHILE,
  21926     TOK_FOR,
  21927     TOK_BREAK,
  21928     TOK_CONTINUE,
  21929     TOK_SWITCH,
  21930     TOK_CASE,
  21931     TOK_DEFAULT,
  21932     TOK_THROW,
  21933     TOK_TRY,
  21934     TOK_CATCH,
  21935     TOK_FINALLY,
  21936     TOK_FUNCTION,
  21937     TOK_DEBUGGER,
  21938     TOK_WITH,
  21939     /* FutureReservedWord */
  21940     TOK_CLASS,
  21941     TOK_CONST,
  21942     TOK_ENUM,
  21943     TOK_EXPORT,
  21944     TOK_EXTENDS,
  21945     TOK_IMPORT,
  21946     TOK_SUPER,
  21947     /* FutureReservedWords when parsing strict mode code */
  21948     TOK_IMPLEMENTS,
  21949     TOK_INTERFACE,
  21950     TOK_LET,
  21951     TOK_PACKAGE,
  21952     TOK_PRIVATE,
  21953     TOK_PROTECTED,
  21954     TOK_PUBLIC,
  21955     TOK_STATIC,
  21956     TOK_YIELD,
  21957     TOK_AWAIT, /* must be last */
  21958     TOK_OF,     /* only used for js_parse_skip_parens_token() */
  21959 };
  21960 
  21961 #define TOK_FIRST_KEYWORD   TOK_NULL
  21962 #define TOK_LAST_KEYWORD    TOK_AWAIT
  21963 
  21964 /* unicode code points */
  21965 #define CP_NBSP 0x00a0
  21966 #define CP_BOM  0xfeff
  21967 
  21968 #define CP_LS   0x2028
  21969 #define CP_PS   0x2029
  21970 
  21971 typedef struct BlockEnv {
  21972     struct BlockEnv *prev;
  21973     JSAtom label_name; /* JS_ATOM_NULL if none */
  21974     int label_break; /* -1 if none */
  21975     int label_cont; /* -1 if none */
  21976     int drop_count; /* number of stack elements to drop */
  21977     int label_finally; /* -1 if none */
  21978     int scope_level;
  21979     uint8_t has_iterator : 1;
  21980     uint8_t is_regular_stmt : 1; /* i.e. not a loop statement */
  21981 } BlockEnv;
  21982 
  21983 typedef struct JSGlobalVar {
  21984     int cpool_idx; /* if >= 0, index in the constant pool for hoisted
  21985                       function defintion*/
  21986     uint8_t force_init : 1; /* force initialization to undefined */
  21987     uint8_t is_lexical : 1; /* global let/const definition */
  21988     uint8_t is_const   : 1; /* const definition */
  21989     int scope_level;    /* scope of definition */
  21990     JSAtom var_name;  /* variable name */
  21991 } JSGlobalVar;
  21992 
  21993 typedef struct RelocEntry {
  21994     struct RelocEntry *next;
  21995     uint32_t addr; /* address to patch */
  21996     int size;   /* address size: 1, 2 or 4 bytes */
  21997 } RelocEntry;
  21998 
  21999 typedef struct JumpSlot {
  22000     int op;
  22001     int size;
  22002     int pos;
  22003     int label;
  22004 } JumpSlot;
  22005 
  22006 typedef struct LabelSlot {
  22007     int ref_count;
  22008     int pos;    /* phase 1 address, -1 means not resolved yet */
  22009     int pos2;   /* phase 2 address, -1 means not resolved yet */
  22010     int addr;   /* phase 3 address, -1 means not resolved yet */
  22011     RelocEntry *first_reloc;
  22012 } LabelSlot;
  22013 
  22014 typedef struct LineNumberSlot {
  22015     uint32_t pc;
  22016     uint32_t source_pos;
  22017 } LineNumberSlot;
  22018 
  22019 typedef struct {
  22020     /* last source position */
  22021     const uint8_t *ptr;
  22022     int line_num;
  22023     int col_num;
  22024     const uint8_t *buf_start;
  22025 } GetLineColCache;
  22026 
  22027 typedef enum JSParseFunctionEnum {
  22028     JS_PARSE_FUNC_STATEMENT,
  22029     JS_PARSE_FUNC_VAR,
  22030     JS_PARSE_FUNC_EXPR,
  22031     JS_PARSE_FUNC_ARROW,
  22032     JS_PARSE_FUNC_GETTER,
  22033     JS_PARSE_FUNC_SETTER,
  22034     JS_PARSE_FUNC_METHOD,
  22035     JS_PARSE_FUNC_CLASS_STATIC_INIT,
  22036     JS_PARSE_FUNC_CLASS_CONSTRUCTOR,
  22037     JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR,
  22038 } JSParseFunctionEnum;
  22039 
  22040 typedef enum JSParseExportEnum {
  22041     JS_PARSE_EXPORT_NONE,
  22042     JS_PARSE_EXPORT_NAMED,
  22043     JS_PARSE_EXPORT_DEFAULT,
  22044 } JSParseExportEnum;
  22045 
  22046 typedef struct JSVarScope {
  22047     int parent;  /* index into fd->scopes of the enclosing scope */
  22048     int first;   /* index into fd->vars of the last variable in this scope */
  22049 } JSVarScope;
  22050 
  22051 typedef struct JSVarDef {
  22052     JSAtom var_name;
  22053     /* index into fd->scopes of this variable lexical scope */
  22054     int scope_level;
  22055     /* - if scope_level = 0: scope in which the variable is defined
  22056        - if scope_level != 0: index into fd->vars of the next
  22057        variable in the same or enclosing lexical scope
  22058     */
  22059     int scope_next;
  22060     uint8_t is_const : 1;
  22061     uint8_t is_lexical : 1;
  22062     uint8_t is_captured : 1; /* XXX: could remove and use a var_ref_idx value */
  22063     uint8_t is_static_private : 1; /* only used during private class field parsing */
  22064     uint8_t var_kind : 4; /* see JSVarKindEnum */
  22065     /* if is_captured = TRUE, provides, the index of the corresponding
  22066        JSVarRef on stack */
  22067     uint16_t var_ref_idx;
  22068     /* function pool index for lexical variables with var_kind =
  22069        JS_VAR_FUNCTION_DECL/JS_VAR_NEW_FUNCTION_DECL or scope level of
  22070        the definition of the 'var' variables (they have scope_level =
  22071        0) */
  22072     int func_pool_idx;
  22073 } JSVarDef;
  22074 
  22075 typedef struct JSFunctionDef {
  22076     JSContext *ctx;
  22077     struct JSFunctionDef *parent;
  22078     int parent_cpool_idx; /* index in the constant pool of the parent
  22079                              or -1 if none */
  22080     int parent_scope_level; /* scope level in parent at point of definition */
  22081     struct list_head child_list; /* list of JSFunctionDef.link */
  22082     struct list_head link;
  22083 
  22084     BOOL is_eval; /* TRUE if eval code */
  22085     int eval_type; /* only valid if is_eval = TRUE */
  22086     BOOL is_global_var; /* TRUE if variables are not defined locally:
  22087                            eval global, eval module or non strict eval */
  22088     BOOL is_func_expr; /* TRUE if function expression */
  22089     BOOL has_home_object; /* TRUE if the home object is available */
  22090     BOOL has_prototype; /* true if a prototype field is necessary */
  22091     BOOL has_simple_parameter_list;
  22092     BOOL has_parameter_expressions; /* if true, an argument scope is created */
  22093     BOOL has_use_strict; /* to reject directive in special cases */
  22094     BOOL has_eval_call; /* true if the function contains a call to eval() */
  22095     BOOL has_arguments_binding; /* true if the 'arguments' binding is
  22096                                    available in the function */
  22097     BOOL has_this_binding; /* true if the 'this' and new.target binding are
  22098                               available in the function */
  22099     BOOL new_target_allowed; /* true if the 'new.target' does not
  22100                                 throw a syntax error */
  22101     BOOL super_call_allowed; /* true if super() is allowed */
  22102     BOOL super_allowed; /* true if super. or super[] is allowed */
  22103     BOOL arguments_allowed; /* true if the 'arguments' identifier is allowed */
  22104     BOOL is_derived_class_constructor;
  22105     BOOL in_function_body;
  22106     JSFunctionKindEnum func_kind : 8;
  22107     JSParseFunctionEnum func_type : 8;
  22108     uint8_t js_mode; /* bitmap of JS_MODE_x */
  22109     JSAtom func_name; /* JS_ATOM_NULL if no name */
  22110 
  22111     JSVarDef *vars;
  22112     int var_size; /* allocated size for vars[] */
  22113     int var_count;
  22114     JSVarDef *args;
  22115     int arg_size; /* allocated size for args[] */
  22116     int arg_count; /* number of arguments */
  22117     int defined_arg_count;
  22118     int var_ref_count; /* number of local/arg variable references */
  22119     int var_object_idx; /* -1 if none */
  22120     int arg_var_object_idx; /* -1 if none (var object for the argument scope) */
  22121     int arguments_var_idx; /* -1 if none */
  22122     int arguments_arg_idx; /* argument variable definition in argument scope,
  22123                               -1 if none */
  22124     int func_var_idx; /* variable containing the current function (-1
  22125                          if none, only used if is_func_expr is true) */
  22126     int eval_ret_idx; /* variable containing the return value of the eval, -1 if none */
  22127     int this_var_idx; /* variable containg the 'this' value, -1 if none */
  22128     int new_target_var_idx; /* variable containg the 'new.target' value, -1 if none */
  22129     int this_active_func_var_idx; /* variable containg the 'this.active_func' value, -1 if none */
  22130     int home_object_var_idx;
  22131     BOOL need_home_object;
  22132 
  22133     int scope_level;    /* index into fd->scopes if the current lexical scope */
  22134     int scope_first;    /* index into vd->vars of first lexically scoped variable */
  22135     int scope_size;     /* allocated size of fd->scopes array */
  22136     int scope_count;    /* number of entries used in the fd->scopes array */
  22137     JSVarScope *scopes;
  22138     JSVarScope def_scope_array[4];
  22139     int body_scope; /* scope of the body of the function or eval */
  22140 
  22141     int global_var_count;
  22142     int global_var_size;
  22143     JSGlobalVar *global_vars;
  22144 
  22145     DynBuf byte_code;
  22146     int last_opcode_pos; /* -1 if no last opcode */
  22147     const uint8_t *last_opcode_source_ptr;
  22148     BOOL use_short_opcodes; /* true if short opcodes are used in byte_code */
  22149 
  22150     LabelSlot *label_slots;
  22151     int label_size; /* allocated size for label_slots[] */
  22152     int label_count;
  22153     BlockEnv *top_break; /* break/continue label stack */
  22154 
  22155     /* constant pool (strings, functions, numbers) */
  22156     JSValue *cpool;
  22157     int cpool_count;
  22158     int cpool_size;
  22159 
  22160     /* list of variables in the closure */
  22161     int closure_var_count;
  22162     int closure_var_size;
  22163     JSClosureVar *closure_var;
  22164 
  22165     JumpSlot *jump_slots;
  22166     int jump_size;
  22167     int jump_count;
  22168 
  22169     LineNumberSlot *line_number_slots;
  22170     int line_number_size;
  22171     int line_number_count;
  22172     int line_number_last;
  22173     int line_number_last_pc;
  22174 
  22175     /* pc2line table */
  22176     BOOL strip_debug : 1; /* strip all debug info (implies strip_source = TRUE) */
  22177     BOOL strip_source : 1; /* strip only source code */
  22178     JSAtom filename;
  22179     uint32_t source_pos; /* pointer in the eval() source */
  22180     GetLineColCache *get_line_col_cache; /* XXX: could remove to save memory */
  22181     DynBuf pc2line;
  22182 
  22183     char *source;  /* raw source, utf-8 encoded */
  22184     int source_len;
  22185 
  22186     JSModuleDef *module; /* != NULL when parsing a module */
  22187     BOOL has_await; /* TRUE if await is used (used in module eval) */
  22188 } JSFunctionDef;
  22189 
  22190 typedef struct JSToken {
  22191     int val;
  22192     const uint8_t *ptr; /* position in the source */
  22193     union {
  22194         struct {
  22195             JSValue str;
  22196             int sep;
  22197         } str;
  22198         struct {
  22199             JSValue val;
  22200         } num;
  22201         struct {
  22202             JSAtom atom;
  22203             BOOL has_escape;
  22204             BOOL is_reserved;
  22205         } ident;
  22206         struct {
  22207             JSValue body;
  22208             JSValue flags;
  22209         } regexp;
  22210     } u;
  22211 } JSToken;
  22212 
  22213 typedef struct JSParseState {
  22214     JSContext *ctx;
  22215     const char *filename;
  22216     JSToken token;
  22217     BOOL got_lf; /* true if got line feed before the current token */
  22218     const uint8_t *last_ptr;
  22219     const uint8_t *buf_start;
  22220     const uint8_t *buf_ptr;
  22221     const uint8_t *buf_end;
  22222 
  22223     /* current function code */
  22224     JSFunctionDef *cur_func;
  22225     BOOL is_module; /* parsing a module */
  22226     BOOL allow_html_comments;
  22227     BOOL ext_json; /* JSON parsing: true if accepting JSON superset */
  22228     GetLineColCache get_line_col_cache;
  22229 } JSParseState;
  22230 
  22231 typedef struct JSOpCode {
  22232 #ifdef DUMP_BYTECODE
  22233     const char *name;
  22234 #endif
  22235     uint8_t size; /* in bytes */
  22236     /* the opcodes remove n_pop items from the top of the stack, then
  22237        pushes n_push items */
  22238     uint8_t n_pop;
  22239     uint8_t n_push;
  22240     uint8_t fmt;
  22241 } JSOpCode;
  22242 
  22243 static const JSOpCode opcode_info[OP_COUNT + (OP_TEMP_END - OP_TEMP_START)] = {
  22244 #define FMT(f)
  22245 #ifdef DUMP_BYTECODE
  22246 #define DEF(id, size, n_pop, n_push, f) { #id, size, n_pop, n_push, OP_FMT_ ## f },
  22247 #else
  22248 #define DEF(id, size, n_pop, n_push, f) { size, n_pop, n_push, OP_FMT_ ## f },
  22249 #endif
  22250 #include "quickjs-opcode.h"
  22251 #undef DEF
  22252 #undef FMT
  22253 };
  22254 
  22255 #if SHORT_OPCODES
  22256 /* After the final compilation pass, short opcodes are used. Their
  22257    opcodes overlap with the temporary opcodes which cannot appear in
  22258    the final bytecode. Their description is after the temporary
  22259    opcodes in opcode_info[]. */
  22260 #define short_opcode_info(op)           \
  22261     opcode_info[(op) >= OP_TEMP_START ? \
  22262                 (op) + (OP_TEMP_END - OP_TEMP_START) : (op)]
  22263 #else
  22264 #define short_opcode_info(op) opcode_info[op]
  22265 #endif
  22266 
  22267 static __exception int next_token(JSParseState *s);
  22268 
  22269 static void free_token(JSParseState *s, JSToken *token)
  22270 {
  22271     switch(token->val) {
  22272     case TOK_NUMBER:
  22273         JS_FreeValue(s->ctx, token->u.num.val);
  22274         break;
  22275     case TOK_STRING:
  22276     case TOK_TEMPLATE:
  22277         JS_FreeValue(s->ctx, token->u.str.str);
  22278         break;
  22279     case TOK_REGEXP:
  22280         JS_FreeValue(s->ctx, token->u.regexp.body);
  22281         JS_FreeValue(s->ctx, token->u.regexp.flags);
  22282         break;
  22283     case TOK_IDENT:
  22284     case TOK_PRIVATE_NAME:
  22285         JS_FreeAtom(s->ctx, token->u.ident.atom);
  22286         break;
  22287     default:
  22288         if (token->val >= TOK_FIRST_KEYWORD &&
  22289             token->val <= TOK_LAST_KEYWORD) {
  22290             JS_FreeAtom(s->ctx, token->u.ident.atom);
  22291         }
  22292         break;
  22293     }
  22294 }
  22295 
  22296 static void __attribute((unused)) dump_token(JSParseState *s,
  22297                                              const JSToken *token)
  22298 {
  22299     switch(token->val) {
  22300     case TOK_NUMBER:
  22301         {
  22302             double d;
  22303             JS_ToFloat64(s->ctx, &d, token->u.num.val);  /* no exception possible */
  22304             printf("number: %.14g\n", d);
  22305         }
  22306         break;
  22307     case TOK_IDENT:
  22308     dump_atom:
  22309         {
  22310             char buf[ATOM_GET_STR_BUF_SIZE];
  22311             printf("ident: '%s'\n",
  22312                    JS_AtomGetStr(s->ctx, buf, sizeof(buf), token->u.ident.atom));
  22313         }
  22314         break;
  22315     case TOK_STRING:
  22316         {
  22317             const char *str;
  22318             /* XXX: quote the string */
  22319             str = JS_ToCString(s->ctx, token->u.str.str);
  22320             printf("string: '%s'\n", str);
  22321             JS_FreeCString(s->ctx, str);
  22322         }
  22323         break;
  22324     case TOK_TEMPLATE:
  22325         {
  22326             const char *str;
  22327             str = JS_ToCString(s->ctx, token->u.str.str);
  22328             printf("template: `%s`\n", str);
  22329             JS_FreeCString(s->ctx, str);
  22330         }
  22331         break;
  22332     case TOK_REGEXP:
  22333         {
  22334             const char *str, *str2;
  22335             str = JS_ToCString(s->ctx, token->u.regexp.body);
  22336             str2 = JS_ToCString(s->ctx, token->u.regexp.flags);
  22337             printf("regexp: '%s' '%s'\n", str, str2);
  22338             JS_FreeCString(s->ctx, str);
  22339             JS_FreeCString(s->ctx, str2);
  22340         }
  22341         break;
  22342     case TOK_EOF:
  22343         printf("eof\n");
  22344         break;
  22345     default:
  22346         if (s->token.val >= TOK_NULL && s->token.val <= TOK_LAST_KEYWORD) {
  22347             goto dump_atom;
  22348         } else if (s->token.val >= 256) {
  22349             printf("token: %d\n", token->val);
  22350         } else {
  22351             printf("token: '%c'\n", token->val);
  22352         }
  22353         break;
  22354     }
  22355 }
  22356 
  22357 /* return the zero based line and column number in the source. */
  22358 /* Note: we no longer support '\r' as line terminator */
  22359 static int get_line_col(int *pcol_num, const uint8_t *buf, size_t len)
  22360 {
  22361     int line_num, col_num, c;
  22362     size_t i;
  22363     
  22364     line_num = 0;
  22365     col_num = 0;
  22366     for(i = 0; i < len; i++) {
  22367         c = buf[i];
  22368         if (c == '\n') {
  22369             line_num++;
  22370             col_num = 0;
  22371         } else if (c < 0x80 || c >= 0xc0) {
  22372             col_num++;
  22373         }
  22374     }
  22375     *pcol_num = col_num;
  22376     return line_num;
  22377 }
  22378 
  22379 static int get_line_col_cached(GetLineColCache *s, int *pcol_num, const uint8_t *ptr)
  22380 {
  22381     int line_num, col_num;
  22382     if (ptr >= s->ptr) {
  22383         line_num = get_line_col(&col_num, s->ptr, ptr - s->ptr);
  22384         if (line_num == 0) {
  22385             s->col_num += col_num;
  22386         } else {
  22387             s->line_num += line_num;
  22388             s->col_num = col_num;
  22389         }
  22390     } else {
  22391         line_num = get_line_col(&col_num, ptr, s->ptr - ptr);
  22392         if (line_num == 0) {
  22393             s->col_num -= col_num;
  22394         } else {
  22395             const uint8_t *p;
  22396             s->line_num -= line_num;
  22397             /* find the absolute column position */
  22398             col_num = 0;
  22399             for(p = ptr - 1; p >= s->buf_start; p--) {
  22400                 if (*p == '\n') {
  22401                     break;
  22402                 } else if (*p < 0x80 || *p >= 0xc0) {
  22403                     col_num++;
  22404                 }
  22405             }
  22406             s->col_num = col_num;
  22407         }
  22408     }
  22409     s->ptr = ptr;
  22410     *pcol_num = s->col_num;
  22411     return s->line_num;
  22412 }
  22413 
  22414 /* 'ptr' is the position of the error in the source */
  22415 static int js_parse_error_v(JSParseState *s, const uint8_t *ptr, const char *fmt, va_list ap)
  22416 {
  22417     JSContext *ctx = s->ctx;
  22418     int line_num, col_num;
  22419     line_num = get_line_col(&col_num, s->buf_start, ptr - s->buf_start);
  22420     JS_ThrowError2(ctx, JS_SYNTAX_ERROR, fmt, ap, FALSE);
  22421     build_backtrace(ctx, ctx->rt->current_exception, s->filename,
  22422                     line_num + 1, col_num + 1, 0);
  22423     return -1;
  22424 }
  22425 
  22426 static __attribute__((format(printf, 3, 4))) int js_parse_error_pos(JSParseState *s, const uint8_t *ptr, const char *fmt, ...)
  22427 {
  22428     va_list ap;
  22429     int ret;
  22430     
  22431     va_start(ap, fmt);
  22432     ret = js_parse_error_v(s, ptr, fmt, ap);
  22433     va_end(ap);
  22434     return ret;
  22435 }
  22436 
  22437 static __attribute__((format(printf, 2, 3))) int js_parse_error(JSParseState *s, const char *fmt, ...)
  22438 {
  22439     va_list ap;
  22440     int ret;
  22441     
  22442     va_start(ap, fmt);
  22443     ret = js_parse_error_v(s, s->token.ptr, fmt, ap);
  22444     va_end(ap);
  22445     return ret;
  22446 }
  22447 
  22448 static int js_parse_expect(JSParseState *s, int tok)
  22449 {
  22450     if (s->token.val != tok) {
  22451         /* XXX: dump token correctly in all cases */
  22452         return js_parse_error(s, "expecting '%c'", tok);
  22453     }
  22454     return next_token(s);
  22455 }
  22456 
  22457 static int js_parse_expect_semi(JSParseState *s)
  22458 {
  22459     if (s->token.val != ';') {
  22460         /* automatic insertion of ';' */
  22461         if (s->token.val == TOK_EOF || s->token.val == '}' || s->got_lf) {
  22462             return 0;
  22463         }
  22464         return js_parse_error(s, "expecting '%c'", ';');
  22465     }
  22466     return next_token(s);
  22467 }
  22468 
  22469 static int js_parse_error_reserved_identifier(JSParseState *s)
  22470 {
  22471     char buf1[ATOM_GET_STR_BUF_SIZE];
  22472     return js_parse_error(s, "'%s' is a reserved identifier",
  22473                           JS_AtomGetStr(s->ctx, buf1, sizeof(buf1),
  22474                                         s->token.u.ident.atom));
  22475 }
  22476 
  22477 static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p)
  22478 {
  22479     uint32_t c;
  22480     StringBuffer b_s, *b = &b_s;
  22481     JSValue str;
  22482 
  22483     /* p points to the first byte of the template part */
  22484     if (string_buffer_init(s->ctx, b, 32))
  22485         goto fail;
  22486     for(;;) {
  22487         if (p >= s->buf_end)
  22488             goto unexpected_eof;
  22489         c = *p++;
  22490         if (c == '`') {
  22491             /* template end part */
  22492             break;
  22493         }
  22494         if (c == '$' && *p == '{') {
  22495             /* template start or middle part */
  22496             p++;
  22497             break;
  22498         }
  22499         if (c == '\\') {
  22500             if (string_buffer_putc8(b, c))
  22501                 goto fail;
  22502             if (p >= s->buf_end)
  22503                 goto unexpected_eof;
  22504             c = *p++;
  22505         }
  22506         /* newline sequences are normalized as single '\n' bytes */
  22507         if (c == '\r') {
  22508             if (*p == '\n')
  22509                 p++;
  22510             c = '\n';
  22511         }
  22512         if (c >= 0x80) {
  22513             const uint8_t *p_next;
  22514             c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
  22515             if (c > 0x10FFFF) {
  22516                 js_parse_error_pos(s, p - 1, "invalid UTF-8 sequence");
  22517                 goto fail;
  22518             }
  22519             p = p_next;
  22520         }
  22521         if (string_buffer_putc(b, c))
  22522             goto fail;
  22523     }
  22524     str = string_buffer_end(b);
  22525     if (JS_IsException(str))
  22526         return -1;
  22527     s->token.val = TOK_TEMPLATE;
  22528     s->token.u.str.sep = c;
  22529     s->token.u.str.str = str;
  22530     s->buf_ptr = p;
  22531     return 0;
  22532 
  22533  unexpected_eof:
  22534     js_parse_error(s, "unexpected end of string");
  22535  fail:
  22536     string_buffer_free(b);
  22537     return -1;
  22538 }
  22539 
  22540 static __exception int js_parse_string(JSParseState *s, int sep,
  22541                                        BOOL do_throw, const uint8_t *p,
  22542                                        JSToken *token, const uint8_t **pp)
  22543 {
  22544     int ret;
  22545     uint32_t c;
  22546     StringBuffer b_s, *b = &b_s;
  22547     const uint8_t *p_escape;
  22548     JSValue str;
  22549 
  22550     /* string */
  22551     if (string_buffer_init(s->ctx, b, 32))
  22552         goto fail;
  22553     for(;;) {
  22554         if (p >= s->buf_end)
  22555             goto invalid_char;
  22556         c = *p;
  22557         if (c < 0x20) {
  22558             if (sep == '`') {
  22559                 if (c == '\r') {
  22560                     if (p[1] == '\n')
  22561                         p++;
  22562                     c = '\n';
  22563                 }
  22564                 /* do not update s->line_num */
  22565             } else if (c == '\n' || c == '\r')
  22566                 goto invalid_char;
  22567         }
  22568         p++;
  22569         if (c == sep)
  22570             break;
  22571         if (c == '$' && *p == '{' && sep == '`') {
  22572             /* template start or middle part */
  22573             p++;
  22574             break;
  22575         }
  22576         if (c == '\\') {
  22577             p_escape = p - 1;
  22578             c = *p;
  22579             /* XXX: need a specific JSON case to avoid
  22580                accepting invalid escapes */
  22581             switch(c) {
  22582             case '\0':
  22583                 if (p >= s->buf_end)
  22584                     goto invalid_char;
  22585                 p++;
  22586                 break;
  22587             case '\'':
  22588             case '\"':
  22589             case '\\':
  22590                 p++;
  22591                 break;
  22592             case '\r':  /* accept DOS and MAC newline sequences */
  22593                 if (p[1] == '\n') {
  22594                     p++;
  22595                 }
  22596                 /* fall thru */
  22597             case '\n':
  22598                 /* ignore escaped newline sequence */
  22599                 p++;
  22600                 continue;
  22601             default:
  22602                 if (c >= '0' && c <= '9') {
  22603                     if (!(s->cur_func->js_mode & JS_MODE_STRICT) && sep != '`')
  22604                         goto parse_escape;
  22605                     if (c == '0' && !(p[1] >= '0' && p[1] <= '9')) {
  22606                         p++;
  22607                         c = '\0';
  22608                     } else {
  22609                         if (c >= '8' || sep == '`') {
  22610                             /* Note: according to ES2021, \8 and \9 are not
  22611                                accepted in strict mode or in templates. */
  22612                             goto invalid_escape;
  22613                         } else {
  22614                             if (do_throw)
  22615                                 js_parse_error_pos(s, p_escape, "octal escape sequences are not allowed in strict mode");
  22616                         }
  22617                         goto fail;
  22618                     }
  22619                 } else if (c >= 0x80) {
  22620                     const uint8_t *p_next;
  22621                     c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
  22622                     if (c > 0x10FFFF) {
  22623                         goto invalid_utf8;
  22624                     }
  22625                     p = p_next;
  22626                     /* LS or PS are skipped */
  22627                     if (c == CP_LS || c == CP_PS)
  22628                         continue;
  22629                 } else {
  22630                 parse_escape:
  22631                     ret = lre_parse_escape(&p, TRUE);
  22632                     if (ret == -1) {
  22633                     invalid_escape:
  22634                         if (do_throw)
  22635                             js_parse_error_pos(s, p_escape, "malformed escape sequence in string literal");
  22636                         goto fail;
  22637                     } else if (ret < 0) {
  22638                         /* ignore the '\' (could output a warning) */
  22639                         p++;
  22640                     } else {
  22641                         c = ret;
  22642                     }
  22643                 }
  22644                 break;
  22645             }
  22646         } else if (c >= 0x80) {
  22647             const uint8_t *p_next;
  22648             c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
  22649             if (c > 0x10FFFF)
  22650                 goto invalid_utf8;
  22651             p = p_next;
  22652         }
  22653         if (string_buffer_putc(b, c))
  22654             goto fail;
  22655     }
  22656     str = string_buffer_end(b);
  22657     if (JS_IsException(str))
  22658         return -1;
  22659     token->val = TOK_STRING;
  22660     token->u.str.sep = c;
  22661     token->u.str.str = str;
  22662     *pp = p;
  22663     return 0;
  22664 
  22665  invalid_utf8:
  22666     if (do_throw)
  22667         js_parse_error(s, "invalid UTF-8 sequence");
  22668     goto fail;
  22669  invalid_char:
  22670     if (do_throw)
  22671         js_parse_error(s, "unexpected end of string");
  22672  fail:
  22673     string_buffer_free(b);
  22674     return -1;
  22675 }
  22676 
  22677 static inline BOOL token_is_pseudo_keyword(JSParseState *s, JSAtom atom) {
  22678     return s->token.val == TOK_IDENT && s->token.u.ident.atom == atom &&
  22679         !s->token.u.ident.has_escape;
  22680 }
  22681 
  22682 static __exception int js_parse_regexp(JSParseState *s)
  22683 {
  22684     const uint8_t *p;
  22685     BOOL in_class;
  22686     StringBuffer b_s, *b = &b_s;
  22687     StringBuffer b2_s, *b2 = &b2_s;
  22688     uint32_t c;
  22689     JSValue body_str, flags_str;
  22690 
  22691     p = s->buf_ptr;
  22692     p++;
  22693     in_class = FALSE;
  22694     if (string_buffer_init(s->ctx, b, 32))
  22695         return -1;
  22696     if (string_buffer_init(s->ctx, b2, 1))
  22697         goto fail;
  22698     for(;;) {
  22699         if (p >= s->buf_end) {
  22700         eof_error:
  22701             js_parse_error(s, "unexpected end of regexp");
  22702             goto fail;
  22703         }
  22704         c = *p++;
  22705         if (c == '\n' || c == '\r') {
  22706             goto eol_error;
  22707         } else if (c == '/') {
  22708             if (!in_class)
  22709                 break;
  22710         } else if (c == '[') {
  22711             in_class = TRUE;
  22712         } else if (c == ']') {
  22713             /* XXX: incorrect as the first character in a class */
  22714             in_class = FALSE;
  22715         } else if (c == '\\') {
  22716             if (string_buffer_putc8(b, c))
  22717                 goto fail;
  22718             c = *p++;
  22719             if (c == '\n' || c == '\r')
  22720                 goto eol_error;
  22721             else if (c == '\0' && p >= s->buf_end)
  22722                 goto eof_error;
  22723             else if (c >= 0x80) {
  22724                 const uint8_t *p_next;
  22725                 c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
  22726                 if (c > 0x10FFFF) {
  22727                     goto invalid_utf8;
  22728                 }
  22729                 p = p_next;
  22730                 if (c == CP_LS || c == CP_PS)
  22731                     goto eol_error;
  22732             }
  22733         } else if (c >= 0x80) {
  22734             const uint8_t *p_next;
  22735             c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
  22736             if (c > 0x10FFFF) {
  22737             invalid_utf8:
  22738                 js_parse_error_pos(s, p - 1, "invalid UTF-8 sequence");
  22739                 goto fail;
  22740             }
  22741             /* LS or PS are considered as line terminator */
  22742             if (c == CP_LS || c == CP_PS) {
  22743             eol_error:
  22744                 js_parse_error_pos(s, p - 1, "unexpected line terminator in regexp");
  22745                 goto fail;
  22746             }
  22747             p = p_next;
  22748         }
  22749         if (string_buffer_putc(b, c))
  22750             goto fail;
  22751     }
  22752 
  22753     /* flags */
  22754     for(;;) {
  22755         const uint8_t *p_next = p;
  22756         c = *p_next++;
  22757         if (c >= 0x80) {
  22758             c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
  22759             if (c > 0x10FFFF) {
  22760                 p++;
  22761                 goto invalid_utf8;
  22762             }
  22763         }
  22764         if (!lre_js_is_ident_next(c))
  22765             break;
  22766         if (string_buffer_putc(b2, c))
  22767             goto fail;
  22768         p = p_next;
  22769     }
  22770 
  22771     body_str = string_buffer_end(b);
  22772     flags_str = string_buffer_end(b2);
  22773     if (JS_IsException(body_str) ||
  22774         JS_IsException(flags_str)) {
  22775         JS_FreeValue(s->ctx, body_str);
  22776         JS_FreeValue(s->ctx, flags_str);
  22777         return -1;
  22778     }
  22779     s->token.val = TOK_REGEXP;
  22780     s->token.u.regexp.body = body_str;
  22781     s->token.u.regexp.flags = flags_str;
  22782     s->buf_ptr = p;
  22783     return 0;
  22784  fail:
  22785     string_buffer_free(b);
  22786     string_buffer_free(b2);
  22787     return -1;
  22788 }
  22789 
  22790 static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize,
  22791                                      char *static_buf)
  22792 {
  22793     char *buf, *new_buf;
  22794     size_t size, new_size;
  22795 
  22796     buf = *pbuf;
  22797     size = *psize;
  22798     if (size >= (SIZE_MAX / 3) * 2)
  22799         new_size = SIZE_MAX;
  22800     else
  22801         new_size = size + (size >> 1);
  22802     if (buf == static_buf) {
  22803         new_buf = js_malloc(ctx, new_size);
  22804         if (!new_buf)
  22805             return -1;
  22806         memcpy(new_buf, buf, size);
  22807     } else {
  22808         new_buf = js_realloc(ctx, buf, new_size);
  22809         if (!new_buf)
  22810             return -1;
  22811     }
  22812     *pbuf = new_buf;
  22813     *psize = new_size;
  22814     return 0;
  22815 }
  22816 
  22817 /* convert a TOK_IDENT to a keyword when needed */
  22818 static void update_token_ident(JSParseState *s)
  22819 {
  22820     if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD ||
  22821         (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD &&
  22822          (s->cur_func->js_mode & JS_MODE_STRICT)) ||
  22823         (s->token.u.ident.atom == JS_ATOM_yield &&
  22824          ((s->cur_func->func_kind & JS_FUNC_GENERATOR) ||
  22825           (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
  22826            !s->cur_func->in_function_body && s->cur_func->parent &&
  22827            (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) ||
  22828         (s->token.u.ident.atom == JS_ATOM_await &&
  22829          (s->is_module ||
  22830           (s->cur_func->func_kind & JS_FUNC_ASYNC) ||
  22831           s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT ||
  22832           (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
  22833            !s->cur_func->in_function_body && s->cur_func->parent &&
  22834            ((s->cur_func->parent->func_kind & JS_FUNC_ASYNC) ||
  22835             s->cur_func->parent->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))))) {
  22836         if (s->token.u.ident.has_escape) {
  22837             s->token.u.ident.is_reserved = TRUE;
  22838             s->token.val = TOK_IDENT;
  22839         } else {
  22840             /* The keywords atoms are pre allocated */
  22841             s->token.val = s->token.u.ident.atom - 1 + TOK_FIRST_KEYWORD;
  22842         }
  22843     }
  22844 }
  22845 
  22846 /* if the current token is an identifier or keyword, reparse it
  22847    according to the current function type */
  22848 static void reparse_ident_token(JSParseState *s)
  22849 {
  22850     if (s->token.val == TOK_IDENT ||
  22851         (s->token.val >= TOK_FIRST_KEYWORD &&
  22852          s->token.val <= TOK_LAST_KEYWORD)) {
  22853         s->token.val = TOK_IDENT;
  22854         s->token.u.ident.is_reserved = FALSE;
  22855         update_token_ident(s);
  22856     }
  22857 }
  22858 
  22859 /* 'c' is the first character. Return JS_ATOM_NULL in case of error */
  22860 static JSAtom parse_ident(JSParseState *s, const uint8_t **pp,
  22861                           BOOL *pident_has_escape, int c, BOOL is_private)
  22862 {
  22863     const uint8_t *p, *p1;
  22864     char ident_buf[128], *buf;
  22865     size_t ident_size, ident_pos;
  22866     JSAtom atom;
  22867 
  22868     p = *pp;
  22869     buf = ident_buf;
  22870     ident_size = sizeof(ident_buf);
  22871     ident_pos = 0;
  22872     if (is_private)
  22873         buf[ident_pos++] = '#';
  22874     for(;;) {
  22875         p1 = p;
  22876 
  22877         if (c < 128) {
  22878             buf[ident_pos++] = c;
  22879         } else {
  22880             ident_pos += unicode_to_utf8((uint8_t*)buf + ident_pos, c);
  22881         }
  22882         c = *p1++;
  22883         if (c == '\\' && *p1 == 'u') {
  22884             c = lre_parse_escape(&p1, TRUE);
  22885             *pident_has_escape = TRUE;
  22886         } else if (c >= 128) {
  22887             c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
  22888         }
  22889         if (!lre_js_is_ident_next(c))
  22890             break;
  22891         p = p1;
  22892         if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
  22893             if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) {
  22894                 atom = JS_ATOM_NULL;
  22895                 goto done;
  22896             }
  22897         }
  22898     }
  22899     atom = JS_NewAtomLen(s->ctx, buf, ident_pos);
  22900  done:
  22901     if (unlikely(buf != ident_buf))
  22902         js_free(s->ctx, buf);
  22903     *pp = p;
  22904     return atom;
  22905 }
  22906 
  22907 
  22908 static __exception int next_token(JSParseState *s)
  22909 {
  22910     const uint8_t *p;
  22911     int c;
  22912     BOOL ident_has_escape;
  22913     JSAtom atom;
  22914 
  22915     if (js_check_stack_overflow(s->ctx->rt, 0)) {
  22916         return js_parse_error(s, "stack overflow");
  22917     }
  22918 
  22919     free_token(s, &s->token);
  22920 
  22921     p = s->last_ptr = s->buf_ptr;
  22922     s->got_lf = FALSE;
  22923  redo:
  22924     s->token.ptr = p;
  22925     c = *p;
  22926     switch(c) {
  22927     case 0:
  22928         if (p >= s->buf_end) {
  22929             s->token.val = TOK_EOF;
  22930         } else {
  22931             goto def_token;
  22932         }
  22933         break;
  22934     case '`':
  22935         if (js_parse_template_part(s, p + 1))
  22936             goto fail;
  22937         p = s->buf_ptr;
  22938         break;
  22939     case '\'':
  22940     case '\"':
  22941         if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))
  22942             goto fail;
  22943         break;
  22944     case '\r':  /* accept DOS and MAC newline sequences */
  22945         if (p[1] == '\n') {
  22946             p++;
  22947         }
  22948         /* fall thru */
  22949     case '\n':
  22950         p++;
  22951     line_terminator:
  22952         s->got_lf = TRUE;
  22953         goto redo;
  22954     case '\f':
  22955     case '\v':
  22956     case ' ':
  22957     case '\t':
  22958         p++;
  22959         goto redo;
  22960     case '/':
  22961         if (p[1] == '*') {
  22962             /* comment */
  22963             p += 2;
  22964             for(;;) {
  22965                 if (*p == '\0' && p >= s->buf_end) {
  22966                     js_parse_error(s, "unexpected end of comment");
  22967                     goto fail;
  22968                 }
  22969                 if (p[0] == '*' && p[1] == '/') {
  22970                     p += 2;
  22971                     break;
  22972                 }
  22973                 if (*p == '\n' || *p == '\r') {
  22974                     s->got_lf = TRUE; /* considered as LF for ASI */
  22975                     p++;
  22976                 } else if (*p >= 0x80) {
  22977                     c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
  22978                     if (c == CP_LS || c == CP_PS) {
  22979                         s->got_lf = TRUE; /* considered as LF for ASI */
  22980                     } else if (c == -1) {
  22981                         p++; /* skip invalid UTF-8 */
  22982                     }
  22983                 } else {
  22984                     p++;
  22985                 }
  22986             }
  22987             goto redo;
  22988         } else if (p[1] == '/') {
  22989             /* line comment */
  22990             p += 2;
  22991         skip_line_comment:
  22992             for(;;) {
  22993                 if (*p == '\0' && p >= s->buf_end)
  22994                     break;
  22995                 if (*p == '\r' || *p == '\n')
  22996                     break;
  22997                 if (*p >= 0x80) {
  22998                     c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
  22999                     /* LS or PS are considered as line terminator */
  23000                     if (c == CP_LS || c == CP_PS) {
  23001                         break;
  23002                     } else if (c == -1) {
  23003                         p++; /* skip invalid UTF-8 */
  23004                     }
  23005                 } else {
  23006                     p++;
  23007                 }
  23008             }
  23009             goto redo;
  23010         } else if (p[1] == '=') {
  23011             p += 2;
  23012             s->token.val = TOK_DIV_ASSIGN;
  23013         } else {
  23014             p++;
  23015             s->token.val = c;
  23016         }
  23017         break;
  23018     case '\\':
  23019         if (p[1] == 'u') {
  23020             const uint8_t *p1 = p + 1;
  23021             int c1 = lre_parse_escape(&p1, TRUE);
  23022             if (c1 >= 0 && lre_js_is_ident_first(c1)) {
  23023                 c = c1;
  23024                 p = p1;
  23025                 ident_has_escape = TRUE;
  23026                 goto has_ident;
  23027             } else {
  23028                 /* XXX: syntax error? */
  23029             }
  23030         }
  23031         goto def_token;
  23032     case 'a': case 'b': case 'c': case 'd':
  23033     case 'e': case 'f': case 'g': case 'h':
  23034     case 'i': case 'j': case 'k': case 'l':
  23035     case 'm': case 'n': case 'o': case 'p':
  23036     case 'q': case 'r': case 's': case 't':
  23037     case 'u': case 'v': case 'w': case 'x':
  23038     case 'y': case 'z':
  23039     case 'A': case 'B': case 'C': case 'D':
  23040     case 'E': case 'F': case 'G': case 'H':
  23041     case 'I': case 'J': case 'K': case 'L':
  23042     case 'M': case 'N': case 'O': case 'P':
  23043     case 'Q': case 'R': case 'S': case 'T':
  23044     case 'U': case 'V': case 'W': case 'X':
  23045     case 'Y': case 'Z':
  23046     case '_':
  23047     case '$':
  23048         /* identifier */
  23049         p++;
  23050         ident_has_escape = FALSE;
  23051     has_ident:
  23052         atom = parse_ident(s, &p, &ident_has_escape, c, FALSE);
  23053         if (atom == JS_ATOM_NULL)
  23054             goto fail;
  23055         s->token.u.ident.atom = atom;
  23056         s->token.u.ident.has_escape = ident_has_escape;
  23057         s->token.u.ident.is_reserved = FALSE;
  23058         s->token.val = TOK_IDENT;
  23059         update_token_ident(s);
  23060         break;
  23061     case '#':
  23062         /* private name */
  23063         {
  23064             const uint8_t *p1;
  23065             p++;
  23066             p1 = p;
  23067             c = *p1++;
  23068             if (c == '\\' && *p1 == 'u') {
  23069                 c = lre_parse_escape(&p1, TRUE);
  23070             } else if (c >= 128) {
  23071                 c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
  23072             }
  23073             if (!lre_js_is_ident_first(c)) {
  23074                 js_parse_error(s, "invalid first character of private name");
  23075                 goto fail;
  23076             }
  23077             p = p1;
  23078             ident_has_escape = FALSE; /* not used */
  23079             atom = parse_ident(s, &p, &ident_has_escape, c, TRUE);
  23080             if (atom == JS_ATOM_NULL)
  23081                 goto fail;
  23082             s->token.u.ident.atom = atom;
  23083             s->token.val = TOK_PRIVATE_NAME;
  23084         }
  23085         break;
  23086     case '.':
  23087         if (p[1] == '.' && p[2] == '.') {
  23088             p += 3;
  23089             s->token.val = TOK_ELLIPSIS;
  23090             break;
  23091         }
  23092         if (p[1] >= '0' && p[1] <= '9') {
  23093             goto parse_number;
  23094         } else {
  23095             goto def_token;
  23096         }
  23097         break;
  23098     case '0':
  23099         /* in strict mode, octal literals are not accepted */
  23100         if (is_digit(p[1]) && (s->cur_func->js_mode & JS_MODE_STRICT)) {
  23101             js_parse_error(s, "octal literals are deprecated in strict mode");
  23102             goto fail;
  23103         }
  23104         goto parse_number;
  23105     case '1': case '2': case '3': case '4':
  23106     case '5': case '6': case '7': case '8':
  23107     case '9':
  23108         /* number */
  23109     parse_number:
  23110         {
  23111             JSValue ret;
  23112             const uint8_t *p1;
  23113             int flags;
  23114             flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL |
  23115                 ATOD_ACCEPT_UNDERSCORES | ATOD_ACCEPT_SUFFIX;
  23116             ret = js_atof(s->ctx, (const char *)p, (const char **)&p, 0,
  23117                           flags);
  23118             if (JS_IsException(ret))
  23119                 goto fail;
  23120             /* reject `10instanceof Number` */
  23121             if (JS_VALUE_IS_NAN(ret) ||
  23122                 lre_js_is_ident_next(unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1))) {
  23123                 JS_FreeValue(s->ctx, ret);
  23124                 js_parse_error(s, "invalid number literal");
  23125                 goto fail;
  23126             }
  23127             s->token.val = TOK_NUMBER;
  23128             s->token.u.num.val = ret;
  23129         }
  23130         break;
  23131     case '*':
  23132         if (p[1] == '=') {
  23133             p += 2;
  23134             s->token.val = TOK_MUL_ASSIGN;
  23135         } else if (p[1] == '*') {
  23136             if (p[2] == '=') {
  23137                 p += 3;
  23138                 s->token.val = TOK_POW_ASSIGN;
  23139             } else {
  23140                 p += 2;
  23141                 s->token.val = TOK_POW;
  23142             }
  23143         } else {
  23144             goto def_token;
  23145         }
  23146         break;
  23147     case '%':
  23148         if (p[1] == '=') {
  23149             p += 2;
  23150             s->token.val = TOK_MOD_ASSIGN;
  23151         } else {
  23152             goto def_token;
  23153         }
  23154         break;
  23155     case '+':
  23156         if (p[1] == '=') {
  23157             p += 2;
  23158             s->token.val = TOK_PLUS_ASSIGN;
  23159         } else if (p[1] == '+') {
  23160             p += 2;
  23161             s->token.val = TOK_INC;
  23162         } else {
  23163             goto def_token;
  23164         }
  23165         break;
  23166     case '-':
  23167         if (p[1] == '=') {
  23168             p += 2;
  23169             s->token.val = TOK_MINUS_ASSIGN;
  23170         } else if (p[1] == '-') {
  23171             if (s->allow_html_comments && p[2] == '>' &&
  23172                 (s->got_lf || s->last_ptr == s->buf_start)) {
  23173                 /* Annex B: `-->` at beginning of line is an html comment end.
  23174                    It extends to the end of the line.
  23175                  */
  23176                 goto skip_line_comment;
  23177             }
  23178             p += 2;
  23179             s->token.val = TOK_DEC;
  23180         } else {
  23181             goto def_token;
  23182         }
  23183         break;
  23184     case '<':
  23185         if (p[1] == '=') {
  23186             p += 2;
  23187             s->token.val = TOK_LTE;
  23188         } else if (p[1] == '<') {
  23189             if (p[2] == '=') {
  23190                 p += 3;
  23191                 s->token.val = TOK_SHL_ASSIGN;
  23192             } else {
  23193                 p += 2;
  23194                 s->token.val = TOK_SHL;
  23195             }
  23196         } else if (s->allow_html_comments &&
  23197                    p[1] == '!' && p[2] == '-' && p[3] == '-') {
  23198             /* Annex B: handle `<!--` single line html comments */
  23199             goto skip_line_comment;
  23200         } else {
  23201             goto def_token;
  23202         }
  23203         break;
  23204     case '>':
  23205         if (p[1] == '=') {
  23206             p += 2;
  23207             s->token.val = TOK_GTE;
  23208         } else if (p[1] == '>') {
  23209             if (p[2] == '>') {
  23210                 if (p[3] == '=') {
  23211                     p += 4;
  23212                     s->token.val = TOK_SHR_ASSIGN;
  23213                 } else {
  23214                     p += 3;
  23215                     s->token.val = TOK_SHR;
  23216                 }
  23217             } else if (p[2] == '=') {
  23218                 p += 3;
  23219                 s->token.val = TOK_SAR_ASSIGN;
  23220             } else {
  23221                 p += 2;
  23222                 s->token.val = TOK_SAR;
  23223             }
  23224         } else {
  23225             goto def_token;
  23226         }
  23227         break;
  23228     case '=':
  23229         if (p[1] == '=') {
  23230             if (p[2] == '=') {
  23231                 p += 3;
  23232                 s->token.val = TOK_STRICT_EQ;
  23233             } else {
  23234                 p += 2;
  23235                 s->token.val = TOK_EQ;
  23236             }
  23237         } else if (p[1] == '>') {
  23238             p += 2;
  23239             s->token.val = TOK_ARROW;
  23240         } else {
  23241             goto def_token;
  23242         }
  23243         break;
  23244     case '!':
  23245         if (p[1] == '=') {
  23246             if (p[2] == '=') {
  23247                 p += 3;
  23248                 s->token.val = TOK_STRICT_NEQ;
  23249             } else {
  23250                 p += 2;
  23251                 s->token.val = TOK_NEQ;
  23252             }
  23253         } else {
  23254             goto def_token;
  23255         }
  23256         break;
  23257     case '&':
  23258         if (p[1] == '=') {
  23259             p += 2;
  23260             s->token.val = TOK_AND_ASSIGN;
  23261         } else if (p[1] == '&') {
  23262             if (p[2] == '=') {
  23263                 p += 3;
  23264                 s->token.val = TOK_LAND_ASSIGN;
  23265             } else {
  23266                 p += 2;
  23267                 s->token.val = TOK_LAND;
  23268             }
  23269         } else {
  23270             goto def_token;
  23271         }
  23272         break;
  23273     case '^':
  23274         if (p[1] == '=') {
  23275             p += 2;
  23276             s->token.val = TOK_XOR_ASSIGN;
  23277         } else {
  23278             goto def_token;
  23279         }
  23280         break;
  23281     case '|':
  23282         if (p[1] == '=') {
  23283             p += 2;
  23284             s->token.val = TOK_OR_ASSIGN;
  23285         } else if (p[1] == '|') {
  23286             if (p[2] == '=') {
  23287                 p += 3;
  23288                 s->token.val = TOK_LOR_ASSIGN;
  23289             } else {
  23290                 p += 2;
  23291                 s->token.val = TOK_LOR;
  23292             }
  23293         } else {
  23294             goto def_token;
  23295         }
  23296         break;
  23297     case '?':
  23298         if (p[1] == '?') {
  23299             if (p[2] == '=') {
  23300                 p += 3;
  23301                 s->token.val = TOK_DOUBLE_QUESTION_MARK_ASSIGN;
  23302             } else {
  23303                 p += 2;
  23304                 s->token.val = TOK_DOUBLE_QUESTION_MARK;
  23305             }
  23306         } else if (p[1] == '.' && !(p[2] >= '0' && p[2] <= '9')) {
  23307             p += 2;
  23308             s->token.val = TOK_QUESTION_MARK_DOT;
  23309         } else {
  23310             goto def_token;
  23311         }
  23312         break;
  23313     default:
  23314         if (c >= 128) {
  23315             /* unicode value */
  23316             c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
  23317             switch(c) {
  23318             case CP_PS:
  23319             case CP_LS:
  23320                 /* XXX: should avoid incrementing line_number, but
  23321                    needed to handle HTML comments */
  23322                 goto line_terminator;
  23323             default:
  23324                 if (lre_is_space(c)) {
  23325                     goto redo;
  23326                 } else if (lre_js_is_ident_first(c)) {
  23327                     ident_has_escape = FALSE;
  23328                     goto has_ident;
  23329                 } else {
  23330                     js_parse_error(s, "unexpected character");
  23331                     goto fail;
  23332                 }
  23333             }
  23334         }
  23335     def_token:
  23336         s->token.val = c;
  23337         p++;
  23338         break;
  23339     }
  23340     s->buf_ptr = p;
  23341 
  23342     //    dump_token(s, &s->token);
  23343     return 0;
  23344 
  23345  fail:
  23346     s->token.val = TOK_ERROR;
  23347     return -1;
  23348 }
  23349 
  23350 /* 'c' is the first character. Return JS_ATOM_NULL in case of error */
  23351 /* XXX: accept unicode identifiers as JSON5 ? */
  23352 static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c)
  23353 {
  23354     const uint8_t *p;
  23355     char ident_buf[128], *buf;
  23356     size_t ident_size, ident_pos;
  23357     JSAtom atom;
  23358 
  23359     p = *pp;
  23360     buf = ident_buf;
  23361     ident_size = sizeof(ident_buf);
  23362     ident_pos = 0;
  23363     for(;;) {
  23364         buf[ident_pos++] = c;
  23365         c = *p;
  23366         if (c >= 128 || !lre_is_id_continue_byte(c))
  23367             break;
  23368         p++;
  23369         if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
  23370             if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) {
  23371                 atom = JS_ATOM_NULL;
  23372                 goto done;
  23373             }
  23374         }
  23375     }
  23376     atom = JS_NewAtomLen(s->ctx, buf, ident_pos);
  23377  done:
  23378     if (unlikely(buf != ident_buf))
  23379         js_free(s->ctx, buf);
  23380     *pp = p;
  23381     return atom;
  23382 }
  23383 
  23384 static int json_parse_string(JSParseState *s, const uint8_t **pp, int sep)
  23385 {
  23386     const uint8_t *p, *p_next;
  23387     int i;
  23388     uint32_t c;
  23389     StringBuffer b_s, *b = &b_s;
  23390 
  23391     if (string_buffer_init(s->ctx, b, 32))
  23392         goto fail;
  23393 
  23394     p = *pp;
  23395     for(;;) {
  23396         if (p >= s->buf_end) {
  23397             goto end_of_input;
  23398         }
  23399         c = *p++;
  23400         if (c == sep)
  23401             break;
  23402         if (c < 0x20) {
  23403             js_parse_error_pos(s, p - 1, "Bad control character in string literal");
  23404             goto fail;
  23405         }
  23406         if (c == '\\') {
  23407             c = *p++;
  23408             switch(c) {
  23409             case 'b':   c = '\b'; break;
  23410             case 'f':   c = '\f'; break;
  23411             case 'n':   c = '\n'; break;
  23412             case 'r':   c = '\r'; break;
  23413             case 't':   c = '\t'; break;
  23414             case '\\':  break;
  23415             case '/':   break; 
  23416             case 'u':
  23417                 c = 0;
  23418                 for(i = 0; i < 4; i++) {
  23419                     int h = from_hex(*p++);
  23420                     if (h < 0) {
  23421                         js_parse_error_pos(s, p - 1, "Bad Unicode escape");
  23422                         goto fail;
  23423                     }
  23424                     c = (c << 4) | h;
  23425                 }
  23426                 break;
  23427             case '\n':
  23428                 if (s->ext_json)
  23429                     continue;
  23430                 goto bad_escape;
  23431             case 'v':
  23432                 if (s->ext_json) {
  23433                     c = '\v';
  23434                     break;
  23435                 }
  23436                 goto bad_escape;
  23437             default:
  23438                 if (c == sep)
  23439                     break;
  23440                 if (p > s->buf_end)
  23441                     goto end_of_input;
  23442             bad_escape:
  23443                 js_parse_error_pos(s, p - 1, "Bad escaped character");
  23444                 goto fail;
  23445             }
  23446         } else
  23447         if (c >= 0x80) {
  23448             c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
  23449             if (c > 0x10FFFF) {
  23450                 js_parse_error_pos(s, p - 1, "Bad UTF-8 sequence");
  23451                 goto fail;
  23452             }
  23453             p = p_next;
  23454         }
  23455         if (string_buffer_putc(b, c))
  23456             goto fail;
  23457     }
  23458     s->token.val = TOK_STRING;
  23459     s->token.u.str.sep = sep;
  23460     s->token.u.str.str = string_buffer_end(b);
  23461     *pp = p;
  23462     return 0;
  23463 
  23464  end_of_input:
  23465     js_parse_error(s, "Unexpected end of JSON input");
  23466  fail:
  23467     string_buffer_free(b);
  23468     return -1;
  23469 }
  23470 
  23471 static int json_parse_number(JSParseState *s, const uint8_t **pp)
  23472 {
  23473     const uint8_t *p = *pp;
  23474     const uint8_t *p_start = p;
  23475     int radix;
  23476     double d;
  23477     JSATODTempMem atod_mem;
  23478     
  23479     if (*p == '+' || *p == '-')
  23480         p++;
  23481 
  23482     if (!is_digit(*p)) {
  23483         if (s->ext_json) {
  23484             if (strstart((const char *)p, "Infinity", (const char **)&p)) {
  23485                 d = 1.0 / 0.0;
  23486                 if (*p_start == '-')
  23487                     d = -d;
  23488                 goto done;
  23489             } else if (strstart((const char *)p, "NaN", (const char **)&p)) {
  23490                 d = NAN;
  23491                 goto done;
  23492             } else if (*p != '.') {
  23493                 goto unexpected_token;
  23494             }
  23495         } else {
  23496             goto unexpected_token;
  23497         }
  23498     }
  23499 
  23500     if (p[0] == '0') {
  23501         if (s->ext_json) {
  23502             /* also accepts base 16, 8 and 2 prefix for integers */
  23503             radix = 10;
  23504             if (p[1] == 'x' || p[1] == 'X') {
  23505                 p += 2;
  23506                 radix = 16;
  23507             } else if ((p[1] == 'o' || p[1] == 'O')) {
  23508                 p += 2;
  23509                 radix = 8;
  23510             } else if ((p[1] == 'b' || p[1] == 'B')) {
  23511                 p += 2;
  23512                 radix = 2;
  23513             }
  23514             if (radix != 10) {
  23515                 /* prefix is present */
  23516                 if (to_digit(*p) >= radix) {
  23517                 unexpected_token:
  23518                     return js_parse_error_pos(s, p, "Unexpected token '%c'", *p);
  23519                 }
  23520                 d = js_atod((const char *)p_start, (const char **)&p, 0,
  23521                             JS_ATOD_INT_ONLY | JS_ATOD_ACCEPT_BIN_OCT, &atod_mem);
  23522                 goto done;
  23523             }
  23524         }
  23525         if (is_digit(p[1]))
  23526             return js_parse_error_pos(s, p, "Unexpected number");
  23527     }
  23528 
  23529     while (is_digit(*p))
  23530         p++;
  23531 
  23532     if (*p == '.') {
  23533         p++;
  23534         if (!is_digit(*p))
  23535             return js_parse_error_pos(s, p, "Unterminated fractional number");
  23536         while (is_digit(*p))
  23537             p++;
  23538     }
  23539     if (*p == 'e' || *p == 'E') {
  23540         p++;
  23541         if (*p == '+' || *p == '-')
  23542             p++;
  23543         if (!is_digit(*p))
  23544             return js_parse_error_pos(s, p, "Exponent part is missing a number");
  23545         while (is_digit(*p))
  23546             p++;
  23547     }
  23548     d = js_atod((const char *)p_start, NULL, 10, 0, &atod_mem);
  23549  done:
  23550     s->token.val = TOK_NUMBER;
  23551     s->token.u.num.val = JS_NewFloat64(s->ctx, d);
  23552     *pp = p;
  23553     return 0;
  23554 }
  23555 
  23556 static __exception int json_next_token(JSParseState *s)
  23557 {
  23558     const uint8_t *p;
  23559     int c;
  23560     JSAtom atom;
  23561 
  23562     if (js_check_stack_overflow(s->ctx->rt, 0)) {
  23563         return js_parse_error(s, "stack overflow");
  23564     }
  23565 
  23566     free_token(s, &s->token);
  23567 
  23568     p = s->last_ptr = s->buf_ptr;
  23569  redo:
  23570     s->token.ptr = p;
  23571     c = *p;
  23572     switch(c) {
  23573     case 0:
  23574         if (p >= s->buf_end) {
  23575             s->token.val = TOK_EOF;
  23576         } else {
  23577             goto def_token;
  23578         }
  23579         break;
  23580     case '\'':
  23581         if (!s->ext_json) {
  23582             /* JSON does not accept single quoted strings */
  23583             goto def_token;
  23584         }
  23585         /* fall through */
  23586     case '\"':
  23587         p++;
  23588         if (json_parse_string(s, &p, c))
  23589             goto fail;
  23590         break;
  23591     case '\r':  /* accept DOS and MAC newline sequences */
  23592         if (p[1] == '\n') {
  23593             p++;
  23594         }
  23595         /* fall thru */
  23596     case '\n':
  23597         p++;
  23598         goto redo;
  23599     case '\f':
  23600     case '\v':
  23601         if (!s->ext_json) {
  23602             /* JSONWhitespace does not match <VT>, nor <FF> */
  23603             goto def_token;
  23604         }
  23605         /* fall through */
  23606     case ' ':
  23607     case '\t':
  23608         p++;
  23609         goto redo;
  23610     case '/':
  23611         if (!s->ext_json) {
  23612             /* JSON does not accept comments */
  23613             goto def_token;
  23614         }
  23615         if (p[1] == '*') {
  23616             /* comment */
  23617             p += 2;
  23618             for(;;) {
  23619                 if (*p == '\0' && p >= s->buf_end) {
  23620                     js_parse_error(s, "unexpected end of comment");
  23621                     goto fail;
  23622                 }
  23623                 if (p[0] == '*' && p[1] == '/') {
  23624                     p += 2;
  23625                     break;
  23626                 }
  23627                 if (*p >= 0x80) {
  23628                     c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
  23629                     if (c == -1) {
  23630                         p++; /* skip invalid UTF-8 */
  23631                     }
  23632                 } else {
  23633                     p++;
  23634                 }
  23635             }
  23636             goto redo;
  23637         } else if (p[1] == '/') {
  23638             /* line comment */
  23639             p += 2;
  23640             for(;;) {
  23641                 if (*p == '\0' && p >= s->buf_end)
  23642                     break;
  23643                 if (*p == '\r' || *p == '\n')
  23644                     break;
  23645                 if (*p >= 0x80) {
  23646                     c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
  23647                     /* LS or PS are considered as line terminator */
  23648                     if (c == CP_LS || c == CP_PS) {
  23649                         break;
  23650                     } else if (c == -1) {
  23651                         p++; /* skip invalid UTF-8 */
  23652                     }
  23653                 } else {
  23654                     p++;
  23655                 }
  23656             }
  23657             goto redo;
  23658         } else {
  23659             goto def_token;
  23660         }
  23661         break;
  23662     case 'a': case 'b': case 'c': case 'd':
  23663     case 'e': case 'f': case 'g': case 'h':
  23664     case 'i': case 'j': case 'k': case 'l':
  23665     case 'm': case 'n': case 'o': case 'p':
  23666     case 'q': case 'r': case 's': case 't':
  23667     case 'u': case 'v': case 'w': case 'x':
  23668     case 'y': case 'z':
  23669     case 'A': case 'B': case 'C': case 'D':
  23670     case 'E': case 'F': case 'G': case 'H':
  23671     case 'I': case 'J': case 'K': case 'L':
  23672     case 'M': case 'N': case 'O': case 'P':
  23673     case 'Q': case 'R': case 'S': case 'T':
  23674     case 'U': case 'V': case 'W': case 'X':
  23675     case 'Y': case 'Z':
  23676     case '_':
  23677     case '$':
  23678         p++;
  23679         atom = json_parse_ident(s, &p, c);
  23680         if (atom == JS_ATOM_NULL)
  23681             goto fail;
  23682         s->token.u.ident.atom = atom;
  23683         s->token.u.ident.has_escape = FALSE;
  23684         s->token.u.ident.is_reserved = FALSE;
  23685         s->token.val = TOK_IDENT;
  23686         break;
  23687     case '+':
  23688         if (!s->ext_json)
  23689             goto def_token;
  23690         goto parse_number;
  23691     case '.':
  23692         if (s->ext_json && is_digit(p[1]))
  23693             goto parse_number;
  23694         else
  23695             goto def_token;
  23696     case '-':
  23697     case '0':
  23698     case '1': case '2': case '3': case '4':
  23699     case '5': case '6': case '7': case '8':
  23700     case '9':
  23701         /* number */
  23702     parse_number:
  23703         if (json_parse_number(s, &p))
  23704             goto fail;
  23705         break;
  23706     default:
  23707         if (c >= 128) {
  23708             js_parse_error(s, "unexpected character");
  23709             goto fail;
  23710         }
  23711     def_token:
  23712         s->token.val = c;
  23713         p++;
  23714         break;
  23715     }
  23716     s->buf_ptr = p;
  23717 
  23718     //    dump_token(s, &s->token);
  23719     return 0;
  23720 
  23721  fail:
  23722     s->token.val = TOK_ERROR;
  23723     return -1;
  23724 }
  23725 
  23726 static int match_identifier(const uint8_t *p, const char *s) {
  23727     uint32_t c;
  23728     while (*s) {
  23729         if ((uint8_t)*s++ != *p++)
  23730             return 0;
  23731     }
  23732     c = *p;
  23733     if (c >= 128)
  23734         c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
  23735     return !lre_js_is_ident_next(c);
  23736 }
  23737 
  23738 /* simple_next_token() is used to check for the next token in simple cases.
  23739    It is only used for ':' and '=>', 'let' or 'function' look-ahead.
  23740    (*pp) is only set if TOK_IMPORT is returned for JS_DetectModule()
  23741    Whitespace and comments are skipped correctly.
  23742    Then the next token is analyzed, only for specific words.
  23743    Return values:
  23744    - '\n' if !no_line_terminator
  23745    - TOK_ARROW, TOK_IN, TOK_IMPORT, TOK_OF, TOK_EXPORT, TOK_FUNCTION
  23746    - TOK_IDENT is returned for other identifiers and keywords
  23747    - otherwise the next character or unicode codepoint is returned.
  23748  */
  23749 static int simple_next_token(const uint8_t **pp, BOOL no_line_terminator)
  23750 {
  23751     const uint8_t *p;
  23752     uint32_t c;
  23753 
  23754     /* skip spaces and comments */
  23755     p = *pp;
  23756     for (;;) {
  23757         switch(c = *p++) {
  23758         case '\r':
  23759         case '\n':
  23760             if (no_line_terminator)
  23761                 return '\n';
  23762             continue;
  23763         case ' ':
  23764         case '\t':
  23765         case '\v':
  23766         case '\f':
  23767             continue;
  23768         case '/':
  23769             if (*p == '/') {
  23770                 if (no_line_terminator)
  23771                     return '\n';
  23772                 while (*p && *p != '\r' && *p != '\n')
  23773                     p++;
  23774                 continue;
  23775             }
  23776             if (*p == '*') {
  23777                 while (*++p) {
  23778                     if ((*p == '\r' || *p == '\n') && no_line_terminator)
  23779                         return '\n';
  23780                     if (*p == '*' && p[1] == '/') {
  23781                         p += 2;
  23782                         break;
  23783                     }
  23784                 }
  23785                 continue;
  23786             }
  23787             break;
  23788         case '=':
  23789             if (*p == '>')
  23790                 return TOK_ARROW;
  23791             break;
  23792         case 'i':
  23793             if (match_identifier(p, "n"))
  23794                 return TOK_IN;
  23795             if (match_identifier(p, "mport")) {
  23796                 *pp = p + 5;
  23797                 return TOK_IMPORT;
  23798             }
  23799             return TOK_IDENT;
  23800         case 'o':
  23801             if (match_identifier(p, "f"))
  23802                 return TOK_OF;
  23803             return TOK_IDENT;
  23804         case 'e':
  23805             if (match_identifier(p, "xport"))
  23806                 return TOK_EXPORT;
  23807             return TOK_IDENT;
  23808         case 'f':
  23809             if (match_identifier(p, "unction"))
  23810                 return TOK_FUNCTION;
  23811             return TOK_IDENT;
  23812         case '\\':
  23813             if (*p == 'u') {
  23814                 if (lre_js_is_ident_first(lre_parse_escape(&p, TRUE)))
  23815                     return TOK_IDENT;
  23816             }
  23817             break;
  23818         default:
  23819             if (c >= 128) {
  23820                 c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p);
  23821                 if (no_line_terminator && (c == CP_PS || c == CP_LS))
  23822                     return '\n';
  23823             }
  23824             if (lre_is_space(c))
  23825                 continue;
  23826             if (lre_js_is_ident_first(c))
  23827                 return TOK_IDENT;
  23828             break;
  23829         }
  23830         return c;
  23831     }
  23832 }
  23833 
  23834 static int peek_token(JSParseState *s, BOOL no_line_terminator)
  23835 {
  23836     const uint8_t *p = s->buf_ptr;
  23837     return simple_next_token(&p, no_line_terminator);
  23838 }
  23839 
  23840 static void skip_shebang(const uint8_t **pp, const uint8_t *buf_end)
  23841 {
  23842     const uint8_t *p = *pp;
  23843     int c;
  23844 
  23845     if (p[0] == '#' && p[1] == '!') {
  23846         p += 2;
  23847         while (p < buf_end) {
  23848             if (*p == '\n' || *p == '\r') {
  23849                 break;
  23850             } else if (*p >= 0x80) {
  23851                 c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
  23852                 if (c == CP_LS || c == CP_PS) {
  23853                     break;
  23854                 } else if (c == -1) {
  23855                     p++; /* skip invalid UTF-8 */
  23856                 }
  23857             } else {
  23858                 p++;
  23859             }
  23860         }
  23861         *pp = p;
  23862     }
  23863 }
  23864 
  23865 /* return true if 'input' contains the source of a module
  23866    (heuristic). 'input' must be a zero terminated.
  23867 
  23868    Heuristic: skip comments and expect 'import' keyword not followed
  23869    by '(' or '.' or export keyword.
  23870 */
  23871 BOOL JS_DetectModule(const char *input, size_t input_len)
  23872 {
  23873     const uint8_t *p = (const uint8_t *)input;
  23874     int tok;
  23875 
  23876     skip_shebang(&p, p + input_len);
  23877     switch(simple_next_token(&p, FALSE)) {
  23878     case TOK_IMPORT:
  23879         tok = simple_next_token(&p, FALSE);
  23880         return (tok != '.' && tok != '(');
  23881     case TOK_EXPORT:
  23882         return TRUE;
  23883     default:
  23884         return FALSE;
  23885     }
  23886 }
  23887 
  23888 static inline int get_prev_opcode(JSFunctionDef *fd) {
  23889     if (fd->last_opcode_pos < 0 || dbuf_error(&fd->byte_code))
  23890         return OP_invalid;
  23891     else
  23892         return fd->byte_code.buf[fd->last_opcode_pos];
  23893 }
  23894 
  23895 static BOOL js_is_live_code(JSParseState *s) {
  23896     switch (get_prev_opcode(s->cur_func)) {
  23897     case OP_tail_call:
  23898     case OP_tail_call_method:
  23899     case OP_return:
  23900     case OP_return_undef:
  23901     case OP_return_async:
  23902     case OP_throw:
  23903     case OP_throw_error:
  23904     case OP_goto:
  23905 #if SHORT_OPCODES
  23906     case OP_goto8:
  23907     case OP_goto16:
  23908 #endif
  23909     case OP_ret:
  23910         return FALSE;
  23911     default:
  23912         return TRUE;
  23913     }
  23914 }
  23915 
  23916 static void emit_u8(JSParseState *s, uint8_t val)
  23917 {
  23918     dbuf_putc(&s->cur_func->byte_code, val);
  23919 }
  23920 
  23921 static void emit_u16(JSParseState *s, uint16_t val)
  23922 {
  23923     dbuf_put_u16(&s->cur_func->byte_code, val);
  23924 }
  23925 
  23926 static void emit_u32(JSParseState *s, uint32_t val)
  23927 {
  23928     dbuf_put_u32(&s->cur_func->byte_code, val);
  23929 }
  23930 
  23931 static void emit_source_pos(JSParseState *s, const uint8_t *source_ptr)
  23932 {
  23933     JSFunctionDef *fd = s->cur_func;
  23934     DynBuf *bc = &fd->byte_code;
  23935 
  23936     if (unlikely(fd->last_opcode_source_ptr != source_ptr)) {
  23937         dbuf_putc(bc, OP_line_num);
  23938         dbuf_put_u32(bc, source_ptr - s->buf_start);
  23939         fd->last_opcode_source_ptr = source_ptr;
  23940     }
  23941 }
  23942 
  23943 static void emit_op(JSParseState *s, uint8_t val)
  23944 {
  23945     JSFunctionDef *fd = s->cur_func;
  23946     DynBuf *bc = &fd->byte_code;
  23947 
  23948     fd->last_opcode_pos = bc->size;
  23949     dbuf_putc(bc, val);
  23950 }
  23951 
  23952 static void emit_atom(JSParseState *s, JSAtom name)
  23953 {
  23954     DynBuf *bc = &s->cur_func->byte_code;
  23955     if (dbuf_claim(bc, 4))
  23956         return; /* not enough memory : don't duplicate the atom */
  23957     put_u32(bc->buf + bc->size, JS_DupAtom(s->ctx, name));
  23958     bc->size += 4;
  23959 }
  23960 
  23961 static int update_label(JSFunctionDef *s, int label, int delta)
  23962 {
  23963     LabelSlot *ls;
  23964 
  23965     assert(label >= 0 && label < s->label_count);
  23966     ls = &s->label_slots[label];
  23967     ls->ref_count += delta;
  23968     assert(ls->ref_count >= 0);
  23969     return ls->ref_count;
  23970 }
  23971 
  23972 static int new_label_fd(JSFunctionDef *fd)
  23973 {
  23974     int label;
  23975     LabelSlot *ls;
  23976 
  23977     if (js_resize_array(fd->ctx, (void *)&fd->label_slots,
  23978                         sizeof(fd->label_slots[0]),
  23979                         &fd->label_size, fd->label_count + 1))
  23980         return -1;
  23981     label = fd->label_count++;
  23982     ls = &fd->label_slots[label];
  23983     ls->ref_count = 0;
  23984     ls->pos = -1;
  23985     ls->pos2 = -1;
  23986     ls->addr = -1;
  23987     ls->first_reloc = NULL;
  23988     return label;
  23989 }
  23990 
  23991 static int new_label(JSParseState *s)
  23992 {
  23993     int label;
  23994     label = new_label_fd(s->cur_func);
  23995     if (unlikely(label < 0)) {
  23996         dbuf_set_error(&s->cur_func->byte_code);
  23997     }
  23998     return label;
  23999 }
  24000 
  24001 /* don't update the last opcode and don't emit line number info */
  24002 static void emit_label_raw(JSParseState *s, int label)
  24003 {
  24004     emit_u8(s, OP_label);
  24005     emit_u32(s, label);
  24006     s->cur_func->label_slots[label].pos = s->cur_func->byte_code.size;
  24007 }
  24008 
  24009 /* return the label ID offset */
  24010 static int emit_label(JSParseState *s, int label)
  24011 {
  24012     if (label >= 0) {
  24013         emit_op(s, OP_label);
  24014         emit_u32(s, label);
  24015         s->cur_func->label_slots[label].pos = s->cur_func->byte_code.size;
  24016         return s->cur_func->byte_code.size - 4;
  24017     } else {
  24018         return -1;
  24019     }
  24020 }
  24021 
  24022 /* return label or -1 if dead code */
  24023 static int emit_goto(JSParseState *s, int opcode, int label)
  24024 {
  24025     if (js_is_live_code(s)) {
  24026         if (label < 0) {
  24027             label = new_label(s);
  24028             if (label < 0)
  24029                 return -1;
  24030         }
  24031         emit_op(s, opcode);
  24032         emit_u32(s, label);
  24033         s->cur_func->label_slots[label].ref_count++;
  24034         return label;
  24035     }
  24036     return -1;
  24037 }
  24038 
  24039 /* return the constant pool index. 'val' is not duplicated. */
  24040 static int cpool_add(JSParseState *s, JSValue val)
  24041 {
  24042     JSFunctionDef *fd = s->cur_func;
  24043 
  24044     if (js_resize_array(s->ctx, (void *)&fd->cpool, sizeof(fd->cpool[0]),
  24045                         &fd->cpool_size, fd->cpool_count + 1)) {
  24046         JS_FreeValue(s->ctx, val);
  24047         return -1;
  24048     }
  24049     fd->cpool[fd->cpool_count++] = val;
  24050     return fd->cpool_count - 1;
  24051 }
  24052 
  24053 static __exception int emit_push_const(JSParseState *s, JSValueConst val,
  24054                                        BOOL as_atom)
  24055 {
  24056     int idx;
  24057 
  24058     if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING && as_atom) {
  24059         JSAtom atom;
  24060         /* warning: JS_NewAtomStr frees the string value */
  24061         JS_DupValue(s->ctx, val);
  24062         atom = JS_NewAtomStr(s->ctx, JS_VALUE_GET_STRING(val));
  24063         if (atom != JS_ATOM_NULL && !__JS_AtomIsTaggedInt(atom)) {
  24064             emit_op(s, OP_push_atom_value);
  24065             emit_u32(s, atom);
  24066             return 0;
  24067         }
  24068     }
  24069 
  24070     idx = cpool_add(s, JS_DupValue(s->ctx, val));
  24071     if (idx < 0)
  24072         return -1;
  24073     emit_op(s, OP_push_const);
  24074     emit_u32(s, idx);
  24075     return 0;
  24076 }
  24077 
  24078 /* return the variable index or -1 if not found,
  24079    add ARGUMENT_VAR_OFFSET for argument variables */
  24080 static int find_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
  24081 {
  24082     int i;
  24083     for(i = fd->arg_count; i-- > 0;) {
  24084         if (fd->args[i].var_name == name)
  24085             return i | ARGUMENT_VAR_OFFSET;
  24086     }
  24087     return -1;
  24088 }
  24089 
  24090 static int find_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
  24091 {
  24092     int i;
  24093     for(i = fd->var_count; i-- > 0;) {
  24094         if (fd->vars[i].var_name == name && fd->vars[i].scope_level == 0)
  24095             return i;
  24096     }
  24097     return find_arg(ctx, fd, name);
  24098 }
  24099 
  24100 /* find a variable declaration in a given scope */
  24101 static int find_var_in_scope(JSContext *ctx, JSFunctionDef *fd,
  24102                              JSAtom name, int scope_level)
  24103 {
  24104     int scope_idx;
  24105     for(scope_idx = fd->scopes[scope_level].first; scope_idx >= 0;
  24106         scope_idx = fd->vars[scope_idx].scope_next) {
  24107         if (fd->vars[scope_idx].scope_level != scope_level)
  24108             break;
  24109         if (fd->vars[scope_idx].var_name == name)
  24110             return scope_idx;
  24111     }
  24112     return -1;
  24113 }
  24114 
  24115 /* return true if scope == parent_scope or if scope is a child of
  24116    parent_scope */
  24117 static BOOL is_child_scope(JSContext *ctx, JSFunctionDef *fd,
  24118                            int scope, int parent_scope)
  24119 {
  24120     while (scope >= 0) {
  24121         if (scope == parent_scope)
  24122             return TRUE;
  24123         scope = fd->scopes[scope].parent;
  24124     }
  24125     return FALSE;
  24126 }
  24127 
  24128 /* find a 'var' declaration in the same scope or a child scope */
  24129 static int find_var_in_child_scope(JSContext *ctx, JSFunctionDef *fd,
  24130                                    JSAtom name, int scope_level)
  24131 {
  24132     int i;
  24133     for(i = 0; i < fd->var_count; i++) {
  24134         JSVarDef *vd = &fd->vars[i];
  24135         if (vd->var_name == name && vd->scope_level == 0) {
  24136             if (is_child_scope(ctx, fd, vd->scope_next,
  24137                                scope_level))
  24138                 return i;
  24139         }
  24140     }
  24141     return -1;
  24142 }
  24143 
  24144 
  24145 static JSGlobalVar *find_global_var(JSFunctionDef *fd, JSAtom name)
  24146 {
  24147     int i;
  24148     for(i = 0; i < fd->global_var_count; i++) {
  24149         JSGlobalVar *hf = &fd->global_vars[i];
  24150         if (hf->var_name == name)
  24151             return hf;
  24152     }
  24153     return NULL;
  24154 
  24155 }
  24156 
  24157 static JSGlobalVar *find_lexical_global_var(JSFunctionDef *fd, JSAtom name)
  24158 {
  24159     JSGlobalVar *hf = find_global_var(fd, name);
  24160     if (hf && hf->is_lexical)
  24161         return hf;
  24162     else
  24163         return NULL;
  24164 }
  24165 
  24166 static int find_lexical_decl(JSContext *ctx, JSFunctionDef *fd, JSAtom name,
  24167                              int scope_idx, BOOL check_catch_var)
  24168 {
  24169     while (scope_idx >= 0) {
  24170         JSVarDef *vd = &fd->vars[scope_idx];
  24171         if (vd->var_name == name &&
  24172             (vd->is_lexical || (vd->var_kind == JS_VAR_CATCH &&
  24173                                 check_catch_var)))
  24174             return scope_idx;
  24175         scope_idx = vd->scope_next;
  24176     }
  24177 
  24178     if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_GLOBAL) {
  24179         if (find_lexical_global_var(fd, name))
  24180             return GLOBAL_VAR_OFFSET;
  24181     }
  24182     return -1;
  24183 }
  24184 
  24185 static int push_scope(JSParseState *s) {
  24186     if (s->cur_func) {
  24187         JSFunctionDef *fd = s->cur_func;
  24188         int scope = fd->scope_count;
  24189         /* XXX: should check for scope overflow */
  24190         if ((fd->scope_count + 1) > fd->scope_size) {
  24191             int new_size;
  24192             size_t slack;
  24193             JSVarScope *new_buf;
  24194             /* XXX: potential arithmetic overflow */
  24195             new_size = max_int(fd->scope_count + 1, fd->scope_size * 3 / 2);
  24196             if (fd->scopes == fd->def_scope_array) {
  24197                 new_buf = js_realloc2(s->ctx, NULL, new_size * sizeof(*fd->scopes), &slack);
  24198                 if (!new_buf)
  24199                     return -1;
  24200                 memcpy(new_buf, fd->scopes, fd->scope_count * sizeof(*fd->scopes));
  24201             } else {
  24202                 new_buf = js_realloc2(s->ctx, fd->scopes, new_size * sizeof(*fd->scopes), &slack);
  24203                 if (!new_buf)
  24204                     return -1;
  24205             }
  24206             new_size += slack / sizeof(*new_buf);
  24207             fd->scopes = new_buf;
  24208             fd->scope_size = new_size;
  24209         }
  24210         fd->scope_count++;
  24211         fd->scopes[scope].parent = fd->scope_level;
  24212         fd->scopes[scope].first = fd->scope_first;
  24213         emit_op(s, OP_enter_scope);
  24214         emit_u16(s, scope);
  24215         return fd->scope_level = scope;
  24216     }
  24217     return 0;
  24218 }
  24219 
  24220 static int get_first_lexical_var(JSFunctionDef *fd, int scope)
  24221 {
  24222     while (scope >= 0) {
  24223         int scope_idx = fd->scopes[scope].first;
  24224         if (scope_idx >= 0)
  24225             return scope_idx;
  24226         scope = fd->scopes[scope].parent;
  24227     }
  24228     return -1;
  24229 }
  24230 
  24231 static void pop_scope(JSParseState *s) {
  24232     if (s->cur_func) {
  24233         /* disable scoped variables */
  24234         JSFunctionDef *fd = s->cur_func;
  24235         int scope = fd->scope_level;
  24236         emit_op(s, OP_leave_scope);
  24237         emit_u16(s, scope);
  24238         fd->scope_level = fd->scopes[scope].parent;
  24239         fd->scope_first = get_first_lexical_var(fd, fd->scope_level);
  24240     }
  24241 }
  24242 
  24243 static void close_scopes(JSParseState *s, int scope, int scope_stop)
  24244 {
  24245     while (scope > scope_stop) {
  24246         emit_op(s, OP_leave_scope);
  24247         emit_u16(s, scope);
  24248         scope = s->cur_func->scopes[scope].parent;
  24249     }
  24250 }
  24251 
  24252 /* return the variable index or -1 if error */
  24253 static int add_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
  24254 {
  24255     JSVarDef *vd;
  24256 
  24257     /* the local variable indexes are currently stored on 16 bits */
  24258     if (fd->var_count >= JS_MAX_LOCAL_VARS) {
  24259         JS_ThrowInternalError(ctx, "too many local variables");
  24260         return -1;
  24261     }
  24262     if (js_resize_array(ctx, (void **)&fd->vars, sizeof(fd->vars[0]),
  24263                         &fd->var_size, fd->var_count + 1))
  24264         return -1;
  24265     vd = &fd->vars[fd->var_count++];
  24266     memset(vd, 0, sizeof(*vd));
  24267     vd->var_name = JS_DupAtom(ctx, name);
  24268     vd->func_pool_idx = -1;
  24269     return fd->var_count - 1;
  24270 }
  24271 
  24272 static int add_scope_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name,
  24273                          JSVarKindEnum var_kind)
  24274 {
  24275     int idx = add_var(ctx, fd, name);
  24276     if (idx >= 0) {
  24277         JSVarDef *vd = &fd->vars[idx];
  24278         vd->var_kind = var_kind;
  24279         vd->scope_level = fd->scope_level;
  24280         vd->scope_next = fd->scope_first;
  24281         fd->scopes[fd->scope_level].first = idx;
  24282         fd->scope_first = idx;
  24283     }
  24284     return idx;
  24285 }
  24286 
  24287 static int add_func_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
  24288 {
  24289     int idx = fd->func_var_idx;
  24290     if (idx < 0 && (idx = add_var(ctx, fd, name)) >= 0) {
  24291         fd->func_var_idx = idx;
  24292         fd->vars[idx].var_kind = JS_VAR_FUNCTION_NAME;
  24293         if (fd->js_mode & JS_MODE_STRICT)
  24294             fd->vars[idx].is_const = TRUE;
  24295     }
  24296     return idx;
  24297 }
  24298 
  24299 static int add_arguments_var(JSContext *ctx, JSFunctionDef *fd)
  24300 {
  24301     int idx = fd->arguments_var_idx;
  24302     if (idx < 0 && (idx = add_var(ctx, fd, JS_ATOM_arguments)) >= 0) {
  24303         fd->arguments_var_idx = idx;
  24304     }
  24305     return idx;
  24306 }
  24307 
  24308 /* add an argument definition in the argument scope. Only needed when
  24309    "eval()" may be called in the argument scope. Return 0 if OK. */
  24310 static int add_arguments_arg(JSContext *ctx, JSFunctionDef *fd)
  24311 {
  24312     int idx;
  24313     if (fd->arguments_arg_idx < 0) {
  24314         idx = find_var_in_scope(ctx, fd, JS_ATOM_arguments, ARG_SCOPE_INDEX);
  24315         if (idx < 0) {
  24316             /* XXX: the scope links are not fully updated. May be an
  24317                issue if there are child scopes of the argument
  24318                scope */
  24319             idx = add_var(ctx, fd, JS_ATOM_arguments);
  24320             if (idx < 0)
  24321                 return -1;
  24322             fd->vars[idx].scope_next = fd->scopes[ARG_SCOPE_INDEX].first;
  24323             fd->scopes[ARG_SCOPE_INDEX].first = idx;
  24324             fd->vars[idx].scope_level = ARG_SCOPE_INDEX;
  24325             fd->vars[idx].is_lexical = TRUE;
  24326 
  24327             fd->arguments_arg_idx = idx;
  24328         }
  24329     }
  24330     return 0;
  24331 }
  24332 
  24333 static int add_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
  24334 {
  24335     JSVarDef *vd;
  24336 
  24337     /* the local variable indexes are currently stored on 16 bits */
  24338     if (fd->arg_count >= JS_MAX_LOCAL_VARS) {
  24339         JS_ThrowInternalError(ctx, "too many arguments");
  24340         return -1;
  24341     }
  24342     if (js_resize_array(ctx, (void **)&fd->args, sizeof(fd->args[0]),
  24343                         &fd->arg_size, fd->arg_count + 1))
  24344         return -1;
  24345     vd = &fd->args[fd->arg_count++];
  24346     memset(vd, 0, sizeof(*vd));
  24347     vd->var_name = JS_DupAtom(ctx, name);
  24348     vd->func_pool_idx = -1;
  24349     return fd->arg_count - 1;
  24350 }
  24351 
  24352 /* add a global variable definition */
  24353 static JSGlobalVar *add_global_var(JSContext *ctx, JSFunctionDef *s,
  24354                                      JSAtom name)
  24355 {
  24356     JSGlobalVar *hf;
  24357 
  24358     if (js_resize_array(ctx, (void **)&s->global_vars,
  24359                         sizeof(s->global_vars[0]),
  24360                         &s->global_var_size, s->global_var_count + 1))
  24361         return NULL;
  24362     hf = &s->global_vars[s->global_var_count++];
  24363     hf->cpool_idx = -1;
  24364     hf->force_init = FALSE;
  24365     hf->is_lexical = FALSE;
  24366     hf->is_const = FALSE;
  24367     hf->scope_level = s->scope_level;
  24368     hf->var_name = JS_DupAtom(ctx, name);
  24369     return hf;
  24370 }
  24371 
  24372 typedef enum {
  24373     JS_VAR_DEF_WITH,
  24374     JS_VAR_DEF_LET,
  24375     JS_VAR_DEF_CONST,
  24376     JS_VAR_DEF_FUNCTION_DECL, /* function declaration */
  24377     JS_VAR_DEF_NEW_FUNCTION_DECL, /* async/generator function declaration */
  24378     JS_VAR_DEF_CATCH,
  24379     JS_VAR_DEF_VAR,
  24380 } JSVarDefEnum;
  24381 
  24382 static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
  24383                       JSVarDefEnum var_def_type)
  24384 {
  24385     JSContext *ctx = s->ctx;
  24386     JSVarDef *vd;
  24387     int idx;
  24388 
  24389     switch (var_def_type) {
  24390     case JS_VAR_DEF_WITH:
  24391         idx = add_scope_var(ctx, fd, name, JS_VAR_NORMAL);
  24392         break;
  24393 
  24394     case JS_VAR_DEF_LET:
  24395     case JS_VAR_DEF_CONST:
  24396     case JS_VAR_DEF_FUNCTION_DECL:
  24397     case JS_VAR_DEF_NEW_FUNCTION_DECL:
  24398         idx = find_lexical_decl(ctx, fd, name, fd->scope_first, TRUE);
  24399         if (idx >= 0) {
  24400             if (idx < GLOBAL_VAR_OFFSET) {
  24401                 if (fd->vars[idx].scope_level == fd->scope_level) {
  24402                     /* same scope: in non strict mode, functions
  24403                        can be redefined (annex B.3.3.4). */
  24404                     if (!(!(fd->js_mode & JS_MODE_STRICT) &&
  24405                           var_def_type == JS_VAR_DEF_FUNCTION_DECL &&
  24406                           fd->vars[idx].var_kind == JS_VAR_FUNCTION_DECL)) {
  24407                         goto redef_lex_error;
  24408                     }
  24409                 } else if (fd->vars[idx].var_kind == JS_VAR_CATCH && (fd->vars[idx].scope_level + 2) == fd->scope_level) {
  24410                     goto redef_lex_error;
  24411                 }
  24412             } else {
  24413                 if (fd->scope_level == fd->body_scope) {
  24414                 redef_lex_error:
  24415                     /* redefining a scoped var in the same scope: error */
  24416                     return js_parse_error(s, "invalid redefinition of lexical identifier");
  24417                 }
  24418             }
  24419         }
  24420         if (var_def_type != JS_VAR_DEF_FUNCTION_DECL &&
  24421             var_def_type != JS_VAR_DEF_NEW_FUNCTION_DECL &&
  24422             fd->scope_level == fd->body_scope &&
  24423             find_arg(ctx, fd, name) >= 0) {
  24424             /* lexical variable redefines a parameter name */
  24425             return js_parse_error(s, "invalid redefinition of parameter name");
  24426         }
  24427 
  24428         if (find_var_in_child_scope(ctx, fd, name, fd->scope_level) >= 0) {
  24429             return js_parse_error(s, "invalid redefinition of a variable");
  24430         }
  24431 
  24432         if (fd->is_global_var) {
  24433             JSGlobalVar *hf;
  24434             hf = find_global_var(fd, name);
  24435             if (hf && is_child_scope(ctx, fd, hf->scope_level,
  24436                                      fd->scope_level)) {
  24437                 return js_parse_error(s, "invalid redefinition of global identifier");
  24438             }
  24439         }
  24440 
  24441         if (fd->is_eval &&
  24442             (fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
  24443              fd->eval_type == JS_EVAL_TYPE_MODULE) &&
  24444             fd->scope_level == fd->body_scope) {
  24445             JSGlobalVar *hf;
  24446             hf = add_global_var(s->ctx, fd, name);
  24447             if (!hf)
  24448                 return -1;
  24449             hf->is_lexical = TRUE;
  24450             hf->is_const = (var_def_type == JS_VAR_DEF_CONST);
  24451             idx = GLOBAL_VAR_OFFSET;
  24452         } else {
  24453             JSVarKindEnum var_kind;
  24454             if (var_def_type == JS_VAR_DEF_FUNCTION_DECL)
  24455                 var_kind = JS_VAR_FUNCTION_DECL;
  24456             else if (var_def_type == JS_VAR_DEF_NEW_FUNCTION_DECL)
  24457                 var_kind = JS_VAR_NEW_FUNCTION_DECL;
  24458             else
  24459                 var_kind = JS_VAR_NORMAL;
  24460             idx = add_scope_var(ctx, fd, name, var_kind);
  24461             if (idx >= 0) {
  24462                 vd = &fd->vars[idx];
  24463                 vd->is_lexical = 1;
  24464                 vd->is_const = (var_def_type == JS_VAR_DEF_CONST);
  24465             }
  24466         }
  24467         break;
  24468 
  24469     case JS_VAR_DEF_CATCH:
  24470         idx = add_scope_var(ctx, fd, name, JS_VAR_CATCH);
  24471         break;
  24472 
  24473     case JS_VAR_DEF_VAR:
  24474         if (find_lexical_decl(ctx, fd, name, fd->scope_first,
  24475                               FALSE) >= 0) {
  24476        invalid_lexical_redefinition:
  24477             /* error to redefine a var that inside a lexical scope */
  24478             return js_parse_error(s, "invalid redefinition of lexical identifier");
  24479         }
  24480         if (fd->is_global_var) {
  24481             JSGlobalVar *hf;
  24482             hf = find_global_var(fd, name);
  24483             if (hf && hf->is_lexical && hf->scope_level == fd->scope_level &&
  24484                 fd->eval_type == JS_EVAL_TYPE_MODULE) {
  24485                 goto invalid_lexical_redefinition;
  24486             }
  24487             hf = add_global_var(s->ctx, fd, name);
  24488             if (!hf)
  24489                 return -1;
  24490             idx = GLOBAL_VAR_OFFSET;
  24491         } else {
  24492             /* if the variable already exists, don't add it again  */
  24493             idx = find_var(ctx, fd, name);
  24494             if (idx >= 0)
  24495                 break;
  24496             idx = add_var(ctx, fd, name);
  24497             if (idx >= 0) {
  24498                 if (name == JS_ATOM_arguments && fd->has_arguments_binding)
  24499                     fd->arguments_var_idx = idx;
  24500                 fd->vars[idx].scope_next = fd->scope_level;
  24501             }
  24502         }
  24503         break;
  24504     default:
  24505         abort();
  24506     }
  24507     return idx;
  24508 }
  24509 
  24510 /* add a private field variable in the current scope */
  24511 static int add_private_class_field(JSParseState *s, JSFunctionDef *fd,
  24512                                    JSAtom name, JSVarKindEnum var_kind, BOOL is_static)
  24513 {
  24514     JSContext *ctx = s->ctx;
  24515     JSVarDef *vd;
  24516     int idx;
  24517 
  24518     idx = add_scope_var(ctx, fd, name, var_kind);
  24519     if (idx < 0)
  24520         return idx;
  24521     vd = &fd->vars[idx];
  24522     vd->is_lexical = 1;
  24523     vd->is_const = 1;
  24524     vd->is_static_private = is_static;
  24525     return idx;
  24526 }
  24527 
  24528 static __exception int js_parse_expr(JSParseState *s);
  24529 static __exception int js_parse_function_decl(JSParseState *s,
  24530                                               JSParseFunctionEnum func_type,
  24531                                               JSFunctionKindEnum func_kind,
  24532                                               JSAtom func_name, const uint8_t *ptr);
  24533 static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s);
  24534 static __exception int js_parse_function_decl2(JSParseState *s,
  24535                                                JSParseFunctionEnum func_type,
  24536                                                JSFunctionKindEnum func_kind,
  24537                                                JSAtom func_name,
  24538                                                const uint8_t *ptr,
  24539                                                JSParseExportEnum export_flag,
  24540                                                JSFunctionDef **pfd);
  24541 static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags);
  24542 static __exception int js_parse_assign_expr(JSParseState *s);
  24543 static __exception int js_parse_unary(JSParseState *s, int parse_flags);
  24544 static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
  24545                              JSAtom label_name,
  24546                              int label_break, int label_cont,
  24547                              int drop_count);
  24548 static void pop_break_entry(JSFunctionDef *fd);
  24549 static JSExportEntry *add_export_entry(JSParseState *s, JSModuleDef *m,
  24550                                        JSAtom local_name, JSAtom export_name,
  24551                                        JSExportTypeEnum export_type);
  24552 
  24553 /* Note: all the fields are already sealed except length */
  24554 static int seal_template_obj(JSContext *ctx, JSValueConst obj)
  24555 {
  24556     JSObject *p;
  24557     JSShapeProperty *prs;
  24558 
  24559     p = JS_VALUE_GET_OBJ(obj);
  24560     prs = find_own_property1(p, JS_ATOM_length);
  24561     if (prs) {
  24562         if (js_update_property_flags(ctx, p, &prs,
  24563                                      prs->flags & ~(JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)))
  24564             return -1;
  24565     }
  24566     p->extensible = FALSE;
  24567     return 0;
  24568 }
  24569 
  24570 static __exception int js_parse_template(JSParseState *s, int call, int *argc)
  24571 {
  24572     JSContext *ctx = s->ctx;
  24573     JSValue raw_array, template_object;
  24574     JSToken cooked;
  24575     int depth, ret;
  24576 
  24577     raw_array = JS_UNDEFINED; /* avoid warning */
  24578     template_object = JS_UNDEFINED; /* avoid warning */
  24579     if (call) {
  24580         /* Create a template object: an array of cooked strings */
  24581         /* Create an array of raw strings and store it to the raw property */
  24582         template_object = JS_NewArray(ctx);
  24583         if (JS_IsException(template_object))
  24584             return -1;
  24585         //        pool_idx = s->cur_func->cpool_count;
  24586         ret = emit_push_const(s, template_object, 0);
  24587         JS_FreeValue(ctx, template_object);
  24588         if (ret)
  24589             return -1;
  24590         raw_array = JS_NewArray(ctx);
  24591         if (JS_IsException(raw_array))
  24592             return -1;
  24593         if (JS_DefinePropertyValue(ctx, template_object, JS_ATOM_raw,
  24594                                    raw_array, JS_PROP_THROW) < 0) {
  24595             return -1;
  24596         }
  24597     }
  24598 
  24599     depth = 0;
  24600     while (s->token.val == TOK_TEMPLATE) {
  24601         const uint8_t *p = s->token.ptr + 1;
  24602         cooked = s->token;
  24603         if (call) {
  24604             if (JS_DefinePropertyValueUint32(ctx, raw_array, depth,
  24605                                              JS_DupValue(ctx, s->token.u.str.str),
  24606                                              JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) {
  24607                 return -1;
  24608             }
  24609             /* re-parse the string with escape sequences but do not throw a
  24610                syntax error if it contains invalid sequences
  24611              */
  24612             if (js_parse_string(s, '`', FALSE, p, &cooked, &p)) {
  24613                 cooked.u.str.str = JS_UNDEFINED;
  24614             }
  24615             if (JS_DefinePropertyValueUint32(ctx, template_object, depth,
  24616                                              cooked.u.str.str,
  24617                                              JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) {
  24618                 return -1;
  24619             }
  24620         } else {
  24621             JSString *str;
  24622             /* re-parse the string with escape sequences and throw a
  24623                syntax error if it contains invalid sequences
  24624              */
  24625             JS_FreeValue(ctx, s->token.u.str.str);
  24626             s->token.u.str.str = JS_UNDEFINED;
  24627             if (js_parse_string(s, '`', TRUE, p, &cooked, &p))
  24628                 return -1;
  24629             str = JS_VALUE_GET_STRING(cooked.u.str.str);
  24630             if (str->len != 0 || depth == 0) {
  24631                 ret = emit_push_const(s, cooked.u.str.str, 1);
  24632                 JS_FreeValue(s->ctx, cooked.u.str.str);
  24633                 if (ret)
  24634                     return -1;
  24635                 if (depth == 0) {
  24636                     if (s->token.u.str.sep == '`')
  24637                         goto done1;
  24638                     emit_op(s, OP_get_field2);
  24639                     emit_atom(s, JS_ATOM_concat);
  24640                 }
  24641                 depth++;
  24642             } else {
  24643                 JS_FreeValue(s->ctx, cooked.u.str.str);
  24644             }
  24645         }
  24646         if (s->token.u.str.sep == '`')
  24647             goto done;
  24648         if (next_token(s))
  24649             return -1;
  24650         if (js_parse_expr(s))
  24651             return -1;
  24652         depth++;
  24653         if (s->token.val != '}') {
  24654             return js_parse_error(s, "expected '}' after template expression");
  24655         }
  24656         /* XXX: should convert to string at this stage? */
  24657         free_token(s, &s->token);
  24658         /* Resume TOK_TEMPLATE parsing (s->token.line_num and
  24659          * s->token.ptr are OK) */
  24660         s->got_lf = FALSE;
  24661         if (js_parse_template_part(s, s->buf_ptr))
  24662             return -1;
  24663     }
  24664     return js_parse_expect(s, TOK_TEMPLATE);
  24665 
  24666  done:
  24667     if (call) {
  24668         /* Seal the objects */
  24669         seal_template_obj(ctx, raw_array);
  24670         seal_template_obj(ctx, template_object);
  24671         *argc = depth + 1;
  24672     } else {
  24673         emit_op(s, OP_call_method);
  24674         emit_u16(s, depth - 1);
  24675     }
  24676  done1:
  24677     return next_token(s);
  24678 }
  24679 
  24680 
  24681 #define PROP_TYPE_IDENT 0
  24682 #define PROP_TYPE_VAR   1
  24683 #define PROP_TYPE_GET   2
  24684 #define PROP_TYPE_SET   3
  24685 #define PROP_TYPE_STAR  4
  24686 #define PROP_TYPE_ASYNC 5
  24687 #define PROP_TYPE_ASYNC_STAR 6
  24688 
  24689 #define PROP_TYPE_PRIVATE (1 << 4)
  24690 
  24691 static BOOL token_is_ident(int tok)
  24692 {
  24693     /* Accept keywords and reserved words as property names */
  24694     return (tok == TOK_IDENT ||
  24695             (tok >= TOK_FIRST_KEYWORD &&
  24696              tok <= TOK_LAST_KEYWORD));
  24697 }
  24698 
  24699 /* if the property is an expression, name = JS_ATOM_NULL */
  24700 static int __exception js_parse_property_name(JSParseState *s,
  24701                                               JSAtom *pname,
  24702                                               BOOL allow_method, BOOL allow_var,
  24703                                               BOOL allow_private)
  24704 {
  24705     int is_private = 0;
  24706     BOOL is_non_reserved_ident;
  24707     JSAtom name;
  24708     int prop_type;
  24709 
  24710     prop_type = PROP_TYPE_IDENT;
  24711     if (allow_method) {
  24712         /* if allow_private is true (for class field parsing) and
  24713            get/set is following by ';' (or LF with ASI), then it
  24714            is a field name */
  24715         if ((token_is_pseudo_keyword(s, JS_ATOM_get) ||
  24716              token_is_pseudo_keyword(s, JS_ATOM_set)) &&
  24717             (!allow_private || peek_token(s, TRUE) != '\n')) {
  24718             /* get x(), set x() */
  24719             name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
  24720             if (next_token(s))
  24721                 goto fail1;
  24722             if (s->token.val == ':' || s->token.val == ',' ||
  24723                 s->token.val == '}' || s->token.val == '(' ||
  24724                 s->token.val == '=' ||
  24725                 (s->token.val == ';' && allow_private)) {
  24726                 is_non_reserved_ident = TRUE;
  24727                 goto ident_found;
  24728             }
  24729             prop_type = PROP_TYPE_GET + (name == JS_ATOM_set);
  24730             JS_FreeAtom(s->ctx, name);
  24731         } else if (s->token.val == '*') {
  24732             if (next_token(s))
  24733                 goto fail;
  24734             prop_type = PROP_TYPE_STAR;
  24735         } else if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
  24736                    peek_token(s, TRUE) != '\n') {
  24737             name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
  24738             if (next_token(s))
  24739                 goto fail1;
  24740             if (s->token.val == ':' || s->token.val == ',' ||
  24741                 s->token.val == '}' || s->token.val == '(' ||
  24742                 s->token.val == '=') {
  24743                 is_non_reserved_ident = TRUE;
  24744                 goto ident_found;
  24745             }
  24746             JS_FreeAtom(s->ctx, name);
  24747             if (s->token.val == '*') {
  24748                 if (next_token(s))
  24749                     goto fail;
  24750                 prop_type = PROP_TYPE_ASYNC_STAR;
  24751             } else {
  24752                 prop_type = PROP_TYPE_ASYNC;
  24753             }
  24754         }
  24755     }
  24756 
  24757     if (token_is_ident(s->token.val)) {
  24758         /* variable can only be a non-reserved identifier */
  24759         is_non_reserved_ident =
  24760             (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved);
  24761         /* keywords and reserved words have a valid atom */
  24762         name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
  24763         if (next_token(s))
  24764             goto fail1;
  24765     ident_found:
  24766         if (is_non_reserved_ident &&
  24767             prop_type == PROP_TYPE_IDENT && allow_var) {
  24768             if (!(s->token.val == ':' ||
  24769                   (s->token.val == '(' && allow_method))) {
  24770                 prop_type = PROP_TYPE_VAR;
  24771             }
  24772         }
  24773     } else if (s->token.val == TOK_STRING) {
  24774         name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
  24775         if (name == JS_ATOM_NULL)
  24776             goto fail;
  24777         if (next_token(s))
  24778             goto fail1;
  24779     } else if (s->token.val == TOK_NUMBER) {
  24780         JSValue val;
  24781         val = s->token.u.num.val;
  24782         name = JS_ValueToAtom(s->ctx, val);
  24783         if (name == JS_ATOM_NULL)
  24784             goto fail;
  24785         if (next_token(s))
  24786             goto fail1;
  24787     } else if (s->token.val == '[') {
  24788         if (next_token(s))
  24789             goto fail;
  24790         if (js_parse_assign_expr(s))
  24791             goto fail;
  24792         if (js_parse_expect(s, ']'))
  24793             goto fail;
  24794         name = JS_ATOM_NULL;
  24795     } else if (s->token.val == TOK_PRIVATE_NAME && allow_private) {
  24796         name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
  24797         if (next_token(s))
  24798             goto fail1;
  24799         is_private = PROP_TYPE_PRIVATE;
  24800     } else {
  24801         goto invalid_prop;
  24802     }
  24803     if (prop_type != PROP_TYPE_IDENT && prop_type != PROP_TYPE_VAR &&
  24804         s->token.val != '(') {
  24805         JS_FreeAtom(s->ctx, name);
  24806     invalid_prop:
  24807         js_parse_error(s, "invalid property name");
  24808         goto fail;
  24809     }
  24810     *pname = name;
  24811     return prop_type | is_private;
  24812  fail1:
  24813     JS_FreeAtom(s->ctx, name);
  24814  fail:
  24815     *pname = JS_ATOM_NULL;
  24816     return -1;
  24817 }
  24818 
  24819 typedef struct JSParsePos {
  24820     BOOL got_lf;
  24821     const uint8_t *ptr;
  24822 } JSParsePos;
  24823 
  24824 static int js_parse_get_pos(JSParseState *s, JSParsePos *sp)
  24825 {
  24826     sp->ptr = s->token.ptr;
  24827     sp->got_lf = s->got_lf;
  24828     return 0;
  24829 }
  24830 
  24831 static __exception int js_parse_seek_token(JSParseState *s, const JSParsePos *sp)
  24832 {
  24833     s->buf_ptr = sp->ptr;
  24834     s->got_lf = sp->got_lf;
  24835     return next_token(s);
  24836 }
  24837 
  24838 /* return TRUE if a regexp literal is allowed after this token */
  24839 static BOOL is_regexp_allowed(int tok)
  24840 {
  24841     switch (tok) {
  24842     case TOK_NUMBER:
  24843     case TOK_STRING:
  24844     case TOK_REGEXP:
  24845     case TOK_DEC:
  24846     case TOK_INC:
  24847     case TOK_NULL:
  24848     case TOK_FALSE:
  24849     case TOK_TRUE:
  24850     case TOK_THIS:
  24851     case ')':
  24852     case ']':
  24853     case '}': /* XXX: regexp may occur after */
  24854     case TOK_IDENT:
  24855         return FALSE;
  24856     default:
  24857         return TRUE;
  24858     }
  24859 }
  24860 
  24861 #define SKIP_HAS_SEMI       (1 << 0)
  24862 #define SKIP_HAS_ELLIPSIS   (1 << 1)
  24863 #define SKIP_HAS_ASSIGNMENT (1 << 2)
  24864 
  24865 static BOOL has_lf_in_range(const uint8_t *p1, const uint8_t *p2)
  24866 {
  24867     const uint8_t *tmp;
  24868     if (p1 > p2) {
  24869         tmp = p1;
  24870         p1 = p2;
  24871         p2 = tmp;
  24872     }
  24873     return (memchr(p1, '\n', p2 - p1) != NULL);
  24874 }
  24875 
  24876 /* XXX: improve speed with early bailout */
  24877 /* XXX: no longer works if regexps are present. Could use previous
  24878    regexp parsing heuristics to handle most cases */
  24879 static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_terminator)
  24880 {
  24881     char state[256];
  24882     size_t level = 0;
  24883     JSParsePos pos;
  24884     int last_tok, tok = TOK_EOF;
  24885     int c, tok_len, bits = 0;
  24886     const uint8_t *last_token_ptr;
  24887     
  24888     /* protect from underflow */
  24889     state[level++] = 0;
  24890 
  24891     js_parse_get_pos(s, &pos);
  24892     last_tok = 0;
  24893     for (;;) {
  24894         switch(s->token.val) {
  24895         case '(':
  24896         case '[':
  24897         case '{':
  24898             if (level >= sizeof(state))
  24899                 goto done;
  24900             state[level++] = s->token.val;
  24901             break;
  24902         case ')':
  24903             if (state[--level] != '(')
  24904                 goto done;
  24905             break;
  24906         case ']':
  24907             if (state[--level] != '[')
  24908                 goto done;
  24909             break;
  24910         case '}':
  24911             c = state[--level];
  24912             if (c == '`') {
  24913                 /* continue the parsing of the template */
  24914                 free_token(s, &s->token);
  24915                 /* Resume TOK_TEMPLATE parsing (s->token.line_num and
  24916                  * s->token.ptr are OK) */
  24917                 s->got_lf = FALSE;
  24918                 if (js_parse_template_part(s, s->buf_ptr))
  24919                     goto done;
  24920                 goto handle_template;
  24921             } else if (c != '{') {
  24922                 goto done;
  24923             }
  24924             break;
  24925         case TOK_TEMPLATE:
  24926         handle_template:
  24927             if (s->token.u.str.sep != '`') {
  24928                 /* '${' inside the template : closing '}' and continue
  24929                    parsing the template */
  24930                 if (level >= sizeof(state))
  24931                     goto done;
  24932                 state[level++] = '`';
  24933             }
  24934             break;
  24935         case TOK_EOF:
  24936             goto done;
  24937         case ';':
  24938             if (level == 2) {
  24939                 bits |= SKIP_HAS_SEMI;
  24940             }
  24941             break;
  24942         case TOK_ELLIPSIS:
  24943             if (level == 2) {
  24944                 bits |= SKIP_HAS_ELLIPSIS;
  24945             }
  24946             break;
  24947         case '=':
  24948             bits |= SKIP_HAS_ASSIGNMENT;
  24949             break;
  24950 
  24951         case TOK_DIV_ASSIGN:
  24952             tok_len = 2;
  24953             goto parse_regexp;
  24954         case '/':
  24955             tok_len = 1;
  24956         parse_regexp:
  24957             if (is_regexp_allowed(last_tok)) {
  24958                 s->buf_ptr -= tok_len;
  24959                 if (js_parse_regexp(s)) {
  24960                     /* XXX: should clear the exception */
  24961                     goto done;
  24962                 }
  24963             }
  24964             break;
  24965         }
  24966         /* last_tok is only used to recognize regexps */
  24967         if (s->token.val == TOK_IDENT &&
  24968             (token_is_pseudo_keyword(s, JS_ATOM_of) ||
  24969              token_is_pseudo_keyword(s, JS_ATOM_yield))) {
  24970             last_tok = TOK_OF;
  24971         } else {
  24972             last_tok = s->token.val;
  24973         }
  24974         last_token_ptr = s->token.ptr;
  24975         if (next_token(s)) {
  24976             /* XXX: should clear the exception generated by next_token() */
  24977             break;
  24978         }
  24979         if (level <= 1) {
  24980             tok = s->token.val;
  24981             if (token_is_pseudo_keyword(s, JS_ATOM_of))
  24982                 tok = TOK_OF;
  24983             if (no_line_terminator && has_lf_in_range(last_token_ptr, s->token.ptr))
  24984                 tok = '\n';
  24985             break;
  24986         }
  24987     }
  24988  done:
  24989     if (pbits) {
  24990         *pbits = bits;
  24991     }
  24992     if (js_parse_seek_token(s, &pos))
  24993         return -1;
  24994     return tok;
  24995 }
  24996 
  24997 static void set_object_name(JSParseState *s, JSAtom name)
  24998 {
  24999     JSFunctionDef *fd = s->cur_func;
  25000     int opcode;
  25001 
  25002     opcode = get_prev_opcode(fd);
  25003     if (opcode == OP_set_name) {
  25004         /* XXX: should free atom after OP_set_name? */
  25005         fd->byte_code.size = fd->last_opcode_pos;
  25006         fd->last_opcode_pos = -1;
  25007         emit_op(s, OP_set_name);
  25008         emit_atom(s, name);
  25009     } else if (opcode == OP_set_class_name) {
  25010         int define_class_pos;
  25011         JSAtom atom;
  25012         define_class_pos = fd->last_opcode_pos + 1 -
  25013             get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
  25014         assert(fd->byte_code.buf[define_class_pos] == OP_define_class);
  25015         /* for consistency we free the previous atom which is
  25016            JS_ATOM_empty_string */
  25017         atom = get_u32(fd->byte_code.buf + define_class_pos + 1);
  25018         JS_FreeAtom(s->ctx, atom);
  25019         put_u32(fd->byte_code.buf + define_class_pos + 1,
  25020                 JS_DupAtom(s->ctx, name));
  25021         fd->last_opcode_pos = -1;
  25022     }
  25023 }
  25024 
  25025 static void set_object_name_computed(JSParseState *s)
  25026 {
  25027     JSFunctionDef *fd = s->cur_func;
  25028     int opcode;
  25029 
  25030     opcode = get_prev_opcode(fd);
  25031     if (opcode == OP_set_name) {
  25032         /* XXX: should free atom after OP_set_name? */
  25033         fd->byte_code.size = fd->last_opcode_pos;
  25034         fd->last_opcode_pos = -1;
  25035         emit_op(s, OP_set_name_computed);
  25036     } else if (opcode == OP_set_class_name) {
  25037         int define_class_pos;
  25038         define_class_pos = fd->last_opcode_pos + 1 -
  25039             get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
  25040         assert(fd->byte_code.buf[define_class_pos] == OP_define_class);
  25041         fd->byte_code.buf[define_class_pos] = OP_define_class_computed;
  25042         fd->last_opcode_pos = -1;
  25043     }
  25044 }
  25045 
  25046 static __exception int js_parse_object_literal(JSParseState *s)
  25047 {
  25048     JSAtom name = JS_ATOM_NULL;
  25049     const uint8_t *start_ptr;
  25050     int prop_type;
  25051     BOOL has_proto;
  25052 
  25053     if (next_token(s))
  25054         goto fail;
  25055     /* XXX: add an initial length that will be patched back */
  25056     emit_op(s, OP_object);
  25057     has_proto = FALSE;
  25058     while (s->token.val != '}') {
  25059         /* specific case for getter/setter */
  25060         start_ptr = s->token.ptr;
  25061 
  25062         if (s->token.val == TOK_ELLIPSIS) {
  25063             if (next_token(s))
  25064                 return -1;
  25065             if (js_parse_assign_expr(s))
  25066                 return -1;
  25067             emit_op(s, OP_null);  /* dummy excludeList */
  25068             emit_op(s, OP_copy_data_properties);
  25069             emit_u8(s, 2 | (1 << 2) | (0 << 5));
  25070             emit_op(s, OP_drop); /* pop excludeList */
  25071             emit_op(s, OP_drop); /* pop src object */
  25072             goto next;
  25073         }
  25074 
  25075         prop_type = js_parse_property_name(s, &name, TRUE, TRUE, FALSE);
  25076         if (prop_type < 0)
  25077             goto fail;
  25078 
  25079         if (prop_type == PROP_TYPE_VAR) {
  25080             /* shortcut for x: x */
  25081             emit_op(s, OP_scope_get_var);
  25082             emit_atom(s, name);
  25083             emit_u16(s, s->cur_func->scope_level);
  25084             emit_op(s, OP_define_field);
  25085             emit_atom(s, name);
  25086         } else if (s->token.val == '(') {
  25087             BOOL is_getset = (prop_type == PROP_TYPE_GET ||
  25088                               prop_type == PROP_TYPE_SET);
  25089             JSParseFunctionEnum func_type;
  25090             JSFunctionKindEnum func_kind;
  25091             int op_flags;
  25092 
  25093             func_kind = JS_FUNC_NORMAL;
  25094             if (is_getset) {
  25095                 func_type = JS_PARSE_FUNC_GETTER + prop_type - PROP_TYPE_GET;
  25096             } else {
  25097                 func_type = JS_PARSE_FUNC_METHOD;
  25098                 if (prop_type == PROP_TYPE_STAR)
  25099                     func_kind = JS_FUNC_GENERATOR;
  25100                 else if (prop_type == PROP_TYPE_ASYNC)
  25101                     func_kind = JS_FUNC_ASYNC;
  25102                 else if (prop_type == PROP_TYPE_ASYNC_STAR)
  25103                     func_kind = JS_FUNC_ASYNC_GENERATOR;
  25104             }
  25105             if (js_parse_function_decl(s, func_type, func_kind, JS_ATOM_NULL,
  25106                                        start_ptr))
  25107                 goto fail;
  25108             if (name == JS_ATOM_NULL) {
  25109                 emit_op(s, OP_define_method_computed);
  25110             } else {
  25111                 emit_op(s, OP_define_method);
  25112                 emit_atom(s, name);
  25113             }
  25114             if (is_getset) {
  25115                 op_flags = OP_DEFINE_METHOD_GETTER +
  25116                     prop_type - PROP_TYPE_GET;
  25117             } else {
  25118                 op_flags = OP_DEFINE_METHOD_METHOD;
  25119             }
  25120             emit_u8(s, op_flags | OP_DEFINE_METHOD_ENUMERABLE);
  25121         } else {
  25122             if (name == JS_ATOM_NULL) {
  25123                 /* must be done before evaluating expr */
  25124                 emit_op(s, OP_to_propkey);
  25125             }
  25126             if (js_parse_expect(s, ':'))
  25127                 goto fail;
  25128             if (js_parse_assign_expr(s))
  25129                 goto fail;
  25130             if (name == JS_ATOM_NULL) {
  25131                 set_object_name_computed(s);
  25132                 emit_op(s, OP_define_array_el);
  25133                 emit_op(s, OP_drop);
  25134             } else if (name == JS_ATOM___proto__) {
  25135                 if (has_proto) {
  25136                     js_parse_error(s, "duplicate __proto__ property name");
  25137                     goto fail;
  25138                 }
  25139                 emit_op(s, OP_set_proto);
  25140                 has_proto = TRUE;
  25141             } else {
  25142                 set_object_name(s, name);
  25143                 emit_op(s, OP_define_field);
  25144                 emit_atom(s, name);
  25145             }
  25146         }
  25147         JS_FreeAtom(s->ctx, name);
  25148     next:
  25149         name = JS_ATOM_NULL;
  25150         if (s->token.val != ',')
  25151             break;
  25152         if (next_token(s))
  25153             goto fail;
  25154     }
  25155     if (js_parse_expect(s, '}'))
  25156         goto fail;
  25157     return 0;
  25158  fail:
  25159     JS_FreeAtom(s->ctx, name);
  25160     return -1;
  25161 }
  25162 
  25163 /* allow the 'in' binary operator */
  25164 #define PF_IN_ACCEPTED  (1 << 0)
  25165 /* allow function calls parsing in js_parse_postfix_expr() */
  25166 #define PF_POSTFIX_CALL (1 << 1)
  25167 /* allow the exponentiation operator in js_parse_unary() */
  25168 #define PF_POW_ALLOWED  (1 << 2)
  25169 /* forbid the exponentiation operator in js_parse_unary() */
  25170 #define PF_POW_FORBIDDEN (1 << 3)
  25171 
  25172 static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags);
  25173 static void emit_class_field_init(JSParseState *s);
  25174 static JSFunctionDef *js_new_function_def(JSContext *ctx,
  25175                                           JSFunctionDef *parent,
  25176                                           BOOL is_eval,
  25177                                           BOOL is_func_expr,
  25178                                           const char *filename,
  25179                                           const uint8_t *source_ptr,
  25180                                           GetLineColCache *get_line_col_cache);
  25181 static void emit_return(JSParseState *s, BOOL hasval);
  25182 
  25183 static __exception int js_parse_left_hand_side_expr(JSParseState *s)
  25184 {
  25185     return js_parse_postfix_expr(s, PF_POSTFIX_CALL);
  25186 }
  25187 
  25188 static __exception int js_parse_class_default_ctor(JSParseState *s,
  25189                                                    BOOL has_super,
  25190                                                    JSFunctionDef **pfd)
  25191 {
  25192     JSParseFunctionEnum func_type;
  25193     JSFunctionDef *fd = s->cur_func;
  25194     int idx;
  25195 
  25196     fd = js_new_function_def(s->ctx, fd, FALSE, FALSE, s->filename,
  25197                              s->token.ptr, &s->get_line_col_cache);
  25198     if (!fd)
  25199         return -1;
  25200 
  25201     s->cur_func = fd;
  25202     fd->has_home_object = TRUE;
  25203     fd->super_allowed = TRUE;
  25204     fd->has_prototype = FALSE;
  25205     fd->has_this_binding = TRUE;
  25206     fd->new_target_allowed = TRUE;
  25207 
  25208     push_scope(s);  /* enter body scope */
  25209     fd->body_scope = fd->scope_level;
  25210     if (has_super) {
  25211         fd->is_derived_class_constructor = TRUE;
  25212         fd->super_call_allowed = TRUE;
  25213         fd->arguments_allowed = TRUE;
  25214         fd->has_arguments_binding = TRUE;
  25215         func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR;
  25216         emit_op(s, OP_init_ctor);
  25217         // TODO(bnoordhuis) roll into OP_init_ctor
  25218         emit_op(s, OP_scope_put_var_init);
  25219         emit_atom(s, JS_ATOM_this);
  25220         emit_u16(s, 0);
  25221         emit_class_field_init(s);
  25222     } else {
  25223         func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;
  25224         /* error if not invoked as a constructor */
  25225         emit_op(s, OP_check_ctor);
  25226         emit_class_field_init(s);
  25227     }
  25228 
  25229     fd->func_kind = JS_FUNC_NORMAL;
  25230     fd->func_type = func_type;
  25231     emit_return(s, FALSE);
  25232 
  25233     s->cur_func = fd->parent;
  25234     if (pfd)
  25235         *pfd = fd;
  25236 
  25237     /* the real object will be set at the end of the compilation */
  25238     idx = cpool_add(s, JS_NULL);
  25239     fd->parent_cpool_idx = idx;
  25240 
  25241     return 0;
  25242 }
  25243 
  25244 /* find field in the current scope */
  25245 static int find_private_class_field(JSContext *ctx, JSFunctionDef *fd,
  25246                                     JSAtom name, int scope_level)
  25247 {
  25248     int idx;
  25249     idx = fd->scopes[scope_level].first;
  25250     while (idx != -1) {
  25251         if (fd->vars[idx].scope_level != scope_level)
  25252             break;
  25253         if (fd->vars[idx].var_name == name)
  25254             return idx;
  25255         idx = fd->vars[idx].scope_next;
  25256     }
  25257     return -1;
  25258 }
  25259 
  25260 /* initialize the class fields, called by the constructor. Note:
  25261    super() can be called in an arrow function, so <this> and
  25262    <class_fields_init> can be variable references */
  25263 static void emit_class_field_init(JSParseState *s)
  25264 {
  25265     int label_next;
  25266 
  25267     emit_op(s, OP_scope_get_var);
  25268     emit_atom(s, JS_ATOM_class_fields_init);
  25269     emit_u16(s, s->cur_func->scope_level);
  25270 
  25271     /* no need to call the class field initializer if not defined */
  25272     emit_op(s, OP_dup);
  25273     label_next = emit_goto(s, OP_if_false, -1);
  25274 
  25275     emit_op(s, OP_scope_get_var);
  25276     emit_atom(s, JS_ATOM_this);
  25277     emit_u16(s, 0);
  25278 
  25279     emit_op(s, OP_swap);
  25280 
  25281     emit_op(s, OP_call_method);
  25282     emit_u16(s, 0);
  25283 
  25284     emit_label(s, label_next);
  25285     emit_op(s, OP_drop);
  25286 }
  25287 
  25288 /* build a private setter function name from the private getter name */
  25289 static JSAtom get_private_setter_name(JSContext *ctx, JSAtom name)
  25290 {
  25291     return js_atom_concat_str(ctx, name, "<set>");
  25292 }
  25293 
  25294 typedef struct {
  25295     JSFunctionDef *fields_init_fd;
  25296     int computed_fields_count;
  25297     BOOL need_brand;
  25298     int brand_push_pos;
  25299     BOOL is_static;
  25300 } ClassFieldsDef;
  25301 
  25302 static __exception int emit_class_init_start(JSParseState *s,
  25303                                              ClassFieldsDef *cf)
  25304 {
  25305     int label_add_brand;
  25306 
  25307     cf->fields_init_fd = js_parse_function_class_fields_init(s);
  25308     if (!cf->fields_init_fd)
  25309         return -1;
  25310 
  25311     s->cur_func = cf->fields_init_fd;
  25312 
  25313     if (!cf->is_static) {
  25314         /* add the brand to the newly created instance */
  25315         /* XXX: would be better to add the code only if needed, maybe in a
  25316            later pass */
  25317         emit_op(s, OP_push_false); /* will be patched later */
  25318         cf->brand_push_pos = cf->fields_init_fd->last_opcode_pos;
  25319         label_add_brand = emit_goto(s, OP_if_false, -1);
  25320 
  25321         emit_op(s, OP_scope_get_var);
  25322         emit_atom(s, JS_ATOM_this);
  25323         emit_u16(s, 0);
  25324 
  25325         emit_op(s, OP_scope_get_var);
  25326         emit_atom(s, JS_ATOM_home_object);
  25327         emit_u16(s, 0);
  25328 
  25329         emit_op(s, OP_add_brand);
  25330 
  25331         emit_label(s, label_add_brand);
  25332     }
  25333     s->cur_func = s->cur_func->parent;
  25334     return 0;
  25335 }
  25336 
  25337 static void emit_class_init_end(JSParseState *s, ClassFieldsDef *cf)
  25338 {
  25339     int cpool_idx;
  25340 
  25341     s->cur_func = cf->fields_init_fd;
  25342     emit_op(s, OP_return_undef);
  25343     s->cur_func = s->cur_func->parent;
  25344 
  25345     cpool_idx = cpool_add(s, JS_NULL);
  25346     cf->fields_init_fd->parent_cpool_idx = cpool_idx;
  25347     emit_op(s, OP_fclosure);
  25348     emit_u32(s, cpool_idx);
  25349     emit_op(s, OP_set_home_object);
  25350 }
  25351 
  25352 
  25353 static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
  25354                                       JSParseExportEnum export_flag)
  25355 {
  25356     JSContext *ctx = s->ctx;
  25357     JSFunctionDef *fd = s->cur_func;
  25358     JSAtom name = JS_ATOM_NULL, class_name = JS_ATOM_NULL, class_name1;
  25359     JSAtom class_var_name = JS_ATOM_NULL;
  25360     JSFunctionDef *method_fd, *ctor_fd;
  25361     int saved_js_mode, class_name_var_idx, prop_type, ctor_cpool_offset;
  25362     int class_flags = 0, i, define_class_offset;
  25363     BOOL is_static, is_private;
  25364     const uint8_t *class_start_ptr = s->token.ptr;
  25365     const uint8_t *start_ptr;
  25366     ClassFieldsDef class_fields[2];
  25367 
  25368     /* classes are parsed and executed in strict mode */
  25369     saved_js_mode = fd->js_mode;
  25370     fd->js_mode |= JS_MODE_STRICT;
  25371     if (next_token(s))
  25372         goto fail;
  25373     if (s->token.val == TOK_IDENT) {
  25374         if (s->token.u.ident.is_reserved) {
  25375             js_parse_error_reserved_identifier(s);
  25376             goto fail;
  25377         }
  25378         class_name = JS_DupAtom(ctx, s->token.u.ident.atom);
  25379         if (next_token(s))
  25380             goto fail;
  25381     } else if (!is_class_expr && export_flag != JS_PARSE_EXPORT_DEFAULT) {
  25382         js_parse_error(s, "class statement requires a name");
  25383         goto fail;
  25384     }
  25385     if (!is_class_expr) {
  25386         if (class_name == JS_ATOM_NULL)
  25387             class_var_name = JS_ATOM__default_; /* export default */
  25388         else
  25389             class_var_name = class_name;
  25390         class_var_name = JS_DupAtom(ctx, class_var_name);
  25391     }
  25392 
  25393     push_scope(s);
  25394 
  25395     if (s->token.val == TOK_EXTENDS) {
  25396         class_flags = JS_DEFINE_CLASS_HAS_HERITAGE;
  25397         if (next_token(s))
  25398             goto fail;
  25399         if (js_parse_left_hand_side_expr(s))
  25400             goto fail;
  25401     } else {
  25402         emit_op(s, OP_undefined);
  25403     }
  25404 
  25405     /* add a 'const' definition for the class name */
  25406     if (class_name != JS_ATOM_NULL) {
  25407         class_name_var_idx = define_var(s, fd, class_name, JS_VAR_DEF_CONST);
  25408         if (class_name_var_idx < 0)
  25409             goto fail;
  25410     }
  25411 
  25412     if (js_parse_expect(s, '{'))
  25413         goto fail;
  25414 
  25415     /* this scope contains the private fields */
  25416     push_scope(s);
  25417 
  25418     emit_op(s, OP_push_const);
  25419     ctor_cpool_offset = fd->byte_code.size;
  25420     emit_u32(s, 0); /* will be patched at the end of the class parsing */
  25421 
  25422     if (class_name == JS_ATOM_NULL) {
  25423         if (class_var_name != JS_ATOM_NULL)
  25424             class_name1 = JS_ATOM_default;
  25425         else
  25426             class_name1 = JS_ATOM_empty_string;
  25427     } else {
  25428         class_name1 = class_name;
  25429     }
  25430 
  25431     emit_op(s, OP_define_class);
  25432     emit_atom(s, class_name1);
  25433     emit_u8(s, class_flags);
  25434     define_class_offset = fd->last_opcode_pos;
  25435 
  25436     for(i = 0; i < 2; i++) {
  25437         ClassFieldsDef *cf = &class_fields[i];
  25438         cf->fields_init_fd = NULL;
  25439         cf->computed_fields_count = 0;
  25440         cf->need_brand = FALSE;
  25441         cf->is_static = i;
  25442     }
  25443 
  25444     ctor_fd = NULL;
  25445     while (s->token.val != '}') {
  25446         if (s->token.val == ';') {
  25447             if (next_token(s))
  25448                 goto fail;
  25449             continue;
  25450         }
  25451         is_static = FALSE;
  25452         if (s->token.val == TOK_STATIC) {
  25453             int next = peek_token(s, TRUE);
  25454             if (!(next == ';' || next == '}' || next == '(' || next == '='))
  25455                 is_static = TRUE;
  25456         }
  25457         prop_type = -1;
  25458         if (is_static) {
  25459             if (next_token(s))
  25460                 goto fail;
  25461             if (s->token.val == '{') {
  25462                 ClassFieldsDef *cf = &class_fields[is_static];
  25463                 JSFunctionDef *init;
  25464                 if (!cf->fields_init_fd) {
  25465                     if (emit_class_init_start(s, cf))
  25466                         goto fail;
  25467                 }
  25468                 s->cur_func = cf->fields_init_fd;
  25469                 /* XXX: could try to avoid creating a new function and
  25470                    reuse 'fields_init_fd' with a specific 'var'
  25471                    scope */
  25472                 // stack is now: <empty>
  25473                 if (js_parse_function_decl2(s, JS_PARSE_FUNC_CLASS_STATIC_INIT,
  25474                                             JS_FUNC_NORMAL, JS_ATOM_NULL,
  25475                                             s->token.ptr,
  25476                                             JS_PARSE_EXPORT_NONE, &init) < 0) {
  25477                     goto fail;
  25478                 }
  25479                 // stack is now: fclosure
  25480                 push_scope(s);
  25481                 emit_op(s, OP_scope_get_var);
  25482                 emit_atom(s, JS_ATOM_this);
  25483                 emit_u16(s, 0);
  25484                 // stack is now: fclosure this
  25485                 emit_op(s, OP_swap);
  25486                 // stack is now: this fclosure
  25487                 emit_op(s, OP_call_method);
  25488                 emit_u16(s, 0);
  25489                 // stack is now: returnvalue
  25490                 emit_op(s, OP_drop);
  25491                 // stack is now: <empty>
  25492                 pop_scope(s);
  25493                 s->cur_func = s->cur_func->parent;
  25494                 continue;
  25495             }
  25496             /* allow "static" field name */
  25497             if (s->token.val == ';' || s->token.val == '=') {
  25498                 is_static = FALSE;
  25499                 name = JS_DupAtom(ctx, JS_ATOM_static);
  25500                 prop_type = PROP_TYPE_IDENT;
  25501             }
  25502         }
  25503         if (is_static)
  25504             emit_op(s, OP_swap);
  25505         start_ptr = s->token.ptr;
  25506         if (prop_type < 0) {
  25507             prop_type = js_parse_property_name(s, &name, TRUE, FALSE, TRUE);
  25508             if (prop_type < 0)
  25509                 goto fail;
  25510         }
  25511         is_private = prop_type & PROP_TYPE_PRIVATE;
  25512         prop_type &= ~PROP_TYPE_PRIVATE;
  25513 
  25514         if ((name == JS_ATOM_constructor && !is_static &&
  25515              prop_type != PROP_TYPE_IDENT) ||
  25516             (name == JS_ATOM_prototype && is_static) ||
  25517             name == JS_ATOM_hash_constructor) {
  25518             js_parse_error(s, "invalid method name");
  25519             goto fail;
  25520         }
  25521         if (prop_type == PROP_TYPE_GET || prop_type == PROP_TYPE_SET) {
  25522             BOOL is_set = prop_type - PROP_TYPE_GET;
  25523             JSFunctionDef *method_fd;
  25524 
  25525             if (is_private) {
  25526                 int idx, var_kind, is_static1;
  25527                 idx = find_private_class_field(ctx, fd, name, fd->scope_level);
  25528                 if (idx >= 0) {
  25529                     var_kind = fd->vars[idx].var_kind;
  25530                     is_static1 = fd->vars[idx].is_static_private;
  25531                     if (var_kind == JS_VAR_PRIVATE_FIELD ||
  25532                         var_kind == JS_VAR_PRIVATE_METHOD ||
  25533                         var_kind == JS_VAR_PRIVATE_GETTER_SETTER ||
  25534                         var_kind == (JS_VAR_PRIVATE_GETTER + is_set) ||
  25535                         (var_kind == (JS_VAR_PRIVATE_GETTER + 1 - is_set) &&
  25536                          is_static != is_static1)) {
  25537                         goto private_field_already_defined;
  25538                     }
  25539                     fd->vars[idx].var_kind = JS_VAR_PRIVATE_GETTER_SETTER;
  25540                 } else {
  25541                     if (add_private_class_field(s, fd, name,
  25542                                                 JS_VAR_PRIVATE_GETTER + is_set, is_static) < 0)
  25543                         goto fail;
  25544                 }
  25545                 class_fields[is_static].need_brand = TRUE;
  25546             }
  25547 
  25548             if (js_parse_function_decl2(s, JS_PARSE_FUNC_GETTER + is_set,
  25549                                         JS_FUNC_NORMAL, JS_ATOM_NULL,
  25550                                         start_ptr,
  25551                                         JS_PARSE_EXPORT_NONE, &method_fd))
  25552                 goto fail;
  25553             if (is_private) {
  25554                 method_fd->need_home_object = TRUE; /* needed for brand check */
  25555                 emit_op(s, OP_set_home_object);
  25556                 /* XXX: missing function name */
  25557                 emit_op(s, OP_scope_put_var_init);
  25558                 if (is_set) {
  25559                     JSAtom setter_name;
  25560                     int ret;
  25561 
  25562                     setter_name = get_private_setter_name(ctx, name);
  25563                     if (setter_name == JS_ATOM_NULL)
  25564                         goto fail;
  25565                     emit_atom(s, setter_name);
  25566                     ret = add_private_class_field(s, fd, setter_name,
  25567                                                   JS_VAR_PRIVATE_SETTER, is_static);
  25568                     JS_FreeAtom(ctx, setter_name);
  25569                     if (ret < 0)
  25570                         goto fail;
  25571                 } else {
  25572                     emit_atom(s, name);
  25573                 }
  25574                 emit_u16(s, s->cur_func->scope_level);
  25575             } else {
  25576                 if (name == JS_ATOM_NULL) {
  25577                     emit_op(s, OP_define_method_computed);
  25578                 } else {
  25579                     emit_op(s, OP_define_method);
  25580                     emit_atom(s, name);
  25581                 }
  25582                 emit_u8(s, OP_DEFINE_METHOD_GETTER + is_set);
  25583             }
  25584         } else if (prop_type == PROP_TYPE_IDENT && s->token.val != '(') {
  25585             ClassFieldsDef *cf = &class_fields[is_static];
  25586             JSAtom field_var_name = JS_ATOM_NULL;
  25587 
  25588             /* class field */
  25589 
  25590             /* XXX: spec: not consistent with method name checks */
  25591             if (name == JS_ATOM_constructor || name == JS_ATOM_prototype) {
  25592                 js_parse_error(s, "invalid field name");
  25593                 goto fail;
  25594             }
  25595 
  25596             if (is_private) {
  25597                 if (find_private_class_field(ctx, fd, name,
  25598                                              fd->scope_level) >= 0) {
  25599                     goto private_field_already_defined;
  25600                 }
  25601                 if (add_private_class_field(s, fd, name,
  25602                                             JS_VAR_PRIVATE_FIELD, is_static) < 0)
  25603                     goto fail;
  25604                 emit_op(s, OP_private_symbol);
  25605                 emit_atom(s, name);
  25606                 emit_op(s, OP_scope_put_var_init);
  25607                 emit_atom(s, name);
  25608                 emit_u16(s, s->cur_func->scope_level);
  25609             }
  25610 
  25611             if (!cf->fields_init_fd) {
  25612                 if (emit_class_init_start(s, cf))
  25613                     goto fail;
  25614             }
  25615             if (name == JS_ATOM_NULL ) {
  25616                 /* save the computed field name into a variable */
  25617                 field_var_name = js_atom_concat_num(ctx, JS_ATOM_computed_field + is_static, cf->computed_fields_count);
  25618                 if (field_var_name == JS_ATOM_NULL)
  25619                     goto fail;
  25620                 if (define_var(s, fd, field_var_name, JS_VAR_DEF_CONST) < 0) {
  25621                     JS_FreeAtom(ctx, field_var_name);
  25622                     goto fail;
  25623                 }
  25624                 emit_op(s, OP_to_propkey);
  25625                 emit_op(s, OP_scope_put_var_init);
  25626                 emit_atom(s, field_var_name);
  25627                 emit_u16(s, s->cur_func->scope_level);
  25628             }
  25629             s->cur_func = cf->fields_init_fd;
  25630             emit_op(s, OP_scope_get_var);
  25631             emit_atom(s, JS_ATOM_this);
  25632             emit_u16(s, 0);
  25633 
  25634             if (name == JS_ATOM_NULL) {
  25635                 emit_op(s, OP_scope_get_var);
  25636                 emit_atom(s, field_var_name);
  25637                 emit_u16(s, s->cur_func->scope_level);
  25638                 cf->computed_fields_count++;
  25639                 JS_FreeAtom(ctx, field_var_name);
  25640             } else if (is_private) {
  25641                 emit_op(s, OP_scope_get_var);
  25642                 emit_atom(s, name);
  25643                 emit_u16(s, s->cur_func->scope_level);
  25644             }
  25645 
  25646             if (s->token.val == '=') {
  25647                 if (next_token(s))
  25648                     goto fail;
  25649                 if (js_parse_assign_expr(s))
  25650                     goto fail;
  25651             } else {
  25652                 emit_op(s, OP_undefined);
  25653             }
  25654             if (is_private) {
  25655                 set_object_name_computed(s);
  25656                 emit_op(s, OP_define_private_field);
  25657             } else if (name == JS_ATOM_NULL) {
  25658                 set_object_name_computed(s);
  25659                 emit_op(s, OP_define_array_el);
  25660                 emit_op(s, OP_drop);
  25661             } else {
  25662                 set_object_name(s, name);
  25663                 emit_op(s, OP_define_field);
  25664                 emit_atom(s, name);
  25665             }
  25666             s->cur_func = s->cur_func->parent;
  25667             if (js_parse_expect_semi(s))
  25668                 goto fail;
  25669         } else {
  25670             JSParseFunctionEnum func_type;
  25671             JSFunctionKindEnum func_kind;
  25672 
  25673             func_type = JS_PARSE_FUNC_METHOD;
  25674             func_kind = JS_FUNC_NORMAL;
  25675             if (prop_type == PROP_TYPE_STAR) {
  25676                 func_kind = JS_FUNC_GENERATOR;
  25677             } else if (prop_type == PROP_TYPE_ASYNC) {
  25678                 func_kind = JS_FUNC_ASYNC;
  25679             } else if (prop_type == PROP_TYPE_ASYNC_STAR) {
  25680                 func_kind = JS_FUNC_ASYNC_GENERATOR;
  25681             } else if (name == JS_ATOM_constructor && !is_static) {
  25682                 if (ctor_fd) {
  25683                     js_parse_error(s, "property constructor appears more than once");
  25684                     goto fail;
  25685                 }
  25686                 if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE)
  25687                     func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR;
  25688                 else
  25689                     func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;
  25690             }
  25691             if (is_private) {
  25692                 class_fields[is_static].need_brand = TRUE;
  25693             }
  25694             if (js_parse_function_decl2(s, func_type, func_kind, JS_ATOM_NULL, start_ptr, JS_PARSE_EXPORT_NONE, &method_fd))
  25695                 goto fail;
  25696             if (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR ||
  25697                 func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) {
  25698                 ctor_fd = method_fd;
  25699             } else if (is_private) {
  25700                 method_fd->need_home_object = TRUE; /* needed for brand check */
  25701                 if (find_private_class_field(ctx, fd, name,
  25702                                              fd->scope_level) >= 0) {
  25703                 private_field_already_defined:
  25704                     js_parse_error(s, "private class field is already defined");
  25705                     goto fail;
  25706                 }
  25707                 if (add_private_class_field(s, fd, name,
  25708                                             JS_VAR_PRIVATE_METHOD, is_static) < 0)
  25709                     goto fail;
  25710                 emit_op(s, OP_set_home_object);
  25711                 emit_op(s, OP_set_name);
  25712                 emit_atom(s, name);
  25713                 emit_op(s, OP_scope_put_var_init);
  25714                 emit_atom(s, name);
  25715                 emit_u16(s, s->cur_func->scope_level);
  25716             } else {
  25717                 if (name == JS_ATOM_NULL) {
  25718                     emit_op(s, OP_define_method_computed);
  25719                 } else {
  25720                     emit_op(s, OP_define_method);
  25721                     emit_atom(s, name);
  25722                 }
  25723                 emit_u8(s, OP_DEFINE_METHOD_METHOD);
  25724             }
  25725         }
  25726         if (is_static)
  25727             emit_op(s, OP_swap);
  25728         JS_FreeAtom(ctx, name);
  25729         name = JS_ATOM_NULL;
  25730     }
  25731 
  25732     if (s->token.val != '}') {
  25733         js_parse_error(s, "expecting '%c'", '}');
  25734         goto fail;
  25735     }
  25736 
  25737     if (!ctor_fd) {
  25738         if (js_parse_class_default_ctor(s, class_flags & JS_DEFINE_CLASS_HAS_HERITAGE, &ctor_fd))
  25739             goto fail;
  25740     }
  25741     /* patch the constant pool index for the constructor */
  25742     put_u32(fd->byte_code.buf + ctor_cpool_offset, ctor_fd->parent_cpool_idx);
  25743 
  25744     /* store the class source code in the constructor. */
  25745     if (!fd->strip_source) {
  25746         js_free(ctx, ctor_fd->source);
  25747         ctor_fd->source_len = s->buf_ptr - class_start_ptr;
  25748         ctor_fd->source = js_strndup(ctx, (const char *)class_start_ptr,
  25749                                      ctor_fd->source_len);
  25750         if (!ctor_fd->source)
  25751             goto fail;
  25752     }
  25753 
  25754     /* consume the '}' */
  25755     if (next_token(s))
  25756         goto fail;
  25757 
  25758     {
  25759         ClassFieldsDef *cf = &class_fields[0];
  25760         int var_idx;
  25761 
  25762         if (cf->need_brand) {
  25763             /* add a private brand to the prototype */
  25764             emit_op(s, OP_dup);
  25765             emit_op(s, OP_null);
  25766             emit_op(s, OP_swap);
  25767             emit_op(s, OP_add_brand);
  25768 
  25769             /* define the brand field in 'this' of the initializer */
  25770             if (!cf->fields_init_fd) {
  25771                 if (emit_class_init_start(s, cf))
  25772                     goto fail;
  25773             }
  25774             /* patch the start of the function to enable the
  25775                OP_add_brand_instance code */
  25776             cf->fields_init_fd->byte_code.buf[cf->brand_push_pos] = OP_push_true;
  25777         }
  25778 
  25779         /* store the function to initialize the fields to that it can be
  25780            referenced by the constructor */
  25781         var_idx = define_var(s, fd, JS_ATOM_class_fields_init,
  25782                              JS_VAR_DEF_CONST);
  25783         if (var_idx < 0)
  25784             goto fail;
  25785         if (cf->fields_init_fd) {
  25786             emit_class_init_end(s, cf);
  25787         } else {
  25788             emit_op(s, OP_undefined);
  25789         }
  25790         emit_op(s, OP_scope_put_var_init);
  25791         emit_atom(s, JS_ATOM_class_fields_init);
  25792         emit_u16(s, s->cur_func->scope_level);
  25793     }
  25794 
  25795     /* drop the prototype */
  25796     emit_op(s, OP_drop);
  25797 
  25798     if (class_fields[1].need_brand) {
  25799         /* add a private brand to the class */
  25800         emit_op(s, OP_dup);
  25801         emit_op(s, OP_dup);
  25802         emit_op(s, OP_add_brand);
  25803     }
  25804 
  25805     if (class_name != JS_ATOM_NULL) {
  25806         /* store the class name in the scoped class name variable (it
  25807            is independent from the class statement variable
  25808            definition) */
  25809         emit_op(s, OP_dup);
  25810         emit_op(s, OP_scope_put_var_init);
  25811         emit_atom(s, class_name);
  25812         emit_u16(s, fd->scope_level);
  25813     }
  25814 
  25815     /* initialize the static fields */
  25816     if (class_fields[1].fields_init_fd != NULL) {
  25817         ClassFieldsDef *cf = &class_fields[1];
  25818         emit_op(s, OP_dup);
  25819         emit_class_init_end(s, cf);
  25820         emit_op(s, OP_call_method);
  25821         emit_u16(s, 0);
  25822         emit_op(s, OP_drop);
  25823     }
  25824 
  25825     pop_scope(s);
  25826     pop_scope(s);
  25827 
  25828     /* the class statements have a block level scope */
  25829     if (class_var_name != JS_ATOM_NULL) {
  25830         if (define_var(s, fd, class_var_name, JS_VAR_DEF_LET) < 0)
  25831             goto fail;
  25832         emit_op(s, OP_scope_put_var_init);
  25833         emit_atom(s, class_var_name);
  25834         emit_u16(s, fd->scope_level);
  25835     } else {
  25836         if (class_name == JS_ATOM_NULL) {
  25837             /* cannot use OP_set_name because the name of the class
  25838                must be defined before the static initializers are
  25839                executed */
  25840             emit_op(s, OP_set_class_name);
  25841             emit_u32(s, fd->last_opcode_pos + 1 - define_class_offset);
  25842         }
  25843     }
  25844 
  25845     if (export_flag != JS_PARSE_EXPORT_NONE) {
  25846         if (!add_export_entry(s, fd->module,
  25847                               class_var_name,
  25848                               export_flag == JS_PARSE_EXPORT_NAMED ? class_var_name : JS_ATOM_default,
  25849                               JS_EXPORT_TYPE_LOCAL))
  25850             goto fail;
  25851     }
  25852 
  25853     JS_FreeAtom(ctx, class_name);
  25854     JS_FreeAtom(ctx, class_var_name);
  25855     fd->js_mode = saved_js_mode;
  25856     return 0;
  25857  fail:
  25858     JS_FreeAtom(ctx, name);
  25859     JS_FreeAtom(ctx, class_name);
  25860     JS_FreeAtom(ctx, class_var_name);
  25861     fd->js_mode = saved_js_mode;
  25862     return -1;
  25863 }
  25864 
  25865 static __exception int js_parse_array_literal(JSParseState *s)
  25866 {
  25867     uint32_t idx;
  25868     BOOL need_length;
  25869 
  25870     if (next_token(s))
  25871         return -1;
  25872     /* small regular arrays are created on the stack */
  25873     idx = 0;
  25874     while (s->token.val != ']' && idx < 32) {
  25875         if (s->token.val == ',' || s->token.val == TOK_ELLIPSIS)
  25876             break;
  25877         if (js_parse_assign_expr(s))
  25878             return -1;
  25879         idx++;
  25880         /* accept trailing comma */
  25881         if (s->token.val == ',') {
  25882             if (next_token(s))
  25883                 return -1;
  25884         } else
  25885         if (s->token.val != ']')
  25886             goto done;
  25887     }
  25888     emit_op(s, OP_array_from);
  25889     emit_u16(s, idx);
  25890 
  25891     /* larger arrays and holes are handled with explicit indices */
  25892     need_length = FALSE;
  25893     while (s->token.val != ']' && idx < 0x7fffffff) {
  25894         if (s->token.val == TOK_ELLIPSIS)
  25895             break;
  25896         need_length = TRUE;
  25897         if (s->token.val != ',') {
  25898             if (js_parse_assign_expr(s))
  25899                 return -1;
  25900             emit_op(s, OP_define_field);
  25901             emit_u32(s, __JS_AtomFromUInt32(idx));
  25902             need_length = FALSE;
  25903         }
  25904         idx++;
  25905         /* accept trailing comma */
  25906         if (s->token.val == ',') {
  25907             if (next_token(s))
  25908                 return -1;
  25909         }
  25910     }
  25911     if (s->token.val == ']') {
  25912         if (need_length) {
  25913             /* Set the length: Cannot use OP_define_field because
  25914                length is not configurable */
  25915             emit_op(s, OP_dup);
  25916             emit_op(s, OP_push_i32);
  25917             emit_u32(s, idx);
  25918             emit_op(s, OP_put_field);
  25919             emit_atom(s, JS_ATOM_length);
  25920         }
  25921         goto done;
  25922     }
  25923 
  25924     /* huge arrays and spread elements require a dynamic index on the stack */
  25925     emit_op(s, OP_push_i32);
  25926     emit_u32(s, idx);
  25927 
  25928     /* stack has array, index */
  25929     while (s->token.val != ']') {
  25930         if (s->token.val == TOK_ELLIPSIS) {
  25931             if (next_token(s))
  25932                 return -1;
  25933             if (js_parse_assign_expr(s))
  25934                 return -1;
  25935 #if 1
  25936             emit_op(s, OP_append);
  25937 #else
  25938             int label_next, label_done;
  25939             label_next = new_label(s);
  25940             label_done = new_label(s);
  25941             /* enumerate object */
  25942             emit_op(s, OP_for_of_start);
  25943             emit_op(s, OP_rot5l);
  25944             emit_op(s, OP_rot5l);
  25945             emit_label(s, label_next);
  25946             /* on stack: enum_rec array idx */
  25947             emit_op(s, OP_for_of_next);
  25948             emit_u8(s, 2);
  25949             emit_goto(s, OP_if_true, label_done);
  25950             /* append element */
  25951             /* enum_rec array idx val -> enum_rec array new_idx */
  25952             emit_op(s, OP_define_array_el);
  25953             emit_op(s, OP_inc);
  25954             emit_goto(s, OP_goto, label_next);
  25955             emit_label(s, label_done);
  25956             /* close enumeration */
  25957             emit_op(s, OP_drop); /* drop undef val */
  25958             emit_op(s, OP_nip1); /* drop enum_rec */
  25959             emit_op(s, OP_nip1);
  25960             emit_op(s, OP_nip1);
  25961 #endif
  25962         } else {
  25963             need_length = TRUE;
  25964             if (s->token.val != ',') {
  25965                 if (js_parse_assign_expr(s))
  25966                     return -1;
  25967                 /* a idx val */
  25968                 emit_op(s, OP_define_array_el);
  25969                 need_length = FALSE;
  25970             }
  25971             emit_op(s, OP_inc);
  25972         }
  25973         if (s->token.val != ',')
  25974             break;
  25975         if (next_token(s))
  25976             return -1;
  25977     }
  25978     if (need_length) {
  25979         /* Set the length: cannot use OP_define_field because
  25980            length is not configurable */
  25981         emit_op(s, OP_dup1);    /* array length - array array length */
  25982         emit_op(s, OP_put_field);
  25983         emit_atom(s, JS_ATOM_length);
  25984     } else {
  25985         emit_op(s, OP_drop);    /* array length - array */
  25986     }
  25987 done:
  25988     return js_parse_expect(s, ']');
  25989 }
  25990 
  25991 /* check if scope chain contains a with statement */
  25992 static BOOL has_with_scope(JSFunctionDef *s, int scope_level)
  25993 {
  25994     while (s) {
  25995         /* no with in strict mode */
  25996         if (!(s->js_mode & JS_MODE_STRICT)) {
  25997             int scope_idx = s->scopes[scope_level].first;
  25998             while (scope_idx >= 0) {
  25999                 JSVarDef *vd = &s->vars[scope_idx];
  26000                 if (vd->var_name == JS_ATOM__with_)
  26001                     return TRUE;
  26002                 scope_idx = vd->scope_next;
  26003             }
  26004         }
  26005         /* check parent scopes */
  26006         scope_level = s->parent_scope_level;
  26007         s = s->parent;
  26008     }
  26009     return FALSE;
  26010 }
  26011 
  26012 static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
  26013                                   JSAtom *pname, int *plabel, int *pdepth, BOOL keep,
  26014                                   int tok)
  26015 {
  26016     JSFunctionDef *fd;
  26017     int opcode, scope, label, depth;
  26018     JSAtom name;
  26019 
  26020     /* we check the last opcode to get the lvalue type */
  26021     fd = s->cur_func;
  26022     scope = 0;
  26023     name = JS_ATOM_NULL;
  26024     label = -1;
  26025     depth = 0;
  26026     switch(opcode = get_prev_opcode(fd)) {
  26027     case OP_scope_get_var:
  26028         name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
  26029         scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
  26030         if ((name == JS_ATOM_arguments || name == JS_ATOM_eval) &&
  26031             (fd->js_mode & JS_MODE_STRICT)) {
  26032             return js_parse_error(s, "invalid lvalue in strict mode");
  26033         }
  26034         if (name == JS_ATOM_this || name == JS_ATOM_new_target)
  26035             goto invalid_lvalue;
  26036         if (has_with_scope(fd, scope)) {
  26037             depth = 2;  /* will generate OP_get_ref_value */
  26038         } else {
  26039             depth = 0;
  26040         }
  26041         break;
  26042     case OP_get_field:
  26043         name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
  26044         depth = 1;
  26045         break;
  26046     case OP_scope_get_private_field:
  26047         name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
  26048         scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
  26049         depth = 1;
  26050         break;
  26051     case OP_get_array_el:
  26052         depth = 2;
  26053         break;
  26054     case OP_get_super_value:
  26055         depth = 3;
  26056         break;
  26057     default:
  26058     invalid_lvalue:
  26059         if (tok == TOK_FOR) {
  26060             return js_parse_error(s, "invalid for in/of left hand-side");
  26061         } else if (tok == TOK_INC || tok == TOK_DEC) {
  26062             return js_parse_error(s, "invalid increment/decrement operand");
  26063         } else if (tok == '[' || tok == '{') {
  26064             return js_parse_error(s, "invalid destructuring target");
  26065         } else {
  26066             return js_parse_error(s, "invalid assignment left-hand side");
  26067         }
  26068     }
  26069     /* remove the last opcode */
  26070     fd->byte_code.size = fd->last_opcode_pos;
  26071     fd->last_opcode_pos = -1;
  26072 
  26073     if (keep) {
  26074         /* get the value but keep the object/fields on the stack */
  26075         switch(opcode) {
  26076         case OP_scope_get_var:
  26077             if (depth != 0) {
  26078                 label = new_label(s);
  26079                 if (label < 0)
  26080                     return -1;
  26081                 emit_op(s, OP_scope_make_ref);
  26082                 emit_atom(s, name);
  26083                 emit_u32(s, label);
  26084                 emit_u16(s, scope);
  26085                 update_label(fd, label, 1);
  26086                 emit_op(s, OP_get_ref_value);
  26087                 opcode = OP_get_ref_value;
  26088             } else {
  26089                 emit_op(s, OP_scope_get_var);
  26090                 emit_atom(s, name);
  26091                 emit_u16(s, scope);
  26092             }
  26093             break;
  26094         case OP_get_field:
  26095             emit_op(s, OP_get_field2);
  26096             emit_atom(s, name);
  26097             break;
  26098         case OP_scope_get_private_field:
  26099             emit_op(s, OP_scope_get_private_field2);
  26100             emit_atom(s, name);
  26101             emit_u16(s, scope);
  26102             break;
  26103         case OP_get_array_el:
  26104             emit_op(s, OP_get_array_el3);
  26105             break;
  26106         case OP_get_super_value:
  26107             emit_op(s, OP_to_propkey);
  26108             emit_op(s, OP_dup3);
  26109             emit_op(s, OP_get_super_value);
  26110             break;
  26111         default:
  26112             abort();
  26113         }
  26114     } else {
  26115         switch(opcode) {
  26116         case OP_scope_get_var:
  26117             if (depth != 0) {
  26118                 label = new_label(s);
  26119                 if (label < 0)
  26120                     return -1;
  26121                 emit_op(s, OP_scope_make_ref);
  26122                 emit_atom(s, name);
  26123                 emit_u32(s, label);
  26124                 emit_u16(s, scope);
  26125                 update_label(fd, label, 1);
  26126                 opcode = OP_get_ref_value;
  26127             }
  26128             break;
  26129         default:
  26130             break;
  26131         }
  26132     }
  26133 
  26134     *popcode = opcode;
  26135     *pscope = scope;
  26136     /* name has refcount for OP_get_field and OP_get_ref_value,
  26137        and JS_ATOM_NULL for other opcodes */
  26138     *pname = name;
  26139     *plabel = label;
  26140     if (pdepth)
  26141         *pdepth = depth;
  26142     return 0;
  26143 }
  26144 
  26145 typedef enum {
  26146     PUT_LVALUE_NOKEEP, /* [depth] v -> */
  26147     PUT_LVALUE_NOKEEP_DEPTH, /* [depth] v -> , keep depth (currently
  26148                                 just disable optimizations) */
  26149     PUT_LVALUE_KEEP_TOP,  /* [depth] v -> v */
  26150     PUT_LVALUE_KEEP_SECOND, /* [depth] v0 v -> v0 */
  26151     PUT_LVALUE_NOKEEP_BOTTOM, /* v [depth] -> */
  26152 } PutLValueEnum;
  26153 
  26154 /* name has a live reference. 'is_let' is only used with opcode =
  26155    OP_scope_get_var which is never generated by get_lvalue(). */
  26156 static void put_lvalue(JSParseState *s, int opcode, int scope,
  26157                        JSAtom name, int label, PutLValueEnum special,
  26158                        BOOL is_let)
  26159 {
  26160     switch(opcode) {
  26161     case OP_scope_get_var:
  26162         /* depth = 0 */
  26163         switch(special) {
  26164         case PUT_LVALUE_NOKEEP:
  26165         case PUT_LVALUE_NOKEEP_DEPTH:
  26166         case PUT_LVALUE_KEEP_SECOND:
  26167         case PUT_LVALUE_NOKEEP_BOTTOM:
  26168             break;
  26169         case PUT_LVALUE_KEEP_TOP:
  26170             emit_op(s, OP_dup);
  26171             break;
  26172         default:
  26173             abort();
  26174         }
  26175         break;
  26176     case OP_get_field:
  26177     case OP_scope_get_private_field:
  26178         /* depth = 1 */
  26179         switch(special) {
  26180         case PUT_LVALUE_NOKEEP:
  26181         case PUT_LVALUE_NOKEEP_DEPTH:
  26182             break;
  26183         case PUT_LVALUE_KEEP_TOP:
  26184             emit_op(s, OP_insert2); /* obj v -> v obj v */
  26185             break;
  26186         case PUT_LVALUE_KEEP_SECOND:
  26187             emit_op(s, OP_perm3); /* obj v0 v -> v0 obj v */
  26188             break;
  26189         case PUT_LVALUE_NOKEEP_BOTTOM:
  26190             emit_op(s, OP_swap);
  26191             break;
  26192         default:
  26193             abort();
  26194         }
  26195         break;
  26196     case OP_get_array_el:
  26197     case OP_get_ref_value:
  26198         /* depth = 2 */
  26199         if (opcode == OP_get_ref_value) {
  26200             JS_FreeAtom(s->ctx, name);
  26201             emit_label(s, label);
  26202         }
  26203         switch(special) {
  26204         case PUT_LVALUE_NOKEEP:
  26205             emit_op(s, OP_nop); /* will trigger optimization */
  26206             break;
  26207         case PUT_LVALUE_NOKEEP_DEPTH:
  26208             break;
  26209         case PUT_LVALUE_KEEP_TOP:
  26210             emit_op(s, OP_insert3); /* obj prop v -> v obj prop v */
  26211             break;
  26212         case PUT_LVALUE_KEEP_SECOND:
  26213             emit_op(s, OP_perm4); /* obj prop v0 v -> v0 obj prop v */
  26214             break;
  26215         case PUT_LVALUE_NOKEEP_BOTTOM:
  26216             emit_op(s, OP_rot3l);
  26217             break;
  26218         default:
  26219             abort();
  26220         }
  26221         break;
  26222     case OP_get_super_value:
  26223         /* depth = 3 */
  26224         switch(special) {
  26225         case PUT_LVALUE_NOKEEP:
  26226         case PUT_LVALUE_NOKEEP_DEPTH:
  26227             break;
  26228         case PUT_LVALUE_KEEP_TOP:
  26229             emit_op(s, OP_insert4); /* this obj prop v -> v this obj prop v */
  26230             break;
  26231         case PUT_LVALUE_KEEP_SECOND:
  26232             emit_op(s, OP_perm5); /* this obj prop v0 v -> v0 this obj prop v */
  26233             break;
  26234         case PUT_LVALUE_NOKEEP_BOTTOM:
  26235             emit_op(s, OP_rot4l);
  26236             break;
  26237         default:
  26238             abort();
  26239         }
  26240         break;
  26241     default:
  26242         break;
  26243     }
  26244 
  26245     switch(opcode) {
  26246     case OP_scope_get_var:  /* val -- */
  26247         emit_op(s, is_let ? OP_scope_put_var_init : OP_scope_put_var);
  26248         emit_u32(s, name);  /* has refcount */
  26249         emit_u16(s, scope);
  26250         break;
  26251     case OP_get_field:
  26252         emit_op(s, OP_put_field);
  26253         emit_u32(s, name);  /* name has refcount */
  26254         break;
  26255     case OP_scope_get_private_field:
  26256         emit_op(s, OP_scope_put_private_field);
  26257         emit_u32(s, name);  /* name has refcount */
  26258         emit_u16(s, scope);
  26259         break;
  26260     case OP_get_array_el:
  26261         emit_op(s, OP_put_array_el);
  26262         break;
  26263     case OP_get_ref_value:
  26264         emit_op(s, OP_put_ref_value);
  26265         break;
  26266     case OP_get_super_value:
  26267         emit_op(s, OP_put_super_value);
  26268         break;
  26269     default:
  26270         abort();
  26271     }
  26272 }
  26273 
  26274 static __exception int js_parse_expr_paren(JSParseState *s)
  26275 {
  26276     if (js_parse_expect(s, '('))
  26277         return -1;
  26278     if (js_parse_expr(s))
  26279         return -1;
  26280     if (js_parse_expect(s, ')'))
  26281         return -1;
  26282     return 0;
  26283 }
  26284 
  26285 static int js_unsupported_keyword(JSParseState *s, JSAtom atom)
  26286 {
  26287     char buf[ATOM_GET_STR_BUF_SIZE];
  26288     return js_parse_error(s, "unsupported keyword: %s",
  26289                           JS_AtomGetStr(s->ctx, buf, sizeof(buf), atom));
  26290 }
  26291 
  26292 static __exception int js_define_var(JSParseState *s, JSAtom name, int tok)
  26293 {
  26294     JSFunctionDef *fd = s->cur_func;
  26295     JSVarDefEnum var_def_type;
  26296 
  26297     if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) {
  26298         return js_parse_error(s, "yield is a reserved identifier");
  26299     }
  26300     if ((name == JS_ATOM_arguments || name == JS_ATOM_eval)
  26301     &&  (fd->js_mode & JS_MODE_STRICT)) {
  26302         return js_parse_error(s, "invalid variable name in strict mode");
  26303     }
  26304     if (name == JS_ATOM_let
  26305     &&  (tok == TOK_LET || tok == TOK_CONST)) {
  26306         return js_parse_error(s, "invalid lexical variable name");
  26307     }
  26308     switch(tok) {
  26309     case TOK_LET:
  26310         var_def_type = JS_VAR_DEF_LET;
  26311         break;
  26312     case TOK_CONST:
  26313         var_def_type = JS_VAR_DEF_CONST;
  26314         break;
  26315     case TOK_VAR:
  26316         var_def_type = JS_VAR_DEF_VAR;
  26317         break;
  26318     case TOK_CATCH:
  26319         var_def_type = JS_VAR_DEF_CATCH;
  26320         break;
  26321     default:
  26322         abort();
  26323     }
  26324     if (define_var(s, fd, name, var_def_type) < 0)
  26325         return -1;
  26326     return 0;
  26327 }
  26328 
  26329 static void js_emit_spread_code(JSParseState *s, int depth)
  26330 {
  26331     int label_rest_next, label_rest_done;
  26332 
  26333     /* XXX: could check if enum object is an actual array and optimize
  26334        slice extraction. enumeration record and target array are in a
  26335        different order from OP_append case. */
  26336     /* enum_rec xxx -- enum_rec xxx array 0 */
  26337     emit_op(s, OP_array_from);
  26338     emit_u16(s, 0);
  26339     emit_op(s, OP_push_i32);
  26340     emit_u32(s, 0);
  26341     emit_label(s, label_rest_next = new_label(s));
  26342     emit_op(s, OP_for_of_next);
  26343     emit_u8(s, 2 + depth);
  26344     label_rest_done = emit_goto(s, OP_if_true, -1);
  26345     /* array idx val -- array idx */
  26346     emit_op(s, OP_define_array_el);
  26347     emit_op(s, OP_inc);
  26348     emit_goto(s, OP_goto, label_rest_next);
  26349     emit_label(s, label_rest_done);
  26350     /* enum_rec xxx array idx undef -- enum_rec xxx array */
  26351     emit_op(s, OP_drop);
  26352     emit_op(s, OP_drop);
  26353 }
  26354 
  26355 static int js_parse_check_duplicate_parameter(JSParseState *s, JSAtom name)
  26356 {
  26357     /* Check for duplicate parameter names */
  26358     JSFunctionDef *fd = s->cur_func;
  26359     int i;
  26360     for (i = 0; i < fd->arg_count; i++) {
  26361         if (fd->args[i].var_name == name)
  26362             goto duplicate;
  26363     }
  26364     for (i = 0; i < fd->var_count; i++) {
  26365         if (fd->vars[i].var_name == name)
  26366             goto duplicate;
  26367     }
  26368     return 0;
  26369 
  26370 duplicate:
  26371     return js_parse_error(s, "duplicate parameter names not allowed in this context");
  26372 }
  26373 
  26374 /* tok = TOK_VAR, TOK_LET or TOK_CONST. Return whether a reference
  26375    must be taken to the variable for proper 'with' or global variable
  26376    evaluation */
  26377 /* Note: this function is needed only because variable references are
  26378    not yet optimized in destructuring */
  26379 static BOOL need_var_reference(JSParseState *s, int tok)
  26380 {
  26381     JSFunctionDef *fd = s->cur_func;
  26382     if (tok != TOK_VAR)
  26383         return FALSE; /* no reference for let/const */
  26384     if (fd->js_mode & JS_MODE_STRICT) {
  26385         if (!fd->is_global_var)
  26386             return FALSE; /* local definitions in strict mode in function or direct eval */
  26387         if (s->is_module)
  26388             return FALSE; /* in a module global variables are like closure variables */
  26389     }
  26390     return TRUE;
  26391 }
  26392 
  26393 static JSAtom js_parse_destructuring_var(JSParseState *s, int tok, int is_arg)
  26394 {
  26395     JSAtom name;
  26396 
  26397     if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)
  26398     ||  ((s->cur_func->js_mode & JS_MODE_STRICT) &&
  26399          (s->token.u.ident.atom == JS_ATOM_eval || s->token.u.ident.atom == JS_ATOM_arguments))) {
  26400         js_parse_error(s, "invalid destructuring target");
  26401         return JS_ATOM_NULL;
  26402     }
  26403     name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
  26404     if (is_arg && js_parse_check_duplicate_parameter(s, name))
  26405         goto fail;
  26406     if (next_token(s))
  26407         goto fail;
  26408 
  26409     return name;
  26410 fail:
  26411     JS_FreeAtom(s->ctx, name);
  26412     return JS_ATOM_NULL;
  26413 }
  26414 
  26415 /* Return -1 if error, 0 if no initializer, 1 if an initializer is
  26416    present at the top level. */
  26417 static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
  26418                                         int hasval, int has_ellipsis,
  26419                                         BOOL allow_initializer, BOOL export_flag)
  26420 {
  26421     int label_parse, label_assign, label_done, label_lvalue, depth_lvalue;
  26422     int start_addr, assign_addr;
  26423     JSAtom prop_name, var_name;
  26424     int opcode, scope, tok1, skip_bits;
  26425     BOOL has_initializer;
  26426 
  26427     if (has_ellipsis < 0) {
  26428         /* pre-parse destructuration target for spread detection */
  26429         js_parse_skip_parens_token(s, &skip_bits, FALSE);
  26430         has_ellipsis = skip_bits & SKIP_HAS_ELLIPSIS;
  26431     }
  26432 
  26433     label_parse = new_label(s);
  26434     label_assign = new_label(s);
  26435 
  26436     start_addr = s->cur_func->byte_code.size;
  26437     if (hasval) {
  26438         /* consume value from the stack */
  26439         emit_op(s, OP_dup);
  26440         emit_op(s, OP_undefined);
  26441         emit_op(s, OP_strict_eq);
  26442         emit_goto(s, OP_if_true, label_parse);
  26443         emit_label(s, label_assign);
  26444     } else {
  26445         emit_goto(s, OP_goto, label_parse);
  26446         emit_label(s, label_assign);
  26447         /* leave value on the stack */
  26448         emit_op(s, OP_dup);
  26449     }
  26450     assign_addr = s->cur_func->byte_code.size;
  26451     if (s->token.val == '{') {
  26452         if (next_token(s))
  26453             return -1;
  26454         /* throw an exception if the value cannot be converted to an object */
  26455         emit_op(s, OP_to_object);
  26456         if (has_ellipsis) {
  26457             /* add excludeList on stack just below src object */
  26458             emit_op(s, OP_object);
  26459             emit_op(s, OP_swap);
  26460         }
  26461         while (s->token.val != '}') {
  26462             int prop_type;
  26463             if (s->token.val == TOK_ELLIPSIS) {
  26464                 if (!has_ellipsis) {
  26465                     JS_ThrowInternalError(s->ctx, "unexpected ellipsis token");
  26466                     return -1;
  26467                 }
  26468                 if (next_token(s))
  26469                     return -1;
  26470                 if (tok) {
  26471                     var_name = js_parse_destructuring_var(s, tok, is_arg);
  26472                     if (var_name == JS_ATOM_NULL)
  26473                         return -1;
  26474                     if (need_var_reference(s, tok)) {
  26475                         /* Must make a reference for proper `with` semantics */
  26476                         emit_op(s, OP_scope_get_var);
  26477                         emit_atom(s, var_name);
  26478                         emit_u16(s, s->cur_func->scope_level);
  26479                         JS_FreeAtom(s->ctx, var_name);
  26480                         goto lvalue0;
  26481                     } else {
  26482                         opcode = OP_scope_get_var;
  26483                         scope = s->cur_func->scope_level;
  26484                         label_lvalue = -1;
  26485                         depth_lvalue = 0;
  26486                     }
  26487                 } else {
  26488                     if (js_parse_left_hand_side_expr(s))
  26489                         return -1;
  26490                 lvalue0:
  26491                     if (get_lvalue(s, &opcode, &scope, &var_name,
  26492                                    &label_lvalue, &depth_lvalue, FALSE, '{'))
  26493                         return -1;
  26494                 }
  26495                 if (s->token.val != '}') {
  26496                     js_parse_error(s, "assignment rest property must be last");
  26497                     goto var_error;
  26498                 }
  26499                 emit_op(s, OP_object);  /* target */
  26500                 emit_op(s, OP_copy_data_properties);
  26501                 emit_u8(s, 0 | ((depth_lvalue + 1) << 2) | ((depth_lvalue + 2) << 5));
  26502                 goto set_val;
  26503             }
  26504             prop_type = js_parse_property_name(s, &prop_name, FALSE, TRUE, FALSE);
  26505             if (prop_type < 0)
  26506                 return -1;
  26507             var_name = JS_ATOM_NULL;
  26508             if (prop_type == PROP_TYPE_IDENT) {
  26509                 if (next_token(s))
  26510                     goto prop_error;
  26511                 if ((s->token.val == '[' || s->token.val == '{')
  26512                     &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' ||
  26513                          tok1 == '=' || tok1 == '}')) {
  26514                     if (prop_name == JS_ATOM_NULL) {
  26515                         /* computed property name on stack */
  26516                         if (has_ellipsis) {
  26517                             /* define the property in excludeList */
  26518                             emit_op(s, OP_to_propkey); /* avoid calling ToString twice */
  26519                             emit_op(s, OP_perm3); /* TOS: src excludeList prop */
  26520                             emit_op(s, OP_null); /* TOS: src excludeList prop null */
  26521                             emit_op(s, OP_define_array_el); /* TOS: src excludeList prop */
  26522                             emit_op(s, OP_perm3); /* TOS: excludeList src prop */
  26523                         }
  26524                         /* get the computed property from the source object */
  26525                         emit_op(s, OP_get_array_el2);
  26526                     } else {
  26527                         /* named property */
  26528                         if (has_ellipsis) {
  26529                             /* define the property in excludeList */
  26530                             emit_op(s, OP_swap); /* TOS: src excludeList */
  26531                             emit_op(s, OP_null); /* TOS: src excludeList null */
  26532                             emit_op(s, OP_define_field); /* TOS: src excludeList */
  26533                             emit_atom(s, prop_name);
  26534                             emit_op(s, OP_swap); /* TOS: excludeList src */
  26535                         }
  26536                         /* get the named property from the source object */
  26537                         emit_op(s, OP_get_field2);
  26538                         emit_u32(s, prop_name);
  26539                     }
  26540                     if (js_parse_destructuring_element(s, tok, is_arg, TRUE, -1, TRUE, export_flag) < 0)
  26541                         return -1;
  26542                     if (s->token.val == '}')
  26543                         break;
  26544                     /* accept a trailing comma before the '}' */
  26545                     if (js_parse_expect(s, ','))
  26546                         return -1;
  26547                     continue;
  26548                 }
  26549                 if (prop_name == JS_ATOM_NULL) {
  26550                     emit_op(s, OP_to_propkey);
  26551                     if (has_ellipsis) {
  26552                         /* define the property in excludeList */
  26553                         emit_op(s, OP_perm3);
  26554                         emit_op(s, OP_null);
  26555                         emit_op(s, OP_define_array_el);
  26556                         emit_op(s, OP_perm3);
  26557                     }
  26558                     /* source prop -- source source prop */
  26559                     emit_op(s, OP_dup1);
  26560                 } else {
  26561                     if (has_ellipsis) {
  26562                         /* define the property in excludeList */
  26563                         emit_op(s, OP_swap);
  26564                         emit_op(s, OP_null);
  26565                         emit_op(s, OP_define_field);
  26566                         emit_atom(s, prop_name);
  26567                         emit_op(s, OP_swap);
  26568                     }
  26569                     /* source -- source source */
  26570                     emit_op(s, OP_dup);
  26571                 }
  26572                 if (tok) {
  26573                     var_name = js_parse_destructuring_var(s, tok, is_arg);
  26574                     if (var_name == JS_ATOM_NULL)
  26575                         goto prop_error;
  26576                     if (need_var_reference(s, tok)) {
  26577                         /* Must make a reference for proper `with` semantics */
  26578                         emit_op(s, OP_scope_get_var);
  26579                         emit_atom(s, var_name);
  26580                         emit_u16(s, s->cur_func->scope_level);
  26581                         JS_FreeAtom(s->ctx, var_name);
  26582                         goto lvalue1;
  26583                     } else {
  26584                         /* no need to make a reference for let/const */
  26585                         opcode = OP_scope_get_var;
  26586                         scope = s->cur_func->scope_level;
  26587                         label_lvalue = -1;
  26588                         depth_lvalue = 0;
  26589                     }
  26590                 } else {
  26591                     if (js_parse_left_hand_side_expr(s))
  26592                         goto prop_error;
  26593                 lvalue1:
  26594                     if (get_lvalue(s, &opcode, &scope, &var_name,
  26595                                    &label_lvalue, &depth_lvalue, FALSE, '{'))
  26596                         goto prop_error;
  26597                     /* swap ref and lvalue object if any */
  26598                     if (prop_name == JS_ATOM_NULL) {
  26599                         switch(depth_lvalue) {
  26600                         case 0:
  26601                             break;
  26602                         case 1:
  26603                             /* source prop x -> x source prop */
  26604                             emit_op(s, OP_rot3r);
  26605                             break;
  26606                         case 2:
  26607                             /* source prop x y -> x y source prop */
  26608                             emit_op(s, OP_swap2);   /* t p2 s p1 */
  26609                             break;
  26610                         case 3:
  26611                             /* source prop x y z -> x y z source prop */
  26612                             emit_op(s, OP_rot5l);
  26613                             emit_op(s, OP_rot5l);
  26614                             break;
  26615                         default:
  26616                             abort();
  26617                         }
  26618                     } else {
  26619                         switch(depth_lvalue) {
  26620                         case 0:
  26621                             break;
  26622                         case 1:
  26623                             /* source x -> x source */
  26624                             emit_op(s, OP_swap);
  26625                             break;
  26626                         case 2:
  26627                             /* source x y -> x y source */
  26628                             emit_op(s, OP_rot3l);
  26629                             break;
  26630                         case 3:
  26631                             /* source x y z -> x y z source */
  26632                             emit_op(s, OP_rot4l);
  26633                             break;
  26634                         default:
  26635                             abort();
  26636                         }
  26637                     }
  26638                 }
  26639                 if (prop_name == JS_ATOM_NULL) {
  26640                     /* computed property name on stack */
  26641                     /* XXX: should have OP_get_array_el2x with depth */
  26642                     /* source prop -- val */
  26643                     emit_op(s, OP_get_array_el);
  26644                 } else {
  26645                     /* named property */
  26646                     /* XXX: should have OP_get_field2x with depth */
  26647                     /* source -- val */
  26648                     emit_op(s, OP_get_field);
  26649                     emit_u32(s, prop_name);
  26650                 }
  26651             } else {
  26652                 /* prop_type = PROP_TYPE_VAR, cannot be a computed property */
  26653                 if (is_arg && js_parse_check_duplicate_parameter(s, prop_name))
  26654                     goto prop_error;
  26655                 if ((s->cur_func->js_mode & JS_MODE_STRICT) &&
  26656                     (prop_name == JS_ATOM_eval || prop_name == JS_ATOM_arguments)) {
  26657                     js_parse_error(s, "invalid destructuring target");
  26658                     goto prop_error;
  26659                 }
  26660                 if (has_ellipsis) {
  26661                     /* define the property in excludeList */
  26662                     emit_op(s, OP_swap);
  26663                     emit_op(s, OP_null);
  26664                     emit_op(s, OP_define_field);
  26665                     emit_atom(s, prop_name);
  26666                     emit_op(s, OP_swap);
  26667                 }
  26668                 if (!tok || need_var_reference(s, tok)) {
  26669                     /* generate reference */
  26670                     /* source -- source source */
  26671                     emit_op(s, OP_dup);
  26672                     emit_op(s, OP_scope_get_var);
  26673                     emit_atom(s, prop_name);
  26674                     emit_u16(s, s->cur_func->scope_level);
  26675                     goto lvalue1;
  26676                 } else {
  26677                     /* no need to make a reference for let/const */
  26678                     var_name = JS_DupAtom(s->ctx, prop_name);
  26679                     opcode = OP_scope_get_var;
  26680                     scope = s->cur_func->scope_level;
  26681                     label_lvalue = -1;
  26682                     depth_lvalue = 0;
  26683                     
  26684                     /* source -- source val */
  26685                     emit_op(s, OP_get_field2);
  26686                     emit_u32(s, prop_name);
  26687                 }
  26688             }
  26689         set_val:
  26690             if (tok) {
  26691                 if (js_define_var(s, var_name, tok))
  26692                     goto var_error;
  26693                 if (export_flag) {
  26694                     if (!add_export_entry(s, s->cur_func->module, var_name, var_name,
  26695                                           JS_EXPORT_TYPE_LOCAL))
  26696                         goto var_error;
  26697                 }
  26698                 scope = s->cur_func->scope_level; /* XXX: check */
  26699             }
  26700             if (s->token.val == '=') {  /* handle optional default value */
  26701                 int label_hasval;
  26702                 emit_op(s, OP_dup);
  26703                 emit_op(s, OP_undefined);
  26704                 emit_op(s, OP_strict_eq);
  26705                 label_hasval = emit_goto(s, OP_if_false, -1);
  26706                 if (next_token(s))
  26707                     goto var_error;
  26708                 emit_op(s, OP_drop);
  26709                 if (js_parse_assign_expr(s))
  26710                     goto var_error;
  26711                 if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
  26712                     set_object_name(s, var_name);
  26713                 emit_label(s, label_hasval);
  26714             }
  26715             /* store value into lvalue object */
  26716             put_lvalue(s, opcode, scope, var_name, label_lvalue,
  26717                        PUT_LVALUE_NOKEEP_DEPTH,
  26718                        (tok == TOK_CONST || tok == TOK_LET));
  26719             if (s->token.val == '}')
  26720                 break;
  26721             /* accept a trailing comma before the '}' */
  26722             if (js_parse_expect(s, ','))
  26723                 return -1;
  26724         }
  26725         /* drop the source object */
  26726         emit_op(s, OP_drop);
  26727         if (has_ellipsis) {
  26728             emit_op(s, OP_drop); /* pop excludeList */
  26729         }
  26730         if (next_token(s))
  26731             return -1;
  26732     } else if (s->token.val == '[') {
  26733         BOOL has_spread;
  26734         int enum_depth;
  26735         BlockEnv block_env;
  26736 
  26737         if (next_token(s))
  26738             return -1;
  26739         /* the block environment is only needed in generators in case
  26740            'yield' triggers a 'return' */
  26741         push_break_entry(s->cur_func, &block_env,
  26742                          JS_ATOM_NULL, -1, -1, 2);
  26743         block_env.has_iterator = TRUE;
  26744         emit_op(s, OP_for_of_start);
  26745         has_spread = FALSE;
  26746         while (s->token.val != ']') {
  26747             /* get the next value */
  26748             if (s->token.val == TOK_ELLIPSIS) {
  26749                 if (next_token(s))
  26750                     return -1;
  26751                 if (s->token.val == ',' || s->token.val == ']')
  26752                     return js_parse_error(s, "missing binding pattern...");
  26753                 has_spread = TRUE;
  26754             }
  26755             if (s->token.val == ',') {
  26756                 /* do nothing, skip the value, has_spread is false */
  26757                 emit_op(s, OP_for_of_next);
  26758                 emit_u8(s, 0);
  26759                 emit_op(s, OP_drop);
  26760                 emit_op(s, OP_drop);
  26761             } else if ((s->token.val == '[' || s->token.val == '{')
  26762                    &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' ||
  26763                         tok1 == '=' || tok1 == ']')) {
  26764                 if (has_spread) {
  26765                     if (tok1 == '=')
  26766                         return js_parse_error(s, "rest element cannot have a default value");
  26767                     js_emit_spread_code(s, 0);
  26768                 } else {
  26769                     emit_op(s, OP_for_of_next);
  26770                     emit_u8(s, 0);
  26771                     emit_op(s, OP_drop);
  26772                 }
  26773                 if (js_parse_destructuring_element(s, tok, is_arg, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE, export_flag) < 0)
  26774                     return -1;
  26775             } else {
  26776                 var_name = JS_ATOM_NULL;
  26777                 if (tok) {
  26778                     var_name = js_parse_destructuring_var(s, tok, is_arg);
  26779                     if (var_name == JS_ATOM_NULL)
  26780                         goto var_error;
  26781                     if (js_define_var(s, var_name, tok))
  26782                         goto var_error;
  26783                     if (need_var_reference(s, tok)) {
  26784                         /* Must make a reference for proper `with` semantics */
  26785                         emit_op(s, OP_scope_get_var);
  26786                         emit_atom(s, var_name);
  26787                         emit_u16(s, s->cur_func->scope_level);
  26788                         JS_FreeAtom(s->ctx, var_name);
  26789                         goto lvalue2;
  26790                     } else {
  26791                         /* no need to make a reference for let/const */
  26792                         opcode = OP_scope_get_var;
  26793                         scope = s->cur_func->scope_level;
  26794                         label_lvalue = -1;
  26795                         enum_depth = 0;
  26796                     }
  26797                 } else {
  26798                     if (js_parse_left_hand_side_expr(s))
  26799                         return -1;
  26800                 lvalue2:
  26801                     if (get_lvalue(s, &opcode, &scope, &var_name,
  26802                                    &label_lvalue, &enum_depth, FALSE, '[')) {
  26803                         return -1;
  26804                     }
  26805                 }
  26806                 if (has_spread) {
  26807                     js_emit_spread_code(s, enum_depth);
  26808                 } else {
  26809                     emit_op(s, OP_for_of_next);
  26810                     emit_u8(s, enum_depth);
  26811                     emit_op(s, OP_drop);
  26812                 }
  26813                 if (s->token.val == '=' && !has_spread) {
  26814                     /* handle optional default value */
  26815                     int label_hasval;
  26816                     emit_op(s, OP_dup);
  26817                     emit_op(s, OP_undefined);
  26818                     emit_op(s, OP_strict_eq);
  26819                     label_hasval = emit_goto(s, OP_if_false, -1);
  26820                     if (next_token(s))
  26821                         goto var_error;
  26822                     emit_op(s, OP_drop);
  26823                     if (js_parse_assign_expr(s))
  26824                         goto var_error;
  26825                     if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
  26826                         set_object_name(s, var_name);
  26827                     emit_label(s, label_hasval);
  26828                 }
  26829                 /* store value into lvalue object */
  26830                 put_lvalue(s, opcode, scope, var_name,
  26831                            label_lvalue, PUT_LVALUE_NOKEEP_DEPTH,
  26832                            (tok == TOK_CONST || tok == TOK_LET));
  26833             }
  26834             if (s->token.val == ']')
  26835                 break;
  26836             if (has_spread)
  26837                 return js_parse_error(s, "rest element must be the last one");
  26838             /* accept a trailing comma before the ']' */
  26839             if (js_parse_expect(s, ','))
  26840                 return -1;
  26841         }
  26842         /* close iterator object:
  26843            if completed, enum_obj has been replaced by undefined */
  26844         emit_op(s, OP_iterator_close);
  26845         pop_break_entry(s->cur_func);
  26846         if (next_token(s))
  26847             return -1;
  26848     } else {
  26849         return js_parse_error(s, "invalid assignment syntax");
  26850     }
  26851     if (s->token.val == '=' && allow_initializer) {
  26852         label_done = emit_goto(s, OP_goto, -1);
  26853         if (next_token(s))
  26854             return -1;
  26855         emit_label(s, label_parse);
  26856         if (hasval)
  26857             emit_op(s, OP_drop);
  26858         if (js_parse_assign_expr(s))
  26859             return -1;
  26860         emit_goto(s, OP_goto, label_assign);
  26861         emit_label(s, label_done);
  26862         has_initializer = TRUE;
  26863     } else {
  26864         /* normally hasval is true except if
  26865            js_parse_skip_parens_token() was wrong in the parsing */
  26866         //        assert(hasval);
  26867         if (!hasval) {
  26868             js_parse_error(s, "too complicated destructuring expression");
  26869             return -1;
  26870         }
  26871         /* remove test and decrement label ref count */
  26872         memset(s->cur_func->byte_code.buf + start_addr, OP_nop,
  26873                assign_addr - start_addr);
  26874         s->cur_func->label_slots[label_parse].ref_count--;
  26875         has_initializer = FALSE;
  26876     }
  26877     return has_initializer;
  26878 
  26879  prop_error:
  26880     JS_FreeAtom(s->ctx, prop_name);
  26881  var_error:
  26882     JS_FreeAtom(s->ctx, var_name);
  26883     return -1;
  26884 }
  26885 
  26886 typedef enum FuncCallType {
  26887     FUNC_CALL_NORMAL,
  26888     FUNC_CALL_NEW,
  26889     FUNC_CALL_SUPER_CTOR,
  26890     FUNC_CALL_TEMPLATE,
  26891 } FuncCallType;
  26892 
  26893 static void optional_chain_test(JSParseState *s, int *poptional_chaining_label,
  26894                                 int drop_count)
  26895 {
  26896     int label_next, i;
  26897     if (*poptional_chaining_label < 0)
  26898         *poptional_chaining_label = new_label(s);
  26899    /* XXX: could be more efficient with a specific opcode */
  26900     emit_op(s, OP_dup);
  26901     emit_op(s, OP_is_undefined_or_null);
  26902     label_next = emit_goto(s, OP_if_false, -1);
  26903     for(i = 0; i < drop_count; i++)
  26904         emit_op(s, OP_drop);
  26905     emit_op(s, OP_undefined);
  26906     emit_goto(s, OP_goto, *poptional_chaining_label);
  26907     emit_label(s, label_next);
  26908 }
  26909 
  26910 /* allowed parse_flags: PF_POSTFIX_CALL */
  26911 static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
  26912 {
  26913     FuncCallType call_type;
  26914     int optional_chaining_label;
  26915     BOOL accept_lparen = (parse_flags & PF_POSTFIX_CALL) != 0;
  26916     const uint8_t *op_token_ptr;
  26917     
  26918     call_type = FUNC_CALL_NORMAL;
  26919     switch(s->token.val) {
  26920     case TOK_NUMBER:
  26921         {
  26922             JSValue val;
  26923             val = s->token.u.num.val;
  26924 
  26925             if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) {
  26926                 emit_op(s, OP_push_i32);
  26927                 emit_u32(s, JS_VALUE_GET_INT(val));
  26928             } else if (JS_VALUE_GET_TAG(val) == JS_TAG_SHORT_BIG_INT) {
  26929                 int64_t v;
  26930                 v = JS_VALUE_GET_SHORT_BIG_INT(val);
  26931                 if (v >= INT32_MIN && v <= INT32_MAX) {
  26932                     emit_op(s, OP_push_bigint_i32);
  26933                     emit_u32(s, v);
  26934                 } else {
  26935                     goto large_number;
  26936                 }
  26937             } else {
  26938             large_number:
  26939                 if (emit_push_const(s, val, 0) < 0)
  26940                     return -1;
  26941             }
  26942         }
  26943         if (next_token(s))
  26944             return -1;
  26945         break;
  26946     case TOK_TEMPLATE:
  26947         if (js_parse_template(s, 0, NULL))
  26948             return -1;
  26949         break;
  26950     case TOK_STRING:
  26951         if (emit_push_const(s, s->token.u.str.str, 1))
  26952             return -1;
  26953         if (next_token(s))
  26954             return -1;
  26955         break;
  26956 
  26957     case TOK_DIV_ASSIGN:
  26958         s->buf_ptr -= 2;
  26959         goto parse_regexp;
  26960     case '/':
  26961         s->buf_ptr--;
  26962     parse_regexp:
  26963         {
  26964             JSValue str;
  26965             int ret;
  26966             if (!s->ctx->compile_regexp)
  26967                 return js_parse_error(s, "RegExp are not supported");
  26968             /* the previous token is '/' or '/=', so no need to free */
  26969             if (js_parse_regexp(s))
  26970                 return -1;
  26971             ret = emit_push_const(s, s->token.u.regexp.body, 0);
  26972             str = s->ctx->compile_regexp(s->ctx, s->token.u.regexp.body,
  26973                                          s->token.u.regexp.flags);
  26974             if (JS_IsException(str)) {
  26975                 /* add the line number info */
  26976                 int line_num, col_num;
  26977                 line_num = get_line_col(&col_num, s->buf_start, s->token.ptr - s->buf_start);
  26978                 build_backtrace(s->ctx, s->ctx->rt->current_exception,
  26979                                 s->filename, line_num + 1, col_num + 1, 0);
  26980                 return -1;
  26981             }
  26982             ret = emit_push_const(s, str, 0);
  26983             JS_FreeValue(s->ctx, str);
  26984             if (ret)
  26985                 return -1;
  26986             /* we use a specific opcode to be sure the correct
  26987                function is called (otherwise the bytecode would have
  26988                to be verified by the RegExp constructor) */
  26989             emit_op(s, OP_regexp);
  26990             if (next_token(s))
  26991                 return -1;
  26992         }
  26993         break;
  26994     case '(':
  26995         if (js_parse_expr_paren(s))
  26996             return -1;
  26997         break;
  26998     case TOK_FUNCTION:
  26999         if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR,
  27000                                    JS_FUNC_NORMAL, JS_ATOM_NULL,
  27001                                    s->token.ptr))
  27002             return -1;
  27003         break;
  27004     case TOK_CLASS:
  27005         if (js_parse_class(s, TRUE, JS_PARSE_EXPORT_NONE))
  27006             return -1;
  27007         break;
  27008     case TOK_NULL:
  27009         if (next_token(s))
  27010             return -1;
  27011         emit_op(s, OP_null);
  27012         break;
  27013     case TOK_THIS:
  27014         if (next_token(s))
  27015             return -1;
  27016         emit_op(s, OP_scope_get_var);
  27017         emit_atom(s, JS_ATOM_this);
  27018         emit_u16(s, 0);
  27019         break;
  27020     case TOK_FALSE:
  27021         if (next_token(s))
  27022             return -1;
  27023         emit_op(s, OP_push_false);
  27024         break;
  27025     case TOK_TRUE:
  27026         if (next_token(s))
  27027             return -1;
  27028         emit_op(s, OP_push_true);
  27029         break;
  27030     case TOK_IDENT:
  27031         {
  27032             JSAtom name;
  27033             const uint8_t *source_ptr;
  27034             if (s->token.u.ident.is_reserved) {
  27035                 return js_parse_error_reserved_identifier(s);
  27036             }
  27037             source_ptr = s->token.ptr;
  27038             if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
  27039                 peek_token(s, TRUE) != '\n') {
  27040                 if (next_token(s))
  27041                     return -1;
  27042                 if (s->token.val == TOK_FUNCTION) {
  27043                     if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR,
  27044                                                JS_FUNC_ASYNC, JS_ATOM_NULL,
  27045                                                source_ptr))
  27046                         return -1;
  27047                 } else {
  27048                     name = JS_DupAtom(s->ctx, JS_ATOM_async);
  27049                     goto do_get_var;
  27050                 }
  27051             } else {
  27052                 if (s->token.u.ident.atom == JS_ATOM_arguments &&
  27053                     !s->cur_func->arguments_allowed) {
  27054                     js_parse_error(s, "'arguments' identifier is not allowed in class field initializer");
  27055                     return -1;
  27056                 }
  27057                 name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
  27058                 if (next_token(s)) {
  27059                     JS_FreeAtom(s->ctx, name);
  27060                     return -1;
  27061                 }
  27062             do_get_var:
  27063                 emit_source_pos(s, source_ptr);
  27064                 emit_op(s, OP_scope_get_var);
  27065                 emit_u32(s, name);
  27066                 emit_u16(s, s->cur_func->scope_level);
  27067             }
  27068         }
  27069         break;
  27070     case '{':
  27071     case '[':
  27072         if (s->token.val == '{') {
  27073             if (js_parse_object_literal(s))
  27074                 return -1;
  27075         } else {
  27076             if (js_parse_array_literal(s))
  27077                 return -1;
  27078         }
  27079         break;
  27080     case TOK_NEW:
  27081         if (next_token(s))
  27082             return -1;
  27083         if (s->token.val == '.') {
  27084             if (next_token(s))
  27085                 return -1;
  27086             if (!token_is_pseudo_keyword(s, JS_ATOM_target))
  27087                 return js_parse_error(s, "expecting target");
  27088             if (!s->cur_func->new_target_allowed)
  27089                 return js_parse_error(s, "new.target only allowed within functions");
  27090             if (next_token(s))
  27091                 return -1;
  27092             emit_op(s, OP_scope_get_var);
  27093             emit_atom(s, JS_ATOM_new_target);
  27094             emit_u16(s, 0);
  27095         } else {
  27096             if (js_parse_postfix_expr(s, 0))
  27097                 return -1;
  27098             accept_lparen = TRUE;
  27099             if (s->token.val != '(') {
  27100                 /* new operator on an object */
  27101                 emit_source_pos(s, s->token.ptr);
  27102                 emit_op(s, OP_dup);
  27103                 emit_op(s, OP_call_constructor);
  27104                 emit_u16(s, 0);
  27105             } else {
  27106                 call_type = FUNC_CALL_NEW;
  27107             }
  27108         }
  27109         break;
  27110     case TOK_SUPER:
  27111         if (next_token(s))
  27112             return -1;
  27113         if (s->token.val == '(') {
  27114             if (!s->cur_func->super_call_allowed)
  27115                 return js_parse_error(s, "super() is only valid in a derived class constructor");
  27116             call_type = FUNC_CALL_SUPER_CTOR;
  27117         } else if (s->token.val == '.' || s->token.val == '[') {
  27118             if (!s->cur_func->super_allowed)
  27119                 return js_parse_error(s, "'super' is only valid in a method");
  27120             emit_op(s, OP_scope_get_var);
  27121             emit_atom(s, JS_ATOM_this);
  27122             emit_u16(s, 0);
  27123             emit_op(s, OP_scope_get_var);
  27124             emit_atom(s, JS_ATOM_home_object);
  27125             emit_u16(s, 0);
  27126             emit_op(s, OP_get_super);
  27127         } else {
  27128             return js_parse_error(s, "invalid use of 'super'");
  27129         }
  27130         break;
  27131     case TOK_IMPORT:
  27132         if (next_token(s))
  27133             return -1;
  27134         if (s->token.val == '.') {
  27135             if (next_token(s))
  27136                 return -1;
  27137             if (!token_is_pseudo_keyword(s, JS_ATOM_meta))
  27138                 return js_parse_error(s, "meta expected");
  27139             if (!s->is_module)
  27140                 return js_parse_error(s, "import.meta only valid in module code");
  27141             if (next_token(s))
  27142                 return -1;
  27143             emit_op(s, OP_special_object);
  27144             emit_u8(s, OP_SPECIAL_OBJECT_IMPORT_META);
  27145         } else {
  27146             if (js_parse_expect(s, '('))
  27147                 return -1;
  27148             if (!accept_lparen)
  27149                 return js_parse_error(s, "invalid use of 'import()'");
  27150             if (js_parse_assign_expr(s))
  27151                 return -1;
  27152             if (s->token.val == ',') {
  27153                 if (next_token(s))
  27154                     return -1;
  27155                 if (s->token.val != ')') {
  27156                     if (js_parse_assign_expr(s))
  27157                         return -1;
  27158                     /* accept a trailing comma */
  27159                     if (s->token.val == ',') {
  27160                         if (next_token(s))
  27161                             return -1;
  27162                     }
  27163                 } else {
  27164                     emit_op(s, OP_undefined);
  27165                 }
  27166             } else {
  27167                 emit_op(s, OP_undefined);
  27168             }
  27169             if (js_parse_expect(s, ')'))
  27170                 return -1;
  27171             emit_op(s, OP_import);
  27172         }
  27173         break;
  27174     default:
  27175         return js_parse_error(s, "unexpected token in expression: '%.*s'",
  27176                               (int)(s->buf_ptr - s->token.ptr), s->token.ptr);
  27177     }
  27178 
  27179     optional_chaining_label = -1;
  27180     for(;;) {
  27181         JSFunctionDef *fd = s->cur_func;
  27182         BOOL has_optional_chain = FALSE;
  27183 
  27184         if (s->token.val == TOK_QUESTION_MARK_DOT) {
  27185             if ((parse_flags & PF_POSTFIX_CALL) == 0)
  27186                 return js_parse_error(s, "new keyword cannot be used with an optional chain");
  27187             op_token_ptr = s->token.ptr;
  27188             /* optional chaining */
  27189             if (next_token(s))
  27190                 return -1;
  27191             has_optional_chain = TRUE;
  27192             if (s->token.val == '(' && accept_lparen) {
  27193                 goto parse_func_call;
  27194             } else if (s->token.val == '[') {
  27195                 goto parse_array_access;
  27196             } else {
  27197                 goto parse_property;
  27198             }
  27199         } else if (s->token.val == TOK_TEMPLATE &&
  27200                    call_type == FUNC_CALL_NORMAL) {
  27201             if (optional_chaining_label >= 0) {
  27202                 return js_parse_error(s, "template literal cannot appear in an optional chain");
  27203             }
  27204             call_type = FUNC_CALL_TEMPLATE;
  27205             op_token_ptr = s->token.ptr; /* XXX: check if right position */
  27206             goto parse_func_call2;
  27207         } else if (s->token.val == '(' && accept_lparen) {
  27208             int opcode, arg_count, drop_count;
  27209 
  27210             /* function call */
  27211         parse_func_call:
  27212             op_token_ptr = s->token.ptr;
  27213             if (next_token(s))
  27214                 return -1;
  27215 
  27216             if (call_type == FUNC_CALL_NORMAL) {
  27217             parse_func_call2:
  27218                 switch(opcode = get_prev_opcode(fd)) {
  27219                 case OP_get_field:
  27220                     /* keep the object on the stack */
  27221                     fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;
  27222                     drop_count = 2;
  27223                     break;
  27224                 case OP_get_field_opt_chain:
  27225                     {
  27226                         int opt_chain_label, next_label;
  27227                         opt_chain_label = get_u32(fd->byte_code.buf +
  27228                                                   fd->last_opcode_pos + 1 + 4 + 1);
  27229                         /* keep the object on the stack */
  27230                         fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;
  27231                         fd->byte_code.size = fd->last_opcode_pos + 1 + 4;
  27232                         next_label = emit_goto(s, OP_goto, -1);
  27233                         emit_label(s, opt_chain_label);
  27234                         /* need an additional undefined value for the
  27235                            case where the optional field does not
  27236                            exists */
  27237                         emit_op(s, OP_undefined);
  27238                         emit_label(s, next_label);
  27239                         drop_count = 2;
  27240                         opcode = OP_get_field;
  27241                     }
  27242                     break;
  27243                 case OP_scope_get_private_field:
  27244                     /* keep the object on the stack */
  27245                     fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_private_field2;
  27246                     drop_count = 2;
  27247                     break;
  27248                 case OP_get_array_el:
  27249                     /* keep the object on the stack */
  27250                     fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;
  27251                     drop_count = 2;
  27252                     break;
  27253                 case OP_get_array_el_opt_chain:
  27254                     {
  27255                         int opt_chain_label, next_label;
  27256                         opt_chain_label = get_u32(fd->byte_code.buf +
  27257                                                   fd->last_opcode_pos + 1 + 1);
  27258                         /* keep the object on the stack */
  27259                         fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;
  27260                         fd->byte_code.size = fd->last_opcode_pos + 1;
  27261                         next_label = emit_goto(s, OP_goto, -1);
  27262                         emit_label(s, opt_chain_label);
  27263                         /* need an additional undefined value for the
  27264                            case where the optional field does not
  27265                            exists */
  27266                         emit_op(s, OP_undefined);
  27267                         emit_label(s, next_label);
  27268                         drop_count = 2;
  27269                         opcode = OP_get_array_el;
  27270                     }
  27271                     break;
  27272                 case OP_scope_get_var:
  27273                     {
  27274                         JSAtom name;
  27275                         int scope;
  27276                         name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
  27277                         scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
  27278                         if (name == JS_ATOM_eval && call_type == FUNC_CALL_NORMAL && !has_optional_chain) {
  27279                             /* direct 'eval' */
  27280                             opcode = OP_eval;
  27281                         } else {
  27282                             /* verify if function name resolves to a simple
  27283                                get_loc/get_arg: a function call inside a `with`
  27284                                statement can resolve to a method call of the
  27285                                `with` context object
  27286                              */
  27287                             /* XXX: always generate the OP_scope_get_ref
  27288                                and remove it in variable resolution
  27289                                pass ? */
  27290                             if (has_with_scope(fd, scope)) {
  27291                                 opcode = OP_scope_get_ref;
  27292                                 fd->byte_code.buf[fd->last_opcode_pos] = opcode;
  27293                             }
  27294                         }
  27295                         drop_count = 1;
  27296                     }
  27297                     break;
  27298                 case OP_get_super_value:
  27299                     fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el;
  27300                     /* on stack: this func_obj */
  27301                     opcode = OP_get_array_el;
  27302                     drop_count = 2;
  27303                     break;
  27304                 default:
  27305                     opcode = OP_invalid;
  27306                     drop_count = 1;
  27307                     break;
  27308                 }
  27309                 if (has_optional_chain) {
  27310                     optional_chain_test(s, &optional_chaining_label,
  27311                                         drop_count);
  27312                 }
  27313             } else {
  27314                 opcode = OP_invalid;
  27315             }
  27316 
  27317             if (call_type == FUNC_CALL_TEMPLATE) {
  27318                 if (js_parse_template(s, 1, &arg_count))
  27319                     return -1;
  27320                 goto emit_func_call;
  27321             } else if (call_type == FUNC_CALL_SUPER_CTOR) {
  27322                 emit_op(s, OP_scope_get_var);
  27323                 emit_atom(s, JS_ATOM_this_active_func);
  27324                 emit_u16(s, 0);
  27325 
  27326                 emit_op(s, OP_get_super);
  27327 
  27328                 emit_op(s, OP_scope_get_var);
  27329                 emit_atom(s, JS_ATOM_new_target);
  27330                 emit_u16(s, 0);
  27331             } else if (call_type == FUNC_CALL_NEW) {
  27332                 emit_op(s, OP_dup); /* new.target = function */
  27333             }
  27334 
  27335             /* parse arguments */
  27336             arg_count = 0;
  27337             while (s->token.val != ')') {
  27338                 if (arg_count >= 65535) {
  27339                     return js_parse_error(s, "Too many call arguments");
  27340                 }
  27341                 if (s->token.val == TOK_ELLIPSIS)
  27342                     break;
  27343                 if (js_parse_assign_expr(s))
  27344                     return -1;
  27345                 arg_count++;
  27346                 if (s->token.val == ')')
  27347                     break;
  27348                 /* accept a trailing comma before the ')' */
  27349                 if (js_parse_expect(s, ','))
  27350                     return -1;
  27351             }
  27352             if (s->token.val == TOK_ELLIPSIS) {
  27353                 emit_op(s, OP_array_from);
  27354                 emit_u16(s, arg_count);
  27355                 emit_op(s, OP_push_i32);
  27356                 emit_u32(s, arg_count);
  27357 
  27358                 /* on stack: array idx */
  27359                 while (s->token.val != ')') {
  27360                     if (s->token.val == TOK_ELLIPSIS) {
  27361                         if (next_token(s))
  27362                             return -1;
  27363                         if (js_parse_assign_expr(s))
  27364                             return -1;
  27365 #if 1
  27366                         /* XXX: could pass is_last indicator? */
  27367                         emit_op(s, OP_append);
  27368 #else
  27369                         int label_next, label_done;
  27370                         label_next = new_label(s);
  27371                         label_done = new_label(s);
  27372                         /* push enumerate object below array/idx pair */
  27373                         emit_op(s, OP_for_of_start);
  27374                         emit_op(s, OP_rot5l);
  27375                         emit_op(s, OP_rot5l);
  27376                         emit_label(s, label_next);
  27377                         /* on stack: enum_rec array idx */
  27378                         emit_op(s, OP_for_of_next);
  27379                         emit_u8(s, 2);
  27380                         emit_goto(s, OP_if_true, label_done);
  27381                         /* append element */
  27382                         /* enum_rec array idx val -> enum_rec array new_idx */
  27383                         emit_op(s, OP_define_array_el);
  27384                         emit_op(s, OP_inc);
  27385                         emit_goto(s, OP_goto, label_next);
  27386                         emit_label(s, label_done);
  27387                         /* close enumeration, drop enum_rec and idx */
  27388                         emit_op(s, OP_drop); /* drop undef */
  27389                         emit_op(s, OP_nip1); /* drop enum_rec */
  27390                         emit_op(s, OP_nip1);
  27391                         emit_op(s, OP_nip1);
  27392 #endif
  27393                     } else {
  27394                         if (js_parse_assign_expr(s))
  27395                             return -1;
  27396                         /* array idx val */
  27397                         emit_op(s, OP_define_array_el);
  27398                         emit_op(s, OP_inc);
  27399                     }
  27400                     if (s->token.val == ')')
  27401                         break;
  27402                     /* accept a trailing comma before the ')' */
  27403                     if (js_parse_expect(s, ','))
  27404                         return -1;
  27405                 }
  27406                 if (next_token(s))
  27407                     return -1;
  27408                 /* drop the index */
  27409                 emit_op(s, OP_drop);
  27410 
  27411                 emit_source_pos(s, op_token_ptr);
  27412                 /* apply function call */
  27413                 switch(opcode) {
  27414                 case OP_get_field:
  27415                 case OP_scope_get_private_field:
  27416                 case OP_get_array_el:
  27417                 case OP_scope_get_ref:
  27418                     /* obj func array -> func obj array */
  27419                     emit_op(s, OP_perm3);
  27420                     emit_op(s, OP_apply);
  27421                     emit_u16(s, call_type == FUNC_CALL_NEW);
  27422                     break;
  27423                 case OP_eval:
  27424                     emit_op(s, OP_apply_eval);
  27425                     emit_u16(s, fd->scope_level);
  27426                     fd->has_eval_call = TRUE;
  27427                     break;
  27428                 default:
  27429                     if (call_type == FUNC_CALL_SUPER_CTOR) {
  27430                         emit_op(s, OP_apply);
  27431                         emit_u16(s, 1);
  27432                         /* set the 'this' value */
  27433                         emit_op(s, OP_dup);
  27434                         emit_op(s, OP_scope_put_var_init);
  27435                         emit_atom(s, JS_ATOM_this);
  27436                         emit_u16(s, 0);
  27437 
  27438                         emit_class_field_init(s);
  27439                     } else if (call_type == FUNC_CALL_NEW) {
  27440                         /* obj func array -> func obj array */
  27441                         emit_op(s, OP_perm3);
  27442                         emit_op(s, OP_apply);
  27443                         emit_u16(s, 1);
  27444                     } else {
  27445                         /* func array -> func undef array */
  27446                         emit_op(s, OP_undefined);
  27447                         emit_op(s, OP_swap);
  27448                         emit_op(s, OP_apply);
  27449                         emit_u16(s, 0);
  27450                     }
  27451                     break;
  27452                 }
  27453             } else {
  27454                 if (next_token(s))
  27455                     return -1;
  27456             emit_func_call:
  27457                 emit_source_pos(s, op_token_ptr);
  27458                 switch(opcode) {
  27459                 case OP_get_field:
  27460                 case OP_scope_get_private_field:
  27461                 case OP_get_array_el:
  27462                 case OP_scope_get_ref:
  27463                     emit_op(s, OP_call_method);
  27464                     emit_u16(s, arg_count);
  27465                     break;
  27466                 case OP_eval:
  27467                     emit_op(s, OP_eval);
  27468                     emit_u16(s, arg_count);
  27469                     emit_u16(s, fd->scope_level);
  27470                     fd->has_eval_call = TRUE;
  27471                     break;
  27472                 default:
  27473                     if (call_type == FUNC_CALL_SUPER_CTOR) {
  27474                         emit_op(s, OP_call_constructor);
  27475                         emit_u16(s, arg_count);
  27476 
  27477                         /* set the 'this' value */
  27478                         emit_op(s, OP_dup);
  27479                         emit_op(s, OP_scope_put_var_init);
  27480                         emit_atom(s, JS_ATOM_this);
  27481                         emit_u16(s, 0);
  27482 
  27483                         emit_class_field_init(s);
  27484                     } else if (call_type == FUNC_CALL_NEW) {
  27485                         emit_op(s, OP_call_constructor);
  27486                         emit_u16(s, arg_count);
  27487                     } else {
  27488                         emit_op(s, OP_call);
  27489                         emit_u16(s, arg_count);
  27490                     }
  27491                     break;
  27492                 }
  27493             }
  27494             call_type = FUNC_CALL_NORMAL;
  27495         } else if (s->token.val == '.') {
  27496             op_token_ptr = s->token.ptr;
  27497             if (next_token(s))
  27498                 return -1;
  27499         parse_property:
  27500             emit_source_pos(s, op_token_ptr);
  27501             if (s->token.val == TOK_PRIVATE_NAME) {
  27502                 /* private class field */
  27503                 if (get_prev_opcode(fd) == OP_get_super) {
  27504                     return js_parse_error(s, "private class field forbidden after super");
  27505                 }
  27506                 if (has_optional_chain) {
  27507                     optional_chain_test(s, &optional_chaining_label, 1);
  27508                 }
  27509                 emit_op(s, OP_scope_get_private_field);
  27510                 emit_atom(s, s->token.u.ident.atom);
  27511                 emit_u16(s, s->cur_func->scope_level);
  27512             } else {
  27513                 if (!token_is_ident(s->token.val)) {
  27514                     return js_parse_error(s, "expecting field name");
  27515                 }
  27516                 if (get_prev_opcode(fd) == OP_get_super) {
  27517                     JSValue val;
  27518                     int ret;
  27519                     val = JS_AtomToValue(s->ctx, s->token.u.ident.atom);
  27520                     ret = emit_push_const(s, val, 1);
  27521                     JS_FreeValue(s->ctx, val);
  27522                     if (ret)
  27523                         return -1;
  27524                     emit_op(s, OP_get_super_value);
  27525                 } else {
  27526                     if (has_optional_chain) {
  27527                         optional_chain_test(s, &optional_chaining_label, 1);
  27528                     }
  27529                     emit_op(s, OP_get_field);
  27530                     emit_atom(s, s->token.u.ident.atom);
  27531                 }
  27532             }
  27533             if (next_token(s))
  27534                 return -1;
  27535         } else if (s->token.val == '[') {
  27536             int prev_op;
  27537             op_token_ptr = s->token.ptr;
  27538         parse_array_access:
  27539             prev_op = get_prev_opcode(fd);
  27540             if (has_optional_chain) {
  27541                 optional_chain_test(s, &optional_chaining_label, 1);
  27542             }
  27543             if (next_token(s))
  27544                 return -1;
  27545             if (js_parse_expr(s))
  27546                 return -1;
  27547             if (js_parse_expect(s, ']'))
  27548                 return -1;
  27549             emit_source_pos(s, op_token_ptr);
  27550             if (prev_op == OP_get_super) {
  27551                 emit_op(s, OP_get_super_value);
  27552             } else {
  27553                 emit_op(s, OP_get_array_el);
  27554             }
  27555         } else {
  27556             break;
  27557         }
  27558     }
  27559     if (optional_chaining_label >= 0) {
  27560         JSFunctionDef *fd = s->cur_func;
  27561         int opcode;
  27562         emit_label_raw(s, optional_chaining_label);
  27563         /* modify the last opcode so that it is an indicator of an
  27564            optional chain */
  27565         opcode = get_prev_opcode(fd);
  27566         if (opcode == OP_get_field || opcode == OP_get_array_el) {
  27567             if (opcode == OP_get_field)
  27568                 opcode = OP_get_field_opt_chain;
  27569             else
  27570                 opcode = OP_get_array_el_opt_chain;
  27571             fd->byte_code.buf[fd->last_opcode_pos] = opcode;
  27572         } else {
  27573             fd->last_opcode_pos = -1;
  27574         }
  27575     }
  27576     return 0;
  27577 }
  27578 
  27579 static __exception int js_parse_delete(JSParseState *s)
  27580 {
  27581     JSFunctionDef *fd = s->cur_func;
  27582     JSAtom name;
  27583     int opcode;
  27584 
  27585     if (next_token(s))
  27586         return -1;
  27587     if (js_parse_unary(s, PF_POW_FORBIDDEN))
  27588         return -1;
  27589     switch(opcode = get_prev_opcode(fd)) {
  27590     case OP_get_field:
  27591     case OP_get_field_opt_chain:
  27592         {
  27593             JSValue val;
  27594             int ret, opt_chain_label, next_label;
  27595             if (opcode == OP_get_field_opt_chain) {
  27596                 opt_chain_label = get_u32(fd->byte_code.buf +
  27597                                           fd->last_opcode_pos + 1 + 4 + 1);
  27598             } else {
  27599                 opt_chain_label = -1;
  27600             }
  27601             name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
  27602             fd->byte_code.size = fd->last_opcode_pos;
  27603             val = JS_AtomToValue(s->ctx, name);
  27604             ret = emit_push_const(s, val, 1);
  27605             JS_FreeValue(s->ctx, val);
  27606             JS_FreeAtom(s->ctx, name);
  27607             if (ret)
  27608                 return ret;
  27609             emit_op(s, OP_delete);
  27610             if (opt_chain_label >= 0) {
  27611                 next_label = emit_goto(s, OP_goto, -1);
  27612                 emit_label(s, opt_chain_label);
  27613                 /* if the optional chain is not taken, return 'true' */
  27614                 emit_op(s, OP_drop);
  27615                 emit_op(s, OP_push_true);
  27616                 emit_label(s, next_label);
  27617             }
  27618             fd->last_opcode_pos = -1;
  27619         }
  27620         break;
  27621     case OP_get_array_el:
  27622         fd->byte_code.size = fd->last_opcode_pos;
  27623         fd->last_opcode_pos = -1;
  27624         emit_op(s, OP_delete);
  27625         break;
  27626     case OP_get_array_el_opt_chain:
  27627         {
  27628             int opt_chain_label, next_label;
  27629             opt_chain_label = get_u32(fd->byte_code.buf +
  27630                                       fd->last_opcode_pos + 1 + 1);
  27631             fd->byte_code.size = fd->last_opcode_pos;
  27632             emit_op(s, OP_delete);
  27633             next_label = emit_goto(s, OP_goto, -1);
  27634             emit_label(s, opt_chain_label);
  27635             /* if the optional chain is not taken, return 'true' */
  27636             emit_op(s, OP_drop);
  27637             emit_op(s, OP_push_true);
  27638             emit_label(s, next_label);
  27639             fd->last_opcode_pos = -1;
  27640         }
  27641         break;
  27642     case OP_scope_get_var:
  27643         /* 'delete this': this is not a reference */
  27644         name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
  27645         if (name == JS_ATOM_this || name == JS_ATOM_new_target)
  27646             goto ret_true;
  27647         if (fd->js_mode & JS_MODE_STRICT) {
  27648             return js_parse_error(s, "cannot delete a direct reference in strict mode");
  27649         } else {
  27650             fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_delete_var;
  27651         }
  27652         break;
  27653     case OP_scope_get_private_field:
  27654         return js_parse_error(s, "cannot delete a private class field");
  27655     case OP_get_super_value:
  27656         fd->byte_code.size = fd->last_opcode_pos;
  27657         fd->last_opcode_pos = -1;
  27658         emit_op(s, OP_throw_error);
  27659         emit_atom(s, JS_ATOM_NULL);
  27660         emit_u8(s, JS_THROW_ERROR_DELETE_SUPER);
  27661         break;
  27662     default:
  27663     ret_true:
  27664         emit_op(s, OP_drop);
  27665         emit_op(s, OP_push_true);
  27666         break;
  27667     }
  27668     return 0;
  27669 }
  27670 
  27671 /* allowed parse_flags: PF_POW_ALLOWED, PF_POW_FORBIDDEN */
  27672 static __exception int js_parse_unary(JSParseState *s, int parse_flags)
  27673 {
  27674     int op;
  27675     const uint8_t *op_token_ptr;
  27676 
  27677     switch(s->token.val) {
  27678     case '+':
  27679     case '-':
  27680     case '!':
  27681     case '~':
  27682     case TOK_VOID:
  27683         op_token_ptr = s->token.ptr;
  27684         op = s->token.val;
  27685         if (next_token(s))
  27686             return -1;
  27687         if (js_parse_unary(s, PF_POW_FORBIDDEN))
  27688             return -1;
  27689         switch(op) {
  27690         case '-':
  27691             emit_source_pos(s, op_token_ptr);
  27692             emit_op(s, OP_neg);
  27693             break;
  27694         case '+':
  27695             emit_source_pos(s, op_token_ptr);
  27696             emit_op(s, OP_plus);
  27697             break;
  27698         case '!':
  27699             emit_op(s, OP_lnot);
  27700             break;
  27701         case '~':
  27702             emit_source_pos(s, op_token_ptr);
  27703             emit_op(s, OP_not);
  27704             break;
  27705         case TOK_VOID:
  27706             emit_op(s, OP_drop);
  27707             emit_op(s, OP_undefined);
  27708             break;
  27709         default:
  27710             abort();
  27711         }
  27712         parse_flags = 0;
  27713         break;
  27714     case TOK_DEC:
  27715     case TOK_INC:
  27716         {
  27717             int opcode, op, scope, label;
  27718             JSAtom name;
  27719             op = s->token.val;
  27720             op_token_ptr = s->token.ptr;
  27721             if (next_token(s))
  27722                 return -1;
  27723             if (js_parse_unary(s, 0))
  27724                 return -1;
  27725             if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))
  27726                 return -1;
  27727             emit_source_pos(s, op_token_ptr);
  27728             emit_op(s, OP_dec + op - TOK_DEC);
  27729             put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP,
  27730                        FALSE);
  27731         }
  27732         break;
  27733     case TOK_TYPEOF:
  27734         {
  27735             JSFunctionDef *fd;
  27736             if (next_token(s))
  27737                 return -1;
  27738             if (js_parse_unary(s, PF_POW_FORBIDDEN))
  27739                 return -1;
  27740             /* reference access should not return an exception, so we
  27741                patch the get_var */
  27742             fd = s->cur_func;
  27743             if (get_prev_opcode(fd) == OP_scope_get_var) {
  27744                 fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_var_undef;
  27745             }
  27746             emit_op(s, OP_typeof);
  27747             parse_flags = 0;
  27748         }
  27749         break;
  27750     case TOK_DELETE:
  27751         if (js_parse_delete(s))
  27752             return -1;
  27753         parse_flags = 0;
  27754         break;
  27755     case TOK_AWAIT:
  27756         if (!(s->cur_func->func_kind & JS_FUNC_ASYNC))
  27757             return js_parse_error(s, "unexpected 'await' keyword");
  27758         if (!s->cur_func->in_function_body)
  27759             return js_parse_error(s, "await in default expression");
  27760         if (next_token(s))
  27761             return -1;
  27762         if (js_parse_unary(s, PF_POW_FORBIDDEN))
  27763             return -1;
  27764         s->cur_func->has_await = TRUE;
  27765         emit_op(s, OP_await);
  27766         parse_flags = 0;
  27767         break;
  27768     default:
  27769         if (js_parse_postfix_expr(s, PF_POSTFIX_CALL))
  27770             return -1;
  27771         if (!s->got_lf &&
  27772             (s->token.val == TOK_DEC || s->token.val == TOK_INC)) {
  27773             int opcode, op, scope, label;
  27774             JSAtom name;
  27775             op = s->token.val;
  27776             op_token_ptr = s->token.ptr;
  27777             if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))
  27778                 return -1;
  27779             emit_source_pos(s, op_token_ptr);
  27780             emit_op(s, OP_post_dec + op - TOK_DEC);
  27781             put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_SECOND,
  27782                        FALSE);
  27783             if (next_token(s))
  27784                 return -1;
  27785         }
  27786         break;
  27787     }
  27788     if (parse_flags & (PF_POW_ALLOWED | PF_POW_FORBIDDEN)) {
  27789         if (s->token.val == TOK_POW) {
  27790             /* Strict ES7 exponentiation syntax rules: To solve
  27791                conficting semantics between different implementations
  27792                regarding the precedence of prefix operators and the
  27793                postifx exponential, ES7 specifies that -2**2 is a
  27794                syntax error. */
  27795             if (parse_flags & PF_POW_FORBIDDEN) {
  27796                 JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'");
  27797                 return -1;
  27798             }
  27799             op_token_ptr = s->token.ptr;
  27800             if (next_token(s))
  27801                 return -1;
  27802             if (js_parse_unary(s, PF_POW_ALLOWED))
  27803                 return -1;
  27804             emit_source_pos(s, op_token_ptr);
  27805             emit_op(s, OP_pow);
  27806         }
  27807     }
  27808     return 0;
  27809 }
  27810 
  27811 /* allowed parse_flags: PF_IN_ACCEPTED */
  27812 static __exception int js_parse_expr_binary(JSParseState *s, int level,
  27813                                             int parse_flags)
  27814 {
  27815     int op, opcode;
  27816     const uint8_t *op_token_ptr;
  27817     
  27818     if (level == 0) {
  27819         return js_parse_unary(s, PF_POW_ALLOWED);
  27820     } else if (s->token.val == TOK_PRIVATE_NAME &&
  27821                (parse_flags & PF_IN_ACCEPTED) && level == 4 &&
  27822                peek_token(s, FALSE) == TOK_IN) {
  27823         JSAtom atom;
  27824 
  27825         atom = JS_DupAtom(s->ctx, s->token.u.ident.atom);
  27826         if (next_token(s))
  27827             goto fail_private_in;
  27828         if (s->token.val != TOK_IN)
  27829             goto fail_private_in;
  27830         if (next_token(s))
  27831             goto fail_private_in;
  27832         if (js_parse_expr_binary(s, level - 1, parse_flags)) {
  27833         fail_private_in:
  27834             JS_FreeAtom(s->ctx, atom);
  27835             return -1;
  27836         }
  27837         emit_op(s, OP_scope_in_private_field);
  27838         emit_atom(s, atom);
  27839         emit_u16(s, s->cur_func->scope_level);
  27840         JS_FreeAtom(s->ctx, atom);
  27841         return 0;
  27842     } else {
  27843         if (js_parse_expr_binary(s, level - 1, parse_flags))
  27844             return -1;
  27845     }
  27846     for(;;) {
  27847         op = s->token.val;
  27848         op_token_ptr = s->token.ptr;
  27849         switch(level) {
  27850         case 1:
  27851             switch(op) {
  27852             case '*':
  27853                 opcode = OP_mul;
  27854                 break;
  27855             case '/':
  27856                 opcode = OP_div;
  27857                 break;
  27858             case '%':
  27859                 opcode = OP_mod;
  27860                 break;
  27861             default:
  27862                 return 0;
  27863             }
  27864             break;
  27865         case 2:
  27866             switch(op) {
  27867             case '+':
  27868                 opcode = OP_add;
  27869                 break;
  27870             case '-':
  27871                 opcode = OP_sub;
  27872                 break;
  27873             default:
  27874                 return 0;
  27875             }
  27876             break;
  27877         case 3:
  27878             switch(op) {
  27879             case TOK_SHL:
  27880                 opcode = OP_shl;
  27881                 break;
  27882             case TOK_SAR:
  27883                 opcode = OP_sar;
  27884                 break;
  27885             case TOK_SHR:
  27886                 opcode = OP_shr;
  27887                 break;
  27888             default:
  27889                 return 0;
  27890             }
  27891             break;
  27892         case 4:
  27893             switch(op) {
  27894             case '<':
  27895                 opcode = OP_lt;
  27896                 break;
  27897             case '>':
  27898                 opcode = OP_gt;
  27899                 break;
  27900             case TOK_LTE:
  27901                 opcode = OP_lte;
  27902                 break;
  27903             case TOK_GTE:
  27904                 opcode = OP_gte;
  27905                 break;
  27906             case TOK_INSTANCEOF:
  27907                 opcode = OP_instanceof;
  27908                 break;
  27909             case TOK_IN:
  27910                 if (parse_flags & PF_IN_ACCEPTED) {
  27911                     opcode = OP_in;
  27912                 } else {
  27913                     return 0;
  27914                 }
  27915                 break;
  27916             default:
  27917                 return 0;
  27918             }
  27919             break;
  27920         case 5:
  27921             switch(op) {
  27922             case TOK_EQ:
  27923                 opcode = OP_eq;
  27924                 break;
  27925             case TOK_NEQ:
  27926                 opcode = OP_neq;
  27927                 break;
  27928             case TOK_STRICT_EQ:
  27929                 opcode = OP_strict_eq;
  27930                 break;
  27931             case TOK_STRICT_NEQ:
  27932                 opcode = OP_strict_neq;
  27933                 break;
  27934             default:
  27935                 return 0;
  27936             }
  27937             break;
  27938         case 6:
  27939             switch(op) {
  27940             case '&':
  27941                 opcode = OP_and;
  27942                 break;
  27943             default:
  27944                 return 0;
  27945             }
  27946             break;
  27947         case 7:
  27948             switch(op) {
  27949             case '^':
  27950                 opcode = OP_xor;
  27951                 break;
  27952             default:
  27953                 return 0;
  27954             }
  27955             break;
  27956         case 8:
  27957             switch(op) {
  27958             case '|':
  27959                 opcode = OP_or;
  27960                 break;
  27961             default:
  27962                 return 0;
  27963             }
  27964             break;
  27965         default:
  27966             abort();
  27967         }
  27968         if (next_token(s))
  27969             return -1;
  27970         if (js_parse_expr_binary(s, level - 1, parse_flags))
  27971             return -1;
  27972         emit_source_pos(s, op_token_ptr);
  27973         emit_op(s, opcode);
  27974     }
  27975     return 0;
  27976 }
  27977 
  27978 /* allowed parse_flags: PF_IN_ACCEPTED */
  27979 static __exception int js_parse_logical_and_or(JSParseState *s, int op,
  27980                                                int parse_flags)
  27981 {
  27982     int label1;
  27983 
  27984     if (op == TOK_LAND) {
  27985         if (js_parse_expr_binary(s, 8, parse_flags))
  27986             return -1;
  27987     } else {
  27988         if (js_parse_logical_and_or(s, TOK_LAND, parse_flags))
  27989             return -1;
  27990     }
  27991     if (s->token.val == op) {
  27992         label1 = new_label(s);
  27993 
  27994         for(;;) {
  27995             if (next_token(s))
  27996                 return -1;
  27997             emit_op(s, OP_dup);
  27998             emit_goto(s, op == TOK_LAND ? OP_if_false : OP_if_true, label1);
  27999             emit_op(s, OP_drop);
  28000 
  28001             if (op == TOK_LAND) {
  28002                 if (js_parse_expr_binary(s, 8, parse_flags))
  28003                     return -1;
  28004             } else {
  28005                 if (js_parse_logical_and_or(s, TOK_LAND,
  28006                                             parse_flags))
  28007                     return -1;
  28008             }
  28009             if (s->token.val != op) {
  28010                 if (s->token.val == TOK_DOUBLE_QUESTION_MARK)
  28011                     return js_parse_error(s, "cannot mix ?? with && or ||");
  28012                 break;
  28013             }
  28014         }
  28015 
  28016         emit_label(s, label1);
  28017     }
  28018     return 0;
  28019 }
  28020 
  28021 static __exception int js_parse_coalesce_expr(JSParseState *s, int parse_flags)
  28022 {
  28023     int label1;
  28024 
  28025     if (js_parse_logical_and_or(s, TOK_LOR, parse_flags))
  28026         return -1;
  28027     if (s->token.val == TOK_DOUBLE_QUESTION_MARK) {
  28028         label1 = new_label(s);
  28029         for(;;) {
  28030             if (next_token(s))
  28031                 return -1;
  28032 
  28033             emit_op(s, OP_dup);
  28034             emit_op(s, OP_is_undefined_or_null);
  28035             emit_goto(s, OP_if_false, label1);
  28036             emit_op(s, OP_drop);
  28037 
  28038             if (js_parse_expr_binary(s, 8, parse_flags))
  28039                 return -1;
  28040             if (s->token.val != TOK_DOUBLE_QUESTION_MARK)
  28041                 break;
  28042         }
  28043         emit_label(s, label1);
  28044     }
  28045     return 0;
  28046 }
  28047 
  28048 /* allowed parse_flags: PF_IN_ACCEPTED */
  28049 static __exception int js_parse_cond_expr(JSParseState *s, int parse_flags)
  28050 {
  28051     int label1, label2;
  28052 
  28053     if (js_parse_coalesce_expr(s, parse_flags))
  28054         return -1;
  28055     if (s->token.val == '?') {
  28056         if (next_token(s))
  28057             return -1;
  28058         label1 = emit_goto(s, OP_if_false, -1);
  28059 
  28060         if (js_parse_assign_expr(s))
  28061             return -1;
  28062         if (js_parse_expect(s, ':'))
  28063             return -1;
  28064 
  28065         label2 = emit_goto(s, OP_goto, -1);
  28066 
  28067         emit_label(s, label1);
  28068 
  28069         if (js_parse_assign_expr2(s, parse_flags & PF_IN_ACCEPTED))
  28070             return -1;
  28071 
  28072         emit_label(s, label2);
  28073     }
  28074     return 0;
  28075 }
  28076 
  28077 /* allowed parse_flags: PF_IN_ACCEPTED */
  28078 static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
  28079 {
  28080     int opcode, op, scope, skip_bits;
  28081     JSAtom name0 = JS_ATOM_NULL;
  28082     JSAtom name;
  28083 
  28084     if (s->token.val == TOK_YIELD) {
  28085         BOOL is_star = FALSE, is_async;
  28086 
  28087         if (!(s->cur_func->func_kind & JS_FUNC_GENERATOR))
  28088             return js_parse_error(s, "unexpected 'yield' keyword");
  28089         if (!s->cur_func->in_function_body)
  28090             return js_parse_error(s, "yield in default expression");
  28091         if (next_token(s))
  28092             return -1;
  28093         /* XXX: is there a better method to detect 'yield' without
  28094            parameters ? */
  28095         if (s->token.val != ';' && s->token.val != ')' &&
  28096             s->token.val != ']' && s->token.val != '}' &&
  28097             s->token.val != ',' && s->token.val != ':' && !s->got_lf) {
  28098             if (s->token.val == '*') {
  28099                 is_star = TRUE;
  28100                 if (next_token(s))
  28101                     return -1;
  28102             }
  28103             if (js_parse_assign_expr2(s, parse_flags))
  28104                 return -1;
  28105         } else {
  28106             emit_op(s, OP_undefined);
  28107         }
  28108         is_async = (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR);
  28109 
  28110         if (is_star) {
  28111             int label_loop, label_return, label_next;
  28112             int label_return1, label_yield, label_throw, label_throw1;
  28113             int label_throw2;
  28114 
  28115             label_loop = new_label(s);
  28116             label_yield = new_label(s);
  28117 
  28118             emit_op(s, is_async ? OP_for_await_of_start : OP_for_of_start);
  28119 
  28120             /* remove the catch offset (XXX: could avoid pushing back
  28121                undefined) */
  28122             emit_op(s, OP_drop);
  28123             emit_op(s, OP_undefined);
  28124 
  28125             emit_op(s, OP_undefined); /* initial value */
  28126 
  28127             emit_label(s, label_loop);
  28128             emit_op(s, OP_iterator_next);
  28129             if (is_async)
  28130                 emit_op(s, OP_await);
  28131             emit_op(s, OP_iterator_check_object);
  28132             emit_op(s, OP_get_field2);
  28133             emit_atom(s, JS_ATOM_done);
  28134             label_next = emit_goto(s, OP_if_true, -1); /* end of loop */
  28135             emit_label(s, label_yield);
  28136             if (is_async) {
  28137                 /* OP_async_yield_star takes the value as parameter */
  28138                 emit_op(s, OP_get_field);
  28139                 emit_atom(s, JS_ATOM_value);
  28140                 emit_op(s, OP_async_yield_star);
  28141             } else {
  28142                 /* OP_yield_star takes (value, done) as parameter */
  28143                 emit_op(s, OP_yield_star);
  28144             }
  28145             emit_op(s, OP_dup);
  28146             label_return = emit_goto(s, OP_if_true, -1);
  28147             emit_op(s, OP_drop);
  28148             emit_goto(s, OP_goto, label_loop);
  28149 
  28150             emit_label(s, label_return);
  28151             emit_op(s, OP_push_i32);
  28152             emit_u32(s, 2);
  28153             emit_op(s, OP_strict_eq);
  28154             label_throw = emit_goto(s, OP_if_true, -1);
  28155 
  28156             /* return handling */
  28157             if (is_async)
  28158                 emit_op(s, OP_await);
  28159             emit_op(s, OP_iterator_call);
  28160             emit_u8(s, 0);
  28161             label_return1 = emit_goto(s, OP_if_true, -1);
  28162             if (is_async)
  28163                 emit_op(s, OP_await);
  28164             emit_op(s, OP_iterator_check_object);
  28165             emit_op(s, OP_get_field2);
  28166             emit_atom(s, JS_ATOM_done);
  28167             emit_goto(s, OP_if_false, label_yield);
  28168 
  28169             emit_op(s, OP_get_field);
  28170             emit_atom(s, JS_ATOM_value);
  28171 
  28172             emit_label(s, label_return1);
  28173             emit_op(s, OP_nip);
  28174             emit_op(s, OP_nip);
  28175             emit_op(s, OP_nip);
  28176             emit_return(s, TRUE);
  28177 
  28178             /* throw handling */
  28179             emit_label(s, label_throw);
  28180             emit_op(s, OP_iterator_call);
  28181             emit_u8(s, 1);
  28182             label_throw1 = emit_goto(s, OP_if_true, -1);
  28183             if (is_async)
  28184                 emit_op(s, OP_await);
  28185             emit_op(s, OP_iterator_check_object);
  28186             emit_op(s, OP_get_field2);
  28187             emit_atom(s, JS_ATOM_done);
  28188             emit_goto(s, OP_if_false, label_yield);
  28189             emit_goto(s, OP_goto, label_next);
  28190             /* close the iterator and throw a type error exception */
  28191             emit_label(s, label_throw1);
  28192             emit_op(s, OP_iterator_call);
  28193             emit_u8(s, 2);
  28194             label_throw2 = emit_goto(s, OP_if_true, -1);
  28195             if (is_async)
  28196                 emit_op(s, OP_await);
  28197             emit_label(s, label_throw2);
  28198 
  28199             emit_op(s, OP_throw_error);
  28200             emit_atom(s, JS_ATOM_NULL);
  28201             emit_u8(s, JS_THROW_ERROR_ITERATOR_THROW);
  28202 
  28203             emit_label(s, label_next);
  28204             emit_op(s, OP_get_field);
  28205             emit_atom(s, JS_ATOM_value);
  28206             emit_op(s, OP_nip); /* keep the value associated with
  28207                                    done = true */
  28208             emit_op(s, OP_nip);
  28209             emit_op(s, OP_nip);
  28210         } else {
  28211             int label_next;
  28212 
  28213             if (is_async)
  28214                 emit_op(s, OP_await);
  28215             emit_op(s, OP_yield);
  28216             label_next = emit_goto(s, OP_if_false, -1);
  28217             emit_return(s, TRUE);
  28218             emit_label(s, label_next);
  28219         }
  28220         return 0;
  28221     } else if (s->token.val == '(' &&
  28222                js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) {
  28223         return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
  28224                                       JS_FUNC_NORMAL, JS_ATOM_NULL,
  28225                                       s->token.ptr);
  28226     } else if (token_is_pseudo_keyword(s, JS_ATOM_async)) {
  28227         const uint8_t *source_ptr;
  28228         int tok;
  28229         JSParsePos pos;
  28230 
  28231         /* fast test */
  28232         tok = peek_token(s, TRUE);
  28233         if (tok == TOK_FUNCTION || tok == '\n')
  28234             goto next;
  28235 
  28236         source_ptr = s->token.ptr;
  28237         js_parse_get_pos(s, &pos);
  28238         if (next_token(s))
  28239             return -1;
  28240         if ((s->token.val == '(' &&
  28241              js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) ||
  28242             (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
  28243              peek_token(s, TRUE) == TOK_ARROW)) {
  28244             return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
  28245                                           JS_FUNC_ASYNC, JS_ATOM_NULL,
  28246                                           source_ptr);
  28247         } else {
  28248             /* undo the token parsing */
  28249             if (js_parse_seek_token(s, &pos))
  28250                 return -1;
  28251         }
  28252     } else if (s->token.val == TOK_IDENT &&
  28253                peek_token(s, TRUE) == TOK_ARROW) {
  28254         return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
  28255                                       JS_FUNC_NORMAL, JS_ATOM_NULL,
  28256                                       s->token.ptr);
  28257     } else if ((s->token.val == '{' || s->token.val == '[') &&
  28258                js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
  28259         if (js_parse_destructuring_element(s, 0, 0, FALSE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE, FALSE) < 0)
  28260             return -1;
  28261         return 0;
  28262     }
  28263  next:
  28264     if (s->token.val == TOK_IDENT) {
  28265         /* name0 is used to check for OP_set_name pattern, not duplicated */
  28266         name0 = s->token.u.ident.atom;
  28267     }
  28268     if (js_parse_cond_expr(s, parse_flags))
  28269         return -1;
  28270 
  28271     op = s->token.val;
  28272     if (op == '=' || (op >= TOK_MUL_ASSIGN && op <= TOK_POW_ASSIGN)) {
  28273         int label;
  28274         const uint8_t *op_token_ptr;
  28275         op_token_ptr = s->token.ptr;
  28276         if (next_token(s))
  28277             return -1;
  28278         if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, (op != '='), op) < 0)
  28279             return -1;
  28280 
  28281         if (js_parse_assign_expr2(s, parse_flags)) {
  28282             JS_FreeAtom(s->ctx, name);
  28283             return -1;
  28284         }
  28285 
  28286         if (op == '=') {
  28287             if ((opcode == OP_get_ref_value || opcode == OP_scope_get_var) && name == name0) {
  28288                 set_object_name(s, name);
  28289             }
  28290         } else {
  28291             static const uint8_t assign_opcodes[] = {
  28292                 OP_mul, OP_div, OP_mod, OP_add, OP_sub,
  28293                 OP_shl, OP_sar, OP_shr, OP_and, OP_xor, OP_or,
  28294                 OP_pow,
  28295             };
  28296             op = assign_opcodes[op - TOK_MUL_ASSIGN];
  28297             emit_source_pos(s, op_token_ptr);
  28298             emit_op(s, op);
  28299         }
  28300         put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP, FALSE);
  28301     } else if (op >= TOK_LAND_ASSIGN && op <= TOK_DOUBLE_QUESTION_MARK_ASSIGN) {
  28302         int label, label1, depth_lvalue, label2;
  28303 
  28304         if (next_token(s))
  28305             return -1;
  28306         if (get_lvalue(s, &opcode, &scope, &name, &label,
  28307                        &depth_lvalue, TRUE, op) < 0)
  28308             return -1;
  28309 
  28310         emit_op(s, OP_dup);
  28311         if (op == TOK_DOUBLE_QUESTION_MARK_ASSIGN)
  28312             emit_op(s, OP_is_undefined_or_null);
  28313         label1 = emit_goto(s, op == TOK_LOR_ASSIGN ? OP_if_true : OP_if_false,
  28314                            -1);
  28315         emit_op(s, OP_drop);
  28316 
  28317         if (js_parse_assign_expr2(s, parse_flags)) {
  28318             JS_FreeAtom(s->ctx, name);
  28319             return -1;
  28320         }
  28321 
  28322         if ((opcode == OP_get_ref_value || opcode == OP_scope_get_var) && name == name0) {
  28323             set_object_name(s, name);
  28324         }
  28325 
  28326         switch(depth_lvalue) {
  28327         case 0:
  28328             emit_op(s, OP_dup);
  28329             break;
  28330         case 1:
  28331             emit_op(s, OP_insert2);
  28332             break;
  28333         case 2:
  28334             emit_op(s, OP_insert3);
  28335             break;
  28336         case 3:
  28337             emit_op(s, OP_insert4);
  28338             break;
  28339         default:
  28340             abort();
  28341         }
  28342 
  28343         /* XXX: we disable the OP_put_ref_value optimization by not
  28344            using put_lvalue() otherwise depth_lvalue is not correct */
  28345         put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_NOKEEP_DEPTH,
  28346                    FALSE);
  28347         label2 = emit_goto(s, OP_goto, -1);
  28348 
  28349         emit_label(s, label1);
  28350 
  28351         /* remove the lvalue stack entries */
  28352         while (depth_lvalue != 0) {
  28353             emit_op(s, OP_nip);
  28354             depth_lvalue--;
  28355         }
  28356 
  28357         emit_label(s, label2);
  28358     }
  28359     return 0;
  28360 }
  28361 
  28362 static __exception int js_parse_assign_expr(JSParseState *s)
  28363 {
  28364     return js_parse_assign_expr2(s, PF_IN_ACCEPTED);
  28365 }
  28366 
  28367 /* allowed parse_flags: PF_IN_ACCEPTED */
  28368 static __exception int js_parse_expr2(JSParseState *s, int parse_flags)
  28369 {
  28370     BOOL comma = FALSE;
  28371     for(;;) {
  28372         if (js_parse_assign_expr2(s, parse_flags))
  28373             return -1;
  28374         if (comma) {
  28375             /* prevent get_lvalue from using the last expression
  28376                as an lvalue. This also prevents the conversion of
  28377                of get_var to get_ref for method lookup in function
  28378                call inside `with` statement.
  28379              */
  28380             s->cur_func->last_opcode_pos = -1;
  28381         }
  28382         if (s->token.val != ',')
  28383             break;
  28384         comma = TRUE;
  28385         if (next_token(s))
  28386             return -1;
  28387         emit_op(s, OP_drop);
  28388     }
  28389     return 0;
  28390 }
  28391 
  28392 static __exception int js_parse_expr(JSParseState *s)
  28393 {
  28394     return js_parse_expr2(s, PF_IN_ACCEPTED);
  28395 }
  28396 
  28397 static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
  28398                              JSAtom label_name,
  28399                              int label_break, int label_cont,
  28400                              int drop_count)
  28401 {
  28402     be->prev = fd->top_break;
  28403     fd->top_break = be;
  28404     be->label_name = label_name;
  28405     be->label_break = label_break;
  28406     be->label_cont = label_cont;
  28407     be->drop_count = drop_count;
  28408     be->label_finally = -1;
  28409     be->scope_level = fd->scope_level;
  28410     be->has_iterator = FALSE;
  28411     be->is_regular_stmt = FALSE;
  28412 }
  28413 
  28414 static void pop_break_entry(JSFunctionDef *fd)
  28415 {
  28416     BlockEnv *be;
  28417     be = fd->top_break;
  28418     fd->top_break = be->prev;
  28419 }
  28420 
  28421 static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont)
  28422 {
  28423     BlockEnv *top;
  28424     int i, scope_level;
  28425 
  28426     scope_level = s->cur_func->scope_level;
  28427     top = s->cur_func->top_break;
  28428     while (top != NULL) {
  28429         close_scopes(s, scope_level, top->scope_level);
  28430         scope_level = top->scope_level;
  28431         if (is_cont &&
  28432             top->label_cont != -1 &&
  28433             (name == JS_ATOM_NULL || top->label_name == name)) {
  28434             /* continue stays inside the same block */
  28435             emit_goto(s, OP_goto, top->label_cont);
  28436             return 0;
  28437         }
  28438         if (!is_cont &&
  28439             top->label_break != -1 &&
  28440             ((name == JS_ATOM_NULL && !top->is_regular_stmt) ||
  28441              top->label_name == name)) {
  28442             emit_goto(s, OP_goto, top->label_break);
  28443             return 0;
  28444         }
  28445         i = 0;
  28446         if (top->has_iterator) {
  28447             emit_op(s, OP_iterator_close);
  28448             i += 3;
  28449         }
  28450         for(; i < top->drop_count; i++)
  28451             emit_op(s, OP_drop);
  28452         if (top->label_finally != -1) {
  28453             /* must push dummy value to keep same stack depth */
  28454             emit_op(s, OP_undefined);
  28455             emit_goto(s, OP_gosub, top->label_finally);
  28456             emit_op(s, OP_drop);
  28457         }
  28458         top = top->prev;
  28459     }
  28460     if (name == JS_ATOM_NULL) {
  28461         if (is_cont)
  28462             return js_parse_error(s, "continue must be inside loop");
  28463         else
  28464             return js_parse_error(s, "break must be inside loop or switch");
  28465     } else {
  28466         return js_parse_error(s, "break/continue label not found");
  28467     }
  28468 }
  28469 
  28470 /* execute the finally blocks before return */
  28471 static void emit_return(JSParseState *s, BOOL hasval)
  28472 {
  28473     BlockEnv *top;
  28474 
  28475     if (s->cur_func->func_kind != JS_FUNC_NORMAL) {
  28476         if (!hasval) {
  28477             /* no value: direct return in case of async generator */
  28478             emit_op(s, OP_undefined);
  28479             hasval = TRUE;
  28480         } else if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
  28481             /* the await must be done before handling the "finally" in
  28482                case it raises an exception */
  28483             emit_op(s, OP_await);
  28484         }
  28485     }
  28486 
  28487     top = s->cur_func->top_break;
  28488     while (top != NULL) {
  28489         if (top->has_iterator || top->label_finally != -1) {
  28490             if (!hasval) {
  28491                 emit_op(s, OP_undefined);
  28492                 hasval = TRUE;
  28493             }
  28494             /* Remove the stack elements up to and including the catch
  28495                offset. When 'yield' is used in an expression we have
  28496                no easy way to count them, so we use this specific
  28497                instruction instead. */
  28498             emit_op(s, OP_nip_catch);
  28499             /* stack: iter_obj next ret_val */
  28500             if (top->has_iterator) {
  28501                 if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
  28502                     int label_next, label_next2;
  28503                     emit_op(s, OP_nip); /* next */
  28504                     emit_op(s, OP_swap);
  28505                     emit_op(s, OP_get_field2);
  28506                     emit_atom(s, JS_ATOM_return);
  28507                     /* stack: iter_obj return_func */
  28508                     emit_op(s, OP_dup);
  28509                     emit_op(s, OP_is_undefined_or_null);
  28510                     label_next = emit_goto(s, OP_if_true, -1);
  28511                     emit_op(s, OP_call_method);
  28512                     emit_u16(s, 0);
  28513                     emit_op(s, OP_iterator_check_object);
  28514                     emit_op(s, OP_await);
  28515                     label_next2 = emit_goto(s, OP_goto, -1);
  28516                     emit_label(s, label_next);
  28517                     emit_op(s, OP_drop);
  28518                     emit_label(s, label_next2);
  28519                     emit_op(s, OP_drop);
  28520                 } else {
  28521                     emit_op(s, OP_rot3r);
  28522                     emit_op(s, OP_undefined); /* dummy catch offset */
  28523                     emit_op(s, OP_iterator_close);
  28524                 }
  28525             } else {
  28526                 /* execute the "finally" block */
  28527                 emit_goto(s, OP_gosub, top->label_finally);
  28528             }
  28529         }
  28530         top = top->prev;
  28531     }
  28532     if (s->cur_func->is_derived_class_constructor) {
  28533         int label_return;
  28534 
  28535         /* 'this' can be uninitialized, so it may be accessed only if
  28536            the derived class constructor does not return an object */
  28537         if (hasval) {
  28538             emit_op(s, OP_check_ctor_return);
  28539             label_return = emit_goto(s, OP_if_false, -1);
  28540             emit_op(s, OP_drop);
  28541         } else {
  28542             label_return = -1;
  28543         }
  28544 
  28545         /* The error should be raised in the caller context, so we use
  28546            a specific opcode */
  28547         emit_op(s, OP_scope_get_var_checkthis);
  28548         emit_atom(s, JS_ATOM_this);
  28549         emit_u16(s, 0);
  28550 
  28551         emit_label(s, label_return);
  28552         emit_op(s, OP_return);
  28553     } else if (s->cur_func->func_kind != JS_FUNC_NORMAL) {
  28554         emit_op(s, OP_return_async);
  28555     } else {
  28556         emit_op(s, hasval ? OP_return : OP_return_undef);
  28557     }
  28558 }
  28559 
  28560 #define DECL_MASK_FUNC  (1 << 0) /* allow normal function declaration */
  28561 /* ored with DECL_MASK_FUNC if function declarations are allowed with a label */
  28562 #define DECL_MASK_FUNC_WITH_LABEL (1 << 1)
  28563 #define DECL_MASK_OTHER (1 << 2) /* all other declarations */
  28564 #define DECL_MASK_ALL   (DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL | DECL_MASK_OTHER)
  28565 
  28566 static __exception int js_parse_statement_or_decl(JSParseState *s,
  28567                                                   int decl_mask);
  28568 
  28569 static __exception int js_parse_statement(JSParseState *s)
  28570 {
  28571     return js_parse_statement_or_decl(s, 0);
  28572 }
  28573 
  28574 static __exception int js_parse_block(JSParseState *s)
  28575 {
  28576     if (js_parse_expect(s, '{'))
  28577         return -1;
  28578     if (s->token.val != '}') {
  28579         push_scope(s);
  28580         for(;;) {
  28581             if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
  28582                 return -1;
  28583             if (s->token.val == '}')
  28584                 break;
  28585         }
  28586         pop_scope(s);
  28587     }
  28588     if (next_token(s))
  28589         return -1;
  28590     return 0;
  28591 }
  28592 
  28593 /* allowed parse_flags: PF_IN_ACCEPTED */
  28594 static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
  28595                                     BOOL export_flag)
  28596 {
  28597     JSContext *ctx = s->ctx;
  28598     JSFunctionDef *fd = s->cur_func;
  28599     JSAtom name = JS_ATOM_NULL;
  28600 
  28601     for (;;) {
  28602         if (s->token.val == TOK_IDENT) {
  28603             if (s->token.u.ident.is_reserved) {
  28604                 return js_parse_error_reserved_identifier(s);
  28605             }
  28606             name = JS_DupAtom(ctx, s->token.u.ident.atom);
  28607             if (name == JS_ATOM_let && (tok == TOK_LET || tok == TOK_CONST)) {
  28608                 js_parse_error(s, "'let' is not a valid lexical identifier");
  28609                 goto var_error;
  28610             }
  28611             if (next_token(s))
  28612                 goto var_error;
  28613             if (js_define_var(s, name, tok))
  28614                 goto var_error;
  28615             if (export_flag) {
  28616                 if (!add_export_entry(s, s->cur_func->module, name, name,
  28617                                       JS_EXPORT_TYPE_LOCAL))
  28618                     goto var_error;
  28619             }
  28620 
  28621             if (s->token.val == '=') {
  28622                 const uint8_t *source_ptr = s->token.ptr;
  28623                 if (next_token(s))
  28624                     goto var_error;
  28625                 if (need_var_reference(s, tok)) {
  28626                     /* Must make a reference for proper `with` semantics */
  28627                     int opcode, scope, label;
  28628                     JSAtom name1;
  28629 
  28630                     emit_op(s, OP_scope_get_var);
  28631                     emit_atom(s, name);
  28632                     emit_u16(s, fd->scope_level);
  28633                     if (get_lvalue(s, &opcode, &scope, &name1, &label, NULL, FALSE, '=') < 0)
  28634                         goto var_error;
  28635                     if (js_parse_assign_expr2(s, parse_flags)) {
  28636                         JS_FreeAtom(ctx, name1);
  28637                         goto var_error;
  28638                     }
  28639                     set_object_name(s, name);
  28640                     emit_source_pos(s, source_ptr);
  28641                     put_lvalue(s, opcode, scope, name1, label,
  28642                                PUT_LVALUE_NOKEEP, FALSE);
  28643                 } else {
  28644                     if (js_parse_assign_expr2(s, parse_flags))
  28645                         goto var_error;
  28646                     set_object_name(s, name);
  28647                     emit_source_pos(s, source_ptr);
  28648                     emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ?
  28649                         OP_scope_put_var_init : OP_scope_put_var);
  28650                     emit_atom(s, name);
  28651                     emit_u16(s, fd->scope_level);
  28652                 }
  28653             } else {
  28654                 if (tok == TOK_CONST) {
  28655                     js_parse_error(s, "missing initializer for const variable");
  28656                     goto var_error;
  28657                 }
  28658                 if (tok == TOK_LET) {
  28659                     /* initialize lexical variable upon entering its scope */
  28660                     emit_op(s, OP_undefined);
  28661                     emit_op(s, OP_scope_put_var_init);
  28662                     emit_atom(s, name);
  28663                     emit_u16(s, fd->scope_level);
  28664                 }
  28665             }
  28666             JS_FreeAtom(ctx, name);
  28667         } else {
  28668             int skip_bits;
  28669             if ((s->token.val == '[' || s->token.val == '{')
  28670             &&  js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
  28671                 emit_op(s, OP_undefined);
  28672                 if (js_parse_destructuring_element(s, tok, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE, export_flag) < 0)
  28673                     return -1;
  28674             } else {
  28675                 return js_parse_error(s, "variable name expected");
  28676             }
  28677         }
  28678         if (s->token.val != ',')
  28679             break;
  28680         if (next_token(s))
  28681             return -1;
  28682     }
  28683     return 0;
  28684 
  28685  var_error:
  28686     JS_FreeAtom(ctx, name);
  28687     return -1;
  28688 }
  28689 
  28690 /* test if the current token is a label. Use simplistic look-ahead scanner */
  28691 static BOOL is_label(JSParseState *s)
  28692 {
  28693     return (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
  28694             peek_token(s, FALSE) == ':');
  28695 }
  28696 
  28697 /* test if the current token is a let keyword. Use simplistic look-ahead scanner */
  28698 static int is_let(JSParseState *s, int decl_mask)
  28699 {
  28700     int res = FALSE;
  28701     const uint8_t *last_token_ptr;
  28702     
  28703     if (token_is_pseudo_keyword(s, JS_ATOM_let)) {
  28704         JSParsePos pos;
  28705         js_parse_get_pos(s, &pos);
  28706         for (;;) {
  28707             last_token_ptr = s->token.ptr;
  28708             if (next_token(s)) {
  28709                 res = -1;
  28710                 break;
  28711             }
  28712             if (s->token.val == '[') {
  28713                 /* let [ is a syntax restriction:
  28714                    it never introduces an ExpressionStatement */
  28715                 res = TRUE;
  28716                 break;
  28717             }
  28718             if (s->token.val == '{' ||
  28719                 (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved) ||
  28720                 s->token.val == TOK_LET ||
  28721                 s->token.val == TOK_YIELD ||
  28722                 s->token.val == TOK_AWAIT) {
  28723                 /* Check for possible ASI if not scanning for Declaration */
  28724                 /* XXX: should also check that `{` introduces a BindingPattern,
  28725                    but Firefox does not and rejects eval("let=1;let\n{if(1)2;}") */
  28726                 if (!has_lf_in_range(last_token_ptr, s->token.ptr) ||
  28727                     (decl_mask & DECL_MASK_OTHER)) {
  28728                     res = TRUE;
  28729                     break;
  28730                 }
  28731                 break;
  28732             }
  28733             break;
  28734         }
  28735         if (js_parse_seek_token(s, &pos)) {
  28736             res = -1;
  28737         }
  28738     }
  28739     return res;
  28740 }
  28741 
  28742 /* XXX: handle IteratorClose when exiting the loop before the
  28743    enumeration is done */
  28744 static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
  28745                                           BOOL is_async)
  28746 {
  28747     JSContext *ctx = s->ctx;
  28748     JSFunctionDef *fd = s->cur_func;
  28749     JSAtom var_name;
  28750     BOOL has_initializer, is_for_of, has_destructuring;
  28751     int tok, tok1, opcode, scope, block_scope_level;
  28752     int label_next, label_expr, label_cont, label_body, label_break;
  28753     int pos_next, pos_expr;
  28754     BlockEnv break_entry;
  28755 
  28756     has_initializer = FALSE;
  28757     has_destructuring = FALSE;
  28758     is_for_of = FALSE;
  28759     block_scope_level = fd->scope_level;
  28760     label_cont = new_label(s);
  28761     label_body = new_label(s);
  28762     label_break = new_label(s);
  28763     label_next = new_label(s);
  28764 
  28765     /* create scope for the lexical variables declared in the enumeration
  28766        expressions. XXX: Not completely correct because of weird capturing
  28767        semantics in `for (i of o) a.push(function(){return i})` */
  28768     push_scope(s);
  28769 
  28770     /* local for_in scope starts here so individual elements
  28771        can be closed in statement. */
  28772     push_break_entry(s->cur_func, &break_entry,
  28773                      label_name, label_break, label_cont, 1);
  28774     break_entry.scope_level = block_scope_level;
  28775 
  28776     label_expr = emit_goto(s, OP_goto, -1);
  28777 
  28778     pos_next = s->cur_func->byte_code.size;
  28779     emit_label(s, label_next);
  28780 
  28781     tok = s->token.val;
  28782     switch (is_let(s, DECL_MASK_OTHER)) {
  28783     case TRUE:
  28784         tok = TOK_LET;
  28785         break;
  28786     case FALSE:
  28787         break;
  28788     default:
  28789         return -1;
  28790     }
  28791     if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) {
  28792         if (next_token(s))
  28793             return -1;
  28794 
  28795         if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
  28796             if (s->token.val == '[' || s->token.val == '{') {
  28797                 if (js_parse_destructuring_element(s, tok, 0, TRUE, -1, FALSE, FALSE) < 0)
  28798                     return -1;
  28799                 has_destructuring = TRUE;
  28800             } else {
  28801                 return js_parse_error(s, "variable name expected");
  28802             }
  28803             var_name = JS_ATOM_NULL;
  28804         } else {
  28805             var_name = JS_DupAtom(ctx, s->token.u.ident.atom);
  28806             if (next_token(s)) {
  28807                 JS_FreeAtom(s->ctx, var_name);
  28808                 return -1;
  28809             }
  28810             if (js_define_var(s, var_name, tok)) {
  28811                 JS_FreeAtom(s->ctx, var_name);
  28812                 return -1;
  28813             }
  28814             emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ?
  28815                     OP_scope_put_var_init : OP_scope_put_var);
  28816             emit_atom(s, var_name);
  28817             emit_u16(s, fd->scope_level);
  28818         }
  28819     } else if (!is_async && token_is_pseudo_keyword(s, JS_ATOM_async) &&
  28820                peek_token(s, FALSE) == TOK_OF) {
  28821         return js_parse_error(s, "'for of' expression cannot start with 'async'");
  28822     } else {
  28823         int skip_bits;
  28824         if ((s->token.val == '[' || s->token.val == '{')
  28825         &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == TOK_IN || tok1 == TOK_OF)) {
  28826             if (js_parse_destructuring_element(s, 0, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE, FALSE) < 0)
  28827                 return -1;
  28828         } else {
  28829             int lvalue_label;
  28830             if (js_parse_left_hand_side_expr(s))
  28831                 return -1;
  28832             if (get_lvalue(s, &opcode, &scope, &var_name, &lvalue_label,
  28833                            NULL, FALSE, TOK_FOR))
  28834                 return -1;
  28835             put_lvalue(s, opcode, scope, var_name, lvalue_label,
  28836                        PUT_LVALUE_NOKEEP_BOTTOM, FALSE);
  28837         }
  28838         var_name = JS_ATOM_NULL;
  28839     }
  28840     emit_goto(s, OP_goto, label_body);
  28841 
  28842     pos_expr = s->cur_func->byte_code.size;
  28843     emit_label(s, label_expr);
  28844     if (s->token.val == '=') {
  28845         /* XXX: potential scoping issue if inside `with` statement */
  28846         has_initializer = TRUE;
  28847         /* parse and evaluate initializer prior to evaluating the
  28848            object (only used with "for in" with a non lexical variable
  28849            in non strict mode */
  28850         if (next_token(s) || js_parse_assign_expr2(s, 0)) {
  28851             JS_FreeAtom(ctx, var_name);
  28852             return -1;
  28853         }
  28854         if (var_name != JS_ATOM_NULL) {
  28855             emit_op(s, OP_scope_put_var);
  28856             emit_atom(s, var_name);
  28857             emit_u16(s, fd->scope_level);
  28858         }
  28859     }
  28860     JS_FreeAtom(ctx, var_name);
  28861 
  28862     if (token_is_pseudo_keyword(s, JS_ATOM_of)) {
  28863         is_for_of = TRUE;
  28864         if (has_initializer)
  28865             goto initializer_error;
  28866     } else if (s->token.val == TOK_IN) {
  28867         if (is_async)
  28868             return js_parse_error(s, "'for await' loop should be used with 'of'");
  28869         if (has_initializer &&
  28870             (tok != TOK_VAR || (fd->js_mode & JS_MODE_STRICT) ||
  28871              has_destructuring)) {
  28872         initializer_error:
  28873             return js_parse_error(s, "a declaration in the head of a for-%s loop can't have an initializer",
  28874                                   is_for_of ? "of" : "in");
  28875         }
  28876     } else {
  28877         return js_parse_error(s, "expected 'of' or 'in' in for control expression");
  28878     }
  28879     if (next_token(s))
  28880         return -1;
  28881     if (is_for_of) {
  28882         if (js_parse_assign_expr(s))
  28883             return -1;
  28884     } else {
  28885         if (js_parse_expr(s))
  28886             return -1;
  28887     }
  28888     /* close the scope after having evaluated the expression so that
  28889        the TDZ values are in the closures */
  28890     close_scopes(s, s->cur_func->scope_level, block_scope_level);
  28891     if (is_for_of) {
  28892         /* set has_iterator after the iterable expression is parsed so
  28893            that a yield in the expression does not try to close a
  28894            not-yet-created iterator */
  28895         break_entry.has_iterator = TRUE;
  28896         break_entry.drop_count += 2;
  28897         if (is_async)
  28898             emit_op(s, OP_for_await_of_start);
  28899         else
  28900             emit_op(s, OP_for_of_start);
  28901         /* on stack: enum_rec */
  28902     } else {
  28903         emit_op(s, OP_for_in_start);
  28904         /* on stack: enum_obj */
  28905     }
  28906     emit_goto(s, OP_goto, label_cont);
  28907 
  28908     if (js_parse_expect(s, ')'))
  28909         return -1;
  28910 
  28911     if (OPTIMIZE) {
  28912         /* move the `next` code here */
  28913         DynBuf *bc = &s->cur_func->byte_code;
  28914         int chunk_size = pos_expr - pos_next;
  28915         int offset = bc->size - pos_next;
  28916         int i;
  28917         if (dbuf_claim(bc, chunk_size))
  28918             return -1;
  28919         dbuf_put(bc, bc->buf + pos_next, chunk_size);
  28920         memset(bc->buf + pos_next, OP_nop, chunk_size);
  28921         /* `next` part ends with a goto */
  28922         s->cur_func->last_opcode_pos = bc->size - 5;
  28923         /* relocate labels */
  28924         for (i = label_cont; i < s->cur_func->label_count; i++) {
  28925             LabelSlot *ls = &s->cur_func->label_slots[i];
  28926             if (ls->pos >= pos_next && ls->pos < pos_expr)
  28927                 ls->pos += offset;
  28928         }
  28929     }
  28930 
  28931     emit_label(s, label_body);
  28932     if (js_parse_statement(s))
  28933         return -1;
  28934 
  28935     close_scopes(s, s->cur_func->scope_level, block_scope_level);
  28936 
  28937     emit_label(s, label_cont);
  28938     if (is_for_of) {
  28939         if (is_async) {
  28940             /* stack: iter_obj next catch_offset */
  28941             /* call the next method */
  28942             emit_op(s, OP_for_await_of_next); 
  28943             /* get the result of the promise */
  28944             emit_op(s, OP_await);
  28945             /* unwrap the value and done values */
  28946             emit_op(s, OP_iterator_get_value_done);
  28947         } else {
  28948             emit_op(s, OP_for_of_next);
  28949             emit_u8(s, 0);
  28950         }
  28951     } else {
  28952         emit_op(s, OP_for_in_next);
  28953     }
  28954     /* on stack: enum_rec / enum_obj value bool */
  28955     emit_goto(s, OP_if_false, label_next);
  28956     /* drop the undefined value from for_xx_next */
  28957     emit_op(s, OP_drop);
  28958 
  28959     emit_label(s, label_break);
  28960     if (is_for_of) {
  28961         /* close and drop enum_rec */
  28962         emit_op(s, OP_iterator_close);
  28963     } else {
  28964         emit_op(s, OP_drop);
  28965     }
  28966     pop_break_entry(s->cur_func);
  28967     pop_scope(s);
  28968     return 0;
  28969 }
  28970 
  28971 static void set_eval_ret_undefined(JSParseState *s)
  28972 {
  28973     if (s->cur_func->eval_ret_idx >= 0) {
  28974         emit_op(s, OP_undefined);
  28975         emit_op(s, OP_put_loc);
  28976         emit_u16(s, s->cur_func->eval_ret_idx);
  28977     }
  28978 }
  28979 
  28980 static __exception int js_parse_statement_or_decl(JSParseState *s,
  28981                                                   int decl_mask)
  28982 {
  28983     JSContext *ctx = s->ctx;
  28984     JSAtom label_name;
  28985     int tok;
  28986 
  28987     /* specific label handling */
  28988     /* XXX: support multiple labels on loop statements */
  28989     label_name = JS_ATOM_NULL;
  28990     if (is_label(s)) {
  28991         BlockEnv *be;
  28992 
  28993         label_name = JS_DupAtom(ctx, s->token.u.ident.atom);
  28994 
  28995         for (be = s->cur_func->top_break; be; be = be->prev) {
  28996             if (be->label_name == label_name) {
  28997                 js_parse_error(s, "duplicate label name");
  28998                 goto fail;
  28999             }
  29000         }
  29001 
  29002         if (next_token(s))
  29003             goto fail;
  29004         if (js_parse_expect(s, ':'))
  29005             goto fail;
  29006         if (s->token.val != TOK_FOR
  29007         &&  s->token.val != TOK_DO
  29008         &&  s->token.val != TOK_WHILE) {
  29009             /* labelled regular statement */
  29010             int label_break, mask;
  29011             BlockEnv break_entry;
  29012 
  29013             label_break = new_label(s);
  29014             push_break_entry(s->cur_func, &break_entry,
  29015                              label_name, label_break, -1, 0);
  29016             break_entry.is_regular_stmt = TRUE;
  29017             if (!(s->cur_func->js_mode & JS_MODE_STRICT) &&
  29018                 (decl_mask & DECL_MASK_FUNC_WITH_LABEL)) {
  29019                 mask = DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL;
  29020             } else {
  29021                 mask = 0;
  29022             }
  29023             if (js_parse_statement_or_decl(s, mask))
  29024                 goto fail;
  29025             emit_label(s, label_break);
  29026             pop_break_entry(s->cur_func);
  29027             goto done;
  29028         }
  29029     }
  29030 
  29031     switch(tok = s->token.val) {
  29032     case '{':
  29033         if (js_parse_block(s))
  29034             goto fail;
  29035         break;
  29036     case TOK_RETURN:
  29037         {
  29038             const uint8_t *op_token_ptr;
  29039             if (s->cur_func->is_eval) {
  29040                 js_parse_error(s, "return not in a function");
  29041                 goto fail;
  29042             }
  29043             if (s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) {
  29044                 js_parse_error(s, "return in a static initializer block");
  29045                 goto fail;
  29046             }
  29047             op_token_ptr = s->token.ptr;
  29048             if (next_token(s))
  29049                 goto fail;
  29050             if (s->token.val != ';' && s->token.val != '}' && !s->got_lf) {
  29051                 if (js_parse_expr(s))
  29052                     goto fail;
  29053                 emit_source_pos(s, op_token_ptr);
  29054                 emit_return(s, TRUE);
  29055             } else {
  29056                 emit_source_pos(s, op_token_ptr);
  29057                 emit_return(s, FALSE);
  29058             }
  29059             if (js_parse_expect_semi(s))
  29060                 goto fail;
  29061         }
  29062         break;
  29063     case TOK_THROW:
  29064         {
  29065             const uint8_t *op_token_ptr;
  29066             op_token_ptr = s->token.ptr;
  29067             if (next_token(s))
  29068                 goto fail;
  29069             if (s->got_lf) {
  29070                 js_parse_error(s, "line terminator not allowed after throw");
  29071                 goto fail;
  29072             }
  29073             if (js_parse_expr(s))
  29074                 goto fail;
  29075             emit_source_pos(s, op_token_ptr);
  29076             emit_op(s, OP_throw);
  29077             if (js_parse_expect_semi(s))
  29078                 goto fail;
  29079         }
  29080         break;
  29081     case TOK_LET:
  29082     case TOK_CONST:
  29083     haslet:
  29084         if (!(decl_mask & DECL_MASK_OTHER)) {
  29085             js_parse_error(s, "lexical declarations can't appear in single-statement context");
  29086             goto fail;
  29087         }
  29088         /* fall thru */
  29089     case TOK_VAR:
  29090         if (next_token(s))
  29091             goto fail;
  29092         if (js_parse_var(s, TRUE, tok, FALSE))
  29093             goto fail;
  29094         if (js_parse_expect_semi(s))
  29095             goto fail;
  29096         break;
  29097     case TOK_IF:
  29098         {
  29099             int label1, label2, mask;
  29100             if (next_token(s))
  29101                 goto fail;
  29102             /* create a new scope for `let f;if(1) function f(){}` */
  29103             push_scope(s);
  29104             set_eval_ret_undefined(s);
  29105             if (js_parse_expr_paren(s))
  29106                 goto fail;
  29107             label1 = emit_goto(s, OP_if_false, -1);
  29108             if (s->cur_func->js_mode & JS_MODE_STRICT)
  29109                 mask = 0;
  29110             else
  29111                 mask = DECL_MASK_FUNC; /* Annex B.3.4 */
  29112 
  29113             if (js_parse_statement_or_decl(s, mask))
  29114                 goto fail;
  29115 
  29116             if (s->token.val == TOK_ELSE) {
  29117                 label2 = emit_goto(s, OP_goto, -1);
  29118                 if (next_token(s))
  29119                     goto fail;
  29120 
  29121                 emit_label(s, label1);
  29122                 if (js_parse_statement_or_decl(s, mask))
  29123                     goto fail;
  29124 
  29125                 label1 = label2;
  29126             }
  29127             emit_label(s, label1);
  29128             pop_scope(s);
  29129         }
  29130         break;
  29131     case TOK_WHILE:
  29132         {
  29133             int label_cont, label_break;
  29134             BlockEnv break_entry;
  29135 
  29136             label_cont = new_label(s);
  29137             label_break = new_label(s);
  29138 
  29139             push_break_entry(s->cur_func, &break_entry,
  29140                              label_name, label_break, label_cont, 0);
  29141 
  29142             if (next_token(s))
  29143                 goto fail;
  29144 
  29145             set_eval_ret_undefined(s);
  29146 
  29147             emit_label(s, label_cont);
  29148             if (js_parse_expr_paren(s))
  29149                 goto fail;
  29150             emit_goto(s, OP_if_false, label_break);
  29151 
  29152             if (js_parse_statement(s))
  29153                 goto fail;
  29154             emit_goto(s, OP_goto, label_cont);
  29155 
  29156             emit_label(s, label_break);
  29157 
  29158             pop_break_entry(s->cur_func);
  29159         }
  29160         break;
  29161     case TOK_DO:
  29162         {
  29163             int label_cont, label_break, label1;
  29164             BlockEnv break_entry;
  29165 
  29166             label_cont = new_label(s);
  29167             label_break = new_label(s);
  29168             label1 = new_label(s);
  29169 
  29170             push_break_entry(s->cur_func, &break_entry,
  29171                              label_name, label_break, label_cont, 0);
  29172 
  29173             if (next_token(s))
  29174                 goto fail;
  29175 
  29176             emit_label(s, label1);
  29177 
  29178             set_eval_ret_undefined(s);
  29179 
  29180             if (js_parse_statement(s))
  29181                 goto fail;
  29182 
  29183             emit_label(s, label_cont);
  29184             if (js_parse_expect(s, TOK_WHILE))
  29185                 goto fail;
  29186             if (js_parse_expr_paren(s))
  29187                 goto fail;
  29188             /* Insert semicolon if missing */
  29189             if (s->token.val == ';') {
  29190                 if (next_token(s))
  29191                     goto fail;
  29192             }
  29193             emit_goto(s, OP_if_true, label1);
  29194 
  29195             emit_label(s, label_break);
  29196 
  29197             pop_break_entry(s->cur_func);
  29198         }
  29199         break;
  29200     case TOK_FOR:
  29201         {
  29202             int label_cont, label_break, label_body, label_test;
  29203             int pos_cont, pos_body, block_scope_level;
  29204             BlockEnv break_entry;
  29205             int tok, bits;
  29206             BOOL is_async;
  29207 
  29208             if (next_token(s))
  29209                 goto fail;
  29210 
  29211             set_eval_ret_undefined(s);
  29212             bits = 0;
  29213             is_async = FALSE;
  29214             if (s->token.val == '(') {
  29215                 js_parse_skip_parens_token(s, &bits, FALSE);
  29216             } else if (s->token.val == TOK_AWAIT) {
  29217                 if (!(s->cur_func->func_kind & JS_FUNC_ASYNC)) {
  29218                     js_parse_error(s, "for await is only valid in asynchronous functions");
  29219                     goto fail;
  29220                 }
  29221                 is_async = TRUE;
  29222                 if (next_token(s))
  29223                     goto fail;
  29224                 s->cur_func->has_await = TRUE;
  29225             }
  29226             if (js_parse_expect(s, '('))
  29227                 goto fail;
  29228 
  29229             if (!(bits & SKIP_HAS_SEMI)) {
  29230                 /* parse for/in or for/of */
  29231                 if (js_parse_for_in_of(s, label_name, is_async))
  29232                     goto fail;
  29233                 break;
  29234             }
  29235             block_scope_level = s->cur_func->scope_level;
  29236 
  29237             /* create scope for the lexical variables declared in the initial,
  29238                test and increment expressions */
  29239             push_scope(s);
  29240             /* initial expression */
  29241             tok = s->token.val;
  29242             if (tok != ';') {
  29243                 switch (is_let(s, DECL_MASK_OTHER)) {
  29244                 case TRUE:
  29245                     tok = TOK_LET;
  29246                     break;
  29247                 case FALSE:
  29248                     break;
  29249                 default:
  29250                     goto fail;
  29251                 }
  29252                 if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) {
  29253                     if (next_token(s))
  29254                         goto fail;
  29255                     if (js_parse_var(s, FALSE, tok, FALSE))
  29256                         goto fail;
  29257                 } else {
  29258                     if (js_parse_expr2(s, FALSE))
  29259                         goto fail;
  29260                     emit_op(s, OP_drop);
  29261                 }
  29262 
  29263                 /* close the closures before the first iteration */
  29264                 close_scopes(s, s->cur_func->scope_level, block_scope_level);
  29265             }
  29266             if (js_parse_expect(s, ';'))
  29267                 goto fail;
  29268 
  29269             label_test = new_label(s);
  29270             label_cont = new_label(s);
  29271             label_body = new_label(s);
  29272             label_break = new_label(s);
  29273 
  29274             push_break_entry(s->cur_func, &break_entry,
  29275                              label_name, label_break, label_cont, 0);
  29276 
  29277             /* test expression */
  29278             if (s->token.val == ';') {
  29279                 /* no test expression */
  29280                 label_test = label_body;
  29281             } else {
  29282                 emit_label(s, label_test);
  29283                 if (js_parse_expr(s))
  29284                     goto fail;
  29285                 emit_goto(s, OP_if_false, label_break);
  29286             }
  29287             if (js_parse_expect(s, ';'))
  29288                 goto fail;
  29289 
  29290             if (s->token.val == ')') {
  29291                 /* no end expression */
  29292                 break_entry.label_cont = label_cont = label_test;
  29293                 pos_cont = 0; /* avoid warning */
  29294             } else {
  29295                 /* skip the end expression */
  29296                 emit_goto(s, OP_goto, label_body);
  29297 
  29298                 pos_cont = s->cur_func->byte_code.size;
  29299                 emit_label(s, label_cont);
  29300                 if (js_parse_expr(s))
  29301                     goto fail;
  29302                 emit_op(s, OP_drop);
  29303                 if (label_test != label_body)
  29304                     emit_goto(s, OP_goto, label_test);
  29305             }
  29306             if (js_parse_expect(s, ')'))
  29307                 goto fail;
  29308 
  29309             pos_body = s->cur_func->byte_code.size;
  29310             emit_label(s, label_body);
  29311             if (js_parse_statement(s))
  29312                 goto fail;
  29313 
  29314             /* close the closures before the next iteration */
  29315             /* XXX: check continue case */
  29316             close_scopes(s, s->cur_func->scope_level, block_scope_level);
  29317 
  29318             if (OPTIMIZE && label_test != label_body && label_cont != label_test) {
  29319                 /* move the increment code here */
  29320                 DynBuf *bc = &s->cur_func->byte_code;
  29321                 int chunk_size = pos_body - pos_cont;
  29322                 int offset = bc->size - pos_cont;
  29323                 int i;
  29324                 if (dbuf_claim(bc, chunk_size))
  29325                     goto fail;
  29326                 dbuf_put(bc, bc->buf + pos_cont, chunk_size);
  29327                 memset(bc->buf + pos_cont, OP_nop, chunk_size);
  29328                 /* increment part ends with a goto */
  29329                 s->cur_func->last_opcode_pos = bc->size - 5;
  29330                 /* relocate labels */
  29331                 for (i = label_cont; i < s->cur_func->label_count; i++) {
  29332                     LabelSlot *ls = &s->cur_func->label_slots[i];
  29333                     if (ls->pos >= pos_cont && ls->pos < pos_body)
  29334                         ls->pos += offset;
  29335                 }
  29336             } else {
  29337                 emit_goto(s, OP_goto, label_cont);
  29338             }
  29339 
  29340             emit_label(s, label_break);
  29341 
  29342             pop_break_entry(s->cur_func);
  29343             pop_scope(s);
  29344         }
  29345         break;
  29346     case TOK_BREAK:
  29347     case TOK_CONTINUE:
  29348         {
  29349             int is_cont = s->token.val - TOK_BREAK;
  29350             int label;
  29351 
  29352             if (next_token(s))
  29353                 goto fail;
  29354             if (!s->got_lf && s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)
  29355                 label = s->token.u.ident.atom;
  29356             else
  29357                 label = JS_ATOM_NULL;
  29358             if (emit_break(s, label, is_cont))
  29359                 goto fail;
  29360             if (label != JS_ATOM_NULL) {
  29361                 if (next_token(s))
  29362                     goto fail;
  29363             }
  29364             if (js_parse_expect_semi(s))
  29365                 goto fail;
  29366         }
  29367         break;
  29368     case TOK_SWITCH:
  29369         {
  29370             int label_case, label_break, label1;
  29371             int default_label_pos;
  29372             BlockEnv break_entry;
  29373 
  29374             if (next_token(s))
  29375                 goto fail;
  29376 
  29377             set_eval_ret_undefined(s);
  29378             if (js_parse_expr_paren(s))
  29379                 goto fail;
  29380 
  29381             push_scope(s);
  29382             label_break = new_label(s);
  29383             push_break_entry(s->cur_func, &break_entry,
  29384                              label_name, label_break, -1, 1);
  29385 
  29386             if (js_parse_expect(s, '{'))
  29387                 goto fail;
  29388 
  29389             default_label_pos = -1;
  29390             label_case = -1;
  29391             while (s->token.val != '}') {
  29392                 if (s->token.val == TOK_CASE) {
  29393                     label1 = -1;
  29394                     if (label_case >= 0) {
  29395                         /* skip the case if needed */
  29396                         label1 = emit_goto(s, OP_goto, -1);
  29397                     }
  29398                     emit_label(s, label_case);
  29399                     label_case = -1;
  29400                     for (;;) {
  29401                         /* parse a sequence of case clauses */
  29402                         if (next_token(s))
  29403                             goto fail;
  29404                         emit_op(s, OP_dup);
  29405                         if (js_parse_expr(s))
  29406                             goto fail;
  29407                         if (js_parse_expect(s, ':'))
  29408                             goto fail;
  29409                         emit_op(s, OP_strict_eq);
  29410                         if (s->token.val == TOK_CASE) {
  29411                             label1 = emit_goto(s, OP_if_true, label1);
  29412                         } else {
  29413                             label_case = emit_goto(s, OP_if_false, -1);
  29414                             emit_label(s, label1);
  29415                             break;
  29416                         }
  29417                     }
  29418                 } else if (s->token.val == TOK_DEFAULT) {
  29419                     if (next_token(s))
  29420                         goto fail;
  29421                     if (js_parse_expect(s, ':'))
  29422                         goto fail;
  29423                     if (default_label_pos >= 0) {
  29424                         js_parse_error(s, "duplicate default");
  29425                         goto fail;
  29426                     }
  29427                     if (label_case < 0) {
  29428                         /* falling thru direct from switch expression */
  29429                         label_case = emit_goto(s, OP_goto, -1);
  29430                     }
  29431                     /* Emit a dummy label opcode. Label will be patched after
  29432                        the end of the switch body. Do not use emit_label(s, 0)
  29433                        because it would clobber label 0 address, preventing
  29434                        proper optimizer operation.
  29435                      */
  29436                     emit_op(s, OP_label);
  29437                     emit_u32(s, 0);
  29438                     default_label_pos = s->cur_func->byte_code.size - 4;
  29439                 } else {
  29440                     if (label_case < 0) {
  29441                         /* falling thru direct from switch expression */
  29442                         js_parse_error(s, "invalid switch statement");
  29443                         goto fail;
  29444                     }
  29445                     if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
  29446                         goto fail;
  29447                 }
  29448             }
  29449             if (js_parse_expect(s, '}'))
  29450                 goto fail;
  29451             if (default_label_pos >= 0) {
  29452                 /* Ugly patch for the `default` label, shameful and risky */
  29453                 put_u32(s->cur_func->byte_code.buf + default_label_pos,
  29454                         label_case);
  29455                 s->cur_func->label_slots[label_case].pos = default_label_pos + 4;
  29456             } else {
  29457                 emit_label(s, label_case);
  29458             }
  29459             emit_label(s, label_break);
  29460             emit_op(s, OP_drop); /* drop the switch expression */
  29461 
  29462             pop_break_entry(s->cur_func);
  29463             pop_scope(s);
  29464         }
  29465         break;
  29466     case TOK_TRY:
  29467         {
  29468             int label_catch, label_catch2, label_finally, label_end;
  29469             JSAtom name;
  29470             BlockEnv block_env;
  29471 
  29472             set_eval_ret_undefined(s);
  29473             if (next_token(s))
  29474                 goto fail;
  29475             label_catch = new_label(s);
  29476             label_catch2 = new_label(s);
  29477             label_finally = new_label(s);
  29478             label_end = new_label(s);
  29479 
  29480             emit_goto(s, OP_catch, label_catch);
  29481 
  29482             push_break_entry(s->cur_func, &block_env,
  29483                              JS_ATOM_NULL, -1, -1, 1);
  29484             block_env.label_finally = label_finally;
  29485 
  29486             if (js_parse_block(s))
  29487                 goto fail;
  29488 
  29489             pop_break_entry(s->cur_func);
  29490 
  29491             if (js_is_live_code(s)) {
  29492                 /* drop the catch offset */
  29493                 emit_op(s, OP_drop);
  29494                 /* must push dummy value to keep same stack size */
  29495                 emit_op(s, OP_undefined);
  29496                 emit_goto(s, OP_gosub, label_finally);
  29497                 emit_op(s, OP_drop);
  29498 
  29499                 emit_goto(s, OP_goto, label_end);
  29500             }
  29501 
  29502             if (s->token.val == TOK_CATCH) {
  29503                 if (next_token(s))
  29504                     goto fail;
  29505 
  29506                 push_scope(s);  /* catch variable */
  29507                 emit_label(s, label_catch);
  29508 
  29509                 if (s->token.val == '{') {
  29510                     /* support optional-catch-binding feature */
  29511                     emit_op(s, OP_drop);    /* pop the exception object */
  29512                 } else {
  29513                     if (js_parse_expect(s, '('))
  29514                         goto fail;
  29515                     if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
  29516                         if (s->token.val == '[' || s->token.val == '{') {
  29517                             /* XXX: TOK_LET is not completely correct */
  29518                             if (js_parse_destructuring_element(s, TOK_LET, 0, TRUE, -1, TRUE, FALSE) < 0)
  29519                                 goto fail;
  29520                         } else {
  29521                             js_parse_error(s, "identifier expected");
  29522                             goto fail;
  29523                         }
  29524                     } else {
  29525                         name = JS_DupAtom(ctx, s->token.u.ident.atom);
  29526                         if (next_token(s)
  29527                         ||  js_define_var(s, name, TOK_CATCH) < 0) {
  29528                             JS_FreeAtom(ctx, name);
  29529                             goto fail;
  29530                         }
  29531                         /* store the exception value in the catch variable */
  29532                         emit_op(s, OP_scope_put_var);
  29533                         emit_u32(s, name);
  29534                         emit_u16(s, s->cur_func->scope_level);
  29535                     }
  29536                     if (js_parse_expect(s, ')'))
  29537                         goto fail;
  29538                 }
  29539                 /* XXX: should keep the address to nop it out if there is no finally block */
  29540                 emit_goto(s, OP_catch, label_catch2);
  29541 
  29542                 push_scope(s);  /* catch block */
  29543                 push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL,
  29544                                  -1, -1, 1);
  29545                 block_env.label_finally = label_finally;
  29546 
  29547                 if (js_parse_block(s))
  29548                     goto fail;
  29549 
  29550                 pop_break_entry(s->cur_func);
  29551                 pop_scope(s);  /* catch block */
  29552                 pop_scope(s);  /* catch variable */
  29553 
  29554                 if (js_is_live_code(s)) {
  29555                     /* drop the catch2 offset */
  29556                     emit_op(s, OP_drop);
  29557                     /* XXX: should keep the address to nop it out if there is no finally block */
  29558                     /* must push dummy value to keep same stack size */
  29559                     emit_op(s, OP_undefined);
  29560                     emit_goto(s, OP_gosub, label_finally);
  29561                     emit_op(s, OP_drop);
  29562                     emit_goto(s, OP_goto, label_end);
  29563                 }
  29564                 /* catch exceptions thrown in the catch block to execute the
  29565                  * finally clause and rethrow the exception */
  29566                 emit_label(s, label_catch2);
  29567                 /* catch value is at TOS, no need to push undefined */
  29568                 emit_goto(s, OP_gosub, label_finally);
  29569                 emit_op(s, OP_throw);
  29570 
  29571             } else if (s->token.val == TOK_FINALLY) {
  29572                 /* finally without catch : execute the finally clause
  29573                  * and rethrow the exception */
  29574                 emit_label(s, label_catch);
  29575                 /* catch value is at TOS, no need to push undefined */
  29576                 emit_goto(s, OP_gosub, label_finally);
  29577                 emit_op(s, OP_throw);
  29578             } else {
  29579                 js_parse_error(s, "expecting catch or finally");
  29580                 goto fail;
  29581             }
  29582             emit_label(s, label_finally);
  29583             if (s->token.val == TOK_FINALLY) {
  29584                 int saved_eval_ret_idx = 0; /* avoid warning */
  29585 
  29586                 if (next_token(s))
  29587                     goto fail;
  29588                 /* on the stack: ret_value gosub_ret_value */
  29589                 push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL,
  29590                                  -1, -1, 2);
  29591 
  29592                 if (s->cur_func->eval_ret_idx >= 0) {
  29593                     /* 'finally' updates eval_ret only if not a normal
  29594                        termination */
  29595                     saved_eval_ret_idx =
  29596                         add_var(s->ctx, s->cur_func, JS_ATOM__ret_);
  29597                     if (saved_eval_ret_idx < 0)
  29598                         goto fail;
  29599                     emit_op(s, OP_get_loc);
  29600                     emit_u16(s, s->cur_func->eval_ret_idx);
  29601                     emit_op(s, OP_put_loc);
  29602                     emit_u16(s, saved_eval_ret_idx);
  29603                     set_eval_ret_undefined(s);
  29604                 }
  29605 
  29606                 if (js_parse_block(s))
  29607                     goto fail;
  29608 
  29609                 if (s->cur_func->eval_ret_idx >= 0) {
  29610                     emit_op(s, OP_get_loc);
  29611                     emit_u16(s, saved_eval_ret_idx);
  29612                     emit_op(s, OP_put_loc);
  29613                     emit_u16(s, s->cur_func->eval_ret_idx);
  29614                 }
  29615                 pop_break_entry(s->cur_func);
  29616             }
  29617             emit_op(s, OP_ret);
  29618             emit_label(s, label_end);
  29619         }
  29620         break;
  29621     case ';':
  29622         /* empty statement */
  29623         if (next_token(s))
  29624             goto fail;
  29625         break;
  29626     case TOK_WITH:
  29627         if (s->cur_func->js_mode & JS_MODE_STRICT) {
  29628             js_parse_error(s, "invalid keyword: with");
  29629             goto fail;
  29630         } else {
  29631             int with_idx;
  29632 
  29633             if (next_token(s))
  29634                 goto fail;
  29635 
  29636             if (js_parse_expr_paren(s))
  29637                 goto fail;
  29638 
  29639             push_scope(s);
  29640             with_idx = define_var(s, s->cur_func, JS_ATOM__with_,
  29641                                   JS_VAR_DEF_WITH);
  29642             if (with_idx < 0)
  29643                 goto fail;
  29644             emit_op(s, OP_to_object);
  29645             emit_op(s, OP_put_loc);
  29646             emit_u16(s, with_idx);
  29647 
  29648             set_eval_ret_undefined(s);
  29649             if (js_parse_statement(s))
  29650                 goto fail;
  29651 
  29652             /* Popping scope drops lexical context for the with object variable */
  29653             pop_scope(s);
  29654         }
  29655         break;
  29656     case TOK_FUNCTION:
  29657         /* ES6 Annex B.3.2 and B.3.3 semantics */
  29658         if (!(decl_mask & DECL_MASK_FUNC))
  29659             goto func_decl_error;
  29660         if (!(decl_mask & DECL_MASK_OTHER) && peek_token(s, FALSE) == '*')
  29661             goto func_decl_error;
  29662         goto parse_func_var;
  29663     case TOK_IDENT:
  29664         if (s->token.u.ident.is_reserved) {
  29665             js_parse_error_reserved_identifier(s);
  29666             goto fail;
  29667         }
  29668         /* Determine if `let` introduces a Declaration or an ExpressionStatement */
  29669         switch (is_let(s, decl_mask)) {
  29670         case TRUE:
  29671             tok = TOK_LET;
  29672             goto haslet;
  29673         case FALSE:
  29674             break;
  29675         default:
  29676             goto fail;
  29677         }
  29678         if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
  29679             peek_token(s, TRUE) == TOK_FUNCTION) {
  29680             if (!(decl_mask & DECL_MASK_OTHER)) {
  29681             func_decl_error:
  29682                 js_parse_error(s, "function declarations can't appear in single-statement context");
  29683                 goto fail;
  29684             }
  29685         parse_func_var:
  29686             if (js_parse_function_decl(s, JS_PARSE_FUNC_VAR,
  29687                                        JS_FUNC_NORMAL, JS_ATOM_NULL,
  29688                                        s->token.ptr))
  29689                 goto fail;
  29690             break;
  29691         }
  29692         goto hasexpr;
  29693 
  29694     case TOK_CLASS:
  29695         if (!(decl_mask & DECL_MASK_OTHER)) {
  29696             js_parse_error(s, "class declarations can't appear in single-statement context");
  29697             goto fail;
  29698         }
  29699         if (js_parse_class(s, FALSE, JS_PARSE_EXPORT_NONE))
  29700             return -1;
  29701         break;
  29702 
  29703     case TOK_DEBUGGER:
  29704         /* currently no debugger, so just skip the keyword */
  29705         if (next_token(s))
  29706             goto fail;
  29707         if (js_parse_expect_semi(s))
  29708             goto fail;
  29709         break;
  29710 
  29711     case TOK_ENUM:
  29712     case TOK_EXPORT:
  29713     case TOK_EXTENDS:
  29714         js_unsupported_keyword(s, s->token.u.ident.atom);
  29715         goto fail;
  29716 
  29717     default:
  29718     hasexpr:
  29719         emit_source_pos(s, s->token.ptr);
  29720         if (js_parse_expr(s))
  29721             goto fail;
  29722         if (s->cur_func->eval_ret_idx >= 0) {
  29723             /* store the expression value so that it can be returned
  29724                by eval() */
  29725             emit_op(s, OP_put_loc);
  29726             emit_u16(s, s->cur_func->eval_ret_idx);
  29727         } else {
  29728             emit_op(s, OP_drop); /* drop the result */
  29729         }
  29730         if (js_parse_expect_semi(s))
  29731             goto fail;
  29732         break;
  29733     }
  29734 done:
  29735     JS_FreeAtom(ctx, label_name);
  29736     return 0;
  29737 fail:
  29738     JS_FreeAtom(ctx, label_name);
  29739     return -1;
  29740 }
  29741 
  29742 /* 'name' is freed. The module is referenced by 'ctx->loaded_modules' */
  29743 static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name)
  29744 {
  29745     JSModuleDef *m;
  29746     m = js_mallocz(ctx, sizeof(*m));
  29747     if (!m) {
  29748         JS_FreeAtom(ctx, name);
  29749         return NULL;
  29750     }
  29751     js_rc(m)->ref_count = 1;
  29752     add_gc_object(ctx->rt, &m->header, JS_GC_OBJ_TYPE_MODULE);
  29753     m->module_name = name;
  29754     m->module_ns = JS_UNDEFINED;
  29755     m->func_obj = JS_UNDEFINED;
  29756     m->eval_exception = JS_UNDEFINED;
  29757     m->meta_obj = JS_UNDEFINED;
  29758     m->promise = JS_UNDEFINED;
  29759     m->resolving_funcs[0] = JS_UNDEFINED;
  29760     m->resolving_funcs[1] = JS_UNDEFINED;
  29761     m->private_value = JS_UNDEFINED;
  29762     list_add_tail(&m->link, &ctx->loaded_modules);
  29763     return m;
  29764 }
  29765 
  29766 static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
  29767                                JS_MarkFunc *mark_func)
  29768 {
  29769     int i;
  29770 
  29771     for(i = 0; i < m->req_module_entries_count; i++) {
  29772         JSReqModuleEntry *rme = &m->req_module_entries[i];
  29773         JS_MarkValue(rt, rme->attributes, mark_func);
  29774     }
  29775     
  29776     for(i = 0; i < m->export_entries_count; i++) {
  29777         JSExportEntry *me = &m->export_entries[i];
  29778         if (me->export_type == JS_EXPORT_TYPE_LOCAL &&
  29779             me->u.local.var_ref) {
  29780             mark_func(rt, &me->u.local.var_ref->header);
  29781         }
  29782     }
  29783 
  29784     JS_MarkValue(rt, m->module_ns, mark_func);
  29785     JS_MarkValue(rt, m->func_obj, mark_func);
  29786     JS_MarkValue(rt, m->eval_exception, mark_func);
  29787     JS_MarkValue(rt, m->meta_obj, mark_func);
  29788     JS_MarkValue(rt, m->promise, mark_func);
  29789     JS_MarkValue(rt, m->resolving_funcs[0], mark_func);
  29790     JS_MarkValue(rt, m->resolving_funcs[1], mark_func);
  29791     JS_MarkValue(rt, m->private_value, mark_func);
  29792 }
  29793 
  29794 static void js_free_module_def(JSRuntime *rt, JSModuleDef *m)
  29795 {
  29796     int i;
  29797 
  29798     JS_FreeAtomRT(rt, m->module_name);
  29799 
  29800     for(i = 0; i < m->req_module_entries_count; i++) {
  29801         JSReqModuleEntry *rme = &m->req_module_entries[i];
  29802         JS_FreeAtomRT(rt, rme->module_name);
  29803         JS_FreeValueRT(rt, rme->attributes);
  29804     }
  29805     js_free_rt(rt, m->req_module_entries);
  29806 
  29807     for(i = 0; i < m->export_entries_count; i++) {
  29808         JSExportEntry *me = &m->export_entries[i];
  29809         if (me->export_type == JS_EXPORT_TYPE_LOCAL)
  29810             free_var_ref(rt, me->u.local.var_ref);
  29811         JS_FreeAtomRT(rt, me->export_name);
  29812         JS_FreeAtomRT(rt, me->local_name);
  29813     }
  29814     js_free_rt(rt, m->export_entries);
  29815 
  29816     js_free_rt(rt, m->star_export_entries);
  29817 
  29818     for(i = 0; i < m->import_entries_count; i++) {
  29819         JSImportEntry *mi = &m->import_entries[i];
  29820         JS_FreeAtomRT(rt, mi->import_name);
  29821     }
  29822     js_free_rt(rt, m->import_entries);
  29823     js_free_rt(rt, m->async_parent_modules);
  29824 
  29825     JS_FreeValueRT(rt, m->module_ns);
  29826     JS_FreeValueRT(rt, m->func_obj);
  29827     JS_FreeValueRT(rt, m->eval_exception);
  29828     JS_FreeValueRT(rt, m->meta_obj);
  29829     JS_FreeValueRT(rt, m->promise);
  29830     JS_FreeValueRT(rt, m->resolving_funcs[0]);
  29831     JS_FreeValueRT(rt, m->resolving_funcs[1]);
  29832     JS_FreeValueRT(rt, m->private_value);
  29833     /* during the GC the finalizers are called in an arbitrary
  29834        order so the module may no longer be referenced by the JSContext list */
  29835     if (m->link.next) {
  29836         list_del(&m->link);
  29837     }
  29838     remove_gc_object(&m->header);
  29839     if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && js_rc(m)->ref_count != 0) {
  29840         list_add_tail(&m->header.link, &rt->gc_zero_ref_count_list);
  29841     } else {
  29842         js_free_rt(rt, m);
  29843     }
  29844 }
  29845 
  29846 static int add_req_module_entry(JSContext *ctx, JSModuleDef *m,
  29847                                 JSAtom module_name)
  29848 {
  29849     JSReqModuleEntry *rme;
  29850 
  29851     if (js_resize_array(ctx, (void **)&m->req_module_entries,
  29852                         sizeof(JSReqModuleEntry),
  29853                         &m->req_module_entries_size,
  29854                         m->req_module_entries_count + 1))
  29855         return -1;
  29856     rme = &m->req_module_entries[m->req_module_entries_count++];
  29857     rme->module_name = JS_DupAtom(ctx, module_name);
  29858     rme->module = NULL;
  29859     rme->attributes = JS_UNDEFINED;
  29860     return m->req_module_entries_count - 1;
  29861 }
  29862 
  29863 static JSExportEntry *find_export_entry(JSContext *ctx, JSModuleDef *m,
  29864                                         JSAtom export_name)
  29865 {
  29866     JSExportEntry *me;
  29867     int i;
  29868     for(i = 0; i < m->export_entries_count; i++) {
  29869         me = &m->export_entries[i];
  29870         if (me->export_name == export_name)
  29871             return me;
  29872     }
  29873     return NULL;
  29874 }
  29875 
  29876 static JSExportEntry *add_export_entry2(JSContext *ctx,
  29877                                         JSParseState *s, JSModuleDef *m,
  29878                                        JSAtom local_name, JSAtom export_name,
  29879                                        JSExportTypeEnum export_type)
  29880 {
  29881     JSExportEntry *me;
  29882 
  29883     if (find_export_entry(ctx, m, export_name)) {
  29884         char buf1[ATOM_GET_STR_BUF_SIZE];
  29885         if (s) {
  29886             js_parse_error(s, "duplicate exported name '%s'",
  29887                            JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name));
  29888         } else {
  29889             JS_ThrowSyntaxErrorAtom(ctx, "duplicate exported name '%s'", export_name);
  29890         }
  29891         return NULL;
  29892     }
  29893 
  29894     if (js_resize_array(ctx, (void **)&m->export_entries,
  29895                         sizeof(JSExportEntry),
  29896                         &m->export_entries_size,
  29897                         m->export_entries_count + 1))
  29898         return NULL;
  29899     me = &m->export_entries[m->export_entries_count++];
  29900     memset(me, 0, sizeof(*me));
  29901     me->local_name = JS_DupAtom(ctx, local_name);
  29902     me->export_name = JS_DupAtom(ctx, export_name);
  29903     me->export_type = export_type;
  29904     return me;
  29905 }
  29906 
  29907 static JSExportEntry *add_export_entry(JSParseState *s, JSModuleDef *m,
  29908                                        JSAtom local_name, JSAtom export_name,
  29909                                        JSExportTypeEnum export_type)
  29910 {
  29911     return add_export_entry2(s->ctx, s, m, local_name, export_name,
  29912                              export_type);
  29913 }
  29914 
  29915 static int add_star_export_entry(JSContext *ctx, JSModuleDef *m,
  29916                                  int req_module_idx)
  29917 {
  29918     JSStarExportEntry *se;
  29919 
  29920     if (js_resize_array(ctx, (void **)&m->star_export_entries,
  29921                         sizeof(JSStarExportEntry),
  29922                         &m->star_export_entries_size,
  29923                         m->star_export_entries_count + 1))
  29924         return -1;
  29925     se = &m->star_export_entries[m->star_export_entries_count++];
  29926     se->req_module_idx = req_module_idx;
  29927     return 0;
  29928 }
  29929 
  29930 /* create a C module */
  29931 JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str,
  29932                            JSModuleInitFunc *func)
  29933 {
  29934     JSModuleDef *m;
  29935     JSAtom name;
  29936     name = JS_NewAtom(ctx, name_str);
  29937     if (name == JS_ATOM_NULL)
  29938         return NULL;
  29939     m = js_new_module_def(ctx, name);
  29940     if (!m)
  29941         return NULL;
  29942     m->init_func = func;
  29943     return m;
  29944 }
  29945 
  29946 int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name)
  29947 {
  29948     JSExportEntry *me;
  29949     JSAtom name;
  29950     name = JS_NewAtom(ctx, export_name);
  29951     if (name == JS_ATOM_NULL)
  29952         return -1;
  29953     me = add_export_entry2(ctx, NULL, m, JS_ATOM_NULL, name,
  29954                            JS_EXPORT_TYPE_LOCAL);
  29955     JS_FreeAtom(ctx, name);
  29956     if (!me)
  29957         return -1;
  29958     else
  29959         return 0;
  29960 }
  29961 
  29962 int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name,
  29963                        JSValue val)
  29964 {
  29965     JSExportEntry *me;
  29966     JSAtom name;
  29967     name = JS_NewAtom(ctx, export_name);
  29968     if (name == JS_ATOM_NULL)
  29969         goto fail;
  29970     me = find_export_entry(ctx, m, name);
  29971     JS_FreeAtom(ctx, name);
  29972     if (!me)
  29973         goto fail;
  29974     set_value(ctx, me->u.local.var_ref->pvalue, val);
  29975     return 0;
  29976  fail:
  29977     JS_FreeValue(ctx, val);
  29978     return -1;
  29979 }
  29980 
  29981 int JS_SetModulePrivateValue(JSContext *ctx, JSModuleDef *m, JSValue val)
  29982 {
  29983     set_value(ctx, &m->private_value, val);
  29984     return 0;
  29985 }
  29986 
  29987 JSValue JS_GetModulePrivateValue(JSContext *ctx, JSModuleDef *m)
  29988 {
  29989     return JS_DupValue(ctx, m->private_value);
  29990 }
  29991 
  29992 void JS_SetModuleLoaderFunc(JSRuntime *rt,
  29993                             JSModuleNormalizeFunc *module_normalize,
  29994                             JSModuleLoaderFunc *module_loader, void *opaque)
  29995 {
  29996     rt->module_normalize_func = module_normalize;
  29997     rt->module_loader_has_attr = FALSE;
  29998     rt->u.module_loader_func = module_loader;
  29999     rt->module_check_attrs = NULL;
  30000     rt->module_loader_opaque = opaque;
  30001 }
  30002 
  30003 void JS_SetModuleLoaderFunc2(JSRuntime *rt,
  30004                              JSModuleNormalizeFunc *module_normalize,
  30005                              JSModuleLoaderFunc2 *module_loader,
  30006                              JSModuleCheckSupportedImportAttributes *module_check_attrs,
  30007                              void *opaque)
  30008 {
  30009     rt->module_normalize_func = module_normalize;
  30010     rt->module_loader_has_attr = TRUE;
  30011     rt->u.module_loader_func2 = module_loader;
  30012     rt->module_check_attrs = module_check_attrs;
  30013     rt->module_loader_opaque = opaque;
  30014 }
  30015 
  30016 /* default module filename normalizer */
  30017 static char *js_default_module_normalize_name(JSContext *ctx,
  30018                                               const char *base_name,
  30019                                               const char *name)
  30020 {
  30021     char *filename, *p;
  30022     const char *r;
  30023     int cap;
  30024     int len;
  30025 
  30026     if (name[0] != '.') {
  30027         /* if no initial dot, the module name is not modified */
  30028         return js_strdup(ctx, name);
  30029     }
  30030 
  30031     p = strrchr(base_name, '/');
  30032     if (p)
  30033         len = p - base_name;
  30034     else
  30035         len = 0;
  30036 
  30037     cap = len + strlen(name) + 1 + 1;
  30038     filename = js_malloc(ctx, cap);
  30039     if (!filename)
  30040         return NULL;
  30041     memcpy(filename, base_name, len);
  30042     filename[len] = '\0';
  30043 
  30044     /* we only normalize the leading '..' or '.' */
  30045     r = name;
  30046     for(;;) {
  30047         if (r[0] == '.' && r[1] == '/') {
  30048             r += 2;
  30049         } else if (r[0] == '.' && r[1] == '.' && r[2] == '/') {
  30050             /* remove the last path element of filename, except if "."
  30051                or ".." */
  30052             if (filename[0] == '\0')
  30053                 break;
  30054             p = strrchr(filename, '/');
  30055             if (!p)
  30056                 p = filename;
  30057             else
  30058                 p++;
  30059             if (!strcmp(p, ".") || !strcmp(p, ".."))
  30060                 break;
  30061             if (p > filename)
  30062                 p--;
  30063             *p = '\0';
  30064             r += 3;
  30065         } else {
  30066             break;
  30067         }
  30068     }
  30069     if (filename[0] != '\0')
  30070         pstrcat(filename, cap, "/");
  30071     pstrcat(filename, cap, r);
  30072     //    printf("normalize: %s %s -> %s\n", base_name, name, filename);
  30073     return filename;
  30074 }
  30075 
  30076 static JSModuleDef *js_find_loaded_module(JSContext *ctx, JSAtom name)
  30077 {
  30078     struct list_head *el;
  30079     JSModuleDef *m;
  30080 
  30081     /* first look at the loaded modules */
  30082     list_for_each(el, &ctx->loaded_modules) {
  30083         m = list_entry(el, JSModuleDef, link);
  30084         if (m->module_name == name)
  30085             return m;
  30086     }
  30087     return NULL;
  30088 }
  30089 
  30090 /* return NULL in case of exception (e.g. module could not be loaded) */
  30091 static JSModuleDef *js_host_resolve_imported_module(JSContext *ctx,
  30092                                                     const char *base_cname,
  30093                                                     const char *cname1,
  30094                                                     JSValueConst attributes)
  30095 {
  30096     JSRuntime *rt = ctx->rt;
  30097     JSModuleDef *m;
  30098     char *cname;
  30099     JSAtom module_name;
  30100 
  30101     if (!rt->module_normalize_func) {
  30102         cname = js_default_module_normalize_name(ctx, base_cname, cname1);
  30103     } else {
  30104         cname = rt->module_normalize_func(ctx, base_cname, cname1,
  30105                                           rt->module_loader_opaque);
  30106     }
  30107     if (!cname)
  30108         return NULL;
  30109 
  30110     module_name = JS_NewAtom(ctx, cname);
  30111     if (module_name == JS_ATOM_NULL) {
  30112         js_free(ctx, cname);
  30113         return NULL;
  30114     }
  30115 
  30116     /* first look at the loaded modules */
  30117     m = js_find_loaded_module(ctx, module_name);
  30118     if (m) {
  30119         js_free(ctx, cname);
  30120         JS_FreeAtom(ctx, module_name);
  30121         return m;
  30122     }
  30123 
  30124     JS_FreeAtom(ctx, module_name);
  30125 
  30126     /* load the module */
  30127     if (!rt->u.module_loader_func) {
  30128         /* XXX: use a syntax error ? */
  30129         JS_ThrowReferenceError(ctx, "could not load module '%s'",
  30130                                cname);
  30131         js_free(ctx, cname);
  30132         return NULL;
  30133     }
  30134     if (rt->module_loader_has_attr) {
  30135         m = rt->u.module_loader_func2(ctx, cname, rt->module_loader_opaque, attributes);
  30136     } else {
  30137         m = rt->u.module_loader_func(ctx, cname, rt->module_loader_opaque);
  30138     }
  30139     js_free(ctx, cname);
  30140     return m;
  30141 }
  30142 
  30143 static JSModuleDef *js_host_resolve_imported_module_atom(JSContext *ctx,
  30144                                                          JSAtom base_module_name,
  30145                                                          JSAtom module_name1,
  30146                                                          JSValueConst attributes)
  30147 {
  30148     const char *base_cname, *cname;
  30149     JSModuleDef *m;
  30150 
  30151     base_cname = JS_AtomToCString(ctx, base_module_name);
  30152     if (!base_cname)
  30153         return NULL;
  30154     cname = JS_AtomToCString(ctx, module_name1);
  30155     if (!cname) {
  30156         JS_FreeCString(ctx, base_cname);
  30157         return NULL;
  30158     }
  30159     m = js_host_resolve_imported_module(ctx, base_cname, cname, attributes);
  30160     JS_FreeCString(ctx, base_cname);
  30161     JS_FreeCString(ctx, cname);
  30162     return m;
  30163 }
  30164 
  30165 typedef struct JSResolveEntry {
  30166     JSModuleDef *module;
  30167     JSAtom name;
  30168 } JSResolveEntry;
  30169 
  30170 typedef struct JSResolveState {
  30171     JSResolveEntry *array;
  30172     int size;
  30173     int count;
  30174 } JSResolveState;
  30175 
  30176 static int find_resolve_entry(JSResolveState *s,
  30177                               JSModuleDef *m, JSAtom name)
  30178 {
  30179     int i;
  30180     for(i = 0; i < s->count; i++) {
  30181         JSResolveEntry *re = &s->array[i];
  30182         if (re->module == m && re->name == name)
  30183             return i;
  30184     }
  30185     return -1;
  30186 }
  30187 
  30188 static int add_resolve_entry(JSContext *ctx, JSResolveState *s,
  30189                              JSModuleDef *m, JSAtom name)
  30190 {
  30191     JSResolveEntry *re;
  30192 
  30193     if (js_resize_array(ctx, (void **)&s->array,
  30194                         sizeof(JSResolveEntry),
  30195                         &s->size, s->count + 1))
  30196         return -1;
  30197     re = &s->array[s->count++];
  30198     re->module = m;
  30199     re->name = JS_DupAtom(ctx, name);
  30200     return 0;
  30201 }
  30202 
  30203 typedef enum JSResolveResultEnum {
  30204     JS_RESOLVE_RES_EXCEPTION = -1, /* memory alloc error */
  30205     JS_RESOLVE_RES_FOUND = 0,
  30206     JS_RESOLVE_RES_NOT_FOUND,
  30207     JS_RESOLVE_RES_CIRCULAR,
  30208     JS_RESOLVE_RES_AMBIGUOUS,
  30209 } JSResolveResultEnum;
  30210 
  30211 static JSResolveResultEnum js_resolve_export1(JSContext *ctx,
  30212                                               JSModuleDef **pmodule,
  30213                                               JSExportEntry **pme,
  30214                                               JSModuleDef *m,
  30215                                               JSAtom export_name,
  30216                                               JSResolveState *s)
  30217 {
  30218     JSExportEntry *me;
  30219 
  30220     *pmodule = NULL;
  30221     *pme = NULL;
  30222     if (find_resolve_entry(s, m, export_name) >= 0)
  30223         return JS_RESOLVE_RES_CIRCULAR;
  30224     if (add_resolve_entry(ctx, s, m, export_name) < 0)
  30225         return JS_RESOLVE_RES_EXCEPTION;
  30226     me = find_export_entry(ctx, m, export_name);
  30227     if (me) {
  30228         if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
  30229             /* local export */
  30230             *pmodule = m;
  30231             *pme = me;
  30232             return JS_RESOLVE_RES_FOUND;
  30233         } else {
  30234             /* indirect export */
  30235             JSModuleDef *m1;
  30236             m1 = m->req_module_entries[me->u.req_module_idx].module;
  30237             if (me->local_name == JS_ATOM__star_) {
  30238                 /* export ns from */
  30239                 *pmodule = m;
  30240                 *pme = me;
  30241                 return JS_RESOLVE_RES_FOUND;
  30242             } else {
  30243                 return js_resolve_export1(ctx, pmodule, pme, m1,
  30244                                           me->local_name, s);
  30245             }
  30246         }
  30247     } else {
  30248         if (export_name != JS_ATOM_default) {
  30249             /* not found in direct or indirect exports: try star exports */
  30250             int i;
  30251 
  30252             for(i = 0; i < m->star_export_entries_count; i++) {
  30253                 JSStarExportEntry *se = &m->star_export_entries[i];
  30254                 JSModuleDef *m1, *res_m;
  30255                 JSExportEntry *res_me;
  30256                 JSResolveResultEnum ret;
  30257 
  30258                 m1 = m->req_module_entries[se->req_module_idx].module;
  30259                 ret = js_resolve_export1(ctx, &res_m, &res_me, m1,
  30260                                          export_name, s);
  30261                 if (ret == JS_RESOLVE_RES_AMBIGUOUS ||
  30262                     ret == JS_RESOLVE_RES_EXCEPTION) {
  30263                     return ret;
  30264                 } else if (ret == JS_RESOLVE_RES_FOUND) {
  30265                     if (*pme != NULL) {
  30266                         if (*pmodule != res_m ||
  30267                             res_me->local_name != (*pme)->local_name) {
  30268                             *pmodule = NULL;
  30269                             *pme = NULL;
  30270                             return JS_RESOLVE_RES_AMBIGUOUS;
  30271                         }
  30272                     } else {
  30273                         *pmodule = res_m;
  30274                         *pme = res_me;
  30275                     }
  30276                 }
  30277             }
  30278             if (*pme != NULL)
  30279                 return JS_RESOLVE_RES_FOUND;
  30280         }
  30281         return JS_RESOLVE_RES_NOT_FOUND;
  30282     }
  30283 }
  30284 
  30285 /* If the return value is JS_RESOLVE_RES_FOUND, return the module
  30286   (*pmodule) and the corresponding local export entry
  30287   (*pme). Otherwise return (NULL, NULL) */
  30288 static JSResolveResultEnum js_resolve_export(JSContext *ctx,
  30289                                              JSModuleDef **pmodule,
  30290                                              JSExportEntry **pme,
  30291                                              JSModuleDef *m,
  30292                                              JSAtom export_name)
  30293 {
  30294     JSResolveState ss, *s = &ss;
  30295     int i;
  30296     JSResolveResultEnum ret;
  30297 
  30298     s->array = NULL;
  30299     s->size = 0;
  30300     s->count = 0;
  30301 
  30302     ret = js_resolve_export1(ctx, pmodule, pme, m, export_name, s);
  30303 
  30304     for(i = 0; i < s->count; i++)
  30305         JS_FreeAtom(ctx, s->array[i].name);
  30306     js_free(ctx, s->array);
  30307 
  30308     return ret;
  30309 }
  30310 
  30311 static void js_resolve_export_throw_error(JSContext *ctx,
  30312                                           JSResolveResultEnum res,
  30313                                           JSModuleDef *m, JSAtom export_name)
  30314 {
  30315     char buf1[ATOM_GET_STR_BUF_SIZE];
  30316     char buf2[ATOM_GET_STR_BUF_SIZE];
  30317     switch(res) {
  30318     case JS_RESOLVE_RES_EXCEPTION:
  30319         break;
  30320     default:
  30321     case JS_RESOLVE_RES_NOT_FOUND:
  30322         JS_ThrowSyntaxError(ctx, "Could not find export '%s' in module '%s'",
  30323                             JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
  30324                             JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
  30325         break;
  30326     case JS_RESOLVE_RES_CIRCULAR:
  30327         JS_ThrowSyntaxError(ctx, "circular reference when looking for export '%s' in module '%s'",
  30328                             JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
  30329                             JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
  30330         break;
  30331     case JS_RESOLVE_RES_AMBIGUOUS:
  30332         JS_ThrowSyntaxError(ctx, "export '%s' in module '%s' is ambiguous",
  30333                             JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
  30334                             JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
  30335         break;
  30336     }
  30337 }
  30338 
  30339 
  30340 typedef enum {
  30341     EXPORTED_NAME_AMBIGUOUS,
  30342     EXPORTED_NAME_NORMAL,
  30343     EXPORTED_NAME_DELAYED,
  30344 } ExportedNameEntryEnum;
  30345 
  30346 typedef struct ExportedNameEntry {
  30347     JSAtom export_name;
  30348     ExportedNameEntryEnum export_type;
  30349     union {
  30350         JSExportEntry *me; /* using when the list is built */
  30351         JSVarRef *var_ref; /* EXPORTED_NAME_NORMAL */
  30352     } u;
  30353 } ExportedNameEntry;
  30354 
  30355 typedef struct GetExportNamesState {
  30356     JSModuleDef **modules;
  30357     int modules_size;
  30358     int modules_count;
  30359 
  30360     ExportedNameEntry *exported_names;
  30361     int exported_names_size;
  30362     int exported_names_count;
  30363 } GetExportNamesState;
  30364 
  30365 static int find_exported_name(GetExportNamesState *s, JSAtom name)
  30366 {
  30367     int i;
  30368     for(i = 0; i < s->exported_names_count; i++) {
  30369         if (s->exported_names[i].export_name == name)
  30370             return i;
  30371     }
  30372     return -1;
  30373 }
  30374 
  30375 static __exception int get_exported_names(JSContext *ctx,
  30376                                           GetExportNamesState *s,
  30377                                           JSModuleDef *m, BOOL from_star)
  30378 {
  30379     ExportedNameEntry *en;
  30380     int i, j;
  30381 
  30382     /* check circular reference */
  30383     for(i = 0; i < s->modules_count; i++) {
  30384         if (s->modules[i] == m)
  30385             return 0;
  30386     }
  30387     if (js_resize_array(ctx, (void **)&s->modules, sizeof(s->modules[0]),
  30388                         &s->modules_size, s->modules_count + 1))
  30389         return -1;
  30390     s->modules[s->modules_count++] = m;
  30391 
  30392     for(i = 0; i < m->export_entries_count; i++) {
  30393         JSExportEntry *me = &m->export_entries[i];
  30394         if (from_star && me->export_name == JS_ATOM_default)
  30395             continue;
  30396         j = find_exported_name(s, me->export_name);
  30397         if (j < 0) {
  30398             if (js_resize_array(ctx, (void **)&s->exported_names, sizeof(s->exported_names[0]),
  30399                                 &s->exported_names_size,
  30400                                 s->exported_names_count + 1))
  30401                 return -1;
  30402             en = &s->exported_names[s->exported_names_count++];
  30403             en->export_name = me->export_name;
  30404             /* avoid a second lookup for simple module exports */
  30405             if (from_star || me->export_type != JS_EXPORT_TYPE_LOCAL)
  30406                 en->u.me = NULL;
  30407             else
  30408                 en->u.me = me;
  30409         } else {
  30410             en = &s->exported_names[j];
  30411             en->u.me = NULL;
  30412         }
  30413     }
  30414     for(i = 0; i < m->star_export_entries_count; i++) {
  30415         JSStarExportEntry *se = &m->star_export_entries[i];
  30416         JSModuleDef *m1;
  30417         m1 = m->req_module_entries[se->req_module_idx].module;
  30418         if (get_exported_names(ctx, s, m1, TRUE))
  30419             return -1;
  30420     }
  30421     return 0;
  30422 }
  30423 
  30424 /* Unfortunately, the spec gives a different behavior from GetOwnProperty ! */
  30425 static int js_module_ns_has(JSContext *ctx, JSValueConst obj, JSAtom atom)
  30426 {
  30427     return (find_own_property1(JS_VALUE_GET_OBJ(obj), atom) != NULL);
  30428 }
  30429 
  30430 static const JSClassExoticMethods js_module_ns_exotic_methods = {
  30431     .has_property = js_module_ns_has,
  30432 };
  30433 
  30434 static int exported_names_cmp(const void *p1, const void *p2, void *opaque)
  30435 {
  30436     JSContext *ctx = opaque;
  30437     const ExportedNameEntry *me1 = p1;
  30438     const ExportedNameEntry *me2 = p2;
  30439     JSValue str1, str2;
  30440     int ret;
  30441 
  30442     /* XXX: should avoid allocation memory in atom comparison */
  30443     str1 = JS_AtomToString(ctx, me1->export_name);
  30444     str2 = JS_AtomToString(ctx, me2->export_name);
  30445     if (JS_IsException(str1) || JS_IsException(str2)) {
  30446         /* XXX: raise an error ? */
  30447         ret = 0;
  30448     } else {
  30449         ret = js_string_compare(ctx, JS_VALUE_GET_STRING(str1),
  30450                                 JS_VALUE_GET_STRING(str2));
  30451     }
  30452     JS_FreeValue(ctx, str1);
  30453     JS_FreeValue(ctx, str2);
  30454     return ret;
  30455 }
  30456 
  30457 static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
  30458                                      void *opaque)
  30459 {
  30460     JSModuleDef *m = opaque;
  30461     JSResolveResultEnum res;
  30462     JSExportEntry *res_me;
  30463     JSModuleDef *res_m;
  30464     JSVarRef *var_ref;
  30465 
  30466     res = js_resolve_export(ctx, &res_m, &res_me, m, atom);
  30467     if (res != JS_RESOLVE_RES_FOUND) {
  30468         /* fail safe: normally no error should happen here except for memory */
  30469         js_resolve_export_throw_error(ctx, res, m, atom);
  30470         return JS_EXCEPTION;
  30471     }
  30472     if (res_me->local_name == JS_ATOM__star_) {
  30473         return JS_GetModuleNamespace(ctx, res_m->req_module_entries[res_me->u.req_module_idx].module);
  30474     } else {
  30475         if (res_me->u.local.var_ref) {
  30476             var_ref = res_me->u.local.var_ref;
  30477         } else {
  30478             JSObject *p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
  30479             var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];
  30480         }
  30481         /* WARNING: a varref is returned as a string ! */
  30482         return JS_MKPTR(JS_TAG_STRING, var_ref);
  30483     }
  30484 }
  30485 
  30486 static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m)
  30487 {
  30488     JSValue obj;
  30489     JSObject *p;
  30490     GetExportNamesState s_s, *s = &s_s;
  30491     int i, ret;
  30492     JSProperty *pr;
  30493 
  30494     obj = JS_NewObjectClass(ctx, JS_CLASS_MODULE_NS);
  30495     if (JS_IsException(obj))
  30496         return obj;
  30497     p = JS_VALUE_GET_OBJ(obj);
  30498 
  30499     memset(s, 0, sizeof(*s));
  30500     ret = get_exported_names(ctx, s, m, FALSE);
  30501     js_free(ctx, s->modules);
  30502     if (ret)
  30503         goto fail;
  30504 
  30505     /* Resolve the exported names. The ambiguous exports are removed */
  30506     for(i = 0; i < s->exported_names_count; i++) {
  30507         ExportedNameEntry *en = &s->exported_names[i];
  30508         JSResolveResultEnum res;
  30509         JSExportEntry *res_me;
  30510         JSModuleDef *res_m;
  30511 
  30512         if (en->u.me) {
  30513             res_me = en->u.me; /* fast case: no resolution needed */
  30514             res_m = m;
  30515             res = JS_RESOLVE_RES_FOUND;
  30516         } else {
  30517             res = js_resolve_export(ctx, &res_m, &res_me, m,
  30518                                     en->export_name);
  30519         }
  30520         if (res != JS_RESOLVE_RES_FOUND) {
  30521             if (res != JS_RESOLVE_RES_AMBIGUOUS) {
  30522                 js_resolve_export_throw_error(ctx, res, m, en->export_name);
  30523                 goto fail;
  30524             }
  30525             en->export_type = EXPORTED_NAME_AMBIGUOUS;
  30526         } else {
  30527             if (res_me->local_name == JS_ATOM__star_) {
  30528                 en->export_type = EXPORTED_NAME_DELAYED;
  30529             } else {
  30530                 if (res_me->u.local.var_ref) {
  30531                     en->u.var_ref = res_me->u.local.var_ref;
  30532                 } else {
  30533                     JSObject *p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
  30534                     en->u.var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];
  30535                 }
  30536                 if (en->u.var_ref == NULL)
  30537                     en->export_type = EXPORTED_NAME_DELAYED;
  30538                 else
  30539                     en->export_type = EXPORTED_NAME_NORMAL;
  30540             }
  30541         }
  30542     }
  30543 
  30544     /* sort the exported names */
  30545     rqsort(s->exported_names, s->exported_names_count,
  30546            sizeof(s->exported_names[0]), exported_names_cmp, ctx);
  30547 
  30548     for(i = 0; i < s->exported_names_count; i++) {
  30549         ExportedNameEntry *en = &s->exported_names[i];
  30550         switch(en->export_type) {
  30551         case EXPORTED_NAME_NORMAL:
  30552             {
  30553                 JSVarRef *var_ref = en->u.var_ref;
  30554                 pr = add_property(ctx, p, en->export_name,
  30555                                   JS_PROP_ENUMERABLE | JS_PROP_WRITABLE |
  30556                                   JS_PROP_VARREF);
  30557                 if (!pr)
  30558                     goto fail;
  30559                 js_rc(var_ref)->ref_count++;
  30560                 pr->u.var_ref = var_ref;
  30561             }
  30562             break;
  30563         case EXPORTED_NAME_DELAYED:
  30564             /* the exported namespace or reference may depend on
  30565                circular references, so we resolve it lazily */
  30566             if (JS_DefineAutoInitProperty(ctx, obj,
  30567                                           en->export_name,
  30568                                           JS_AUTOINIT_ID_MODULE_NS,
  30569                                           m, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
  30570                 goto fail;
  30571             break;
  30572         default:
  30573             break;
  30574         }
  30575     }
  30576 
  30577     js_free(ctx, s->exported_names);
  30578 
  30579     JS_DefinePropertyValue(ctx, obj, JS_ATOM_Symbol_toStringTag,
  30580                            JS_AtomToString(ctx, JS_ATOM_Module),
  30581                            0);
  30582 
  30583     p->extensible = FALSE;
  30584     return obj;
  30585  fail:
  30586     js_free(ctx, s->exported_names);
  30587     JS_FreeValue(ctx, obj);
  30588     return JS_EXCEPTION;
  30589 }
  30590 
  30591 JSValue JS_GetModuleNamespace(JSContext *ctx, JSModuleDef *m)
  30592 {
  30593     if (JS_IsUndefined(m->module_ns)) {
  30594         JSValue val;
  30595         val = js_build_module_ns(ctx, m);
  30596         if (JS_IsException(val))
  30597             return JS_EXCEPTION;
  30598         m->module_ns = val;
  30599     }
  30600     return JS_DupValue(ctx, m->module_ns);
  30601 }
  30602 
  30603 /* Load all the required modules for module 'm' */
  30604 static int js_resolve_module(JSContext *ctx, JSModuleDef *m)
  30605 {
  30606     int i;
  30607     JSModuleDef *m1;
  30608 
  30609     if (m->resolved)
  30610         return 0;
  30611 #ifdef DUMP_MODULE_RESOLVE
  30612     {
  30613         char buf1[ATOM_GET_STR_BUF_SIZE];
  30614         printf("resolving module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
  30615     }
  30616 #endif
  30617     m->resolved = TRUE;
  30618     /* resolve each requested module */
  30619     for(i = 0; i < m->req_module_entries_count; i++) {
  30620         JSReqModuleEntry *rme = &m->req_module_entries[i];
  30621         m1 = js_host_resolve_imported_module_atom(ctx, m->module_name,
  30622                                                   rme->module_name,
  30623                                                   rme->attributes);
  30624         if (!m1)
  30625             return -1;
  30626         rme->module = m1;
  30627         /* already done in js_host_resolve_imported_module() except if
  30628            the module was loaded with JS_EvalBinary() */
  30629         if (js_resolve_module(ctx, m1) < 0)
  30630             return -1;
  30631     }
  30632     return 0;
  30633 }
  30634 
  30635 /* Create the <eval> function associated with the module */
  30636 static int js_create_module_bytecode_function(JSContext *ctx, JSModuleDef *m)
  30637 {
  30638     JSFunctionBytecode *b;
  30639     JSValue func_obj, bfunc;
  30640 
  30641     bfunc = m->func_obj;
  30642     func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
  30643                                       JS_CLASS_BYTECODE_FUNCTION);
  30644 
  30645     if (JS_IsException(func_obj))
  30646         return -1;
  30647     m->func_obj = func_obj;
  30648     b = JS_VALUE_GET_PTR(bfunc);
  30649     func_obj = js_closure2(ctx, func_obj, b, NULL, NULL, TRUE, m);
  30650     if (JS_IsException(func_obj)) {
  30651         m->func_obj = JS_UNDEFINED; /* XXX: keep it ? */
  30652         JS_FreeValue(ctx, func_obj);
  30653         return -1;
  30654     }
  30655     return 0;
  30656 }
  30657 
  30658 /* must be done before js_link_module() because of cyclic references */
  30659 static int js_create_module_function(JSContext *ctx, JSModuleDef *m)
  30660 {
  30661     BOOL is_c_module;
  30662     int i;
  30663     JSVarRef *var_ref;
  30664 
  30665     if (m->func_created)
  30666         return 0;
  30667 
  30668     is_c_module = (m->init_func != NULL);
  30669 
  30670     if (is_c_module) {
  30671         /* initialize the exported variables */
  30672         for(i = 0; i < m->export_entries_count; i++) {
  30673             JSExportEntry *me = &m->export_entries[i];
  30674             if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
  30675                 var_ref = js_create_var_ref(ctx, FALSE);
  30676                 if (!var_ref)
  30677                     return -1;
  30678                 me->u.local.var_ref = var_ref;
  30679             }
  30680         }
  30681     } else {
  30682         if (js_create_module_bytecode_function(ctx, m))
  30683             return -1;
  30684     }
  30685     m->func_created = TRUE;
  30686 
  30687     /* do it on the dependencies */
  30688 
  30689     for(i = 0; i < m->req_module_entries_count; i++) {
  30690         JSReqModuleEntry *rme = &m->req_module_entries[i];
  30691         if (js_create_module_function(ctx, rme->module) < 0)
  30692             return -1;
  30693     }
  30694 
  30695     return 0;
  30696 }
  30697 
  30698 
  30699 /* Prepare a module to be executed by resolving all the imported
  30700    variables. */
  30701 static int js_inner_module_linking(JSContext *ctx, JSModuleDef *m,
  30702                                    JSModuleDef **pstack_top, int index)
  30703 {
  30704     int i;
  30705     JSImportEntry *mi;
  30706     JSModuleDef *m1;
  30707     JSVarRef **var_refs, *var_ref;
  30708     JSObject *p;
  30709     BOOL is_c_module;
  30710     JSValue ret_val;
  30711 
  30712     if (js_check_stack_overflow(ctx->rt, 0)) {
  30713         JS_ThrowStackOverflow(ctx);
  30714         return -1;
  30715     }
  30716 
  30717 #ifdef DUMP_MODULE_RESOLVE
  30718     {
  30719         char buf1[ATOM_GET_STR_BUF_SIZE];
  30720         printf("js_inner_module_linking '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
  30721     }
  30722 #endif
  30723 
  30724     if (m->status == JS_MODULE_STATUS_LINKING ||
  30725         m->status == JS_MODULE_STATUS_LINKED ||
  30726         m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
  30727         m->status == JS_MODULE_STATUS_EVALUATED)
  30728         return index;
  30729 
  30730     assert(m->status == JS_MODULE_STATUS_UNLINKED);
  30731     m->status = JS_MODULE_STATUS_LINKING;
  30732     m->dfs_index = index;
  30733     m->dfs_ancestor_index = index;
  30734     index++;
  30735     /* push 'm' on stack */
  30736     m->stack_prev = *pstack_top;
  30737     *pstack_top = m;
  30738 
  30739     for(i = 0; i < m->req_module_entries_count; i++) {
  30740         JSReqModuleEntry *rme = &m->req_module_entries[i];
  30741         m1 = rme->module;
  30742         index = js_inner_module_linking(ctx, m1, pstack_top, index);
  30743         if (index < 0)
  30744             goto fail;
  30745         assert(m1->status == JS_MODULE_STATUS_LINKING ||
  30746                m1->status == JS_MODULE_STATUS_LINKED ||
  30747                m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
  30748                m1->status == JS_MODULE_STATUS_EVALUATED);
  30749         if (m1->status == JS_MODULE_STATUS_LINKING) {
  30750             m->dfs_ancestor_index = min_int(m->dfs_ancestor_index,
  30751                                             m1->dfs_ancestor_index);
  30752         }
  30753     }
  30754 
  30755 #ifdef DUMP_MODULE_RESOLVE
  30756     {
  30757         char buf1[ATOM_GET_STR_BUF_SIZE];
  30758         printf("instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
  30759     }
  30760 #endif
  30761     /* check the indirect exports */
  30762     for(i = 0; i < m->export_entries_count; i++) {
  30763         JSExportEntry *me = &m->export_entries[i];
  30764         if (me->export_type == JS_EXPORT_TYPE_INDIRECT &&
  30765             me->local_name != JS_ATOM__star_) {
  30766             JSResolveResultEnum ret;
  30767             JSExportEntry *res_me;
  30768             JSModuleDef *res_m, *m1;
  30769             m1 = m->req_module_entries[me->u.req_module_idx].module;
  30770             ret = js_resolve_export(ctx, &res_m, &res_me, m1, me->local_name);
  30771             if (ret != JS_RESOLVE_RES_FOUND) {
  30772                 js_resolve_export_throw_error(ctx, ret, m, me->export_name);
  30773                 goto fail;
  30774             }
  30775         }
  30776     }
  30777 
  30778 #ifdef DUMP_MODULE_RESOLVE
  30779     {
  30780         printf("exported bindings:\n");
  30781         for(i = 0; i < m->export_entries_count; i++) {
  30782             JSExportEntry *me = &m->export_entries[i];
  30783             printf(" name="); print_atom(ctx, me->export_name);
  30784             printf(" local="); print_atom(ctx, me->local_name);
  30785             printf(" type=%d idx=%d\n", me->export_type, me->u.local.var_idx);
  30786         }
  30787     }
  30788 #endif
  30789 
  30790     is_c_module = (m->init_func != NULL);
  30791 
  30792     if (!is_c_module) {
  30793         p = JS_VALUE_GET_OBJ(m->func_obj);
  30794         var_refs = p->u.func.var_refs;
  30795 
  30796         for(i = 0; i < m->import_entries_count; i++) {
  30797             mi = &m->import_entries[i];
  30798 #ifdef DUMP_MODULE_RESOLVE
  30799             printf("import var_idx=%d name=", mi->var_idx);
  30800             print_atom(ctx, mi->import_name);
  30801             printf(": ");
  30802 #endif
  30803             m1 = m->req_module_entries[mi->req_module_idx].module;
  30804             if (mi->is_star) {
  30805                 JSValue val;
  30806                 /* name space import */
  30807                 val = JS_GetModuleNamespace(ctx, m1);
  30808                 if (JS_IsException(val))
  30809                     goto fail;
  30810                 set_value(ctx, &var_refs[mi->var_idx]->value, val);
  30811 #ifdef DUMP_MODULE_RESOLVE
  30812                 printf("namespace\n");
  30813 #endif
  30814             } else {
  30815                 JSResolveResultEnum ret;
  30816                 JSExportEntry *res_me;
  30817                 JSModuleDef *res_m;
  30818                 JSObject *p1;
  30819 
  30820                 ret = js_resolve_export(ctx, &res_m,
  30821                                         &res_me, m1, mi->import_name);
  30822                 if (ret != JS_RESOLVE_RES_FOUND) {
  30823                     js_resolve_export_throw_error(ctx, ret, m1, mi->import_name);
  30824                     goto fail;
  30825                 }
  30826                 if (res_me->local_name == JS_ATOM__star_) {
  30827                     JSValue val;
  30828                     JSModuleDef *m2;
  30829                     /* name space import from */
  30830                     m2 = res_m->req_module_entries[res_me->u.req_module_idx].module;
  30831                     val = JS_GetModuleNamespace(ctx, m2);
  30832                     if (JS_IsException(val))
  30833                         goto fail;
  30834                     var_ref = js_create_var_ref(ctx, TRUE);
  30835                     if (!var_ref) {
  30836                         JS_FreeValue(ctx, val);
  30837                         goto fail;
  30838                     }
  30839                     set_value(ctx, &var_ref->value, val);
  30840                     var_refs[mi->var_idx] = var_ref;
  30841 #ifdef DUMP_MODULE_RESOLVE
  30842                     printf("namespace from\n");
  30843 #endif
  30844                 } else {
  30845                     var_ref = res_me->u.local.var_ref;
  30846                     if (!var_ref) {
  30847                         p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
  30848                         var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];
  30849                     }
  30850                     js_rc(var_ref)->ref_count++;
  30851                     var_refs[mi->var_idx] = var_ref;
  30852 #ifdef DUMP_MODULE_RESOLVE
  30853                     printf("local export (var_ref=%p)\n", var_ref);
  30854 #endif
  30855                 }
  30856             }
  30857         }
  30858 
  30859         /* keep the exported variables in the module export entries (they
  30860            are used when the eval function is deleted and cannot be
  30861            initialized before in case imports are exported) */
  30862         for(i = 0; i < m->export_entries_count; i++) {
  30863             JSExportEntry *me = &m->export_entries[i];
  30864             if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
  30865                 var_ref = var_refs[me->u.local.var_idx];
  30866                 js_rc(var_ref)->ref_count++;
  30867                 me->u.local.var_ref = var_ref;
  30868             }
  30869         }
  30870 
  30871         /* initialize the global variables */
  30872         ret_val = JS_Call(ctx, m->func_obj, JS_TRUE, 0, NULL);
  30873         if (JS_IsException(ret_val))
  30874             goto fail;
  30875         JS_FreeValue(ctx, ret_val);
  30876     }
  30877 
  30878     assert(m->dfs_ancestor_index <= m->dfs_index);
  30879     if (m->dfs_index == m->dfs_ancestor_index) {
  30880         for(;;) {
  30881             /* pop m1 from stack */
  30882             m1 = *pstack_top;
  30883             *pstack_top = m1->stack_prev;
  30884             m1->status = JS_MODULE_STATUS_LINKED;
  30885             if (m1 == m)
  30886                 break;
  30887         }
  30888     }
  30889 
  30890 #ifdef DUMP_MODULE_RESOLVE
  30891     printf("js_inner_module_linking done\n");
  30892 #endif
  30893     return index;
  30894  fail:
  30895     return -1;
  30896 }
  30897 
  30898 /* Prepare a module to be executed by resolving all the imported
  30899    variables. */
  30900 static int js_link_module(JSContext *ctx, JSModuleDef *m)
  30901 {
  30902     JSModuleDef *stack_top, *m1;
  30903 
  30904 #ifdef DUMP_MODULE_RESOLVE
  30905     {
  30906         char buf1[ATOM_GET_STR_BUF_SIZE];
  30907         printf("js_link_module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
  30908     }
  30909 #endif
  30910     assert(m->status == JS_MODULE_STATUS_UNLINKED ||
  30911            m->status == JS_MODULE_STATUS_LINKED ||
  30912            m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
  30913            m->status == JS_MODULE_STATUS_EVALUATED);
  30914     stack_top = NULL;
  30915     if (js_inner_module_linking(ctx, m, &stack_top, 0) < 0) {
  30916         while (stack_top != NULL) {
  30917             m1 = stack_top;
  30918             assert(m1->status == JS_MODULE_STATUS_LINKING);
  30919             m1->status = JS_MODULE_STATUS_UNLINKED;
  30920             stack_top = m1->stack_prev;
  30921         }
  30922         return -1;
  30923     }
  30924     assert(stack_top == NULL);
  30925     assert(m->status == JS_MODULE_STATUS_LINKED ||
  30926            m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
  30927            m->status == JS_MODULE_STATUS_EVALUATED);
  30928     return 0;
  30929 }
  30930 
  30931 /* return JS_ATOM_NULL if the name cannot be found. Only works with
  30932    not striped bytecode functions. */
  30933 JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels)
  30934 {
  30935     JSStackFrame *sf;
  30936     JSFunctionBytecode *b;
  30937     JSObject *p;
  30938     /* XXX: currently we just use the filename of the englobing
  30939        function from the debug info. May need to add a ScriptOrModule
  30940        info in JSFunctionBytecode. */
  30941     sf = ctx->rt->current_stack_frame;
  30942     if (!sf)
  30943         return JS_ATOM_NULL;
  30944     while (n_stack_levels-- > 0) {
  30945         sf = sf->prev_frame;
  30946         if (!sf)
  30947             return JS_ATOM_NULL;
  30948     }
  30949     for(;;) {
  30950         if (JS_VALUE_GET_TAG(sf->cur_func) != JS_TAG_OBJECT)
  30951             return JS_ATOM_NULL;
  30952         p = JS_VALUE_GET_OBJ(sf->cur_func);
  30953         if (!js_class_has_bytecode(p->class_id))
  30954             return JS_ATOM_NULL;
  30955         b = p->u.func.function_bytecode;
  30956         if (!b->is_direct_or_indirect_eval) {
  30957             if (!b->has_debug)
  30958                 return JS_ATOM_NULL;
  30959             return JS_DupAtom(ctx, b->debug.filename);
  30960         } else {
  30961             sf = sf->prev_frame;
  30962             if (!sf)
  30963                 return JS_ATOM_NULL;
  30964         }
  30965     }
  30966 }
  30967 
  30968 JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m)
  30969 {
  30970     return JS_DupAtom(ctx, m->module_name);
  30971 }
  30972 
  30973 JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m)
  30974 {
  30975     JSValue obj;
  30976     /* allocate meta_obj only if requested to save memory */
  30977     obj = m->meta_obj;
  30978     if (JS_IsUndefined(obj)) {
  30979         obj = JS_NewObjectProto(ctx, JS_NULL);
  30980         if (JS_IsException(obj))
  30981             return JS_EXCEPTION;
  30982         m->meta_obj = obj;
  30983     }
  30984     return JS_DupValue(ctx, obj);
  30985 }
  30986 
  30987 static JSValue js_import_meta(JSContext *ctx)
  30988 {
  30989     JSAtom filename;
  30990     JSModuleDef *m;
  30991 
  30992     filename = JS_GetScriptOrModuleName(ctx, 0);
  30993     if (filename == JS_ATOM_NULL)
  30994         goto fail;
  30995 
  30996     /* XXX: inefficient, need to add a module or script pointer in
  30997        JSFunctionBytecode */
  30998     m = js_find_loaded_module(ctx, filename);
  30999     JS_FreeAtom(ctx, filename);
  31000     if (!m) {
  31001     fail:
  31002         JS_ThrowTypeError(ctx, "import.meta not supported in this context");
  31003         return JS_EXCEPTION;
  31004     }
  31005     return JS_GetImportMeta(ctx, m);
  31006 }
  31007 
  31008 static JSValue JS_NewModuleValue(JSContext *ctx, JSModuleDef *m)
  31009 {
  31010     return JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
  31011 }
  31012 
  31013 static JSValue js_load_module_rejected(JSContext *ctx, JSValueConst this_val,
  31014                                        int argc, JSValueConst *argv, int magic, JSValue *func_data)
  31015 {
  31016     JSValueConst *resolving_funcs = (JSValueConst *)func_data;
  31017     JSValueConst error;
  31018     JSValue ret;
  31019 
  31020     /* XXX: check if the test is necessary */
  31021     if (argc >= 1)
  31022         error = argv[0];
  31023     else
  31024         error = JS_UNDEFINED;
  31025     ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
  31026                   1, &error);
  31027     JS_FreeValue(ctx, ret);
  31028     return JS_UNDEFINED;
  31029 }
  31030 
  31031 static JSValue js_load_module_fulfilled(JSContext *ctx, JSValueConst this_val,
  31032                                         int argc, JSValueConst *argv, int magic, JSValue *func_data)
  31033 {
  31034     JSValueConst *resolving_funcs = (JSValueConst *)func_data;
  31035     JSModuleDef *m = JS_VALUE_GET_PTR(func_data[2]);
  31036     JSValue ret, ns;
  31037 
  31038     /* return the module namespace */
  31039     ns = JS_GetModuleNamespace(ctx, m);
  31040     if (JS_IsException(ns)) {
  31041         JSValue err = JS_GetException(ctx);
  31042         js_load_module_rejected(ctx, JS_UNDEFINED, 1, (JSValueConst *)&err, 0, func_data);
  31043         return JS_UNDEFINED;
  31044     }
  31045     ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED,
  31046                    1, (JSValueConst *)&ns);
  31047     JS_FreeValue(ctx, ret);
  31048     JS_FreeValue(ctx, ns);
  31049     return JS_UNDEFINED;
  31050 }
  31051 
  31052 static void JS_LoadModuleInternal(JSContext *ctx, const char *basename,
  31053                                   const char *filename,
  31054                                   JSValueConst *resolving_funcs,
  31055                                   JSValueConst attributes)
  31056 {
  31057     JSValue evaluate_promise;
  31058     JSModuleDef *m;
  31059     JSValue ret, err, func_obj, evaluate_resolving_funcs[2];
  31060     JSValueConst func_data[3];
  31061 
  31062     m = js_host_resolve_imported_module(ctx, basename, filename, attributes);
  31063     if (!m)
  31064         goto fail;
  31065 
  31066     if (js_resolve_module(ctx, m) < 0) {
  31067         js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);
  31068         goto fail;
  31069     }
  31070 
  31071     /* Evaluate the module code */
  31072     func_obj = JS_NewModuleValue(ctx, m);
  31073     evaluate_promise = JS_EvalFunction(ctx, func_obj);
  31074     if (JS_IsException(evaluate_promise)) {
  31075     fail:
  31076         err = JS_GetException(ctx);
  31077         ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
  31078                       1, (JSValueConst *)&err);
  31079         JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
  31080         JS_FreeValue(ctx, err);
  31081         return;
  31082     }
  31083 
  31084     func_obj = JS_NewModuleValue(ctx, m);
  31085     func_data[0] = resolving_funcs[0];
  31086     func_data[1] = resolving_funcs[1];
  31087     func_data[2] = func_obj;
  31088     evaluate_resolving_funcs[0] = JS_NewCFunctionData(ctx, js_load_module_fulfilled, 0, 0, 3, func_data);
  31089     evaluate_resolving_funcs[1] = JS_NewCFunctionData(ctx, js_load_module_rejected, 0, 0, 3, func_data);
  31090     JS_FreeValue(ctx, func_obj);
  31091     ret = js_promise_then(ctx, evaluate_promise, 2, (JSValueConst *)evaluate_resolving_funcs);
  31092     JS_FreeValue(ctx, ret);
  31093     JS_FreeValue(ctx, evaluate_resolving_funcs[0]);
  31094     JS_FreeValue(ctx, evaluate_resolving_funcs[1]);
  31095     JS_FreeValue(ctx, evaluate_promise);
  31096 }
  31097 
  31098 /* Return a promise or an exception in case of memory error. Used by
  31099    os.Worker() */
  31100 JSValue JS_LoadModule(JSContext *ctx, const char *basename,
  31101                       const char *filename)
  31102 {
  31103     JSValue promise, resolving_funcs[2];
  31104 
  31105     promise = JS_NewPromiseCapability(ctx, resolving_funcs);
  31106     if (JS_IsException(promise))
  31107         return JS_EXCEPTION;
  31108     JS_LoadModuleInternal(ctx, basename, filename,
  31109                           (JSValueConst *)resolving_funcs, JS_UNDEFINED);
  31110     JS_FreeValue(ctx, resolving_funcs[0]);
  31111     JS_FreeValue(ctx, resolving_funcs[1]);
  31112     return promise;
  31113 }
  31114 
  31115 static JSValue js_dynamic_import_job(JSContext *ctx,
  31116                                      int argc, JSValueConst *argv)
  31117 {
  31118     JSValueConst *resolving_funcs = argv;
  31119     JSValueConst basename_val = argv[2];
  31120     JSValueConst specifier = argv[3];
  31121     JSValueConst attributes = argv[4];
  31122     const char *basename = NULL, *filename;
  31123     JSValue ret, err;
  31124 
  31125     if (!JS_IsString(basename_val)) {
  31126         JS_ThrowTypeError(ctx, "no function filename for import()");
  31127         goto exception;
  31128     }
  31129     basename = JS_ToCString(ctx, basename_val);
  31130     if (!basename)
  31131         goto exception;
  31132 
  31133     filename = JS_ToCString(ctx, specifier);
  31134     if (!filename)
  31135         goto exception;
  31136 
  31137     JS_LoadModuleInternal(ctx, basename, filename,
  31138                           resolving_funcs, attributes);
  31139     JS_FreeCString(ctx, filename);
  31140     JS_FreeCString(ctx, basename);
  31141     return JS_UNDEFINED;
  31142  exception:
  31143     err = JS_GetException(ctx);
  31144     ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
  31145                    1, (JSValueConst *)&err);
  31146     JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
  31147     JS_FreeValue(ctx, err);
  31148     JS_FreeCString(ctx, basename);
  31149     return JS_UNDEFINED;
  31150 }
  31151 
  31152 static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier, JSValueConst options)
  31153 {
  31154     JSAtom basename;
  31155     JSValue promise, resolving_funcs[2], basename_val, err, ret;
  31156     JSValue specifier_str = JS_UNDEFINED, attributes = JS_UNDEFINED, attributes_obj = JS_UNDEFINED;
  31157     JSValueConst args[5];
  31158 
  31159     basename = JS_GetScriptOrModuleName(ctx, 0);
  31160     if (basename == JS_ATOM_NULL)
  31161         basename_val = JS_NULL;
  31162     else
  31163         basename_val = JS_AtomToValue(ctx, basename);
  31164     JS_FreeAtom(ctx, basename);
  31165     if (JS_IsException(basename_val))
  31166         return basename_val;
  31167 
  31168     promise = JS_NewPromiseCapability(ctx, resolving_funcs);
  31169     if (JS_IsException(promise)) {
  31170         JS_FreeValue(ctx, basename_val);
  31171         return promise;
  31172     }
  31173 
  31174     /* the string conversion must occur here */
  31175     specifier_str = JS_ToString(ctx, specifier);
  31176     if (JS_IsException(specifier_str))
  31177         goto exception;
  31178     
  31179     if (!JS_IsUndefined(options)) {
  31180         if (!JS_IsObject(options)) {
  31181             JS_ThrowTypeError(ctx, "options must be an object");
  31182             goto exception;
  31183         }
  31184         attributes_obj = JS_GetProperty(ctx, options, JS_ATOM_with);
  31185         if (JS_IsException(attributes_obj))
  31186             goto exception;
  31187         if (!JS_IsUndefined(attributes_obj)) {
  31188             JSPropertyEnum *atoms;
  31189             uint32_t atoms_len, i;
  31190             JSValue val;
  31191             
  31192             if (!JS_IsObject(attributes_obj)) {
  31193                 JS_ThrowTypeError(ctx, "options.with must be an object");
  31194                 goto exception;
  31195             }
  31196             attributes = JS_NewObjectProto(ctx, JS_NULL);
  31197             if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &atoms_len, JS_VALUE_GET_OBJ(attributes_obj),
  31198                                                JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) {
  31199                 goto exception;
  31200             }
  31201             for(i = 0; i < atoms_len; i++) {
  31202                 val = JS_GetProperty(ctx, attributes_obj, atoms[i].atom);
  31203                 if (JS_IsException(val))
  31204                     goto exception1;
  31205                 if (!JS_IsString(val)) {
  31206                     JS_FreeValue(ctx, val);
  31207                     JS_ThrowTypeError(ctx, "module attribute values must be strings");
  31208                     goto exception1;
  31209                 }
  31210                 if (JS_DefinePropertyValue(ctx, attributes,  atoms[i].atom, val,
  31211                                            JS_PROP_C_W_E) < 0) {
  31212                 exception1:
  31213                     JS_FreePropertyEnum(ctx, atoms, atoms_len);
  31214                     goto exception;
  31215                 }
  31216             }
  31217             JS_FreePropertyEnum(ctx, atoms, atoms_len);
  31218             if (ctx->rt->module_check_attrs &&
  31219                 ctx->rt->module_check_attrs(ctx, ctx->rt->module_loader_opaque, attributes) < 0) {
  31220                 goto exception;
  31221             }
  31222             JS_FreeValue(ctx, attributes_obj);
  31223         }
  31224     }
  31225 
  31226     args[0] = resolving_funcs[0];
  31227     args[1] = resolving_funcs[1];
  31228     args[2] = basename_val;
  31229     args[3] = specifier_str;
  31230     args[4] = attributes;
  31231     
  31232     /* cannot run JS_LoadModuleInternal synchronously because it would
  31233        cause an unexpected recursion in js_evaluate_module() */
  31234     JS_EnqueueJob(ctx, js_dynamic_import_job, 5, args);
  31235  done:
  31236     JS_FreeValue(ctx, basename_val);
  31237     JS_FreeValue(ctx, resolving_funcs[0]);
  31238     JS_FreeValue(ctx, resolving_funcs[1]);
  31239     JS_FreeValue(ctx, specifier_str);
  31240     JS_FreeValue(ctx, attributes);
  31241     return promise;
  31242  exception:
  31243     JS_FreeValue(ctx, attributes_obj);
  31244     err = JS_GetException(ctx);
  31245     ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
  31246                    1, (JSValueConst *)&err);
  31247     JS_FreeValue(ctx, ret);
  31248     JS_FreeValue(ctx, err);
  31249     goto done;
  31250 }
  31251 
  31252 static void js_set_module_evaluated(JSContext *ctx, JSModuleDef *m)
  31253 {
  31254     m->status = JS_MODULE_STATUS_EVALUATED;
  31255     if (!JS_IsUndefined(m->promise)) {
  31256         JSValue value, ret_val;
  31257         assert(m->cycle_root == m);
  31258         value = JS_UNDEFINED;
  31259         ret_val = JS_Call(ctx, m->resolving_funcs[0], JS_UNDEFINED,
  31260                           1, (JSValueConst *)&value);
  31261         JS_FreeValue(ctx, ret_val);
  31262     }
  31263 }
  31264 
  31265 typedef struct {
  31266     JSModuleDef **tab;
  31267     int count;
  31268     int size;
  31269 } ExecModuleList;
  31270 
  31271 /* XXX: slow. Could use a linked list instead of ExecModuleList */
  31272 static BOOL find_in_exec_module_list(ExecModuleList *exec_list, JSModuleDef *m)
  31273 {
  31274     int i;
  31275     for(i = 0; i < exec_list->count; i++) {
  31276         if (exec_list->tab[i] == m)
  31277             return TRUE;
  31278     }
  31279     return FALSE;
  31280 }
  31281 
  31282 static int gather_available_ancestors(JSContext *ctx, JSModuleDef *module,
  31283                                       ExecModuleList *exec_list)
  31284 {
  31285     int i;
  31286 
  31287     if (js_check_stack_overflow(ctx->rt, 0)) {
  31288         JS_ThrowStackOverflow(ctx);
  31289         return -1;
  31290     }
  31291     for(i = 0; i < module->async_parent_modules_count; i++) {
  31292         JSModuleDef *m = module->async_parent_modules[i];
  31293         if (!find_in_exec_module_list(exec_list, m) &&
  31294             !m->cycle_root->eval_has_exception) {
  31295             assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC);
  31296             assert(!m->eval_has_exception);
  31297             assert(m->async_evaluation);
  31298             assert(m->pending_async_dependencies > 0);
  31299             m->pending_async_dependencies--;
  31300             if (m->pending_async_dependencies == 0) {
  31301                 if (js_resize_array(ctx, (void **)&exec_list->tab, sizeof(exec_list->tab[0]), &exec_list->size, exec_list->count + 1)) {
  31302                     return -1;
  31303                 }
  31304                 exec_list->tab[exec_list->count++] = m;
  31305                 if (!m->has_tla) {
  31306                     if (gather_available_ancestors(ctx, m, exec_list))
  31307                         return -1;
  31308                 }
  31309             }
  31310         }
  31311     }
  31312     return 0;
  31313 }
  31314 
  31315 static int exec_module_list_cmp(const void *p1, const void *p2, void *opaque)
  31316 {
  31317     JSModuleDef *m1 = *(JSModuleDef **)p1;
  31318     JSModuleDef *m2 = *(JSModuleDef **)p2;
  31319     return (m1->async_evaluation_timestamp > m2->async_evaluation_timestamp) -
  31320         (m1->async_evaluation_timestamp < m2->async_evaluation_timestamp);
  31321 }
  31322 
  31323 static int js_execute_async_module(JSContext *ctx, JSModuleDef *m);
  31324 static int js_execute_sync_module(JSContext *ctx, JSModuleDef *m,
  31325                                   JSValue *pvalue);
  31326 #ifdef DUMP_MODULE_EXEC
  31327 static void js_dump_module(JSContext *ctx, const char *str, JSModuleDef *m)
  31328 {
  31329     char buf1[ATOM_GET_STR_BUF_SIZE];
  31330     static const char *module_status_str[] = { "unlinked", "linking", "linked", "evaluating", "evaluating_async", "evaluated" };
  31331     printf("%s: %s status=%s\n", str, JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name), module_status_str[m->status]);
  31332 }
  31333 #endif
  31334 
  31335 static JSValue js_async_module_execution_rejected(JSContext *ctx, JSValueConst this_val,
  31336                                                   int argc, JSValueConst *argv, int magic, JSValue *func_data)
  31337 {
  31338     JSModuleDef *module = JS_VALUE_GET_PTR(func_data[0]);
  31339     JSValueConst error = argv[0];
  31340     int i;
  31341 
  31342 #ifdef DUMP_MODULE_EXEC
  31343     js_dump_module(ctx, __func__, module);
  31344 #endif
  31345     if (js_check_stack_overflow(ctx->rt, 0))
  31346         return JS_ThrowStackOverflow(ctx);
  31347 
  31348     if (module->status == JS_MODULE_STATUS_EVALUATED) {
  31349         assert(module->eval_has_exception);
  31350         return JS_UNDEFINED;
  31351     }
  31352 
  31353     assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC);
  31354     assert(!module->eval_has_exception);
  31355     assert(module->async_evaluation);
  31356 
  31357     module->eval_has_exception = TRUE;
  31358     module->eval_exception = JS_DupValue(ctx, error);
  31359     module->status = JS_MODULE_STATUS_EVALUATED;
  31360     module->async_evaluation = FALSE;
  31361 
  31362     if (!JS_IsUndefined(module->promise)) {
  31363         JSValue ret_val;
  31364         assert(module->cycle_root == module);
  31365         ret_val = JS_Call(ctx, module->resolving_funcs[1], JS_UNDEFINED,
  31366                           1, &error);
  31367         JS_FreeValue(ctx, ret_val);
  31368     }
  31369 
  31370     for(i = 0; i < module->async_parent_modules_count; i++) {
  31371         JSModuleDef *m = module->async_parent_modules[i];
  31372         JSValue m_obj = JS_NewModuleValue(ctx, m);
  31373         js_async_module_execution_rejected(ctx, JS_UNDEFINED, 1, &error, 0,
  31374                                            &m_obj);
  31375         JS_FreeValue(ctx, m_obj);
  31376     }
  31377     return JS_UNDEFINED;
  31378 }
  31379 
  31380 static JSValue js_async_module_execution_fulfilled(JSContext *ctx, JSValueConst this_val,
  31381                                                    int argc, JSValueConst *argv, int magic, JSValue *func_data)
  31382 {
  31383     JSModuleDef *module = JS_VALUE_GET_PTR(func_data[0]);
  31384     ExecModuleList exec_list_s, *exec_list = &exec_list_s;
  31385     int i;
  31386 
  31387 #ifdef DUMP_MODULE_EXEC
  31388     js_dump_module(ctx, __func__, module);
  31389 #endif
  31390     if (module->status == JS_MODULE_STATUS_EVALUATED) {
  31391         assert(module->eval_has_exception);
  31392         return JS_UNDEFINED;
  31393     }
  31394     assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC);
  31395     assert(!module->eval_has_exception);
  31396     assert(module->async_evaluation);
  31397     module->async_evaluation = FALSE;
  31398     js_set_module_evaluated(ctx, module);
  31399 
  31400     exec_list->tab = NULL;
  31401     exec_list->count = 0;
  31402     exec_list->size = 0;
  31403 
  31404     if (gather_available_ancestors(ctx, module, exec_list) < 0) {
  31405         js_free(ctx, exec_list->tab);
  31406         return JS_EXCEPTION;
  31407     }
  31408 
  31409     /* sort by increasing async_evaluation timestamp */
  31410     rqsort(exec_list->tab, exec_list->count, sizeof(exec_list->tab[0]),
  31411            exec_module_list_cmp, NULL);
  31412 
  31413     for(i = 0; i < exec_list->count; i++) {
  31414         JSModuleDef *m = exec_list->tab[i];
  31415 #ifdef DUMP_MODULE_EXEC
  31416         printf("  %d/%d", i, exec_list->count); js_dump_module(ctx, "", m);
  31417 #endif
  31418         if (m->status == JS_MODULE_STATUS_EVALUATED) {
  31419             assert(m->eval_has_exception);
  31420         } else if (m->has_tla) {
  31421             js_execute_async_module(ctx, m);
  31422         } else {
  31423             JSValue error;
  31424             if (js_execute_sync_module(ctx, m, &error) < 0) {
  31425                 JSValue m_obj = JS_NewModuleValue(ctx, m);
  31426                 js_async_module_execution_rejected(ctx, JS_UNDEFINED,
  31427                                                    1, (JSValueConst *)&error, 0,
  31428                                                    &m_obj);
  31429                 JS_FreeValue(ctx, m_obj);
  31430                 JS_FreeValue(ctx, error);
  31431             } else {
  31432                 m->async_evaluation = FALSE;
  31433                 js_set_module_evaluated(ctx, m);
  31434             }
  31435         }
  31436     }
  31437     js_free(ctx, exec_list->tab);
  31438     return JS_UNDEFINED;
  31439 }
  31440 
  31441 static int js_execute_async_module(JSContext *ctx, JSModuleDef *m)
  31442 {
  31443     JSValue promise, m_obj;
  31444     JSValue resolve_funcs[2], ret_val;
  31445 #ifdef DUMP_MODULE_EXEC
  31446     js_dump_module(ctx, __func__, m);
  31447 #endif
  31448     promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0);
  31449     if (JS_IsException(promise))
  31450         return -1;
  31451     m_obj = JS_NewModuleValue(ctx, m);
  31452     resolve_funcs[0] = JS_NewCFunctionData(ctx, js_async_module_execution_fulfilled, 0, 0, 1, (JSValueConst *)&m_obj);
  31453     resolve_funcs[1] = JS_NewCFunctionData(ctx, js_async_module_execution_rejected, 0, 0, 1, (JSValueConst *)&m_obj);
  31454     ret_val = js_promise_then(ctx, promise, 2, (JSValueConst *)resolve_funcs);
  31455     JS_FreeValue(ctx, ret_val);
  31456     JS_FreeValue(ctx, m_obj);
  31457     JS_FreeValue(ctx, resolve_funcs[0]);
  31458     JS_FreeValue(ctx, resolve_funcs[1]);
  31459     JS_FreeValue(ctx, promise);
  31460     return 0;
  31461 }
  31462 
  31463 /* return < 0 in case of exception. *pvalue contains the exception. */
  31464 static int js_execute_sync_module(JSContext *ctx, JSModuleDef *m,
  31465                                   JSValue *pvalue)
  31466 {
  31467 #ifdef DUMP_MODULE_EXEC
  31468     js_dump_module(ctx, __func__, m);
  31469 #endif
  31470     if (m->init_func) {
  31471         /* C module init : no asynchronous execution */
  31472         if (m->init_func(ctx, m) < 0)
  31473             goto fail;
  31474     } else {
  31475         JSValue promise;
  31476         JSPromiseStateEnum state;
  31477 
  31478         promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0);
  31479         if (JS_IsException(promise))
  31480             goto fail;
  31481         state = JS_PromiseState(ctx, promise);
  31482         if (state == JS_PROMISE_FULFILLED) {
  31483             JS_FreeValue(ctx, promise);
  31484         } else if (state == JS_PROMISE_REJECTED) {
  31485             *pvalue = JS_PromiseResult(ctx, promise);
  31486             JS_FreeValue(ctx, promise);
  31487             return -1;
  31488         } else {
  31489             JS_FreeValue(ctx, promise);
  31490             JS_ThrowTypeError(ctx, "promise is pending");
  31491         fail:
  31492             *pvalue = JS_GetException(ctx);
  31493             return -1;
  31494         }
  31495     }
  31496     *pvalue = JS_UNDEFINED;
  31497     return 0;
  31498 }
  31499 
  31500 /* spec: InnerModuleEvaluation. Return (index, JS_UNDEFINED) or (-1,
  31501    exception) */
  31502 static int js_inner_module_evaluation(JSContext *ctx, JSModuleDef *m,
  31503                                       int index, JSModuleDef **pstack_top,
  31504                                       JSValue *pvalue)
  31505 {
  31506     JSModuleDef *m1;
  31507     int i;
  31508 
  31509 #ifdef DUMP_MODULE_EXEC
  31510     js_dump_module(ctx, __func__, m);
  31511 #endif
  31512 
  31513     if (js_check_stack_overflow(ctx->rt, 0)) {
  31514         JS_ThrowStackOverflow(ctx);
  31515         *pvalue = JS_GetException(ctx);
  31516         return -1;
  31517     }
  31518 
  31519     if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
  31520         m->status == JS_MODULE_STATUS_EVALUATED) {
  31521         if (m->eval_has_exception) {
  31522             *pvalue = JS_DupValue(ctx, m->eval_exception);
  31523             return -1;
  31524         } else {
  31525             *pvalue = JS_UNDEFINED;
  31526             return index;
  31527         }
  31528     }
  31529     if (m->status == JS_MODULE_STATUS_EVALUATING) {
  31530         *pvalue = JS_UNDEFINED;
  31531         return index;
  31532     }
  31533     assert(m->status == JS_MODULE_STATUS_LINKED);
  31534 
  31535     m->status = JS_MODULE_STATUS_EVALUATING;
  31536     m->dfs_index = index;
  31537     m->dfs_ancestor_index = index;
  31538     m->pending_async_dependencies = 0;
  31539     index++;
  31540     /* push 'm' on stack */
  31541     m->stack_prev = *pstack_top;
  31542     *pstack_top = m;
  31543 
  31544     for(i = 0; i < m->req_module_entries_count; i++) {
  31545         JSReqModuleEntry *rme = &m->req_module_entries[i];
  31546         m1 = rme->module;
  31547         index = js_inner_module_evaluation(ctx, m1, index, pstack_top, pvalue);
  31548         if (index < 0)
  31549             return -1;
  31550         assert(m1->status == JS_MODULE_STATUS_EVALUATING ||
  31551                m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
  31552                m1->status == JS_MODULE_STATUS_EVALUATED);
  31553         if (m1->status == JS_MODULE_STATUS_EVALUATING) {
  31554             m->dfs_ancestor_index = min_int(m->dfs_ancestor_index,
  31555                                             m1->dfs_ancestor_index);
  31556         } else {
  31557             m1 = m1->cycle_root;
  31558             assert(m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
  31559                    m1->status == JS_MODULE_STATUS_EVALUATED);
  31560             if (m1->eval_has_exception) {
  31561                 *pvalue = JS_DupValue(ctx, m1->eval_exception);
  31562                 return -1;
  31563             }
  31564         }
  31565         if (m1->async_evaluation) {
  31566             m->pending_async_dependencies++;
  31567             if (js_resize_array(ctx, (void **)&m1->async_parent_modules, sizeof(m1->async_parent_modules[0]), &m1->async_parent_modules_size, m1->async_parent_modules_count + 1)) {
  31568                 *pvalue = JS_GetException(ctx);
  31569                 return -1;
  31570             }
  31571             m1->async_parent_modules[m1->async_parent_modules_count++] = m;
  31572         }
  31573     }
  31574 
  31575     if (m->pending_async_dependencies > 0) {
  31576         assert(!m->async_evaluation);
  31577         m->async_evaluation = TRUE;
  31578         m->async_evaluation_timestamp =
  31579             ctx->rt->module_async_evaluation_next_timestamp++;
  31580     } else if (m->has_tla) {
  31581         assert(!m->async_evaluation);
  31582         m->async_evaluation = TRUE;
  31583         m->async_evaluation_timestamp =
  31584             ctx->rt->module_async_evaluation_next_timestamp++;
  31585         js_execute_async_module(ctx, m);
  31586     } else {
  31587         if (js_execute_sync_module(ctx, m, pvalue) < 0)
  31588             return -1;
  31589     }
  31590 
  31591     assert(m->dfs_ancestor_index <= m->dfs_index);
  31592     if (m->dfs_index == m->dfs_ancestor_index) {
  31593         for(;;) {
  31594             /* pop m1 from stack */
  31595             m1 = *pstack_top;
  31596             *pstack_top = m1->stack_prev;
  31597             if (!m1->async_evaluation) {
  31598                 m1->status = JS_MODULE_STATUS_EVALUATED;
  31599             } else {
  31600                 m1->status = JS_MODULE_STATUS_EVALUATING_ASYNC;
  31601             }
  31602             /* spec bug: cycle_root must be assigned before the test */
  31603             m1->cycle_root = m;
  31604             if (m1 == m)
  31605                 break;
  31606         }
  31607     }
  31608     *pvalue = JS_UNDEFINED;
  31609     return index;
  31610 }
  31611 
  31612 /* Run the <eval> function of the module and of all its requested
  31613    modules. Return a promise or an exception. */
  31614 static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m)
  31615 {
  31616     JSModuleDef *m1, *stack_top;
  31617     JSValue ret_val, result;
  31618 
  31619 #ifdef DUMP_MODULE_EXEC
  31620     js_dump_module(ctx, __func__, m);
  31621 #endif
  31622     assert(m->status == JS_MODULE_STATUS_LINKED ||
  31623            m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
  31624            m->status == JS_MODULE_STATUS_EVALUATED);
  31625     if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
  31626         m->status == JS_MODULE_STATUS_EVALUATED) {
  31627         m = m->cycle_root;
  31628     }
  31629     /* a promise may be created only on the cycle_root of a cycle */
  31630     if (!JS_IsUndefined(m->promise))
  31631         return JS_DupValue(ctx, m->promise);
  31632     m->promise = JS_NewPromiseCapability(ctx, m->resolving_funcs);
  31633     if (JS_IsException(m->promise))
  31634         return JS_EXCEPTION;
  31635 
  31636     stack_top = NULL;
  31637     if (js_inner_module_evaluation(ctx, m, 0, &stack_top, &result) < 0) {
  31638         while (stack_top != NULL) {
  31639             m1 = stack_top;
  31640             assert(m1->status == JS_MODULE_STATUS_EVALUATING);
  31641             m1->status = JS_MODULE_STATUS_EVALUATED;
  31642             m1->eval_has_exception = TRUE;
  31643             m1->eval_exception = JS_DupValue(ctx, result);
  31644             m1->cycle_root = m; /* spec bug: should be present */
  31645             stack_top = m1->stack_prev;
  31646         }
  31647         JS_FreeValue(ctx, result);
  31648         assert(m->status == JS_MODULE_STATUS_EVALUATED);
  31649         assert(m->eval_has_exception);
  31650         ret_val = JS_Call(ctx, m->resolving_funcs[1], JS_UNDEFINED,
  31651                           1, (JSValueConst *)&m->eval_exception);
  31652         JS_FreeValue(ctx, ret_val);
  31653     } else {
  31654 #ifdef DUMP_MODULE_EXEC
  31655         js_dump_module(ctx, "  done", m);
  31656 #endif
  31657         assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
  31658                m->status == JS_MODULE_STATUS_EVALUATED);
  31659         assert(!m->eval_has_exception);
  31660         if (!m->async_evaluation) {
  31661             JSValue value;
  31662             assert(m->status == JS_MODULE_STATUS_EVALUATED);
  31663             value = JS_UNDEFINED;
  31664             ret_val = JS_Call(ctx, m->resolving_funcs[0], JS_UNDEFINED,
  31665                               1, (JSValueConst *)&value);
  31666             JS_FreeValue(ctx, ret_val);
  31667         }
  31668         assert(stack_top == NULL);
  31669     }
  31670     return JS_DupValue(ctx, m->promise);
  31671 }
  31672 
  31673 static __exception int js_parse_with_clause(JSParseState *s, JSReqModuleEntry *rme)
  31674 {
  31675     JSContext *ctx = s->ctx;
  31676     JSAtom key;
  31677     int ret;
  31678     const uint8_t *key_token_ptr;
  31679     
  31680     if (next_token(s))
  31681         return -1;
  31682     if (js_parse_expect(s, '{'))
  31683         return -1;
  31684     while (s->token.val != '}') {
  31685         key_token_ptr = s->token.ptr;
  31686         if (s->token.val == TOK_STRING) {
  31687             key = JS_ValueToAtom(ctx, s->token.u.str.str);
  31688             if (key == JS_ATOM_NULL)
  31689                 return -1;
  31690         } else {
  31691             if (!token_is_ident(s->token.val)) {
  31692                 js_parse_error(s, "identifier expected");
  31693                 return -1;
  31694             }
  31695             key = JS_DupAtom(ctx, s->token.u.ident.atom);
  31696         }
  31697         if (next_token(s))
  31698             return -1;
  31699         if (js_parse_expect(s, ':')) {
  31700             JS_FreeAtom(ctx, key);
  31701             return -1;
  31702         }
  31703         if (s->token.val != TOK_STRING) {
  31704             js_parse_error_pos(s, key_token_ptr, "string expected");
  31705             return -1;
  31706         }
  31707         if (JS_IsUndefined(rme->attributes)) {
  31708             JSValue attributes = JS_NewObjectProto(ctx, JS_NULL);
  31709             if (JS_IsException(attributes)) {
  31710                 JS_FreeAtom(ctx, key);
  31711                 return -1;
  31712             }
  31713             rme->attributes = attributes;
  31714         }
  31715         ret = JS_HasProperty(ctx, rme->attributes, key);
  31716         if (ret != 0) {
  31717             JS_FreeAtom(ctx, key);
  31718             if (ret < 0)
  31719                 return -1;
  31720             else
  31721                 return js_parse_error(s, "duplicate with key");
  31722         }
  31723         ret = JS_DefinePropertyValue(ctx, rme->attributes, key,
  31724                                      JS_DupValue(ctx, s->token.u.str.str), JS_PROP_C_W_E);
  31725         JS_FreeAtom(ctx, key);
  31726         if (ret < 0)
  31727             return -1;
  31728         if (next_token(s))
  31729             return -1;
  31730         if (s->token.val != ',')
  31731             break;
  31732         if (next_token(s))
  31733             return -1;
  31734     }
  31735     if (!JS_IsUndefined(rme->attributes) &&
  31736         ctx->rt->module_check_attrs &&
  31737         ctx->rt->module_check_attrs(ctx, ctx->rt->module_loader_opaque, rme->attributes) < 0) {
  31738         return -1;
  31739     }
  31740     return js_parse_expect(s, '}');
  31741 }
  31742 
  31743 /* return the module index in m->req_module_entries[] or < 0 if error */
  31744 static __exception int js_parse_from_clause(JSParseState *s, JSModuleDef *m)
  31745 {
  31746     JSAtom module_name;
  31747     int idx;
  31748 
  31749     if (!token_is_pseudo_keyword(s, JS_ATOM_from)) {
  31750         js_parse_error(s, "from clause expected");
  31751         return -1;
  31752     }
  31753     if (next_token(s))
  31754         return -1;
  31755     if (s->token.val != TOK_STRING) {
  31756         js_parse_error(s, "string expected");
  31757         return -1;
  31758     }
  31759     module_name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
  31760     if (module_name == JS_ATOM_NULL)
  31761         return -1;
  31762     if (next_token(s)) {
  31763         JS_FreeAtom(s->ctx, module_name);
  31764         return -1;
  31765     }
  31766 
  31767     idx = add_req_module_entry(s->ctx, m, module_name);
  31768     JS_FreeAtom(s->ctx, module_name);
  31769     if (idx < 0)
  31770         return -1;
  31771     if (s->token.val == TOK_WITH) {
  31772         if (js_parse_with_clause(s, &m->req_module_entries[idx]))
  31773             return -1;
  31774     }
  31775     return idx;
  31776 }
  31777 
  31778 static __exception int js_parse_export(JSParseState *s)
  31779 {
  31780     JSContext *ctx = s->ctx;
  31781     JSModuleDef *m = s->cur_func->module;
  31782     JSAtom local_name, export_name;
  31783     int first_export, idx, i, tok;
  31784     JSExportEntry *me;
  31785 
  31786     if (next_token(s))
  31787         return -1;
  31788 
  31789     tok = s->token.val;
  31790     if (tok == TOK_CLASS) {
  31791         return js_parse_class(s, FALSE, JS_PARSE_EXPORT_NAMED);
  31792     } else if (tok == TOK_FUNCTION ||
  31793                (token_is_pseudo_keyword(s, JS_ATOM_async) &&
  31794                 peek_token(s, TRUE) == TOK_FUNCTION)) {
  31795         return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT,
  31796                                        JS_FUNC_NORMAL, JS_ATOM_NULL,
  31797                                        s->token.ptr,
  31798                                        JS_PARSE_EXPORT_NAMED, NULL);
  31799     }
  31800 
  31801     if (next_token(s))
  31802         return -1;
  31803 
  31804     switch(tok) {
  31805     case '{':
  31806         first_export = m->export_entries_count;
  31807         while (s->token.val != '}') {
  31808             if (!token_is_ident(s->token.val)) {
  31809                 js_parse_error(s, "identifier expected");
  31810                 return -1;
  31811             }
  31812             local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
  31813             export_name = JS_ATOM_NULL;
  31814             if (next_token(s))
  31815                 goto fail;
  31816             if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
  31817                 if (next_token(s))
  31818                     goto fail;
  31819                 if (s->token.val == TOK_STRING) {
  31820                     if (js_string_find_invalid_codepoint(JS_VALUE_GET_STRING(s->token.u.str.str)) >= 0) {
  31821                         js_parse_error(s, "contains unpaired surrogate");
  31822                         goto fail;
  31823                     }
  31824                     export_name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
  31825                     if (export_name == JS_ATOM_NULL)
  31826                         goto fail;
  31827                 } else {
  31828                     if (!token_is_ident(s->token.val)) {
  31829                         js_parse_error(s, "identifier expected");
  31830                         goto fail;
  31831                     }
  31832                     export_name = JS_DupAtom(ctx, s->token.u.ident.atom);
  31833                 }
  31834                 if (next_token(s)) {
  31835                 fail:
  31836                     JS_FreeAtom(ctx, local_name);
  31837                 fail1:
  31838                     JS_FreeAtom(ctx, export_name);
  31839                     return -1;
  31840                 }
  31841             } else {
  31842                 export_name = JS_DupAtom(ctx, local_name);
  31843             }
  31844             me = add_export_entry(s, m, local_name, export_name,
  31845                                   JS_EXPORT_TYPE_LOCAL);
  31846             JS_FreeAtom(ctx, local_name);
  31847             JS_FreeAtom(ctx, export_name);
  31848             if (!me)
  31849                 return -1;
  31850             if (s->token.val != ',')
  31851                 break;
  31852             if (next_token(s))
  31853                 return -1;
  31854         }
  31855         if (js_parse_expect(s, '}'))
  31856             return -1;
  31857         if (token_is_pseudo_keyword(s, JS_ATOM_from)) {
  31858             idx = js_parse_from_clause(s, m);
  31859             if (idx < 0)
  31860                 return -1;
  31861             for(i = first_export; i < m->export_entries_count; i++) {
  31862                 me = &m->export_entries[i];
  31863                 me->export_type = JS_EXPORT_TYPE_INDIRECT;
  31864                 me->u.req_module_idx = idx;
  31865             }
  31866         }
  31867         break;
  31868     case '*':
  31869         if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
  31870             /* export ns from */
  31871             if (next_token(s))
  31872                 return -1;
  31873             if (!token_is_ident(s->token.val)) {
  31874                 js_parse_error(s, "identifier expected");
  31875                 return -1;
  31876             }
  31877             export_name = JS_DupAtom(ctx, s->token.u.ident.atom);
  31878             if (next_token(s))
  31879                 goto fail1;
  31880             idx = js_parse_from_clause(s, m);
  31881             if (idx < 0)
  31882                 goto fail1;
  31883             me = add_export_entry(s, m, JS_ATOM__star_, export_name,
  31884                                   JS_EXPORT_TYPE_INDIRECT);
  31885             JS_FreeAtom(ctx, export_name);
  31886             if (!me)
  31887                 return -1;
  31888             me->u.req_module_idx = idx;
  31889         } else {
  31890             idx = js_parse_from_clause(s, m);
  31891             if (idx < 0)
  31892                 return -1;
  31893             if (add_star_export_entry(ctx, m, idx) < 0)
  31894                 return -1;
  31895         }
  31896         break;
  31897     case TOK_DEFAULT:
  31898         if (s->token.val == TOK_CLASS) {
  31899             return js_parse_class(s, FALSE, JS_PARSE_EXPORT_DEFAULT);
  31900         } else if (s->token.val == TOK_FUNCTION ||
  31901                    (token_is_pseudo_keyword(s, JS_ATOM_async) &&
  31902                     peek_token(s, TRUE) == TOK_FUNCTION)) {
  31903             return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT,
  31904                                            JS_FUNC_NORMAL, JS_ATOM_NULL,
  31905                                            s->token.ptr,
  31906                                            JS_PARSE_EXPORT_DEFAULT, NULL);
  31907         } else {
  31908             if (js_parse_assign_expr(s))
  31909                 return -1;
  31910         }
  31911         /* set the name of anonymous functions */
  31912         set_object_name(s, JS_ATOM_default);
  31913 
  31914         /* store the value in the _default_ global variable and export
  31915            it */
  31916         local_name = JS_ATOM__default_;
  31917         if (define_var(s, s->cur_func, local_name, JS_VAR_DEF_LET) < 0)
  31918             return -1;
  31919         emit_op(s, OP_scope_put_var_init);
  31920         emit_atom(s, local_name);
  31921         emit_u16(s, 0);
  31922 
  31923         if (!add_export_entry(s, m, local_name, JS_ATOM_default,
  31924                               JS_EXPORT_TYPE_LOCAL))
  31925             return -1;
  31926         break;
  31927     case TOK_VAR:
  31928     case TOK_LET:
  31929     case TOK_CONST:
  31930         return js_parse_var(s, TRUE, tok, TRUE);
  31931     default:
  31932         return js_parse_error(s, "invalid export syntax");
  31933     }
  31934     return js_parse_expect_semi(s);
  31935 }
  31936 
  31937 static int add_closure_var(JSContext *ctx, JSFunctionDef *s,
  31938                            JSClosureTypeEnum closure_type,
  31939                            int var_idx, JSAtom var_name,
  31940                            BOOL is_const, BOOL is_lexical,
  31941                            JSVarKindEnum var_kind);
  31942 
  31943 static int add_import(JSParseState *s, JSModuleDef *m,
  31944                       JSAtom local_name, JSAtom import_name, BOOL is_star)
  31945 {
  31946     JSContext *ctx = s->ctx;
  31947     int i, var_idx;
  31948     JSImportEntry *mi;
  31949 
  31950     if (local_name == JS_ATOM_arguments || local_name == JS_ATOM_eval)
  31951         return js_parse_error(s, "invalid import binding");
  31952 
  31953     if (local_name != JS_ATOM_default) {
  31954         for (i = 0; i < s->cur_func->closure_var_count; i++) {
  31955             if (s->cur_func->closure_var[i].var_name == local_name)
  31956                 return js_parse_error(s, "duplicate import binding");
  31957         }
  31958     }
  31959 
  31960     var_idx = add_closure_var(ctx, s->cur_func,
  31961                               is_star ? JS_CLOSURE_MODULE_DECL : JS_CLOSURE_MODULE_IMPORT,
  31962                               m->import_entries_count,
  31963                               local_name, TRUE, TRUE, JS_VAR_NORMAL);
  31964     if (var_idx < 0)
  31965         return -1;
  31966     if (js_resize_array(ctx, (void **)&m->import_entries,
  31967                         sizeof(JSImportEntry),
  31968                         &m->import_entries_size,
  31969                         m->import_entries_count + 1))
  31970         return -1;
  31971     mi = &m->import_entries[m->import_entries_count++];
  31972     mi->import_name = JS_DupAtom(ctx, import_name);
  31973     mi->var_idx = var_idx;
  31974     mi->is_star = is_star;
  31975     return 0;
  31976 }
  31977 
  31978 static __exception int js_parse_import(JSParseState *s)
  31979 {
  31980     JSContext *ctx = s->ctx;
  31981     JSModuleDef *m = s->cur_func->module;
  31982     JSAtom local_name, import_name, module_name;
  31983     int first_import, i, idx;
  31984 
  31985     if (next_token(s))
  31986         return -1;
  31987 
  31988     first_import = m->import_entries_count;
  31989     if (s->token.val == TOK_STRING) {
  31990         module_name = JS_ValueToAtom(ctx, s->token.u.str.str);
  31991         if (module_name == JS_ATOM_NULL)
  31992             return -1;
  31993         if (next_token(s)) {
  31994             JS_FreeAtom(ctx, module_name);
  31995             return -1;
  31996         }
  31997         idx = add_req_module_entry(ctx, m, module_name);
  31998         JS_FreeAtom(ctx, module_name);
  31999         if (idx < 0)
  32000             return -1;
  32001         if (s->token.val == TOK_WITH) {
  32002             if (js_parse_with_clause(s, &m->req_module_entries[idx]))
  32003                 return -1;
  32004         }
  32005     } else {
  32006         if (s->token.val == TOK_IDENT) {
  32007             if (s->token.u.ident.is_reserved) {
  32008                 return js_parse_error_reserved_identifier(s);
  32009             }
  32010             /* "default" import */
  32011             local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
  32012             import_name = JS_ATOM_default;
  32013             if (next_token(s))
  32014                 goto fail;
  32015             if (add_import(s, m, local_name, import_name, FALSE))
  32016                 goto fail;
  32017             JS_FreeAtom(ctx, local_name);
  32018 
  32019             if (s->token.val != ',')
  32020                 goto end_import_clause;
  32021             if (next_token(s))
  32022                 return -1;
  32023         }
  32024 
  32025         if (s->token.val == '*') {
  32026             /* name space import */
  32027             if (next_token(s))
  32028                 return -1;
  32029             if (!token_is_pseudo_keyword(s, JS_ATOM_as))
  32030                 return js_parse_error(s, "expecting 'as'");
  32031             if (next_token(s))
  32032                 return -1;
  32033             if (!token_is_ident(s->token.val)) {
  32034                 js_parse_error(s, "identifier expected");
  32035                 return -1;
  32036             }
  32037             local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
  32038             import_name = JS_ATOM__star_;
  32039             if (next_token(s))
  32040                 goto fail;
  32041             if (add_import(s, m, local_name, import_name, TRUE))
  32042                 goto fail;
  32043             JS_FreeAtom(ctx, local_name);
  32044         } else if (s->token.val == '{') {
  32045             if (next_token(s))
  32046                 return -1;
  32047 
  32048             while (s->token.val != '}') {
  32049                 BOOL is_string;
  32050                 if (s->token.val == TOK_STRING) {
  32051                     is_string = TRUE;
  32052                     if (js_string_find_invalid_codepoint(JS_VALUE_GET_STRING(s->token.u.str.str)) >= 0) {
  32053                         js_parse_error(s, "contains unpaired surrogate");
  32054                         return -1;
  32055                     }
  32056                     import_name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
  32057                     if (import_name == JS_ATOM_NULL)
  32058                         return -1;
  32059                 } else {
  32060                     is_string = FALSE;
  32061                     if (!token_is_ident(s->token.val)) {
  32062                         js_parse_error(s, "identifier expected");
  32063                         return -1;
  32064                     }
  32065                     import_name = JS_DupAtom(ctx, s->token.u.ident.atom);
  32066                 }
  32067                 local_name = JS_ATOM_NULL;
  32068                 if (next_token(s))
  32069                     goto fail;
  32070                 if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
  32071                     if (next_token(s))
  32072                         goto fail;
  32073                     if (!token_is_ident(s->token.val)) {
  32074                         js_parse_error(s, "identifier expected");
  32075                         goto fail;
  32076                     }
  32077                     local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
  32078                     if (next_token(s))
  32079                         goto fail;
  32080                 } else {
  32081                     if (is_string) {
  32082                         js_parse_error(s, "expecting 'as'");
  32083                     fail:
  32084                         JS_FreeAtom(ctx, local_name);
  32085                         JS_FreeAtom(ctx, import_name);
  32086                         return -1;
  32087                     }
  32088                     local_name = JS_DupAtom(ctx, import_name);
  32089                 }
  32090                 if (add_import(s, m, local_name, import_name, FALSE))
  32091                     goto fail;
  32092                 JS_FreeAtom(ctx, local_name);
  32093                 JS_FreeAtom(ctx, import_name);
  32094                 if (s->token.val != ',')
  32095                     break;
  32096                 if (next_token(s))
  32097                     return -1;
  32098             }
  32099             if (js_parse_expect(s, '}'))
  32100                 return -1;
  32101         }
  32102     end_import_clause:
  32103         idx = js_parse_from_clause(s, m);
  32104         if (idx < 0)
  32105             return -1;
  32106     }
  32107     for(i = first_import; i < m->import_entries_count; i++)
  32108         m->import_entries[i].req_module_idx = idx;
  32109 
  32110     return js_parse_expect_semi(s);
  32111 }
  32112 
  32113 static __exception int js_parse_source_element(JSParseState *s)
  32114 {
  32115     JSFunctionDef *fd = s->cur_func;
  32116     int tok;
  32117 
  32118     if (s->token.val == TOK_FUNCTION ||
  32119         (token_is_pseudo_keyword(s, JS_ATOM_async) &&
  32120          peek_token(s, TRUE) == TOK_FUNCTION)) {
  32121         if (js_parse_function_decl(s, JS_PARSE_FUNC_STATEMENT,
  32122                                    JS_FUNC_NORMAL, JS_ATOM_NULL,
  32123                                    s->token.ptr))
  32124             return -1;
  32125     } else if (s->token.val == TOK_EXPORT && fd->module) {
  32126         if (js_parse_export(s))
  32127             return -1;
  32128     } else if (s->token.val == TOK_IMPORT && fd->module &&
  32129                ((tok = peek_token(s, FALSE)) != '(' && tok != '.'))  {
  32130         /* the peek_token is needed to avoid confusion with ImportCall
  32131            (dynamic import) or import.meta */
  32132         if (js_parse_import(s))
  32133             return -1;
  32134     } else {
  32135         if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
  32136             return -1;
  32137     }
  32138     return 0;
  32139 }
  32140 
  32141 static JSFunctionDef *js_new_function_def(JSContext *ctx,
  32142                                           JSFunctionDef *parent,
  32143                                           BOOL is_eval,
  32144                                           BOOL is_func_expr,
  32145                                           const char *filename,
  32146                                           const uint8_t *source_ptr,
  32147                                           GetLineColCache *get_line_col_cache)
  32148 {
  32149     JSFunctionDef *fd;
  32150 
  32151     fd = js_mallocz(ctx, sizeof(*fd));
  32152     if (!fd)
  32153         return NULL;
  32154 
  32155     fd->ctx = ctx;
  32156     init_list_head(&fd->child_list);
  32157 
  32158     /* insert in parent list */
  32159     fd->parent = parent;
  32160     fd->parent_cpool_idx = -1;
  32161     if (parent) {
  32162         list_add_tail(&fd->link, &parent->child_list);
  32163         fd->js_mode = parent->js_mode;
  32164         fd->parent_scope_level = parent->scope_level;
  32165     }
  32166     fd->strip_debug = ((ctx->rt->strip_flags & JS_STRIP_DEBUG) != 0);
  32167     fd->strip_source = ((ctx->rt->strip_flags & (JS_STRIP_DEBUG | JS_STRIP_SOURCE)) != 0);
  32168 
  32169     fd->is_eval = is_eval;
  32170     fd->is_func_expr = is_func_expr;
  32171     js_dbuf_bytecode_init(ctx, &fd->byte_code);
  32172     fd->last_opcode_pos = -1;
  32173     fd->func_name = JS_ATOM_NULL;
  32174     fd->var_object_idx = -1;
  32175     fd->arg_var_object_idx = -1;
  32176     fd->arguments_var_idx = -1;
  32177     fd->arguments_arg_idx = -1;
  32178     fd->func_var_idx = -1;
  32179     fd->eval_ret_idx = -1;
  32180     fd->this_var_idx = -1;
  32181     fd->new_target_var_idx = -1;
  32182     fd->this_active_func_var_idx = -1;
  32183     fd->home_object_var_idx = -1;
  32184 
  32185     /* XXX: should distinguish arg, var and var object and body scopes */
  32186     fd->scopes = fd->def_scope_array;
  32187     fd->scope_size = countof(fd->def_scope_array);
  32188     fd->scope_count = 1;
  32189     fd->scopes[0].first = -1;
  32190     fd->scopes[0].parent = -1;
  32191     fd->scope_level = 0;  /* 0: var/arg scope */
  32192     fd->scope_first = -1;
  32193     fd->body_scope = -1;
  32194 
  32195     fd->filename = JS_NewAtom(ctx, filename);
  32196     fd->source_pos = source_ptr - get_line_col_cache->buf_start;
  32197     fd->get_line_col_cache = get_line_col_cache;
  32198     
  32199     js_dbuf_init(ctx, &fd->pc2line);
  32200     //fd->pc2line_last_line_num = line_num;
  32201     //fd->pc2line_last_pc = 0;
  32202     fd->last_opcode_source_ptr = source_ptr;
  32203     return fd;
  32204 }
  32205 
  32206 static void free_bytecode_atoms(JSRuntime *rt,
  32207                                 const uint8_t *bc_buf, int bc_len,
  32208                                 BOOL use_short_opcodes)
  32209 {
  32210     int pos, len, op;
  32211     JSAtom atom;
  32212     const JSOpCode *oi;
  32213 
  32214     pos = 0;
  32215     while (pos < bc_len) {
  32216         op = bc_buf[pos];
  32217         if (use_short_opcodes)
  32218             oi = &short_opcode_info(op);
  32219         else
  32220             oi = &opcode_info[op];
  32221 
  32222         len = oi->size;
  32223         switch(oi->fmt) {
  32224         case OP_FMT_atom:
  32225         case OP_FMT_atom_u8:
  32226         case OP_FMT_atom_u16:
  32227         case OP_FMT_atom_label_u8:
  32228         case OP_FMT_atom_label_u16:
  32229             if ((pos + 1 + 4) > bc_len)
  32230                 break; /* may happen if there is not enough memory when emiting bytecode */
  32231             atom = get_u32(bc_buf + pos + 1);
  32232             JS_FreeAtomRT(rt, atom);
  32233             break;
  32234         default:
  32235             break;
  32236         }
  32237         pos += len;
  32238     }
  32239 }
  32240 
  32241 static void js_free_function_def(JSContext *ctx, JSFunctionDef *fd)
  32242 {
  32243     int i;
  32244     struct list_head *el, *el1;
  32245 
  32246     /* free the child functions */
  32247     list_for_each_safe(el, el1, &fd->child_list) {
  32248         JSFunctionDef *fd1;
  32249         fd1 = list_entry(el, JSFunctionDef, link);
  32250         js_free_function_def(ctx, fd1);
  32251     }
  32252 
  32253     free_bytecode_atoms(ctx->rt, fd->byte_code.buf, fd->byte_code.size,
  32254                         fd->use_short_opcodes);
  32255     dbuf_free(&fd->byte_code);
  32256     js_free(ctx, fd->jump_slots);
  32257     js_free(ctx, fd->label_slots);
  32258     js_free(ctx, fd->line_number_slots);
  32259 
  32260     for(i = 0; i < fd->cpool_count; i++) {
  32261         JS_FreeValue(ctx, fd->cpool[i]);
  32262     }
  32263     js_free(ctx, fd->cpool);
  32264 
  32265     JS_FreeAtom(ctx, fd->func_name);
  32266 
  32267     for(i = 0; i < fd->var_count; i++) {
  32268         JS_FreeAtom(ctx, fd->vars[i].var_name);
  32269     }
  32270     js_free(ctx, fd->vars);
  32271     for(i = 0; i < fd->arg_count; i++) {
  32272         JS_FreeAtom(ctx, fd->args[i].var_name);
  32273     }
  32274     js_free(ctx, fd->args);
  32275 
  32276     for(i = 0; i < fd->global_var_count; i++) {
  32277         JS_FreeAtom(ctx, fd->global_vars[i].var_name);
  32278     }
  32279     js_free(ctx, fd->global_vars);
  32280 
  32281     for(i = 0; i < fd->closure_var_count; i++) {
  32282         JSClosureVar *cv = &fd->closure_var[i];
  32283         JS_FreeAtom(ctx, cv->var_name);
  32284     }
  32285     js_free(ctx, fd->closure_var);
  32286 
  32287     if (fd->scopes != fd->def_scope_array)
  32288         js_free(ctx, fd->scopes);
  32289 
  32290     JS_FreeAtom(ctx, fd->filename);
  32291     dbuf_free(&fd->pc2line);
  32292 
  32293     js_free(ctx, fd->source);
  32294 
  32295     if (fd->parent) {
  32296         /* remove in parent list */
  32297         list_del(&fd->link);
  32298     }
  32299     js_free(ctx, fd);
  32300 }
  32301 
  32302 #ifdef DUMP_BYTECODE
  32303 static const char *skip_lines(const char *p, int n) {
  32304     while (n-- > 0 && *p) {
  32305         while (*p && *p++ != '\n')
  32306             continue;
  32307     }
  32308     return p;
  32309 }
  32310 
  32311 static void print_lines(const char *source, int line, int line1) {
  32312     const char *s = source;
  32313     const char *p = skip_lines(s, line);
  32314     if (*p) {
  32315         while (line++ < line1) {
  32316             p = skip_lines(s = p, 1);
  32317             printf(";; %.*s", (int)(p - s), s);
  32318             if (!*p) {
  32319                 if (p[-1] != '\n')
  32320                     printf("\n");
  32321                 break;
  32322             }
  32323         }
  32324     }
  32325 }
  32326 
  32327 static void dump_byte_code(JSContext *ctx, int pass,
  32328                            const uint8_t *tab, int len,
  32329                            const JSBytecodeVarDef *vardefs, 
  32330                            const JSVarDef *args, int arg_count,
  32331                            const JSVarDef *vars, int var_count,
  32332                            const JSClosureVar *closure_var, int closure_var_count,
  32333                            const JSValue *cpool, uint32_t cpool_count,
  32334                            const char *source,
  32335                            const LabelSlot *label_slots, JSFunctionBytecode *b)
  32336 {
  32337     const JSOpCode *oi;
  32338     int pos, pos_next, op, size, idx, addr, line, line1, in_source, line_num;
  32339     uint8_t *bits = js_mallocz(ctx, len * sizeof(*bits));
  32340     BOOL use_short_opcodes = (b != NULL), dump_pc;
  32341 
  32342     if (b) {
  32343         int col_num;
  32344         line_num = find_line_num(ctx, b, -1, &col_num);
  32345     }
  32346     
  32347     /* scan for jump targets */
  32348     for (pos = 0; pos < len; pos = pos_next) {
  32349         op = tab[pos];
  32350         if (use_short_opcodes)
  32351             oi = &short_opcode_info(op);
  32352         else
  32353             oi = &opcode_info[op];
  32354         pos_next = pos + oi->size;
  32355         if (op < OP_COUNT) {
  32356             switch (oi->fmt) {
  32357 #if SHORT_OPCODES
  32358             case OP_FMT_label8:
  32359                 pos++;
  32360                 addr = (int8_t)tab[pos];
  32361                 goto has_addr;
  32362             case OP_FMT_label16:
  32363                 pos++;
  32364                 addr = (int16_t)get_u16(tab + pos);
  32365                 goto has_addr;
  32366 #endif
  32367             case OP_FMT_atom_label_u8:
  32368             case OP_FMT_atom_label_u16:
  32369                 pos += 4;
  32370                 /* fall thru */
  32371             case OP_FMT_label:
  32372             case OP_FMT_label_u16:
  32373                 pos++;
  32374                 addr = get_u32(tab + pos);
  32375                 goto has_addr;
  32376             has_addr:
  32377                 if (pass == 1)
  32378                     addr = label_slots[addr].pos;
  32379                 if (pass == 2)
  32380                     addr = label_slots[addr].pos2;
  32381                 if (pass == 3)
  32382                     addr += pos;
  32383                 if (addr >= 0 && addr < len)
  32384                     bits[addr] |= 1;
  32385                 break;
  32386             }
  32387         }
  32388     }
  32389     in_source = 0;
  32390     if (source) {
  32391         /* Always print first line: needed if single line */
  32392         print_lines(source, 0, 1);
  32393         in_source = 1;
  32394     }
  32395     line1 = line = 1;
  32396     pos = 0;
  32397     while (pos < len) {
  32398         op = tab[pos];
  32399         if (source && b) {
  32400             int col_num;
  32401             if (b) {
  32402                 line1 = find_line_num(ctx, b, pos, &col_num) - line_num + 1;
  32403             } else if (op == OP_line_num) {
  32404                 /* XXX: no longer works */
  32405                 line1 = get_u32(tab + pos + 1) - line_num + 1;
  32406             }
  32407             if (line1 > line) {
  32408                 if (!in_source)
  32409                     printf("\n");
  32410                 in_source = 1;
  32411                 print_lines(source, line, line1);
  32412                 line = line1;
  32413                 //bits[pos] |= 2;
  32414             }
  32415         }
  32416         if (in_source)
  32417             printf("\n");
  32418         in_source = 0;
  32419         if (op >= OP_COUNT) {
  32420             printf("invalid opcode (0x%02x)\n", op);
  32421             pos++;
  32422             continue;
  32423         }
  32424         if (use_short_opcodes)
  32425             oi = &short_opcode_info(op);
  32426         else
  32427             oi = &opcode_info[op];
  32428         size = oi->size;
  32429         if (pos + size > len) {
  32430             printf("truncated opcode (0x%02x)\n", op);
  32431             break;
  32432         }
  32433 #if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 16)
  32434         {
  32435             int i, x, x0;
  32436             x = x0 = printf("%5d ", pos);
  32437             for (i = 0; i < size; i++) {
  32438                 if (i == 6) {
  32439                     printf("\n%*s", x = x0, "");
  32440                 }
  32441                 x += printf(" %02X", tab[pos + i]);
  32442             }
  32443             printf("%*s", x0 + 20 - x, "");
  32444         }
  32445 #endif
  32446 #if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 32)
  32447         dump_pc = TRUE;
  32448 #else
  32449         dump_pc = bits[pos];
  32450 #endif
  32451         if (dump_pc) {
  32452             printf("%5d:  ", pos);
  32453         } else {
  32454             printf("        ");
  32455         }
  32456         printf("%s", oi->name);
  32457         pos++;
  32458         switch(oi->fmt) {
  32459         case OP_FMT_none_int:
  32460             printf(" %d", op - OP_push_0);
  32461             break;
  32462         case OP_FMT_npopx:
  32463             printf(" %d", op - OP_call0);
  32464             break;
  32465         case OP_FMT_u8:
  32466             printf(" %u", get_u8(tab + pos));
  32467             break;
  32468         case OP_FMT_i8:
  32469             printf(" %d", get_i8(tab + pos));
  32470             break;
  32471         case OP_FMT_u16:
  32472         case OP_FMT_npop:
  32473             printf(" %u", get_u16(tab + pos));
  32474             break;
  32475         case OP_FMT_npop_u16:
  32476             printf(" %u,%u", get_u16(tab + pos), get_u16(tab + pos + 2));
  32477             break;
  32478         case OP_FMT_i16:
  32479             printf(" %d", get_i16(tab + pos));
  32480             break;
  32481         case OP_FMT_i32:
  32482             printf(" %d", get_i32(tab + pos));
  32483             break;
  32484         case OP_FMT_u32:
  32485             printf(" %u", get_u32(tab + pos));
  32486             break;
  32487 #if SHORT_OPCODES
  32488         case OP_FMT_label8:
  32489             addr = get_i8(tab + pos);
  32490             goto has_addr1;
  32491         case OP_FMT_label16:
  32492             addr = get_i16(tab + pos);
  32493             goto has_addr1;
  32494 #endif
  32495         case OP_FMT_label:
  32496             addr = get_u32(tab + pos);
  32497             goto has_addr1;
  32498         has_addr1:
  32499             if (pass == 1)
  32500                 printf(" %u:%u", addr, label_slots[addr].pos);
  32501             if (pass == 2)
  32502                 printf(" %u:%u", addr, label_slots[addr].pos2);
  32503             if (pass == 3)
  32504                 printf(" %u", addr + pos);
  32505             break;
  32506         case OP_FMT_label_u16:
  32507             addr = get_u32(tab + pos);
  32508             if (pass == 1)
  32509                 printf(" %u:%u", addr, label_slots[addr].pos);
  32510             if (pass == 2)
  32511                 printf(" %u:%u", addr, label_slots[addr].pos2);
  32512             if (pass == 3)
  32513                 printf(" %u", addr + pos);
  32514             printf(",%u", get_u16(tab + pos + 4));
  32515             break;
  32516 #if SHORT_OPCODES
  32517         case OP_FMT_const8:
  32518             idx = get_u8(tab + pos);
  32519             goto has_pool_idx;
  32520 #endif
  32521         case OP_FMT_const:
  32522             idx = get_u32(tab + pos);
  32523             goto has_pool_idx;
  32524         has_pool_idx:
  32525             printf(" %u: ", idx);
  32526             if (idx < cpool_count) {
  32527                 JS_PrintValue(ctx, js_dump_value_write, stdout, cpool[idx], NULL);
  32528             }
  32529             break;
  32530         case OP_FMT_atom:
  32531             printf(" ");
  32532             print_atom(ctx, get_u32(tab + pos));
  32533             break;
  32534         case OP_FMT_atom_u8:
  32535             printf(" ");
  32536             print_atom(ctx, get_u32(tab + pos));
  32537             printf(",%d", get_u8(tab + pos + 4));
  32538             break;
  32539         case OP_FMT_atom_u16:
  32540             printf(" ");
  32541             print_atom(ctx, get_u32(tab + pos));
  32542             printf(",%d", get_u16(tab + pos + 4));
  32543             break;
  32544         case OP_FMT_atom_label_u8:
  32545         case OP_FMT_atom_label_u16:
  32546             printf(" ");
  32547             print_atom(ctx, get_u32(tab + pos));
  32548             addr = get_u32(tab + pos + 4);
  32549             if (pass == 1)
  32550                 printf(",%u:%u", addr, label_slots[addr].pos);
  32551             if (pass == 2)
  32552                 printf(",%u:%u", addr, label_slots[addr].pos2);
  32553             if (pass == 3)
  32554                 printf(",%u", addr + pos + 4);
  32555             if (oi->fmt == OP_FMT_atom_label_u8)
  32556                 printf(",%u", get_u8(tab + pos + 8));
  32557             else
  32558                 printf(",%u", get_u16(tab + pos + 8));
  32559             break;
  32560         case OP_FMT_none_loc:
  32561             idx = (op - OP_get_loc0) % 4;
  32562             goto has_loc;
  32563         case OP_FMT_loc8:
  32564             idx = get_u8(tab + pos);
  32565             goto has_loc;
  32566         case OP_FMT_loc:
  32567             idx = get_u16(tab + pos);
  32568         has_loc:
  32569             printf(" %d: ", idx);
  32570             if (idx < var_count) {
  32571                 print_atom(ctx, vars ? vars[idx].var_name : vardefs[arg_count + idx].var_name);
  32572             }
  32573             break;
  32574         case OP_FMT_none_arg:
  32575             idx = (op - OP_get_arg0) % 4;
  32576             goto has_arg;
  32577         case OP_FMT_arg:
  32578             idx = get_u16(tab + pos);
  32579         has_arg:
  32580             printf(" %d: ", idx);
  32581             if (idx < arg_count) {
  32582                 print_atom(ctx, args ? args[idx].var_name : vardefs[idx].var_name);
  32583             }
  32584             break;
  32585         case OP_FMT_none_var_ref:
  32586             idx = (op - OP_get_var_ref0) % 4;
  32587             goto has_var_ref;
  32588         case OP_FMT_var_ref:
  32589             idx = get_u16(tab + pos);
  32590         has_var_ref:
  32591             printf(" %d: ", idx);
  32592             if (idx < closure_var_count) {
  32593                 print_atom(ctx, closure_var[idx].var_name);
  32594             }
  32595             break;
  32596         default:
  32597             break;
  32598         }
  32599         printf("\n");
  32600         pos += oi->size - 1;
  32601     }
  32602     if (source) {
  32603         if (!in_source)
  32604             printf("\n");
  32605         print_lines(source, line, INT32_MAX);
  32606     }
  32607     js_free(ctx, bits);
  32608 }
  32609 
  32610 static __maybe_unused void dump_pc2line(JSContext *ctx, const uint8_t *buf, int len)
  32611 {
  32612     const uint8_t *p_end, *p;
  32613     int pc, v, line_num, col_num, ret;
  32614     unsigned int op;
  32615     uint32_t val;
  32616     
  32617     if (len <= 0)
  32618         return;
  32619 
  32620     printf("%5s %5s %5s\n", "PC", "LINE", "COL");
  32621 
  32622     p = buf;
  32623     p_end = buf + len;
  32624     
  32625     /* get the function line and column numbers */
  32626     ret = get_leb128(&val, p, p_end);
  32627     if (ret < 0)
  32628         goto fail;
  32629     p += ret;
  32630     line_num = val + 1;
  32631 
  32632     ret = get_leb128(&val, p, p_end);
  32633     if (ret < 0)
  32634         goto fail;
  32635     p += ret;
  32636     col_num = val + 1;
  32637 
  32638     printf("%5s %5d %5d\n", "-", line_num, col_num);
  32639     
  32640     pc = 0;
  32641     while (p < p_end) {
  32642         op = *p++;
  32643         if (op == 0) {
  32644             ret = get_leb128(&val, p, p_end);
  32645             if (ret < 0)
  32646                 goto fail;
  32647             pc += val;
  32648             p += ret;
  32649             ret = get_sleb128(&v, p, p_end);
  32650             if (ret < 0)
  32651                 goto fail;
  32652             p += ret;
  32653             line_num += v;
  32654         } else {
  32655             op -= PC2LINE_OP_FIRST;
  32656             pc += (op / PC2LINE_RANGE);
  32657             line_num += (op % PC2LINE_RANGE) + PC2LINE_BASE;
  32658         }
  32659         ret = get_sleb128(&v, p, p_end);
  32660         if (ret < 0)
  32661             goto fail;
  32662         p += ret;
  32663         col_num += v;
  32664         
  32665         printf("%5d %5d %5d\n", pc, line_num, col_num);
  32666     }
  32667  fail: ;
  32668 }
  32669 
  32670 static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionBytecode *b)
  32671 {
  32672     int i;
  32673     char atom_buf[ATOM_GET_STR_BUF_SIZE];
  32674     const char *str;
  32675 
  32676     if (b->has_debug && b->debug.filename != JS_ATOM_NULL) {
  32677         int line_num, col_num;
  32678         str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->debug.filename);
  32679         line_num = find_line_num(ctx, b, -1, &col_num);
  32680         printf("%s:%d:%d: ", str, line_num, col_num);
  32681     }
  32682 
  32683     str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->func_name);
  32684     printf("function: %s%s\n", &"*"[b->func_kind != JS_FUNC_GENERATOR], str);
  32685     if (b->js_mode) {
  32686         printf("  mode:");
  32687         if (b->js_mode & JS_MODE_STRICT)
  32688             printf(" strict");
  32689         printf("\n");
  32690     }
  32691     if (b->arg_count && b->vardefs) {
  32692         printf("  args:");
  32693         for(i = 0; i < b->arg_count; i++) {
  32694             printf(" %s", JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf),
  32695                                         b->vardefs[i].var_name));
  32696         }
  32697         printf("\n");
  32698     }
  32699     if (b->var_count && b->vardefs) {
  32700         printf("  locals:\n");
  32701         for(i = 0; i < b->var_count; i++) {
  32702             JSBytecodeVarDef *vd = &b->vardefs[b->arg_count + i];
  32703             printf("%5d: %s %s", i,
  32704                    vd->var_kind == JS_VAR_CATCH ? "catch" :
  32705                    (vd->var_kind == JS_VAR_FUNCTION_DECL ||
  32706                     vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) ? "function" :
  32707                    vd->is_const ? "const" :
  32708                    vd->is_lexical ? "let" : "var",
  32709                    JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), vd->var_name));
  32710             if (vd->has_scope)
  32711                 printf(" [next:%d]", vd->scope_next);
  32712             printf("\n");
  32713         }
  32714     }
  32715     if (b->closure_var_count) {
  32716         printf("  closure vars:\n");
  32717         for(i = 0; i < b->closure_var_count; i++) {
  32718             JSClosureVar *cv = &b->closure_var[i];
  32719             printf("%5d: %s %s", i,
  32720                    cv->is_const ? "const" :
  32721                    cv->is_lexical ? "let" : "var",
  32722                    JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), cv->var_name));
  32723             switch(cv->closure_type) {
  32724             case JS_CLOSURE_LOCAL:
  32725                 printf(" [loc%d]\n", cv->var_idx);
  32726                 break;
  32727             case JS_CLOSURE_ARG:
  32728                 printf(" [arg%d]\n", cv->var_idx);
  32729                 break;
  32730             case JS_CLOSURE_REF:
  32731                 printf(" [ref%d]\n", cv->var_idx);
  32732                 break;
  32733             case JS_CLOSURE_GLOBAL_REF:
  32734                 printf(" [global_ref%d]\n", cv->var_idx);
  32735                 break;
  32736             case JS_CLOSURE_GLOBAL_DECL:
  32737                 printf(" [global_decl]\n");
  32738                 break;
  32739             case JS_CLOSURE_GLOBAL:
  32740                 printf(" [global]\n");
  32741                 break;
  32742             case JS_CLOSURE_MODULE_DECL:
  32743                 printf(" [module_decl]\n");
  32744                 break;
  32745             case JS_CLOSURE_MODULE_IMPORT:
  32746                 printf(" [module_import]\n");
  32747                 break;
  32748             default:
  32749                 printf(" [?]\n");
  32750                 break;
  32751             }
  32752         }
  32753     }
  32754     printf("  stack_size: %d\n", b->stack_size);
  32755     printf("  var_ref_count: %d\n", b->var_ref_count);
  32756     printf("  opcodes:\n");
  32757     dump_byte_code(ctx, 3, b->byte_code_buf, b->byte_code_len,
  32758                    b->vardefs,
  32759                    NULL, b->arg_count,
  32760                    NULL, b->var_count,
  32761                    b->closure_var, b->closure_var_count,
  32762                    b->cpool, b->cpool_count,
  32763                    b->has_debug ? b->debug.source : NULL,
  32764                    NULL, b);
  32765 #if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 32)
  32766     if (b->has_debug)
  32767         dump_pc2line(ctx, b->debug.pc2line_buf, b->debug.pc2line_len);
  32768 #endif
  32769     printf("\n");
  32770 }
  32771 #endif
  32772 
  32773 static int add_closure_var(JSContext *ctx, JSFunctionDef *s,
  32774                            JSClosureTypeEnum closure_type,
  32775                            int var_idx, JSAtom var_name,
  32776                            BOOL is_const, BOOL is_lexical,
  32777                            JSVarKindEnum var_kind)
  32778 {
  32779     JSClosureVar *cv;
  32780 
  32781     /* the closure variable indexes are currently stored on 16 bits */
  32782     if (s->closure_var_count >= JS_MAX_LOCAL_VARS) {
  32783         JS_ThrowInternalError(ctx, "too many closure variables");
  32784         return -1;
  32785     }
  32786 
  32787     if (js_resize_array(ctx, (void **)&s->closure_var,
  32788                         sizeof(s->closure_var[0]),
  32789                         &s->closure_var_size, s->closure_var_count + 1))
  32790         return -1;
  32791     cv = &s->closure_var[s->closure_var_count++];
  32792     cv->closure_type = closure_type;
  32793     cv->is_const = is_const;
  32794     cv->is_lexical = is_lexical;
  32795     cv->var_kind = var_kind;
  32796     cv->var_idx = var_idx;
  32797     cv->var_name = JS_DupAtom(ctx, var_name);
  32798     return s->closure_var_count - 1;
  32799 }
  32800 
  32801 static int find_closure_var(JSContext *ctx, JSFunctionDef *s,
  32802                             JSAtom var_name)
  32803 {
  32804     int i;
  32805     for(i = 0; i < s->closure_var_count; i++) {
  32806         JSClosureVar *cv = &s->closure_var[i];
  32807         if (cv->var_name == var_name)
  32808             return i;
  32809     }
  32810     return -1;
  32811 }
  32812 
  32813 /* 'fd' must be a parent of 's'. Create in 's' a closure referencing
  32814    another one in 'fd' */
  32815 static int get_closure_var(JSContext *ctx, JSFunctionDef *s,
  32816                            JSFunctionDef *fd, JSClosureTypeEnum closure_type,
  32817                            int var_idx, JSAtom var_name,
  32818                            BOOL is_const, BOOL is_lexical,
  32819                            JSVarKindEnum var_kind)
  32820 {
  32821     int i;
  32822 
  32823     if (fd != s->parent) {
  32824         var_idx = get_closure_var(ctx, s->parent, fd, closure_type,
  32825                                   var_idx, var_name,
  32826                                   is_const, is_lexical, var_kind);
  32827         if (var_idx < 0)
  32828             return -1;
  32829         if (closure_type != JS_CLOSURE_GLOBAL_REF)
  32830             closure_type = JS_CLOSURE_REF;
  32831     }
  32832     for(i = 0; i < s->closure_var_count; i++) {
  32833         JSClosureVar *cv = &s->closure_var[i];
  32834         if (cv->var_idx == var_idx && cv->closure_type == closure_type)
  32835             return i;
  32836     }
  32837     return add_closure_var(ctx, s, closure_type, var_idx, var_name,
  32838                            is_const, is_lexical, var_kind);
  32839 }
  32840 
  32841 static int get_with_scope_opcode(int op)
  32842 {
  32843     if (op == OP_scope_get_var_undef)
  32844         return OP_with_get_var;
  32845     else
  32846         return OP_with_get_var + (op - OP_scope_get_var);
  32847 }
  32848 
  32849 static BOOL can_opt_put_ref_value(const uint8_t *bc_buf, int pos)
  32850 {
  32851     int opcode = bc_buf[pos];
  32852     return (bc_buf[pos + 1] == OP_put_ref_value &&
  32853             (opcode == OP_insert3 ||
  32854              opcode == OP_perm4 ||
  32855              opcode == OP_nop ||
  32856              opcode == OP_rot3l));
  32857 }
  32858 
  32859 static BOOL can_opt_put_global_ref_value(const uint8_t *bc_buf, int pos)
  32860 {
  32861     int opcode = bc_buf[pos];
  32862     return (bc_buf[pos + 1] == OP_put_ref_value &&
  32863             (opcode == OP_insert3 ||
  32864              opcode == OP_perm4 ||
  32865              opcode == OP_nop ||
  32866              opcode == OP_rot3l));
  32867 }
  32868 
  32869 static int optimize_scope_make_ref(JSContext *ctx, JSFunctionDef *s,
  32870                                    DynBuf *bc, uint8_t *bc_buf,
  32871                                    LabelSlot *ls, int pos_next,
  32872                                    int get_op, int var_idx)
  32873 {
  32874     int label_pos, end_pos, pos;
  32875 
  32876     /* XXX: should optimize `loc(a) += expr` as `expr add_loc(a)`
  32877        but only if expr does not modify `a`.
  32878        should scan the code between pos_next and label_pos
  32879        for operations that can potentially change `a`:
  32880        OP_scope_make_ref(a), function calls, jumps and gosub.
  32881      */
  32882     /* replace the reference get/put with normal variable
  32883        accesses */
  32884     if (bc_buf[pos_next] == OP_get_ref_value) {
  32885         dbuf_putc(bc, get_op);
  32886         dbuf_put_u16(bc, var_idx);
  32887         pos_next++;
  32888     }
  32889     /* remove the OP_label to make room for replacement */
  32890     /* label should have a refcount of 0 anyway */
  32891     /* XXX: should avoid this patch by inserting nops in phase 1 */
  32892     label_pos = ls->pos;
  32893     pos = label_pos - 5;
  32894     assert(bc_buf[pos] == OP_label);
  32895     /* label points to an instruction pair:
  32896        - insert3 / put_ref_value
  32897        - perm4 / put_ref_value
  32898        - rot3l / put_ref_value
  32899        - nop / put_ref_value
  32900      */
  32901     end_pos = label_pos + 2;
  32902     if (bc_buf[label_pos] == OP_insert3)
  32903         bc_buf[pos++] = OP_dup;
  32904     bc_buf[pos] = get_op + 1;
  32905     put_u16(bc_buf + pos + 1, var_idx);
  32906     pos += 3;
  32907     /* pad with OP_nop */
  32908     while (pos < end_pos)
  32909         bc_buf[pos++] = OP_nop;
  32910     return pos_next;
  32911 }
  32912 
  32913 static int add_var_this(JSContext *ctx, JSFunctionDef *fd)
  32914 {
  32915     int idx;
  32916     idx = add_var(ctx, fd, JS_ATOM_this);
  32917     if (idx >= 0 && fd->is_derived_class_constructor) {
  32918         JSVarDef *vd = &fd->vars[idx];
  32919         /* XXX: should have is_this flag or var type */
  32920         vd->is_lexical = 1; /* used to trigger 'uninitialized' checks
  32921                                in a derived class constructor */
  32922     }
  32923     return idx;
  32924 }
  32925 
  32926 static int resolve_pseudo_var(JSContext *ctx, JSFunctionDef *s,
  32927                                JSAtom var_name)
  32928 {
  32929     int var_idx;
  32930 
  32931     if (!s->has_this_binding)
  32932         return -1;
  32933     switch(var_name) {
  32934     case JS_ATOM_home_object:
  32935         /* 'home_object' pseudo variable */
  32936         if (s->home_object_var_idx < 0)
  32937             s->home_object_var_idx = add_var(ctx, s, var_name);
  32938         var_idx = s->home_object_var_idx;
  32939         break;
  32940     case JS_ATOM_this_active_func:
  32941         /* 'this.active_func' pseudo variable */
  32942         if (s->this_active_func_var_idx < 0)
  32943             s->this_active_func_var_idx = add_var(ctx, s, var_name);
  32944         var_idx = s->this_active_func_var_idx;
  32945         break;
  32946     case JS_ATOM_new_target:
  32947         /* 'new.target' pseudo variable */
  32948         if (s->new_target_var_idx < 0)
  32949             s->new_target_var_idx = add_var(ctx, s, var_name);
  32950         var_idx = s->new_target_var_idx;
  32951         break;
  32952     case JS_ATOM_this:
  32953         /* 'this' pseudo variable */
  32954         if (s->this_var_idx < 0)
  32955             s->this_var_idx = add_var_this(ctx, s);
  32956         var_idx = s->this_var_idx;
  32957         break;
  32958     default:
  32959         var_idx = -1;
  32960         break;
  32961     }
  32962     return var_idx;
  32963 }
  32964 
  32965 /* test if 'var_name' is in the variable object on the stack. If is it
  32966    the case, handle it and jump to 'label_done' */
  32967 static void var_object_test(JSContext *ctx, JSFunctionDef *s,
  32968                             JSAtom var_name, int op, DynBuf *bc,
  32969                             int *plabel_done, BOOL is_with)
  32970 {
  32971     dbuf_putc(bc, get_with_scope_opcode(op));
  32972     dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
  32973     if (*plabel_done < 0) {
  32974         *plabel_done = new_label_fd(s);
  32975         if (*plabel_done < 0) {
  32976             dbuf_set_error(bc);
  32977             return;
  32978         }
  32979     }
  32980     dbuf_put_u32(bc, *plabel_done);
  32981     dbuf_putc(bc, is_with);
  32982     update_label(s, *plabel_done, 1);
  32983     s->jump_size++;
  32984 }
  32985 
  32986 static inline void capture_var(JSFunctionDef *s, JSVarDef *vd)
  32987 {
  32988     if (!vd->is_captured) {
  32989         vd->is_captured = 1;
  32990         vd->var_ref_idx = s->var_ref_count++;
  32991     }
  32992 }
  32993 
  32994 /* return the position of the next opcode or -1 if error */
  32995 static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
  32996                              JSAtom var_name, int scope_level, int op,
  32997                              DynBuf *bc, uint8_t *bc_buf,
  32998                              LabelSlot *ls, int pos_next)
  32999 {
  33000     int idx, var_idx, is_put;
  33001     int label_done;
  33002     JSFunctionDef *fd;
  33003     JSVarDef *vd;
  33004     BOOL is_pseudo_var, is_arg_scope;
  33005 
  33006     label_done = -1;
  33007 
  33008     /* XXX: could be simpler to use a specific function to
  33009        resolve the pseudo variables */
  33010     is_pseudo_var = (var_name == JS_ATOM_home_object ||
  33011                      var_name == JS_ATOM_this_active_func ||
  33012                      var_name == JS_ATOM_new_target ||
  33013                      var_name == JS_ATOM_this);
  33014 
  33015     /* resolve local scoped variables */
  33016     var_idx = -1;
  33017     for (idx = s->scopes[scope_level].first; idx >= 0;) {
  33018         vd = &s->vars[idx];
  33019         if (vd->var_name == var_name) {
  33020             if (op == OP_scope_put_var || op == OP_scope_make_ref) {
  33021                 if (vd->is_const) {
  33022                     dbuf_putc(bc, OP_throw_error);
  33023                     dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
  33024                     dbuf_putc(bc, JS_THROW_VAR_RO);
  33025                     goto done;
  33026                 }
  33027             }
  33028             var_idx = idx;
  33029             break;
  33030         } else
  33031         if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
  33032             dbuf_putc(bc, OP_get_loc);
  33033             dbuf_put_u16(bc, idx);
  33034             var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
  33035         }
  33036         idx = vd->scope_next;
  33037     }
  33038     is_arg_scope = (idx == ARG_SCOPE_END);
  33039     if (var_idx < 0) {
  33040         /* argument scope: variables are not visible but pseudo
  33041            variables are visible */
  33042         if (!is_arg_scope) {
  33043             var_idx = find_var(ctx, s, var_name);
  33044         }
  33045 
  33046         if (var_idx < 0 && is_pseudo_var)
  33047             var_idx = resolve_pseudo_var(ctx, s, var_name);
  33048 
  33049         if (var_idx < 0 && var_name == JS_ATOM_arguments &&
  33050             s->has_arguments_binding) {
  33051             /* 'arguments' pseudo variable */
  33052             var_idx = add_arguments_var(ctx, s);
  33053         }
  33054         if (var_idx < 0 && s->is_func_expr && var_name == s->func_name) {
  33055             /* add a new variable with the function name */
  33056             var_idx = add_func_var(ctx, s, var_name);
  33057         }
  33058     }
  33059     if (var_idx >= 0) {
  33060         if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&
  33061             !(var_idx & ARGUMENT_VAR_OFFSET) &&
  33062             s->vars[var_idx].is_const) {
  33063             /* only happens when assigning a function expression name
  33064                in strict mode */
  33065             dbuf_putc(bc, OP_throw_error);
  33066             dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
  33067             dbuf_putc(bc, JS_THROW_VAR_RO);
  33068             goto done;
  33069         }
  33070         /* OP_scope_put_var_init is only used to initialize a
  33071            lexical variable, so it is never used in a with or var object. It
  33072            can be used with a closure (module global variable case). */
  33073         switch (op) {
  33074         case OP_scope_make_ref:
  33075             if (!(var_idx & ARGUMENT_VAR_OFFSET) &&
  33076                 s->vars[var_idx].var_kind == JS_VAR_FUNCTION_NAME) {
  33077                 /* Create a dummy object reference for the func_var */
  33078                 dbuf_putc(bc, OP_object);
  33079                 dbuf_putc(bc, OP_get_loc);
  33080                 dbuf_put_u16(bc, var_idx);
  33081                 dbuf_putc(bc, OP_define_field);
  33082                 dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
  33083                 dbuf_putc(bc, OP_push_atom_value);
  33084                 dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
  33085             } else
  33086             if (label_done == -1 && can_opt_put_ref_value(bc_buf, ls->pos)) {
  33087                 int get_op;
  33088                 if (var_idx & ARGUMENT_VAR_OFFSET) {
  33089                     get_op = OP_get_arg;
  33090                     var_idx -= ARGUMENT_VAR_OFFSET;
  33091                 } else {
  33092                     if (s->vars[var_idx].is_lexical)
  33093                         get_op = OP_get_loc_check;
  33094                     else
  33095                         get_op = OP_get_loc;
  33096                 }
  33097                 pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,
  33098                                                    pos_next, get_op, var_idx);
  33099             } else {
  33100                 /* Create a dummy object with a named slot that is
  33101                    a reference to the local variable */
  33102                 if (var_idx & ARGUMENT_VAR_OFFSET) {
  33103                     capture_var(s, &s->args[var_idx - ARGUMENT_VAR_OFFSET]);
  33104                     dbuf_putc(bc, OP_make_arg_ref);
  33105                     dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
  33106                     dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
  33107                 } else {
  33108                     capture_var(s, &s->vars[var_idx]);
  33109                     dbuf_putc(bc, OP_make_loc_ref);
  33110                     dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
  33111                     dbuf_put_u16(bc, var_idx);
  33112                 }
  33113             }
  33114             break;
  33115         case OP_scope_put_var:
  33116             if (!(var_idx & ARGUMENT_VAR_OFFSET) &&
  33117                 s->vars[var_idx].var_kind == JS_VAR_FUNCTION_NAME) {
  33118                 /* in non strict mode, modifying the function name is ignored */
  33119                 dbuf_putc(bc, OP_drop);
  33120                 goto done;
  33121             }
  33122             goto local_scope_var;
  33123         case OP_scope_get_ref:
  33124             dbuf_putc(bc, OP_undefined);
  33125             goto local_scope_var;
  33126         case OP_scope_get_var_checkthis:
  33127         case OP_scope_get_var_undef:
  33128         case OP_scope_get_var:
  33129         case OP_scope_put_var_init:
  33130         local_scope_var:
  33131             is_put = (op == OP_scope_put_var || op == OP_scope_put_var_init);
  33132             if (var_idx & ARGUMENT_VAR_OFFSET) {
  33133                 dbuf_putc(bc, OP_get_arg + is_put);
  33134                 dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
  33135             } else {
  33136                 if (is_put) {
  33137                     if (s->vars[var_idx].is_lexical) {
  33138                         if (op == OP_scope_put_var_init) {
  33139                             /* 'this' can only be initialized once */
  33140                             if (var_name == JS_ATOM_this)
  33141                                 dbuf_putc(bc, OP_put_loc_check_init);
  33142                             else
  33143                                 dbuf_putc(bc, OP_put_loc);
  33144                         } else {
  33145                             dbuf_putc(bc, OP_put_loc_check);
  33146                         }
  33147                     } else {
  33148                         dbuf_putc(bc, OP_put_loc);
  33149                     }
  33150                 } else {
  33151                     if (s->vars[var_idx].is_lexical) {
  33152                         if (op == OP_scope_get_var_checkthis) {
  33153                             /* only used for 'this' return in derived class constructors */
  33154                             dbuf_putc(bc, OP_get_loc_checkthis);
  33155                         } else {
  33156                             dbuf_putc(bc, OP_get_loc_check);
  33157                         }
  33158                     } else {
  33159                         dbuf_putc(bc, OP_get_loc);
  33160                     }
  33161                 }
  33162                 dbuf_put_u16(bc, var_idx);
  33163             }
  33164             break;
  33165         case OP_scope_delete_var:
  33166             dbuf_putc(bc, OP_push_false);
  33167             break;
  33168         }
  33169         goto done;
  33170     }
  33171     /* check eval object */
  33172     if (!is_arg_scope && s->var_object_idx >= 0 && !is_pseudo_var) {
  33173         dbuf_putc(bc, OP_get_loc);
  33174         dbuf_put_u16(bc, s->var_object_idx);
  33175         var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
  33176     }
  33177     /* check eval object in argument scope */
  33178     if (s->arg_var_object_idx >= 0 && !is_pseudo_var) {
  33179         dbuf_putc(bc, OP_get_loc);
  33180         dbuf_put_u16(bc, s->arg_var_object_idx);
  33181         var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
  33182     }
  33183 
  33184     /* check parent scopes */
  33185     for (fd = s; fd->parent;) {
  33186         scope_level = fd->parent_scope_level;
  33187         fd = fd->parent;
  33188         for (idx = fd->scopes[scope_level].first; idx >= 0;) {
  33189             vd = &fd->vars[idx];
  33190             if (vd->var_name == var_name) {
  33191                 if (op == OP_scope_put_var || op == OP_scope_make_ref) {
  33192                     if (vd->is_const) {
  33193                         dbuf_putc(bc, OP_throw_error);
  33194                         dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
  33195                         dbuf_putc(bc, JS_THROW_VAR_RO);
  33196                         goto done;
  33197                     }
  33198                 }
  33199                 var_idx = idx;
  33200                 break;
  33201             } else if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
  33202                 capture_var(fd, vd);
  33203                 idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL, idx, vd->var_name, FALSE, FALSE, JS_VAR_NORMAL);
  33204                 if (idx >= 0) {
  33205                     dbuf_putc(bc, OP_get_var_ref);
  33206                     dbuf_put_u16(bc, idx);
  33207                     var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
  33208                 }
  33209             }
  33210             idx = vd->scope_next;
  33211         }
  33212         is_arg_scope = (idx == ARG_SCOPE_END);
  33213         if (var_idx >= 0)
  33214             break;
  33215 
  33216         if (!is_arg_scope) {
  33217             var_idx = find_var(ctx, fd, var_name);
  33218             if (var_idx >= 0)
  33219                 break;
  33220         }
  33221         if (is_pseudo_var) {
  33222             var_idx = resolve_pseudo_var(ctx, fd, var_name);
  33223             if (var_idx >= 0)
  33224                 break;
  33225         }
  33226         if (var_name == JS_ATOM_arguments && fd->has_arguments_binding) {
  33227             var_idx = add_arguments_var(ctx, fd);
  33228             break;
  33229         }
  33230         if (fd->is_func_expr && fd->func_name == var_name) {
  33231             /* add a new variable with the function name */
  33232             var_idx = add_func_var(ctx, fd, var_name);
  33233             break;
  33234         }
  33235 
  33236         /* check eval object */
  33237         if (!is_arg_scope && fd->var_object_idx >= 0 && !is_pseudo_var) {
  33238             vd = &fd->vars[fd->var_object_idx];
  33239             capture_var(fd, vd);
  33240             idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL,
  33241                                   fd->var_object_idx, vd->var_name,
  33242                                   FALSE, FALSE, JS_VAR_NORMAL);
  33243             dbuf_putc(bc, OP_get_var_ref);
  33244             dbuf_put_u16(bc, idx);
  33245             var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
  33246         }
  33247 
  33248         /* check eval object in argument scope */
  33249         if (fd->arg_var_object_idx >= 0 && !is_pseudo_var) {
  33250             vd = &fd->vars[fd->arg_var_object_idx];
  33251             capture_var(fd, vd);
  33252             idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL,
  33253                                   fd->arg_var_object_idx, vd->var_name,
  33254                                   FALSE, FALSE, JS_VAR_NORMAL);
  33255             dbuf_putc(bc, OP_get_var_ref);
  33256             dbuf_put_u16(bc, idx);
  33257             var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
  33258         }
  33259 
  33260         if (fd->is_eval)
  33261             break; /* it it necessarily the top level function */
  33262     }
  33263 
  33264     /* check direct eval scope (in the closure of the eval function
  33265        which is necessarily at the top level) */
  33266     if (!fd)
  33267         fd = s;
  33268     if (var_idx < 0 && fd->is_eval) {
  33269         int idx1;
  33270         for (idx1 = 0; idx1 < fd->closure_var_count; idx1++) {
  33271             JSClosureVar *cv = &fd->closure_var[idx1];
  33272             if (var_name == cv->var_name) {
  33273                 if (fd != s) {
  33274                     JSClosureTypeEnum closure_type;
  33275                     if (cv->closure_type == JS_CLOSURE_GLOBAL ||
  33276                         cv->closure_type == JS_CLOSURE_GLOBAL_DECL ||
  33277                         cv->closure_type == JS_CLOSURE_GLOBAL_REF)
  33278                         closure_type = JS_CLOSURE_GLOBAL_REF;
  33279                     else
  33280                         closure_type = JS_CLOSURE_REF;
  33281                     idx = get_closure_var(ctx, s, fd,
  33282                                           closure_type,
  33283                                           idx1,
  33284                                           cv->var_name, cv->is_const,
  33285                                           cv->is_lexical, cv->var_kind);
  33286                 } else {
  33287                     idx = idx1;
  33288                 }
  33289                 if (cv->closure_type == JS_CLOSURE_GLOBAL ||
  33290                     cv->closure_type == JS_CLOSURE_GLOBAL_DECL ||
  33291                     cv->closure_type == JS_CLOSURE_GLOBAL_REF)
  33292                     goto has_global_idx;
  33293                 else
  33294                     goto has_idx;
  33295             } else if ((cv->var_name == JS_ATOM__var_ ||
  33296                         cv->var_name == JS_ATOM__arg_var_ ||
  33297                         cv->var_name == JS_ATOM__with_) && !is_pseudo_var) {
  33298                 int is_with = (cv->var_name == JS_ATOM__with_);
  33299                 if (fd != s) {
  33300                     idx = get_closure_var(ctx, s, fd,
  33301                                           JS_CLOSURE_REF,
  33302                                           idx1,
  33303                                           cv->var_name, FALSE, FALSE,
  33304                                           JS_VAR_NORMAL);
  33305                 } else {
  33306                     idx = idx1;
  33307                 }
  33308                 dbuf_putc(bc, OP_get_var_ref);
  33309                 dbuf_put_u16(bc, idx);
  33310                 var_object_test(ctx, s, var_name, op, bc, &label_done, is_with);
  33311             }
  33312         }
  33313 
  33314         /* not found: add a closure for a global variable access */
  33315         idx1 = add_closure_var(ctx, fd, JS_CLOSURE_GLOBAL, 0, var_name,
  33316                               FALSE, FALSE, JS_VAR_NORMAL);
  33317         if (idx1 < 0)
  33318             return -1;
  33319         if (fd != s) {
  33320             idx = get_closure_var(ctx, s, fd,
  33321                                   JS_CLOSURE_GLOBAL_REF,
  33322                                   idx1,
  33323                                   var_name, FALSE, FALSE, 
  33324                                   JS_VAR_NORMAL);
  33325         } else {
  33326             idx = idx1;
  33327         }
  33328     has_global_idx:
  33329         /* global variable access */
  33330         switch (op) {
  33331         case OP_scope_make_ref:
  33332             if (label_done == -1 && can_opt_put_global_ref_value(bc_buf, ls->pos)) {
  33333                 pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,
  33334                                                    pos_next,
  33335                                                    OP_get_var, idx);
  33336             } else {
  33337                 dbuf_putc(bc, OP_make_var_ref);
  33338                 dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
  33339             }
  33340             break;
  33341         case OP_scope_get_ref:
  33342             /* XXX: should create a dummy object with a named slot that is
  33343                a reference to the global variable */
  33344             dbuf_putc(bc, OP_undefined);
  33345             dbuf_putc(bc, OP_get_var);
  33346             dbuf_put_u16(bc, idx);
  33347             break;
  33348         case OP_scope_get_var_undef:
  33349         case OP_scope_get_var:
  33350         case OP_scope_put_var:
  33351             dbuf_putc(bc, OP_get_var_undef + (op - OP_scope_get_var_undef));
  33352             dbuf_put_u16(bc, idx);
  33353             break;
  33354         case OP_scope_put_var_init:
  33355             dbuf_putc(bc, OP_put_var_init);
  33356             dbuf_put_u16(bc, idx);
  33357             break;
  33358         case OP_scope_delete_var:
  33359             dbuf_putc(bc, OP_delete_var);
  33360             dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
  33361             break;
  33362         }
  33363     } else {
  33364         /* find the corresponding closure variable */
  33365         if (var_idx & ARGUMENT_VAR_OFFSET) {
  33366             capture_var(fd, &fd->args[var_idx - ARGUMENT_VAR_OFFSET]);
  33367             idx = get_closure_var(ctx, s, fd,
  33368                                   JS_CLOSURE_ARG, var_idx - ARGUMENT_VAR_OFFSET,
  33369                                   var_name, FALSE, FALSE, JS_VAR_NORMAL);
  33370         } else {
  33371             capture_var(fd, &fd->vars[var_idx]);
  33372             idx = get_closure_var(ctx, s, fd,
  33373                                   JS_CLOSURE_LOCAL, var_idx,
  33374                                   var_name,
  33375                                   fd->vars[var_idx].is_const,
  33376                                   fd->vars[var_idx].is_lexical,
  33377                                   fd->vars[var_idx].var_kind);
  33378         }
  33379         if (idx >= 0) {
  33380         has_idx:
  33381             if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&
  33382                 s->closure_var[idx].is_const) {
  33383                 dbuf_putc(bc, OP_throw_error);
  33384                 dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
  33385                 dbuf_putc(bc, JS_THROW_VAR_RO);
  33386                 goto done;
  33387             }
  33388             switch (op) {
  33389             case OP_scope_make_ref:
  33390                 if (s->closure_var[idx].var_kind == JS_VAR_FUNCTION_NAME) {
  33391                     /* Create a dummy object reference for the func_var */
  33392                     dbuf_putc(bc, OP_object);
  33393                     dbuf_putc(bc, OP_get_var_ref);
  33394                     dbuf_put_u16(bc, idx);
  33395                     dbuf_putc(bc, OP_define_field);
  33396                     dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
  33397                     dbuf_putc(bc, OP_push_atom_value);
  33398                     dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
  33399                 } else
  33400                 if (label_done == -1 &&
  33401                     can_opt_put_ref_value(bc_buf, ls->pos)) {
  33402                     int get_op;
  33403                     if (s->closure_var[idx].is_lexical)
  33404                         get_op = OP_get_var_ref_check;
  33405                     else
  33406                         get_op = OP_get_var_ref;
  33407                     pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,
  33408                                                        pos_next,
  33409                                                        get_op, idx);
  33410                 } else {
  33411                     /* Create a dummy object with a named slot that is
  33412                        a reference to the closure variable */
  33413                     dbuf_putc(bc, OP_make_var_ref_ref);
  33414                     dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
  33415                     dbuf_put_u16(bc, idx);
  33416                 }
  33417                 break;
  33418             case OP_scope_put_var:
  33419                 if (s->closure_var[idx].var_kind == JS_VAR_FUNCTION_NAME) {
  33420                     /* in non strict mode, modifying the function name is ignored */
  33421                     dbuf_putc(bc, OP_drop);
  33422                     goto done;
  33423                 }
  33424                 goto closure_scope_var;
  33425             case OP_scope_get_ref:
  33426                 /* XXX: should create a dummy object with a named slot that is
  33427                    a reference to the closure variable */
  33428                 dbuf_putc(bc, OP_undefined);
  33429                 goto closure_scope_var;
  33430             case OP_scope_get_var_undef:
  33431             case OP_scope_get_var:
  33432             case OP_scope_put_var_init:
  33433             closure_scope_var:
  33434                 is_put = (op == OP_scope_put_var ||
  33435                           op == OP_scope_put_var_init);
  33436                 if (is_put) {
  33437                     if (s->closure_var[idx].is_lexical) {
  33438                         if (op == OP_scope_put_var_init) {
  33439                             /* 'this' can only be initialized once */
  33440                             if (var_name == JS_ATOM_this)
  33441                                 dbuf_putc(bc, OP_put_var_ref_check_init);
  33442                             else
  33443                                 dbuf_putc(bc, OP_put_var_ref);
  33444                         } else {
  33445                             dbuf_putc(bc, OP_put_var_ref_check);
  33446                         }
  33447                     } else {
  33448                         dbuf_putc(bc, OP_put_var_ref);
  33449                     }
  33450                 } else {
  33451                     if (s->closure_var[idx].is_lexical) {
  33452                         dbuf_putc(bc, OP_get_var_ref_check);
  33453                     } else {
  33454                         dbuf_putc(bc, OP_get_var_ref);
  33455                     }
  33456                 }
  33457                 dbuf_put_u16(bc, idx);
  33458                 break;
  33459             case OP_scope_delete_var:
  33460                 dbuf_putc(bc, OP_push_false);
  33461                 break;
  33462             }
  33463             goto done;
  33464         }
  33465     }
  33466 
  33467 done:
  33468     if (label_done >= 0) {
  33469         dbuf_putc(bc, OP_label);
  33470         dbuf_put_u32(bc, label_done);
  33471         s->label_slots[label_done].pos2 = bc->size;
  33472     }
  33473     return pos_next;
  33474 }
  33475 
  33476 /* search in all scopes */
  33477 static int find_private_class_field_all(JSContext *ctx, JSFunctionDef *fd,
  33478                                         JSAtom name, int scope_level)
  33479 {
  33480     int idx;
  33481 
  33482     idx = fd->scopes[scope_level].first;
  33483     while (idx >= 0) {
  33484         if (fd->vars[idx].var_name == name)
  33485             return idx;
  33486         idx = fd->vars[idx].scope_next;
  33487     }
  33488     return -1;
  33489 }
  33490 
  33491 static void get_loc_or_ref(DynBuf *bc, BOOL is_ref, int idx)
  33492 {
  33493     /* if the field is not initialized, the error is catched when
  33494        accessing it */
  33495     if (is_ref)
  33496         dbuf_putc(bc, OP_get_var_ref);
  33497     else
  33498         dbuf_putc(bc, OP_get_loc);
  33499     dbuf_put_u16(bc, idx);
  33500 }
  33501 
  33502 static int resolve_scope_private_field1(JSContext *ctx,
  33503                                         BOOL *pis_ref, int *pvar_kind,
  33504                                         JSFunctionDef *s,
  33505                                         JSAtom var_name, int scope_level)
  33506 {
  33507     int idx, var_kind;
  33508     JSFunctionDef *fd;
  33509     BOOL is_ref;
  33510 
  33511     fd = s;
  33512     is_ref = FALSE;
  33513     for(;;) {
  33514         idx = find_private_class_field_all(ctx, fd, var_name, scope_level);
  33515         if (idx >= 0) {
  33516             var_kind = fd->vars[idx].var_kind;
  33517             if (is_ref) {
  33518                 capture_var(fd, &fd->vars[idx]);
  33519                 idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL, idx, var_name,
  33520                                       TRUE, TRUE, JS_VAR_NORMAL);
  33521                 if (idx < 0)
  33522                     return -1;
  33523             }
  33524             break;
  33525         }
  33526         scope_level = fd->parent_scope_level;
  33527         if (!fd->parent) {
  33528             if (fd->is_eval) {
  33529                 /* closure of the eval function (top level) */
  33530                 for (idx = 0; idx < fd->closure_var_count; idx++) {
  33531                     JSClosureVar *cv = &fd->closure_var[idx];
  33532                     if (cv->var_name == var_name) {
  33533                         var_kind = cv->var_kind;
  33534                         is_ref = TRUE;
  33535                         if (fd != s) {
  33536                             idx = get_closure_var(ctx, s, fd,
  33537                                                   JS_CLOSURE_REF,
  33538                                                   idx,
  33539                                                   cv->var_name, cv->is_const,
  33540                                                   cv->is_lexical,
  33541                                                   cv->var_kind);
  33542                             if (idx < 0)
  33543                                 return -1;
  33544                         }
  33545                         goto done;
  33546                     }
  33547                 }
  33548             }
  33549             /* XXX: no line number info */
  33550             JS_ThrowSyntaxErrorAtom(ctx, "undefined private field '%s'",
  33551                                     var_name);
  33552             return -1;
  33553         } else {
  33554             fd = fd->parent;
  33555         }
  33556         is_ref = TRUE;
  33557     }
  33558  done:
  33559     *pis_ref = is_ref;
  33560     *pvar_kind = var_kind;
  33561     return idx;
  33562 }
  33563 
  33564 /* return 0 if OK or -1 if the private field could not be resolved */
  33565 static int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s,
  33566                                        JSAtom var_name, int scope_level, int op,
  33567                                        DynBuf *bc)
  33568 {
  33569     int idx, var_kind;
  33570     BOOL is_ref;
  33571 
  33572     idx = resolve_scope_private_field1(ctx, &is_ref, &var_kind, s,
  33573                                        var_name, scope_level);
  33574     if (idx < 0)
  33575         return -1;
  33576     assert(var_kind != JS_VAR_NORMAL);
  33577     switch (op) {
  33578     case OP_scope_get_private_field:
  33579     case OP_scope_get_private_field2:
  33580         switch(var_kind) {
  33581         case JS_VAR_PRIVATE_FIELD:
  33582             if (op == OP_scope_get_private_field2)
  33583                 dbuf_putc(bc, OP_dup);
  33584             get_loc_or_ref(bc, is_ref, idx);
  33585             dbuf_putc(bc, OP_get_private_field);
  33586             break;
  33587         case JS_VAR_PRIVATE_METHOD:
  33588             get_loc_or_ref(bc, is_ref, idx);
  33589             dbuf_putc(bc, OP_check_brand);
  33590             if (op != OP_scope_get_private_field2)
  33591                 dbuf_putc(bc, OP_nip);
  33592             break;
  33593         case JS_VAR_PRIVATE_GETTER:
  33594         case JS_VAR_PRIVATE_GETTER_SETTER:
  33595             if (op == OP_scope_get_private_field2)
  33596                 dbuf_putc(bc, OP_dup);
  33597             get_loc_or_ref(bc, is_ref, idx);
  33598             dbuf_putc(bc, OP_check_brand);
  33599             dbuf_putc(bc, OP_call_method);
  33600             dbuf_put_u16(bc, 0);
  33601             break;
  33602         case JS_VAR_PRIVATE_SETTER:
  33603             /* XXX: add clearer error message */
  33604             dbuf_putc(bc, OP_throw_error);
  33605             dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
  33606             dbuf_putc(bc, JS_THROW_VAR_RO);
  33607             break;
  33608         default:
  33609             abort();
  33610         }
  33611         break;
  33612     case OP_scope_put_private_field:
  33613         switch(var_kind) {
  33614         case JS_VAR_PRIVATE_FIELD:
  33615             get_loc_or_ref(bc, is_ref, idx);
  33616             dbuf_putc(bc, OP_put_private_field);
  33617             break;
  33618         case JS_VAR_PRIVATE_METHOD:
  33619         case JS_VAR_PRIVATE_GETTER:
  33620             /* XXX: add clearer error message */
  33621             dbuf_putc(bc, OP_throw_error);
  33622             dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
  33623             dbuf_putc(bc, JS_THROW_VAR_RO);
  33624             break;
  33625         case JS_VAR_PRIVATE_SETTER:
  33626         case JS_VAR_PRIVATE_GETTER_SETTER:
  33627             {
  33628                 JSAtom setter_name = get_private_setter_name(ctx, var_name);
  33629                 if (setter_name == JS_ATOM_NULL)
  33630                     return -1;
  33631                 idx = resolve_scope_private_field1(ctx, &is_ref,
  33632                                                    &var_kind, s,
  33633                                                    setter_name, scope_level);
  33634                 JS_FreeAtom(ctx, setter_name);
  33635                 if (idx < 0)
  33636                     return -1;
  33637                 assert(var_kind == JS_VAR_PRIVATE_SETTER);
  33638                 get_loc_or_ref(bc, is_ref, idx);
  33639                 dbuf_putc(bc, OP_swap);
  33640                 /* obj func value */
  33641                 dbuf_putc(bc, OP_rot3r);
  33642                 /* value obj func */
  33643                 dbuf_putc(bc, OP_check_brand);
  33644                 dbuf_putc(bc, OP_rot3l);
  33645                 /* obj func value */
  33646                 dbuf_putc(bc, OP_call_method);
  33647                 dbuf_put_u16(bc, 1);
  33648                 dbuf_putc(bc, OP_drop);
  33649             }
  33650             break;
  33651         default:
  33652             abort();
  33653         }
  33654         break;
  33655     case OP_scope_in_private_field:
  33656         get_loc_or_ref(bc, is_ref, idx);
  33657         dbuf_putc(bc, OP_private_in);
  33658         break;
  33659     default:
  33660         abort();
  33661     }
  33662     return 0;
  33663 }
  33664 
  33665 static void mark_eval_captured_variables(JSContext *ctx, JSFunctionDef *s,
  33666                                          int scope_level)
  33667 {
  33668     int idx;
  33669     JSVarDef *vd;
  33670 
  33671     for (idx = s->scopes[scope_level].first; idx >= 0;) {
  33672         vd = &s->vars[idx];
  33673         capture_var(s, vd);
  33674         idx = vd->scope_next;
  33675     }
  33676 }
  33677 
  33678 /* XXX: should handle the argument scope generically */
  33679 static BOOL is_var_in_arg_scope(JSAtom var_name, JSVarKindEnum var_kind)
  33680 {
  33681     return (var_name == JS_ATOM_home_object ||
  33682             var_name == JS_ATOM_this_active_func ||
  33683             var_name == JS_ATOM_new_target ||
  33684             var_name == JS_ATOM_this ||
  33685             var_name == JS_ATOM__arg_var_ ||
  33686             var_kind == JS_VAR_FUNCTION_NAME);
  33687 }
  33688 
  33689 static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
  33690 {
  33691     JSFunctionDef *fd;
  33692     JSVarDef *vd;
  33693     int i, scope_level, scope_idx;
  33694     BOOL has_arguments_binding, has_this_binding, is_arg_scope;
  33695 
  33696     /* in non strict mode, variables are created in the caller's
  33697        environment object */
  33698     if (!s->is_eval && !(s->js_mode & JS_MODE_STRICT)) {
  33699         s->var_object_idx = add_var(ctx, s, JS_ATOM__var_);
  33700         if (s->has_parameter_expressions) {
  33701             /* an additional variable object is needed for the
  33702                argument scope */
  33703             s->arg_var_object_idx = add_var(ctx, s, JS_ATOM__arg_var_);
  33704         }
  33705     }
  33706 
  33707     /* eval can potentially use 'arguments' so we must define it */
  33708     has_this_binding = s->has_this_binding;
  33709     if (has_this_binding) {
  33710         if (s->this_var_idx < 0)
  33711             s->this_var_idx = add_var_this(ctx, s);
  33712         if (s->new_target_var_idx < 0)
  33713             s->new_target_var_idx = add_var(ctx, s, JS_ATOM_new_target);
  33714         if (s->is_derived_class_constructor && s->this_active_func_var_idx < 0)
  33715             s->this_active_func_var_idx = add_var(ctx, s, JS_ATOM_this_active_func);
  33716         if (s->has_home_object && s->home_object_var_idx < 0)
  33717             s->home_object_var_idx = add_var(ctx, s, JS_ATOM_home_object);
  33718     }
  33719     has_arguments_binding = s->has_arguments_binding;
  33720     if (has_arguments_binding) {
  33721         add_arguments_var(ctx, s);
  33722         /* also add an arguments binding in the argument scope to
  33723            raise an error if a direct eval in the argument scope tries
  33724            to redefine it */
  33725         if (s->has_parameter_expressions && !(s->js_mode & JS_MODE_STRICT))
  33726             add_arguments_arg(ctx, s);
  33727     }
  33728     if (s->is_func_expr && s->func_name != JS_ATOM_NULL)
  33729         add_func_var(ctx, s, s->func_name);
  33730 
  33731     for(i = 0; i < s->arg_count; i++) {
  33732         vd = &s->args[i];
  33733         capture_var(s, vd);
  33734     }
  33735     for(i = 0; i < s->var_count; i++) {
  33736         vd = &s->vars[i];
  33737         /* do not close top level last result */
  33738         if (vd->scope_level == 0 &&
  33739             vd->var_name != JS_ATOM__ret_ &&
  33740             vd->var_name != JS_ATOM_NULL) {
  33741             capture_var(s, vd);
  33742         }
  33743     }
  33744     
  33745     /* eval can use all the variables of the enclosing functions, so
  33746        they must be all put in the closure. The closure variables are
  33747        ordered by scope. It works only because no closure are created
  33748        before. */
  33749     assert(s->is_eval || s->closure_var_count == 0);
  33750 
  33751     /* XXX: inefficient, but eval performance is less critical */
  33752     fd = s;
  33753     for(;;) {
  33754         scope_level = fd->parent_scope_level;
  33755         fd = fd->parent;
  33756         if (!fd)
  33757             break;
  33758         /* add 'this' if it was not previously added */
  33759         if (!has_this_binding && fd->has_this_binding) {
  33760             if (fd->this_var_idx < 0)
  33761                 fd->this_var_idx = add_var_this(ctx, fd);
  33762             if (fd->new_target_var_idx < 0)
  33763                 fd->new_target_var_idx = add_var(ctx, fd, JS_ATOM_new_target);
  33764             if (fd->is_derived_class_constructor && fd->this_active_func_var_idx < 0)
  33765                 fd->this_active_func_var_idx = add_var(ctx, fd, JS_ATOM_this_active_func);
  33766             if (fd->has_home_object && fd->home_object_var_idx < 0)
  33767                 fd->home_object_var_idx = add_var(ctx, fd, JS_ATOM_home_object);
  33768             has_this_binding = TRUE;
  33769         }
  33770         /* add 'arguments' if it was not previously added */
  33771         if (!has_arguments_binding && fd->has_arguments_binding) {
  33772             add_arguments_var(ctx, fd);
  33773             has_arguments_binding = TRUE;
  33774         }
  33775         /* add function name */
  33776         if (fd->is_func_expr && fd->func_name != JS_ATOM_NULL)
  33777             add_func_var(ctx, fd, fd->func_name);
  33778 
  33779         /* add lexical variables */
  33780         scope_idx = fd->scopes[scope_level].first;
  33781         while (scope_idx >= 0) {
  33782             vd = &fd->vars[scope_idx];
  33783             capture_var(fd, vd);
  33784             get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL, scope_idx,
  33785                             vd->var_name, vd->is_const, vd->is_lexical, vd->var_kind);
  33786             scope_idx = vd->scope_next;
  33787         }
  33788         is_arg_scope = (scope_idx == ARG_SCOPE_END);
  33789         if (!is_arg_scope) {
  33790             /* add unscoped variables */
  33791             /* XXX: propagate is_const and var_kind too ? */
  33792             for(i = 0; i < fd->arg_count; i++) {
  33793                 vd = &fd->args[i];
  33794                 if (vd->var_name != JS_ATOM_NULL) {
  33795                     capture_var(fd, vd);
  33796                     get_closure_var(ctx, s, fd,
  33797                                     JS_CLOSURE_ARG, i, vd->var_name, FALSE,
  33798                                     vd->is_lexical, JS_VAR_NORMAL);
  33799                 }
  33800             }
  33801             for(i = 0; i < fd->var_count; i++) {
  33802                 vd = &fd->vars[i];
  33803                 /* do not close top level last result */
  33804                 if (vd->scope_level == 0 &&
  33805                     vd->var_name != JS_ATOM__ret_ &&
  33806                     vd->var_name != JS_ATOM_NULL) {
  33807                     capture_var(fd, vd);
  33808                     get_closure_var(ctx, s, fd,
  33809                                     JS_CLOSURE_LOCAL, i, vd->var_name, FALSE,
  33810                                     vd->is_lexical, JS_VAR_NORMAL);
  33811                 }
  33812             }
  33813         } else {
  33814             for(i = 0; i < fd->var_count; i++) {
  33815                 vd = &fd->vars[i];
  33816                 /* do not close top level last result */
  33817                 if (vd->scope_level == 0 && is_var_in_arg_scope(vd->var_name, vd->var_kind)) {
  33818                     capture_var(fd, vd);
  33819                     get_closure_var(ctx, s, fd,
  33820                                     JS_CLOSURE_LOCAL, i, vd->var_name, FALSE,
  33821                                     vd->is_lexical, JS_VAR_NORMAL);
  33822                 }
  33823             }
  33824         }
  33825         if (fd->is_eval) {
  33826             int idx;
  33827             /* add direct eval variables (we are necessarily at the
  33828                top level). */
  33829             for (idx = 0; idx < fd->closure_var_count; idx++) {
  33830                 JSClosureVar *cv = &fd->closure_var[idx];
  33831                 /* Global variables are removed but module
  33832                    definitions are kept. */
  33833                 if (cv->closure_type != JS_CLOSURE_GLOBAL_REF &&
  33834                     cv->closure_type != JS_CLOSURE_GLOBAL_DECL &&
  33835                     cv->closure_type != JS_CLOSURE_GLOBAL) {
  33836                     get_closure_var(ctx, s, fd,
  33837                                     JS_CLOSURE_REF,
  33838                                     idx, cv->var_name, cv->is_const,
  33839                                     cv->is_lexical, cv->var_kind);
  33840                 }
  33841             }
  33842         }
  33843     }
  33844 }
  33845 
  33846 static void set_closure_from_var(JSContext *ctx, JSClosureVar *cv,
  33847                                  JSBytecodeVarDef *vd, int var_idx)
  33848 {
  33849     cv->closure_type = JS_CLOSURE_LOCAL;
  33850     cv->is_const = vd->is_const;
  33851     cv->is_lexical = vd->is_lexical;
  33852     cv->var_kind = vd->var_kind;
  33853     cv->var_idx = var_idx;
  33854     cv->var_name = JS_DupAtom(ctx, vd->var_name);
  33855 }
  33856 
  33857 /* for direct eval compilation: add references to the variables of the
  33858    calling function */
  33859 static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
  33860                                              JSFunctionBytecode *b, int scope_idx)
  33861 {
  33862     int i, count;
  33863     JSBytecodeVarDef *vd;
  33864     BOOL is_arg_scope;
  33865 
  33866     count = b->arg_count + b->var_count + b->closure_var_count;
  33867     s->closure_var = NULL;
  33868     s->closure_var_count = 0;
  33869     s->closure_var_size = count;
  33870     if (count == 0)
  33871         return 0;
  33872     s->closure_var = js_malloc(ctx, sizeof(s->closure_var[0]) * count);
  33873     if (!s->closure_var)
  33874         return -1;
  33875     /* Add lexical variables in scope at the point of evaluation */
  33876     for (i = scope_idx; i >= 0;) {
  33877         vd = &b->vardefs[b->arg_count + i];
  33878         if (vd->has_scope) {
  33879             JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
  33880             set_closure_from_var(ctx, cv, vd, i);
  33881         }
  33882         i = vd->scope_next;
  33883     }
  33884     is_arg_scope = (i == ARG_SCOPE_END);
  33885     if (!is_arg_scope) {
  33886         /* Add argument variables */
  33887         for(i = 0; i < b->arg_count; i++) {
  33888             JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
  33889             vd = &b->vardefs[i];
  33890             cv->closure_type = JS_CLOSURE_ARG;
  33891             cv->is_const = FALSE;
  33892             cv->is_lexical = FALSE;
  33893             cv->var_kind = JS_VAR_NORMAL;
  33894             cv->var_idx = i;
  33895             cv->var_name = JS_DupAtom(ctx, vd->var_name);
  33896         }
  33897         /* Add local non lexical variables */
  33898         for(i = 0; i < b->var_count; i++) {
  33899             vd = &b->vardefs[b->arg_count + i];
  33900             if (!vd->has_scope && vd->var_name != JS_ATOM__ret_) {
  33901                 JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
  33902                 set_closure_from_var(ctx, cv, vd, i);
  33903             }
  33904         }
  33905     } else {
  33906         /* only add pseudo variables */
  33907         for(i = 0; i < b->var_count; i++) {
  33908             vd = &b->vardefs[b->arg_count + i];
  33909             if (!vd->has_scope && is_var_in_arg_scope(vd->var_name, vd->var_kind)) {
  33910                 JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
  33911                 set_closure_from_var(ctx, cv, vd, i);
  33912             }
  33913         }
  33914     }
  33915     for(i = 0; i < b->closure_var_count; i++) {
  33916         JSClosureVar *cv0 = &b->closure_var[i];
  33917         JSClosureVar *cv;
  33918 
  33919         switch(cv0->closure_type) {
  33920         case JS_CLOSURE_LOCAL:
  33921         case JS_CLOSURE_ARG:
  33922         case JS_CLOSURE_REF:
  33923         case JS_CLOSURE_MODULE_DECL:
  33924         case JS_CLOSURE_MODULE_IMPORT:
  33925             break;
  33926         case JS_CLOSURE_GLOBAL_REF:
  33927         case JS_CLOSURE_GLOBAL_DECL:
  33928         case JS_CLOSURE_GLOBAL:
  33929             continue; /* not necessary to add global variables */
  33930         default:
  33931             abort();
  33932         }
  33933         cv = &s->closure_var[s->closure_var_count++];
  33934         cv->closure_type = JS_CLOSURE_REF;
  33935         cv->is_const = cv0->is_const;
  33936         cv->is_lexical = cv0->is_lexical;
  33937         cv->var_kind = cv0->var_kind;
  33938         cv->var_idx = i;
  33939         cv->var_name = JS_DupAtom(ctx, cv0->var_name);
  33940     }
  33941     return 0;
  33942 }
  33943 
  33944 typedef struct CodeContext {
  33945     const uint8_t *bc_buf; /* code buffer */
  33946     int bc_len;   /* length of the code buffer */
  33947     int pos;      /* position past the matched code pattern */
  33948     int line_num; /* last visited OP_line_num parameter or -1 */
  33949     int op;
  33950     int idx;
  33951     int label;
  33952     int val;
  33953     JSAtom atom;
  33954 } CodeContext;
  33955 
  33956 #define M2(op1, op2)            ((int)((uint32_t)(op1) | ((uint32_t)(op2) << 8)))
  33957 #define M3(op1, op2, op3)       ((int)((uint32_t)(op1) | ((uint32_t)(op2) << 8) | ((uint32_t)(op3) << 16)))
  33958 #define M4(op1, op2, op3, op4)  ((int)((uint32_t)(op1) | ((uint32_t)(op2) << 8) | ((uint32_t)(op3) << 16) | ((uint32_t)(op4) << 24)))
  33959 
  33960 static BOOL code_match(CodeContext *s, int pos, ...)
  33961 {
  33962     const uint8_t *tab = s->bc_buf;
  33963     int op, len, op1, line_num, pos_next;
  33964     va_list ap;
  33965     BOOL ret = FALSE;
  33966 
  33967     line_num = -1;
  33968     va_start(ap, pos);
  33969 
  33970     for(;;) {
  33971         op1 = va_arg(ap, int);
  33972         if (op1 == -1) {
  33973             s->pos = pos;
  33974             s->line_num = line_num;
  33975             ret = TRUE;
  33976             break;
  33977         }
  33978         for (;;) {
  33979             if (pos >= s->bc_len)
  33980                 goto done;
  33981             op = tab[pos];
  33982             len = opcode_info[op].size;
  33983             pos_next = pos + len;
  33984             if (pos_next > s->bc_len)
  33985                 goto done;
  33986             if (op == OP_line_num) {
  33987                 line_num = get_u32(tab + pos + 1);
  33988                 pos = pos_next;
  33989             } else {
  33990                 break;
  33991             }
  33992         }
  33993         if (op != op1) {
  33994             if (op1 == (uint8_t)op1 || !op)
  33995                 break;
  33996             if (op != (uint8_t)op1
  33997             &&  op != (uint8_t)(op1 >> 8)
  33998             &&  op != (uint8_t)(op1 >> 16)
  33999             &&  op != (uint8_t)(op1 >> 24)) {
  34000                 break;
  34001             }
  34002             s->op = op;
  34003         }
  34004 
  34005         pos++;
  34006         switch(opcode_info[op].fmt) {
  34007         case OP_FMT_loc8:
  34008         case OP_FMT_u8:
  34009             {
  34010                 int idx = tab[pos];
  34011                 int arg = va_arg(ap, int);
  34012                 if (arg == -1) {
  34013                     s->idx = idx;
  34014                 } else {
  34015                     if (arg != idx)
  34016                         goto done;
  34017                 }
  34018                 break;
  34019             }
  34020         case OP_FMT_u16:
  34021         case OP_FMT_npop:
  34022         case OP_FMT_loc:
  34023         case OP_FMT_arg:
  34024         case OP_FMT_var_ref:
  34025             {
  34026                 int idx = get_u16(tab + pos);
  34027                 int arg = va_arg(ap, int);
  34028                 if (arg == -1) {
  34029                     s->idx = idx;
  34030                 } else {
  34031                     if (arg != idx)
  34032                         goto done;
  34033                 }
  34034                 break;
  34035             }
  34036         case OP_FMT_i32:
  34037         case OP_FMT_u32:
  34038         case OP_FMT_label:
  34039         case OP_FMT_const:
  34040             {
  34041                 s->label = get_u32(tab + pos);
  34042                 break;
  34043             }
  34044         case OP_FMT_label_u16:
  34045             {
  34046                 s->label = get_u32(tab + pos);
  34047                 s->val = get_u16(tab + pos + 4);
  34048                 break;
  34049             }
  34050         case OP_FMT_atom:
  34051             {
  34052                 s->atom = get_u32(tab + pos);
  34053                 break;
  34054             }
  34055         case OP_FMT_atom_u8:
  34056             {
  34057                 s->atom = get_u32(tab + pos);
  34058                 s->val = get_u8(tab + pos + 4);
  34059                 break;
  34060             }
  34061         case OP_FMT_atom_u16:
  34062             {
  34063                 s->atom = get_u32(tab + pos);
  34064                 s->val = get_u16(tab + pos + 4);
  34065                 break;
  34066             }
  34067         case OP_FMT_atom_label_u8:
  34068             {
  34069                 s->atom = get_u32(tab + pos);
  34070                 s->label = get_u32(tab + pos + 4);
  34071                 s->val = get_u8(tab + pos + 8);
  34072                 break;
  34073             }
  34074         default:
  34075             break;
  34076         }
  34077         pos = pos_next;
  34078     }
  34079  done:
  34080     va_end(ap);
  34081     return ret;
  34082 }
  34083 
  34084 static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, DynBuf *bc)
  34085 {
  34086     int i, idx, label_next = -1;
  34087 
  34088     /* add the hoisted functions in arguments and local variables */
  34089     for(i = 0; i < s->arg_count; i++) {
  34090         JSVarDef *vd = &s->args[i];
  34091         if (vd->func_pool_idx >= 0) {
  34092             dbuf_putc(bc, OP_fclosure);
  34093             dbuf_put_u32(bc, vd->func_pool_idx);
  34094             dbuf_putc(bc, OP_put_arg);
  34095             dbuf_put_u16(bc, i);
  34096         }
  34097     }
  34098     for(i = 0; i < s->var_count; i++) {
  34099         JSVarDef *vd = &s->vars[i];
  34100         if (vd->scope_level == 0 && vd->func_pool_idx >= 0) {
  34101             dbuf_putc(bc, OP_fclosure);
  34102             dbuf_put_u32(bc, vd->func_pool_idx);
  34103             dbuf_putc(bc, OP_put_loc);
  34104             dbuf_put_u16(bc, i);
  34105         }
  34106     }
  34107 
  34108     /* the module global variables must be initialized before
  34109        evaluating the module so that the exported functions are
  34110        visible if there are cyclic module references */
  34111     if (s->module) {
  34112         label_next = new_label_fd(s);
  34113         if (label_next < 0) {
  34114             dbuf_set_error(bc);
  34115             return;
  34116         }
  34117         /* if 'this' is true, initialize the global variables and return */
  34118         dbuf_putc(bc, OP_push_this);
  34119         dbuf_putc(bc, OP_if_false);
  34120         dbuf_put_u32(bc, label_next);
  34121         update_label(s, label_next, 1);
  34122         s->jump_size++;
  34123     }
  34124 
  34125     /* add the global variables (only happens if s->is_global_var is
  34126        true) */
  34127     /* XXX: inefficient, add a closure index in JSGlobalVar */
  34128     for(i = 0; i < s->global_var_count; i++) {
  34129         JSGlobalVar *hf = &s->global_vars[i];
  34130         BOOL has_var_obj = FALSE;
  34131         BOOL force_init = hf->force_init;
  34132         /* we are in an eval, so the closure contains all the
  34133            enclosing variables */
  34134         /* If the outer function has a variable environment,
  34135            create a property for the variable there */
  34136         for(idx = 0; idx < s->closure_var_count; idx++) {
  34137             JSClosureVar *cv = &s->closure_var[idx];
  34138             if (cv->var_name == hf->var_name) {
  34139                 force_init = FALSE;
  34140                 goto closure_found;
  34141             }
  34142             if (cv->var_name == JS_ATOM__var_ ||
  34143                 cv->var_name == JS_ATOM__arg_var_) {
  34144                 dbuf_putc(bc, OP_get_var_ref);
  34145                 dbuf_put_u16(bc, idx);
  34146                 has_var_obj = TRUE;
  34147                 force_init = TRUE;
  34148                 goto closure_found;
  34149             }
  34150         }
  34151         abort();
  34152     closure_found:
  34153         if (hf->cpool_idx >= 0 || force_init) {
  34154             if (hf->cpool_idx >= 0) {
  34155                 dbuf_putc(bc, OP_fclosure);
  34156                 dbuf_put_u32(bc, hf->cpool_idx);
  34157                 if (hf->var_name == JS_ATOM__default_) {
  34158                     /* set default export function name */
  34159                     dbuf_putc(bc, OP_set_name);
  34160                     dbuf_put_u32(bc, JS_DupAtom(ctx, JS_ATOM_default));
  34161                 }
  34162             } else {
  34163                 dbuf_putc(bc, OP_undefined);
  34164             }
  34165             if (!has_var_obj) {
  34166                 dbuf_putc(bc, OP_put_var_ref);
  34167                 dbuf_put_u16(bc, idx);
  34168             } else {
  34169                 dbuf_putc(bc, OP_define_field);
  34170                 dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
  34171                 dbuf_putc(bc, OP_drop);
  34172             }
  34173         }
  34174         JS_FreeAtom(ctx, hf->var_name);
  34175     }
  34176 
  34177     if (s->module) {
  34178         dbuf_putc(bc, OP_return_undef);
  34179 
  34180         dbuf_putc(bc, OP_label);
  34181         dbuf_put_u32(bc, label_next);
  34182         s->label_slots[label_next].pos2 = bc->size;
  34183     }
  34184 
  34185     js_free(ctx, s->global_vars);
  34186     s->global_vars = NULL;
  34187     s->global_var_count = 0;
  34188     s->global_var_size = 0;
  34189 }
  34190 
  34191 static int skip_dead_code(JSFunctionDef *s, const uint8_t *bc_buf, int bc_len,
  34192                           int pos, int *linep)
  34193 {
  34194     int op, len, label;
  34195 
  34196     for (; pos < bc_len; pos += len) {
  34197         op = bc_buf[pos];
  34198         len = opcode_info[op].size;
  34199         if (op == OP_line_num) {
  34200             *linep = get_u32(bc_buf + pos + 1);
  34201         } else
  34202         if (op == OP_label) {
  34203             label = get_u32(bc_buf + pos + 1);
  34204             if (update_label(s, label, 0) > 0)
  34205                 break;
  34206 #if 0
  34207             if (s->label_slots[label].first_reloc) {
  34208                 printf("line %d: unreferenced label %d:%d has relocations\n",
  34209                        *linep, label, s->label_slots[label].pos2);
  34210             }
  34211 #endif
  34212             assert(s->label_slots[label].first_reloc == NULL);
  34213         } else {
  34214             /* XXX: output a warning for unreachable code? */
  34215             JSAtom atom;
  34216             switch(opcode_info[op].fmt) {
  34217             case OP_FMT_label:
  34218             case OP_FMT_label_u16:
  34219                 label = get_u32(bc_buf + pos + 1);
  34220                 update_label(s, label, -1);
  34221                 break;
  34222             case OP_FMT_atom_label_u8:
  34223             case OP_FMT_atom_label_u16:
  34224                 label = get_u32(bc_buf + pos + 5);
  34225                 update_label(s, label, -1);
  34226                 /* fall thru */
  34227             case OP_FMT_atom:
  34228             case OP_FMT_atom_u8:
  34229             case OP_FMT_atom_u16:
  34230                 atom = get_u32(bc_buf + pos + 1);
  34231                 JS_FreeAtom(s->ctx, atom);
  34232                 break;
  34233             default:
  34234                 break;
  34235             }
  34236         }
  34237     }
  34238     return pos;
  34239 }
  34240 
  34241 static int get_label_pos(JSFunctionDef *s, int label)
  34242 {
  34243     int i, pos;
  34244     for (i = 0; i < 20; i++) {
  34245         pos = s->label_slots[label].pos;
  34246         for (;;) {
  34247             switch (s->byte_code.buf[pos]) {
  34248             case OP_line_num:
  34249             case OP_label:
  34250                 pos += 5;
  34251                 continue;
  34252             case OP_goto:
  34253                 label = get_u32(s->byte_code.buf + pos + 1);
  34254                 break;
  34255             default:
  34256                 return pos;
  34257             }
  34258             break;
  34259         }
  34260     }
  34261     return pos;
  34262 }
  34263 
  34264 /* convert global variable accesses to local variables or closure
  34265    variables when necessary */
  34266 static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
  34267 {
  34268     int pos, pos_next, bc_len, op, len, line_num, i, idx;
  34269     uint8_t *bc_buf;
  34270     JSAtom var_name;
  34271     DynBuf bc_out;
  34272     CodeContext cc;
  34273     int scope;
  34274 
  34275     cc.bc_buf = bc_buf = s->byte_code.buf;
  34276     cc.bc_len = bc_len = s->byte_code.size;
  34277     js_dbuf_bytecode_init(ctx, &bc_out);
  34278 
  34279     /* first pass for runtime checks (must be done before the
  34280        variables are created) */
  34281     /* XXX: inefficient */
  34282     for(i = 0; i < s->global_var_count; i++) {
  34283         JSGlobalVar *hf = &s->global_vars[i];
  34284 
  34285         /* check if global variable (XXX: simplify) */
  34286         for(idx = 0; idx < s->closure_var_count; idx++) {
  34287             JSClosureVar *cv = &s->closure_var[idx];
  34288             if (cv->closure_type == JS_CLOSURE_GLOBAL_REF ||
  34289                 cv->closure_type == JS_CLOSURE_GLOBAL_DECL ||
  34290                 cv->closure_type == JS_CLOSURE_GLOBAL ||
  34291                 cv->closure_type == JS_CLOSURE_MODULE_DECL ||
  34292                 cv->closure_type == JS_CLOSURE_MODULE_IMPORT)
  34293                 goto next; /* don't look at global variables (they are at the end) */
  34294             if (cv->var_name == hf->var_name) {
  34295                 if (s->eval_type == JS_EVAL_TYPE_DIRECT &&
  34296                     cv->is_lexical) {
  34297                     /* Check if a lexical variable is
  34298                        redefined as 'var'. XXX: Could abort
  34299                        compilation here, but for consistency
  34300                        with the other checks, we delay the
  34301                        error generation. */
  34302                     dbuf_putc(&bc_out, OP_throw_error);
  34303                     dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
  34304                     dbuf_putc(&bc_out, JS_THROW_VAR_REDECL);
  34305                 }
  34306                 goto next;
  34307             }
  34308             if (cv->var_name == JS_ATOM__var_ ||
  34309                 cv->var_name == JS_ATOM__arg_var_)
  34310                 goto next;
  34311         }
  34312     next: ;
  34313     }
  34314 
  34315     line_num = 0; /* avoid warning */
  34316     for (pos = 0; pos < bc_len; pos = pos_next) {
  34317         op = bc_buf[pos];
  34318         len = opcode_info[op].size;
  34319         pos_next = pos + len;
  34320         switch(op) {
  34321         case OP_line_num:
  34322             line_num = get_u32(bc_buf + pos + 1);
  34323             s->line_number_size++;
  34324             goto no_change;
  34325 
  34326         case OP_eval: /* convert scope index to adjusted variable index */
  34327             {
  34328                 int call_argc = get_u16(bc_buf + pos + 1);
  34329                 scope = get_u16(bc_buf + pos + 1 + 2);
  34330                 mark_eval_captured_variables(ctx, s, scope);
  34331                 dbuf_putc(&bc_out, op);
  34332                 dbuf_put_u16(&bc_out, call_argc);
  34333                 dbuf_put_u16(&bc_out, s->scopes[scope].first - ARG_SCOPE_END);
  34334             }
  34335             break;
  34336         case OP_apply_eval: /* convert scope index to adjusted variable index */
  34337             scope = get_u16(bc_buf + pos + 1);
  34338             mark_eval_captured_variables(ctx, s, scope);
  34339             dbuf_putc(&bc_out, op);
  34340             dbuf_put_u16(&bc_out, s->scopes[scope].first - ARG_SCOPE_END);
  34341             break;
  34342         case OP_scope_get_var_checkthis:
  34343         case OP_scope_get_var_undef:
  34344         case OP_scope_get_var:
  34345         case OP_scope_put_var:
  34346         case OP_scope_delete_var:
  34347         case OP_scope_get_ref:
  34348         case OP_scope_put_var_init:
  34349             var_name = get_u32(bc_buf + pos + 1);
  34350             scope = get_u16(bc_buf + pos + 5);
  34351             pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
  34352                                          NULL, NULL, pos_next);
  34353             JS_FreeAtom(ctx, var_name);
  34354             break;
  34355         case OP_scope_make_ref:
  34356             {
  34357                 int label;
  34358                 LabelSlot *ls;
  34359                 var_name = get_u32(bc_buf + pos + 1);
  34360                 label = get_u32(bc_buf + pos + 5);
  34361                 scope = get_u16(bc_buf + pos + 9);
  34362                 ls = &s->label_slots[label];
  34363                 ls->ref_count--;  /* always remove label reference */
  34364                 pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
  34365                                              bc_buf, ls, pos_next);
  34366                 JS_FreeAtom(ctx, var_name);
  34367             }
  34368             break;
  34369         case OP_scope_get_private_field:
  34370         case OP_scope_get_private_field2:
  34371         case OP_scope_put_private_field:
  34372         case OP_scope_in_private_field:
  34373             {
  34374                 int ret;
  34375                 var_name = get_u32(bc_buf + pos + 1);
  34376                 scope = get_u16(bc_buf + pos + 5);
  34377                 ret = resolve_scope_private_field(ctx, s, var_name, scope, op, &bc_out);
  34378                 if (ret < 0)
  34379                     goto fail;
  34380                 JS_FreeAtom(ctx, var_name);
  34381             }
  34382             break;
  34383         case OP_gosub:
  34384             s->jump_size++;
  34385             if (OPTIMIZE) {
  34386                 /* remove calls to empty finalizers  */
  34387                 int label;
  34388                 LabelSlot *ls;
  34389 
  34390                 label = get_u32(bc_buf + pos + 1);
  34391                 assert(label >= 0 && label < s->label_count);
  34392                 ls = &s->label_slots[label];
  34393                 if (code_match(&cc, ls->pos, OP_ret, -1)) {
  34394                     ls->ref_count--;
  34395                     break;
  34396                 }
  34397             }
  34398             goto no_change;
  34399         case OP_drop:
  34400             if (0) {
  34401                 /* remove drops before return_undef */
  34402                 /* do not perform this optimization in pass2 because
  34403                    it breaks patterns recognised in resolve_labels */
  34404                 int pos1 = pos_next;
  34405                 int line1 = line_num;
  34406                 while (code_match(&cc, pos1, OP_drop, -1)) {
  34407                     if (cc.line_num >= 0) line1 = cc.line_num;
  34408                     pos1 = cc.pos;
  34409                 }
  34410                 if (code_match(&cc, pos1, OP_return_undef, -1)) {
  34411                     pos_next = pos1;
  34412                     if (line1 != -1 && line1 != line_num) {
  34413                         line_num = line1;
  34414                         s->line_number_size++;
  34415                         dbuf_putc(&bc_out, OP_line_num);
  34416                         dbuf_put_u32(&bc_out, line_num);
  34417                     }
  34418                     break;
  34419                 }
  34420             }
  34421             goto no_change;
  34422         case OP_insert3:
  34423             if (OPTIMIZE) {
  34424                 /* Transformation: insert3 put_array_el|put_ref_value drop -> put_array_el|put_ref_value */
  34425                 if (code_match(&cc, pos_next, M2(OP_put_array_el, OP_put_ref_value), OP_drop, -1)) {
  34426                     dbuf_putc(&bc_out, cc.op);
  34427                     pos_next = cc.pos;
  34428                     if (cc.line_num != -1 && cc.line_num != line_num) {
  34429                         line_num = cc.line_num;
  34430                         s->line_number_size++;
  34431                         dbuf_putc(&bc_out, OP_line_num);
  34432                         dbuf_put_u32(&bc_out, line_num);
  34433                     }
  34434                     break;
  34435                 }
  34436             }
  34437             goto no_change;
  34438 
  34439         case OP_goto:
  34440             s->jump_size++;
  34441             /* fall thru */
  34442         case OP_tail_call:
  34443         case OP_tail_call_method:
  34444         case OP_return:
  34445         case OP_return_undef:
  34446         case OP_throw:
  34447         case OP_throw_error:
  34448         case OP_ret:
  34449             if (OPTIMIZE) {
  34450                 /* remove dead code */
  34451                 int line = -1;
  34452                 dbuf_put(&bc_out, bc_buf + pos, len);
  34453                 pos = skip_dead_code(s, bc_buf, bc_len, pos + len, &line);
  34454                 pos_next = pos;
  34455                 if (pos < bc_len && line >= 0 && line_num != line) {
  34456                     line_num = line;
  34457                     s->line_number_size++;
  34458                     dbuf_putc(&bc_out, OP_line_num);
  34459                     dbuf_put_u32(&bc_out, line_num);
  34460                 }
  34461                 break;
  34462             }
  34463             goto no_change;
  34464 
  34465         case OP_label:
  34466             {
  34467                 int label;
  34468                 LabelSlot *ls;
  34469 
  34470                 label = get_u32(bc_buf + pos + 1);
  34471                 assert(label >= 0 && label < s->label_count);
  34472                 ls = &s->label_slots[label];
  34473                 ls->pos2 = bc_out.size + opcode_info[op].size;
  34474             }
  34475             goto no_change;
  34476 
  34477         case OP_enter_scope:
  34478             {
  34479                 int scope_idx, scope = get_u16(bc_buf + pos + 1);
  34480 
  34481                 if (scope == s->body_scope) {
  34482                     instantiate_hoisted_definitions(ctx, s, &bc_out);
  34483                 }
  34484 
  34485                 for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {
  34486                     JSVarDef *vd = &s->vars[scope_idx];
  34487                     if (vd->scope_level == scope) {
  34488                         if (scope_idx != s->arguments_arg_idx) {
  34489                             if (vd->var_kind == JS_VAR_FUNCTION_DECL ||
  34490                                 vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) {
  34491                                 /* Initialize lexical variable upon entering scope */
  34492                                 dbuf_putc(&bc_out, OP_fclosure);
  34493                                 dbuf_put_u32(&bc_out, vd->func_pool_idx);
  34494                                 dbuf_putc(&bc_out, OP_put_loc);
  34495                                 dbuf_put_u16(&bc_out, scope_idx);
  34496                             } else {
  34497                                 /* XXX: should check if variable can be used
  34498                                    before initialization */
  34499                                 dbuf_putc(&bc_out, OP_set_loc_uninitialized);
  34500                                 dbuf_put_u16(&bc_out, scope_idx);
  34501                             }
  34502                         }
  34503                         scope_idx = vd->scope_next;
  34504                     } else {
  34505                         break;
  34506                     }
  34507                 }
  34508             }
  34509             break;
  34510 
  34511         case OP_leave_scope:
  34512             {
  34513                 int scope_idx, scope = get_u16(bc_buf + pos + 1);
  34514 
  34515                 for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {
  34516                     JSVarDef *vd = &s->vars[scope_idx];
  34517                     if (vd->scope_level == scope) {
  34518                         if (vd->is_captured) {
  34519                             dbuf_putc(&bc_out, OP_close_loc);
  34520                             dbuf_put_u16(&bc_out, scope_idx);
  34521                         }
  34522                         scope_idx = vd->scope_next;
  34523                     } else {
  34524                         break;
  34525                     }
  34526                 }
  34527             }
  34528             break;
  34529 
  34530         case OP_set_name:
  34531             {
  34532                 /* remove dummy set_name opcodes */
  34533                 JSAtom name = get_u32(bc_buf + pos + 1);
  34534                 if (name == JS_ATOM_NULL)
  34535                     break;
  34536             }
  34537             goto no_change;
  34538 
  34539         case OP_if_false:
  34540         case OP_if_true:
  34541         case OP_catch:
  34542             s->jump_size++;
  34543             goto no_change;
  34544 
  34545         case OP_dup:
  34546             if (OPTIMIZE) {
  34547                 /* Transformation: dup if_false(l1) drop, l1: if_false(l2) -> if_false(l2) */
  34548                 /* Transformation: dup if_true(l1) drop, l1: if_true(l2) -> if_true(l2) */
  34549                 if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), OP_drop, -1)) {
  34550                     int lab0, lab1, op1, pos1, line1, pos2;
  34551                     lab0 = lab1 = cc.label;
  34552                     assert(lab1 >= 0 && lab1 < s->label_count);
  34553                     op1 = cc.op;
  34554                     pos1 = cc.pos;
  34555                     line1 = cc.line_num;
  34556                     while (code_match(&cc, (pos2 = get_label_pos(s, lab1)), OP_dup, op1, OP_drop, -1)) {
  34557                         lab1 = cc.label;
  34558                     }
  34559                     if (code_match(&cc, pos2, op1, -1)) {
  34560                         s->jump_size++;
  34561                         update_label(s, lab0, -1);
  34562                         update_label(s, cc.label, +1);
  34563                         dbuf_putc(&bc_out, op1);
  34564                         dbuf_put_u32(&bc_out, cc.label);
  34565                         pos_next = pos1;
  34566                         if (line1 != -1 && line1 != line_num) {
  34567                             line_num = line1;
  34568                             s->line_number_size++;
  34569                             dbuf_putc(&bc_out, OP_line_num);
  34570                             dbuf_put_u32(&bc_out, line_num);
  34571                         }
  34572                         break;
  34573                     }
  34574                 }
  34575             }
  34576             goto no_change;
  34577 
  34578         case OP_nop:
  34579             /* remove erased code */
  34580             break;
  34581         case OP_set_class_name:
  34582             /* only used during parsing */
  34583             break;
  34584 
  34585         case OP_get_field_opt_chain: /* equivalent to OP_get_field */
  34586             {
  34587                 JSAtom name = get_u32(bc_buf + pos + 1);
  34588                 dbuf_putc(&bc_out, OP_get_field);
  34589                 dbuf_put_u32(&bc_out, name);
  34590             }
  34591             break;
  34592         case OP_get_array_el_opt_chain: /* equivalent to OP_get_array_el */
  34593             dbuf_putc(&bc_out, OP_get_array_el);
  34594             break;
  34595 
  34596         default:
  34597         no_change:
  34598             dbuf_put(&bc_out, bc_buf + pos, len);
  34599             break;
  34600         }
  34601     }
  34602 
  34603     /* set the new byte code */
  34604     dbuf_free(&s->byte_code);
  34605     s->byte_code = bc_out;
  34606     if (dbuf_error(&s->byte_code)) {
  34607         JS_ThrowOutOfMemory(ctx);
  34608         return -1;
  34609     }
  34610     return 0;
  34611  fail:
  34612     /* continue the copy to keep the atom refcounts consistent */
  34613     /* XXX: find a better solution ? */
  34614     for (; pos < bc_len; pos = pos_next) {
  34615         op = bc_buf[pos];
  34616         len = opcode_info[op].size;
  34617         pos_next = pos + len;
  34618         dbuf_put(&bc_out, bc_buf + pos, len);
  34619     }
  34620     dbuf_free(&s->byte_code);
  34621     s->byte_code = bc_out;
  34622     return -1;
  34623 }
  34624 
  34625 /* the pc2line table gives a source position for each PC value */
  34626 static void add_pc2line_info(JSFunctionDef *s, uint32_t pc, uint32_t source_pos)
  34627 {
  34628     if (s->line_number_slots != NULL
  34629     &&  s->line_number_count < s->line_number_size
  34630     &&  pc >= s->line_number_last_pc
  34631     &&  source_pos != s->line_number_last) {
  34632         s->line_number_slots[s->line_number_count].pc = pc;
  34633         s->line_number_slots[s->line_number_count].source_pos = source_pos;
  34634         s->line_number_count++;
  34635         s->line_number_last_pc = pc;
  34636         s->line_number_last = source_pos;
  34637     }
  34638 }
  34639 
  34640 /* XXX: could use a more compact storage */
  34641 /* XXX: get_line_col_cached() is slow. For more predictable
  34642    performance, line/cols could be stored every N source
  34643    bytes. Alternatively, get_line_col_cached() could be issued in
  34644    emit_source_pos() so that the deltas are more likely to be
  34645    small. */
  34646 static void compute_pc2line_info(JSFunctionDef *s)
  34647 {
  34648     if (!s->strip_debug) {
  34649         int last_line_num, last_col_num;
  34650         uint32_t last_pc = 0;
  34651         int i, line_num, col_num;
  34652         const uint8_t *buf_start = s->get_line_col_cache->buf_start;
  34653         js_dbuf_init(s->ctx, &s->pc2line);
  34654 
  34655         last_line_num = get_line_col_cached(s->get_line_col_cache,
  34656                                             &last_col_num,
  34657                                             buf_start + s->source_pos);
  34658         dbuf_put_leb128(&s->pc2line, last_line_num); /* line number minus 1 */
  34659         dbuf_put_leb128(&s->pc2line, last_col_num); /* column number minus 1 */
  34660 
  34661         for (i = 0; i < s->line_number_count; i++) {
  34662             uint32_t pc = s->line_number_slots[i].pc;
  34663             uint32_t source_pos = s->line_number_slots[i].source_pos;
  34664             int diff_pc, diff_line, diff_col;
  34665 
  34666             if (source_pos == -1)
  34667                 continue;
  34668             diff_pc = pc - last_pc;
  34669             if (diff_pc < 0)
  34670                 continue;
  34671 
  34672             line_num = get_line_col_cached(s->get_line_col_cache, &col_num,
  34673                                            buf_start + source_pos);
  34674             diff_line = line_num - last_line_num;
  34675             diff_col = col_num - last_col_num;
  34676             if (diff_line == 0 && diff_col == 0)
  34677                 continue;
  34678 
  34679             if (diff_line >= PC2LINE_BASE &&
  34680                 diff_line < PC2LINE_BASE + PC2LINE_RANGE &&
  34681                 diff_pc <= PC2LINE_DIFF_PC_MAX) {
  34682                 dbuf_putc(&s->pc2line, (diff_line - PC2LINE_BASE) +
  34683                           diff_pc * PC2LINE_RANGE + PC2LINE_OP_FIRST);
  34684             } else {
  34685                 /* longer encoding */
  34686                 dbuf_putc(&s->pc2line, 0);
  34687                 dbuf_put_leb128(&s->pc2line, diff_pc);
  34688                 dbuf_put_sleb128(&s->pc2line, diff_line);
  34689             }
  34690             dbuf_put_sleb128(&s->pc2line, diff_col);
  34691                 
  34692             last_pc = pc;
  34693             last_line_num = line_num;
  34694             last_col_num = col_num;
  34695         }
  34696     }
  34697 }
  34698 
  34699 static RelocEntry *add_reloc(JSContext *ctx, LabelSlot *ls, uint32_t addr, int size)
  34700 {
  34701     RelocEntry *re;
  34702     re = js_malloc(ctx, sizeof(*re));
  34703     if (!re)
  34704         return NULL;
  34705     re->addr = addr;
  34706     re->size = size;
  34707     re->next = ls->first_reloc;
  34708     ls->first_reloc = re;
  34709     return re;
  34710 }
  34711 
  34712 static BOOL code_has_label(CodeContext *s, int pos, int label)
  34713 {
  34714     while (pos < s->bc_len) {
  34715         int op = s->bc_buf[pos];
  34716         if (op == OP_line_num) {
  34717             pos += 5;
  34718             continue;
  34719         }
  34720         if (op == OP_label) {
  34721             int lab = get_u32(s->bc_buf + pos + 1);
  34722             if (lab == label)
  34723                 return TRUE;
  34724             pos += 5;
  34725             continue;
  34726         }
  34727         if (op == OP_goto) {
  34728             int lab = get_u32(s->bc_buf + pos + 1);
  34729             if (lab == label)
  34730                 return TRUE;
  34731         }
  34732         break;
  34733     }
  34734     return FALSE;
  34735 }
  34736 
  34737 /* return the target label, following the OP_goto jumps
  34738    the first opcode at destination is stored in *pop
  34739  */
  34740 static int find_jump_target(JSFunctionDef *s, int label0, int *pop, int *pline)
  34741 {
  34742     int i, pos, op, label;
  34743 
  34744     label = label0;
  34745     update_label(s, label, -1);
  34746     for (i = 0; i < 10; i++) {
  34747         assert(label >= 0 && label < s->label_count);
  34748         pos = s->label_slots[label].pos2;
  34749         for (;;) {
  34750             switch(op = s->byte_code.buf[pos]) {
  34751             case OP_line_num:
  34752                 if (pline)
  34753                     *pline = get_u32(s->byte_code.buf + pos + 1);
  34754                 /* fall thru */
  34755             case OP_label:
  34756                 pos += opcode_info[op].size;
  34757                 continue;
  34758             case OP_goto:
  34759                 label = get_u32(s->byte_code.buf + pos + 1);
  34760                 break;
  34761             case OP_drop:
  34762                 /* ignore drop opcodes if followed by OP_return_undef */
  34763                 while (s->byte_code.buf[++pos] == OP_drop)
  34764                     continue;
  34765                 if (s->byte_code.buf[pos] == OP_return_undef)
  34766                     op = OP_return_undef;
  34767                 /* fall thru */
  34768             default:
  34769                 goto done;
  34770             }
  34771             break;
  34772         }
  34773     }
  34774     /* cycle detected, could issue a warning */
  34775     /* XXX: the combination of find_jump_target() and skip_dead_code()
  34776        seems incorrect with cyclic labels. See for exemple:
  34777 
  34778        for (;;) {
  34779        l:break l;
  34780        l:break l;
  34781        l:break l;
  34782        l:break l;
  34783        }
  34784 
  34785        Avoiding changing the target is just a workaround and might not
  34786        suffice to completely fix the problem. */
  34787     label = label0;
  34788  done:
  34789     *pop = op;
  34790     update_label(s, label, +1);
  34791     return label;
  34792 }
  34793 
  34794 static void push_short_int(DynBuf *bc_out, int val)
  34795 {
  34796 #if SHORT_OPCODES
  34797     if (val >= -1 && val <= 7) {
  34798         dbuf_putc(bc_out, OP_push_0 + val);
  34799         return;
  34800     }
  34801     if (val == (int8_t)val) {
  34802         dbuf_putc(bc_out, OP_push_i8);
  34803         dbuf_putc(bc_out, val);
  34804         return;
  34805     }
  34806     if (val == (int16_t)val) {
  34807         dbuf_putc(bc_out, OP_push_i16);
  34808         dbuf_put_u16(bc_out, val);
  34809         return;
  34810     }
  34811 #endif
  34812     dbuf_putc(bc_out, OP_push_i32);
  34813     dbuf_put_u32(bc_out, val);
  34814 }
  34815 
  34816 static void put_short_code(DynBuf *bc_out, int op, int idx)
  34817 {
  34818 #if SHORT_OPCODES
  34819     if (idx < 4) {
  34820         switch (op) {
  34821         case OP_get_loc:
  34822             dbuf_putc(bc_out, OP_get_loc0 + idx);
  34823             return;
  34824         case OP_put_loc:
  34825             dbuf_putc(bc_out, OP_put_loc0 + idx);
  34826             return;
  34827         case OP_set_loc:
  34828             dbuf_putc(bc_out, OP_set_loc0 + idx);
  34829             return;
  34830         case OP_get_arg:
  34831             dbuf_putc(bc_out, OP_get_arg0 + idx);
  34832             return;
  34833         case OP_put_arg:
  34834             dbuf_putc(bc_out, OP_put_arg0 + idx);
  34835             return;
  34836         case OP_set_arg:
  34837             dbuf_putc(bc_out, OP_set_arg0 + idx);
  34838             return;
  34839         case OP_get_var_ref:
  34840             dbuf_putc(bc_out, OP_get_var_ref0 + idx);
  34841             return;
  34842         case OP_put_var_ref:
  34843             dbuf_putc(bc_out, OP_put_var_ref0 + idx);
  34844             return;
  34845         case OP_set_var_ref:
  34846             dbuf_putc(bc_out, OP_set_var_ref0 + idx);
  34847             return;
  34848         case OP_call:
  34849             dbuf_putc(bc_out, OP_call0 + idx);
  34850             return;
  34851         }
  34852     }
  34853     if (idx < 256) {
  34854         switch (op) {
  34855         case OP_get_loc:
  34856             dbuf_putc(bc_out, OP_get_loc8);
  34857             dbuf_putc(bc_out, idx);
  34858             return;
  34859         case OP_put_loc:
  34860             dbuf_putc(bc_out, OP_put_loc8);
  34861             dbuf_putc(bc_out, idx);
  34862             return;
  34863         case OP_set_loc:
  34864             dbuf_putc(bc_out, OP_set_loc8);
  34865             dbuf_putc(bc_out, idx);
  34866             return;
  34867         }
  34868     }
  34869 #endif
  34870     dbuf_putc(bc_out, op);
  34871     dbuf_put_u16(bc_out, idx);
  34872 }
  34873 
  34874 /* peephole optimizations and resolve goto/labels */
  34875 static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
  34876 {
  34877     int pos, pos_next, bc_len, op, op1, len, i, line_num;
  34878     const uint8_t *bc_buf;
  34879     DynBuf bc_out;
  34880     LabelSlot *label_slots, *ls;
  34881     RelocEntry *re, *re_next;
  34882     CodeContext cc;
  34883     int label;
  34884 #if SHORT_OPCODES
  34885     JumpSlot *jp;
  34886 #endif
  34887 
  34888     label_slots = s->label_slots;
  34889 
  34890     line_num = s->source_pos;
  34891 
  34892     cc.bc_buf = bc_buf = s->byte_code.buf;
  34893     cc.bc_len = bc_len = s->byte_code.size;
  34894     js_dbuf_bytecode_init(ctx, &bc_out);
  34895 
  34896 #if SHORT_OPCODES
  34897     if (s->jump_size) {
  34898         s->jump_slots = js_mallocz(s->ctx, sizeof(*s->jump_slots) * s->jump_size);
  34899         if (s->jump_slots == NULL)
  34900             return -1;
  34901     }
  34902 #endif
  34903     /* XXX: Should skip this phase if not generating SHORT_OPCODES */
  34904     if (s->line_number_size && !s->strip_debug) {
  34905         s->line_number_slots = js_mallocz(s->ctx, sizeof(*s->line_number_slots) * s->line_number_size);
  34906         if (s->line_number_slots == NULL)
  34907             return -1;
  34908         s->line_number_last = s->source_pos;
  34909         s->line_number_last_pc = 0;
  34910     }
  34911 
  34912     /* initialize the 'home_object' variable if needed */
  34913     if (s->home_object_var_idx >= 0) {
  34914         dbuf_putc(&bc_out, OP_special_object);
  34915         dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_HOME_OBJECT);
  34916         put_short_code(&bc_out, OP_put_loc, s->home_object_var_idx);
  34917     }
  34918     /* initialize the 'this.active_func' variable if needed */
  34919     if (s->this_active_func_var_idx >= 0) {
  34920         dbuf_putc(&bc_out, OP_special_object);
  34921         dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_THIS_FUNC);
  34922         put_short_code(&bc_out, OP_put_loc, s->this_active_func_var_idx);
  34923     }
  34924     /* initialize the 'new.target' variable if needed */
  34925     if (s->new_target_var_idx >= 0) {
  34926         dbuf_putc(&bc_out, OP_special_object);
  34927         dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_NEW_TARGET);
  34928         put_short_code(&bc_out, OP_put_loc, s->new_target_var_idx);
  34929     }
  34930     /* initialize the 'this' variable if needed. In a derived class
  34931        constructor, this is initially uninitialized. */
  34932     if (s->this_var_idx >= 0) {
  34933         if (s->is_derived_class_constructor) {
  34934             dbuf_putc(&bc_out, OP_set_loc_uninitialized);
  34935             dbuf_put_u16(&bc_out, s->this_var_idx);
  34936         } else {
  34937             dbuf_putc(&bc_out, OP_push_this);
  34938             put_short_code(&bc_out, OP_put_loc, s->this_var_idx);
  34939         }
  34940     }
  34941     /* initialize the 'arguments' variable if needed */
  34942     if (s->arguments_var_idx >= 0) {
  34943         if ((s->js_mode & JS_MODE_STRICT) || !s->has_simple_parameter_list) {
  34944             dbuf_putc(&bc_out, OP_special_object);
  34945             dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_ARGUMENTS);
  34946         } else {
  34947             dbuf_putc(&bc_out, OP_special_object);
  34948             dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS);
  34949             /* the arguments are implicitly captured because
  34950                references to them are created with the 'argument'
  34951                object */
  34952             for(i = 0; i < s->arg_count; i++)
  34953                 capture_var(s, &s->args[i]);
  34954         }
  34955         if (s->arguments_arg_idx >= 0)
  34956             put_short_code(&bc_out, OP_set_loc, s->arguments_arg_idx);
  34957         put_short_code(&bc_out, OP_put_loc, s->arguments_var_idx);
  34958     }
  34959     /* initialize a reference to the current function if needed */
  34960     if (s->func_var_idx >= 0) {
  34961         dbuf_putc(&bc_out, OP_special_object);
  34962         dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_THIS_FUNC);
  34963         put_short_code(&bc_out, OP_put_loc, s->func_var_idx);
  34964     }
  34965     /* initialize the variable environment object if needed */
  34966     if (s->var_object_idx >= 0) {
  34967         dbuf_putc(&bc_out, OP_special_object);
  34968         dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
  34969         put_short_code(&bc_out, OP_put_loc, s->var_object_idx);
  34970     }
  34971     if (s->arg_var_object_idx >= 0) {
  34972         dbuf_putc(&bc_out, OP_special_object);
  34973         dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
  34974         put_short_code(&bc_out, OP_put_loc, s->arg_var_object_idx);
  34975     }
  34976 
  34977     for (pos = 0; pos < bc_len; pos = pos_next) {
  34978         int val;
  34979         op = bc_buf[pos];
  34980         len = opcode_info[op].size;
  34981         pos_next = pos + len;
  34982         switch(op) {
  34983         case OP_line_num:
  34984             /* line number info (for debug). We put it in a separate
  34985                compressed table to reduce memory usage and get better
  34986                performance */
  34987             line_num = get_u32(bc_buf + pos + 1);
  34988             break;
  34989 
  34990         case OP_label:
  34991             {
  34992                 label = get_u32(bc_buf + pos + 1);
  34993                 assert(label >= 0 && label < s->label_count);
  34994                 ls = &label_slots[label];
  34995                 assert(ls->addr == -1);
  34996                 ls->addr = bc_out.size;
  34997                 /* resolve the relocation entries */
  34998                 for(re = ls->first_reloc; re != NULL; re = re_next) {
  34999                     int diff = ls->addr - re->addr;
  35000                     re_next = re->next;
  35001                     switch (re->size) {
  35002                     case 4:
  35003                         put_u32(bc_out.buf + re->addr, diff);
  35004                         break;
  35005                     case 2:
  35006                         assert(diff == (int16_t)diff);
  35007                         put_u16(bc_out.buf + re->addr, diff);
  35008                         break;
  35009                     case 1:
  35010                         assert(diff == (int8_t)diff);
  35011                         put_u8(bc_out.buf + re->addr, diff);
  35012                         break;
  35013                     }
  35014                     js_free(ctx, re);
  35015                 }
  35016                 ls->first_reloc = NULL;
  35017             }
  35018             break;
  35019 
  35020         case OP_call:
  35021         case OP_call_method:
  35022             {
  35023                 /* detect and transform tail calls */
  35024                 int argc;
  35025                 argc = get_u16(bc_buf + pos + 1);
  35026                 if (code_match(&cc, pos_next, OP_return, -1)) {
  35027                     if (cc.line_num >= 0) line_num = cc.line_num;
  35028                     add_pc2line_info(s, bc_out.size, line_num);
  35029                     put_short_code(&bc_out, op + 1, argc);
  35030                     pos_next = skip_dead_code(s, bc_buf, bc_len, cc.pos, &line_num);
  35031                     break;
  35032                 }
  35033                 add_pc2line_info(s, bc_out.size, line_num);
  35034                 put_short_code(&bc_out, op, argc);
  35035                 break;
  35036             }
  35037             goto no_change;
  35038 
  35039         case OP_return:
  35040         case OP_return_undef:
  35041         case OP_return_async:
  35042         case OP_throw:
  35043         case OP_throw_error:
  35044             pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
  35045             goto no_change;
  35046 
  35047         case OP_goto:
  35048             label = get_u32(bc_buf + pos + 1);
  35049         has_goto:
  35050             if (OPTIMIZE) {
  35051                 int line1 = -1;
  35052                 /* Use custom matcher because multiple labels can follow */
  35053                 label = find_jump_target(s, label, &op1, &line1);
  35054                 if (code_has_label(&cc, pos_next, label)) {
  35055                     /* jump to next instruction: remove jump */
  35056                     update_label(s, label, -1);
  35057                     break;
  35058                 }
  35059                 if (op1 == OP_return || op1 == OP_return_undef || op1 == OP_throw) {
  35060                     /* jump to return/throw: remove jump, append return/throw */
  35061                     /* updating the line number obfuscates assembly listing */
  35062                     //if (line1 != -1) line_num = line1;
  35063                     update_label(s, label, -1);
  35064                     add_pc2line_info(s, bc_out.size, line_num);
  35065                     dbuf_putc(&bc_out, op1);
  35066                     pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
  35067                     break;
  35068                 }
  35069                 /* XXX: should duplicate single instructions followed by goto or return */
  35070                 /* For example, can match one of these followed by return:
  35071                    push_i32 / push_const / push_atom_value / get_var /
  35072                    undefined / null / push_false / push_true / get_ref_value /
  35073                    get_loc / get_arg / get_var_ref
  35074                  */
  35075             }
  35076             goto has_label;
  35077 
  35078         case OP_gosub:
  35079             label = get_u32(bc_buf + pos + 1);
  35080             if (0 && OPTIMIZE) {
  35081                 label = find_jump_target(s, label, &op1, NULL);
  35082                 if (op1 == OP_ret) {
  35083                     update_label(s, label, -1);
  35084                     /* empty finally clause: remove gosub */
  35085                     break;
  35086                 }
  35087             }
  35088             goto has_label;
  35089 
  35090         case OP_catch:
  35091             label = get_u32(bc_buf + pos + 1);
  35092             goto has_label;
  35093 
  35094         case OP_if_true:
  35095         case OP_if_false:
  35096             label = get_u32(bc_buf + pos + 1);
  35097             if (OPTIMIZE) {
  35098                 label = find_jump_target(s, label, &op1, NULL);
  35099                 /* transform if_false/if_true(l1) label(l1) -> drop label(l1) */
  35100                 if (code_has_label(&cc, pos_next, label)) {
  35101                     update_label(s, label, -1);
  35102                     dbuf_putc(&bc_out, OP_drop);
  35103                     break;
  35104                 }
  35105                 /* transform if_false(l1) goto(l2) label(l1) -> if_false(l2) label(l1) */
  35106                 if (code_match(&cc, pos_next, OP_goto, -1)) {
  35107                     int pos1 = cc.pos;
  35108                     int line1 = cc.line_num;
  35109                     if (code_has_label(&cc, pos1, label)) {
  35110                         if (line1 != -1) line_num = line1;
  35111                         pos_next = pos1;
  35112                         update_label(s, label, -1);
  35113                         label = cc.label;
  35114                         op ^= OP_if_true ^ OP_if_false;
  35115                     }
  35116                 }
  35117             }
  35118         has_label:
  35119             add_pc2line_info(s, bc_out.size, line_num);
  35120             if (op == OP_goto) {
  35121                 pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
  35122             }
  35123             assert(label >= 0 && label < s->label_count);
  35124             ls = &label_slots[label];
  35125 #if SHORT_OPCODES
  35126             jp = &s->jump_slots[s->jump_count++];
  35127             jp->op = op;
  35128             jp->size = 4;
  35129             jp->pos = bc_out.size + 1;
  35130             jp->label = label;
  35131 
  35132             if (ls->addr == -1) {
  35133                 int diff = ls->pos2 - pos - 1;
  35134                 if (diff < 128 && (op == OP_if_false || op == OP_if_true || op == OP_goto)) {
  35135                     jp->size = 1;
  35136                     jp->op = OP_if_false8 + (op - OP_if_false);
  35137                     dbuf_putc(&bc_out, OP_if_false8 + (op - OP_if_false));
  35138                     dbuf_putc(&bc_out, 0);
  35139                     if (!add_reloc(ctx, ls, bc_out.size - 1, 1))
  35140                         goto fail;
  35141                     break;
  35142                 }
  35143                 if (diff < 32768 && op == OP_goto) {
  35144                     jp->size = 2;
  35145                     jp->op = OP_goto16;
  35146                     dbuf_putc(&bc_out, OP_goto16);
  35147                     dbuf_put_u16(&bc_out, 0);
  35148                     if (!add_reloc(ctx, ls, bc_out.size - 2, 2))
  35149                         goto fail;
  35150                     break;
  35151                 }
  35152             } else {
  35153                 int diff = ls->addr - bc_out.size - 1;
  35154                 if (diff == (int8_t)diff && (op == OP_if_false || op == OP_if_true || op == OP_goto)) {
  35155                     jp->size = 1;
  35156                     jp->op = OP_if_false8 + (op - OP_if_false);
  35157                     dbuf_putc(&bc_out, OP_if_false8 + (op - OP_if_false));
  35158                     dbuf_putc(&bc_out, diff);
  35159                     break;
  35160                 }
  35161                 if (diff == (int16_t)diff && op == OP_goto) {
  35162                     jp->size = 2;
  35163                     jp->op = OP_goto16;
  35164                     dbuf_putc(&bc_out, OP_goto16);
  35165                     dbuf_put_u16(&bc_out, diff);
  35166                     break;
  35167                 }
  35168             }
  35169 #endif
  35170             dbuf_putc(&bc_out, op);
  35171             dbuf_put_u32(&bc_out, ls->addr - bc_out.size);
  35172             if (ls->addr == -1) {
  35173                 /* unresolved yet: create a new relocation entry */
  35174                 if (!add_reloc(ctx, ls, bc_out.size - 4, 4))
  35175                     goto fail;
  35176             }
  35177             break;
  35178         case OP_with_get_var:
  35179         case OP_with_put_var:
  35180         case OP_with_delete_var:
  35181         case OP_with_make_ref:
  35182         case OP_with_get_ref:
  35183             {
  35184                 JSAtom atom;
  35185                 int is_with;
  35186 
  35187                 atom = get_u32(bc_buf + pos + 1);
  35188                 label = get_u32(bc_buf + pos + 5);
  35189                 is_with = bc_buf[pos + 9];
  35190                 if (OPTIMIZE) {
  35191                     label = find_jump_target(s, label, &op1, NULL);
  35192                 }
  35193                 assert(label >= 0 && label < s->label_count);
  35194                 ls = &label_slots[label];
  35195                 add_pc2line_info(s, bc_out.size, line_num);
  35196 #if SHORT_OPCODES
  35197                 jp = &s->jump_slots[s->jump_count++];
  35198                 jp->op = op;
  35199                 jp->size = 4;
  35200                 jp->pos = bc_out.size + 5;
  35201                 jp->label = label;
  35202 #endif
  35203                 dbuf_putc(&bc_out, op);
  35204                 dbuf_put_u32(&bc_out, atom);
  35205                 dbuf_put_u32(&bc_out, ls->addr - bc_out.size);
  35206                 if (ls->addr == -1) {
  35207                     /* unresolved yet: create a new relocation entry */
  35208                     if (!add_reloc(ctx, ls, bc_out.size - 4, 4))
  35209                         goto fail;
  35210                 }
  35211                 dbuf_putc(&bc_out, is_with);
  35212             }
  35213             break;
  35214 
  35215         case OP_drop:
  35216             if (OPTIMIZE) {
  35217                 /* remove useless drops before return */
  35218                 if (code_match(&cc, pos_next, OP_return_undef, -1)) {
  35219                     if (cc.line_num >= 0) line_num = cc.line_num;
  35220                     break;
  35221                 }
  35222             }
  35223             goto no_change;
  35224 
  35225         case OP_null:
  35226 #if SHORT_OPCODES
  35227             if (OPTIMIZE) {
  35228                 /* transform null strict_eq into is_null */
  35229                 if (code_match(&cc, pos_next, OP_strict_eq, -1)) {
  35230                     if (cc.line_num >= 0) line_num = cc.line_num;
  35231                     add_pc2line_info(s, bc_out.size, line_num);
  35232                     dbuf_putc(&bc_out, OP_is_null);
  35233                     pos_next = cc.pos;
  35234                     break;
  35235                 }
  35236                 /* transform null strict_neq if_false/if_true -> is_null if_true/if_false */
  35237                 if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) {
  35238                     if (cc.line_num >= 0) line_num = cc.line_num;
  35239                     add_pc2line_info(s, bc_out.size, line_num);
  35240                     dbuf_putc(&bc_out, OP_is_null);
  35241                     pos_next = cc.pos;
  35242                     label = cc.label;
  35243                     op = cc.op ^ OP_if_false ^ OP_if_true;
  35244                     goto has_label;
  35245                 }
  35246             }
  35247 #endif
  35248             /* fall thru */
  35249         case OP_push_false:
  35250         case OP_push_true:
  35251             if (OPTIMIZE) {
  35252                 val = (op == OP_push_true);
  35253                 if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
  35254                 has_constant_test:
  35255                     if (cc.line_num >= 0) line_num = cc.line_num;
  35256                     if (val == cc.op - OP_if_false) {
  35257                         /* transform null if_false(l1) -> goto l1 */
  35258                         /* transform false if_false(l1) -> goto l1 */
  35259                         /* transform true if_true(l1) -> goto l1 */
  35260                         pos_next = cc.pos;
  35261                         op = OP_goto;
  35262                         label = cc.label;
  35263                         goto has_goto;
  35264                     } else {
  35265                         /* transform null if_true(l1) -> nop */
  35266                         /* transform false if_true(l1) -> nop */
  35267                         /* transform true if_false(l1) -> nop */
  35268                         pos_next = cc.pos;
  35269                         update_label(s, cc.label, -1);
  35270                         break;
  35271                     }
  35272                 }
  35273             }
  35274             goto no_change;
  35275 
  35276         case OP_push_i32:
  35277             if (OPTIMIZE) {
  35278                 /* transform i32(val) neg -> i32(-val) */
  35279                 val = get_i32(bc_buf + pos + 1);
  35280                 if ((val != INT32_MIN && val != 0)
  35281                 &&  code_match(&cc, pos_next, OP_neg, -1)) {
  35282                     if (cc.line_num >= 0) line_num = cc.line_num;
  35283                     if (code_match(&cc, cc.pos, OP_drop, -1)) {
  35284                         if (cc.line_num >= 0) line_num = cc.line_num;
  35285                     } else {
  35286                         add_pc2line_info(s, bc_out.size, line_num);
  35287                         push_short_int(&bc_out, -val);
  35288                     }
  35289                     pos_next = cc.pos;
  35290                     break;
  35291                 }
  35292                 /* remove push/drop pairs generated by the parser */
  35293                 if (code_match(&cc, pos_next, OP_drop, -1)) {
  35294                     if (cc.line_num >= 0) line_num = cc.line_num;
  35295                     pos_next = cc.pos;
  35296                     break;
  35297                 }
  35298                 /* Optimize constant tests: `if (0)`, `if (1)`, `if (!0)`... */
  35299                 if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
  35300                     val = (val != 0);
  35301                     goto has_constant_test;
  35302                 }
  35303                 add_pc2line_info(s, bc_out.size, line_num);
  35304                 push_short_int(&bc_out, val);
  35305                 break;
  35306             }
  35307             goto no_change;
  35308 
  35309         case OP_push_bigint_i32:
  35310             if (OPTIMIZE) {
  35311                 /* transform i32(val) neg -> i32(-val) */
  35312                 val = get_i32(bc_buf + pos + 1);
  35313                 if (val != INT32_MIN
  35314                 &&  code_match(&cc, pos_next, OP_neg, -1)) {
  35315                     if (cc.line_num >= 0) line_num = cc.line_num;
  35316                     if (code_match(&cc, cc.pos, OP_drop, -1)) {
  35317                         if (cc.line_num >= 0) line_num = cc.line_num;
  35318                     } else {
  35319                         add_pc2line_info(s, bc_out.size, line_num);
  35320                         dbuf_putc(&bc_out, OP_push_bigint_i32);
  35321                         dbuf_put_u32(&bc_out, -val);
  35322                     }
  35323                     pos_next = cc.pos;
  35324                     break;
  35325                 }
  35326             }
  35327             goto no_change;
  35328 
  35329 #if SHORT_OPCODES
  35330         case OP_push_const:
  35331         case OP_fclosure:
  35332             if (OPTIMIZE) {
  35333                 int idx = get_u32(bc_buf + pos + 1);
  35334                 if (idx < 256) {
  35335                     add_pc2line_info(s, bc_out.size, line_num);
  35336                     dbuf_putc(&bc_out, OP_push_const8 + op - OP_push_const);
  35337                     dbuf_putc(&bc_out, idx);
  35338                     break;
  35339                 }
  35340             }
  35341             goto no_change;
  35342 
  35343         case OP_get_field:
  35344             if (OPTIMIZE) {
  35345                 JSAtom atom = get_u32(bc_buf + pos + 1);
  35346                 if (atom == JS_ATOM_length) {
  35347                     JS_FreeAtom(ctx, atom);
  35348                     add_pc2line_info(s, bc_out.size, line_num);
  35349                     dbuf_putc(&bc_out, OP_get_length);
  35350                     break;
  35351                 }
  35352             }
  35353             goto no_change;
  35354 #endif
  35355         case OP_push_atom_value:
  35356             if (OPTIMIZE) {
  35357                 JSAtom atom = get_u32(bc_buf + pos + 1);
  35358                 /* remove push/drop pairs generated by the parser */
  35359                 if (code_match(&cc, pos_next, OP_drop, -1)) {
  35360                     JS_FreeAtom(ctx, atom);
  35361                     if (cc.line_num >= 0) line_num = cc.line_num;
  35362                     pos_next = cc.pos;
  35363                     break;
  35364                 }
  35365 #if SHORT_OPCODES
  35366                 if (atom == JS_ATOM_empty_string) {
  35367                     JS_FreeAtom(ctx, atom);
  35368                     add_pc2line_info(s, bc_out.size, line_num);
  35369                     dbuf_putc(&bc_out, OP_push_empty_string);
  35370                     break;
  35371                 }
  35372 #endif
  35373             }
  35374             goto no_change;
  35375 
  35376         case OP_to_propkey:
  35377             if (OPTIMIZE) {
  35378                 /* remove redundant to_propkey opcodes when storing simple data */
  35379                 if (code_match(&cc, pos_next, M3(OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_put_array_el, -1)
  35380                 ||  code_match(&cc, pos_next, M3(OP_push_i32, OP_push_const, OP_push_atom_value), OP_put_array_el, -1)
  35381                 ||  code_match(&cc, pos_next, M4(OP_undefined, OP_null, OP_push_true, OP_push_false), OP_put_array_el, -1)) {
  35382                     break;
  35383                 }
  35384             }
  35385             goto no_change;
  35386 
  35387         case OP_undefined:
  35388             if (OPTIMIZE) {
  35389                 /* remove push/drop pairs generated by the parser */
  35390                 if (code_match(&cc, pos_next, OP_drop, -1)) {
  35391                     if (cc.line_num >= 0) line_num = cc.line_num;
  35392                     pos_next = cc.pos;
  35393                     break;
  35394                 }
  35395                 /* transform undefined return -> return_undefined */
  35396                 if (code_match(&cc, pos_next, OP_return, -1)) {
  35397                     if (cc.line_num >= 0) line_num = cc.line_num;
  35398                     add_pc2line_info(s, bc_out.size, line_num);
  35399                     dbuf_putc(&bc_out, OP_return_undef);
  35400                     pos_next = cc.pos;
  35401                     break;
  35402                 }
  35403                 /* transform undefined if_true(l1)/if_false(l1) -> nop/goto(l1) */
  35404                 if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
  35405                     val = 0;
  35406                     goto has_constant_test;
  35407                 }
  35408 #if SHORT_OPCODES
  35409                 /* transform undefined strict_eq -> is_undefined */
  35410                 if (code_match(&cc, pos_next, OP_strict_eq, -1)) {
  35411                     if (cc.line_num >= 0) line_num = cc.line_num;
  35412                     add_pc2line_info(s, bc_out.size, line_num);
  35413                     dbuf_putc(&bc_out, OP_is_undefined);
  35414                     pos_next = cc.pos;
  35415                     break;
  35416                 }
  35417                 /* transform undefined strict_neq if_false/if_true -> is_undefined if_true/if_false */
  35418                 if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) {
  35419                     if (cc.line_num >= 0) line_num = cc.line_num;
  35420                     add_pc2line_info(s, bc_out.size, line_num);
  35421                     dbuf_putc(&bc_out, OP_is_undefined);
  35422                     pos_next = cc.pos;
  35423                     label = cc.label;
  35424                     op = cc.op ^ OP_if_false ^ OP_if_true;
  35425                     goto has_label;
  35426                 }
  35427 #endif
  35428             }
  35429             goto no_change;
  35430 
  35431         case OP_insert2:
  35432             if (OPTIMIZE) {
  35433                 /* Transformation:
  35434                    insert2 put_field(a) drop -> put_field(a)
  35435                 */
  35436                 if (code_match(&cc, pos_next, OP_put_field, OP_drop, -1)) {
  35437                     if (cc.line_num >= 0) line_num = cc.line_num;
  35438                     add_pc2line_info(s, bc_out.size, line_num);
  35439                     dbuf_putc(&bc_out, OP_put_field);
  35440                     dbuf_put_u32(&bc_out, cc.atom);
  35441                     pos_next = cc.pos;
  35442                     break;
  35443                 }
  35444             }
  35445             goto no_change;
  35446 
  35447         case OP_dup:
  35448             if (OPTIMIZE) {
  35449                 /* Transformation: dup put_x(n) drop -> put_x(n) */
  35450                 int op1, line2 = -1;
  35451                 /* Transformation: dup put_x(n) -> set_x(n) */
  35452                 if (code_match(&cc, pos_next, M4(OP_put_loc, OP_put_loc_check, OP_put_arg, OP_put_var_ref), -1, -1)) {
  35453                     if (cc.line_num >= 0) line_num = cc.line_num;
  35454                     op1 = cc.op + 1;  /* put_x -> set_x */
  35455                     pos_next = cc.pos;
  35456                     if (code_match(&cc, cc.pos, OP_drop, -1)) {
  35457                         if (cc.line_num >= 0) line_num = cc.line_num;
  35458                         op1 -= 1; /* set_x drop -> put_x */
  35459                         pos_next = cc.pos;
  35460                         if (code_match(&cc, cc.pos, op1 - 1, cc.idx, -1)) {
  35461                             line2 = cc.line_num; /* delay line number update */
  35462                             op1 += 1;   /* put_x(n) get_x(n) -> set_x(n) */
  35463                             pos_next = cc.pos;
  35464                         }
  35465                     }
  35466                     add_pc2line_info(s, bc_out.size, line_num);
  35467                     put_short_code(&bc_out, op1, cc.idx);
  35468                     if (line2 >= 0) line_num = line2;
  35469                     break;
  35470                 }
  35471             }
  35472             goto no_change;
  35473 
  35474         case OP_get_loc:
  35475             if (OPTIMIZE) {
  35476                 /* transformation:
  35477                    get_loc(n) post_dec put_loc(n) drop -> dec_loc(n)
  35478                    get_loc(n) post_inc put_loc(n) drop -> inc_loc(n)
  35479                    get_loc(n) dec dup put_loc(n) drop -> dec_loc(n)
  35480                    get_loc(n) inc dup put_loc(n) drop -> inc_loc(n)
  35481                  */
  35482                 int idx;
  35483                 idx = get_u16(bc_buf + pos + 1);
  35484                 if (idx >= 256)
  35485                     goto no_change;
  35486                 if (code_match(&cc, pos_next, M2(OP_post_dec, OP_post_inc), OP_put_loc, idx, OP_drop, -1) ||
  35487                     code_match(&cc, pos_next, M2(OP_dec, OP_inc), OP_dup, OP_put_loc, idx, OP_drop, -1)) {
  35488                     if (cc.line_num >= 0) line_num = cc.line_num;
  35489                     add_pc2line_info(s, bc_out.size, line_num);
  35490                     dbuf_putc(&bc_out, (cc.op == OP_inc || cc.op == OP_post_inc) ? OP_inc_loc : OP_dec_loc);
  35491                     dbuf_putc(&bc_out, idx);
  35492                     pos_next = cc.pos;
  35493                     break;
  35494                 }
  35495                 /* transformation:
  35496                    get_loc(n) push_atom_value(x) add dup put_loc(n) drop -> push_atom_value(x) add_loc(n)
  35497                  */
  35498                 if (code_match(&cc, pos_next, OP_push_atom_value, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
  35499                     if (cc.line_num >= 0) line_num = cc.line_num;
  35500                     add_pc2line_info(s, bc_out.size, line_num);
  35501 #if SHORT_OPCODES
  35502                     if (cc.atom == JS_ATOM_empty_string) {
  35503                         JS_FreeAtom(ctx, cc.atom);
  35504                         dbuf_putc(&bc_out, OP_push_empty_string);
  35505                     } else
  35506 #endif
  35507                     {
  35508                         dbuf_putc(&bc_out, OP_push_atom_value);
  35509                         dbuf_put_u32(&bc_out, cc.atom);
  35510                     }
  35511                     dbuf_putc(&bc_out, OP_add_loc);
  35512                     dbuf_putc(&bc_out, idx);
  35513                     pos_next = cc.pos;
  35514                     break;
  35515                 }
  35516                 /* transformation:
  35517                    get_loc(n) push_i32(x) add dup put_loc(n) drop -> push_i32(x) add_loc(n)
  35518                  */
  35519                 if (code_match(&cc, pos_next, OP_push_i32, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
  35520                     if (cc.line_num >= 0) line_num = cc.line_num;
  35521                     add_pc2line_info(s, bc_out.size, line_num);
  35522                     push_short_int(&bc_out, cc.label);
  35523                     dbuf_putc(&bc_out, OP_add_loc);
  35524                     dbuf_putc(&bc_out, idx);
  35525                     pos_next = cc.pos;
  35526                     break;
  35527                 }
  35528                 /* transformation: XXX: also do these:
  35529                    get_loc(n) get_loc(x) add dup put_loc(n) drop -> get_loc(x) add_loc(n)
  35530                    get_loc(n) get_arg(x) add dup put_loc(n) drop -> get_arg(x) add_loc(n)
  35531                    get_loc(n) get_var_ref(x) add dup put_loc(n) drop -> get_var_ref(x) add_loc(n)
  35532                  */
  35533                 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)) {
  35534                     if (cc.line_num >= 0) line_num = cc.line_num;
  35535                     add_pc2line_info(s, bc_out.size, line_num);
  35536                     put_short_code(&bc_out, cc.op, cc.idx);
  35537                     dbuf_putc(&bc_out, OP_add_loc);
  35538                     dbuf_putc(&bc_out, idx);
  35539                     pos_next = cc.pos;
  35540                     break;
  35541                 }
  35542                 add_pc2line_info(s, bc_out.size, line_num);
  35543                 put_short_code(&bc_out, op, idx);
  35544                 break;
  35545             }
  35546             goto no_change;
  35547 #if SHORT_OPCODES
  35548         case OP_get_arg:
  35549         case OP_get_var_ref:
  35550             if (OPTIMIZE) {
  35551                 int idx;
  35552                 idx = get_u16(bc_buf + pos + 1);
  35553                 add_pc2line_info(s, bc_out.size, line_num);
  35554                 put_short_code(&bc_out, op, idx);
  35555                 break;
  35556             }
  35557             goto no_change;
  35558 #endif
  35559         case OP_put_loc:
  35560         case OP_put_loc_check:
  35561         case OP_put_arg:
  35562         case OP_put_var_ref:
  35563             if (OPTIMIZE) {
  35564                 /* transformation: put_x(n) get_x(n) -> set_x(n) */
  35565                 int idx;
  35566                 idx = get_u16(bc_buf + pos + 1);
  35567                 if (code_match(&cc, pos_next, op - 1, idx, -1)) {
  35568                     if (cc.line_num >= 0) line_num = cc.line_num;
  35569                     add_pc2line_info(s, bc_out.size, line_num);
  35570                     put_short_code(&bc_out, op + 1, idx);
  35571                     pos_next = cc.pos;
  35572                     break;
  35573                 }
  35574                 add_pc2line_info(s, bc_out.size, line_num);
  35575                 put_short_code(&bc_out, op, idx);
  35576                 break;
  35577             }
  35578             goto no_change;
  35579 
  35580         case OP_post_inc:
  35581         case OP_post_dec:
  35582             if (OPTIMIZE) {
  35583                 /* transformation:
  35584                    post_inc put_x drop -> inc put_x
  35585                    post_inc perm3 put_field drop -> inc put_field
  35586                    post_inc perm4 put_array_el drop -> inc put_array_el
  35587                  */
  35588                 int op1, idx;
  35589                 if (code_match(&cc, pos_next, M3(OP_put_loc, OP_put_arg, OP_put_var_ref), -1, OP_drop, -1)) {
  35590                     if (cc.line_num >= 0) line_num = cc.line_num;
  35591                     op1 = cc.op;
  35592                     idx = cc.idx;
  35593                     pos_next = cc.pos;
  35594                     if (code_match(&cc, cc.pos, op1 - 1, idx, -1)) {
  35595                         if (cc.line_num >= 0) line_num = cc.line_num;
  35596                         op1 += 1;   /* put_x(n) get_x(n) -> set_x(n) */
  35597                         pos_next = cc.pos;
  35598                     }
  35599                     add_pc2line_info(s, bc_out.size, line_num);
  35600                     dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
  35601                     put_short_code(&bc_out, op1, idx);
  35602                     break;
  35603                 }
  35604                 if (code_match(&cc, pos_next, OP_perm3, OP_put_field, OP_drop, -1)) {
  35605                     if (cc.line_num >= 0) line_num = cc.line_num;
  35606                     add_pc2line_info(s, bc_out.size, line_num);
  35607                     dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
  35608                     dbuf_putc(&bc_out, OP_put_field);
  35609                     dbuf_put_u32(&bc_out, cc.atom);
  35610                     pos_next = cc.pos;
  35611                     break;
  35612                 }
  35613                 if (code_match(&cc, pos_next, OP_perm4, OP_put_array_el, OP_drop, -1)) {
  35614                     if (cc.line_num >= 0) line_num = cc.line_num;
  35615                     add_pc2line_info(s, bc_out.size, line_num);
  35616                     dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
  35617                     dbuf_putc(&bc_out, OP_put_array_el);
  35618                     pos_next = cc.pos;
  35619                     break;
  35620                 }
  35621             }
  35622             goto no_change;
  35623 
  35624 #if SHORT_OPCODES
  35625         case OP_typeof:
  35626             if (OPTIMIZE) {
  35627                 /* simplify typeof tests */
  35628                 if (code_match(&cc, pos_next, OP_push_atom_value, M4(OP_strict_eq, OP_strict_neq, OP_eq, OP_neq), -1)) {
  35629                     if (cc.line_num >= 0) line_num = cc.line_num;
  35630                     int op1 = (cc.op == OP_strict_eq || cc.op == OP_eq) ? OP_strict_eq : OP_strict_neq;
  35631                     int op2 = -1;
  35632                     switch (cc.atom) {
  35633                     case JS_ATOM_undefined:
  35634                         op2 = OP_typeof_is_undefined;
  35635                         break;
  35636                     case JS_ATOM_function:
  35637                         op2 = OP_typeof_is_function;
  35638                         break;
  35639                     }
  35640                     if (op2 >= 0) {
  35641                         /* transform typeof(s) == "<type>" into is_<type> */
  35642                         if (op1 == OP_strict_eq) {
  35643                             add_pc2line_info(s, bc_out.size, line_num);
  35644                             dbuf_putc(&bc_out, op2);
  35645                             JS_FreeAtom(ctx, cc.atom);
  35646                             pos_next = cc.pos;
  35647                             break;
  35648                         }
  35649                         if (op1 == OP_strict_neq && code_match(&cc, cc.pos, OP_if_false, -1)) {
  35650                             /* transform typeof(s) != "<type>" if_false into is_<type> if_true */
  35651                             if (cc.line_num >= 0) line_num = cc.line_num;
  35652                             add_pc2line_info(s, bc_out.size, line_num);
  35653                             dbuf_putc(&bc_out, op2);
  35654                             JS_FreeAtom(ctx, cc.atom);
  35655                             pos_next = cc.pos;
  35656                             label = cc.label;
  35657                             op = OP_if_true;
  35658                             goto has_label;
  35659                         }
  35660                     }
  35661                 }
  35662             }
  35663             goto no_change;
  35664 #endif
  35665 
  35666         default:
  35667         no_change:
  35668             add_pc2line_info(s, bc_out.size, line_num);
  35669             dbuf_put(&bc_out, bc_buf + pos, len);
  35670             break;
  35671         }
  35672     }
  35673 
  35674     /* check that there were no missing labels */
  35675     for(i = 0; i < s->label_count; i++) {
  35676         assert(label_slots[i].first_reloc == NULL);
  35677     }
  35678 #if SHORT_OPCODES
  35679     if (OPTIMIZE) {
  35680         /* more jump optimizations */
  35681         int patch_offsets = 0;
  35682         for (i = 0, jp = s->jump_slots; i < s->jump_count; i++, jp++) {
  35683             LabelSlot *ls;
  35684             JumpSlot *jp1;
  35685             int j, pos, diff, delta;
  35686 
  35687             delta = 3;
  35688             switch (op = jp->op) {
  35689             case OP_goto16:
  35690                 delta = 1;
  35691                 /* fall thru */
  35692             case OP_if_false:
  35693             case OP_if_true:
  35694             case OP_goto:
  35695                 pos = jp->pos;
  35696                 diff = s->label_slots[jp->label].addr - pos;
  35697                 if (diff >= -128 && diff <= 127 + delta) {
  35698                     //put_u8(bc_out.buf + pos, diff);
  35699                     jp->size = 1;
  35700                     if (op == OP_goto16) {
  35701                         bc_out.buf[pos - 1] = jp->op = OP_goto8;
  35702                     } else {
  35703                         bc_out.buf[pos - 1] = jp->op = OP_if_false8 + (op - OP_if_false);
  35704                     }
  35705                     goto shrink;
  35706                 } else
  35707                 if (diff == (int16_t)diff && op == OP_goto) {
  35708                     //put_u16(bc_out.buf + pos, diff);
  35709                     jp->size = 2;
  35710                     delta = 2;
  35711                     bc_out.buf[pos - 1] = jp->op = OP_goto16;
  35712                 shrink:
  35713                     /* XXX: should reduce complexity, using 2 finger copy scheme */
  35714                     memmove(bc_out.buf + pos + jp->size, bc_out.buf + pos + jp->size + delta,
  35715                             bc_out.size - pos - jp->size - delta);
  35716                     bc_out.size -= delta;
  35717                     patch_offsets++;
  35718                     for (j = 0, ls = s->label_slots; j < s->label_count; j++, ls++) {
  35719                         if (ls->addr > pos)
  35720                             ls->addr -= delta;
  35721                     }
  35722                     for (j = i + 1, jp1 = jp + 1; j < s->jump_count; j++, jp1++) {
  35723                         if (jp1->pos > pos)
  35724                             jp1->pos -= delta;
  35725                     }
  35726                     for (j = 0; j < s->line_number_count; j++) {
  35727                         if (s->line_number_slots[j].pc > pos)
  35728                             s->line_number_slots[j].pc -= delta;
  35729                     }
  35730                     continue;
  35731                 }
  35732                 break;
  35733             }
  35734         }
  35735         if (patch_offsets) {
  35736             JumpSlot *jp1;
  35737             int j;
  35738             for (j = 0, jp1 = s->jump_slots; j < s->jump_count; j++, jp1++) {
  35739                 int diff1 = s->label_slots[jp1->label].addr - jp1->pos;
  35740                 switch (jp1->size) {
  35741                 case 1:
  35742                     put_u8(bc_out.buf + jp1->pos, diff1);
  35743                     break;
  35744                 case 2:
  35745                     put_u16(bc_out.buf + jp1->pos, diff1);
  35746                     break;
  35747                 case 4:
  35748                     put_u32(bc_out.buf + jp1->pos, diff1);
  35749                     break;
  35750                 }
  35751             }
  35752         }
  35753     }
  35754     js_free(ctx, s->jump_slots);
  35755     s->jump_slots = NULL;
  35756 #endif
  35757     js_free(ctx, s->label_slots);
  35758     s->label_slots = NULL;
  35759     /* XXX: should delay until copying to runtime bytecode function */
  35760     compute_pc2line_info(s);
  35761     js_free(ctx, s->line_number_slots);
  35762     s->line_number_slots = NULL;
  35763     /* set the new byte code */
  35764     dbuf_free(&s->byte_code);
  35765     s->byte_code = bc_out;
  35766     s->use_short_opcodes = TRUE;
  35767     if (dbuf_error(&s->byte_code)) {
  35768         JS_ThrowOutOfMemory(ctx);
  35769         return -1;
  35770     }
  35771     return 0;
  35772  fail:
  35773     /* XXX: not safe */
  35774     dbuf_free(&bc_out);
  35775     return -1;
  35776 }
  35777 
  35778 /* compute the maximum stack size needed by the function */
  35779 
  35780 typedef struct StackSizeState {
  35781     int bc_len;
  35782     int stack_len_max;
  35783     uint16_t *stack_level_tab;
  35784     int32_t *catch_pos_tab;
  35785     int *pc_stack;
  35786     int pc_stack_len;
  35787     int pc_stack_size;
  35788 } StackSizeState;
  35789 
  35790 /* 'op' is only used for error indication */
  35791 static __exception int ss_check(JSContext *ctx, StackSizeState *s,
  35792                                 int pos, int op, int stack_len, int catch_pos)
  35793 {
  35794     if ((unsigned)pos >= s->bc_len) {
  35795         JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
  35796         return -1;
  35797     }
  35798     if (stack_len > s->stack_len_max) {
  35799         s->stack_len_max = stack_len;
  35800         if (s->stack_len_max > JS_STACK_SIZE_MAX) {
  35801             JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
  35802             return -1;
  35803         }
  35804     }
  35805     if (s->stack_level_tab[pos] != 0xffff) {
  35806         /* already explored: check that the stack size is consistent */
  35807         if (s->stack_level_tab[pos] != stack_len) {
  35808             JS_ThrowInternalError(ctx, "inconsistent stack size: %d %d (pc=%d)",
  35809                                   s->stack_level_tab[pos], stack_len, pos);
  35810             return -1;
  35811         } else if (s->catch_pos_tab[pos] != catch_pos) {
  35812             JS_ThrowInternalError(ctx, "inconsistent catch position: %d %d (pc=%d)",
  35813                                   s->catch_pos_tab[pos], catch_pos, pos);
  35814             return -1;
  35815         } else {
  35816             return 0;
  35817         }
  35818     }
  35819 
  35820     /* mark as explored and store the stack size */
  35821     s->stack_level_tab[pos] = stack_len;
  35822     s->catch_pos_tab[pos] = catch_pos;
  35823 
  35824     /* queue the new PC to explore */
  35825     if (js_resize_array(ctx, (void **)&s->pc_stack, sizeof(s->pc_stack[0]),
  35826                         &s->pc_stack_size, s->pc_stack_len + 1))
  35827         return -1;
  35828     s->pc_stack[s->pc_stack_len++] = pos;
  35829     return 0;
  35830 }
  35831 
  35832 static __exception int compute_stack_size(JSContext *ctx,
  35833                                           JSFunctionDef *fd,
  35834                                           int *pstack_size)
  35835 {
  35836     StackSizeState s_s, *s = &s_s;
  35837     int i, diff, n_pop, pos_next, stack_len, pos, op, catch_pos, catch_level;
  35838     const JSOpCode *oi;
  35839     const uint8_t *bc_buf;
  35840 
  35841     bc_buf = fd->byte_code.buf;
  35842     s->bc_len = fd->byte_code.size;
  35843     /* bc_len > 0 */
  35844     s->stack_level_tab = js_malloc(ctx, sizeof(s->stack_level_tab[0]) *
  35845                                    s->bc_len);
  35846     if (!s->stack_level_tab)
  35847         return -1;
  35848     for(i = 0; i < s->bc_len; i++)
  35849         s->stack_level_tab[i] = 0xffff;
  35850     s->pc_stack = NULL;
  35851     s->catch_pos_tab = js_malloc(ctx, sizeof(s->catch_pos_tab[0]) *
  35852                                    s->bc_len);
  35853     if (!s->catch_pos_tab)
  35854         goto fail;
  35855 
  35856     s->stack_len_max = 0;
  35857     s->pc_stack_len = 0;
  35858     s->pc_stack_size = 0;
  35859 
  35860     /* breadth-first graph exploration */
  35861     if (ss_check(ctx, s, 0, OP_invalid, 0, -1))
  35862         goto fail;
  35863 
  35864     while (s->pc_stack_len > 0) {
  35865         pos = s->pc_stack[--s->pc_stack_len];
  35866         stack_len = s->stack_level_tab[pos];
  35867         catch_pos = s->catch_pos_tab[pos];
  35868         op = bc_buf[pos];
  35869         if (op == 0 || op >= OP_COUNT) {
  35870             JS_ThrowInternalError(ctx, "invalid opcode (op=%d, pc=%d)", op, pos);
  35871             goto fail;
  35872         }
  35873         oi = &short_opcode_info(op);
  35874 #if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 64)
  35875         printf("%5d: %10s %5d %5d\n", pos, oi->name, stack_len, catch_pos);
  35876 #endif
  35877         pos_next = pos + oi->size;
  35878         if (pos_next > s->bc_len) {
  35879             JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
  35880             goto fail;
  35881         }
  35882         n_pop = oi->n_pop;
  35883         /* call pops a variable number of arguments */
  35884         if (oi->fmt == OP_FMT_npop || oi->fmt == OP_FMT_npop_u16) {
  35885             n_pop += get_u16(bc_buf + pos + 1);
  35886         } else {
  35887 #if SHORT_OPCODES
  35888             if (oi->fmt == OP_FMT_npopx) {
  35889                 n_pop += op - OP_call0;
  35890             }
  35891 #endif
  35892         }
  35893 
  35894         if (stack_len < n_pop) {
  35895             JS_ThrowInternalError(ctx, "stack underflow (op=%d, pc=%d)", op, pos);
  35896             goto fail;
  35897         }
  35898         stack_len += oi->n_push - n_pop;
  35899         if (stack_len > s->stack_len_max) {
  35900             s->stack_len_max = stack_len;
  35901             if (s->stack_len_max > JS_STACK_SIZE_MAX) {
  35902                 JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
  35903                 goto fail;
  35904             }
  35905         }
  35906         switch(op) {
  35907         case OP_tail_call:
  35908         case OP_tail_call_method:
  35909         case OP_return:
  35910         case OP_return_undef:
  35911         case OP_return_async:
  35912         case OP_throw:
  35913         case OP_throw_error:
  35914         case OP_ret:
  35915             goto done_insn;
  35916         case OP_goto:
  35917             diff = get_u32(bc_buf + pos + 1);
  35918             pos_next = pos + 1 + diff;
  35919             break;
  35920 #if SHORT_OPCODES
  35921         case OP_goto16:
  35922             diff = (int16_t)get_u16(bc_buf + pos + 1);
  35923             pos_next = pos + 1 + diff;
  35924             break;
  35925         case OP_goto8:
  35926             diff = (int8_t)bc_buf[pos + 1];
  35927             pos_next = pos + 1 + diff;
  35928             break;
  35929         case OP_if_true8:
  35930         case OP_if_false8:
  35931             diff = (int8_t)bc_buf[pos + 1];
  35932             if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))
  35933                 goto fail;
  35934             break;
  35935 #endif
  35936         case OP_if_true:
  35937         case OP_if_false:
  35938             diff = get_u32(bc_buf + pos + 1);
  35939             if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))
  35940                 goto fail;
  35941             break;
  35942         case OP_gosub:
  35943             diff = get_u32(bc_buf + pos + 1);
  35944             if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1, catch_pos))
  35945                 goto fail;
  35946             break;
  35947         case OP_with_get_var:
  35948         case OP_with_delete_var:
  35949             diff = get_u32(bc_buf + pos + 5);
  35950             if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1, catch_pos))
  35951                 goto fail;
  35952             break;
  35953         case OP_with_make_ref:
  35954         case OP_with_get_ref:
  35955             diff = get_u32(bc_buf + pos + 5);
  35956             if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2, catch_pos))
  35957                 goto fail;
  35958             break;
  35959         case OP_with_put_var:
  35960             diff = get_u32(bc_buf + pos + 5);
  35961             if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1, catch_pos))
  35962                 goto fail;
  35963             break;
  35964         case OP_catch:
  35965             diff = get_u32(bc_buf + pos + 1);
  35966             if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))
  35967                 goto fail;
  35968             catch_pos = pos;
  35969             break;
  35970         case OP_for_of_start:
  35971         case OP_for_await_of_start:
  35972             catch_pos = pos;
  35973             break;
  35974             /* we assume the catch offset entry is only removed with
  35975                some op codes */
  35976         case OP_drop:
  35977             catch_level = stack_len;
  35978             goto check_catch;
  35979         case OP_nip:
  35980             catch_level = stack_len - 1;
  35981             goto check_catch;
  35982         case OP_nip1:
  35983             catch_level = stack_len - 1;
  35984             goto check_catch;
  35985         case OP_iterator_close:
  35986             catch_level = stack_len + 2;
  35987         check_catch:
  35988             /* Note: for for_of_start/for_await_of_start we consider
  35989                the catch offset is on the first stack entry instead of
  35990                the thirst */
  35991             if (catch_pos >= 0) {
  35992                 int level;
  35993                 level = s->stack_level_tab[catch_pos];
  35994                 if (bc_buf[catch_pos] != OP_catch)
  35995                     level++; /* for_of_start, for_wait_of_start */
  35996                 /* catch_level = stack_level before op_catch is executed ? */
  35997                 if (catch_level == level) {
  35998                     catch_pos = s->catch_pos_tab[catch_pos];
  35999                 }
  36000             }
  36001             break;
  36002         case OP_nip_catch:
  36003             if (catch_pos < 0) {
  36004                 JS_ThrowInternalError(ctx, "nip_catch: no catch op (pc=%d)", pos);
  36005                 goto fail;
  36006             }
  36007             stack_len = s->stack_level_tab[catch_pos];
  36008             if (bc_buf[catch_pos] != OP_catch)
  36009                 stack_len++; /* for_of_start, for_wait_of_start */
  36010             stack_len++; /* no stack overflow is possible by construction */
  36011             catch_pos = s->catch_pos_tab[catch_pos];
  36012             break;
  36013         default:
  36014             break;
  36015         }
  36016         if (ss_check(ctx, s, pos_next, op, stack_len, catch_pos))
  36017             goto fail;
  36018     done_insn: ;
  36019     }
  36020     js_free(ctx, s->pc_stack);
  36021     js_free(ctx, s->catch_pos_tab);
  36022     js_free(ctx, s->stack_level_tab);
  36023     *pstack_size = s->stack_len_max;
  36024     return 0;
  36025  fail:
  36026     js_free(ctx, s->pc_stack);
  36027     js_free(ctx, s->catch_pos_tab);
  36028     js_free(ctx, s->stack_level_tab);
  36029     *pstack_size = 0;
  36030     return -1;
  36031 }
  36032 
  36033 static int add_global_variables(JSContext *ctx, JSFunctionDef *fd)
  36034 {
  36035     int i, idx;
  36036     JSModuleDef *m = fd->module;
  36037     JSExportEntry *me;
  36038     JSGlobalVar *hf;
  36039     BOOL need_global_closures;
  36040     
  36041     /* Script: add the defined global variables. In the non strict
  36042        direct eval not in global scope, the global variables are
  36043        created in the enclosing scope so they are not created as
  36044        variable references.
  36045 
  36046        In modules, the imported global variables were added as closure
  36047        global variables in js_parse_import().
  36048     */
  36049     need_global_closures = TRUE;
  36050     if (fd->eval_type == JS_EVAL_TYPE_DIRECT && !(fd->js_mode & JS_MODE_STRICT)) {
  36051         /* XXX: add a flag ? */
  36052         for(idx = 0; idx < fd->closure_var_count; idx++) {
  36053             JSClosureVar *cv = &fd->closure_var[idx];
  36054             if (cv->var_name == JS_ATOM__var_ ||
  36055                 cv->var_name == JS_ATOM__arg_var_) {
  36056                 need_global_closures = FALSE;
  36057                 break;
  36058             }
  36059         }
  36060     }
  36061 
  36062     if (need_global_closures) {
  36063         JSClosureTypeEnum closure_type;
  36064         if (fd->module)
  36065             closure_type = JS_CLOSURE_MODULE_DECL;
  36066         else
  36067             closure_type = JS_CLOSURE_GLOBAL_DECL;
  36068         for(i = 0; i < fd->global_var_count; i++) {
  36069             JSVarKindEnum var_kind;
  36070             hf = &fd->global_vars[i];
  36071             if (hf->cpool_idx >= 0 && !hf->is_lexical) {
  36072                 var_kind = JS_VAR_GLOBAL_FUNCTION_DECL;
  36073             } else {
  36074                 var_kind = JS_VAR_NORMAL;
  36075             }
  36076             if (add_closure_var(ctx, fd, closure_type, i, hf->var_name, hf->is_const,
  36077                                 hf->is_lexical, var_kind) < 0)
  36078                 return -1;
  36079         }
  36080     }
  36081 
  36082     if (fd->module) {
  36083         /* resolve the variable names of the local exports */
  36084         for(i = 0; i < m->export_entries_count; i++) {
  36085             me = &m->export_entries[i];
  36086             if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
  36087                 idx = find_closure_var(ctx, fd, me->local_name);
  36088                 if (idx < 0) {
  36089                     JS_ThrowSyntaxErrorAtom(ctx, "exported variable '%s' does not exist",
  36090                                             me->local_name);
  36091                     return -1;
  36092                 }
  36093                 me->u.local.var_idx = idx;
  36094             }
  36095         }
  36096     }
  36097     return 0;
  36098 }
  36099 
  36100 /* create a function object from a function definition. The function
  36101    definition is freed. All the child functions are also created. It
  36102    must be done this way to resolve all the variables. */
  36103 static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
  36104 {
  36105     JSValue func_obj;
  36106     JSFunctionBytecode *b;
  36107     struct list_head *el, *el1;
  36108     int stack_size, scope, idx;
  36109     int function_size, byte_code_offset, cpool_offset;
  36110     int closure_var_offset, vardefs_offset;
  36111     BOOL strip_var_debug;
  36112     
  36113     /* recompute scope linkage */
  36114     for (scope = 0; scope < fd->scope_count; scope++) {
  36115         fd->scopes[scope].first = -1;
  36116     }
  36117     if (fd->has_parameter_expressions) {
  36118         /* special end of variable list marker for the argument scope */
  36119         fd->scopes[ARG_SCOPE_INDEX].first = ARG_SCOPE_END;
  36120     }
  36121     for (idx = 0; idx < fd->var_count; idx++) {
  36122         JSVarDef *vd = &fd->vars[idx];
  36123         vd->scope_next = fd->scopes[vd->scope_level].first;
  36124         fd->scopes[vd->scope_level].first = idx;
  36125     }
  36126     for (scope = 2; scope < fd->scope_count; scope++) {
  36127         JSVarScope *sd = &fd->scopes[scope];
  36128         if (sd->first < 0)
  36129             sd->first = fd->scopes[sd->parent].first;
  36130     }
  36131     for (idx = 0; idx < fd->var_count; idx++) {
  36132         JSVarDef *vd = &fd->vars[idx];
  36133         if (vd->scope_next < 0 && vd->scope_level > 1) {
  36134             scope = fd->scopes[vd->scope_level].parent;
  36135             vd->scope_next = fd->scopes[scope].first;
  36136         }
  36137     }
  36138 
  36139     /* if the function contains an eval call, the closure variables
  36140        are used to compile the eval and they must be ordered by scope,
  36141        so it is necessary to create the closure variables before any
  36142        other variable lookup is done. */
  36143     if (fd->has_eval_call)
  36144         add_eval_variables(ctx, fd);
  36145 
  36146     /* add the module global variables in the closure */
  36147     if (fd->is_eval) {
  36148         if (add_global_variables(ctx, fd))
  36149             goto fail;
  36150     } 
  36151 
  36152     /* first create all the child functions */
  36153     list_for_each_safe(el, el1, &fd->child_list) {
  36154         JSFunctionDef *fd1;
  36155         int cpool_idx;
  36156 
  36157         fd1 = list_entry(el, JSFunctionDef, link);
  36158         cpool_idx = fd1->parent_cpool_idx;
  36159         func_obj = js_create_function(ctx, fd1);
  36160         if (JS_IsException(func_obj))
  36161             goto fail;
  36162         /* save it in the constant pool */
  36163         assert(cpool_idx >= 0);
  36164         fd->cpool[cpool_idx] = func_obj;
  36165     }
  36166 
  36167 #if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 4)
  36168     if (!fd->strip_debug) {
  36169         printf("pass 1\n");
  36170         dump_byte_code(ctx, 1, fd->byte_code.buf, fd->byte_code.size,
  36171                        NULL, fd->args, fd->arg_count, fd->vars, fd->var_count,
  36172                        fd->closure_var, fd->closure_var_count,
  36173                        fd->cpool, fd->cpool_count, fd->source,
  36174                        fd->label_slots, NULL);
  36175         printf("\n");
  36176     }
  36177 #endif
  36178 
  36179     if (resolve_variables(ctx, fd))
  36180         goto fail;
  36181 
  36182 #if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 2)
  36183     if (!fd->strip_debug) {
  36184         printf("pass 2\n");
  36185         dump_byte_code(ctx, 2, fd->byte_code.buf, fd->byte_code.size,
  36186                        NULL, fd->args, fd->arg_count, fd->vars, fd->var_count,
  36187                        fd->closure_var, fd->closure_var_count,
  36188                        fd->cpool, fd->cpool_count, fd->source,
  36189                        fd->label_slots, NULL);
  36190         printf("\n");
  36191     }
  36192 #endif
  36193 
  36194     if (resolve_labels(ctx, fd))
  36195         goto fail;
  36196 
  36197     if (compute_stack_size(ctx, fd, &stack_size) < 0)
  36198         goto fail;
  36199 
  36200     if (fd->strip_debug) {
  36201         function_size = offsetof(JSFunctionBytecode, debug);
  36202     } else {
  36203         function_size = sizeof(*b);
  36204     }
  36205     cpool_offset = function_size;
  36206     function_size += fd->cpool_count * sizeof(*fd->cpool);
  36207     vardefs_offset = function_size;
  36208     function_size += (fd->arg_count + fd->var_count) * sizeof(*b->vardefs);
  36209     closure_var_offset = function_size;
  36210     function_size += fd->closure_var_count * sizeof(*fd->closure_var);
  36211     byte_code_offset = function_size;
  36212     function_size += fd->byte_code.size;
  36213 
  36214     b = js_mallocz(ctx, function_size);
  36215     if (!b)
  36216         goto fail;
  36217     js_rc(b)->ref_count = 1;
  36218 
  36219     b->byte_code_buf = (void *)((uint8_t*)b + byte_code_offset);
  36220     b->byte_code_len = fd->byte_code.size;
  36221     memcpy(b->byte_code_buf, fd->byte_code.buf, fd->byte_code.size);
  36222     js_free(ctx, fd->byte_code.buf);
  36223     fd->byte_code.buf = NULL;
  36224 
  36225     strip_var_debug = fd->strip_debug && !fd->has_eval_call; /* XXX: check */
  36226     b->func_name = fd->func_name;
  36227     if (fd->arg_count + fd->var_count > 0) {
  36228         int i;
  36229         b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
  36230         for(i = 0; i < fd->arg_count; i++) {
  36231             JSVarDef *vd = &fd->args[i];
  36232             JSBytecodeVarDef *vd1 = &b->vardefs[i];
  36233             if (strip_var_debug) {
  36234                 JS_FreeAtom(ctx, vd->var_name);
  36235                 vd1->var_name = JS_ATOM_NULL;
  36236             } else {
  36237                 vd1->var_name = vd->var_name;
  36238             }
  36239             vd1->has_scope = (vd->scope_level != 0);
  36240             vd1->scope_next = vd->scope_next;
  36241             vd1->is_const = vd->is_const;
  36242             vd1->is_lexical = vd->is_lexical;
  36243             vd1->is_captured = vd->is_captured;
  36244             vd1->var_kind = vd->var_kind;
  36245             vd1->var_ref_idx = vd->var_ref_idx;
  36246         }
  36247         
  36248         for(i = 0; i < fd->var_count; i++) {
  36249             JSVarDef *vd = &fd->vars[i];
  36250             JSBytecodeVarDef *vd1 = &b->vardefs[i + fd->arg_count];
  36251             if (strip_var_debug) {
  36252                 JS_FreeAtom(ctx, vd->var_name);
  36253                 vd1->var_name = JS_ATOM_NULL;
  36254             } else {
  36255                 vd1->var_name = vd->var_name;
  36256             }
  36257             vd1->has_scope = (vd->scope_level != 0);
  36258             vd1->scope_next = vd->scope_next;
  36259             vd1->is_const = vd->is_const;
  36260             vd1->is_lexical = vd->is_lexical;
  36261             vd1->is_captured = vd->is_captured;
  36262             vd1->var_kind = vd->var_kind;
  36263             vd1->var_ref_idx = vd->var_ref_idx;
  36264         }
  36265         b->var_count = fd->var_count;
  36266         b->arg_count = fd->arg_count;
  36267         b->defined_arg_count = fd->defined_arg_count;
  36268         b->var_ref_count = fd->var_ref_count;
  36269         js_free(ctx, fd->args);
  36270         js_free(ctx, fd->vars);
  36271     }
  36272     b->cpool_count = fd->cpool_count;
  36273     if (b->cpool_count) {
  36274         b->cpool = (void *)((uint8_t*)b + cpool_offset);
  36275         memcpy(b->cpool, fd->cpool, b->cpool_count * sizeof(*b->cpool));
  36276     }
  36277     js_free(ctx, fd->cpool);
  36278     fd->cpool = NULL;
  36279 
  36280     b->stack_size = stack_size;
  36281 
  36282     b->perf_trampoline = NULL;
  36283 
  36284     if (fd->strip_debug) {
  36285         JS_FreeAtom(ctx, fd->filename);
  36286         dbuf_free(&fd->pc2line);    // probably useless
  36287     } else {
  36288         /* XXX: source and pc2line info should be packed at the end of the
  36289            JSFunctionBytecode structure, avoiding allocation overhead
  36290          */
  36291         b->has_debug = 1;
  36292         b->debug.filename = fd->filename;
  36293 
  36294         //DynBuf pc2line;
  36295         //compute_pc2line_info(fd, &pc2line);
  36296         //js_free(ctx, fd->line_number_slots)
  36297         b->debug.pc2line_buf = js_realloc(ctx, fd->pc2line.buf, fd->pc2line.size);
  36298         if (!b->debug.pc2line_buf)
  36299             b->debug.pc2line_buf = fd->pc2line.buf;
  36300         b->debug.pc2line_len = fd->pc2line.size;
  36301         b->debug.source = fd->source;
  36302         b->debug.source_len = fd->source_len;
  36303     }
  36304     if (fd->scopes != fd->def_scope_array)
  36305         js_free(ctx, fd->scopes);
  36306 
  36307     b->closure_var_count = fd->closure_var_count;
  36308     if (b->closure_var_count) {
  36309         if (strip_var_debug) {
  36310             int i;
  36311             for(i = 0; i < fd->closure_var_count; i++) {
  36312                 JSClosureVar *cv = &fd->closure_var[i];
  36313                 if (cv->closure_type != JS_CLOSURE_GLOBAL_REF &&
  36314                     cv->closure_type != JS_CLOSURE_GLOBAL_DECL &&
  36315                     cv->closure_type != JS_CLOSURE_GLOBAL &&
  36316                     cv->closure_type != JS_CLOSURE_MODULE_DECL &&
  36317                     cv->closure_type != JS_CLOSURE_MODULE_IMPORT) {
  36318                     JS_FreeAtom(ctx, cv->var_name);
  36319                     cv->var_name = JS_ATOM_NULL;
  36320                 }
  36321             }
  36322         }
  36323         b->closure_var = (void *)((uint8_t*)b + closure_var_offset);
  36324         memcpy(b->closure_var, fd->closure_var, b->closure_var_count * sizeof(*b->closure_var));
  36325     }
  36326     js_free(ctx, fd->closure_var);
  36327     fd->closure_var = NULL;
  36328 
  36329     b->has_prototype = fd->has_prototype;
  36330     b->has_simple_parameter_list = fd->has_simple_parameter_list;
  36331     b->js_mode = fd->js_mode;
  36332     b->is_derived_class_constructor = fd->is_derived_class_constructor;
  36333     b->func_kind = fd->func_kind;
  36334     b->need_home_object = (fd->home_object_var_idx >= 0 ||
  36335                            fd->need_home_object);
  36336     b->new_target_allowed = fd->new_target_allowed;
  36337     b->super_call_allowed = fd->super_call_allowed;
  36338     b->super_allowed = fd->super_allowed;
  36339     b->arguments_allowed = fd->arguments_allowed;
  36340     b->is_direct_or_indirect_eval = (fd->eval_type == JS_EVAL_TYPE_DIRECT ||
  36341                                      fd->eval_type == JS_EVAL_TYPE_INDIRECT);
  36342     b->realm = JS_DupContext(ctx);
  36343 
  36344     add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
  36345 
  36346 #if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 1)
  36347     if (!fd->strip_debug) {
  36348         js_dump_function_bytecode(ctx, b);
  36349     }
  36350 #endif
  36351 
  36352     if (fd->parent) {
  36353         /* remove from parent list */
  36354         list_del(&fd->link);
  36355     }
  36356 
  36357     js_free(ctx, fd);
  36358     return JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);
  36359  fail:
  36360     js_free_function_def(ctx, fd);
  36361     return JS_EXCEPTION;
  36362 }
  36363 
  36364 static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b)
  36365 {
  36366     int i;
  36367 
  36368 #if 0
  36369     {
  36370         char buf[ATOM_GET_STR_BUF_SIZE];
  36371         printf("freeing %s\n",
  36372                JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
  36373     }
  36374 #endif
  36375     if (b->byte_code_buf)
  36376         free_bytecode_atoms(rt, b->byte_code_buf, b->byte_code_len, TRUE);
  36377 
  36378     if (b->vardefs) {
  36379         for(i = 0; i < b->arg_count + b->var_count; i++) {
  36380             JS_FreeAtomRT(rt, b->vardefs[i].var_name);
  36381         }
  36382     }
  36383     for(i = 0; i < b->cpool_count; i++)
  36384         JS_FreeValueRT(rt, b->cpool[i]);
  36385 
  36386     for(i = 0; i < b->closure_var_count; i++) {
  36387         JSClosureVar *cv = &b->closure_var[i];
  36388         JS_FreeAtomRT(rt, cv->var_name);
  36389     }
  36390     if (b->realm)
  36391         JS_FreeContext(b->realm);
  36392 
  36393     JS_FreeAtomRT(rt, b->func_name);
  36394     if (b->has_debug) {
  36395         JS_FreeAtomRT(rt, b->debug.filename);
  36396         js_free_rt(rt, b->debug.pc2line_buf);
  36397         js_free_rt(rt, b->debug.source);
  36398     }
  36399 
  36400     remove_gc_object(&b->header);
  36401     if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && js_rc(b)->ref_count != 0) {
  36402         list_add_tail(&b->header.link, &rt->gc_zero_ref_count_list);
  36403     } else {
  36404         js_free_rt(rt, b);
  36405     }
  36406 }
  36407 
  36408 static __exception int js_parse_directives(JSParseState *s)
  36409 {
  36410     char str[20];
  36411     JSParsePos pos;
  36412     BOOL has_semi;
  36413 
  36414     if (s->token.val != TOK_STRING)
  36415         return 0;
  36416 
  36417     js_parse_get_pos(s, &pos);
  36418 
  36419     while(s->token.val == TOK_STRING) {
  36420         /* Copy actual source string representation */
  36421         snprintf(str, sizeof str, "%.*s",
  36422                  (int)(s->buf_ptr - s->token.ptr - 2), s->token.ptr + 1);
  36423 
  36424         if (next_token(s))
  36425             return -1;
  36426 
  36427         has_semi = FALSE;
  36428         switch (s->token.val) {
  36429         case ';':
  36430             if (next_token(s))
  36431                 return -1;
  36432             has_semi = TRUE;
  36433             break;
  36434         case '}':
  36435         case TOK_EOF:
  36436             has_semi = TRUE;
  36437             break;
  36438         case TOK_NUMBER:
  36439         case TOK_STRING:
  36440         case TOK_TEMPLATE:
  36441         case TOK_IDENT:
  36442         case TOK_REGEXP:
  36443         case TOK_DEC:
  36444         case TOK_INC:
  36445         case TOK_NULL:
  36446         case TOK_FALSE:
  36447         case TOK_TRUE:
  36448         case TOK_IF:
  36449         case TOK_RETURN:
  36450         case TOK_VAR:
  36451         case TOK_THIS:
  36452         case TOK_DELETE:
  36453         case TOK_TYPEOF:
  36454         case TOK_NEW:
  36455         case TOK_DO:
  36456         case TOK_WHILE:
  36457         case TOK_FOR:
  36458         case TOK_SWITCH:
  36459         case TOK_THROW:
  36460         case TOK_TRY:
  36461         case TOK_FUNCTION:
  36462         case TOK_DEBUGGER:
  36463         case TOK_WITH:
  36464         case TOK_CLASS:
  36465         case TOK_CONST:
  36466         case TOK_ENUM:
  36467         case TOK_EXPORT:
  36468         case TOK_IMPORT:
  36469         case TOK_SUPER:
  36470         case TOK_INTERFACE:
  36471         case TOK_LET:
  36472         case TOK_PACKAGE:
  36473         case TOK_PRIVATE:
  36474         case TOK_PROTECTED:
  36475         case TOK_PUBLIC:
  36476         case TOK_STATIC:
  36477             /* automatic insertion of ';' */
  36478             if (s->got_lf)
  36479                 has_semi = TRUE;
  36480             break;
  36481         default:
  36482             break;
  36483         }
  36484         if (!has_semi)
  36485             break;
  36486         if (!strcmp(str, "use strict")) {
  36487             s->cur_func->has_use_strict = TRUE;
  36488             s->cur_func->js_mode |= JS_MODE_STRICT;
  36489         }
  36490     }
  36491     return js_parse_seek_token(s, &pos);
  36492 }
  36493 
  36494 /* return TRUE if the keyword is forbidden only in strict mode */
  36495 static BOOL is_strict_future_keyword(JSAtom atom)
  36496 {
  36497     return (atom >= JS_ATOM_LAST_KEYWORD + 1 && atom <= JS_ATOM_LAST_STRICT_KEYWORD);
  36498 }
  36499 
  36500 static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd,
  36501                                          JSAtom func_name)
  36502 {
  36503     JSAtom name;
  36504     int i, idx;
  36505 
  36506     if (fd->js_mode & JS_MODE_STRICT) {
  36507         if (!fd->has_simple_parameter_list && fd->has_use_strict) {
  36508             return js_parse_error(s, "\"use strict\" not allowed in function with default or destructuring parameter");
  36509         }
  36510         if (func_name == JS_ATOM_eval || func_name == JS_ATOM_arguments ||
  36511             is_strict_future_keyword(func_name)) {
  36512             return js_parse_error(s, "invalid function name in strict code");
  36513         }
  36514         for (idx = 0; idx < fd->arg_count; idx++) {
  36515             name = fd->args[idx].var_name;
  36516 
  36517             if (name == JS_ATOM_eval || name == JS_ATOM_arguments ||
  36518                 is_strict_future_keyword(name)) {
  36519                 return js_parse_error(s, "invalid argument name in strict code");
  36520             }
  36521         }
  36522     }
  36523     /* check async_generator case */
  36524     if ((fd->js_mode & JS_MODE_STRICT)
  36525     ||  !fd->has_simple_parameter_list
  36526     ||  (fd->func_type == JS_PARSE_FUNC_METHOD && fd->func_kind == JS_FUNC_ASYNC)
  36527     ||  fd->func_type == JS_PARSE_FUNC_ARROW
  36528     ||  fd->func_type == JS_PARSE_FUNC_METHOD) {
  36529         for (idx = 0; idx < fd->arg_count; idx++) {
  36530             name = fd->args[idx].var_name;
  36531             if (name != JS_ATOM_NULL) {
  36532                 for (i = 0; i < idx; i++) {
  36533                     if (fd->args[i].var_name == name)
  36534                         goto duplicate;
  36535                 }
  36536                 /* Check if argument name duplicates a destructuring parameter */
  36537                 /* XXX: should have a flag for such variables */
  36538                 for (i = 0; i < fd->var_count; i++) {
  36539                     if (fd->vars[i].var_name == name &&
  36540                         fd->vars[i].scope_level == 0)
  36541                         goto duplicate;
  36542                 }
  36543             }
  36544         }
  36545     }
  36546     return 0;
  36547 
  36548 duplicate:
  36549     return js_parse_error(s, "duplicate argument names not allowed in this context");
  36550 }
  36551 
  36552 /* create a function to initialize class fields */
  36553 static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s)
  36554 {
  36555     JSFunctionDef *fd;
  36556 
  36557     fd = js_new_function_def(s->ctx, s->cur_func, FALSE, FALSE,
  36558                              s->filename, s->buf_start,
  36559                              &s->get_line_col_cache);
  36560     if (!fd)
  36561         return NULL;
  36562     fd->func_name = JS_ATOM_NULL;
  36563     fd->has_prototype = FALSE;
  36564     fd->has_home_object = TRUE;
  36565 
  36566     fd->has_arguments_binding = FALSE;
  36567     fd->has_this_binding = TRUE;
  36568     fd->is_derived_class_constructor = FALSE;
  36569     fd->new_target_allowed = TRUE;
  36570     fd->super_call_allowed = FALSE;
  36571     fd->super_allowed = fd->has_home_object;
  36572     fd->arguments_allowed = FALSE;
  36573 
  36574     fd->func_kind = JS_FUNC_NORMAL;
  36575     fd->func_type = JS_PARSE_FUNC_METHOD;
  36576     return fd;
  36577 }
  36578 
  36579 /* func_name must be JS_ATOM_NULL for JS_PARSE_FUNC_STATEMENT and
  36580    JS_PARSE_FUNC_EXPR, JS_PARSE_FUNC_ARROW and JS_PARSE_FUNC_VAR */
  36581 static __exception int js_parse_function_decl2(JSParseState *s,
  36582                                                JSParseFunctionEnum func_type,
  36583                                                JSFunctionKindEnum func_kind,
  36584                                                JSAtom func_name,
  36585                                                const uint8_t *ptr,
  36586                                                JSParseExportEnum export_flag,
  36587                                                JSFunctionDef **pfd)
  36588 {
  36589     JSContext *ctx = s->ctx;
  36590     JSFunctionDef *fd = s->cur_func;
  36591     BOOL is_expr;
  36592     int func_idx, lexical_func_idx = -1;
  36593     BOOL has_opt_arg;
  36594     BOOL create_func_var = FALSE;
  36595 
  36596     is_expr = (func_type != JS_PARSE_FUNC_STATEMENT &&
  36597                func_type != JS_PARSE_FUNC_VAR);
  36598 
  36599     if (func_type == JS_PARSE_FUNC_STATEMENT ||
  36600         func_type == JS_PARSE_FUNC_VAR ||
  36601         func_type == JS_PARSE_FUNC_EXPR) {
  36602         if (func_kind == JS_FUNC_NORMAL &&
  36603             token_is_pseudo_keyword(s, JS_ATOM_async) &&
  36604             peek_token(s, TRUE) != '\n') {
  36605             if (next_token(s))
  36606                 return -1;
  36607             func_kind = JS_FUNC_ASYNC;
  36608         }
  36609         if (next_token(s))
  36610             return -1;
  36611         if (s->token.val == '*') {
  36612             if (next_token(s))
  36613                 return -1;
  36614             func_kind |= JS_FUNC_GENERATOR;
  36615         }
  36616 
  36617         if (s->token.val == TOK_IDENT) {
  36618             if (s->token.u.ident.is_reserved ||
  36619                 (s->token.u.ident.atom == JS_ATOM_yield &&
  36620                  func_type == JS_PARSE_FUNC_EXPR &&
  36621                  (func_kind & JS_FUNC_GENERATOR)) ||
  36622                 (s->token.u.ident.atom == JS_ATOM_await &&
  36623                  ((func_type == JS_PARSE_FUNC_EXPR &&
  36624                    (func_kind & JS_FUNC_ASYNC)) ||
  36625                   func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))) {
  36626                 return js_parse_error_reserved_identifier(s);
  36627             }
  36628         }
  36629         if (s->token.val == TOK_IDENT ||
  36630             (((s->token.val == TOK_YIELD && !(fd->js_mode & JS_MODE_STRICT)) ||
  36631              (s->token.val == TOK_AWAIT && !s->is_module)) &&
  36632              func_type == JS_PARSE_FUNC_EXPR)) {
  36633             func_name = JS_DupAtom(ctx, s->token.u.ident.atom);
  36634             if (next_token(s)) {
  36635                 JS_FreeAtom(ctx, func_name);
  36636                 return -1;
  36637             }
  36638         } else {
  36639             if (func_type != JS_PARSE_FUNC_EXPR &&
  36640                 export_flag != JS_PARSE_EXPORT_DEFAULT) {
  36641                 return js_parse_error(s, "function name expected");
  36642             }
  36643         }
  36644     } else if (func_type != JS_PARSE_FUNC_ARROW) {
  36645         func_name = JS_DupAtom(ctx, func_name);
  36646     }
  36647 
  36648     if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_MODULE &&
  36649         (func_type == JS_PARSE_FUNC_STATEMENT || func_type == JS_PARSE_FUNC_VAR)) {
  36650         JSGlobalVar *hf;
  36651         hf = find_global_var(fd, func_name);
  36652         /* XXX: should check scope chain */
  36653         if (hf && hf->scope_level == fd->scope_level) {
  36654             js_parse_error(s, "invalid redefinition of global identifier in module code");
  36655             JS_FreeAtom(ctx, func_name);
  36656             return -1;
  36657         }
  36658     }
  36659 
  36660     if (func_type == JS_PARSE_FUNC_VAR) {
  36661         if (!(fd->js_mode & JS_MODE_STRICT)
  36662         && func_kind == JS_FUNC_NORMAL
  36663         &&  find_lexical_decl(ctx, fd, func_name, fd->scope_first, FALSE) < 0
  36664         &&  !((func_idx = find_var(ctx, fd, func_name)) >= 0 && (func_idx & ARGUMENT_VAR_OFFSET))
  36665         &&  !(func_name == JS_ATOM_arguments && fd->has_arguments_binding)) {
  36666             create_func_var = TRUE;
  36667         }
  36668         /* Create the lexical name here so that the function closure
  36669            contains it */
  36670         if (fd->is_eval &&
  36671             (fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
  36672              fd->eval_type == JS_EVAL_TYPE_MODULE) &&
  36673             fd->scope_level == fd->body_scope) {
  36674             /* avoid creating a lexical variable in the global
  36675                scope. XXX: check annex B */
  36676             JSGlobalVar *hf;
  36677             hf = find_global_var(fd, func_name);
  36678             /* XXX: should check scope chain */
  36679             if (hf && hf->scope_level == fd->scope_level) {
  36680                 js_parse_error(s, "invalid redefinition of global identifier");
  36681                 JS_FreeAtom(ctx, func_name);
  36682                 return -1;
  36683             }
  36684         } else {
  36685             /* Always create a lexical name, fail if at the same scope as
  36686                existing name */
  36687             /* Lexical variable will be initialized upon entering scope */
  36688             lexical_func_idx = define_var(s, fd, func_name,
  36689                                           func_kind != JS_FUNC_NORMAL ?
  36690                                           JS_VAR_DEF_NEW_FUNCTION_DECL :
  36691                                           JS_VAR_DEF_FUNCTION_DECL);
  36692             if (lexical_func_idx < 0) {
  36693                 JS_FreeAtom(ctx, func_name);
  36694                 return -1;
  36695             }
  36696         }
  36697     }
  36698 
  36699     fd = js_new_function_def(ctx, fd, FALSE, is_expr,
  36700                              s->filename, ptr,
  36701                              &s->get_line_col_cache);
  36702     if (!fd) {
  36703         JS_FreeAtom(ctx, func_name);
  36704         return -1;
  36705     }
  36706     if (pfd)
  36707         *pfd = fd;
  36708     s->cur_func = fd;
  36709     fd->func_name = func_name;
  36710     /* XXX: test !fd->is_generator is always false */
  36711     fd->has_prototype = (func_type == JS_PARSE_FUNC_STATEMENT ||
  36712                          func_type == JS_PARSE_FUNC_VAR ||
  36713                          func_type == JS_PARSE_FUNC_EXPR) &&
  36714                         func_kind == JS_FUNC_NORMAL;
  36715     fd->has_home_object = (func_type == JS_PARSE_FUNC_METHOD ||
  36716                            func_type == JS_PARSE_FUNC_GETTER ||
  36717                            func_type == JS_PARSE_FUNC_SETTER ||
  36718                            func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR ||
  36719                            func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);
  36720     fd->has_arguments_binding = (func_type != JS_PARSE_FUNC_ARROW &&
  36721                                  func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT);
  36722     fd->has_this_binding = fd->has_arguments_binding;
  36723     fd->is_derived_class_constructor = (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);
  36724     if (func_type == JS_PARSE_FUNC_ARROW) {
  36725         fd->new_target_allowed = fd->parent->new_target_allowed;
  36726         fd->super_call_allowed = fd->parent->super_call_allowed;
  36727         fd->super_allowed = fd->parent->super_allowed;
  36728         fd->arguments_allowed = fd->parent->arguments_allowed;
  36729     } else if (func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) {
  36730         fd->new_target_allowed = TRUE; // although new.target === undefined
  36731         fd->super_call_allowed = FALSE;
  36732         fd->super_allowed = TRUE;
  36733         fd->arguments_allowed = FALSE;
  36734     } else {
  36735         fd->new_target_allowed = TRUE;
  36736         fd->super_call_allowed = fd->is_derived_class_constructor;
  36737         fd->super_allowed = fd->has_home_object;
  36738         fd->arguments_allowed = TRUE;
  36739     }
  36740 
  36741     /* fd->in_function_body == FALSE prevents yield/await during the parsing
  36742        of the arguments in generator/async functions. They are parsed as
  36743        regular identifiers for other function kinds. */
  36744     fd->func_kind = func_kind;
  36745     fd->func_type = func_type;
  36746 
  36747     if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR ||
  36748         func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR) {
  36749         /* error if not invoked as a constructor */
  36750         emit_op(s, OP_check_ctor);
  36751     }
  36752 
  36753     if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) {
  36754         emit_class_field_init(s);
  36755     }
  36756 
  36757     /* parse arguments */
  36758     fd->has_simple_parameter_list = TRUE;
  36759     fd->has_parameter_expressions = FALSE;
  36760     has_opt_arg = FALSE;
  36761     if (func_type == JS_PARSE_FUNC_ARROW && s->token.val == TOK_IDENT) {
  36762         JSAtom name;
  36763         if (s->token.u.ident.is_reserved) {
  36764             js_parse_error_reserved_identifier(s);
  36765             goto fail;
  36766         }
  36767         name = s->token.u.ident.atom;
  36768         if (add_arg(ctx, fd, name) < 0)
  36769             goto fail;
  36770         fd->defined_arg_count = 1;
  36771     } else if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) {
  36772         if (s->token.val == '(') {
  36773             int skip_bits;
  36774             /* if there is an '=' inside the parameter list, we
  36775                consider there is a parameter expression inside */
  36776             js_parse_skip_parens_token(s, &skip_bits, FALSE);
  36777             if (skip_bits & SKIP_HAS_ASSIGNMENT)
  36778                 fd->has_parameter_expressions = TRUE;
  36779             if (next_token(s))
  36780                 goto fail;
  36781         } else {
  36782             if (js_parse_expect(s, '('))
  36783                 goto fail;
  36784         }
  36785 
  36786         if (fd->has_parameter_expressions) {
  36787             fd->scope_level = -1; /* force no parent scope */
  36788             if (push_scope(s) < 0)
  36789                 return -1;
  36790         }
  36791 
  36792         while (s->token.val != ')') {
  36793             JSAtom name;
  36794             BOOL rest = FALSE;
  36795             int idx, has_initializer;
  36796 
  36797             if (s->token.val == TOK_ELLIPSIS) {
  36798                 if (func_type == JS_PARSE_FUNC_SETTER)
  36799                     goto fail_accessor;
  36800                 fd->has_simple_parameter_list = FALSE;
  36801                 rest = TRUE;
  36802                 if (next_token(s))
  36803                     goto fail;
  36804             }
  36805             if (s->token.val == '[' || s->token.val == '{') {
  36806                 fd->has_simple_parameter_list = FALSE;
  36807                 if (rest) {
  36808                     emit_op(s, OP_rest);
  36809                     emit_u16(s, fd->arg_count);
  36810                 } else {
  36811                     /* unnamed arg for destructuring */
  36812                     idx = add_arg(ctx, fd, JS_ATOM_NULL);
  36813                     emit_op(s, OP_get_arg);
  36814                     emit_u16(s, idx);
  36815                 }
  36816                 has_initializer = js_parse_destructuring_element(s, fd->has_parameter_expressions ? TOK_LET : TOK_VAR, 1, TRUE, -1, TRUE, FALSE);
  36817                 if (has_initializer < 0)
  36818                     goto fail;
  36819                 if (has_initializer)
  36820                     has_opt_arg = TRUE;
  36821                 if (!has_opt_arg)
  36822                     fd->defined_arg_count++;
  36823             } else if (s->token.val == TOK_IDENT) {
  36824                 if (s->token.u.ident.is_reserved) {
  36825                     js_parse_error_reserved_identifier(s);
  36826                     goto fail;
  36827                 }
  36828                 name = s->token.u.ident.atom;
  36829                 if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) {
  36830                     js_parse_error_reserved_identifier(s);
  36831                     goto fail;
  36832                 }
  36833                 if (fd->has_parameter_expressions) {
  36834                     if (js_parse_check_duplicate_parameter(s, name))
  36835                         goto fail;
  36836                     if (define_var(s, fd, name, JS_VAR_DEF_LET) < 0)
  36837                         goto fail;
  36838                 }
  36839                 /* XXX: could avoid allocating an argument if rest is true */
  36840                 idx = add_arg(ctx, fd, name);
  36841                 if (idx < 0)
  36842                     goto fail;
  36843                 if (next_token(s))
  36844                     goto fail;
  36845                 if (rest) {
  36846                     emit_op(s, OP_rest);
  36847                     emit_u16(s, idx);
  36848                     if (fd->has_parameter_expressions) {
  36849                         emit_op(s, OP_dup);
  36850                         emit_op(s, OP_scope_put_var_init);
  36851                         emit_atom(s, name);
  36852                         emit_u16(s, fd->scope_level);
  36853                     }
  36854                     emit_op(s, OP_put_arg);
  36855                     emit_u16(s, idx);
  36856                     fd->has_simple_parameter_list = FALSE;
  36857                     has_opt_arg = TRUE;
  36858                 } else if (s->token.val == '=') {
  36859                     int label;
  36860 
  36861                     fd->has_simple_parameter_list = FALSE;
  36862                     has_opt_arg = TRUE;
  36863 
  36864                     if (next_token(s))
  36865                         goto fail;
  36866 
  36867                     label = new_label(s);
  36868                     emit_op(s, OP_get_arg);
  36869                     emit_u16(s, idx);
  36870                     emit_op(s, OP_dup);
  36871                     emit_op(s, OP_undefined);
  36872                     emit_op(s, OP_strict_eq);
  36873                     emit_goto(s, OP_if_false, label);
  36874                     emit_op(s, OP_drop);
  36875                     if (js_parse_assign_expr(s))
  36876                         goto fail;
  36877                     set_object_name(s, name);
  36878                     emit_op(s, OP_dup);
  36879                     emit_op(s, OP_put_arg);
  36880                     emit_u16(s, idx);
  36881                     emit_label(s, label);
  36882                     emit_op(s, OP_scope_put_var_init);
  36883                     emit_atom(s, name);
  36884                     emit_u16(s, fd->scope_level);
  36885                 } else {
  36886                     if (!has_opt_arg) {
  36887                         fd->defined_arg_count++;
  36888                     }
  36889                     if (fd->has_parameter_expressions) {
  36890                         /* copy the argument to the argument scope */
  36891                         emit_op(s, OP_get_arg);
  36892                         emit_u16(s, idx);
  36893                         emit_op(s, OP_scope_put_var_init);
  36894                         emit_atom(s, name);
  36895                         emit_u16(s, fd->scope_level);
  36896                     }
  36897                 }
  36898             } else {
  36899                 js_parse_error(s, "missing formal parameter");
  36900                 goto fail;
  36901             }
  36902             if (rest && s->token.val != ')') {
  36903                 js_parse_expect(s, ')');
  36904                 goto fail;
  36905             }
  36906             if (s->token.val == ')')
  36907                 break;
  36908             if (js_parse_expect(s, ','))
  36909                 goto fail;
  36910         }
  36911         if ((func_type == JS_PARSE_FUNC_GETTER && fd->arg_count != 0) ||
  36912             (func_type == JS_PARSE_FUNC_SETTER && fd->arg_count != 1)) {
  36913         fail_accessor:
  36914             js_parse_error(s, "invalid number of arguments for getter or setter");
  36915             goto fail;
  36916         }
  36917     }
  36918 
  36919     if (fd->has_parameter_expressions) {
  36920         int idx;
  36921 
  36922         /* Copy the variables in the argument scope to the variable
  36923            scope (see FunctionDeclarationInstantiation() in spec). The
  36924            normal arguments are already present, so no need to copy
  36925            them. */
  36926         idx = fd->scopes[fd->scope_level].first;
  36927         while (idx >= 0) {
  36928             JSVarDef *vd = &fd->vars[idx];
  36929             if (vd->scope_level != fd->scope_level)
  36930                 break;
  36931             if (find_var(ctx, fd, vd->var_name) < 0) {
  36932                 if (add_var(ctx, fd, vd->var_name) < 0)
  36933                     goto fail;
  36934                 vd = &fd->vars[idx]; /* fd->vars may have been reallocated */
  36935                 emit_op(s, OP_scope_get_var);
  36936                 emit_atom(s, vd->var_name);
  36937                 emit_u16(s, fd->scope_level);
  36938                 emit_op(s, OP_scope_put_var);
  36939                 emit_atom(s, vd->var_name);
  36940                 emit_u16(s, 0);
  36941             }
  36942             idx = vd->scope_next;
  36943         }
  36944 
  36945         /* the argument scope has no parent, hence we don't use pop_scope(s) */
  36946         emit_op(s, OP_leave_scope);
  36947         emit_u16(s, fd->scope_level);
  36948 
  36949         /* set the variable scope as the current scope */
  36950         fd->scope_level = 0;
  36951         fd->scope_first = fd->scopes[fd->scope_level].first;
  36952     }
  36953 
  36954     if (next_token(s))
  36955         goto fail;
  36956 
  36957     /* generator function: yield after the parameters are evaluated */
  36958     if (func_kind == JS_FUNC_GENERATOR ||
  36959         func_kind == JS_FUNC_ASYNC_GENERATOR)
  36960         emit_op(s, OP_initial_yield);
  36961 
  36962     /* in generators, yield expression is forbidden during the parsing
  36963        of the arguments */
  36964     fd->in_function_body = TRUE;
  36965     push_scope(s);  /* enter body scope */
  36966     fd->body_scope = fd->scope_level;
  36967 
  36968     if (s->token.val == TOK_ARROW && func_type == JS_PARSE_FUNC_ARROW) {
  36969         if (next_token(s))
  36970             goto fail;
  36971 
  36972         if (s->token.val != '{') {
  36973             if (js_parse_function_check_names(s, fd, func_name))
  36974                 goto fail;
  36975 
  36976             if (js_parse_assign_expr(s))
  36977                 goto fail;
  36978 
  36979             if (func_kind != JS_FUNC_NORMAL)
  36980                 emit_op(s, OP_return_async);
  36981             else
  36982                 emit_op(s, OP_return);
  36983 
  36984             if (!fd->strip_source) {
  36985                 /* save the function source code */
  36986                 /* the end of the function source code is after the last
  36987                    token of the function source stored into s->last_ptr */
  36988                 fd->source_len = s->last_ptr - ptr;
  36989                 fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len);
  36990                 if (!fd->source)
  36991                     goto fail;
  36992             }
  36993             goto done;
  36994         }
  36995     }
  36996 
  36997     if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) {
  36998         if (js_parse_expect(s, '{'))
  36999             goto fail;
  37000     }
  37001 
  37002     if (js_parse_directives(s))
  37003         goto fail;
  37004 
  37005     /* in strict_mode, check function and argument names */
  37006     if (js_parse_function_check_names(s, fd, func_name))
  37007         goto fail;
  37008 
  37009     while (s->token.val != '}') {
  37010         if (js_parse_source_element(s))
  37011             goto fail;
  37012     }
  37013     if (!fd->strip_source) {
  37014         /* save the function source code */
  37015         fd->source_len = s->buf_ptr - ptr;
  37016         fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len);
  37017         if (!fd->source)
  37018             goto fail;
  37019     }
  37020 
  37021     if (next_token(s)) {
  37022         /* consume the '}' */
  37023         goto fail;
  37024     }
  37025 
  37026     /* in case there is no return, add one */
  37027     if (js_is_live_code(s)) {
  37028         emit_return(s, FALSE);
  37029     }
  37030  done:
  37031     s->cur_func = fd->parent;
  37032 
  37033     /* Reparse identifiers after the function is terminated so that
  37034        the token is parsed in the englobing function. It could be done
  37035        by just using next_token() here for normal functions, but it is
  37036        necessary for arrow functions with an expression body. */
  37037     reparse_ident_token(s);
  37038 
  37039     /* create the function object */
  37040     {
  37041         int idx;
  37042         JSAtom func_name = fd->func_name;
  37043 
  37044         /* the real object will be set at the end of the compilation */
  37045         idx = cpool_add(s, JS_NULL);
  37046         fd->parent_cpool_idx = idx;
  37047 
  37048         if (is_expr) {
  37049             /* for constructors, no code needs to be generated here */
  37050             if (func_type != JS_PARSE_FUNC_CLASS_CONSTRUCTOR &&
  37051                 func_type != JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR) {
  37052                 /* OP_fclosure creates the function object from the bytecode
  37053                    and adds the scope information */
  37054                 emit_op(s, OP_fclosure);
  37055                 emit_u32(s, idx);
  37056                 if (func_name == JS_ATOM_NULL) {
  37057                     emit_op(s, OP_set_name);
  37058                     emit_u32(s, JS_ATOM_NULL);
  37059                 }
  37060             }
  37061         } else if (func_type == JS_PARSE_FUNC_VAR) {
  37062             emit_op(s, OP_fclosure);
  37063             emit_u32(s, idx);
  37064             if (create_func_var) {
  37065                 if (s->cur_func->is_global_var) {
  37066                     JSGlobalVar *hf;
  37067                     /* the global variable must be defined at the start of the
  37068                        function */
  37069                     hf = add_global_var(ctx, s->cur_func, func_name);
  37070                     if (!hf)
  37071                         goto fail;
  37072                     /* it is considered as defined at the top level
  37073                        (needed for annex B.3.3.4 and B.3.3.5
  37074                        checks) */
  37075                     hf->scope_level = 0;
  37076                     hf->force_init = ((s->cur_func->js_mode & JS_MODE_STRICT) != 0);
  37077                     /* store directly into global var, bypass lexical scope */
  37078                     emit_op(s, OP_dup);
  37079                     emit_op(s, OP_scope_put_var);
  37080                     emit_atom(s, func_name);
  37081                     emit_u16(s, 0);
  37082                 } else {
  37083                     /* do not call define_var to bypass lexical scope check */
  37084                     func_idx = find_var(ctx, s->cur_func, func_name);
  37085                     if (func_idx < 0) {
  37086                         func_idx = add_var(ctx, s->cur_func, func_name);
  37087                         if (func_idx < 0)
  37088                             goto fail;
  37089                     }
  37090                     /* store directly into local var, bypass lexical catch scope */
  37091                     emit_op(s, OP_dup);
  37092                     emit_op(s, OP_scope_put_var);
  37093                     emit_atom(s, func_name);
  37094                     emit_u16(s, 0);
  37095                 }
  37096             }
  37097             if (lexical_func_idx >= 0) {
  37098                 /* lexical variable will be initialized upon entering scope */
  37099                 s->cur_func->vars[lexical_func_idx].func_pool_idx = idx;
  37100                 emit_op(s, OP_drop);
  37101             } else {
  37102                 /* store function object into its lexical name */
  37103                 /* XXX: could use OP_put_loc directly */
  37104                 emit_op(s, OP_scope_put_var_init);
  37105                 emit_atom(s, func_name);
  37106                 emit_u16(s, s->cur_func->scope_level);
  37107             }
  37108         } else {
  37109             if (!s->cur_func->is_global_var) {
  37110                 int var_idx = define_var(s, s->cur_func, func_name, JS_VAR_DEF_VAR);
  37111 
  37112                 if (var_idx < 0)
  37113                     goto fail;
  37114                 /* the variable will be assigned at the top of the function */
  37115                 if (var_idx & ARGUMENT_VAR_OFFSET) {
  37116                     s->cur_func->args[var_idx - ARGUMENT_VAR_OFFSET].func_pool_idx = idx;
  37117                 } else {
  37118                     s->cur_func->vars[var_idx].func_pool_idx = idx;
  37119                 }
  37120             } else {
  37121                 JSAtom func_var_name;
  37122                 JSGlobalVar *hf;
  37123                 if (func_name == JS_ATOM_NULL)
  37124                     func_var_name = JS_ATOM__default_; /* export default */
  37125                 else
  37126                     func_var_name = func_name;
  37127                 /* the variable will be assigned at the top of the function */
  37128                 hf = add_global_var(ctx, s->cur_func, func_var_name);
  37129                 if (!hf)
  37130                     goto fail;
  37131                 hf->cpool_idx = idx;
  37132                 if (export_flag != JS_PARSE_EXPORT_NONE) {
  37133                     if (!add_export_entry(s, s->cur_func->module, func_var_name,
  37134                                           export_flag == JS_PARSE_EXPORT_NAMED ? func_var_name : JS_ATOM_default, JS_EXPORT_TYPE_LOCAL))
  37135                         goto fail;
  37136                 }
  37137             }
  37138         }
  37139     }
  37140     return 0;
  37141  fail:
  37142     s->cur_func = fd->parent;
  37143     js_free_function_def(ctx, fd);
  37144     if (pfd)
  37145         *pfd = NULL;
  37146     return -1;
  37147 }
  37148 
  37149 static __exception int js_parse_function_decl(JSParseState *s,
  37150                                               JSParseFunctionEnum func_type,
  37151                                               JSFunctionKindEnum func_kind,
  37152                                               JSAtom func_name,
  37153                                               const uint8_t *ptr)
  37154 {
  37155     return js_parse_function_decl2(s, func_type, func_kind, func_name, ptr,
  37156                                    JS_PARSE_EXPORT_NONE, NULL);
  37157 }
  37158 
  37159 static __exception int js_parse_program(JSParseState *s)
  37160 {
  37161     JSFunctionDef *fd = s->cur_func;
  37162     int idx;
  37163 
  37164     if (next_token(s))
  37165         return -1;
  37166 
  37167     if (js_parse_directives(s))
  37168         return -1;
  37169 
  37170     fd->is_global_var = (fd->eval_type == JS_EVAL_TYPE_GLOBAL) ||
  37171         (fd->eval_type == JS_EVAL_TYPE_MODULE) ||
  37172         !(fd->js_mode & JS_MODE_STRICT);
  37173 
  37174     if (!s->is_module) {
  37175         /* hidden variable for the return value */
  37176         fd->eval_ret_idx = idx = add_var(s->ctx, fd, JS_ATOM__ret_);
  37177         if (idx < 0)
  37178             return -1;
  37179     }
  37180 
  37181     while (s->token.val != TOK_EOF) {
  37182         if (js_parse_source_element(s))
  37183             return -1;
  37184     }
  37185 
  37186     if (!s->is_module) {
  37187         /* return the value of the hidden variable eval_ret_idx  */
  37188         if (fd->func_kind == JS_FUNC_ASYNC) {
  37189             /* wrap the return value in an object so that promises can
  37190                be safely returned */
  37191             emit_op(s, OP_object);
  37192             emit_op(s, OP_dup);
  37193 
  37194             emit_op(s, OP_get_loc);
  37195             emit_u16(s, fd->eval_ret_idx);
  37196 
  37197             emit_op(s, OP_put_field);
  37198             emit_atom(s, JS_ATOM_value);
  37199         } else {
  37200             emit_op(s, OP_get_loc);
  37201             emit_u16(s, fd->eval_ret_idx);
  37202         }
  37203         emit_return(s, TRUE);
  37204     } else {
  37205         emit_return(s, FALSE);
  37206     }
  37207 
  37208     return 0;
  37209 }
  37210 
  37211 static void js_parse_init(JSContext *ctx, JSParseState *s,
  37212                           const char *input, size_t input_len,
  37213                           const char *filename)
  37214 {
  37215     memset(s, 0, sizeof(*s));
  37216     s->ctx = ctx;
  37217     s->filename = filename;
  37218     s->buf_start = s->buf_ptr = (const uint8_t *)input;
  37219     s->buf_end = s->buf_ptr + input_len;
  37220     s->token.val = ' ';
  37221     s->token.ptr = s->buf_ptr;
  37222 
  37223     s->get_line_col_cache.ptr = s->buf_start;
  37224     s->get_line_col_cache.buf_start = s->buf_start;
  37225     s->get_line_col_cache.line_num = 0;
  37226     s->get_line_col_cache.col_num = 0;
  37227 }
  37228 
  37229 static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj,
  37230                                        JSValueConst this_obj,
  37231                                        JSVarRef **var_refs, JSStackFrame *sf)
  37232 {
  37233     JSValue ret_val;
  37234     uint32_t tag;
  37235 
  37236     tag = JS_VALUE_GET_TAG(fun_obj);
  37237     if (tag == JS_TAG_FUNCTION_BYTECODE) {
  37238         fun_obj = js_closure(ctx, fun_obj, var_refs, sf, TRUE);
  37239         if (JS_IsException(fun_obj))
  37240             return JS_EXCEPTION;
  37241         ret_val = JS_CallFree(ctx, fun_obj, this_obj, 0, NULL);
  37242     } else if (tag == JS_TAG_MODULE) {
  37243         JSModuleDef *m;
  37244         m = JS_VALUE_GET_PTR(fun_obj);
  37245         /* the module refcount should be >= 2 */
  37246         JS_FreeValue(ctx, fun_obj);
  37247         if (js_create_module_function(ctx, m) < 0)
  37248             goto fail;
  37249         if (js_link_module(ctx, m) < 0)
  37250             goto fail;
  37251         ret_val = js_evaluate_module(ctx, m);
  37252         if (JS_IsException(ret_val)) {
  37253         fail:
  37254             return JS_EXCEPTION;
  37255         }
  37256     } else {
  37257         JS_FreeValue(ctx, fun_obj);
  37258         ret_val = JS_ThrowTypeError(ctx, "bytecode function expected");
  37259     }
  37260     return ret_val;
  37261 }
  37262 
  37263 JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj)
  37264 {
  37265     return JS_EvalFunctionInternal(ctx, fun_obj, ctx->global_obj, NULL, NULL);
  37266 }
  37267 
  37268 /* 'input' must be zero terminated i.e. input[input_len] = '\0'. */
  37269 static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
  37270                                  const char *input, size_t input_len,
  37271                                  const char *filename, int flags, int scope_idx)
  37272 {
  37273     JSParseState s1, *s = &s1;
  37274     int err, js_mode, eval_type;
  37275     JSValue fun_obj, ret_val;
  37276     JSStackFrame *sf;
  37277     JSVarRef **var_refs;
  37278     JSFunctionBytecode *b;
  37279     JSFunctionDef *fd;
  37280     JSModuleDef *m;
  37281 
  37282     js_parse_init(ctx, s, input, input_len, filename);
  37283     skip_shebang(&s->buf_ptr, s->buf_end);
  37284 
  37285     eval_type = flags & JS_EVAL_TYPE_MASK;
  37286     m = NULL;
  37287     if (eval_type == JS_EVAL_TYPE_DIRECT) {
  37288         JSObject *p;
  37289         sf = ctx->rt->current_stack_frame;
  37290         assert(sf != NULL);
  37291         assert(JS_VALUE_GET_TAG(sf->cur_func) == JS_TAG_OBJECT);
  37292         p = JS_VALUE_GET_OBJ(sf->cur_func);
  37293         assert(js_class_has_bytecode(p->class_id));
  37294         b = p->u.func.function_bytecode;
  37295         var_refs = p->u.func.var_refs;
  37296         js_mode = b->js_mode;
  37297     } else {
  37298         sf = NULL;
  37299         b = NULL;
  37300         var_refs = NULL;
  37301         js_mode = 0;
  37302         if (flags & JS_EVAL_FLAG_STRICT)
  37303             js_mode |= JS_MODE_STRICT;
  37304         if (eval_type == JS_EVAL_TYPE_MODULE) {
  37305             JSAtom module_name = JS_NewAtom(ctx, filename);
  37306             if (module_name == JS_ATOM_NULL)
  37307                 return JS_EXCEPTION;
  37308             m = js_new_module_def(ctx, module_name);
  37309             if (!m)
  37310                 return JS_EXCEPTION;
  37311             js_mode |= JS_MODE_STRICT;
  37312         }
  37313     }
  37314     fd = js_new_function_def(ctx, NULL, TRUE, FALSE, filename,
  37315                              s->buf_start, &s->get_line_col_cache);
  37316     if (!fd)
  37317         goto fail1;
  37318     s->cur_func = fd;
  37319     fd->eval_type = eval_type;
  37320     fd->has_this_binding = (eval_type != JS_EVAL_TYPE_DIRECT);
  37321     if (eval_type == JS_EVAL_TYPE_DIRECT) {
  37322         fd->new_target_allowed = b->new_target_allowed;
  37323         fd->super_call_allowed = b->super_call_allowed;
  37324         fd->super_allowed = b->super_allowed;
  37325         fd->arguments_allowed = b->arguments_allowed;
  37326     } else {
  37327         fd->new_target_allowed = FALSE;
  37328         fd->super_call_allowed = FALSE;
  37329         fd->super_allowed = FALSE;
  37330         fd->arguments_allowed = TRUE;
  37331     }
  37332     fd->js_mode = js_mode;
  37333     fd->func_name = JS_DupAtom(ctx, JS_ATOM__eval_);
  37334     if (b) {
  37335         if (add_closure_variables(ctx, fd, b, scope_idx)) {
  37336             goto fail;
  37337         }
  37338     }
  37339     fd->module = m;
  37340     if (m != NULL || (flags & JS_EVAL_FLAG_ASYNC)) {
  37341         fd->in_function_body = TRUE;
  37342         fd->func_kind = JS_FUNC_ASYNC;
  37343     }
  37344     s->is_module = (m != NULL);
  37345     s->allow_html_comments = !s->is_module;
  37346 
  37347     push_scope(s); /* body scope */
  37348     fd->body_scope = fd->scope_level;
  37349 
  37350     err = js_parse_program(s);
  37351     if (err) {
  37352     fail:
  37353         free_token(s, &s->token);
  37354         js_free_function_def(ctx, fd);
  37355         goto fail1;
  37356     }
  37357 
  37358     if (m != NULL)
  37359         m->has_tla = fd->has_await;
  37360 
  37361     /* create the function object and all the enclosed functions */
  37362     fun_obj = js_create_function(ctx, fd);
  37363     if (JS_IsException(fun_obj))
  37364         goto fail1;
  37365     /* Could add a flag to avoid resolution if necessary */
  37366     if (m) {
  37367         m->func_obj = fun_obj;
  37368         if (js_resolve_module(ctx, m) < 0)
  37369             goto fail1;
  37370         fun_obj = JS_NewModuleValue(ctx, m);
  37371     }
  37372     if (flags & JS_EVAL_FLAG_COMPILE_ONLY) {
  37373         ret_val = fun_obj;
  37374     } else {
  37375         ret_val = JS_EvalFunctionInternal(ctx, fun_obj, this_obj, var_refs, sf);
  37376     }
  37377     return ret_val;
  37378  fail1:
  37379     /* XXX: should free all the unresolved dependencies */
  37380     if (m)
  37381         JS_FreeValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
  37382     return JS_EXCEPTION;
  37383 }
  37384 
  37385 /* the indirection is needed to make 'eval' optional */
  37386 static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
  37387                                const char *input, size_t input_len,
  37388                                const char *filename, int flags, int scope_idx)
  37389 {
  37390     BOOL backtrace_barrier = ((flags & JS_EVAL_FLAG_BACKTRACE_BARRIER) != 0);
  37391     int saved_js_mode = 0;
  37392     JSValue ret;
  37393     
  37394     if (unlikely(!ctx->eval_internal)) {
  37395         return JS_ThrowTypeError(ctx, "eval is not supported");
  37396     }
  37397     if (backtrace_barrier && ctx->rt->current_stack_frame) {
  37398         saved_js_mode = ctx->rt->current_stack_frame->js_mode;
  37399         ctx->rt->current_stack_frame->js_mode |= JS_MODE_BACKTRACE_BARRIER;
  37400     }
  37401     ret = ctx->eval_internal(ctx, this_obj, input, input_len, filename,
  37402                              flags, scope_idx);
  37403     if (backtrace_barrier && ctx->rt->current_stack_frame)
  37404         ctx->rt->current_stack_frame->js_mode = saved_js_mode;
  37405     return ret;
  37406 }
  37407 
  37408 static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
  37409                              JSValueConst val, int flags, int scope_idx)
  37410 {
  37411     JSValue ret;
  37412     const char *str;
  37413     size_t len;
  37414 
  37415     if (!JS_IsString(val))
  37416         return JS_DupValue(ctx, val);
  37417     str = JS_ToCStringLen(ctx, &len, val);
  37418     if (!str)
  37419         return JS_EXCEPTION;
  37420     ret = JS_EvalInternal(ctx, this_obj, str, len, "<input>", flags, scope_idx);
  37421     JS_FreeCString(ctx, str);
  37422     return ret;
  37423 }
  37424 
  37425 JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj,
  37426                     const char *input, size_t input_len,
  37427                     const char *filename, int eval_flags)
  37428 {
  37429     int eval_type = eval_flags & JS_EVAL_TYPE_MASK;
  37430     JSValue ret;
  37431 
  37432     assert(eval_type == JS_EVAL_TYPE_GLOBAL ||
  37433            eval_type == JS_EVAL_TYPE_MODULE);
  37434     ret = JS_EvalInternal(ctx, this_obj, input, input_len, filename,
  37435                           eval_flags, -1);
  37436     return ret;
  37437 }
  37438 
  37439 JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
  37440                 const char *filename, int eval_flags)
  37441 {
  37442     return JS_EvalThis(ctx, ctx->global_obj, input, input_len, filename,
  37443                        eval_flags);
  37444 }
  37445 
  37446 int JS_ResolveModule(JSContext *ctx, JSValueConst obj)
  37447 {
  37448     if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
  37449         JSModuleDef *m = JS_VALUE_GET_PTR(obj);
  37450         if (js_resolve_module(ctx, m) < 0) {
  37451             js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);
  37452             return -1;
  37453         }
  37454     }
  37455     return 0;
  37456 }
  37457 
  37458 /*******************************************************************/
  37459 /* object list */
  37460 
  37461 typedef struct {
  37462     JSObject *obj;
  37463     uint32_t hash_next; /* -1 if no next entry */
  37464 } JSObjectListEntry;
  37465 
  37466 /* XXX: reuse it to optimize weak references */
  37467 typedef struct {
  37468     JSObjectListEntry *object_tab;
  37469     int object_count;
  37470     int object_size;
  37471     uint32_t *hash_table;
  37472     uint32_t hash_size;
  37473 } JSObjectList;
  37474 
  37475 static void js_object_list_init(JSObjectList *s)
  37476 {
  37477     memset(s, 0, sizeof(*s));
  37478 }
  37479 
  37480 static uint32_t js_object_list_get_hash(JSObject *p, uint32_t hash_size)
  37481 {
  37482     return ((uintptr_t)p * 3163) & (hash_size - 1);
  37483 }
  37484 
  37485 static int js_object_list_resize_hash(JSContext *ctx, JSObjectList *s,
  37486                                  uint32_t new_hash_size)
  37487 {
  37488     JSObjectListEntry *e;
  37489     uint32_t i, h, *new_hash_table;
  37490 
  37491     new_hash_table = js_malloc(ctx, sizeof(new_hash_table[0]) * new_hash_size);
  37492     if (!new_hash_table)
  37493         return -1;
  37494     js_free(ctx, s->hash_table);
  37495     s->hash_table = new_hash_table;
  37496     s->hash_size = new_hash_size;
  37497 
  37498     for(i = 0; i < s->hash_size; i++) {
  37499         s->hash_table[i] = -1;
  37500     }
  37501     for(i = 0; i < s->object_count; i++) {
  37502         e = &s->object_tab[i];
  37503         h = js_object_list_get_hash(e->obj, s->hash_size);
  37504         e->hash_next = s->hash_table[h];
  37505         s->hash_table[h] = i;
  37506     }
  37507     return 0;
  37508 }
  37509 
  37510 /* the reference count of 'obj' is not modified. Return 0 if OK, -1 if
  37511    memory error */
  37512 static int js_object_list_add(JSContext *ctx, JSObjectList *s, JSObject *obj)
  37513 {
  37514     JSObjectListEntry *e;
  37515     uint32_t h, new_hash_size;
  37516 
  37517     if (js_resize_array(ctx, (void *)&s->object_tab,
  37518                         sizeof(s->object_tab[0]),
  37519                         &s->object_size, s->object_count + 1))
  37520         return -1;
  37521     if (unlikely((s->object_count + 1) >= s->hash_size)) {
  37522         new_hash_size = max_uint32(s->hash_size, 4);
  37523         while (new_hash_size <= s->object_count)
  37524             new_hash_size *= 2;
  37525         if (js_object_list_resize_hash(ctx, s, new_hash_size))
  37526             return -1;
  37527     }
  37528     e = &s->object_tab[s->object_count++];
  37529     h = js_object_list_get_hash(obj, s->hash_size);
  37530     e->obj = obj;
  37531     e->hash_next = s->hash_table[h];
  37532     s->hash_table[h] = s->object_count - 1;
  37533     return 0;
  37534 }
  37535 
  37536 /* return -1 if not present or the object index */
  37537 static int js_object_list_find(JSContext *ctx, JSObjectList *s, JSObject *obj)
  37538 {
  37539     JSObjectListEntry *e;
  37540     uint32_t h, p;
  37541 
  37542     /* must test empty size because there is no hash table */
  37543     if (s->object_count == 0)
  37544         return -1;
  37545     h = js_object_list_get_hash(obj, s->hash_size);
  37546     p = s->hash_table[h];
  37547     while (p != -1) {
  37548         e = &s->object_tab[p];
  37549         if (e->obj == obj)
  37550             return p;
  37551         p = e->hash_next;
  37552     }
  37553     return -1;
  37554 }
  37555 
  37556 static void js_object_list_end(JSContext *ctx, JSObjectList *s)
  37557 {
  37558     js_free(ctx, s->object_tab);
  37559     js_free(ctx, s->hash_table);
  37560 }
  37561 
  37562 /*******************************************************************/
  37563 /* binary object writer & reader */
  37564 
  37565 typedef enum BCTagEnum {
  37566     BC_TAG_NULL = 1,
  37567     BC_TAG_UNDEFINED,
  37568     BC_TAG_BOOL_FALSE,
  37569     BC_TAG_BOOL_TRUE,
  37570     BC_TAG_INT32,
  37571     BC_TAG_FLOAT64,
  37572     BC_TAG_STRING,
  37573     BC_TAG_OBJECT,
  37574     BC_TAG_ARRAY,
  37575     BC_TAG_BIG_INT,
  37576     BC_TAG_TEMPLATE_OBJECT,
  37577     BC_TAG_FUNCTION_BYTECODE,
  37578     BC_TAG_MODULE,
  37579     BC_TAG_TYPED_ARRAY,
  37580     BC_TAG_ARRAY_BUFFER,
  37581     BC_TAG_SHARED_ARRAY_BUFFER,
  37582     BC_TAG_DATE,
  37583     BC_TAG_OBJECT_VALUE,
  37584     BC_TAG_OBJECT_REFERENCE,
  37585 } BCTagEnum;
  37586 
  37587 #define BC_VERSION 5
  37588 
  37589 typedef struct BCWriterState {
  37590     JSContext *ctx;
  37591     DynBuf dbuf;
  37592     BOOL allow_bytecode : 8;
  37593     BOOL allow_sab : 8;
  37594     BOOL allow_reference : 8;
  37595     uint32_t first_atom;
  37596     uint32_t *atom_to_idx;
  37597     int atom_to_idx_size;
  37598     JSAtom *idx_to_atom;
  37599     int idx_to_atom_count;
  37600     int idx_to_atom_size;
  37601     uint8_t **sab_tab;
  37602     int sab_tab_len;
  37603     int sab_tab_size;
  37604     /* list of referenced objects (used if allow_reference = TRUE) */
  37605     JSObjectList object_list;
  37606 } BCWriterState;
  37607 
  37608 #ifdef DUMP_READ_OBJECT
  37609 static const char * const bc_tag_str[] = {
  37610     "invalid",
  37611     "null",
  37612     "undefined",
  37613     "false",
  37614     "true",
  37615     "int32",
  37616     "float64",
  37617     "string",
  37618     "object",
  37619     "array",
  37620     "bigint",
  37621     "template",
  37622     "function",
  37623     "module",
  37624     "TypedArray",
  37625     "ArrayBuffer",
  37626     "SharedArrayBuffer",
  37627     "Date",
  37628     "ObjectValue",
  37629     "ObjectReference",
  37630 };
  37631 #endif
  37632 
  37633 static inline BOOL is_be(void)
  37634 {
  37635     union {
  37636         uint16_t a;
  37637         uint8_t  b;
  37638     } u = {0x100};
  37639     return u.b;
  37640 }
  37641 
  37642 static void bc_put_u8(BCWriterState *s, uint8_t v)
  37643 {
  37644     dbuf_putc(&s->dbuf, v);
  37645 }
  37646 
  37647 static void bc_put_u16(BCWriterState *s, uint16_t v)
  37648 {
  37649     if (is_be())
  37650         v = bswap16(v);
  37651     dbuf_put_u16(&s->dbuf, v);
  37652 }
  37653 
  37654 static __maybe_unused void bc_put_u32(BCWriterState *s, uint32_t v)
  37655 {
  37656     if (is_be())
  37657         v = bswap32(v);
  37658     dbuf_put_u32(&s->dbuf, v);
  37659 }
  37660 
  37661 static void bc_put_u64(BCWriterState *s, uint64_t v)
  37662 {
  37663     if (is_be())
  37664         v = bswap64(v);
  37665     dbuf_put(&s->dbuf, (uint8_t *)&v, sizeof(v));
  37666 }
  37667 
  37668 static void bc_put_leb128(BCWriterState *s, uint32_t v)
  37669 {
  37670     dbuf_put_leb128(&s->dbuf, v);
  37671 }
  37672 
  37673 static void bc_put_sleb128(BCWriterState *s, int32_t v)
  37674 {
  37675     dbuf_put_sleb128(&s->dbuf, v);
  37676 }
  37677 
  37678 static void bc_set_flags(uint32_t *pflags, int *pidx, uint32_t val, int n)
  37679 {
  37680     *pflags = *pflags | (val << *pidx);
  37681     *pidx += n;
  37682 }
  37683 
  37684 static int bc_atom_to_idx(BCWriterState *s, uint32_t *pres, JSAtom atom)
  37685 {
  37686     uint32_t v;
  37687 
  37688     if (atom < s->first_atom || __JS_AtomIsTaggedInt(atom)) {
  37689         *pres = atom;
  37690         return 0;
  37691     }
  37692     atom -= s->first_atom;
  37693     if (atom < s->atom_to_idx_size && s->atom_to_idx[atom] != 0) {
  37694         *pres = s->atom_to_idx[atom];
  37695         return 0;
  37696     }
  37697     if (atom >= s->atom_to_idx_size) {
  37698         int old_size, i;
  37699         old_size = s->atom_to_idx_size;
  37700         if (js_resize_array(s->ctx, (void **)&s->atom_to_idx,
  37701                             sizeof(s->atom_to_idx[0]), &s->atom_to_idx_size,
  37702                             atom + 1))
  37703             return -1;
  37704         /* XXX: could add a specific js_resize_array() function to do it */
  37705         for(i = old_size; i < s->atom_to_idx_size; i++)
  37706             s->atom_to_idx[i] = 0;
  37707     }
  37708     if (js_resize_array(s->ctx, (void **)&s->idx_to_atom,
  37709                         sizeof(s->idx_to_atom[0]),
  37710                         &s->idx_to_atom_size, s->idx_to_atom_count + 1))
  37711         goto fail;
  37712 
  37713     v = s->idx_to_atom_count++;
  37714     s->idx_to_atom[v] = atom + s->first_atom;
  37715     v += s->first_atom;
  37716     s->atom_to_idx[atom] = v;
  37717     *pres = v;
  37718     return 0;
  37719  fail:
  37720     *pres = 0;
  37721     return -1;
  37722 }
  37723 
  37724 static int bc_put_atom(BCWriterState *s, JSAtom atom)
  37725 {
  37726     uint32_t v;
  37727 
  37728     if (__JS_AtomIsTaggedInt(atom)) {
  37729         v = (__JS_AtomToUInt32(atom) << 1) | 1;
  37730     } else {
  37731         if (bc_atom_to_idx(s, &v, atom))
  37732             return -1;
  37733         v <<= 1;
  37734     }
  37735     bc_put_leb128(s, v);
  37736     return 0;
  37737 }
  37738 
  37739 static void bc_byte_swap(uint8_t *bc_buf, int bc_len)
  37740 {
  37741     int pos, len, op, fmt;
  37742 
  37743     pos = 0;
  37744     while (pos < bc_len) {
  37745         op = bc_buf[pos];
  37746         len = short_opcode_info(op).size;
  37747         fmt = short_opcode_info(op).fmt;
  37748         switch(fmt) {
  37749         case OP_FMT_u16:
  37750         case OP_FMT_i16:
  37751         case OP_FMT_label16:
  37752         case OP_FMT_npop:
  37753         case OP_FMT_loc:
  37754         case OP_FMT_arg:
  37755         case OP_FMT_var_ref:
  37756             put_u16(bc_buf + pos + 1,
  37757                     bswap16(get_u16(bc_buf + pos + 1)));
  37758             break;
  37759         case OP_FMT_i32:
  37760         case OP_FMT_u32:
  37761         case OP_FMT_const:
  37762         case OP_FMT_label:
  37763         case OP_FMT_atom:
  37764         case OP_FMT_atom_u8:
  37765             put_u32(bc_buf + pos + 1,
  37766                     bswap32(get_u32(bc_buf + pos + 1)));
  37767             break;
  37768         case OP_FMT_atom_u16:
  37769         case OP_FMT_label_u16:
  37770             put_u32(bc_buf + pos + 1,
  37771                     bswap32(get_u32(bc_buf + pos + 1)));
  37772             put_u16(bc_buf + pos + 1 + 4,
  37773                     bswap16(get_u16(bc_buf + pos + 1 + 4)));
  37774             break;
  37775         case OP_FMT_atom_label_u8:
  37776         case OP_FMT_atom_label_u16:
  37777             put_u32(bc_buf + pos + 1,
  37778                     bswap32(get_u32(bc_buf + pos + 1)));
  37779             put_u32(bc_buf + pos + 1 + 4,
  37780                     bswap32(get_u32(bc_buf + pos + 1 + 4)));
  37781             if (fmt == OP_FMT_atom_label_u16) {
  37782                 put_u16(bc_buf + pos + 1 + 4 + 4,
  37783                         bswap16(get_u16(bc_buf + pos + 1 + 4 + 4)));
  37784             }
  37785             break;
  37786         case OP_FMT_npop_u16:
  37787             put_u16(bc_buf + pos + 1,
  37788                     bswap16(get_u16(bc_buf + pos + 1)));
  37789             put_u16(bc_buf + pos + 1 + 2,
  37790                     bswap16(get_u16(bc_buf + pos + 1 + 2)));
  37791             break;
  37792         default:
  37793             break;
  37794         }
  37795         pos += len;
  37796     }
  37797 }
  37798 
  37799 static int JS_WriteFunctionBytecode(BCWriterState *s,
  37800                                     const uint8_t *bc_buf1, int bc_len)
  37801 {
  37802     int pos, len, op;
  37803     JSAtom atom;
  37804     uint8_t *bc_buf;
  37805     uint32_t val;
  37806 
  37807     bc_buf = js_malloc(s->ctx, bc_len);
  37808     if (!bc_buf)
  37809         return -1;
  37810     memcpy(bc_buf, bc_buf1, bc_len);
  37811 
  37812     pos = 0;
  37813     while (pos < bc_len) {
  37814         op = bc_buf[pos];
  37815         len = short_opcode_info(op).size;
  37816         switch(short_opcode_info(op).fmt) {
  37817         case OP_FMT_atom:
  37818         case OP_FMT_atom_u8:
  37819         case OP_FMT_atom_u16:
  37820         case OP_FMT_atom_label_u8:
  37821         case OP_FMT_atom_label_u16:
  37822             atom = get_u32(bc_buf + pos + 1);
  37823             if (bc_atom_to_idx(s, &val, atom))
  37824                 goto fail;
  37825             put_u32(bc_buf + pos + 1, val);
  37826             break;
  37827         default:
  37828             break;
  37829         }
  37830         pos += len;
  37831     }
  37832 
  37833     if (is_be())
  37834         bc_byte_swap(bc_buf, bc_len);
  37835 
  37836     dbuf_put(&s->dbuf, bc_buf, bc_len);
  37837 
  37838     js_free(s->ctx, bc_buf);
  37839     return 0;
  37840  fail:
  37841     js_free(s->ctx, bc_buf);
  37842     return -1;
  37843 }
  37844 
  37845 static void JS_WriteString(BCWriterState *s, JSString *p)
  37846 {
  37847     int i;
  37848     bc_put_leb128(s, ((uint32_t)p->len << 1) | p->is_wide_char);
  37849     if (p->is_wide_char) {
  37850         for(i = 0; i < p->len; i++)
  37851             bc_put_u16(s, p->u.str16[i]);
  37852     } else {
  37853         dbuf_put(&s->dbuf, p->u.str8, p->len);
  37854     }
  37855 }
  37856 
  37857 static int JS_WriteBigInt(BCWriterState *s, JSValueConst obj)
  37858 {
  37859     JSBigIntBuf buf;
  37860     JSBigInt *p;
  37861     uint32_t len, i;
  37862     js_limb_t v, b;
  37863     int shift;
  37864     
  37865     bc_put_u8(s, BC_TAG_BIG_INT);
  37866 
  37867     if (JS_VALUE_GET_TAG(obj) == JS_TAG_SHORT_BIG_INT)
  37868         p = js_bigint_set_short(&buf, obj);
  37869     else
  37870         p = JS_VALUE_GET_PTR(obj);
  37871     if (p->len == 1 && p->tab[0] == 0) {
  37872         /* zero case */
  37873         len = 0;
  37874     } else {
  37875         /* compute the length of the two's complement representation
  37876            in bytes */
  37877         len = p->len * (JS_LIMB_BITS / 8);
  37878         v = p->tab[p->len - 1];
  37879         shift = JS_LIMB_BITS - 8;
  37880         while (shift > 0) {
  37881             b = (v >> shift) & 0xff;
  37882             if (b != 0x00 && b != 0xff)
  37883                 break;
  37884             if ((b & 1) != ((v >> (shift - 1)) & 1))
  37885                 break;
  37886             shift -= 8;
  37887             len--;
  37888         }
  37889     }
  37890     bc_put_leb128(s, len);
  37891     if (len > 0) {
  37892         for(i = 0; i < (len / (JS_LIMB_BITS / 8)); i++) {
  37893 #if JS_LIMB_BITS == 32
  37894             bc_put_u32(s, p->tab[i]);
  37895 #else
  37896             bc_put_u64(s, p->tab[i]);
  37897 #endif
  37898         }
  37899         for(i = 0; i < len % (JS_LIMB_BITS / 8); i++) {
  37900             bc_put_u8(s, (p->tab[p->len - 1] >> (i * 8)) & 0xff);
  37901         }
  37902     }
  37903     return 0;
  37904 }
  37905 
  37906 static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj);
  37907 
  37908 static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj)
  37909 {
  37910     JSFunctionBytecode *b = JS_VALUE_GET_PTR(obj);
  37911     uint32_t flags;
  37912     int idx, i;
  37913 
  37914     bc_put_u8(s, BC_TAG_FUNCTION_BYTECODE);
  37915     flags = idx = 0;
  37916     bc_set_flags(&flags, &idx, b->has_prototype, 1);
  37917     bc_set_flags(&flags, &idx, b->has_simple_parameter_list, 1);
  37918     bc_set_flags(&flags, &idx, b->is_derived_class_constructor, 1);
  37919     bc_set_flags(&flags, &idx, b->need_home_object, 1);
  37920     bc_set_flags(&flags, &idx, b->func_kind, 2);
  37921     bc_set_flags(&flags, &idx, b->new_target_allowed, 1);
  37922     bc_set_flags(&flags, &idx, b->super_call_allowed, 1);
  37923     bc_set_flags(&flags, &idx, b->super_allowed, 1);
  37924     bc_set_flags(&flags, &idx, b->arguments_allowed, 1);
  37925     bc_set_flags(&flags, &idx, b->has_debug, 1);
  37926     bc_set_flags(&flags, &idx, b->is_direct_or_indirect_eval, 1);
  37927     assert(idx <= 16);
  37928     bc_put_u16(s, flags);
  37929     bc_put_u8(s, b->js_mode);
  37930     bc_put_atom(s, b->func_name);
  37931 
  37932     bc_put_leb128(s, b->arg_count);
  37933     bc_put_leb128(s, b->var_count);
  37934     bc_put_leb128(s, b->defined_arg_count);
  37935     bc_put_leb128(s, b->stack_size);
  37936     bc_put_leb128(s, b->var_ref_count);
  37937     bc_put_leb128(s, b->closure_var_count);
  37938     bc_put_leb128(s, b->cpool_count);
  37939     bc_put_leb128(s, b->byte_code_len);
  37940     if (b->vardefs) {
  37941         bc_put_leb128(s, b->arg_count + b->var_count);
  37942         for(i = 0; i < b->arg_count + b->var_count; i++) {
  37943             JSBytecodeVarDef *vd = &b->vardefs[i];
  37944             bc_put_atom(s, vd->var_name);
  37945             bc_put_leb128(s, vd->scope_next + 1);
  37946             bc_put_leb128(s, vd->var_ref_idx);
  37947             flags = idx = 0;
  37948             bc_set_flags(&flags, &idx, vd->var_kind, 4);
  37949             bc_set_flags(&flags, &idx, vd->is_const, 1);
  37950             bc_set_flags(&flags, &idx, vd->is_lexical, 1);
  37951             bc_set_flags(&flags, &idx, vd->is_captured, 1);
  37952             bc_set_flags(&flags, &idx, vd->has_scope, 1);
  37953             assert(idx <= 8);
  37954             bc_put_u8(s, flags);
  37955         }
  37956     } else {
  37957         bc_put_leb128(s, 0);
  37958     }
  37959 
  37960     for(i = 0; i < b->closure_var_count; i++) {
  37961         JSClosureVar *cv = &b->closure_var[i];
  37962         bc_put_atom(s, cv->var_name);
  37963         bc_put_leb128(s, cv->var_idx);
  37964         flags = idx = 0;
  37965         bc_set_flags(&flags, &idx, cv->closure_type, 3);
  37966         bc_set_flags(&flags, &idx, cv->is_const, 1);
  37967         bc_set_flags(&flags, &idx, cv->is_lexical, 1);
  37968         bc_set_flags(&flags, &idx, cv->var_kind, 4);
  37969         assert(idx <= 16);
  37970         bc_put_u16(s, flags);
  37971     }
  37972 
  37973     if (JS_WriteFunctionBytecode(s, b->byte_code_buf, b->byte_code_len))
  37974         goto fail;
  37975 
  37976     if (b->has_debug) {
  37977         bc_put_atom(s, b->debug.filename);
  37978         bc_put_leb128(s, b->debug.pc2line_len);
  37979         dbuf_put(&s->dbuf, b->debug.pc2line_buf, b->debug.pc2line_len);
  37980         if (b->debug.source) {
  37981             bc_put_leb128(s, b->debug.source_len);
  37982             dbuf_put(&s->dbuf, (uint8_t *)b->debug.source, b->debug.source_len);
  37983         } else {
  37984             bc_put_leb128(s, 0);
  37985         }
  37986     }
  37987 
  37988     for(i = 0; i < b->cpool_count; i++) {
  37989         if (JS_WriteObjectRec(s, b->cpool[i]))
  37990             goto fail;
  37991     }
  37992     return 0;
  37993  fail:
  37994     return -1;
  37995 }
  37996 
  37997 static int JS_WriteModule(BCWriterState *s, JSValueConst obj)
  37998 {
  37999     JSModuleDef *m = JS_VALUE_GET_PTR(obj);
  38000     int i;
  38001 
  38002     bc_put_u8(s, BC_TAG_MODULE);
  38003     bc_put_atom(s, m->module_name);
  38004 
  38005     bc_put_leb128(s, m->req_module_entries_count);
  38006     for(i = 0; i < m->req_module_entries_count; i++) {
  38007         JSReqModuleEntry *rme = &m->req_module_entries[i];
  38008         bc_put_atom(s, rme->module_name);
  38009         if (JS_WriteObjectRec(s, rme->attributes))
  38010             goto fail;
  38011     }
  38012 
  38013     bc_put_leb128(s, m->export_entries_count);
  38014     for(i = 0; i < m->export_entries_count; i++) {
  38015         JSExportEntry *me = &m->export_entries[i];
  38016         bc_put_u8(s, me->export_type);
  38017         if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
  38018             bc_put_leb128(s, me->u.local.var_idx);
  38019         } else {
  38020             bc_put_leb128(s, me->u.req_module_idx);
  38021             bc_put_atom(s, me->local_name);
  38022         }
  38023         bc_put_atom(s, me->export_name);
  38024     }
  38025 
  38026     bc_put_leb128(s, m->star_export_entries_count);
  38027     for(i = 0; i < m->star_export_entries_count; i++) {
  38028         JSStarExportEntry *se = &m->star_export_entries[i];
  38029         bc_put_leb128(s, se->req_module_idx);
  38030     }
  38031 
  38032     bc_put_leb128(s, m->import_entries_count);
  38033     for(i = 0; i < m->import_entries_count; i++) {
  38034         JSImportEntry *mi = &m->import_entries[i];
  38035         bc_put_leb128(s, mi->var_idx);
  38036         bc_put_u8(s, mi->is_star);
  38037         bc_put_atom(s, mi->import_name);
  38038         bc_put_leb128(s, mi->req_module_idx);
  38039     }
  38040 
  38041     bc_put_u8(s, m->has_tla);
  38042 
  38043     if (JS_WriteObjectRec(s, m->func_obj))
  38044         goto fail;
  38045     return 0;
  38046  fail:
  38047     return -1;
  38048 }
  38049 
  38050 /* XXX: be compatible with the structured clone algorithm */
  38051 static int JS_WriteArray(BCWriterState *s, JSValueConst obj)
  38052 {
  38053     JSContext *ctx = s->ctx;
  38054     JSObject *p = JS_VALUE_GET_OBJ(obj);
  38055     uint32_t i, len;
  38056     int ret;
  38057     BOOL is_template;
  38058     JSShapeProperty *prs;
  38059     JSProperty *pr;
  38060     
  38061     if (s->allow_bytecode && !p->extensible) {
  38062         /* not extensible array: we consider it is a
  38063            template when we are saving bytecode */
  38064         bc_put_u8(s, BC_TAG_TEMPLATE_OBJECT);
  38065         is_template = TRUE;
  38066     } else {
  38067         bc_put_u8(s, BC_TAG_ARRAY);
  38068         is_template = FALSE;
  38069     }
  38070     if (js_get_length32(ctx, &len, obj)) /* no side effect */
  38071         goto fail;
  38072     bc_put_leb128(s, len);
  38073     if (p->fast_array) {
  38074         for(i = 0; i < p->u.array.count; i++) {
  38075             ret = JS_WriteObjectRec(s, p->u.array.u.values[i]);
  38076             if (ret)
  38077                 goto fail;
  38078         }
  38079         for(i = p->u.array.count; i < len; i++) {
  38080             ret = JS_WriteObjectRec(s, JS_UNDEFINED);
  38081             if (ret)
  38082                 goto fail;
  38083         }
  38084     } else {
  38085         for(i = 0; i < len; i++) {
  38086             JSAtom atom;
  38087             atom = JS_NewAtomUInt32(ctx, i);
  38088             if (atom == JS_ATOM_NULL)
  38089                 goto fail;
  38090             prs = find_own_property(&pr, p, atom);
  38091             JS_FreeAtom(ctx, atom);
  38092             if (prs && (prs->flags & JS_PROP_ENUMERABLE)) {
  38093                 if (prs->flags & JS_PROP_TMASK) {
  38094                     JS_ThrowTypeError(ctx, "only value properties are supported");
  38095                     goto fail;
  38096                 }
  38097                 ret = JS_WriteObjectRec(s, pr->u.value);
  38098                 if (ret)
  38099                     goto fail;
  38100             } else {
  38101                 ret = JS_WriteObjectRec(s, JS_UNDEFINED);
  38102                 if (ret)
  38103                     goto fail;
  38104             }
  38105         }
  38106     }
  38107     if (is_template) {
  38108         /* the 'raw' property is not enumerable */
  38109         prs = find_own_property(&pr, p, JS_ATOM_raw);
  38110         if (prs) {
  38111             if (prs->flags & JS_PROP_TMASK) {
  38112                 JS_ThrowTypeError(ctx, "only value properties are supported");
  38113                 goto fail;
  38114             }
  38115             ret = JS_WriteObjectRec(s, pr->u.value);
  38116             if (ret)
  38117                 goto fail;
  38118         } else {
  38119             ret = JS_WriteObjectRec(s, JS_UNDEFINED);
  38120             if (ret)
  38121                 goto fail;
  38122         }
  38123     }
  38124     return 0;
  38125  fail:
  38126     return -1;
  38127 }
  38128 
  38129 static int JS_WriteObjectTag(BCWriterState *s, JSValueConst obj)
  38130 {
  38131     JSObject *p = JS_VALUE_GET_OBJ(obj);
  38132     uint32_t i, prop_count;
  38133     JSShape *sh;
  38134     JSShapeProperty *pr;
  38135     int pass;
  38136     JSAtom atom;
  38137 
  38138     bc_put_u8(s, BC_TAG_OBJECT);
  38139     prop_count = 0;
  38140     sh = p->shape;
  38141     for(pass = 0; pass < 2; pass++) {
  38142         if (pass == 1)
  38143             bc_put_leb128(s, prop_count);
  38144         for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {
  38145             atom = pr->atom;
  38146             if (atom != JS_ATOM_NULL &&
  38147                 JS_AtomIsString(s->ctx, atom) &&
  38148                 (pr->flags & JS_PROP_ENUMERABLE)) {
  38149                 if (pr->flags & JS_PROP_TMASK) {
  38150                     JS_ThrowTypeError(s->ctx, "only value properties are supported");
  38151                     goto fail;
  38152                 }
  38153                 if (pass == 0) {
  38154                     prop_count++;
  38155                 } else {
  38156                     bc_put_atom(s, atom);
  38157                     if (JS_WriteObjectRec(s, p->prop[i].u.value))
  38158                         goto fail;
  38159                 }
  38160             }
  38161         }
  38162     }
  38163     return 0;
  38164  fail:
  38165     return -1;
  38166 }
  38167 
  38168 static int JS_WriteTypedArray(BCWriterState *s, JSValueConst obj)
  38169 {
  38170     JSObject *p = JS_VALUE_GET_OBJ(obj);
  38171     JSTypedArray *ta = p->u.typed_array;
  38172 
  38173     bc_put_u8(s, BC_TAG_TYPED_ARRAY);
  38174     bc_put_u8(s, p->class_id - JS_CLASS_UINT8C_ARRAY);
  38175     bc_put_leb128(s, p->u.array.count);
  38176     bc_put_leb128(s, ta->offset);
  38177     if (JS_WriteObjectRec(s, JS_MKPTR(JS_TAG_OBJECT, ta->buffer)))
  38178         return -1;
  38179     return 0;
  38180 }
  38181 
  38182 static int JS_WriteArrayBuffer(BCWriterState *s, JSValueConst obj)
  38183 {
  38184     JSObject *p = JS_VALUE_GET_OBJ(obj);
  38185     JSArrayBuffer *abuf = p->u.array_buffer;
  38186     if (abuf->detached) {
  38187         JS_ThrowTypeErrorDetachedArrayBuffer(s->ctx);
  38188         return -1;
  38189     }
  38190     bc_put_u8(s, BC_TAG_ARRAY_BUFFER);
  38191     bc_put_leb128(s, abuf->byte_length);
  38192     bc_put_leb128(s, abuf->max_byte_length);
  38193     dbuf_put(&s->dbuf, abuf->data, abuf->byte_length);
  38194     return 0;
  38195 }
  38196 
  38197 static int JS_WriteSharedArrayBuffer(BCWriterState *s, JSValueConst obj)
  38198 {
  38199     JSObject *p = JS_VALUE_GET_OBJ(obj);
  38200     JSArrayBuffer *abuf = p->u.array_buffer;
  38201     assert(!abuf->detached); /* SharedArrayBuffer are never detached */
  38202     bc_put_u8(s, BC_TAG_SHARED_ARRAY_BUFFER);
  38203     bc_put_leb128(s, abuf->byte_length);
  38204     bc_put_leb128(s, abuf->max_byte_length);
  38205     bc_put_u64(s, (uintptr_t)abuf->data);
  38206     if (js_resize_array(s->ctx, (void **)&s->sab_tab, sizeof(s->sab_tab[0]),
  38207                         &s->sab_tab_size, s->sab_tab_len + 1))
  38208         return -1;
  38209     /* keep the SAB pointer so that the user can clone it or free it */
  38210     s->sab_tab[s->sab_tab_len++] = abuf->data;
  38211     return 0;
  38212 }
  38213 
  38214 static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj)
  38215 {
  38216     uint32_t tag;
  38217 
  38218     if (js_check_stack_overflow(s->ctx->rt, 0)) {
  38219         JS_ThrowStackOverflow(s->ctx);
  38220         return -1;
  38221     }
  38222 
  38223     tag = JS_VALUE_GET_NORM_TAG(obj);
  38224     switch(tag) {
  38225     case JS_TAG_NULL:
  38226         bc_put_u8(s, BC_TAG_NULL);
  38227         break;
  38228     case JS_TAG_UNDEFINED:
  38229         bc_put_u8(s, BC_TAG_UNDEFINED);
  38230         break;
  38231     case JS_TAG_BOOL:
  38232         bc_put_u8(s, BC_TAG_BOOL_FALSE + JS_VALUE_GET_INT(obj));
  38233         break;
  38234     case JS_TAG_INT:
  38235         bc_put_u8(s, BC_TAG_INT32);
  38236         bc_put_sleb128(s, JS_VALUE_GET_INT(obj));
  38237         break;
  38238     case JS_TAG_FLOAT64:
  38239         {
  38240             JSFloat64Union u;
  38241             bc_put_u8(s, BC_TAG_FLOAT64);
  38242             u.d = JS_VALUE_GET_FLOAT64(obj);
  38243             bc_put_u64(s, u.u64);
  38244         }
  38245         break;
  38246     case JS_TAG_STRING:
  38247         {
  38248             JSString *p = JS_VALUE_GET_STRING(obj);
  38249             bc_put_u8(s, BC_TAG_STRING);
  38250             JS_WriteString(s, p);
  38251         }
  38252         break;
  38253     case JS_TAG_STRING_ROPE:
  38254         {
  38255             JSValue str;
  38256             int ret;
  38257             str = JS_ToString(s->ctx, obj);
  38258             if (JS_IsException(str))
  38259                 goto fail;
  38260             ret = JS_WriteObjectRec(s, str);
  38261             JS_FreeValue(s->ctx, str);
  38262             if (ret)
  38263                 goto fail;
  38264         }
  38265         break;
  38266     case JS_TAG_FUNCTION_BYTECODE:
  38267         if (!s->allow_bytecode)
  38268             goto invalid_tag;
  38269         if (JS_WriteFunctionTag(s, obj))
  38270             goto fail;
  38271         break;
  38272     case JS_TAG_MODULE:
  38273         if (!s->allow_bytecode)
  38274             goto invalid_tag;
  38275         if (JS_WriteModule(s, obj))
  38276             goto fail;
  38277         break;
  38278     case JS_TAG_OBJECT:
  38279         {
  38280             JSObject *p = JS_VALUE_GET_OBJ(obj);
  38281             int ret, idx;
  38282 
  38283             if (s->allow_reference) {
  38284                 idx = js_object_list_find(s->ctx, &s->object_list, p);
  38285                 if (idx >= 0) {
  38286                     bc_put_u8(s, BC_TAG_OBJECT_REFERENCE);
  38287                     bc_put_leb128(s, idx);
  38288                     break;
  38289                 } else {
  38290                     if (js_object_list_add(s->ctx, &s->object_list, p))
  38291                         goto fail;
  38292                 }
  38293             } else {
  38294                 if (p->tmp_mark) {
  38295                     JS_ThrowTypeError(s->ctx, "circular reference");
  38296                     goto fail;
  38297                 }
  38298                 p->tmp_mark = 1;
  38299             }
  38300             switch(p->class_id) {
  38301             case JS_CLASS_ARRAY:
  38302                 ret = JS_WriteArray(s, obj);
  38303                 break;
  38304             case JS_CLASS_OBJECT:
  38305                 ret = JS_WriteObjectTag(s, obj);
  38306                 break;
  38307             case JS_CLASS_ARRAY_BUFFER:
  38308                 ret = JS_WriteArrayBuffer(s, obj);
  38309                 break;
  38310             case JS_CLASS_SHARED_ARRAY_BUFFER:
  38311                 if (!s->allow_sab)
  38312                     goto invalid_tag;
  38313                 ret = JS_WriteSharedArrayBuffer(s, obj);
  38314                 break;
  38315             case JS_CLASS_DATE:
  38316                 bc_put_u8(s, BC_TAG_DATE);
  38317                 ret = JS_WriteObjectRec(s, p->u.object_data);
  38318                 break;
  38319             case JS_CLASS_NUMBER:
  38320             case JS_CLASS_STRING:
  38321             case JS_CLASS_BOOLEAN:
  38322             case JS_CLASS_BIG_INT:
  38323                 bc_put_u8(s, BC_TAG_OBJECT_VALUE);
  38324                 ret = JS_WriteObjectRec(s, p->u.object_data);
  38325                 break;
  38326             default:
  38327                 if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
  38328                     p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
  38329                     ret = JS_WriteTypedArray(s, obj);
  38330                 } else {
  38331                     JS_ThrowTypeError(s->ctx, "unsupported object class");
  38332                     ret = -1;
  38333                 }
  38334                 break;
  38335             }
  38336             p->tmp_mark = 0;
  38337             if (ret)
  38338                 goto fail;
  38339         }
  38340         break;
  38341     case JS_TAG_SHORT_BIG_INT:
  38342     case JS_TAG_BIG_INT:
  38343         if (JS_WriteBigInt(s, obj))
  38344             goto fail;
  38345         break;
  38346     default:
  38347     invalid_tag:
  38348         JS_ThrowInternalError(s->ctx, "unsupported tag (%d)", tag);
  38349         goto fail;
  38350     }
  38351     return 0;
  38352 
  38353  fail:
  38354     return -1;
  38355 }
  38356 
  38357 /* create the atom table */
  38358 static int JS_WriteObjectAtoms(BCWriterState *s)
  38359 {
  38360     JSRuntime *rt = s->ctx->rt;
  38361     DynBuf dbuf1;
  38362     int i, atoms_size;
  38363 
  38364     dbuf1 = s->dbuf;
  38365     js_dbuf_init(s->ctx, &s->dbuf);
  38366     bc_put_u8(s, BC_VERSION);
  38367 
  38368     bc_put_leb128(s, s->idx_to_atom_count);
  38369     for(i = 0; i < s->idx_to_atom_count; i++) {
  38370         JSAtomStruct *p = rt->atom_array[s->idx_to_atom[i]];
  38371         JS_WriteString(s, p);
  38372     }
  38373     /* XXX: should check for OOM in above phase */
  38374 
  38375     /* move the atoms at the start */
  38376     /* XXX: could just append dbuf1 data, but it uses more memory if
  38377        dbuf1 is larger than dbuf */
  38378     atoms_size = s->dbuf.size;
  38379     if (dbuf_claim(&dbuf1, atoms_size))
  38380         goto fail;
  38381     memmove(dbuf1.buf + atoms_size, dbuf1.buf, dbuf1.size);
  38382     memcpy(dbuf1.buf, s->dbuf.buf, atoms_size);
  38383     dbuf1.size += atoms_size;
  38384     dbuf_free(&s->dbuf);
  38385     s->dbuf = dbuf1;
  38386     return 0;
  38387  fail:
  38388     dbuf_free(&dbuf1);
  38389     return -1;
  38390 }
  38391 
  38392 uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj,
  38393                          int flags, uint8_t ***psab_tab, size_t *psab_tab_len)
  38394 {
  38395     BCWriterState ss, *s = &ss;
  38396 
  38397     memset(s, 0, sizeof(*s));
  38398     s->ctx = ctx;
  38399     s->allow_bytecode = ((flags & JS_WRITE_OBJ_BYTECODE) != 0);
  38400     s->allow_sab = ((flags & JS_WRITE_OBJ_SAB) != 0);
  38401     s->allow_reference = ((flags & JS_WRITE_OBJ_REFERENCE) != 0);
  38402     /* XXX: could use a different version when bytecode is included */
  38403     if (s->allow_bytecode)
  38404         s->first_atom = JS_ATOM_END;
  38405     else
  38406         s->first_atom = 1;
  38407     js_dbuf_init(ctx, &s->dbuf);
  38408     js_object_list_init(&s->object_list);
  38409 
  38410     if (JS_WriteObjectRec(s, obj))
  38411         goto fail;
  38412     if (JS_WriteObjectAtoms(s))
  38413         goto fail;
  38414     js_object_list_end(ctx, &s->object_list);
  38415     js_free(ctx, s->atom_to_idx);
  38416     js_free(ctx, s->idx_to_atom);
  38417     *psize = s->dbuf.size;
  38418     if (psab_tab)
  38419         *psab_tab = s->sab_tab;
  38420     if (psab_tab_len)
  38421         *psab_tab_len = s->sab_tab_len;
  38422     return s->dbuf.buf;
  38423  fail:
  38424     js_object_list_end(ctx, &s->object_list);
  38425     js_free(ctx, s->atom_to_idx);
  38426     js_free(ctx, s->idx_to_atom);
  38427     dbuf_free(&s->dbuf);
  38428     *psize = 0;
  38429     if (psab_tab)
  38430         *psab_tab = NULL;
  38431     if (psab_tab_len)
  38432         *psab_tab_len = 0;
  38433     return NULL;
  38434 }
  38435 
  38436 uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj,
  38437                         int flags)
  38438 {
  38439     return JS_WriteObject2(ctx, psize, obj, flags, NULL, NULL);
  38440 }
  38441 
  38442 typedef struct BCReaderState {
  38443     JSContext *ctx;
  38444     const uint8_t *buf_start, *ptr, *buf_end;
  38445     uint32_t first_atom;
  38446     uint32_t idx_to_atom_count;
  38447     JSAtom *idx_to_atom;
  38448     int error_state;
  38449     BOOL allow_sab : 8;
  38450     BOOL allow_bytecode : 8;
  38451     BOOL is_rom_data : 8;
  38452     BOOL allow_reference : 8;
  38453     /* object references */
  38454     JSObject **objects;
  38455     int objects_count;
  38456     int objects_size;
  38457 
  38458 #ifdef DUMP_READ_OBJECT
  38459     const uint8_t *ptr_last;
  38460     int level;
  38461 #endif
  38462 } BCReaderState;
  38463 
  38464 #ifdef DUMP_READ_OBJECT
  38465 static void __attribute__((format(printf, 2, 3))) bc_read_trace(BCReaderState *s, const char *fmt, ...) {
  38466     va_list ap;
  38467     int i, n, n0;
  38468 
  38469     if (!s->ptr_last)
  38470         s->ptr_last = s->buf_start;
  38471 
  38472     n = n0 = 0;
  38473     if (s->ptr > s->ptr_last || s->ptr == s->buf_start) {
  38474         n0 = printf("%04x: ", (int)(s->ptr_last - s->buf_start));
  38475         n += n0;
  38476     }
  38477     for (i = 0; s->ptr_last < s->ptr; i++) {
  38478         if ((i & 7) == 0 && i > 0) {
  38479             printf("\n%*s", n0, "");
  38480             n = n0;
  38481         }
  38482         n += printf(" %02x", *s->ptr_last++);
  38483     }
  38484     if (*fmt == '}')
  38485         s->level--;
  38486     if (n < 32 + s->level * 2) {
  38487         printf("%*s", 32 + s->level * 2 - n, "");
  38488     }
  38489     va_start(ap, fmt);
  38490     vfprintf(stdout, fmt, ap);
  38491     va_end(ap);
  38492     if (strchr(fmt, '{'))
  38493         s->level++;
  38494 }
  38495 #else
  38496 #define bc_read_trace(...)
  38497 #endif
  38498 
  38499 static int bc_read_error_end(BCReaderState *s)
  38500 {
  38501     if (!s->error_state) {
  38502         JS_ThrowSyntaxError(s->ctx, "read after the end of the buffer");
  38503     }
  38504     return s->error_state = -1;
  38505 }
  38506 
  38507 static int bc_get_u8(BCReaderState *s, uint8_t *pval)
  38508 {
  38509     if (unlikely(s->buf_end - s->ptr < 1)) {
  38510         *pval = 0; /* avoid warning */
  38511         return bc_read_error_end(s);
  38512     }
  38513     *pval = *s->ptr++;
  38514     return 0;
  38515 }
  38516 
  38517 static int bc_get_u16(BCReaderState *s, uint16_t *pval)
  38518 {
  38519     uint16_t v;
  38520     if (unlikely(s->buf_end - s->ptr < 2)) {
  38521         *pval = 0; /* avoid warning */
  38522         return bc_read_error_end(s);
  38523     }
  38524     v = get_u16(s->ptr);
  38525     if (is_be())
  38526         v = bswap16(v);
  38527     *pval = v;
  38528     s->ptr += 2;
  38529     return 0;
  38530 }
  38531 
  38532 static __maybe_unused int bc_get_u32(BCReaderState *s, uint32_t *pval)
  38533 {
  38534     uint32_t v;
  38535     if (unlikely(s->buf_end - s->ptr < 4)) {
  38536         *pval = 0; /* avoid warning */
  38537         return bc_read_error_end(s);
  38538     }
  38539     v = get_u32(s->ptr);
  38540     if (is_be())
  38541         v = bswap32(v);
  38542     *pval = v;
  38543     s->ptr += 4;
  38544     return 0;
  38545 }
  38546 
  38547 static int bc_get_u64(BCReaderState *s, uint64_t *pval)
  38548 {
  38549     uint64_t v;
  38550     if (unlikely(s->buf_end - s->ptr < 8)) {
  38551         *pval = 0; /* avoid warning */
  38552         return bc_read_error_end(s);
  38553     }
  38554     v = get_u64(s->ptr);
  38555     if (is_be())
  38556         v = bswap64(v);
  38557     *pval = v;
  38558     s->ptr += 8;
  38559     return 0;
  38560 }
  38561 
  38562 static int bc_get_leb128(BCReaderState *s, uint32_t *pval)
  38563 {
  38564     int ret;
  38565     ret = get_leb128(pval, s->ptr, s->buf_end);
  38566     if (unlikely(ret < 0))
  38567         return bc_read_error_end(s);
  38568     s->ptr += ret;
  38569     return 0;
  38570 }
  38571 
  38572 static int bc_get_sleb128(BCReaderState *s, int32_t *pval)
  38573 {
  38574     int ret;
  38575     ret = get_sleb128(pval, s->ptr, s->buf_end);
  38576     if (unlikely(ret < 0))
  38577         return bc_read_error_end(s);
  38578     s->ptr += ret;
  38579     return 0;
  38580 }
  38581 
  38582 /* XXX: used to read an `int` with a positive value */
  38583 static int bc_get_leb128_int(BCReaderState *s, int *pval)
  38584 {
  38585     return bc_get_leb128(s, (uint32_t *)pval);
  38586 }
  38587 
  38588 static int bc_get_leb128_u16(BCReaderState *s, uint16_t *pval)
  38589 {
  38590     uint32_t val;
  38591     if (bc_get_leb128(s, &val)) {
  38592         *pval = 0;
  38593         return -1;
  38594     }
  38595     *pval = val;
  38596     return 0;
  38597 }
  38598 
  38599 static int bc_get_buf(BCReaderState *s, uint8_t *buf, uint32_t buf_len)
  38600 {
  38601     if (buf_len != 0) {
  38602         if (unlikely(!buf || s->buf_end - s->ptr < buf_len))
  38603             return bc_read_error_end(s);
  38604         memcpy(buf, s->ptr, buf_len);
  38605         s->ptr += buf_len;
  38606     }
  38607     return 0;
  38608 }
  38609 
  38610 static int bc_idx_to_atom(BCReaderState *s, JSAtom *patom, uint32_t idx)
  38611 {
  38612     JSAtom atom;
  38613 
  38614     if (__JS_AtomIsTaggedInt(idx)) {
  38615         atom = idx;
  38616     } else if (idx < s->first_atom) {
  38617         atom = JS_DupAtom(s->ctx, idx);
  38618     } else {
  38619         idx -= s->first_atom;
  38620         if (idx >= s->idx_to_atom_count) {
  38621             JS_ThrowSyntaxError(s->ctx, "invalid atom index (pos=%u)",
  38622                                 (unsigned int)(s->ptr - s->buf_start));
  38623             *patom = JS_ATOM_NULL;
  38624             return s->error_state = -1;
  38625         }
  38626         atom = JS_DupAtom(s->ctx, s->idx_to_atom[idx]);
  38627     }
  38628     *patom = atom;
  38629     return 0;
  38630 }
  38631 
  38632 static int bc_get_atom(BCReaderState *s, JSAtom *patom)
  38633 {
  38634     uint32_t v;
  38635     if (bc_get_leb128(s, &v))
  38636         return -1;
  38637     if (v & 1) {
  38638         *patom = __JS_AtomFromUInt32(v >> 1);
  38639         return 0;
  38640     } else {
  38641         return bc_idx_to_atom(s, patom, v >> 1);
  38642     }
  38643 }
  38644 
  38645 static JSString *JS_ReadString(BCReaderState *s)
  38646 {
  38647     uint32_t len;
  38648     size_t size;
  38649     BOOL is_wide_char;
  38650     JSString *p;
  38651 
  38652     if (bc_get_leb128(s, &len))
  38653         return NULL;
  38654     is_wide_char = len & 1;
  38655     len >>= 1;
  38656     if (len > JS_STRING_LEN_MAX) {
  38657         JS_ThrowInternalError(s->ctx, "string too long");
  38658         return NULL;
  38659     }
  38660     p = js_alloc_string(s->ctx, len, is_wide_char);
  38661     if (!p) {
  38662         s->error_state = -1;
  38663         return NULL;
  38664     }
  38665     size = (size_t)len << is_wide_char;
  38666     if ((s->buf_end - s->ptr) < size) {
  38667         bc_read_error_end(s);
  38668         js_free_string(s->ctx->rt, p);
  38669         return NULL;
  38670     }
  38671     memcpy(p->u.str8, s->ptr, size);
  38672     s->ptr += size;
  38673     if (is_wide_char) {
  38674         if (is_be()) {
  38675             uint32_t i;
  38676             for (i = 0; i < len; i++)
  38677                 p->u.str16[i] = bswap16(p->u.str16[i]);
  38678         }
  38679     } else {
  38680         p->u.str8[size] = '\0'; /* add the trailing zero for 8 bit strings */
  38681     }
  38682 #ifdef DUMP_READ_OBJECT
  38683     JS_DumpString(s->ctx->rt, p); printf("\n");
  38684 #endif
  38685     return p;
  38686 }
  38687 
  38688 static uint32_t bc_get_flags(uint32_t flags, int *pidx, int n)
  38689 {
  38690     uint32_t val;
  38691     /* XXX: this does not work for n == 32 */
  38692     val = (flags >> *pidx) & ((1U << n) - 1);
  38693     *pidx += n;
  38694     return val;
  38695 }
  38696 
  38697 static int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b,
  38698                                    int byte_code_offset, uint32_t bc_len)
  38699 {
  38700     uint8_t *bc_buf;
  38701     int pos, len, op;
  38702     JSAtom atom;
  38703     uint32_t idx;
  38704 
  38705     if (s->is_rom_data) {
  38706         /* directly use the input buffer */
  38707         if (unlikely(s->buf_end - s->ptr < bc_len))
  38708             return bc_read_error_end(s);
  38709         bc_buf = (uint8_t *)s->ptr;
  38710         s->ptr += bc_len;
  38711     } else {
  38712         bc_buf = (void *)((uint8_t*)b + byte_code_offset);
  38713         if (bc_get_buf(s, bc_buf, bc_len))
  38714             return -1;
  38715     }
  38716     b->byte_code_buf = bc_buf;
  38717 
  38718     if (is_be())
  38719         bc_byte_swap(bc_buf, bc_len);
  38720 
  38721     pos = 0;
  38722     while (pos < bc_len) {
  38723         op = bc_buf[pos];
  38724         len = short_opcode_info(op).size;
  38725         switch(short_opcode_info(op).fmt) {
  38726         case OP_FMT_atom:
  38727         case OP_FMT_atom_u8:
  38728         case OP_FMT_atom_u16:
  38729         case OP_FMT_atom_label_u8:
  38730         case OP_FMT_atom_label_u16:
  38731             idx = get_u32(bc_buf + pos + 1);
  38732             if (s->is_rom_data) {
  38733                 /* just increment the reference count of the atom */
  38734                 JS_DupAtom(s->ctx, (JSAtom)idx);
  38735             } else {
  38736                 if (bc_idx_to_atom(s, &atom, idx)) {
  38737                     /* Note: the atoms will be freed up to this position */
  38738                     b->byte_code_len = pos;
  38739                     return -1;
  38740                 }
  38741                 put_u32(bc_buf + pos + 1, atom);
  38742 #ifdef DUMP_READ_OBJECT
  38743                 bc_read_trace(s, "at %d, fixup atom: ", pos + 1); print_atom(s->ctx, atom); printf("\n");
  38744 #endif
  38745             }
  38746             break;
  38747         default:
  38748             break;
  38749         }
  38750         pos += len;
  38751     }
  38752     return 0;
  38753 }
  38754 
  38755 static JSValue JS_ReadBigInt(BCReaderState *s)
  38756 {
  38757     JSValue obj = JS_UNDEFINED;
  38758     uint32_t len, i, n;
  38759     JSBigInt *p;
  38760     js_limb_t v;
  38761     uint8_t v8;
  38762     
  38763     if (bc_get_leb128(s, &len))
  38764         goto fail;
  38765     bc_read_trace(s, "len=%" PRId64 "\n", (int64_t)len);
  38766     if (len == 0) {
  38767         /* zero case */
  38768         bc_read_trace(s, "}\n");
  38769         return __JS_NewShortBigInt(s->ctx, 0);
  38770     }
  38771     p = js_bigint_new(s->ctx, (len - 1) / (JS_LIMB_BITS / 8) + 1);
  38772     if (!p)
  38773         goto fail;
  38774     for(i = 0; i < len / (JS_LIMB_BITS / 8); i++) {
  38775 #if JS_LIMB_BITS == 32
  38776         if (bc_get_u32(s, &v))
  38777             goto fail;
  38778 #else
  38779         if (bc_get_u64(s, &v))
  38780             goto fail;
  38781 #endif
  38782         p->tab[i] = v;
  38783     }
  38784     n = len % (JS_LIMB_BITS / 8);
  38785     if (n != 0) {
  38786         int shift;
  38787         v = 0;
  38788         for(i = 0; i < n; i++) {
  38789             if (bc_get_u8(s, &v8))
  38790                 goto fail;
  38791             v |= (js_limb_t)v8 << (i * 8);
  38792         }
  38793         shift = JS_LIMB_BITS - n * 8;
  38794         /* extend the sign */
  38795         if (shift != 0) {
  38796             v = (js_slimb_t)(v << shift) >> shift;
  38797         }
  38798         p->tab[p->len - 1] = v;
  38799     }
  38800     bc_read_trace(s, "}\n");
  38801     return JS_CompactBigInt(s->ctx, p);
  38802  fail:
  38803     JS_FreeValue(s->ctx, obj);
  38804     return JS_EXCEPTION;
  38805 }
  38806 
  38807 static JSValue JS_ReadObjectRec(BCReaderState *s);
  38808 
  38809 static int BC_add_object_ref1(BCReaderState *s, JSObject *p)
  38810 {
  38811     if (s->allow_reference) {
  38812         if (js_resize_array(s->ctx, (void *)&s->objects,
  38813                             sizeof(s->objects[0]),
  38814                             &s->objects_size, s->objects_count + 1))
  38815             return -1;
  38816         s->objects[s->objects_count++] = p;
  38817     }
  38818     return 0;
  38819 }
  38820 
  38821 static int BC_add_object_ref(BCReaderState *s, JSValueConst obj)
  38822 {
  38823     return BC_add_object_ref1(s, JS_VALUE_GET_OBJ(obj));
  38824 }
  38825 
  38826 static JSValue JS_ReadFunctionTag(BCReaderState *s)
  38827 {
  38828     JSContext *ctx = s->ctx;
  38829     JSFunctionBytecode bc, *b;
  38830     JSValue obj = JS_UNDEFINED;
  38831     uint16_t v16;
  38832     uint8_t v8;
  38833     int idx, i, local_count;
  38834     int cpool_offset, byte_code_offset;
  38835     int closure_var_offset, vardefs_offset;
  38836     uint64_t function_size;
  38837     
  38838     memset(&bc, 0, sizeof(bc));
  38839 
  38840     if (bc_get_u16(s, &v16))
  38841         goto fail;
  38842     idx = 0;
  38843     bc.has_prototype = bc_get_flags(v16, &idx, 1);
  38844     bc.has_simple_parameter_list = bc_get_flags(v16, &idx, 1);
  38845     bc.is_derived_class_constructor = bc_get_flags(v16, &idx, 1);
  38846     bc.need_home_object = bc_get_flags(v16, &idx, 1);
  38847     bc.func_kind = bc_get_flags(v16, &idx, 2);
  38848     bc.new_target_allowed = bc_get_flags(v16, &idx, 1);
  38849     bc.super_call_allowed = bc_get_flags(v16, &idx, 1);
  38850     bc.super_allowed = bc_get_flags(v16, &idx, 1);
  38851     bc.arguments_allowed = bc_get_flags(v16, &idx, 1);
  38852     bc.has_debug = bc_get_flags(v16, &idx, 1);
  38853     bc.is_direct_or_indirect_eval = bc_get_flags(v16, &idx, 1);
  38854     bc.read_only_bytecode = s->is_rom_data;
  38855     if (bc_get_u8(s, &v8))
  38856         goto fail;
  38857     bc.js_mode = v8;
  38858     if (bc_get_atom(s, &bc.func_name))  //@ atom leak if failure
  38859         goto fail;
  38860     if (bc_get_leb128_u16(s, &bc.arg_count))
  38861         goto fail;
  38862     if (bc_get_leb128_u16(s, &bc.var_count))
  38863         goto fail;
  38864     if (bc_get_leb128_u16(s, &bc.defined_arg_count))
  38865         goto fail;
  38866     if (bc_get_leb128_u16(s, &bc.stack_size))
  38867         goto fail;
  38868     if (bc_get_leb128_u16(s, &bc.var_ref_count))
  38869         goto fail;
  38870     if (bc_get_leb128_int(s, &bc.closure_var_count))
  38871         goto fail;
  38872     if (bc_get_leb128_int(s, &bc.cpool_count))
  38873         goto fail;
  38874     if (bc_get_leb128_int(s, &bc.byte_code_len))
  38875         goto fail;
  38876     if (bc_get_leb128_int(s, &local_count))
  38877         goto fail;
  38878 
  38879     if (bc.has_debug) {
  38880         function_size = sizeof(*b);
  38881     } else {
  38882         function_size = offsetof(JSFunctionBytecode, debug);
  38883     }
  38884     cpool_offset = function_size;
  38885     function_size += (uint64_t)bc.cpool_count * sizeof(*bc.cpool);
  38886     vardefs_offset = function_size;
  38887     function_size += (uint64_t)local_count * sizeof(*bc.vardefs);
  38888     closure_var_offset = function_size;
  38889     function_size += (uint64_t)bc.closure_var_count * sizeof(*bc.closure_var);
  38890     byte_code_offset = function_size;
  38891     if (!bc.read_only_bytecode) {
  38892         function_size += bc.byte_code_len;
  38893     }
  38894 
  38895     if (function_size > INT32_MAX)
  38896         return JS_ThrowOutOfMemory(ctx);
  38897 
  38898     b = js_mallocz(ctx, function_size);
  38899     if (!b)
  38900         return JS_EXCEPTION;
  38901 
  38902     memcpy(b, &bc, offsetof(JSFunctionBytecode, debug));
  38903     if (local_count != 0) {
  38904         b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
  38905     }
  38906     if (b->closure_var_count != 0) {
  38907         b->closure_var = (void *)((uint8_t*)b + closure_var_offset);
  38908     }
  38909     if (b->cpool_count != 0) {
  38910         b->cpool = (void *)((uint8_t*)b + cpool_offset);
  38911     }
  38912 
  38913     js_rc(b)->ref_count = 1;
  38914     add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
  38915 
  38916     obj = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);
  38917 
  38918 #ifdef DUMP_READ_OBJECT
  38919     bc_read_trace(s, "name: "); print_atom(s->ctx, b->func_name); printf("\n");
  38920 #endif
  38921     bc_read_trace(s, "args=%d vars=%d defargs=%d closures=%d cpool=%d\n",
  38922                   b->arg_count, b->var_count, b->defined_arg_count,
  38923                   b->closure_var_count, b->cpool_count);
  38924     bc_read_trace(s, "stack=%d bclen=%d locals=%d\n",
  38925                   b->stack_size, b->byte_code_len, local_count);
  38926 
  38927     if (local_count != 0) {
  38928         bc_read_trace(s, "vars {\n");
  38929         for(i = 0; i < local_count; i++) {
  38930             JSBytecodeVarDef *vd = &b->vardefs[i];
  38931             if (bc_get_atom(s, &vd->var_name))
  38932                 goto fail;
  38933             if (bc_get_leb128_int(s, &vd->scope_next))
  38934                 goto fail;
  38935             vd->scope_next--;
  38936             if (bc_get_leb128_u16(s, &vd->var_ref_idx))
  38937                 goto fail;
  38938             if (bc_get_u8(s, &v8))
  38939                 goto fail;
  38940             idx = 0;
  38941             vd->var_kind = bc_get_flags(v8, &idx, 4);
  38942             vd->is_const = bc_get_flags(v8, &idx, 1);
  38943             vd->is_lexical = bc_get_flags(v8, &idx, 1);
  38944             vd->is_captured = bc_get_flags(v8, &idx, 1);
  38945             vd->has_scope = bc_get_flags(v8, &idx, 1);
  38946 #ifdef DUMP_READ_OBJECT
  38947             bc_read_trace(s, "name: "); print_atom(s->ctx, vd->var_name); printf("\n");
  38948 #endif
  38949         }
  38950         bc_read_trace(s, "}\n");
  38951     }
  38952     if (b->closure_var_count != 0) {
  38953         bc_read_trace(s, "closure vars {\n");
  38954         for(i = 0; i < b->closure_var_count; i++) {
  38955             JSClosureVar *cv = &b->closure_var[i];
  38956             int var_idx;
  38957             if (bc_get_atom(s, &cv->var_name))
  38958                 goto fail;
  38959             if (bc_get_leb128_int(s, &var_idx))
  38960                 goto fail;
  38961             cv->var_idx = var_idx;
  38962             if (bc_get_u16(s, &v16))
  38963                 goto fail;
  38964             idx = 0;
  38965             cv->closure_type = bc_get_flags(v16, &idx, 3);
  38966             cv->is_const = bc_get_flags(v16, &idx, 1);
  38967             cv->is_lexical = bc_get_flags(v16, &idx, 1);
  38968             cv->var_kind = bc_get_flags(v16, &idx, 4);
  38969 #ifdef DUMP_READ_OBJECT
  38970             bc_read_trace(s, "name: "); print_atom(s->ctx, cv->var_name); printf("\n");
  38971 #endif
  38972         }
  38973         bc_read_trace(s, "}\n");
  38974     }
  38975     {
  38976         bc_read_trace(s, "bytecode {\n");
  38977         if (JS_ReadFunctionBytecode(s, b, byte_code_offset, b->byte_code_len))
  38978             goto fail;
  38979         bc_read_trace(s, "}\n");
  38980     }
  38981     if (b->has_debug) {
  38982         /* read optional debug information */
  38983         bc_read_trace(s, "debug {\n");
  38984         if (bc_get_atom(s, &b->debug.filename))
  38985             goto fail;
  38986 #ifdef DUMP_READ_OBJECT
  38987         bc_read_trace(s, "filename: "); print_atom(s->ctx, b->debug.filename); printf("\n");
  38988 #endif
  38989         if (bc_get_leb128_int(s, &b->debug.pc2line_len))
  38990             goto fail;
  38991         if (b->debug.pc2line_len) {
  38992             b->debug.pc2line_buf = js_mallocz(ctx, b->debug.pc2line_len);
  38993             if (!b->debug.pc2line_buf)
  38994                 goto fail;
  38995             if (bc_get_buf(s, b->debug.pc2line_buf, b->debug.pc2line_len))
  38996                 goto fail;
  38997         }
  38998         if (bc_get_leb128_int(s, &b->debug.source_len))
  38999             goto fail;
  39000         if (b->debug.source_len) {
  39001             bc_read_trace(s, "source: %d bytes\n", b->source_len);
  39002             b->debug.source = js_mallocz(ctx, b->debug.source_len);
  39003             if (!b->debug.source)
  39004                 goto fail;
  39005             if (bc_get_buf(s, (uint8_t *)b->debug.source, b->debug.source_len))
  39006                 goto fail;
  39007         }
  39008         bc_read_trace(s, "}\n");
  39009     }
  39010     if (b->cpool_count != 0) {
  39011         bc_read_trace(s, "cpool {\n");
  39012         for(i = 0; i < b->cpool_count; i++) {
  39013             JSValue val;
  39014             val = JS_ReadObjectRec(s);
  39015             if (JS_IsException(val))
  39016                 goto fail;
  39017             b->cpool[i] = val;
  39018         }
  39019         bc_read_trace(s, "}\n");
  39020     }
  39021     b->realm = JS_DupContext(ctx);
  39022     return obj;
  39023  fail:
  39024     JS_FreeValue(ctx, obj);
  39025     return JS_EXCEPTION;
  39026 }
  39027 
  39028 static JSValue JS_ReadModule(BCReaderState *s)
  39029 {
  39030     JSContext *ctx = s->ctx;
  39031     JSValue obj;
  39032     JSModuleDef *m = NULL;
  39033     JSAtom module_name;
  39034     int i;
  39035     uint8_t v8;
  39036 
  39037     if (bc_get_atom(s, &module_name))
  39038         goto fail;
  39039 #ifdef DUMP_READ_OBJECT
  39040     bc_read_trace(s, "name: "); print_atom(s->ctx, module_name); printf("\n");
  39041 #endif
  39042     m = js_new_module_def(ctx, module_name);
  39043     if (!m)
  39044         goto fail;
  39045     obj = JS_NewModuleValue(ctx, m);
  39046     if (bc_get_leb128_int(s, &m->req_module_entries_count))
  39047         goto fail;
  39048     if (m->req_module_entries_count != 0) {
  39049         m->req_module_entries_size = m->req_module_entries_count;
  39050         m->req_module_entries = js_mallocz(ctx, sizeof(m->req_module_entries[0]) * m->req_module_entries_size);
  39051         if (!m->req_module_entries)
  39052             goto fail;
  39053         for(i = 0; i < m->req_module_entries_count; i++) {
  39054             JSReqModuleEntry *rme = &m->req_module_entries[i];
  39055             JSValue val;
  39056             if (bc_get_atom(s, &rme->module_name))
  39057                 goto fail;
  39058             val = JS_ReadObjectRec(s);
  39059             if (JS_IsException(val))
  39060                 goto fail;
  39061             rme->attributes = val;
  39062         }
  39063     }
  39064 
  39065     if (bc_get_leb128_int(s, &m->export_entries_count))
  39066         goto fail;
  39067     if (m->export_entries_count != 0) {
  39068         m->export_entries_size = m->export_entries_count;
  39069         m->export_entries = js_mallocz(ctx, sizeof(m->export_entries[0]) * m->export_entries_size);
  39070         if (!m->export_entries)
  39071             goto fail;
  39072         for(i = 0; i < m->export_entries_count; i++) {
  39073             JSExportEntry *me = &m->export_entries[i];
  39074             if (bc_get_u8(s, &v8))
  39075                 goto fail;
  39076             me->export_type = v8;
  39077             if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
  39078                 if (bc_get_leb128_int(s, &me->u.local.var_idx))
  39079                     goto fail;
  39080             } else {
  39081                 if (bc_get_leb128_int(s, &me->u.req_module_idx))
  39082                     goto fail;
  39083                 if (bc_get_atom(s, &me->local_name))
  39084                     goto fail;
  39085             }
  39086             if (bc_get_atom(s, &me->export_name))
  39087                 goto fail;
  39088         }
  39089     }
  39090 
  39091     if (bc_get_leb128_int(s, &m->star_export_entries_count))
  39092         goto fail;
  39093     if (m->star_export_entries_count != 0) {
  39094         m->star_export_entries_size = m->star_export_entries_count;
  39095         m->star_export_entries = js_mallocz(ctx, sizeof(m->star_export_entries[0]) * m->star_export_entries_size);
  39096         if (!m->star_export_entries)
  39097             goto fail;
  39098         for(i = 0; i < m->star_export_entries_count; i++) {
  39099             JSStarExportEntry *se = &m->star_export_entries[i];
  39100             if (bc_get_leb128_int(s, &se->req_module_idx))
  39101                 goto fail;
  39102         }
  39103     }
  39104 
  39105     if (bc_get_leb128_int(s, &m->import_entries_count))
  39106         goto fail;
  39107     if (m->import_entries_count != 0) {
  39108         m->import_entries_size = m->import_entries_count;
  39109         m->import_entries = js_mallocz(ctx, sizeof(m->import_entries[0]) * m->import_entries_size);
  39110         if (!m->import_entries)
  39111             goto fail;
  39112         for(i = 0; i < m->import_entries_count; i++) {
  39113             JSImportEntry *mi = &m->import_entries[i];
  39114             uint8_t v8;
  39115             if (bc_get_leb128_int(s, &mi->var_idx))
  39116                 goto fail;
  39117             if (bc_get_u8(s, &v8))
  39118                 goto fail;
  39119             mi->is_star = (v8 != 0);
  39120             if (bc_get_atom(s, &mi->import_name))
  39121                 goto fail;
  39122             if (bc_get_leb128_int(s, &mi->req_module_idx))
  39123                 goto fail;
  39124         }
  39125     }
  39126 
  39127     if (bc_get_u8(s, &v8))
  39128         goto fail;
  39129     m->has_tla = (v8 != 0);
  39130 
  39131     m->func_obj = JS_ReadObjectRec(s);
  39132     if (JS_IsException(m->func_obj))
  39133         goto fail;
  39134     return obj;
  39135  fail:
  39136     if (m) {
  39137         JS_FreeValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
  39138     }
  39139     return JS_EXCEPTION;
  39140 }
  39141 
  39142 static JSValue JS_ReadObjectTag(BCReaderState *s)
  39143 {
  39144     JSContext *ctx = s->ctx;
  39145     JSValue obj;
  39146     uint32_t prop_count, i;
  39147     JSAtom atom;
  39148     JSValue val;
  39149     int ret;
  39150 
  39151     obj = JS_NewObject(ctx);
  39152     if (BC_add_object_ref(s, obj))
  39153         goto fail;
  39154     if (bc_get_leb128(s, &prop_count))
  39155         goto fail;
  39156     for(i = 0; i < prop_count; i++) {
  39157         if (bc_get_atom(s, &atom))
  39158             goto fail;
  39159 #ifdef DUMP_READ_OBJECT
  39160         bc_read_trace(s, "propname: "); print_atom(s->ctx, atom); printf("\n");
  39161 #endif
  39162         val = JS_ReadObjectRec(s);
  39163         if (JS_IsException(val)) {
  39164             JS_FreeAtom(ctx, atom);
  39165             goto fail;
  39166         }
  39167         ret = JS_DefinePropertyValue(ctx, obj, atom, val, JS_PROP_C_W_E);
  39168         JS_FreeAtom(ctx, atom);
  39169         if (ret < 0)
  39170             goto fail;
  39171     }
  39172     return obj;
  39173  fail:
  39174     JS_FreeValue(ctx, obj);
  39175     return JS_EXCEPTION;
  39176 }
  39177 
  39178 static JSValue JS_ReadArray(BCReaderState *s, int tag)
  39179 {
  39180     JSContext *ctx = s->ctx;
  39181     JSValue obj;
  39182     uint32_t len, i;
  39183     JSValue val;
  39184     int ret, prop_flags;
  39185     BOOL is_template;
  39186 
  39187     obj = JS_NewArray(ctx);
  39188     if (BC_add_object_ref(s, obj))
  39189         goto fail;
  39190     is_template = (tag == BC_TAG_TEMPLATE_OBJECT);
  39191     if (bc_get_leb128(s, &len))
  39192         goto fail;
  39193     for(i = 0; i < len; i++) {
  39194         val = JS_ReadObjectRec(s);
  39195         if (JS_IsException(val))
  39196             goto fail;
  39197         if (is_template)
  39198             prop_flags = JS_PROP_ENUMERABLE;
  39199         else
  39200             prop_flags = JS_PROP_C_W_E;
  39201         ret = JS_DefinePropertyValueUint32(ctx, obj, i, val,
  39202                                            prop_flags);
  39203         if (ret < 0)
  39204             goto fail;
  39205     }
  39206     if (is_template) {
  39207         val = JS_ReadObjectRec(s);
  39208         if (JS_IsException(val))
  39209             goto fail;
  39210         if (!JS_IsUndefined(val)) {
  39211             ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_raw, val, 0);
  39212             if (ret < 0)
  39213                 goto fail;
  39214         }
  39215         JS_PreventExtensions(ctx, obj);
  39216     }
  39217     return obj;
  39218  fail:
  39219     JS_FreeValue(ctx, obj);
  39220     return JS_EXCEPTION;
  39221 }
  39222 
  39223 static JSValue JS_ReadTypedArray(BCReaderState *s)
  39224 {
  39225     JSContext *ctx = s->ctx;
  39226     JSValue obj = JS_UNDEFINED, array_buffer = JS_UNDEFINED;
  39227     uint8_t array_tag;
  39228     JSValueConst args[3];
  39229     uint32_t offset, len, idx;
  39230 
  39231     if (bc_get_u8(s, &array_tag))
  39232         return JS_EXCEPTION;
  39233     if (array_tag >= JS_TYPED_ARRAY_COUNT)
  39234         return JS_ThrowTypeError(ctx, "invalid typed array");
  39235     if (bc_get_leb128(s, &len))
  39236         return JS_EXCEPTION;
  39237     if (bc_get_leb128(s, &offset))
  39238         return JS_EXCEPTION;
  39239     /* XXX: this hack could be avoided if the typed array could be
  39240        created before the array buffer */
  39241     idx = s->objects_count;
  39242     if (BC_add_object_ref1(s, NULL))
  39243         goto fail;
  39244     array_buffer = JS_ReadObjectRec(s);
  39245     if (JS_IsException(array_buffer))
  39246         return JS_EXCEPTION;
  39247     if (!js_get_array_buffer(ctx, array_buffer)) {
  39248         JS_FreeValue(ctx, array_buffer);
  39249         return JS_EXCEPTION;
  39250     }
  39251     args[0] = array_buffer;
  39252     args[1] = JS_NewInt64(ctx, offset);
  39253     args[2] = JS_NewInt64(ctx, len);
  39254     obj = js_typed_array_constructor(ctx, JS_UNDEFINED,
  39255                                      3, args,
  39256                                      JS_CLASS_UINT8C_ARRAY + array_tag);
  39257     if (JS_IsException(obj))
  39258         goto fail;
  39259     if (s->allow_reference) {
  39260         s->objects[idx] = JS_VALUE_GET_OBJ(obj);
  39261     }
  39262     JS_FreeValue(ctx, array_buffer);
  39263     return obj;
  39264  fail:
  39265     JS_FreeValue(ctx, array_buffer);
  39266     JS_FreeValue(ctx, obj);
  39267     return JS_EXCEPTION;
  39268 }
  39269 
  39270 static JSValue JS_ReadArrayBuffer(BCReaderState *s)
  39271 {
  39272     JSContext *ctx = s->ctx;
  39273     uint32_t byte_length, max_byte_length;
  39274     uint64_t max_byte_length_u64, *pmax_byte_length = NULL;
  39275     JSValue obj;
  39276 
  39277     if (bc_get_leb128(s, &byte_length))
  39278         return JS_EXCEPTION;
  39279     if (bc_get_leb128(s, &max_byte_length))
  39280         return JS_EXCEPTION;
  39281     if (max_byte_length < byte_length)
  39282         return JS_ThrowTypeError(ctx, "invalid array buffer");
  39283     if (max_byte_length != UINT32_MAX) {
  39284         max_byte_length_u64 = max_byte_length;
  39285         pmax_byte_length = &max_byte_length_u64;
  39286     }
  39287     if (unlikely(s->buf_end - s->ptr < byte_length)) {
  39288         bc_read_error_end(s);
  39289         return JS_EXCEPTION;
  39290     }
  39291     // makes a copy of the input
  39292     obj = js_array_buffer_constructor3(ctx, JS_UNDEFINED,
  39293                                        byte_length, pmax_byte_length,
  39294                                        JS_CLASS_ARRAY_BUFFER,
  39295                                        (uint8_t*)s->ptr,
  39296                                        js_array_buffer_free, NULL,
  39297                                        /*alloc_flag*/TRUE);
  39298     if (JS_IsException(obj))
  39299         goto fail;
  39300     if (BC_add_object_ref(s, obj))
  39301         goto fail;
  39302     s->ptr += byte_length;
  39303     return obj;
  39304  fail:
  39305     JS_FreeValue(ctx, obj);
  39306     return JS_EXCEPTION;
  39307 }
  39308 
  39309 static JSValue JS_ReadSharedArrayBuffer(BCReaderState *s)
  39310 {
  39311     JSContext *ctx = s->ctx;
  39312     uint32_t byte_length, max_byte_length;
  39313     uint64_t max_byte_length_u64, *pmax_byte_length = NULL;
  39314     uint8_t *data_ptr;
  39315     JSValue obj;
  39316     uint64_t u64;
  39317 
  39318     if (bc_get_leb128(s, &byte_length))
  39319         return JS_EXCEPTION;
  39320     if (bc_get_leb128(s, &max_byte_length))
  39321         return JS_EXCEPTION;
  39322     if (max_byte_length < byte_length)
  39323         return JS_ThrowTypeError(ctx, "invalid array buffer");
  39324     if (max_byte_length != UINT32_MAX) {
  39325         max_byte_length_u64 = max_byte_length;
  39326         pmax_byte_length = &max_byte_length_u64;
  39327     }
  39328     if (bc_get_u64(s, &u64))
  39329         return JS_EXCEPTION;
  39330     data_ptr = (uint8_t *)(uintptr_t)u64;
  39331     /* the SharedArrayBuffer is cloned */
  39332     obj = js_array_buffer_constructor3(ctx, JS_UNDEFINED,
  39333                                        byte_length, pmax_byte_length,
  39334                                        JS_CLASS_SHARED_ARRAY_BUFFER,
  39335                                        data_ptr,
  39336                                        NULL, NULL, FALSE);
  39337     if (JS_IsException(obj))
  39338         goto fail;
  39339     if (BC_add_object_ref(s, obj))
  39340         goto fail;
  39341     return obj;
  39342  fail:
  39343     JS_FreeValue(ctx, obj);
  39344     return JS_EXCEPTION;
  39345 }
  39346 
  39347 static JSValue JS_ReadDate(BCReaderState *s)
  39348 {
  39349     JSContext *ctx = s->ctx;
  39350     JSValue val, obj = JS_UNDEFINED;
  39351 
  39352     val = JS_ReadObjectRec(s);
  39353     if (JS_IsException(val))
  39354         goto fail;
  39355     if (!JS_IsNumber(val)) {
  39356         JS_ThrowTypeError(ctx, "Number tag expected for date");
  39357         goto fail;
  39358     }
  39359     obj = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_DATE],
  39360                                  JS_CLASS_DATE);
  39361     if (JS_IsException(obj))
  39362         goto fail;
  39363     if (BC_add_object_ref(s, obj))
  39364         goto fail;
  39365     JS_SetObjectData(ctx, obj, val);
  39366     return obj;
  39367  fail:
  39368     JS_FreeValue(ctx, val);
  39369     JS_FreeValue(ctx, obj);
  39370     return JS_EXCEPTION;
  39371 }
  39372 
  39373 static JSValue JS_ReadObjectValue(BCReaderState *s)
  39374 {
  39375     JSContext *ctx = s->ctx;
  39376     JSValue val, obj = JS_UNDEFINED;
  39377 
  39378     val = JS_ReadObjectRec(s);
  39379     if (JS_IsException(val))
  39380         goto fail;
  39381     obj = JS_ToObject(ctx, val);
  39382     if (JS_IsException(obj))
  39383         goto fail;
  39384     if (BC_add_object_ref(s, obj))
  39385         goto fail;
  39386     JS_FreeValue(ctx, val);
  39387     return obj;
  39388  fail:
  39389     JS_FreeValue(ctx, val);
  39390     JS_FreeValue(ctx, obj);
  39391     return JS_EXCEPTION;
  39392 }
  39393 
  39394 static JSValue JS_ReadObjectRec(BCReaderState *s)
  39395 {
  39396     JSContext *ctx = s->ctx;
  39397     uint8_t tag;
  39398     JSValue obj = JS_UNDEFINED;
  39399 
  39400     if (js_check_stack_overflow(ctx->rt, 0))
  39401         return JS_ThrowStackOverflow(ctx);
  39402 
  39403     if (bc_get_u8(s, &tag))
  39404         return JS_EXCEPTION;
  39405 
  39406     bc_read_trace(s, "%s {\n", bc_tag_str[tag]);
  39407 
  39408     switch(tag) {
  39409     case BC_TAG_NULL:
  39410         obj = JS_NULL;
  39411         break;
  39412     case BC_TAG_UNDEFINED:
  39413         obj = JS_UNDEFINED;
  39414         break;
  39415     case BC_TAG_BOOL_FALSE:
  39416     case BC_TAG_BOOL_TRUE:
  39417         obj = JS_NewBool(ctx, tag - BC_TAG_BOOL_FALSE);
  39418         break;
  39419     case BC_TAG_INT32:
  39420         {
  39421             int32_t val;
  39422             if (bc_get_sleb128(s, &val))
  39423                 return JS_EXCEPTION;
  39424             bc_read_trace(s, "%d\n", val);
  39425             obj = JS_NewInt32(ctx, val);
  39426         }
  39427         break;
  39428     case BC_TAG_FLOAT64:
  39429         {
  39430             JSFloat64Union u;
  39431             if (bc_get_u64(s, &u.u64))
  39432                 return JS_EXCEPTION;
  39433             bc_read_trace(s, "%g\n", u.d);
  39434             obj = __JS_NewFloat64(ctx, u.d);
  39435         }
  39436         break;
  39437     case BC_TAG_STRING:
  39438         {
  39439             JSString *p;
  39440             p = JS_ReadString(s);
  39441             if (!p)
  39442                 return JS_EXCEPTION;
  39443             obj = JS_MKPTR(JS_TAG_STRING, p);
  39444         }
  39445         break;
  39446     case BC_TAG_FUNCTION_BYTECODE:
  39447         if (!s->allow_bytecode)
  39448             goto invalid_tag;
  39449         obj = JS_ReadFunctionTag(s);
  39450         break;
  39451     case BC_TAG_MODULE:
  39452         if (!s->allow_bytecode)
  39453             goto invalid_tag;
  39454         obj = JS_ReadModule(s);
  39455         break;
  39456     case BC_TAG_OBJECT:
  39457         obj = JS_ReadObjectTag(s);
  39458         break;
  39459     case BC_TAG_ARRAY:
  39460     case BC_TAG_TEMPLATE_OBJECT:
  39461         obj = JS_ReadArray(s, tag);
  39462         break;
  39463     case BC_TAG_TYPED_ARRAY:
  39464         obj = JS_ReadTypedArray(s);
  39465         break;
  39466     case BC_TAG_ARRAY_BUFFER:
  39467         obj = JS_ReadArrayBuffer(s);
  39468         break;
  39469     case BC_TAG_SHARED_ARRAY_BUFFER:
  39470         if (!s->allow_sab || !ctx->rt->sab_funcs.sab_dup)
  39471             goto invalid_tag;
  39472         obj = JS_ReadSharedArrayBuffer(s);
  39473         break;
  39474     case BC_TAG_DATE:
  39475         obj = JS_ReadDate(s);
  39476         break;
  39477     case BC_TAG_OBJECT_VALUE:
  39478         obj = JS_ReadObjectValue(s);
  39479         break;
  39480     case BC_TAG_BIG_INT:
  39481         obj = JS_ReadBigInt(s);
  39482         break;
  39483     case BC_TAG_OBJECT_REFERENCE:
  39484         {
  39485             uint32_t val;
  39486             if (!s->allow_reference)
  39487                 return JS_ThrowSyntaxError(ctx, "object references are not allowed");
  39488             if (bc_get_leb128(s, &val))
  39489                 return JS_EXCEPTION;
  39490             bc_read_trace(s, "%u\n", val);
  39491             if (val >= s->objects_count) {
  39492                 return JS_ThrowSyntaxError(ctx, "invalid object reference (%u >= %u)",
  39493                                            val, s->objects_count);
  39494             }
  39495             obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, s->objects[val]));
  39496         }
  39497         break;
  39498     default:
  39499     invalid_tag:
  39500         return JS_ThrowSyntaxError(ctx, "invalid tag (tag=%d pos=%u)",
  39501                                    tag, (unsigned int)(s->ptr - s->buf_start));
  39502     }
  39503     bc_read_trace(s, "}\n");
  39504     return obj;
  39505 }
  39506 
  39507 static int JS_ReadObjectAtoms(BCReaderState *s)
  39508 {
  39509     uint8_t v8;
  39510     JSString *p;
  39511     int i;
  39512     JSAtom atom;
  39513 
  39514     if (bc_get_u8(s, &v8))
  39515         return -1;
  39516     if (v8 != BC_VERSION) {
  39517         JS_ThrowSyntaxError(s->ctx, "invalid version (%d expected=%d)",
  39518                             v8, BC_VERSION);
  39519         return -1;
  39520     }
  39521     if (bc_get_leb128(s, &s->idx_to_atom_count))
  39522         return -1;
  39523 
  39524     bc_read_trace(s, "%d atom indexes {\n", s->idx_to_atom_count);
  39525 
  39526     if (s->idx_to_atom_count != 0) {
  39527         s->idx_to_atom = js_mallocz(s->ctx, s->idx_to_atom_count *
  39528                                     sizeof(s->idx_to_atom[0]));
  39529         if (!s->idx_to_atom)
  39530             return s->error_state = -1;
  39531     }
  39532     for(i = 0; i < s->idx_to_atom_count; i++) {
  39533         p = JS_ReadString(s);
  39534         if (!p)
  39535             return -1;
  39536         atom = JS_NewAtomStr(s->ctx, p);
  39537         if (atom == JS_ATOM_NULL)
  39538             return s->error_state = -1;
  39539         s->idx_to_atom[i] = atom;
  39540         if (s->is_rom_data && (atom != (i + s->first_atom)))
  39541             s->is_rom_data = FALSE; /* atoms must be relocated */
  39542     }
  39543     bc_read_trace(s, "}\n");
  39544     return 0;
  39545 }
  39546 
  39547 static void bc_reader_free(BCReaderState *s)
  39548 {
  39549     int i;
  39550     if (s->idx_to_atom) {
  39551         for(i = 0; i < s->idx_to_atom_count; i++) {
  39552             JS_FreeAtom(s->ctx, s->idx_to_atom[i]);
  39553         }
  39554         js_free(s->ctx, s->idx_to_atom);
  39555     }
  39556     js_free(s->ctx, s->objects);
  39557 }
  39558 
  39559 JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len,
  39560                        int flags)
  39561 {
  39562     BCReaderState ss, *s = &ss;
  39563     JSValue obj;
  39564 
  39565     ctx->binary_object_count += 1;
  39566     ctx->binary_object_size += buf_len;
  39567 
  39568     memset(s, 0, sizeof(*s));
  39569     s->ctx = ctx;
  39570     s->buf_start = buf;
  39571     s->buf_end = buf + buf_len;
  39572     s->ptr = buf;
  39573     s->allow_bytecode = ((flags & JS_READ_OBJ_BYTECODE) != 0);
  39574     s->is_rom_data = ((flags & JS_READ_OBJ_ROM_DATA) != 0);
  39575     s->allow_sab = ((flags & JS_READ_OBJ_SAB) != 0);
  39576     s->allow_reference = ((flags & JS_READ_OBJ_REFERENCE) != 0);
  39577     if (s->allow_bytecode)
  39578         s->first_atom = JS_ATOM_END;
  39579     else
  39580         s->first_atom = 1;
  39581     if (JS_ReadObjectAtoms(s)) {
  39582         obj = JS_EXCEPTION;
  39583     } else {
  39584         obj = JS_ReadObjectRec(s);
  39585     }
  39586     bc_reader_free(s);
  39587     return obj;
  39588 }
  39589 
  39590 /*******************************************************************/
  39591 /* runtime functions & objects */
  39592 
  39593 static JSValue js_string_constructor(JSContext *ctx, JSValueConst this_val,
  39594                                      int argc, JSValueConst *argv);
  39595 static JSValue js_boolean_constructor(JSContext *ctx, JSValueConst this_val,
  39596                                       int argc, JSValueConst *argv);
  39597 static JSValue js_number_constructor(JSContext *ctx, JSValueConst this_val,
  39598                                      int argc, JSValueConst *argv);
  39599 
  39600 static int check_function(JSContext *ctx, JSValueConst obj)
  39601 {
  39602     if (likely(JS_IsFunction(ctx, obj)))
  39603         return 0;
  39604     JS_ThrowTypeError(ctx, "not a function");
  39605     return -1;
  39606 }
  39607 
  39608 static int check_exception_free(JSContext *ctx, JSValue obj)
  39609 {
  39610     JS_FreeValue(ctx, obj);
  39611     return JS_IsException(obj);
  39612 }
  39613 
  39614 static JSAtom find_atom(JSContext *ctx, const char *name)
  39615 {
  39616     JSAtom atom;
  39617     int len;
  39618 
  39619     if (*name == '[') {
  39620         name++;
  39621         len = strlen(name) - 1;
  39622         /* We assume 8 bit non null strings, which is the case for these
  39623            symbols */
  39624         for(atom = JS_ATOM_Symbol_toPrimitive; atom < JS_ATOM_END; atom++) {
  39625             JSAtomStruct *p = ctx->rt->atom_array[atom];
  39626             JSString *str = p;
  39627             if (str->len == len && !memcmp(str->u.str8, name, len))
  39628                 return JS_DupAtom(ctx, atom);
  39629         }
  39630         abort();
  39631     } else {
  39632         atom = JS_NewAtom(ctx, name);
  39633     }
  39634     return atom;
  39635 }
  39636 
  39637 static JSValue JS_NewObjectProtoList(JSContext *ctx, JSValueConst proto,
  39638                                      const JSCFunctionListEntry *fields, int n_fields)
  39639 {
  39640     JSValue obj;
  39641     obj = JS_NewObjectProtoClassAlloc(ctx, proto, JS_CLASS_OBJECT, n_fields);
  39642     if (JS_IsException(obj))
  39643         return obj;
  39644     if (JS_SetPropertyFunctionList(ctx, obj, fields, n_fields)) {
  39645         JS_FreeValue(ctx, obj);
  39646         return JS_EXCEPTION;
  39647     }
  39648     return obj;
  39649 }
  39650 
  39651 static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,
  39652                                                JSAtom atom, void *opaque)
  39653 {
  39654     const JSCFunctionListEntry *e = opaque;
  39655     JSValue val, proto;
  39656 
  39657     switch(e->def_type) {
  39658     case JS_DEF_CFUNC:
  39659         val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic,
  39660                                e->name, e->u.func.length, e->u.func.cproto, e->magic);
  39661         break;
  39662     case JS_DEF_PROP_STRING:
  39663         val = JS_NewAtomString(ctx, e->u.str);
  39664         break;
  39665     case JS_DEF_OBJECT:
  39666         /* XXX: could add a flag */
  39667         if (atom == JS_ATOM_Symbol_unscopables)
  39668             proto = JS_NULL;
  39669         else
  39670             proto = ctx->class_proto[JS_CLASS_OBJECT];
  39671         val = JS_NewObjectProtoList(ctx, proto,
  39672                                     e->u.prop_list.tab, e->u.prop_list.len);
  39673         break;
  39674     default:
  39675         abort();
  39676     }
  39677     return val;
  39678 }
  39679 
  39680 static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj,
  39681                                           JSAtom atom,
  39682                                           const JSCFunctionListEntry *e)
  39683 {
  39684     JSValue val;
  39685     int prop_flags = e->prop_flags;
  39686 
  39687     switch(e->def_type) {
  39688     case JS_DEF_ALIAS: /* using autoinit for aliases is not safe */
  39689         {
  39690             JSAtom atom1 = find_atom(ctx, e->u.alias.name);
  39691             switch (e->u.alias.base) {
  39692             case -1:
  39693                 val = JS_GetProperty(ctx, obj, atom1);
  39694                 break;
  39695             case 0:
  39696                 val = JS_GetProperty(ctx, ctx->global_obj, atom1);
  39697                 break;
  39698             case 1:
  39699                 val = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], atom1);
  39700                 break;
  39701             default:
  39702                 abort();
  39703             }
  39704             JS_FreeAtom(ctx, atom1);
  39705             if (JS_IsException(val))
  39706                 return -1;
  39707             if (atom == JS_ATOM_Symbol_toPrimitive) {
  39708                 /* Symbol.toPrimitive functions are not writable */
  39709                 prop_flags = JS_PROP_CONFIGURABLE;
  39710             } else if (atom == JS_ATOM_Symbol_hasInstance) {
  39711                 /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */
  39712                 prop_flags = 0;
  39713             }
  39714         }
  39715         break;
  39716     case JS_DEF_CFUNC:
  39717         if (atom == JS_ATOM_Symbol_toPrimitive) {
  39718             /* Symbol.toPrimitive functions are not writable */
  39719             prop_flags = JS_PROP_CONFIGURABLE;
  39720         } else if (atom == JS_ATOM_Symbol_hasInstance) {
  39721             /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */
  39722             prop_flags = 0;
  39723         }
  39724         if (JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP,
  39725                                       (void *)e, prop_flags) < 0)
  39726             return -1;
  39727         return 0;
  39728     case JS_DEF_CGETSET: /* XXX: use autoinit again ? */
  39729     case JS_DEF_CGETSET_MAGIC:
  39730         {
  39731             JSValue getter, setter;
  39732             char buf[64];
  39733 
  39734             getter = JS_UNDEFINED;
  39735             if (e->u.getset.get.generic) {
  39736                 snprintf(buf, sizeof(buf), "get %s", e->name);
  39737                 getter = JS_NewCFunction2(ctx, e->u.getset.get.generic,
  39738                                           buf, 0, e->def_type == JS_DEF_CGETSET_MAGIC ? JS_CFUNC_getter_magic : JS_CFUNC_getter,
  39739                                           e->magic);
  39740                 if (JS_IsException(getter))
  39741                     return -1;
  39742             }
  39743             setter = JS_UNDEFINED;
  39744             if (e->u.getset.set.generic) {
  39745                 snprintf(buf, sizeof(buf), "set %s", e->name);
  39746                 setter = JS_NewCFunction2(ctx, e->u.getset.set.generic,
  39747                                           buf, 1, e->def_type == JS_DEF_CGETSET_MAGIC ? JS_CFUNC_setter_magic : JS_CFUNC_setter,
  39748                                           e->magic);
  39749                 if (JS_IsException(setter)) {
  39750                     JS_FreeValue(ctx, getter);
  39751                     return -1;
  39752                 }
  39753             }
  39754             if (JS_DefinePropertyGetSet(ctx, obj, atom, getter, setter, prop_flags) < 0)
  39755                 return -1;
  39756             return 0;
  39757         }
  39758         break;
  39759     case JS_DEF_PROP_INT32:
  39760         val = JS_NewInt32(ctx, e->u.i32);
  39761         break;
  39762     case JS_DEF_PROP_INT64:
  39763         val = JS_NewInt64(ctx, e->u.i64);
  39764         break;
  39765     case JS_DEF_PROP_DOUBLE:
  39766         val = __JS_NewFloat64(ctx, e->u.f64);
  39767         break;
  39768     case JS_DEF_PROP_UNDEFINED:
  39769         val = JS_UNDEFINED;
  39770         break;
  39771     case JS_DEF_PROP_ATOM:
  39772         val = JS_AtomToValue(ctx, e->u.i32);
  39773         break;
  39774     case JS_DEF_PROP_BOOL:
  39775         val = JS_NewBool(ctx, e->u.i32);
  39776         break;
  39777     case JS_DEF_PROP_STRING:
  39778     case JS_DEF_OBJECT:
  39779         if (JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP,
  39780                                       (void *)e, prop_flags) < 0)
  39781             return -1;
  39782         return 0;
  39783     default:
  39784         abort();
  39785     }
  39786     if (JS_DefinePropertyValue(ctx, obj, atom, val, prop_flags) < 0)
  39787         return -1;
  39788     return 0;
  39789 }
  39790 
  39791 int JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
  39792                                const JSCFunctionListEntry *tab, int len)
  39793 {
  39794     int i, ret;
  39795 
  39796     for (i = 0; i < len; i++) {
  39797         const JSCFunctionListEntry *e = &tab[i];
  39798         JSAtom atom = find_atom(ctx, e->name);
  39799         if (atom == JS_ATOM_NULL)
  39800             return -1;
  39801         ret = JS_InstantiateFunctionListItem(ctx, obj, atom, e);
  39802         JS_FreeAtom(ctx, atom);
  39803         if (ret)
  39804             return -1;
  39805     }
  39806     return 0;
  39807 }
  39808 
  39809 int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m,
  39810                            const JSCFunctionListEntry *tab, int len)
  39811 {
  39812     int i;
  39813     for(i = 0; i < len; i++) {
  39814         if (JS_AddModuleExport(ctx, m, tab[i].name))
  39815             return -1;
  39816     }
  39817     return 0;
  39818 }
  39819 
  39820 int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,
  39821                            const JSCFunctionListEntry *tab, int len)
  39822 {
  39823     int i;
  39824     JSValue val;
  39825 
  39826     for(i = 0; i < len; i++) {
  39827         const JSCFunctionListEntry *e = &tab[i];
  39828         switch(e->def_type) {
  39829         case JS_DEF_CFUNC:
  39830             val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic,
  39831                                    e->name, e->u.func.length, e->u.func.cproto, e->magic);
  39832             break;
  39833         case JS_DEF_PROP_STRING:
  39834             val = JS_NewString(ctx, e->u.str);
  39835             break;
  39836         case JS_DEF_PROP_INT32:
  39837             val = JS_NewInt32(ctx, e->u.i32);
  39838             break;
  39839         case JS_DEF_PROP_INT64:
  39840             val = JS_NewInt64(ctx, e->u.i64);
  39841             break;
  39842         case JS_DEF_PROP_DOUBLE:
  39843             val = __JS_NewFloat64(ctx, e->u.f64);
  39844             break;
  39845         case JS_DEF_OBJECT:
  39846             val = JS_NewObjectProtoList(ctx, ctx->class_proto[JS_CLASS_OBJECT],
  39847                                         e->u.prop_list.tab, e->u.prop_list.len);
  39848             break;
  39849         default:
  39850             abort();
  39851         }
  39852         if (JS_SetModuleExport(ctx, m, e->name, val))
  39853             return -1;
  39854     }
  39855     return 0;
  39856 }
  39857 
  39858 /* Note: 'func_obj' is not necessarily a constructor */
  39859 static int JS_SetConstructor2(JSContext *ctx,
  39860                               JSValueConst func_obj,
  39861                               JSValueConst proto,
  39862                               int proto_flags, int ctor_flags)
  39863 {
  39864     if (JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype,
  39865                                JS_DupValue(ctx, proto), proto_flags) < 0)
  39866         return -1;
  39867     if (JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor,
  39868                                JS_DupValue(ctx, func_obj),
  39869                                ctor_flags) < 0)
  39870         return -1;
  39871     set_cycle_flag(ctx, func_obj);
  39872     set_cycle_flag(ctx, proto);
  39873     return 0;
  39874 }
  39875 
  39876 /* return 0 if OK, -1 if exception */
  39877 int JS_SetConstructor(JSContext *ctx, JSValueConst func_obj,
  39878                       JSValueConst proto)
  39879 {
  39880     return JS_SetConstructor2(ctx, func_obj, proto,
  39881                               0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
  39882 }
  39883 
  39884 #define JS_NEW_CTOR_NO_GLOBAL   (1 << 0) /* don't create a global binding */
  39885 #define JS_NEW_CTOR_PROTO_CLASS (1 << 1) /* the prototype class is 'class_id' instead of JS_CLASS_OBJECT */
  39886 #define JS_NEW_CTOR_PROTO_EXIST (1 << 2) /* the prototype is already defined */
  39887 #define JS_NEW_CTOR_READONLY    (1 << 3) /* read-only constructor field */
  39888 
  39889 /* Return the constructor and. Define it as a global variable unless
  39890    JS_NEW_CTOR_NO_GLOBAL is set. The new class inherit from
  39891    parent_ctor if it is not JS_UNDEFINED. if class_id is != -1,
  39892    class_proto[class_id] is set. */
  39893 static JSValue JS_NewCConstructor(JSContext *ctx, int class_id, const char *name,
  39894                                   JSCFunction *func, int length, JSCFunctionEnum cproto, int magic,
  39895                                   JSValueConst parent_ctor,
  39896                                   const JSCFunctionListEntry *ctor_fields, int n_ctor_fields,
  39897                                   const JSCFunctionListEntry *proto_fields, int n_proto_fields,
  39898                                   int flags)
  39899 {
  39900     JSValue ctor = JS_UNDEFINED, proto, parent_proto;
  39901     int proto_class_id, proto_flags, ctor_flags;
  39902 
  39903     proto_flags = 0;
  39904     if (flags & JS_NEW_CTOR_READONLY) {
  39905         ctor_flags = JS_PROP_CONFIGURABLE;
  39906     } else {
  39907         ctor_flags = JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE;
  39908     }
  39909     
  39910     if (JS_IsUndefined(parent_ctor)) {
  39911         parent_proto = JS_DupValue(ctx, ctx->class_proto[JS_CLASS_OBJECT]);
  39912         parent_ctor = ctx->function_proto;
  39913     } else {
  39914         parent_proto = JS_GetProperty(ctx, parent_ctor, JS_ATOM_prototype);
  39915         if (JS_IsException(parent_proto))
  39916             return JS_EXCEPTION;
  39917     }
  39918     
  39919     if (flags & JS_NEW_CTOR_PROTO_EXIST) {
  39920         proto = JS_DupValue(ctx, ctx->class_proto[class_id]);
  39921     } else {
  39922         if (flags & JS_NEW_CTOR_PROTO_CLASS)
  39923             proto_class_id = class_id;
  39924         else
  39925             proto_class_id = JS_CLASS_OBJECT;
  39926         /* one additional field: constructor */
  39927         proto = JS_NewObjectProtoClassAlloc(ctx, parent_proto, proto_class_id,
  39928                                             n_proto_fields + 1);
  39929         if (JS_IsException(proto))
  39930             goto fail;
  39931         if (class_id >= 0)
  39932             ctx->class_proto[class_id] = JS_DupValue(ctx, proto);
  39933     }
  39934     if (JS_SetPropertyFunctionList(ctx, proto, proto_fields, n_proto_fields))
  39935         goto fail;
  39936 
  39937     /* additional fields: name, length, prototype */
  39938     ctor = JS_NewCFunction3(ctx, func, name, length, cproto, magic, parent_ctor,
  39939                             n_ctor_fields + 3);
  39940     if (JS_IsException(ctor))
  39941         goto fail;
  39942     if (JS_SetPropertyFunctionList(ctx, ctor, ctor_fields, n_ctor_fields))
  39943         goto fail;
  39944     if (!(flags & JS_NEW_CTOR_NO_GLOBAL)) {
  39945         if (JS_DefinePropertyValueStr(ctx, ctx->global_obj, name,
  39946                                       JS_DupValue(ctx, ctor),
  39947                                       JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0)
  39948             goto fail;
  39949     }
  39950     JS_SetConstructor2(ctx, ctor, proto, proto_flags, ctor_flags);
  39951 
  39952     JS_FreeValue(ctx, proto);
  39953     JS_FreeValue(ctx, parent_proto);
  39954     return ctor;
  39955  fail:
  39956     JS_FreeValue(ctx, proto);
  39957     JS_FreeValue(ctx, parent_proto);
  39958     JS_FreeValue(ctx, ctor);
  39959     return JS_EXCEPTION;
  39960 }
  39961 
  39962 static JSValue js_global_eval(JSContext *ctx, JSValueConst this_val,
  39963                               int argc, JSValueConst *argv)
  39964 {
  39965     return JS_EvalObject(ctx, ctx->global_obj, argv[0], JS_EVAL_TYPE_INDIRECT, -1);
  39966 }
  39967 
  39968 static JSValue js_global_isNaN(JSContext *ctx, JSValueConst this_val,
  39969                                int argc, JSValueConst *argv)
  39970 {
  39971     double d;
  39972 
  39973     if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
  39974         return JS_EXCEPTION;
  39975     return JS_NewBool(ctx, isnan(d));
  39976 }
  39977 
  39978 static JSValue js_global_isFinite(JSContext *ctx, JSValueConst this_val,
  39979                                   int argc, JSValueConst *argv)
  39980 {
  39981     double d;
  39982     if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
  39983         return JS_EXCEPTION;
  39984     return JS_NewBool(ctx, isfinite(d));
  39985 }
  39986 
  39987 /* Object class */
  39988 
  39989 static JSValue JS_ToObject(JSContext *ctx, JSValueConst val)
  39990 {
  39991     int tag = JS_VALUE_GET_NORM_TAG(val);
  39992     JSValue obj;
  39993 
  39994     switch(tag) {
  39995     default:
  39996     case JS_TAG_NULL:
  39997     case JS_TAG_UNDEFINED:
  39998         return JS_ThrowTypeError(ctx, "cannot convert to object");
  39999     case JS_TAG_OBJECT:
  40000     case JS_TAG_EXCEPTION:
  40001         return JS_DupValue(ctx, val);
  40002     case JS_TAG_SHORT_BIG_INT:
  40003     case JS_TAG_BIG_INT:
  40004         obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT);
  40005         goto set_value;
  40006     case JS_TAG_INT:
  40007     case JS_TAG_FLOAT64:
  40008         obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER);
  40009         goto set_value;
  40010     case JS_TAG_STRING:
  40011     case JS_TAG_STRING_ROPE:
  40012         /* XXX: should call the string constructor */
  40013         {
  40014             JSValue str;
  40015             str = JS_ToString(ctx, val); /* ensure that we never store a rope */
  40016             if (JS_IsException(str))
  40017                 return JS_EXCEPTION;
  40018             obj = JS_NewObjectClass(ctx, JS_CLASS_STRING);
  40019             if (!JS_IsException(obj)) {
  40020                 JS_DefinePropertyValue(ctx, obj, JS_ATOM_length,
  40021                                        JS_NewInt32(ctx, JS_VALUE_GET_STRING(str)->len), 0);
  40022                 JS_SetObjectData(ctx, obj, JS_DupValue(ctx, str));
  40023             }
  40024             JS_FreeValue(ctx, str);
  40025             return obj;
  40026         }
  40027     case JS_TAG_BOOL:
  40028         obj = JS_NewObjectClass(ctx, JS_CLASS_BOOLEAN);
  40029         goto set_value;
  40030     case JS_TAG_SYMBOL:
  40031         obj = JS_NewObjectClass(ctx, JS_CLASS_SYMBOL);
  40032     set_value:
  40033         if (!JS_IsException(obj))
  40034             JS_SetObjectData(ctx, obj, JS_DupValue(ctx, val));
  40035         return obj;
  40036     }
  40037 }
  40038 
  40039 static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val)
  40040 {
  40041     JSValue obj = JS_ToObject(ctx, val);
  40042     JS_FreeValue(ctx, val);
  40043     return obj;
  40044 }
  40045 
  40046 static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
  40047                           JSValueConst desc)
  40048 {
  40049     JSValue val, getter, setter;
  40050     int flags;
  40051 
  40052     if (!JS_IsObject(desc)) {
  40053         JS_ThrowTypeErrorNotAnObject(ctx);
  40054         return -1;
  40055     }
  40056     flags = 0;
  40057     val = JS_UNDEFINED;
  40058     getter = JS_UNDEFINED;
  40059     setter = JS_UNDEFINED;
  40060     if (JS_HasProperty(ctx, desc, JS_ATOM_enumerable)) {
  40061         JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_enumerable);
  40062         if (JS_IsException(prop))
  40063             goto fail;
  40064         flags |= JS_PROP_HAS_ENUMERABLE;
  40065         if (JS_ToBoolFree(ctx, prop))
  40066             flags |= JS_PROP_ENUMERABLE;
  40067     }
  40068     if (JS_HasProperty(ctx, desc, JS_ATOM_configurable)) {
  40069         JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_configurable);
  40070         if (JS_IsException(prop))
  40071             goto fail;
  40072         flags |= JS_PROP_HAS_CONFIGURABLE;
  40073         if (JS_ToBoolFree(ctx, prop))
  40074             flags |= JS_PROP_CONFIGURABLE;
  40075     }
  40076     if (JS_HasProperty(ctx, desc, JS_ATOM_value)) {
  40077         flags |= JS_PROP_HAS_VALUE;
  40078         val = JS_GetProperty(ctx, desc, JS_ATOM_value);
  40079         if (JS_IsException(val))
  40080             goto fail;
  40081     }
  40082     if (JS_HasProperty(ctx, desc, JS_ATOM_writable)) {
  40083         JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_writable);
  40084         if (JS_IsException(prop))
  40085             goto fail;
  40086         flags |= JS_PROP_HAS_WRITABLE;
  40087         if (JS_ToBoolFree(ctx, prop))
  40088             flags |= JS_PROP_WRITABLE;
  40089     }
  40090     if (JS_HasProperty(ctx, desc, JS_ATOM_get)) {
  40091         flags |= JS_PROP_HAS_GET;
  40092         getter = JS_GetProperty(ctx, desc, JS_ATOM_get);
  40093         if (JS_IsException(getter) ||
  40094             !(JS_IsUndefined(getter) || JS_IsFunction(ctx, getter))) {
  40095             JS_ThrowTypeError(ctx, "invalid getter");
  40096             goto fail;
  40097         }
  40098     }
  40099     if (JS_HasProperty(ctx, desc, JS_ATOM_set)) {
  40100         flags |= JS_PROP_HAS_SET;
  40101         setter = JS_GetProperty(ctx, desc, JS_ATOM_set);
  40102         if (JS_IsException(setter) ||
  40103             !(JS_IsUndefined(setter) || JS_IsFunction(ctx, setter))) {
  40104             JS_ThrowTypeError(ctx, "invalid setter");
  40105             goto fail;
  40106         }
  40107     }
  40108     if ((flags & (JS_PROP_HAS_SET | JS_PROP_HAS_GET)) &&
  40109         (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE))) {
  40110         JS_ThrowTypeError(ctx, "cannot have setter/getter and value or writable");
  40111         goto fail;
  40112     }
  40113     d->flags = flags;
  40114     d->value = val;
  40115     d->getter = getter;
  40116     d->setter = setter;
  40117     return 0;
  40118  fail:
  40119     JS_FreeValue(ctx, val);
  40120     JS_FreeValue(ctx, getter);
  40121     JS_FreeValue(ctx, setter);
  40122     return -1;
  40123 }
  40124 
  40125 static __exception int JS_DefinePropertyDesc(JSContext *ctx, JSValueConst obj,
  40126                                              JSAtom prop, JSValueConst desc,
  40127                                              int flags)
  40128 {
  40129     JSPropertyDescriptor d;
  40130     int ret;
  40131 
  40132     if (js_obj_to_desc(ctx, &d, desc) < 0)
  40133         return -1;
  40134 
  40135     ret = JS_DefineProperty(ctx, obj, prop,
  40136                             d.value, d.getter, d.setter, d.flags | flags);
  40137     js_free_desc(ctx, &d);
  40138     return ret;
  40139 }
  40140 
  40141 static __exception int JS_ObjectDefineProperties(JSContext *ctx,
  40142                                                  JSValueConst obj,
  40143                                                  JSValueConst properties)
  40144 {
  40145     JSValue props, desc;
  40146     JSObject *p;
  40147     JSPropertyEnum *atoms;
  40148     uint32_t len, i;
  40149     int ret = -1;
  40150 
  40151     if (!JS_IsObject(obj)) {
  40152         JS_ThrowTypeErrorNotAnObject(ctx);
  40153         return -1;
  40154     }
  40155     desc = JS_UNDEFINED;
  40156     props = JS_ToObject(ctx, properties);
  40157     if (JS_IsException(props))
  40158         return -1;
  40159     p = JS_VALUE_GET_OBJ(props);
  40160     /* XXX: not done in the same order as the spec */
  40161     if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK) < 0)
  40162         goto exception;
  40163     for(i = 0; i < len; i++) {
  40164         JS_FreeValue(ctx, desc);
  40165         desc = JS_GetProperty(ctx, props, atoms[i].atom);
  40166         if (JS_IsException(desc))
  40167             goto exception;
  40168         if (JS_DefinePropertyDesc(ctx, obj, atoms[i].atom, desc, JS_PROP_THROW) < 0)
  40169             goto exception;
  40170     }
  40171     ret = 0;
  40172 
  40173 exception:
  40174     JS_FreePropertyEnum(ctx, atoms, len);
  40175     JS_FreeValue(ctx, props);
  40176     JS_FreeValue(ctx, desc);
  40177     return ret;
  40178 }
  40179 
  40180 static JSValue js_object_constructor(JSContext *ctx, JSValueConst new_target,
  40181                                      int argc, JSValueConst *argv)
  40182 {
  40183     JSValue ret;
  40184     if (!JS_IsUndefined(new_target) &&
  40185         JS_VALUE_GET_OBJ(new_target) !=
  40186         JS_VALUE_GET_OBJ(JS_GetActiveFunction(ctx))) {
  40187         ret = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
  40188     } else {
  40189         int tag = JS_VALUE_GET_NORM_TAG(argv[0]);
  40190         switch(tag) {
  40191         case JS_TAG_NULL:
  40192         case JS_TAG_UNDEFINED:
  40193             ret = JS_NewObject(ctx);
  40194             break;
  40195         default:
  40196             ret = JS_ToObject(ctx, argv[0]);
  40197             break;
  40198         }
  40199     }
  40200     return ret;
  40201 }
  40202 
  40203 static JSValue js_object_create(JSContext *ctx, JSValueConst this_val,
  40204                                 int argc, JSValueConst *argv)
  40205 {
  40206     JSValueConst proto, props;
  40207     JSValue obj;
  40208 
  40209     proto = argv[0];
  40210     if (!JS_IsObject(proto) && !JS_IsNull(proto))
  40211         return JS_ThrowTypeError(ctx, "not a prototype");
  40212     obj = JS_NewObjectProto(ctx, proto);
  40213     if (JS_IsException(obj))
  40214         return JS_EXCEPTION;
  40215     props = argv[1];
  40216     if (!JS_IsUndefined(props)) {
  40217         if (JS_ObjectDefineProperties(ctx, obj, props)) {
  40218             JS_FreeValue(ctx, obj);
  40219             return JS_EXCEPTION;
  40220         }
  40221     }
  40222     return obj;
  40223 }
  40224 
  40225 static JSValue js_object_getPrototypeOf(JSContext *ctx, JSValueConst this_val,
  40226                                         int argc, JSValueConst *argv, int magic)
  40227 {
  40228     JSValueConst val;
  40229 
  40230     val = argv[0];
  40231     if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) {
  40232         /* ES6 feature non compatible with ES5.1: primitive types are
  40233            accepted */
  40234         if (magic || JS_VALUE_GET_TAG(val) == JS_TAG_NULL ||
  40235             JS_VALUE_GET_TAG(val) == JS_TAG_UNDEFINED)
  40236             return JS_ThrowTypeErrorNotAnObject(ctx);
  40237     }
  40238     return JS_GetPrototype(ctx, val);
  40239 }
  40240 
  40241 static JSValue js_object_setPrototypeOf(JSContext *ctx, JSValueConst this_val,
  40242                                         int argc, JSValueConst *argv)
  40243 {
  40244     JSValueConst obj;
  40245     obj = argv[0];
  40246     if (JS_SetPrototypeInternal(ctx, obj, argv[1], TRUE) < 0)
  40247         return JS_EXCEPTION;
  40248     return JS_DupValue(ctx, obj);
  40249 }
  40250 
  40251 /* magic = 1 if called as Reflect.defineProperty */
  40252 static JSValue js_object_defineProperty(JSContext *ctx, JSValueConst this_val,
  40253                                         int argc, JSValueConst *argv, int magic)
  40254 {
  40255     JSValueConst obj, prop, desc;
  40256     int ret, flags;
  40257     JSAtom atom;
  40258 
  40259     obj = argv[0];
  40260     prop = argv[1];
  40261     desc = argv[2];
  40262 
  40263     if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
  40264         return JS_ThrowTypeErrorNotAnObject(ctx);
  40265     atom = JS_ValueToAtom(ctx, prop);
  40266     if (unlikely(atom == JS_ATOM_NULL))
  40267         return JS_EXCEPTION;
  40268     flags = 0;
  40269     if (!magic)
  40270         flags |= JS_PROP_THROW;
  40271     ret = JS_DefinePropertyDesc(ctx, obj, atom, desc, flags);
  40272     JS_FreeAtom(ctx, atom);
  40273     if (ret < 0) {
  40274         return JS_EXCEPTION;
  40275     } else if (magic) {
  40276         return JS_NewBool(ctx, ret);
  40277     } else {
  40278         return JS_DupValue(ctx, obj);
  40279     }
  40280 }
  40281 
  40282 static JSValue js_object_defineProperties(JSContext *ctx, JSValueConst this_val,
  40283                                           int argc, JSValueConst *argv)
  40284 {
  40285     // defineProperties(obj, properties)
  40286     JSValueConst obj = argv[0];
  40287 
  40288     if (JS_ObjectDefineProperties(ctx, obj, argv[1]))
  40289         return JS_EXCEPTION;
  40290     else
  40291         return JS_DupValue(ctx, obj);
  40292 }
  40293 
  40294 /* magic = 1 if called as __defineSetter__ */
  40295 static JSValue js_object___defineGetter__(JSContext *ctx, JSValueConst this_val,
  40296                                           int argc, JSValueConst *argv, int magic)
  40297 {
  40298     JSValue obj;
  40299     JSValueConst prop, value, get, set;
  40300     int ret, flags;
  40301     JSAtom atom;
  40302 
  40303     prop = argv[0];
  40304     value = argv[1];
  40305 
  40306     obj = JS_ToObject(ctx, this_val);
  40307     if (JS_IsException(obj))
  40308         return JS_EXCEPTION;
  40309 
  40310     if (check_function(ctx, value)) {
  40311         JS_FreeValue(ctx, obj);
  40312         return JS_EXCEPTION;
  40313     }
  40314     atom = JS_ValueToAtom(ctx, prop);
  40315     if (unlikely(atom == JS_ATOM_NULL)) {
  40316         JS_FreeValue(ctx, obj);
  40317         return JS_EXCEPTION;
  40318     }
  40319     flags = JS_PROP_THROW |
  40320         JS_PROP_HAS_ENUMERABLE | JS_PROP_ENUMERABLE |
  40321         JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE;
  40322     if (magic) {
  40323         get = JS_UNDEFINED;
  40324         set = value;
  40325         flags |= JS_PROP_HAS_SET;
  40326     } else {
  40327         get = value;
  40328         set = JS_UNDEFINED;
  40329         flags |= JS_PROP_HAS_GET;
  40330     }
  40331     ret = JS_DefineProperty(ctx, obj, atom, JS_UNDEFINED, get, set, flags);
  40332     JS_FreeValue(ctx, obj);
  40333     JS_FreeAtom(ctx, atom);
  40334     if (ret < 0) {
  40335         return JS_EXCEPTION;
  40336     } else {
  40337         return JS_UNDEFINED;
  40338     }
  40339 }
  40340 
  40341 static JSValue js_object_getOwnPropertyDescriptor(JSContext *ctx, JSValueConst this_val,
  40342                                                   int argc, JSValueConst *argv, int magic)
  40343 {
  40344     JSValueConst prop;
  40345     JSAtom atom;
  40346     JSValue ret, obj;
  40347     JSPropertyDescriptor desc;
  40348     int res, flags;
  40349 
  40350     if (magic) {
  40351         /* Reflect.getOwnPropertyDescriptor case */
  40352         if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT)
  40353             return JS_ThrowTypeErrorNotAnObject(ctx);
  40354         obj = JS_DupValue(ctx, argv[0]);
  40355     } else {
  40356         obj = JS_ToObject(ctx, argv[0]);
  40357         if (JS_IsException(obj))
  40358             return obj;
  40359     }
  40360     prop = argv[1];
  40361     atom = JS_ValueToAtom(ctx, prop);
  40362     if (unlikely(atom == JS_ATOM_NULL))
  40363         goto exception;
  40364     ret = JS_UNDEFINED;
  40365     if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
  40366         res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), atom);
  40367         if (res < 0)
  40368             goto exception;
  40369         if (res) {
  40370             ret = JS_NewObject(ctx);
  40371             if (JS_IsException(ret))
  40372                 goto exception1;
  40373             flags = JS_PROP_C_W_E | JS_PROP_THROW;
  40374             if (desc.flags & JS_PROP_GETSET) {
  40375                 if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, desc.getter), flags) < 0
  40376                 ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, desc.setter), flags) < 0)
  40377                     goto exception1;
  40378             } else {
  40379                 if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, desc.value), flags) < 0
  40380                 ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,
  40381                                            JS_NewBool(ctx, desc.flags & JS_PROP_WRITABLE), flags) < 0)
  40382                     goto exception1;
  40383             }
  40384             if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,
  40385                                        JS_NewBool(ctx, desc.flags & JS_PROP_ENUMERABLE), flags) < 0
  40386             ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
  40387                                        JS_NewBool(ctx, desc.flags & JS_PROP_CONFIGURABLE), flags) < 0)
  40388                 goto exception1;
  40389             js_free_desc(ctx, &desc);
  40390         }
  40391     }
  40392     JS_FreeAtom(ctx, atom);
  40393     JS_FreeValue(ctx, obj);
  40394     return ret;
  40395 
  40396 exception1:
  40397     js_free_desc(ctx, &desc);
  40398     JS_FreeValue(ctx, ret);
  40399 exception:
  40400     JS_FreeAtom(ctx, atom);
  40401     JS_FreeValue(ctx, obj);
  40402     return JS_EXCEPTION;
  40403 }
  40404 
  40405 static JSValue js_object_getOwnPropertyDescriptors(JSContext *ctx, JSValueConst this_val,
  40406                                                    int argc, JSValueConst *argv)
  40407 {
  40408     //getOwnPropertyDescriptors(obj)
  40409     JSValue obj, r;
  40410     JSObject *p;
  40411     JSPropertyEnum *props;
  40412     uint32_t len, i;
  40413 
  40414     r = JS_UNDEFINED;
  40415     obj = JS_ToObject(ctx, argv[0]);
  40416     if (JS_IsException(obj))
  40417         return JS_EXCEPTION;
  40418 
  40419     p = JS_VALUE_GET_OBJ(obj);
  40420     if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p,
  40421                                JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK))
  40422         goto exception;
  40423     r = JS_NewObject(ctx);
  40424     if (JS_IsException(r))
  40425         goto exception;
  40426     for(i = 0; i < len; i++) {
  40427         JSValue atomValue, desc;
  40428         JSValueConst args[2];
  40429 
  40430         atomValue = JS_AtomToValue(ctx, props[i].atom);
  40431         if (JS_IsException(atomValue))
  40432             goto exception;
  40433         args[0] = obj;
  40434         args[1] = atomValue;
  40435         desc = js_object_getOwnPropertyDescriptor(ctx, JS_UNDEFINED, 2, args, 0);
  40436         JS_FreeValue(ctx, atomValue);
  40437         if (JS_IsException(desc))
  40438             goto exception;
  40439         if (!JS_IsUndefined(desc)) {
  40440             if (JS_DefinePropertyValue(ctx, r, props[i].atom, desc,
  40441                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)
  40442                 goto exception;
  40443         }
  40444     }
  40445     JS_FreePropertyEnum(ctx, props, len);
  40446     JS_FreeValue(ctx, obj);
  40447     return r;
  40448 
  40449 exception:
  40450     JS_FreePropertyEnum(ctx, props, len);
  40451     JS_FreeValue(ctx, obj);
  40452     JS_FreeValue(ctx, r);
  40453     return JS_EXCEPTION;
  40454 }
  40455 
  40456 static JSValue JS_GetOwnPropertyNames2(JSContext *ctx, JSValueConst obj1,
  40457                                        int flags, int kind)
  40458 {
  40459     JSValue obj, r, val, key, value;
  40460     JSObject *p;
  40461     JSPropertyEnum *atoms;
  40462     uint32_t len, i, j;
  40463 
  40464     r = JS_UNDEFINED;
  40465     val = JS_UNDEFINED;
  40466     obj = JS_ToObject(ctx, obj1);
  40467     if (JS_IsException(obj))
  40468         return JS_EXCEPTION;
  40469     p = JS_VALUE_GET_OBJ(obj);
  40470     if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, flags & ~JS_GPN_ENUM_ONLY))
  40471         goto exception;
  40472     r = JS_NewArray(ctx);
  40473     if (JS_IsException(r))
  40474         goto exception;
  40475     for(j = i = 0; i < len; i++) {
  40476         JSAtom atom = atoms[i].atom;
  40477         if (flags & JS_GPN_ENUM_ONLY) {
  40478             JSPropertyDescriptor desc;
  40479             int res;
  40480 
  40481             /* Check if property is still enumerable */
  40482             res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
  40483             if (res < 0)
  40484                 goto exception;
  40485             if (!res)
  40486                 continue;
  40487             js_free_desc(ctx, &desc);
  40488             if (!(desc.flags & JS_PROP_ENUMERABLE))
  40489                 continue;
  40490         }
  40491         switch(kind) {
  40492         default:
  40493         case JS_ITERATOR_KIND_KEY:
  40494             val = JS_AtomToValue(ctx, atom);
  40495             if (JS_IsException(val))
  40496                 goto exception;
  40497             break;
  40498         case JS_ITERATOR_KIND_VALUE:
  40499             val = JS_GetProperty(ctx, obj, atom);
  40500             if (JS_IsException(val))
  40501                 goto exception;
  40502             break;
  40503         case JS_ITERATOR_KIND_KEY_AND_VALUE:
  40504             val = JS_NewArray(ctx);
  40505             if (JS_IsException(val))
  40506                 goto exception;
  40507             key = JS_AtomToValue(ctx, atom);
  40508             if (JS_IsException(key))
  40509                 goto exception1;
  40510             if (JS_CreateDataPropertyUint32(ctx, val, 0, key, JS_PROP_THROW) < 0)
  40511                 goto exception1;
  40512             value = JS_GetProperty(ctx, obj, atom);
  40513             if (JS_IsException(value))
  40514                 goto exception1;
  40515             if (JS_CreateDataPropertyUint32(ctx, val, 1, value, JS_PROP_THROW) < 0)
  40516                 goto exception1;
  40517             break;
  40518         }
  40519         if (JS_CreateDataPropertyUint32(ctx, r, j++, val, 0) < 0)
  40520             goto exception;
  40521     }
  40522     goto done;
  40523 
  40524 exception1:
  40525     JS_FreeValue(ctx, val);
  40526 exception:
  40527     JS_FreeValue(ctx, r);
  40528     r = JS_EXCEPTION;
  40529 done:
  40530     JS_FreePropertyEnum(ctx, atoms, len);
  40531     JS_FreeValue(ctx, obj);
  40532     return r;
  40533 }
  40534 
  40535 static JSValue js_object_getOwnPropertyNames(JSContext *ctx, JSValueConst this_val,
  40536                                              int argc, JSValueConst *argv)
  40537 {
  40538     return JS_GetOwnPropertyNames2(ctx, argv[0],
  40539                                    JS_GPN_STRING_MASK, JS_ITERATOR_KIND_KEY);
  40540 }
  40541 
  40542 static JSValue js_object_getOwnPropertySymbols(JSContext *ctx, JSValueConst this_val,
  40543                                              int argc, JSValueConst *argv)
  40544 {
  40545     return JS_GetOwnPropertyNames2(ctx, argv[0],
  40546                                    JS_GPN_SYMBOL_MASK, JS_ITERATOR_KIND_KEY);
  40547 }
  40548 
  40549 static JSValue js_object_keys(JSContext *ctx, JSValueConst this_val,
  40550                               int argc, JSValueConst *argv, int kind)
  40551 {
  40552     return JS_GetOwnPropertyNames2(ctx, argv[0],
  40553                                    JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK, kind);
  40554 }
  40555 
  40556 static JSValue js_object_isExtensible(JSContext *ctx, JSValueConst this_val,
  40557                                       int argc, JSValueConst *argv, int reflect)
  40558 {
  40559     JSValueConst obj;
  40560     int ret;
  40561 
  40562     obj = argv[0];
  40563     if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
  40564         if (reflect)
  40565             return JS_ThrowTypeErrorNotAnObject(ctx);
  40566         else
  40567             return JS_FALSE;
  40568     }
  40569     ret = JS_IsExtensible(ctx, obj);
  40570     if (ret < 0)
  40571         return JS_EXCEPTION;
  40572     else
  40573         return JS_NewBool(ctx, ret);
  40574 }
  40575 
  40576 static JSValue js_object_preventExtensions(JSContext *ctx, JSValueConst this_val,
  40577                                            int argc, JSValueConst *argv, int reflect)
  40578 {
  40579     JSValueConst obj;
  40580     int ret;
  40581 
  40582     obj = argv[0];
  40583     if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
  40584         if (reflect)
  40585             return JS_ThrowTypeErrorNotAnObject(ctx);
  40586         else
  40587             return JS_DupValue(ctx, obj);
  40588     }
  40589     ret = JS_PreventExtensions(ctx, obj);
  40590     if (ret < 0)
  40591         return JS_EXCEPTION;
  40592     if (reflect) {
  40593         return JS_NewBool(ctx, ret);
  40594     } else {
  40595         if (!ret)
  40596             return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
  40597         return JS_DupValue(ctx, obj);
  40598     }
  40599 }
  40600 
  40601 static JSValue js_object_hasOwnProperty(JSContext *ctx, JSValueConst this_val,
  40602                                         int argc, JSValueConst *argv)
  40603 {
  40604     JSValue obj;
  40605     JSAtom atom;
  40606     JSObject *p;
  40607     BOOL ret;
  40608 
  40609     atom = JS_ValueToAtom(ctx, argv[0]); /* must be done first */
  40610     if (unlikely(atom == JS_ATOM_NULL))
  40611         return JS_EXCEPTION;
  40612     obj = JS_ToObject(ctx, this_val);
  40613     if (JS_IsException(obj)) {
  40614         JS_FreeAtom(ctx, atom);
  40615         return obj;
  40616     }
  40617     p = JS_VALUE_GET_OBJ(obj);
  40618     ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);
  40619     JS_FreeAtom(ctx, atom);
  40620     JS_FreeValue(ctx, obj);
  40621     if (ret < 0)
  40622         return JS_EXCEPTION;
  40623     else
  40624         return JS_NewBool(ctx, ret);
  40625 }
  40626 
  40627 static JSValue js_object_hasOwn(JSContext *ctx, JSValueConst this_val,
  40628                                 int argc, JSValueConst *argv)
  40629 {
  40630     JSValue obj;
  40631     JSAtom atom;
  40632     JSObject *p;
  40633     BOOL ret;
  40634 
  40635     obj = JS_ToObject(ctx, argv[0]);
  40636     if (JS_IsException(obj))
  40637         return obj;
  40638     atom = JS_ValueToAtom(ctx, argv[1]);
  40639     if (unlikely(atom == JS_ATOM_NULL)) {
  40640         JS_FreeValue(ctx, obj);
  40641         return JS_EXCEPTION;
  40642     }
  40643     p = JS_VALUE_GET_OBJ(obj);
  40644     ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);
  40645     JS_FreeAtom(ctx, atom);
  40646     JS_FreeValue(ctx, obj);
  40647     if (ret < 0)
  40648         return JS_EXCEPTION;
  40649     else
  40650         return JS_NewBool(ctx, ret);
  40651 }
  40652 
  40653 static JSValue js_object_valueOf(JSContext *ctx, JSValueConst this_val,
  40654                                  int argc, JSValueConst *argv)
  40655 {
  40656     return JS_ToObject(ctx, this_val);
  40657 }
  40658 
  40659 static JSValue js_object_toString(JSContext *ctx, JSValueConst this_val,
  40660                                   int argc, JSValueConst *argv)
  40661 {
  40662     JSValue obj, tag;
  40663     int is_array;
  40664     JSAtom atom;
  40665     JSObject *p;
  40666 
  40667     if (JS_IsNull(this_val)) {
  40668         tag = js_new_string8(ctx, "Null");
  40669     } else if (JS_IsUndefined(this_val)) {
  40670         tag = js_new_string8(ctx, "Undefined");
  40671     } else {
  40672         obj = JS_ToObject(ctx, this_val);
  40673         if (JS_IsException(obj))
  40674             return obj;
  40675         is_array = JS_IsArray(ctx, obj);
  40676         if (is_array < 0) {
  40677             JS_FreeValue(ctx, obj);
  40678             return JS_EXCEPTION;
  40679         }
  40680         if (is_array) {
  40681             atom = JS_ATOM_Array;
  40682         } else if (JS_IsFunction(ctx, obj)) {
  40683             atom = JS_ATOM_Function;
  40684         } else {
  40685             p = JS_VALUE_GET_OBJ(obj);
  40686             switch(p->class_id) {
  40687             case JS_CLASS_STRING:
  40688             case JS_CLASS_ARGUMENTS:
  40689             case JS_CLASS_MAPPED_ARGUMENTS:
  40690             case JS_CLASS_ERROR:
  40691             case JS_CLASS_BOOLEAN:
  40692             case JS_CLASS_NUMBER:
  40693             case JS_CLASS_DATE:
  40694             case JS_CLASS_REGEXP:
  40695                 atom = ctx->rt->class_array[p->class_id].class_name;
  40696                 break;
  40697             default:
  40698                 atom = JS_ATOM_Object;
  40699                 break;
  40700             }
  40701         }
  40702         tag = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_toStringTag);
  40703         JS_FreeValue(ctx, obj);
  40704         if (JS_IsException(tag))
  40705             return JS_EXCEPTION;
  40706         if (!JS_IsString(tag)) {
  40707             JS_FreeValue(ctx, tag);
  40708             tag = JS_AtomToString(ctx, atom);
  40709         }
  40710     }
  40711     return JS_ConcatString3(ctx, "[object ", tag, "]");
  40712 }
  40713 
  40714 static JSValue js_object_toLocaleString(JSContext *ctx, JSValueConst this_val,
  40715                                         int argc, JSValueConst *argv)
  40716 {
  40717     return JS_Invoke(ctx, this_val, JS_ATOM_toString, 0, NULL);
  40718 }
  40719 
  40720 static JSValue js_object_assign(JSContext *ctx, JSValueConst this_val,
  40721                                 int argc, JSValueConst *argv)
  40722 {
  40723     // Object.assign(obj, source1)
  40724     JSValue obj, s;
  40725     int i;
  40726 
  40727     s = JS_UNDEFINED;
  40728     obj = JS_ToObject(ctx, argv[0]);
  40729     if (JS_IsException(obj))
  40730         goto exception;
  40731     for (i = 1; i < argc; i++) {
  40732         if (!JS_IsNull(argv[i]) && !JS_IsUndefined(argv[i])) {
  40733             s = JS_ToObject(ctx, argv[i]);
  40734             if (JS_IsException(s))
  40735                 goto exception;
  40736             if (JS_CopyDataProperties(ctx, obj, s, JS_UNDEFINED, TRUE))
  40737                 goto exception;
  40738             JS_FreeValue(ctx, s);
  40739         }
  40740     }
  40741     return obj;
  40742 exception:
  40743     JS_FreeValue(ctx, obj);
  40744     JS_FreeValue(ctx, s);
  40745     return JS_EXCEPTION;
  40746 }
  40747 
  40748 static JSValue js_object_seal(JSContext *ctx, JSValueConst this_val,
  40749                               int argc, JSValueConst *argv, int freeze_flag)
  40750 {
  40751     JSValueConst obj = argv[0];
  40752     JSObject *p;
  40753     JSPropertyEnum *props;
  40754     uint32_t len, i;
  40755     int flags, desc_flags, res;
  40756 
  40757     if (!JS_IsObject(obj))
  40758         return JS_DupValue(ctx, obj);
  40759 
  40760     res = JS_PreventExtensions(ctx, obj);
  40761     if (res < 0)
  40762         return JS_EXCEPTION;
  40763     if (!res) {
  40764         return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
  40765     }
  40766 
  40767     p = JS_VALUE_GET_OBJ(obj);
  40768     flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK;
  40769     if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags))
  40770         return JS_EXCEPTION;
  40771 
  40772     for(i = 0; i < len; i++) {
  40773         JSPropertyDescriptor desc;
  40774         JSAtom prop = props[i].atom;
  40775 
  40776         desc_flags = JS_PROP_THROW | JS_PROP_HAS_CONFIGURABLE;
  40777         if (freeze_flag) {
  40778             res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
  40779             if (res < 0)
  40780                 goto exception;
  40781             if (res) {
  40782                 if (desc.flags & JS_PROP_WRITABLE)
  40783                     desc_flags |= JS_PROP_HAS_WRITABLE;
  40784                 js_free_desc(ctx, &desc);
  40785             }
  40786         }
  40787         if (JS_DefineProperty(ctx, obj, prop, JS_UNDEFINED,
  40788                               JS_UNDEFINED, JS_UNDEFINED, desc_flags) < 0)
  40789             goto exception;
  40790     }
  40791     JS_FreePropertyEnum(ctx, props, len);
  40792     return JS_DupValue(ctx, obj);
  40793 
  40794  exception:
  40795     JS_FreePropertyEnum(ctx, props, len);
  40796     return JS_EXCEPTION;
  40797 }
  40798 
  40799 static JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val,
  40800                                   int argc, JSValueConst *argv, int is_frozen)
  40801 {
  40802     JSValueConst obj = argv[0];
  40803     JSObject *p;
  40804     JSPropertyEnum *props;
  40805     uint32_t len, i;
  40806     int flags, res;
  40807 
  40808     if (!JS_IsObject(obj))
  40809         return JS_TRUE;
  40810 
  40811     p = JS_VALUE_GET_OBJ(obj);
  40812     flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK;
  40813     if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags))
  40814         return JS_EXCEPTION;
  40815 
  40816     for(i = 0; i < len; i++) {
  40817         JSPropertyDescriptor desc;
  40818         JSAtom prop = props[i].atom;
  40819 
  40820         res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
  40821         if (res < 0)
  40822             goto exception;
  40823         if (res) {
  40824             js_free_desc(ctx, &desc);
  40825             if ((desc.flags & JS_PROP_CONFIGURABLE)
  40826             ||  (is_frozen && (desc.flags & JS_PROP_WRITABLE))) {
  40827                 res = FALSE;
  40828                 goto done;
  40829             }
  40830         }
  40831     }
  40832     res = JS_IsExtensible(ctx, obj);
  40833     if (res < 0)
  40834         return JS_EXCEPTION;
  40835     res ^= 1;
  40836 done:
  40837     JS_FreePropertyEnum(ctx, props, len);
  40838     return JS_NewBool(ctx, res);
  40839 
  40840 exception:
  40841     JS_FreePropertyEnum(ctx, props, len);
  40842     return JS_EXCEPTION;
  40843 }
  40844 
  40845 static JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val,
  40846                                      int argc, JSValueConst *argv)
  40847 {
  40848     JSValue obj, iter, next_method = JS_UNDEFINED;
  40849     JSValueConst iterable;
  40850     BOOL done;
  40851 
  40852     /*  RequireObjectCoercible() not necessary because it is tested in
  40853         JS_GetIterator() by JS_GetProperty() */
  40854     iterable = argv[0];
  40855 
  40856     obj = JS_NewObject(ctx);
  40857     if (JS_IsException(obj))
  40858         return obj;
  40859 
  40860     iter = JS_GetIterator(ctx, iterable, FALSE);
  40861     if (JS_IsException(iter))
  40862         goto fail;
  40863     next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
  40864     if (JS_IsException(next_method))
  40865         goto fail;
  40866 
  40867     for(;;) {
  40868         JSValue key, value, item;
  40869         item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
  40870         if (JS_IsException(item))
  40871             goto fail;
  40872         if (done)
  40873             break;
  40874 
  40875         key = JS_UNDEFINED;
  40876         value = JS_UNDEFINED;
  40877         if (!JS_IsObject(item)) {
  40878             JS_ThrowTypeErrorNotAnObject(ctx);
  40879             goto fail1;
  40880         }
  40881         key = JS_GetPropertyUint32(ctx, item, 0);
  40882         if (JS_IsException(key))
  40883             goto fail1;
  40884         value = JS_GetPropertyUint32(ctx, item, 1);
  40885         if (JS_IsException(value)) {
  40886             JS_FreeValue(ctx, key);
  40887             goto fail1;
  40888         }
  40889         if (JS_DefinePropertyValueValue(ctx, obj, key, value,
  40890                                         JS_PROP_C_W_E | JS_PROP_THROW) < 0) {
  40891         fail1:
  40892             JS_FreeValue(ctx, item);
  40893             goto fail;
  40894         }
  40895         JS_FreeValue(ctx, item);
  40896     }
  40897     JS_FreeValue(ctx, next_method);
  40898     JS_FreeValue(ctx, iter);
  40899     return obj;
  40900  fail:
  40901     if (JS_IsObject(iter)) {
  40902         /* close the iterator object, preserving pending exception */
  40903         JS_IteratorClose(ctx, iter, TRUE);
  40904     }
  40905     JS_FreeValue(ctx, next_method);
  40906     JS_FreeValue(ctx, iter);
  40907     JS_FreeValue(ctx, obj);
  40908     return JS_EXCEPTION;
  40909 }
  40910 
  40911 static JSValue js_object_is(JSContext *ctx, JSValueConst this_val,
  40912                             int argc, JSValueConst *argv)
  40913 {
  40914     return JS_NewBool(ctx, js_same_value(ctx, argv[0], argv[1]));
  40915 }
  40916 
  40917 static JSValue JS_SpeciesConstructor(JSContext *ctx, JSValueConst obj,
  40918                                      JSValueConst defaultConstructor)
  40919 {
  40920     JSValue ctor, species;
  40921 
  40922     if (!JS_IsObject(obj))
  40923         return JS_ThrowTypeErrorNotAnObject(ctx);
  40924     ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);
  40925     if (JS_IsException(ctor))
  40926         return ctor;
  40927     if (JS_IsUndefined(ctor))
  40928         return JS_DupValue(ctx, defaultConstructor);
  40929     if (!JS_IsObject(ctor)) {
  40930         JS_FreeValue(ctx, ctor);
  40931         return JS_ThrowTypeErrorNotAnObject(ctx);
  40932     }
  40933     species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species);
  40934     JS_FreeValue(ctx, ctor);
  40935     if (JS_IsException(species))
  40936         return species;
  40937     if (JS_IsUndefined(species) || JS_IsNull(species))
  40938         return JS_DupValue(ctx, defaultConstructor);
  40939     if (!JS_IsConstructor(ctx, species)) {
  40940         JS_ThrowTypeErrorNotAConstructor(ctx, species);
  40941         JS_FreeValue(ctx, species);
  40942         return JS_EXCEPTION;
  40943     }
  40944     return species;
  40945 }
  40946 
  40947 static JSValue js_object_get___proto__(JSContext *ctx, JSValueConst this_val)
  40948 {
  40949     JSValue val, ret;
  40950 
  40951     val = JS_ToObject(ctx, this_val);
  40952     if (JS_IsException(val))
  40953         return val;
  40954     ret = JS_GetPrototype(ctx, val);
  40955     JS_FreeValue(ctx, val);
  40956     return ret;
  40957 }
  40958 
  40959 static JSValue js_object_set___proto__(JSContext *ctx, JSValueConst this_val,
  40960                                        JSValueConst proto)
  40961 {
  40962     if (JS_IsUndefined(this_val) || JS_IsNull(this_val))
  40963         return JS_ThrowTypeErrorNotAnObject(ctx);
  40964     if (!JS_IsObject(proto) && !JS_IsNull(proto))
  40965         return JS_UNDEFINED;
  40966     if (JS_SetPrototypeInternal(ctx, this_val, proto, TRUE) < 0)
  40967         return JS_EXCEPTION;
  40968     else
  40969         return JS_UNDEFINED;
  40970 }
  40971 
  40972 static JSValue js_object_isPrototypeOf(JSContext *ctx, JSValueConst this_val,
  40973                                        int argc, JSValueConst *argv)
  40974 {
  40975     JSValue obj, v1;
  40976     JSValueConst v;
  40977     int res;
  40978 
  40979     v = argv[0];
  40980     if (!JS_IsObject(v))
  40981         return JS_FALSE;
  40982     obj = JS_ToObject(ctx, this_val);
  40983     if (JS_IsException(obj))
  40984         return JS_EXCEPTION;
  40985     v1 = JS_DupValue(ctx, v);
  40986     for(;;) {
  40987         v1 = JS_GetPrototypeFree(ctx, v1);
  40988         if (JS_IsException(v1))
  40989             goto exception;
  40990         if (JS_IsNull(v1)) {
  40991             res = FALSE;
  40992             break;
  40993         }
  40994         if (JS_VALUE_GET_OBJ(obj) == JS_VALUE_GET_OBJ(v1)) {
  40995             res = TRUE;
  40996             break;
  40997         }
  40998         /* avoid infinite loop (possible with proxies) */
  40999         if (js_poll_interrupts(ctx))
  41000             goto exception;
  41001     }
  41002     JS_FreeValue(ctx, v1);
  41003     JS_FreeValue(ctx, obj);
  41004     return JS_NewBool(ctx, res);
  41005 
  41006 exception:
  41007     JS_FreeValue(ctx, v1);
  41008     JS_FreeValue(ctx, obj);
  41009     return JS_EXCEPTION;
  41010 }
  41011 
  41012 static JSValue js_object_propertyIsEnumerable(JSContext *ctx, JSValueConst this_val,
  41013                                               int argc, JSValueConst *argv)
  41014 {
  41015     JSValue obj = JS_UNDEFINED, res = JS_EXCEPTION;
  41016     JSAtom prop;
  41017     JSPropertyDescriptor desc;
  41018     int has_prop;
  41019 
  41020     prop = JS_ValueToAtom(ctx, argv[0]);
  41021     if (unlikely(prop == JS_ATOM_NULL))
  41022         goto exception;
  41023     obj = JS_ToObject(ctx, this_val);
  41024     if (JS_IsException(obj))
  41025         goto exception;
  41026 
  41027     has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);
  41028     if (has_prop < 0)
  41029         goto exception;
  41030     if (has_prop) {
  41031         res = JS_NewBool(ctx, desc.flags & JS_PROP_ENUMERABLE);
  41032         js_free_desc(ctx, &desc);
  41033     } else {
  41034         res = JS_FALSE;
  41035     }
  41036 
  41037 exception:
  41038     JS_FreeAtom(ctx, prop);
  41039     JS_FreeValue(ctx, obj);
  41040     return res;
  41041 }
  41042 
  41043 static JSValue js_object___lookupGetter__(JSContext *ctx, JSValueConst this_val,
  41044                                           int argc, JSValueConst *argv, int setter)
  41045 {
  41046     JSValue obj, res = JS_EXCEPTION;
  41047     JSAtom prop = JS_ATOM_NULL;
  41048     JSPropertyDescriptor desc;
  41049     int has_prop;
  41050 
  41051     obj = JS_ToObject(ctx, this_val);
  41052     if (JS_IsException(obj))
  41053         goto exception;
  41054     prop = JS_ValueToAtom(ctx, argv[0]);
  41055     if (unlikely(prop == JS_ATOM_NULL))
  41056         goto exception;
  41057 
  41058     for (;;) {
  41059         has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);
  41060         if (has_prop < 0)
  41061             goto exception;
  41062         if (has_prop) {
  41063             if (desc.flags & JS_PROP_GETSET)
  41064                 res = JS_DupValue(ctx, setter ? desc.setter : desc.getter);
  41065             else
  41066                 res = JS_UNDEFINED;
  41067             js_free_desc(ctx, &desc);
  41068             break;
  41069         }
  41070         obj = JS_GetPrototypeFree(ctx, obj);
  41071         if (JS_IsException(obj))
  41072             goto exception;
  41073         if (JS_IsNull(obj)) {
  41074             res = JS_UNDEFINED;
  41075             break;
  41076         }
  41077         /* avoid infinite loop (possible with proxies) */
  41078         if (js_poll_interrupts(ctx))
  41079             goto exception;
  41080     }
  41081 
  41082 exception:
  41083     JS_FreeAtom(ctx, prop);
  41084     JS_FreeValue(ctx, obj);
  41085     return res;
  41086 }
  41087 
  41088 static const JSCFunctionListEntry js_object_funcs[] = {
  41089     JS_CFUNC_DEF("create", 2, js_object_create ),
  41090     JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 0 ),
  41091     JS_CFUNC_DEF("setPrototypeOf", 2, js_object_setPrototypeOf ),
  41092     JS_CFUNC_MAGIC_DEF("defineProperty", 3, js_object_defineProperty, 0 ),
  41093     JS_CFUNC_DEF("defineProperties", 2, js_object_defineProperties ),
  41094     JS_CFUNC_DEF("getOwnPropertyNames", 1, js_object_getOwnPropertyNames ),
  41095     JS_CFUNC_DEF("getOwnPropertySymbols", 1, js_object_getOwnPropertySymbols ),
  41096     JS_CFUNC_MAGIC_DEF("groupBy", 2, js_object_groupBy, 0 ),
  41097     JS_CFUNC_MAGIC_DEF("keys", 1, js_object_keys, JS_ITERATOR_KIND_KEY ),
  41098     JS_CFUNC_MAGIC_DEF("values", 1, js_object_keys, JS_ITERATOR_KIND_VALUE ),
  41099     JS_CFUNC_MAGIC_DEF("entries", 1, js_object_keys, JS_ITERATOR_KIND_KEY_AND_VALUE ),
  41100     JS_CFUNC_MAGIC_DEF("isExtensible", 1, js_object_isExtensible, 0 ),
  41101     JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 0 ),
  41102     JS_CFUNC_MAGIC_DEF("getOwnPropertyDescriptor", 2, js_object_getOwnPropertyDescriptor, 0 ),
  41103     JS_CFUNC_DEF("getOwnPropertyDescriptors", 1, js_object_getOwnPropertyDescriptors ),
  41104     JS_CFUNC_DEF("is", 2, js_object_is ),
  41105     JS_CFUNC_DEF("assign", 2, js_object_assign ),
  41106     JS_CFUNC_MAGIC_DEF("seal", 1, js_object_seal, 0 ),
  41107     JS_CFUNC_MAGIC_DEF("freeze", 1, js_object_seal, 1 ),
  41108     JS_CFUNC_MAGIC_DEF("isSealed", 1, js_object_isSealed, 0 ),
  41109     JS_CFUNC_MAGIC_DEF("isFrozen", 1, js_object_isSealed, 1 ),
  41110     JS_CFUNC_DEF("fromEntries", 1, js_object_fromEntries ),
  41111     JS_CFUNC_DEF("hasOwn", 2, js_object_hasOwn ),
  41112 };
  41113 
  41114 static const JSCFunctionListEntry js_object_proto_funcs[] = {
  41115     JS_CFUNC_DEF("toString", 0, js_object_toString ),
  41116     JS_CFUNC_DEF("toLocaleString", 0, js_object_toLocaleString ),
  41117     JS_CFUNC_DEF("valueOf", 0, js_object_valueOf ),
  41118     JS_CFUNC_DEF("hasOwnProperty", 1, js_object_hasOwnProperty ),
  41119     JS_CFUNC_DEF("isPrototypeOf", 1, js_object_isPrototypeOf ),
  41120     JS_CFUNC_DEF("propertyIsEnumerable", 1, js_object_propertyIsEnumerable ),
  41121     JS_CGETSET_DEF("__proto__", js_object_get___proto__, js_object_set___proto__ ),
  41122     JS_CFUNC_MAGIC_DEF("__defineGetter__", 2, js_object___defineGetter__, 0 ),
  41123     JS_CFUNC_MAGIC_DEF("__defineSetter__", 2, js_object___defineGetter__, 1 ),
  41124     JS_CFUNC_MAGIC_DEF("__lookupGetter__", 1, js_object___lookupGetter__, 0 ),
  41125     JS_CFUNC_MAGIC_DEF("__lookupSetter__", 1, js_object___lookupGetter__, 1 ),
  41126 };
  41127 
  41128 /* Function class */
  41129 
  41130 static JSValue js_function_proto(JSContext *ctx, JSValueConst this_val,
  41131                                  int argc, JSValueConst *argv)
  41132 {
  41133     return JS_UNDEFINED;
  41134 }
  41135 
  41136 /* XXX: add a specific eval mode so that Function("}), ({") is rejected */
  41137 static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target,
  41138                                        int argc, JSValueConst *argv, int magic)
  41139 {
  41140     JSFunctionKindEnum func_kind = magic;
  41141     int i, n, ret;
  41142     JSValue s, proto, obj = JS_UNDEFINED;
  41143     StringBuffer b_s, *b = &b_s;
  41144 
  41145     string_buffer_init(ctx, b, 0);
  41146     string_buffer_putc8(b, '(');
  41147 
  41148     if (func_kind == JS_FUNC_ASYNC || func_kind == JS_FUNC_ASYNC_GENERATOR) {
  41149         string_buffer_puts8(b, "async ");
  41150     }
  41151     string_buffer_puts8(b, "function");
  41152 
  41153     if (func_kind == JS_FUNC_GENERATOR || func_kind == JS_FUNC_ASYNC_GENERATOR) {
  41154         string_buffer_putc8(b, '*');
  41155     }
  41156     string_buffer_puts8(b, " anonymous(");
  41157 
  41158     n = argc - 1;
  41159     for(i = 0; i < n; i++) {
  41160         if (i != 0) {
  41161             string_buffer_putc8(b, ',');
  41162         }
  41163         if (string_buffer_concat_value(b, argv[i]))
  41164             goto fail;
  41165     }
  41166     string_buffer_puts8(b, "\n) {\n");
  41167     if (n >= 0) {
  41168         if (string_buffer_concat_value(b, argv[n]))
  41169             goto fail;
  41170     }
  41171     string_buffer_puts8(b, "\n})");
  41172     s = string_buffer_end(b);
  41173     if (JS_IsException(s))
  41174         goto fail1;
  41175 
  41176     obj = JS_EvalObject(ctx, ctx->global_obj, s, JS_EVAL_TYPE_INDIRECT, -1);
  41177     JS_FreeValue(ctx, s);
  41178     if (JS_IsException(obj))
  41179         goto fail1;
  41180     if (!JS_IsUndefined(new_target)) {
  41181         /* set the prototype */
  41182         proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);
  41183         if (JS_IsException(proto))
  41184             goto fail1;
  41185         if (!JS_IsObject(proto)) {
  41186             JSContext *realm;
  41187             JS_FreeValue(ctx, proto);
  41188             realm = JS_GetFunctionRealm(ctx, new_target);
  41189             if (!realm)
  41190                 goto fail1;
  41191             proto = JS_DupValue(ctx, realm->class_proto[func_kind_to_class_id[func_kind]]);
  41192         }
  41193         ret = JS_SetPrototypeInternal(ctx, obj, proto, TRUE);
  41194         JS_FreeValue(ctx, proto);
  41195         if (ret < 0)
  41196             goto fail1;
  41197     }
  41198     return obj;
  41199 
  41200  fail:
  41201     string_buffer_free(b);
  41202  fail1:
  41203     JS_FreeValue(ctx, obj);
  41204     return JS_EXCEPTION;
  41205 }
  41206 
  41207 static __exception int js_get_length32(JSContext *ctx, uint32_t *pres,
  41208                                        JSValueConst obj)
  41209 {
  41210     JSValue len_val;
  41211     len_val = JS_GetProperty(ctx, obj, JS_ATOM_length);
  41212     if (JS_IsException(len_val)) {
  41213         *pres = 0;
  41214         return -1;
  41215     }
  41216     return JS_ToUint32Free(ctx, pres, len_val);
  41217 }
  41218 
  41219 static __exception int js_get_length64(JSContext *ctx, int64_t *pres,
  41220                                        JSValueConst obj)
  41221 {
  41222     JSValue len_val;
  41223     len_val = JS_GetProperty(ctx, obj, JS_ATOM_length);
  41224     if (JS_IsException(len_val)) {
  41225         *pres = 0;
  41226         return -1;
  41227     }
  41228     return JS_ToLengthFree(ctx, pres, len_val);
  41229 }
  41230 
  41231 static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len)
  41232 {
  41233     uint32_t i;
  41234     for(i = 0; i < len; i++) {
  41235         JS_FreeValue(ctx, tab[i]);
  41236     }
  41237     js_free(ctx, tab);
  41238 }
  41239 
  41240 /* XXX: should use ValueArray */
  41241 static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
  41242                                JSValueConst array_arg)
  41243 {
  41244     uint32_t len, i;
  41245     int64_t len64;
  41246     JSValue *tab, ret;
  41247     JSObject *p;
  41248 
  41249     if (JS_VALUE_GET_TAG(array_arg) != JS_TAG_OBJECT) {
  41250         JS_ThrowTypeError(ctx, "not a object");
  41251         return NULL;
  41252     }
  41253     if (js_get_length64(ctx, &len64, array_arg))
  41254         return NULL;
  41255     if (len64 > JS_MAX_LOCAL_VARS) {
  41256         // XXX: check for stack overflow?
  41257         JS_ThrowRangeError(ctx, "too many arguments in function call (only %d allowed)",
  41258                            JS_MAX_LOCAL_VARS);
  41259         return NULL;
  41260     }
  41261     len = len64;
  41262     /* avoid allocating 0 bytes */
  41263     tab = js_mallocz(ctx, sizeof(tab[0]) * max_uint32(1, len));
  41264     if (!tab)
  41265         return NULL;
  41266     p = JS_VALUE_GET_OBJ(array_arg);
  41267     if ((p->class_id == JS_CLASS_ARRAY || p->class_id == JS_CLASS_ARGUMENTS || p->class_id == JS_CLASS_MAPPED_ARGUMENTS) &&
  41268         p->fast_array &&
  41269         len == p->u.array.count) {
  41270         if (p->class_id == JS_CLASS_MAPPED_ARGUMENTS) {
  41271             for(i = 0; i < len; i++) {
  41272                 tab[i] = JS_DupValue(ctx, *p->u.array.u.var_refs[i]->pvalue);
  41273             }
  41274         } else {
  41275             for(i = 0; i < len; i++) {
  41276                 tab[i] = JS_DupValue(ctx, p->u.array.u.values[i]);
  41277             }
  41278         }
  41279     } else {
  41280         for(i = 0; i < len; i++) {
  41281             ret = JS_GetPropertyUint32(ctx, array_arg, i);
  41282             if (JS_IsException(ret)) {
  41283                 free_arg_list(ctx, tab, i);
  41284                 return NULL;
  41285             }
  41286             tab[i] = ret;
  41287         }
  41288     }
  41289     *plen = len;
  41290     return tab;
  41291 }
  41292 
  41293 /* magic value: 0 = normal apply, 1 = apply for constructor, 2 =
  41294    Reflect.apply */
  41295 static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
  41296                                  int argc, JSValueConst *argv, int magic)
  41297 {
  41298     JSValueConst this_arg, array_arg;
  41299     uint32_t len;
  41300     JSValue *tab, ret;
  41301 
  41302     if (check_function(ctx, this_val))
  41303         return JS_EXCEPTION;
  41304     this_arg = argv[0];
  41305     array_arg = argv[1];
  41306     if ((JS_VALUE_GET_TAG(array_arg) == JS_TAG_UNDEFINED ||
  41307          JS_VALUE_GET_TAG(array_arg) == JS_TAG_NULL) && magic != 2) {
  41308         return JS_Call(ctx, this_val, this_arg, 0, NULL);
  41309     }
  41310     tab = build_arg_list(ctx, &len, array_arg);
  41311     if (!tab)
  41312         return JS_EXCEPTION;
  41313     if (magic & 1) {
  41314         ret = JS_CallConstructor2(ctx, this_val, this_arg, len, (JSValueConst *)tab);
  41315     } else {
  41316         ret = JS_Call(ctx, this_val, this_arg, len, (JSValueConst *)tab);
  41317     }
  41318     free_arg_list(ctx, tab, len);
  41319     return ret;
  41320 }
  41321 
  41322 static JSValue js_function_call(JSContext *ctx, JSValueConst this_val,
  41323                                 int argc, JSValueConst *argv)
  41324 {
  41325     if (argc <= 0) {
  41326         return JS_Call(ctx, this_val, JS_UNDEFINED, 0, NULL);
  41327     } else {
  41328         return JS_Call(ctx, this_val, argv[0], argc - 1, argv + 1);
  41329     }
  41330 }
  41331 
  41332 static JSValue js_function_bind(JSContext *ctx, JSValueConst this_val,
  41333                                 int argc, JSValueConst *argv)
  41334 {
  41335     JSBoundFunction *bf;
  41336     JSValue func_obj, name1, len_val;
  41337     JSObject *p;
  41338     int arg_count, i, ret;
  41339 
  41340     if (check_function(ctx, this_val))
  41341         return JS_EXCEPTION;
  41342 
  41343     func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
  41344                                  JS_CLASS_BOUND_FUNCTION);
  41345     if (JS_IsException(func_obj))
  41346         return JS_EXCEPTION;
  41347     p = JS_VALUE_GET_OBJ(func_obj);
  41348     p->is_constructor = JS_IsConstructor(ctx, this_val);
  41349     arg_count = max_int(0, argc - 1);
  41350     bf = js_malloc(ctx, sizeof(*bf) + arg_count * sizeof(JSValue));
  41351     if (!bf)
  41352         goto exception;
  41353     bf->func_obj = JS_DupValue(ctx, this_val);
  41354     bf->this_val = JS_DupValue(ctx, argv[0]);
  41355     bf->argc = arg_count;
  41356     for(i = 0; i < arg_count; i++) {
  41357         bf->argv[i] = JS_DupValue(ctx, argv[i + 1]);
  41358     }
  41359     p->u.bound_function = bf;
  41360 
  41361     /* XXX: the spec could be simpler by only using GetOwnProperty */
  41362     ret = JS_GetOwnProperty(ctx, NULL, this_val, JS_ATOM_length);
  41363     if (ret < 0)
  41364         goto exception;
  41365     if (!ret) {
  41366         len_val = JS_NewInt32(ctx, 0);
  41367     } else {
  41368         len_val = JS_GetProperty(ctx, this_val, JS_ATOM_length);
  41369         if (JS_IsException(len_val))
  41370             goto exception;
  41371         if (JS_VALUE_GET_TAG(len_val) == JS_TAG_INT) {
  41372             /* most common case */
  41373             int len1 = JS_VALUE_GET_INT(len_val);
  41374             if (len1 <= arg_count)
  41375                 len1 = 0;
  41376             else
  41377                 len1 -= arg_count;
  41378             len_val = JS_NewInt32(ctx, len1);
  41379         } else if (JS_VALUE_GET_NORM_TAG(len_val) == JS_TAG_FLOAT64) {
  41380             double d = JS_VALUE_GET_FLOAT64(len_val);
  41381             if (isnan(d)) {
  41382                 d = 0.0;
  41383             } else {
  41384                 d = trunc(d);
  41385                 if (d <= (double)arg_count)
  41386                     d = 0.0;
  41387                 else
  41388                     d -= (double)arg_count; /* also converts -0 to +0 */
  41389             }
  41390             len_val = JS_NewFloat64(ctx, d);
  41391         } else {
  41392             JS_FreeValue(ctx, len_val);
  41393             len_val = JS_NewInt32(ctx, 0);
  41394         }
  41395     }
  41396     JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length,
  41397                            len_val, JS_PROP_CONFIGURABLE);
  41398 
  41399     name1 = JS_GetProperty(ctx, this_val, JS_ATOM_name);
  41400     if (JS_IsException(name1))
  41401         goto exception;
  41402     if (!JS_IsString(name1)) {
  41403         JS_FreeValue(ctx, name1);
  41404         name1 = JS_AtomToString(ctx, JS_ATOM_empty_string);
  41405     }
  41406     name1 = JS_ConcatString3(ctx, "bound ", name1, "");
  41407     if (JS_IsException(name1))
  41408         goto exception;
  41409     JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name1,
  41410                            JS_PROP_CONFIGURABLE);
  41411     return func_obj;
  41412  exception:
  41413     JS_FreeValue(ctx, func_obj);
  41414     return JS_EXCEPTION;
  41415 }
  41416 
  41417 static JSValue js_function_toString(JSContext *ctx, JSValueConst this_val,
  41418                                     int argc, JSValueConst *argv)
  41419 {
  41420     JSObject *p;
  41421     JSFunctionKindEnum func_kind = JS_FUNC_NORMAL;
  41422 
  41423     if (check_function(ctx, this_val))
  41424         return JS_EXCEPTION;
  41425 
  41426     p = JS_VALUE_GET_OBJ(this_val);
  41427     if (js_class_has_bytecode(p->class_id)) {
  41428         JSFunctionBytecode *b = p->u.func.function_bytecode;
  41429         if (b->has_debug && b->debug.source) {
  41430             return JS_NewStringLen(ctx, b->debug.source, b->debug.source_len);
  41431         }
  41432         func_kind = b->func_kind;
  41433     }
  41434     {
  41435         JSValue name;
  41436         const char *pref, *suff;
  41437 
  41438         switch(func_kind) {
  41439         default:
  41440         case JS_FUNC_NORMAL:
  41441             pref = "function ";
  41442             break;
  41443         case JS_FUNC_GENERATOR:
  41444             pref = "function *";
  41445             break;
  41446         case JS_FUNC_ASYNC:
  41447             pref = "async function ";
  41448             break;
  41449         case JS_FUNC_ASYNC_GENERATOR:
  41450             pref = "async function *";
  41451             break;
  41452         }
  41453         suff = "() {\n    [native code]\n}";
  41454         name = JS_GetProperty(ctx, this_val, JS_ATOM_name);
  41455         if (JS_IsUndefined(name))
  41456             name = JS_AtomToString(ctx, JS_ATOM_empty_string);
  41457         return JS_ConcatString3(ctx, pref, name, suff);
  41458     }
  41459 }
  41460 
  41461 static JSValue js_function_hasInstance(JSContext *ctx, JSValueConst this_val,
  41462                                        int argc, JSValueConst *argv)
  41463 {
  41464     int ret;
  41465     ret = JS_OrdinaryIsInstanceOf(ctx, argv[0], this_val);
  41466     if (ret < 0)
  41467         return JS_EXCEPTION;
  41468     else
  41469         return JS_NewBool(ctx, ret);
  41470 }
  41471 
  41472 static const JSCFunctionListEntry js_function_proto_funcs[] = {
  41473     JS_CFUNC_DEF("call", 1, js_function_call ),
  41474     JS_CFUNC_MAGIC_DEF("apply", 2, js_function_apply, 0 ),
  41475     JS_CFUNC_DEF("bind", 1, js_function_bind ),
  41476     JS_CFUNC_DEF("toString", 0, js_function_toString ),
  41477     JS_CFUNC_DEF("[Symbol.hasInstance]", 1, js_function_hasInstance ),
  41478     JS_CGETSET_DEF("fileName", js_function_proto_fileName, NULL ),
  41479     JS_CGETSET_MAGIC_DEF("lineNumber", js_function_proto_lineNumber, NULL, 0 ),
  41480     JS_CGETSET_MAGIC_DEF("columnNumber", js_function_proto_lineNumber, NULL, 1 ),
  41481 };
  41482 
  41483 /* Error class */
  41484 
  41485 static JSValue iterator_to_array(JSContext *ctx, JSValueConst items)
  41486 {
  41487     JSValue iter, next_method = JS_UNDEFINED;
  41488     JSValue v, r = JS_UNDEFINED;
  41489     int64_t k;
  41490     BOOL done;
  41491 
  41492     iter = JS_GetIterator(ctx, items, FALSE);
  41493     if (JS_IsException(iter))
  41494         goto exception;
  41495     next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
  41496     if (JS_IsException(next_method))
  41497         goto exception;
  41498     r = JS_NewArray(ctx);
  41499     if (JS_IsException(r))
  41500         goto exception;
  41501     for (k = 0;; k++) {
  41502         v = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
  41503         if (JS_IsException(v))
  41504             goto exception_close;
  41505         if (done)
  41506             break;
  41507         if (JS_DefinePropertyValueInt64(ctx, r, k, v,
  41508                                         JS_PROP_C_W_E | JS_PROP_THROW) < 0)
  41509             goto exception_close;
  41510     }
  41511  done:
  41512     JS_FreeValue(ctx, next_method);
  41513     JS_FreeValue(ctx, iter);
  41514     return r;
  41515  exception_close:
  41516     JS_IteratorClose(ctx, iter, TRUE);
  41517  exception:
  41518     JS_FreeValue(ctx, r);
  41519     r = JS_EXCEPTION;
  41520     goto done;
  41521 }
  41522 
  41523 static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target,
  41524                                     int argc, JSValueConst *argv, int magic)
  41525 {
  41526     JSValue obj, msg, proto;
  41527     JSValueConst message, options;
  41528     int arg_index;
  41529 
  41530     if (JS_IsUndefined(new_target))
  41531         new_target = JS_GetActiveFunction(ctx);
  41532     proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);
  41533     if (JS_IsException(proto))
  41534         return proto;
  41535     if (!JS_IsObject(proto)) {
  41536         JSContext *realm;
  41537         JSValueConst proto1;
  41538 
  41539         JS_FreeValue(ctx, proto);
  41540         realm = JS_GetFunctionRealm(ctx, new_target);
  41541         if (!realm)
  41542             return JS_EXCEPTION;
  41543         if (magic < 0) {
  41544             proto1 = realm->class_proto[JS_CLASS_ERROR];
  41545         } else {
  41546             proto1 = realm->native_error_proto[magic];
  41547         }
  41548         proto = JS_DupValue(ctx, proto1);
  41549     }
  41550     obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_ERROR);
  41551     JS_FreeValue(ctx, proto);
  41552     if (JS_IsException(obj))
  41553         return obj;
  41554     arg_index = (magic == JS_AGGREGATE_ERROR);
  41555 
  41556     message = argv[arg_index++];
  41557     if (!JS_IsUndefined(message)) {
  41558         msg = JS_ToString(ctx, message);
  41559         if (unlikely(JS_IsException(msg)))
  41560             goto exception;
  41561         JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, msg,
  41562                                JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
  41563     }
  41564 
  41565     if (arg_index < argc) {
  41566         options = argv[arg_index];
  41567         if (JS_IsObject(options)) {
  41568             int present = JS_HasProperty(ctx, options, JS_ATOM_cause);
  41569             if (present < 0)
  41570                 goto exception;
  41571             if (present) {
  41572                 JSValue cause = JS_GetProperty(ctx, options, JS_ATOM_cause);
  41573                 if (JS_IsException(cause))
  41574                     goto exception;
  41575                 JS_DefinePropertyValue(ctx, obj, JS_ATOM_cause, cause,
  41576                                        JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
  41577             }
  41578         }
  41579     }
  41580 
  41581     if (magic == JS_AGGREGATE_ERROR) {
  41582         JSValue error_list = iterator_to_array(ctx, argv[0]);
  41583         if (JS_IsException(error_list))
  41584             goto exception;
  41585         JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, error_list,
  41586                                JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
  41587     }
  41588 
  41589     /* skip the Error() function in the backtrace */
  41590     build_backtrace(ctx, obj, NULL, 0, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL);
  41591     return obj;
  41592  exception:
  41593     JS_FreeValue(ctx, obj);
  41594     return JS_EXCEPTION;
  41595 }
  41596 
  41597 static JSValue js_error_toString(JSContext *ctx, JSValueConst this_val,
  41598                                  int argc, JSValueConst *argv)
  41599 {
  41600     JSValue name, msg;
  41601 
  41602     if (!JS_IsObject(this_val))
  41603         return JS_ThrowTypeErrorNotAnObject(ctx);
  41604     name = JS_GetProperty(ctx, this_val, JS_ATOM_name);
  41605     if (JS_IsUndefined(name))
  41606         name = JS_AtomToString(ctx, JS_ATOM_Error);
  41607     else
  41608         name = JS_ToStringFree(ctx, name);
  41609     if (JS_IsException(name))
  41610         return JS_EXCEPTION;
  41611 
  41612     msg = JS_GetProperty(ctx, this_val, JS_ATOM_message);
  41613     if (JS_IsUndefined(msg))
  41614         msg = JS_AtomToString(ctx, JS_ATOM_empty_string);
  41615     else
  41616         msg = JS_ToStringFree(ctx, msg);
  41617     if (JS_IsException(msg)) {
  41618         JS_FreeValue(ctx, name);
  41619         return JS_EXCEPTION;
  41620     }
  41621     if (!JS_IsEmptyString(name) && !JS_IsEmptyString(msg))
  41622         name = JS_ConcatString3(ctx, "", name, ": ");
  41623     return JS_ConcatString(ctx, name, msg);
  41624 }
  41625 
  41626 static const JSCFunctionListEntry js_error_proto_funcs[] = {
  41627     JS_CFUNC_DEF("toString", 0, js_error_toString ),
  41628     JS_PROP_STRING_DEF("name", "Error", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
  41629     JS_PROP_STRING_DEF("message", "", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
  41630 };
  41631 
  41632 /* 2 entries for each native error class */
  41633 /* Note: we use an atom to avoid the autoinit definition which does
  41634    not work in get_prop_string() */
  41635 static const JSCFunctionListEntry js_native_error_proto_funcs[] = {
  41636 #define DEF(name) \
  41637     JS_PROP_ATOM_DEF("name", name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),\
  41638     JS_PROP_STRING_DEF("message", "", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
  41639     
  41640     DEF(JS_ATOM_EvalError)
  41641     DEF(JS_ATOM_RangeError)
  41642     DEF(JS_ATOM_ReferenceError)
  41643     DEF(JS_ATOM_SyntaxError)
  41644     DEF(JS_ATOM_TypeError)
  41645     DEF(JS_ATOM_URIError)
  41646     DEF(JS_ATOM_InternalError)
  41647     DEF(JS_ATOM_AggregateError)
  41648 #undef DEF    
  41649 };
  41650 
  41651 static JSValue js_error_isError(JSContext *ctx, JSValueConst this_val,
  41652                                 int argc, JSValueConst *argv)
  41653 {
  41654     return JS_NewBool(ctx, JS_IsError(ctx, argv[0]));
  41655 }
  41656 
  41657 static const JSCFunctionListEntry js_error_funcs[] = {
  41658     JS_CFUNC_DEF("isError", 1, js_error_isError),
  41659 };
  41660 
  41661 /* AggregateError */
  41662 
  41663 /* used by C code. */
  41664 static JSValue js_aggregate_error_constructor(JSContext *ctx,
  41665                                               JSValueConst errors)
  41666 {
  41667     JSValue obj;
  41668 
  41669     obj = JS_NewObjectProtoClass(ctx,
  41670                                  ctx->native_error_proto[JS_AGGREGATE_ERROR],
  41671                                  JS_CLASS_ERROR);
  41672     if (JS_IsException(obj))
  41673         return obj;
  41674     JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, JS_DupValue(ctx, errors),
  41675                            JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
  41676     return obj;
  41677 }
  41678 
  41679 /* Array */
  41680 
  41681 static int JS_CopySubArray(JSContext *ctx,
  41682                            JSValueConst obj, int64_t to_pos,
  41683                            int64_t from_pos, int64_t count, int dir)
  41684 {
  41685     JSObject *p;
  41686     int64_t i, from, to, len;
  41687     JSValue val;
  41688     int fromPresent;
  41689 
  41690     p = NULL;
  41691     if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
  41692         p = JS_VALUE_GET_OBJ(obj);
  41693         if (p->class_id != JS_CLASS_ARRAY || !p->fast_array) {
  41694             p = NULL;
  41695         }
  41696     }
  41697 
  41698     for (i = 0; i < count; ) {
  41699         if (dir < 0) {
  41700             from = from_pos + count - i - 1;
  41701             to = to_pos + count - i - 1;
  41702         } else {
  41703             from = from_pos + i;
  41704             to = to_pos + i;
  41705         }
  41706         if (p && p->fast_array &&
  41707             from >= 0 && from < (len = p->u.array.count)  &&
  41708             to >= 0 && to < len) {
  41709             int64_t l, j;
  41710             /* Fast path for fast arrays. Since we don't look at the
  41711                prototype chain, we can optimize only the cases where
  41712                all the elements are present in the array. */
  41713             l = count - i;
  41714             if (dir < 0) {
  41715                 l = min_int64(l, from + 1);
  41716                 l = min_int64(l, to + 1);
  41717                 for(j = 0; j < l; j++) {
  41718                     set_value(ctx, &p->u.array.u.values[to - j],
  41719                               JS_DupValue(ctx, p->u.array.u.values[from - j]));
  41720                 }
  41721             } else {
  41722                 l = min_int64(l, len - from);
  41723                 l = min_int64(l, len - to);
  41724                 for(j = 0; j < l; j++) {
  41725                     set_value(ctx, &p->u.array.u.values[to + j],
  41726                               JS_DupValue(ctx, p->u.array.u.values[from + j]));
  41727                 }
  41728             }
  41729             i += l;
  41730         } else {
  41731             fromPresent = JS_TryGetPropertyInt64(ctx, obj, from, &val);
  41732             if (fromPresent < 0)
  41733                 goto exception;
  41734 
  41735             if (fromPresent) {
  41736                 if (JS_SetPropertyInt64(ctx, obj, to, val) < 0)
  41737                     goto exception;
  41738             } else {
  41739                 if (JS_DeletePropertyInt64(ctx, obj, to, JS_PROP_THROW) < 0)
  41740                     goto exception;
  41741             }
  41742             i++;
  41743         }
  41744     }
  41745     return 0;
  41746 
  41747  exception:
  41748     return -1;
  41749 }
  41750 
  41751 static JSValue js_array_constructor(JSContext *ctx, JSValueConst new_target,
  41752                                     int argc, JSValueConst *argv)
  41753 {
  41754     JSValue obj;
  41755     int i;
  41756 
  41757     obj = js_create_from_ctor(ctx, new_target, JS_CLASS_ARRAY);
  41758     if (JS_IsException(obj))
  41759         return obj;
  41760     if (argc == 1 && JS_IsNumber(argv[0])) {
  41761         uint32_t len;
  41762         if (JS_ToArrayLengthFree(ctx, &len, JS_DupValue(ctx, argv[0]), TRUE))
  41763             goto fail;
  41764         if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, len)) < 0)
  41765             goto fail;
  41766     } else {
  41767         for(i = 0; i < argc; i++) {
  41768             if (JS_SetPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i])) < 0)
  41769                 goto fail;
  41770         }
  41771     }
  41772     return obj;
  41773 fail:
  41774     JS_FreeValue(ctx, obj);
  41775     return JS_EXCEPTION;
  41776 }
  41777 
  41778 static JSValue js_array_from(JSContext *ctx, JSValueConst this_val,
  41779                              int argc, JSValueConst *argv)
  41780 {
  41781     // from(items, mapfn = void 0, this_arg = void 0)
  41782     JSValueConst items = argv[0], mapfn, this_arg;
  41783     JSValueConst args[2];
  41784     JSValue iter, r, v, v2, arrayLike, next_method, enum_obj;
  41785     int64_t k, len;
  41786     int done, mapping;
  41787 
  41788     mapping = FALSE;
  41789     mapfn = JS_UNDEFINED;
  41790     this_arg = JS_UNDEFINED;
  41791     r = JS_UNDEFINED;
  41792     arrayLike = JS_UNDEFINED;
  41793     iter = JS_UNDEFINED;
  41794     enum_obj = JS_UNDEFINED;
  41795     next_method = JS_UNDEFINED;
  41796 
  41797     if (argc > 1) {
  41798         mapfn = argv[1];
  41799         if (!JS_IsUndefined(mapfn)) {
  41800             if (check_function(ctx, mapfn))
  41801                 goto exception;
  41802             mapping = 1;
  41803             if (argc > 2)
  41804                 this_arg = argv[2];
  41805         }
  41806     }
  41807     iter = JS_GetProperty(ctx, items, JS_ATOM_Symbol_iterator);
  41808     if (JS_IsException(iter))
  41809         goto exception;
  41810     if (!JS_IsUndefined(iter) && !JS_IsNull(iter)) {
  41811         if (!JS_IsFunction(ctx, iter)) {
  41812             JS_ThrowTypeError(ctx, "value is not iterable");
  41813             goto exception;
  41814         }
  41815         if (JS_IsConstructor(ctx, this_val))
  41816             r = JS_CallConstructor(ctx, this_val, 0, NULL);
  41817         else
  41818             r = JS_NewArray(ctx);
  41819         if (JS_IsException(r))
  41820             goto exception;
  41821         enum_obj = JS_GetIterator2(ctx, items, iter);
  41822         if (JS_IsException(enum_obj))
  41823             goto exception;
  41824         next_method = JS_GetProperty(ctx, enum_obj, JS_ATOM_next);
  41825         if (JS_IsException(next_method))
  41826             goto exception;
  41827         for (k = 0;; k++) {
  41828             v = JS_IteratorNext(ctx, enum_obj, next_method, 0, NULL, &done);
  41829             if (JS_IsException(v))
  41830                 goto exception;
  41831             if (done)
  41832                 break;
  41833             if (mapping) {
  41834                 args[0] = v;
  41835                 args[1] = JS_NewInt32(ctx, k);
  41836                 v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
  41837                 JS_FreeValue(ctx, v);
  41838                 v = v2;
  41839                 if (JS_IsException(v))
  41840                     goto exception_close;
  41841             }
  41842             if (JS_DefinePropertyValueInt64(ctx, r, k, v,
  41843                                             JS_PROP_C_W_E | JS_PROP_THROW) < 0)
  41844                 goto exception_close;
  41845         }
  41846     } else {
  41847         arrayLike = JS_ToObject(ctx, items);
  41848         if (JS_IsException(arrayLike))
  41849             goto exception;
  41850         if (js_get_length64(ctx, &len, arrayLike) < 0)
  41851             goto exception;
  41852         v = JS_NewInt64(ctx, len);
  41853         args[0] = v;
  41854         if (JS_IsConstructor(ctx, this_val)) {
  41855             r = JS_CallConstructor(ctx, this_val, 1, args);
  41856         } else {
  41857             r = js_array_constructor(ctx, JS_UNDEFINED, 1, args);
  41858         }
  41859         JS_FreeValue(ctx, v);
  41860         if (JS_IsException(r))
  41861             goto exception;
  41862         for(k = 0; k < len; k++) {
  41863             v = JS_GetPropertyInt64(ctx, arrayLike, k);
  41864             if (JS_IsException(v))
  41865                 goto exception;
  41866             if (mapping) {
  41867                 args[0] = v;
  41868                 args[1] = JS_NewInt32(ctx, k);
  41869                 v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
  41870                 JS_FreeValue(ctx, v);
  41871                 v = v2;
  41872                 if (JS_IsException(v))
  41873                     goto exception;
  41874             }
  41875             if (JS_DefinePropertyValueInt64(ctx, r, k, v,
  41876                                             JS_PROP_C_W_E | JS_PROP_THROW) < 0)
  41877                 goto exception;
  41878         }
  41879     }
  41880     if (JS_SetProperty(ctx, r, JS_ATOM_length, JS_NewUint32(ctx, k)) < 0)
  41881         goto exception;
  41882     goto done;
  41883 
  41884  exception_close:
  41885     JS_IteratorClose(ctx, enum_obj, TRUE);
  41886  exception:
  41887     JS_FreeValue(ctx, r);
  41888     r = JS_EXCEPTION;
  41889  done:
  41890     JS_FreeValue(ctx, arrayLike);
  41891     JS_FreeValue(ctx, iter);
  41892     JS_FreeValue(ctx, enum_obj);
  41893     JS_FreeValue(ctx, next_method);
  41894     return r;
  41895 }
  41896 
  41897 static JSValue js_array_of(JSContext *ctx, JSValueConst this_val,
  41898                            int argc, JSValueConst *argv)
  41899 {
  41900     JSValue obj, args[1];
  41901     int i;
  41902 
  41903     if (JS_IsConstructor(ctx, this_val)) {
  41904         args[0] = JS_NewInt32(ctx, argc);
  41905         obj = JS_CallConstructor(ctx, this_val, 1, (JSValueConst *)args);
  41906     } else {
  41907         obj = JS_NewArray(ctx);
  41908     }
  41909     if (JS_IsException(obj))
  41910         return JS_EXCEPTION;
  41911     for(i = 0; i < argc; i++) {
  41912         if (JS_CreateDataPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i]),
  41913                                         JS_PROP_THROW) < 0) {
  41914             goto fail;
  41915         }
  41916     }
  41917     if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, argc)) < 0) {
  41918     fail:
  41919         JS_FreeValue(ctx, obj);
  41920         return JS_EXCEPTION;
  41921     }
  41922     return obj;
  41923 }
  41924 
  41925 static JSValue js_array_isArray(JSContext *ctx, JSValueConst this_val,
  41926                                 int argc, JSValueConst *argv)
  41927 {
  41928     int ret;
  41929     ret = JS_IsArray(ctx, argv[0]);
  41930     if (ret < 0)
  41931         return JS_EXCEPTION;
  41932     else
  41933         return JS_NewBool(ctx, ret);
  41934 }
  41935 
  41936 static JSValue js_get_this(JSContext *ctx,
  41937                            JSValueConst this_val)
  41938 {
  41939     return JS_DupValue(ctx, this_val);
  41940 }
  41941 
  41942 static JSValue JS_ArraySpeciesCreate(JSContext *ctx, JSValueConst obj,
  41943                                      JSValueConst len_val)
  41944 {
  41945     JSValue ctor, ret, species;
  41946     int res;
  41947     JSContext *realm;
  41948 
  41949     res = JS_IsArray(ctx, obj);
  41950     if (res < 0)
  41951         return JS_EXCEPTION;
  41952     if (!res)
  41953         return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);
  41954     ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);
  41955     if (JS_IsException(ctor))
  41956         return ctor;
  41957     if (JS_IsConstructor(ctx, ctor)) {
  41958         /* legacy web compatibility */
  41959         realm = JS_GetFunctionRealm(ctx, ctor);
  41960         if (!realm) {
  41961             JS_FreeValue(ctx, ctor);
  41962             return JS_EXCEPTION;
  41963         }
  41964         if (realm != ctx &&
  41965             js_same_value(ctx, ctor, realm->array_ctor)) {
  41966             JS_FreeValue(ctx, ctor);
  41967             ctor = JS_UNDEFINED;
  41968         }
  41969     }
  41970     if (JS_IsObject(ctor)) {
  41971         species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species);
  41972         JS_FreeValue(ctx, ctor);
  41973         if (JS_IsException(species))
  41974             return species;
  41975         ctor = species;
  41976         if (JS_IsNull(ctor))
  41977             ctor = JS_UNDEFINED;
  41978     }
  41979     if (JS_IsUndefined(ctor)) {
  41980         return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);
  41981     } else {
  41982         ret = JS_CallConstructor(ctx, ctor, 1, &len_val);
  41983         JS_FreeValue(ctx, ctor);
  41984         return ret;
  41985     }
  41986 }
  41987 
  41988 static const JSCFunctionListEntry js_array_funcs[] = {
  41989     JS_CFUNC_DEF("isArray", 1, js_array_isArray ),
  41990     JS_CFUNC_DEF("from", 1, js_array_from ),
  41991     JS_CFUNC_DEF("of", 0, js_array_of ),
  41992     JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
  41993 };
  41994 
  41995 static int JS_isConcatSpreadable(JSContext *ctx, JSValueConst obj)
  41996 {
  41997     JSValue val;
  41998 
  41999     if (!JS_IsObject(obj))
  42000         return FALSE;
  42001     val = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_isConcatSpreadable);
  42002     if (JS_IsException(val))
  42003         return -1;
  42004     if (!JS_IsUndefined(val))
  42005         return JS_ToBoolFree(ctx, val);
  42006     return JS_IsArray(ctx, obj);
  42007 }
  42008 
  42009 static JSValue js_array_at(JSContext *ctx, JSValueConst this_val,
  42010                            int argc, JSValueConst *argv)
  42011 {
  42012     JSValue obj, ret;
  42013     int64_t len, idx;
  42014     JSValue *arrp;
  42015     uint32_t count;
  42016 
  42017     obj = JS_ToObject(ctx, this_val);
  42018     if (js_get_length64(ctx, &len, obj))
  42019         goto exception;
  42020 
  42021     if (JS_ToInt64Sat(ctx, &idx, argv[0]))
  42022         goto exception;
  42023 
  42024     if (idx < 0)
  42025         idx = len + idx;
  42026     if (idx < 0 || idx >= len) {
  42027         ret = JS_UNDEFINED;
  42028     } else if (js_get_fast_array(ctx, obj, &arrp, &count) && idx < count) {
  42029         ret = JS_DupValue(ctx, arrp[idx]);
  42030     } else {
  42031         int present = JS_TryGetPropertyInt64(ctx, obj, idx, &ret);
  42032         if (present < 0)
  42033             goto exception;
  42034         if (!present)
  42035             ret = JS_UNDEFINED;
  42036     }
  42037     JS_FreeValue(ctx, obj);
  42038     return ret;
  42039  exception:
  42040     JS_FreeValue(ctx, obj);
  42041     return JS_EXCEPTION;
  42042 }
  42043 
  42044 static JSValue js_array_with(JSContext *ctx, JSValueConst this_val,
  42045                              int argc, JSValueConst *argv)
  42046 {
  42047     JSValue arr, obj, ret, *arrp, *pval;
  42048     JSObject *p;
  42049     int64_t i, len, idx;
  42050     uint32_t count32;
  42051 
  42052     ret = JS_EXCEPTION;
  42053     arr = JS_UNDEFINED;
  42054     obj = JS_ToObject(ctx, this_val);
  42055     if (js_get_length64(ctx, &len, obj))
  42056         goto exception;
  42057 
  42058     if (JS_ToInt64Sat(ctx, &idx, argv[0]))
  42059         goto exception;
  42060 
  42061     if (idx < 0)
  42062         idx = len + idx;
  42063 
  42064     if (idx < 0 || idx >= len) {
  42065         JS_ThrowRangeError(ctx, "invalid array index: %" PRId64, idx);
  42066         goto exception;
  42067     }
  42068 
  42069     arr = js_allocate_fast_array(ctx, len);
  42070     if (JS_IsException(arr))
  42071         goto exception;
  42072 
  42073     p = JS_VALUE_GET_OBJ(arr);
  42074     i = 0;
  42075     pval = p->u.array.u.values;
  42076     if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
  42077         for (; i < idx; i++, pval++)
  42078             *pval = JS_DupValue(ctx, arrp[i]);
  42079         *pval = JS_DupValue(ctx, argv[1]);
  42080         for (i++, pval++; i < len; i++, pval++)
  42081             *pval = JS_DupValue(ctx, arrp[i]);
  42082     } else {
  42083         for (; i < idx; i++, pval++)
  42084             if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
  42085                 goto exception;
  42086         *pval = JS_DupValue(ctx, argv[1]);
  42087         for (i++, pval++; i < len; i++, pval++) {
  42088             if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
  42089                 goto exception;
  42090         }
  42091     }
  42092 
  42093     ret = arr;
  42094     arr = JS_UNDEFINED;
  42095 
  42096 exception:
  42097     JS_FreeValue(ctx, arr);
  42098     JS_FreeValue(ctx, obj);
  42099     return ret;
  42100 }
  42101 
  42102 static JSValue js_array_concat(JSContext *ctx, JSValueConst this_val,
  42103                                int argc, JSValueConst *argv)
  42104 {
  42105     JSValue obj, arr, val;
  42106     JSValueConst e;
  42107     int64_t len, k, n;
  42108     int i, res;
  42109 
  42110     arr = JS_UNDEFINED;
  42111     obj = JS_ToObject(ctx, this_val);
  42112     if (JS_IsException(obj))
  42113         goto exception;
  42114 
  42115     arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
  42116     if (JS_IsException(arr))
  42117         goto exception;
  42118     n = 0;
  42119     for (i = -1; i < argc; i++) {
  42120         if (i < 0)
  42121             e = obj;
  42122         else
  42123             e = argv[i];
  42124 
  42125         res = JS_isConcatSpreadable(ctx, e);
  42126         if (res < 0)
  42127             goto exception;
  42128         if (res) {
  42129             if (js_get_length64(ctx, &len, e))
  42130                 goto exception;
  42131             if (n + len > MAX_SAFE_INTEGER) {
  42132                 JS_ThrowTypeError(ctx, "Array loo long");
  42133                 goto exception;
  42134             }
  42135             for (k = 0; k < len; k++, n++) {
  42136                 res = JS_TryGetPropertyInt64(ctx, e, k, &val);
  42137                 if (res < 0)
  42138                     goto exception;
  42139                 if (res) {
  42140                     if (JS_DefinePropertyValueInt64(ctx, arr, n, val,
  42141                                                     JS_PROP_C_W_E | JS_PROP_THROW) < 0)
  42142                         goto exception;
  42143                 }
  42144             }
  42145         } else {
  42146             if (n >= MAX_SAFE_INTEGER) {
  42147                 JS_ThrowTypeError(ctx, "Array loo long");
  42148                 goto exception;
  42149             }
  42150             if (JS_DefinePropertyValueInt64(ctx, arr, n, JS_DupValue(ctx, e),
  42151                                             JS_PROP_C_W_E | JS_PROP_THROW) < 0)
  42152                 goto exception;
  42153             n++;
  42154         }
  42155     }
  42156     if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0)
  42157         goto exception;
  42158 
  42159     JS_FreeValue(ctx, obj);
  42160     return arr;
  42161 
  42162 exception:
  42163     JS_FreeValue(ctx, arr);
  42164     JS_FreeValue(ctx, obj);
  42165     return JS_EXCEPTION;
  42166 }
  42167 
  42168 #define special_every    0
  42169 #define special_some     1
  42170 #define special_forEach  2
  42171 #define special_map      3
  42172 #define special_filter   4
  42173 #define special_TA       8
  42174 
  42175 static JSValue js_typed_array___speciesCreate(JSContext *ctx,
  42176                                               JSValueConst this_val,
  42177                                               int argc, JSValueConst *argv);
  42178 
  42179 static JSValue js_array_every(JSContext *ctx, JSValueConst this_val,
  42180                               int argc, JSValueConst *argv, int special)
  42181 {
  42182     JSValue obj, val, index_val, res, ret;
  42183     JSValueConst args[3];
  42184     JSValueConst func, this_arg;
  42185     int64_t len, k, n;
  42186     int present;
  42187 
  42188     ret = JS_UNDEFINED;
  42189     val = JS_UNDEFINED;
  42190     if (special & special_TA) {
  42191         obj = JS_DupValue(ctx, this_val);
  42192         len = js_typed_array_get_length_unsafe(ctx, obj);
  42193         if (len < 0)
  42194             goto exception;
  42195     } else {
  42196         obj = JS_ToObject(ctx, this_val);
  42197         if (js_get_length64(ctx, &len, obj))
  42198             goto exception;
  42199     }
  42200     func = argv[0];
  42201     this_arg = JS_UNDEFINED;
  42202     if (argc > 1)
  42203         this_arg = argv[1];
  42204 
  42205     if (check_function(ctx, func))
  42206         goto exception;
  42207 
  42208     switch (special) {
  42209     case special_every:
  42210     case special_every | special_TA:
  42211         ret = JS_TRUE;
  42212         break;
  42213     case special_some:
  42214     case special_some | special_TA:
  42215         ret = JS_FALSE;
  42216         break;
  42217     case special_map:
  42218         /* XXX: JS_ArraySpeciesCreate should take int64_t */
  42219         ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt64(ctx, len));
  42220         if (JS_IsException(ret))
  42221             goto exception;
  42222         break;
  42223     case special_filter:
  42224         ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
  42225         if (JS_IsException(ret))
  42226             goto exception;
  42227         break;
  42228     case special_map | special_TA:
  42229         args[0] = obj;
  42230         args[1] = JS_NewInt32(ctx, len);
  42231         ret = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
  42232         if (JS_IsException(ret))
  42233             goto exception;
  42234         break;
  42235     case special_filter | special_TA:
  42236         ret = JS_NewArray(ctx);
  42237         if (JS_IsException(ret))
  42238             goto exception;
  42239         break;
  42240     }
  42241     n = 0;
  42242 
  42243     for(k = 0; k < len; k++) {
  42244         if (special & special_TA) {
  42245             val = JS_GetPropertyInt64(ctx, obj, k);
  42246             if (JS_IsException(val))
  42247                 goto exception;
  42248             present = TRUE;
  42249         } else {
  42250             present = JS_TryGetPropertyInt64(ctx, obj, k, &val);
  42251             if (present < 0)
  42252                 goto exception;
  42253         }
  42254         if (present) {
  42255             index_val = JS_NewInt64(ctx, k);
  42256             if (JS_IsException(index_val))
  42257                 goto exception;
  42258             args[0] = val;
  42259             args[1] = index_val;
  42260             args[2] = obj;
  42261             res = JS_Call(ctx, func, this_arg, 3, args);
  42262             JS_FreeValue(ctx, index_val);
  42263             if (JS_IsException(res))
  42264                 goto exception;
  42265             switch (special) {
  42266             case special_every:
  42267             case special_every | special_TA:
  42268                 if (!JS_ToBoolFree(ctx, res)) {
  42269                     ret = JS_FALSE;
  42270                     goto done;
  42271                 }
  42272                 break;
  42273             case special_some:
  42274             case special_some | special_TA:
  42275                 if (JS_ToBoolFree(ctx, res)) {
  42276                     ret = JS_TRUE;
  42277                     goto done;
  42278                 }
  42279                 break;
  42280             case special_map:
  42281                 if (JS_DefinePropertyValueInt64(ctx, ret, k, res,
  42282                                                 JS_PROP_C_W_E | JS_PROP_THROW) < 0)
  42283                     goto exception;
  42284                 break;
  42285             case special_map | special_TA:
  42286                 if (JS_SetPropertyValue(ctx, ret, JS_NewInt32(ctx, k), res, JS_PROP_THROW) < 0)
  42287                     goto exception;
  42288                 break;
  42289             case special_filter:
  42290             case special_filter | special_TA:
  42291                 if (JS_ToBoolFree(ctx, res)) {
  42292                     if (JS_DefinePropertyValueInt64(ctx, ret, n++, JS_DupValue(ctx, val),
  42293                                                     JS_PROP_C_W_E | JS_PROP_THROW) < 0)
  42294                         goto exception;
  42295                 }
  42296                 break;
  42297             default:
  42298                 JS_FreeValue(ctx, res);
  42299                 break;
  42300             }
  42301             JS_FreeValue(ctx, val);
  42302             val = JS_UNDEFINED;
  42303         }
  42304     }
  42305 done:
  42306     if (special == (special_filter | special_TA)) {
  42307         JSValue arr;
  42308         args[0] = obj;
  42309         args[1] = JS_NewInt32(ctx, n);
  42310         arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
  42311         if (JS_IsException(arr))
  42312             goto exception;
  42313         args[0] = ret;
  42314         res = JS_Invoke(ctx, arr, JS_ATOM_set, 1, args);
  42315         if (check_exception_free(ctx, res)) {
  42316             JS_FreeValue(ctx, arr);
  42317             goto exception;
  42318         }
  42319         JS_FreeValue(ctx, ret);
  42320         ret = arr;
  42321     }
  42322     JS_FreeValue(ctx, val);
  42323     JS_FreeValue(ctx, obj);
  42324     return ret;
  42325 
  42326 exception:
  42327     JS_FreeValue(ctx, ret);
  42328     JS_FreeValue(ctx, val);
  42329     JS_FreeValue(ctx, obj);
  42330     return JS_EXCEPTION;
  42331 }
  42332 
  42333 #define special_reduce       0
  42334 #define special_reduceRight  1
  42335 
  42336 static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val,
  42337                                int argc, JSValueConst *argv, int special)
  42338 {
  42339     JSValue obj, val, index_val, acc, acc1;
  42340     JSValueConst args[4];
  42341     JSValueConst func;
  42342     int64_t len, k, k1;
  42343     int present;
  42344 
  42345     acc = JS_UNDEFINED;
  42346     val = JS_UNDEFINED;
  42347     if (special & special_TA) {
  42348         obj = JS_DupValue(ctx, this_val);
  42349         len = js_typed_array_get_length_unsafe(ctx, obj);
  42350         if (len < 0)
  42351             goto exception;
  42352     } else {
  42353         obj = JS_ToObject(ctx, this_val);
  42354         if (js_get_length64(ctx, &len, obj))
  42355             goto exception;
  42356     }
  42357     func = argv[0];
  42358 
  42359     if (check_function(ctx, func))
  42360         goto exception;
  42361 
  42362     k = 0;
  42363     if (argc > 1) {
  42364         acc = JS_DupValue(ctx, argv[1]);
  42365     } else {
  42366         for(;;) {
  42367             if (k >= len) {
  42368                 JS_ThrowTypeError(ctx, "empty array");
  42369                 goto exception;
  42370             }
  42371             k1 = (special & special_reduceRight) ? len - k - 1 : k;
  42372             k++;
  42373             if (special & special_TA) {
  42374                 acc = JS_GetPropertyInt64(ctx, obj, k1);
  42375                 if (JS_IsException(acc))
  42376                     goto exception;
  42377                 break;
  42378             } else {
  42379                 present = JS_TryGetPropertyInt64(ctx, obj, k1, &acc);
  42380                 if (present < 0)
  42381                     goto exception;
  42382                 if (present)
  42383                     break;
  42384             }
  42385         }
  42386     }
  42387     for (; k < len; k++) {
  42388         k1 = (special & special_reduceRight) ? len - k - 1 : k;
  42389         if (special & special_TA) {
  42390             val = JS_GetPropertyInt64(ctx, obj, k1);
  42391             if (JS_IsException(val))
  42392                 goto exception;
  42393             present = TRUE;
  42394         } else {
  42395             present = JS_TryGetPropertyInt64(ctx, obj, k1, &val);
  42396             if (present < 0)
  42397                 goto exception;
  42398         }
  42399         if (present) {
  42400             index_val = JS_NewInt64(ctx, k1);
  42401             if (JS_IsException(index_val))
  42402                 goto exception;
  42403             args[0] = acc;
  42404             args[1] = val;
  42405             args[2] = index_val;
  42406             args[3] = obj;
  42407             acc1 = JS_Call(ctx, func, JS_UNDEFINED, 4, args);
  42408             JS_FreeValue(ctx, index_val);
  42409             JS_FreeValue(ctx, val);
  42410             val = JS_UNDEFINED;
  42411             if (JS_IsException(acc1))
  42412                 goto exception;
  42413             JS_FreeValue(ctx, acc);
  42414             acc = acc1;
  42415         }
  42416     }
  42417     JS_FreeValue(ctx, obj);
  42418     return acc;
  42419 
  42420 exception:
  42421     JS_FreeValue(ctx, acc);
  42422     JS_FreeValue(ctx, val);
  42423     JS_FreeValue(ctx, obj);
  42424     return JS_EXCEPTION;
  42425 }
  42426 
  42427 static JSValue js_array_fill(JSContext *ctx, JSValueConst this_val,
  42428                              int argc, JSValueConst *argv)
  42429 {
  42430     JSValue obj;
  42431     int64_t len, start, end;
  42432 
  42433     obj = JS_ToObject(ctx, this_val);
  42434     if (js_get_length64(ctx, &len, obj))
  42435         goto exception;
  42436 
  42437     start = 0;
  42438     if (argc > 1 && !JS_IsUndefined(argv[1])) {
  42439         if (JS_ToInt64Clamp(ctx, &start, argv[1], 0, len, len))
  42440             goto exception;
  42441     }
  42442 
  42443     end = len;
  42444     if (argc > 2 && !JS_IsUndefined(argv[2])) {
  42445         if (JS_ToInt64Clamp(ctx, &end, argv[2], 0, len, len))
  42446             goto exception;
  42447     }
  42448 
  42449     /* XXX: should special case fast arrays */
  42450     while (start < end) {
  42451         if (JS_SetPropertyInt64(ctx, obj, start,
  42452                                 JS_DupValue(ctx, argv[0])) < 0)
  42453             goto exception;
  42454         start++;
  42455     }
  42456     return obj;
  42457 
  42458  exception:
  42459     JS_FreeValue(ctx, obj);
  42460     return JS_EXCEPTION;
  42461 }
  42462 
  42463 static JSValue js_array_includes(JSContext *ctx, JSValueConst this_val,
  42464                                  int argc, JSValueConst *argv)
  42465 {
  42466     JSValue obj, val;
  42467     int64_t len, n;
  42468     JSValue *arrp;
  42469     uint32_t count;
  42470     int res;
  42471 
  42472     obj = JS_ToObject(ctx, this_val);
  42473     if (js_get_length64(ctx, &len, obj))
  42474         goto exception;
  42475 
  42476     res = FALSE;
  42477     if (len > 0) {
  42478         n = 0;
  42479         if (argc > 1) {
  42480             if (JS_ToInt64Clamp(ctx, &n, argv[1], 0, len, len))
  42481                 goto exception;
  42482         }
  42483         if (js_get_fast_array(ctx, obj, &arrp, &count)) {
  42484             for (; n < count; n++) {
  42485                 if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]),
  42486                                   JS_DupValue(ctx, arrp[n]),
  42487                                   JS_EQ_SAME_VALUE_ZERO)) {
  42488                     res = TRUE;
  42489                     goto done;
  42490                 }
  42491             }
  42492         }
  42493         for (; n < len; n++) {
  42494             val = JS_GetPropertyInt64(ctx, obj, n);
  42495             if (JS_IsException(val))
  42496                 goto exception;
  42497             if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val,
  42498                               JS_EQ_SAME_VALUE_ZERO)) {
  42499                 res = TRUE;
  42500                 break;
  42501             }
  42502         }
  42503     }
  42504  done:
  42505     JS_FreeValue(ctx, obj);
  42506     return JS_NewBool(ctx, res);
  42507 
  42508  exception:
  42509     JS_FreeValue(ctx, obj);
  42510     return JS_EXCEPTION;
  42511 }
  42512 
  42513 static JSValue js_array_indexOf(JSContext *ctx, JSValueConst this_val,
  42514                                 int argc, JSValueConst *argv)
  42515 {
  42516     JSValue obj, val;
  42517     int64_t len, n, res;
  42518     JSValue *arrp;
  42519     uint32_t count;
  42520 
  42521     obj = JS_ToObject(ctx, this_val);
  42522     if (js_get_length64(ctx, &len, obj))
  42523         goto exception;
  42524 
  42525     res = -1;
  42526     if (len > 0) {
  42527         n = 0;
  42528         if (argc > 1) {
  42529             if (JS_ToInt64Clamp(ctx, &n, argv[1], 0, len, len))
  42530                 goto exception;
  42531         }
  42532         if (js_get_fast_array(ctx, obj, &arrp, &count)) {
  42533             for (; n < count; n++) {
  42534                 if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]),
  42535                                   JS_DupValue(ctx, arrp[n]), JS_EQ_STRICT)) {
  42536                     res = n;
  42537                     goto done;
  42538                 }
  42539             }
  42540         }
  42541         for (; n < len; n++) {
  42542             int present = JS_TryGetPropertyInt64(ctx, obj, n, &val);
  42543             if (present < 0)
  42544                 goto exception;
  42545             if (present) {
  42546                 if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_STRICT)) {
  42547                     res = n;
  42548                     break;
  42549                 }
  42550             }
  42551         }
  42552     }
  42553  done:
  42554     JS_FreeValue(ctx, obj);
  42555     return JS_NewInt64(ctx, res);
  42556 
  42557  exception:
  42558     JS_FreeValue(ctx, obj);
  42559     return JS_EXCEPTION;
  42560 }
  42561 
  42562 static JSValue js_array_lastIndexOf(JSContext *ctx, JSValueConst this_val,
  42563                                     int argc, JSValueConst *argv)
  42564 {
  42565     JSValue obj, val;
  42566     int64_t len, n, res;
  42567     int present;
  42568 
  42569     obj = JS_ToObject(ctx, this_val);
  42570     if (js_get_length64(ctx, &len, obj))
  42571         goto exception;
  42572 
  42573     res = -1;
  42574     if (len > 0) {
  42575         n = len - 1;
  42576         if (argc > 1) {
  42577             if (JS_ToInt64Clamp(ctx, &n, argv[1], -1, len - 1, len))
  42578                 goto exception;
  42579         }
  42580         /* XXX: should special case fast arrays */
  42581         for (; n >= 0; n--) {
  42582             present = JS_TryGetPropertyInt64(ctx, obj, n, &val);
  42583             if (present < 0)
  42584                 goto exception;
  42585             if (present) {
  42586                 if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_STRICT)) {
  42587                     res = n;
  42588                     break;
  42589                 }
  42590             }
  42591         }
  42592     }
  42593     JS_FreeValue(ctx, obj);
  42594     return JS_NewInt64(ctx, res);
  42595 
  42596  exception:
  42597     JS_FreeValue(ctx, obj);
  42598     return JS_EXCEPTION;
  42599 }
  42600 
  42601 enum {
  42602     ArrayFind,
  42603     ArrayFindIndex,
  42604     ArrayFindLast,
  42605     ArrayFindLastIndex,
  42606 };
  42607 
  42608 static JSValue js_array_find(JSContext *ctx, JSValueConst this_val,
  42609                              int argc, JSValueConst *argv, int mode)
  42610 {
  42611     JSValueConst func, this_arg;
  42612     JSValueConst args[3];
  42613     JSValue obj, val, index_val, res;
  42614     int64_t len, k, end;
  42615     int dir;
  42616 
  42617     index_val = JS_UNDEFINED;
  42618     val = JS_UNDEFINED;
  42619     obj = JS_ToObject(ctx, this_val);
  42620     if (js_get_length64(ctx, &len, obj))
  42621         goto exception;
  42622 
  42623     func = argv[0];
  42624     if (check_function(ctx, func))
  42625         goto exception;
  42626 
  42627     this_arg = JS_UNDEFINED;
  42628     if (argc > 1)
  42629         this_arg = argv[1];
  42630 
  42631     k = 0;
  42632     dir = 1;
  42633     end = len;
  42634     if (mode == ArrayFindLast || mode == ArrayFindLastIndex) {
  42635         k = len - 1;
  42636         dir = -1;
  42637         end = -1;
  42638     }
  42639 
  42640     // TODO(bnoordhuis) add fast path for fast arrays
  42641     for(; k != end; k += dir) {
  42642         index_val = JS_NewInt64(ctx, k);
  42643         if (JS_IsException(index_val))
  42644             goto exception;
  42645         val = JS_GetPropertyValue(ctx, obj, index_val);
  42646         if (JS_IsException(val))
  42647             goto exception;
  42648         args[0] = val;
  42649         args[1] = index_val;
  42650         args[2] = this_val;
  42651         res = JS_Call(ctx, func, this_arg, 3, args);
  42652         if (JS_IsException(res))
  42653             goto exception;
  42654         if (JS_ToBoolFree(ctx, res)) {
  42655             if (mode == ArrayFindIndex || mode == ArrayFindLastIndex) {
  42656                 JS_FreeValue(ctx, val);
  42657                 JS_FreeValue(ctx, obj);
  42658                 return index_val;
  42659             } else {
  42660                 JS_FreeValue(ctx, index_val);
  42661                 JS_FreeValue(ctx, obj);
  42662                 return val;
  42663             }
  42664         }
  42665         JS_FreeValue(ctx, val);
  42666         JS_FreeValue(ctx, index_val);
  42667     }
  42668     JS_FreeValue(ctx, obj);
  42669     if (mode == ArrayFindIndex || mode == ArrayFindLastIndex)
  42670         return JS_NewInt32(ctx, -1);
  42671     else
  42672         return JS_UNDEFINED;
  42673 
  42674 exception:
  42675     JS_FreeValue(ctx, index_val);
  42676     JS_FreeValue(ctx, val);
  42677     JS_FreeValue(ctx, obj);
  42678     return JS_EXCEPTION;
  42679 }
  42680 
  42681 static JSValue js_array_toString(JSContext *ctx, JSValueConst this_val,
  42682                                  int argc, JSValueConst *argv)
  42683 {
  42684     JSValue obj, method, ret;
  42685 
  42686     obj = JS_ToObject(ctx, this_val);
  42687     if (JS_IsException(obj))
  42688         return JS_EXCEPTION;
  42689     method = JS_GetProperty(ctx, obj, JS_ATOM_join);
  42690     if (JS_IsException(method)) {
  42691         ret = JS_EXCEPTION;
  42692     } else
  42693     if (!JS_IsFunction(ctx, method)) {
  42694         /* Use intrinsic Object.prototype.toString */
  42695         JS_FreeValue(ctx, method);
  42696         ret = js_object_toString(ctx, obj, 0, NULL);
  42697     } else {
  42698         ret = JS_CallFree(ctx, method, obj, 0, NULL);
  42699     }
  42700     JS_FreeValue(ctx, obj);
  42701     return ret;
  42702 }
  42703 
  42704 static JSValue js_array_join(JSContext *ctx, JSValueConst this_val,
  42705                              int argc, JSValueConst *argv, int toLocaleString)
  42706 {
  42707     JSValue obj, sep = JS_UNDEFINED, el;
  42708     StringBuffer b_s, *b = &b_s;
  42709     JSString *p = NULL;
  42710     int64_t i, n;
  42711     int c;
  42712 
  42713     obj = JS_ToObject(ctx, this_val);
  42714     if (js_get_length64(ctx, &n, obj))
  42715         goto exception;
  42716 
  42717     c = ',';    /* default separator */
  42718     if (!toLocaleString && argc > 0 && !JS_IsUndefined(argv[0])) {
  42719         sep = JS_ToString(ctx, argv[0]);
  42720         if (JS_IsException(sep))
  42721             goto exception;
  42722         p = JS_VALUE_GET_STRING(sep);
  42723         if (p->len == 1 && !p->is_wide_char)
  42724             c = p->u.str8[0];
  42725         else
  42726             c = -1;
  42727     }
  42728     string_buffer_init(ctx, b, 0);
  42729 
  42730     for(i = 0; i < n; i++) {
  42731         if (i > 0) {
  42732             if (c >= 0) {
  42733                 string_buffer_putc8(b, c);
  42734             } else {
  42735                 string_buffer_concat(b, p, 0, p->len);
  42736             }
  42737         }
  42738         el = JS_GetPropertyUint32(ctx, obj, i);
  42739         if (JS_IsException(el))
  42740             goto fail;
  42741         if (!JS_IsNull(el) && !JS_IsUndefined(el)) {
  42742             if (toLocaleString) {
  42743                 el = JS_ToLocaleStringFree(ctx, el);
  42744             }
  42745             if (string_buffer_concat_value_free(b, el))
  42746                 goto fail;
  42747         }
  42748     }
  42749     JS_FreeValue(ctx, sep);
  42750     JS_FreeValue(ctx, obj);
  42751     return string_buffer_end(b);
  42752 
  42753 fail:
  42754     string_buffer_free(b);
  42755     JS_FreeValue(ctx, sep);
  42756 exception:
  42757     JS_FreeValue(ctx, obj);
  42758     return JS_EXCEPTION;
  42759 }
  42760 
  42761 static JSValue js_array_pop(JSContext *ctx, JSValueConst this_val,
  42762                             int argc, JSValueConst *argv, int shift)
  42763 {
  42764     JSValue obj, res = JS_UNDEFINED;
  42765     int64_t len, newLen;
  42766     JSValue *arrp;
  42767     uint32_t count32;
  42768 
  42769     obj = JS_ToObject(ctx, this_val);
  42770     if (js_get_length64(ctx, &len, obj))
  42771         goto exception;
  42772     newLen = 0;
  42773     if (len > 0) {
  42774         newLen = len - 1;
  42775         /* Special case fast arrays */
  42776         if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
  42777             JSObject *p = JS_VALUE_GET_OBJ(obj);
  42778             if (shift) {
  42779                 res = arrp[0];
  42780                 memmove(arrp, arrp + 1, (count32 - 1) * sizeof(*arrp));
  42781                 p->u.array.count--;
  42782             } else {
  42783                 res = arrp[count32 - 1];
  42784                 p->u.array.count--;
  42785             }
  42786         } else {
  42787             if (shift) {
  42788                 res = JS_GetPropertyInt64(ctx, obj, 0);
  42789                 if (JS_IsException(res))
  42790                     goto exception;
  42791                 if (JS_CopySubArray(ctx, obj, 0, 1, len - 1, +1))
  42792                     goto exception;
  42793             } else {
  42794                 res = JS_GetPropertyInt64(ctx, obj, newLen);
  42795                 if (JS_IsException(res))
  42796                     goto exception;
  42797             }
  42798             if (JS_DeletePropertyInt64(ctx, obj, newLen, JS_PROP_THROW) < 0)
  42799                 goto exception;
  42800         }
  42801     }
  42802     if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
  42803         goto exception;
  42804 
  42805     JS_FreeValue(ctx, obj);
  42806     return res;
  42807 
  42808  exception:
  42809     JS_FreeValue(ctx, res);
  42810     JS_FreeValue(ctx, obj);
  42811     return JS_EXCEPTION;
  42812 }
  42813 
  42814 int qjs_array_append_new(JSContext *ctx, JSValue this_val, JSValue item)
  42815 {
  42816     JSValue obj;
  42817     int64_t len, from, newLen;
  42818 
  42819     obj = JS_ToObject(ctx, this_val);
  42820     if (JS_IsException(obj)) {
  42821         JS_FreeValue(ctx, item);
  42822         return -1;
  42823     }
  42824     if (js_get_length64(ctx, &len, obj))
  42825         goto exception;
  42826     newLen = len + 1;
  42827     if (newLen > MAX_SAFE_INTEGER) {
  42828         JS_ThrowTypeError(ctx, "Array loo long");
  42829         goto exception;
  42830     }
  42831     from = len;
  42832     if (JS_SetPropertyInt64(ctx, obj, from, item) < 0)
  42833         goto exception;
  42834     if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
  42835         goto exception;
  42836 
  42837     JS_FreeValue(ctx, obj);
  42838     return 0;
  42839 
  42840  exception:
  42841     JS_FreeValue(ctx, obj);
  42842     return -1;
  42843 }
  42844 
  42845 static JSValue js_array_push(JSContext *ctx, JSValueConst this_val,
  42846                              int argc, JSValueConst *argv, int unshift)
  42847 {
  42848     JSValue obj;
  42849     int i;
  42850     int64_t len, from, newLen;
  42851 
  42852     if (likely(JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT && !unshift)) {
  42853         JSObject *p = JS_VALUE_GET_OBJ(this_val);
  42854         if (likely(p->class_id == JS_CLASS_ARRAY && p->fast_array &&
  42855                    can_extend_fast_array(p) &&
  42856                    JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT &&
  42857                    JS_VALUE_GET_INT(p->prop[0].u.value) == p->u.array.count &&
  42858                    (get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE) != 0)) {
  42859             /* fast case */
  42860             uint32_t new_len;
  42861             new_len = p->u.array.count + argc;
  42862             if (likely(new_len <= INT32_MAX)) {
  42863                 if (unlikely(new_len > p->u.array.u1.size)) {
  42864                     if (expand_fast_array(ctx, p, new_len))
  42865                         return JS_EXCEPTION;
  42866                 }
  42867                 for(i = 0; i < argc; i++)
  42868                     p->u.array.u.values[p->u.array.count + i] = JS_DupValue(ctx, argv[i]);
  42869                 p->prop[0].u.value = JS_NewInt32(ctx, new_len);
  42870                 p->u.array.count = new_len;
  42871                 return JS_NewInt32(ctx, new_len);
  42872             }
  42873         }
  42874     }
  42875     obj = JS_ToObject(ctx, this_val);
  42876     if (js_get_length64(ctx, &len, obj))
  42877         goto exception;
  42878     newLen = len + argc;
  42879     if (newLen > MAX_SAFE_INTEGER) {
  42880         JS_ThrowTypeError(ctx, "Array loo long");
  42881         goto exception;
  42882     }
  42883     from = len;
  42884     if (unshift && argc > 0) {
  42885         if (JS_CopySubArray(ctx, obj, argc, 0, len, -1))
  42886             goto exception;
  42887         from = 0;
  42888     }
  42889     for(i = 0; i < argc; i++) {
  42890         if (JS_SetPropertyInt64(ctx, obj, from + i,
  42891                                 JS_DupValue(ctx, argv[i])) < 0)
  42892             goto exception;
  42893     }
  42894     if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
  42895         goto exception;
  42896 
  42897     JS_FreeValue(ctx, obj);
  42898     return JS_NewInt64(ctx, newLen);
  42899 
  42900  exception:
  42901     JS_FreeValue(ctx, obj);
  42902     return JS_EXCEPTION;
  42903 }
  42904 
  42905 static JSValue js_array_reverse(JSContext *ctx, JSValueConst this_val,
  42906                                 int argc, JSValueConst *argv)
  42907 {
  42908     JSValue obj, lval, hval;
  42909     JSValue *arrp;
  42910     int64_t len, l, h;
  42911     int l_present, h_present;
  42912     uint32_t count32;
  42913 
  42914     lval = JS_UNDEFINED;
  42915     obj = JS_ToObject(ctx, this_val);
  42916     if (js_get_length64(ctx, &len, obj))
  42917         goto exception;
  42918 
  42919     /* Special case fast arrays */
  42920     if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
  42921         uint32_t ll, hh;
  42922 
  42923         if (count32 > 1) {
  42924             for (ll = 0, hh = count32 - 1; ll < hh; ll++, hh--) {
  42925                 lval = arrp[ll];
  42926                 arrp[ll] = arrp[hh];
  42927                 arrp[hh] = lval;
  42928             }
  42929         }
  42930         return obj;
  42931     }
  42932 
  42933     for (l = 0, h = len - 1; l < h; l++, h--) {
  42934         l_present = JS_TryGetPropertyInt64(ctx, obj, l, &lval);
  42935         if (l_present < 0)
  42936             goto exception;
  42937         h_present = JS_TryGetPropertyInt64(ctx, obj, h, &hval);
  42938         if (h_present < 0)
  42939             goto exception;
  42940         if (h_present) {
  42941             if (JS_SetPropertyInt64(ctx, obj, l, hval) < 0)
  42942                 goto exception;
  42943 
  42944             if (l_present) {
  42945                 if (JS_SetPropertyInt64(ctx, obj, h, lval) < 0) {
  42946                     lval = JS_UNDEFINED;
  42947                     goto exception;
  42948                 }
  42949                 lval = JS_UNDEFINED;
  42950             } else {
  42951                 if (JS_DeletePropertyInt64(ctx, obj, h, JS_PROP_THROW) < 0)
  42952                     goto exception;
  42953             }
  42954         } else {
  42955             if (l_present) {
  42956                 if (JS_DeletePropertyInt64(ctx, obj, l, JS_PROP_THROW) < 0)
  42957                     goto exception;
  42958                 if (JS_SetPropertyInt64(ctx, obj, h, lval) < 0) {
  42959                     lval = JS_UNDEFINED;
  42960                     goto exception;
  42961                 }
  42962                 lval = JS_UNDEFINED;
  42963             }
  42964         }
  42965     }
  42966     return obj;
  42967 
  42968  exception:
  42969     JS_FreeValue(ctx, lval);
  42970     JS_FreeValue(ctx, obj);
  42971     return JS_EXCEPTION;
  42972 }
  42973 
  42974 // Note: a.toReversed() is a.slice().reverse() with the twist that a.slice()
  42975 // leaves holes in sparse arrays intact whereas a.toReversed() replaces them
  42976 // with undefined, thus in effect creating a dense array.
  42977 // Does not use Array[@@species], always returns a base Array.
  42978 static JSValue js_array_toReversed(JSContext *ctx, JSValueConst this_val,
  42979                                    int argc, JSValueConst *argv)
  42980 {
  42981     JSValue arr, obj, ret, *arrp, *pval;
  42982     JSObject *p;
  42983     int64_t i, len;
  42984     uint32_t count32;
  42985 
  42986     ret = JS_EXCEPTION;
  42987     arr = JS_UNDEFINED;
  42988     obj = JS_ToObject(ctx, this_val);
  42989     if (js_get_length64(ctx, &len, obj))
  42990         goto exception;
  42991 
  42992     arr = js_allocate_fast_array(ctx, len);
  42993     if (JS_IsException(arr))
  42994         goto exception;
  42995 
  42996     if (len > 0) {
  42997         p = JS_VALUE_GET_OBJ(arr);
  42998 
  42999         i = len - 1;
  43000         pval = p->u.array.u.values;
  43001         if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
  43002             for (; i >= 0; i--, pval++)
  43003                 *pval = JS_DupValue(ctx, arrp[i]);
  43004         } else {
  43005             // Query order is observable; test262 expects descending order.
  43006             for (; i >= 0; i--, pval++) {
  43007                 if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
  43008                     goto exception;
  43009             }
  43010         }
  43011     }
  43012 
  43013     ret = arr;
  43014     arr = JS_UNDEFINED;
  43015 
  43016 exception:
  43017     JS_FreeValue(ctx, arr);
  43018     JS_FreeValue(ctx, obj);
  43019     return ret;
  43020 }
  43021 
  43022 static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val,
  43023                               int argc, JSValueConst *argv, int splice)
  43024 {
  43025     JSValue obj, arr, val, len_val;
  43026     int64_t len, start, k, final, n, count, del_count, new_len;
  43027     int kPresent;
  43028     JSValue *arrp;
  43029     uint32_t count32, i, item_count;
  43030 
  43031     arr = JS_UNDEFINED;
  43032     obj = JS_ToObject(ctx, this_val);
  43033     if (js_get_length64(ctx, &len, obj))
  43034         goto exception;
  43035 
  43036     if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
  43037         goto exception;
  43038 
  43039     if (splice) {
  43040         if (argc == 0) {
  43041             item_count = 0;
  43042             del_count = 0;
  43043         } else
  43044         if (argc == 1) {
  43045             item_count = 0;
  43046             del_count = len - start;
  43047         } else {
  43048             item_count = argc - 2;
  43049             if (JS_ToInt64Clamp(ctx, &del_count, argv[1], 0, len - start, 0))
  43050                 goto exception;
  43051         }
  43052         if (len + item_count - del_count > MAX_SAFE_INTEGER) {
  43053             JS_ThrowTypeError(ctx, "Array loo long");
  43054             goto exception;
  43055         }
  43056         count = del_count;
  43057     } else {
  43058         item_count = 0; /* avoid warning */
  43059         final = len;
  43060         if (!JS_IsUndefined(argv[1])) {
  43061             if (JS_ToInt64Clamp(ctx, &final, argv[1], 0, len, len))
  43062                 goto exception;
  43063         }
  43064         count = max_int64(final - start, 0);
  43065     }
  43066     len_val = JS_NewInt64(ctx, count);
  43067     arr = JS_ArraySpeciesCreate(ctx, obj, len_val);
  43068     JS_FreeValue(ctx, len_val);
  43069     if (JS_IsException(arr))
  43070         goto exception;
  43071 
  43072     k = start;
  43073     final = start + count;
  43074     n = 0;
  43075     /* The fast array test on arr ensures that
  43076        JS_CreateDataPropertyUint32() won't modify obj in case arr is
  43077        an exotic object */
  43078     /* Special case fast arrays */
  43079     if (js_get_fast_array(ctx, obj, &arrp, &count32) &&
  43080         js_is_fast_array(ctx, arr)) {
  43081         /* XXX: should share code with fast array constructor */
  43082         for (; k < final && k < count32; k++, n++) {
  43083             if (JS_CreateDataPropertyUint32(ctx, arr, n, JS_DupValue(ctx, arrp[k]), JS_PROP_THROW) < 0)
  43084                 goto exception;
  43085         }
  43086     }
  43087     /* Copy the remaining elements if any (handle case of inherited properties) */
  43088     for (; k < final; k++, n++) {
  43089         kPresent = JS_TryGetPropertyInt64(ctx, obj, k, &val);
  43090         if (kPresent < 0)
  43091             goto exception;
  43092         if (kPresent) {
  43093             if (JS_CreateDataPropertyUint32(ctx, arr, n, val, JS_PROP_THROW) < 0)
  43094                 goto exception;
  43095         }
  43096     }
  43097     if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0)
  43098         goto exception;
  43099 
  43100     if (splice) {
  43101         new_len = len + item_count - del_count;
  43102         if (item_count != del_count) {
  43103             if (JS_CopySubArray(ctx, obj, start + item_count,
  43104                                 start + del_count, len - (start + del_count),
  43105                                 item_count <= del_count ? +1 : -1) < 0)
  43106                 goto exception;
  43107 
  43108             for (k = len; k-- > new_len; ) {
  43109                 if (JS_DeletePropertyInt64(ctx, obj, k, JS_PROP_THROW) < 0)
  43110                     goto exception;
  43111             }
  43112         }
  43113         for (i = 0; i < item_count; i++) {
  43114             if (JS_SetPropertyInt64(ctx, obj, start + i, JS_DupValue(ctx, argv[i + 2])) < 0)
  43115                 goto exception;
  43116         }
  43117         if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, new_len)) < 0)
  43118             goto exception;
  43119     }
  43120     JS_FreeValue(ctx, obj);
  43121     return arr;
  43122 
  43123  exception:
  43124     JS_FreeValue(ctx, obj);
  43125     JS_FreeValue(ctx, arr);
  43126     return JS_EXCEPTION;
  43127 }
  43128 
  43129 static JSValue js_array_toSpliced(JSContext *ctx, JSValueConst this_val,
  43130                                   int argc, JSValueConst *argv)
  43131 {
  43132     JSValue arr, obj, ret, *arrp, *pval, *last;
  43133     JSObject *p;
  43134     int64_t i, j, len, newlen, start, add, del;
  43135     uint32_t count32;
  43136 
  43137     pval = NULL;
  43138     last = NULL;
  43139     ret = JS_EXCEPTION;
  43140     arr = JS_UNDEFINED;
  43141 
  43142     obj = JS_ToObject(ctx, this_val);
  43143     if (js_get_length64(ctx, &len, obj))
  43144         goto exception;
  43145 
  43146     start = 0;
  43147     if (argc > 0)
  43148         if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
  43149             goto exception;
  43150 
  43151     del = 0;
  43152     if (argc > 0)
  43153         del = len - start;
  43154     if (argc > 1)
  43155         if (JS_ToInt64Clamp(ctx, &del, argv[1], 0, del, 0))
  43156             goto exception;
  43157 
  43158     add = 0;
  43159     if (argc > 2)
  43160         add = argc - 2;
  43161 
  43162     newlen = len + add - del;
  43163     if (newlen > MAX_SAFE_INTEGER) {
  43164         JS_ThrowTypeError(ctx, "invalid array length");
  43165         goto exception;
  43166     }
  43167 
  43168     arr = js_allocate_fast_array(ctx, newlen);
  43169     if (JS_IsException(arr))
  43170         goto exception;
  43171 
  43172     if (newlen <= 0)
  43173         goto done;
  43174 
  43175     p = JS_VALUE_GET_OBJ(arr);
  43176     pval = &p->u.array.u.values[0];
  43177     last = &p->u.array.u.values[newlen];
  43178 
  43179     if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
  43180         for (i = 0; i < start; i++, pval++)
  43181             *pval = JS_DupValue(ctx, arrp[i]);
  43182         for (j = 0; j < add; j++, pval++)
  43183             *pval = JS_DupValue(ctx, argv[2 + j]);
  43184         for (i += del; i < len; i++, pval++)
  43185             *pval = JS_DupValue(ctx, arrp[i]);
  43186     } else {
  43187         for (i = 0; i < start; i++, pval++)
  43188             if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
  43189                 goto exception;
  43190         for (j = 0; j < add; j++, pval++)
  43191             *pval = JS_DupValue(ctx, argv[2 + j]);
  43192         for (i += del; i < len; i++, pval++)
  43193             if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
  43194                 goto exception;
  43195     }
  43196 
  43197     assert(pval == last);
  43198 
  43199 done:
  43200     ret = arr;
  43201     arr = JS_UNDEFINED;
  43202 
  43203 exception:
  43204     JS_FreeValue(ctx, arr);
  43205     JS_FreeValue(ctx, obj);
  43206     return ret;
  43207 }
  43208 
  43209 static JSValue js_array_copyWithin(JSContext *ctx, JSValueConst this_val,
  43210                                    int argc, JSValueConst *argv)
  43211 {
  43212     JSValue obj;
  43213     int64_t len, from, to, final, count;
  43214 
  43215     obj = JS_ToObject(ctx, this_val);
  43216     if (js_get_length64(ctx, &len, obj))
  43217         goto exception;
  43218 
  43219     if (JS_ToInt64Clamp(ctx, &to, argv[0], 0, len, len))
  43220         goto exception;
  43221 
  43222     if (JS_ToInt64Clamp(ctx, &from, argv[1], 0, len, len))
  43223         goto exception;
  43224 
  43225     final = len;
  43226     if (argc > 2 && !JS_IsUndefined(argv[2])) {
  43227         if (JS_ToInt64Clamp(ctx, &final, argv[2], 0, len, len))
  43228             goto exception;
  43229     }
  43230 
  43231     count = min_int64(final - from, len - to);
  43232 
  43233     if (JS_CopySubArray(ctx, obj, to, from, count,
  43234                         (from < to && to < from + count) ? -1 : +1))
  43235         goto exception;
  43236 
  43237     return obj;
  43238 
  43239  exception:
  43240     JS_FreeValue(ctx, obj);
  43241     return JS_EXCEPTION;
  43242 }
  43243 
  43244 static int64_t JS_FlattenIntoArray(JSContext *ctx, JSValueConst target,
  43245                                    JSValueConst source, int64_t sourceLen,
  43246                                    int64_t targetIndex, int depth,
  43247                                    JSValueConst mapperFunction,
  43248                                    JSValueConst thisArg)
  43249 {
  43250     JSValue element;
  43251     int64_t sourceIndex, elementLen;
  43252     int present, is_array;
  43253 
  43254     if (js_check_stack_overflow(ctx->rt, 0)) {
  43255         JS_ThrowStackOverflow(ctx);
  43256         return -1;
  43257     }
  43258 
  43259     for (sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) {
  43260         present = JS_TryGetPropertyInt64(ctx, source, sourceIndex, &element);
  43261         if (present < 0)
  43262             return -1;
  43263         if (!present)
  43264             continue;
  43265         if (!JS_IsUndefined(mapperFunction)) {
  43266             JSValueConst args[3] = { element, JS_NewInt64(ctx, sourceIndex), source };
  43267             element = JS_Call(ctx, mapperFunction, thisArg, 3, args);
  43268             JS_FreeValue(ctx, (JSValue)args[0]);
  43269             JS_FreeValue(ctx, (JSValue)args[1]);
  43270             if (JS_IsException(element))
  43271                 return -1;
  43272         }
  43273         if (depth > 0) {
  43274             is_array = JS_IsArray(ctx, element);
  43275             if (is_array < 0)
  43276                 goto fail;
  43277             if (is_array) {
  43278                 if (js_get_length64(ctx, &elementLen, element) < 0)
  43279                     goto fail;
  43280                 targetIndex = JS_FlattenIntoArray(ctx, target, element,
  43281                                                   elementLen, targetIndex,
  43282                                                   depth - 1,
  43283                                                   JS_UNDEFINED, JS_UNDEFINED);
  43284                 if (targetIndex < 0)
  43285                     goto fail;
  43286                 JS_FreeValue(ctx, element);
  43287                 continue;
  43288             }
  43289         }
  43290         if (targetIndex >= MAX_SAFE_INTEGER) {
  43291             JS_ThrowTypeError(ctx, "Array too long");
  43292             goto fail;
  43293         }
  43294         if (JS_DefinePropertyValueInt64(ctx, target, targetIndex, element,
  43295                                         JS_PROP_C_W_E | JS_PROP_THROW) < 0)
  43296             return -1;
  43297         targetIndex++;
  43298     }
  43299     return targetIndex;
  43300 
  43301 fail:
  43302     JS_FreeValue(ctx, element);
  43303     return -1;
  43304 }
  43305 
  43306 static JSValue js_array_flatten(JSContext *ctx, JSValueConst this_val,
  43307                                 int argc, JSValueConst *argv, int map)
  43308 {
  43309     JSValue obj, arr;
  43310     JSValueConst mapperFunction, thisArg;
  43311     int64_t sourceLen;
  43312     int depthNum;
  43313 
  43314     arr = JS_UNDEFINED;
  43315     obj = JS_ToObject(ctx, this_val);
  43316     if (js_get_length64(ctx, &sourceLen, obj))
  43317         goto exception;
  43318 
  43319     depthNum = 1;
  43320     mapperFunction = JS_UNDEFINED;
  43321     thisArg = JS_UNDEFINED;
  43322     if (map) {
  43323         mapperFunction = argv[0];
  43324         if (argc > 1) {
  43325             thisArg = argv[1];
  43326         }
  43327         if (check_function(ctx, mapperFunction))
  43328             goto exception;
  43329     } else {
  43330         if (argc > 0 && !JS_IsUndefined(argv[0])) {
  43331             if (JS_ToInt32Sat(ctx, &depthNum, argv[0]) < 0)
  43332                 goto exception;
  43333         }
  43334     }
  43335     arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
  43336     if (JS_IsException(arr))
  43337         goto exception;
  43338     if (JS_FlattenIntoArray(ctx, arr, obj, sourceLen, 0, depthNum,
  43339                             mapperFunction, thisArg) < 0)
  43340         goto exception;
  43341     JS_FreeValue(ctx, obj);
  43342     return arr;
  43343 
  43344 exception:
  43345     JS_FreeValue(ctx, obj);
  43346     JS_FreeValue(ctx, arr);
  43347     return JS_EXCEPTION;
  43348 }
  43349 
  43350 /* Array sort */
  43351 
  43352 typedef struct ValueSlot {
  43353     JSValue val;
  43354     JSString *str;
  43355     int64_t pos;
  43356 } ValueSlot;
  43357 
  43358 struct array_sort_context {
  43359     JSContext *ctx;
  43360     int exception;
  43361     int has_method;
  43362     JSValueConst method;
  43363 };
  43364 
  43365 static int js_array_cmp_generic(const void *a, const void *b, void *opaque) {
  43366     struct array_sort_context *psc = opaque;
  43367     JSContext *ctx = psc->ctx;
  43368     JSValueConst argv[2];
  43369     JSValue res;
  43370     ValueSlot *ap = (ValueSlot *)(void *)a;
  43371     ValueSlot *bp = (ValueSlot *)(void *)b;
  43372     int cmp;
  43373 
  43374     if (psc->exception)
  43375         return 0;
  43376 
  43377     if (psc->has_method) {
  43378         /* custom sort function is specified as returning 0 for identical
  43379          * objects: avoid method call overhead.
  43380          */
  43381         if (!memcmp(&ap->val, &bp->val, sizeof(ap->val)))
  43382             goto cmp_same;
  43383         argv[0] = ap->val;
  43384         argv[1] = bp->val;
  43385         res = JS_Call(ctx, psc->method, JS_UNDEFINED, 2, argv);
  43386         if (JS_IsException(res))
  43387             goto exception;
  43388         if (JS_VALUE_GET_TAG(res) == JS_TAG_INT) {
  43389             int val = JS_VALUE_GET_INT(res);
  43390             cmp = (val > 0) - (val < 0);
  43391         } else {
  43392             double val;
  43393             if (JS_ToFloat64Free(ctx, &val, res) < 0)
  43394                 goto exception;
  43395             cmp = (val > 0) - (val < 0);
  43396         }
  43397     } else {
  43398         /* Not supposed to bypass ToString even for identical objects as
  43399          * tested in test262/test/built-ins/Array/prototype/sort/bug_596_1.js
  43400          */
  43401         if (!ap->str) {
  43402             JSValue str = JS_ToString(ctx, ap->val);
  43403             if (JS_IsException(str))
  43404                 goto exception;
  43405             ap->str = JS_VALUE_GET_STRING(str);
  43406         }
  43407         if (!bp->str) {
  43408             JSValue str = JS_ToString(ctx, bp->val);
  43409             if (JS_IsException(str))
  43410                 goto exception;
  43411             bp->str = JS_VALUE_GET_STRING(str);
  43412         }
  43413         cmp = js_string_compare(ctx, ap->str, bp->str);
  43414     }
  43415     if (cmp != 0)
  43416         return cmp;
  43417 cmp_same:
  43418     /* make sort stable: compare array offsets */
  43419     return (ap->pos > bp->pos) - (ap->pos < bp->pos);
  43420 
  43421 exception:
  43422     psc->exception = 1;
  43423     return 0;
  43424 }
  43425 
  43426 static JSValue js_array_sort(JSContext *ctx, JSValueConst this_val,
  43427                              int argc, JSValueConst *argv)
  43428 {
  43429     struct array_sort_context asc = { ctx, 0, 0, argv[0] };
  43430     JSValue obj = JS_UNDEFINED;
  43431     ValueSlot *array = NULL;
  43432     size_t array_size = 0, pos = 0, n = 0;
  43433     int64_t i, len, undefined_count = 0;
  43434     int present;
  43435 
  43436     if (!JS_IsUndefined(asc.method)) {
  43437         if (check_function(ctx, asc.method))
  43438             goto exception;
  43439         asc.has_method = 1;
  43440     }
  43441     obj = JS_ToObject(ctx, this_val);
  43442     if (js_get_length64(ctx, &len, obj))
  43443         goto exception;
  43444 
  43445     /* XXX: should special case fast arrays */
  43446     for (i = 0; i < len; i++) {
  43447         if (pos >= array_size) {
  43448             size_t new_size, slack;
  43449             ValueSlot *new_array;
  43450             new_size = (array_size + (array_size >> 1) + 31) & ~15;
  43451             new_array = js_realloc2(ctx, array, new_size * sizeof(*array), &slack);
  43452             if (new_array == NULL)
  43453                 goto exception;
  43454             new_size += slack / sizeof(*new_array);
  43455             array = new_array;
  43456             array_size = new_size;
  43457         }
  43458         present = JS_TryGetPropertyInt64(ctx, obj, i, &array[pos].val);
  43459         if (present < 0)
  43460             goto exception;
  43461         if (present == 0)
  43462             continue;
  43463         if (JS_IsUndefined(array[pos].val)) {
  43464             undefined_count++;
  43465             continue;
  43466         }
  43467         array[pos].str = NULL;
  43468         array[pos].pos = i;
  43469         pos++;
  43470     }
  43471     rqsort(array, pos, sizeof(*array), js_array_cmp_generic, &asc);
  43472     if (asc.exception)
  43473         goto exception;
  43474 
  43475     /* XXX: should special case fast arrays */
  43476     while (n < pos) {
  43477         if (array[n].str)
  43478             JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, array[n].str));
  43479         if (array[n].pos == n) {
  43480             JS_FreeValue(ctx, array[n].val);
  43481         } else {
  43482             if (JS_SetPropertyInt64(ctx, obj, n, array[n].val) < 0) {
  43483                 n++;
  43484                 goto exception;
  43485             }
  43486         }
  43487         n++;
  43488     }
  43489     js_free(ctx, array);
  43490     for (i = n; undefined_count-- > 0; i++) {
  43491         if (JS_SetPropertyInt64(ctx, obj, i, JS_UNDEFINED) < 0)
  43492             goto fail;
  43493     }
  43494     for (; i < len; i++) {
  43495         if (JS_DeletePropertyInt64(ctx, obj, i, JS_PROP_THROW) < 0)
  43496             goto fail;
  43497     }
  43498     return obj;
  43499 
  43500 exception:
  43501     for (; n < pos; n++) {
  43502         JS_FreeValue(ctx, array[n].val);
  43503         if (array[n].str)
  43504             JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, array[n].str));
  43505     }
  43506     js_free(ctx, array);
  43507 fail:
  43508     JS_FreeValue(ctx, obj);
  43509     return JS_EXCEPTION;
  43510 }
  43511 
  43512 // Note: a.toSorted() is a.slice().sort() with the twist that a.slice()
  43513 // leaves holes in sparse arrays intact whereas a.toSorted() replaces them
  43514 // with undefined, thus in effect creating a dense array.
  43515 // Does not use Array[@@species], always returns a base Array.
  43516 static JSValue js_array_toSorted(JSContext *ctx, JSValueConst this_val,
  43517                                  int argc, JSValueConst *argv)
  43518 {
  43519     JSValue arr, obj, ret, *arrp, *pval;
  43520     JSObject *p;
  43521     int64_t i, len;
  43522     uint32_t count32;
  43523     int ok;
  43524 
  43525     ok = JS_IsUndefined(argv[0]) || JS_IsFunction(ctx, argv[0]);
  43526     if (!ok)
  43527         return JS_ThrowTypeError(ctx, "not a function");
  43528 
  43529     ret = JS_EXCEPTION;
  43530     arr = JS_UNDEFINED;
  43531     obj = JS_ToObject(ctx, this_val);
  43532     if (js_get_length64(ctx, &len, obj))
  43533         goto exception;
  43534 
  43535     arr = js_allocate_fast_array(ctx, len);
  43536     if (JS_IsException(arr))
  43537         goto exception;
  43538 
  43539     if (len > 0) {
  43540         p = JS_VALUE_GET_OBJ(arr);
  43541         i = 0;
  43542         pval = p->u.array.u.values;
  43543         if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
  43544             for (; i < len; i++, pval++)
  43545                 *pval = JS_DupValue(ctx, arrp[i]);
  43546         } else {
  43547             for (; i < len; i++, pval++) {
  43548                 if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
  43549                     goto exception;
  43550             }
  43551         }
  43552     }
  43553 
  43554     ret = js_array_sort(ctx, arr, argc, argv);
  43555     if (JS_IsException(ret))
  43556         goto exception;
  43557     JS_FreeValue(ctx, ret);
  43558 
  43559     ret = arr;
  43560     arr = JS_UNDEFINED;
  43561 
  43562 exception:
  43563     JS_FreeValue(ctx, arr);
  43564     JS_FreeValue(ctx, obj);
  43565     return ret;
  43566 }
  43567 
  43568 typedef struct JSArrayIteratorData {
  43569     JSValue obj;
  43570     JSIteratorKindEnum kind;
  43571     uint32_t idx;
  43572 } JSArrayIteratorData;
  43573 
  43574 static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val)
  43575 {
  43576     JSObject *p = JS_VALUE_GET_OBJ(val);
  43577     JSArrayIteratorData *it = p->u.array_iterator_data;
  43578     if (it) {
  43579         JS_FreeValueRT(rt, it->obj);
  43580         js_free_rt(rt, it);
  43581     }
  43582 }
  43583 
  43584 static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val,
  43585                                    JS_MarkFunc *mark_func)
  43586 {
  43587     JSObject *p = JS_VALUE_GET_OBJ(val);
  43588     JSArrayIteratorData *it = p->u.array_iterator_data;
  43589     if (it) {
  43590         JS_MarkValue(rt, it->obj, mark_func);
  43591     }
  43592 }
  43593 
  43594 static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val,
  43595                                         int argc, JSValueConst *argv, int magic)
  43596 {
  43597     JSValue enum_obj, arr;
  43598     JSArrayIteratorData *it;
  43599     JSIteratorKindEnum kind;
  43600     int class_id;
  43601 
  43602     kind = magic & 3;
  43603     if (magic & 4) {
  43604         /* string iterator case */
  43605         arr = JS_ToStringCheckObject(ctx, this_val);
  43606         class_id = JS_CLASS_STRING_ITERATOR;
  43607     } else {
  43608         arr = JS_ToObject(ctx, this_val);
  43609         class_id = JS_CLASS_ARRAY_ITERATOR;
  43610     }
  43611     if (JS_IsException(arr))
  43612         goto fail;
  43613     enum_obj = JS_NewObjectClass(ctx, class_id);
  43614     if (JS_IsException(enum_obj))
  43615         goto fail;
  43616     it = js_malloc(ctx, sizeof(*it));
  43617     if (!it)
  43618         goto fail1;
  43619     it->obj = arr;
  43620     it->kind = kind;
  43621     it->idx = 0;
  43622     JS_SetOpaque(enum_obj, it);
  43623     return enum_obj;
  43624  fail1:
  43625     JS_FreeValue(ctx, enum_obj);
  43626  fail:
  43627     JS_FreeValue(ctx, arr);
  43628     return JS_EXCEPTION;
  43629 }
  43630 
  43631 static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val,
  43632                                       int argc, JSValueConst *argv,
  43633                                       BOOL *pdone, int magic)
  43634 {
  43635     JSArrayIteratorData *it;
  43636     uint32_t len, idx;
  43637     JSValue val, obj;
  43638     JSObject *p;
  43639 
  43640     it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_ITERATOR);
  43641     if (!it)
  43642         goto fail1;
  43643     if (JS_IsUndefined(it->obj))
  43644         goto done;
  43645     p = JS_VALUE_GET_OBJ(it->obj);
  43646     if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
  43647         p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
  43648         if (typed_array_is_oob(p)) {
  43649             JS_ThrowTypeErrorArrayBufferOOB(ctx);
  43650             goto fail1;
  43651         }
  43652         len = p->u.array.count;
  43653     } else {
  43654         if (js_get_length32(ctx, &len, it->obj)) {
  43655         fail1:
  43656             *pdone = FALSE;
  43657             return JS_EXCEPTION;
  43658         }
  43659     }
  43660     idx = it->idx;
  43661     if (idx >= len) {
  43662         JS_FreeValue(ctx, it->obj);
  43663         it->obj = JS_UNDEFINED;
  43664     done:
  43665         *pdone = TRUE;
  43666         return JS_UNDEFINED;
  43667     }
  43668     it->idx = idx + 1;
  43669     *pdone = FALSE;
  43670     if (it->kind == JS_ITERATOR_KIND_KEY) {
  43671         return JS_NewUint32(ctx, idx);
  43672     } else {
  43673         val = JS_GetPropertyUint32(ctx, it->obj, idx);
  43674         if (JS_IsException(val))
  43675             return JS_EXCEPTION;
  43676         if (it->kind == JS_ITERATOR_KIND_VALUE) {
  43677             return val;
  43678         } else {
  43679             JSValueConst args[2];
  43680             JSValue num;
  43681             num = JS_NewUint32(ctx, idx);
  43682             args[0] = num;
  43683             args[1] = val;
  43684             obj = js_create_array(ctx, 2, args);
  43685             JS_FreeValue(ctx, val);
  43686             JS_FreeValue(ctx, num);
  43687             return obj;
  43688         }
  43689     }
  43690 }
  43691 
  43692 /* Iterator Wrap */
  43693 
  43694 typedef struct JSIteratorWrapData {
  43695     JSValue wrapped_iter;
  43696     JSValue wrapped_next;
  43697 } JSIteratorWrapData;
  43698 
  43699 static void js_iterator_wrap_finalizer(JSRuntime *rt, JSValue val)
  43700 {
  43701     JSObject *p = JS_VALUE_GET_OBJ(val);
  43702     JSIteratorWrapData *it = p->u.iterator_wrap_data;
  43703     if (it) {
  43704         JS_FreeValueRT(rt, it->wrapped_iter);
  43705         JS_FreeValueRT(rt, it->wrapped_next);
  43706         js_free_rt(rt, it);
  43707     }
  43708 }
  43709 
  43710 static void js_iterator_wrap_mark(JSRuntime *rt, JSValueConst val,
  43711                                   JS_MarkFunc *mark_func)
  43712 {
  43713     JSObject *p = JS_VALUE_GET_OBJ(val);
  43714     JSIteratorWrapData *it = p->u.iterator_wrap_data;
  43715     if (it) {
  43716         JS_MarkValue(rt, it->wrapped_iter, mark_func);
  43717         JS_MarkValue(rt, it->wrapped_next, mark_func);
  43718     }
  43719 }
  43720 
  43721 static JSValue js_iterator_wrap_next(JSContext *ctx, JSValueConst this_val,
  43722                                      int argc, JSValueConst *argv,
  43723                                      int *pdone, int magic)
  43724 {
  43725     JSIteratorWrapData *it;
  43726     JSValue method, ret;
  43727     it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ITERATOR_WRAP);
  43728     if (!it)
  43729         return JS_EXCEPTION;
  43730     if (magic == GEN_MAGIC_NEXT) {
  43731         return JS_IteratorNext(ctx, it->wrapped_iter, it->wrapped_next, 0, NULL, pdone);
  43732     } else {
  43733         method = JS_GetProperty(ctx, it->wrapped_iter, JS_ATOM_return);
  43734         if (JS_IsException(method))
  43735             return JS_EXCEPTION;
  43736         if (JS_IsNull(method) || JS_IsUndefined(method)) {
  43737             *pdone = TRUE;
  43738             return JS_UNDEFINED;
  43739         }
  43740         ret = JS_IteratorNext2(ctx, it->wrapped_iter, method, 0, NULL, pdone);
  43741         JS_FreeValue(ctx, method);
  43742         return ret;
  43743     }
  43744 }
  43745 
  43746 static const JSCFunctionListEntry js_iterator_wrap_proto_funcs[] = {
  43747     JS_ITERATOR_NEXT_DEF("next", 0, js_iterator_wrap_next, GEN_MAGIC_NEXT ),
  43748     JS_ITERATOR_NEXT_DEF("return", 0, js_iterator_wrap_next, GEN_MAGIC_RETURN ),
  43749 };
  43750 
  43751 /* Iterator */
  43752 
  43753 static JSValue js_iterator_constructor_getset(JSContext *ctx,
  43754                                               JSValueConst this_val,
  43755                                               int argc, JSValueConst *argv,
  43756                                               int magic,
  43757                                               JSValue *func_data)
  43758 {
  43759     int ret;
  43760 
  43761     if (argc > 0) { // if setter
  43762         if (!JS_IsObject(argv[0]))
  43763             return JS_ThrowTypeErrorNotAnObject(ctx);
  43764         ret = JS_DefinePropertyValue(ctx, this_val, JS_ATOM_constructor,
  43765                                      JS_DupValue(ctx, argv[0]),
  43766                                      JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
  43767         if (ret < 0)
  43768             return JS_EXCEPTION;
  43769         return JS_UNDEFINED;
  43770     } else {
  43771         return JS_DupValue(ctx, func_data[0]);
  43772     }
  43773 }
  43774 
  43775 static JSValue js_iterator_constructor(JSContext *ctx, JSValueConst new_target,
  43776                                        int argc, JSValueConst *argv)
  43777 {
  43778     JSObject *p;
  43779 
  43780     if (JS_TAG_OBJECT != JS_VALUE_GET_TAG(new_target))
  43781         return JS_ThrowTypeError(ctx, "constructor requires 'new'");
  43782     p = JS_VALUE_GET_OBJ(new_target);
  43783     if (p->class_id == JS_CLASS_C_FUNCTION &&
  43784         p->u.cfunc.c_function.generic == js_iterator_constructor) {
  43785         return JS_ThrowTypeError(ctx, "abstract class not constructable");
  43786     }
  43787     return js_create_from_ctor(ctx, new_target, JS_CLASS_ITERATOR);
  43788 }
  43789 
  43790 // note: deliberately doesn't use space-saving bit fields for
  43791 // |index|, |count| and |running| because tcc miscompiles them
  43792 typedef struct JSIteratorConcatData {
  43793     int index, count;             // elements (not pairs!) in values[] array
  43794     BOOL running;
  43795     JSValue iter, next, values[]; // array of (object, method) pairs
  43796 } JSIteratorConcatData;
  43797 
  43798 static void js_iterator_concat_finalizer(JSRuntime *rt, JSValue val)
  43799 {
  43800     JSObject *p = JS_VALUE_GET_OBJ(val);
  43801     JSIteratorConcatData *it = p->u.iterator_concat_data;
  43802     if (it) {
  43803         JS_FreeValueRT(rt, it->iter);
  43804         JS_FreeValueRT(rt, it->next);
  43805         for (int i = it->index; i < it->count; i++)
  43806             JS_FreeValueRT(rt, it->values[i]);
  43807         js_free_rt(rt, it);
  43808     }
  43809 }
  43810 
  43811 static void js_iterator_concat_mark(JSRuntime *rt, JSValueConst val,
  43812                                     JS_MarkFunc *mark_func)
  43813 {
  43814     JSObject *p = JS_VALUE_GET_OBJ(val);
  43815     JSIteratorConcatData *it = p->u.iterator_concat_data;
  43816     if (it) {
  43817         JS_MarkValue(rt, it->iter, mark_func);
  43818         JS_MarkValue(rt, it->next, mark_func);
  43819         for (int i = it->index; i < it->count; i++)
  43820             JS_MarkValue(rt, it->values[i], mark_func);
  43821     }
  43822 }
  43823 
  43824 static JSValue js_iterator_concat_next(JSContext *ctx, JSValueConst this_val,
  43825                                        int argc, JSValueConst *argv,
  43826                                        int *pdone, int magic)
  43827 {
  43828     JSValue iter, item, next, val, *obj, *meth, ret;
  43829     JSIteratorConcatData *it;
  43830     int done;
  43831 
  43832     *pdone = FALSE;
  43833 
  43834     it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ITERATOR_CONCAT);
  43835     if (!it)
  43836         return JS_EXCEPTION;
  43837     if (it->running)
  43838         return JS_ThrowTypeError(ctx, "already running");
  43839 
  43840     it->running = TRUE;
  43841     for(;;) {
  43842         if (it->index >= it->count) {
  43843             *pdone = TRUE;
  43844             ret = JS_UNDEFINED;
  43845             break;
  43846         }
  43847         obj = &it->values[it->index + 0];
  43848         meth = &it->values[it->index + 1];
  43849         iter = it->iter;
  43850         if (JS_IsUndefined(iter)) {
  43851             iter = JS_GetIterator2(ctx, *obj, *meth);
  43852             if (JS_IsException(iter))
  43853                 goto fail;
  43854             it->iter = iter;
  43855         }
  43856         next = it->next;
  43857         if (JS_IsUndefined(next)) {
  43858             next = JS_GetProperty(ctx, iter, JS_ATOM_next);
  43859             if (JS_IsException(next))
  43860                 goto fail;
  43861             it->next = next;
  43862         }
  43863         item = JS_IteratorNext2(ctx, iter, next, 0, NULL, &done);
  43864         if (JS_IsException(item))
  43865             goto fail;
  43866         if (done == 0) {
  43867             ret = item;
  43868             break;
  43869         } else if (done == 2) {
  43870             val = JS_GetProperty(ctx, item, JS_ATOM_done);
  43871             if (JS_IsException(val)) {
  43872                 JS_FreeValue(ctx, item);
  43873             fail:
  43874                 ret = JS_EXCEPTION;
  43875                 break;
  43876             }
  43877             done = JS_ToBoolFree(ctx, val);
  43878             if (done)
  43879                 goto done_next;
  43880             ret = JS_GetProperty(ctx, item, JS_ATOM_value);
  43881             JS_FreeValue(ctx, item);
  43882             break;
  43883         } else {
  43884         done_next:
  43885             JS_FreeValue(ctx, item);
  43886             JS_FreeValue(ctx, iter);
  43887             JS_FreeValue(ctx, next);
  43888             it->iter = JS_UNDEFINED;
  43889             it->next = JS_UNDEFINED;
  43890             JS_FreeValue(ctx, *meth);
  43891             JS_FreeValue(ctx, *obj);
  43892             it->index += 2;
  43893         }
  43894     }
  43895     it->running = FALSE;
  43896     return ret;
  43897 }
  43898 
  43899 static JSValue js_iterator_concat_return(JSContext *ctx, JSValueConst this_val,
  43900                                          int argc, JSValueConst *argv)
  43901 {
  43902     JSIteratorConcatData *it;
  43903     JSValue ret;
  43904 
  43905     it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ITERATOR_CONCAT);
  43906     if (!it)
  43907         return JS_EXCEPTION;
  43908     if (it->running)
  43909         return JS_ThrowTypeError(ctx, "already running");
  43910     ret = JS_UNDEFINED;
  43911     if (!JS_IsUndefined(it->iter)) {
  43912         it->running = TRUE;
  43913         ret = JS_GetProperty(ctx, it->iter, JS_ATOM_return);
  43914         if (JS_IsException(ret)) {
  43915             it->running = FALSE;
  43916             return JS_EXCEPTION;
  43917         }
  43918         ret = JS_CallFree(ctx, ret, it->iter, 0, NULL);
  43919         it->running = FALSE;
  43920     }
  43921     while (it->index < it->count)
  43922         JS_FreeValue(ctx, it->values[it->index++]);
  43923     JS_FreeValue(ctx, it->iter);
  43924     JS_FreeValue(ctx, it->next);
  43925     it->iter = JS_UNDEFINED;
  43926     it->next = JS_UNDEFINED;
  43927     return ret;
  43928 }
  43929 
  43930 static const JSCFunctionListEntry js_iterator_concat_proto_funcs[] = {
  43931     JS_ITERATOR_NEXT_DEF("next", 0, js_iterator_concat_next, 0 ),
  43932     JS_CFUNC_DEF("return", 0, js_iterator_concat_return ),
  43933     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Iterator Concat", JS_PROP_CONFIGURABLE ),
  43934 };
  43935 
  43936 static JSValue js_iterator_concat(JSContext *ctx, JSValueConst this_val,
  43937                                   int argc, JSValueConst *argv)
  43938 {
  43939     JSIteratorConcatData *it;
  43940     JSValue obj, method;
  43941 
  43942     it = js_malloc(ctx, sizeof(*it) + 2*argc * sizeof(it->values[0]));
  43943     if (!it)
  43944         return JS_EXCEPTION;
  43945     it->running = FALSE;
  43946     it->index = 0;
  43947     it->count = 0;
  43948     it->iter = JS_UNDEFINED;
  43949     it->next = JS_UNDEFINED;
  43950     for (int i = 0; i < argc; i++) {
  43951         JSValueConst obj = argv[i];
  43952         if (!JS_IsObject(obj)) {
  43953             JS_ThrowTypeErrorNotAnObject(ctx);
  43954             goto fail;
  43955         }
  43956         method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
  43957         if (JS_IsException(method))
  43958             goto fail;
  43959         if (!JS_IsFunction(ctx, method)) {
  43960             JS_ThrowTypeError(ctx, "not a function");
  43961             JS_FreeValue(ctx, method);
  43962             goto fail;
  43963         }
  43964         it->values[it->count++] = JS_DupValue(ctx, obj);
  43965         it->values[it->count++] = method;
  43966     }
  43967     obj = JS_NewObjectClass(ctx, JS_CLASS_ITERATOR_CONCAT);
  43968     if (JS_IsException(obj))
  43969         goto fail;
  43970     JS_SetOpaque(obj, it);
  43971     return obj;
  43972 fail:
  43973     for (int i = 0; i < it->count; i++)
  43974         JS_FreeValue(ctx, it->values[i]);
  43975     js_free(ctx, it);
  43976     return JS_EXCEPTION;
  43977 }
  43978 
  43979 static JSValue js_iterator_from(JSContext *ctx, JSValueConst this_val,
  43980                                 int argc, JSValueConst *argv)
  43981 {
  43982     JSValueConst obj = argv[0];
  43983     JSValue method, iter, wrapper;
  43984     JSIteratorWrapData *it;
  43985     int ret;
  43986 
  43987     if (!JS_IsObject(obj)) {
  43988         if (!JS_IsString(obj))
  43989             return JS_ThrowTypeError(ctx, "Iterator.from called on non-object");
  43990     }
  43991     method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
  43992     if (JS_IsException(method))
  43993         return JS_EXCEPTION;
  43994     if (JS_IsNull(method) || JS_IsUndefined(method)) {
  43995         iter = JS_DupValue(ctx, obj);
  43996     } else {
  43997         iter = JS_GetIterator2(ctx, obj, method);
  43998         JS_FreeValue(ctx, method);
  43999         if (JS_IsException(iter))
  44000             return JS_EXCEPTION;
  44001     }
  44002 
  44003     wrapper = JS_UNDEFINED;
  44004     method = JS_GetProperty(ctx, iter, JS_ATOM_next);
  44005     if (JS_IsException(method))
  44006         goto fail;
  44007 
  44008     ret = JS_OrdinaryIsInstanceOf(ctx, iter, ctx->iterator_ctor);
  44009     if (ret < 0)
  44010         goto fail;
  44011     if (ret) {
  44012         JS_FreeValue(ctx, method);
  44013         return iter;
  44014     }
  44015     
  44016     wrapper = JS_NewObjectClass(ctx, JS_CLASS_ITERATOR_WRAP);
  44017     if (JS_IsException(wrapper))
  44018         goto fail;
  44019     it = js_malloc(ctx, sizeof(*it));
  44020     if (!it)
  44021         goto fail;
  44022     it->wrapped_iter = iter;
  44023     it->wrapped_next = method;
  44024     JS_SetOpaque(wrapper, it);
  44025     return wrapper;
  44026 
  44027  fail:
  44028     JS_FreeValue(ctx, method);
  44029     JS_FreeValue(ctx, iter);
  44030     JS_FreeValue(ctx, wrapper);
  44031     return JS_EXCEPTION;
  44032 }
  44033 
  44034 typedef enum JSIteratorHelperKindEnum {
  44035     JS_ITERATOR_HELPER_KIND_DROP,
  44036     JS_ITERATOR_HELPER_KIND_EVERY,
  44037     JS_ITERATOR_HELPER_KIND_FILTER,
  44038     JS_ITERATOR_HELPER_KIND_FIND,
  44039     JS_ITERATOR_HELPER_KIND_FLAT_MAP,
  44040     JS_ITERATOR_HELPER_KIND_FOR_EACH,
  44041     JS_ITERATOR_HELPER_KIND_MAP,
  44042     JS_ITERATOR_HELPER_KIND_SOME,
  44043     JS_ITERATOR_HELPER_KIND_TAKE,
  44044 } JSIteratorHelperKindEnum;
  44045 
  44046 typedef struct JSIteratorHelperData {
  44047     JSValue obj;
  44048     JSValue next;
  44049     JSValue func; // predicate (filter) or mapper (flatMap, map)
  44050     JSValue inner; // innerValue (flatMap)
  44051     int64_t count; // limit (drop, take) or counter (filter, map, flatMap)
  44052     JSIteratorHelperKindEnum kind : 8;
  44053     uint8_t executing : 1;
  44054     uint8_t done : 1;
  44055 } JSIteratorHelperData;
  44056 
  44057 static JSValue js_create_iterator_helper(JSContext *ctx, JSValueConst this_val,
  44058                                          int argc, JSValueConst *argv, int magic)
  44059 {
  44060     JSValueConst func;
  44061     JSValue obj, method;
  44062     int64_t count;
  44063     JSIteratorHelperData *it;
  44064 
  44065     if (!JS_IsObject(this_val))
  44066         return JS_ThrowTypeErrorNotAnObject(ctx);
  44067     func = JS_UNDEFINED;
  44068     count = 0;
  44069 
  44070     switch(magic) {
  44071     case JS_ITERATOR_HELPER_KIND_DROP:
  44072     case JS_ITERATOR_HELPER_KIND_TAKE:
  44073         {
  44074             JSValue v;
  44075             double dlimit;
  44076             v = JS_ToNumber(ctx, argv[0]);
  44077             if (JS_IsException(v))
  44078                 goto fail;
  44079             // Check for Infinity.
  44080             if (JS_ToFloat64(ctx, &dlimit, v)) {
  44081                 JS_FreeValue(ctx, v);
  44082                 goto fail;
  44083             }
  44084             if (isnan(dlimit)) {
  44085                 JS_FreeValue(ctx, v);
  44086                 goto range_error;
  44087             }
  44088             if (!isfinite(dlimit)) {
  44089                 JS_FreeValue(ctx, v);
  44090                 if (dlimit < 0)
  44091                     goto range_error;
  44092                 else
  44093                     count = MAX_SAFE_INTEGER;
  44094             } else {
  44095                 v = JS_ToIntegerFree(ctx, v);
  44096                 if (JS_IsException(v))
  44097                     goto fail;
  44098                 if (JS_ToInt64Free(ctx, &count, v))
  44099                     goto fail;
  44100             }
  44101             if (count < 0)
  44102                 goto range_error;
  44103         }
  44104         break;
  44105     case JS_ITERATOR_HELPER_KIND_FILTER:
  44106     case JS_ITERATOR_HELPER_KIND_FLAT_MAP:
  44107     case JS_ITERATOR_HELPER_KIND_MAP:
  44108         {
  44109             func = argv[0];
  44110             if (check_function(ctx, func))
  44111                 goto fail;
  44112         }
  44113         break;
  44114     default:
  44115         abort();
  44116         break;
  44117     }
  44118 
  44119     method = JS_GetProperty(ctx, this_val, JS_ATOM_next);
  44120     if (JS_IsException(method))
  44121         goto fail;
  44122     obj = JS_NewObjectClass(ctx, JS_CLASS_ITERATOR_HELPER);
  44123     if (JS_IsException(obj)) {
  44124         JS_FreeValue(ctx, method);
  44125         goto fail;
  44126     }
  44127     it = js_malloc(ctx, sizeof(*it));
  44128     if (!it) {
  44129         JS_FreeValue(ctx, obj);
  44130         JS_FreeValue(ctx, method);
  44131         goto fail;
  44132     }
  44133     it->kind = magic;
  44134     it->obj = JS_DupValue(ctx, this_val);
  44135     it->func = JS_DupValue(ctx, func);
  44136     it->next = method;
  44137     it->inner = JS_UNDEFINED;
  44138     it->count = count;
  44139     it->executing = 0;
  44140     it->done = 0;
  44141     JS_SetOpaque(obj, it);
  44142     return obj;
  44143 range_error:
  44144     JS_ThrowRangeError(ctx, "must be positive");
  44145 fail:
  44146     JS_IteratorClose(ctx, this_val, TRUE);
  44147     return JS_EXCEPTION;
  44148 }
  44149 
  44150 static JSValue js_iterator_proto_func(JSContext *ctx, JSValueConst this_val,
  44151                                       int argc, JSValueConst *argv, int magic)
  44152 {
  44153     JSValue item, method, ret, func, index_val, r;
  44154     JSValueConst args[2];
  44155     int64_t idx;
  44156     int done;
  44157 
  44158     if (!JS_IsObject(this_val))
  44159         return JS_ThrowTypeErrorNotAnObject(ctx);
  44160     func = JS_UNDEFINED;
  44161     method = JS_UNDEFINED;
  44162     
  44163     if (check_function(ctx, argv[0]))
  44164         goto fail;
  44165     func = JS_DupValue(ctx, argv[0]);
  44166     method = JS_GetProperty(ctx, this_val, JS_ATOM_next);
  44167     if (JS_IsException(method))
  44168         goto fail_no_close;
  44169 
  44170     r = JS_UNDEFINED;
  44171 
  44172     switch(magic) {
  44173     case JS_ITERATOR_HELPER_KIND_EVERY:
  44174         {
  44175             r = JS_TRUE;
  44176             for (idx = 0; /*empty*/; idx++) {
  44177                 item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);
  44178                 if (JS_IsException(item))
  44179                     goto fail_no_close;
  44180                 if (done)
  44181                     break;
  44182                 index_val = JS_NewInt64(ctx, idx);
  44183                 args[0] = item;
  44184                 args[1] = index_val;
  44185                 ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args);
  44186                 JS_FreeValue(ctx, item);
  44187                 JS_FreeValue(ctx, index_val);
  44188                 if (JS_IsException(ret))
  44189                     goto fail;
  44190                 if (!JS_ToBoolFree(ctx, ret)) {
  44191                     if (JS_IteratorClose(ctx, this_val, FALSE) < 0)
  44192                         r = JS_EXCEPTION;
  44193                     else
  44194                         r = JS_FALSE;
  44195                     break;
  44196                 }
  44197                 index_val = JS_UNDEFINED;
  44198                 ret = JS_UNDEFINED;
  44199                 item = JS_UNDEFINED;
  44200             }
  44201         }
  44202         break;
  44203     case JS_ITERATOR_HELPER_KIND_FIND:
  44204         {
  44205             for (idx = 0; /*empty*/; idx++) {
  44206                 item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);
  44207                 if (JS_IsException(item))
  44208                     goto fail_no_close;
  44209                 if (done)
  44210                     break;
  44211                 index_val = JS_NewInt64(ctx, idx);
  44212                 args[0] = item;
  44213                 args[1] = index_val;
  44214                 ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args);
  44215                 JS_FreeValue(ctx, index_val);
  44216                 if (JS_IsException(ret)) {
  44217                     JS_FreeValue(ctx, item);
  44218                     goto fail;
  44219                 }
  44220                 if (JS_ToBoolFree(ctx, ret)) {
  44221                     if (JS_IteratorClose(ctx, this_val, FALSE) < 0) {
  44222                         JS_FreeValue(ctx, item);
  44223                         r = JS_EXCEPTION;
  44224                     } else {
  44225                         r = item;
  44226                     }
  44227                     break;
  44228                 }
  44229                 JS_FreeValue(ctx, item);
  44230                 index_val = JS_UNDEFINED;
  44231                 ret = JS_UNDEFINED;
  44232                 item = JS_UNDEFINED;
  44233             }
  44234         }
  44235         break;
  44236     case JS_ITERATOR_HELPER_KIND_FOR_EACH:
  44237         {
  44238             for (idx = 0; /*empty*/; idx++) {
  44239                 item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);
  44240                 if (JS_IsException(item))
  44241                     goto fail_no_close;
  44242                 if (done)
  44243                     break;
  44244                 index_val = JS_NewInt64(ctx, idx);
  44245                 args[0] = item;
  44246                 args[1] = index_val;
  44247                 ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args);
  44248                 JS_FreeValue(ctx, item);
  44249                 JS_FreeValue(ctx, index_val);
  44250                 if (JS_IsException(ret))
  44251                     goto fail;
  44252                 JS_FreeValue(ctx, ret);
  44253                 index_val = JS_UNDEFINED;
  44254                 ret = JS_UNDEFINED;
  44255                 item = JS_UNDEFINED;
  44256             }
  44257         }
  44258         break;
  44259     case JS_ITERATOR_HELPER_KIND_SOME:
  44260         {
  44261             r = JS_FALSE;
  44262             for (idx = 0; /*empty*/; idx++) {
  44263                 item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);
  44264                 if (JS_IsException(item))
  44265                     goto fail_no_close;
  44266                 if (done)
  44267                     break;
  44268                 index_val = JS_NewInt64(ctx, idx);
  44269                 args[0] = item;
  44270                 args[1] = index_val;
  44271                 ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args);
  44272                 JS_FreeValue(ctx, item);
  44273                 JS_FreeValue(ctx, index_val);
  44274                 if (JS_IsException(ret))
  44275                     goto fail;
  44276                 if (JS_ToBoolFree(ctx, ret)) {
  44277                     if (JS_IteratorClose(ctx, this_val, FALSE) < 0)
  44278                         r = JS_EXCEPTION;
  44279                     else
  44280                         r = JS_TRUE;
  44281                     break;
  44282                 }
  44283                 index_val = JS_UNDEFINED;
  44284                 ret = JS_UNDEFINED;
  44285                 item = JS_UNDEFINED;
  44286             }
  44287         }
  44288         break;
  44289     default:
  44290         abort();
  44291         break;
  44292     }
  44293 
  44294     JS_FreeValue(ctx, func);
  44295     JS_FreeValue(ctx, method);
  44296     return r;
  44297  fail:
  44298     JS_IteratorClose(ctx, this_val, TRUE);
  44299  fail_no_close:
  44300     JS_FreeValue(ctx, func);
  44301     JS_FreeValue(ctx, method);
  44302     return JS_EXCEPTION;
  44303 }
  44304 
  44305 static JSValue js_iterator_proto_reduce(JSContext *ctx, JSValueConst this_val,
  44306                                         int argc, JSValueConst *argv)
  44307 {
  44308     JSValue item, method, ret, func, index_val, acc;
  44309     JSValueConst args[3];
  44310     int64_t idx;
  44311     int done;
  44312 
  44313     if (!JS_IsObject(this_val))
  44314         return JS_ThrowTypeErrorNotAnObject(ctx);
  44315     acc = JS_UNDEFINED;
  44316     func = JS_UNDEFINED;
  44317     method = JS_UNDEFINED;
  44318     if (check_function(ctx, argv[0]))
  44319         goto exception;
  44320     func = JS_DupValue(ctx, argv[0]);
  44321     method = JS_GetProperty(ctx, this_val, JS_ATOM_next);
  44322     if (JS_IsException(method))
  44323         goto exception;
  44324     if (argc > 1) {
  44325         acc = JS_DupValue(ctx, argv[1]);
  44326         idx = 0;
  44327     } else {
  44328         acc = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);
  44329         if (JS_IsException(acc))
  44330             goto exception_no_close;
  44331         if (done) {
  44332             JS_ThrowTypeError(ctx, "empty iterator");
  44333             goto exception;
  44334         }
  44335         idx = 1;
  44336     }
  44337     for (/* empty */; /*empty*/; idx++) {
  44338         item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);
  44339         if (JS_IsException(item))
  44340             goto exception_no_close;
  44341         if (done)
  44342             break;
  44343         index_val = JS_NewInt64(ctx, idx);
  44344         args[0] = acc;
  44345         args[1] = item;
  44346         args[2] = index_val;
  44347         ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args);
  44348         JS_FreeValue(ctx, item);
  44349         JS_FreeValue(ctx, index_val);
  44350         if (JS_IsException(ret))
  44351             goto exception;
  44352         JS_FreeValue(ctx, acc);
  44353         acc = ret;
  44354         index_val = JS_UNDEFINED;
  44355         ret = JS_UNDEFINED;
  44356         item = JS_UNDEFINED;
  44357     }
  44358     JS_FreeValue(ctx, func);
  44359     JS_FreeValue(ctx, method);
  44360     return acc;
  44361  exception:
  44362     JS_IteratorClose(ctx, this_val, TRUE);
  44363  exception_no_close:
  44364     JS_FreeValue(ctx, acc);
  44365     JS_FreeValue(ctx, func);
  44366     JS_FreeValue(ctx, method);
  44367     return JS_EXCEPTION;
  44368 }
  44369 
  44370 static JSValue js_iterator_proto_toArray(JSContext *ctx, JSValueConst this_val,
  44371                                          int argc, JSValueConst *argv)
  44372 {
  44373     JSValue item, method, result;
  44374     int64_t idx;
  44375     int done;
  44376 
  44377     result = JS_UNDEFINED;
  44378     if (!JS_IsObject(this_val))
  44379         return JS_ThrowTypeErrorNotAnObject(ctx);
  44380     method = JS_GetProperty(ctx, this_val, JS_ATOM_next);
  44381     if (JS_IsException(method))
  44382         return JS_EXCEPTION;
  44383     result = JS_NewArray(ctx);
  44384     if (JS_IsException(result))
  44385         goto exception;
  44386     for (idx = 0; /*empty*/; idx++) {
  44387         item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);
  44388         if (JS_IsException(item))
  44389             goto exception;
  44390         if (done)
  44391             break;
  44392         if (JS_DefinePropertyValueInt64(ctx, result, idx, item,
  44393                                         JS_PROP_C_W_E | JS_PROP_THROW) < 0)
  44394             goto exception;
  44395     }
  44396     if (JS_SetProperty(ctx, result, JS_ATOM_length, JS_NewUint32(ctx, idx)) < 0)
  44397         goto exception;
  44398     JS_FreeValue(ctx, method);
  44399     return result;
  44400 exception:
  44401     JS_FreeValue(ctx, result);
  44402     JS_FreeValue(ctx, method);
  44403     return JS_EXCEPTION;
  44404 }
  44405 
  44406 static JSValue js_iterator_proto_iterator(JSContext *ctx, JSValueConst this_val,
  44407                                           int argc, JSValueConst *argv)
  44408 {
  44409     return JS_DupValue(ctx, this_val);
  44410 }
  44411 
  44412 static JSValue js_iterator_proto_get_toStringTag(JSContext *ctx, JSValueConst this_val)
  44413 {
  44414     return JS_AtomToString(ctx, JS_ATOM_Iterator);
  44415 }
  44416 
  44417 static JSValue js_iterator_proto_set_toStringTag(JSContext *ctx, JSValueConst this_val, JSValueConst val)
  44418 {
  44419     int res;
  44420 
  44421     if (!JS_IsObject(this_val))
  44422         return JS_ThrowTypeErrorNotAnObject(ctx);
  44423     if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_ITERATOR]))
  44424         return JS_ThrowTypeError(ctx, "Cannot assign to read only property");
  44425     res = JS_GetOwnProperty(ctx, NULL, this_val, JS_ATOM_Symbol_toStringTag);
  44426     if (res < 0)
  44427         return JS_EXCEPTION;
  44428     if (res) {
  44429         if (JS_SetProperty(ctx, this_val, JS_ATOM_Symbol_toStringTag, JS_DupValue(ctx, val)) < 0)
  44430             return JS_EXCEPTION;
  44431     } else {
  44432         if (JS_DefinePropertyValue(ctx, this_val, JS_ATOM_Symbol_toStringTag, JS_DupValue(ctx, val), JS_PROP_C_W_E) < 0)
  44433             return JS_EXCEPTION;
  44434     }
  44435     return JS_UNDEFINED;
  44436 }
  44437 
  44438 /* Iterator Helper */
  44439 
  44440 static void js_iterator_helper_finalizer(JSRuntime *rt, JSValue val)
  44441 {
  44442     JSObject *p = JS_VALUE_GET_OBJ(val);
  44443     JSIteratorHelperData *it = p->u.iterator_helper_data;
  44444     if (it) {
  44445         JS_FreeValueRT(rt, it->obj);
  44446         JS_FreeValueRT(rt, it->func);
  44447         JS_FreeValueRT(rt, it->next);
  44448         JS_FreeValueRT(rt, it->inner);
  44449         js_free_rt(rt, it);
  44450     }
  44451 }
  44452 
  44453 static void js_iterator_helper_mark(JSRuntime *rt, JSValueConst val,
  44454                                    JS_MarkFunc *mark_func)
  44455 {
  44456     JSObject *p = JS_VALUE_GET_OBJ(val);
  44457     JSIteratorHelperData *it = p->u.iterator_helper_data;
  44458     if (it) {
  44459         JS_MarkValue(rt, it->obj, mark_func);
  44460         JS_MarkValue(rt, it->func, mark_func);
  44461         JS_MarkValue(rt, it->next, mark_func);
  44462         JS_MarkValue(rt, it->inner, mark_func);
  44463     }
  44464 }
  44465 
  44466 static JSValue js_iterator_helper_next(JSContext *ctx, JSValueConst this_val,
  44467                                       int argc, JSValueConst *argv,
  44468                                       int *pdone, int magic)
  44469 {
  44470     JSIteratorHelperData *it;
  44471     JSValue ret;
  44472 
  44473     *pdone = FALSE;
  44474 
  44475     it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ITERATOR_HELPER);
  44476     if (!it)
  44477         return JS_EXCEPTION;
  44478     if (it->executing)
  44479         return JS_ThrowTypeError(ctx, "cannot invoke a running iterator");
  44480     if (it->done) {
  44481         *pdone = TRUE;
  44482         return JS_UNDEFINED;
  44483     }
  44484 
  44485     it->executing = 1;
  44486 
  44487     switch (it->kind) {
  44488     case JS_ITERATOR_HELPER_KIND_DROP:
  44489         {
  44490             JSValue item, method;
  44491             if (magic == GEN_MAGIC_NEXT) {
  44492                 method = JS_DupValue(ctx, it->next);
  44493             } else {
  44494                 method = JS_GetProperty(ctx, it->obj, JS_ATOM_return);
  44495                 if (JS_IsException(method))
  44496                     goto fail;
  44497             }
  44498             while (it->count > 0) {
  44499                 it->count--;
  44500                 item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone);
  44501                 if (JS_IsException(item)) {
  44502                     JS_FreeValue(ctx, method);
  44503                     goto fail_no_close;
  44504                 }
  44505                 JS_FreeValue(ctx, item);
  44506                 if (magic == GEN_MAGIC_RETURN)
  44507                     *pdone = TRUE;
  44508                 if (*pdone) {
  44509                     JS_FreeValue(ctx, method);
  44510                     ret = JS_UNDEFINED;
  44511                     goto done;
  44512                 }
  44513             }
  44514 
  44515             item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone);
  44516             JS_FreeValue(ctx, method);
  44517             if (JS_IsException(item))
  44518                 goto fail_no_close;
  44519             ret = item;
  44520             goto done;
  44521         }
  44522         break;
  44523     case JS_ITERATOR_HELPER_KIND_FILTER:
  44524         {
  44525             JSValue item, method, selected, index_val;
  44526             JSValueConst args[2];
  44527             if (magic == GEN_MAGIC_NEXT) {
  44528                 method = JS_DupValue(ctx, it->next);
  44529             } else {
  44530                 method = JS_GetProperty(ctx, it->obj, JS_ATOM_return);
  44531                 if (JS_IsException(method))
  44532                     goto fail;
  44533             }
  44534         filter_again:
  44535             item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone);
  44536             if (JS_IsException(item)) {
  44537                 JS_FreeValue(ctx, method);
  44538                 goto fail_no_close;
  44539             }
  44540             if (*pdone || magic == GEN_MAGIC_RETURN) {
  44541                 JS_FreeValue(ctx, method);
  44542                 ret = item;
  44543                 goto done;
  44544             }
  44545             index_val = JS_NewInt64(ctx, it->count++);
  44546             args[0] = item;
  44547             args[1] = index_val;
  44548             selected = JS_Call(ctx, it->func, JS_UNDEFINED, countof(args), args);
  44549             JS_FreeValue(ctx, index_val);
  44550             if (JS_IsException(selected)) {
  44551                 JS_FreeValue(ctx, item);
  44552                 JS_FreeValue(ctx, method);
  44553                 goto fail;
  44554             }
  44555             if (JS_ToBoolFree(ctx, selected)) {
  44556                 JS_FreeValue(ctx, method);
  44557                 ret = item;
  44558                 goto done;
  44559             }
  44560             JS_FreeValue(ctx, item);
  44561             goto filter_again;
  44562         }
  44563         break;
  44564     case JS_ITERATOR_HELPER_KIND_FLAT_MAP:
  44565         {
  44566             JSValue item, method, index_val, iter;
  44567             JSValueConst args[2];
  44568         flat_map_again:
  44569             if (JS_IsUndefined(it->inner)) {
  44570                 if (magic == GEN_MAGIC_NEXT) {
  44571                     method = JS_DupValue(ctx, it->next);
  44572                 } else {
  44573                     method = JS_GetProperty(ctx, it->obj, JS_ATOM_return);
  44574                     if (JS_IsException(method))
  44575                         goto fail;
  44576                 }
  44577                 item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone);
  44578                 JS_FreeValue(ctx, method);
  44579                 if (JS_IsException(item))
  44580                     goto fail_no_close;
  44581                 if (*pdone || magic == GEN_MAGIC_RETURN) {
  44582                     ret = item;
  44583                     goto done;
  44584                 }
  44585                 index_val = JS_NewInt64(ctx, it->count++);
  44586                 args[0] = item;
  44587                 args[1] = index_val;
  44588                 ret = JS_Call(ctx, it->func, JS_UNDEFINED, countof(args), args);
  44589                 JS_FreeValue(ctx, item);
  44590                 JS_FreeValue(ctx, index_val);
  44591                 if (JS_IsException(ret))
  44592                     goto fail;
  44593                 if (!JS_IsObject(ret)) {
  44594                     JS_FreeValue(ctx, ret);
  44595                     JS_ThrowTypeError(ctx, "not an object");
  44596                     goto fail;
  44597                 }
  44598                 method = JS_GetProperty(ctx, ret, JS_ATOM_Symbol_iterator);
  44599                 if (JS_IsException(method)) {
  44600                     JS_FreeValue(ctx, ret);
  44601                     goto fail;
  44602                 }
  44603                 if (JS_IsNull(method) || JS_IsUndefined(method)) {
  44604                     JS_FreeValue(ctx, method);
  44605                     iter = ret;
  44606                 } else {
  44607                     iter = JS_GetIterator2(ctx, ret, method);
  44608                     JS_FreeValue(ctx, method);
  44609                     JS_FreeValue(ctx, ret);
  44610                     if (JS_IsException(iter))
  44611                         goto fail;
  44612                 }
  44613 
  44614                 it->inner = iter;
  44615             }
  44616 
  44617             if (magic == GEN_MAGIC_NEXT)
  44618                 method = JS_GetProperty(ctx, it->inner, JS_ATOM_next);
  44619             else
  44620                 method = JS_GetProperty(ctx, it->inner, JS_ATOM_return);
  44621             if (JS_IsException(method)) {
  44622             inner_fail:
  44623                 JS_IteratorClose(ctx, it->inner, FALSE);
  44624                 JS_FreeValue(ctx, it->inner);
  44625                 it->inner = JS_UNDEFINED;
  44626                 goto fail;
  44627             }
  44628             if (magic == GEN_MAGIC_RETURN && (JS_IsUndefined(method) || JS_IsNull(method))) {
  44629                 goto inner_end;
  44630             } else {
  44631                 item = JS_IteratorNext(ctx, it->inner, method, 0, NULL, pdone);
  44632                 JS_FreeValue(ctx, method);
  44633                 if (JS_IsException(item))
  44634                     goto inner_fail;
  44635             }
  44636             if (*pdone) {
  44637             inner_end:
  44638                 *pdone = FALSE; // The outer iterator must continue.
  44639                 JS_IteratorClose(ctx, it->inner, FALSE);
  44640                 JS_FreeValue(ctx, it->inner);
  44641                 it->inner = JS_UNDEFINED;
  44642                 goto flat_map_again;
  44643             }
  44644             ret = item;
  44645             goto done;
  44646         }
  44647         break;
  44648     case JS_ITERATOR_HELPER_KIND_MAP:
  44649         {
  44650             JSValue item, method, index_val;
  44651             JSValueConst args[2];
  44652             if (magic == GEN_MAGIC_NEXT) {
  44653                 method = JS_DupValue(ctx, it->next);
  44654             } else {
  44655                 method = JS_GetProperty(ctx, it->obj, JS_ATOM_return);
  44656                 if (JS_IsException(method))
  44657                     goto fail;
  44658             }
  44659             item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone);
  44660             JS_FreeValue(ctx, method);
  44661             if (JS_IsException(item))
  44662                 goto fail_no_close;
  44663             if (*pdone || magic == GEN_MAGIC_RETURN) {
  44664                 ret = item;
  44665                 goto done;
  44666             }
  44667             index_val = JS_NewInt64(ctx, it->count++);
  44668             args[0] = item;
  44669             args[1] = index_val;
  44670             ret = JS_Call(ctx, it->func, JS_UNDEFINED, countof(args), args);
  44671             JS_FreeValue(ctx, index_val);
  44672             JS_FreeValue(ctx, item);
  44673             if (JS_IsException(ret))
  44674                 goto fail;
  44675             goto done;
  44676         }
  44677         break;
  44678     case JS_ITERATOR_HELPER_KIND_TAKE:
  44679         {
  44680             JSValue item, method;
  44681             if (it->count > 0) {
  44682                 if (magic == GEN_MAGIC_NEXT) {
  44683                     method = JS_DupValue(ctx, it->next);
  44684                 } else {
  44685                     method = JS_GetProperty(ctx, it->obj, JS_ATOM_return);
  44686                     if (JS_IsException(method))
  44687                         goto fail;
  44688                 }
  44689                 it->count--;
  44690                 item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone);
  44691                 JS_FreeValue(ctx, method);
  44692                 if (JS_IsException(item))
  44693                     goto fail_no_close;
  44694                 ret = item;
  44695                 goto done;
  44696             }
  44697 
  44698             *pdone = TRUE;
  44699             if (JS_IteratorClose(ctx, it->obj, FALSE))
  44700                 ret = JS_EXCEPTION;
  44701             else
  44702                 ret = JS_UNDEFINED;
  44703             goto done;
  44704         }
  44705         break;
  44706     default:
  44707         abort();
  44708     }
  44709 
  44710  done:
  44711     it->done = magic == GEN_MAGIC_NEXT ? *pdone : 1;
  44712     it->executing = 0;
  44713     return ret;
  44714  fail:
  44715     /* close the iterator object, preserving pending exception */
  44716     JS_IteratorClose(ctx, it->obj, TRUE);
  44717  fail_no_close:
  44718     ret = JS_EXCEPTION;
  44719     goto done;
  44720 }
  44721 
  44722 static const JSCFunctionListEntry js_iterator_funcs[] = {
  44723     JS_CFUNC_DEF("concat", 0, js_iterator_concat ),
  44724     JS_CFUNC_DEF("from", 1, js_iterator_from ),
  44725 };
  44726 
  44727 static const JSCFunctionListEntry js_iterator_proto_funcs[] = {
  44728     JS_CFUNC_MAGIC_DEF("drop", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_DROP ),
  44729     JS_CFUNC_MAGIC_DEF("filter", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_FILTER ),
  44730     JS_CFUNC_MAGIC_DEF("flatMap", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_FLAT_MAP ),
  44731     JS_CFUNC_MAGIC_DEF("map", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_MAP ),
  44732     JS_CFUNC_MAGIC_DEF("take", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_TAKE ),
  44733     JS_CFUNC_MAGIC_DEF("every", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_EVERY ),
  44734     JS_CFUNC_MAGIC_DEF("find", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_FIND),
  44735     JS_CFUNC_MAGIC_DEF("forEach", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_FOR_EACH ),
  44736     JS_CFUNC_MAGIC_DEF("some", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_SOME ),
  44737     JS_CFUNC_DEF("reduce", 1, js_iterator_proto_reduce ),
  44738     JS_CFUNC_DEF("toArray", 0, js_iterator_proto_toArray ),
  44739     JS_CFUNC_DEF("[Symbol.iterator]", 0, js_iterator_proto_iterator ),
  44740     JS_CGETSET_DEF("[Symbol.toStringTag]", js_iterator_proto_get_toStringTag, js_iterator_proto_set_toStringTag),
  44741 };
  44742 
  44743 static const JSCFunctionListEntry js_iterator_helper_proto_funcs[] = {
  44744     JS_ITERATOR_NEXT_DEF("next", 0, js_iterator_helper_next, GEN_MAGIC_NEXT ),
  44745     JS_ITERATOR_NEXT_DEF("return", 0, js_iterator_helper_next, GEN_MAGIC_RETURN ),
  44746     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Iterator Helper", JS_PROP_CONFIGURABLE ),
  44747 };
  44748 
  44749 static const JSCFunctionListEntry js_array_unscopables_funcs[] = {
  44750     JS_PROP_BOOL_DEF("at", TRUE, JS_PROP_C_W_E),
  44751     JS_PROP_BOOL_DEF("copyWithin", TRUE, JS_PROP_C_W_E),
  44752     JS_PROP_BOOL_DEF("entries", TRUE, JS_PROP_C_W_E),
  44753     JS_PROP_BOOL_DEF("fill", TRUE, JS_PROP_C_W_E),
  44754     JS_PROP_BOOL_DEF("find", TRUE, JS_PROP_C_W_E),
  44755     JS_PROP_BOOL_DEF("findIndex", TRUE, JS_PROP_C_W_E),
  44756     JS_PROP_BOOL_DEF("findLast", TRUE, JS_PROP_C_W_E),
  44757     JS_PROP_BOOL_DEF("findLastIndex", TRUE, JS_PROP_C_W_E),
  44758     JS_PROP_BOOL_DEF("flat", TRUE, JS_PROP_C_W_E),
  44759     JS_PROP_BOOL_DEF("flatMap", TRUE, JS_PROP_C_W_E),
  44760     JS_PROP_BOOL_DEF("includes", TRUE, JS_PROP_C_W_E),
  44761     JS_PROP_BOOL_DEF("keys", TRUE, JS_PROP_C_W_E),
  44762     JS_PROP_BOOL_DEF("toReversed", TRUE, JS_PROP_C_W_E),
  44763     JS_PROP_BOOL_DEF("toSorted", TRUE, JS_PROP_C_W_E),
  44764     JS_PROP_BOOL_DEF("toSpliced", TRUE, JS_PROP_C_W_E),
  44765     JS_PROP_BOOL_DEF("values", TRUE, JS_PROP_C_W_E),
  44766 };
  44767 
  44768 static const JSCFunctionListEntry js_array_proto_funcs[] = {
  44769     JS_CFUNC_DEF("at", 1, js_array_at ),
  44770     JS_CFUNC_DEF("with", 2, js_array_with ),
  44771     JS_CFUNC_DEF("concat", 1, js_array_concat ),
  44772     JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every ),
  44773     JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some ),
  44774     JS_CFUNC_MAGIC_DEF("forEach", 1, js_array_every, special_forEach ),
  44775     JS_CFUNC_MAGIC_DEF("map", 1, js_array_every, special_map ),
  44776     JS_CFUNC_MAGIC_DEF("filter", 1, js_array_every, special_filter ),
  44777     JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce ),
  44778     JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight ),
  44779     JS_CFUNC_DEF("fill", 1, js_array_fill ),
  44780     JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, ArrayFind ),
  44781     JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, ArrayFindIndex ),
  44782     JS_CFUNC_MAGIC_DEF("findLast", 1, js_array_find, ArrayFindLast ),
  44783     JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_array_find, ArrayFindLastIndex ),
  44784     JS_CFUNC_DEF("indexOf", 1, js_array_indexOf ),
  44785     JS_CFUNC_DEF("lastIndexOf", 1, js_array_lastIndexOf ),
  44786     JS_CFUNC_DEF("includes", 1, js_array_includes ),
  44787     JS_CFUNC_MAGIC_DEF("join", 1, js_array_join, 0 ),
  44788     JS_CFUNC_DEF("toString", 0, js_array_toString ),
  44789     JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_array_join, 1 ),
  44790     JS_CFUNC_MAGIC_DEF("pop", 0, js_array_pop, 0 ),
  44791     JS_CFUNC_MAGIC_DEF("push", 1, js_array_push, 0 ),
  44792     JS_CFUNC_MAGIC_DEF("shift", 0, js_array_pop, 1 ),
  44793     JS_CFUNC_MAGIC_DEF("unshift", 1, js_array_push, 1 ),
  44794     JS_CFUNC_DEF("reverse", 0, js_array_reverse ),
  44795     JS_CFUNC_DEF("toReversed", 0, js_array_toReversed ),
  44796     JS_CFUNC_DEF("sort", 1, js_array_sort ),
  44797     JS_CFUNC_DEF("toSorted", 1, js_array_toSorted ),
  44798     JS_CFUNC_MAGIC_DEF("slice", 2, js_array_slice, 0 ),
  44799     JS_CFUNC_MAGIC_DEF("splice", 2, js_array_slice, 1 ),
  44800     JS_CFUNC_DEF("toSpliced", 2, js_array_toSpliced ),
  44801     JS_CFUNC_DEF("copyWithin", 2, js_array_copyWithin ),
  44802     JS_CFUNC_MAGIC_DEF("flatMap", 1, js_array_flatten, 1 ),
  44803     JS_CFUNC_MAGIC_DEF("flat", 0, js_array_flatten, 0 ),
  44804     JS_CFUNC_MAGIC_DEF("values", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE ),
  44805     JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
  44806     JS_CFUNC_MAGIC_DEF("keys", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY ),
  44807     JS_CFUNC_MAGIC_DEF("entries", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE ),
  44808     JS_OBJECT_DEF("[Symbol.unscopables]", js_array_unscopables_funcs, countof(js_array_unscopables_funcs), JS_PROP_CONFIGURABLE ),
  44809 };
  44810 
  44811 static const JSCFunctionListEntry js_array_iterator_proto_funcs[] = {
  44812     JS_ITERATOR_NEXT_DEF("next", 0, js_array_iterator_next, 0 ),
  44813     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Array Iterator", JS_PROP_CONFIGURABLE ),
  44814 };
  44815 
  44816 /* Number */
  44817 
  44818 static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target,
  44819                                      int argc, JSValueConst *argv)
  44820 {
  44821     JSValue val, obj;
  44822     if (argc == 0) {
  44823         val = JS_NewInt32(ctx, 0);
  44824     } else {
  44825         val = JS_ToNumeric(ctx, argv[0]);
  44826         if (JS_IsException(val))
  44827             return val;
  44828         switch(JS_VALUE_GET_TAG(val)) {
  44829         case JS_TAG_SHORT_BIG_INT:
  44830             val = JS_NewInt64(ctx, JS_VALUE_GET_SHORT_BIG_INT(val));
  44831             if (JS_IsException(val))
  44832                 return val;
  44833             break;
  44834         case JS_TAG_BIG_INT:
  44835             {
  44836                 JSBigInt *p = JS_VALUE_GET_PTR(val);
  44837                 double d;
  44838                 d = js_bigint_to_float64(ctx, p);
  44839                 JS_FreeValue(ctx, val);
  44840                 val = JS_NewFloat64(ctx, d);
  44841             }
  44842             break;
  44843         default:
  44844             break;
  44845         }
  44846     }
  44847     if (!JS_IsUndefined(new_target)) {
  44848         obj = js_create_from_ctor(ctx, new_target, JS_CLASS_NUMBER);
  44849         if (!JS_IsException(obj))
  44850             JS_SetObjectData(ctx, obj, val);
  44851         return obj;
  44852     } else {
  44853         return val;
  44854     }
  44855 }
  44856 
  44857 #if 0
  44858 static JSValue js_number___toInteger(JSContext *ctx, JSValueConst this_val,
  44859                                      int argc, JSValueConst *argv)
  44860 {
  44861     return JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[0]));
  44862 }
  44863 
  44864 static JSValue js_number___toLength(JSContext *ctx, JSValueConst this_val,
  44865                                     int argc, JSValueConst *argv)
  44866 {
  44867     int64_t v;
  44868     if (JS_ToLengthFree(ctx, &v, JS_DupValue(ctx, argv[0])))
  44869         return JS_EXCEPTION;
  44870     return JS_NewInt64(ctx, v);
  44871 }
  44872 #endif
  44873 
  44874 static JSValue js_number_isNaN(JSContext *ctx, JSValueConst this_val,
  44875                                int argc, JSValueConst *argv)
  44876 {
  44877     if (!JS_IsNumber(argv[0]))
  44878         return JS_FALSE;
  44879     return js_global_isNaN(ctx, this_val, argc, argv);
  44880 }
  44881 
  44882 static JSValue js_number_isFinite(JSContext *ctx, JSValueConst this_val,
  44883                                   int argc, JSValueConst *argv)
  44884 {
  44885     if (!JS_IsNumber(argv[0]))
  44886         return JS_FALSE;
  44887     return js_global_isFinite(ctx, this_val, argc, argv);
  44888 }
  44889 
  44890 static JSValue js_number_isInteger(JSContext *ctx, JSValueConst this_val,
  44891                                    int argc, JSValueConst *argv)
  44892 {
  44893     int ret;
  44894     ret = JS_NumberIsInteger(ctx, argv[0]);
  44895     if (ret < 0)
  44896         return JS_EXCEPTION;
  44897     else
  44898         return JS_NewBool(ctx, ret);
  44899 }
  44900 
  44901 static JSValue js_number_isSafeInteger(JSContext *ctx, JSValueConst this_val,
  44902                                        int argc, JSValueConst *argv)
  44903 {
  44904     double d;
  44905     if (!JS_IsNumber(argv[0]))
  44906         return JS_FALSE;
  44907     if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
  44908         return JS_EXCEPTION;
  44909     return JS_NewBool(ctx, is_safe_integer(d));
  44910 }
  44911 
  44912 static const JSCFunctionListEntry js_number_funcs[] = {
  44913     /* global ParseInt and parseFloat should be defined already or delayed */
  44914     JS_ALIAS_BASE_DEF("parseInt", "parseInt", 0 ),
  44915     JS_ALIAS_BASE_DEF("parseFloat", "parseFloat", 0 ),
  44916     JS_CFUNC_DEF("isNaN", 1, js_number_isNaN ),
  44917     JS_CFUNC_DEF("isFinite", 1, js_number_isFinite ),
  44918     JS_CFUNC_DEF("isInteger", 1, js_number_isInteger ),
  44919     JS_CFUNC_DEF("isSafeInteger", 1, js_number_isSafeInteger ),
  44920     JS_PROP_DOUBLE_DEF("MAX_VALUE", 1.7976931348623157e+308, 0 ),
  44921     JS_PROP_DOUBLE_DEF("MIN_VALUE", 5e-324, 0 ),
  44922     JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ),
  44923     JS_PROP_DOUBLE_DEF("NEGATIVE_INFINITY", -INFINITY, 0 ),
  44924     JS_PROP_DOUBLE_DEF("POSITIVE_INFINITY", INFINITY, 0 ),
  44925     JS_PROP_DOUBLE_DEF("EPSILON", 2.220446049250313e-16, 0 ), /* ES6 */
  44926     JS_PROP_DOUBLE_DEF("MAX_SAFE_INTEGER", 9007199254740991.0, 0 ), /* ES6 */
  44927     JS_PROP_DOUBLE_DEF("MIN_SAFE_INTEGER", -9007199254740991.0, 0 ), /* ES6 */
  44928     //JS_CFUNC_DEF("__toInteger", 1, js_number___toInteger ),
  44929     //JS_CFUNC_DEF("__toLength", 1, js_number___toLength ),
  44930 };
  44931 
  44932 static JSValue js_thisNumberValue(JSContext *ctx, JSValueConst this_val)
  44933 {
  44934     if (JS_IsNumber(this_val))
  44935         return JS_DupValue(ctx, this_val);
  44936 
  44937     if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
  44938         JSObject *p = JS_VALUE_GET_OBJ(this_val);
  44939         if (p->class_id == JS_CLASS_NUMBER) {
  44940             if (JS_IsNumber(p->u.object_data))
  44941                 return JS_DupValue(ctx, p->u.object_data);
  44942         }
  44943     }
  44944     return JS_ThrowTypeError(ctx, "not a number");
  44945 }
  44946 
  44947 static JSValue js_number_valueOf(JSContext *ctx, JSValueConst this_val,
  44948                                  int argc, JSValueConst *argv)
  44949 {
  44950     return js_thisNumberValue(ctx, this_val);
  44951 }
  44952 
  44953 static int js_get_radix(JSContext *ctx, JSValueConst val)
  44954 {
  44955     int radix;
  44956     if (JS_ToInt32Sat(ctx, &radix, val))
  44957         return -1;
  44958     if (radix < 2 || radix > 36) {
  44959         JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
  44960         return -1;
  44961     }
  44962     return radix;
  44963 }
  44964 
  44965 static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val,
  44966                                   int argc, JSValueConst *argv, int magic)
  44967 {
  44968     JSValue val;
  44969     int base, flags;
  44970     double d;
  44971 
  44972     val = js_thisNumberValue(ctx, this_val);
  44973     if (JS_IsException(val))
  44974         return val;
  44975     if (magic || JS_IsUndefined(argv[0])) {
  44976         base = 10;
  44977     } else {
  44978         base = js_get_radix(ctx, argv[0]);
  44979         if (base < 0)
  44980             goto fail;
  44981     }
  44982     if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) {
  44983         char buf1[70];
  44984         int len;
  44985         len = i64toa_radix(buf1, JS_VALUE_GET_INT(val), base);
  44986         return js_new_string8_len(ctx, buf1, len);
  44987     }
  44988     if (JS_ToFloat64Free(ctx, &d, val))
  44989         return JS_EXCEPTION;
  44990     flags = JS_DTOA_FORMAT_FREE;
  44991     if (base != 10)
  44992         flags |= JS_DTOA_EXP_DISABLED;
  44993     return js_dtoa2(ctx, d, base, 0, flags);
  44994  fail:
  44995     JS_FreeValue(ctx, val);
  44996     return JS_EXCEPTION;
  44997 }
  44998 
  44999 static JSValue js_number_toFixed(JSContext *ctx, JSValueConst this_val,
  45000                                  int argc, JSValueConst *argv)
  45001 {
  45002     JSValue val;
  45003     int f, flags;
  45004     double d;
  45005 
  45006     val = js_thisNumberValue(ctx, this_val);
  45007     if (JS_IsException(val))
  45008         return val;
  45009     if (JS_ToFloat64Free(ctx, &d, val))
  45010         return JS_EXCEPTION;
  45011     if (JS_ToInt32Sat(ctx, &f, argv[0]))
  45012         return JS_EXCEPTION;
  45013     if (f < 0 || f > 100)
  45014         return JS_ThrowRangeError(ctx, "invalid number of digits");
  45015     if (fabs(d) >= 1e21)
  45016         flags = JS_DTOA_FORMAT_FREE;
  45017     else
  45018         flags = JS_DTOA_FORMAT_FRAC;
  45019     return js_dtoa2(ctx, d, 10, f, flags);
  45020 }
  45021 
  45022 static JSValue js_number_toExponential(JSContext *ctx, JSValueConst this_val,
  45023                                        int argc, JSValueConst *argv)
  45024 {
  45025     JSValue val;
  45026     int f, flags;
  45027     double d;
  45028 
  45029     val = js_thisNumberValue(ctx, this_val);
  45030     if (JS_IsException(val))
  45031         return val;
  45032     if (JS_ToFloat64Free(ctx, &d, val))
  45033         return JS_EXCEPTION;
  45034     if (JS_ToInt32Sat(ctx, &f, argv[0]))
  45035         return JS_EXCEPTION;
  45036     if (!isfinite(d)) {
  45037         return JS_ToStringFree(ctx,  __JS_NewFloat64(ctx, d));
  45038     }
  45039     if (JS_IsUndefined(argv[0])) {
  45040         flags = JS_DTOA_FORMAT_FREE;
  45041         f = 0;
  45042     } else {
  45043         if (f < 0 || f > 100)
  45044             return JS_ThrowRangeError(ctx, "invalid number of digits");
  45045         f++;
  45046         flags = JS_DTOA_FORMAT_FIXED;
  45047     }
  45048     return js_dtoa2(ctx, d, 10, f, flags | JS_DTOA_EXP_ENABLED);
  45049 }
  45050 
  45051 static JSValue js_number_toPrecision(JSContext *ctx, JSValueConst this_val,
  45052                                      int argc, JSValueConst *argv)
  45053 {
  45054     JSValue val;
  45055     int p;
  45056     double d;
  45057 
  45058     val = js_thisNumberValue(ctx, this_val);
  45059     if (JS_IsException(val))
  45060         return val;
  45061     if (JS_ToFloat64Free(ctx, &d, val))
  45062         return JS_EXCEPTION;
  45063     if (JS_IsUndefined(argv[0]))
  45064         goto to_string;
  45065     if (JS_ToInt32Sat(ctx, &p, argv[0]))
  45066         return JS_EXCEPTION;
  45067     if (!isfinite(d)) {
  45068     to_string:
  45069         return JS_ToStringFree(ctx,  __JS_NewFloat64(ctx, d));
  45070     }
  45071     if (p < 1 || p > 100)
  45072         return JS_ThrowRangeError(ctx, "invalid number of digits");
  45073     return js_dtoa2(ctx, d, 10, p, JS_DTOA_FORMAT_FIXED);
  45074 }
  45075 
  45076 static const JSCFunctionListEntry js_number_proto_funcs[] = {
  45077     JS_CFUNC_DEF("toExponential", 1, js_number_toExponential ),
  45078     JS_CFUNC_DEF("toFixed", 1, js_number_toFixed ),
  45079     JS_CFUNC_DEF("toPrecision", 1, js_number_toPrecision ),
  45080     JS_CFUNC_MAGIC_DEF("toString", 1, js_number_toString, 0 ),
  45081     JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_number_toString, 1 ),
  45082     JS_CFUNC_DEF("valueOf", 0, js_number_valueOf ),
  45083 };
  45084 
  45085 static JSValue js_parseInt(JSContext *ctx, JSValueConst this_val,
  45086                            int argc, JSValueConst *argv)
  45087 {
  45088     const char *str, *p;
  45089     int radix, flags;
  45090     JSValue ret;
  45091 
  45092     str = JS_ToCString(ctx, argv[0]);
  45093     if (!str)
  45094         return JS_EXCEPTION;
  45095     if (JS_ToInt32(ctx, &radix, argv[1])) {
  45096         JS_FreeCString(ctx, str);
  45097         return JS_EXCEPTION;
  45098     }
  45099     if (radix != 0 && (radix < 2 || radix > 36)) {
  45100         ret = JS_NAN;
  45101     } else {
  45102         p = str;
  45103         p += skip_spaces(p);
  45104         flags = ATOD_INT_ONLY | ATOD_ACCEPT_PREFIX_AFTER_SIGN;
  45105         ret = js_atof(ctx, p, NULL, radix, flags);
  45106     }
  45107     JS_FreeCString(ctx, str);
  45108     return ret;
  45109 }
  45110 
  45111 static JSValue js_parseFloat(JSContext *ctx, JSValueConst this_val,
  45112                              int argc, JSValueConst *argv)
  45113 {
  45114     const char *str, *p;
  45115     JSValue ret;
  45116 
  45117     str = JS_ToCString(ctx, argv[0]);
  45118     if (!str)
  45119         return JS_EXCEPTION;
  45120     p = str;
  45121     p += skip_spaces(p);
  45122     ret = js_atof(ctx, p, NULL, 10, 0);
  45123     JS_FreeCString(ctx, str);
  45124     return ret;
  45125 }
  45126 
  45127 /* Boolean */
  45128 static JSValue js_boolean_constructor(JSContext *ctx, JSValueConst new_target,
  45129                                      int argc, JSValueConst *argv)
  45130 {
  45131     JSValue val, obj;
  45132     val = JS_NewBool(ctx, JS_ToBool(ctx, argv[0]));
  45133     if (!JS_IsUndefined(new_target)) {
  45134         obj = js_create_from_ctor(ctx, new_target, JS_CLASS_BOOLEAN);
  45135         if (!JS_IsException(obj))
  45136             JS_SetObjectData(ctx, obj, val);
  45137         return obj;
  45138     } else {
  45139         return val;
  45140     }
  45141 }
  45142 
  45143 static JSValue js_thisBooleanValue(JSContext *ctx, JSValueConst this_val)
  45144 {
  45145     if (JS_VALUE_GET_TAG(this_val) == JS_TAG_BOOL)
  45146         return JS_DupValue(ctx, this_val);
  45147 
  45148     if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
  45149         JSObject *p = JS_VALUE_GET_OBJ(this_val);
  45150         if (p->class_id == JS_CLASS_BOOLEAN) {
  45151             if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_BOOL)
  45152                 return p->u.object_data;
  45153         }
  45154     }
  45155     return JS_ThrowTypeError(ctx, "not a boolean");
  45156 }
  45157 
  45158 static JSValue js_boolean_toString(JSContext *ctx, JSValueConst this_val,
  45159                                    int argc, JSValueConst *argv)
  45160 {
  45161     JSValue val = js_thisBooleanValue(ctx, this_val);
  45162     if (JS_IsException(val))
  45163         return val;
  45164     return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ?
  45165                        JS_ATOM_true : JS_ATOM_false);
  45166 }
  45167 
  45168 static JSValue js_boolean_valueOf(JSContext *ctx, JSValueConst this_val,
  45169                                   int argc, JSValueConst *argv)
  45170 {
  45171     return js_thisBooleanValue(ctx, this_val);
  45172 }
  45173 
  45174 static const JSCFunctionListEntry js_boolean_proto_funcs[] = {
  45175     JS_CFUNC_DEF("toString", 0, js_boolean_toString ),
  45176     JS_CFUNC_DEF("valueOf", 0, js_boolean_valueOf ),
  45177 };
  45178 
  45179 /* String */
  45180 
  45181 static int js_string_get_own_property(JSContext *ctx,
  45182                                       JSPropertyDescriptor *desc,
  45183                                       JSValueConst obj, JSAtom prop)
  45184 {
  45185     JSObject *p;
  45186     JSString *p1;
  45187     uint32_t idx, ch;
  45188 
  45189     /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
  45190     if (__JS_AtomIsTaggedInt(prop)) {
  45191         p = JS_VALUE_GET_OBJ(obj);
  45192         if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
  45193             p1 = JS_VALUE_GET_STRING(p->u.object_data);
  45194             idx = __JS_AtomToUInt32(prop);
  45195             if (idx < p1->len) {
  45196                 if (desc) {
  45197                     ch = string_get(p1, idx);
  45198                     desc->flags = JS_PROP_ENUMERABLE;
  45199                     desc->value = js_new_string_char(ctx, ch);
  45200                     desc->getter = JS_UNDEFINED;
  45201                     desc->setter = JS_UNDEFINED;
  45202                 }
  45203                 return TRUE;
  45204             }
  45205         }
  45206     }
  45207     return FALSE;
  45208 }
  45209 
  45210 static int js_string_define_own_property(JSContext *ctx,
  45211                                          JSValueConst this_obj,
  45212                                          JSAtom prop, JSValueConst val,
  45213                                          JSValueConst getter,
  45214                                          JSValueConst setter, int flags)
  45215 {
  45216     uint32_t idx;
  45217     JSObject *p;
  45218     JSString *p1, *p2;
  45219 
  45220     if (__JS_AtomIsTaggedInt(prop)) {
  45221         idx = __JS_AtomToUInt32(prop);
  45222         p = JS_VALUE_GET_OBJ(this_obj);
  45223         if (JS_VALUE_GET_TAG(p->u.object_data) != JS_TAG_STRING)
  45224             goto def;
  45225         p1 = JS_VALUE_GET_STRING(p->u.object_data);
  45226         if (idx >= p1->len)
  45227             goto def;
  45228         if (!check_define_prop_flags(JS_PROP_ENUMERABLE, flags))
  45229             goto fail;
  45230         /* check that the same value is configured */
  45231         if (flags & JS_PROP_HAS_VALUE) {
  45232             if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
  45233                 goto fail;
  45234             p2 = JS_VALUE_GET_STRING(val);
  45235             if (p2->len != 1)
  45236                 goto fail;
  45237             if (string_get(p1, idx) != string_get(p2, 0)) {
  45238             fail:
  45239                 return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
  45240             }
  45241         }
  45242         return TRUE;
  45243     } else {
  45244     def:
  45245         return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter,
  45246                                  flags | JS_PROP_NO_EXOTIC);
  45247     }
  45248 }
  45249 
  45250 static int js_string_delete_property(JSContext *ctx,
  45251                                      JSValueConst obj, JSAtom prop)
  45252 {
  45253     uint32_t idx;
  45254 
  45255     if (__JS_AtomIsTaggedInt(prop)) {
  45256         idx = __JS_AtomToUInt32(prop);
  45257         if (idx < js_string_obj_get_length(ctx, obj)) {
  45258             return FALSE;
  45259         }
  45260     }
  45261     return TRUE;
  45262 }
  45263 
  45264 static const JSClassExoticMethods js_string_exotic_methods = {
  45265     .get_own_property = js_string_get_own_property,
  45266     .define_own_property = js_string_define_own_property,
  45267     .delete_property = js_string_delete_property,
  45268 };
  45269 
  45270 static JSValue js_string_constructor(JSContext *ctx, JSValueConst new_target,
  45271                                      int argc, JSValueConst *argv)
  45272 {
  45273     JSValue val, obj;
  45274     if (argc == 0) {
  45275         val = JS_AtomToString(ctx, JS_ATOM_empty_string);
  45276     } else {
  45277         if (JS_IsUndefined(new_target) && JS_IsSymbol(argv[0])) {
  45278             JSAtomStruct *p = JS_VALUE_GET_PTR(argv[0]);
  45279             val = JS_ConcatString3(ctx, "Symbol(", JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p)), ")");
  45280         } else {
  45281             val = JS_ToString(ctx, argv[0]);
  45282         }
  45283         if (JS_IsException(val))
  45284             return val;
  45285     }
  45286     if (!JS_IsUndefined(new_target)) {
  45287         JSString *p1 = JS_VALUE_GET_STRING(val);
  45288 
  45289         obj = js_create_from_ctor(ctx, new_target, JS_CLASS_STRING);
  45290         if (JS_IsException(obj)) {
  45291             JS_FreeValue(ctx, val);
  45292         } else {
  45293             JS_SetObjectData(ctx, obj, val);
  45294             JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, JS_NewInt32(ctx, p1->len), 0);
  45295         }
  45296         return obj;
  45297     } else {
  45298         return val;
  45299     }
  45300 }
  45301 
  45302 static JSValue js_thisStringValue(JSContext *ctx, JSValueConst this_val)
  45303 {
  45304     if (JS_VALUE_GET_TAG(this_val) == JS_TAG_STRING ||
  45305         JS_VALUE_GET_TAG(this_val) == JS_TAG_STRING_ROPE)
  45306         return JS_DupValue(ctx, this_val);
  45307 
  45308     if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
  45309         JSObject *p = JS_VALUE_GET_OBJ(this_val);
  45310         if (p->class_id == JS_CLASS_STRING) {
  45311             if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING)
  45312                 return JS_DupValue(ctx, p->u.object_data);
  45313         }
  45314     }
  45315     return JS_ThrowTypeError(ctx, "not a string");
  45316 }
  45317 
  45318 static JSValue js_string_fromCharCode(JSContext *ctx, JSValueConst this_val,
  45319                                       int argc, JSValueConst *argv)
  45320 {
  45321     int i;
  45322     StringBuffer b_s, *b = &b_s;
  45323 
  45324     string_buffer_init(ctx, b, argc);
  45325 
  45326     for(i = 0; i < argc; i++) {
  45327         int32_t c;
  45328         if (JS_ToInt32(ctx, &c, argv[i]) || string_buffer_putc16(b, c & 0xffff)) {
  45329             string_buffer_free(b);
  45330             return JS_EXCEPTION;
  45331         }
  45332     }
  45333     return string_buffer_end(b);
  45334 }
  45335 
  45336 static JSValue js_string_fromCodePoint(JSContext *ctx, JSValueConst this_val,
  45337                                        int argc, JSValueConst *argv)
  45338 {
  45339     double d;
  45340     int i, c;
  45341     StringBuffer b_s, *b = &b_s;
  45342 
  45343     /* XXX: could pre-compute string length if all arguments are JS_TAG_INT */
  45344 
  45345     if (string_buffer_init(ctx, b, argc))
  45346         goto fail;
  45347     for(i = 0; i < argc; i++) {
  45348         if (JS_VALUE_GET_TAG(argv[i]) == JS_TAG_INT) {
  45349             c = JS_VALUE_GET_INT(argv[i]);
  45350             if (c < 0 || c > 0x10ffff)
  45351                 goto range_error;
  45352         } else {
  45353             if (JS_ToFloat64(ctx, &d, argv[i]))
  45354                 goto fail;
  45355             if (isnan(d) || d < 0 || d > 0x10ffff || (c = (int)d) != d)
  45356                 goto range_error;
  45357         }
  45358         if (string_buffer_putc(b, c))
  45359             goto fail;
  45360     }
  45361     return string_buffer_end(b);
  45362 
  45363  range_error:
  45364     JS_ThrowRangeError(ctx, "invalid code point");
  45365  fail:
  45366     string_buffer_free(b);
  45367     return JS_EXCEPTION;
  45368 }
  45369 
  45370 static JSValue js_string_raw(JSContext *ctx, JSValueConst this_val,
  45371                              int argc, JSValueConst *argv)
  45372 {
  45373     // raw(temp,...a)
  45374     JSValue cooked, val, raw;
  45375     StringBuffer b_s, *b = &b_s;
  45376     int64_t i, n;
  45377 
  45378     string_buffer_init(ctx, b, 0);
  45379     raw = JS_UNDEFINED;
  45380     cooked = JS_ToObject(ctx, argv[0]);
  45381     if (JS_IsException(cooked))
  45382         goto exception;
  45383     raw = JS_ToObjectFree(ctx, JS_GetProperty(ctx, cooked, JS_ATOM_raw));
  45384     if (JS_IsException(raw))
  45385         goto exception;
  45386     if (js_get_length64(ctx, &n, raw) < 0)
  45387         goto exception;
  45388 
  45389     for (i = 0; i < n; i++) {
  45390         val = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, raw, i));
  45391         if (JS_IsException(val))
  45392             goto exception;
  45393         string_buffer_concat_value_free(b, val);
  45394         if (i < n - 1 && i + 1 < argc) {
  45395             if (string_buffer_concat_value(b, argv[i + 1]))
  45396                 goto exception;
  45397         }
  45398     }
  45399     JS_FreeValue(ctx, cooked);
  45400     JS_FreeValue(ctx, raw);
  45401     return string_buffer_end(b);
  45402 
  45403 exception:
  45404     JS_FreeValue(ctx, cooked);
  45405     JS_FreeValue(ctx, raw);
  45406     string_buffer_free(b);
  45407     return JS_EXCEPTION;
  45408 }
  45409 
  45410 /* only used in test262 */
  45411 JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val,
  45412                                  int argc, JSValueConst *argv)
  45413 {
  45414     uint32_t start, end, i, n;
  45415     StringBuffer b_s, *b = &b_s;
  45416 
  45417     if (JS_ToUint32(ctx, &start, argv[0]) ||
  45418         JS_ToUint32(ctx, &end, argv[1]))
  45419         return JS_EXCEPTION;
  45420     end = min_uint32(end, 0x10ffff + 1);
  45421 
  45422     if (start > end) {
  45423         start = end;
  45424     }
  45425     n = end - start;
  45426     if (end > 0x10000) {
  45427         n += end - max_uint32(start, 0x10000);
  45428     }
  45429     if (string_buffer_init2(ctx, b, n, end >= 0x100))
  45430         return JS_EXCEPTION;
  45431     for(i = start; i < end; i++) {
  45432         string_buffer_putc(b, i);
  45433     }
  45434     return string_buffer_end(b);
  45435 }
  45436 
  45437 #if 0
  45438 static JSValue js_string___isSpace(JSContext *ctx, JSValueConst this_val,
  45439                                    int argc, JSValueConst *argv)
  45440 {
  45441     int c;
  45442     if (JS_ToInt32(ctx, &c, argv[0]))
  45443         return JS_EXCEPTION;
  45444     return JS_NewBool(ctx, lre_is_space(c));
  45445 }
  45446 #endif
  45447 
  45448 static JSValue js_string_charCodeAt(JSContext *ctx, JSValueConst this_val,
  45449                                      int argc, JSValueConst *argv)
  45450 {
  45451     JSValue val, ret;
  45452     JSString *p;
  45453     int idx, c;
  45454 
  45455     val = JS_ToStringCheckObject(ctx, this_val);
  45456     if (JS_IsException(val))
  45457         return val;
  45458     p = JS_VALUE_GET_STRING(val);
  45459     if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
  45460         JS_FreeValue(ctx, val);
  45461         return JS_EXCEPTION;
  45462     }
  45463     if (idx < 0 || idx >= p->len) {
  45464         ret = JS_NAN;
  45465     } else {
  45466         c = string_get(p, idx);
  45467         ret = JS_NewInt32(ctx, c);
  45468     }
  45469     JS_FreeValue(ctx, val);
  45470     return ret;
  45471 }
  45472 
  45473 static JSValue js_string_charAt(JSContext *ctx, JSValueConst this_val,
  45474                                 int argc, JSValueConst *argv, int is_at)
  45475 {
  45476     JSValue val, ret;
  45477     JSString *p;
  45478     int idx, c;
  45479 
  45480     val = JS_ToStringCheckObject(ctx, this_val);
  45481     if (JS_IsException(val))
  45482         return val;
  45483     p = JS_VALUE_GET_STRING(val);
  45484     if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
  45485         JS_FreeValue(ctx, val);
  45486         return JS_EXCEPTION;
  45487     }
  45488     if (idx < 0 && is_at)
  45489         idx += p->len;
  45490     if (idx < 0 || idx >= p->len) {
  45491         if (is_at)
  45492             ret = JS_UNDEFINED;
  45493         else
  45494             ret = JS_AtomToString(ctx, JS_ATOM_empty_string);
  45495     } else {
  45496         c = string_get(p, idx);
  45497         ret = js_new_string_char(ctx, c);
  45498     }
  45499     JS_FreeValue(ctx, val);
  45500     return ret;
  45501 }
  45502 
  45503 static JSValue js_string_codePointAt(JSContext *ctx, JSValueConst this_val,
  45504                                      int argc, JSValueConst *argv)
  45505 {
  45506     JSValue val, ret;
  45507     JSString *p;
  45508     int idx, c;
  45509 
  45510     val = JS_ToStringCheckObject(ctx, this_val);
  45511     if (JS_IsException(val))
  45512         return val;
  45513     p = JS_VALUE_GET_STRING(val);
  45514     if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
  45515         JS_FreeValue(ctx, val);
  45516         return JS_EXCEPTION;
  45517     }
  45518     if (idx < 0 || idx >= p->len) {
  45519         ret = JS_UNDEFINED;
  45520     } else {
  45521         c = string_getc(p, &idx);
  45522         ret = JS_NewInt32(ctx, c);
  45523     }
  45524     JS_FreeValue(ctx, val);
  45525     return ret;
  45526 }
  45527 
  45528 static JSValue js_string_concat(JSContext *ctx, JSValueConst this_val,
  45529                                 int argc, JSValueConst *argv)
  45530 {
  45531     JSValue r;
  45532     int i;
  45533 
  45534     /* XXX: Use more efficient method */
  45535     /* XXX: This method is OK if r has a single refcount */
  45536     /* XXX: should use string_buffer? */
  45537     r = JS_ToStringCheckObject(ctx, this_val);
  45538     for (i = 0; i < argc; i++) {
  45539         if (JS_IsException(r))
  45540             break;
  45541         r = JS_ConcatString(ctx, r, JS_DupValue(ctx, argv[i]));
  45542     }
  45543     return r;
  45544 }
  45545 
  45546 static int string_cmp(JSString *p1, JSString *p2, int x1, int x2, int len)
  45547 {
  45548     int i, c1, c2;
  45549     for (i = 0; i < len; i++) {
  45550         if ((c1 = string_get(p1, x1 + i)) != (c2 = string_get(p2, x2 + i)))
  45551             return c1 - c2;
  45552     }
  45553     return 0;
  45554 }
  45555 
  45556 static int string_indexof_char(JSString *p, int c, int from)
  45557 {
  45558     /* assuming 0 <= from <= p->len */
  45559     int i, len = p->len;
  45560     if (p->is_wide_char) {
  45561         for (i = from; i < len; i++) {
  45562             if (p->u.str16[i] == c)
  45563                 return i;
  45564         }
  45565     } else {
  45566         if ((c & ~0xff) == 0) {
  45567             for (i = from; i < len; i++) {
  45568                 if (p->u.str8[i] == (uint8_t)c)
  45569                     return i;
  45570             }
  45571         }
  45572     }
  45573     return -1;
  45574 }
  45575 
  45576 static int string_indexof(JSString *p1, JSString *p2, int from)
  45577 {
  45578     /* assuming 0 <= from <= p1->len */
  45579     int c, i, j, len1 = p1->len, len2 = p2->len;
  45580     if (len2 == 0)
  45581         return from;
  45582     for (i = from, c = string_get(p2, 0); i + len2 <= len1; i = j + 1) {
  45583         j = string_indexof_char(p1, c, i);
  45584         if (j < 0 || j + len2 > len1)
  45585             break;
  45586         if (!string_cmp(p1, p2, j + 1, 1, len2 - 1))
  45587             return j;
  45588     }
  45589     return -1;
  45590 }
  45591 
  45592 static int64_t string_advance_index(JSString *p, int64_t index, BOOL unicode)
  45593 {
  45594     if (!unicode || index >= p->len || !p->is_wide_char) {
  45595         index++;
  45596     } else {
  45597         int index32 = (int)index;
  45598         string_getc(p, &index32);
  45599         index = index32;
  45600     }
  45601     return index;
  45602 }
  45603 
  45604 /* return the position of the first invalid character in the string or
  45605    -1 if none */
  45606 static int js_string_find_invalid_codepoint(JSString *p)
  45607 {
  45608     int i;
  45609     if (!p->is_wide_char)
  45610         return -1;
  45611     for(i = 0; i < p->len; i++) {
  45612         uint32_t c = p->u.str16[i];
  45613         if (is_surrogate(c)) {
  45614             if (is_hi_surrogate(c) && (i + 1) < p->len
  45615             &&  is_lo_surrogate(p->u.str16[i + 1])) {
  45616                 i++;
  45617             } else {
  45618                 return i;
  45619             }
  45620         }
  45621     }
  45622     return -1;
  45623 }
  45624 
  45625 static JSValue js_string_isWellFormed(JSContext *ctx, JSValueConst this_val,
  45626                                       int argc, JSValueConst *argv)
  45627 {
  45628     JSValue str;
  45629     JSString *p;
  45630     BOOL ret;
  45631 
  45632     str = JS_ToStringCheckObject(ctx, this_val);
  45633     if (JS_IsException(str))
  45634         return JS_EXCEPTION;
  45635     p = JS_VALUE_GET_STRING(str);
  45636     ret = (js_string_find_invalid_codepoint(p) < 0);
  45637     JS_FreeValue(ctx, str);
  45638     return JS_NewBool(ctx, ret);
  45639 }
  45640 
  45641 static JSValue js_string_toWellFormed(JSContext *ctx, JSValueConst this_val,
  45642                                       int argc, JSValueConst *argv)
  45643 {
  45644     JSValue str, ret;
  45645     JSString *p;
  45646     int i;
  45647 
  45648     str = JS_ToStringCheckObject(ctx, this_val);
  45649     if (JS_IsException(str))
  45650         return JS_EXCEPTION;
  45651 
  45652     p = JS_VALUE_GET_STRING(str);
  45653     /* avoid reallocating the string if it is well-formed */
  45654     i = js_string_find_invalid_codepoint(p);
  45655     if (i < 0)
  45656         return str;
  45657 
  45658     ret = js_new_string16_len(ctx, p->u.str16, p->len);
  45659     JS_FreeValue(ctx, str);
  45660     if (JS_IsException(ret))
  45661         return JS_EXCEPTION;
  45662 
  45663     p = JS_VALUE_GET_STRING(ret);
  45664     for (; i < p->len; i++) {
  45665         uint32_t c = p->u.str16[i];
  45666         if (is_surrogate(c)) {
  45667             if (is_hi_surrogate(c) && (i + 1) < p->len
  45668             &&  is_lo_surrogate(p->u.str16[i + 1])) {
  45669                 i++;
  45670             } else {
  45671                 p->u.str16[i] = 0xFFFD;
  45672             }
  45673         }
  45674     }
  45675     return ret;
  45676 }
  45677 
  45678 static JSValue js_string_indexOf(JSContext *ctx, JSValueConst this_val,
  45679                                  int argc, JSValueConst *argv, int lastIndexOf)
  45680 {
  45681     JSValue str, v;
  45682     int i, len, v_len, pos, start, stop, ret, inc;
  45683     JSString *p;
  45684     JSString *p1;
  45685 
  45686     str = JS_ToStringCheckObject(ctx, this_val);
  45687     if (JS_IsException(str))
  45688         return str;
  45689     v = JS_ToString(ctx, argv[0]);
  45690     if (JS_IsException(v))
  45691         goto fail;
  45692     p = JS_VALUE_GET_STRING(str);
  45693     p1 = JS_VALUE_GET_STRING(v);
  45694     len = p->len;
  45695     v_len = p1->len;
  45696     if (lastIndexOf) {
  45697         pos = len - v_len;
  45698         if (argc > 1) {
  45699             double d;
  45700             if (JS_ToFloat64(ctx, &d, argv[1]))
  45701                 goto fail;
  45702             if (!isnan(d)) {
  45703                 if (d <= 0)
  45704                     pos = 0;
  45705                 else if (d < pos)
  45706                     pos = d;
  45707             }
  45708         }
  45709         start = pos;
  45710         stop = 0;
  45711         inc = -1;
  45712     } else {
  45713         pos = 0;
  45714         if (argc > 1) {
  45715             if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0))
  45716                 goto fail;
  45717         }
  45718         start = pos;
  45719         stop = len - v_len;
  45720         inc = 1;
  45721     }
  45722     ret = -1;
  45723     if (len >= v_len && inc * (stop - start) >= 0) {
  45724         for (i = start;; i += inc) {
  45725             if (!string_cmp(p, p1, i, 0, v_len)) {
  45726                 ret = i;
  45727                 break;
  45728             }
  45729             if (i == stop)
  45730                 break;
  45731         }
  45732     }
  45733     JS_FreeValue(ctx, str);
  45734     JS_FreeValue(ctx, v);
  45735     return JS_NewInt32(ctx, ret);
  45736 
  45737 fail:
  45738     JS_FreeValue(ctx, str);
  45739     JS_FreeValue(ctx, v);
  45740     return JS_EXCEPTION;
  45741 }
  45742 
  45743 /* return < 0 if exception or TRUE/FALSE */
  45744 static int js_is_regexp(JSContext *ctx, JSValueConst obj);
  45745 
  45746 static JSValue js_string_includes(JSContext *ctx, JSValueConst this_val,
  45747                                   int argc, JSValueConst *argv, int magic)
  45748 {
  45749     JSValue str, v = JS_UNDEFINED;
  45750     int i, len, v_len, pos, start, stop, ret;
  45751     JSString *p;
  45752     JSString *p1;
  45753 
  45754     str = JS_ToStringCheckObject(ctx, this_val);
  45755     if (JS_IsException(str))
  45756         return str;
  45757     ret = js_is_regexp(ctx, argv[0]);
  45758     if (ret) {
  45759         if (ret > 0)
  45760             JS_ThrowTypeError(ctx, "regexp not supported");
  45761         goto fail;
  45762     }
  45763     v = JS_ToString(ctx, argv[0]);
  45764     if (JS_IsException(v))
  45765         goto fail;
  45766     p = JS_VALUE_GET_STRING(str);
  45767     p1 = JS_VALUE_GET_STRING(v);
  45768     len = p->len;
  45769     v_len = p1->len;
  45770     pos = (magic == 2) ? len : 0;
  45771     if (argc > 1 && !JS_IsUndefined(argv[1])) {
  45772         if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0))
  45773             goto fail;
  45774     }
  45775     len -= v_len;
  45776     ret = 0;
  45777     if (magic == 0) {
  45778         start = pos;
  45779         stop = len;
  45780     } else {
  45781         if (magic == 1) {
  45782             if (pos > len)
  45783                 goto done;
  45784         } else {
  45785             pos -= v_len;
  45786         }
  45787         start = stop = pos;
  45788     }
  45789     if (start >= 0 && start <= stop) {
  45790         for (i = start;; i++) {
  45791             if (!string_cmp(p, p1, i, 0, v_len)) {
  45792                 ret = 1;
  45793                 break;
  45794             }
  45795             if (i == stop)
  45796                 break;
  45797         }
  45798     }
  45799  done:
  45800     JS_FreeValue(ctx, str);
  45801     JS_FreeValue(ctx, v);
  45802     return JS_NewBool(ctx, ret);
  45803 
  45804 fail:
  45805     JS_FreeValue(ctx, str);
  45806     JS_FreeValue(ctx, v);
  45807     return JS_EXCEPTION;
  45808 }
  45809 
  45810 static int check_regexp_g_flag(JSContext *ctx, JSValueConst regexp)
  45811 {
  45812     int ret;
  45813     JSValue flags;
  45814 
  45815     ret = js_is_regexp(ctx, regexp);
  45816     if (ret < 0)
  45817         return -1;
  45818     if (ret) {
  45819         flags = JS_GetProperty(ctx, regexp, JS_ATOM_flags);
  45820         if (JS_IsException(flags))
  45821             return -1;
  45822         if (JS_IsUndefined(flags) || JS_IsNull(flags)) {
  45823             JS_ThrowTypeError(ctx, "cannot convert to object");
  45824             return -1;
  45825         }
  45826         flags = JS_ToStringFree(ctx, flags);
  45827         if (JS_IsException(flags))
  45828             return -1;
  45829         ret = string_indexof_char(JS_VALUE_GET_STRING(flags), 'g', 0);
  45830         JS_FreeValue(ctx, flags);
  45831         if (ret < 0) {
  45832             JS_ThrowTypeError(ctx, "regexp must have the 'g' flag");
  45833             return -1;
  45834         }
  45835     }
  45836     return 0;
  45837 }
  45838 
  45839 static JSValue js_string_match(JSContext *ctx, JSValueConst this_val,
  45840                                int argc, JSValueConst *argv, int atom)
  45841 {
  45842     // match(rx), search(rx), matchAll(rx)
  45843     // atom is JS_ATOM_Symbol_match, JS_ATOM_Symbol_search, or JS_ATOM_Symbol_matchAll
  45844     JSValueConst O = this_val, regexp = argv[0], args[2];
  45845     JSValue matcher, S, rx, result, str;
  45846     int args_len;
  45847 
  45848     if (JS_IsUndefined(O) || JS_IsNull(O))
  45849         return JS_ThrowTypeError(ctx, "cannot convert to object");
  45850 
  45851     if (JS_IsObject(regexp)) {
  45852         matcher = JS_GetProperty(ctx, regexp, atom);
  45853         if (JS_IsException(matcher))
  45854             return JS_EXCEPTION;
  45855         if (atom == JS_ATOM_Symbol_matchAll) {
  45856             if (check_regexp_g_flag(ctx, regexp) < 0) {
  45857                 JS_FreeValue(ctx, matcher);
  45858                 return JS_EXCEPTION;
  45859             }
  45860         }
  45861         if (!JS_IsUndefined(matcher) && !JS_IsNull(matcher)) {
  45862             return JS_CallFree(ctx, matcher, regexp, 1, &O);
  45863         }
  45864     }
  45865     S = JS_ToString(ctx, O);
  45866     if (JS_IsException(S))
  45867         return JS_EXCEPTION;
  45868     args_len = 1;
  45869     args[0] = regexp;
  45870     str = JS_UNDEFINED;
  45871     if (atom == JS_ATOM_Symbol_matchAll) {
  45872         str = js_new_string8(ctx, "g");
  45873         if (JS_IsException(str))
  45874             goto fail;
  45875         args[args_len++] = (JSValueConst)str;
  45876     }
  45877     rx = JS_CallConstructor(ctx, ctx->regexp_ctor, args_len, args);
  45878     JS_FreeValue(ctx, str);
  45879     if (JS_IsException(rx)) {
  45880     fail:
  45881         JS_FreeValue(ctx, S);
  45882         return JS_EXCEPTION;
  45883     }
  45884     result = JS_InvokeFree(ctx, rx, atom, 1, (JSValueConst *)&S);
  45885     JS_FreeValue(ctx, S);
  45886     return result;
  45887 }
  45888 
  45889 /* if captures != NULL, captures_val and matched are ignored. Otherwise,
  45890    captures_len is ignored */
  45891 static int js_string_GetSubstitution(JSContext *ctx,
  45892                                      StringBuffer *b,
  45893                                      JSValueConst matched,
  45894                                      JSString *sp,
  45895                                      uint32_t position,
  45896                                      JSValueConst captures_val,
  45897                                      JSValueConst namedCaptures,
  45898                                      JSValueConst rep,
  45899                                      uint8_t **captures,
  45900                                      uint32_t captures_len)
  45901 {
  45902     JSValue capture, name, s;
  45903     uint32_t len, matched_len;
  45904     int i, j, j0, k, k1, shift;
  45905     int c, c1;
  45906     JSString *rp;
  45907 
  45908     if (JS_VALUE_GET_TAG(rep) != JS_TAG_STRING) {
  45909         JS_ThrowTypeError(ctx, "not a string");
  45910         goto exception;
  45911     }
  45912     shift = sp->is_wide_char;
  45913     rp = JS_VALUE_GET_STRING(rep);
  45914 
  45915     if (captures) {
  45916         matched_len = (captures[1] - captures[0]) >> shift;
  45917     } else {
  45918         captures_len = 0;
  45919         if (!JS_IsUndefined(captures_val)) {
  45920             if (js_get_length32(ctx, &captures_len, captures_val))
  45921                 goto exception;
  45922         }
  45923         if (js_get_length32(ctx, &matched_len, matched))
  45924             goto exception;
  45925     }
  45926 
  45927     len = rp->len;
  45928     i = 0;
  45929     for(;;) {
  45930         j = string_indexof_char(rp, '$', i);
  45931         if (j < 0 || j + 1 >= len)
  45932             break;
  45933         string_buffer_concat(b, rp, i, j);
  45934         j0 = j++;
  45935         c = string_get(rp, j++);
  45936         if (c == '$') {
  45937             string_buffer_putc8(b, '$');
  45938         } else if (c == '&') {
  45939             if (captures) {
  45940                 string_buffer_concat(b, sp, position, position + matched_len);
  45941             } else {
  45942                 if (string_buffer_concat_value(b, matched))
  45943                     goto exception;
  45944             }
  45945         } else if (c == '`') {
  45946             string_buffer_concat(b, sp, 0, position);
  45947         } else if (c == '\'') {
  45948             string_buffer_concat(b, sp, position + matched_len, sp->len);
  45949         } else if (c >= '0' && c <= '9') {
  45950             k = c - '0';
  45951             if (j < len) {
  45952                 c1 = string_get(rp, j);
  45953                 if (c1 >= '0' && c1 <= '9') {
  45954                     /* This behavior is specified in ES6 and refined in ECMA 2019 */
  45955                     /* ECMA 2019 does not have the extra test, but
  45956                        Test262 S15.5.4.11_A3_T1..3 require this behavior */
  45957                     k1 = k * 10 + c1 - '0';
  45958                     if (k1 >= 1 && k1 < captures_len) {
  45959                         k = k1;
  45960                         j++;
  45961                     }
  45962                 }
  45963             }
  45964             if (k >= 1 && k < captures_len) {
  45965                 if (captures) {
  45966                     int start, end;
  45967                     if (captures[2 * k] && captures[2 * k + 1]) {
  45968                         start = (captures[2 * k] - sp->u.str8) >> shift;
  45969                         end = (captures[2 * k + 1] - sp->u.str8) >> shift;
  45970                         string_buffer_concat(b, sp, start, end);
  45971                     }
  45972                 } else {
  45973                     s = JS_GetPropertyInt64(ctx, captures_val, k);
  45974                     if (JS_IsException(s))
  45975                         goto exception;
  45976                     if (!JS_IsUndefined(s)) {
  45977                         if (string_buffer_concat_value_free(b, s))
  45978                             goto exception;
  45979                     }
  45980                 }
  45981             } else {
  45982                 goto norep;
  45983             }
  45984         } else if (c == '<' && !JS_IsUndefined(namedCaptures)) {
  45985             k = string_indexof_char(rp, '>', j);
  45986             if (k < 0)
  45987                 goto norep;
  45988             name = js_sub_string(ctx, rp, j, k);
  45989             if (JS_IsException(name))
  45990                 goto exception;
  45991             capture = JS_GetPropertyValue(ctx, namedCaptures, name);
  45992             if (JS_IsException(capture))
  45993                 goto exception;
  45994             if (!JS_IsUndefined(capture)) {
  45995                 if (string_buffer_concat_value_free(b, capture))
  45996                     goto exception;
  45997             }
  45998             j = k + 1;
  45999         } else {
  46000         norep:
  46001             string_buffer_concat(b, rp, j0, j);
  46002         }
  46003         i = j;
  46004     }
  46005     string_buffer_concat(b, rp, i, rp->len);
  46006     return 0;
  46007 exception:
  46008     return -1;
  46009 }
  46010 
  46011 static JSValue js_string_replace(JSContext *ctx, JSValueConst this_val,
  46012                                  int argc, JSValueConst *argv,
  46013                                  int is_replaceAll)
  46014 {
  46015     // replace(rx, rep)
  46016     JSValueConst O = this_val, searchValue = argv[0], replaceValue = argv[1];
  46017     JSValueConst args[3];
  46018     JSValue str, search_str, replaceValue_str, repl_str;
  46019     JSString *sp, *searchp;
  46020     StringBuffer b_s, *b = &b_s;
  46021     int pos, functionalReplace, endOfLastMatch;
  46022     BOOL is_first;
  46023 
  46024     if (JS_IsUndefined(O) || JS_IsNull(O))
  46025         return JS_ThrowTypeError(ctx, "cannot convert to object");
  46026 
  46027     search_str = JS_UNDEFINED;
  46028     replaceValue_str = JS_UNDEFINED;
  46029     repl_str = JS_UNDEFINED;
  46030 
  46031     if (JS_IsObject(searchValue)) {
  46032         JSValue replacer;
  46033         if (is_replaceAll) {
  46034             if (check_regexp_g_flag(ctx, searchValue) < 0)
  46035                 return JS_EXCEPTION;
  46036         }
  46037         replacer = JS_GetProperty(ctx, searchValue, JS_ATOM_Symbol_replace);
  46038         if (JS_IsException(replacer))
  46039             return JS_EXCEPTION;
  46040         if (!JS_IsUndefined(replacer) && !JS_IsNull(replacer)) {
  46041             args[0] = O;
  46042             args[1] = replaceValue;
  46043             return JS_CallFree(ctx, replacer, searchValue, 2, args);
  46044         }
  46045     }
  46046     string_buffer_init(ctx, b, 0);
  46047 
  46048     str = JS_ToString(ctx, O);
  46049     if (JS_IsException(str))
  46050         goto exception;
  46051     search_str = JS_ToString(ctx, searchValue);
  46052     if (JS_IsException(search_str))
  46053         goto exception;
  46054     functionalReplace = JS_IsFunction(ctx, replaceValue);
  46055     if (!functionalReplace) {
  46056         replaceValue_str = JS_ToString(ctx, replaceValue);
  46057         if (JS_IsException(replaceValue_str))
  46058             goto exception;
  46059     }
  46060 
  46061     sp = JS_VALUE_GET_STRING(str);
  46062     searchp = JS_VALUE_GET_STRING(search_str);
  46063     endOfLastMatch = 0;
  46064     is_first = TRUE;
  46065     for(;;) {
  46066         if (unlikely(searchp->len == 0)) {
  46067             if (is_first)
  46068                 pos = 0;
  46069             else if (endOfLastMatch >= sp->len)
  46070                 pos = -1;
  46071             else
  46072                 pos = endOfLastMatch + 1;
  46073         } else {
  46074             pos = string_indexof(sp, searchp, endOfLastMatch);
  46075         }
  46076         if (pos < 0) {
  46077             if (is_first) {
  46078                 string_buffer_free(b);
  46079                 JS_FreeValue(ctx, search_str);
  46080                 JS_FreeValue(ctx, replaceValue_str);
  46081                 return str;
  46082             } else {
  46083                 break;
  46084             }
  46085         }
  46086 
  46087         string_buffer_concat(b, sp, endOfLastMatch, pos);
  46088 
  46089         if (functionalReplace) {
  46090             args[0] = search_str;
  46091             args[1] = JS_NewInt32(ctx, pos);
  46092             args[2] = str;
  46093             repl_str = JS_ToStringFree(ctx, JS_Call(ctx, replaceValue, JS_UNDEFINED, 3, args));
  46094             if (JS_IsException(repl_str))
  46095                 goto exception;
  46096             string_buffer_concat_value_free(b, repl_str);
  46097         } else {
  46098             if (js_string_GetSubstitution(ctx, b, search_str, sp, pos,
  46099                                           JS_UNDEFINED, JS_UNDEFINED, replaceValue_str,
  46100                                           NULL, 0)) {
  46101                 goto exception;
  46102             }
  46103         }
  46104 
  46105         endOfLastMatch = pos + searchp->len;
  46106         is_first = FALSE;
  46107         if (!is_replaceAll)
  46108             break;
  46109     }
  46110     string_buffer_concat(b, sp, endOfLastMatch, sp->len);
  46111     JS_FreeValue(ctx, search_str);
  46112     JS_FreeValue(ctx, replaceValue_str);
  46113     JS_FreeValue(ctx, str);
  46114     return string_buffer_end(b);
  46115 
  46116 exception:
  46117     string_buffer_free(b);
  46118     JS_FreeValue(ctx, search_str);
  46119     JS_FreeValue(ctx, replaceValue_str);
  46120     JS_FreeValue(ctx, str);
  46121     return JS_EXCEPTION;
  46122 }
  46123 
  46124 static JSValue js_string_split(JSContext *ctx, JSValueConst this_val,
  46125                                int argc, JSValueConst *argv)
  46126 {
  46127     // split(sep, limit)
  46128     JSValueConst O = this_val, separator = argv[0], limit = argv[1];
  46129     JSValueConst args[2];
  46130     JSValue S, A, R, T;
  46131     uint32_t lim, lengthA;
  46132     int64_t p, q, s, r, e;
  46133     JSString *sp, *rp;
  46134 
  46135     if (JS_IsUndefined(O) || JS_IsNull(O))
  46136         return JS_ThrowTypeError(ctx, "cannot convert to object");
  46137 
  46138     S = JS_UNDEFINED;
  46139     A = JS_UNDEFINED;
  46140     R = JS_UNDEFINED;
  46141 
  46142     if (JS_IsObject(separator)) {
  46143         JSValue splitter;
  46144         splitter = JS_GetProperty(ctx, separator, JS_ATOM_Symbol_split);
  46145         if (JS_IsException(splitter))
  46146             return JS_EXCEPTION;
  46147         if (!JS_IsUndefined(splitter) && !JS_IsNull(splitter)) {
  46148             args[0] = O;
  46149             args[1] = limit;
  46150             return JS_CallFree(ctx, splitter, separator, 2, args);
  46151         }
  46152     }
  46153     S = JS_ToString(ctx, O);
  46154     if (JS_IsException(S))
  46155         goto exception;
  46156     A = JS_NewArray(ctx);
  46157     if (JS_IsException(A))
  46158         goto exception;
  46159     lengthA = 0;
  46160     if (JS_IsUndefined(limit)) {
  46161         lim = 0xffffffff;
  46162     } else {
  46163         if (JS_ToUint32(ctx, &lim, limit) < 0)
  46164             goto exception;
  46165     }
  46166     sp = JS_VALUE_GET_STRING(S);
  46167     s = sp->len;
  46168     R = JS_ToString(ctx, separator);
  46169     if (JS_IsException(R))
  46170         goto exception;
  46171     rp = JS_VALUE_GET_STRING(R);
  46172     r = rp->len;
  46173     p = 0;
  46174     if (lim == 0)
  46175         goto done;
  46176     if (JS_IsUndefined(separator))
  46177         goto add_tail;
  46178     if (s == 0) {
  46179         if (r != 0)
  46180             goto add_tail;
  46181         goto done;
  46182     }
  46183     for (q = p; (q += !r) <= s - r - !r; q = p = e + r) {
  46184         e = string_indexof(sp, rp, q);
  46185         if (e < 0)
  46186             break;
  46187         T = js_sub_string(ctx, sp, p, e);
  46188         if (JS_IsException(T))
  46189             goto exception;
  46190         if (JS_CreateDataPropertyUint32(ctx, A, lengthA++, T, 0) < 0)
  46191             goto exception;
  46192         if (lengthA == lim)
  46193             goto done;
  46194     }
  46195 add_tail:
  46196     T = js_sub_string(ctx, sp, p, s);
  46197     if (JS_IsException(T))
  46198         goto exception;
  46199     if (JS_CreateDataPropertyUint32(ctx, A, lengthA++, T,0 ) < 0)
  46200         goto exception;
  46201 done:
  46202     JS_FreeValue(ctx, S);
  46203     JS_FreeValue(ctx, R);
  46204     return A;
  46205 
  46206 exception:
  46207     JS_FreeValue(ctx, A);
  46208     JS_FreeValue(ctx, S);
  46209     JS_FreeValue(ctx, R);
  46210     return JS_EXCEPTION;
  46211 }
  46212 
  46213 static JSValue js_string_substring(JSContext *ctx, JSValueConst this_val,
  46214                                    int argc, JSValueConst *argv)
  46215 {
  46216     JSValue str, ret;
  46217     int a, b, start, end;
  46218     JSString *p;
  46219 
  46220     str = JS_ToStringCheckObject(ctx, this_val);
  46221     if (JS_IsException(str))
  46222         return str;
  46223     p = JS_VALUE_GET_STRING(str);
  46224     if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, p->len, 0)) {
  46225         JS_FreeValue(ctx, str);
  46226         return JS_EXCEPTION;
  46227     }
  46228     b = p->len;
  46229     if (!JS_IsUndefined(argv[1])) {
  46230         if (JS_ToInt32Clamp(ctx, &b, argv[1], 0, p->len, 0)) {
  46231             JS_FreeValue(ctx, str);
  46232             return JS_EXCEPTION;
  46233         }
  46234     }
  46235     if (a < b) {
  46236         start = a;
  46237         end = b;
  46238     } else {
  46239         start = b;
  46240         end = a;
  46241     }
  46242     ret = js_sub_string(ctx, p, start, end);
  46243     JS_FreeValue(ctx, str);
  46244     return ret;
  46245 }
  46246 
  46247 static JSValue js_string_substr(JSContext *ctx, JSValueConst this_val,
  46248                                 int argc, JSValueConst *argv)
  46249 {
  46250     JSValue str, ret;
  46251     int a, len, n;
  46252     JSString *p;
  46253 
  46254     str = JS_ToStringCheckObject(ctx, this_val);
  46255     if (JS_IsException(str))
  46256         return str;
  46257     p = JS_VALUE_GET_STRING(str);
  46258     len = p->len;
  46259     if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, len, len)) {
  46260         JS_FreeValue(ctx, str);
  46261         return JS_EXCEPTION;
  46262     }
  46263     n = len - a;
  46264     if (!JS_IsUndefined(argv[1])) {
  46265         if (JS_ToInt32Clamp(ctx, &n, argv[1], 0, len - a, 0)) {
  46266             JS_FreeValue(ctx, str);
  46267             return JS_EXCEPTION;
  46268         }
  46269     }
  46270     ret = js_sub_string(ctx, p, a, a + n);
  46271     JS_FreeValue(ctx, str);
  46272     return ret;
  46273 }
  46274 
  46275 static JSValue js_string_slice(JSContext *ctx, JSValueConst this_val,
  46276                                int argc, JSValueConst *argv)
  46277 {
  46278     JSValue str, ret;
  46279     int len, start, end;
  46280     JSString *p;
  46281 
  46282     str = JS_ToStringCheckObject(ctx, this_val);
  46283     if (JS_IsException(str))
  46284         return str;
  46285     p = JS_VALUE_GET_STRING(str);
  46286     len = p->len;
  46287     if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len)) {
  46288         JS_FreeValue(ctx, str);
  46289         return JS_EXCEPTION;
  46290     }
  46291     end = len;
  46292     if (!JS_IsUndefined(argv[1])) {
  46293         if (JS_ToInt32Clamp(ctx, &end, argv[1], 0, len, len)) {
  46294             JS_FreeValue(ctx, str);
  46295             return JS_EXCEPTION;
  46296         }
  46297     }
  46298     ret = js_sub_string(ctx, p, start, max_int(end, start));
  46299     JS_FreeValue(ctx, str);
  46300     return ret;
  46301 }
  46302 
  46303 static JSValue js_string_pad(JSContext *ctx, JSValueConst this_val,
  46304                              int argc, JSValueConst *argv, int padEnd)
  46305 {
  46306     JSValue str, v = JS_UNDEFINED;
  46307     StringBuffer b_s, *b = &b_s;
  46308     JSString *p, *p1 = NULL;
  46309     int n, len, c = ' ';
  46310 
  46311     str = JS_ToStringCheckObject(ctx, this_val);
  46312     if (JS_IsException(str))
  46313         goto fail1;
  46314     if (JS_ToInt32Sat(ctx, &n, argv[0]))
  46315         goto fail2;
  46316     p = JS_VALUE_GET_STRING(str);
  46317     len = p->len;
  46318     if (len >= n)
  46319         return str;
  46320     if (argc > 1 && !JS_IsUndefined(argv[1])) {
  46321         v = JS_ToString(ctx, argv[1]);
  46322         if (JS_IsException(v))
  46323             goto fail2;
  46324         p1 = JS_VALUE_GET_STRING(v);
  46325         if (p1->len == 0) {
  46326             JS_FreeValue(ctx, v);
  46327             return str;
  46328         }
  46329         if (p1->len == 1) {
  46330             c = string_get(p1, 0);
  46331             p1 = NULL;
  46332         }
  46333     }
  46334     if (n > JS_STRING_LEN_MAX) {
  46335         JS_ThrowRangeError(ctx, "invalid string length");
  46336         goto fail3;
  46337     }
  46338     if (string_buffer_init(ctx, b, n))
  46339         goto fail3;
  46340     n -= len;
  46341     if (padEnd) {
  46342         if (string_buffer_concat(b, p, 0, len))
  46343             goto fail;
  46344     }
  46345     if (p1) {
  46346         while (n > 0) {
  46347             int chunk = min_int(n, p1->len);
  46348             if (string_buffer_concat(b, p1, 0, chunk))
  46349                 goto fail;
  46350             n -= chunk;
  46351         }
  46352     } else {
  46353         if (string_buffer_fill(b, c, n))
  46354             goto fail;
  46355     }
  46356     if (!padEnd) {
  46357         if (string_buffer_concat(b, p, 0, len))
  46358             goto fail;
  46359     }
  46360     JS_FreeValue(ctx, v);
  46361     JS_FreeValue(ctx, str);
  46362     return string_buffer_end(b);
  46363 
  46364 fail:
  46365     string_buffer_free(b);
  46366 fail3:
  46367     JS_FreeValue(ctx, v);
  46368 fail2:
  46369     JS_FreeValue(ctx, str);
  46370 fail1:
  46371     return JS_EXCEPTION;
  46372 }
  46373 
  46374 static JSValue js_string_repeat(JSContext *ctx, JSValueConst this_val,
  46375                                 int argc, JSValueConst *argv)
  46376 {
  46377     JSValue str;
  46378     StringBuffer b_s, *b = &b_s;
  46379     JSString *p;
  46380     int64_t val;
  46381     int n, len;
  46382 
  46383     str = JS_ToStringCheckObject(ctx, this_val);
  46384     if (JS_IsException(str))
  46385         goto fail;
  46386     if (JS_ToInt64Sat(ctx, &val, argv[0]))
  46387         goto fail;
  46388     if (val < 0 || val > 2147483647) {
  46389         JS_ThrowRangeError(ctx, "invalid repeat count");
  46390         goto fail;
  46391     }
  46392     n = val;
  46393     p = JS_VALUE_GET_STRING(str);
  46394     len = p->len;
  46395     if (len == 0 || n == 1)
  46396         return str;
  46397     // XXX: potential arithmetic overflow
  46398     if (val * len > JS_STRING_LEN_MAX) {
  46399         JS_ThrowRangeError(ctx, "invalid string length");
  46400         goto fail;
  46401     }
  46402     if (string_buffer_init2(ctx, b, n * len, p->is_wide_char))
  46403         goto fail;
  46404     if (len == 1) {
  46405         string_buffer_fill(b, string_get(p, 0), n);
  46406     } else {
  46407         while (n-- > 0) {
  46408             string_buffer_concat(b, p, 0, len);
  46409         }
  46410     }
  46411     JS_FreeValue(ctx, str);
  46412     return string_buffer_end(b);
  46413 
  46414 fail:
  46415     JS_FreeValue(ctx, str);
  46416     return JS_EXCEPTION;
  46417 }
  46418 
  46419 static JSValue js_string_trim(JSContext *ctx, JSValueConst this_val,
  46420                               int argc, JSValueConst *argv, int magic)
  46421 {
  46422     JSValue str, ret;
  46423     int a, b, len;
  46424     JSString *p;
  46425 
  46426     str = JS_ToStringCheckObject(ctx, this_val);
  46427     if (JS_IsException(str))
  46428         return str;
  46429     p = JS_VALUE_GET_STRING(str);
  46430     a = 0;
  46431     b = len = p->len;
  46432     if (magic & 1) {
  46433         while (a < len && lre_is_space(string_get(p, a)))
  46434             a++;
  46435     }
  46436     if (magic & 2) {
  46437         while (b > a && lre_is_space(string_get(p, b - 1)))
  46438             b--;
  46439     }
  46440     ret = js_sub_string(ctx, p, a, b);
  46441     JS_FreeValue(ctx, str);
  46442     return ret;
  46443 }
  46444 
  46445 /* return 0 if before the first char */
  46446 static int string_prevc(JSString *p, int *pidx)
  46447 {
  46448     int idx, c, c1;
  46449 
  46450     idx = *pidx;
  46451     if (idx <= 0)
  46452         return 0;
  46453     idx--;
  46454     if (p->is_wide_char) {
  46455         c = p->u.str16[idx];
  46456         if (is_lo_surrogate(c) && idx > 0) {
  46457             c1 = p->u.str16[idx - 1];
  46458             if (is_hi_surrogate(c1)) {
  46459                 c = from_surrogate(c1, c);
  46460                 idx--;
  46461             }
  46462         }
  46463     } else {
  46464         c = p->u.str8[idx];
  46465     }
  46466     *pidx = idx;
  46467     return c;
  46468 }
  46469 
  46470 static BOOL test_final_sigma(JSString *p, int sigma_pos)
  46471 {
  46472     int k, c1;
  46473 
  46474     /* before C: skip case ignorable chars and check there is
  46475        a cased letter */
  46476     k = sigma_pos;
  46477     for(;;) {
  46478         c1 = string_prevc(p, &k);
  46479         if (!lre_is_case_ignorable(c1))
  46480             break;
  46481     }
  46482     if (!lre_is_cased(c1))
  46483         return FALSE;
  46484 
  46485     /* after C: skip case ignorable chars and check there is
  46486        no cased letter */
  46487     k = sigma_pos + 1;
  46488     for(;;) {
  46489         if (k >= p->len)
  46490             return TRUE;
  46491         c1 = string_getc(p, &k);
  46492         if (!lre_is_case_ignorable(c1))
  46493             break;
  46494     }
  46495     return !lre_is_cased(c1);
  46496 }
  46497 
  46498 static JSValue js_string_toLowerCase(JSContext *ctx, JSValueConst this_val,
  46499                                      int argc, JSValueConst *argv, int to_lower)
  46500 {
  46501     JSValue val;
  46502     StringBuffer b_s, *b = &b_s;
  46503     JSString *p;
  46504     int i, c, j, l;
  46505     uint32_t res[LRE_CC_RES_LEN_MAX];
  46506 
  46507     val = JS_ToStringCheckObject(ctx, this_val);
  46508     if (JS_IsException(val))
  46509         return val;
  46510     p = JS_VALUE_GET_STRING(val);
  46511     if (p->len == 0)
  46512         return val;
  46513     if (string_buffer_init(ctx, b, p->len))
  46514         goto fail;
  46515     for(i = 0; i < p->len;) {
  46516         c = string_getc(p, &i);
  46517         if (c == 0x3a3 && to_lower && test_final_sigma(p, i - 1)) {
  46518             res[0] = 0x3c2; /* final sigma */
  46519             l = 1;
  46520         } else {
  46521             l = lre_case_conv(res, c, to_lower);
  46522         }
  46523         for(j = 0; j < l; j++) {
  46524             if (string_buffer_putc(b, res[j]))
  46525                 goto fail;
  46526         }
  46527     }
  46528     JS_FreeValue(ctx, val);
  46529     return string_buffer_end(b);
  46530  fail:
  46531     JS_FreeValue(ctx, val);
  46532     string_buffer_free(b);
  46533     return JS_EXCEPTION;
  46534 }
  46535 
  46536 #ifdef CONFIG_ALL_UNICODE
  46537 
  46538 /* return (-1, NULL) if exception, otherwise (len, buf) */
  46539 static int JS_ToUTF32String(JSContext *ctx, uint32_t **pbuf, JSValueConst val1)
  46540 {
  46541     JSValue val;
  46542     JSString *p;
  46543     uint32_t *buf;
  46544     int i, j, len;
  46545 
  46546     val = JS_ToString(ctx, val1);
  46547     if (JS_IsException(val))
  46548         return -1;
  46549     p = JS_VALUE_GET_STRING(val);
  46550     len = p->len;
  46551     /* UTF32 buffer length is len minus the number of correct surrogates pairs */
  46552     buf = js_malloc(ctx, sizeof(buf[0]) * max_int(len, 1));
  46553     if (!buf) {
  46554         JS_FreeValue(ctx, val);
  46555         goto fail;
  46556     }
  46557     for(i = j = 0; i < len;)
  46558         buf[j++] = string_getc(p, &i);
  46559     JS_FreeValue(ctx, val);
  46560     *pbuf = buf;
  46561     return j;
  46562  fail:
  46563     *pbuf = NULL;
  46564     return -1;
  46565 }
  46566 
  46567 static JSValue JS_NewUTF32String(JSContext *ctx, const uint32_t *buf, int len)
  46568 {
  46569     int i;
  46570     StringBuffer b_s, *b = &b_s;
  46571     if (string_buffer_init(ctx, b, len))
  46572         return JS_EXCEPTION;
  46573     for(i = 0; i < len; i++) {
  46574         if (string_buffer_putc(b, buf[i]))
  46575             goto fail;
  46576     }
  46577     return string_buffer_end(b);
  46578  fail:
  46579     string_buffer_free(b);
  46580     return JS_EXCEPTION;
  46581 }
  46582 
  46583 static int js_string_normalize1(JSContext *ctx, uint32_t **pout_buf,
  46584                                 JSValueConst val,
  46585                                 UnicodeNormalizationEnum n_type)
  46586 {
  46587     int buf_len, out_len;
  46588     uint32_t *buf, *out_buf;
  46589 
  46590     buf_len = JS_ToUTF32String(ctx, &buf, val);
  46591     if (buf_len < 0)
  46592         return -1;
  46593     out_len = unicode_normalize(&out_buf, buf, buf_len, n_type,
  46594                                 ctx->rt, js_realloc_rt_opaque);
  46595     js_free(ctx, buf);
  46596     if (out_len < 0)
  46597         return -1;
  46598     *pout_buf = out_buf;
  46599     return out_len;
  46600 }
  46601 
  46602 static JSValue js_string_normalize(JSContext *ctx, JSValueConst this_val,
  46603                                    int argc, JSValueConst *argv)
  46604 {
  46605     const char *form, *p;
  46606     size_t form_len;
  46607     int is_compat, out_len;
  46608     UnicodeNormalizationEnum n_type;
  46609     JSValue val;
  46610     uint32_t *out_buf;
  46611 
  46612     val = JS_ToStringCheckObject(ctx, this_val);
  46613     if (JS_IsException(val))
  46614         return val;
  46615 
  46616     if (argc == 0 || JS_IsUndefined(argv[0])) {
  46617         n_type = UNICODE_NFC;
  46618     } else {
  46619         form = JS_ToCStringLen(ctx, &form_len, argv[0]);
  46620         if (!form)
  46621             goto fail1;
  46622         p = form;
  46623         if (p[0] != 'N' || p[1] != 'F')
  46624             goto bad_form;
  46625         p += 2;
  46626         is_compat = FALSE;
  46627         if (*p == 'K') {
  46628             is_compat = TRUE;
  46629             p++;
  46630         }
  46631         if (*p == 'C' || *p == 'D') {
  46632             n_type = UNICODE_NFC + is_compat * 2 + (*p - 'C');
  46633             if ((p + 1 - form) != form_len)
  46634                 goto bad_form;
  46635         } else {
  46636         bad_form:
  46637             JS_FreeCString(ctx, form);
  46638             JS_ThrowRangeError(ctx, "bad normalization form");
  46639         fail1:
  46640             JS_FreeValue(ctx, val);
  46641             return JS_EXCEPTION;
  46642         }
  46643         JS_FreeCString(ctx, form);
  46644     }
  46645 
  46646     out_len = js_string_normalize1(ctx, &out_buf, val, n_type);
  46647     JS_FreeValue(ctx, val);
  46648     if (out_len < 0)
  46649         return JS_EXCEPTION;
  46650     val = JS_NewUTF32String(ctx, out_buf, out_len);
  46651     js_free(ctx, out_buf);
  46652     return val;
  46653 }
  46654 
  46655 /* return < 0, 0 or > 0 */
  46656 static int js_UTF32_compare(const uint32_t *buf1, int buf1_len,
  46657                             const uint32_t *buf2, int buf2_len)
  46658 {
  46659     int i, len, c, res;
  46660     len = min_int(buf1_len, buf2_len);
  46661     for(i = 0; i < len; i++) {
  46662         /* Note: range is limited so a subtraction is valid */
  46663         c = buf1[i] - buf2[i];
  46664         if (c != 0)
  46665             return c;
  46666     }
  46667     if (buf1_len == buf2_len)
  46668         res = 0;
  46669     else if (buf1_len < buf2_len)
  46670         res = -1;
  46671     else
  46672         res = 1;
  46673     return res;
  46674 }
  46675 
  46676 static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val,
  46677                                        int argc, JSValueConst *argv)
  46678 {
  46679     JSValue a, b;
  46680     int cmp, a_len, b_len;
  46681     uint32_t *a_buf, *b_buf;
  46682 
  46683     a = JS_ToStringCheckObject(ctx, this_val);
  46684     if (JS_IsException(a))
  46685         return JS_EXCEPTION;
  46686     b = JS_ToString(ctx, argv[0]);
  46687     if (JS_IsException(b)) {
  46688         JS_FreeValue(ctx, a);
  46689         return JS_EXCEPTION;
  46690     }
  46691     a_len = js_string_normalize1(ctx, &a_buf, a, UNICODE_NFC);
  46692     JS_FreeValue(ctx, a);
  46693     if (a_len < 0) {
  46694         JS_FreeValue(ctx, b);
  46695         return JS_EXCEPTION;
  46696     }
  46697 
  46698     b_len = js_string_normalize1(ctx, &b_buf, b, UNICODE_NFC);
  46699     JS_FreeValue(ctx, b);
  46700     if (b_len < 0) {
  46701         js_free(ctx, a_buf);
  46702         return JS_EXCEPTION;
  46703     }
  46704     cmp = js_UTF32_compare(a_buf, a_len, b_buf, b_len);
  46705     js_free(ctx, a_buf);
  46706     js_free(ctx, b_buf);
  46707     return JS_NewInt32(ctx, cmp);
  46708 }
  46709 #else /* CONFIG_ALL_UNICODE */
  46710 static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val,
  46711                                        int argc, JSValueConst *argv)
  46712 {
  46713     JSValue a, b;
  46714     int cmp;
  46715 
  46716     a = JS_ToStringCheckObject(ctx, this_val);
  46717     if (JS_IsException(a))
  46718         return JS_EXCEPTION;
  46719     b = JS_ToString(ctx, argv[0]);
  46720     if (JS_IsException(b)) {
  46721         JS_FreeValue(ctx, a);
  46722         return JS_EXCEPTION;
  46723     }
  46724     cmp = js_string_compare(ctx, JS_VALUE_GET_STRING(a), JS_VALUE_GET_STRING(b));
  46725     JS_FreeValue(ctx, a);
  46726     JS_FreeValue(ctx, b);
  46727     return JS_NewInt32(ctx, cmp);
  46728 }
  46729 #endif /* !CONFIG_ALL_UNICODE */
  46730 
  46731 /* also used for String.prototype.valueOf */
  46732 static JSValue js_string_toString(JSContext *ctx, JSValueConst this_val,
  46733                                   int argc, JSValueConst *argv)
  46734 {
  46735     return js_thisStringValue(ctx, this_val);
  46736 }
  46737 
  46738 /* String Iterator */
  46739 
  46740 static JSValue js_string_iterator_next(JSContext *ctx, JSValueConst this_val,
  46741                                        int argc, JSValueConst *argv,
  46742                                        BOOL *pdone, int magic)
  46743 {
  46744     JSArrayIteratorData *it;
  46745     uint32_t idx, c, start;
  46746     JSString *p;
  46747 
  46748     it = JS_GetOpaque2(ctx, this_val, JS_CLASS_STRING_ITERATOR);
  46749     if (!it) {
  46750         *pdone = FALSE;
  46751         return JS_EXCEPTION;
  46752     }
  46753     if (JS_IsUndefined(it->obj))
  46754         goto done;
  46755     p = JS_VALUE_GET_STRING(it->obj);
  46756     idx = it->idx;
  46757     if (idx >= p->len) {
  46758         JS_FreeValue(ctx, it->obj);
  46759         it->obj = JS_UNDEFINED;
  46760     done:
  46761         *pdone = TRUE;
  46762         return JS_UNDEFINED;
  46763     }
  46764 
  46765     start = idx;
  46766     c = string_getc(p, (int *)&idx);
  46767     it->idx = idx;
  46768     *pdone = FALSE;
  46769     if (c <= 0xffff) {
  46770         return js_new_string_char(ctx, c);
  46771     } else {
  46772         return js_new_string16_len(ctx, p->u.str16 + start, 2);
  46773     }
  46774 }
  46775 
  46776 /* ES6 Annex B 2.3.2 etc. */
  46777 enum {
  46778     magic_string_anchor,
  46779     magic_string_big,
  46780     magic_string_blink,
  46781     magic_string_bold,
  46782     magic_string_fixed,
  46783     magic_string_fontcolor,
  46784     magic_string_fontsize,
  46785     magic_string_italics,
  46786     magic_string_link,
  46787     magic_string_small,
  46788     magic_string_strike,
  46789     magic_string_sub,
  46790     magic_string_sup,
  46791 };
  46792 
  46793 static JSValue js_string_CreateHTML(JSContext *ctx, JSValueConst this_val,
  46794                                     int argc, JSValueConst *argv, int magic)
  46795 {
  46796     JSValue str;
  46797     const JSString *p;
  46798     StringBuffer b_s, *b = &b_s;
  46799     static struct { const char *tag, *attr; } const defs[] = {
  46800         { "a", "name" }, { "big", NULL }, { "blink", NULL }, { "b", NULL },
  46801         { "tt", NULL }, { "font", "color" }, { "font", "size" }, { "i", NULL },
  46802         { "a", "href" }, { "small", NULL }, { "strike", NULL },
  46803         { "sub", NULL }, { "sup", NULL },
  46804     };
  46805 
  46806     str = JS_ToStringCheckObject(ctx, this_val);
  46807     if (JS_IsException(str))
  46808         return JS_EXCEPTION;
  46809     string_buffer_init(ctx, b, 7);
  46810     string_buffer_putc8(b, '<');
  46811     string_buffer_puts8(b, defs[magic].tag);
  46812     if (defs[magic].attr) {
  46813         // r += " " + attr + "=\"" + value + "\"";
  46814         JSValue value;
  46815         int i;
  46816 
  46817         string_buffer_putc8(b, ' ');
  46818         string_buffer_puts8(b, defs[magic].attr);
  46819         string_buffer_puts8(b, "=\"");
  46820         value = JS_ToStringCheckObject(ctx, argv[0]);
  46821         if (JS_IsException(value)) {
  46822             JS_FreeValue(ctx, str);
  46823             string_buffer_free(b);
  46824             return JS_EXCEPTION;
  46825         }
  46826         p = JS_VALUE_GET_STRING(value);
  46827         for (i = 0; i < p->len; i++) {
  46828             int c = string_get(p, i);
  46829             if (c == '"') {
  46830                 string_buffer_puts8(b, "&quot;");
  46831             } else {
  46832                 string_buffer_putc16(b, c);
  46833             }
  46834         }
  46835         JS_FreeValue(ctx, value);
  46836         string_buffer_putc8(b, '\"');
  46837     }
  46838     // return r + ">" + str + "</" + tag + ">";
  46839     string_buffer_putc8(b, '>');
  46840     string_buffer_concat_value_free(b, str);
  46841     string_buffer_puts8(b, "</");
  46842     string_buffer_puts8(b, defs[magic].tag);
  46843     string_buffer_putc8(b, '>');
  46844     return string_buffer_end(b);
  46845 }
  46846 
  46847 static const JSCFunctionListEntry js_string_funcs[] = {
  46848     JS_CFUNC_DEF("fromCharCode", 1, js_string_fromCharCode ),
  46849     JS_CFUNC_DEF("fromCodePoint", 1, js_string_fromCodePoint ),
  46850     JS_CFUNC_DEF("raw", 1, js_string_raw ),
  46851 };
  46852 
  46853 static const JSCFunctionListEntry js_string_proto_funcs[] = {
  46854     JS_PROP_INT32_DEF("length", 0, JS_PROP_CONFIGURABLE ),
  46855     JS_CFUNC_MAGIC_DEF("at", 1, js_string_charAt, 1 ),
  46856     JS_CFUNC_DEF("charCodeAt", 1, js_string_charCodeAt ),
  46857     JS_CFUNC_MAGIC_DEF("charAt", 1, js_string_charAt, 0 ),
  46858     JS_CFUNC_DEF("concat", 1, js_string_concat ),
  46859     JS_CFUNC_DEF("codePointAt", 1, js_string_codePointAt ),
  46860     JS_CFUNC_DEF("isWellFormed", 0, js_string_isWellFormed ),
  46861     JS_CFUNC_DEF("toWellFormed", 0, js_string_toWellFormed ),
  46862     JS_CFUNC_MAGIC_DEF("indexOf", 1, js_string_indexOf, 0 ),
  46863     JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_string_indexOf, 1 ),
  46864     JS_CFUNC_MAGIC_DEF("includes", 1, js_string_includes, 0 ),
  46865     JS_CFUNC_MAGIC_DEF("endsWith", 1, js_string_includes, 2 ),
  46866     JS_CFUNC_MAGIC_DEF("startsWith", 1, js_string_includes, 1 ),
  46867     JS_CFUNC_MAGIC_DEF("match", 1, js_string_match, JS_ATOM_Symbol_match ),
  46868     JS_CFUNC_MAGIC_DEF("matchAll", 1, js_string_match, JS_ATOM_Symbol_matchAll ),
  46869     JS_CFUNC_MAGIC_DEF("search", 1, js_string_match, JS_ATOM_Symbol_search ),
  46870     JS_CFUNC_DEF("split", 2, js_string_split ),
  46871     JS_CFUNC_DEF("substring", 2, js_string_substring ),
  46872     JS_CFUNC_DEF("substr", 2, js_string_substr ),
  46873     JS_CFUNC_DEF("slice", 2, js_string_slice ),
  46874     JS_CFUNC_DEF("repeat", 1, js_string_repeat ),
  46875     JS_CFUNC_MAGIC_DEF("replace", 2, js_string_replace, 0 ),
  46876     JS_CFUNC_MAGIC_DEF("replaceAll", 2, js_string_replace, 1 ),
  46877     JS_CFUNC_MAGIC_DEF("padEnd", 1, js_string_pad, 1 ),
  46878     JS_CFUNC_MAGIC_DEF("padStart", 1, js_string_pad, 0 ),
  46879     JS_CFUNC_MAGIC_DEF("trim", 0, js_string_trim, 3 ),
  46880     JS_CFUNC_MAGIC_DEF("trimEnd", 0, js_string_trim, 2 ),
  46881     JS_ALIAS_DEF("trimRight", "trimEnd" ),
  46882     JS_CFUNC_MAGIC_DEF("trimStart", 0, js_string_trim, 1 ),
  46883     JS_ALIAS_DEF("trimLeft", "trimStart" ),
  46884     JS_CFUNC_DEF("toString", 0, js_string_toString ),
  46885     JS_CFUNC_DEF("valueOf", 0, js_string_toString ),
  46886     JS_CFUNC_MAGIC_DEF("toLowerCase", 0, js_string_toLowerCase, 1 ),
  46887     JS_CFUNC_MAGIC_DEF("toUpperCase", 0, js_string_toLowerCase, 0 ),
  46888     JS_CFUNC_MAGIC_DEF("toLocaleLowerCase", 0, js_string_toLowerCase, 1 ),
  46889     JS_CFUNC_MAGIC_DEF("toLocaleUpperCase", 0, js_string_toLowerCase, 0 ),
  46890     JS_CFUNC_MAGIC_DEF("[Symbol.iterator]", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE | 4 ),
  46891     /* ES6 Annex B 2.3.2 etc. */
  46892     JS_CFUNC_MAGIC_DEF("anchor", 1, js_string_CreateHTML, magic_string_anchor ),
  46893     JS_CFUNC_MAGIC_DEF("big", 0, js_string_CreateHTML, magic_string_big ),
  46894     JS_CFUNC_MAGIC_DEF("blink", 0, js_string_CreateHTML, magic_string_blink ),
  46895     JS_CFUNC_MAGIC_DEF("bold", 0, js_string_CreateHTML, magic_string_bold ),
  46896     JS_CFUNC_MAGIC_DEF("fixed", 0, js_string_CreateHTML, magic_string_fixed ),
  46897     JS_CFUNC_MAGIC_DEF("fontcolor", 1, js_string_CreateHTML, magic_string_fontcolor ),
  46898     JS_CFUNC_MAGIC_DEF("fontsize", 1, js_string_CreateHTML, magic_string_fontsize ),
  46899     JS_CFUNC_MAGIC_DEF("italics", 0, js_string_CreateHTML, magic_string_italics ),
  46900     JS_CFUNC_MAGIC_DEF("link", 1, js_string_CreateHTML, magic_string_link ),
  46901     JS_CFUNC_MAGIC_DEF("small", 0, js_string_CreateHTML, magic_string_small ),
  46902     JS_CFUNC_MAGIC_DEF("strike", 0, js_string_CreateHTML, magic_string_strike ),
  46903     JS_CFUNC_MAGIC_DEF("sub", 0, js_string_CreateHTML, magic_string_sub ),
  46904     JS_CFUNC_MAGIC_DEF("sup", 0, js_string_CreateHTML, magic_string_sup ),
  46905 };
  46906 
  46907 static const JSCFunctionListEntry js_string_iterator_proto_funcs[] = {
  46908     JS_ITERATOR_NEXT_DEF("next", 0, js_string_iterator_next, 0 ),
  46909     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "String Iterator", JS_PROP_CONFIGURABLE ),
  46910 };
  46911 
  46912 static const JSCFunctionListEntry js_string_proto_normalize[] = {
  46913 #ifdef CONFIG_ALL_UNICODE
  46914     JS_CFUNC_DEF("normalize", 0, js_string_normalize ),
  46915 #endif
  46916     JS_CFUNC_DEF("localeCompare", 1, js_string_localeCompare ),
  46917 };
  46918 
  46919 int JS_AddIntrinsicStringNormalize(JSContext *ctx)
  46920 {
  46921     return JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING], js_string_proto_normalize,
  46922                                       countof(js_string_proto_normalize));
  46923 }
  46924 
  46925 /* Math */
  46926 
  46927 /* precondition: a and b are not NaN */
  46928 static double js_fmin(double a, double b)
  46929 {
  46930     if (a == 0 && b == 0) {
  46931         JSFloat64Union a1, b1;
  46932         a1.d = a;
  46933         b1.d = b;
  46934         a1.u64 |= b1.u64;
  46935         return a1.d;
  46936     } else {
  46937         return fmin(a, b);
  46938     }
  46939 }
  46940 
  46941 /* precondition: a and b are not NaN */
  46942 static double js_fmax(double a, double b)
  46943 {
  46944     if (a == 0 && b == 0) {
  46945         JSFloat64Union a1, b1;
  46946         a1.d = a;
  46947         b1.d = b;
  46948         a1.u64 &= b1.u64;
  46949         return a1.d;
  46950     } else {
  46951         return fmax(a, b);
  46952     }
  46953 }
  46954 
  46955 static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,
  46956                                int argc, JSValueConst *argv, int magic)
  46957 {
  46958     BOOL is_max = magic;
  46959     double r, a;
  46960     int i;
  46961     uint32_t tag;
  46962 
  46963     if (unlikely(argc == 0)) {
  46964         return __JS_NewFloat64(ctx, is_max ? -1.0 / 0.0 : 1.0 / 0.0);
  46965     }
  46966 
  46967     tag = JS_VALUE_GET_TAG(argv[0]);
  46968     if (tag == JS_TAG_INT) {
  46969         int a1, r1 = JS_VALUE_GET_INT(argv[0]);
  46970         for(i = 1; i < argc; i++) {
  46971             tag = JS_VALUE_GET_TAG(argv[i]);
  46972             if (tag != JS_TAG_INT) {
  46973                 r = r1;
  46974                 goto generic_case;
  46975             }
  46976             a1 = JS_VALUE_GET_INT(argv[i]);
  46977             if (is_max)
  46978                 r1 = max_int(r1, a1);
  46979             else
  46980                 r1 = min_int(r1, a1);
  46981 
  46982         }
  46983         return JS_NewInt32(ctx, r1);
  46984     } else {
  46985         if (JS_ToFloat64(ctx, &r, argv[0]))
  46986             return JS_EXCEPTION;
  46987         i = 1;
  46988     generic_case:
  46989         while (i < argc) {
  46990             if (JS_ToFloat64(ctx, &a, argv[i]))
  46991                 return JS_EXCEPTION;
  46992             if (!isnan(r)) {
  46993                 if (isnan(a)) {
  46994                     r = a;
  46995                 } else {
  46996                     if (is_max)
  46997                         r = js_fmax(r, a);
  46998                     else
  46999                         r = js_fmin(r, a);
  47000                 }
  47001             }
  47002             i++;
  47003         }
  47004         return JS_NewFloat64(ctx, r);
  47005     }
  47006 }
  47007 
  47008 static double js_math_sign(double a)
  47009 {
  47010     if (isnan(a) || a == 0.0)
  47011         return a;
  47012     if (a < 0)
  47013         return -1;
  47014     else
  47015         return 1;
  47016 }
  47017 
  47018 static double js_math_round(double a)
  47019 {
  47020     JSFloat64Union u;
  47021     uint64_t frac_mask, one;
  47022     unsigned int e, s;
  47023 
  47024     u.d = a;
  47025     e = (u.u64 >> 52) & 0x7ff;
  47026     if (e < 1023) {
  47027         /* abs(a) < 1 */
  47028         if (e == (1023 - 1) && u.u64 != 0xbfe0000000000000) {
  47029             /* abs(a) > 0.5 or a = 0.5: return +/-1.0 */
  47030             u.u64 = (u.u64 & ((uint64_t)1 << 63)) | ((uint64_t)1023 << 52);
  47031         } else {
  47032             /* return +/-0.0 */
  47033             u.u64 &= (uint64_t)1 << 63;
  47034         }
  47035     } else if (e < (1023 + 52)) {
  47036         s = u.u64 >> 63;
  47037         one = (uint64_t)1 << (52 - (e - 1023));
  47038         frac_mask = one - 1;
  47039         u.u64 += (one >> 1) - s;
  47040         u.u64 &= ~frac_mask; /* truncate to an integer */
  47041     }
  47042     /* otherwise: abs(a) >= 2^52, or NaN, +/-Infinity: no change */
  47043     return u.d;
  47044 }
  47045 
  47046 static JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val,
  47047                              int argc, JSValueConst *argv)
  47048 {
  47049     double r, a;
  47050     int i;
  47051 
  47052     r = 0;
  47053     if (argc > 0) {
  47054         if (JS_ToFloat64(ctx, &r, argv[0]))
  47055             return JS_EXCEPTION;
  47056         if (argc == 1) {
  47057             r = fabs(r);
  47058         } else {
  47059             /* use the built-in function to minimize precision loss */
  47060             for (i = 1; i < argc; i++) {
  47061                 if (JS_ToFloat64(ctx, &a, argv[i]))
  47062                     return JS_EXCEPTION;
  47063                 r = hypot(r, a);
  47064             }
  47065         }
  47066     }
  47067     return JS_NewFloat64(ctx, r);
  47068 }
  47069 
  47070 static double js_math_f16round(double a)
  47071 {
  47072     return fromfp16(tofp16(a));
  47073 }
  47074 
  47075 static double js_math_fround(double a)
  47076 {
  47077     return (float)a;
  47078 }
  47079 
  47080 static JSValue js_math_imul(JSContext *ctx, JSValueConst this_val,
  47081                             int argc, JSValueConst *argv)
  47082 {
  47083     uint32_t a, b, c;
  47084     int32_t d;
  47085 
  47086     if (JS_ToUint32(ctx, &a, argv[0]))
  47087         return JS_EXCEPTION;
  47088     if (JS_ToUint32(ctx, &b, argv[1]))
  47089         return JS_EXCEPTION;
  47090     c = a * b;
  47091     memcpy(&d, &c, sizeof(d));
  47092     return JS_NewInt32(ctx, d);
  47093 }
  47094 
  47095 static JSValue js_math_clz32(JSContext *ctx, JSValueConst this_val,
  47096                              int argc, JSValueConst *argv)
  47097 {
  47098     uint32_t a, r;
  47099 
  47100     if (JS_ToUint32(ctx, &a, argv[0]))
  47101         return JS_EXCEPTION;
  47102     if (a == 0)
  47103         r = 32;
  47104     else
  47105         r = clz32(a);
  47106     return JS_NewInt32(ctx, r);
  47107 }
  47108 
  47109 typedef enum {
  47110     SUM_PRECISE_STATE_FINITE,
  47111     SUM_PRECISE_STATE_INFINITY,
  47112     SUM_PRECISE_STATE_MINUS_INFINITY, /* must be after SUM_PRECISE_STATE_INFINITY */
  47113     SUM_PRECISE_STATE_NAN, /* must be after SUM_PRECISE_STATE_MINUS_INFINITY */
  47114 } SumPreciseStateEnum;
  47115 
  47116 #define SP_LIMB_BITS 56
  47117 #define SP_RND_BITS (SP_LIMB_BITS - 53)
  47118 /* we add one extra limb to avoid having to test for overflows during the sum */
  47119 #define SUM_PRECISE_ACC_LEN 39
  47120 
  47121 #define SUM_PRECISE_COUNTER_INIT 250
  47122 
  47123 typedef struct {
  47124     SumPreciseStateEnum state;
  47125     uint32_t counter;
  47126     int n_limbs; /* 'acc' contains n_limbs and is not necessarily
  47127                     acc[n_limb - 1] may be 0. 0 indicates minus zero
  47128                     result when state = SUM_PRECISE_STATE_FINITE */
  47129     int64_t acc[SUM_PRECISE_ACC_LEN];
  47130 } SumPreciseState;
  47131 
  47132 static void sum_precise_init(SumPreciseState *s)
  47133 {
  47134     memset(s->acc, 0, sizeof(s->acc));
  47135     s->state = SUM_PRECISE_STATE_FINITE;
  47136     s->counter = SUM_PRECISE_COUNTER_INIT;
  47137     s->n_limbs = 0;
  47138 }
  47139 
  47140 static void sum_precise_renorm(SumPreciseState *s)
  47141 {
  47142     int64_t v, carry;
  47143     int i;
  47144     
  47145     carry = 0;
  47146     for(i = 0; i < s->n_limbs; i++) {
  47147         v = s->acc[i] + carry;
  47148         s->acc[i] = v & (((uint64_t)1 << SP_LIMB_BITS) - 1);
  47149         carry = v >> SP_LIMB_BITS;
  47150     }
  47151     /* we add a failsafe but it should be never reached in a
  47152        reasonnable amount of time */
  47153     if (carry != 0 && s->n_limbs < SUM_PRECISE_ACC_LEN)
  47154         s->acc[s->n_limbs++] = carry;
  47155 }
  47156 
  47157 static void sum_precise_add(SumPreciseState *s, double d)
  47158 {
  47159     uint64_t a, m, a0, a1;
  47160     int sgn, e, p;
  47161     unsigned int shift;
  47162     
  47163     a = float64_as_uint64(d);
  47164     sgn = a >> 63;
  47165     e = (a >> 52) & ((1 << 11) - 1);
  47166     m = a & (((uint64_t)1 << 52) - 1);
  47167     if (unlikely(e == 2047)) {
  47168         if (m == 0) {
  47169             /* +/- infinity */
  47170             if (s->state == SUM_PRECISE_STATE_NAN ||
  47171                 (s->state == SUM_PRECISE_STATE_MINUS_INFINITY && !sgn) ||
  47172                 (s->state == SUM_PRECISE_STATE_INFINITY && sgn)) {
  47173                 s->state = SUM_PRECISE_STATE_NAN;
  47174             } else {
  47175                 s->state = SUM_PRECISE_STATE_INFINITY + sgn;
  47176             }
  47177         } else {
  47178             /* NaN */
  47179             s->state = SUM_PRECISE_STATE_NAN;
  47180         }
  47181     } else if (e == 0) {
  47182         if (likely(m == 0)) {
  47183             /* zero */
  47184             if (s->n_limbs == 0 && !sgn)
  47185                 s->n_limbs = 1;
  47186         } else {
  47187             /* subnormal */
  47188             p = 0;
  47189             shift = 0;
  47190             goto add;
  47191         }
  47192     } else {
  47193         /* Note: we sum even if state != SUM_PRECISE_STATE_FINITE to
  47194            avoid tests */
  47195         m |= (uint64_t)1 << 52;
  47196         shift = e - 1;
  47197         /* 'p' is the position of a0 in acc. The division is normally
  47198            implementation as a multiplication by the compiler. */
  47199         p = shift / SP_LIMB_BITS;
  47200         shift %= SP_LIMB_BITS;
  47201     add:
  47202         a0 = (m << shift) & (((uint64_t)1 << SP_LIMB_BITS) - 1);
  47203         a1 = m >> (SP_LIMB_BITS - shift);
  47204         if (!sgn) {
  47205             s->acc[p] += a0;
  47206             s->acc[p + 1] += a1;
  47207         } else {
  47208             s->acc[p] -= a0;
  47209             s->acc[p + 1] -= a1;
  47210         }
  47211         s->n_limbs = max_int(s->n_limbs, p + 2);
  47212 
  47213         if (unlikely(--s->counter == 0)) {
  47214             s->counter = SUM_PRECISE_COUNTER_INIT;
  47215             sum_precise_renorm(s);
  47216         }
  47217     }
  47218 }
  47219 
  47220 static double sum_precise_get_result(SumPreciseState *s)
  47221 {
  47222     int n, shift, e, p, is_neg;
  47223     uint64_t m, addend;
  47224         
  47225     if (s->state != SUM_PRECISE_STATE_FINITE) {
  47226         switch(s->state) {
  47227         default:
  47228         case SUM_PRECISE_STATE_INFINITY:
  47229             return INFINITY;
  47230         case SUM_PRECISE_STATE_MINUS_INFINITY:
  47231             return -INFINITY;
  47232         case SUM_PRECISE_STATE_NAN:
  47233             return NAN;
  47234         }
  47235     }
  47236 
  47237     sum_precise_renorm(s);
  47238 
  47239     /* extract the sign and absolute value */
  47240 #if 0
  47241     {
  47242         int i;
  47243         printf("len=%d:", s->n_limbs);
  47244         for(i = s->n_limbs - 1; i >= 0; i--)
  47245             printf(" %014lx", s->acc[i]);
  47246         printf("\n");
  47247     }
  47248 #endif
  47249     n = s->n_limbs;
  47250     /* minus zero result */
  47251     if (n == 0)
  47252         return -0.0;
  47253     
  47254     /* normalize */
  47255     while (n > 0 && s->acc[n - 1] == 0)
  47256         n--;
  47257     /* zero result. The spec tells it is always positive in the finite case */
  47258     if (n == 0)
  47259         return 0.0;
  47260     is_neg = (s->acc[n - 1] < 0);
  47261     if (is_neg) {
  47262         uint64_t v, carry;
  47263         int i;
  47264         /* negate */
  47265         /* XXX: do it only when needed */
  47266         carry = 1;
  47267         for(i = 0; i < n - 1; i++) {
  47268             v = (((uint64_t)1 << SP_LIMB_BITS) - 1) - s->acc[i] + carry;
  47269             carry = v >> SP_LIMB_BITS;
  47270             s->acc[i] = v & (((uint64_t)1 << SP_LIMB_BITS) - 1);
  47271         }
  47272         s->acc[n - 1] = -s->acc[n - 1] + carry - 1;
  47273         while (n > 1 && s->acc[n - 1] == 0)
  47274             n--;
  47275     }
  47276     /* subnormal case */
  47277     if (n == 1 && s->acc[0] < ((uint64_t)1 << 52))
  47278         return uint64_as_float64(((uint64_t)is_neg << 63) | s->acc[0]); 
  47279     /* normal case */
  47280     e = n * SP_LIMB_BITS;
  47281     p = n - 1;
  47282     m = s->acc[p];
  47283     shift = clz64(m) - (64 - SP_LIMB_BITS);
  47284     e = e - shift - 52;
  47285     if (shift != 0) {
  47286         m <<= shift;
  47287         if (p > 0) {
  47288             int shift1;
  47289             uint64_t nz;
  47290             p--;
  47291             shift1 = SP_LIMB_BITS - shift;
  47292             nz = s->acc[p] & (((uint64_t)1 << shift1) - 1);
  47293             m = m | (s->acc[p] >> shift1) | (nz != 0);
  47294         }
  47295     }
  47296     if ((m & ((1 << SP_RND_BITS) - 1)) == (1 << (SP_RND_BITS - 1))) {
  47297         /* see if the LSB part is non zero for the final rounding  */
  47298         while (p > 0) {
  47299             p--;
  47300             if (s->acc[p] != 0) {
  47301                 m |= 1;
  47302                 break;
  47303             }
  47304         }
  47305     }
  47306     /* rounding to nearest with ties to even */
  47307     addend = (1 << (SP_RND_BITS - 1)) - 1 + ((m >> SP_RND_BITS) & 1);
  47308     m = (m + addend) >> SP_RND_BITS;
  47309     /* handle overflow in the rounding */
  47310     if (m == ((uint64_t)1 << 53))
  47311         e++;
  47312     if (unlikely(e >= 2047)) {
  47313         /* infinity */
  47314         return uint64_as_float64(((uint64_t)is_neg << 63) | ((uint64_t)2047 << 52));
  47315     } else {
  47316         m &= (((uint64_t)1 << 52) - 1);
  47317         return uint64_as_float64(((uint64_t)is_neg << 63) | ((uint64_t)e << 52) | m);
  47318     }
  47319 }
  47320 
  47321 static JSValue js_math_sumPrecise(JSContext *ctx, JSValueConst this_val,
  47322                                   int argc, JSValueConst *argv)
  47323 {
  47324     JSValue iter, next, item, ret;
  47325     uint32_t tag;
  47326     int done;
  47327     double d;
  47328     SumPreciseState s_s, *s = &s_s;
  47329 
  47330     iter = JS_GetIterator(ctx, argv[0], FALSE);
  47331     if (JS_IsException(iter))
  47332         return JS_EXCEPTION;
  47333     ret = JS_EXCEPTION;
  47334     next = JS_GetProperty(ctx, iter, JS_ATOM_next);
  47335     if (JS_IsException(next))
  47336         goto fail;
  47337     sum_precise_init(s);
  47338     for (;;) {
  47339         item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
  47340         if (JS_IsException(item))
  47341             goto fail;
  47342         if (done)
  47343             break;
  47344         tag = JS_VALUE_GET_TAG(item);
  47345         if (JS_TAG_IS_FLOAT64(tag)) {
  47346             d = JS_VALUE_GET_FLOAT64(item);
  47347         } else if (tag == JS_TAG_INT) {
  47348             d = JS_VALUE_GET_INT(item);
  47349         } else {
  47350             JS_FreeValue(ctx, item);
  47351             JS_ThrowTypeError(ctx, "not a number");
  47352             JS_IteratorClose(ctx, iter, TRUE);
  47353             goto fail;
  47354         }
  47355         sum_precise_add(s, d);
  47356     }
  47357     ret = __JS_NewFloat64(ctx, sum_precise_get_result(s));
  47358 fail:
  47359     JS_FreeValue(ctx, iter);
  47360     JS_FreeValue(ctx, next);
  47361     return ret;
  47362 }
  47363 
  47364 /* xorshift* random number generator by Marsaglia */
  47365 static uint64_t xorshift64star(uint64_t *pstate)
  47366 {
  47367     uint64_t x;
  47368     x = *pstate;
  47369     x ^= x >> 12;
  47370     x ^= x << 25;
  47371     x ^= x >> 27;
  47372     *pstate = x;
  47373     return x * 0x2545F4914F6CDD1D;
  47374 }
  47375 
  47376 static void js_random_init(JSContext *ctx)
  47377 {
  47378     struct timeval tv;
  47379     gettimeofday(&tv, NULL);
  47380     ctx->random_state = ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec;
  47381     /* the state must be non zero */
  47382     if (ctx->random_state == 0)
  47383         ctx->random_state = 1;
  47384 }
  47385 
  47386 static JSValue js_math_random(JSContext *ctx, JSValueConst this_val,
  47387                               int argc, JSValueConst *argv)
  47388 {
  47389     JSFloat64Union u;
  47390     uint64_t v;
  47391 
  47392     v = xorshift64star(&ctx->random_state);
  47393     /* 1.0 <= u.d < 2 */
  47394     u.u64 = ((uint64_t)0x3ff << 52) | (v >> 12);
  47395     return __JS_NewFloat64(ctx, u.d - 1.0);
  47396 }
  47397 
  47398 static const JSCFunctionListEntry js_math_funcs[] = {
  47399     JS_CFUNC_MAGIC_DEF("min", 2, js_math_min_max, 0 ),
  47400     JS_CFUNC_MAGIC_DEF("max", 2, js_math_min_max, 1 ),
  47401     JS_CFUNC_SPECIAL_DEF("abs", 1, f_f, fabs ),
  47402     JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, floor ),
  47403     JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, ceil ),
  47404     JS_CFUNC_SPECIAL_DEF("round", 1, f_f, js_math_round ),
  47405     JS_CFUNC_SPECIAL_DEF("sqrt", 1, f_f, sqrt ),
  47406 
  47407     JS_CFUNC_SPECIAL_DEF("acos", 1, f_f, acos ),
  47408     JS_CFUNC_SPECIAL_DEF("asin", 1, f_f, asin ),
  47409     JS_CFUNC_SPECIAL_DEF("atan", 1, f_f, atan ),
  47410     JS_CFUNC_SPECIAL_DEF("atan2", 2, f_f_f, atan2 ),
  47411     JS_CFUNC_SPECIAL_DEF("cos", 1, f_f, cos ),
  47412     JS_CFUNC_SPECIAL_DEF("exp", 1, f_f, exp ),
  47413     JS_CFUNC_SPECIAL_DEF("log", 1, f_f, log ),
  47414     JS_CFUNC_SPECIAL_DEF("pow", 2, f_f_f, js_pow ),
  47415     JS_CFUNC_SPECIAL_DEF("sin", 1, f_f, sin ),
  47416     JS_CFUNC_SPECIAL_DEF("tan", 1, f_f, tan ),
  47417     /* ES6 */
  47418     JS_CFUNC_SPECIAL_DEF("trunc", 1, f_f, trunc ),
  47419     JS_CFUNC_SPECIAL_DEF("sign", 1, f_f, js_math_sign ),
  47420     JS_CFUNC_SPECIAL_DEF("cosh", 1, f_f, cosh ),
  47421     JS_CFUNC_SPECIAL_DEF("sinh", 1, f_f, sinh ),
  47422     JS_CFUNC_SPECIAL_DEF("tanh", 1, f_f, tanh ),
  47423     JS_CFUNC_SPECIAL_DEF("acosh", 1, f_f, acosh ),
  47424     JS_CFUNC_SPECIAL_DEF("asinh", 1, f_f, asinh ),
  47425     JS_CFUNC_SPECIAL_DEF("atanh", 1, f_f, atanh ),
  47426     JS_CFUNC_SPECIAL_DEF("expm1", 1, f_f, expm1 ),
  47427     JS_CFUNC_SPECIAL_DEF("log1p", 1, f_f, log1p ),
  47428     JS_CFUNC_SPECIAL_DEF("log2", 1, f_f, log2 ),
  47429     JS_CFUNC_SPECIAL_DEF("log10", 1, f_f, log10 ),
  47430     JS_CFUNC_SPECIAL_DEF("cbrt", 1, f_f, cbrt ),
  47431     JS_CFUNC_DEF("hypot", 2, js_math_hypot ),
  47432     JS_CFUNC_DEF("random", 0, js_math_random ),
  47433     JS_CFUNC_SPECIAL_DEF("f16round", 1, f_f, js_math_f16round ),
  47434     JS_CFUNC_SPECIAL_DEF("fround", 1, f_f, js_math_fround ),
  47435     JS_CFUNC_DEF("imul", 2, js_math_imul ),
  47436     JS_CFUNC_DEF("clz32", 1, js_math_clz32 ),
  47437     JS_CFUNC_DEF("sumPrecise", 1, js_math_sumPrecise ),
  47438     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Math", JS_PROP_CONFIGURABLE ),
  47439     JS_PROP_DOUBLE_DEF("E", 2.718281828459045, 0 ),
  47440     JS_PROP_DOUBLE_DEF("LN10", 2.302585092994046, 0 ),
  47441     JS_PROP_DOUBLE_DEF("LN2", 0.6931471805599453, 0 ),
  47442     JS_PROP_DOUBLE_DEF("LOG2E", 1.4426950408889634, 0 ),
  47443     JS_PROP_DOUBLE_DEF("LOG10E", 0.4342944819032518, 0 ),
  47444     JS_PROP_DOUBLE_DEF("PI", 3.141592653589793, 0 ),
  47445     JS_PROP_DOUBLE_DEF("SQRT1_2", 0.7071067811865476, 0 ),
  47446     JS_PROP_DOUBLE_DEF("SQRT2", 1.4142135623730951, 0 ),
  47447 };
  47448 
  47449 static const JSCFunctionListEntry js_math_obj[] = {
  47450     JS_OBJECT_DEF("Math", js_math_funcs, countof(js_math_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
  47451 };
  47452 
  47453 /* Date */
  47454 
  47455 /* OS dependent. d = argv[0] is in ms from 1970. Return the difference
  47456    between UTC time and local time 'd' in minutes */
  47457 static int getTimezoneOffset(int64_t time)
  47458 {
  47459     time_t ti;
  47460     int res;
  47461 
  47462     time /= 1000; /* convert to seconds */
  47463     if (sizeof(time_t) == 4) {
  47464         /* on 32-bit systems, we need to clamp the time value to the
  47465            range of `time_t`. This is better than truncating values to
  47466            32 bits and hopefully provides the same result as 64-bit
  47467            implementation of localtime_r.
  47468          */
  47469         if ((time_t)-1 < 0) {
  47470             if (time < INT32_MIN) {
  47471                 time = INT32_MIN;
  47472             } else if (time > INT32_MAX) {
  47473                 time = INT32_MAX;
  47474             }
  47475         } else {
  47476             if (time < 0) {
  47477                 time = 0;
  47478             } else if (time > UINT32_MAX) {
  47479                 time = UINT32_MAX;
  47480             }
  47481         }
  47482     }
  47483     ti = time;
  47484 #if defined(_WIN32)
  47485     {
  47486         struct tm *tm;
  47487         time_t gm_ti, loc_ti;
  47488 
  47489         tm = gmtime(&ti);
  47490         if (!tm)
  47491             return 0;
  47492         gm_ti = mktime(tm);
  47493 
  47494         tm = localtime(&ti);
  47495         if (!tm)
  47496             return 0;
  47497         loc_ti = mktime(tm);
  47498 
  47499         res = (gm_ti - loc_ti) / 60;
  47500     }
  47501 #else
  47502     {
  47503         struct tm tm;
  47504         localtime_r(&ti, &tm);
  47505         res = -tm.tm_gmtoff / 60;
  47506     }
  47507 #endif
  47508     return res;
  47509 }
  47510 
  47511 #if 0
  47512 static JSValue js___date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val,
  47513                                            int argc, JSValueConst *argv)
  47514 {
  47515     double dd;
  47516 
  47517     if (JS_ToFloat64(ctx, &dd, argv[0]))
  47518         return JS_EXCEPTION;
  47519     if (isnan(dd))
  47520         return __JS_NewFloat64(ctx, dd);
  47521     else
  47522         return JS_NewInt32(ctx, getTimezoneOffset((int64_t)dd));
  47523 }
  47524 
  47525 static JSValue js_get_prototype_from_ctor(JSContext *ctx, JSValueConst ctor,
  47526                                           JSValueConst def_proto)
  47527 {
  47528     JSValue proto;
  47529     proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);
  47530     if (JS_IsException(proto))
  47531         return proto;
  47532     if (!JS_IsObject(proto)) {
  47533         JS_FreeValue(ctx, proto);
  47534         proto = JS_DupValue(ctx, def_proto);
  47535     }
  47536     return proto;
  47537 }
  47538 
  47539 /* create a new date object */
  47540 static JSValue js___date_create(JSContext *ctx, JSValueConst this_val,
  47541                                 int argc, JSValueConst *argv)
  47542 {
  47543     JSValue obj, proto;
  47544     proto = js_get_prototype_from_ctor(ctx, argv[0], argv[1]);
  47545     if (JS_IsException(proto))
  47546         return proto;
  47547     obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_DATE);
  47548     JS_FreeValue(ctx, proto);
  47549     if (!JS_IsException(obj))
  47550         JS_SetObjectData(ctx, obj, JS_DupValue(ctx, argv[2]));
  47551     return obj;
  47552 }
  47553 #endif
  47554 
  47555 /* RegExp */
  47556 
  47557 static void js_regexp_finalizer(JSRuntime *rt, JSValue val)
  47558 {
  47559     JSObject *p = JS_VALUE_GET_OBJ(val);
  47560     JSRegExp *re = &p->u.regexp;
  47561     if (re->bytecode != NULL)
  47562         JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, re->bytecode));
  47563     if (re->pattern != NULL)
  47564         JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, re->pattern));
  47565 }
  47566 
  47567 /* create a string containing the RegExp bytecode */
  47568 static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
  47569                                  JSValueConst flags)
  47570 {
  47571     const char *str;
  47572     int re_flags, mask;
  47573     uint8_t *re_bytecode_buf;
  47574     size_t i, len;
  47575     int re_bytecode_len;
  47576     JSValue ret;
  47577     char error_msg[64];
  47578 
  47579     re_flags = 0;
  47580     if (!JS_IsUndefined(flags)) {
  47581         str = JS_ToCStringLen(ctx, &len, flags);
  47582         if (!str)
  47583             return JS_EXCEPTION;
  47584         /* XXX: re_flags = LRE_FLAG_OCTAL unless strict mode? */
  47585         for (i = 0; i < len; i++) {
  47586             switch(str[i]) {
  47587             case 'd':
  47588                 mask = LRE_FLAG_INDICES;
  47589                 break;
  47590             case 'g':
  47591                 mask = LRE_FLAG_GLOBAL;
  47592                 break;
  47593             case 'i':
  47594                 mask = LRE_FLAG_IGNORECASE;
  47595                 break;
  47596             case 'm':
  47597                 mask = LRE_FLAG_MULTILINE;
  47598                 break;
  47599             case 's':
  47600                 mask = LRE_FLAG_DOTALL;
  47601                 break;
  47602             case 'u':
  47603                 mask = LRE_FLAG_UNICODE;
  47604                 break;
  47605             case 'v':
  47606                 mask = LRE_FLAG_UNICODE_SETS;
  47607                 break;
  47608             case 'y':
  47609                 mask = LRE_FLAG_STICKY;
  47610                 break;
  47611             default:
  47612                 goto bad_flags;
  47613             }
  47614             if ((re_flags & mask) != 0) {
  47615             bad_flags:
  47616                 JS_FreeCString(ctx, str);
  47617                 goto bad_flags1;
  47618             }
  47619             re_flags |= mask;
  47620         }
  47621         JS_FreeCString(ctx, str);
  47622     }
  47623 
  47624     /* 'u' and 'v' cannot be both set */
  47625     if ((re_flags & LRE_FLAG_UNICODE_SETS) && (re_flags & LRE_FLAG_UNICODE)) {
  47626     bad_flags1:
  47627         return JS_ThrowSyntaxError(ctx, "invalid regular expression flags");
  47628     }
  47629     
  47630     str = JS_ToCStringLen2(ctx, &len, pattern, !(re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)));
  47631     if (!str)
  47632         return JS_EXCEPTION;
  47633     re_bytecode_buf = lre_compile(&re_bytecode_len, error_msg,
  47634                                   sizeof(error_msg), str, len, re_flags, ctx);
  47635     JS_FreeCString(ctx, str);
  47636     if (!re_bytecode_buf) {
  47637         JS_ThrowSyntaxError(ctx, "%s", error_msg);
  47638         return JS_EXCEPTION;
  47639     }
  47640 
  47641     ret = js_new_string8_len(ctx, (const char *)re_bytecode_buf, re_bytecode_len);
  47642     js_free(ctx, re_bytecode_buf);
  47643     return ret;
  47644 }
  47645 
  47646 /* fast regexp creation */
  47647 static JSValue JS_NewRegexp(JSContext *ctx, JSValue pattern, JSValue bc)
  47648 {
  47649     JSValue obj;
  47650     JSProperty props[1];
  47651     JSObject *p;
  47652     JSRegExp *re;
  47653 
  47654     /* sanity check */
  47655     if (unlikely(JS_VALUE_GET_TAG(bc) != JS_TAG_STRING ||
  47656                  JS_VALUE_GET_TAG(pattern) != JS_TAG_STRING)) {
  47657         JS_ThrowTypeError(ctx, "string expected");
  47658         goto fail;
  47659     }
  47660     props[0].u.value = JS_NewInt32(ctx, 0); /* lastIndex */
  47661     obj = JS_NewObjectFromShape(ctx, js_dup_shape(ctx->regexp_shape), JS_CLASS_REGEXP, props);
  47662     if (JS_IsException(obj))
  47663         goto fail;
  47664     p = JS_VALUE_GET_OBJ(obj);
  47665     re = &p->u.regexp;
  47666     re->pattern = JS_VALUE_GET_STRING(pattern);
  47667     re->bytecode = JS_VALUE_GET_STRING(bc);
  47668     return obj;
  47669  fail:
  47670     JS_FreeValue(ctx, bc);
  47671     JS_FreeValue(ctx, pattern);
  47672     return JS_EXCEPTION;
  47673 }
  47674 
  47675 /* set the RegExp fields */
  47676 static JSValue js_regexp_set_internal(JSContext *ctx,
  47677                                       JSValue obj,
  47678                                       JSValue pattern, JSValue bc)
  47679 {
  47680     JSObject *p;
  47681     JSRegExp *re;
  47682 
  47683     /* sanity check */
  47684     if (unlikely(JS_VALUE_GET_TAG(bc) != JS_TAG_STRING ||
  47685                  JS_VALUE_GET_TAG(pattern) != JS_TAG_STRING)) {
  47686         JS_ThrowTypeError(ctx, "string expected");
  47687         JS_FreeValue(ctx, obj);
  47688         JS_FreeValue(ctx, bc);
  47689         JS_FreeValue(ctx, pattern);
  47690         return JS_EXCEPTION;
  47691     }
  47692 
  47693     p = JS_VALUE_GET_OBJ(obj);
  47694     re = &p->u.regexp;
  47695     re->pattern = JS_VALUE_GET_STRING(pattern);
  47696     re->bytecode = JS_VALUE_GET_STRING(bc);
  47697     /* Note: cannot fail because the field is preallocated */
  47698     JS_DefinePropertyValue(ctx, obj, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0),
  47699                            JS_PROP_WRITABLE);
  47700     return obj;
  47701 }
  47702 
  47703 static JSRegExp *js_get_regexp(JSContext *ctx, JSValueConst obj, BOOL throw_error)
  47704 {
  47705     if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
  47706         JSObject *p = JS_VALUE_GET_OBJ(obj);
  47707         if (p->class_id == JS_CLASS_REGEXP)
  47708             return &p->u.regexp;
  47709     }
  47710     if (throw_error) {
  47711         JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP);
  47712     }
  47713     return NULL;
  47714 }
  47715 
  47716 /* return < 0 if exception or TRUE/FALSE */
  47717 static int js_is_regexp(JSContext *ctx, JSValueConst obj)
  47718 {
  47719     JSValue m;
  47720 
  47721     if (!JS_IsObject(obj))
  47722         return FALSE;
  47723     m = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_match);
  47724     if (JS_IsException(m))
  47725         return -1;
  47726     if (!JS_IsUndefined(m))
  47727         return JS_ToBoolFree(ctx, m);
  47728     return js_get_regexp(ctx, obj, FALSE) != NULL;
  47729 }
  47730 
  47731 static JSValue js_regexp_constructor(JSContext *ctx, JSValueConst new_target,
  47732                                      int argc, JSValueConst *argv)
  47733 {
  47734     JSValue pattern, flags, bc, val, obj = JS_UNDEFINED;
  47735     JSValueConst pat, flags1;
  47736     JSRegExp *re;
  47737     int pat_is_regexp;
  47738 
  47739     pat = argv[0];
  47740     flags1 = argv[1];
  47741     pat_is_regexp = js_is_regexp(ctx, pat);
  47742     if (pat_is_regexp < 0)
  47743         return JS_EXCEPTION;
  47744     if (JS_IsUndefined(new_target)) {
  47745         /* called as a function */
  47746         new_target = JS_GetActiveFunction(ctx);
  47747         if (pat_is_regexp && JS_IsUndefined(flags1)) {
  47748             JSValue ctor;
  47749             BOOL res;
  47750             ctor = JS_GetProperty(ctx, pat, JS_ATOM_constructor);
  47751             if (JS_IsException(ctor))
  47752                 return ctor;
  47753             res = js_same_value(ctx, ctor, new_target);
  47754             JS_FreeValue(ctx, ctor);
  47755             if (res)
  47756                 return JS_DupValue(ctx, pat);
  47757         }
  47758     }
  47759     re = js_get_regexp(ctx, pat, FALSE);
  47760     flags = JS_UNDEFINED;
  47761     if (re) {
  47762         pattern = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
  47763         if (JS_IsUndefined(flags1)) {
  47764             bc = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->bytecode));
  47765             obj = js_create_from_ctor(ctx, new_target, JS_CLASS_REGEXP);
  47766             if (JS_IsException(obj))
  47767                 goto fail;
  47768             goto no_compilation;
  47769         } else {
  47770             flags = JS_DupValue(ctx, flags1);
  47771         }
  47772     } else {
  47773         if (pat_is_regexp) {
  47774             pattern = JS_GetProperty(ctx, pat, JS_ATOM_source);
  47775             if (JS_IsException(pattern))
  47776                 goto fail;
  47777             if (JS_IsUndefined(flags1)) {
  47778                 flags = JS_GetProperty(ctx, pat, JS_ATOM_flags);
  47779                 if (JS_IsException(flags))
  47780                     goto fail;
  47781             } else {
  47782                 flags = JS_DupValue(ctx, flags1);
  47783             }
  47784         } else {
  47785             pattern = JS_DupValue(ctx, pat);
  47786             flags = JS_DupValue(ctx, flags1);
  47787         }
  47788         if (JS_IsUndefined(pattern)) {
  47789             pattern = JS_AtomToString(ctx, JS_ATOM_empty_string);
  47790         } else {
  47791             val = pattern;
  47792             pattern = JS_ToString(ctx, val);
  47793             JS_FreeValue(ctx, val);
  47794             if (JS_IsException(pattern))
  47795                 goto fail;
  47796         }
  47797     }
  47798     obj = js_create_from_ctor(ctx, new_target, JS_CLASS_REGEXP);
  47799     if (JS_IsException(obj))
  47800         goto fail;
  47801     bc = js_compile_regexp(ctx, pattern, flags);
  47802     if (JS_IsException(bc))
  47803         goto fail;
  47804     JS_FreeValue(ctx, flags);
  47805  no_compilation:
  47806     return js_regexp_set_internal(ctx, obj, pattern, bc);
  47807  fail:
  47808     JS_FreeValue(ctx, pattern);
  47809     JS_FreeValue(ctx, flags);
  47810     JS_FreeValue(ctx, obj);
  47811     return JS_EXCEPTION;
  47812 }
  47813 
  47814 static JSValue js_regexp_compile(JSContext *ctx, JSValueConst this_val,
  47815                                  int argc, JSValueConst *argv)
  47816 {
  47817     JSRegExp *re1, *re;
  47818     JSValueConst pattern1, flags1;
  47819     JSValue bc, pattern;
  47820 
  47821     re = js_get_regexp(ctx, this_val, TRUE);
  47822     if (!re)
  47823         return JS_EXCEPTION;
  47824     pattern1 = argv[0];
  47825     flags1 = argv[1];
  47826     re1 = js_get_regexp(ctx, pattern1, FALSE);
  47827     if (re1) {
  47828         if (!JS_IsUndefined(flags1))
  47829             return JS_ThrowTypeError(ctx, "flags must be undefined");
  47830         pattern = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re1->pattern));
  47831         bc = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re1->bytecode));
  47832     } else {
  47833         bc = JS_UNDEFINED;
  47834         if (JS_IsUndefined(pattern1))
  47835             pattern = JS_AtomToString(ctx, JS_ATOM_empty_string);
  47836         else
  47837             pattern = JS_ToString(ctx, pattern1);
  47838         if (JS_IsException(pattern))
  47839             goto fail;
  47840         bc = js_compile_regexp(ctx, pattern, flags1);
  47841         if (JS_IsException(bc))
  47842             goto fail;
  47843     }
  47844     JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
  47845     JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, re->bytecode));
  47846     re->pattern = JS_VALUE_GET_STRING(pattern);
  47847     re->bytecode = JS_VALUE_GET_STRING(bc);
  47848     if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
  47849                        JS_NewInt32(ctx, 0)) < 0)
  47850         return JS_EXCEPTION;
  47851     return JS_DupValue(ctx, this_val);
  47852  fail:
  47853     JS_FreeValue(ctx, pattern);
  47854     JS_FreeValue(ctx, bc);
  47855     return JS_EXCEPTION;
  47856 }
  47857 
  47858 static JSValue js_regexp_get_source(JSContext *ctx, JSValueConst this_val)
  47859 {
  47860     JSRegExp *re;
  47861     JSString *p;
  47862     StringBuffer b_s, *b = &b_s;
  47863     int i, n, c, c2, bra;
  47864 
  47865     if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
  47866         return JS_ThrowTypeErrorNotAnObject(ctx);
  47867 
  47868     if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP]))
  47869         goto empty_regex;
  47870 
  47871     re = js_get_regexp(ctx, this_val, TRUE);
  47872     if (!re)
  47873         return JS_EXCEPTION;
  47874 
  47875     p = re->pattern;
  47876 
  47877     if (p->len == 0) {
  47878     empty_regex:
  47879         return js_new_string8(ctx, "(?:)");
  47880     }
  47881     string_buffer_init2(ctx, b, p->len, p->is_wide_char);
  47882 
  47883     /* Escape '/' and newline sequences as needed */
  47884     bra = 0;
  47885     for (i = 0, n = p->len; i < n;) {
  47886         c2 = -1;
  47887         switch (c = string_get(p, i++)) {
  47888         case '\\':
  47889             if (i < n)
  47890                 c2 = string_get(p, i++);
  47891             break;
  47892         case ']':
  47893             bra = 0;
  47894             break;
  47895         case '[':
  47896             if (!bra) {
  47897                 if (i < n && string_get(p, i) == ']')
  47898                     c2 = string_get(p, i++);
  47899                 bra = 1;
  47900             }
  47901             break;
  47902         case '\n':
  47903             c = '\\';
  47904             c2 = 'n';
  47905             break;
  47906         case '\r':
  47907             c = '\\';
  47908             c2 = 'r';
  47909             break;
  47910         case '/':
  47911             if (!bra) {
  47912                 c = '\\';
  47913                 c2 = '/';
  47914             }
  47915             break;
  47916         }
  47917         string_buffer_putc16(b, c);
  47918         if (c2 >= 0)
  47919             string_buffer_putc16(b, c2);
  47920     }
  47921     return string_buffer_end(b);
  47922 }
  47923 
  47924 static JSValue js_regexp_get_flag(JSContext *ctx, JSValueConst this_val, int mask)
  47925 {
  47926     JSRegExp *re;
  47927     int flags;
  47928 
  47929     if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
  47930         return JS_ThrowTypeErrorNotAnObject(ctx);
  47931 
  47932     re = js_get_regexp(ctx, this_val, FALSE);
  47933     if (!re) {
  47934         if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP]))
  47935             return JS_UNDEFINED;
  47936         else
  47937             return JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP);
  47938     }
  47939 
  47940     flags = lre_get_flags(re->bytecode->u.str8);
  47941     return JS_NewBool(ctx, flags & mask);
  47942 }
  47943 
  47944 #define RE_FLAG_COUNT 8
  47945 
  47946 static JSValue js_regexp_get_flags(JSContext *ctx, JSValueConst this_val)
  47947 {
  47948     char str[RE_FLAG_COUNT], *p = str;
  47949     int res, i;
  47950     static const int flag_atom[RE_FLAG_COUNT] = {
  47951         JS_ATOM_hasIndices,
  47952         JS_ATOM_global,
  47953         JS_ATOM_ignoreCase,
  47954         JS_ATOM_multiline,
  47955         JS_ATOM_dotAll,
  47956         JS_ATOM_unicode,
  47957         JS_ATOM_unicodeSets,
  47958         JS_ATOM_sticky,
  47959     };
  47960     static const char flag_char[RE_FLAG_COUNT] = { 'd', 'g', 'i', 'm', 's', 'u', 'v', 'y' };
  47961     
  47962     if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
  47963         return JS_ThrowTypeErrorNotAnObject(ctx);
  47964 
  47965     for(i = 0; i < RE_FLAG_COUNT; i++) {
  47966         res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, flag_atom[i]));
  47967         if (res < 0)
  47968             goto exception;
  47969         if (res)
  47970             *p++ = flag_char[i];
  47971     }
  47972     return JS_NewStringLen(ctx, str, p - str);
  47973 
  47974 exception:
  47975     return JS_EXCEPTION;
  47976 }
  47977 
  47978 static JSValue js_regexp_toString(JSContext *ctx, JSValueConst this_val,
  47979                                   int argc, JSValueConst *argv)
  47980 {
  47981     JSValue pattern, flags;
  47982     StringBuffer b_s, *b = &b_s;
  47983 
  47984     if (!JS_IsObject(this_val))
  47985         return JS_ThrowTypeErrorNotAnObject(ctx);
  47986 
  47987     string_buffer_init(ctx, b, 0);
  47988     string_buffer_putc8(b, '/');
  47989     pattern = JS_GetProperty(ctx, this_val, JS_ATOM_source);
  47990     if (string_buffer_concat_value_free(b, pattern))
  47991         goto fail;
  47992     string_buffer_putc8(b, '/');
  47993     flags = JS_GetProperty(ctx, this_val, JS_ATOM_flags);
  47994     if (string_buffer_concat_value_free(b, flags))
  47995         goto fail;
  47996     return string_buffer_end(b);
  47997 
  47998 fail:
  47999     string_buffer_free(b);
  48000     return JS_EXCEPTION;
  48001 }
  48002 
  48003 int lre_check_stack_overflow(void *opaque, size_t alloca_size)
  48004 {
  48005     JSContext *ctx = opaque;
  48006     return js_check_stack_overflow(ctx->rt, alloca_size);
  48007 }
  48008 
  48009 int lre_check_timeout(void *opaque)
  48010 {
  48011     JSContext *ctx = opaque;
  48012     JSRuntime *rt = ctx->rt;
  48013     return (rt->interrupt_handler && 
  48014             rt->interrupt_handler(rt, rt->interrupt_opaque));
  48015 }
  48016 
  48017 void *lre_realloc(void *opaque, void *ptr, size_t size)
  48018 {
  48019     JSContext *ctx = opaque;
  48020     /* No JS exception is raised here */
  48021     return js_realloc_rt(ctx->rt, ptr, size);
  48022 }
  48023 
  48024 static JSValue js_regexp_escape(JSContext *ctx, JSValueConst this_val,
  48025                                 int argc, JSValueConst *argv)
  48026 {
  48027     JSValue str;
  48028     StringBuffer b_s, *b = &b_s;
  48029     JSString *p;
  48030     uint32_t c;
  48031     char s[16];
  48032     int i, i0;
  48033     
  48034     if (!JS_IsString(argv[0]))
  48035         return JS_ThrowTypeError(ctx, "not a string");
  48036     str = JS_ToString(ctx, argv[0]); /* must call it to linearlize ropes */
  48037     if (JS_IsException(str))
  48038         return JS_EXCEPTION;
  48039     p = JS_VALUE_GET_STRING(str);
  48040     string_buffer_init2(ctx, b, 0, p->is_wide_char);
  48041     for (i = 0; i < p->len; ) {
  48042         i0 = i;
  48043         c = string_getc(p, &i);
  48044         if (c < 33) {
  48045             if (c >= 9 && c <= 13) {
  48046                 string_buffer_putc8(b, '\\');
  48047                 string_buffer_putc8(b, "tnvfr"[c - 9]);
  48048             } else {
  48049                 goto hex2;
  48050             }
  48051         } else if (c < 128) {
  48052             if ((c >= '0' && c <= '9')
  48053              || (c >= 'A' && c <= 'Z')
  48054              || (c >= 'a' && c <= 'z')) {
  48055                 if (i0 == 0)
  48056                     goto hex2;
  48057             } else if (strchr(",-=<>#&!%:;@~'`\"", c)) {
  48058                 goto hex2;
  48059             } else if (c != '_') {
  48060                 string_buffer_putc8(b, '\\');
  48061             }
  48062             string_buffer_putc8(b, c);
  48063         } else if (c < 256) {
  48064         hex2:
  48065             snprintf(s, sizeof(s), "\\x%02x", c);
  48066             string_buffer_puts8(b, s);
  48067         } else if (is_surrogate(c) || lre_is_space(c)) {
  48068             snprintf(s, sizeof(s), "\\u%04x", c);
  48069             string_buffer_puts8(b, s);
  48070         } else {
  48071             string_buffer_putc(b, c);
  48072         }
  48073     }
  48074     JS_FreeValue(ctx, str);
  48075     return string_buffer_end(b);
  48076 }
  48077 
  48078 /* this_val must be of JS_CLASS_REGEXP */
  48079 static force_inline int js_regexp_get_lastIndex(JSContext *ctx, int64_t *plast_index,
  48080                                                 JSValueConst this_val)
  48081 {
  48082     JSObject *p = JS_VALUE_GET_OBJ(this_val);
  48083     
  48084     /* lastIndex is always the first property (it is not configurable) */
  48085     if (likely(JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT)) {
  48086         *plast_index = max_int(JS_VALUE_GET_INT(p->prop[0].u.value), 0);
  48087         return 0;
  48088     } else {
  48089         return JS_ToLengthFree(ctx, plast_index, JS_DupValue(ctx, p->prop[0].u.value));
  48090     }
  48091 }
  48092 
  48093 /* this_val must be of JS_CLASS_REGEXP */
  48094 static force_inline int js_regexp_set_lastIndex(JSContext *ctx, JSValueConst this_val,
  48095                                                 int last_index)
  48096 {
  48097     JSObject *p = JS_VALUE_GET_OBJ(this_val);
  48098     
  48099     /* lastIndex is always the first property (it is not configurable) */
  48100     if (likely(JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT &&
  48101                (get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE))) {
  48102         set_value(ctx, &p->prop[0].u.value, JS_NewInt32(ctx, last_index));
  48103     } else {
  48104         if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
  48105                            JS_NewInt32(ctx, last_index)) < 0)
  48106             return -1;
  48107     }
  48108     return 0;
  48109 }
  48110 
  48111 static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val,
  48112                               int argc, JSValueConst *argv)
  48113 {
  48114     JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
  48115     JSString *str;
  48116     JSValue t, ret, str_val, obj, groups;
  48117     JSValue indices, indices_groups;
  48118     uint8_t *re_bytecode;
  48119     uint8_t **capture, *str_buf;
  48120     int rc, capture_count, shift, i, re_flags, alloc_count;
  48121     int64_t last_index;
  48122     const char *group_name_ptr;
  48123     JSObject *p_obj;
  48124     JSAtom group_name;
  48125     
  48126     if (!re)
  48127         return JS_EXCEPTION;
  48128 
  48129     str_val = JS_ToString(ctx, argv[0]);
  48130     if (JS_IsException(str_val))
  48131         return JS_EXCEPTION;
  48132 
  48133     ret = JS_EXCEPTION;
  48134     obj = JS_NULL;
  48135     groups = JS_UNDEFINED;
  48136     indices = JS_UNDEFINED;
  48137     indices_groups = JS_UNDEFINED;
  48138     capture = NULL;
  48139     group_name = JS_ATOM_NULL;
  48140     
  48141     if (js_regexp_get_lastIndex(ctx, &last_index, this_val))
  48142         goto fail;
  48143 
  48144     re_bytecode = re->bytecode->u.str8;
  48145     re_flags = lre_get_flags(re_bytecode);
  48146     if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {
  48147         last_index = 0;
  48148     }
  48149     str = JS_VALUE_GET_STRING(str_val);
  48150     alloc_count = lre_get_alloc_count(re_bytecode);
  48151     if (alloc_count > 0) {
  48152         capture = js_malloc(ctx, sizeof(capture[0]) * alloc_count);
  48153         if (!capture)
  48154             goto fail;
  48155     }
  48156     capture_count = lre_get_capture_count(re_bytecode);
  48157     shift = str->is_wide_char;
  48158     str_buf = str->u.str8;
  48159     if (last_index > str->len) {
  48160         rc = 2;
  48161     } else {
  48162         rc = lre_exec(capture, re_bytecode,
  48163                       str_buf, last_index, str->len,
  48164                       shift, ctx);
  48165     }
  48166     if (rc != 1) {
  48167         if (rc >= 0) {
  48168             if (rc == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
  48169                 if (js_regexp_set_lastIndex(ctx, this_val, 0) < 0)
  48170                     goto fail;
  48171             }
  48172         } else {
  48173             if (rc == LRE_RET_TIMEOUT) {
  48174                 JS_ThrowInterrupted(ctx);
  48175             } else {
  48176                 JS_ThrowInternalError(ctx, "out of memory in regexp execution");
  48177             }
  48178             goto fail;
  48179         }
  48180     } else {
  48181         int prop_flags;
  48182         JSProperty props[4];
  48183         
  48184         if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) {
  48185             if (js_regexp_set_lastIndex(ctx, this_val,
  48186                                         (capture[1] - str_buf) >> shift) < 0)
  48187                 goto fail;
  48188         }
  48189         prop_flags = JS_PROP_C_W_E | JS_PROP_THROW;
  48190         group_name_ptr = lre_get_groupnames(re_bytecode);
  48191         if (group_name_ptr) {
  48192             groups = JS_NewObjectProto(ctx, JS_NULL);
  48193             if (JS_IsException(groups))
  48194                 goto fail;
  48195         }
  48196         if (re_flags & LRE_FLAG_INDICES) {
  48197             indices = JS_NewArray(ctx);
  48198             if (JS_IsException(indices))
  48199                 goto fail;
  48200             if (group_name_ptr) {
  48201                 indices_groups = JS_NewObjectProto(ctx, JS_NULL);
  48202                 if (JS_IsException(indices_groups))
  48203                     goto fail;
  48204             }
  48205         }
  48206 
  48207         props[0].u.value = JS_NewInt32(ctx, capture_count); /* length */
  48208         props[1].u.value = JS_NewInt32(ctx, (capture[0] - str_buf) >> shift); /* index */
  48209         props[2].u.value = str_val; /* input */
  48210         props[3].u.value = JS_DupValue(ctx, groups); /* groups */
  48211 
  48212         str_val = JS_UNDEFINED;
  48213         obj = JS_NewObjectFromShape(ctx, js_dup_shape(ctx->regexp_result_shape),
  48214                                     JS_CLASS_ARRAY, props);
  48215         if (JS_IsException(obj))
  48216             goto fail;
  48217 
  48218         p_obj = JS_VALUE_GET_OBJ(obj);
  48219         if (expand_fast_array(ctx, p_obj, capture_count))
  48220             goto fail;
  48221         
  48222         for(i = 0; i < capture_count; i++) {
  48223             uint8_t **match = &capture[2 * i];
  48224             int start = -1;
  48225             int end = -1;
  48226             JSValue val;
  48227 
  48228             if (group_name_ptr && i > 0) {
  48229                 if (*group_name_ptr) {
  48230                     /* XXX: slow, should create a shape when the regexp is
  48231                        compiled */
  48232                     group_name = JS_NewAtom(ctx, group_name_ptr);
  48233                     if (group_name == JS_ATOM_NULL)
  48234                         goto fail;
  48235                 }
  48236                 group_name_ptr += strlen(group_name_ptr) + LRE_GROUP_NAME_TRAILER_LEN;
  48237             }
  48238 
  48239             if (match[0] && match[1]) {
  48240                 start = (match[0] - str_buf) >> shift;
  48241                 end = (match[1] - str_buf) >> shift;
  48242             }
  48243 
  48244             if (!JS_IsUndefined(indices)) {
  48245                 val = JS_UNDEFINED;
  48246                 if (start != -1) {
  48247                     val = JS_NewArray(ctx);
  48248                     if (JS_IsException(val))
  48249                         goto fail;
  48250                     if (JS_DefinePropertyValueUint32(ctx, val, 0,
  48251                                                      JS_NewInt32(ctx, start),
  48252                                                      prop_flags) < 0) {
  48253                         JS_FreeValue(ctx, val);
  48254                         goto fail;
  48255                     }
  48256                     if (JS_DefinePropertyValueUint32(ctx, val, 1,
  48257                                                      JS_NewInt32(ctx, end),
  48258                                                      prop_flags) < 0) {
  48259                         JS_FreeValue(ctx, val);
  48260                         goto fail;
  48261                     }
  48262                 }
  48263                 if (group_name != JS_ATOM_NULL) {
  48264                     /* JS_HasProperty() cannot fail here */
  48265                     if (!JS_IsUndefined(val) ||
  48266                         !JS_HasProperty(ctx, indices_groups, group_name)) {
  48267                         if (JS_DefinePropertyValue(ctx, indices_groups,
  48268                                                    group_name, JS_DupValue(ctx, val), prop_flags) < 0) {
  48269                             JS_FreeValue(ctx, val);
  48270                             goto fail;
  48271                         }
  48272                     }
  48273                 }
  48274                 if (JS_DefinePropertyValueUint32(ctx, indices, i, val,
  48275                                                  prop_flags) < 0) {
  48276                     goto fail;
  48277                 }
  48278             }
  48279 
  48280             val = JS_UNDEFINED;
  48281             if (start != -1) {
  48282                 val = js_sub_string(ctx, str, start, end);
  48283                 if (JS_IsException(val))
  48284                     goto fail;
  48285             }
  48286 
  48287             if (group_name != JS_ATOM_NULL) {
  48288                 /* JS_HasProperty() cannot fail here */
  48289                 if (!JS_IsUndefined(val) ||
  48290                     !JS_HasProperty(ctx, groups, group_name)) {
  48291                     if (JS_DefinePropertyValue(ctx, groups, group_name,
  48292                                                JS_DupValue(ctx, val),
  48293                                                prop_flags) < 0) {
  48294                         JS_FreeValue(ctx, val);
  48295                         goto fail;
  48296                     }
  48297                 }
  48298                 JS_FreeAtom(ctx, group_name);
  48299                 group_name = JS_ATOM_NULL;
  48300             }
  48301             p_obj->u.array.u.values[p_obj->u.array.count++] = val;
  48302         }
  48303 
  48304         if (!JS_IsUndefined(indices)) {
  48305             t = indices_groups, indices_groups = JS_UNDEFINED;
  48306             if (JS_DefinePropertyValue(ctx, indices, JS_ATOM_groups,
  48307                                        t, prop_flags) < 0) {
  48308                 goto fail;
  48309             }
  48310             t = indices, indices = JS_UNDEFINED;
  48311             if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_indices,
  48312                                        t, prop_flags) < 0) {
  48313                 goto fail;
  48314             }
  48315         }
  48316     }
  48317     ret = obj;
  48318     obj = JS_UNDEFINED;
  48319 fail:
  48320     JS_FreeAtom(ctx, group_name);
  48321     JS_FreeValue(ctx, indices_groups);
  48322     JS_FreeValue(ctx, indices);
  48323     JS_FreeValue(ctx, str_val);
  48324     JS_FreeValue(ctx, groups);
  48325     JS_FreeValue(ctx, obj);
  48326     js_free(ctx, capture);
  48327     return ret;
  48328 }
  48329 
  48330 /* XXX: add group names support */
  48331 static JSValue js_regexp_replace(JSContext *ctx, JSValueConst this_val, JSValueConst arg,
  48332                                  JSValueConst rep_val)
  48333 {
  48334     JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
  48335     JSString *str;
  48336     JSValue str_val;
  48337     uint8_t *re_bytecode;
  48338     int ret;
  48339     uint8_t **capture, *str_buf;
  48340     int capture_count, alloc_count, shift, re_flags;
  48341     int next_src_pos, start, end;
  48342     int64_t last_index;
  48343     StringBuffer b_s, *b = &b_s;
  48344     JSString *rp = JS_VALUE_GET_STRING(rep_val);
  48345     const char *group_name_ptr;
  48346     BOOL fullUnicode;
  48347     
  48348     if (!re)
  48349         return JS_EXCEPTION;
  48350     re_bytecode = re->bytecode->u.str8;
  48351     group_name_ptr = lre_get_groupnames(re_bytecode);
  48352     if (group_name_ptr)
  48353         return JS_UNDEFINED; /* group names are not supported yet */
  48354     
  48355     string_buffer_init(ctx, b, 0);
  48356 
  48357     capture = NULL;
  48358     str_val = JS_ToString(ctx, arg);
  48359     if (JS_IsException(str_val))
  48360         goto fail;
  48361     str = JS_VALUE_GET_STRING(str_val);
  48362     re_flags = lre_get_flags(re_bytecode);
  48363 
  48364     if (re_flags & LRE_FLAG_GLOBAL) {
  48365         if (js_regexp_set_lastIndex(ctx, this_val, 0))
  48366             goto fail;
  48367     }
  48368     if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {
  48369         last_index = 0;
  48370     } else {
  48371         if (js_regexp_get_lastIndex(ctx, &last_index, this_val))
  48372             goto fail;
  48373     }
  48374     alloc_count = lre_get_alloc_count(re_bytecode);
  48375     if (alloc_count > 0) {
  48376         capture = js_malloc(ctx, sizeof(capture[0]) * alloc_count);
  48377         if (!capture)
  48378             goto fail;
  48379     }
  48380     capture_count = lre_get_capture_count(re_bytecode);
  48381     fullUnicode = ((re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0);
  48382     shift = str->is_wide_char;
  48383     str_buf = str->u.str8;
  48384     next_src_pos = 0;
  48385     for (;;) {
  48386         if (last_index > str->len) {
  48387             ret = 0;
  48388         } else {
  48389             ret = lre_exec(capture, re_bytecode,
  48390                            str_buf, last_index, str->len, shift, ctx);
  48391         }
  48392         if (ret != 1) {
  48393             if (ret >= 0) {
  48394                 if (ret == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
  48395                     if (js_regexp_set_lastIndex(ctx, this_val, 0) < 0)
  48396                         goto fail;
  48397                 }
  48398             } else {
  48399                 if (ret == LRE_RET_TIMEOUT) {
  48400                     JS_ThrowInterrupted(ctx);
  48401                 } else {
  48402                     JS_ThrowInternalError(ctx, "out of memory in regexp execution");
  48403                 }
  48404                 goto fail;
  48405             }
  48406             break;
  48407         }
  48408         start = (capture[0] - str_buf) >> shift;
  48409         end = (capture[1] - str_buf) >> shift;
  48410         last_index = end;
  48411         if (next_src_pos < start) {
  48412             if (string_buffer_concat(b, str, next_src_pos, start))
  48413                 goto fail;
  48414         }
  48415         if (rp->len != 0) {
  48416             if (js_string_GetSubstitution(ctx, b, JS_UNDEFINED, str, start,
  48417                                           JS_UNDEFINED, JS_UNDEFINED, rep_val,
  48418                                           capture, capture_count)) {
  48419                 goto fail;
  48420             }
  48421         }
  48422         next_src_pos = end;
  48423         if (!(re_flags & LRE_FLAG_GLOBAL)) {
  48424             if (re_flags & LRE_FLAG_STICKY) {
  48425                 if (js_regexp_set_lastIndex(ctx, this_val, end) < 0)
  48426                     goto fail;
  48427             }
  48428             break;
  48429         }
  48430         if (end == start) {
  48431             end = string_advance_index(str, end, fullUnicode);
  48432         }
  48433         last_index = end;
  48434     }
  48435     if (string_buffer_concat(b, str, next_src_pos, str->len))
  48436         goto fail;
  48437     JS_FreeValue(ctx, str_val);
  48438     js_free(ctx, capture);
  48439     return string_buffer_end(b);
  48440 fail:
  48441     JS_FreeValue(ctx, str_val);
  48442     js_free(ctx, capture);
  48443     string_buffer_free(b);
  48444     return JS_EXCEPTION;
  48445 }
  48446 
  48447 static JSValue JS_RegExpExec(JSContext *ctx, JSValueConst r, JSValueConst s)
  48448 {
  48449     JSValue method, ret;
  48450 
  48451     method = JS_GetProperty(ctx, r, JS_ATOM_exec);
  48452     if (JS_IsException(method))
  48453         return method;
  48454     if (JS_IsFunction(ctx, method)) {
  48455         ret = JS_CallFree(ctx, method, r, 1, &s);
  48456         if (JS_IsException(ret))
  48457             return ret;
  48458         if (!JS_IsObject(ret) && !JS_IsNull(ret)) {
  48459             JS_FreeValue(ctx, ret);
  48460             return JS_ThrowTypeError(ctx, "RegExp exec method must return an object or null");
  48461         }
  48462         return ret;
  48463     }
  48464     JS_FreeValue(ctx, method);
  48465     return js_regexp_exec(ctx, r, 1, &s);
  48466 }
  48467 
  48468 static JSValue js_regexp_test(JSContext *ctx, JSValueConst this_val,
  48469                               int argc, JSValueConst *argv)
  48470 {
  48471     JSValue val;
  48472     BOOL ret;
  48473 
  48474     val = JS_RegExpExec(ctx, this_val, argv[0]);
  48475     if (JS_IsException(val))
  48476         return JS_EXCEPTION;
  48477     ret = !JS_IsNull(val);
  48478     JS_FreeValue(ctx, val);
  48479     return JS_NewBool(ctx, ret);
  48480 }
  48481 
  48482 static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val,
  48483                                       int argc, JSValueConst *argv)
  48484 {
  48485     // [Symbol.match](str)
  48486     JSValueConst rx = this_val;
  48487     JSValue A, S, flags, result, matchStr;
  48488     int global, n, fullUnicode, isEmpty;
  48489     JSString *p;
  48490 
  48491     if (!JS_IsObject(rx))
  48492         return JS_ThrowTypeErrorNotAnObject(ctx);
  48493 
  48494     A = JS_UNDEFINED;
  48495     flags = JS_UNDEFINED;
  48496     result = JS_UNDEFINED;
  48497     matchStr = JS_UNDEFINED;
  48498     S = JS_ToString(ctx, argv[0]);
  48499     if (JS_IsException(S))
  48500         goto exception;
  48501 
  48502     flags = JS_GetProperty(ctx, rx, JS_ATOM_flags);
  48503     if (JS_IsException(flags))
  48504         goto exception;
  48505     flags = JS_ToStringFree(ctx, flags);
  48506     if (JS_IsException(flags))
  48507         goto exception;
  48508     p = JS_VALUE_GET_STRING(flags);
  48509 
  48510     global = (-1 != string_indexof_char(p, 'g', 0));
  48511     if (!global) {
  48512         A = JS_RegExpExec(ctx, rx, S);
  48513     } else {
  48514         fullUnicode = (string_indexof_char(p, 'u', 0) >= 0 ||
  48515                        string_indexof_char(p, 'v', 0) >= 0);
  48516 
  48517         if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0)
  48518             goto exception;
  48519         A = JS_NewArray(ctx);
  48520         if (JS_IsException(A))
  48521             goto exception;
  48522         n = 0;
  48523         for(;;) {
  48524             JS_FreeValue(ctx, result);
  48525             result = JS_RegExpExec(ctx, rx, S);
  48526             if (JS_IsException(result))
  48527                 goto exception;
  48528             if (JS_IsNull(result))
  48529                 break;
  48530             matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
  48531             if (JS_IsException(matchStr))
  48532                 goto exception;
  48533             isEmpty = JS_IsEmptyString(matchStr);
  48534             if (JS_DefinePropertyValueInt64(ctx, A, n++, matchStr, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
  48535                 goto exception;
  48536             if (isEmpty) {
  48537                 int64_t thisIndex, nextIndex;
  48538                 if (JS_ToLengthFree(ctx, &thisIndex,
  48539                                     JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0)
  48540                     goto exception;
  48541                 p = JS_VALUE_GET_STRING(S);
  48542                 nextIndex = string_advance_index(p, thisIndex, fullUnicode);
  48543                 if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0)
  48544                     goto exception;
  48545             }
  48546         }
  48547         if (n == 0) {
  48548             JS_FreeValue(ctx, A);
  48549             A = JS_NULL;
  48550         }
  48551     }
  48552     JS_FreeValue(ctx, result);
  48553     JS_FreeValue(ctx, flags);
  48554     JS_FreeValue(ctx, S);
  48555     return A;
  48556 
  48557 exception:
  48558     JS_FreeValue(ctx, A);
  48559     JS_FreeValue(ctx, result);
  48560     JS_FreeValue(ctx, flags);
  48561     JS_FreeValue(ctx, S);
  48562     return JS_EXCEPTION;
  48563 }
  48564 
  48565 typedef struct JSRegExpStringIteratorData {
  48566     JSValue iterating_regexp;
  48567     JSValue iterated_string;
  48568     BOOL global;
  48569     BOOL unicode;
  48570     BOOL done;
  48571 } JSRegExpStringIteratorData;
  48572 
  48573 static void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val)
  48574 {
  48575     JSObject *p = JS_VALUE_GET_OBJ(val);
  48576     JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data;
  48577     if (it) {
  48578         JS_FreeValueRT(rt, it->iterating_regexp);
  48579         JS_FreeValueRT(rt, it->iterated_string);
  48580         js_free_rt(rt, it);
  48581     }
  48582 }
  48583 
  48584 static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val,
  48585                                            JS_MarkFunc *mark_func)
  48586 {
  48587     JSObject *p = JS_VALUE_GET_OBJ(val);
  48588     JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data;
  48589     if (it) {
  48590         JS_MarkValue(rt, it->iterating_regexp, mark_func);
  48591         JS_MarkValue(rt, it->iterated_string, mark_func);
  48592     }
  48593 }
  48594 
  48595 static JSValue js_regexp_string_iterator_next(JSContext *ctx,
  48596                                               JSValueConst this_val,
  48597                                               int argc, JSValueConst *argv,
  48598                                               BOOL *pdone, int magic)
  48599 {
  48600     JSRegExpStringIteratorData *it;
  48601     JSValueConst R, S;
  48602     JSValue matchStr = JS_UNDEFINED, match = JS_UNDEFINED;
  48603     JSString *sp;
  48604 
  48605     it = JS_GetOpaque2(ctx, this_val, JS_CLASS_REGEXP_STRING_ITERATOR);
  48606     if (!it)
  48607         goto exception;
  48608     if (it->done) {
  48609         *pdone = TRUE;
  48610         return JS_UNDEFINED;
  48611     }
  48612     R = it->iterating_regexp;
  48613     S = it->iterated_string;
  48614     match = JS_RegExpExec(ctx, R, S);
  48615     if (JS_IsException(match))
  48616         goto exception;
  48617     if (JS_IsNull(match)) {
  48618         it->done = TRUE;
  48619         *pdone = TRUE;
  48620         return JS_UNDEFINED;
  48621     } else if (it->global) {
  48622         matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, match, 0));
  48623         if (JS_IsException(matchStr))
  48624             goto exception;
  48625         if (JS_IsEmptyString(matchStr)) {
  48626             int64_t thisIndex, nextIndex;
  48627             if (JS_ToLengthFree(ctx, &thisIndex,
  48628                                 JS_GetProperty(ctx, R, JS_ATOM_lastIndex)) < 0)
  48629                 goto exception;
  48630             sp = JS_VALUE_GET_STRING(S);
  48631             nextIndex = string_advance_index(sp, thisIndex, it->unicode);
  48632             if (JS_SetProperty(ctx, R, JS_ATOM_lastIndex,
  48633                                JS_NewInt64(ctx, nextIndex)) < 0)
  48634                 goto exception;
  48635         }
  48636         JS_FreeValue(ctx, matchStr);
  48637     } else {
  48638         it->done = TRUE;
  48639     }
  48640     *pdone = FALSE;
  48641     return match;
  48642  exception:
  48643     JS_FreeValue(ctx, match);
  48644     JS_FreeValue(ctx, matchStr);
  48645     *pdone = FALSE;
  48646     return JS_EXCEPTION;
  48647 }
  48648 
  48649 static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val,
  48650                                          int argc, JSValueConst *argv)
  48651 {
  48652     // [Symbol.matchAll](str)
  48653     JSValueConst R = this_val;
  48654     JSValue S, C, flags, matcher, iter;
  48655     JSValueConst args[2];
  48656     JSString *strp;
  48657     int64_t lastIndex;
  48658     JSRegExpStringIteratorData *it;
  48659 
  48660     if (!JS_IsObject(R))
  48661         return JS_ThrowTypeErrorNotAnObject(ctx);
  48662 
  48663     C = JS_UNDEFINED;
  48664     flags = JS_UNDEFINED;
  48665     matcher = JS_UNDEFINED;
  48666     iter = JS_UNDEFINED;
  48667 
  48668     S = JS_ToString(ctx, argv[0]);
  48669     if (JS_IsException(S))
  48670         goto exception;
  48671     C = JS_SpeciesConstructor(ctx, R, ctx->regexp_ctor);
  48672     if (JS_IsException(C))
  48673         goto exception;
  48674     flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, R, JS_ATOM_flags));
  48675     if (JS_IsException(flags))
  48676         goto exception;
  48677     args[0] = R;
  48678     args[1] = flags;
  48679     matcher = JS_CallConstructor(ctx, C, 2, args);
  48680     if (JS_IsException(matcher))
  48681         goto exception;
  48682     if (JS_ToLengthFree(ctx, &lastIndex,
  48683                         JS_GetProperty(ctx, R, JS_ATOM_lastIndex)))
  48684         goto exception;
  48685     if (JS_SetProperty(ctx, matcher, JS_ATOM_lastIndex,
  48686                        JS_NewInt64(ctx, lastIndex)) < 0)
  48687         goto exception;
  48688 
  48689     iter = JS_NewObjectClass(ctx, JS_CLASS_REGEXP_STRING_ITERATOR);
  48690     if (JS_IsException(iter))
  48691         goto exception;
  48692     it = js_malloc(ctx, sizeof(*it));
  48693     if (!it)
  48694         goto exception;
  48695     it->iterating_regexp = matcher;
  48696     it->iterated_string = S;
  48697     strp = JS_VALUE_GET_STRING(flags);
  48698     it->global = string_indexof_char(strp, 'g', 0) >= 0;
  48699     it->unicode = (string_indexof_char(strp, 'u', 0) >= 0 ||
  48700                    string_indexof_char(strp, 'v', 0) >= 0);
  48701     it->done = FALSE;
  48702     JS_SetOpaque(iter, it);
  48703 
  48704     JS_FreeValue(ctx, C);
  48705     JS_FreeValue(ctx, flags);
  48706     return iter;
  48707  exception:
  48708     JS_FreeValue(ctx, S);
  48709     JS_FreeValue(ctx, C);
  48710     JS_FreeValue(ctx, flags);
  48711     JS_FreeValue(ctx, matcher);
  48712     JS_FreeValue(ctx, iter);
  48713     return JS_EXCEPTION;
  48714 }
  48715 
  48716 typedef struct ValueBuffer {
  48717     JSContext *ctx;
  48718     JSValue *arr;
  48719     JSValue def[4];
  48720     int len;
  48721     int size;
  48722     int error_status;
  48723 } ValueBuffer;
  48724 
  48725 static int value_buffer_init(JSContext *ctx, ValueBuffer *b)
  48726 {
  48727     b->ctx = ctx;
  48728     b->len = 0;
  48729     b->size = 4;
  48730     b->error_status = 0;
  48731     b->arr = b->def;
  48732     return 0;
  48733 }
  48734 
  48735 static void value_buffer_free(ValueBuffer *b)
  48736 {
  48737     while (b->len > 0)
  48738         JS_FreeValue(b->ctx, b->arr[--b->len]);
  48739     if (b->arr != b->def)
  48740         js_free(b->ctx, b->arr);
  48741     b->arr = b->def;
  48742     b->size = 4;
  48743 }
  48744 
  48745 static int value_buffer_append(ValueBuffer *b, JSValue val)
  48746 {
  48747     if (b->error_status)
  48748         return -1;
  48749 
  48750     if (b->len >= b->size) {
  48751         int new_size = (b->len + (b->len >> 1) + 31) & ~16;
  48752         size_t slack;
  48753         JSValue *new_arr;
  48754 
  48755         if (b->arr == b->def) {
  48756             new_arr = js_realloc2(b->ctx, NULL, sizeof(*b->arr) * new_size, &slack);
  48757             if (new_arr)
  48758                 memcpy(new_arr, b->def, sizeof b->def);
  48759         } else {
  48760             new_arr = js_realloc2(b->ctx, b->arr, sizeof(*b->arr) * new_size, &slack);
  48761         }
  48762         if (!new_arr) {
  48763             value_buffer_free(b);
  48764             JS_FreeValue(b->ctx, val);
  48765             b->error_status = -1;
  48766             return -1;
  48767         }
  48768         new_size += slack / sizeof(*new_arr);
  48769         b->arr = new_arr;
  48770         b->size = new_size;
  48771     }
  48772     b->arr[b->len++] = val;
  48773     return 0;
  48774 }
  48775 
  48776 /* find in 'p' or its prototypes */
  48777 static JSShapeProperty *find_property_regexp(JSProperty **ppr,
  48778                                              JSObject *p, JSAtom atom)
  48779 {
  48780     JSShapeProperty *prs;
  48781 
  48782     for(;;) {
  48783         prs = find_own_property(ppr, p, atom);
  48784         if (prs)
  48785             return prs;
  48786         p = p->shape->proto;
  48787         if (!p)
  48788             return NULL;
  48789         if (p->is_exotic)
  48790             return NULL;
  48791     }
  48792 }
  48793 
  48794 static BOOL check_regexp_getter(JSContext *ctx,
  48795                                 JSObject *p, JSAtom atom,
  48796                                 JSCFunction *func, int magic)
  48797 {
  48798     JSProperty *pr;
  48799     JSShapeProperty *prs;
  48800 
  48801     prs = find_property_regexp(&pr, p, atom);
  48802     if (!prs)
  48803         return FALSE;
  48804     if ((prs->flags & JS_PROP_TMASK) != JS_PROP_GETSET)
  48805         return FALSE;
  48806     if (!pr->u.getset.getter)
  48807         return FALSE;
  48808     return JS_IsCFunction(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter),
  48809                           func, magic);
  48810 }
  48811 
  48812 static BOOL js_is_standard_regexp(JSContext *ctx, JSValueConst obj)
  48813 {
  48814     JSObject *p;
  48815     JSProperty *pr;
  48816     JSShapeProperty *prs;
  48817     JSCFunctionType ft;
  48818     
  48819     if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
  48820         return FALSE;
  48821     p = JS_VALUE_GET_OBJ(obj);
  48822     if (p->class_id != JS_CLASS_REGEXP)
  48823         return FALSE;
  48824     /* check that the lastIndex is a number (no side effect while getting it) */
  48825     prs = find_own_property(&pr, p, JS_ATOM_lastIndex);
  48826     if (!prs)
  48827         return FALSE;
  48828     if (!JS_IsNumber(pr->u.value))
  48829         return FALSE;
  48830 
  48831     /* check the 'exec' method. */
  48832     prs = find_property_regexp(&pr, p, JS_ATOM_exec);
  48833     if (!prs)
  48834         return FALSE;
  48835     if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
  48836         return FALSE;
  48837     if (!JS_IsCFunction(ctx, pr->u.value, js_regexp_exec, 0))
  48838         return FALSE;
  48839     /* check the flag getters */
  48840     ft.getter = js_regexp_get_flags;
  48841     if (!check_regexp_getter(ctx, p, JS_ATOM_flags, ft.generic, 0))
  48842         return FALSE;
  48843     ft.getter_magic = js_regexp_get_flag;
  48844     if (!check_regexp_getter(ctx, p, JS_ATOM_global, ft.generic, LRE_FLAG_GLOBAL))
  48845         return FALSE;
  48846     if (!check_regexp_getter(ctx, p, JS_ATOM_unicode, ft.generic, LRE_FLAG_UNICODE))
  48847         return FALSE;
  48848     /* XXX: need to check all accessors, need a faster way.  */
  48849     return TRUE;
  48850 }
  48851 
  48852 static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
  48853                                         int argc, JSValueConst *argv)
  48854 {
  48855     // [Symbol.replace](str, rep)
  48856     JSValueConst rx = this_val, rep = argv[1];
  48857     JSValueConst args[6];
  48858     JSValue flags, str, rep_val, matched, tab, rep_str, namedCaptures, res;
  48859     JSString *p, *sp;
  48860     StringBuffer b_s, *b = &b_s;
  48861     ValueBuffer v_b, *results = &v_b;
  48862     int nextSourcePosition, n, j, functionalReplace, is_global, fullUnicode;
  48863     uint32_t nCaptures;
  48864     int64_t position;
  48865 
  48866     if (!JS_IsObject(rx))
  48867         return JS_ThrowTypeErrorNotAnObject(ctx);
  48868 
  48869     string_buffer_init(ctx, b, 0);
  48870     value_buffer_init(ctx, results);
  48871 
  48872     rep_val = JS_UNDEFINED;
  48873     matched = JS_UNDEFINED;
  48874     tab = JS_UNDEFINED;
  48875     flags = JS_UNDEFINED;
  48876     rep_str = JS_UNDEFINED;
  48877     namedCaptures = JS_UNDEFINED;
  48878 
  48879     str = JS_ToString(ctx, argv[0]);
  48880     if (JS_IsException(str))
  48881         goto exception;
  48882 
  48883     sp = JS_VALUE_GET_STRING(str);
  48884     functionalReplace = JS_IsFunction(ctx, rep);
  48885     if (!functionalReplace) {
  48886         rep_val = JS_ToString(ctx, rep);
  48887         if (JS_IsException(rep_val))
  48888             goto exception;
  48889     }
  48890 
  48891     if (!functionalReplace && js_is_standard_regexp(ctx, rx)) {
  48892         /* use faster version for simple cases */
  48893         res = js_regexp_replace(ctx, rx, str, rep_val);
  48894         if (!JS_IsUndefined(res))
  48895             goto done;
  48896     }
  48897     
  48898     flags = JS_GetProperty(ctx, rx, JS_ATOM_flags);
  48899     if (JS_IsException(flags))
  48900         goto exception;
  48901     flags = JS_ToStringFree(ctx, flags);
  48902     if (JS_IsException(flags))
  48903         goto exception;
  48904     p = JS_VALUE_GET_STRING(flags);
  48905 
  48906     fullUnicode = 0;
  48907     is_global = (-1 != string_indexof_char(p, 'g', 0));
  48908     if (is_global) {
  48909         fullUnicode = (string_indexof_char(p, 'u', 0) >= 0 ||
  48910                        string_indexof_char(p, 'v', 0) >= 0);
  48911         if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0)
  48912             goto exception;
  48913     }
  48914 
  48915     for(;;) {
  48916         JSValue result;
  48917         result = JS_RegExpExec(ctx, rx, str);
  48918         if (JS_IsException(result))
  48919             goto exception;
  48920         if (JS_IsNull(result))
  48921             break;
  48922         if (value_buffer_append(results, result) < 0)
  48923             goto exception;
  48924         if (!is_global)
  48925             break;
  48926         JS_FreeValue(ctx, matched);
  48927         matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
  48928         if (JS_IsException(matched))
  48929             goto exception;
  48930         if (JS_IsEmptyString(matched)) {
  48931             /* always advance of at least one char */
  48932             int64_t thisIndex, nextIndex;
  48933             if (JS_ToLengthFree(ctx, &thisIndex, JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0)
  48934                 goto exception;
  48935             nextIndex = string_advance_index(sp, thisIndex, fullUnicode);
  48936             if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0)
  48937                 goto exception;
  48938         }
  48939     }
  48940     nextSourcePosition = 0;
  48941     for(j = 0; j < results->len; j++) {
  48942         JSValueConst result;
  48943         result = results->arr[j];
  48944         if (js_get_length32(ctx, &nCaptures, result) < 0)
  48945             goto exception;
  48946         JS_FreeValue(ctx, matched);
  48947         matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
  48948         if (JS_IsException(matched))
  48949             goto exception;
  48950         if (JS_ToLengthFree(ctx, &position, JS_GetProperty(ctx, result, JS_ATOM_index)))
  48951             goto exception;
  48952         if (position > sp->len)
  48953             position = sp->len;
  48954         else if (position < 0)
  48955             position = 0;
  48956         /* ignore substition if going backward (can happen
  48957            with custom regexp object) */
  48958         JS_FreeValue(ctx, tab);
  48959         tab = JS_NewArray(ctx);
  48960         if (JS_IsException(tab))
  48961             goto exception;
  48962         if (JS_DefinePropertyValueInt64(ctx, tab, 0, JS_DupValue(ctx, matched),
  48963                                         JS_PROP_C_W_E | JS_PROP_THROW) < 0)
  48964             goto exception;
  48965         for(n = 1; n < nCaptures; n++) {
  48966             JSValue capN;
  48967             capN = JS_GetPropertyInt64(ctx, result, n);
  48968             if (JS_IsException(capN))
  48969                 goto exception;
  48970             if (!JS_IsUndefined(capN)) {
  48971                 capN = JS_ToStringFree(ctx, capN);
  48972                 if (JS_IsException(capN))
  48973                     goto exception;
  48974             }
  48975             if (JS_DefinePropertyValueInt64(ctx, tab, n, capN,
  48976                                             JS_PROP_C_W_E | JS_PROP_THROW) < 0)
  48977                 goto exception;
  48978         }
  48979         JS_FreeValue(ctx, namedCaptures);
  48980         namedCaptures = JS_GetProperty(ctx, result, JS_ATOM_groups);
  48981         if (JS_IsException(namedCaptures))
  48982             goto exception;
  48983         if (functionalReplace) {
  48984             if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_NewInt32(ctx, position), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
  48985                 goto exception;
  48986             if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, str), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
  48987                 goto exception;
  48988             if (!JS_IsUndefined(namedCaptures)) {
  48989                 if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, namedCaptures), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
  48990                     goto exception;
  48991             }
  48992             args[0] = JS_UNDEFINED;
  48993             args[1] = tab;
  48994             JS_FreeValue(ctx, rep_str);
  48995             rep_str = JS_ToStringFree(ctx, js_function_apply(ctx, rep, 2, args, 0));
  48996         } else {
  48997             JSValue namedCaptures1;
  48998             StringBuffer b1_s, *b1 = &b1_s;
  48999             int ret;
  49000             
  49001             if (!JS_IsUndefined(namedCaptures)) {
  49002                 namedCaptures1 = JS_ToObject(ctx, namedCaptures);
  49003                 if (JS_IsException(namedCaptures1))
  49004                     goto exception;
  49005             } else {
  49006                 namedCaptures1 = JS_UNDEFINED;
  49007             }
  49008             JS_FreeValue(ctx, rep_str);
  49009             
  49010             string_buffer_init(ctx, b1, 0);
  49011             ret = js_string_GetSubstitution(ctx, b1, matched, sp, position,
  49012                                             tab, namedCaptures1, rep_val,
  49013                                             NULL, 0);
  49014             rep_str = string_buffer_end(b1);
  49015             JS_FreeValue(ctx, namedCaptures1);
  49016             if (ret)
  49017                 goto exception;
  49018         }
  49019         if (JS_IsException(rep_str))
  49020             goto exception;
  49021         if (position >= nextSourcePosition) {
  49022             string_buffer_concat(b, sp, nextSourcePosition, position);
  49023             string_buffer_concat_value(b, rep_str);
  49024             nextSourcePosition = position + JS_VALUE_GET_STRING(matched)->len;
  49025         }
  49026     }
  49027     string_buffer_concat(b, sp, nextSourcePosition, sp->len);
  49028     res = string_buffer_end(b);
  49029     goto done1;
  49030 
  49031 exception:
  49032     res = JS_EXCEPTION;
  49033 done:
  49034     string_buffer_free(b);
  49035 done1:
  49036     value_buffer_free(results);
  49037     JS_FreeValue(ctx, rep_val);
  49038     JS_FreeValue(ctx, matched);
  49039     JS_FreeValue(ctx, flags);
  49040     JS_FreeValue(ctx, tab);
  49041     JS_FreeValue(ctx, rep_str);
  49042     JS_FreeValue(ctx, namedCaptures);
  49043     JS_FreeValue(ctx, str);
  49044     return res;
  49045 }
  49046 
  49047 static JSValue js_regexp_Symbol_search(JSContext *ctx, JSValueConst this_val,
  49048                                        int argc, JSValueConst *argv)
  49049 {
  49050     JSValueConst rx = this_val;
  49051     JSValue str, previousLastIndex, currentLastIndex, result, index;
  49052 
  49053     if (!JS_IsObject(rx))
  49054         return JS_ThrowTypeErrorNotAnObject(ctx);
  49055 
  49056     result = JS_UNDEFINED;
  49057     currentLastIndex = JS_UNDEFINED;
  49058     previousLastIndex = JS_UNDEFINED;
  49059     str = JS_ToString(ctx, argv[0]);
  49060     if (JS_IsException(str))
  49061         goto exception;
  49062 
  49063     previousLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex);
  49064     if (JS_IsException(previousLastIndex))
  49065         goto exception;
  49066 
  49067     if (!js_same_value(ctx, previousLastIndex, JS_NewInt32(ctx, 0))) {
  49068         if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0) {
  49069             goto exception;
  49070         }
  49071     }
  49072     result = JS_RegExpExec(ctx, rx, str);
  49073     if (JS_IsException(result))
  49074         goto exception;
  49075     currentLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex);
  49076     if (JS_IsException(currentLastIndex))
  49077         goto exception;
  49078     if (js_same_value(ctx, currentLastIndex, previousLastIndex)) {
  49079         JS_FreeValue(ctx, previousLastIndex);
  49080     } else {
  49081         if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, previousLastIndex) < 0) {
  49082             previousLastIndex = JS_UNDEFINED;
  49083             goto exception;
  49084         }
  49085     }
  49086     JS_FreeValue(ctx, str);
  49087     JS_FreeValue(ctx, currentLastIndex);
  49088 
  49089     if (JS_IsNull(result)) {
  49090         return JS_NewInt32(ctx, -1);
  49091     } else {
  49092         index = JS_GetProperty(ctx, result, JS_ATOM_index);
  49093         JS_FreeValue(ctx, result);
  49094         return index;
  49095     }
  49096 
  49097 exception:
  49098     JS_FreeValue(ctx, result);
  49099     JS_FreeValue(ctx, str);
  49100     JS_FreeValue(ctx, currentLastIndex);
  49101     JS_FreeValue(ctx, previousLastIndex);
  49102     return JS_EXCEPTION;
  49103 }
  49104 
  49105 static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val,
  49106                                        int argc, JSValueConst *argv)
  49107 {
  49108     // [Symbol.split](str, limit)
  49109     JSValueConst rx = this_val;
  49110     JSValueConst args[2];
  49111     JSValue str, ctor, splitter, A, flags, z, sub;
  49112     JSString *strp;
  49113     uint32_t lim, size, p, q;
  49114     int unicodeMatching;
  49115     int64_t lengthA, e, numberOfCaptures, i;
  49116 
  49117     if (!JS_IsObject(rx))
  49118         return JS_ThrowTypeErrorNotAnObject(ctx);
  49119 
  49120     ctor = JS_UNDEFINED;
  49121     splitter = JS_UNDEFINED;
  49122     A = JS_UNDEFINED;
  49123     flags = JS_UNDEFINED;
  49124     z = JS_UNDEFINED;
  49125     str = JS_ToString(ctx, argv[0]);
  49126     if (JS_IsException(str))
  49127         goto exception;
  49128     ctor = JS_SpeciesConstructor(ctx, rx, ctx->regexp_ctor);
  49129     if (JS_IsException(ctor))
  49130         goto exception;
  49131     flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_flags));
  49132     if (JS_IsException(flags))
  49133         goto exception;
  49134     strp = JS_VALUE_GET_STRING(flags);
  49135     unicodeMatching = (string_indexof_char(strp, 'u', 0) >= 0 ||
  49136                        string_indexof_char(strp, 'v', 0) >= 0);
  49137     if (string_indexof_char(strp, 'y', 0) < 0) {
  49138         flags = JS_ConcatString3(ctx, "", flags, "y");
  49139         if (JS_IsException(flags))
  49140             goto exception;
  49141     }
  49142     args[0] = rx;
  49143     args[1] = flags;
  49144     splitter = JS_CallConstructor(ctx, ctor, 2, args);
  49145     if (JS_IsException(splitter))
  49146         goto exception;
  49147     A = JS_NewArray(ctx);
  49148     if (JS_IsException(A))
  49149         goto exception;
  49150     lengthA = 0;
  49151     if (JS_IsUndefined(argv[1])) {
  49152         lim = 0xffffffff;
  49153     } else {
  49154         if (JS_ToUint32(ctx, &lim, argv[1]) < 0)
  49155             goto exception;
  49156         if (lim == 0)
  49157             goto done;
  49158     }
  49159     strp = JS_VALUE_GET_STRING(str);
  49160     p = q = 0;
  49161     size = strp->len;
  49162     if (size == 0) {
  49163         z = JS_RegExpExec(ctx, splitter, str);
  49164         if (JS_IsException(z))
  49165             goto exception;
  49166         if (JS_IsNull(z))
  49167             goto add_tail;
  49168         goto done;
  49169     }
  49170     while (q < size) {
  49171         if (JS_SetProperty(ctx, splitter, JS_ATOM_lastIndex, JS_NewInt32(ctx, q)) < 0)
  49172             goto exception;
  49173         JS_FreeValue(ctx, z);
  49174         z = JS_RegExpExec(ctx, splitter, str);
  49175         if (JS_IsException(z))
  49176             goto exception;
  49177         if (JS_IsNull(z)) {
  49178             q = string_advance_index(strp, q, unicodeMatching);
  49179         } else {
  49180             if (JS_ToLengthFree(ctx, &e, JS_GetProperty(ctx, splitter, JS_ATOM_lastIndex)))
  49181                 goto exception;
  49182             if (e > size)
  49183                 e = size;
  49184             if (e == p) {
  49185                 q = string_advance_index(strp, q, unicodeMatching);
  49186             } else {
  49187                 sub = js_sub_string(ctx, strp, p, q);
  49188                 if (JS_IsException(sub))
  49189                     goto exception;
  49190                 if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub,
  49191                                                 JS_PROP_C_W_E | JS_PROP_THROW) < 0)
  49192                     goto exception;
  49193                 if (lengthA == lim)
  49194                     goto done;
  49195                 p = e;
  49196                 if (js_get_length64(ctx, &numberOfCaptures, z))
  49197                     goto exception;
  49198                 for(i = 1; i < numberOfCaptures; i++) {
  49199                     sub = JS_GetPropertyInt64(ctx, z, i);
  49200                     if (JS_IsException(sub))
  49201                         goto exception;
  49202                     if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
  49203                         goto exception;
  49204                     if (lengthA == lim)
  49205                         goto done;
  49206                 }
  49207                 q = p;
  49208             }
  49209         }
  49210     }
  49211 add_tail:
  49212     if (p > size)
  49213         p = size;
  49214     sub = js_sub_string(ctx, strp, p, size);
  49215     if (JS_IsException(sub))
  49216         goto exception;
  49217     if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
  49218         goto exception;
  49219     goto done;
  49220 exception:
  49221     JS_FreeValue(ctx, A);
  49222     A = JS_EXCEPTION;
  49223 done:
  49224     JS_FreeValue(ctx, str);
  49225     JS_FreeValue(ctx, ctor);
  49226     JS_FreeValue(ctx, splitter);
  49227     JS_FreeValue(ctx, flags);
  49228     JS_FreeValue(ctx, z);
  49229     return A;
  49230 }
  49231 
  49232 static const JSCFunctionListEntry js_regexp_funcs[] = {
  49233     JS_CFUNC_DEF("escape", 1, js_regexp_escape ),
  49234     JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
  49235 };
  49236 
  49237 static const JSCFunctionListEntry js_regexp_proto_funcs[] = {
  49238     JS_CGETSET_DEF("flags", js_regexp_get_flags, NULL ),
  49239     JS_CGETSET_DEF("source", js_regexp_get_source, NULL ),
  49240     JS_CGETSET_MAGIC_DEF("global", js_regexp_get_flag, NULL, LRE_FLAG_GLOBAL ),
  49241     JS_CGETSET_MAGIC_DEF("ignoreCase", js_regexp_get_flag, NULL, LRE_FLAG_IGNORECASE ),
  49242     JS_CGETSET_MAGIC_DEF("multiline", js_regexp_get_flag, NULL, LRE_FLAG_MULTILINE ),
  49243     JS_CGETSET_MAGIC_DEF("dotAll", js_regexp_get_flag, NULL, LRE_FLAG_DOTALL ),
  49244     JS_CGETSET_MAGIC_DEF("unicode", js_regexp_get_flag, NULL, LRE_FLAG_UNICODE ),
  49245     JS_CGETSET_MAGIC_DEF("unicodeSets", js_regexp_get_flag, NULL, LRE_FLAG_UNICODE_SETS ),
  49246     JS_CGETSET_MAGIC_DEF("sticky", js_regexp_get_flag, NULL, LRE_FLAG_STICKY ),
  49247     JS_CGETSET_MAGIC_DEF("hasIndices", js_regexp_get_flag, NULL, LRE_FLAG_INDICES ),
  49248     JS_CFUNC_DEF("exec", 1, js_regexp_exec ),
  49249     JS_CFUNC_DEF("compile", 2, js_regexp_compile ),
  49250     JS_CFUNC_DEF("test", 1, js_regexp_test ),
  49251     JS_CFUNC_DEF("toString", 0, js_regexp_toString ),
  49252     JS_CFUNC_DEF("[Symbol.replace]", 2, js_regexp_Symbol_replace ),
  49253     JS_CFUNC_DEF("[Symbol.match]", 1, js_regexp_Symbol_match ),
  49254     JS_CFUNC_DEF("[Symbol.matchAll]", 1, js_regexp_Symbol_matchAll ),
  49255     JS_CFUNC_DEF("[Symbol.search]", 1, js_regexp_Symbol_search ),
  49256     JS_CFUNC_DEF("[Symbol.split]", 2, js_regexp_Symbol_split ),
  49257 };
  49258 
  49259 static const JSCFunctionListEntry js_regexp_string_iterator_proto_funcs[] = {
  49260     JS_ITERATOR_NEXT_DEF("next", 0, js_regexp_string_iterator_next, 0 ),
  49261     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "RegExp String Iterator", JS_PROP_CONFIGURABLE ),
  49262 };
  49263 
  49264 void JS_AddIntrinsicRegExpCompiler(JSContext *ctx)
  49265 {
  49266     ctx->compile_regexp = js_compile_regexp;
  49267 }
  49268 
  49269 int JS_AddIntrinsicRegExp(JSContext *ctx)
  49270 {
  49271     JSValue obj;
  49272 
  49273     JS_AddIntrinsicRegExpCompiler(ctx);
  49274 
  49275     obj = JS_NewCConstructor(ctx, JS_CLASS_REGEXP, "RegExp",
  49276                                     js_regexp_constructor, 2, JS_CFUNC_constructor_or_func, 0,
  49277                                     JS_UNDEFINED,
  49278                                     js_regexp_funcs, countof(js_regexp_funcs),
  49279                                     js_regexp_proto_funcs, countof(js_regexp_proto_funcs),
  49280                                     0);
  49281     if (JS_IsException(obj))
  49282         return -1;
  49283     ctx->regexp_ctor = obj;
  49284     
  49285     ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR] =
  49286         JS_NewObjectProtoList(ctx, ctx->class_proto[JS_CLASS_ITERATOR],
  49287                               js_regexp_string_iterator_proto_funcs,
  49288                               countof(js_regexp_string_iterator_proto_funcs));
  49289     if (JS_IsException(ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR]))
  49290         return -1;
  49291 
  49292     ctx->regexp_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_REGEXP]),
  49293                                      JS_PROP_INITIAL_HASH_SIZE, 1);
  49294     if (!ctx->regexp_shape)
  49295         return -1;
  49296     if (add_shape_property(ctx, &ctx->regexp_shape, NULL,
  49297                            JS_ATOM_lastIndex, JS_PROP_WRITABLE))
  49298         return -1;
  49299 
  49300     ctx->regexp_result_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_ARRAY]),
  49301                                      JS_PROP_INITIAL_HASH_SIZE, 4);
  49302     if (!ctx->regexp_result_shape)
  49303         return -1;
  49304     if (add_shape_property(ctx, &ctx->regexp_result_shape, NULL,
  49305                            JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_LENGTH))
  49306         return -1;
  49307     if (add_shape_property(ctx, &ctx->regexp_result_shape, NULL,
  49308                            JS_ATOM_index, JS_PROP_C_W_E))
  49309         return -1;
  49310     if (add_shape_property(ctx, &ctx->regexp_result_shape, NULL,
  49311                            JS_ATOM_input, JS_PROP_C_W_E))
  49312         return -1;
  49313     if (add_shape_property(ctx, &ctx->regexp_result_shape, NULL,
  49314                            JS_ATOM_groups, JS_PROP_C_W_E))
  49315         return -1;
  49316 
  49317     return 0;
  49318 }
  49319 
  49320 /* JSON */
  49321 
  49322 static int json_parse_expect(JSParseState *s, int tok)
  49323 {
  49324     if (s->token.val != tok) {
  49325         /* XXX: dump token correctly in all cases */
  49326         return js_parse_error(s, "expecting '%c'", tok);
  49327     }
  49328     return json_next_token(s);
  49329 }
  49330 
  49331 
  49332 typedef struct {
  49333     int count;
  49334     uint32_t hash_size;
  49335     struct JSONParseRecordEntry *entries;
  49336     uint32_t *hash_table;
  49337 } JSONParseRecordObject;
  49338     
  49339 typedef struct JSONParseRecord {
  49340     JSValue value;
  49341     union {
  49342         JSONParseRecordObject obj;
  49343         struct {
  49344             int count;
  49345             struct JSONParseRecord *elements;
  49346         } array;
  49347         struct {
  49348             uint32_t source_pos;
  49349             uint32_t source_len;
  49350         } primitive;
  49351     } u;
  49352 } JSONParseRecord;
  49353 
  49354 typedef struct JSONParseRecordEntry {
  49355     JSAtom atom;
  49356     uint32_t hash_next;
  49357     JSONParseRecord parse_record;
  49358 } JSONParseRecordEntry;
  49359 
  49360 static void json_parse_record_init_obj(JSContext *ctx, JSONParseRecord *pr, JSValueConst val)
  49361 {
  49362     pr->value = JS_DupValue(ctx, val);
  49363     pr->u.obj.count = 0;
  49364     pr->u.obj.entries = NULL;
  49365     pr->u.obj.hash_table = NULL;
  49366     pr->u.obj.hash_size = 0;
  49367 }
  49368 
  49369 static void json_parse_record_init_array(JSContext *ctx, JSONParseRecord *pr, JSValueConst val)
  49370 {
  49371     pr->value = JS_DupValue(ctx, val);
  49372     pr->u.array.count = 0;
  49373     pr->u.array.elements = NULL;
  49374 }
  49375 
  49376 static void json_parse_record_init_primitive(JSContext *ctx, JSONParseRecord *pr, JSValueConst val,
  49377                                              uint32_t source_pos, uint32_t source_len)
  49378 {
  49379     pr->value = JS_DupValue(ctx, val);
  49380     pr->u.primitive.source_pos = source_pos;
  49381     pr->u.primitive.source_len = source_len;
  49382 }
  49383 
  49384 static int json_parse_record_resize_hash(JSContext *ctx, JSONParseRecordObject *po, uint32_t new_hash_size)
  49385 {
  49386     uint32_t i, h, *new_hash_table;
  49387     JSONParseRecordEntry *e;
  49388 
  49389     new_hash_table = js_malloc(ctx, sizeof(new_hash_table[0]) * new_hash_size);
  49390     if (!new_hash_table)
  49391         return -1;
  49392     js_free(ctx, po->hash_table);
  49393     po->hash_table = new_hash_table;
  49394     po->hash_size = new_hash_size;
  49395 
  49396     for(i = 0; i < po->hash_size; i++) {
  49397         po->hash_table[i] = -1;
  49398     }
  49399     for(i = 0; i < po->count; i++) {
  49400         e = &po->entries[i];
  49401         h = e->atom & (po->hash_size - 1);
  49402         e->hash_next = po->hash_table[h];
  49403         po->hash_table[h] = i;
  49404     }
  49405     return 0;
  49406 }
  49407 
  49408 static JSONParseRecord *json_parse_record_add(JSContext *ctx, JSONParseRecord *pr, JSAtom key, int *psize)
  49409 {
  49410     JSONParseRecordObject *po = &pr->u.obj;
  49411     JSONParseRecordEntry *e;
  49412     JSONParseRecord *pr1;
  49413     uint32_t h;
  49414     
  49415     if (js_resize_array(ctx, (void **)&po->entries, sizeof(po->entries[0]),
  49416                         psize, po->count + 1)) {
  49417         return NULL;
  49418     }
  49419     /* don't use a hash table when the number of entries is small */
  49420     if (po->count >= 8 && (po->count + 1) > po->hash_size) {
  49421         int hash_bits = 32 - clz32(po->count);
  49422         if (json_parse_record_resize_hash(ctx, po, 1 << hash_bits))
  49423             return NULL;
  49424     }
  49425 
  49426     e = &po->entries[po->count++];
  49427     e->atom = JS_DupAtom(ctx, key);
  49428     pr1 = &e->parse_record;
  49429     pr1->value = JS_UNDEFINED;
  49430     if (po->hash_size != 0) {
  49431         h = key & (po->hash_size - 1);
  49432         e->hash_next = po->hash_table[h];
  49433         po->hash_table[h] = po->count - 1;
  49434     }
  49435     return pr1;
  49436 }
  49437 
  49438 static JSONParseRecord *json_parse_record_find(JSONParseRecord *pr, JSAtom key)
  49439 {
  49440     JSONParseRecordObject *po = &pr->u.obj;
  49441     JSONParseRecordEntry *e;
  49442     uint32_t h, i;
  49443     
  49444     if (po->hash_size == 0) {
  49445         for(i = 0; i < po->count; i++) {
  49446             if (po->entries[i].atom == key)
  49447                 return &po->entries[i].parse_record;
  49448         }
  49449     } else {
  49450         h = key & (po->hash_size - 1);
  49451         i = po->hash_table[h];
  49452         while (i != -1) {
  49453             e = &po->entries[i];
  49454             if (e->atom == key)
  49455                 return &e->parse_record;
  49456             i = e->hash_next;
  49457         }
  49458     }
  49459     return NULL;
  49460 }
  49461 
  49462 static void json_free_parse_record(JSContext *ctx, JSONParseRecord *pr)
  49463 {
  49464     int i;
  49465     if (!pr)
  49466         return;
  49467     if (JS_IsObject(pr->value)) {
  49468         if (JS_IsArray(ctx, pr->value)) {
  49469             for(i = 0; i < pr->u.array.count; i++) {
  49470                 json_free_parse_record(ctx, &pr->u.array.elements[i]);
  49471             }
  49472             js_free(ctx, pr->u.array.elements);
  49473         } else {
  49474             for(i = 0; i < pr->u.obj.count; i++) {
  49475                 JS_FreeAtom(ctx, pr->u.obj.entries[i].atom);
  49476                 json_free_parse_record(ctx, &pr->u.obj.entries[i].parse_record);
  49477             }
  49478             js_free(ctx, pr->u.obj.entries);
  49479             js_free(ctx, pr->u.obj.hash_table);
  49480         }
  49481     }
  49482     JS_FreeValue(ctx, pr->value);
  49483     pr->value = JS_UNDEFINED; /* fail safe */
  49484 }
  49485 
  49486 /* 'pr' can be NULL */
  49487 static JSValue json_parse_value(JSParseState *s, JSONParseRecord *pr)
  49488 {
  49489     JSContext *ctx = s->ctx;
  49490     JSValue val = JS_NULL;
  49491     int ret;
  49492 
  49493     if (pr) {
  49494         pr->value = JS_UNDEFINED;
  49495     }
  49496     
  49497     switch(s->token.val) {
  49498     case '{':
  49499         {
  49500             JSValue prop_val;
  49501             JSAtom prop_name;
  49502             JSONParseRecord *pr1;
  49503             int pr_size;
  49504             
  49505             if (json_next_token(s))
  49506                 goto fail;
  49507             val = JS_NewObject(ctx);
  49508             if (JS_IsException(val))
  49509                 goto fail;
  49510             if (pr) {
  49511                 json_parse_record_init_obj(ctx, pr, val);
  49512                 pr_size = 0;
  49513             }
  49514             if (s->token.val != '}') {
  49515                 for(;;) {
  49516                     if (s->token.val == TOK_STRING) {
  49517                         prop_name = JS_ValueToAtom(ctx, s->token.u.str.str);
  49518                         if (prop_name == JS_ATOM_NULL)
  49519                             goto fail;
  49520                     } else if (s->ext_json && s->token.val == TOK_IDENT) {
  49521                         prop_name = JS_DupAtom(ctx, s->token.u.ident.atom);
  49522                     } else {
  49523                         js_parse_error(s, "expecting property name");
  49524                         goto fail;
  49525                     }
  49526                     if (json_next_token(s))
  49527                         goto fail1;
  49528                     if (json_parse_expect(s, ':'))
  49529                         goto fail1;
  49530                     if (pr) {
  49531                         pr1 = json_parse_record_add(ctx, pr, prop_name, &pr_size);
  49532                         if (!pr1)
  49533                             goto fail1;
  49534                     } else {
  49535                         pr1 = NULL;
  49536                     }
  49537                     prop_val = json_parse_value(s, pr1);
  49538                     if (JS_IsException(prop_val)) {
  49539                     fail1:
  49540                         JS_FreeAtom(ctx, prop_name);
  49541                         goto fail;
  49542                     }
  49543                     ret = JS_DefinePropertyValue(ctx, val, prop_name,
  49544                                                  prop_val, JS_PROP_C_W_E);
  49545                     JS_FreeAtom(ctx, prop_name);
  49546                     if (ret < 0)
  49547                         goto fail;
  49548 
  49549                     if (s->token.val != ',')
  49550                         break;
  49551                     if (json_next_token(s))
  49552                         goto fail;
  49553                     if (s->ext_json && s->token.val == '}')
  49554                         break;
  49555                 }
  49556             }
  49557             if (json_parse_expect(s, '}'))
  49558                 goto fail;
  49559         }
  49560         break;
  49561     case '[':
  49562         {
  49563             JSValue el;
  49564             uint32_t idx;
  49565             JSONParseRecord *pr1;
  49566             int pr_size;
  49567             
  49568             if (json_next_token(s))
  49569                 goto fail;
  49570             val = JS_NewArray(ctx);
  49571             if (JS_IsException(val))
  49572                 goto fail;
  49573             if (pr) {
  49574                 json_parse_record_init_array(ctx, pr, val);
  49575                 pr_size = 0;
  49576             }
  49577             if (s->token.val != ']') {
  49578                 idx = 0;
  49579                 for(;;) {
  49580                     if (pr) {
  49581                         if (js_resize_array(ctx, (void **)&pr->u.array.elements, sizeof(pr->u.array.elements[0]),
  49582                                             &pr_size, pr->u.array.count + 1))
  49583                             goto fail;
  49584                         pr1 = &pr->u.array.elements[pr->u.array.count++];
  49585                         pr1->value = JS_UNDEFINED;
  49586                     } else {
  49587                         pr1 = NULL;
  49588                     }
  49589                     el = json_parse_value(s, pr1);
  49590                     if (JS_IsException(el))
  49591                         goto fail;
  49592                     ret = JS_DefinePropertyValueUint32(ctx, val, idx, el, JS_PROP_C_W_E);
  49593                     if (ret < 0)
  49594                         goto fail;
  49595                     if (s->token.val != ',')
  49596                         break;
  49597                     if (json_next_token(s))
  49598                         goto fail;
  49599                     idx++;
  49600                     if (s->ext_json && s->token.val == ']')
  49601                         break;
  49602                 }
  49603             }
  49604             if (json_parse_expect(s, ']'))
  49605                 goto fail;
  49606         }
  49607         break;
  49608     case TOK_STRING:
  49609         val = JS_DupValue(ctx, s->token.u.str.str);
  49610         if (pr) {
  49611             json_parse_record_init_primitive(ctx, pr, val, 
  49612                                              s->token.ptr - s->buf_start,
  49613                                              s->buf_ptr - s->token.ptr);
  49614         }
  49615         if (json_next_token(s))
  49616             goto fail;
  49617         break;
  49618     case TOK_NUMBER:
  49619         val = s->token.u.num.val;
  49620         if (pr) {
  49621             json_parse_record_init_primitive(ctx, pr, val, 
  49622                                              s->token.ptr - s->buf_start,
  49623                                              s->buf_ptr - s->token.ptr);
  49624         }
  49625         if (json_next_token(s))
  49626             goto fail;
  49627         break;
  49628     case TOK_IDENT:
  49629         if (s->token.u.ident.atom == JS_ATOM_false ||
  49630             s->token.u.ident.atom == JS_ATOM_true) {
  49631             val = JS_NewBool(ctx, s->token.u.ident.atom == JS_ATOM_true);
  49632             if (pr) {
  49633                 json_parse_record_init_primitive(ctx, pr, val, 
  49634                                                  s->token.ptr - s->buf_start,
  49635                                                  s->buf_ptr - s->token.ptr);
  49636             }
  49637         } else if (s->token.u.ident.atom == JS_ATOM_null) {
  49638             val = JS_NULL;
  49639             if (pr) {
  49640                 json_parse_record_init_primitive(ctx, pr, val, 
  49641                                                  s->token.ptr - s->buf_start,
  49642                                                  s->buf_ptr - s->token.ptr);
  49643             }
  49644         } else if (s->token.u.ident.atom == JS_ATOM_NaN && s->ext_json) {
  49645             /* Note: json5 identifier handling is ambiguous e.g. is 
  49646                '{ NaN: 1 }' a valid JSON5 production ? */ 
  49647             val = JS_NewFloat64(s->ctx, NAN);
  49648         } else if (s->token.u.ident.atom == JS_ATOM_Infinity && s->ext_json) {
  49649             val = JS_NewFloat64(s->ctx, INFINITY);
  49650         } else {
  49651             goto def_token;
  49652         }
  49653         if (json_next_token(s))
  49654             goto fail;
  49655         break;
  49656     default:
  49657     def_token:
  49658         if (s->token.val == TOK_EOF) {
  49659             js_parse_error(s, "Unexpected end of JSON input");
  49660         } else {
  49661             js_parse_error(s, "unexpected token: '%.*s'",
  49662                            (int)(s->buf_ptr - s->token.ptr), s->token.ptr);
  49663         }
  49664         goto fail;
  49665     }
  49666     return val;
  49667  fail:
  49668     json_free_parse_record(ctx, pr);
  49669     JS_FreeValue(ctx, val);
  49670     return JS_EXCEPTION;
  49671 }
  49672 
  49673 JSValue JS_ParseJSON3(JSContext *ctx, const char *buf, size_t buf_len,
  49674                       const char *filename, int flags, JSONParseRecord *pr)
  49675 {
  49676     JSParseState s1, *s = &s1;
  49677     JSValue val = JS_UNDEFINED;
  49678 
  49679     js_parse_init(ctx, s, buf, buf_len, filename);
  49680     s->ext_json = ((flags & JS_PARSE_JSON_EXT) != 0);
  49681     if (json_next_token(s))
  49682         goto fail;
  49683     val = json_parse_value(s, pr);
  49684     if (JS_IsException(val))
  49685         goto fail;
  49686     if (s->token.val != TOK_EOF) {
  49687         if (js_parse_error(s, "unexpected data at the end")) {
  49688             json_free_parse_record(ctx, pr);
  49689             goto fail;
  49690         }
  49691     }
  49692     return val;
  49693  fail:
  49694     JS_FreeValue(ctx, val);
  49695     free_token(s, &s->token);
  49696     return JS_EXCEPTION;
  49697 }
  49698 
  49699 JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
  49700                       const char *filename, int flags)
  49701 {
  49702     return JS_ParseJSON3(ctx, buf, buf_len, filename, flags, NULL);
  49703 }
  49704 
  49705 JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
  49706                      const char *filename)
  49707 {
  49708     return JS_ParseJSON3(ctx, buf, buf_len, filename, 0, NULL);
  49709 }
  49710 
  49711 /* if pr != NULL, then pr->value = holder by construction */
  49712 static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
  49713                                          JSAtom name, JSValueConst reviver,
  49714                                          const char *text_str, JSONParseRecord *pr)
  49715 {
  49716     JSValue val, new_el, name_val, res, context;
  49717     JSValueConst args[3];
  49718     int ret, is_array;
  49719     uint32_t i, len = 0;
  49720     JSAtom prop;
  49721     JSPropertyEnum *atoms = NULL;
  49722 
  49723     if (js_check_stack_overflow(ctx->rt, 0)) {
  49724         return JS_ThrowStackOverflow(ctx);
  49725     }
  49726 
  49727     val = JS_GetProperty(ctx, holder, name);
  49728     if (JS_IsException(val))
  49729         return val;
  49730 
  49731     if (pr) {
  49732         if (JS_IsArray(ctx, pr->value)) {
  49733             if (__JS_AtomIsTaggedInt(name)) {
  49734                 uint32_t idx = __JS_AtomToUInt32(name);
  49735                 if (idx < pr->u.array.count) {
  49736                     pr = &pr->u.array.elements[idx];
  49737                 } else {
  49738                     pr = NULL;
  49739                 }
  49740             }
  49741         } else {
  49742             pr = json_parse_record_find(pr, name);
  49743         }
  49744         if (pr && !js_same_value(ctx, pr->value, val)) {
  49745             pr = NULL;
  49746         }
  49747     }
  49748 
  49749     context = JS_NewObject(ctx);
  49750     if (JS_IsException(context))
  49751         goto fail;
  49752     
  49753     if (JS_IsObject(val)) {
  49754         is_array = JS_IsArray(ctx, val);
  49755         if (is_array < 0)
  49756             goto fail;
  49757         if (is_array) {
  49758             if (js_get_length32(ctx, &len, val))
  49759                 goto fail;
  49760         } else {
  49761             ret = JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, JS_VALUE_GET_OBJ(val), JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK);
  49762             if (ret < 0)
  49763                 goto fail;
  49764         }
  49765         for(i = 0; i < len; i++) {
  49766             if (is_array) {
  49767                 prop = JS_NewAtomUInt32(ctx, i);
  49768                 if (prop == JS_ATOM_NULL)
  49769                     goto fail;
  49770             } else {
  49771                 prop = JS_DupAtom(ctx, atoms[i].atom);
  49772             }
  49773             new_el = internalize_json_property(ctx, val, prop, reviver, text_str, pr);
  49774             if (JS_IsException(new_el)) {
  49775                 JS_FreeAtom(ctx, prop);
  49776                 goto fail;
  49777             }
  49778             if (JS_IsUndefined(new_el)) {
  49779                 ret = JS_DeleteProperty(ctx, val, prop, 0);
  49780             } else {
  49781                 ret = JS_DefinePropertyValue(ctx, val, prop, new_el, JS_PROP_C_W_E);
  49782             }
  49783             JS_FreeAtom(ctx, prop);
  49784             if (ret < 0)
  49785                 goto fail;
  49786         }
  49787     } else {
  49788         if (pr) {
  49789             new_el = JS_NewStringLen(ctx, text_str + pr->u.primitive.source_pos,
  49790                                      pr->u.primitive.source_len);
  49791             if (JS_IsException(new_el))
  49792                 goto fail;
  49793             if (JS_DefinePropertyValue(ctx, context, JS_ATOM_source, new_el, JS_PROP_C_W_E) < 0)
  49794                 goto fail;
  49795         }
  49796     }
  49797     JS_FreePropertyEnum(ctx, atoms, len);
  49798     atoms = NULL;
  49799     name_val = JS_AtomToValue(ctx, name);
  49800     if (JS_IsException(name_val))
  49801         goto fail;
  49802     args[0] = name_val;
  49803     args[1] = val;
  49804     args[2] = context;
  49805     res = JS_Call(ctx, reviver, holder, 3, args);
  49806     JS_FreeValue(ctx, name_val);
  49807     JS_FreeValue(ctx, val);
  49808     JS_FreeValue(ctx, context);
  49809     return res;
  49810  fail:
  49811     JS_FreePropertyEnum(ctx, atoms, len);
  49812     JS_FreeValue(ctx, context);
  49813     JS_FreeValue(ctx, val);
  49814     return JS_EXCEPTION;
  49815 }
  49816 
  49817 static JSValue js_json_parse(JSContext *ctx, JSValueConst this_val,
  49818                              int argc, JSValueConst *argv)
  49819 {
  49820     JSValue obj;
  49821     const char *str;
  49822     size_t len;
  49823     
  49824     str = JS_ToCStringLen(ctx, &len, argv[0]);
  49825     if (!str)
  49826         return JS_EXCEPTION;
  49827     if (argc > 1 && JS_IsFunction(ctx, argv[1])) {
  49828         JSONParseRecord pr_s, *pr = &pr_s, *pr1;
  49829         JSValue root;
  49830         JSValueConst reviver;
  49831         int size;
  49832         
  49833         reviver = argv[1];
  49834         root = JS_NewObject(ctx);
  49835         if (JS_IsException(root))
  49836             goto fail;
  49837         json_parse_record_init_obj(ctx, pr, root);
  49838         size = 0;
  49839         pr1 = json_parse_record_add(ctx, pr, JS_ATOM_empty_string, &size);
  49840         if (!pr1)
  49841             goto fail1;
  49842 
  49843         obj = JS_ParseJSON3(ctx, str, len, "<input>", 0, pr1);
  49844         if (JS_IsException(obj))
  49845             goto fail1;
  49846         
  49847         if (JS_DefinePropertyValue(ctx, root, JS_ATOM_empty_string, obj,
  49848                                    JS_PROP_C_W_E) < 0) {
  49849             JS_FreeValue(ctx, obj);
  49850         fail1:
  49851             json_free_parse_record(ctx, pr);
  49852             JS_FreeValue(ctx, root);
  49853             goto fail;
  49854         }
  49855         
  49856         obj = internalize_json_property(ctx, root, JS_ATOM_empty_string,
  49857                                         reviver, str, pr);
  49858         json_free_parse_record(ctx, pr);
  49859         JS_FreeValue(ctx, root);
  49860     } else {
  49861         obj = JS_ParseJSON3(ctx, str, len, "<input>", 0, NULL);
  49862     }
  49863     JS_FreeCString(ctx, str);
  49864     return obj;
  49865  fail:
  49866     JS_FreeCString(ctx, str);
  49867     return JS_EXCEPTION;
  49868 }
  49869 
  49870 static JSValue js_json_isRawJSON(JSContext *ctx, JSValueConst this_val,
  49871                                  int argc, JSValueConst *argv)
  49872 {
  49873     JSValueConst obj = argv[0];
  49874     if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
  49875         JSObject *p = JS_VALUE_GET_OBJ(obj);
  49876         return JS_NewBool(ctx, p->class_id == JS_CLASS_RAWJSON);
  49877     } else {
  49878         return JS_FALSE;
  49879     }
  49880 }
  49881 
  49882 static BOOL is_valid_raw_json_char(int c)
  49883 {
  49884     return ((c >= 'a' && c <= 'z') ||
  49885             (c >= '0' && c <= '9') ||
  49886             c == '-' || 
  49887             c == '"');
  49888 }
  49889 
  49890 static JSValue js_json_rawJSON(JSContext *ctx, JSValueConst this_val,
  49891                                  int argc, JSValueConst *argv)
  49892 {
  49893     JSValue str, res, obj;
  49894     JSString *p;
  49895     str = JS_ToString(ctx, argv[0]);
  49896     if (JS_IsException(str))
  49897         return str;
  49898     p = JS_VALUE_GET_STRING(str);
  49899     if (p->len == 0 ||
  49900         !is_valid_raw_json_char(string_get(p, 0)) ||
  49901         !is_valid_raw_json_char(string_get(p, p->len - 1))) {
  49902         goto syntax_error;
  49903     }
  49904     res = js_json_parse(ctx, JS_UNDEFINED, 1, (JSValueConst *)&str);
  49905     if (JS_IsException(res)) {
  49906     syntax_error:
  49907         JS_ThrowSyntaxError(ctx, "invalid rawJSON string");
  49908         goto fail;
  49909     }
  49910     JS_FreeValue(ctx, res);
  49911     
  49912     obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_RAWJSON);
  49913     if (JS_IsException(obj))
  49914         goto fail;
  49915     if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_rawJSON, str, JS_PROP_ENUMERABLE) < 0) {
  49916         JS_FreeValue(ctx, obj);
  49917         return JS_EXCEPTION;
  49918     }
  49919     JS_PreventExtensions(ctx, obj);
  49920     return obj;
  49921  fail:
  49922     JS_FreeValue(ctx, str);
  49923     return JS_EXCEPTION;
  49924 }
  49925 
  49926 
  49927 typedef struct JSONStringifyContext {
  49928     JSValueConst replacer_func;
  49929     JSValue stack;
  49930     JSValue property_list;
  49931     JSValue gap;
  49932     JSValue empty;
  49933     StringBuffer *b;
  49934 } JSONStringifyContext;
  49935 
  49936 static int JS_ToQuotedString(JSContext *ctx, StringBuffer *b, JSValueConst val1)
  49937 {
  49938     JSValue val;
  49939     JSString *p;
  49940     int i;
  49941     uint32_t c;
  49942     char buf[16];
  49943 
  49944     val = JS_ToStringCheckObject(ctx, val1);
  49945     if (JS_IsException(val))
  49946         return -1;
  49947     p = JS_VALUE_GET_STRING(val);
  49948 
  49949     if (string_buffer_putc8(b, '\"'))
  49950         goto fail;
  49951     for(i = 0; i < p->len; ) {
  49952         c = string_getc(p, &i);
  49953         switch(c) {
  49954         case '\t':
  49955             c = 't';
  49956             goto quote;
  49957         case '\r':
  49958             c = 'r';
  49959             goto quote;
  49960         case '\n':
  49961             c = 'n';
  49962             goto quote;
  49963         case '\b':
  49964             c = 'b';
  49965             goto quote;
  49966         case '\f':
  49967             c = 'f';
  49968             goto quote;
  49969         case '\"':
  49970         case '\\':
  49971         quote:
  49972             if (string_buffer_putc8(b, '\\'))
  49973                 goto fail;
  49974             if (string_buffer_putc8(b, c))
  49975                 goto fail;
  49976             break;
  49977         default:
  49978             if (c < 32 || is_surrogate(c)) {
  49979                 snprintf(buf, sizeof(buf), "\\u%04x", c);
  49980                 if (string_buffer_puts8(b, buf))
  49981                     goto fail;
  49982             } else {
  49983                 if (string_buffer_putc(b, c))
  49984                     goto fail;
  49985             }
  49986             break;
  49987         }
  49988     }
  49989     if (string_buffer_putc8(b, '\"'))
  49990         goto fail;
  49991     JS_FreeValue(ctx, val);
  49992     return 0;
  49993  fail:
  49994     JS_FreeValue(ctx, val);
  49995     return -1;
  49996 }
  49997 
  49998 static int JS_ToQuotedStringFree(JSContext *ctx, StringBuffer *b, JSValue val) {
  49999     int ret = JS_ToQuotedString(ctx, b, val);
  50000     JS_FreeValue(ctx, val);
  50001     return ret;
  50002 }
  50003 
  50004 static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,
  50005                              JSValueConst holder, JSValue val, JSValueConst key)
  50006 {
  50007     JSValue v;
  50008     JSValueConst args[2];
  50009 
  50010     /* check for object.toJSON method */
  50011     /* ECMA specifies this is done only for Object and BigInt */
  50012     if (JS_IsObject(val) || JS_IsBigInt(ctx, val)) {
  50013         JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON);
  50014         if (JS_IsException(f))
  50015             goto exception;
  50016         if (JS_IsFunction(ctx, f)) {
  50017             v = JS_CallFree(ctx, f, val, 1, &key);
  50018             JS_FreeValue(ctx, val);
  50019             val = v;
  50020             if (JS_IsException(val))
  50021                 goto exception;
  50022         } else {
  50023             JS_FreeValue(ctx, f);
  50024         }
  50025     }
  50026 
  50027     if (!JS_IsUndefined(jsc->replacer_func)) {
  50028         args[0] = key;
  50029         args[1] = val;
  50030         v = JS_Call(ctx, jsc->replacer_func, holder, 2, args);
  50031         JS_FreeValue(ctx, val);
  50032         val = v;
  50033         if (JS_IsException(val))
  50034             goto exception;
  50035     }
  50036 
  50037     switch (JS_VALUE_GET_NORM_TAG(val)) {
  50038     case JS_TAG_OBJECT:
  50039         if (JS_IsFunction(ctx, val))
  50040             break;
  50041     case JS_TAG_STRING:
  50042     case JS_TAG_STRING_ROPE:
  50043     case JS_TAG_INT:
  50044     case JS_TAG_FLOAT64:
  50045     case JS_TAG_BOOL:
  50046     case JS_TAG_NULL:
  50047     case JS_TAG_SHORT_BIG_INT:
  50048     case JS_TAG_BIG_INT:
  50049     case JS_TAG_EXCEPTION:
  50050         return val;
  50051     default:
  50052         break;
  50053     }
  50054     JS_FreeValue(ctx, val);
  50055     return JS_UNDEFINED;
  50056 
  50057 exception:
  50058     JS_FreeValue(ctx, val);
  50059     return JS_EXCEPTION;
  50060 }
  50061 
  50062 static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
  50063                           JSValueConst holder, JSValue val,
  50064                           JSValueConst indent)
  50065 {
  50066     JSValue indent1, sep, sep1, tab, v, prop;
  50067     JSObject *p;
  50068     int64_t i, len;
  50069     int cl, ret;
  50070     BOOL has_content;
  50071 
  50072     indent1 = JS_UNDEFINED;
  50073     sep = JS_UNDEFINED;
  50074     sep1 = JS_UNDEFINED;
  50075     tab = JS_UNDEFINED;
  50076     prop = JS_UNDEFINED;
  50077 
  50078     if (js_check_stack_overflow(ctx->rt, 0)) {
  50079         JS_ThrowStackOverflow(ctx);
  50080         goto exception;
  50081     }
  50082 
  50083     if (JS_IsObject(val)) {
  50084         p = JS_VALUE_GET_OBJ(val);
  50085         cl = p->class_id;
  50086         if (cl == JS_CLASS_STRING) {
  50087             val = JS_ToStringFree(ctx, val);
  50088             if (JS_IsException(val))
  50089                 goto exception;
  50090             goto concat_primitive;
  50091         } else if (cl == JS_CLASS_NUMBER) {
  50092             val = JS_ToNumberFree(ctx, val);
  50093             if (JS_IsException(val))
  50094                 goto exception;
  50095             goto concat_primitive;
  50096         } else if (cl == JS_CLASS_BOOLEAN || cl == JS_CLASS_BIG_INT) {
  50097             /* This will thow the same error as for the primitive object */
  50098             set_value(ctx, &val, JS_DupValue(ctx, p->u.object_data));
  50099             goto concat_primitive;
  50100         } else if (cl == JS_CLASS_RAWJSON) {
  50101             JSValue val1;
  50102             val1 = JS_GetProperty(ctx, val, JS_ATOM_rawJSON);
  50103             if (JS_IsException(val1))
  50104                 goto exception;
  50105             JS_FreeValue(ctx, val);
  50106             val = val1;
  50107             goto concat_value;
  50108         }
  50109         v = js_array_includes(ctx, jsc->stack, 1, (JSValueConst *)&val);
  50110         if (JS_IsException(v))
  50111             goto exception;
  50112         if (JS_ToBoolFree(ctx, v)) {
  50113             JS_ThrowTypeError(ctx, "circular reference");
  50114             goto exception;
  50115         }
  50116         indent1 = JS_ConcatString(ctx, JS_DupValue(ctx, indent), JS_DupValue(ctx, jsc->gap));
  50117         if (JS_IsException(indent1))
  50118             goto exception;
  50119         if (!JS_IsEmptyString(jsc->gap)) {
  50120             sep = JS_ConcatString3(ctx, "\n", JS_DupValue(ctx, indent1), "");
  50121             if (JS_IsException(sep))
  50122                 goto exception;
  50123             sep1 = js_new_string8(ctx, " ");
  50124             if (JS_IsException(sep1))
  50125                 goto exception;
  50126         } else {
  50127             sep = JS_DupValue(ctx, jsc->empty);
  50128             sep1 = JS_DupValue(ctx, jsc->empty);
  50129         }
  50130         v = js_array_push(ctx, jsc->stack, 1, (JSValueConst *)&val, 0);
  50131         if (check_exception_free(ctx, v))
  50132             goto exception;
  50133         ret = JS_IsArray(ctx, val);
  50134         if (ret < 0)
  50135             goto exception;
  50136         if (ret) {
  50137             if (js_get_length64(ctx, &len, val))
  50138                 goto exception;
  50139             string_buffer_putc8(jsc->b, '[');
  50140             for(i = 0; i < len; i++) {
  50141                 if (i > 0)
  50142                     string_buffer_putc8(jsc->b, ',');
  50143                 string_buffer_concat_value(jsc->b, sep);
  50144                 v = JS_GetPropertyInt64(ctx, val, i);
  50145                 if (JS_IsException(v))
  50146                     goto exception;
  50147                 /* XXX: could do this string conversion only when needed */
  50148                 prop = JS_ToStringFree(ctx, JS_NewInt64(ctx, i));
  50149                 if (JS_IsException(prop))
  50150                     goto exception;
  50151                 v = js_json_check(ctx, jsc, val, v, prop);
  50152                 JS_FreeValue(ctx, prop);
  50153                 prop = JS_UNDEFINED;
  50154                 if (JS_IsException(v))
  50155                     goto exception;
  50156                 if (JS_IsUndefined(v))
  50157                     v = JS_NULL;
  50158                 if (js_json_to_str(ctx, jsc, val, v, indent1))
  50159                     goto exception;
  50160             }
  50161             if (len > 0 && !JS_IsEmptyString(jsc->gap)) {
  50162                 string_buffer_putc8(jsc->b, '\n');
  50163                 string_buffer_concat_value(jsc->b, indent);
  50164             }
  50165             string_buffer_putc8(jsc->b, ']');
  50166         } else {
  50167             if (!JS_IsUndefined(jsc->property_list))
  50168                 tab = JS_DupValue(ctx, jsc->property_list);
  50169             else
  50170                 tab = js_object_keys(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val, JS_ITERATOR_KIND_KEY);
  50171             if (JS_IsException(tab))
  50172                 goto exception;
  50173             if (js_get_length64(ctx, &len, tab))
  50174                 goto exception;
  50175             string_buffer_putc8(jsc->b, '{');
  50176             has_content = FALSE;
  50177             for(i = 0; i < len; i++) {
  50178                 JS_FreeValue(ctx, prop);
  50179                 prop = JS_GetPropertyInt64(ctx, tab, i);
  50180                 if (JS_IsException(prop))
  50181                     goto exception;
  50182                 v = JS_GetPropertyValue(ctx, val, JS_DupValue(ctx, prop));
  50183                 if (JS_IsException(v))
  50184                     goto exception;
  50185                 v = js_json_check(ctx, jsc, val, v, prop);
  50186                 if (JS_IsException(v))
  50187                     goto exception;
  50188                 if (!JS_IsUndefined(v)) {
  50189                     if (has_content)
  50190                         string_buffer_putc8(jsc->b, ',');
  50191                     string_buffer_concat_value(jsc->b, sep);
  50192                     if (JS_ToQuotedString(ctx, jsc->b, prop)) {
  50193                         JS_FreeValue(ctx, v);
  50194                         goto exception;
  50195                     }
  50196                     string_buffer_putc8(jsc->b, ':');
  50197                     string_buffer_concat_value(jsc->b, sep1);
  50198                     if (js_json_to_str(ctx, jsc, val, v, indent1))
  50199                         goto exception;
  50200                     has_content = TRUE;
  50201                 }
  50202             }
  50203             if (has_content && !JS_IsEmptyString(jsc->gap)) {
  50204                 string_buffer_putc8(jsc->b, '\n');
  50205                 string_buffer_concat_value(jsc->b, indent);
  50206             }
  50207             string_buffer_putc8(jsc->b, '}');
  50208         }
  50209         if (check_exception_free(ctx, js_array_pop(ctx, jsc->stack, 0, NULL, 0)))
  50210             goto exception;
  50211         JS_FreeValue(ctx, val);
  50212         JS_FreeValue(ctx, tab);
  50213         JS_FreeValue(ctx, sep);
  50214         JS_FreeValue(ctx, sep1);
  50215         JS_FreeValue(ctx, indent1);
  50216         JS_FreeValue(ctx, prop);
  50217         return 0;
  50218     }
  50219  concat_primitive:
  50220     switch (JS_VALUE_GET_NORM_TAG(val)) {
  50221     case JS_TAG_STRING:
  50222     case JS_TAG_STRING_ROPE:
  50223         return JS_ToQuotedStringFree(ctx, jsc->b, val);
  50224     case JS_TAG_FLOAT64:
  50225         if (!isfinite(JS_VALUE_GET_FLOAT64(val))) {
  50226             val = JS_NULL;
  50227         }
  50228         goto concat_value;
  50229     case JS_TAG_INT:
  50230     case JS_TAG_BOOL:
  50231     case JS_TAG_NULL:
  50232     concat_value:
  50233         return string_buffer_concat_value_free(jsc->b, val);
  50234     case JS_TAG_SHORT_BIG_INT:
  50235     case JS_TAG_BIG_INT:
  50236         /* reject big numbers: use toJSON method to override */
  50237         JS_ThrowTypeError(ctx, "Do not know how to serialize a BigInt");
  50238         goto exception;
  50239     default:
  50240         JS_FreeValue(ctx, val);
  50241         return 0;
  50242     }
  50243 
  50244 exception:
  50245     JS_FreeValue(ctx, val);
  50246     JS_FreeValue(ctx, tab);
  50247     JS_FreeValue(ctx, sep);
  50248     JS_FreeValue(ctx, sep1);
  50249     JS_FreeValue(ctx, indent1);
  50250     JS_FreeValue(ctx, prop);
  50251     return -1;
  50252 }
  50253 
  50254 JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
  50255                          JSValueConst replacer, JSValueConst space0)
  50256 {
  50257     StringBuffer b_s;
  50258     JSONStringifyContext jsc_s, *jsc = &jsc_s;
  50259     JSValue val, v, space, ret, wrapper;
  50260     int res;
  50261     int64_t i, j, n;
  50262 
  50263     jsc->replacer_func = JS_UNDEFINED;
  50264     jsc->stack = JS_UNDEFINED;
  50265     jsc->property_list = JS_UNDEFINED;
  50266     jsc->gap = JS_UNDEFINED;
  50267     jsc->b = &b_s;
  50268     jsc->empty = JS_AtomToString(ctx, JS_ATOM_empty_string);
  50269     ret = JS_UNDEFINED;
  50270     wrapper = JS_UNDEFINED;
  50271 
  50272     string_buffer_init(ctx, jsc->b, 0);
  50273     jsc->stack = JS_NewArray(ctx);
  50274     if (JS_IsException(jsc->stack))
  50275         goto exception;
  50276     if (JS_IsFunction(ctx, replacer)) {
  50277         jsc->replacer_func = replacer;
  50278     } else {
  50279         res = JS_IsArray(ctx, replacer);
  50280         if (res < 0)
  50281             goto exception;
  50282         if (res) {
  50283             /* XXX: enumeration is not fully correct */
  50284             jsc->property_list = JS_NewArray(ctx);
  50285             if (JS_IsException(jsc->property_list))
  50286                 goto exception;
  50287             if (js_get_length64(ctx, &n, replacer))
  50288                 goto exception;
  50289             for (i = j = 0; i < n; i++) {
  50290                 JSValue present;
  50291                 v = JS_GetPropertyInt64(ctx, replacer, i);
  50292                 if (JS_IsException(v))
  50293                     goto exception;
  50294                 if (JS_IsObject(v)) {
  50295                     JSObject *p = JS_VALUE_GET_OBJ(v);
  50296                     if (p->class_id == JS_CLASS_STRING ||
  50297                         p->class_id == JS_CLASS_NUMBER) {
  50298                         v = JS_ToStringFree(ctx, v);
  50299                         if (JS_IsException(v))
  50300                             goto exception;
  50301                     } else {
  50302                         JS_FreeValue(ctx, v);
  50303                         continue;
  50304                     }
  50305                 } else if (JS_IsNumber(v)) {
  50306                     v = JS_ToStringFree(ctx, v);
  50307                     if (JS_IsException(v))
  50308                         goto exception;
  50309                 } else if (!JS_IsString(v)) {
  50310                     JS_FreeValue(ctx, v);
  50311                     continue;
  50312                 }
  50313                 present = js_array_includes(ctx, jsc->property_list,
  50314                                             1, (JSValueConst *)&v);
  50315                 if (JS_IsException(present)) {
  50316                     JS_FreeValue(ctx, v);
  50317                     goto exception;
  50318                 }
  50319                 if (!JS_ToBoolFree(ctx, present)) {
  50320                     JS_SetPropertyInt64(ctx, jsc->property_list, j++, v);
  50321                 } else {
  50322                     JS_FreeValue(ctx, v);
  50323                 }
  50324             }
  50325         }
  50326     }
  50327     space = JS_DupValue(ctx, space0);
  50328     if (JS_IsObject(space)) {
  50329         JSObject *p = JS_VALUE_GET_OBJ(space);
  50330         if (p->class_id == JS_CLASS_NUMBER) {
  50331             space = JS_ToNumberFree(ctx, space);
  50332         } else if (p->class_id == JS_CLASS_STRING) {
  50333             space = JS_ToStringFree(ctx, space);
  50334         }
  50335         if (JS_IsException(space)) {
  50336             JS_FreeValue(ctx, space);
  50337             goto exception;
  50338         }
  50339     }
  50340     if (JS_IsNumber(space)) {
  50341         int n;
  50342         if (JS_ToInt32Clamp(ctx, &n, space, 0, 10, 0))
  50343             goto exception;
  50344         jsc->gap = js_new_string8_len(ctx, "          ", n);
  50345     } else if (JS_IsString(space)) {
  50346         JSString *p = JS_VALUE_GET_STRING(space);
  50347         jsc->gap = js_sub_string(ctx, p, 0, min_int(p->len, 10));
  50348     } else {
  50349         jsc->gap = JS_DupValue(ctx, jsc->empty);
  50350     }
  50351     JS_FreeValue(ctx, space);
  50352     if (JS_IsException(jsc->gap))
  50353         goto exception;
  50354     wrapper = JS_NewObject(ctx);
  50355     if (JS_IsException(wrapper))
  50356         goto exception;
  50357     if (JS_DefinePropertyValue(ctx, wrapper, JS_ATOM_empty_string,
  50358                                JS_DupValue(ctx, obj), JS_PROP_C_W_E) < 0)
  50359         goto exception;
  50360     val = JS_DupValue(ctx, obj);
  50361 
  50362     val = js_json_check(ctx, jsc, wrapper, val, jsc->empty);
  50363     if (JS_IsException(val))
  50364         goto exception;
  50365     if (JS_IsUndefined(val)) {
  50366         ret = JS_UNDEFINED;
  50367         goto done1;
  50368     }
  50369     if (js_json_to_str(ctx, jsc, wrapper, val, jsc->empty))
  50370         goto exception;
  50371 
  50372     ret = string_buffer_end(jsc->b);
  50373     goto done;
  50374 
  50375 exception:
  50376     ret = JS_EXCEPTION;
  50377 done1:
  50378     string_buffer_free(jsc->b);
  50379 done:
  50380     JS_FreeValue(ctx, wrapper);
  50381     JS_FreeValue(ctx, jsc->empty);
  50382     JS_FreeValue(ctx, jsc->gap);
  50383     JS_FreeValue(ctx, jsc->property_list);
  50384     JS_FreeValue(ctx, jsc->stack);
  50385     return ret;
  50386 }
  50387 
  50388 static JSValue js_json_stringify(JSContext *ctx, JSValueConst this_val,
  50389                                  int argc, JSValueConst *argv)
  50390 {
  50391     // stringify(val, replacer, space)
  50392     return JS_JSONStringify(ctx, argv[0], argv[1], argv[2]);
  50393 }
  50394 
  50395 static const JSCFunctionListEntry js_json_funcs[] = {
  50396     JS_CFUNC_DEF("isRawJSON", 1, js_json_isRawJSON ),
  50397     JS_CFUNC_DEF("parse", 2, js_json_parse ),
  50398     JS_CFUNC_DEF("rawJSON", 1, js_json_rawJSON ),
  50399     JS_CFUNC_DEF("stringify", 3, js_json_stringify ),
  50400     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "JSON", JS_PROP_CONFIGURABLE ),
  50401 };
  50402 
  50403 static const JSCFunctionListEntry js_json_obj[] = {
  50404     JS_OBJECT_DEF("JSON", js_json_funcs, countof(js_json_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
  50405 };
  50406 
  50407 int JS_AddIntrinsicJSON(JSContext *ctx)
  50408 {
  50409     /* add JSON as autoinit object */
  50410     return JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_json_obj, countof(js_json_obj));
  50411 }
  50412 
  50413 /* Reflect */
  50414 
  50415 static JSValue js_reflect_apply(JSContext *ctx, JSValueConst this_val,
  50416                                 int argc, JSValueConst *argv)
  50417 {
  50418     return js_function_apply(ctx, argv[0], max_int(0, argc - 1), argv + 1, 2);
  50419 }
  50420 
  50421 static JSValue js_reflect_construct(JSContext *ctx, JSValueConst this_val,
  50422                                     int argc, JSValueConst *argv)
  50423 {
  50424     JSValueConst func, array_arg, new_target;
  50425     JSValue *tab, ret;
  50426     uint32_t len;
  50427 
  50428     func = argv[0];
  50429     array_arg = argv[1];
  50430     if (argc > 2) {
  50431         new_target = argv[2];
  50432         if (!JS_IsConstructor(ctx, new_target))
  50433             return JS_ThrowTypeErrorNotAConstructor(ctx, new_target);
  50434     } else {
  50435         new_target = func;
  50436     }
  50437     tab = build_arg_list(ctx, &len, array_arg);
  50438     if (!tab)
  50439         return JS_EXCEPTION;
  50440     ret = JS_CallConstructor2(ctx, func, new_target, len, (JSValueConst *)tab);
  50441     free_arg_list(ctx, tab, len);
  50442     return ret;
  50443 }
  50444 
  50445 static JSValue js_reflect_deleteProperty(JSContext *ctx, JSValueConst this_val,
  50446                                          int argc, JSValueConst *argv)
  50447 {
  50448     JSValueConst obj;
  50449     JSAtom atom;
  50450     int ret;
  50451 
  50452     obj = argv[0];
  50453     if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
  50454         return JS_ThrowTypeErrorNotAnObject(ctx);
  50455     atom = JS_ValueToAtom(ctx, argv[1]);
  50456     if (unlikely(atom == JS_ATOM_NULL))
  50457         return JS_EXCEPTION;
  50458     ret = JS_DeleteProperty(ctx, obj, atom, 0);
  50459     JS_FreeAtom(ctx, atom);
  50460     if (ret < 0)
  50461         return JS_EXCEPTION;
  50462     else
  50463         return JS_NewBool(ctx, ret);
  50464 }
  50465 
  50466 static JSValue js_reflect_get(JSContext *ctx, JSValueConst this_val,
  50467                               int argc, JSValueConst *argv)
  50468 {
  50469     JSValueConst obj, prop, receiver;
  50470     JSAtom atom;
  50471     JSValue ret;
  50472 
  50473     obj = argv[0];
  50474     prop = argv[1];
  50475     if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
  50476         return JS_ThrowTypeErrorNotAnObject(ctx);
  50477     if (argc > 2)
  50478         receiver = argv[2];
  50479     else
  50480         receiver = obj;
  50481     atom = JS_ValueToAtom(ctx, prop);
  50482     if (unlikely(atom == JS_ATOM_NULL))
  50483         return JS_EXCEPTION;
  50484     ret = JS_GetPropertyInternal(ctx, obj, atom, receiver, FALSE);
  50485     JS_FreeAtom(ctx, atom);
  50486     return ret;
  50487 }
  50488 
  50489 static JSValue js_reflect_has(JSContext *ctx, JSValueConst this_val,
  50490                               int argc, JSValueConst *argv)
  50491 {
  50492     JSValueConst obj, prop;
  50493     JSAtom atom;
  50494     int ret;
  50495 
  50496     obj = argv[0];
  50497     prop = argv[1];
  50498     if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
  50499         return JS_ThrowTypeErrorNotAnObject(ctx);
  50500     atom = JS_ValueToAtom(ctx, prop);
  50501     if (unlikely(atom == JS_ATOM_NULL))
  50502         return JS_EXCEPTION;
  50503     ret = JS_HasProperty(ctx, obj, atom);
  50504     JS_FreeAtom(ctx, atom);
  50505     if (ret < 0)
  50506         return JS_EXCEPTION;
  50507     else
  50508         return JS_NewBool(ctx, ret);
  50509 }
  50510 
  50511 static JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val,
  50512                               int argc, JSValueConst *argv)
  50513 {
  50514     JSValueConst obj, prop, val, receiver;
  50515     int ret;
  50516     JSAtom atom;
  50517 
  50518     obj = argv[0];
  50519     prop = argv[1];
  50520     val = argv[2];
  50521     if (argc > 3)
  50522         receiver = argv[3];
  50523     else
  50524         receiver = obj;
  50525     if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
  50526         return JS_ThrowTypeErrorNotAnObject(ctx);
  50527     atom = JS_ValueToAtom(ctx, prop);
  50528     if (unlikely(atom == JS_ATOM_NULL))
  50529         return JS_EXCEPTION;
  50530     ret = JS_SetPropertyInternal(ctx, obj, atom,
  50531                                  JS_DupValue(ctx, val), receiver, 0);
  50532     JS_FreeAtom(ctx, atom);
  50533     if (ret < 0)
  50534         return JS_EXCEPTION;
  50535     else
  50536         return JS_NewBool(ctx, ret);
  50537 }
  50538 
  50539 static JSValue js_reflect_setPrototypeOf(JSContext *ctx, JSValueConst this_val,
  50540                                          int argc, JSValueConst *argv)
  50541 {
  50542     int ret;
  50543     ret = JS_SetPrototypeInternal(ctx, argv[0], argv[1], FALSE);
  50544     if (ret < 0)
  50545         return JS_EXCEPTION;
  50546     else
  50547         return JS_NewBool(ctx, ret);
  50548 }
  50549 
  50550 static JSValue js_reflect_ownKeys(JSContext *ctx, JSValueConst this_val,
  50551                                   int argc, JSValueConst *argv)
  50552 {
  50553     if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT)
  50554         return JS_ThrowTypeErrorNotAnObject(ctx);
  50555     return JS_GetOwnPropertyNames2(ctx, argv[0],
  50556                                    JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK,
  50557                                    JS_ITERATOR_KIND_KEY);
  50558 }
  50559 
  50560 static const JSCFunctionListEntry js_reflect_funcs[] = {
  50561     JS_CFUNC_DEF("apply", 3, js_reflect_apply ),
  50562     JS_CFUNC_DEF("construct", 2, js_reflect_construct ),
  50563     JS_CFUNC_MAGIC_DEF("defineProperty", 3, js_object_defineProperty, 1 ),
  50564     JS_CFUNC_DEF("deleteProperty", 2, js_reflect_deleteProperty ),
  50565     JS_CFUNC_DEF("get", 2, js_reflect_get ),
  50566     JS_CFUNC_MAGIC_DEF("getOwnPropertyDescriptor", 2, js_object_getOwnPropertyDescriptor, 1 ),
  50567     JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 1 ),
  50568     JS_CFUNC_DEF("has", 2, js_reflect_has ),
  50569     JS_CFUNC_MAGIC_DEF("isExtensible", 1, js_object_isExtensible, 1 ),
  50570     JS_CFUNC_DEF("ownKeys", 1, js_reflect_ownKeys ),
  50571     JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 1 ),
  50572     JS_CFUNC_DEF("set", 3, js_reflect_set ),
  50573     JS_CFUNC_DEF("setPrototypeOf", 2, js_reflect_setPrototypeOf ),
  50574     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Reflect", JS_PROP_CONFIGURABLE ),
  50575 };
  50576 
  50577 static const JSCFunctionListEntry js_reflect_obj[] = {
  50578     JS_OBJECT_DEF("Reflect", js_reflect_funcs, countof(js_reflect_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
  50579 };
  50580 
  50581 /* Proxy */
  50582 
  50583 static void js_proxy_finalizer(JSRuntime *rt, JSValue val)
  50584 {
  50585     JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY);
  50586     if (s) {
  50587         JS_FreeValueRT(rt, s->target);
  50588         JS_FreeValueRT(rt, s->handler);
  50589         js_free_rt(rt, s);
  50590     }
  50591 }
  50592 
  50593 static void js_proxy_mark(JSRuntime *rt, JSValueConst val,
  50594                           JS_MarkFunc *mark_func)
  50595 {
  50596     JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY);
  50597     if (s) {
  50598         JS_MarkValue(rt, s->target, mark_func);
  50599         JS_MarkValue(rt, s->handler, mark_func);
  50600     }
  50601 }
  50602 
  50603 static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx)
  50604 {
  50605     return JS_ThrowTypeError(ctx, "revoked proxy");
  50606 }
  50607 
  50608 static JSProxyData *get_proxy_method(JSContext *ctx, JSValue *pmethod,
  50609                                      JSValueConst obj, JSAtom name)
  50610 {
  50611     JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY);
  50612     JSValue method;
  50613 
  50614     /* safer to test recursion in all proxy methods */
  50615     if (js_check_stack_overflow(ctx->rt, 0)) {
  50616         JS_ThrowStackOverflow(ctx);
  50617         return NULL;
  50618     }
  50619 
  50620     /* 's' should never be NULL */
  50621     if (s->is_revoked) {
  50622         JS_ThrowTypeErrorRevokedProxy(ctx);
  50623         return NULL;
  50624     }
  50625     method = JS_GetProperty(ctx, s->handler, name);
  50626     if (JS_IsException(method))
  50627         return NULL;
  50628     if (JS_IsNull(method))
  50629         method = JS_UNDEFINED;
  50630     *pmethod = method;
  50631     return s;
  50632 }
  50633 
  50634 static JSValue js_proxy_get_prototype(JSContext *ctx, JSValueConst obj)
  50635 {
  50636     JSProxyData *s;
  50637     JSValue method, ret, proto1;
  50638     int res;
  50639 
  50640     s = get_proxy_method(ctx, &method, obj, JS_ATOM_getPrototypeOf);
  50641     if (!s)
  50642         return JS_EXCEPTION;
  50643     if (JS_IsUndefined(method))
  50644         return JS_GetPrototype(ctx, s->target);
  50645     ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
  50646     if (JS_IsException(ret))
  50647         return ret;
  50648     if (JS_VALUE_GET_TAG(ret) != JS_TAG_NULL &&
  50649         JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
  50650         goto fail;
  50651     }
  50652     res = JS_IsExtensible(ctx, s->target);
  50653     if (res < 0) {
  50654         JS_FreeValue(ctx, ret);
  50655         return JS_EXCEPTION;
  50656     }
  50657     if (!res) {
  50658         /* check invariant */
  50659         proto1 = JS_GetPrototype(ctx, s->target);
  50660         if (JS_IsException(proto1)) {
  50661             JS_FreeValue(ctx, ret);
  50662             return JS_EXCEPTION;
  50663         }
  50664         if (!js_same_value(ctx, proto1, ret)) {
  50665             JS_FreeValue(ctx, proto1);
  50666         fail:
  50667             JS_FreeValue(ctx, ret);
  50668             return JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
  50669         }
  50670         JS_FreeValue(ctx, proto1);
  50671     }
  50672     return ret;
  50673 }
  50674 
  50675 static int js_proxy_set_prototype(JSContext *ctx, JSValueConst obj,
  50676                                   JSValueConst proto_val)
  50677 {
  50678     JSProxyData *s;
  50679     JSValue method, ret, proto1;
  50680     JSValueConst args[2];
  50681     BOOL res;
  50682     int res2;
  50683 
  50684     s = get_proxy_method(ctx, &method, obj, JS_ATOM_setPrototypeOf);
  50685     if (!s)
  50686         return -1;
  50687     if (JS_IsUndefined(method))
  50688         return JS_SetPrototypeInternal(ctx, s->target, proto_val, FALSE);
  50689     args[0] = s->target;
  50690     args[1] = proto_val;
  50691     ret = JS_CallFree(ctx, method, s->handler, 2, args);
  50692     if (JS_IsException(ret))
  50693         return -1;
  50694     res = JS_ToBoolFree(ctx, ret);
  50695     if (!res)
  50696         return FALSE;
  50697     res2 = JS_IsExtensible(ctx, s->target);
  50698     if (res2 < 0)
  50699         return -1;
  50700     if (!res2) {
  50701         proto1 = JS_GetPrototype(ctx, s->target);
  50702         if (JS_IsException(proto1))
  50703             return -1;
  50704         if (!js_same_value(ctx, proto_val, proto1)) {
  50705             JS_FreeValue(ctx, proto1);
  50706             JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
  50707             return -1;
  50708         }
  50709         JS_FreeValue(ctx, proto1);
  50710     }
  50711     return TRUE;
  50712 }
  50713 
  50714 static int js_proxy_is_extensible(JSContext *ctx, JSValueConst obj)
  50715 {
  50716     JSProxyData *s;
  50717     JSValue method, ret;
  50718     BOOL res;
  50719     int res2;
  50720 
  50721     s = get_proxy_method(ctx, &method, obj, JS_ATOM_isExtensible);
  50722     if (!s)
  50723         return -1;
  50724     if (JS_IsUndefined(method))
  50725         return JS_IsExtensible(ctx, s->target);
  50726     ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
  50727     if (JS_IsException(ret))
  50728         return -1;
  50729     res = JS_ToBoolFree(ctx, ret);
  50730     res2 = JS_IsExtensible(ctx, s->target);
  50731     if (res2 < 0)
  50732         return res2;
  50733     if (res != res2) {
  50734         JS_ThrowTypeError(ctx, "proxy: inconsistent isExtensible");
  50735         return -1;
  50736     }
  50737     return res;
  50738 }
  50739 
  50740 static int js_proxy_prevent_extensions(JSContext *ctx, JSValueConst obj)
  50741 {
  50742     JSProxyData *s;
  50743     JSValue method, ret;
  50744     BOOL res;
  50745     int res2;
  50746 
  50747     s = get_proxy_method(ctx, &method, obj, JS_ATOM_preventExtensions);
  50748     if (!s)
  50749         return -1;
  50750     if (JS_IsUndefined(method))
  50751         return JS_PreventExtensions(ctx, s->target);
  50752     ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
  50753     if (JS_IsException(ret))
  50754         return -1;
  50755     res = JS_ToBoolFree(ctx, ret);
  50756     if (res) {
  50757         res2 = JS_IsExtensible(ctx, s->target);
  50758         if (res2 < 0)
  50759             return res2;
  50760         if (res2) {
  50761             JS_ThrowTypeError(ctx, "proxy: inconsistent preventExtensions");
  50762             return -1;
  50763         }
  50764     }
  50765     return res;
  50766 }
  50767 
  50768 static int js_proxy_has(JSContext *ctx, JSValueConst obj, JSAtom atom)
  50769 {
  50770     JSProxyData *s;
  50771     JSValue method, ret1, atom_val;
  50772     int ret, res;
  50773     JSObject *p;
  50774     JSValueConst args[2];
  50775     BOOL res2;
  50776 
  50777     s = get_proxy_method(ctx, &method, obj, JS_ATOM_has);
  50778     if (!s)
  50779         return -1;
  50780     if (JS_IsUndefined(method))
  50781         return JS_HasProperty(ctx, s->target, atom);
  50782     atom_val = JS_AtomToValue(ctx, atom);
  50783     if (JS_IsException(atom_val)) {
  50784         JS_FreeValue(ctx, method);
  50785         return -1;
  50786     }
  50787     args[0] = s->target;
  50788     args[1] = atom_val;
  50789     ret1 = JS_CallFree(ctx, method, s->handler, 2, args);
  50790     JS_FreeValue(ctx, atom_val);
  50791     if (JS_IsException(ret1))
  50792         return -1;
  50793     ret = JS_ToBoolFree(ctx, ret1);
  50794     if (!ret) {
  50795         JSPropertyDescriptor desc;
  50796         p = JS_VALUE_GET_OBJ(s->target);
  50797         res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
  50798         if (res < 0)
  50799             return -1;
  50800         if (res) {
  50801             res2 = !(desc.flags & JS_PROP_CONFIGURABLE);
  50802             js_free_desc(ctx, &desc);
  50803             if (res2 || !p->extensible) {
  50804                 JS_ThrowTypeError(ctx, "proxy: inconsistent has");
  50805                 return -1;
  50806             }
  50807         }
  50808     }
  50809     return ret;
  50810 }
  50811 
  50812 static JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom,
  50813                             JSValueConst receiver)
  50814 {
  50815     JSProxyData *s;
  50816     JSValue method, ret, atom_val;
  50817     int res;
  50818     JSValueConst args[3];
  50819     JSPropertyDescriptor desc;
  50820 
  50821     s = get_proxy_method(ctx, &method, obj, JS_ATOM_get);
  50822     if (!s)
  50823         return JS_EXCEPTION;
  50824     /* Note: recursion is possible thru the prototype of s->target */
  50825     if (JS_IsUndefined(method))
  50826         return JS_GetPropertyInternal(ctx, s->target, atom, receiver, FALSE);
  50827     atom_val = JS_AtomToValue(ctx, atom);
  50828     if (JS_IsException(atom_val)) {
  50829         JS_FreeValue(ctx, method);
  50830         return JS_EXCEPTION;
  50831     }
  50832     args[0] = s->target;
  50833     args[1] = atom_val;
  50834     args[2] = receiver;
  50835     ret = JS_CallFree(ctx, method, s->handler, 3, args);
  50836     JS_FreeValue(ctx, atom_val);
  50837     if (JS_IsException(ret))
  50838         return JS_EXCEPTION;
  50839     res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
  50840     if (res < 0) {
  50841         JS_FreeValue(ctx, ret);
  50842         return JS_EXCEPTION;
  50843     }
  50844     if (res) {
  50845         if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {
  50846             if (!js_same_value(ctx, desc.value, ret)) {
  50847                 goto fail;
  50848             }
  50849         } else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET) {
  50850             if (JS_IsUndefined(desc.getter) && !JS_IsUndefined(ret)) {
  50851             fail:
  50852                 js_free_desc(ctx, &desc);
  50853                 JS_FreeValue(ctx, ret);
  50854                 return JS_ThrowTypeError(ctx, "proxy: inconsistent get");
  50855             }
  50856         }
  50857         js_free_desc(ctx, &desc);
  50858     }
  50859     return ret;
  50860 }
  50861 
  50862 static int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom,
  50863                         JSValueConst value, JSValueConst receiver, int flags)
  50864 {
  50865     JSProxyData *s;
  50866     JSValue method, ret1, atom_val;
  50867     int ret, res;
  50868     JSValueConst args[4];
  50869 
  50870     s = get_proxy_method(ctx, &method, obj, JS_ATOM_set);
  50871     if (!s)
  50872         return -1;
  50873     if (JS_IsUndefined(method)) {
  50874         return JS_SetPropertyInternal(ctx, s->target, atom,
  50875                                       JS_DupValue(ctx, value), receiver,
  50876                                       flags);
  50877     }
  50878     atom_val = JS_AtomToValue(ctx, atom);
  50879     if (JS_IsException(atom_val)) {
  50880         JS_FreeValue(ctx, method);
  50881         return -1;
  50882     }
  50883     args[0] = s->target;
  50884     args[1] = atom_val;
  50885     args[2] = value;
  50886     args[3] = receiver;
  50887     ret1 = JS_CallFree(ctx, method, s->handler, 4, args);
  50888     JS_FreeValue(ctx, atom_val);
  50889     if (JS_IsException(ret1))
  50890         return -1;
  50891     ret = JS_ToBoolFree(ctx, ret1);
  50892     if (ret) {
  50893         JSPropertyDescriptor desc;
  50894         res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
  50895         if (res < 0)
  50896             return -1;
  50897         if (res) {
  50898             if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {
  50899                 if (!js_same_value(ctx, desc.value, value)) {
  50900                     goto fail;
  50901                 }
  50902             } else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET && JS_IsUndefined(desc.setter)) {
  50903                 fail:
  50904                     js_free_desc(ctx, &desc);
  50905                     JS_ThrowTypeError(ctx, "proxy: inconsistent set");
  50906                     return -1;
  50907             }
  50908             js_free_desc(ctx, &desc);
  50909         }
  50910     } else {
  50911         if ((flags & JS_PROP_THROW) ||
  50912             ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
  50913             JS_ThrowTypeError(ctx, "proxy: cannot set property");
  50914             return -1;
  50915         }
  50916     }
  50917     return ret;
  50918 }
  50919 
  50920 static JSValue js_create_desc(JSContext *ctx, JSValueConst val,
  50921                               JSValueConst getter, JSValueConst setter,
  50922                               int flags)
  50923 {
  50924     JSValue ret;
  50925     ret = JS_NewObject(ctx);
  50926     if (JS_IsException(ret))
  50927         return ret;
  50928     if (flags & JS_PROP_HAS_GET) {
  50929         JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, getter),
  50930                                JS_PROP_C_W_E);
  50931     }
  50932     if (flags & JS_PROP_HAS_SET) {
  50933         JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, setter),
  50934                                JS_PROP_C_W_E);
  50935     }
  50936     if (flags & JS_PROP_HAS_VALUE) {
  50937         JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, val),
  50938                                JS_PROP_C_W_E);
  50939     }
  50940     if (flags & JS_PROP_HAS_WRITABLE) {
  50941         JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,
  50942                                JS_NewBool(ctx, flags & JS_PROP_WRITABLE),
  50943                                JS_PROP_C_W_E);
  50944     }
  50945     if (flags & JS_PROP_HAS_ENUMERABLE) {
  50946         JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,
  50947                                JS_NewBool(ctx, flags & JS_PROP_ENUMERABLE),
  50948                                JS_PROP_C_W_E);
  50949     }
  50950     if (flags & JS_PROP_HAS_CONFIGURABLE) {
  50951         JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
  50952                                JS_NewBool(ctx, flags & JS_PROP_CONFIGURABLE),
  50953                                JS_PROP_C_W_E);
  50954     }
  50955     return ret;
  50956 }
  50957 
  50958 static int js_proxy_get_own_property(JSContext *ctx, JSPropertyDescriptor *pdesc,
  50959                                      JSValueConst obj, JSAtom prop)
  50960 {
  50961     JSProxyData *s;
  50962     JSValue method, trap_result_obj, prop_val;
  50963     int res, target_desc_ret, ret;
  50964     JSObject *p;
  50965     JSValueConst args[2];
  50966     JSPropertyDescriptor result_desc, target_desc;
  50967 
  50968     s = get_proxy_method(ctx, &method, obj, JS_ATOM_getOwnPropertyDescriptor);
  50969     if (!s)
  50970         return -1;
  50971     p = JS_VALUE_GET_OBJ(s->target);
  50972     if (JS_IsUndefined(method)) {
  50973         return JS_GetOwnPropertyInternal(ctx, pdesc, p, prop);
  50974     }
  50975     prop_val = JS_AtomToValue(ctx, prop);
  50976     if (JS_IsException(prop_val)) {
  50977         JS_FreeValue(ctx, method);
  50978         return -1;
  50979     }
  50980     args[0] = s->target;
  50981     args[1] = prop_val;
  50982     trap_result_obj = JS_CallFree(ctx, method, s->handler, 2, args);
  50983     JS_FreeValue(ctx, prop_val);
  50984     if (JS_IsException(trap_result_obj))
  50985         return -1;
  50986     if (!JS_IsObject(trap_result_obj) && !JS_IsUndefined(trap_result_obj)) {
  50987         JS_FreeValue(ctx, trap_result_obj);
  50988         goto fail;
  50989     }
  50990     target_desc_ret = JS_GetOwnPropertyInternal(ctx, &target_desc, p, prop);
  50991     if (target_desc_ret < 0) {
  50992         JS_FreeValue(ctx, trap_result_obj);
  50993         return -1;
  50994     }
  50995     if (target_desc_ret)
  50996         js_free_desc(ctx, &target_desc);
  50997     if (JS_IsUndefined(trap_result_obj)) {
  50998         if (target_desc_ret) {
  50999             if (!(target_desc.flags & JS_PROP_CONFIGURABLE) || !p->extensible)
  51000                 goto fail;
  51001         }
  51002         ret = FALSE;
  51003     } else {
  51004         int flags1, extensible_target;
  51005         extensible_target = JS_IsExtensible(ctx, s->target);
  51006         if (extensible_target < 0) {
  51007             JS_FreeValue(ctx, trap_result_obj);
  51008             return -1;
  51009         }
  51010         res = js_obj_to_desc(ctx, &result_desc, trap_result_obj);
  51011         JS_FreeValue(ctx, trap_result_obj);
  51012         if (res < 0)
  51013             return -1;
  51014 
  51015         /* convert the result_desc.flags to property flags */
  51016         if (result_desc.flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
  51017             result_desc.flags |= JS_PROP_GETSET;
  51018         } else {
  51019             result_desc.flags |= JS_PROP_NORMAL;
  51020         }
  51021         result_desc.flags &= (JS_PROP_C_W_E | JS_PROP_TMASK);
  51022         
  51023         if (target_desc_ret) {
  51024             /* convert result_desc.flags to defineProperty flags */
  51025             flags1 = result_desc.flags | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE;
  51026             if (result_desc.flags & JS_PROP_GETSET)
  51027                 flags1 |= JS_PROP_HAS_GET | JS_PROP_HAS_SET;
  51028             else
  51029                 flags1 |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE;
  51030             /* XXX: not complete check: need to compare value &
  51031                getter/setter as in defineproperty */
  51032             if (!check_define_prop_flags(target_desc.flags, flags1))
  51033                 goto fail1;
  51034         } else {
  51035             if (!extensible_target)
  51036                 goto fail1;
  51037         }
  51038         if (!(result_desc.flags & JS_PROP_CONFIGURABLE)) {
  51039             if (!target_desc_ret || (target_desc.flags & JS_PROP_CONFIGURABLE))
  51040                 goto fail1;
  51041             if ((result_desc.flags &
  51042                  (JS_PROP_GETSET | JS_PROP_WRITABLE)) == 0 &&
  51043                 target_desc_ret &&
  51044                 (target_desc.flags & JS_PROP_WRITABLE) != 0) {
  51045                 /* proxy-missing-checks */
  51046             fail1:
  51047                 js_free_desc(ctx, &result_desc);
  51048             fail:
  51049                 JS_ThrowTypeError(ctx, "proxy: inconsistent getOwnPropertyDescriptor");
  51050                 return -1;
  51051             }
  51052         }
  51053         ret = TRUE;
  51054         if (pdesc) {
  51055             *pdesc = result_desc;
  51056         } else {
  51057             js_free_desc(ctx, &result_desc);
  51058         }
  51059     }
  51060     return ret;
  51061 }
  51062 
  51063 static int js_proxy_define_own_property(JSContext *ctx, JSValueConst obj,
  51064                                         JSAtom prop, JSValueConst val,
  51065                                         JSValueConst getter, JSValueConst setter,
  51066                                         int flags)
  51067 {
  51068     JSProxyData *s;
  51069     JSValue method, ret1, prop_val, desc_val;
  51070     int res, ret;
  51071     JSObject *p;
  51072     JSValueConst args[3];
  51073     JSPropertyDescriptor desc;
  51074     BOOL setting_not_configurable;
  51075 
  51076     s = get_proxy_method(ctx, &method, obj, JS_ATOM_defineProperty);
  51077     if (!s)
  51078         return -1;
  51079     if (JS_IsUndefined(method)) {
  51080         return JS_DefineProperty(ctx, s->target, prop, val, getter, setter, flags);
  51081     }
  51082     prop_val = JS_AtomToValue(ctx, prop);
  51083     if (JS_IsException(prop_val)) {
  51084         JS_FreeValue(ctx, method);
  51085         return -1;
  51086     }
  51087     desc_val = js_create_desc(ctx, val, getter, setter, flags);
  51088     if (JS_IsException(desc_val)) {
  51089         JS_FreeValue(ctx, prop_val);
  51090         JS_FreeValue(ctx, method);
  51091         return -1;
  51092     }
  51093     args[0] = s->target;
  51094     args[1] = prop_val;
  51095     args[2] = desc_val;
  51096     ret1 = JS_CallFree(ctx, method, s->handler, 3, args);
  51097     JS_FreeValue(ctx, prop_val);
  51098     JS_FreeValue(ctx, desc_val);
  51099     if (JS_IsException(ret1))
  51100         return -1;
  51101     ret = JS_ToBoolFree(ctx, ret1);
  51102     if (!ret) {
  51103         if (flags & JS_PROP_THROW) {
  51104             JS_ThrowTypeError(ctx, "proxy: defineProperty exception");
  51105             return -1;
  51106         } else {
  51107             return 0;
  51108         }
  51109     }
  51110     p = JS_VALUE_GET_OBJ(s->target);
  51111     res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
  51112     if (res < 0)
  51113         return -1;
  51114     setting_not_configurable = ((flags & (JS_PROP_HAS_CONFIGURABLE |
  51115                                           JS_PROP_CONFIGURABLE)) ==
  51116                                 JS_PROP_HAS_CONFIGURABLE);
  51117     if (!res) {
  51118         if (!p->extensible || setting_not_configurable)
  51119             goto fail;
  51120     } else {
  51121         if (!check_define_prop_flags(desc.flags, flags))
  51122             goto fail1;
  51123         /* do the missing check from check_define_prop_flags() */
  51124         if (!(desc.flags & JS_PROP_CONFIGURABLE)) {
  51125             if ((desc.flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
  51126                 if ((flags & JS_PROP_HAS_GET) &&
  51127                     !js_same_value(ctx, getter, desc.getter)) {
  51128                     goto fail1;
  51129                 }
  51130                 if ((flags & JS_PROP_HAS_SET) &&
  51131                     !js_same_value(ctx, setter, desc.setter)) {
  51132                     goto fail1;
  51133                 }
  51134             } else if (!(desc.flags & JS_PROP_WRITABLE)) {
  51135                 if ((flags & JS_PROP_HAS_VALUE) &&
  51136                     !js_same_value(ctx, val, desc.value)) {
  51137                     goto fail1;
  51138                 }
  51139             }
  51140         }
  51141 
  51142         /* additional checks */
  51143         if ((desc.flags & JS_PROP_CONFIGURABLE) && setting_not_configurable)
  51144             goto fail1;
  51145 
  51146         if ((desc.flags & JS_PROP_TMASK) != JS_PROP_GETSET &&
  51147             (desc.flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == JS_PROP_WRITABLE &&
  51148             (flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) {
  51149         fail1:
  51150             js_free_desc(ctx, &desc);
  51151         fail:
  51152             JS_ThrowTypeError(ctx, "proxy: inconsistent defineProperty");
  51153             return -1;
  51154         }
  51155         js_free_desc(ctx, &desc);
  51156     }
  51157     return 1;
  51158 }
  51159 
  51160 static int js_proxy_delete_property(JSContext *ctx, JSValueConst obj,
  51161                                     JSAtom atom)
  51162 {
  51163     JSProxyData *s;
  51164     JSValue method, ret, atom_val;
  51165     int res, res2, is_extensible;
  51166     JSValueConst args[2];
  51167 
  51168     s = get_proxy_method(ctx, &method, obj, JS_ATOM_deleteProperty);
  51169     if (!s)
  51170         return -1;
  51171     if (JS_IsUndefined(method)) {
  51172         return JS_DeleteProperty(ctx, s->target, atom, 0);
  51173     }
  51174     atom_val = JS_AtomToValue(ctx, atom);;
  51175     if (JS_IsException(atom_val)) {
  51176         JS_FreeValue(ctx, method);
  51177         return -1;
  51178     }
  51179     args[0] = s->target;
  51180     args[1] = atom_val;
  51181     ret = JS_CallFree(ctx, method, s->handler, 2, args);
  51182     JS_FreeValue(ctx, atom_val);
  51183     if (JS_IsException(ret))
  51184         return -1;
  51185     res = JS_ToBoolFree(ctx, ret);
  51186     if (res) {
  51187         JSPropertyDescriptor desc;
  51188         res2 = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
  51189         if (res2 < 0)
  51190             return -1;
  51191         if (res2) {
  51192             if (!(desc.flags & JS_PROP_CONFIGURABLE))
  51193                 goto fail;
  51194             is_extensible = JS_IsExtensible(ctx, s->target);
  51195             if (is_extensible < 0)
  51196                 goto fail1;
  51197             if (!is_extensible) {
  51198                 /* proxy-missing-checks */
  51199             fail:
  51200                 JS_ThrowTypeError(ctx, "proxy: inconsistent deleteProperty");
  51201             fail1:
  51202                 js_free_desc(ctx, &desc);
  51203                 return -1;
  51204             }
  51205             js_free_desc(ctx, &desc);
  51206         }
  51207     }
  51208     return res;
  51209 }
  51210 
  51211 /* return the index of the property or -1 if not found */
  51212 static int find_prop_key(const JSPropertyEnum *tab, int n, JSAtom atom)
  51213 {
  51214     int i;
  51215     for(i = 0; i < n; i++) {
  51216         if (tab[i].atom == atom)
  51217             return i;
  51218     }
  51219     return -1;
  51220 }
  51221 
  51222 static int js_proxy_get_own_property_names(JSContext *ctx,
  51223                                            JSPropertyEnum **ptab,
  51224                                            uint32_t *plen,
  51225                                            JSValueConst obj)
  51226 {
  51227     JSProxyData *s;
  51228     JSValue method, prop_array, val;
  51229     uint32_t len, i, len2;
  51230     JSPropertyEnum *tab, *tab2;
  51231     JSAtom atom;
  51232     JSPropertyDescriptor desc;
  51233     int res, is_extensible, idx;
  51234 
  51235     s = get_proxy_method(ctx, &method, obj, JS_ATOM_ownKeys);
  51236     if (!s)
  51237         return -1;
  51238     if (JS_IsUndefined(method)) {
  51239         return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen,
  51240                                       JS_VALUE_GET_OBJ(s->target),
  51241                                       JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK);
  51242     }
  51243     prop_array = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
  51244     if (JS_IsException(prop_array))
  51245         return -1;
  51246     tab = NULL;
  51247     len = 0;
  51248     tab2 = NULL;
  51249     len2 = 0;
  51250     if (js_get_length32(ctx, &len, prop_array))
  51251         goto fail;
  51252     if (len > 0) {
  51253         tab = js_mallocz(ctx, sizeof(tab[0]) * len);
  51254         if (!tab)
  51255             goto fail;
  51256     }
  51257     for(i = 0; i < len; i++) {
  51258         val = JS_GetPropertyUint32(ctx, prop_array, i);
  51259         if (JS_IsException(val))
  51260             goto fail;
  51261         if (!JS_IsString(val) && !JS_IsSymbol(val)) {
  51262             JS_FreeValue(ctx, val);
  51263             JS_ThrowTypeError(ctx, "proxy: properties must be strings or symbols");
  51264             goto fail;
  51265         }
  51266         atom = JS_ValueToAtom(ctx, val);
  51267         JS_FreeValue(ctx, val);
  51268         if (atom == JS_ATOM_NULL)
  51269             goto fail;
  51270         tab[i].atom = atom;
  51271         tab[i].is_enumerable = FALSE; /* XXX: redundant? */
  51272     }
  51273 
  51274     /* check duplicate properties (XXX: inefficient, could store the
  51275      * properties an a temporary object to use the hash) */
  51276     for(i = 1; i < len; i++) {
  51277         if (find_prop_key(tab, i, tab[i].atom) >= 0) {
  51278             JS_ThrowTypeError(ctx, "proxy: duplicate property");
  51279             goto fail;
  51280         }
  51281     }
  51282 
  51283     is_extensible = JS_IsExtensible(ctx, s->target);
  51284     if (is_extensible < 0)
  51285         goto fail;
  51286 
  51287     /* check if there are non configurable properties */
  51288     if (s->is_revoked) {
  51289         JS_ThrowTypeErrorRevokedProxy(ctx);
  51290         goto fail;
  51291     }
  51292     if (JS_GetOwnPropertyNamesInternal(ctx, &tab2, &len2, JS_VALUE_GET_OBJ(s->target),
  51293                                JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK))
  51294         goto fail;
  51295     for(i = 0; i < len2; i++) {
  51296         if (s->is_revoked) {
  51297             JS_ThrowTypeErrorRevokedProxy(ctx);
  51298             goto fail;
  51299         }
  51300         res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target),
  51301                                 tab2[i].atom);
  51302         if (res < 0)
  51303             goto fail;
  51304         if (res) {  /* safety, property should be found */
  51305             js_free_desc(ctx, &desc);
  51306             if (!(desc.flags & JS_PROP_CONFIGURABLE) || !is_extensible) {
  51307                 idx = find_prop_key(tab, len, tab2[i].atom);
  51308                 if (idx < 0) {
  51309                     JS_ThrowTypeError(ctx, "proxy: target property must be present in proxy ownKeys");
  51310                     goto fail;
  51311                 }
  51312                 /* mark the property as found */
  51313                 if (!is_extensible)
  51314                     tab[idx].is_enumerable = TRUE;
  51315             }
  51316         }
  51317     }
  51318     if (!is_extensible) {
  51319         /* check that all property in 'tab' were checked */
  51320         for(i = 0; i < len; i++) {
  51321             if (!tab[i].is_enumerable) {
  51322                 JS_ThrowTypeError(ctx, "proxy: property not present in target were returned by non extensible proxy");
  51323                 goto fail;
  51324             }
  51325         }
  51326     }
  51327 
  51328     JS_FreePropertyEnum(ctx, tab2, len2);
  51329     JS_FreeValue(ctx, prop_array);
  51330     *ptab = tab;
  51331     *plen = len;
  51332     return 0;
  51333  fail:
  51334     JS_FreePropertyEnum(ctx, tab2, len2);
  51335     JS_FreePropertyEnum(ctx, tab, len);
  51336     JS_FreeValue(ctx, prop_array);
  51337     return -1;
  51338 }
  51339 
  51340 static JSValue js_proxy_call_constructor(JSContext *ctx, JSValueConst func_obj,
  51341                                          JSValueConst new_target,
  51342                                          int argc, JSValueConst *argv)
  51343 {
  51344     JSProxyData *s;
  51345     JSValue method, arg_array, ret;
  51346     JSValueConst args[3];
  51347 
  51348     s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_construct);
  51349     if (!s)
  51350         return JS_EXCEPTION;
  51351     if (!JS_IsConstructor(ctx, s->target))
  51352         return JS_ThrowTypeErrorNotAConstructor(ctx, s->target);
  51353     if (JS_IsUndefined(method))
  51354         return JS_CallConstructor2(ctx, s->target, new_target, argc, argv);
  51355     arg_array = js_create_array(ctx, argc, argv);
  51356     if (JS_IsException(arg_array)) {
  51357         ret = JS_EXCEPTION;
  51358         goto fail;
  51359     }
  51360     args[0] = s->target;
  51361     args[1] = arg_array;
  51362     args[2] = new_target;
  51363     ret = JS_Call(ctx, method, s->handler, 3, args);
  51364     if (!JS_IsException(ret) && JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
  51365         JS_FreeValue(ctx, ret);
  51366         ret = JS_ThrowTypeErrorNotAnObject(ctx);
  51367     }
  51368  fail:
  51369     JS_FreeValue(ctx, method);
  51370     JS_FreeValue(ctx, arg_array);
  51371     return ret;
  51372 }
  51373 
  51374 static JSValue js_proxy_call(JSContext *ctx, JSValueConst func_obj,
  51375                              JSValueConst this_obj,
  51376                              int argc, JSValueConst *argv, int flags)
  51377 {
  51378     JSProxyData *s;
  51379     JSValue method, arg_array, ret;
  51380     JSValueConst args[3];
  51381 
  51382     if (flags & JS_CALL_FLAG_CONSTRUCTOR)
  51383         return js_proxy_call_constructor(ctx, func_obj, this_obj, argc, argv);
  51384 
  51385     s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_apply);
  51386     if (!s)
  51387         return JS_EXCEPTION;
  51388     if (!s->is_func) {
  51389         JS_FreeValue(ctx, method);
  51390         return JS_ThrowTypeError(ctx, "not a function");
  51391     }
  51392     if (JS_IsUndefined(method))
  51393         return JS_Call(ctx, s->target, this_obj, argc, argv);
  51394     arg_array = js_create_array(ctx, argc, argv);
  51395     if (JS_IsException(arg_array)) {
  51396         ret = JS_EXCEPTION;
  51397         goto fail;
  51398     }
  51399     args[0] = s->target;
  51400     args[1] = this_obj;
  51401     args[2] = arg_array;
  51402     ret = JS_Call(ctx, method, s->handler, 3, args);
  51403  fail:
  51404     JS_FreeValue(ctx, method);
  51405     JS_FreeValue(ctx, arg_array);
  51406     return ret;
  51407 }
  51408 
  51409 /* `js_resolve_proxy`: resolve the proxy chain
  51410    `*pval` is updated with to ultimate proxy target
  51411    `throw_exception` controls whether exceptions are thown or not
  51412    - return -1 in case of error
  51413    - otherwise return 0
  51414  */
  51415 static int js_resolve_proxy(JSContext *ctx, JSValueConst *pval, BOOL throw_exception) {
  51416     int depth = 0;
  51417     JSObject *p;
  51418     JSProxyData *s;
  51419 
  51420     while (JS_VALUE_GET_TAG(*pval) == JS_TAG_OBJECT) {
  51421         p = JS_VALUE_GET_OBJ(*pval);
  51422         if (p->class_id != JS_CLASS_PROXY)
  51423             break;
  51424         if (depth++ > 1000) {
  51425             if (throw_exception)
  51426                 JS_ThrowStackOverflow(ctx);
  51427             return -1;
  51428         }
  51429         s = p->u.opaque;
  51430         if (s->is_revoked) {
  51431             if (throw_exception)
  51432                 JS_ThrowTypeErrorRevokedProxy(ctx);
  51433             return -1;
  51434         }
  51435         *pval = s->target;
  51436     }
  51437     return 0;
  51438 }
  51439 
  51440 static const JSClassExoticMethods js_proxy_exotic_methods = {
  51441     .get_own_property = js_proxy_get_own_property,
  51442     .define_own_property = js_proxy_define_own_property,
  51443     .delete_property = js_proxy_delete_property,
  51444     .get_own_property_names = js_proxy_get_own_property_names,
  51445     .has_property = js_proxy_has,
  51446     .get_property = js_proxy_get,
  51447     .set_property = js_proxy_set,
  51448     .get_prototype = js_proxy_get_prototype,
  51449     .set_prototype = js_proxy_set_prototype,
  51450     .is_extensible = js_proxy_is_extensible,
  51451     .prevent_extensions = js_proxy_prevent_extensions,
  51452 };
  51453 
  51454 static JSValue js_proxy_constructor(JSContext *ctx, JSValueConst this_val,
  51455                                     int argc, JSValueConst *argv)
  51456 {
  51457     JSValueConst target, handler;
  51458     JSValue obj;
  51459     JSProxyData *s;
  51460 
  51461     target = argv[0];
  51462     handler = argv[1];
  51463     if (JS_VALUE_GET_TAG(target) != JS_TAG_OBJECT ||
  51464         JS_VALUE_GET_TAG(handler) != JS_TAG_OBJECT)
  51465         return JS_ThrowTypeErrorNotAnObject(ctx);
  51466 
  51467     obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_PROXY);
  51468     if (JS_IsException(obj))
  51469         return obj;
  51470     s = js_malloc(ctx, sizeof(JSProxyData));
  51471     if (!s) {
  51472         JS_FreeValue(ctx, obj);
  51473         return JS_EXCEPTION;
  51474     }
  51475     s->target = JS_DupValue(ctx, target);
  51476     s->handler = JS_DupValue(ctx, handler);
  51477     s->is_func = JS_IsFunction(ctx, target);
  51478     s->is_revoked = FALSE;
  51479     JS_SetOpaque(obj, s);
  51480     JS_SetConstructorBit(ctx, obj, JS_IsConstructor(ctx, target));
  51481     return obj;
  51482 }
  51483 
  51484 static JSValue js_proxy_revoke(JSContext *ctx, JSValueConst this_val,
  51485                                int argc, JSValueConst *argv, int magic,
  51486                                JSValue *func_data)
  51487 {
  51488     JSProxyData *s = JS_GetOpaque(func_data[0], JS_CLASS_PROXY);
  51489     if (s) {
  51490         /* We do not free the handler and target in case they are
  51491            referenced as constants in the C call stack */
  51492         s->is_revoked = TRUE;
  51493         JS_FreeValue(ctx, func_data[0]);
  51494         func_data[0] = JS_NULL;
  51495     }
  51496     return JS_UNDEFINED;
  51497 }
  51498 
  51499 static JSValue js_proxy_revoke_constructor(JSContext *ctx,
  51500                                            JSValueConst proxy_obj)
  51501 {
  51502     return JS_NewCFunctionData(ctx, js_proxy_revoke, 0, 0, 1, &proxy_obj);
  51503 }
  51504 
  51505 static JSValue js_proxy_revocable(JSContext *ctx, JSValueConst this_val,
  51506                                  int argc, JSValueConst *argv)
  51507 {
  51508     JSValue proxy_obj, revoke_obj = JS_UNDEFINED, obj;
  51509 
  51510     proxy_obj = js_proxy_constructor(ctx, JS_UNDEFINED, argc, argv);
  51511     if (JS_IsException(proxy_obj))
  51512         goto fail;
  51513     revoke_obj = js_proxy_revoke_constructor(ctx, proxy_obj);
  51514     if (JS_IsException(revoke_obj))
  51515         goto fail;
  51516     obj = JS_NewObject(ctx);
  51517     if (JS_IsException(obj))
  51518         goto fail;
  51519     // XXX: exceptions?
  51520     JS_DefinePropertyValue(ctx, obj, JS_ATOM_proxy, proxy_obj, JS_PROP_C_W_E);
  51521     JS_DefinePropertyValue(ctx, obj, JS_ATOM_revoke, revoke_obj, JS_PROP_C_W_E);
  51522     return obj;
  51523  fail:
  51524     JS_FreeValue(ctx, proxy_obj);
  51525     JS_FreeValue(ctx, revoke_obj);
  51526     return JS_EXCEPTION;
  51527 }
  51528 
  51529 static const JSCFunctionListEntry js_proxy_funcs[] = {
  51530     JS_CFUNC_DEF("revocable", 2, js_proxy_revocable ),
  51531 };
  51532 
  51533 static const JSClassShortDef js_proxy_class_def[] = {
  51534     { JS_ATOM_Object, js_proxy_finalizer, js_proxy_mark }, /* JS_CLASS_PROXY */
  51535 };
  51536 
  51537 int JS_AddIntrinsicProxy(JSContext *ctx)
  51538 {
  51539     JSRuntime *rt = ctx->rt;
  51540     JSValue obj1;
  51541 
  51542     if (!JS_IsRegisteredClass(rt, JS_CLASS_PROXY)) {
  51543         if (init_class_range(rt, js_proxy_class_def, JS_CLASS_PROXY,
  51544                              countof(js_proxy_class_def)))
  51545             return -1;
  51546         rt->class_array[JS_CLASS_PROXY].exotic = &js_proxy_exotic_methods;
  51547         rt->class_array[JS_CLASS_PROXY].call = js_proxy_call;
  51548     }
  51549 
  51550     /* additional fields: name, length */
  51551     obj1 = JS_NewCFunction3(ctx, js_proxy_constructor, "Proxy", 2,
  51552                             JS_CFUNC_constructor, 0,
  51553                             ctx->function_proto, countof(js_proxy_funcs) + 2);
  51554     if (JS_IsException(obj1))
  51555         return -1;
  51556     JS_SetConstructorBit(ctx, obj1, TRUE);
  51557     if (JS_SetPropertyFunctionList(ctx, obj1, js_proxy_funcs,
  51558                                    countof(js_proxy_funcs)))
  51559         goto fail;
  51560     if (JS_DefinePropertyValueStr(ctx, ctx->global_obj, "Proxy",
  51561                                   obj1, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0)
  51562         goto fail;
  51563     return 0;
  51564  fail:
  51565     JS_FreeValue(ctx, obj1);
  51566     return -1;
  51567 }
  51568 
  51569 /* Symbol */
  51570 
  51571 static JSValue js_symbol_constructor(JSContext *ctx, JSValueConst new_target,
  51572                                      int argc, JSValueConst *argv)
  51573 {
  51574     JSValue str;
  51575     JSString *p;
  51576 
  51577     if (!JS_IsUndefined(new_target))
  51578         return JS_ThrowTypeErrorNotAConstructor(ctx, new_target);
  51579     if (argc == 0 || JS_IsUndefined(argv[0])) {
  51580         p = NULL;
  51581     } else {
  51582         str = JS_ToString(ctx, argv[0]);
  51583         if (JS_IsException(str))
  51584             return JS_EXCEPTION;
  51585         p = JS_VALUE_GET_STRING(str);
  51586     }
  51587     return JS_NewSymbol(ctx, p, JS_ATOM_TYPE_SYMBOL);
  51588 }
  51589 
  51590 static JSValue js_thisSymbolValue(JSContext *ctx, JSValueConst this_val)
  51591 {
  51592     if (JS_VALUE_GET_TAG(this_val) == JS_TAG_SYMBOL)
  51593         return JS_DupValue(ctx, this_val);
  51594 
  51595     if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
  51596         JSObject *p = JS_VALUE_GET_OBJ(this_val);
  51597         if (p->class_id == JS_CLASS_SYMBOL) {
  51598             if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_SYMBOL)
  51599                 return JS_DupValue(ctx, p->u.object_data);
  51600         }
  51601     }
  51602     return JS_ThrowTypeError(ctx, "not a symbol");
  51603 }
  51604 
  51605 static JSValue js_symbol_toString(JSContext *ctx, JSValueConst this_val,
  51606                                   int argc, JSValueConst *argv)
  51607 {
  51608     JSValue val, ret;
  51609     val = js_thisSymbolValue(ctx, this_val);
  51610     if (JS_IsException(val))
  51611         return val;
  51612     /* XXX: use JS_ToStringInternal() with a flags */
  51613     ret = js_string_constructor(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val);
  51614     JS_FreeValue(ctx, val);
  51615     return ret;
  51616 }
  51617 
  51618 static JSValue js_symbol_valueOf(JSContext *ctx, JSValueConst this_val,
  51619                                  int argc, JSValueConst *argv)
  51620 {
  51621     return js_thisSymbolValue(ctx, this_val);
  51622 }
  51623 
  51624 static JSValue js_symbol_get_description(JSContext *ctx, JSValueConst this_val)
  51625 {
  51626     JSValue val, ret;
  51627     JSAtomStruct *p;
  51628 
  51629     val = js_thisSymbolValue(ctx, this_val);
  51630     if (JS_IsException(val))
  51631         return val;
  51632     p = JS_VALUE_GET_PTR(val);
  51633     if (p->len == 0 && p->is_wide_char != 0) {
  51634         ret = JS_UNDEFINED;
  51635     } else {
  51636         ret = JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p));
  51637     }
  51638     JS_FreeValue(ctx, val);
  51639     return ret;
  51640 }
  51641 
  51642 static const JSCFunctionListEntry js_symbol_proto_funcs[] = {
  51643     JS_CFUNC_DEF("toString", 0, js_symbol_toString ),
  51644     JS_CFUNC_DEF("valueOf", 0, js_symbol_valueOf ),
  51645     // XXX: should have writable: false
  51646     JS_CFUNC_DEF("[Symbol.toPrimitive]", 1, js_symbol_valueOf ),
  51647     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Symbol", JS_PROP_CONFIGURABLE ),
  51648     JS_CGETSET_DEF("description", js_symbol_get_description, NULL ),
  51649 };
  51650 
  51651 static JSValue js_symbol_for(JSContext *ctx, JSValueConst this_val,
  51652                              int argc, JSValueConst *argv)
  51653 {
  51654     JSValue str;
  51655 
  51656     str = JS_ToString(ctx, argv[0]);
  51657     if (JS_IsException(str))
  51658         return JS_EXCEPTION;
  51659     return JS_NewSymbol(ctx, JS_VALUE_GET_STRING(str), JS_ATOM_TYPE_GLOBAL_SYMBOL);
  51660 }
  51661 
  51662 static JSValue js_symbol_keyFor(JSContext *ctx, JSValueConst this_val,
  51663                                 int argc, JSValueConst *argv)
  51664 {
  51665     JSAtomStruct *p;
  51666 
  51667     if (!JS_IsSymbol(argv[0]))
  51668         return JS_ThrowTypeError(ctx, "not a symbol");
  51669     p = JS_VALUE_GET_PTR(argv[0]);
  51670     if (p->atom_type != JS_ATOM_TYPE_GLOBAL_SYMBOL)
  51671         return JS_UNDEFINED;
  51672     return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
  51673 }
  51674 
  51675 static const JSCFunctionListEntry js_symbol_funcs[] = {
  51676     JS_CFUNC_DEF("for", 1, js_symbol_for ),
  51677     JS_CFUNC_DEF("keyFor", 1, js_symbol_keyFor ),
  51678     JS_PROP_ATOM_DEF("toPrimitive", JS_ATOM_Symbol_toPrimitive, 0),
  51679     JS_PROP_ATOM_DEF("iterator", JS_ATOM_Symbol_iterator, 0),
  51680     JS_PROP_ATOM_DEF("match", JS_ATOM_Symbol_match, 0),
  51681     JS_PROP_ATOM_DEF("matchAll", JS_ATOM_Symbol_matchAll, 0),
  51682     JS_PROP_ATOM_DEF("replace", JS_ATOM_Symbol_replace, 0),
  51683     JS_PROP_ATOM_DEF("search", JS_ATOM_Symbol_search, 0),
  51684     JS_PROP_ATOM_DEF("split", JS_ATOM_Symbol_split, 0),
  51685     JS_PROP_ATOM_DEF("toStringTag", JS_ATOM_Symbol_toStringTag, 0),
  51686     JS_PROP_ATOM_DEF("isConcatSpreadable", JS_ATOM_Symbol_isConcatSpreadable, 0),
  51687     JS_PROP_ATOM_DEF("hasInstance", JS_ATOM_Symbol_hasInstance, 0),
  51688     JS_PROP_ATOM_DEF("species", JS_ATOM_Symbol_species, 0),
  51689     JS_PROP_ATOM_DEF("unscopables", JS_ATOM_Symbol_unscopables, 0),
  51690     JS_PROP_ATOM_DEF("asyncIterator", JS_ATOM_Symbol_asyncIterator, 0),
  51691 };
  51692 
  51693 /* Set/Map/WeakSet/WeakMap */
  51694 
  51695 static BOOL js_weakref_is_target(JSValueConst val)
  51696 {
  51697     switch (JS_VALUE_GET_TAG(val)) {
  51698     case JS_TAG_OBJECT:
  51699         return TRUE;
  51700     case JS_TAG_SYMBOL:
  51701         {
  51702             JSAtomStruct *p = JS_VALUE_GET_PTR(val);
  51703             if (p->atom_type == JS_ATOM_TYPE_SYMBOL &&
  51704                 p->hash != JS_ATOM_HASH_PRIVATE)
  51705                 return TRUE;
  51706         }
  51707         break;
  51708     default:
  51709         break;
  51710     }
  51711     return FALSE;
  51712 }
  51713 
  51714 /* JS_UNDEFINED is considered as a live weakref */
  51715 /* XXX: add a specific JSWeakRef value type ? */
  51716 static BOOL js_weakref_is_live(JSValueConst val)
  51717 {
  51718     void *p;
  51719     if (JS_IsUndefined(val))
  51720         return TRUE;
  51721     p = JS_VALUE_GET_PTR(val);
  51722     return (js_rc(p)->ref_count != 0);
  51723 }
  51724 
  51725 /* 'val' can be JS_UNDEFINED */
  51726 static void js_weakref_free(JSRuntime *rt, JSValue val)
  51727 {
  51728     if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {
  51729         JSObject *p = JS_VALUE_GET_OBJ(val);
  51730         assert(p->weakref_count >= 1);
  51731         p->weakref_count--;
  51732         /* 'mark' is tested to avoid freeing the object structure when
  51733            it is about to be freed in a cycle or in
  51734            free_zero_refcount() */
  51735         if (p->weakref_count == 0 && js_rc(p)->ref_count == 0 &&
  51736             js_rc(p)->mark == 0) {
  51737             js_free_rt(rt, p);
  51738         }
  51739     } else if (JS_VALUE_GET_TAG(val) == JS_TAG_SYMBOL) {
  51740         JSString *p = JS_VALUE_GET_STRING(val);
  51741         assert(p->hash >= 1);
  51742         p->hash--;
  51743         if (p->hash == 0 && js_rc(p)->ref_count == 0) {
  51744             /* can remove the dummy structure */
  51745             js_free_rt(rt, p);
  51746         }
  51747     }
  51748 }
  51749 
  51750 /* val must be an object, a symbol or undefined (see
  51751    js_weakref_is_target). */
  51752 static JSValue js_weakref_new(JSContext *ctx, JSValueConst val)
  51753 {
  51754     if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {
  51755         JSObject *p = JS_VALUE_GET_OBJ(val);
  51756         p->weakref_count++;
  51757     } else if (JS_VALUE_GET_TAG(val) == JS_TAG_SYMBOL) {
  51758         JSString *p = JS_VALUE_GET_STRING(val);
  51759         /* XXX: could return an exception if too many references */
  51760         assert(p->hash < JS_ATOM_HASH_MASK - 2);
  51761         p->hash++;
  51762     } else {
  51763         assert(JS_IsUndefined(val));
  51764     }
  51765     return (JSValue)val;
  51766 }
  51767 
  51768 #define MAGIC_SET (1 << 0)
  51769 #define MAGIC_WEAK (1 << 1)
  51770 
  51771 static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target,
  51772                                   int argc, JSValueConst *argv, int magic)
  51773 {
  51774     JSMapState *s;
  51775     JSValue obj, adder = JS_UNDEFINED, iter = JS_UNDEFINED, next_method = JS_UNDEFINED;
  51776     JSValueConst arr;
  51777     BOOL is_set, is_weak;
  51778 
  51779     is_set = magic & MAGIC_SET;
  51780     is_weak = ((magic & MAGIC_WEAK) != 0);
  51781     obj = js_create_from_ctor(ctx, new_target, JS_CLASS_MAP + magic);
  51782     if (JS_IsException(obj))
  51783         return JS_EXCEPTION;
  51784     s = js_mallocz(ctx, sizeof(*s));
  51785     if (!s)
  51786         goto fail;
  51787     init_list_head(&s->records);
  51788     s->is_weak = is_weak;
  51789     if (is_weak) {
  51790         s->weakref_header.weakref_type = JS_WEAKREF_TYPE_MAP;
  51791         list_add_tail(&s->weakref_header.link, &ctx->rt->weakref_list);
  51792     }
  51793     JS_SetOpaque(obj, s);
  51794     s->hash_bits = 1;
  51795     s->hash_size = 1U << s->hash_bits;
  51796     s->hash_table = js_mallocz(ctx, sizeof(s->hash_table[0]) * s->hash_size);
  51797     if (!s->hash_table)
  51798         goto fail;
  51799     s->record_count_threshold = 4;
  51800 
  51801     arr = JS_UNDEFINED;
  51802     if (argc > 0)
  51803         arr = argv[0];
  51804     if (!JS_IsUndefined(arr) && !JS_IsNull(arr)) {
  51805         JSValue item, ret;
  51806         BOOL done;
  51807 
  51808         adder = JS_GetProperty(ctx, obj, is_set ? JS_ATOM_add : JS_ATOM_set);
  51809         if (JS_IsException(adder))
  51810             goto fail;
  51811         if (!JS_IsFunction(ctx, adder)) {
  51812             JS_ThrowTypeError(ctx, "set/add is not a function");
  51813             goto fail;
  51814         }
  51815 
  51816         iter = JS_GetIterator(ctx, arr, FALSE);
  51817         if (JS_IsException(iter))
  51818             goto fail;
  51819         next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
  51820         if (JS_IsException(next_method))
  51821             goto fail;
  51822 
  51823         for(;;) {
  51824             item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
  51825             if (JS_IsException(item))
  51826                 goto fail;
  51827             if (done)
  51828                 break;
  51829             if (is_set) {
  51830                 ret = JS_Call(ctx, adder, obj, 1, (JSValueConst *)&item);
  51831                 if (JS_IsException(ret)) {
  51832                     JS_FreeValue(ctx, item);
  51833                     goto fail_close;
  51834                 }
  51835             } else {
  51836                 JSValue key, value;
  51837                 JSValueConst args[2];
  51838                 key = JS_UNDEFINED;
  51839                 value = JS_UNDEFINED;
  51840                 if (!JS_IsObject(item)) {
  51841                     JS_ThrowTypeErrorNotAnObject(ctx);
  51842                     goto fail1;
  51843                 }
  51844                 key = JS_GetPropertyUint32(ctx, item, 0);
  51845                 if (JS_IsException(key))
  51846                     goto fail1;
  51847                 value = JS_GetPropertyUint32(ctx, item, 1);
  51848                 if (JS_IsException(value))
  51849                     goto fail1;
  51850                 args[0] = key;
  51851                 args[1] = value;
  51852                 ret = JS_Call(ctx, adder, obj, 2, args);
  51853                 if (JS_IsException(ret)) {
  51854                 fail1:
  51855                     JS_FreeValue(ctx, item);
  51856                     JS_FreeValue(ctx, key);
  51857                     JS_FreeValue(ctx, value);
  51858                     goto fail_close;
  51859                 }
  51860                 JS_FreeValue(ctx, key);
  51861                 JS_FreeValue(ctx, value);
  51862             }
  51863             JS_FreeValue(ctx, ret);
  51864             JS_FreeValue(ctx, item);
  51865         }
  51866         JS_FreeValue(ctx, next_method);
  51867         JS_FreeValue(ctx, iter);
  51868         JS_FreeValue(ctx, adder);
  51869     }
  51870     return obj;
  51871  fail_close:
  51872     /* close the iterator object, preserving pending exception */
  51873     JS_IteratorClose(ctx, iter, TRUE);
  51874  fail:
  51875     JS_FreeValue(ctx, next_method);
  51876     JS_FreeValue(ctx, iter);
  51877     JS_FreeValue(ctx, adder);
  51878     JS_FreeValue(ctx, obj);
  51879     return JS_EXCEPTION;
  51880 }
  51881 
  51882 /* XXX: could normalize strings to speed up comparison */
  51883 static JSValue map_normalize_key(JSContext *ctx, JSValue key)
  51884 {
  51885     uint32_t tag = JS_VALUE_GET_TAG(key);
  51886     /* convert -0.0 to +0.0 */
  51887     if (JS_TAG_IS_FLOAT64(tag) && JS_VALUE_GET_FLOAT64(key) == 0.0) {
  51888         key = JS_NewInt32(ctx, 0);
  51889     }
  51890     return key;
  51891 }
  51892 
  51893 static JSValueConst map_normalize_key_const(JSContext *ctx, JSValueConst key)
  51894 {
  51895     return (JSValueConst)map_normalize_key(ctx, (JSValue)key);
  51896 }
  51897 
  51898 /* hash multipliers, same as the Linux kernel (see Knuth vol 3,
  51899    section 6.4, exercise 9) */
  51900 #define HASH_MUL32 0x61C88647
  51901 #define HASH_MUL64 UINT64_C(0x61C8864680B583EB)
  51902 
  51903 static uint32_t map_hash32(uint32_t a, int hash_bits)
  51904 {
  51905     return (a * HASH_MUL32) >> (32 - hash_bits);
  51906 }
  51907 
  51908 static uint32_t map_hash64(uint64_t a, int hash_bits)
  51909 {
  51910     return (a * HASH_MUL64) >> (64 - hash_bits);
  51911 }
  51912 
  51913 static uint32_t map_hash_pointer(uintptr_t a, int hash_bits)
  51914 {
  51915 #ifdef JS_PTR64
  51916     return map_hash64(a, hash_bits);
  51917 #else
  51918     return map_hash32(a, hash_bits);
  51919 #endif
  51920 }
  51921 
  51922 /* XXX: better hash ? */
  51923 /* precondition: 1 <= hash_bits <= 32 */
  51924 static uint32_t map_hash_key(JSValueConst key, int hash_bits)
  51925 {
  51926     uint32_t tag = JS_VALUE_GET_NORM_TAG(key);
  51927     uint32_t h;
  51928     double d;
  51929     JSBigInt *p;
  51930     JSBigIntBuf buf;
  51931     
  51932     switch(tag) {
  51933     case JS_TAG_BOOL:
  51934         h = map_hash32(JS_VALUE_GET_INT(key) ^ JS_TAG_BOOL, hash_bits);
  51935         break;
  51936     case JS_TAG_STRING:
  51937         h = map_hash32(hash_string(JS_VALUE_GET_STRING(key), 0) ^ JS_TAG_STRING, hash_bits);
  51938         break;
  51939     case JS_TAG_STRING_ROPE:
  51940         h = map_hash32(hash_string_rope(key, 0) ^ JS_TAG_STRING, hash_bits);
  51941         break;
  51942     case JS_TAG_OBJECT:
  51943     case JS_TAG_SYMBOL:
  51944         h = map_hash_pointer((uintptr_t)JS_VALUE_GET_PTR(key) ^ tag, hash_bits);
  51945         break;
  51946     case JS_TAG_INT:
  51947         d = JS_VALUE_GET_INT(key);
  51948         goto hash_float64;
  51949     case JS_TAG_FLOAT64:
  51950         d = JS_VALUE_GET_FLOAT64(key);
  51951         /* normalize the NaN */
  51952         if (isnan(d))
  51953             d = JS_FLOAT64_NAN;
  51954     hash_float64:
  51955         h = map_hash64(float64_as_uint64(d) ^ JS_TAG_FLOAT64, hash_bits);
  51956         break;
  51957     case JS_TAG_SHORT_BIG_INT:
  51958         p = js_bigint_set_short(&buf, key);
  51959         goto hash_bigint;
  51960     case JS_TAG_BIG_INT:
  51961         p = JS_VALUE_GET_PTR(key);
  51962     hash_bigint:
  51963         {
  51964             int i;
  51965             h = 1;
  51966             for(i = p->len - 1; i >= 0; i--) {
  51967                 h = h * 263 + p->tab[i];
  51968             }
  51969             /* the final step is necessary otherwise h mod n only
  51970                depends of p->tab[i] mod n */
  51971             h = map_hash32(h ^ JS_TAG_BIG_INT, hash_bits);
  51972         }
  51973         break;
  51974     default:
  51975         h = 0;
  51976         break;
  51977     }
  51978     return h;
  51979 }
  51980 
  51981 static JSMapRecord *map_find_record(JSContext *ctx, JSMapState *s,
  51982                                     JSValueConst key)
  51983 {
  51984     JSMapRecord *mr;
  51985     uint32_t h;
  51986     h = map_hash_key(key, s->hash_bits);
  51987     for(mr = s->hash_table[h]; mr != NULL; mr = mr->hash_next) {
  51988         if (mr->empty || (s->is_weak && !js_weakref_is_live(mr->key))) {
  51989             /* cannot match */
  51990         } else {
  51991             if (js_same_value_zero(ctx, mr->key, key))
  51992                 return mr;
  51993         }
  51994     }
  51995     return NULL;
  51996 }
  51997 
  51998 static void map_hash_resize(JSContext *ctx, JSMapState *s)
  51999 {
  52000     uint32_t new_hash_size, h;
  52001     int new_hash_bits;
  52002     struct list_head *el;
  52003     JSMapRecord *mr, **new_hash_table;
  52004 
  52005     /* XXX: no reporting of memory allocation failure */
  52006     new_hash_bits = min_int(s->hash_bits + 1, 31);
  52007     new_hash_size = 1U << new_hash_bits;
  52008     new_hash_table = js_realloc(ctx, s->hash_table,
  52009                                 sizeof(new_hash_table[0]) * new_hash_size);
  52010     if (!new_hash_table)
  52011         return;
  52012 
  52013     memset(new_hash_table, 0, sizeof(new_hash_table[0]) * new_hash_size);
  52014 
  52015     list_for_each(el, &s->records) {
  52016         mr = list_entry(el, JSMapRecord, link);
  52017         if (mr->empty || (s->is_weak && !js_weakref_is_live(mr->key))) {
  52018         } else {
  52019             h = map_hash_key(mr->key, new_hash_bits);
  52020             mr->hash_next = new_hash_table[h];
  52021             new_hash_table[h] = mr;
  52022         }
  52023     }
  52024     s->hash_table = new_hash_table;
  52025     s->hash_bits = new_hash_bits;
  52026     s->hash_size = new_hash_size;
  52027     s->record_count_threshold = new_hash_size * 2;
  52028 }
  52029 
  52030 static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s,
  52031                                    JSValueConst key)
  52032 {
  52033     uint32_t h;
  52034     JSMapRecord *mr;
  52035 
  52036     mr = js_malloc(ctx, sizeof(*mr));
  52037     if (!mr)
  52038         return NULL;
  52039     mr->ref_count = 1;
  52040     mr->empty = FALSE;
  52041     if (s->is_weak) {
  52042         mr->key = js_weakref_new(ctx, key);
  52043     } else {
  52044         mr->key = JS_DupValue(ctx, key);
  52045     }
  52046     h = map_hash_key(key, s->hash_bits);
  52047     mr->hash_next = s->hash_table[h];
  52048     s->hash_table[h] = mr;
  52049     list_add_tail(&mr->link, &s->records);
  52050     s->record_count++;
  52051     if (s->record_count >= s->record_count_threshold) {
  52052         map_hash_resize(ctx, s);
  52053     }
  52054     return mr;
  52055 }
  52056 
  52057 static JSMapRecord *set_add_record(JSContext *ctx, JSMapState *s,
  52058                                    JSValueConst key)
  52059 {
  52060     JSMapRecord *mr;
  52061     mr = map_add_record(ctx, s, key);
  52062     if (!mr)
  52063         return NULL;
  52064     mr->value = JS_UNDEFINED;
  52065     return mr;
  52066 }
  52067 
  52068 /* warning: the record must be removed from the hash table before */
  52069 static void map_delete_record_internal(JSRuntime *rt, JSMapState *s, JSMapRecord *mr)
  52070 {
  52071     if (mr->empty)
  52072         return;
  52073     
  52074     if (s->is_weak) {
  52075         js_weakref_free(rt, mr->key);
  52076     } else {
  52077         JS_FreeValueRT(rt, mr->key);
  52078     }
  52079     JS_FreeValueRT(rt, mr->value);
  52080     if (--mr->ref_count == 0) {
  52081         list_del(&mr->link);
  52082         js_free_rt(rt, mr);
  52083     } else {
  52084         /* keep a zombie record for iterators */
  52085         mr->empty = TRUE;
  52086         mr->key = JS_UNDEFINED;
  52087         mr->value = JS_UNDEFINED;
  52088     }
  52089     s->record_count--;
  52090 }
  52091 
  52092 static void map_decref_record(JSRuntime *rt, JSMapRecord *mr)
  52093 {
  52094     if (--mr->ref_count == 0) {
  52095         /* the record can be safely removed */
  52096         assert(mr->empty);
  52097         list_del(&mr->link);
  52098         js_free_rt(rt, mr);
  52099     }
  52100 }
  52101 
  52102 static void map_delete_weakrefs(JSRuntime *rt, JSWeakRefHeader *wh)
  52103 {
  52104     JSMapState *s = container_of(wh, JSMapState, weakref_header);
  52105     struct list_head *el, *el1;
  52106     JSMapRecord *mr1, **pmr;
  52107     uint32_t h;
  52108 
  52109     list_for_each_safe(el, el1, &s->records) {
  52110         JSMapRecord *mr = list_entry(el, JSMapRecord, link);
  52111         if (!js_weakref_is_live(mr->key)) {
  52112 
  52113             /* even if key is not live it can be hashed as a pointer */
  52114             h = map_hash_key(mr->key, s->hash_bits);
  52115             pmr = &s->hash_table[h];
  52116             for(;;) {
  52117                 mr1 = *pmr;
  52118                 /* the entry may already be removed from the hash
  52119                    table if the map was resized */
  52120                 if (mr1 == NULL)
  52121                     goto done; 
  52122                 if (mr1 == mr)
  52123                     break;
  52124                 pmr = &mr1->hash_next;
  52125             }
  52126             /* remove from the hash table */
  52127             *pmr = mr1->hash_next;
  52128         done:
  52129             map_delete_record_internal(rt, s, mr);
  52130         }
  52131     }
  52132 }
  52133 
  52134 static JSValue js_map_set(JSContext *ctx, JSValueConst this_val,
  52135                           int argc, JSValueConst *argv, int magic)
  52136 {
  52137     JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
  52138     JSMapRecord *mr;
  52139     JSValueConst key, value;
  52140 
  52141     if (!s)
  52142         return JS_EXCEPTION;
  52143     key = map_normalize_key_const(ctx, argv[0]);
  52144     if (s->is_weak && !js_weakref_is_target(key))
  52145         return JS_ThrowTypeError(ctx, "invalid value used as %s key", (magic & MAGIC_SET) ? "WeakSet" : "WeakMap");
  52146     if (magic & MAGIC_SET)
  52147         value = JS_UNDEFINED;
  52148     else
  52149         value = argv[1];
  52150     mr = map_find_record(ctx, s, key);
  52151     if (mr) {
  52152         JS_FreeValue(ctx, mr->value);
  52153     } else {
  52154         mr = map_add_record(ctx, s, key);
  52155         if (!mr)
  52156             return JS_EXCEPTION;
  52157     }
  52158     mr->value = JS_DupValue(ctx, value);
  52159     return JS_DupValue(ctx, this_val);
  52160 }
  52161 
  52162 static JSValue js_map_get(JSContext *ctx, JSValueConst this_val,
  52163                           int argc, JSValueConst *argv, int magic)
  52164 {
  52165     JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
  52166     JSMapRecord *mr;
  52167     JSValueConst key;
  52168 
  52169     if (!s)
  52170         return JS_EXCEPTION;
  52171     key = map_normalize_key_const(ctx, argv[0]);
  52172     mr = map_find_record(ctx, s, key);
  52173     if (!mr)
  52174         return JS_UNDEFINED;
  52175     else
  52176         return JS_DupValue(ctx, mr->value);
  52177 }
  52178 
  52179 /* return JS_TRUE or JS_FALSE */
  52180 static JSValue map_delete_record(JSContext *ctx, JSMapState *s, JSValueConst key)
  52181 {
  52182     JSMapRecord *mr, **pmr;
  52183     uint32_t h;
  52184 
  52185     key = map_normalize_key_const(ctx, key);
  52186     
  52187     h = map_hash_key(key, s->hash_bits);
  52188     pmr = &s->hash_table[h];
  52189     for(;;) {
  52190         mr = *pmr;
  52191         if (mr == NULL)
  52192             return JS_FALSE;
  52193         if (mr->empty || (s->is_weak && !js_weakref_is_live(mr->key))) {
  52194             /* not valid */
  52195         } else {
  52196             if (js_same_value_zero(ctx, mr->key, key))
  52197                 break;
  52198         }
  52199         pmr = &mr->hash_next;
  52200     }
  52201 
  52202     /* remove from the hash table */
  52203     *pmr = mr->hash_next;
  52204     
  52205     map_delete_record_internal(ctx->rt, s, mr);
  52206     return JS_TRUE;
  52207 }
  52208 
  52209 static JSValue js_map_getOrInsert(JSContext *ctx, JSValueConst this_val,
  52210                                   int argc, JSValueConst *argv, int magic)
  52211 {
  52212     BOOL computed = magic & 1;
  52213     JSClassID class_id = magic >> 1;
  52214     JSMapState *s = JS_GetOpaque2(ctx, this_val, class_id);
  52215     JSMapRecord *mr;
  52216     JSValueConst key;
  52217     JSValue value;
  52218 
  52219     if (!s)
  52220         return JS_EXCEPTION;
  52221     if (computed && !JS_IsFunction(ctx, argv[1]))
  52222         return JS_ThrowTypeError(ctx, "not a function");
  52223     key = map_normalize_key_const(ctx, argv[0]);
  52224     if (s->is_weak && !js_weakref_is_target(key))
  52225         return JS_ThrowTypeError(ctx, "invalid value used as WeakMap key");
  52226     mr = map_find_record(ctx, s, key);
  52227     if (!mr) {
  52228         if (computed) {
  52229             value = JS_Call(ctx, argv[1], JS_UNDEFINED, 1, &key);
  52230             if (JS_IsException(value))
  52231                 return JS_EXCEPTION;
  52232             map_delete_record(ctx, s, key);
  52233         } else {
  52234             value = JS_DupValue(ctx, argv[1]);
  52235         }
  52236         mr = map_add_record(ctx, s, key);
  52237         if (!mr) {
  52238             JS_FreeValue(ctx, value);
  52239             return JS_EXCEPTION;
  52240         }
  52241         mr->value = value;
  52242     }
  52243     return JS_DupValue(ctx, mr->value);
  52244 }
  52245 
  52246 static JSValue js_map_has(JSContext *ctx, JSValueConst this_val,
  52247                           int argc, JSValueConst *argv, int magic)
  52248 {
  52249     JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
  52250     JSMapRecord *mr;
  52251     JSValueConst key;
  52252 
  52253     if (!s)
  52254         return JS_EXCEPTION;
  52255     key = map_normalize_key_const(ctx, argv[0]);
  52256     mr = map_find_record(ctx, s, key);
  52257     return JS_NewBool(ctx, mr != NULL);
  52258 }
  52259 
  52260 static JSValue js_map_delete(JSContext *ctx, JSValueConst this_val,
  52261                              int argc, JSValueConst *argv, int magic)
  52262 {
  52263     JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
  52264     if (!s)
  52265         return JS_EXCEPTION;
  52266     return map_delete_record(ctx, s, argv[0]);
  52267 }
  52268 
  52269 static JSValue js_map_clear(JSContext *ctx, JSValueConst this_val,
  52270                             int argc, JSValueConst *argv, int magic)
  52271 {
  52272     JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
  52273     struct list_head *el, *el1;
  52274     JSMapRecord *mr;
  52275 
  52276     if (!s)
  52277         return JS_EXCEPTION;
  52278 
  52279     /* remove from the hash table */
  52280     memset(s->hash_table, 0, sizeof(s->hash_table[0]) * s->hash_size);
  52281     
  52282     list_for_each_safe(el, el1, &s->records) {
  52283         mr = list_entry(el, JSMapRecord, link);
  52284         map_delete_record_internal(ctx->rt, s, mr);
  52285     }
  52286     return JS_UNDEFINED;
  52287 }
  52288 
  52289 static JSValue js_map_get_size(JSContext *ctx, JSValueConst this_val, int magic)
  52290 {
  52291     JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
  52292     if (!s)
  52293         return JS_EXCEPTION;
  52294     return JS_NewUint32(ctx, s->record_count);
  52295 }
  52296 
  52297 static JSValue js_map_forEach(JSContext *ctx, JSValueConst this_val,
  52298                               int argc, JSValueConst *argv, int magic)
  52299 {
  52300     JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
  52301     JSValueConst func, this_arg;
  52302     JSValue ret, args[3];
  52303     struct list_head *el;
  52304     JSMapRecord *mr;
  52305 
  52306     if (!s)
  52307         return JS_EXCEPTION;
  52308     func = argv[0];
  52309     if (argc > 1)
  52310         this_arg = argv[1];
  52311     else
  52312         this_arg = JS_UNDEFINED;
  52313     if (check_function(ctx, func))
  52314         return JS_EXCEPTION;
  52315     /* Note: the list can be modified while traversing it, but the
  52316        current element is locked */
  52317     el = s->records.next;
  52318     while (el != &s->records) {
  52319         mr = list_entry(el, JSMapRecord, link);
  52320         if (!mr->empty) {
  52321             mr->ref_count++;
  52322             /* must duplicate in case the record is deleted */
  52323             args[1] = JS_DupValue(ctx, mr->key);
  52324             if (magic)
  52325                 args[0] = args[1];
  52326             else
  52327                 args[0] = JS_DupValue(ctx, mr->value);
  52328             args[2] = (JSValue)this_val;
  52329             ret = JS_Call(ctx, func, this_arg, 3, (JSValueConst *)args);
  52330             JS_FreeValue(ctx, args[0]);
  52331             if (!magic)
  52332                 JS_FreeValue(ctx, args[1]);
  52333             el = el->next;
  52334             map_decref_record(ctx->rt, mr);
  52335             if (JS_IsException(ret))
  52336                 return ret;
  52337             JS_FreeValue(ctx, ret);
  52338         } else {
  52339             el = el->next;
  52340         }
  52341     }
  52342     return JS_UNDEFINED;
  52343 }
  52344 
  52345 static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val,
  52346                                  int argc, JSValueConst *argv, int is_map)
  52347 {
  52348     JSValueConst cb, args[2];
  52349     JSValue res, iter, next, groups, key, v, prop;
  52350     JSAtom key_atom = JS_ATOM_NULL;
  52351     int64_t idx;
  52352     BOOL done;
  52353 
  52354     // "is function?" check must be observed before argv[0] is accessed
  52355     cb = argv[1];
  52356     if (check_function(ctx, cb))
  52357         return JS_EXCEPTION;
  52358 
  52359     iter = JS_GetIterator(ctx, argv[0], /*is_async*/FALSE);
  52360     if (JS_IsException(iter))
  52361         return JS_EXCEPTION;
  52362 
  52363     key = JS_UNDEFINED;
  52364     key_atom = JS_ATOM_NULL;
  52365     v = JS_UNDEFINED;
  52366     prop = JS_UNDEFINED;
  52367     groups = JS_UNDEFINED;
  52368 
  52369     next = JS_GetProperty(ctx, iter, JS_ATOM_next);
  52370     if (JS_IsException(next))
  52371         goto exception;
  52372 
  52373     if (is_map) {
  52374         groups = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, 0);
  52375     } else {
  52376         groups = JS_NewObjectProto(ctx, JS_NULL);
  52377     }
  52378     if (JS_IsException(groups))
  52379         goto exception;
  52380 
  52381     for (idx = 0; ; idx++) {
  52382         if (idx >= MAX_SAFE_INTEGER) {
  52383             JS_ThrowTypeError(ctx, "too many elements");
  52384             goto iterator_close_exception;
  52385         }
  52386         v = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
  52387         if (JS_IsException(v))
  52388             goto exception;
  52389         if (done)
  52390             break; // v is JS_UNDEFINED
  52391 
  52392         args[0] = v;
  52393         args[1] = JS_NewInt64(ctx, idx);
  52394         key = JS_Call(ctx, cb, ctx->global_obj, 2, args);
  52395         if (JS_IsException(key))
  52396             goto iterator_close_exception;
  52397 
  52398         if (is_map) {
  52399             prop = js_map_get(ctx, groups, 1, (JSValueConst *)&key, 0);
  52400         } else {
  52401             key_atom = JS_ValueToAtom(ctx, key);
  52402             JS_FreeValue(ctx, key);
  52403             key = JS_UNDEFINED;
  52404             if (key_atom == JS_ATOM_NULL)
  52405                 goto iterator_close_exception;
  52406             prop = JS_GetProperty(ctx, groups, key_atom);
  52407         }
  52408         if (JS_IsException(prop))
  52409             goto exception;
  52410 
  52411         if (JS_IsUndefined(prop)) {
  52412             prop = JS_NewArray(ctx);
  52413             if (JS_IsException(prop))
  52414                 goto exception;
  52415             if (is_map) {
  52416                 args[0] = key;
  52417                 args[1] = prop;
  52418                 res = js_map_set(ctx, groups, 2, args, 0);
  52419                 if (JS_IsException(res))
  52420                     goto exception;
  52421                 JS_FreeValue(ctx, res);
  52422             } else {
  52423                 prop = JS_DupValue(ctx, prop);
  52424                 if (JS_DefinePropertyValue(ctx, groups, key_atom, prop,
  52425                                            JS_PROP_C_W_E) < 0) {
  52426                     goto exception;
  52427                 }
  52428             }
  52429         }
  52430         res = js_array_push(ctx, prop, 1, (JSValueConst *)&v, /*unshift*/0);
  52431         if (JS_IsException(res))
  52432             goto exception;
  52433         // res is an int64
  52434 
  52435         JS_FreeValue(ctx, prop);
  52436         JS_FreeValue(ctx, key);
  52437         JS_FreeAtom(ctx, key_atom);
  52438         JS_FreeValue(ctx, v);
  52439         prop = JS_UNDEFINED;
  52440         key = JS_UNDEFINED;
  52441         key_atom = JS_ATOM_NULL;
  52442         v = JS_UNDEFINED;
  52443     }
  52444 
  52445     JS_FreeValue(ctx, iter);
  52446     JS_FreeValue(ctx, next);
  52447     return groups;
  52448 
  52449  iterator_close_exception:
  52450     JS_IteratorClose(ctx, iter, TRUE);
  52451  exception:
  52452     JS_FreeAtom(ctx, key_atom);
  52453     JS_FreeValue(ctx, prop);
  52454     JS_FreeValue(ctx, key);
  52455     JS_FreeValue(ctx, v);
  52456     JS_FreeValue(ctx, groups);
  52457     JS_FreeValue(ctx, iter);
  52458     JS_FreeValue(ctx, next);
  52459     return JS_EXCEPTION;
  52460 }
  52461 
  52462 static void js_map_finalizer(JSRuntime *rt, JSValue val)
  52463 {
  52464     JSObject *p;
  52465     JSMapState *s;
  52466     struct list_head *el, *el1;
  52467     JSMapRecord *mr;
  52468 
  52469     p = JS_VALUE_GET_OBJ(val);
  52470     s = p->u.map_state;
  52471     if (s) {
  52472         /* if the object is deleted we are sure that no iterator is
  52473            using it */
  52474         list_for_each_safe(el, el1, &s->records) {
  52475             mr = list_entry(el, JSMapRecord, link);
  52476             if (!mr->empty) {
  52477                 if (s->is_weak)
  52478                     js_weakref_free(rt, mr->key);
  52479                 else
  52480                     JS_FreeValueRT(rt, mr->key);
  52481                 JS_FreeValueRT(rt, mr->value);
  52482             }
  52483             js_free_rt(rt, mr);
  52484         }
  52485         js_free_rt(rt, s->hash_table);
  52486         if (s->is_weak) {
  52487             list_del(&s->weakref_header.link);
  52488         }
  52489         js_free_rt(rt, s);
  52490     }
  52491 }
  52492 
  52493 static void js_map_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
  52494 {
  52495     JSObject *p = JS_VALUE_GET_OBJ(val);
  52496     JSMapState *s;
  52497     struct list_head *el;
  52498     JSMapRecord *mr;
  52499 
  52500     s = p->u.map_state;
  52501     if (s) {
  52502         list_for_each(el, &s->records) {
  52503             mr = list_entry(el, JSMapRecord, link);
  52504             if (!s->is_weak)
  52505                 JS_MarkValue(rt, mr->key, mark_func);
  52506             JS_MarkValue(rt, mr->value, mark_func);
  52507         }
  52508     }
  52509 }
  52510 
  52511 /* Map Iterator */
  52512 
  52513 typedef struct JSMapIteratorData {
  52514     JSValue obj;
  52515     JSIteratorKindEnum kind;
  52516     JSMapRecord *cur_record;
  52517 } JSMapIteratorData;
  52518 
  52519 static void js_map_iterator_finalizer(JSRuntime *rt, JSValue val)
  52520 {
  52521     JSObject *p;
  52522     JSMapIteratorData *it;
  52523 
  52524     p = JS_VALUE_GET_OBJ(val);
  52525     it = p->u.map_iterator_data;
  52526     if (it) {
  52527         /* During the GC sweep phase the Map finalizer may be
  52528            called before the Map iterator finalizer */
  52529         if (JS_IsLiveObject(rt, it->obj) && it->cur_record) {
  52530             map_decref_record(rt, it->cur_record);
  52531         }
  52532         JS_FreeValueRT(rt, it->obj);
  52533         js_free_rt(rt, it);
  52534     }
  52535 }
  52536 
  52537 static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val,
  52538                                  JS_MarkFunc *mark_func)
  52539 {
  52540     JSObject *p = JS_VALUE_GET_OBJ(val);
  52541     JSMapIteratorData *it;
  52542     it = p->u.map_iterator_data;
  52543     if (it) {
  52544         /* the record is already marked by the object */
  52545         JS_MarkValue(rt, it->obj, mark_func);
  52546     }
  52547 }
  52548 
  52549 static JSValue js_create_map_iterator(JSContext *ctx, JSValueConst this_val,
  52550                                       int argc, JSValueConst *argv, int magic)
  52551 {
  52552     JSIteratorKindEnum kind;
  52553     JSMapState *s;
  52554     JSMapIteratorData *it;
  52555     JSValue enum_obj;
  52556 
  52557     kind = magic >> 2;
  52558     magic &= 3;
  52559     s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
  52560     if (!s)
  52561         return JS_EXCEPTION;
  52562     enum_obj = JS_NewObjectClass(ctx, JS_CLASS_MAP_ITERATOR + magic);
  52563     if (JS_IsException(enum_obj))
  52564         goto fail;
  52565     it = js_malloc(ctx, sizeof(*it));
  52566     if (!it) {
  52567         JS_FreeValue(ctx, enum_obj);
  52568         goto fail;
  52569     }
  52570     it->obj = JS_DupValue(ctx, this_val);
  52571     it->kind = kind;
  52572     it->cur_record = NULL;
  52573     JS_SetOpaque(enum_obj, it);
  52574     return enum_obj;
  52575  fail:
  52576     return JS_EXCEPTION;
  52577 }
  52578 
  52579 static JSValue js_map_iterator_next(JSContext *ctx, JSValueConst this_val,
  52580                                     int argc, JSValueConst *argv,
  52581                                     BOOL *pdone, int magic)
  52582 {
  52583     JSMapIteratorData *it;
  52584     JSMapState *s;
  52585     JSMapRecord *mr;
  52586     struct list_head *el;
  52587 
  52588     it = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP_ITERATOR + magic);
  52589     if (!it) {
  52590         *pdone = FALSE;
  52591         return JS_EXCEPTION;
  52592     }
  52593     if (JS_IsUndefined(it->obj))
  52594         goto done;
  52595     s = JS_GetOpaque(it->obj, JS_CLASS_MAP + magic);
  52596     assert(s != NULL);
  52597     if (!it->cur_record) {
  52598         el = s->records.next;
  52599     } else {
  52600         mr = it->cur_record;
  52601         el = mr->link.next;
  52602         map_decref_record(ctx->rt, mr); /* the record can be freed here */
  52603     }
  52604     for(;;) {
  52605         if (el == &s->records) {
  52606             /* no more record  */
  52607             it->cur_record = NULL;
  52608             JS_FreeValue(ctx, it->obj);
  52609             it->obj = JS_UNDEFINED;
  52610         done:
  52611             /* end of enumeration */
  52612             *pdone = TRUE;
  52613             return JS_UNDEFINED;
  52614         }
  52615         mr = list_entry(el, JSMapRecord, link);
  52616         if (!mr->empty)
  52617             break;
  52618         /* get the next record */
  52619         el = mr->link.next;
  52620     }
  52621 
  52622     /* lock the record so that it won't be freed */
  52623     mr->ref_count++;
  52624     it->cur_record = mr;
  52625     *pdone = FALSE;
  52626 
  52627     if (it->kind == JS_ITERATOR_KIND_KEY) {
  52628         return JS_DupValue(ctx, mr->key);
  52629     } else {
  52630         JSValueConst args[2];
  52631         args[0] = mr->key;
  52632         if (magic)
  52633             args[1] = mr->key;
  52634         else
  52635             args[1] = mr->value;
  52636         if (it->kind == JS_ITERATOR_KIND_VALUE) {
  52637             return JS_DupValue(ctx, args[1]);
  52638         } else {
  52639             return js_create_array(ctx, 2, args);
  52640         }
  52641     }
  52642 }
  52643 
  52644 static int get_set_record(JSContext *ctx, JSValueConst obj,
  52645                           int64_t *psize, JSValue *phas, JSValue *pkeys)
  52646 {
  52647     JSMapState *s;
  52648     int64_t size;
  52649     JSValue has = JS_UNDEFINED, keys = JS_UNDEFINED;
  52650     
  52651     s = JS_GetOpaque(obj, JS_CLASS_SET);
  52652     if (s) {
  52653         size = s->record_count;
  52654     } else {
  52655         JSValue v;
  52656         double d;
  52657 
  52658         v = JS_GetProperty(ctx, obj, JS_ATOM_size);
  52659         if (JS_IsException(v))
  52660             goto exception;
  52661         if (JS_ToFloat64Free(ctx, &d, v) < 0)
  52662             goto exception;
  52663         if (isnan(d)) {
  52664             JS_ThrowTypeError(ctx, ".size is not a number");
  52665             goto exception;
  52666         }
  52667         if (d < INT64_MIN)
  52668             size = INT64_MIN;
  52669         else if (d >= 0x1p63) /* must use INT64_MAX + 1 because INT64_MAX cannot be exactly represented as a double */
  52670             size = INT64_MAX;
  52671         else
  52672             size = (int64_t)d;
  52673         if (size < 0) {
  52674             JS_ThrowRangeError(ctx, ".size must be positive");
  52675             goto exception;
  52676         }
  52677     }
  52678 
  52679     has = JS_GetProperty(ctx, obj, JS_ATOM_has);
  52680     if (JS_IsException(has))
  52681         goto exception;
  52682     if (JS_IsUndefined(has)) {
  52683         JS_ThrowTypeError(ctx, ".has is undefined");
  52684         goto exception;
  52685     }
  52686     if (!JS_IsFunction(ctx, has)) {
  52687         JS_ThrowTypeError(ctx, ".has is not a function");
  52688         goto exception;
  52689     }
  52690 
  52691     keys = JS_GetProperty(ctx, obj, JS_ATOM_keys);
  52692     if (JS_IsException(keys))
  52693         goto exception;
  52694     if (JS_IsUndefined(keys)) {
  52695         JS_ThrowTypeError(ctx, ".keys is undefined");
  52696         goto exception;
  52697     }
  52698     if (!JS_IsFunction(ctx, keys)) {
  52699         JS_ThrowTypeError(ctx, ".keys is not a function");
  52700         goto exception;
  52701     }
  52702     *psize = size;
  52703     *phas = has;
  52704     *pkeys = keys;
  52705     return 0;
  52706 
  52707  exception:
  52708     JS_FreeValue(ctx, has);
  52709     JS_FreeValue(ctx, keys);
  52710     *psize = 0;
  52711     *phas = JS_UNDEFINED;
  52712     *pkeys = JS_UNDEFINED;
  52713     return -1;
  52714 }
  52715 
  52716 /* copy 'this_val' in a new set without side effects */
  52717 static JSValue js_copy_set(JSContext *ctx, JSValueConst this_val)
  52718 {
  52719     JSValue newset;
  52720     JSMapState *s, *t;
  52721     struct list_head *el;
  52722     JSMapRecord *mr;
  52723    
  52724     s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
  52725     if (!s)
  52726         return JS_EXCEPTION;
  52727 
  52728     newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET);
  52729     if (JS_IsException(newset))
  52730         return JS_EXCEPTION;
  52731     t = JS_GetOpaque(newset, JS_CLASS_SET);
  52732 
  52733     // can't clone this_val using js_map_constructor(),
  52734     // test262 mandates we don't call the .add method
  52735     list_for_each(el, &s->records) {
  52736         mr = list_entry(el, JSMapRecord, link);
  52737         if (mr->empty)
  52738             continue;
  52739         if (!set_add_record(ctx, t, mr->key))
  52740             goto exception;
  52741     }
  52742     return newset;
  52743  exception:
  52744     JS_FreeValue(ctx, newset);
  52745     return JS_EXCEPTION;
  52746 }
  52747 
  52748 static JSValue js_set_isDisjointFrom(JSContext *ctx, JSValueConst this_val,
  52749                                      int argc, JSValueConst *argv)
  52750 {
  52751     JSValue item, iter, keys, has, next, rv, rval;
  52752     int done;
  52753     BOOL found;
  52754     JSMapState *s;
  52755     int64_t size;
  52756     int ok;
  52757 
  52758     iter = JS_UNDEFINED;
  52759     next = JS_UNDEFINED;
  52760     rval = JS_EXCEPTION;
  52761     s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
  52762     if (!s)
  52763         return JS_EXCEPTION;
  52764     if (get_set_record(ctx, argv[0], &size, &has, &keys) < 0)
  52765         goto exception;
  52766     if (s->record_count <= size) {
  52767         iter = js_create_map_iterator(ctx, this_val, 0, NULL, MAGIC_SET);
  52768         if (JS_IsException(iter))
  52769             goto exception;
  52770         found = FALSE;
  52771         do {
  52772             item = js_map_iterator_next(ctx, iter, 0, NULL, &done, MAGIC_SET);
  52773             if (JS_IsException(item))
  52774                 goto exception;
  52775             if (done) // item is JS_UNDEFINED
  52776                 break;
  52777             rv = JS_Call(ctx, has, argv[0], 1, (JSValueConst *)&item);
  52778             JS_FreeValue(ctx, item);
  52779             ok = JS_ToBoolFree(ctx, rv); // returns -1 if rv is JS_EXCEPTION
  52780             if (ok < 0)
  52781                 goto exception;
  52782             found = (ok > 0);
  52783         } while (!found);
  52784     } else {
  52785         iter = JS_Call(ctx, keys, argv[0], 0, NULL);
  52786         if (JS_IsException(iter))
  52787             goto exception;
  52788         next = JS_GetProperty(ctx, iter, JS_ATOM_next);
  52789         if (JS_IsException(next))
  52790             goto exception;
  52791         found = FALSE;
  52792         for(;;) {
  52793             item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
  52794             if (JS_IsException(item))
  52795                 goto exception;
  52796             if (done) // item is JS_UNDEFINED
  52797                 break;
  52798             item = map_normalize_key(ctx, item);
  52799             found = (NULL != map_find_record(ctx, s, item));
  52800             JS_FreeValue(ctx, item);
  52801             if (found) {
  52802                 JS_IteratorClose(ctx, iter, FALSE);
  52803                 break;
  52804             }
  52805         }
  52806     }
  52807     rval = !found ? JS_TRUE : JS_FALSE;
  52808 exception:
  52809     JS_FreeValue(ctx, has);
  52810     JS_FreeValue(ctx, keys);
  52811     JS_FreeValue(ctx, iter);
  52812     JS_FreeValue(ctx, next);
  52813     return rval;
  52814 }
  52815 
  52816 static JSValue js_set_isSubsetOf(JSContext *ctx, JSValueConst this_val,
  52817                                  int argc, JSValueConst *argv)
  52818 {
  52819     JSValue item, iter, keys, has, next, rv, rval;
  52820     BOOL found;
  52821     JSMapState *s;
  52822     int64_t size;
  52823     int done, ok;
  52824 
  52825     iter = JS_UNDEFINED;
  52826     next = JS_UNDEFINED;
  52827     rval = JS_EXCEPTION;
  52828     s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
  52829     if (!s)
  52830         return JS_EXCEPTION;
  52831     if (get_set_record(ctx, argv[0], &size, &has, &keys) < 0)
  52832         goto exception;
  52833     found = FALSE;
  52834     if (s->record_count > size)
  52835         goto fini;
  52836     iter = js_create_map_iterator(ctx, this_val, 0, NULL, MAGIC_SET);
  52837     if (JS_IsException(iter))
  52838         goto exception;
  52839     found = TRUE;
  52840     do {
  52841         item = js_map_iterator_next(ctx, iter, 0, NULL, &done, MAGIC_SET);
  52842         if (JS_IsException(item))
  52843             goto exception;
  52844         if (done) // item is JS_UNDEFINED
  52845             break;
  52846         rv = JS_Call(ctx, has, argv[0], 1, (JSValueConst *)&item);
  52847         JS_FreeValue(ctx, item);
  52848         ok = JS_ToBoolFree(ctx, rv); // returns -1 if rv is JS_EXCEPTION
  52849         if (ok < 0)
  52850             goto exception;
  52851         found = (ok > 0);
  52852     } while (found);
  52853 fini:
  52854     rval = found ? JS_TRUE : JS_FALSE;
  52855 exception:
  52856     JS_FreeValue(ctx, has);
  52857     JS_FreeValue(ctx, keys);
  52858     JS_FreeValue(ctx, iter);
  52859     JS_FreeValue(ctx, next);
  52860     return rval;
  52861 }
  52862 
  52863 static JSValue js_set_isSupersetOf(JSContext *ctx, JSValueConst this_val,
  52864                                    int argc, JSValueConst *argv)
  52865 {
  52866     JSValue item, iter, keys, has, next, rval;
  52867     int done;
  52868     BOOL found;
  52869     JSMapState *s;
  52870     int64_t size;
  52871 
  52872     iter = JS_UNDEFINED;
  52873     next = JS_UNDEFINED;
  52874     rval = JS_EXCEPTION;
  52875     s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
  52876     if (!s)
  52877         return JS_EXCEPTION;
  52878     if (get_set_record(ctx, argv[0], &size, &has, &keys) < 0)
  52879         goto exception;
  52880     found = FALSE;
  52881     if (s->record_count < size)
  52882         goto fini;
  52883     iter = JS_Call(ctx, keys, argv[0], 0, NULL);
  52884     if (JS_IsException(iter))
  52885         goto exception;
  52886     next = JS_GetProperty(ctx, iter, JS_ATOM_next);
  52887     if (JS_IsException(next))
  52888         goto exception;
  52889     found = TRUE;
  52890     for(;;) {
  52891         item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
  52892         if (JS_IsException(item))
  52893             goto exception;
  52894         if (done) // item is JS_UNDEFINED
  52895             break;
  52896         item = map_normalize_key(ctx, item);
  52897         found = (NULL != map_find_record(ctx, s, item));
  52898         JS_FreeValue(ctx, item);
  52899         if (!found) {
  52900             JS_IteratorClose(ctx, iter, FALSE);
  52901             break;
  52902         }
  52903     }
  52904 fini:
  52905     rval = found ? JS_TRUE : JS_FALSE;
  52906 exception:
  52907     JS_FreeValue(ctx, has);
  52908     JS_FreeValue(ctx, keys);
  52909     JS_FreeValue(ctx, iter);
  52910     JS_FreeValue(ctx, next);
  52911     return rval;
  52912 }
  52913 
  52914 static JSValue js_set_intersection(JSContext *ctx, JSValueConst this_val,
  52915                                    int argc, JSValueConst *argv)
  52916 {
  52917     JSValue newset, item, iter, keys, has, next, rv;
  52918     JSMapState *s, *t;
  52919     JSMapRecord *mr;
  52920     int64_t size;
  52921     int done, ok;
  52922 
  52923     iter = JS_UNDEFINED;
  52924     next = JS_UNDEFINED;
  52925     newset = JS_UNDEFINED;
  52926     s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
  52927     if (!s)
  52928         return JS_EXCEPTION;
  52929     if (get_set_record(ctx, argv[0], &size, &has, &keys) < 0)
  52930         goto exception;
  52931     if (s->record_count > size) {
  52932         iter = JS_Call(ctx, keys, argv[0], 0, NULL);
  52933         if (JS_IsException(iter))
  52934             goto exception;
  52935         next = JS_GetProperty(ctx, iter, JS_ATOM_next);
  52936         if (JS_IsException(next))
  52937             goto exception;
  52938         newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET);
  52939         if (JS_IsException(newset))
  52940             goto exception;
  52941         t = JS_GetOpaque(newset, JS_CLASS_SET);
  52942         for (;;) {
  52943             item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
  52944             if (JS_IsException(item))
  52945                 goto exception;
  52946             if (done) // item is JS_UNDEFINED
  52947                 break;
  52948             item = map_normalize_key(ctx, item);
  52949             if (!map_find_record(ctx, s, item)) {
  52950                 JS_FreeValue(ctx, item);
  52951             } else if (map_find_record(ctx, t, item)) {
  52952                 JS_FreeValue(ctx, item); // no duplicates
  52953             } else {
  52954                 mr = set_add_record(ctx, t, item);
  52955                 JS_FreeValue(ctx, item);
  52956                 if (!mr)
  52957                     goto exception;
  52958             }
  52959         }
  52960     } else {
  52961         iter = js_create_map_iterator(ctx, this_val, 0, NULL, MAGIC_SET);
  52962         if (JS_IsException(iter))
  52963             goto exception;
  52964         newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET);
  52965         if (JS_IsException(newset))
  52966             goto exception;
  52967         t = JS_GetOpaque(newset, JS_CLASS_SET);
  52968         for (;;) {
  52969             item = js_map_iterator_next(ctx, iter, 0, NULL, &done, MAGIC_SET);
  52970             if (JS_IsException(item))
  52971                 goto exception;
  52972             if (done) // item is JS_UNDEFINED
  52973                 break;
  52974             rv = JS_Call(ctx, has, argv[0], 1, (JSValueConst *)&item);
  52975             ok = JS_ToBoolFree(ctx, rv); // returns -1 if rv is JS_EXCEPTION
  52976             if (ok > 0) {
  52977                 item = map_normalize_key(ctx, item);
  52978                 if (map_find_record(ctx, t, item)) {
  52979                     JS_FreeValue(ctx, item); // no duplicates
  52980                 } else {
  52981                     mr = set_add_record(ctx, t, item);
  52982                     JS_FreeValue(ctx, item);
  52983                     if (!mr)
  52984                         goto exception;
  52985                 }
  52986             } else {
  52987                 JS_FreeValue(ctx, item);
  52988                 if (ok < 0)
  52989                     goto exception;
  52990             }
  52991         }
  52992     }
  52993     goto fini;
  52994 exception:
  52995     JS_FreeValue(ctx, newset);
  52996     newset = JS_EXCEPTION;
  52997 fini:
  52998     JS_FreeValue(ctx, has);
  52999     JS_FreeValue(ctx, keys);
  53000     JS_FreeValue(ctx, iter);
  53001     JS_FreeValue(ctx, next);
  53002     return newset;
  53003 }
  53004 
  53005 static JSValue js_set_difference(JSContext *ctx, JSValueConst this_val,
  53006                                  int argc, JSValueConst *argv)
  53007 {
  53008     JSValue newset, item, iter, keys, has, next, rv;
  53009     JSMapState *s, *t;
  53010     int64_t size;
  53011     int done;
  53012     int ok;
  53013 
  53014     iter = JS_UNDEFINED;
  53015     next = JS_UNDEFINED;
  53016     newset = JS_UNDEFINED;
  53017     s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
  53018     if (!s)
  53019         return JS_EXCEPTION;
  53020     if (get_set_record(ctx, argv[0], &size, &has, &keys) < 0)
  53021         goto exception;
  53022 
  53023     newset = js_copy_set(ctx, this_val);
  53024     if (JS_IsException(newset))
  53025         goto exception;
  53026     t = JS_GetOpaque(newset, JS_CLASS_SET);
  53027     
  53028     if (s->record_count <= size) {
  53029         iter = js_create_map_iterator(ctx, newset, 0, NULL, MAGIC_SET);
  53030         if (JS_IsException(iter))
  53031             goto exception;
  53032         for (;;) {
  53033             item = js_map_iterator_next(ctx, iter, 0, NULL, &done, MAGIC_SET);
  53034             if (JS_IsException(item))
  53035                 goto exception;
  53036             if (done) // item is JS_UNDEFINED
  53037                 break;
  53038             rv = JS_Call(ctx, has, argv[0], 1, (JSValueConst *)&item);
  53039             ok = JS_ToBoolFree(ctx, rv); // returns -1 if rv is JS_EXCEPTION
  53040             if (ok < 0) {
  53041                 JS_FreeValue(ctx, item);
  53042                 goto exception;
  53043             }
  53044             if (ok) {
  53045                 map_delete_record(ctx, t, item);
  53046             }
  53047             JS_FreeValue(ctx, item);
  53048         }
  53049     } else {
  53050         iter = JS_Call(ctx, keys, argv[0], 0, NULL);
  53051         if (JS_IsException(iter))
  53052             goto exception;
  53053         next = JS_GetProperty(ctx, iter, JS_ATOM_next);
  53054         if (JS_IsException(next))
  53055             goto exception;
  53056         for (;;) {
  53057             item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
  53058             if (JS_IsException(item))
  53059                 goto exception;
  53060             if (done) // item is JS_UNDEFINED
  53061                 break;
  53062             map_delete_record(ctx, t, item);
  53063             JS_FreeValue(ctx, item);
  53064         }
  53065     }
  53066     goto fini;
  53067 exception:
  53068     JS_FreeValue(ctx, newset);
  53069     newset = JS_EXCEPTION;
  53070 fini:
  53071     JS_FreeValue(ctx, has);
  53072     JS_FreeValue(ctx, keys);
  53073     JS_FreeValue(ctx, iter);
  53074     JS_FreeValue(ctx, next);
  53075     return newset;
  53076 }
  53077 
  53078 static JSValue js_set_symmetricDifference(JSContext *ctx, JSValueConst this_val,
  53079                                           int argc, JSValueConst *argv)
  53080 {
  53081     JSValue newset, item, iter, next, has, keys;
  53082     JSMapState *s, *t;
  53083     JSMapRecord *mr;
  53084     int64_t size;
  53085     int done;
  53086     BOOL present;
  53087 
  53088     s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
  53089     if (!s)
  53090         return JS_EXCEPTION;
  53091     if (get_set_record(ctx, argv[0], &size, &has, &keys) < 0)
  53092         return JS_EXCEPTION;
  53093     JS_FreeValue(ctx, has);
  53094 
  53095     next = JS_UNDEFINED;
  53096     newset = JS_UNDEFINED;
  53097     iter = JS_Call(ctx, keys, argv[0], 0, NULL);
  53098     if (JS_IsException(iter))
  53099         goto exception;
  53100     next = JS_GetProperty(ctx, iter, JS_ATOM_next);
  53101     if (JS_IsException(next))
  53102         goto exception;
  53103     newset = js_copy_set(ctx, this_val);
  53104     if (JS_IsException(newset))
  53105         goto exception;
  53106     t = JS_GetOpaque(newset, JS_CLASS_SET);
  53107     for (;;) {
  53108         item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
  53109         if (JS_IsException(item))
  53110             goto exception;
  53111         if (done) // item is JS_UNDEFINED
  53112             break;
  53113         // note the subtlety here: due to mutating iterators, it's
  53114         // possible for keys to disappear during iteration; test262
  53115         // still expects us to maintain insertion order though, so
  53116         // we first check |this|, then |new|; |new| is a copy of |this|
  53117         // - if item exists in |this|, delete (if it exists) from |new|
  53118         // - if item misses in |this| and |new|, add to |new|
  53119         // - if item exists in |new| but misses in |this|, *don't* add it,
  53120         //   mutating iterator erased it
  53121         item = map_normalize_key(ctx, item);
  53122         present = (NULL != map_find_record(ctx, s, item));
  53123         mr = map_find_record(ctx, t, item);
  53124         if (present) {
  53125             map_delete_record(ctx, t, item);
  53126             JS_FreeValue(ctx, item);
  53127         } else if (mr) {
  53128             JS_FreeValue(ctx, item);
  53129         } else {
  53130             mr = set_add_record(ctx, t, item);
  53131             JS_FreeValue(ctx, item);
  53132             if (!mr)
  53133                 goto exception;
  53134         }
  53135     }
  53136     goto fini;
  53137 exception:
  53138     JS_FreeValue(ctx, newset);
  53139     newset = JS_EXCEPTION;
  53140 fini:
  53141     JS_FreeValue(ctx, next);
  53142     JS_FreeValue(ctx, iter);
  53143     JS_FreeValue(ctx, keys);
  53144     return newset;
  53145 }
  53146 
  53147 static JSValue js_set_union(JSContext *ctx, JSValueConst this_val,
  53148                             int argc, JSValueConst *argv)
  53149 {
  53150     JSValue newset, item, iter, next, has, keys, rv;
  53151     JSMapState *s;
  53152     int64_t size;
  53153     int done;
  53154 
  53155     s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);
  53156     if (!s)
  53157         return JS_EXCEPTION;
  53158     if (get_set_record(ctx, argv[0], &size, &has, &keys) < 0)
  53159         return JS_EXCEPTION;
  53160     JS_FreeValue(ctx, has);
  53161 
  53162     next = JS_UNDEFINED;
  53163     newset = JS_UNDEFINED;
  53164     iter = JS_Call(ctx, keys, argv[0], 0, NULL);
  53165     if (JS_IsException(iter))
  53166         goto exception;
  53167     next = JS_GetProperty(ctx, iter, JS_ATOM_next);
  53168     if (JS_IsException(next))
  53169         goto exception;
  53170 
  53171     newset = js_copy_set(ctx, this_val);
  53172     if (JS_IsException(newset))
  53173         goto exception;
  53174 
  53175     for (;;) {
  53176         item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
  53177         if (JS_IsException(item))
  53178             goto exception;
  53179         if (done) // item is JS_UNDEFINED
  53180             break;
  53181         rv = js_map_set(ctx, newset, 1, (JSValueConst *)&item, MAGIC_SET);
  53182         JS_FreeValue(ctx, item);
  53183         if (JS_IsException(rv))
  53184             goto exception;
  53185         JS_FreeValue(ctx, rv);
  53186     }
  53187     goto fini;
  53188 exception:
  53189     JS_FreeValue(ctx, newset);
  53190     newset = JS_EXCEPTION;
  53191 fini:
  53192     JS_FreeValue(ctx, next);
  53193     JS_FreeValue(ctx, iter);
  53194     JS_FreeValue(ctx, keys);
  53195     return newset;
  53196 }
  53197 
  53198 static const JSCFunctionListEntry js_map_funcs[] = {
  53199     JS_CFUNC_MAGIC_DEF("groupBy", 2, js_object_groupBy, 1 ),
  53200     JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
  53201 };
  53202 
  53203 static const JSCFunctionListEntry js_map_proto_funcs[] = {
  53204     JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, 0 ),
  53205     JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, 0 ),
  53206     JS_CFUNC_MAGIC_DEF("getOrInsert", 2, js_map_getOrInsert,
  53207                        (JS_CLASS_MAP << 1) | /*computed*/FALSE ),
  53208     JS_CFUNC_MAGIC_DEF("getOrInsertComputed", 2, js_map_getOrInsert,
  53209                        (JS_CLASS_MAP << 1) | /*computed*/TRUE ),
  53210     JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, 0 ),
  53211     JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, 0 ),
  53212     JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, 0 ),
  53213     JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, 0),
  53214     JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, 0 ),
  53215     JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_VALUE << 2) | 0 ),
  53216     JS_CFUNC_MAGIC_DEF("keys", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | 0 ),
  53217     JS_CFUNC_MAGIC_DEF("entries", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | 0 ),
  53218     JS_ALIAS_DEF("[Symbol.iterator]", "entries" ),
  53219     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Map", JS_PROP_CONFIGURABLE ),
  53220 };
  53221 
  53222 static const JSCFunctionListEntry js_map_iterator_proto_funcs[] = {
  53223     JS_ITERATOR_NEXT_DEF("next", 0, js_map_iterator_next, 0 ),
  53224     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Map Iterator", JS_PROP_CONFIGURABLE ),
  53225 };
  53226 
  53227 static const JSCFunctionListEntry js_set_proto_funcs[] = {
  53228     JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET ),
  53229     JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET ),
  53230     JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET ),
  53231     JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, MAGIC_SET ),
  53232     JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, MAGIC_SET ),
  53233     JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, MAGIC_SET ),
  53234     JS_CFUNC_DEF("isDisjointFrom", 1, js_set_isDisjointFrom ),
  53235     JS_CFUNC_DEF("isSubsetOf", 1, js_set_isSubsetOf ),
  53236     JS_CFUNC_DEF("isSupersetOf", 1, js_set_isSupersetOf ),
  53237     JS_CFUNC_DEF("intersection", 1, js_set_intersection ),
  53238     JS_CFUNC_DEF("difference", 1, js_set_difference ),
  53239     JS_CFUNC_DEF("symmetricDifference", 1, js_set_symmetricDifference ),
  53240     JS_CFUNC_DEF("union", 1, js_set_union ),
  53241     JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | MAGIC_SET ),
  53242     JS_ALIAS_DEF("keys", "values" ),
  53243     JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
  53244     JS_CFUNC_MAGIC_DEF("entries", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | MAGIC_SET ),
  53245     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set", JS_PROP_CONFIGURABLE ),
  53246 };
  53247 
  53248 static const JSCFunctionListEntry js_set_iterator_proto_funcs[] = {
  53249     JS_ITERATOR_NEXT_DEF("next", 0, js_map_iterator_next, MAGIC_SET ),
  53250     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set Iterator", JS_PROP_CONFIGURABLE ),
  53251 };
  53252 
  53253 static const JSCFunctionListEntry js_weak_map_proto_funcs[] = {
  53254     JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, MAGIC_WEAK ),
  53255     JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, MAGIC_WEAK ),
  53256     JS_CFUNC_MAGIC_DEF("getOrInsert", 2, js_map_getOrInsert,
  53257                        (JS_CLASS_WEAKMAP << 1) | /*computed*/FALSE ),
  53258     JS_CFUNC_MAGIC_DEF("getOrInsertComputed", 2, js_map_getOrInsert,
  53259                        (JS_CLASS_WEAKMAP << 1) | /*computed*/TRUE ),
  53260     JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_WEAK ),
  53261     JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_WEAK ),
  53262     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakMap", JS_PROP_CONFIGURABLE ),
  53263 };
  53264 
  53265 static const JSCFunctionListEntry js_weak_set_proto_funcs[] = {
  53266     JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET | MAGIC_WEAK ),
  53267     JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET | MAGIC_WEAK ),
  53268     JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET | MAGIC_WEAK ),
  53269     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakSet", JS_PROP_CONFIGURABLE ),
  53270 };
  53271 
  53272 static const JSCFunctionListEntry * const js_map_proto_funcs_ptr[6] = {
  53273     js_map_proto_funcs,
  53274     js_set_proto_funcs,
  53275     js_weak_map_proto_funcs,
  53276     js_weak_set_proto_funcs,
  53277     js_map_iterator_proto_funcs,
  53278     js_set_iterator_proto_funcs,
  53279 };
  53280 
  53281 static const uint8_t js_map_proto_funcs_count[6] = {
  53282     countof(js_map_proto_funcs),
  53283     countof(js_set_proto_funcs),
  53284     countof(js_weak_map_proto_funcs),
  53285     countof(js_weak_set_proto_funcs),
  53286     countof(js_map_iterator_proto_funcs),
  53287     countof(js_set_iterator_proto_funcs),
  53288 };
  53289 
  53290 int JS_AddIntrinsicMapSet(JSContext *ctx)
  53291 {
  53292     int i;
  53293     JSValue obj1;
  53294     char buf[ATOM_GET_STR_BUF_SIZE];
  53295 
  53296     for(i = 0; i < 4; i++) {
  53297         JSCFunctionType ft;
  53298         const char *name = JS_AtomGetStr(ctx, buf, sizeof(buf),
  53299                                          JS_ATOM_Map + i);
  53300         ft.constructor_magic = js_map_constructor;
  53301         obj1 = JS_NewCConstructor(ctx, JS_CLASS_MAP + i, name,
  53302                                   ft.generic, 0, JS_CFUNC_constructor_magic, i,
  53303                                   JS_UNDEFINED,
  53304                                   js_map_funcs, i < 2 ? countof(js_map_funcs) : 0,
  53305                                   js_map_proto_funcs_ptr[i], js_map_proto_funcs_count[i],
  53306                                   0);
  53307         if (JS_IsException(obj1))
  53308             return -1;
  53309         JS_FreeValue(ctx, obj1);
  53310     }
  53311 
  53312     for(i = 0; i < 2; i++) {
  53313         ctx->class_proto[JS_CLASS_MAP_ITERATOR + i] =
  53314             JS_NewObjectProtoList(ctx, ctx->class_proto[JS_CLASS_ITERATOR], 
  53315                                   js_map_proto_funcs_ptr[i + 4],
  53316                                   js_map_proto_funcs_count[i + 4]);
  53317         if (JS_IsException(ctx->class_proto[JS_CLASS_MAP_ITERATOR + i]))
  53318             return -1;
  53319     }
  53320     return 0;
  53321 }
  53322 
  53323 /* Generator */
  53324 static const JSCFunctionListEntry js_generator_function_proto_funcs[] = {
  53325     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "GeneratorFunction", JS_PROP_CONFIGURABLE),
  53326 };
  53327 
  53328 static const JSCFunctionListEntry js_generator_proto_funcs[] = {
  53329     JS_ITERATOR_NEXT_DEF("next", 1, js_generator_next, GEN_MAGIC_NEXT ),
  53330     JS_ITERATOR_NEXT_DEF("return", 1, js_generator_next, GEN_MAGIC_RETURN ),
  53331     JS_ITERATOR_NEXT_DEF("throw", 1, js_generator_next, GEN_MAGIC_THROW ),
  53332     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Generator", JS_PROP_CONFIGURABLE),
  53333 };
  53334 
  53335 /* Promise */
  53336 
  53337 typedef struct JSPromiseData {
  53338     JSPromiseStateEnum promise_state;
  53339     /* 0=fulfill, 1=reject, list of JSPromiseReactionData.link */
  53340     struct list_head promise_reactions[2];
  53341     BOOL is_handled; /* Note: only useful to debug */
  53342     JSValue promise_result;
  53343 } JSPromiseData;
  53344 
  53345 typedef struct JSPromiseFunctionDataResolved {
  53346     int ref_count;
  53347     BOOL already_resolved;
  53348 } JSPromiseFunctionDataResolved;
  53349 
  53350 typedef struct JSPromiseFunctionData {
  53351     JSValue promise;
  53352     JSPromiseFunctionDataResolved *presolved;
  53353 } JSPromiseFunctionData;
  53354 
  53355 typedef struct JSPromiseReactionData {
  53356     struct list_head link; /* not used in promise_reaction_job */
  53357     JSValue resolving_funcs[2];
  53358     JSValue handler;
  53359 } JSPromiseReactionData;
  53360 
  53361 JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise)
  53362 {
  53363     JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
  53364     if (!s)
  53365         return -1;
  53366     return s->promise_state;
  53367 }
  53368 
  53369 JSValue JS_PromiseResult(JSContext *ctx, JSValue promise)
  53370 {
  53371     JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
  53372     if (!s)
  53373         return JS_UNDEFINED;
  53374     return JS_DupValue(ctx, s->promise_result);
  53375 }
  53376 
  53377 static int js_create_resolving_functions(JSContext *ctx, JSValue *args,
  53378                                          JSValueConst promise);
  53379 
  53380 static void promise_reaction_data_free(JSRuntime *rt,
  53381                                        JSPromiseReactionData *rd)
  53382 {
  53383     JS_FreeValueRT(rt, rd->resolving_funcs[0]);
  53384     JS_FreeValueRT(rt, rd->resolving_funcs[1]);
  53385     JS_FreeValueRT(rt, rd->handler);
  53386     js_free_rt(rt, rd);
  53387 }
  53388 
  53389 static JSValue promise_reaction_job(JSContext *ctx, int argc,
  53390                                     JSValueConst *argv)
  53391 {
  53392     JSValueConst handler, arg, func;
  53393     JSValue res, res2;
  53394     BOOL is_reject;
  53395 
  53396     assert(argc == 5);
  53397     handler = argv[2];
  53398     is_reject = JS_ToBool(ctx, argv[3]);
  53399     arg = argv[4];
  53400 #ifdef DUMP_PROMISE
  53401     printf("promise_reaction_job: is_reject=%d\n", is_reject);
  53402 #endif
  53403 
  53404     if (JS_IsUndefined(handler)) {
  53405         if (is_reject) {
  53406             res = JS_Throw(ctx, JS_DupValue(ctx, arg));
  53407         } else {
  53408             res = JS_DupValue(ctx, arg);
  53409         }
  53410     } else {
  53411         res = JS_Call(ctx, handler, JS_UNDEFINED, 1, &arg);
  53412     }
  53413     is_reject = JS_IsException(res);
  53414     if (is_reject)
  53415         res = JS_GetException(ctx);
  53416     func = argv[is_reject];
  53417     /* as an extension, we support undefined as value to avoid
  53418        creating a dummy promise in the 'await' implementation of async
  53419        functions */
  53420     if (!JS_IsUndefined(func)) {
  53421         res2 = JS_Call(ctx, func, JS_UNDEFINED,
  53422                        1, (JSValueConst *)&res);
  53423     } else {
  53424         res2 = JS_UNDEFINED;
  53425     }
  53426     JS_FreeValue(ctx, res);
  53427 
  53428     return res2;
  53429 }
  53430 
  53431 void JS_SetHostPromiseRejectionTracker(JSRuntime *rt,
  53432                                        JSHostPromiseRejectionTracker *cb,
  53433                                        void *opaque)
  53434 {
  53435     rt->host_promise_rejection_tracker = cb;
  53436     rt->host_promise_rejection_tracker_opaque = opaque;
  53437 }
  53438 
  53439 static void fulfill_or_reject_promise(JSContext *ctx, JSValueConst promise,
  53440                                       JSValueConst value, BOOL is_reject)
  53441 {
  53442     JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
  53443     struct list_head *el, *el1;
  53444     JSPromiseReactionData *rd;
  53445     JSValueConst args[5];
  53446 
  53447     if (!s || s->promise_state != JS_PROMISE_PENDING)
  53448         return; /* should never happen */
  53449     set_value(ctx, &s->promise_result, JS_DupValue(ctx, value));
  53450     s->promise_state = JS_PROMISE_FULFILLED + is_reject;
  53451 #ifdef DUMP_PROMISE
  53452     printf("fulfill_or_reject_promise: is_reject=%d\n", is_reject);
  53453 #endif
  53454     if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {
  53455         JSRuntime *rt = ctx->rt;
  53456         if (rt->host_promise_rejection_tracker) {
  53457             rt->host_promise_rejection_tracker(ctx, promise, value, FALSE,
  53458                                                rt->host_promise_rejection_tracker_opaque);
  53459         }
  53460     }
  53461 
  53462     list_for_each_safe(el, el1, &s->promise_reactions[is_reject]) {
  53463         rd = list_entry(el, JSPromiseReactionData, link);
  53464         args[0] = rd->resolving_funcs[0];
  53465         args[1] = rd->resolving_funcs[1];
  53466         args[2] = rd->handler;
  53467         args[3] = JS_NewBool(ctx, is_reject);
  53468         args[4] = value;
  53469         JS_EnqueueJob(ctx, promise_reaction_job, 5, args);
  53470         list_del(&rd->link);
  53471         promise_reaction_data_free(ctx->rt, rd);
  53472     }
  53473 
  53474     list_for_each_safe(el, el1, &s->promise_reactions[1 - is_reject]) {
  53475         rd = list_entry(el, JSPromiseReactionData, link);
  53476         list_del(&rd->link);
  53477         promise_reaction_data_free(ctx->rt, rd);
  53478     }
  53479 }
  53480 
  53481 static void reject_promise(JSContext *ctx, JSValueConst promise,
  53482                            JSValueConst value)
  53483 {
  53484     fulfill_or_reject_promise(ctx, promise, value, TRUE);
  53485 }
  53486 
  53487 static JSValue js_promise_resolve_thenable_job(JSContext *ctx,
  53488                                                int argc, JSValueConst *argv)
  53489 {
  53490     JSValueConst promise, thenable, then;
  53491     JSValue args[2], res;
  53492 
  53493 #ifdef DUMP_PROMISE
  53494     printf("js_promise_resolve_thenable_job\n");
  53495 #endif
  53496     assert(argc == 3);
  53497     promise = argv[0];
  53498     thenable = argv[1];
  53499     then = argv[2];
  53500     if (js_create_resolving_functions(ctx, args, promise) < 0)
  53501         return JS_EXCEPTION;
  53502     res = JS_Call(ctx, then, thenable, 2, (JSValueConst *)args);
  53503     if (JS_IsException(res)) {
  53504         JSValue error = JS_GetException(ctx);
  53505         res = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error);
  53506         JS_FreeValue(ctx, error);
  53507     }
  53508     JS_FreeValue(ctx, args[0]);
  53509     JS_FreeValue(ctx, args[1]);
  53510     return res;
  53511 }
  53512 
  53513 static void js_promise_resolve_function_free_resolved(JSRuntime *rt,
  53514                                                       JSPromiseFunctionDataResolved *sr)
  53515 {
  53516     if (--sr->ref_count == 0) {
  53517         js_free_rt(rt, sr);
  53518     }
  53519 }
  53520 
  53521 static int js_create_resolving_functions(JSContext *ctx,
  53522                                          JSValue *resolving_funcs,
  53523                                          JSValueConst promise)
  53524 
  53525 {
  53526     JSValue obj;
  53527     JSPromiseFunctionData *s;
  53528     JSPromiseFunctionDataResolved *sr;
  53529     int i, ret;
  53530 
  53531     sr = js_malloc(ctx, sizeof(*sr));
  53532     if (!sr)
  53533         return -1;
  53534     sr->ref_count = 1;
  53535     sr->already_resolved = FALSE; /* must be shared between the two functions */
  53536     ret = 0;
  53537     for(i = 0; i < 2; i++) {
  53538         obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
  53539                                      JS_CLASS_PROMISE_RESOLVE_FUNCTION + i);
  53540         if (JS_IsException(obj))
  53541             goto fail;
  53542         s = js_malloc(ctx, sizeof(*s));
  53543         if (!s) {
  53544             JS_FreeValue(ctx, obj);
  53545         fail:
  53546 
  53547             if (i != 0)
  53548                 JS_FreeValue(ctx, resolving_funcs[0]);
  53549             ret = -1;
  53550             break;
  53551         }
  53552         sr->ref_count++;
  53553         s->presolved = sr;
  53554         s->promise = JS_DupValue(ctx, promise);
  53555         JS_SetOpaque(obj, s);
  53556         js_function_set_properties(ctx, obj, JS_ATOM_empty_string, 1);
  53557         resolving_funcs[i] = obj;
  53558     }
  53559     js_promise_resolve_function_free_resolved(ctx->rt, sr);
  53560     return ret;
  53561 }
  53562 
  53563 static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val)
  53564 {
  53565     JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data;
  53566     if (s) {
  53567         js_promise_resolve_function_free_resolved(rt, s->presolved);
  53568         JS_FreeValueRT(rt, s->promise);
  53569         js_free_rt(rt, s);
  53570     }
  53571 }
  53572 
  53573 static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
  53574                                              JS_MarkFunc *mark_func)
  53575 {
  53576     JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data;
  53577     if (s) {
  53578         JS_MarkValue(rt, s->promise, mark_func);
  53579     }
  53580 }
  53581 
  53582 static JSValue js_promise_resolve_function_call(JSContext *ctx,
  53583                                                 JSValueConst func_obj,
  53584                                                 JSValueConst this_val,
  53585                                                 int argc, JSValueConst *argv,
  53586                                                 int flags)
  53587 {
  53588     JSObject *p = JS_VALUE_GET_OBJ(func_obj);
  53589     JSPromiseFunctionData *s;
  53590     JSValueConst resolution, args[3];
  53591     JSValue then;
  53592     BOOL is_reject;
  53593 
  53594     s = p->u.promise_function_data;
  53595     if (!s || s->presolved->already_resolved)
  53596         return JS_UNDEFINED;
  53597     s->presolved->already_resolved = TRUE;
  53598     is_reject = p->class_id - JS_CLASS_PROMISE_RESOLVE_FUNCTION;
  53599     if (argc > 0)
  53600         resolution = argv[0];
  53601     else
  53602         resolution = JS_UNDEFINED;
  53603 #ifdef DUMP_PROMISE
  53604     printf("js_promise_resolving_function_call: is_reject=%d ", is_reject);
  53605     JS_DumpValue(ctx, "resolution", resolution);
  53606     printf("\n");
  53607 #endif
  53608     if (is_reject || !JS_IsObject(resolution)) {
  53609         goto done;
  53610     } else if (js_same_value(ctx, resolution, s->promise)) {
  53611         JS_ThrowTypeError(ctx, "promise self resolution");
  53612         goto fail_reject;
  53613     }
  53614     then = JS_GetProperty(ctx, resolution, JS_ATOM_then);
  53615     if (JS_IsException(then)) {
  53616         JSValue error;
  53617     fail_reject:
  53618         error = JS_GetException(ctx);
  53619         reject_promise(ctx, s->promise, error);
  53620         JS_FreeValue(ctx, error);
  53621     } else if (!JS_IsFunction(ctx, then)) {
  53622         JS_FreeValue(ctx, then);
  53623     done:
  53624         fulfill_or_reject_promise(ctx, s->promise, resolution, is_reject);
  53625     } else {
  53626         args[0] = s->promise;
  53627         args[1] = resolution;
  53628         args[2] = then;
  53629         JS_EnqueueJob(ctx, js_promise_resolve_thenable_job, 3, args);
  53630         JS_FreeValue(ctx, then);
  53631     }
  53632     return JS_UNDEFINED;
  53633 }
  53634 
  53635 static void js_promise_finalizer(JSRuntime *rt, JSValue val)
  53636 {
  53637     JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE);
  53638     struct list_head *el, *el1;
  53639     int i;
  53640 
  53641     if (!s)
  53642         return;
  53643     for(i = 0; i < 2; i++) {
  53644         list_for_each_safe(el, el1, &s->promise_reactions[i]) {
  53645             JSPromiseReactionData *rd =
  53646                 list_entry(el, JSPromiseReactionData, link);
  53647             promise_reaction_data_free(rt, rd);
  53648         }
  53649     }
  53650     JS_FreeValueRT(rt, s->promise_result);
  53651     js_free_rt(rt, s);
  53652 }
  53653 
  53654 static void js_promise_mark(JSRuntime *rt, JSValueConst val,
  53655                             JS_MarkFunc *mark_func)
  53656 {
  53657     JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE);
  53658     struct list_head *el;
  53659     int i;
  53660 
  53661     if (!s)
  53662         return;
  53663     for(i = 0; i < 2; i++) {
  53664         list_for_each(el, &s->promise_reactions[i]) {
  53665             JSPromiseReactionData *rd =
  53666                 list_entry(el, JSPromiseReactionData, link);
  53667             JS_MarkValue(rt, rd->resolving_funcs[0], mark_func);
  53668             JS_MarkValue(rt, rd->resolving_funcs[1], mark_func);
  53669             JS_MarkValue(rt, rd->handler, mark_func);
  53670         }
  53671     }
  53672     JS_MarkValue(rt, s->promise_result, mark_func);
  53673 }
  53674 
  53675 static JSValue js_promise_constructor(JSContext *ctx, JSValueConst new_target,
  53676                                       int argc, JSValueConst *argv)
  53677 {
  53678     JSValueConst executor;
  53679     JSValue obj;
  53680     JSPromiseData *s;
  53681     JSValue args[2], ret;
  53682     int i;
  53683 
  53684     executor = argv[0];
  53685     if (check_function(ctx, executor))
  53686         return JS_EXCEPTION;
  53687     obj = js_create_from_ctor(ctx, new_target, JS_CLASS_PROMISE);
  53688     if (JS_IsException(obj))
  53689         return JS_EXCEPTION;
  53690     s = js_mallocz(ctx, sizeof(*s));
  53691     if (!s)
  53692         goto fail;
  53693     s->promise_state = JS_PROMISE_PENDING;
  53694     s->is_handled = FALSE;
  53695     for(i = 0; i < 2; i++)
  53696         init_list_head(&s->promise_reactions[i]);
  53697     s->promise_result = JS_UNDEFINED;
  53698     JS_SetOpaque(obj, s);
  53699     if (js_create_resolving_functions(ctx, args, obj))
  53700         goto fail;
  53701     ret = JS_Call(ctx, executor, JS_UNDEFINED, 2, (JSValueConst *)args);
  53702     if (JS_IsException(ret)) {
  53703         JSValue ret2, error;
  53704         error = JS_GetException(ctx);
  53705         ret2 = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error);
  53706         JS_FreeValue(ctx, error);
  53707         if (JS_IsException(ret2))
  53708             goto fail1;
  53709         JS_FreeValue(ctx, ret2);
  53710     }
  53711     JS_FreeValue(ctx, ret);
  53712     JS_FreeValue(ctx, args[0]);
  53713     JS_FreeValue(ctx, args[1]);
  53714     return obj;
  53715  fail1:
  53716     JS_FreeValue(ctx, args[0]);
  53717     JS_FreeValue(ctx, args[1]);
  53718  fail:
  53719     JS_FreeValue(ctx, obj);
  53720     return JS_EXCEPTION;
  53721 }
  53722 
  53723 static JSValue js_promise_executor(JSContext *ctx,
  53724                                    JSValueConst this_val,
  53725                                    int argc, JSValueConst *argv,
  53726                                    int magic, JSValue *func_data)
  53727 {
  53728     int i;
  53729 
  53730     for(i = 0; i < 2; i++) {
  53731         if (!JS_IsUndefined(func_data[i]))
  53732             return JS_ThrowTypeError(ctx, "resolving function already set");
  53733         func_data[i] = JS_DupValue(ctx, argv[i]);
  53734     }
  53735     return JS_UNDEFINED;
  53736 }
  53737 
  53738 static JSValue js_promise_executor_new(JSContext *ctx)
  53739 {
  53740     JSValueConst func_data[2];
  53741 
  53742     func_data[0] = JS_UNDEFINED;
  53743     func_data[1] = JS_UNDEFINED;
  53744     return JS_NewCFunctionData(ctx, js_promise_executor, 2,
  53745                                0, 2, func_data);
  53746 }
  53747 
  53748 static JSValue js_new_promise_capability(JSContext *ctx,
  53749                                          JSValue *resolving_funcs,
  53750                                          JSValueConst ctor)
  53751 {
  53752     JSValue executor, result_promise;
  53753     JSCFunctionDataRecord *s;
  53754     int i;
  53755 
  53756     executor = js_promise_executor_new(ctx);
  53757     if (JS_IsException(executor))
  53758         return executor;
  53759 
  53760     if (JS_IsUndefined(ctor)) {
  53761         result_promise = js_promise_constructor(ctx, ctor, 1,
  53762                                                 (JSValueConst *)&executor);
  53763     } else {
  53764         result_promise = JS_CallConstructor(ctx, ctor, 1,
  53765                                             (JSValueConst *)&executor);
  53766     }
  53767     if (JS_IsException(result_promise))
  53768         goto fail;
  53769     s = JS_GetOpaque(executor, JS_CLASS_C_FUNCTION_DATA);
  53770     for(i = 0; i < 2; i++) {
  53771         if (check_function(ctx, s->data[i]))
  53772             goto fail;
  53773     }
  53774     for(i = 0; i < 2; i++)
  53775         resolving_funcs[i] = JS_DupValue(ctx, s->data[i]);
  53776     JS_FreeValue(ctx, executor);
  53777     return result_promise;
  53778  fail:
  53779     JS_FreeValue(ctx, executor);
  53780     JS_FreeValue(ctx, result_promise);
  53781     return JS_EXCEPTION;
  53782 }
  53783 
  53784 JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs)
  53785 {
  53786     return js_new_promise_capability(ctx, resolving_funcs, JS_UNDEFINED);
  53787 }
  53788 
  53789 static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
  53790                                   int argc, JSValueConst *argv, int magic)
  53791 {
  53792     JSValue result_promise, resolving_funcs[2], ret;
  53793     BOOL is_reject = magic;
  53794 
  53795     if (!JS_IsObject(this_val))
  53796         return JS_ThrowTypeErrorNotAnObject(ctx);
  53797     if (!is_reject && JS_GetOpaque(argv[0], JS_CLASS_PROMISE)) {
  53798         JSValue ctor;
  53799         BOOL is_same;
  53800         ctor = JS_GetProperty(ctx, argv[0], JS_ATOM_constructor);
  53801         if (JS_IsException(ctor))
  53802             return ctor;
  53803         is_same = js_same_value(ctx, ctor, this_val);
  53804         JS_FreeValue(ctx, ctor);
  53805         if (is_same)
  53806             return JS_DupValue(ctx, argv[0]);
  53807     }
  53808     result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
  53809     if (JS_IsException(result_promise))
  53810         return result_promise;
  53811     ret = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED, 1, argv);
  53812     JS_FreeValue(ctx, resolving_funcs[0]);
  53813     JS_FreeValue(ctx, resolving_funcs[1]);
  53814     if (JS_IsException(ret)) {
  53815         JS_FreeValue(ctx, result_promise);
  53816         return ret;
  53817     }
  53818     JS_FreeValue(ctx, ret);
  53819     return result_promise;
  53820 }
  53821 
  53822 static JSValue js_promise_withResolvers(JSContext *ctx,
  53823                                         JSValueConst this_val,
  53824                                         int argc, JSValueConst *argv)
  53825 {
  53826     JSValue result_promise, resolving_funcs[2], obj;
  53827     if (!JS_IsObject(this_val))
  53828         return JS_ThrowTypeErrorNotAnObject(ctx);
  53829     result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
  53830     if (JS_IsException(result_promise))
  53831         return result_promise;
  53832     obj = JS_NewObject(ctx);
  53833     if (JS_IsException(obj))
  53834         goto exception;
  53835     if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_promise, result_promise,
  53836                                JS_PROP_C_W_E) < 0) {
  53837         goto exception;
  53838     }
  53839     result_promise = JS_UNDEFINED;
  53840     if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_resolve, resolving_funcs[0],
  53841                                JS_PROP_C_W_E) < 0) {
  53842         goto exception;
  53843     }
  53844     resolving_funcs[0] = JS_UNDEFINED;
  53845     if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_reject, resolving_funcs[1],
  53846                                JS_PROP_C_W_E) < 0) {
  53847         goto exception;
  53848     }
  53849     return obj;
  53850 exception:
  53851     JS_FreeValue(ctx, resolving_funcs[0]);
  53852     JS_FreeValue(ctx, resolving_funcs[1]);
  53853     JS_FreeValue(ctx, result_promise);
  53854     JS_FreeValue(ctx, obj);
  53855     return JS_EXCEPTION;
  53856 }
  53857 
  53858 static JSValue js_promise_try(JSContext *ctx, JSValueConst this_val,
  53859                               int argc, JSValueConst *argv)
  53860 {
  53861     JSValue result_promise, resolving_funcs[2], ret, ret2;
  53862     BOOL is_reject = 0;
  53863 
  53864     if (!JS_IsObject(this_val))
  53865         return JS_ThrowTypeErrorNotAnObject(ctx);
  53866     result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
  53867     if (JS_IsException(result_promise))
  53868         return result_promise;
  53869     ret = JS_Call(ctx, argv[0], JS_UNDEFINED, argc - 1, argv + 1);
  53870     if (JS_IsException(ret)) {
  53871         is_reject = 1;
  53872         ret = JS_GetException(ctx);
  53873     }
  53874     ret2 = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED, 1, (JSValueConst *)&ret);
  53875     JS_FreeValue(ctx, resolving_funcs[0]);
  53876     JS_FreeValue(ctx, resolving_funcs[1]);
  53877     JS_FreeValue(ctx, ret);
  53878     if (JS_IsException(ret2)) {
  53879         JS_FreeValue(ctx, result_promise);
  53880         return ret2;
  53881     }
  53882     JS_FreeValue(ctx, ret2);
  53883     return result_promise;
  53884 }
  53885 
  53886 static __exception int remainingElementsCount_add(JSContext *ctx,
  53887                                                   JSValueConst resolve_element_env,
  53888                                                   int addend)
  53889 {
  53890     JSValue val;
  53891     int remainingElementsCount;
  53892 
  53893     val = JS_GetPropertyUint32(ctx, resolve_element_env, 0);
  53894     if (JS_IsException(val))
  53895         return -1;
  53896     if (JS_ToInt32Free(ctx, &remainingElementsCount, val))
  53897         return -1;
  53898     remainingElementsCount += addend;
  53899     if (JS_SetPropertyUint32(ctx, resolve_element_env, 0,
  53900                              JS_NewInt32(ctx, remainingElementsCount)) < 0)
  53901         return -1;
  53902     return (remainingElementsCount == 0);
  53903 }
  53904 
  53905 #define PROMISE_MAGIC_all        0
  53906 #define PROMISE_MAGIC_allSettled 1
  53907 #define PROMISE_MAGIC_any        2
  53908 
  53909 static JSValue js_promise_all_resolve_element(JSContext *ctx,
  53910                                               JSValueConst this_val,
  53911                                               int argc, JSValueConst *argv,
  53912                                               int magic,
  53913                                               JSValue *func_data)
  53914 {
  53915     int resolve_type = magic & 3;
  53916     int is_reject = magic & 4;
  53917     BOOL alreadyCalled = JS_ToBool(ctx, func_data[0]);
  53918     JSValueConst values = func_data[2];
  53919     JSValueConst resolve = func_data[3];
  53920     JSValueConst resolve_element_env = func_data[4];
  53921     JSValue ret, obj;
  53922     int is_zero, index;
  53923 
  53924     if (JS_ToInt32(ctx, &index, func_data[1]))
  53925         return JS_EXCEPTION;
  53926     if (alreadyCalled)
  53927         return JS_UNDEFINED;
  53928     func_data[0] = JS_NewBool(ctx, TRUE);
  53929 
  53930     if (resolve_type == PROMISE_MAGIC_allSettled) {
  53931         JSValue str;
  53932 
  53933         obj = JS_NewObject(ctx);
  53934         if (JS_IsException(obj))
  53935             return JS_EXCEPTION;
  53936         str = js_new_string8(ctx, is_reject ? "rejected" : "fulfilled");
  53937         if (JS_IsException(str))
  53938             goto fail1;
  53939         if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_status,
  53940                                    str,
  53941                                    JS_PROP_C_W_E) < 0)
  53942             goto fail1;
  53943         if (JS_DefinePropertyValue(ctx, obj,
  53944                                    is_reject ? JS_ATOM_reason : JS_ATOM_value,
  53945                                    JS_DupValue(ctx, argv[0]),
  53946                                    JS_PROP_C_W_E) < 0) {
  53947         fail1:
  53948             JS_FreeValue(ctx, obj);
  53949             return JS_EXCEPTION;
  53950         }
  53951     } else {
  53952         obj = JS_DupValue(ctx, argv[0]);
  53953     }
  53954     if (JS_DefinePropertyValueUint32(ctx, values, index,
  53955                                      obj, JS_PROP_C_W_E) < 0)
  53956         return JS_EXCEPTION;
  53957 
  53958     is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1);
  53959     if (is_zero < 0)
  53960         return JS_EXCEPTION;
  53961     if (is_zero) {
  53962         if (resolve_type == PROMISE_MAGIC_any) {
  53963             JSValue error;
  53964             error = js_aggregate_error_constructor(ctx, values);
  53965             if (JS_IsException(error))
  53966                 return JS_EXCEPTION;
  53967             ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&error);
  53968             JS_FreeValue(ctx, error);
  53969         } else {
  53970             ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&values);
  53971         }
  53972         if (JS_IsException(ret))
  53973             return ret;
  53974         JS_FreeValue(ctx, ret);
  53975     }
  53976     return JS_UNDEFINED;
  53977 }
  53978 
  53979 /* magic = 0: Promise.all 1: Promise.allSettled */
  53980 static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
  53981                               int argc, JSValueConst *argv, int magic)
  53982 {
  53983     JSValue result_promise, resolving_funcs[2], item, next_promise, ret;
  53984     JSValue next_method = JS_UNDEFINED, values = JS_UNDEFINED;
  53985     JSValue resolve_element_env = JS_UNDEFINED, resolve_element, reject_element;
  53986     JSValue promise_resolve = JS_UNDEFINED, iter = JS_UNDEFINED;
  53987     JSValueConst then_args[2], resolve_element_data[5];
  53988     BOOL done;
  53989     int index, is_zero, is_promise_any = (magic == PROMISE_MAGIC_any);
  53990 
  53991     if (!JS_IsObject(this_val))
  53992         return JS_ThrowTypeErrorNotAnObject(ctx);
  53993     result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
  53994     if (JS_IsException(result_promise))
  53995         return result_promise;
  53996     promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);
  53997     if (JS_IsException(promise_resolve) ||
  53998         check_function(ctx, promise_resolve))
  53999         goto fail_reject;
  54000     iter = JS_GetIterator(ctx, argv[0], FALSE);
  54001     if (JS_IsException(iter)) {
  54002         JSValue error;
  54003     fail_reject:
  54004         error = JS_GetException(ctx);
  54005         ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
  54006                        (JSValueConst *)&error);
  54007         JS_FreeValue(ctx, error);
  54008         if (JS_IsException(ret))
  54009             goto fail;
  54010         JS_FreeValue(ctx, ret);
  54011     } else {
  54012         next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
  54013         if (JS_IsException(next_method))
  54014             goto fail_reject;
  54015         values = JS_NewArray(ctx);
  54016         if (JS_IsException(values))
  54017             goto fail_reject;
  54018         resolve_element_env = JS_NewArray(ctx);
  54019         if (JS_IsException(resolve_element_env))
  54020             goto fail_reject;
  54021         /* remainingElementsCount field */
  54022         if (JS_DefinePropertyValueUint32(ctx, resolve_element_env, 0,
  54023                                          JS_NewInt32(ctx, 1),
  54024                                          JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
  54025             goto fail_reject;
  54026 
  54027         index = 0;
  54028         for(;;) {
  54029             /* XXX: conformance: should close the iterator if error on 'done'
  54030                access, but not on 'value' access */
  54031             item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
  54032             if (JS_IsException(item))
  54033                 goto fail_reject;
  54034             if (done)
  54035                 break;
  54036             next_promise = JS_Call(ctx, promise_resolve,
  54037                                    this_val, 1, (JSValueConst *)&item);
  54038             JS_FreeValue(ctx, item);
  54039             if (JS_IsException(next_promise)) {
  54040             fail_reject1:
  54041                 JS_IteratorClose(ctx, iter, TRUE);
  54042                 goto fail_reject;
  54043             }
  54044             resolve_element_data[0] = JS_NewBool(ctx, FALSE);
  54045             resolve_element_data[1] = (JSValueConst)JS_NewInt32(ctx, index);
  54046             resolve_element_data[2] = values;
  54047             resolve_element_data[3] = resolving_funcs[is_promise_any];
  54048             resolve_element_data[4] = resolve_element_env;
  54049             resolve_element =
  54050                 JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,
  54051                                     magic, 5, resolve_element_data);
  54052             if (JS_IsException(resolve_element)) {
  54053                 JS_FreeValue(ctx, next_promise);
  54054                 goto fail_reject1;
  54055             }
  54056 
  54057             if (magic == PROMISE_MAGIC_allSettled) {
  54058                 reject_element =
  54059                     JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,
  54060                                         magic | 4, 5, resolve_element_data);
  54061                 if (JS_IsException(reject_element)) {
  54062                     JS_FreeValue(ctx, next_promise);
  54063                     goto fail_reject1;
  54064                 }
  54065             } else if (magic == PROMISE_MAGIC_any) {
  54066                 if (JS_DefinePropertyValueUint32(ctx, values, index,
  54067                                                  JS_UNDEFINED, JS_PROP_C_W_E) < 0)
  54068                     goto fail_reject1;
  54069                 reject_element = resolve_element;
  54070                 resolve_element = JS_DupValue(ctx, resolving_funcs[0]);
  54071             } else {
  54072                 reject_element = JS_DupValue(ctx, resolving_funcs[1]);
  54073             }
  54074 
  54075             if (remainingElementsCount_add(ctx, resolve_element_env, 1) < 0) {
  54076                 JS_FreeValue(ctx, next_promise);
  54077                 JS_FreeValue(ctx, resolve_element);
  54078                 JS_FreeValue(ctx, reject_element);
  54079                 goto fail_reject1;
  54080             }
  54081 
  54082             then_args[0] = resolve_element;
  54083             then_args[1] = reject_element;
  54084             ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2, then_args);
  54085             JS_FreeValue(ctx, resolve_element);
  54086             JS_FreeValue(ctx, reject_element);
  54087             if (check_exception_free(ctx, ret))
  54088                 goto fail_reject1;
  54089             index++;
  54090         }
  54091 
  54092         is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1);
  54093         if (is_zero < 0)
  54094             goto fail_reject;
  54095         if (is_zero) {
  54096             if (magic == PROMISE_MAGIC_any) {
  54097                 JSValue error;
  54098                 error = js_aggregate_error_constructor(ctx, values);
  54099                 if (JS_IsException(error))
  54100                     goto fail_reject;
  54101                 JS_FreeValue(ctx, values);
  54102                 values = error;
  54103             }
  54104             ret = JS_Call(ctx, resolving_funcs[is_promise_any], JS_UNDEFINED,
  54105                           1, (JSValueConst *)&values);
  54106             if (check_exception_free(ctx, ret))
  54107                 goto fail_reject;
  54108         }
  54109     }
  54110  done:
  54111     JS_FreeValue(ctx, promise_resolve);
  54112     JS_FreeValue(ctx, resolve_element_env);
  54113     JS_FreeValue(ctx, values);
  54114     JS_FreeValue(ctx, next_method);
  54115     JS_FreeValue(ctx, iter);
  54116     JS_FreeValue(ctx, resolving_funcs[0]);
  54117     JS_FreeValue(ctx, resolving_funcs[1]);
  54118     return result_promise;
  54119  fail:
  54120     JS_FreeValue(ctx, result_promise);
  54121     result_promise = JS_EXCEPTION;
  54122     goto done;
  54123 }
  54124 
  54125 static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val,
  54126                                int argc, JSValueConst *argv)
  54127 {
  54128     JSValue result_promise, resolving_funcs[2], item, next_promise, ret;
  54129     JSValue next_method = JS_UNDEFINED, iter = JS_UNDEFINED;
  54130     JSValue promise_resolve = JS_UNDEFINED;
  54131     BOOL done;
  54132 
  54133     if (!JS_IsObject(this_val))
  54134         return JS_ThrowTypeErrorNotAnObject(ctx);
  54135     result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
  54136     if (JS_IsException(result_promise))
  54137         return result_promise;
  54138     promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);
  54139     if (JS_IsException(promise_resolve) ||
  54140         check_function(ctx, promise_resolve))
  54141         goto fail_reject;
  54142     iter = JS_GetIterator(ctx, argv[0], FALSE);
  54143     if (JS_IsException(iter)) {
  54144         JSValue error;
  54145     fail_reject:
  54146         error = JS_GetException(ctx);
  54147         ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
  54148                        (JSValueConst *)&error);
  54149         JS_FreeValue(ctx, error);
  54150         if (JS_IsException(ret))
  54151             goto fail;
  54152         JS_FreeValue(ctx, ret);
  54153     } else {
  54154         next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
  54155         if (JS_IsException(next_method))
  54156             goto fail_reject;
  54157 
  54158         for(;;) {
  54159             /* XXX: conformance: should close the iterator if error on 'done'
  54160                access, but not on 'value' access */
  54161             item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
  54162             if (JS_IsException(item))
  54163                 goto fail_reject;
  54164             if (done)
  54165                 break;
  54166             next_promise = JS_Call(ctx, promise_resolve,
  54167                                    this_val, 1, (JSValueConst *)&item);
  54168             JS_FreeValue(ctx, item);
  54169             if (JS_IsException(next_promise)) {
  54170             fail_reject1:
  54171                 JS_IteratorClose(ctx, iter, TRUE);
  54172                 goto fail_reject;
  54173             }
  54174             ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2,
  54175                                 (JSValueConst *)resolving_funcs);
  54176             if (check_exception_free(ctx, ret))
  54177                 goto fail_reject1;
  54178         }
  54179     }
  54180  done:
  54181     JS_FreeValue(ctx, promise_resolve);
  54182     JS_FreeValue(ctx, next_method);
  54183     JS_FreeValue(ctx, iter);
  54184     JS_FreeValue(ctx, resolving_funcs[0]);
  54185     JS_FreeValue(ctx, resolving_funcs[1]);
  54186     return result_promise;
  54187  fail:
  54188     //JS_FreeValue(ctx, next_method); // why not???
  54189     JS_FreeValue(ctx, result_promise);
  54190     result_promise = JS_EXCEPTION;
  54191     goto done;
  54192 }
  54193 
  54194 static __exception int perform_promise_then(JSContext *ctx,
  54195                                             JSValueConst promise,
  54196                                             JSValueConst *resolve_reject,
  54197                                             JSValueConst *cap_resolving_funcs)
  54198 {
  54199     JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
  54200     JSPromiseReactionData *rd_array[2], *rd;
  54201     int i, j;
  54202 
  54203     rd_array[0] = NULL;
  54204     rd_array[1] = NULL;
  54205     for(i = 0; i < 2; i++) {
  54206         JSValueConst handler;
  54207         rd = js_mallocz(ctx, sizeof(*rd));
  54208         if (!rd) {
  54209             if (i == 1)
  54210                 promise_reaction_data_free(ctx->rt, rd_array[0]);
  54211             return -1;
  54212         }
  54213         for(j = 0; j < 2; j++)
  54214             rd->resolving_funcs[j] = JS_DupValue(ctx, cap_resolving_funcs[j]);
  54215         handler = resolve_reject[i];
  54216         if (!JS_IsFunction(ctx, handler))
  54217             handler = JS_UNDEFINED;
  54218         rd->handler = JS_DupValue(ctx, handler);
  54219         rd_array[i] = rd;
  54220     }
  54221 
  54222     if (s->promise_state == JS_PROMISE_PENDING) {
  54223         for(i = 0; i < 2; i++)
  54224             list_add_tail(&rd_array[i]->link, &s->promise_reactions[i]);
  54225     } else {
  54226         JSValueConst args[5];
  54227         if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {
  54228             JSRuntime *rt = ctx->rt;
  54229             if (rt->host_promise_rejection_tracker) {
  54230                 rt->host_promise_rejection_tracker(ctx, promise, s->promise_result,
  54231                                                    TRUE, rt->host_promise_rejection_tracker_opaque);
  54232             }
  54233         }
  54234         i = s->promise_state - JS_PROMISE_FULFILLED;
  54235         rd = rd_array[i];
  54236         args[0] = rd->resolving_funcs[0];
  54237         args[1] = rd->resolving_funcs[1];
  54238         args[2] = rd->handler;
  54239         args[3] = JS_NewBool(ctx, i);
  54240         args[4] = s->promise_result;
  54241         JS_EnqueueJob(ctx, promise_reaction_job, 5, args);
  54242         for(i = 0; i < 2; i++)
  54243             promise_reaction_data_free(ctx->rt, rd_array[i]);
  54244     }
  54245     s->is_handled = TRUE;
  54246     return 0;
  54247 }
  54248 
  54249 static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val,
  54250                                int argc, JSValueConst *argv)
  54251 {
  54252     JSValue ctor, result_promise, resolving_funcs[2];
  54253     JSPromiseData *s;
  54254     int i, ret;
  54255 
  54256     s = JS_GetOpaque2(ctx, this_val, JS_CLASS_PROMISE);
  54257     if (!s)
  54258         return JS_EXCEPTION;
  54259 
  54260     ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
  54261     if (JS_IsException(ctor))
  54262         return ctor;
  54263     result_promise = js_new_promise_capability(ctx, resolving_funcs, ctor);
  54264     JS_FreeValue(ctx, ctor);
  54265     if (JS_IsException(result_promise))
  54266         return result_promise;
  54267     ret = perform_promise_then(ctx, this_val, argv,
  54268                                (JSValueConst *)resolving_funcs);
  54269     for(i = 0; i < 2; i++)
  54270         JS_FreeValue(ctx, resolving_funcs[i]);
  54271     if (ret) {
  54272         JS_FreeValue(ctx, result_promise);
  54273         return JS_EXCEPTION;
  54274     }
  54275     return result_promise;
  54276 }
  54277 
  54278 static JSValue js_promise_catch(JSContext *ctx, JSValueConst this_val,
  54279                                 int argc, JSValueConst *argv)
  54280 {
  54281     JSValueConst args[2];
  54282     args[0] = JS_UNDEFINED;
  54283     args[1] = argv[0];
  54284     return JS_Invoke(ctx, this_val, JS_ATOM_then, 2, args);
  54285 }
  54286 
  54287 static JSValue js_promise_finally_value_thunk(JSContext *ctx, JSValueConst this_val,
  54288                                               int argc, JSValueConst *argv,
  54289                                               int magic, JSValue *func_data)
  54290 {
  54291     return JS_DupValue(ctx, func_data[0]);
  54292 }
  54293 
  54294 static JSValue js_promise_finally_thrower(JSContext *ctx, JSValueConst this_val,
  54295                                           int argc, JSValueConst *argv,
  54296                                           int magic, JSValue *func_data)
  54297 {
  54298     return JS_Throw(ctx, JS_DupValue(ctx, func_data[0]));
  54299 }
  54300 
  54301 static JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_val,
  54302                                             int argc, JSValueConst *argv,
  54303                                             int magic, JSValue *func_data)
  54304 {
  54305     JSValueConst ctor = func_data[0];
  54306     JSValueConst onFinally = func_data[1];
  54307     JSValue res, promise, ret, then_func;
  54308 
  54309     res = JS_Call(ctx, onFinally, JS_UNDEFINED, 0, NULL);
  54310     if (JS_IsException(res))
  54311         return res;
  54312     promise = js_promise_resolve(ctx, ctor, 1, (JSValueConst *)&res, 0);
  54313     JS_FreeValue(ctx, res);
  54314     if (JS_IsException(promise))
  54315         return promise;
  54316     if (magic == 0) {
  54317         then_func = JS_NewCFunctionData(ctx, js_promise_finally_value_thunk, 0,
  54318                                         0, 1, argv);
  54319     } else {
  54320         then_func = JS_NewCFunctionData(ctx, js_promise_finally_thrower, 0,
  54321                                         0, 1, argv);
  54322     }
  54323     if (JS_IsException(then_func)) {
  54324         JS_FreeValue(ctx, promise);
  54325         return then_func;
  54326     }
  54327     ret = JS_InvokeFree(ctx, promise, JS_ATOM_then, 1, (JSValueConst *)&then_func);
  54328     JS_FreeValue(ctx, then_func);
  54329     return ret;
  54330 }
  54331 
  54332 static JSValue js_promise_finally(JSContext *ctx, JSValueConst this_val,
  54333                                   int argc, JSValueConst *argv)
  54334 {
  54335     JSValueConst onFinally = argv[0];
  54336     JSValue ctor, ret;
  54337     JSValue then_funcs[2];
  54338     JSValueConst func_data[2];
  54339     int i;
  54340 
  54341     ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
  54342     if (JS_IsException(ctor))
  54343         return ctor;
  54344     if (!JS_IsFunction(ctx, onFinally)) {
  54345         then_funcs[0] = JS_DupValue(ctx, onFinally);
  54346         then_funcs[1] = JS_DupValue(ctx, onFinally);
  54347     } else {
  54348         func_data[0] = ctor;
  54349         func_data[1] = onFinally;
  54350         for(i = 0; i < 2; i++) {
  54351             then_funcs[i] = JS_NewCFunctionData(ctx, js_promise_then_finally_func, 1, i, 2, func_data);
  54352             if (JS_IsException(then_funcs[i])) {
  54353                 if (i == 1)
  54354                     JS_FreeValue(ctx, then_funcs[0]);
  54355                 JS_FreeValue(ctx, ctor);
  54356                 return JS_EXCEPTION;
  54357             }
  54358         }
  54359     }
  54360     JS_FreeValue(ctx, ctor);
  54361     ret = JS_Invoke(ctx, this_val, JS_ATOM_then, 2, (JSValueConst *)then_funcs);
  54362     JS_FreeValue(ctx, then_funcs[0]);
  54363     JS_FreeValue(ctx, then_funcs[1]);
  54364     return ret;
  54365 }
  54366 
  54367 static const JSCFunctionListEntry js_promise_funcs[] = {
  54368     JS_CFUNC_MAGIC_DEF("resolve", 1, js_promise_resolve, 0 ),
  54369     JS_CFUNC_MAGIC_DEF("reject", 1, js_promise_resolve, 1 ),
  54370     JS_CFUNC_MAGIC_DEF("all", 1, js_promise_all, PROMISE_MAGIC_all ),
  54371     JS_CFUNC_MAGIC_DEF("allSettled", 1, js_promise_all, PROMISE_MAGIC_allSettled ),
  54372     JS_CFUNC_MAGIC_DEF("any", 1, js_promise_all, PROMISE_MAGIC_any ),
  54373     JS_CFUNC_DEF("try", 1, js_promise_try ),
  54374     JS_CFUNC_DEF("race", 1, js_promise_race ),
  54375     JS_CFUNC_DEF("withResolvers", 0, js_promise_withResolvers ),
  54376     JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL),
  54377 };
  54378 
  54379 static const JSCFunctionListEntry js_promise_proto_funcs[] = {
  54380     JS_CFUNC_DEF("then", 2, js_promise_then ),
  54381     JS_CFUNC_DEF("catch", 1, js_promise_catch ),
  54382     JS_CFUNC_DEF("finally", 1, js_promise_finally ),
  54383     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Promise", JS_PROP_CONFIGURABLE ),
  54384 };
  54385 
  54386 /* AsyncFunction */
  54387 static const JSCFunctionListEntry js_async_function_proto_funcs[] = {
  54388     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncFunction", JS_PROP_CONFIGURABLE ),
  54389 };
  54390 
  54391 /* AsyncIteratorPrototype */
  54392 
  54393 static const JSCFunctionListEntry js_async_iterator_proto_funcs[] = {
  54394     JS_CFUNC_DEF("[Symbol.asyncIterator]", 0, js_iterator_proto_iterator ),
  54395 };
  54396 
  54397 /* AsyncFromSyncIteratorPrototype */
  54398 
  54399 typedef struct JSAsyncFromSyncIteratorData {
  54400     JSValue sync_iter;
  54401     JSValue next_method;
  54402 } JSAsyncFromSyncIteratorData;
  54403 
  54404 static void js_async_from_sync_iterator_finalizer(JSRuntime *rt, JSValue val)
  54405 {
  54406     JSAsyncFromSyncIteratorData *s =
  54407         JS_GetOpaque(val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
  54408     if (s) {
  54409         JS_FreeValueRT(rt, s->sync_iter);
  54410         JS_FreeValueRT(rt, s->next_method);
  54411         js_free_rt(rt, s);
  54412     }
  54413 }
  54414 
  54415 static void js_async_from_sync_iterator_mark(JSRuntime *rt, JSValueConst val,
  54416                                              JS_MarkFunc *mark_func)
  54417 {
  54418     JSAsyncFromSyncIteratorData *s =
  54419         JS_GetOpaque(val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
  54420     if (s) {
  54421         JS_MarkValue(rt, s->sync_iter, mark_func);
  54422         JS_MarkValue(rt, s->next_method, mark_func);
  54423     }
  54424 }
  54425 
  54426 static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx,
  54427                                               JSValueConst sync_iter)
  54428 {
  54429     JSValue async_iter, next_method;
  54430     JSAsyncFromSyncIteratorData *s;
  54431 
  54432     next_method = JS_GetProperty(ctx, sync_iter, JS_ATOM_next);
  54433     if (JS_IsException(next_method))
  54434         return JS_EXCEPTION;
  54435     async_iter = JS_NewObjectClass(ctx, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
  54436     if (JS_IsException(async_iter)) {
  54437         JS_FreeValue(ctx, next_method);
  54438         return async_iter;
  54439     }
  54440     s = js_mallocz(ctx, sizeof(*s));
  54441     if (!s) {
  54442         JS_FreeValue(ctx, async_iter);
  54443         JS_FreeValue(ctx, next_method);
  54444         return JS_EXCEPTION;
  54445     }
  54446     s->sync_iter = JS_DupValue(ctx, sync_iter);
  54447     s->next_method = next_method;
  54448     JS_SetOpaque(async_iter, s);
  54449     return async_iter;
  54450 }
  54451 
  54452 static JSValue js_async_from_sync_iterator_unwrap(JSContext *ctx,
  54453                                                   JSValueConst this_val,
  54454                                                   int argc, JSValueConst *argv,
  54455                                                   int magic, JSValue *func_data)
  54456 {
  54457     return js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]),
  54458                                      JS_ToBool(ctx, func_data[0]));
  54459 }
  54460 
  54461 static JSValue js_async_from_sync_iterator_unwrap_func_create(JSContext *ctx,
  54462                                                               BOOL done)
  54463 {
  54464     JSValueConst func_data[1];
  54465 
  54466     func_data[0] = (JSValueConst)JS_NewBool(ctx, done);
  54467     return JS_NewCFunctionData(ctx, js_async_from_sync_iterator_unwrap,
  54468                                1, 0, 1, func_data);
  54469 }
  54470 
  54471 static JSValue js_async_from_sync_iterator_close_wrap(JSContext *ctx,
  54472                                                       JSValueConst this_val,
  54473                                                       int argc, JSValueConst *argv,
  54474                                                       int magic, JSValue *func_data)
  54475 {
  54476     JS_Throw(ctx, JS_DupValue(ctx, argv[0]));
  54477     JS_IteratorClose(ctx, func_data[0], TRUE);
  54478     return JS_EXCEPTION;
  54479 }
  54480 
  54481 static JSValue js_async_from_sync_iterator_close_wrap_func_create(JSContext *ctx, JSValueConst sync_iter)
  54482 {
  54483     return JS_NewCFunctionData(ctx, js_async_from_sync_iterator_close_wrap,
  54484                                1, 0, 1, &sync_iter);
  54485 }
  54486 
  54487 static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst this_val,
  54488                                                 int argc, JSValueConst *argv,
  54489                                                 int magic)
  54490 {
  54491     JSValue promise, resolving_funcs[2], value, err, method;
  54492     JSAsyncFromSyncIteratorData *s;
  54493     int done;
  54494     int is_reject;
  54495 
  54496     promise = JS_NewPromiseCapability(ctx, resolving_funcs);
  54497     if (JS_IsException(promise))
  54498         return JS_EXCEPTION;
  54499     s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
  54500     if (!s) {
  54501         JS_ThrowTypeError(ctx, "not an Async-from-Sync Iterator");
  54502         goto reject;
  54503     }
  54504 
  54505     if (magic == GEN_MAGIC_NEXT) {
  54506         method = JS_DupValue(ctx, s->next_method);
  54507     } else {
  54508         method = JS_GetProperty(ctx, s->sync_iter,
  54509                                 magic == GEN_MAGIC_RETURN ? JS_ATOM_return :
  54510                                 JS_ATOM_throw);
  54511         if (JS_IsException(method))
  54512             goto reject;
  54513         if (JS_IsUndefined(method) || JS_IsNull(method)) {
  54514             if (magic == GEN_MAGIC_RETURN) {
  54515                 err = js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]), TRUE);
  54516                 is_reject = 0;
  54517                 goto done_resolve;
  54518             } else {
  54519                 if (JS_IteratorClose(ctx, s->sync_iter, FALSE))
  54520                     goto reject;
  54521                 JS_ThrowTypeError(ctx, "throw is not a method");
  54522                 goto reject;
  54523             }
  54524         }
  54525     }
  54526     value = JS_IteratorNext2(ctx, s->sync_iter, method,
  54527                              argc >= 1 ? 1 : 0, argv, &done);
  54528     JS_FreeValue(ctx, method);
  54529     if (JS_IsException(value))
  54530         goto reject;
  54531     if (done == 2) {
  54532         JSValue obj = value;
  54533         value = JS_IteratorGetCompleteValue(ctx, obj, &done);
  54534         JS_FreeValue(ctx, obj);
  54535         if (JS_IsException(value))
  54536             goto reject;
  54537     }
  54538     
  54539     if (JS_IsException(value))
  54540         goto reject;
  54541     {
  54542         JSValue value_wrapper_promise, resolve_reject[2];
  54543         int res;
  54544 
  54545         value_wrapper_promise = js_promise_resolve(ctx, ctx->promise_ctor,
  54546                                                    1, (JSValueConst *)&value, 0);
  54547         if (JS_IsException(value_wrapper_promise)) {
  54548             JSValue res2;
  54549             JS_FreeValue(ctx, value);
  54550             if (magic != GEN_MAGIC_RETURN && !done) {
  54551                 JS_IteratorClose(ctx, s->sync_iter, TRUE);
  54552             }
  54553         reject:
  54554             err = JS_GetException(ctx);
  54555             is_reject = 1;
  54556         done_resolve:
  54557             res2 = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED,
  54558                            1, (JSValueConst *)&err);
  54559             JS_FreeValue(ctx, err);
  54560             JS_FreeValue(ctx, res2);
  54561             JS_FreeValue(ctx, resolving_funcs[0]);
  54562             JS_FreeValue(ctx, resolving_funcs[1]);
  54563             return promise;
  54564         }
  54565 
  54566         resolve_reject[0] =
  54567             js_async_from_sync_iterator_unwrap_func_create(ctx, done);
  54568         if (JS_IsException(resolve_reject[0])) {
  54569             JS_FreeValue(ctx, value_wrapper_promise);
  54570             goto fail;
  54571         }
  54572         if (done || magic == GEN_MAGIC_RETURN) {
  54573             resolve_reject[1] = JS_UNDEFINED;
  54574         } else {
  54575             resolve_reject[1] =
  54576                 js_async_from_sync_iterator_close_wrap_func_create(ctx, s->sync_iter);
  54577             if (JS_IsException(resolve_reject[1])) {
  54578                 JS_FreeValue(ctx, value_wrapper_promise);
  54579                 JS_FreeValue(ctx, resolve_reject[0]);
  54580                 goto fail;
  54581             }
  54582         }
  54583         JS_FreeValue(ctx, value);
  54584         res = perform_promise_then(ctx, value_wrapper_promise,
  54585                                    (JSValueConst *)resolve_reject,
  54586                                    (JSValueConst *)resolving_funcs);
  54587         JS_FreeValue(ctx, resolve_reject[0]);
  54588         JS_FreeValue(ctx, resolve_reject[1]);
  54589         JS_FreeValue(ctx, value_wrapper_promise);
  54590         JS_FreeValue(ctx, resolving_funcs[0]);
  54591         JS_FreeValue(ctx, resolving_funcs[1]);
  54592         if (res) {
  54593             JS_FreeValue(ctx, promise);
  54594             return JS_EXCEPTION;
  54595         }
  54596     }
  54597     return promise;
  54598  fail:
  54599     JS_FreeValue(ctx, value);
  54600     JS_FreeValue(ctx, resolving_funcs[0]);
  54601     JS_FreeValue(ctx, resolving_funcs[1]);
  54602     JS_FreeValue(ctx, promise);
  54603     return JS_EXCEPTION;
  54604 }
  54605 
  54606 static const JSCFunctionListEntry js_async_from_sync_iterator_proto_funcs[] = {
  54607     JS_CFUNC_MAGIC_DEF("next", 1, js_async_from_sync_iterator_next, GEN_MAGIC_NEXT ),
  54608     JS_CFUNC_MAGIC_DEF("return", 1, js_async_from_sync_iterator_next, GEN_MAGIC_RETURN ),
  54609     JS_CFUNC_MAGIC_DEF("throw", 1, js_async_from_sync_iterator_next, GEN_MAGIC_THROW ),
  54610 };
  54611 
  54612 /* AsyncGeneratorFunction */
  54613 
  54614 static const JSCFunctionListEntry js_async_generator_function_proto_funcs[] = {
  54615     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncGeneratorFunction", JS_PROP_CONFIGURABLE ),
  54616 };
  54617 
  54618 /* AsyncGenerator prototype */
  54619 
  54620 static const JSCFunctionListEntry js_async_generator_proto_funcs[] = {
  54621     JS_CFUNC_MAGIC_DEF("next", 1, js_async_generator_next, GEN_MAGIC_NEXT ),
  54622     JS_CFUNC_MAGIC_DEF("return", 1, js_async_generator_next, GEN_MAGIC_RETURN ),
  54623     JS_CFUNC_MAGIC_DEF("throw", 1, js_async_generator_next, GEN_MAGIC_THROW ),
  54624     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncGenerator", JS_PROP_CONFIGURABLE ),
  54625 };
  54626 
  54627 static JSClassShortDef const js_async_class_def[] = {
  54628     { JS_ATOM_Promise, js_promise_finalizer, js_promise_mark },                      /* JS_CLASS_PROMISE */
  54629     { JS_ATOM_PromiseResolveFunction, js_promise_resolve_function_finalizer, js_promise_resolve_function_mark }, /* JS_CLASS_PROMISE_RESOLVE_FUNCTION */
  54630     { JS_ATOM_PromiseRejectFunction, js_promise_resolve_function_finalizer, js_promise_resolve_function_mark }, /* JS_CLASS_PROMISE_REJECT_FUNCTION */
  54631     { JS_ATOM_AsyncFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_ASYNC_FUNCTION */
  54632     { JS_ATOM_AsyncFunctionResolve, js_async_function_resolve_finalizer, js_async_function_resolve_mark }, /* JS_CLASS_ASYNC_FUNCTION_RESOLVE */
  54633     { JS_ATOM_AsyncFunctionReject, js_async_function_resolve_finalizer, js_async_function_resolve_mark }, /* JS_CLASS_ASYNC_FUNCTION_REJECT */
  54634     { JS_ATOM_empty_string, js_async_from_sync_iterator_finalizer, js_async_from_sync_iterator_mark }, /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */
  54635     { JS_ATOM_AsyncGeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_ASYNC_GENERATOR_FUNCTION */
  54636     { JS_ATOM_AsyncGenerator, js_async_generator_finalizer, js_async_generator_mark },  /* JS_CLASS_ASYNC_GENERATOR */
  54637 };
  54638 
  54639 int JS_AddIntrinsicPromise(JSContext *ctx)
  54640 {
  54641     JSRuntime *rt = ctx->rt;
  54642     JSValue obj1;
  54643     JSCFunctionType ft;
  54644 
  54645     if (!JS_IsRegisteredClass(rt, JS_CLASS_PROMISE)) {
  54646         if (init_class_range(rt, js_async_class_def, JS_CLASS_PROMISE,
  54647                              countof(js_async_class_def)))
  54648             return -1;
  54649         rt->class_array[JS_CLASS_PROMISE_RESOLVE_FUNCTION].call = js_promise_resolve_function_call;
  54650         rt->class_array[JS_CLASS_PROMISE_REJECT_FUNCTION].call = js_promise_resolve_function_call;
  54651         rt->class_array[JS_CLASS_ASYNC_FUNCTION].call = js_async_function_call;
  54652         rt->class_array[JS_CLASS_ASYNC_FUNCTION_RESOLVE].call = js_async_function_resolve_call;
  54653         rt->class_array[JS_CLASS_ASYNC_FUNCTION_REJECT].call = js_async_function_resolve_call;
  54654         rt->class_array[JS_CLASS_ASYNC_GENERATOR_FUNCTION].call = js_async_generator_function_call;
  54655     }
  54656 
  54657     /* Promise */
  54658     obj1 = JS_NewCConstructor(ctx, JS_CLASS_PROMISE, "Promise",
  54659                                      js_promise_constructor, 1, JS_CFUNC_constructor, 0,
  54660                                      JS_UNDEFINED,
  54661                                      js_promise_funcs, countof(js_promise_funcs),
  54662                                      js_promise_proto_funcs, countof(js_promise_proto_funcs),
  54663                                      0);
  54664     if (JS_IsException(obj1))
  54665         return -1;
  54666     ctx->promise_ctor = obj1;
  54667     
  54668     /* AsyncFunction */
  54669     ft.generic_magic = js_function_constructor;
  54670     obj1 = JS_NewCConstructor(ctx, JS_CLASS_ASYNC_FUNCTION, "AsyncFunction",
  54671                                      ft.generic, 1, JS_CFUNC_constructor_or_func_magic, JS_FUNC_ASYNC,
  54672                                      ctx->function_ctor,
  54673                                      NULL, 0,
  54674                                      js_async_function_proto_funcs, countof(js_async_function_proto_funcs),
  54675                                      JS_NEW_CTOR_NO_GLOBAL | JS_NEW_CTOR_READONLY);
  54676     if (JS_IsException(obj1))
  54677         return -1;
  54678     JS_FreeValue(ctx, obj1);
  54679     
  54680     /* AsyncIteratorPrototype */
  54681     ctx->async_iterator_proto =
  54682         JS_NewObjectProtoList(ctx,  ctx->class_proto[JS_CLASS_OBJECT],
  54683                               js_async_iterator_proto_funcs,
  54684                               countof(js_async_iterator_proto_funcs));
  54685     if (JS_IsException(ctx->async_iterator_proto))
  54686         return -1;
  54687 
  54688     /* AsyncFromSyncIteratorPrototype */
  54689     ctx->class_proto[JS_CLASS_ASYNC_FROM_SYNC_ITERATOR] =
  54690         JS_NewObjectProtoList(ctx, ctx->async_iterator_proto,
  54691                               js_async_from_sync_iterator_proto_funcs,
  54692                               countof(js_async_from_sync_iterator_proto_funcs));
  54693     if (JS_IsException(ctx->class_proto[JS_CLASS_ASYNC_FROM_SYNC_ITERATOR]))
  54694         return -1;
  54695     
  54696     /* AsyncGeneratorPrototype */
  54697     ctx->class_proto[JS_CLASS_ASYNC_GENERATOR] =
  54698         JS_NewObjectProtoList(ctx, ctx->async_iterator_proto, 
  54699                               js_async_generator_proto_funcs,
  54700                               countof(js_async_generator_proto_funcs));
  54701     if (JS_IsException(ctx->class_proto[JS_CLASS_ASYNC_GENERATOR]))
  54702         return -1;
  54703 
  54704     /* AsyncGeneratorFunction */
  54705     ft.generic_magic = js_function_constructor;
  54706     obj1 = JS_NewCConstructor(ctx, JS_CLASS_ASYNC_GENERATOR_FUNCTION, "AsyncGeneratorFunction",
  54707                                      ft.generic, 1, JS_CFUNC_constructor_or_func_magic, JS_FUNC_ASYNC_GENERATOR,
  54708                                      ctx->function_ctor,
  54709                                      NULL, 0,
  54710                                      js_async_generator_function_proto_funcs, countof(js_async_generator_function_proto_funcs),
  54711                                      JS_NEW_CTOR_NO_GLOBAL | JS_NEW_CTOR_READONLY);
  54712     if (JS_IsException(obj1))
  54713         return -1;
  54714     JS_FreeValue(ctx, obj1);
  54715 
  54716     return JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
  54717                               ctx->class_proto[JS_CLASS_ASYNC_GENERATOR],
  54718                               JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE);
  54719 }
  54720 
  54721 /* URI handling */
  54722 
  54723 static int string_get_hex(JSString *p, int k, int n) {
  54724     int c = 0, h;
  54725     while (n-- > 0) {
  54726         if ((h = from_hex(string_get(p, k++))) < 0)
  54727             return -1;
  54728         c = (c << 4) | h;
  54729     }
  54730     return c;
  54731 }
  54732 
  54733 static int isURIReserved(int c) {
  54734     return c < 0x100 && memchr(";/?:@&=+$,#", c, sizeof(";/?:@&=+$,#") - 1) != NULL;
  54735 }
  54736 
  54737 static int __attribute__((format(printf, 2, 3))) js_throw_URIError(JSContext *ctx, const char *fmt, ...)
  54738 {
  54739     va_list ap;
  54740 
  54741     va_start(ap, fmt);
  54742     JS_ThrowError(ctx, JS_URI_ERROR, fmt, ap);
  54743     va_end(ap);
  54744     return -1;
  54745 }
  54746 
  54747 static int hex_decode(JSContext *ctx, JSString *p, int k) {
  54748     int c;
  54749 
  54750     if (k >= p->len || string_get(p, k) != '%')
  54751         return js_throw_URIError(ctx, "expecting %%");
  54752     if (k + 2 >= p->len || (c = string_get_hex(p, k + 1, 2)) < 0)
  54753         return js_throw_URIError(ctx, "expecting hex digit");
  54754 
  54755     return c;
  54756 }
  54757 
  54758 static JSValue js_global_decodeURI(JSContext *ctx, JSValueConst this_val,
  54759                                    int argc, JSValueConst *argv, int isComponent)
  54760 {
  54761     JSValue str;
  54762     StringBuffer b_s, *b = &b_s;
  54763     JSString *p;
  54764     int k, c, c1, n, c_min;
  54765 
  54766     str = JS_ToString(ctx, argv[0]);
  54767     if (JS_IsException(str))
  54768         return str;
  54769 
  54770     string_buffer_init(ctx, b, 0);
  54771 
  54772     p = JS_VALUE_GET_STRING(str);
  54773     for (k = 0; k < p->len;) {
  54774         c = string_get(p, k);
  54775         if (c == '%') {
  54776             c = hex_decode(ctx, p, k);
  54777             if (c < 0)
  54778                 goto fail;
  54779             k += 3;
  54780             if (c < 0x80) {
  54781                 if (!isComponent && isURIReserved(c)) {
  54782                     c = '%';
  54783                     k -= 2;
  54784                 }
  54785             } else {
  54786                 /* Decode URI-encoded UTF-8 sequence */
  54787                 if (c >= 0xc0 && c <= 0xdf) {
  54788                     n = 1;
  54789                     c_min = 0x80;
  54790                     c &= 0x1f;
  54791                 } else if (c >= 0xe0 && c <= 0xef) {
  54792                     n = 2;
  54793                     c_min = 0x800;
  54794                     c &= 0xf;
  54795                 } else if (c >= 0xf0 && c <= 0xf7) {
  54796                     n = 3;
  54797                     c_min = 0x10000;
  54798                     c &= 0x7;
  54799                 } else {
  54800                     n = 0;
  54801                     c_min = 1;
  54802                     c = 0;
  54803                 }
  54804                 while (n-- > 0) {
  54805                     c1 = hex_decode(ctx, p, k);
  54806                     if (c1 < 0)
  54807                         goto fail;
  54808                     k += 3;
  54809                     if ((c1 & 0xc0) != 0x80) {
  54810                         c = 0;
  54811                         break;
  54812                     }
  54813                     c = (c << 6) | (c1 & 0x3f);
  54814                 }
  54815                 if (c < c_min || c > 0x10FFFF || is_surrogate(c)) {
  54816                     js_throw_URIError(ctx, "malformed UTF-8");
  54817                     goto fail;
  54818                 }
  54819             }
  54820         } else {
  54821             k++;
  54822         }
  54823         string_buffer_putc(b, c);
  54824     }
  54825     JS_FreeValue(ctx, str);
  54826     return string_buffer_end(b);
  54827 
  54828 fail:
  54829     JS_FreeValue(ctx, str);
  54830     string_buffer_free(b);
  54831     return JS_EXCEPTION;
  54832 }
  54833 
  54834 static int isUnescaped(int c) {
  54835     static char const unescaped_chars[] =
  54836         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  54837         "abcdefghijklmnopqrstuvwxyz"
  54838         "0123456789"
  54839         "@*_+-./";
  54840     return c < 0x100 &&
  54841         memchr(unescaped_chars, c, sizeof(unescaped_chars) - 1);
  54842 }
  54843 
  54844 static int isURIUnescaped(int c, int isComponent) {
  54845     return c < 0x100 &&
  54846         ((c >= 0x61 && c <= 0x7a) ||
  54847          (c >= 0x41 && c <= 0x5a) ||
  54848          (c >= 0x30 && c <= 0x39) ||
  54849          memchr("-_.!~*'()", c, sizeof("-_.!~*'()") - 1) != NULL ||
  54850          (!isComponent && isURIReserved(c)));
  54851 }
  54852 
  54853 static int encodeURI_hex(StringBuffer *b, int c) {
  54854     uint8_t buf[6];
  54855     int n = 0;
  54856     const char *hex = "0123456789ABCDEF";
  54857 
  54858     buf[n++] = '%';
  54859     if (c >= 256) {
  54860         buf[n++] = 'u';
  54861         buf[n++] = hex[(c >> 12) & 15];
  54862         buf[n++] = hex[(c >>  8) & 15];
  54863     }
  54864     buf[n++] = hex[(c >> 4) & 15];
  54865     buf[n++] = hex[(c >> 0) & 15];
  54866     return string_buffer_write8(b, buf, n);
  54867 }
  54868 
  54869 static JSValue js_global_encodeURI(JSContext *ctx, JSValueConst this_val,
  54870                                    int argc, JSValueConst *argv,
  54871                                    int isComponent)
  54872 {
  54873     JSValue str;
  54874     StringBuffer b_s, *b = &b_s;
  54875     JSString *p;
  54876     int k, c, c1;
  54877 
  54878     str = JS_ToString(ctx, argv[0]);
  54879     if (JS_IsException(str))
  54880         return str;
  54881 
  54882     p = JS_VALUE_GET_STRING(str);
  54883     string_buffer_init(ctx, b, p->len);
  54884     for (k = 0; k < p->len;) {
  54885         c = string_get(p, k);
  54886         k++;
  54887         if (isURIUnescaped(c, isComponent)) {
  54888             string_buffer_putc16(b, c);
  54889         } else {
  54890             if (is_lo_surrogate(c)) {
  54891                 js_throw_URIError(ctx, "invalid character");
  54892                 goto fail;
  54893             } else if (is_hi_surrogate(c)) {
  54894                 if (k >= p->len) {
  54895                     js_throw_URIError(ctx, "expecting surrogate pair");
  54896                     goto fail;
  54897                 }
  54898                 c1 = string_get(p, k);
  54899                 k++;
  54900                 if (!is_lo_surrogate(c1)) {
  54901                     js_throw_URIError(ctx, "expecting surrogate pair");
  54902                     goto fail;
  54903                 }
  54904                 c = from_surrogate(c, c1);
  54905             }
  54906             if (c < 0x80) {
  54907                 encodeURI_hex(b, c);
  54908             } else {
  54909                 /* XXX: use C UTF-8 conversion ? */
  54910                 if (c < 0x800) {
  54911                     encodeURI_hex(b, (c >> 6) | 0xc0);
  54912                 } else {
  54913                     if (c < 0x10000) {
  54914                         encodeURI_hex(b, (c >> 12) | 0xe0);
  54915                     } else {
  54916                         encodeURI_hex(b, (c >> 18) | 0xf0);
  54917                         encodeURI_hex(b, ((c >> 12) & 0x3f) | 0x80);
  54918                     }
  54919                     encodeURI_hex(b, ((c >> 6) & 0x3f) | 0x80);
  54920                 }
  54921                 encodeURI_hex(b, (c & 0x3f) | 0x80);
  54922             }
  54923         }
  54924     }
  54925     JS_FreeValue(ctx, str);
  54926     return string_buffer_end(b);
  54927 
  54928 fail:
  54929     JS_FreeValue(ctx, str);
  54930     string_buffer_free(b);
  54931     return JS_EXCEPTION;
  54932 }
  54933 
  54934 static JSValue js_global_escape(JSContext *ctx, JSValueConst this_val,
  54935                                 int argc, JSValueConst *argv)
  54936 {
  54937     JSValue str;
  54938     StringBuffer b_s, *b = &b_s;
  54939     JSString *p;
  54940     int i, len, c;
  54941 
  54942     str = JS_ToString(ctx, argv[0]);
  54943     if (JS_IsException(str))
  54944         return str;
  54945 
  54946     p = JS_VALUE_GET_STRING(str);
  54947     string_buffer_init(ctx, b, p->len);
  54948     for (i = 0, len = p->len; i < len; i++) {
  54949         c = string_get(p, i);
  54950         if (isUnescaped(c)) {
  54951             string_buffer_putc16(b, c);
  54952         } else {
  54953             encodeURI_hex(b, c);
  54954         }
  54955     }
  54956     JS_FreeValue(ctx, str);
  54957     return string_buffer_end(b);
  54958 }
  54959 
  54960 static JSValue js_global_unescape(JSContext *ctx, JSValueConst this_val,
  54961                                   int argc, JSValueConst *argv)
  54962 {
  54963     JSValue str;
  54964     StringBuffer b_s, *b = &b_s;
  54965     JSString *p;
  54966     int i, len, c, n;
  54967 
  54968     str = JS_ToString(ctx, argv[0]);
  54969     if (JS_IsException(str))
  54970         return str;
  54971 
  54972     string_buffer_init(ctx, b, 0);
  54973     p = JS_VALUE_GET_STRING(str);
  54974     for (i = 0, len = p->len; i < len; i++) {
  54975         c = string_get(p, i);
  54976         if (c == '%') {
  54977             if (i + 6 <= len
  54978             &&  string_get(p, i + 1) == 'u'
  54979             &&  (n = string_get_hex(p, i + 2, 4)) >= 0) {
  54980                 c = n;
  54981                 i += 6 - 1;
  54982             } else
  54983             if (i + 3 <= len
  54984             &&  (n = string_get_hex(p, i + 1, 2)) >= 0) {
  54985                 c = n;
  54986                 i += 3 - 1;
  54987             }
  54988         }
  54989         string_buffer_putc16(b, c);
  54990     }
  54991     JS_FreeValue(ctx, str);
  54992     return string_buffer_end(b);
  54993 }
  54994 
  54995 /* global object */
  54996 
  54997 static const JSCFunctionListEntry js_global_funcs[] = {
  54998     JS_CFUNC_DEF("parseInt", 2, js_parseInt ),
  54999     JS_CFUNC_DEF("parseFloat", 1, js_parseFloat ),
  55000     JS_CFUNC_DEF("isNaN", 1, js_global_isNaN ),
  55001     JS_CFUNC_DEF("isFinite", 1, js_global_isFinite ),
  55002 
  55003     JS_CFUNC_MAGIC_DEF("decodeURI", 1, js_global_decodeURI, 0 ),
  55004     JS_CFUNC_MAGIC_DEF("decodeURIComponent", 1, js_global_decodeURI, 1 ),
  55005     JS_CFUNC_MAGIC_DEF("encodeURI", 1, js_global_encodeURI, 0 ),
  55006     JS_CFUNC_MAGIC_DEF("encodeURIComponent", 1, js_global_encodeURI, 1 ),
  55007     JS_CFUNC_DEF("escape", 1, js_global_escape ),
  55008     JS_CFUNC_DEF("unescape", 1, js_global_unescape ),
  55009     JS_PROP_DOUBLE_DEF("Infinity", 1.0 / 0.0, 0 ),
  55010     JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ),
  55011     JS_PROP_UNDEFINED_DEF("undefined", 0 ),
  55012     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "global", JS_PROP_CONFIGURABLE ),
  55013     JS_CFUNC_DEF("eval", 1, js_global_eval ),
  55014 };
  55015 
  55016 /* Date */
  55017 
  55018 static int64_t math_mod(int64_t a, int64_t b) {
  55019     /* return positive modulo */
  55020     int64_t m = a % b;
  55021     return m + (m < 0) * b;
  55022 }
  55023 
  55024 static int64_t floor_div(int64_t a, int64_t b) {
  55025     /* integer division rounding toward -Infinity */
  55026     int64_t m = a % b;
  55027     return (a - (m + (m < 0) * b)) / b;
  55028 }
  55029 
  55030 static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
  55031                              int argc, JSValueConst *argv);
  55032 
  55033 static __exception int JS_ThisTimeValue(JSContext *ctx, double *valp, JSValueConst this_val)
  55034 {
  55035     if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
  55036         JSObject *p = JS_VALUE_GET_OBJ(this_val);
  55037         if (p->class_id == JS_CLASS_DATE && JS_IsNumber(p->u.object_data))
  55038             return JS_ToFloat64(ctx, valp, p->u.object_data);
  55039     }
  55040     JS_ThrowTypeError(ctx, "not a Date object");
  55041     return -1;
  55042 }
  55043 
  55044 static JSValue JS_SetThisTimeValue(JSContext *ctx, JSValueConst this_val, double v)
  55045 {
  55046     if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
  55047         JSObject *p = JS_VALUE_GET_OBJ(this_val);
  55048         if (p->class_id == JS_CLASS_DATE) {
  55049             JS_FreeValue(ctx, p->u.object_data);
  55050             p->u.object_data = JS_NewFloat64(ctx, v);
  55051             return JS_DupValue(ctx, p->u.object_data);
  55052         }
  55053     }
  55054     return JS_ThrowTypeError(ctx, "not a Date object");
  55055 }
  55056 
  55057 static int64_t days_from_year(int64_t y) {
  55058     return 365 * (y - 1970) + floor_div(y - 1969, 4) -
  55059         floor_div(y - 1901, 100) + floor_div(y - 1601, 400);
  55060 }
  55061 
  55062 static int64_t days_in_year(int64_t y) {
  55063     return 365 + !(y % 4) - !(y % 100) + !(y % 400);
  55064 }
  55065 
  55066 /* return the year, update days */
  55067 static int64_t year_from_days(int64_t *days) {
  55068     int64_t y, d1, nd, d = *days;
  55069     y = floor_div(d * 10000, 3652425) + 1970;
  55070     /* the initial approximation is very good, so only a few
  55071        iterations are necessary */
  55072     for(;;) {
  55073         d1 = d - days_from_year(y);
  55074         if (d1 < 0) {
  55075             y--;
  55076             d1 += days_in_year(y);
  55077         } else {
  55078             nd = days_in_year(y);
  55079             if (d1 < nd)
  55080                 break;
  55081             d1 -= nd;
  55082             y++;
  55083         }
  55084     }
  55085     *days = d1;
  55086     return y;
  55087 }
  55088 
  55089 static int const month_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  55090 static char const month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
  55091 static char const day_names[] = "SunMonTueWedThuFriSat";
  55092 
  55093 static __exception int get_date_fields(JSContext *ctx, JSValueConst obj,
  55094                                        double fields[minimum_length(9)], int is_local, int force)
  55095 {
  55096     double dval;
  55097     int64_t d, days, wd, y, i, md, h, m, s, ms, tz = 0;
  55098 
  55099     if (JS_ThisTimeValue(ctx, &dval, obj))
  55100         return -1;
  55101 
  55102     if (isnan(dval)) {
  55103         if (!force)
  55104             return FALSE; /* NaN */
  55105         d = 0;        /* initialize all fields to 0 */
  55106     } else {
  55107         d = dval;     /* assuming -8.64e15 <= dval <= -8.64e15 */
  55108         if (is_local) {
  55109             tz = -getTimezoneOffset(d);
  55110             d += tz * 60000;
  55111         }
  55112     }
  55113 
  55114     /* result is >= 0, we can use % */
  55115     h = math_mod(d, 86400000);
  55116     days = (d - h) / 86400000;
  55117     ms = h % 1000;
  55118     h = (h - ms) / 1000;
  55119     s = h % 60;
  55120     h = (h - s) / 60;
  55121     m = h % 60;
  55122     h = (h - m) / 60;
  55123     wd = math_mod(days + 4, 7); /* week day */
  55124     y = year_from_days(&days);
  55125 
  55126     for(i = 0; i < 11; i++) {
  55127         md = month_days[i];
  55128         if (i == 1)
  55129             md += days_in_year(y) - 365;
  55130         if (days < md)
  55131             break;
  55132         days -= md;
  55133     }
  55134     fields[0] = y;
  55135     fields[1] = i;
  55136     fields[2] = days + 1;
  55137     fields[3] = h;
  55138     fields[4] = m;
  55139     fields[5] = s;
  55140     fields[6] = ms;
  55141     fields[7] = wd;
  55142     fields[8] = tz;
  55143     return TRUE;
  55144 }
  55145 
  55146 static double time_clip(double t) {
  55147     if (t >= -8.64e15 && t <= 8.64e15)
  55148         return trunc(t) + 0.0;  /* convert -0 to +0 */
  55149     else
  55150         return NAN;
  55151 }
  55152 
  55153 /* The spec mandates the use of 'double' and it specifies the order
  55154    of the operations */
  55155 static double set_date_fields(double fields[minimum_length(7)], int is_local) {
  55156     double y, m, dt, ym, mn, day, h, s, milli, time, tv;
  55157     int yi, mi, i;
  55158     int64_t days;
  55159     volatile double temp;  /* enforce evaluation order */
  55160 
  55161     /* emulate 21.4.1.15 MakeDay ( year, month, date ) */
  55162     y = fields[0];
  55163     m = fields[1];
  55164     dt = fields[2];
  55165     ym = y + floor(m / 12);
  55166     mn = fmod(m, 12);
  55167     if (mn < 0)
  55168         mn += 12;
  55169     if (ym < -271821 || ym > 275760)
  55170         return NAN;
  55171 
  55172     yi = ym;
  55173     mi = mn;
  55174     days = days_from_year(yi);
  55175     for(i = 0; i < mi; i++) {
  55176         days += month_days[i];
  55177         if (i == 1)
  55178             days += days_in_year(yi) - 365;
  55179     }
  55180     day = days + dt - 1;
  55181 
  55182     /* emulate 21.4.1.14 MakeTime ( hour, min, sec, ms ) */
  55183     h = fields[3];
  55184     m = fields[4];
  55185     s = fields[5];
  55186     milli = fields[6];
  55187     /* Use a volatile intermediary variable to ensure order of evaluation
  55188      * as specified in ECMA. This fixes a test262 error on
  55189      * test262/test/built-ins/Date/UTC/fp-evaluation-order.js.
  55190      * Without the volatile qualifier, the compile can generate code
  55191      * that performs the computation in a different order or with instructions
  55192      * that produce a different result such as FMA (float multiply and add).
  55193      */
  55194     time = h * 3600000;
  55195     time += (temp = m * 60000);
  55196     time += (temp = s * 1000);
  55197     time += milli;
  55198 
  55199     /* emulate 21.4.1.16 MakeDate ( day, time ) */
  55200     tv = (temp = day * 86400000) + time;   /* prevent generation of FMA */
  55201     if (!isfinite(tv))
  55202         return NAN;
  55203 
  55204     /* adjust for local time and clip */
  55205     if (is_local) {
  55206         int64_t ti = tv < INT64_MIN ? INT64_MIN : tv >= 0x1p63 ? INT64_MAX : (int64_t)tv;
  55207         tv += getTimezoneOffset(ti) * 60000;
  55208     }
  55209     return time_clip(tv);
  55210 }
  55211 
  55212 static double set_date_fields_checked(double fields[minimum_length(7)], int is_local)
  55213 {
  55214     int i;
  55215     double a;
  55216     for(i = 0; i < 7; i++) {
  55217         a = fields[i];
  55218         if (!isfinite(a))
  55219             return NAN;
  55220         fields[i] = trunc(a);
  55221         if (i == 0 && fields[0] >= 0 && fields[0] < 100)
  55222             fields[0] += 1900;
  55223     }
  55224     return set_date_fields(fields, is_local);
  55225 }
  55226 
  55227 static JSValue get_date_field(JSContext *ctx, JSValueConst this_val,
  55228                               int argc, JSValueConst *argv, int magic)
  55229 {
  55230     // get_date_field(obj, n, is_local)
  55231     double fields[9];
  55232     int res, n, is_local;
  55233 
  55234     is_local = magic & 0x0F;
  55235     n = (magic >> 4) & 0x0F;
  55236     res = get_date_fields(ctx, this_val, fields, is_local, 0);
  55237     if (res < 0)
  55238         return JS_EXCEPTION;
  55239     if (!res)
  55240         return JS_NAN;
  55241 
  55242     if (magic & 0x100) {    // getYear
  55243         fields[0] -= 1900;
  55244     }
  55245     return JS_NewFloat64(ctx, fields[n]);
  55246 }
  55247 
  55248 static JSValue set_date_field(JSContext *ctx, JSValueConst this_val,
  55249                               int argc, JSValueConst *argv, int magic)
  55250 {
  55251     // _field(obj, first_field, end_field, args, is_local)
  55252     double fields[9];
  55253     int res, first_field, end_field, is_local, i, n, res1;
  55254     double d, a;
  55255 
  55256     d = NAN;
  55257     first_field = (magic >> 8) & 0x0F;
  55258     end_field = (magic >> 4) & 0x0F;
  55259     is_local = magic & 0x0F;
  55260 
  55261     res = get_date_fields(ctx, this_val, fields, is_local, first_field == 0);
  55262     if (res < 0)
  55263         return JS_EXCEPTION;
  55264     res1 = res;
  55265     
  55266     // Argument coercion is observable and must be done unconditionally.
  55267     n = min_int(argc, end_field - first_field);
  55268     for(i = 0; i < n; i++) {
  55269         if (JS_ToFloat64(ctx, &a, argv[i]))
  55270             return JS_EXCEPTION;
  55271         if (!isfinite(a))
  55272             res = FALSE;
  55273         fields[first_field + i] = trunc(a);
  55274     }
  55275 
  55276     if (!res1)
  55277         return JS_NAN; /* thisTimeValue is NaN */
  55278 
  55279     if (res && argc > 0)
  55280         d = set_date_fields(fields, is_local);
  55281 
  55282     return JS_SetThisTimeValue(ctx, this_val, d);
  55283 }
  55284 
  55285 /* fmt:
  55286    0: toUTCString: "Tue, 02 Jan 2018 23:04:46 GMT"
  55287    1: toString: "Wed Jan 03 2018 00:05:22 GMT+0100 (CET)"
  55288    2: toISOString: "2018-01-02T23:02:56.927Z"
  55289    3: toLocaleString: "1/2/2018, 11:40:40 PM"
  55290    part: 1=date, 2=time 3=all
  55291    XXX: should use a variant of strftime().
  55292  */
  55293 static JSValue get_date_string(JSContext *ctx, JSValueConst this_val,
  55294                                int argc, JSValueConst *argv, int magic)
  55295 {
  55296     // _string(obj, fmt, part)
  55297     char buf[64];
  55298     double fields[9];
  55299     int res, fmt, part, pos;
  55300     int y, mon, d, h, m, s, ms, wd, tz;
  55301 
  55302     fmt = (magic >> 4) & 0x0F;
  55303     part = magic & 0x0F;
  55304 
  55305     res = get_date_fields(ctx, this_val, fields, fmt & 1, 0);
  55306     if (res < 0)
  55307         return JS_EXCEPTION;
  55308     if (!res) {
  55309         if (fmt == 2)
  55310             return JS_ThrowRangeError(ctx, "Date value is NaN");
  55311         else
  55312             return js_new_string8(ctx, "Invalid Date");
  55313     }
  55314 
  55315     y = fields[0];
  55316     mon = fields[1];
  55317     d = fields[2];
  55318     h = fields[3];
  55319     m = fields[4];
  55320     s = fields[5];
  55321     ms = fields[6];
  55322     wd = fields[7];
  55323     tz = fields[8];
  55324 
  55325     pos = 0;
  55326 
  55327     if (part & 1) { /* date part */
  55328         switch(fmt) {
  55329         case 0:
  55330             pos += snprintf(buf + pos, sizeof(buf) - pos,
  55331                             "%.3s, %02d %.3s %0*d ",
  55332                             day_names + wd * 3, d,
  55333                             month_names + mon * 3, 4 + (y < 0), y);
  55334             break;
  55335         case 1:
  55336             pos += snprintf(buf + pos, sizeof(buf) - pos,
  55337                             "%.3s %.3s %02d %0*d",
  55338                             day_names + wd * 3,
  55339                             month_names + mon * 3, d, 4 + (y < 0), y);
  55340             if (part == 3) {
  55341                 buf[pos++] = ' ';
  55342             }
  55343             break;
  55344         case 2:
  55345             if (y >= 0 && y <= 9999) {
  55346                 pos += snprintf(buf + pos, sizeof(buf) - pos,
  55347                                 "%04d", y);
  55348             } else {
  55349                 pos += snprintf(buf + pos, sizeof(buf) - pos,
  55350                                 "%+07d", y);
  55351             }
  55352             pos += snprintf(buf + pos, sizeof(buf) - pos,
  55353                             "-%02d-%02dT", mon + 1, d);
  55354             break;
  55355         case 3:
  55356             pos += snprintf(buf + pos, sizeof(buf) - pos,
  55357                             "%02d/%02d/%0*d", mon + 1, d, 4 + (y < 0), y);
  55358             if (part == 3) {
  55359                 buf[pos++] = ',';
  55360                 buf[pos++] = ' ';
  55361             }
  55362             break;
  55363         }
  55364     }
  55365     if (part & 2) { /* time part */
  55366         switch(fmt) {
  55367         case 0:
  55368             pos += snprintf(buf + pos, sizeof(buf) - pos,
  55369                             "%02d:%02d:%02d GMT", h, m, s);
  55370             break;
  55371         case 1:
  55372             pos += snprintf(buf + pos, sizeof(buf) - pos,
  55373                             "%02d:%02d:%02d GMT", h, m, s);
  55374             if (tz < 0) {
  55375                 buf[pos++] = '-';
  55376                 tz = -tz;
  55377             } else {
  55378                 buf[pos++] = '+';
  55379             }
  55380             /* tz is >= 0, can use % */
  55381             pos += snprintf(buf + pos, sizeof(buf) - pos,
  55382                             "%02d%02d", tz / 60, tz % 60);
  55383             /* XXX: tack the time zone code? */
  55384             break;
  55385         case 2:
  55386             pos += snprintf(buf + pos, sizeof(buf) - pos,
  55387                             "%02d:%02d:%02d.%03dZ", h, m, s, ms);
  55388             break;
  55389         case 3:
  55390             pos += snprintf(buf + pos, sizeof(buf) - pos,
  55391                             "%02d:%02d:%02d %cM", (h + 11) % 12 + 1, m, s,
  55392                             (h < 12) ? 'A' : 'P');
  55393             break;
  55394         }
  55395     }
  55396     return JS_NewStringLen(ctx, buf, pos);
  55397 }
  55398 
  55399 /* OS dependent: return the UTC time in ms since 1970. */
  55400 static int64_t date_now(void) {
  55401     struct timeval tv;
  55402     gettimeofday(&tv, NULL);
  55403     return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
  55404 }
  55405 
  55406 static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target,
  55407                                    int argc, JSValueConst *argv)
  55408 {
  55409     // Date(y, mon, d, h, m, s, ms)
  55410     JSValue rv;
  55411     int i, n;
  55412     double val;
  55413 
  55414     if (JS_IsUndefined(new_target)) {
  55415         /* invoked as function */
  55416         argc = 0;
  55417     }
  55418     n = argc;
  55419     if (n == 0) {
  55420         val = date_now();
  55421     } else if (n == 1) {
  55422         JSValue v, dv;
  55423         if (JS_VALUE_GET_TAG(argv[0]) == JS_TAG_OBJECT) {
  55424             JSObject *p = JS_VALUE_GET_OBJ(argv[0]);
  55425             if (p->class_id == JS_CLASS_DATE && JS_IsNumber(p->u.object_data)) {
  55426                 if (JS_ToFloat64(ctx, &val, p->u.object_data))
  55427                     return JS_EXCEPTION;
  55428                 val = time_clip(val);
  55429                 goto has_val;
  55430             }
  55431         }
  55432         v = JS_ToPrimitive(ctx, argv[0], HINT_NONE);
  55433         if (JS_IsString(v)) {
  55434             dv = js_Date_parse(ctx, JS_UNDEFINED, 1, (JSValueConst *)&v);
  55435             JS_FreeValue(ctx, v);
  55436             if (JS_IsException(dv))
  55437                 return JS_EXCEPTION;
  55438             if (JS_ToFloat64Free(ctx, &val, dv))
  55439                 return JS_EXCEPTION;
  55440         } else {
  55441             if (JS_ToFloat64Free(ctx, &val, v))
  55442                 return JS_EXCEPTION;
  55443         }
  55444         val = time_clip(val);
  55445     } else {
  55446         double fields[] = { 0, 0, 1, 0, 0, 0, 0 };
  55447         if (n > 7)
  55448             n = 7;
  55449         for(i = 0; i < n; i++) {
  55450             if (JS_ToFloat64(ctx, &fields[i], argv[i]))
  55451                 return JS_EXCEPTION;
  55452         }
  55453         val = set_date_fields_checked(fields, 1);
  55454     }
  55455 has_val:
  55456 #if 0
  55457     JSValueConst args[3];
  55458     args[0] = new_target;
  55459     args[1] = ctx->class_proto[JS_CLASS_DATE];
  55460     args[2] = JS_NewFloat64(ctx, val);
  55461     rv = js___date_create(ctx, JS_UNDEFINED, 3, args);
  55462 #else
  55463     rv = js_create_from_ctor(ctx, new_target, JS_CLASS_DATE);
  55464     if (!JS_IsException(rv))
  55465         JS_SetObjectData(ctx, rv, JS_NewFloat64(ctx, val));
  55466 #endif
  55467     if (!JS_IsException(rv) && JS_IsUndefined(new_target)) {
  55468         /* invoked as a function, return (new Date()).toString(); */
  55469         JSValue s;
  55470         s = get_date_string(ctx, rv, 0, NULL, 0x13);
  55471         JS_FreeValue(ctx, rv);
  55472         rv = s;
  55473     }
  55474     return rv;
  55475 }
  55476 
  55477 static JSValue js_Date_UTC(JSContext *ctx, JSValueConst this_val,
  55478                            int argc, JSValueConst *argv)
  55479 {
  55480     // UTC(y, mon, d, h, m, s, ms)
  55481     double fields[] = { 0, 0, 1, 0, 0, 0, 0 };
  55482     int i, n;
  55483 
  55484     n = argc;
  55485     if (n == 0)
  55486         return JS_NAN;
  55487     if (n > 7)
  55488         n = 7;
  55489     for(i = 0; i < n; i++) {
  55490         if (JS_ToFloat64(ctx, &fields[i], argv[i]))
  55491             return JS_EXCEPTION;
  55492     }
  55493     return JS_NewFloat64(ctx, set_date_fields_checked(fields, 0));
  55494 }
  55495 
  55496 /* Date string parsing */
  55497 
  55498 static BOOL string_skip_char(const uint8_t *sp, int *pp, int c) {
  55499     if (sp[*pp] == c) {
  55500         *pp += 1;
  55501         return TRUE;
  55502     } else {
  55503         return FALSE;
  55504     }
  55505 }
  55506 
  55507 /* skip spaces, update offset, return next char */
  55508 static int string_skip_spaces(const uint8_t *sp, int *pp) {
  55509     int c;
  55510     while ((c = sp[*pp]) == ' ')
  55511         *pp += 1;
  55512     return c;
  55513 }
  55514 
  55515 /* skip dashes dots and commas */
  55516 static int string_skip_separators(const uint8_t *sp, int *pp) {
  55517     int c;
  55518     while ((c = sp[*pp]) == '-' || c == '/' || c == '.' || c == ',')
  55519         *pp += 1;
  55520     return c;
  55521 }
  55522 
  55523 /* skip a word, stop on spaces, digits and separators, update offset */
  55524 static int string_skip_until(const uint8_t *sp, int *pp, const char *stoplist) {
  55525     int c;
  55526     while (!strchr(stoplist, c = sp[*pp]))
  55527         *pp += 1;
  55528     return c;
  55529 }
  55530 
  55531 /* parse a numeric field (max_digits = 0 -> no maximum) */
  55532 static BOOL string_get_digits(const uint8_t *sp, int *pp, int *pval,
  55533                               int min_digits, int max_digits)
  55534 {
  55535     int v = 0;
  55536     int c, p = *pp, p_start;
  55537 
  55538     p_start = p;
  55539     while ((c = sp[p]) >= '0' && c <= '9') {
  55540         /* arbitrary limit to 9 digits */
  55541         if (v >= 100000000)
  55542             return FALSE;
  55543         v = v * 10 + c - '0';
  55544         p++;
  55545         if (p - p_start == max_digits)
  55546             break;
  55547     }
  55548     if (p - p_start < min_digits)
  55549         return FALSE;
  55550     *pval = v;
  55551     *pp = p;
  55552     return TRUE;
  55553 }
  55554 
  55555 static BOOL string_get_milliseconds(const uint8_t *sp, int *pp, int *pval) {
  55556     /* parse optional fractional part as milliseconds and truncate. */
  55557     /* spec does not indicate which rounding should be used */
  55558     int mul = 100, ms = 0, c, p_start, p = *pp;
  55559 
  55560     c = sp[p];
  55561     if (c == '.' || c == ',') {
  55562         p++;
  55563         p_start = p;
  55564         while ((c = sp[p]) >= '0' && c <= '9') {
  55565             ms += (c - '0') * mul;
  55566             mul /= 10;
  55567             p++;
  55568             if (p - p_start == 9)
  55569                 break;
  55570         }
  55571         if (p > p_start) {
  55572             /* only consume the separator if digits are present */
  55573             *pval = ms;
  55574             *pp = p;
  55575         }
  55576     }
  55577     return TRUE;
  55578 }
  55579 
  55580 static uint8_t upper_ascii(uint8_t c) {
  55581     return c >= 'a' && c <= 'z' ? c - 'a' + 'A' : c;
  55582 }
  55583 
  55584 static BOOL string_get_tzoffset(const uint8_t *sp, int *pp, int *tzp, BOOL strict) {
  55585     int tz = 0, sgn, hh, mm, p = *pp;
  55586 
  55587     sgn = sp[p++];
  55588     if (sgn == '+' || sgn == '-') {
  55589         int n = p;
  55590         if (!string_get_digits(sp, &p, &hh, 1, 0))
  55591             return FALSE;
  55592         n = p - n;
  55593         if (strict && n != 2 && n != 4)
  55594             return FALSE;
  55595         while (n > 4) {
  55596             n -= 2;
  55597             hh /= 100;
  55598         }
  55599         if (n > 2) {
  55600             mm = hh % 100;
  55601             hh = hh / 100;
  55602         } else {
  55603             mm = 0;
  55604             if (string_skip_char(sp, &p, ':')) {
  55605                 /* optional separator */
  55606                 if (!string_get_digits(sp, &p, &mm, 2, 2))
  55607                     return FALSE;
  55608             } else {
  55609                 if (strict)
  55610                     return FALSE; /* [+-]HH is not accepted in strict mode */
  55611             }
  55612         }
  55613         if (hh > 23 || mm > 59)
  55614             return FALSE;
  55615         tz = hh * 60 + mm;
  55616         if (sgn != '+')
  55617             tz = -tz;
  55618     } else
  55619     if (sgn != 'Z') {
  55620         return FALSE;
  55621     }
  55622     *pp = p;
  55623     *tzp = tz;
  55624     return TRUE;
  55625 }
  55626 
  55627 static BOOL string_match(const uint8_t *sp, int *pp, const char *s) {
  55628     int p = *pp;
  55629     while (*s != '\0') {
  55630         if (upper_ascii(sp[p]) != upper_ascii(*s++))
  55631             return FALSE;
  55632         p++;
  55633     }
  55634     *pp = p;
  55635     return TRUE;
  55636 }
  55637 
  55638 static int find_abbrev(const uint8_t *sp, int p, const char *list, int count) {
  55639     int n, i;
  55640 
  55641     for (n = 0; n < count; n++) {
  55642         for (i = 0;; i++) {
  55643             if (upper_ascii(sp[p + i]) != upper_ascii(list[n * 3 + i]))
  55644                 break;
  55645             if (i == 2)
  55646                 return n;
  55647         }
  55648     }
  55649     return -1;
  55650 }
  55651 
  55652 static BOOL string_get_month(const uint8_t *sp, int *pp, int *pval) {
  55653     int n;
  55654 
  55655     n = find_abbrev(sp, *pp, month_names, 12);
  55656     if (n < 0)
  55657         return FALSE;
  55658 
  55659     *pval = n + 1;
  55660     *pp += 3;
  55661     return TRUE;
  55662 }
  55663 
  55664 /* parse toISOString format */
  55665 static BOOL js_date_parse_isostring(const uint8_t *sp, int fields[9], BOOL *is_local) {
  55666     int sgn, i, p = 0;
  55667 
  55668     /* initialize fields to the beginning of the Epoch */
  55669     for (i = 0; i < 9; i++) {
  55670         fields[i] = (i == 2);
  55671     }
  55672     *is_local = FALSE;
  55673 
  55674     /* year is either yyyy digits or [+-]yyyyyy */
  55675     sgn = sp[p];
  55676     if (sgn == '-' || sgn == '+') {
  55677         p++;
  55678         if (!string_get_digits(sp, &p, &fields[0], 6, 6))
  55679             return FALSE;
  55680         if (sgn == '-') {
  55681             if (fields[0] == 0)
  55682                 return FALSE; // reject -000000
  55683             fields[0] = -fields[0];
  55684         }
  55685     } else {
  55686         if (!string_get_digits(sp, &p, &fields[0], 4, 4))
  55687             return FALSE;
  55688     }
  55689     if (string_skip_char(sp, &p, '-')) {
  55690         if (!string_get_digits(sp, &p, &fields[1], 2, 2))  /* month */
  55691             return FALSE;
  55692         if (fields[1] < 1)
  55693             return FALSE;
  55694         fields[1] -= 1;
  55695         if (string_skip_char(sp, &p, '-')) {
  55696             if (!string_get_digits(sp, &p, &fields[2], 2, 2))  /* day */
  55697                 return FALSE;
  55698             if (fields[2] < 1)
  55699                 return FALSE;
  55700         }
  55701     }
  55702     if (string_skip_char(sp, &p, 'T')) {
  55703         *is_local = TRUE;
  55704         if (!string_get_digits(sp, &p, &fields[3], 2, 2)  /* hour */
  55705         ||  !string_skip_char(sp, &p, ':')
  55706         ||  !string_get_digits(sp, &p, &fields[4], 2, 2)) {  /* minute */
  55707             fields[3] = 100;  // reject unconditionally
  55708             return TRUE;
  55709         }
  55710         if (string_skip_char(sp, &p, ':')) {
  55711             if (!string_get_digits(sp, &p, &fields[5], 2, 2))  /* second */
  55712                 return FALSE;
  55713             string_get_milliseconds(sp, &p, &fields[6]);
  55714         }
  55715     }
  55716     /* parse the time zone offset if present: [+-]HH:mm or [+-]HHmm */
  55717     if (sp[p]) {
  55718         *is_local = FALSE;
  55719         if (!string_get_tzoffset(sp, &p, &fields[8], TRUE))
  55720             return FALSE;
  55721     }
  55722     /* error if extraneous characters */
  55723     return sp[p] == '\0';
  55724 }
  55725 
  55726 static struct {
  55727     char name[6];
  55728     int16_t offset;
  55729 } const js_tzabbr[] = {
  55730     { "GMT",   0 },         // Greenwich Mean Time
  55731     { "UTC",   0 },         // Coordinated Universal Time
  55732     { "UT",    0 },         // Universal Time
  55733     { "Z",     0 },         // Zulu Time
  55734     { "EDT",  -4 * 60 },    // Eastern Daylight Time
  55735     { "EST",  -5 * 60 },    // Eastern Standard Time
  55736     { "CDT",  -5 * 60 },    // Central Daylight Time
  55737     { "CST",  -6 * 60 },    // Central Standard Time
  55738     { "MDT",  -6 * 60 },    // Mountain Daylight Time
  55739     { "MST",  -7 * 60 },    // Mountain Standard Time
  55740     { "PDT",  -7 * 60 },    // Pacific Daylight Time
  55741     { "PST",  -8 * 60 },    // Pacific Standard Time
  55742     { "WET",  +0 * 60 },    // Western European Time
  55743     { "WEST", +1 * 60 },    // Western European Summer Time
  55744     { "CET",  +1 * 60 },    // Central European Time
  55745     { "CEST", +2 * 60 },    // Central European Summer Time
  55746     { "EET",  +2 * 60 },    // Eastern European Time
  55747     { "EEST", +3 * 60 },    // Eastern European Summer Time
  55748 };
  55749 
  55750 static BOOL string_get_tzabbr(const uint8_t *sp, int *pp, int *offset) {
  55751     for (size_t i = 0; i < countof(js_tzabbr); i++) {
  55752         if (string_match(sp, pp, js_tzabbr[i].name)) {
  55753             *offset = js_tzabbr[i].offset;
  55754             return TRUE;
  55755         }
  55756     }
  55757     return FALSE;
  55758 }
  55759 
  55760 /* parse toString, toUTCString and other formats */
  55761 static BOOL js_date_parse_otherstring(const uint8_t *sp,
  55762                                       int fields[minimum_length(9)],
  55763                                       BOOL *is_local) {
  55764     int c, i, val, p = 0, p_start;
  55765     int num[3];
  55766     BOOL has_year = FALSE;
  55767     BOOL has_mon = FALSE;
  55768     BOOL has_time = FALSE;
  55769     int num_index = 0;
  55770 
  55771     /* initialize fields to the beginning of 2001-01-01 */
  55772     fields[0] = 2001;
  55773     fields[1] = 1;
  55774     fields[2] = 1;
  55775     for (i = 3; i < 9; i++) {
  55776         fields[i] = 0;
  55777     }
  55778     *is_local = TRUE;
  55779 
  55780     while (string_skip_spaces(sp, &p)) {
  55781         p_start = p;
  55782         if ((c = sp[p]) == '+' || c == '-') {
  55783             if (has_time && string_get_tzoffset(sp, &p, &fields[8], FALSE)) {
  55784                 *is_local = FALSE;
  55785             } else {
  55786                 p++;
  55787                 if (string_get_digits(sp, &p, &val, 1, 0)) {
  55788                     if (c == '-') {
  55789                         if (val == 0)
  55790                             return FALSE;
  55791                         val = -val;
  55792                     }
  55793                     fields[0] = val;
  55794                     has_year = TRUE;
  55795                 }
  55796             }
  55797         } else
  55798         if (string_get_digits(sp, &p, &val, 1, 0)) {
  55799             if (string_skip_char(sp, &p, ':')) {
  55800                 /* time part */
  55801                 fields[3] = val;
  55802                 if (!string_get_digits(sp, &p, &fields[4], 1, 2))
  55803                     return FALSE;
  55804                 if (string_skip_char(sp, &p, ':')) {
  55805                     if (!string_get_digits(sp, &p, &fields[5], 1, 2))
  55806                         return FALSE;
  55807                     string_get_milliseconds(sp, &p, &fields[6]);
  55808                 }
  55809                 has_time = TRUE;
  55810                 if ((sp[p] == '+' || sp[p] == '-') &&
  55811                     string_get_tzoffset(sp, &p, &fields[8], FALSE)) {
  55812                     *is_local = FALSE;
  55813                 }
  55814             } else {
  55815                 if (p - p_start > 2 && !has_year) {
  55816                     fields[0] = val;
  55817                     has_year = TRUE;
  55818                 } else
  55819                 if ((val < 1 || val > 31) && !has_year) {
  55820                     fields[0] = val + (val < 100) * 1900 + (val < 50) * 100;
  55821                     has_year = TRUE;
  55822                 } else {
  55823                     if (num_index == 3)
  55824                         return FALSE;
  55825                     num[num_index++] = val;
  55826                 }
  55827             }
  55828         } else
  55829         if (string_get_month(sp, &p, &fields[1])) {
  55830             has_mon = TRUE;
  55831             string_skip_until(sp, &p, "0123456789 -/(");
  55832         } else
  55833         if (has_time && string_match(sp, &p, "PM")) {
  55834             if (fields[3] < 12)
  55835                 fields[3] += 12;
  55836             continue;
  55837         } else
  55838         if (has_time && string_match(sp, &p, "AM")) {
  55839             if (fields[3] == 12)
  55840                 fields[3] -= 12;
  55841             continue;
  55842         } else
  55843         if (string_get_tzabbr(sp, &p, &fields[8])) {
  55844             *is_local = FALSE;
  55845             continue;
  55846         } else
  55847         if (c == '(') {  /* skip parenthesized phrase */
  55848             int level = 0;
  55849             while ((c = sp[p]) != '\0') {
  55850                 p++;
  55851                 level += (c == '(');
  55852                 level -= (c == ')');
  55853                 if (!level)
  55854                     break;
  55855             }
  55856             if (level > 0)
  55857                 return FALSE;
  55858         } else
  55859         if (c == ')') {
  55860             return FALSE;
  55861         } else {
  55862             if (has_year + has_mon + has_time + num_index)
  55863                 return FALSE;
  55864             /* skip a word */
  55865             string_skip_until(sp, &p, " -/(");
  55866         }
  55867         string_skip_separators(sp, &p);
  55868     }
  55869     if (num_index + has_year + has_mon > 3)
  55870         return FALSE;
  55871 
  55872     switch (num_index) {
  55873     case 0:
  55874         if (!has_year)
  55875             return FALSE;
  55876         break;
  55877     case 1:
  55878         if (has_mon)
  55879             fields[2] = num[0];
  55880         else
  55881             fields[1] = num[0];
  55882         break;
  55883     case 2:
  55884         if (has_year) {
  55885             fields[1] = num[0];
  55886             fields[2] = num[1];
  55887         } else
  55888         if (has_mon) {
  55889             fields[0] = num[1] + (num[1] < 100) * 1900 + (num[1] < 50) * 100;
  55890             fields[2] = num[0];
  55891         } else {
  55892             fields[1] = num[0];
  55893             fields[2] = num[1];
  55894         }
  55895         break;
  55896     case 3:
  55897         fields[0] = num[2] + (num[2] < 100) * 1900 + (num[2] < 50) * 100;
  55898         fields[1] = num[0];
  55899         fields[2] = num[1];
  55900         break;
  55901     default:
  55902         return FALSE;
  55903     }
  55904     if (fields[1] < 1 || fields[2] < 1)
  55905         return FALSE;
  55906     fields[1] -= 1;
  55907     return TRUE;
  55908 }
  55909 
  55910 static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
  55911                              int argc, JSValueConst *argv)
  55912 {
  55913     JSValue s, rv;
  55914     int fields[9];
  55915     double fields1[9];
  55916     double d;
  55917     int i, c;
  55918     JSString *sp;
  55919     uint8_t buf[128];
  55920     BOOL is_local;
  55921 
  55922     rv = JS_NAN;
  55923 
  55924     s = JS_ToString(ctx, argv[0]);
  55925     if (JS_IsException(s))
  55926         return JS_EXCEPTION;
  55927 
  55928     sp = JS_VALUE_GET_STRING(s);
  55929     /* convert the string as a byte array */
  55930     for (i = 0; i < sp->len && i < (int)countof(buf) - 1; i++) {
  55931         c = string_get(sp, i);
  55932         if (c > 255)
  55933             c = (c == 0x2212) ? '-' : 'x';
  55934         buf[i] = c;
  55935     }
  55936     buf[i] = '\0';
  55937     if (js_date_parse_isostring(buf, fields, &is_local)
  55938     ||  js_date_parse_otherstring(buf, fields, &is_local)) {
  55939         static int const field_max[6] = { 0, 11, 31, 24, 59, 59 };
  55940         BOOL valid = TRUE;
  55941         /* check field maximum values */
  55942         for (i = 1; i < 6; i++) {
  55943             if (fields[i] > field_max[i])
  55944                 valid = FALSE;
  55945         }
  55946         /* special case 24:00:00.000 */
  55947         if (fields[3] == 24 && (fields[4] | fields[5] | fields[6]))
  55948             valid = FALSE;
  55949         if (valid) {
  55950             for(i = 0; i < 7; i++)
  55951                 fields1[i] = fields[i];
  55952             d = set_date_fields(fields1, is_local) - fields[8] * 60000;
  55953             rv = JS_NewFloat64(ctx, d);
  55954         }
  55955     }
  55956     JS_FreeValue(ctx, s);
  55957     return rv;
  55958 }
  55959 
  55960 static JSValue js_Date_now(JSContext *ctx, JSValueConst this_val,
  55961                            int argc, JSValueConst *argv)
  55962 {
  55963     // now()
  55964     return JS_NewInt64(ctx, date_now());
  55965 }
  55966 
  55967 static JSValue js_date_Symbol_toPrimitive(JSContext *ctx, JSValueConst this_val,
  55968                                           int argc, JSValueConst *argv)
  55969 {
  55970     // Symbol_toPrimitive(hint)
  55971     JSValueConst obj = this_val;
  55972     JSAtom hint = JS_ATOM_NULL;
  55973     int hint_num;
  55974 
  55975     if (!JS_IsObject(obj))
  55976         return JS_ThrowTypeErrorNotAnObject(ctx);
  55977 
  55978     if (JS_IsString(argv[0])) {
  55979         hint = JS_ValueToAtom(ctx, argv[0]);
  55980         if (hint == JS_ATOM_NULL)
  55981             return JS_EXCEPTION;
  55982         JS_FreeAtom(ctx, hint);
  55983     }
  55984     switch (hint) {
  55985     case JS_ATOM_number:
  55986     case JS_ATOM_integer:
  55987         hint_num = HINT_NUMBER;
  55988         break;
  55989     case JS_ATOM_string:
  55990     case JS_ATOM_default:
  55991         hint_num = HINT_STRING;
  55992         break;
  55993     default:
  55994         return JS_ThrowTypeError(ctx, "invalid hint");
  55995     }
  55996     return JS_ToPrimitive(ctx, obj, hint_num | HINT_FORCE_ORDINARY);
  55997 }
  55998 
  55999 static JSValue js_date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val,
  56000                                          int argc, JSValueConst *argv)
  56001 {
  56002     // getTimezoneOffset()
  56003     double v;
  56004 
  56005     if (JS_ThisTimeValue(ctx, &v, this_val))
  56006         return JS_EXCEPTION;
  56007     if (isnan(v))
  56008         return JS_NAN;
  56009     else
  56010         /* assuming -8.64e15 <= v <= -8.64e15 */
  56011         return JS_NewInt64(ctx, getTimezoneOffset((int64_t)trunc(v)));
  56012 }
  56013 
  56014 static JSValue js_date_getTime(JSContext *ctx, JSValueConst this_val,
  56015                                int argc, JSValueConst *argv)
  56016 {
  56017     // getTime()
  56018     double v;
  56019 
  56020     if (JS_ThisTimeValue(ctx, &v, this_val))
  56021         return JS_EXCEPTION;
  56022     return JS_NewFloat64(ctx, v);
  56023 }
  56024 
  56025 static JSValue js_date_setTime(JSContext *ctx, JSValueConst this_val,
  56026                                int argc, JSValueConst *argv)
  56027 {
  56028     // setTime(v)
  56029     double v;
  56030 
  56031     if (JS_ThisTimeValue(ctx, &v, this_val) || JS_ToFloat64(ctx, &v, argv[0]))
  56032         return JS_EXCEPTION;
  56033     return JS_SetThisTimeValue(ctx, this_val, time_clip(v));
  56034 }
  56035 
  56036 static JSValue js_date_setYear(JSContext *ctx, JSValueConst this_val,
  56037                                int argc, JSValueConst *argv)
  56038 {
  56039     // setYear(y)
  56040     double y;
  56041     JSValueConst args[1];
  56042 
  56043     if (JS_ThisTimeValue(ctx, &y, this_val) || JS_ToFloat64(ctx, &y, argv[0]))
  56044         return JS_EXCEPTION;
  56045     y = +y;
  56046     if (isfinite(y)) {
  56047         y = trunc(y);
  56048         if (y >= 0 && y < 100)
  56049             y += 1900;
  56050     }
  56051     args[0] = JS_NewFloat64(ctx, y);
  56052     return set_date_field(ctx, this_val, 1, args, 0x011);
  56053 }
  56054 
  56055 static JSValue js_date_toJSON(JSContext *ctx, JSValueConst this_val,
  56056                               int argc, JSValueConst *argv)
  56057 {
  56058     // toJSON(key)
  56059     JSValue obj, tv, method, rv;
  56060     double d;
  56061 
  56062     rv = JS_EXCEPTION;
  56063     tv = JS_UNDEFINED;
  56064 
  56065     obj = JS_ToObject(ctx, this_val);
  56066     tv = JS_ToPrimitive(ctx, obj, HINT_NUMBER);
  56067     if (JS_IsException(tv))
  56068         goto exception;
  56069     if (JS_IsNumber(tv)) {
  56070         if (JS_ToFloat64(ctx, &d, tv) < 0)
  56071             goto exception;
  56072         if (!isfinite(d)) {
  56073             rv = JS_NULL;
  56074             goto done;
  56075         }
  56076     }
  56077     method = JS_GetProperty(ctx, obj, JS_ATOM_toISOString);
  56078     if (JS_IsException(method))
  56079         goto exception;
  56080     if (!JS_IsFunction(ctx, method)) {
  56081         JS_ThrowTypeError(ctx, "object needs toISOString method");
  56082         JS_FreeValue(ctx, method);
  56083         goto exception;
  56084     }
  56085     rv = JS_CallFree(ctx, method, obj, 0, NULL);
  56086 exception:
  56087 done:
  56088     JS_FreeValue(ctx, obj);
  56089     JS_FreeValue(ctx, tv);
  56090     return rv;
  56091 }
  56092 
  56093 static const JSCFunctionListEntry js_date_funcs[] = {
  56094     JS_CFUNC_DEF("now", 0, js_Date_now ),
  56095     JS_CFUNC_DEF("parse", 1, js_Date_parse ),
  56096     JS_CFUNC_DEF("UTC", 7, js_Date_UTC ),
  56097 };
  56098 
  56099 static const JSCFunctionListEntry js_date_proto_funcs[] = {
  56100     JS_CFUNC_DEF("valueOf", 0, js_date_getTime ),
  56101     JS_CFUNC_MAGIC_DEF("toString", 0, get_date_string, 0x13 ),
  56102     JS_CFUNC_DEF("[Symbol.toPrimitive]", 1, js_date_Symbol_toPrimitive ),
  56103     JS_CFUNC_MAGIC_DEF("toUTCString", 0, get_date_string, 0x03 ),
  56104     JS_ALIAS_DEF("toGMTString", "toUTCString" ),
  56105     JS_CFUNC_MAGIC_DEF("toISOString", 0, get_date_string, 0x23 ),
  56106     JS_CFUNC_MAGIC_DEF("toDateString", 0, get_date_string, 0x11 ),
  56107     JS_CFUNC_MAGIC_DEF("toTimeString", 0, get_date_string, 0x12 ),
  56108     JS_CFUNC_MAGIC_DEF("toLocaleString", 0, get_date_string, 0x33 ),
  56109     JS_CFUNC_MAGIC_DEF("toLocaleDateString", 0, get_date_string, 0x31 ),
  56110     JS_CFUNC_MAGIC_DEF("toLocaleTimeString", 0, get_date_string, 0x32 ),
  56111     JS_CFUNC_DEF("getTimezoneOffset", 0, js_date_getTimezoneOffset ),
  56112     JS_CFUNC_DEF("getTime", 0, js_date_getTime ),
  56113     JS_CFUNC_MAGIC_DEF("getYear", 0, get_date_field, 0x101 ),
  56114     JS_CFUNC_MAGIC_DEF("getFullYear", 0, get_date_field, 0x01 ),
  56115     JS_CFUNC_MAGIC_DEF("getUTCFullYear", 0, get_date_field, 0x00 ),
  56116     JS_CFUNC_MAGIC_DEF("getMonth", 0, get_date_field, 0x11 ),
  56117     JS_CFUNC_MAGIC_DEF("getUTCMonth", 0, get_date_field, 0x10 ),
  56118     JS_CFUNC_MAGIC_DEF("getDate", 0, get_date_field, 0x21 ),
  56119     JS_CFUNC_MAGIC_DEF("getUTCDate", 0, get_date_field, 0x20 ),
  56120     JS_CFUNC_MAGIC_DEF("getHours", 0, get_date_field, 0x31 ),
  56121     JS_CFUNC_MAGIC_DEF("getUTCHours", 0, get_date_field, 0x30 ),
  56122     JS_CFUNC_MAGIC_DEF("getMinutes", 0, get_date_field, 0x41 ),
  56123     JS_CFUNC_MAGIC_DEF("getUTCMinutes", 0, get_date_field, 0x40 ),
  56124     JS_CFUNC_MAGIC_DEF("getSeconds", 0, get_date_field, 0x51 ),
  56125     JS_CFUNC_MAGIC_DEF("getUTCSeconds", 0, get_date_field, 0x50 ),
  56126     JS_CFUNC_MAGIC_DEF("getMilliseconds", 0, get_date_field, 0x61 ),
  56127     JS_CFUNC_MAGIC_DEF("getUTCMilliseconds", 0, get_date_field, 0x60 ),
  56128     JS_CFUNC_MAGIC_DEF("getDay", 0, get_date_field, 0x71 ),
  56129     JS_CFUNC_MAGIC_DEF("getUTCDay", 0, get_date_field, 0x70 ),
  56130     JS_CFUNC_DEF("setTime", 1, js_date_setTime ),
  56131     JS_CFUNC_MAGIC_DEF("setMilliseconds", 1, set_date_field, 0x671 ),
  56132     JS_CFUNC_MAGIC_DEF("setUTCMilliseconds", 1, set_date_field, 0x670 ),
  56133     JS_CFUNC_MAGIC_DEF("setSeconds", 2, set_date_field, 0x571 ),
  56134     JS_CFUNC_MAGIC_DEF("setUTCSeconds", 2, set_date_field, 0x570 ),
  56135     JS_CFUNC_MAGIC_DEF("setMinutes", 3, set_date_field, 0x471 ),
  56136     JS_CFUNC_MAGIC_DEF("setUTCMinutes", 3, set_date_field, 0x470 ),
  56137     JS_CFUNC_MAGIC_DEF("setHours", 4, set_date_field, 0x371 ),
  56138     JS_CFUNC_MAGIC_DEF("setUTCHours", 4, set_date_field, 0x370 ),
  56139     JS_CFUNC_MAGIC_DEF("setDate", 1, set_date_field, 0x231 ),
  56140     JS_CFUNC_MAGIC_DEF("setUTCDate", 1, set_date_field, 0x230 ),
  56141     JS_CFUNC_MAGIC_DEF("setMonth", 2, set_date_field, 0x131 ),
  56142     JS_CFUNC_MAGIC_DEF("setUTCMonth", 2, set_date_field, 0x130 ),
  56143     JS_CFUNC_DEF("setYear", 1, js_date_setYear ),
  56144     JS_CFUNC_MAGIC_DEF("setFullYear", 3, set_date_field, 0x031 ),
  56145     JS_CFUNC_MAGIC_DEF("setUTCFullYear", 3, set_date_field, 0x030 ),
  56146     JS_CFUNC_DEF("toJSON", 1, js_date_toJSON ),
  56147 };
  56148 
  56149 JSValue JS_NewDate(JSContext *ctx, double epoch_ms)
  56150 {
  56151     JSValue obj = js_create_from_ctor(ctx, JS_UNDEFINED, JS_CLASS_DATE);
  56152     if (JS_IsException(obj))
  56153         return JS_EXCEPTION;
  56154     JS_SetObjectData(ctx, obj, __JS_NewFloat64(ctx, time_clip(epoch_ms)));
  56155     return obj;
  56156 }
  56157 
  56158 int JS_AddIntrinsicDate(JSContext *ctx)
  56159 {
  56160     JSValue obj;
  56161 
  56162     /* Date */
  56163     obj = JS_NewCConstructor(ctx, JS_CLASS_DATE, "Date",
  56164                                     js_date_constructor, 7, JS_CFUNC_constructor_or_func, 0,
  56165                                     JS_UNDEFINED,
  56166                                     js_date_funcs, countof(js_date_funcs),
  56167                                     js_date_proto_funcs, countof(js_date_proto_funcs),
  56168                                     0);
  56169     if (JS_IsException(obj))
  56170         return -1;
  56171     JS_FreeValue(ctx, obj);
  56172     return 0;
  56173 }
  56174 
  56175 /* eval */
  56176 
  56177 int JS_AddIntrinsicEval(JSContext *ctx)
  56178 {
  56179     ctx->eval_internal = __JS_EvalInternal;
  56180     return 0;
  56181 }
  56182 
  56183 /* BigInt */
  56184 
  56185 static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)
  56186 {
  56187     uint32_t tag;
  56188 
  56189  redo:
  56190     tag = JS_VALUE_GET_NORM_TAG(val);
  56191     switch(tag) {
  56192     case JS_TAG_INT:
  56193     case JS_TAG_BOOL:
  56194         val = JS_NewBigInt64(ctx, JS_VALUE_GET_INT(val));
  56195         break;
  56196     case JS_TAG_SHORT_BIG_INT:
  56197     case JS_TAG_BIG_INT:
  56198         break;
  56199     case JS_TAG_FLOAT64:
  56200         {
  56201             double d = JS_VALUE_GET_FLOAT64(val);
  56202             JSBigInt *r;
  56203             int res;
  56204             r = js_bigint_from_float64(ctx, &res, d);
  56205             if (!r) {
  56206                 if (res == 0) {
  56207                     val = JS_EXCEPTION;
  56208                 } else if (res == 1) {
  56209                     val = JS_ThrowRangeError(ctx, "cannot convert to BigInt: not an integer");
  56210                 } else {
  56211                     val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to BigInt");                }
  56212             } else {
  56213                 val = JS_CompactBigInt(ctx, r);
  56214             }
  56215         }
  56216         break;
  56217     case JS_TAG_STRING:
  56218     case JS_TAG_STRING_ROPE:
  56219         val = JS_StringToBigIntErr(ctx, val);
  56220         break;
  56221     case JS_TAG_OBJECT:
  56222         val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
  56223         if (JS_IsException(val))
  56224             break;
  56225         goto redo;
  56226     case JS_TAG_NULL:
  56227     case JS_TAG_UNDEFINED:
  56228     default:
  56229         JS_FreeValue(ctx, val);
  56230         return JS_ThrowTypeError(ctx, "cannot convert to BigInt");
  56231     }
  56232     return val;
  56233 }
  56234 
  56235 static JSValue js_bigint_constructor(JSContext *ctx,
  56236                                      JSValueConst new_target,
  56237                                      int argc, JSValueConst *argv)
  56238 {
  56239     if (!JS_IsUndefined(new_target))
  56240         return JS_ThrowTypeErrorNotAConstructor(ctx, new_target);
  56241     return JS_ToBigIntCtorFree(ctx, JS_DupValue(ctx, argv[0]));
  56242 }
  56243 
  56244 static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val)
  56245 {
  56246     if (JS_IsBigInt(ctx, this_val))
  56247         return JS_DupValue(ctx, this_val);
  56248 
  56249     if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
  56250         JSObject *p = JS_VALUE_GET_OBJ(this_val);
  56251         if (p->class_id == JS_CLASS_BIG_INT) {
  56252             if (JS_IsBigInt(ctx, p->u.object_data))
  56253                 return JS_DupValue(ctx, p->u.object_data);
  56254         }
  56255     }
  56256     return JS_ThrowTypeError(ctx, "not a BigInt");
  56257 }
  56258 
  56259 static JSValue js_bigint_toString(JSContext *ctx, JSValueConst this_val,
  56260                                   int argc, JSValueConst *argv)
  56261 {
  56262     JSValue val;
  56263     int base;
  56264     JSValue ret;
  56265 
  56266     val = js_thisBigIntValue(ctx, this_val);
  56267     if (JS_IsException(val))
  56268         return val;
  56269     if (argc == 0 || JS_IsUndefined(argv[0])) {
  56270         base = 10;
  56271     } else {
  56272         base = js_get_radix(ctx, argv[0]);
  56273         if (base < 0)
  56274             goto fail;
  56275     }
  56276     ret = js_bigint_to_string1(ctx, val, base);
  56277     JS_FreeValue(ctx, val);
  56278     return ret;
  56279  fail:
  56280     JS_FreeValue(ctx, val);
  56281     return JS_EXCEPTION;
  56282 }
  56283 
  56284 static JSValue js_bigint_valueOf(JSContext *ctx, JSValueConst this_val,
  56285                                  int argc, JSValueConst *argv)
  56286 {
  56287     return js_thisBigIntValue(ctx, this_val);
  56288 }
  56289 
  56290 static JSValue js_bigint_asUintN(JSContext *ctx,
  56291                                   JSValueConst this_val,
  56292                                   int argc, JSValueConst *argv, int asIntN)
  56293 {
  56294     uint64_t bits;
  56295     JSValue res, a;
  56296     
  56297     if (JS_ToIndex(ctx, &bits, argv[0]))
  56298         return JS_EXCEPTION;
  56299     a = JS_ToBigInt(ctx, argv[1]);
  56300     if (JS_IsException(a))
  56301         return JS_EXCEPTION;
  56302     if (bits == 0) {
  56303         JS_FreeValue(ctx, a);
  56304         res = __JS_NewShortBigInt(ctx, 0);
  56305     } else if (JS_VALUE_GET_TAG(a) == JS_TAG_SHORT_BIG_INT) {
  56306         /* fast case */
  56307         if (bits >= JS_SHORT_BIG_INT_BITS) {
  56308             res = a;
  56309         } else {
  56310             uint64_t v;
  56311             int shift;
  56312             shift = 64 - bits;
  56313             v = JS_VALUE_GET_SHORT_BIG_INT(a);
  56314             v = v << shift;
  56315             if (asIntN)
  56316                 v = (int64_t)v >> shift;
  56317             else
  56318                 v = v >> shift;
  56319             res = __JS_NewShortBigInt(ctx, v);
  56320         }
  56321     } else {
  56322         JSBigInt *r, *p = JS_VALUE_GET_PTR(a);
  56323         if (bits >= p->len * JS_LIMB_BITS) {
  56324             res = a;
  56325         } else {
  56326             int len, shift, i;
  56327             js_limb_t v;
  56328             len = (bits + JS_LIMB_BITS - 1) / JS_LIMB_BITS;
  56329             r = js_bigint_new(ctx, len);
  56330             if (!r) {
  56331                 JS_FreeValue(ctx, a);
  56332                 return JS_EXCEPTION;
  56333             }
  56334             r->len = len;
  56335             for(i = 0; i < len - 1; i++)
  56336                 r->tab[i] = p->tab[i];
  56337             shift = (-bits) & (JS_LIMB_BITS - 1);
  56338             /* 0 <= shift <= JS_LIMB_BITS - 1 */
  56339             v = p->tab[len - 1] << shift;
  56340             if (asIntN)
  56341                 v = (js_slimb_t)v >> shift;
  56342             else
  56343                 v = v >> shift;
  56344             r->tab[len - 1] = v;
  56345             r = js_bigint_normalize(ctx, r);
  56346             JS_FreeValue(ctx, a);
  56347             res = JS_CompactBigInt(ctx, r);
  56348         }
  56349     }
  56350     return res;
  56351 }
  56352 
  56353 static const JSCFunctionListEntry js_bigint_funcs[] = {
  56354     JS_CFUNC_MAGIC_DEF("asUintN", 2, js_bigint_asUintN, 0 ),
  56355     JS_CFUNC_MAGIC_DEF("asIntN", 2, js_bigint_asUintN, 1 ),
  56356 };
  56357 
  56358 static const JSCFunctionListEntry js_bigint_proto_funcs[] = {
  56359     JS_CFUNC_DEF("toString", 0, js_bigint_toString ),
  56360     JS_CFUNC_DEF("valueOf", 0, js_bigint_valueOf ),
  56361     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "BigInt", JS_PROP_CONFIGURABLE ),
  56362 };
  56363 
  56364 static int JS_AddIntrinsicBigInt(JSContext *ctx)
  56365 {
  56366     JSValue obj1;
  56367 
  56368     obj1 = JS_NewCConstructor(ctx, JS_CLASS_BIG_INT, "BigInt",
  56369                                      js_bigint_constructor, 1, JS_CFUNC_constructor_or_func, 0,
  56370                                      JS_UNDEFINED,
  56371                                      js_bigint_funcs, countof(js_bigint_funcs),
  56372                                      js_bigint_proto_funcs, countof(js_bigint_proto_funcs),
  56373                                      0);
  56374     if (JS_IsException(obj1))
  56375         return -1;
  56376     JS_FreeValue(ctx, obj1);
  56377     return 0;
  56378 }
  56379 
  56380 /* Minimum amount of objects to be able to compile code and display
  56381    error messages. */
  56382 static int JS_AddIntrinsicBasicObjects(JSContext *ctx)
  56383 {
  56384     JSValue obj;
  56385     JSCFunctionType ft;
  56386     int i;
  56387 
  56388     /* warning: ordering is tricky */
  56389     ctx->class_proto[JS_CLASS_OBJECT] =
  56390         JS_NewObjectProtoClassAlloc(ctx, JS_NULL, JS_CLASS_OBJECT,
  56391                                     countof(js_object_proto_funcs) + 1);
  56392     if (JS_IsException(ctx->class_proto[JS_CLASS_OBJECT]))
  56393         return -1;
  56394     JS_SetImmutablePrototype(ctx, ctx->class_proto[JS_CLASS_OBJECT]);
  56395 
  56396     /* 2 more properties: caller and arguments */
  56397     ctx->function_proto = JS_NewCFunction3(ctx, js_function_proto, "", 0,
  56398                                            JS_CFUNC_generic, 0,
  56399                                            ctx->class_proto[JS_CLASS_OBJECT],
  56400                                            countof(js_function_proto_funcs) + 3 + 2);
  56401     if (JS_IsException(ctx->function_proto))
  56402         return -1;
  56403     ctx->class_proto[JS_CLASS_BYTECODE_FUNCTION] = JS_DupValue(ctx, ctx->function_proto);
  56404 
  56405     ctx->global_obj = JS_NewObjectProtoClassAlloc(ctx, ctx->class_proto[JS_CLASS_OBJECT],
  56406                                                   JS_CLASS_GLOBAL_OBJECT, 64);
  56407     if (JS_IsException(ctx->global_obj))
  56408         return -1;
  56409     {
  56410         JSObject *p;
  56411         obj = JS_NewObjectProtoClassAlloc(ctx, JS_NULL, JS_CLASS_OBJECT, 4);
  56412         p = JS_VALUE_GET_OBJ(ctx->global_obj);
  56413         p->u.global_object.uninitialized_vars = obj;
  56414     }
  56415     ctx->global_var_obj = JS_NewObjectProtoClassAlloc(ctx, JS_NULL,
  56416                                                       JS_CLASS_OBJECT, 16);
  56417     if (JS_IsException(ctx->global_var_obj))
  56418         return -1;
  56419 
  56420     /* Error */
  56421     ft.generic_magic = js_error_constructor;
  56422     obj = JS_NewCConstructor(ctx, JS_CLASS_ERROR, "Error",
  56423                                     ft.generic, 1, JS_CFUNC_constructor_or_func_magic, -1,
  56424                                     JS_UNDEFINED,
  56425                                     js_error_funcs, countof(js_error_funcs),
  56426                                     js_error_proto_funcs, countof(js_error_proto_funcs),
  56427                                     0);
  56428     if (JS_IsException(obj))
  56429         return -1;
  56430 
  56431     for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
  56432         JSValue func_obj;
  56433         const JSCFunctionListEntry *funcs;
  56434         int n_args;
  56435         char buf[ATOM_GET_STR_BUF_SIZE];
  56436         const char *name = JS_AtomGetStr(ctx, buf, sizeof(buf),
  56437                                          JS_ATOM_EvalError + i);
  56438         n_args = 1 + (i == JS_AGGREGATE_ERROR);
  56439         funcs = js_native_error_proto_funcs + 2 * i;
  56440         func_obj = JS_NewCConstructor(ctx, -1, name,
  56441                                       ft.generic, n_args, JS_CFUNC_constructor_or_func_magic, i,
  56442                                       obj,
  56443                                       NULL, 0,
  56444                                       funcs, 2,
  56445                                       0);
  56446         if (JS_IsException(func_obj)) {
  56447             JS_FreeValue(ctx, obj);
  56448             return -1;
  56449         }
  56450         ctx->native_error_proto[i] = JS_GetProperty(ctx, func_obj, JS_ATOM_prototype);
  56451         JS_FreeValue(ctx, func_obj);
  56452         if (JS_IsException(ctx->native_error_proto[i])) {
  56453             JS_FreeValue(ctx, obj);
  56454             return -1;
  56455         }
  56456     }
  56457     JS_FreeValue(ctx, obj);
  56458 
  56459     /* Array */
  56460     obj = JS_NewCConstructor(ctx, JS_CLASS_ARRAY, "Array",
  56461                                     js_array_constructor, 1, JS_CFUNC_constructor_or_func, 0,
  56462                                     JS_UNDEFINED,
  56463                                     js_array_funcs, countof(js_array_funcs),
  56464                                     js_array_proto_funcs, countof(js_array_proto_funcs),
  56465                                     JS_NEW_CTOR_PROTO_CLASS);
  56466     if (JS_IsException(obj))
  56467         return -1;
  56468     ctx->array_ctor = obj;
  56469 
  56470     {
  56471         JSObject *p = JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_ARRAY]);
  56472         p->is_std_array_prototype = TRUE;
  56473     }
  56474     
  56475     ctx->array_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_ARRAY]),
  56476                                      JS_PROP_INITIAL_HASH_SIZE, 1);
  56477     if (!ctx->array_shape)
  56478         return -1;
  56479     if (add_shape_property(ctx, &ctx->array_shape, NULL,
  56480                            JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_LENGTH))
  56481         return -1;
  56482 
  56483     ctx->arguments_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_OBJECT]),
  56484                                          JS_PROP_INITIAL_HASH_SIZE, 3);
  56485     if (!ctx->arguments_shape)
  56486         return -1;
  56487     if (add_shape_property(ctx, &ctx->arguments_shape, NULL,
  56488                            JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE))
  56489         return -1;
  56490     if (add_shape_property(ctx, &ctx->arguments_shape, NULL,
  56491                            JS_ATOM_Symbol_iterator, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE))
  56492         return -1;
  56493     if (add_shape_property(ctx, &ctx->arguments_shape, NULL,
  56494                            JS_ATOM_callee, JS_PROP_GETSET))
  56495         return -1;
  56496 
  56497     ctx->mapped_arguments_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_OBJECT]),
  56498                                          JS_PROP_INITIAL_HASH_SIZE, 3);
  56499     if (!ctx->mapped_arguments_shape)
  56500         return -1;
  56501     if (add_shape_property(ctx, &ctx->mapped_arguments_shape, NULL,
  56502                            JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE))
  56503         return -1;
  56504     if (add_shape_property(ctx, &ctx->mapped_arguments_shape, NULL,
  56505                            JS_ATOM_Symbol_iterator, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE))
  56506         return -1;
  56507     if (add_shape_property(ctx, &ctx->mapped_arguments_shape, NULL,
  56508                            JS_ATOM_callee, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE))
  56509         return -1;
  56510     
  56511     return 0;
  56512 }
  56513 
  56514 int JS_AddIntrinsicBaseObjects(JSContext *ctx)
  56515 {
  56516     JSValue obj1, obj2;
  56517     JSCFunctionType ft;
  56518 
  56519     ctx->throw_type_error = JS_NewCFunction(ctx, js_throw_type_error, NULL, 0);
  56520     if (JS_IsException(ctx->throw_type_error))
  56521         return -1;
  56522     /* add caller and arguments properties to throw a TypeError */
  56523     if (JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_caller, JS_UNDEFINED,
  56524                           ctx->throw_type_error, ctx->throw_type_error,
  56525                           JS_PROP_HAS_GET | JS_PROP_HAS_SET |
  56526                           JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE) < 0)
  56527         return -1;
  56528     if (JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_arguments, JS_UNDEFINED,
  56529                           ctx->throw_type_error, ctx->throw_type_error,
  56530                           JS_PROP_HAS_GET | JS_PROP_HAS_SET |
  56531                           JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE) < 0)
  56532         return -1;
  56533     JS_FreeValue(ctx, js_object_seal(ctx, JS_UNDEFINED, 1, (JSValueConst *)&ctx->throw_type_error, 1));
  56534 
  56535     /* Object */
  56536     obj1 = JS_NewCConstructor(ctx, JS_CLASS_OBJECT, "Object",
  56537                               js_object_constructor, 1, JS_CFUNC_constructor_or_func, 0,
  56538                               JS_UNDEFINED,
  56539                               js_object_funcs, countof(js_object_funcs),
  56540                               js_object_proto_funcs, countof(js_object_proto_funcs),
  56541                               JS_NEW_CTOR_PROTO_EXIST);
  56542     if (JS_IsException(obj1))
  56543         return -1;
  56544     JS_FreeValue(ctx, obj1);
  56545     
  56546     /* Function */
  56547     ft.generic_magic = js_function_constructor;
  56548     obj1 = JS_NewCConstructor(ctx, JS_CLASS_BYTECODE_FUNCTION, "Function",
  56549                               ft.generic, 1, JS_CFUNC_constructor_or_func_magic, JS_FUNC_NORMAL,
  56550                               JS_UNDEFINED,
  56551                               NULL, 0,
  56552                               js_function_proto_funcs, countof(js_function_proto_funcs),
  56553                               JS_NEW_CTOR_PROTO_EXIST);
  56554     if (JS_IsException(obj1))
  56555         return -1;
  56556     ctx->function_ctor = obj1;
  56557 
  56558     /* Iterator */
  56559     obj2 = JS_NewCConstructor(ctx, JS_CLASS_ITERATOR, "Iterator",
  56560                                      js_iterator_constructor, 0, JS_CFUNC_constructor_or_func, 0,
  56561                                      JS_UNDEFINED,
  56562                                      js_iterator_funcs, countof(js_iterator_funcs),
  56563                                      js_iterator_proto_funcs, countof(js_iterator_proto_funcs),
  56564                                      0);
  56565     if (JS_IsException(obj2))
  56566         return -1;
  56567     // quirk: Iterator.prototype.constructor is an accessor property
  56568     // TODO(bnoordhuis) mildly inefficient because JS_NewGlobalCConstructor
  56569     // first creates a .constructor value property that we then replace with
  56570     // an accessor
  56571     obj1 = JS_NewCFunctionData(ctx, js_iterator_constructor_getset,
  56572                                0, 0, 1, (JSValueConst *)&obj2);
  56573     if (JS_IsException(obj1)) {
  56574         JS_FreeValue(ctx, obj2);
  56575         return -1;
  56576     }
  56577     if (JS_DefineProperty(ctx, ctx->class_proto[JS_CLASS_ITERATOR],
  56578                           JS_ATOM_constructor, JS_UNDEFINED,
  56579                           obj1, obj1,
  56580                           JS_PROP_HAS_GET | JS_PROP_HAS_SET | JS_PROP_CONFIGURABLE) < 0) {
  56581         JS_FreeValue(ctx, obj2);
  56582         JS_FreeValue(ctx, obj1);
  56583         return -1;
  56584     }
  56585     JS_FreeValue(ctx, obj1);
  56586     ctx->iterator_ctor = obj2;
  56587     
  56588     ctx->class_proto[JS_CLASS_ITERATOR_CONCAT] =
  56589         JS_NewObjectProtoList(ctx, ctx->class_proto[JS_CLASS_ITERATOR], 
  56590                               js_iterator_concat_proto_funcs,
  56591                               countof(js_iterator_concat_proto_funcs));
  56592     if (JS_IsException(ctx->class_proto[JS_CLASS_ITERATOR_CONCAT]))
  56593         return -1;
  56594     ctx->class_proto[JS_CLASS_ITERATOR_HELPER] =
  56595         JS_NewObjectProtoList(ctx, ctx->class_proto[JS_CLASS_ITERATOR], 
  56596                               js_iterator_helper_proto_funcs,
  56597                               countof(js_iterator_helper_proto_funcs));
  56598     if (JS_IsException(ctx->class_proto[JS_CLASS_ITERATOR_HELPER]))
  56599         return -1;
  56600                        
  56601     ctx->class_proto[JS_CLASS_ITERATOR_WRAP] =
  56602         JS_NewObjectProtoList(ctx, ctx->class_proto[JS_CLASS_ITERATOR], 
  56603                               js_iterator_wrap_proto_funcs,
  56604                               countof(js_iterator_wrap_proto_funcs));
  56605     if (JS_IsException(ctx->class_proto[JS_CLASS_ITERATOR_WRAP]))
  56606         return -1;
  56607 
  56608     /* needed to initialize arguments[Symbol.iterator] */
  56609     ctx->array_proto_values =
  56610         JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_values);
  56611     if (JS_IsException(ctx->array_proto_values))
  56612         return -1;
  56613 
  56614     ctx->class_proto[JS_CLASS_ARRAY_ITERATOR] =
  56615         JS_NewObjectProtoList(ctx, ctx->class_proto[JS_CLASS_ITERATOR], 
  56616                               js_array_iterator_proto_funcs,
  56617                               countof(js_array_iterator_proto_funcs));
  56618     if (JS_IsException(ctx->class_proto[JS_CLASS_ARRAY_ITERATOR]))
  56619         return -1;
  56620 
  56621     /* parseFloat and parseInteger must be defined before Number
  56622        because of the Number.parseFloat and Number.parseInteger
  56623        aliases */
  56624     if (JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_global_funcs,
  56625                                    countof(js_global_funcs)))
  56626         return -1;
  56627 
  56628     /* Number */
  56629     obj1 = JS_NewCConstructor(ctx, JS_CLASS_NUMBER, "Number",
  56630                                      js_number_constructor, 1, JS_CFUNC_constructor_or_func, 0,
  56631                                      JS_UNDEFINED,
  56632                                      js_number_funcs, countof(js_number_funcs),
  56633                                      js_number_proto_funcs, countof(js_number_proto_funcs),
  56634                                      JS_NEW_CTOR_PROTO_CLASS);
  56635     if (JS_IsException(obj1))
  56636         return -1;
  56637     JS_FreeValue(ctx, obj1);
  56638     if (JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_NUMBER], JS_NewInt32(ctx, 0)))
  56639         return -1;
  56640     
  56641     /* Boolean */
  56642     obj1 = JS_NewCConstructor(ctx, JS_CLASS_BOOLEAN, "Boolean",
  56643                                      js_boolean_constructor, 1, JS_CFUNC_constructor_or_func, 0,
  56644                                      JS_UNDEFINED,
  56645                                      NULL, 0,
  56646                                      js_boolean_proto_funcs, countof(js_boolean_proto_funcs),
  56647                                      JS_NEW_CTOR_PROTO_CLASS);
  56648     if (JS_IsException(obj1))
  56649         return -1;
  56650     JS_FreeValue(ctx, obj1);
  56651     if (JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], JS_NewBool(ctx, FALSE)))
  56652         return -1;
  56653 
  56654     /* String */
  56655     obj1 = JS_NewCConstructor(ctx, JS_CLASS_STRING, "String",
  56656                                      js_string_constructor, 1, JS_CFUNC_constructor_or_func, 0,
  56657                                      JS_UNDEFINED,
  56658                                      js_string_funcs, countof(js_string_funcs),
  56659                                      js_string_proto_funcs, countof(js_string_proto_funcs),
  56660                                      JS_NEW_CTOR_PROTO_CLASS);
  56661     if (JS_IsException(obj1))
  56662         return -1;
  56663     JS_FreeValue(ctx, obj1);
  56664     if (JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_STRING], JS_AtomToString(ctx, JS_ATOM_empty_string)))
  56665         return -1;
  56666 
  56667     ctx->class_proto[JS_CLASS_STRING_ITERATOR] =
  56668         JS_NewObjectProtoList(ctx, ctx->class_proto[JS_CLASS_ITERATOR], 
  56669                               js_string_iterator_proto_funcs,
  56670                               countof(js_string_iterator_proto_funcs));
  56671     if (JS_IsException(ctx->class_proto[JS_CLASS_STRING_ITERATOR]))
  56672         return -1;
  56673 
  56674     /* Math: create as autoinit object */
  56675     js_random_init(ctx);
  56676     if (JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_math_obj, countof(js_math_obj)))
  56677         return -1;
  56678 
  56679     /* ES6 Reflect: create as autoinit object */
  56680     if (JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_reflect_obj, countof(js_reflect_obj)))
  56681         return -1;
  56682 
  56683     /* ES6 Symbol */
  56684     obj1 = JS_NewCConstructor(ctx, JS_CLASS_SYMBOL, "Symbol",
  56685                                      js_symbol_constructor, 0, JS_CFUNC_constructor_or_func, 0,
  56686                                      JS_UNDEFINED,
  56687                                      js_symbol_funcs, countof(js_symbol_funcs),
  56688                                      js_symbol_proto_funcs, countof(js_symbol_proto_funcs),
  56689                                      0);
  56690     if (JS_IsException(obj1))
  56691         return -1;
  56692     JS_FreeValue(ctx, obj1);
  56693     
  56694     /* ES6 Generator */
  56695     ctx->class_proto[JS_CLASS_GENERATOR] =
  56696         JS_NewObjectProtoList(ctx, ctx->class_proto[JS_CLASS_ITERATOR],
  56697                               js_generator_proto_funcs,
  56698                               countof(js_generator_proto_funcs));
  56699     if (JS_IsException(ctx->class_proto[JS_CLASS_GENERATOR]))
  56700         return -1;
  56701 
  56702     ft.generic_magic = js_function_constructor;
  56703     obj1 = JS_NewCConstructor(ctx, JS_CLASS_GENERATOR_FUNCTION, "GeneratorFunction",
  56704                                      ft.generic, 1, JS_CFUNC_constructor_or_func_magic, JS_FUNC_GENERATOR,
  56705                                      ctx->function_ctor,
  56706                                      NULL, 0,
  56707                                      js_generator_function_proto_funcs,
  56708                                      countof(js_generator_function_proto_funcs),
  56709                                      JS_NEW_CTOR_NO_GLOBAL | JS_NEW_CTOR_READONLY);
  56710     if (JS_IsException(obj1))
  56711         return -1;
  56712     JS_FreeValue(ctx, obj1);
  56713     if (JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
  56714                            ctx->class_proto[JS_CLASS_GENERATOR],
  56715                            JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE))
  56716         return -1;
  56717     
  56718     /* global properties */
  56719     ctx->eval_obj = JS_GetProperty(ctx, ctx->global_obj, JS_ATOM_eval);
  56720     if (JS_IsException(ctx->eval_obj))
  56721         return -1;
  56722     
  56723     if (JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_globalThis,
  56724                                JS_DupValue(ctx, ctx->global_obj),
  56725                                JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE) < 0)
  56726         return -1;
  56727 
  56728     /* BigInt */
  56729     if (JS_AddIntrinsicBigInt(ctx))
  56730         return -1;
  56731     return 0;
  56732 }
  56733 
  56734 /* Typed Arrays */
  56735 
  56736 static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT] = {
  56737     0, 0, 0, 1, 1, 2, 2,
  56738     3, 3,                   // BigInt64Array, BigUint64Array
  56739     1, 2, 3                 // Float16Array, Float32Array, Float64Array
  56740 };
  56741 
  56742 static JSValue js_array_buffer_constructor3(JSContext *ctx,
  56743                                             JSValueConst new_target,
  56744                                             uint64_t len, uint64_t *max_len,
  56745                                             JSClassID class_id,
  56746                                             uint8_t *buf,
  56747                                             JSFreeArrayBufferDataFunc *free_func,
  56748                                             void *opaque, BOOL alloc_flag)
  56749 {
  56750     JSRuntime *rt = ctx->rt;
  56751     JSValue obj;
  56752     JSArrayBuffer *abuf = NULL;
  56753     uint64_t sab_alloc_len;
  56754 
  56755     if (!alloc_flag && buf && max_len && free_func != js_array_buffer_free) {
  56756         // not observable from JS land, only through C API misuse;
  56757         // JS code cannot create externally managed buffers directly
  56758         return JS_ThrowInternalError(ctx,
  56759                                      "resizable ArrayBuffers not supported "
  56760                                      "for externally managed buffers");
  56761     }
  56762     obj = js_create_from_ctor(ctx, new_target, class_id);
  56763     if (JS_IsException(obj))
  56764         return obj;
  56765     /* XXX: we are currently limited to 2 GB */
  56766     if (len > INT32_MAX) {
  56767         JS_ThrowRangeError(ctx, "invalid array buffer length");
  56768         goto fail;
  56769     }
  56770     if (max_len && *max_len > INT32_MAX) {
  56771         JS_ThrowRangeError(ctx, "invalid max array buffer length");
  56772         goto fail;
  56773     }
  56774     abuf = js_malloc(ctx, sizeof(*abuf));
  56775     if (!abuf)
  56776         goto fail;
  56777     abuf->byte_length = len;
  56778     abuf->max_byte_length = max_len ? *max_len : -1;
  56779     if (alloc_flag) {
  56780         if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER &&
  56781             rt->sab_funcs.sab_alloc) {
  56782             // TOOD(bnoordhuis) resizing backing memory for SABs atomically
  56783             // is hard so we cheat and allocate |maxByteLength| bytes upfront
  56784             sab_alloc_len = max_len ? *max_len : len;
  56785             abuf->data = rt->sab_funcs.sab_alloc(rt->sab_funcs.sab_opaque,
  56786                                                  max_int(sab_alloc_len, 1));
  56787             if (!abuf->data)
  56788                 goto fail;
  56789             memset(abuf->data, 0, sab_alloc_len);
  56790         } else {
  56791             /* the allocation must be done after the object creation */
  56792             abuf->data = js_mallocz(ctx, max_int(len, 1));
  56793             if (!abuf->data)
  56794                 goto fail;
  56795         }
  56796     } else {
  56797         if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER &&
  56798             rt->sab_funcs.sab_dup) {
  56799             rt->sab_funcs.sab_dup(rt->sab_funcs.sab_opaque, buf);
  56800         }
  56801         abuf->data = buf;
  56802     }
  56803     init_list_head(&abuf->array_list);
  56804     abuf->detached = FALSE;
  56805     abuf->shared = (class_id == JS_CLASS_SHARED_ARRAY_BUFFER);
  56806     abuf->opaque = opaque;
  56807     abuf->free_func = free_func;
  56808     if (alloc_flag && buf)
  56809         memcpy(abuf->data, buf, len);
  56810     JS_SetOpaque(obj, abuf);
  56811     return obj;
  56812  fail:
  56813     JS_FreeValue(ctx, obj);
  56814     js_free(ctx, abuf);
  56815     return JS_EXCEPTION;
  56816 }
  56817 
  56818 static void js_array_buffer_free(JSRuntime *rt, void *opaque, void *ptr)
  56819 {
  56820     js_free_rt(rt, ptr);
  56821 }
  56822 
  56823 static JSValue js_array_buffer_constructor2(JSContext *ctx,
  56824                                             JSValueConst new_target,
  56825                                             uint64_t len, uint64_t *max_len,
  56826                                             JSClassID class_id)
  56827 {
  56828     return js_array_buffer_constructor3(ctx, new_target, len, max_len, class_id,
  56829                                         NULL, js_array_buffer_free, NULL,
  56830                                         TRUE);
  56831 }
  56832 
  56833 static JSValue js_array_buffer_constructor1(JSContext *ctx,
  56834                                             JSValueConst new_target,
  56835                                             uint64_t len, uint64_t *max_len)
  56836 {
  56837     return js_array_buffer_constructor2(ctx, new_target, len, max_len,
  56838                                         JS_CLASS_ARRAY_BUFFER);
  56839 }
  56840 
  56841 JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len,
  56842                           JSFreeArrayBufferDataFunc *free_func, void *opaque,
  56843                           BOOL is_shared)
  56844 {
  56845     JSClassID class_id =
  56846         is_shared ? JS_CLASS_SHARED_ARRAY_BUFFER : JS_CLASS_ARRAY_BUFFER;
  56847     return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len, NULL, class_id,
  56848                                         buf, free_func, opaque, FALSE);
  56849 }
  56850 
  56851 /* create a new ArrayBuffer of length 'len' and copy 'buf' to it */
  56852 JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len)
  56853 {
  56854     return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len, NULL,
  56855                                         JS_CLASS_ARRAY_BUFFER,
  56856                                         (uint8_t *)buf,
  56857                                         js_array_buffer_free, NULL,
  56858                                         TRUE);
  56859 }
  56860 
  56861 static JSValue js_array_buffer_constructor0(JSContext *ctx, JSValueConst new_target,
  56862                                             int argc, JSValueConst *argv,
  56863                                             JSClassID class_id)
  56864  {
  56865     uint64_t len, max_len, *pmax_len = NULL;
  56866     JSValue obj, val;
  56867     int64_t i;
  56868 
  56869      if (JS_ToIndex(ctx, &len, argv[0]))
  56870          return JS_EXCEPTION;
  56871     if (argc < 2)
  56872         goto next;
  56873     if (!JS_IsObject(argv[1]))
  56874         goto next;
  56875     obj = JS_ToObject(ctx, argv[1]);
  56876     if (JS_IsException(obj))
  56877         return JS_EXCEPTION;
  56878     val = JS_GetProperty(ctx, obj, JS_ATOM_maxByteLength);
  56879     JS_FreeValue(ctx, obj);
  56880     if (JS_IsException(val))
  56881         return JS_EXCEPTION;
  56882     if (JS_IsUndefined(val))
  56883         goto next;
  56884     if (JS_ToInt64Free(ctx, &i, val))
  56885         return JS_EXCEPTION;
  56886     // don't have to check i < 0 because len >= 0
  56887     if (len > i || i > MAX_SAFE_INTEGER)
  56888         return JS_ThrowRangeError(ctx, "invalid array buffer max length");
  56889     max_len = i;
  56890     pmax_len = &max_len;
  56891 next:
  56892     return js_array_buffer_constructor2(ctx, new_target, len, pmax_len,
  56893                                         class_id);
  56894 }
  56895 
  56896 static JSValue js_array_buffer_constructor(JSContext *ctx,
  56897                                            JSValueConst new_target,
  56898                                            int argc, JSValueConst *argv)
  56899 {
  56900     return js_array_buffer_constructor0(ctx, new_target, argc, argv,
  56901                                         JS_CLASS_ARRAY_BUFFER);
  56902 }
  56903 
  56904 static JSValue js_shared_array_buffer_constructor(JSContext *ctx,
  56905                                                   JSValueConst new_target,
  56906                                                   int argc, JSValueConst *argv)
  56907 {
  56908     return js_array_buffer_constructor0(ctx, new_target, argc, argv,
  56909                                         JS_CLASS_SHARED_ARRAY_BUFFER);
  56910 }
  56911 
  56912 /* also used for SharedArrayBuffer */
  56913 static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val)
  56914 {
  56915     JSObject *p = JS_VALUE_GET_OBJ(val);
  56916     JSArrayBuffer *abuf = p->u.array_buffer;
  56917     struct list_head *el, *el1;
  56918 
  56919     if (abuf) {
  56920         /* The ArrayBuffer finalizer may be called before the typed
  56921            array finalizers using it, so abuf->array_list is not
  56922            necessarily empty. */
  56923         list_for_each_safe(el, el1, &abuf->array_list) {
  56924             JSTypedArray *ta;
  56925             JSObject *p1;
  56926 
  56927             ta = list_entry(el, JSTypedArray, link);
  56928             ta->link.prev = NULL;
  56929             ta->link.next = NULL;
  56930             p1 = ta->obj;
  56931             /* Note: the typed array length and offset fields are not modified */
  56932             if (p1->class_id != JS_CLASS_DATAVIEW) {
  56933                 p1->u.array.count = 0;
  56934                 p1->u.array.u.ptr = NULL;
  56935             }
  56936         }
  56937         if (abuf->shared && rt->sab_funcs.sab_free) {
  56938             rt->sab_funcs.sab_free(rt->sab_funcs.sab_opaque, abuf->data);
  56939         } else {
  56940             if (abuf->free_func)
  56941                 abuf->free_func(rt, abuf->opaque, abuf->data);
  56942         }
  56943         js_free_rt(rt, abuf);
  56944     }
  56945 }
  56946 
  56947 static JSValue js_array_buffer_isView(JSContext *ctx,
  56948                                       JSValueConst this_val,
  56949                                       int argc, JSValueConst *argv)
  56950 {
  56951     JSObject *p;
  56952     BOOL res;
  56953     res = FALSE;
  56954     if (JS_VALUE_GET_TAG(argv[0]) == JS_TAG_OBJECT) {
  56955         p = JS_VALUE_GET_OBJ(argv[0]);
  56956         if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
  56957             p->class_id <= JS_CLASS_DATAVIEW) {
  56958             res = TRUE;
  56959         }
  56960     }
  56961     return JS_NewBool(ctx, res);
  56962 }
  56963 
  56964 static const JSCFunctionListEntry js_array_buffer_funcs[] = {
  56965     JS_CFUNC_DEF("isView", 1, js_array_buffer_isView ),
  56966     JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
  56967 };
  56968 
  56969 static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx)
  56970 {
  56971     return JS_ThrowTypeError(ctx, "ArrayBuffer is detached");
  56972 }
  56973 
  56974 static JSValue JS_ThrowTypeErrorArrayBufferOOB(JSContext *ctx)
  56975 {
  56976     return JS_ThrowTypeError(ctx, "ArrayBuffer is detached or resized");
  56977 }
  56978 
  56979 // #sec-get-arraybuffer.prototype.detached
  56980 static JSValue js_array_buffer_get_detached(JSContext *ctx,
  56981                                                  JSValueConst this_val)
  56982 {
  56983     JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_BUFFER);
  56984     if (!abuf)
  56985         return JS_EXCEPTION;
  56986     if (abuf->shared)
  56987         return JS_ThrowTypeError(ctx, "detached called on SharedArrayBuffer");
  56988     return JS_NewBool(ctx, abuf->detached);
  56989 }
  56990 
  56991 static JSValue js_array_buffer_get_byteLength(JSContext *ctx,
  56992                                               JSValueConst this_val,
  56993                                               int class_id)
  56994 {
  56995     JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, class_id);
  56996     if (!abuf)
  56997         return JS_EXCEPTION;
  56998     /* return 0 if detached */
  56999     return JS_NewUint32(ctx, abuf->byte_length);
  57000 }
  57001 
  57002 static JSValue js_array_buffer_get_maxByteLength(JSContext *ctx,
  57003                                                  JSValueConst this_val,
  57004                                                  int class_id)
  57005 {
  57006     JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, class_id);
  57007     if (!abuf)
  57008         return JS_EXCEPTION;
  57009     if (array_buffer_is_resizable(abuf))
  57010         return JS_NewUint32(ctx, abuf->max_byte_length);
  57011     return JS_NewUint32(ctx, abuf->byte_length);
  57012 }
  57013 
  57014 static JSValue js_array_buffer_get_resizable(JSContext *ctx,
  57015                                              JSValueConst this_val,
  57016                                              int class_id)
  57017 {
  57018     JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, class_id);
  57019     if (!abuf)
  57020         return JS_EXCEPTION;
  57021     return JS_NewBool(ctx, array_buffer_is_resizable(abuf));
  57022 }
  57023 
  57024 static void js_array_buffer_update_typed_arrays(JSArrayBuffer *abuf)
  57025 {
  57026     uint32_t size_log2, size_elem;
  57027     struct list_head *el;
  57028     JSTypedArray *ta;
  57029     JSObject *p;
  57030     uint8_t *data;
  57031     int64_t len;
  57032 
  57033     len = abuf->byte_length;
  57034     data = abuf->data;
  57035     // update lengths of all typed arrays backed by this array buffer
  57036     list_for_each(el, &abuf->array_list) {
  57037         ta = list_entry(el, JSTypedArray, link);
  57038         p = ta->obj;
  57039         if (p->class_id == JS_CLASS_DATAVIEW) {
  57040             if (ta->track_rab) {
  57041                 if (ta->offset < len)
  57042                     ta->length = len - ta->offset;
  57043                 else
  57044                     ta->length = 0;
  57045             }
  57046         } else {
  57047             p->u.array.count = 0;
  57048             p->u.array.u.ptr = NULL;
  57049             size_log2 = typed_array_size_log2(p->class_id);
  57050             size_elem = 1 << size_log2;
  57051             if (ta->track_rab) {
  57052                 if (len >= (int64_t)ta->offset + size_elem) {
  57053                     p->u.array.count = (len - ta->offset) >> size_log2;
  57054                     p->u.array.u.ptr = &data[ta->offset];
  57055                 }
  57056             } else {
  57057                 if (len >= (int64_t)ta->offset + ta->length) {
  57058                     p->u.array.count = ta->length >> size_log2;
  57059                     p->u.array.u.ptr = &data[ta->offset];
  57060                 }
  57061             }
  57062         }
  57063     }
  57064     
  57065 }
  57066 
  57067 void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj)
  57068 {
  57069     JSArrayBuffer *abuf = JS_GetOpaque(obj, JS_CLASS_ARRAY_BUFFER);
  57070 
  57071     if (!abuf || abuf->detached)
  57072         return;
  57073     if (abuf->free_func)
  57074         abuf->free_func(ctx->rt, abuf->opaque, abuf->data);
  57075     abuf->data = NULL;
  57076     abuf->byte_length = 0;
  57077     abuf->detached = TRUE;
  57078     js_array_buffer_update_typed_arrays(abuf);
  57079 }
  57080 
  57081 /* check if obj is ArrayBuffer or SharedArrayBuffer */
  57082 static BOOL js_is_array_buffer(JSContext *ctx, JSValueConst obj)
  57083 {
  57084   JSObject *p;
  57085   if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
  57086       return FALSE;
  57087   p = JS_VALUE_GET_OBJ(obj);
  57088   if (p->class_id != JS_CLASS_ARRAY_BUFFER &&
  57089       p->class_id != JS_CLASS_SHARED_ARRAY_BUFFER) {
  57090     return FALSE;
  57091   }
  57092   return TRUE;
  57093 }
  57094 
  57095 /* get an ArrayBuffer or SharedArrayBuffer */
  57096 static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj)
  57097 {
  57098     JSObject *p;
  57099     if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
  57100         goto fail;
  57101     p = JS_VALUE_GET_OBJ(obj);
  57102     if (p->class_id != JS_CLASS_ARRAY_BUFFER &&
  57103         p->class_id != JS_CLASS_SHARED_ARRAY_BUFFER) {
  57104     fail:
  57105         JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_ARRAY_BUFFER);
  57106         return NULL;
  57107     }
  57108     return p->u.array_buffer;
  57109 }
  57110 
  57111 static BOOL array_buffer_is_resizable(const JSArrayBuffer *abuf)
  57112 {
  57113     return abuf->max_byte_length >= 0;
  57114 }
  57115 
  57116 // ES #sec-arraybuffer.prototype.transfer
  57117 static JSValue js_array_buffer_transfer(JSContext *ctx,
  57118                                         JSValueConst this_val,
  57119                                         int argc, JSValueConst *argv,
  57120                                         int transfer_to_fixed_length)
  57121 {
  57122     JSArrayBuffer *abuf;
  57123     uint64_t new_len, *pmax_len, max_len;
  57124     JSValue res;
  57125 
  57126     abuf = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_BUFFER);
  57127     if (!abuf)
  57128         return JS_EXCEPTION;
  57129     if (abuf->shared)
  57130         return JS_ThrowTypeError(ctx, "cannot transfer a SharedArrayBuffer");
  57131     if (argc < 1 || JS_IsUndefined(argv[0]))
  57132         new_len = abuf->byte_length;
  57133     else if (JS_ToIndex(ctx, &new_len, argv[0]))
  57134         return JS_EXCEPTION;
  57135     if (abuf->detached)
  57136         return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
  57137     pmax_len = NULL;
  57138     if (!transfer_to_fixed_length) {
  57139         if (array_buffer_is_resizable(abuf)) { // carry over maxByteLength
  57140             max_len = abuf->max_byte_length;
  57141             if (new_len > max_len)
  57142                 return JS_ThrowTypeError(ctx, "invalid array buffer length");
  57143             // TODO(bnoordhuis) support externally managed RABs
  57144             if (abuf->free_func == js_array_buffer_free)
  57145                 pmax_len = &max_len;
  57146         }
  57147     }
  57148 
  57149     /* create an empty AB */
  57150     if (new_len == 0) {
  57151         res = js_array_buffer_constructor2(ctx, JS_UNDEFINED, 0, pmax_len, JS_CLASS_ARRAY_BUFFER);
  57152         if (JS_IsException(res))
  57153             return res;
  57154         JS_DetachArrayBuffer(ctx, this_val);
  57155     } else {
  57156         uint64_t old_len;
  57157         
  57158         old_len = abuf->byte_length;
  57159 
  57160         /* if length mismatch, realloc. Otherwise, use the same backing buffer. */
  57161         if (new_len != old_len) {
  57162             /* XXX: we are currently limited to 2 GB */
  57163             if (new_len > INT32_MAX)
  57164                 return JS_ThrowRangeError(ctx, "invalid array buffer length");
  57165 
  57166             if (abuf->free_func != js_array_buffer_free) {
  57167                 JSArrayBuffer *new_abuf;
  57168                 /* cannot use js_realloc() because the buffer was
  57169                    allocated with a custom allocator */
  57170                 res = js_array_buffer_constructor2(ctx, JS_UNDEFINED, new_len, pmax_len, JS_CLASS_ARRAY_BUFFER);
  57171                 if (JS_IsException(res))
  57172                     return res;
  57173                 new_abuf = JS_GetOpaque2(ctx, res, JS_CLASS_ARRAY_BUFFER);
  57174                 memcpy(new_abuf->data, abuf->data, min_int(old_len, new_len));
  57175                 abuf->free_func(ctx->rt, abuf->opaque, abuf->data);
  57176             } else {
  57177                 JSArrayBuffer *new_abuf;
  57178                 uint8_t *new_bs;
  57179                 /* reallocate the buffer after the new array buffer is
  57180                    created in case the new array buffer creation
  57181                    fails. */
  57182                 res = js_array_buffer_constructor2(ctx, JS_UNDEFINED, 0, pmax_len, JS_CLASS_ARRAY_BUFFER);
  57183                 if (JS_IsException(res))
  57184                     return res;
  57185                 new_bs = js_realloc(ctx, abuf->data, new_len);
  57186                 if (!new_bs) {
  57187                     JS_FreeValue(ctx, res);
  57188                     return JS_EXCEPTION;
  57189                 }
  57190                 if (new_len > old_len)
  57191                     memset(new_bs + old_len, 0, new_len - old_len);
  57192                 new_abuf = JS_GetOpaque2(ctx, res, JS_CLASS_ARRAY_BUFFER);
  57193                 js_free(ctx, new_abuf->data);
  57194                 new_abuf->data = new_bs;
  57195                 new_abuf->byte_length = new_len;
  57196             }
  57197         } else {
  57198             /* can keep the custom free function */
  57199             res = js_array_buffer_constructor3(ctx, JS_UNDEFINED, new_len, pmax_len,
  57200                                                JS_CLASS_ARRAY_BUFFER,
  57201                                                abuf->data, abuf->free_func,
  57202                                                abuf->opaque, FALSE);
  57203             if (JS_IsException(res))
  57204                 return res;
  57205         }
  57206         /* neuter the backing buffer */
  57207         abuf->data = NULL;
  57208         abuf->byte_length = 0;
  57209         abuf->detached = TRUE;
  57210         js_array_buffer_update_typed_arrays(abuf);
  57211     }
  57212     return res;
  57213 }
  57214 
  57215 static JSValue js_array_buffer_resize(JSContext *ctx, JSValueConst this_val,
  57216                                       int argc, JSValueConst *argv, int class_id)
  57217 {
  57218     JSArrayBuffer *abuf;
  57219     uint8_t *data;
  57220     int64_t len;
  57221 
  57222     abuf = JS_GetOpaque2(ctx, this_val, class_id);
  57223     if (!abuf)
  57224         return JS_EXCEPTION;
  57225     if (JS_ToInt64(ctx, &len, argv[0]))
  57226         return JS_EXCEPTION;
  57227     if (abuf->detached)
  57228         return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
  57229     if (!array_buffer_is_resizable(abuf))
  57230         return JS_ThrowTypeError(ctx, "array buffer is not resizable");
  57231     // TODO(bnoordhuis) support externally managed RABs
  57232     if (abuf->free_func != js_array_buffer_free)
  57233         return JS_ThrowTypeError(ctx, "external array buffer is not resizable");
  57234     if (len < 0 || len > abuf->max_byte_length) {
  57235     bad_length:
  57236         return JS_ThrowRangeError(ctx, "invalid array buffer length");
  57237     }
  57238     // SABs can only grow and we don't need to realloc because
  57239     // js_array_buffer_constructor3 commits all memory upfront;
  57240     // regular RABs are resizable both ways and realloc
  57241     if (abuf->shared) {
  57242         if (len < abuf->byte_length)
  57243             goto bad_length;
  57244         // Note this is off-spec; there's supposed to be a single atomic
  57245         // |byteLength| property that's shared across SABs but we store
  57246         // it per SAB instead. That means when thread A calls sab.grow(2)
  57247         // at time t0, and thread B calls sab.grow(1) at time t1, we don't
  57248         // throw a TypeError in thread B as the spec says we should,
  57249         // instead both threads get their own view of the backing memory,
  57250         // 2 bytes big in A, and 1 byte big in B
  57251         abuf->byte_length = len;
  57252     } else {
  57253         data = js_realloc(ctx, abuf->data, max_int(len, 1));
  57254         if (!data)
  57255             return JS_EXCEPTION;
  57256         if (len > abuf->byte_length)
  57257             memset(&data[abuf->byte_length], 0, len - abuf->byte_length);
  57258         abuf->byte_length = len;
  57259         abuf->data = data;
  57260     }
  57261     js_array_buffer_update_typed_arrays(abuf);
  57262     return JS_UNDEFINED;
  57263 }
  57264 
  57265 static JSValue js_array_buffer_slice(JSContext *ctx,
  57266                                      JSValueConst this_val,
  57267                                      int argc, JSValueConst *argv, int class_id)
  57268 {
  57269     JSArrayBuffer *abuf, *new_abuf;
  57270     int64_t len, start, end, new_len;
  57271     JSValue ctor, new_obj;
  57272 
  57273     abuf = JS_GetOpaque2(ctx, this_val, class_id);
  57274     if (!abuf)
  57275         return JS_EXCEPTION;
  57276     if (abuf->detached)
  57277         return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
  57278     len = abuf->byte_length;
  57279 
  57280     if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
  57281         return JS_EXCEPTION;
  57282 
  57283     end = len;
  57284     if (!JS_IsUndefined(argv[1])) {
  57285         if (JS_ToInt64Clamp(ctx, &end, argv[1], 0, len, len))
  57286             return JS_EXCEPTION;
  57287     }
  57288     new_len = max_int64(end - start, 0);
  57289     ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
  57290     if (JS_IsException(ctor))
  57291         return ctor;
  57292     if (JS_IsUndefined(ctor)) {
  57293         new_obj = js_array_buffer_constructor2(ctx, JS_UNDEFINED, new_len,
  57294                                                NULL, class_id);
  57295     } else {
  57296         JSValue args[1];
  57297         args[0] = JS_NewInt64(ctx, new_len);
  57298         new_obj = JS_CallConstructor(ctx, ctor, 1, (JSValueConst *)args);
  57299         JS_FreeValue(ctx, ctor);
  57300         JS_FreeValue(ctx, args[0]);
  57301     }
  57302     if (JS_IsException(new_obj))
  57303         return new_obj;
  57304     new_abuf = JS_GetOpaque2(ctx, new_obj, class_id);
  57305     if (!new_abuf)
  57306         goto fail;
  57307     if (js_same_value(ctx, new_obj, this_val)) {
  57308         JS_ThrowTypeError(ctx, "cannot use identical ArrayBuffer");
  57309         goto fail;
  57310     }
  57311     if (new_abuf->detached) {
  57312         JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
  57313         goto fail;
  57314     }
  57315     if (new_abuf->byte_length < new_len) {
  57316         JS_ThrowTypeError(ctx, "new ArrayBuffer is too small");
  57317         goto fail;
  57318     }
  57319     /* must test again because of side effects */
  57320     if (abuf->detached || abuf->byte_length < start + new_len) {
  57321         JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
  57322         goto fail;
  57323     }
  57324     memcpy(new_abuf->data, abuf->data + start, new_len);
  57325     return new_obj;
  57326  fail:
  57327     JS_FreeValue(ctx, new_obj);
  57328     return JS_EXCEPTION;
  57329 }
  57330 
  57331 static const JSCFunctionListEntry js_array_buffer_proto_funcs[] = {
  57332     JS_CGETSET_MAGIC_DEF("byteLength", js_array_buffer_get_byteLength, NULL, JS_CLASS_ARRAY_BUFFER ),
  57333     JS_CGETSET_MAGIC_DEF("maxByteLength", js_array_buffer_get_maxByteLength, NULL, JS_CLASS_ARRAY_BUFFER ),
  57334     JS_CGETSET_MAGIC_DEF("resizable", js_array_buffer_get_resizable, NULL, JS_CLASS_ARRAY_BUFFER ),
  57335     JS_CGETSET_DEF("detached", js_array_buffer_get_detached, NULL ),
  57336     JS_CFUNC_MAGIC_DEF("resize", 1, js_array_buffer_resize, JS_CLASS_ARRAY_BUFFER ),
  57337     JS_CFUNC_MAGIC_DEF("slice", 2, js_array_buffer_slice, JS_CLASS_ARRAY_BUFFER ),
  57338     JS_CFUNC_MAGIC_DEF("transfer", 0, js_array_buffer_transfer, 0 ),
  57339     JS_CFUNC_MAGIC_DEF("transferToFixedLength", 0, js_array_buffer_transfer, 1 ),
  57340     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "ArrayBuffer", JS_PROP_CONFIGURABLE ),
  57341 };
  57342 
  57343 /* SharedArrayBuffer */
  57344 
  57345 static const JSCFunctionListEntry js_shared_array_buffer_funcs[] = {
  57346     JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
  57347 };
  57348 
  57349 static const JSCFunctionListEntry js_shared_array_buffer_proto_funcs[] = {
  57350     JS_CGETSET_MAGIC_DEF("byteLength", js_array_buffer_get_byteLength, NULL, JS_CLASS_SHARED_ARRAY_BUFFER ),
  57351     JS_CGETSET_MAGIC_DEF("maxByteLength", js_array_buffer_get_maxByteLength, NULL, JS_CLASS_SHARED_ARRAY_BUFFER ),
  57352     JS_CGETSET_MAGIC_DEF("growable", js_array_buffer_get_resizable, NULL, JS_CLASS_SHARED_ARRAY_BUFFER ),
  57353     JS_CFUNC_MAGIC_DEF("grow", 1, js_array_buffer_resize, JS_CLASS_SHARED_ARRAY_BUFFER ),
  57354     JS_CFUNC_MAGIC_DEF("slice", 2, js_array_buffer_slice, JS_CLASS_SHARED_ARRAY_BUFFER ),
  57355     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "SharedArrayBuffer", JS_PROP_CONFIGURABLE ),
  57356 };
  57357 
  57358 static JSObject *get_typed_array(JSContext *ctx, JSValueConst this_val)
  57359 {
  57360     JSObject *p;
  57361     if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
  57362         goto fail;
  57363     p = JS_VALUE_GET_OBJ(this_val);
  57364     if (!(p->class_id >= JS_CLASS_UINT8C_ARRAY &&
  57365           p->class_id <= JS_CLASS_FLOAT64_ARRAY)) {
  57366     fail:
  57367         JS_ThrowTypeError(ctx, "not a TypedArray");
  57368         return NULL;
  57369     }
  57370     return p;
  57371 }
  57372 
  57373 // is the typed array detached or out of bounds relative to its RAB?
  57374 // |p| must be a typed array, *not* a DataView
  57375 static BOOL typed_array_is_oob(JSObject *p)
  57376 {
  57377     JSArrayBuffer *abuf;
  57378     JSTypedArray *ta;
  57379     int len, size_elem;
  57380     int64_t end;
  57381 
  57382     assert(p->class_id >= JS_CLASS_UINT8C_ARRAY);
  57383     assert(p->class_id <= JS_CLASS_FLOAT64_ARRAY);
  57384 
  57385     ta = p->u.typed_array;
  57386     abuf = ta->buffer->u.array_buffer;
  57387     if (abuf->detached)
  57388         return TRUE;
  57389     len = abuf->byte_length;
  57390     if (ta->offset > len)
  57391         return TRUE;
  57392     if (ta->track_rab)
  57393         return FALSE;
  57394     if (len < (int64_t)ta->offset + ta->length)
  57395         return TRUE;
  57396     size_elem = 1 << typed_array_size_log2(p->class_id);
  57397     end = (int64_t)ta->offset + (int64_t)p->u.array.count * size_elem;
  57398     return end > len;
  57399 }
  57400 
  57401 // Be *very* careful if you touch the typed array's memory directly:
  57402 // the length is only valid until the next call into JS land because
  57403 // JS code can detach or resize the backing array buffer. Functions
  57404 // like JS_GetProperty and JS_ToIndex call JS code.
  57405 //
  57406 // Exclusively reading or writing elements with JS_GetProperty,
  57407 // JS_GetPropertyInt64, JS_SetProperty, etc. is safe because they
  57408 // perform bounds checks, as does js_get_fast_array_element.
  57409 static int js_typed_array_get_length_unsafe(JSContext *ctx, JSValueConst obj)
  57410 {
  57411     JSObject *p;
  57412     p = get_typed_array(ctx, obj);
  57413     if (!p)
  57414         return -1;
  57415     if (typed_array_is_oob(p)) {
  57416         JS_ThrowTypeErrorArrayBufferOOB(ctx);
  57417         return -1;
  57418     }
  57419     return p->u.array.count;
  57420 }
  57421 
  57422 static int validate_typed_array(JSContext *ctx, JSValueConst this_val)
  57423 {
  57424     JSObject *p;
  57425     p = get_typed_array(ctx, this_val);
  57426     if (!p)
  57427         return -1;
  57428     if (typed_array_is_oob(p)) {
  57429         JS_ThrowTypeErrorArrayBufferOOB(ctx);
  57430         return -1;
  57431     }
  57432     return 0;
  57433 }
  57434 
  57435 static JSValue js_typed_array_get_length(JSContext *ctx,
  57436                                          JSValueConst this_val)
  57437 {
  57438     JSObject *p;
  57439     p = get_typed_array(ctx, this_val);
  57440     if (!p)
  57441         return JS_EXCEPTION;
  57442     return JS_NewInt32(ctx, p->u.array.count);
  57443 }
  57444 
  57445 static JSValue js_typed_array_get_buffer(JSContext *ctx,
  57446                                          JSValueConst this_val)
  57447 {
  57448     JSObject *p;
  57449     JSTypedArray *ta;
  57450     p = get_typed_array(ctx, this_val);
  57451     if (!p)
  57452         return JS_EXCEPTION;
  57453     ta = p->u.typed_array;
  57454     return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
  57455 }
  57456 
  57457 static JSValue js_typed_array_get_byteLength(JSContext *ctx,
  57458                                              JSValueConst this_val)
  57459 {
  57460     JSObject *p;
  57461     JSTypedArray *ta;
  57462     int size_log2;
  57463 
  57464     p = get_typed_array(ctx, this_val);
  57465     if (!p)
  57466         return JS_EXCEPTION;
  57467     if (typed_array_is_oob(p))
  57468         return JS_NewInt32(ctx, 0);
  57469     ta = p->u.typed_array;
  57470     if (!ta->track_rab)
  57471         return JS_NewUint32(ctx, ta->length);
  57472     size_log2 = typed_array_size_log2(p->class_id);
  57473     return JS_NewInt64(ctx, (int64_t)p->u.array.count << size_log2);
  57474 }
  57475 
  57476 static JSValue js_typed_array_get_byteOffset(JSContext *ctx,
  57477                                              JSValueConst this_val)
  57478 {
  57479     JSObject *p;
  57480     JSTypedArray *ta;
  57481     p = get_typed_array(ctx, this_val);
  57482     if (!p)
  57483         return JS_EXCEPTION;
  57484     if (typed_array_is_oob(p))
  57485         return JS_NewInt32(ctx, 0);
  57486     ta = p->u.typed_array;
  57487     return JS_NewUint32(ctx, ta->offset);
  57488 }
  57489 
  57490 JSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValueConst *argv,
  57491                          JSTypedArrayEnum type)
  57492 {
  57493     if (type < JS_TYPED_ARRAY_UINT8C || type > JS_TYPED_ARRAY_FLOAT64)
  57494         return JS_ThrowRangeError(ctx, "invalid typed array type");
  57495 
  57496     return js_typed_array_constructor(ctx, JS_UNDEFINED, argc, argv,
  57497                                       JS_CLASS_UINT8C_ARRAY + type);
  57498 }
  57499 
  57500 /* Return the buffer associated to the typed array or an exception if
  57501    it is not a typed array or if the buffer is detached. pbyte_offset,
  57502    pbyte_length or pbytes_per_element can be NULL. */
  57503 JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj,
  57504                                size_t *pbyte_offset,
  57505                                size_t *pbyte_length,
  57506                                size_t *pbytes_per_element)
  57507 {
  57508     JSObject *p;
  57509     JSTypedArray *ta;
  57510     p = get_typed_array(ctx, obj);
  57511     if (!p)
  57512         return JS_EXCEPTION;
  57513     if (typed_array_is_oob(p))
  57514         return JS_ThrowTypeErrorArrayBufferOOB(ctx);
  57515     ta = p->u.typed_array;
  57516     if (pbyte_offset)
  57517         *pbyte_offset = ta->offset;
  57518     if (pbyte_length)
  57519         *pbyte_length = ta->length;
  57520     if (pbytes_per_element) {
  57521         *pbytes_per_element = 1 << typed_array_size_log2(p->class_id);
  57522     }
  57523     return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
  57524 }
  57525 
  57526 BOOL JS_IsArrayBuffer(JSValueConst obj)
  57527 {
  57528     JSObject *p;
  57529 
  57530     if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
  57531         return FALSE;
  57532     p = JS_VALUE_GET_OBJ(obj);
  57533     if (p->class_id == JS_CLASS_ARRAY_BUFFER ||
  57534         p->class_id == JS_CLASS_SHARED_ARRAY_BUFFER) {
  57535         return TRUE;
  57536     }
  57537     if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
  57538         p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
  57539         return TRUE;
  57540     }
  57541     return FALSE;
  57542 }
  57543 
  57544 /* return NULL if exception. WARNING: any JS call can detach the
  57545    buffer and render the returned pointer invalid */
  57546 uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj)
  57547 {
  57548     if (js_is_array_buffer(ctx, obj)) {
  57549         JSArrayBuffer* abuf = js_get_array_buffer(ctx, obj);
  57550         if (!abuf)
  57551             goto fail;
  57552         if (abuf->detached) {
  57553             JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
  57554             goto fail;
  57555         }
  57556         *psize = abuf->byte_length;
  57557         return abuf->data;
  57558     } else {
  57559         JSObject* p;
  57560         JSTypedArray* ta;
  57561         JSArrayBuffer* abuf;
  57562         p = get_typed_array(ctx, obj);
  57563         if (!p) {
  57564             goto fail;
  57565         }
  57566         if (typed_array_is_oob(p)) {
  57567             JS_ThrowTypeErrorArrayBufferOOB(ctx);
  57568             goto fail;
  57569         }
  57570         ta = p->u.typed_array;
  57571         abuf = ta->buffer->u.array_buffer;
  57572         if (!abuf)
  57573             goto fail;
  57574         if (abuf->detached) {
  57575             JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
  57576             goto fail;
  57577         }
  57578         *psize = ta->length;
  57579         return abuf->data + ta->offset;
  57580     }
  57581     JS_ThrowTypeError(ctx, "expected ArrayBuffer or ArrayBufferView");
  57582 fail:
  57583     *psize = 0;
  57584     return NULL;
  57585 }
  57586 
  57587                                
  57588 static JSValue js_typed_array_get_toStringTag(JSContext *ctx,
  57589                                               JSValueConst this_val)
  57590 {
  57591     JSObject *p;
  57592     if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
  57593         return JS_UNDEFINED;
  57594     p = JS_VALUE_GET_OBJ(this_val);
  57595     if (!(p->class_id >= JS_CLASS_UINT8C_ARRAY &&
  57596           p->class_id <= JS_CLASS_FLOAT64_ARRAY))
  57597         return JS_UNDEFINED;
  57598     return JS_AtomToString(ctx, ctx->rt->class_array[p->class_id].class_name);
  57599 }
  57600 
  57601 static JSValue js_typed_array_set_internal(JSContext *ctx,
  57602                                            JSValueConst dst,
  57603                                            JSValueConst src,
  57604                                            JSValueConst off)
  57605 {
  57606     JSObject *p;
  57607     JSObject *src_p;
  57608     uint32_t i;
  57609     int64_t dst_len, src_len, offset;
  57610     JSValue val, src_obj = JS_UNDEFINED;
  57611 
  57612     p = get_typed_array(ctx, dst);
  57613     if (!p)
  57614         goto fail;
  57615     if (JS_ToInt64Sat(ctx, &offset, off))
  57616         goto fail;
  57617     if (offset < 0)
  57618         goto range_error;
  57619     if (typed_array_is_oob(p)) {
  57620     detached:
  57621         JS_ThrowTypeErrorArrayBufferOOB(ctx);
  57622         goto fail;
  57623     }
  57624     dst_len = p->u.array.count;
  57625     src_obj = JS_ToObject(ctx, src);
  57626     if (JS_IsException(src_obj))
  57627         goto fail;
  57628     src_p = JS_VALUE_GET_OBJ(src_obj);
  57629     if (src_p->class_id >= JS_CLASS_UINT8C_ARRAY &&
  57630         src_p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
  57631         JSTypedArray *dest_ta = p->u.typed_array;
  57632         JSArrayBuffer *dest_abuf = dest_ta->buffer->u.array_buffer;
  57633         JSTypedArray *src_ta = src_p->u.typed_array;
  57634         JSArrayBuffer *src_abuf = src_ta->buffer->u.array_buffer;
  57635         int shift = typed_array_size_log2(p->class_id);
  57636 
  57637         if (typed_array_is_oob(src_p))
  57638             goto detached;
  57639 
  57640         src_len = src_p->u.array.count;
  57641         if (offset > dst_len - src_len)
  57642             goto range_error;
  57643 
  57644         /* copying between typed objects */
  57645         if (src_p->class_id == p->class_id) {
  57646             /* same type, use memmove */
  57647             memmove(dest_abuf->data + dest_ta->offset + (offset << shift),
  57648                     src_abuf->data + src_ta->offset, src_len << shift);
  57649             goto done;
  57650         }
  57651         if (dest_abuf->data == src_abuf->data) {
  57652             /* copying between the same buffer using different types of mappings
  57653                would require a temporary buffer */
  57654         }
  57655         /* otherwise, default behavior is slow but correct */
  57656     } else {
  57657         // can change |dst| as a side effect; per spec,
  57658         // perform the range check against its old length
  57659         if (js_get_length64(ctx, &src_len, src_obj))
  57660             goto fail;
  57661         if (offset > dst_len - src_len) {
  57662         range_error:
  57663             JS_ThrowRangeError(ctx, "invalid array length");
  57664             goto fail;
  57665         }
  57666     }
  57667     for(i = 0; i < src_len; i++) {
  57668         val = JS_GetPropertyUint32(ctx, src_obj, i);
  57669         if (JS_IsException(val))
  57670             goto fail;
  57671         if (JS_SetPropertyUint32(ctx, dst, offset + i, val) < 0)
  57672             goto fail;
  57673     }
  57674 done:
  57675     JS_FreeValue(ctx, src_obj);
  57676     return JS_UNDEFINED;
  57677 fail:
  57678     JS_FreeValue(ctx, src_obj);
  57679     return JS_EXCEPTION;
  57680 }
  57681 
  57682 static JSValue js_typed_array_at(JSContext *ctx, JSValueConst this_val,
  57683                                  int argc, JSValueConst *argv)
  57684 {
  57685     JSObject *p;
  57686     int64_t idx, len;
  57687 
  57688     p = get_typed_array(ctx, this_val);
  57689     if (!p)
  57690         return JS_EXCEPTION;
  57691 
  57692     if (typed_array_is_oob(p))
  57693         return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
  57694     len = p->u.array.count;
  57695 
  57696     // note: can change p->u.array.count
  57697     if (JS_ToInt64Sat(ctx, &idx, argv[0]))
  57698         return JS_EXCEPTION;
  57699 
  57700     if (idx < 0)
  57701         idx = len + idx;
  57702 
  57703     len = p->u.array.count;
  57704     if (idx < 0 || idx >= len)
  57705         return JS_UNDEFINED;
  57706     return JS_GetPropertyInt64(ctx, this_val, idx);
  57707 }
  57708 
  57709 static JSValue js_typed_array_with(JSContext *ctx, JSValueConst this_val,
  57710                                    int argc, JSValueConst *argv)
  57711 {
  57712     JSValue arr, val;
  57713     JSObject *p;
  57714     int64_t idx, len;
  57715 
  57716     p = get_typed_array(ctx, this_val);
  57717     if (!p)
  57718         return JS_EXCEPTION;
  57719     if (typed_array_is_oob(p))
  57720         return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
  57721 
  57722     len = p->u.array.count;
  57723     if (JS_ToInt64Sat(ctx, &idx, argv[0]))
  57724         return JS_EXCEPTION;
  57725 
  57726     if (idx < 0)
  57727         idx = len + idx;
  57728 
  57729     val = JS_ToPrimitive(ctx, argv[1], HINT_NUMBER);
  57730     if (JS_IsException(val))
  57731         return JS_EXCEPTION;
  57732 
  57733     if (typed_array_is_oob(p) || idx < 0 || idx >= p->u.array.count)
  57734         return JS_ThrowRangeError(ctx, "invalid array index");
  57735 
  57736     /* warning: 'this_val' may have been resized, so 'len' may be
  57737        larger than its length */
  57738     arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,
  57739                                         p->class_id, len);
  57740     if (JS_IsException(arr)) {
  57741         JS_FreeValue(ctx, val);
  57742         return JS_EXCEPTION;
  57743     }
  57744     if (JS_SetPropertyInt64(ctx, arr, idx, val) < 0) {
  57745         JS_FreeValue(ctx, arr);
  57746         return JS_EXCEPTION;
  57747     }
  57748     return arr;
  57749 }
  57750 
  57751 static JSValue js_typed_array_set(JSContext *ctx,
  57752                                   JSValueConst this_val,
  57753                                   int argc, JSValueConst *argv)
  57754 {
  57755     JSValueConst offset = JS_UNDEFINED;
  57756     if (argc > 1) {
  57757         offset = argv[1];
  57758     }
  57759     return js_typed_array_set_internal(ctx, this_val, argv[0], offset);
  57760 }
  57761 
  57762 static JSValue js_create_typed_array_iterator(JSContext *ctx, JSValueConst this_val,
  57763                                               int argc, JSValueConst *argv, int magic)
  57764 {
  57765     if (validate_typed_array(ctx, this_val))
  57766         return JS_EXCEPTION;
  57767     return js_create_array_iterator(ctx, this_val, argc, argv, magic);
  57768 }
  57769 
  57770 static JSValue js_typed_array_create(JSContext *ctx, JSValueConst ctor,
  57771                                      int argc, JSValueConst *argv)
  57772 {
  57773     JSValue ret;
  57774     int new_len;
  57775     int64_t len;
  57776 
  57777     ret = JS_CallConstructor(ctx, ctor, argc, argv);
  57778     if (JS_IsException(ret))
  57779         return ret;
  57780     /* validate the typed array */
  57781     new_len = js_typed_array_get_length_unsafe(ctx, ret);
  57782     if (new_len < 0)
  57783         goto fail;
  57784     if (argc == 1) {
  57785         /* ensure that it is large enough */
  57786         if (JS_ToLengthFree(ctx, &len, JS_DupValue(ctx, argv[0])))
  57787             goto fail;
  57788         if (new_len < len) {
  57789             JS_ThrowTypeError(ctx, "TypedArray length is too small");
  57790         fail:
  57791             JS_FreeValue(ctx, ret);
  57792             return JS_EXCEPTION;
  57793         }
  57794     }
  57795     return ret;
  57796 }
  57797 
  57798 #if 0
  57799 static JSValue js_typed_array___create(JSContext *ctx,
  57800                                        JSValueConst this_val,
  57801                                        int argc, JSValueConst *argv)
  57802 {
  57803     return js_typed_array_create(ctx, argv[0], max_int(argc - 1, 0), argv + 1);
  57804 }
  57805 #endif
  57806 
  57807 static JSValue js_typed_array___speciesCreate(JSContext *ctx,
  57808                                               JSValueConst this_val,
  57809                                               int argc, JSValueConst *argv)
  57810 {
  57811     JSValueConst obj;
  57812     JSObject *p;
  57813     JSValue ctor, ret;
  57814     int argc1;
  57815 
  57816     obj = argv[0];
  57817     p = get_typed_array(ctx, obj);
  57818     if (!p)
  57819         return JS_EXCEPTION;
  57820     ctor = JS_SpeciesConstructor(ctx, obj, JS_UNDEFINED);
  57821     if (JS_IsException(ctor))
  57822         return ctor;
  57823     argc1 = max_int(argc - 1, 0);
  57824     if (JS_IsUndefined(ctor)) {
  57825         ret = js_typed_array_constructor(ctx, JS_UNDEFINED, argc1, argv + 1,
  57826                                          p->class_id);
  57827     } else {
  57828         ret = js_typed_array_create(ctx, ctor, argc1, argv + 1);
  57829         JS_FreeValue(ctx, ctor);
  57830     }
  57831     return ret;
  57832 }
  57833 
  57834 static JSValue js_typed_array_from(JSContext *ctx, JSValueConst this_val,
  57835                                    int argc, JSValueConst *argv)
  57836 {
  57837     // from(items, mapfn = void 0, this_arg = void 0)
  57838     JSValueConst items = argv[0], mapfn, this_arg;
  57839     JSValueConst args[2];
  57840     JSValue iter, arr, r, v, v2;
  57841     int64_t k, len;
  57842     int mapping;
  57843 
  57844     mapping = FALSE;
  57845     mapfn = JS_UNDEFINED;
  57846     this_arg = JS_UNDEFINED;
  57847     r = JS_UNDEFINED;
  57848     arr = JS_UNDEFINED;
  57849     iter = JS_UNDEFINED;
  57850 
  57851     if (argc > 1) {
  57852         mapfn = argv[1];
  57853         if (!JS_IsUndefined(mapfn)) {
  57854             if (check_function(ctx, mapfn))
  57855                 goto exception;
  57856             mapping = 1;
  57857             if (argc > 2)
  57858                 this_arg = argv[2];
  57859         }
  57860     }
  57861     iter = JS_GetProperty(ctx, items, JS_ATOM_Symbol_iterator);
  57862     if (JS_IsException(iter))
  57863         goto exception;
  57864     if (!JS_IsUndefined(iter) && !JS_IsNull(iter)) {
  57865         uint32_t len1;
  57866         if (!JS_IsFunction(ctx, iter)) {
  57867             JS_ThrowTypeError(ctx, "value is not iterable");
  57868             goto exception;
  57869         }
  57870         arr = js_array_from_iterator(ctx, &len1, items, iter);
  57871         if (JS_IsException(arr))
  57872             goto exception;
  57873         len = len1;
  57874     } else {
  57875         arr = JS_ToObject(ctx, items);
  57876         if (JS_IsException(arr))
  57877             goto exception;
  57878         if (js_get_length64(ctx, &len, arr) < 0)
  57879             goto exception;
  57880     }
  57881     v = JS_NewInt64(ctx, len);
  57882     args[0] = v;
  57883     r = js_typed_array_create(ctx, this_val, 1, args);
  57884     JS_FreeValue(ctx, v);
  57885     if (JS_IsException(r))
  57886         goto exception;
  57887     for(k = 0; k < len; k++) {
  57888         v = JS_GetPropertyInt64(ctx, arr, k);
  57889         if (JS_IsException(v))
  57890             goto exception;
  57891         if (mapping) {
  57892             args[0] = v;
  57893             args[1] = JS_NewInt32(ctx, k);
  57894             v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
  57895             JS_FreeValue(ctx, v);
  57896             v = v2;
  57897             if (JS_IsException(v))
  57898                 goto exception;
  57899         }
  57900         if (JS_SetPropertyInt64(ctx, r, k, v) < 0)
  57901             goto exception;
  57902     }
  57903     goto done;
  57904  exception:
  57905     JS_FreeValue(ctx, r);
  57906     r = JS_EXCEPTION;
  57907  done:
  57908     JS_FreeValue(ctx, arr);
  57909     JS_FreeValue(ctx, iter);
  57910     return r;
  57911 }
  57912 
  57913 static JSValue js_typed_array_of(JSContext *ctx, JSValueConst this_val,
  57914                                  int argc, JSValueConst *argv)
  57915 {
  57916     JSValue obj;
  57917     JSValueConst args[1];
  57918     int i;
  57919 
  57920     args[0] = JS_NewInt32(ctx, argc);
  57921     obj = js_typed_array_create(ctx, this_val, 1, args);
  57922     if (JS_IsException(obj))
  57923         return obj;
  57924 
  57925     for(i = 0; i < argc; i++) {
  57926         if (JS_SetPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i])) < 0) {
  57927             JS_FreeValue(ctx, obj);
  57928             return JS_EXCEPTION;
  57929         }
  57930     }
  57931     return obj;
  57932 }
  57933 
  57934 static JSValue js_typed_array_copyWithin(JSContext *ctx, JSValueConst this_val,
  57935                                          int argc, JSValueConst *argv)
  57936 {
  57937     JSObject *p;
  57938     int len, to, from, final, count, shift, space;
  57939 
  57940     p = get_typed_array(ctx, this_val);
  57941     if (!p)
  57942         return JS_EXCEPTION;
  57943     if (typed_array_is_oob(p))
  57944         return JS_ThrowTypeErrorArrayBufferOOB(ctx);
  57945     len = p->u.array.count;
  57946 
  57947     if (JS_ToInt32Clamp(ctx, &to, argv[0], 0, len, len))
  57948         return JS_EXCEPTION;
  57949 
  57950     if (JS_ToInt32Clamp(ctx, &from, argv[1], 0, len, len))
  57951         return JS_EXCEPTION;
  57952 
  57953     final = len;
  57954     if (argc > 2 && !JS_IsUndefined(argv[2])) {
  57955         if (JS_ToInt32Clamp(ctx, &final, argv[2], 0, len, len))
  57956             return JS_EXCEPTION;
  57957     }
  57958 
  57959     if (typed_array_is_oob(p))
  57960         return JS_ThrowTypeErrorArrayBufferOOB(ctx);
  57961 
  57962     // RAB may have been resized by evil .valueOf method
  57963     space = p->u.array.count - max_int(to, from);
  57964     count = min_int(final - from, len - to);
  57965     count = min_int(count, space);
  57966     if (count > 0) {
  57967         shift = typed_array_size_log2(p->class_id);
  57968         memmove(p->u.array.u.uint8_ptr + (to << shift),
  57969                 p->u.array.u.uint8_ptr + (from << shift),
  57970                 count << shift);
  57971     }
  57972     return JS_DupValue(ctx, this_val);
  57973 }
  57974 
  57975 static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val,
  57976                                    int argc, JSValueConst *argv)
  57977 {
  57978     JSObject *p;
  57979     int len, k, final, shift;
  57980     uint64_t v64;
  57981 
  57982     p = get_typed_array(ctx, this_val);
  57983     if (!p)
  57984         return JS_EXCEPTION;
  57985     if (typed_array_is_oob(p))
  57986         return JS_ThrowTypeErrorArrayBufferOOB(ctx);
  57987     len = p->u.array.count;
  57988 
  57989     if (p->class_id == JS_CLASS_UINT8C_ARRAY) {
  57990         int32_t v;
  57991         if (JS_ToUint8ClampFree(ctx, &v, JS_DupValue(ctx, argv[0])))
  57992             return JS_EXCEPTION;
  57993         v64 = v;
  57994     } else if (p->class_id <= JS_CLASS_UINT32_ARRAY) {
  57995         uint32_t v;
  57996         if (JS_ToUint32(ctx, &v, argv[0]))
  57997             return JS_EXCEPTION;
  57998         v64 = v;
  57999     } else if (p->class_id <= JS_CLASS_BIG_UINT64_ARRAY) {
  58000         if (JS_ToBigInt64(ctx, (int64_t *)&v64, argv[0]))
  58001             return JS_EXCEPTION;
  58002     } else {
  58003         double d;
  58004         if (JS_ToFloat64(ctx, &d, argv[0]))
  58005             return JS_EXCEPTION;
  58006         if (p->class_id == JS_CLASS_FLOAT16_ARRAY) {
  58007             v64 = tofp16(d);
  58008         } else if (p->class_id == JS_CLASS_FLOAT32_ARRAY) {
  58009             union {
  58010                 float f;
  58011                 uint32_t u32;
  58012             } u;
  58013             u.f = d;
  58014             v64 = u.u32;
  58015         } else {
  58016             JSFloat64Union u;
  58017             u.d = d;
  58018             v64 = u.u64;
  58019         }
  58020     }
  58021 
  58022     k = 0;
  58023     if (argc > 1) {
  58024         if (JS_ToInt32Clamp(ctx, &k, argv[1], 0, len, len))
  58025             return JS_EXCEPTION;
  58026     }
  58027 
  58028     final = len;
  58029     if (argc > 2 && !JS_IsUndefined(argv[2])) {
  58030         if (JS_ToInt32Clamp(ctx, &final, argv[2], 0, len, len))
  58031             return JS_EXCEPTION;
  58032     }
  58033 
  58034     if (typed_array_is_oob(p))
  58035         return JS_ThrowTypeErrorArrayBufferOOB(ctx);
  58036 
  58037     // RAB may have been resized by evil .valueOf method
  58038     final = min_int(final, p->u.array.count);
  58039     shift = typed_array_size_log2(p->class_id);
  58040     switch(shift) {
  58041     case 0:
  58042         if (k < final) {
  58043             memset(p->u.array.u.uint8_ptr + k, v64, final - k);
  58044         }
  58045         break;
  58046     case 1:
  58047         for(; k < final; k++) {
  58048             p->u.array.u.uint16_ptr[k] = v64;
  58049         }
  58050         break;
  58051     case 2:
  58052         for(; k < final; k++) {
  58053             p->u.array.u.uint32_ptr[k] = v64;
  58054         }
  58055         break;
  58056     case 3:
  58057         for(; k < final; k++) {
  58058             p->u.array.u.uint64_ptr[k] = v64;
  58059         }
  58060         break;
  58061     default:
  58062         abort();
  58063     }
  58064     return JS_DupValue(ctx, this_val);
  58065 }
  58066 
  58067 static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val,
  58068                                    int argc, JSValueConst *argv, int mode)
  58069 {
  58070     JSValueConst func, this_arg;
  58071     JSValueConst args[3];
  58072     JSValue val, index_val, res;
  58073     int len, k, end;
  58074     int dir;
  58075 
  58076     val = JS_UNDEFINED;
  58077     len = js_typed_array_get_length_unsafe(ctx, this_val);
  58078     if (len < 0)
  58079         goto exception;
  58080 
  58081     func = argv[0];
  58082     if (check_function(ctx, func))
  58083         goto exception;
  58084 
  58085     this_arg = JS_UNDEFINED;
  58086     if (argc > 1)
  58087         this_arg = argv[1];
  58088 
  58089     k = 0;
  58090     dir = 1;
  58091     end = len;
  58092     if (mode == ArrayFindLast || mode == ArrayFindLastIndex) {
  58093         k = len - 1;
  58094         dir = -1;
  58095         end = -1;
  58096     }
  58097 
  58098     for(; k != end; k += dir) {
  58099         index_val = JS_NewInt32(ctx, k);
  58100         val = JS_GetPropertyValue(ctx, this_val, index_val);
  58101         if (JS_IsException(val))
  58102             goto exception;
  58103         args[0] = val;
  58104         args[1] = index_val;
  58105         args[2] = this_val;
  58106         res = JS_Call(ctx, func, this_arg, 3, args);
  58107         if (JS_IsException(res))
  58108             goto exception;
  58109         if (JS_ToBoolFree(ctx, res)) {
  58110             if (mode == ArrayFindIndex || mode == ArrayFindLastIndex) {
  58111                 JS_FreeValue(ctx, val);
  58112                 return index_val;
  58113             } else {
  58114                 return val;
  58115             }
  58116         }
  58117         JS_FreeValue(ctx, val);
  58118     }
  58119     if (mode == ArrayFindIndex || mode == ArrayFindLastIndex)
  58120         return JS_NewInt32(ctx, -1);
  58121     else
  58122         return JS_UNDEFINED;
  58123 
  58124 exception:
  58125     JS_FreeValue(ctx, val);
  58126     return JS_EXCEPTION;
  58127 }
  58128 
  58129 #define special_indexOf 0
  58130 #define special_lastIndexOf 1
  58131 #define special_includes -1
  58132 
  58133 static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
  58134                                       int argc, JSValueConst *argv, int special)
  58135 {
  58136     JSObject *p;
  58137     int len, tag, is_int, is_bigint, k, stop, inc, res = -1;
  58138     int64_t v64;
  58139     double d;
  58140     float f;
  58141     uint16_t hf;
  58142 
  58143     p = get_typed_array(ctx, this_val);
  58144     if (!p)
  58145         return JS_EXCEPTION;
  58146     if (typed_array_is_oob(p))
  58147         return JS_ThrowTypeErrorArrayBufferOOB(ctx);
  58148     len = p->u.array.count;
  58149 
  58150     if (len == 0)
  58151         goto done;
  58152 
  58153     if (special == special_lastIndexOf) {
  58154         k = len - 1;
  58155         if (argc > 1) {
  58156             int64_t k1;
  58157             if (JS_ToInt64Clamp(ctx, &k1, argv[1], -1, len - 1, len))
  58158                 goto exception;
  58159             k = k1;
  58160             if (k < 0)
  58161                 goto done;
  58162         }
  58163         stop = -1;
  58164         inc = -1;
  58165     } else {
  58166         k = 0;
  58167         if (argc > 1) {
  58168             if (JS_ToInt32Clamp(ctx, &k, argv[1], 0, len, len))
  58169                 goto exception;
  58170         }
  58171         stop = len;
  58172         inc = 1;
  58173     }
  58174 
  58175     /* includes function: 'undefined' can be found if searching out of bounds */
  58176     if (len > p->u.array.count && special == special_includes &&
  58177         JS_IsUndefined(argv[0]) && k < len) {
  58178         res = 0;
  58179         goto done;
  58180     }
  58181 
  58182     // RAB may have been resized by evil .valueOf method
  58183     len = min_int(len, p->u.array.count);
  58184     if (len == 0)
  58185         goto done;
  58186     if (special == special_lastIndexOf)
  58187         k = min_int(k, len - 1);
  58188     else
  58189         k = min_int(k, len);
  58190     stop = min_int(stop, len);
  58191 
  58192     is_bigint = 0;
  58193     is_int = 0; /* avoid warning */
  58194     v64 = 0; /* avoid warning */
  58195     tag = JS_VALUE_GET_NORM_TAG(argv[0]);
  58196     if (tag == JS_TAG_INT) {
  58197         is_int = 1;
  58198         v64 = JS_VALUE_GET_INT(argv[0]);
  58199         d = v64;
  58200     } else
  58201     if (tag == JS_TAG_FLOAT64) {
  58202         d = JS_VALUE_GET_FLOAT64(argv[0]);
  58203         if (d >= INT64_MIN && d < 0x1p63) {
  58204             v64 = d;
  58205             is_int = (v64 == d);
  58206         }
  58207     } else if (tag == JS_TAG_BIG_INT || tag == JS_TAG_SHORT_BIG_INT) {
  58208         JSBigIntBuf buf1;
  58209         JSBigInt *p1;
  58210         int sz = (64 / JS_LIMB_BITS);
  58211         if (tag == JS_TAG_SHORT_BIG_INT)
  58212             p1 = js_bigint_set_short(&buf1, argv[0]);
  58213         else
  58214             p1 = JS_VALUE_GET_PTR(argv[0]);
  58215         
  58216         if (p->class_id == JS_CLASS_BIG_INT64_ARRAY) {
  58217             if (p1->len > sz)
  58218                 goto done; /* does not fit an int64 : cannot be found */
  58219         } else if (p->class_id == JS_CLASS_BIG_UINT64_ARRAY) {
  58220             if (js_bigint_sign(p1))
  58221                 goto done; /* v < 0 */
  58222             if (p1->len <= sz) {
  58223                 /* OK */
  58224             } else if (p1->len == sz + 1 && p1->tab[sz] == 0) {
  58225                 /* 2^63 <= v <= 2^64-1 */
  58226             } else {
  58227                 goto done;
  58228             }
  58229         } else {
  58230             goto done;
  58231         }
  58232         if (JS_ToBigInt64(ctx, &v64, argv[0]))
  58233             goto exception;
  58234         d = 0;
  58235         is_bigint = 1;
  58236     } else {
  58237         goto done;
  58238     }
  58239 
  58240     switch (p->class_id) {
  58241     case JS_CLASS_INT8_ARRAY:
  58242         if (is_int && (int8_t)v64 == v64)
  58243             goto scan8;
  58244         break;
  58245     case JS_CLASS_UINT8C_ARRAY:
  58246     case JS_CLASS_UINT8_ARRAY:
  58247         if (is_int && (uint8_t)v64 == v64) {
  58248             const uint8_t *pv, *pp;
  58249             uint16_t v;
  58250         scan8:
  58251             pv = p->u.array.u.uint8_ptr;
  58252             v = v64;
  58253             if (inc > 0) {
  58254                 pp = NULL;
  58255                 if (pv)
  58256                     pp = memchr(pv + k, v, len - k);
  58257                 if (pp)
  58258                     res = pp - pv;
  58259             } else {
  58260                 for (; k != stop; k += inc) {
  58261                     if (pv[k] == v) {
  58262                         res = k;
  58263                         break;
  58264                     }
  58265                 }
  58266             }
  58267         }
  58268         break;
  58269     case JS_CLASS_INT16_ARRAY:
  58270         if (is_int && (int16_t)v64 == v64)
  58271             goto scan16;
  58272         break;
  58273     case JS_CLASS_UINT16_ARRAY:
  58274         if (is_int && (uint16_t)v64 == v64) {
  58275             const uint16_t *pv;
  58276             uint16_t v;
  58277         scan16:
  58278             pv = p->u.array.u.uint16_ptr;
  58279             v = v64;
  58280             for (; k != stop; k += inc) {
  58281                 if (pv[k] == v) {
  58282                     res = k;
  58283                     break;
  58284                 }
  58285             }
  58286         }
  58287         break;
  58288     case JS_CLASS_INT32_ARRAY:
  58289         if (is_int && (int32_t)v64 == v64)
  58290             goto scan32;
  58291         break;
  58292     case JS_CLASS_UINT32_ARRAY:
  58293         if (is_int && (uint32_t)v64 == v64) {
  58294             const uint32_t *pv;
  58295             uint32_t v;
  58296         scan32:
  58297             pv = p->u.array.u.uint32_ptr;
  58298             v = v64;
  58299             for (; k != stop; k += inc) {
  58300                 if (pv[k] == v) {
  58301                     res = k;
  58302                     break;
  58303                 }
  58304             }
  58305         }
  58306         break;
  58307     case JS_CLASS_FLOAT16_ARRAY:
  58308         if (is_bigint)
  58309             break;
  58310         if (isnan(d)) {
  58311             const uint16_t *pv = p->u.array.u.fp16_ptr;
  58312             /* special case: indexOf returns -1, includes finds NaN */
  58313             if (special != special_includes)
  58314                 goto done;
  58315             for (; k != stop; k += inc) {
  58316                 if (isfp16nan(pv[k])) {
  58317                     res = k;
  58318                     break;
  58319                 }
  58320             }
  58321         } else if (d == 0) {
  58322             // special case: includes also finds negative zero
  58323             const uint16_t *pv = p->u.array.u.fp16_ptr;
  58324             for (; k != stop; k += inc) {
  58325                 if (isfp16zero(pv[k])) {
  58326                     res = k;
  58327                     break;
  58328                 }
  58329             }
  58330         } else if (hf = tofp16(d), d == fromfp16(hf)) {
  58331             const uint16_t *pv = p->u.array.u.fp16_ptr;
  58332             for (; k != stop; k += inc) {
  58333                 if (pv[k] == hf) {
  58334                     res = k;
  58335                     break;
  58336                 }
  58337             }
  58338         }
  58339         break;
  58340     case JS_CLASS_FLOAT32_ARRAY:
  58341         if (is_bigint)
  58342             break;
  58343         if (isnan(d)) {
  58344             const float *pv = p->u.array.u.float_ptr;
  58345             /* special case: indexOf returns -1, includes finds NaN */
  58346             if (special != special_includes)
  58347                 goto done;
  58348             for (; k != stop; k += inc) {
  58349                 if (isnan(pv[k])) {
  58350                     res = k;
  58351                     break;
  58352                 }
  58353             }
  58354         } else if ((f = (float)d) == d) {
  58355             const float *pv = p->u.array.u.float_ptr;
  58356             for (; k != stop; k += inc) {
  58357                 if (pv[k] == f) {
  58358                     res = k;
  58359                     break;
  58360                 }
  58361             }
  58362         }
  58363         break;
  58364     case JS_CLASS_FLOAT64_ARRAY:
  58365         if (is_bigint)
  58366             break;
  58367         if (isnan(d)) {
  58368             const double *pv = p->u.array.u.double_ptr;
  58369             /* special case: indexOf returns -1, includes finds NaN */
  58370             if (special != special_includes)
  58371                 goto done;
  58372             for (; k != stop; k += inc) {
  58373                 if (isnan(pv[k])) {
  58374                     res = k;
  58375                     break;
  58376                 }
  58377             }
  58378         } else {
  58379             const double *pv = p->u.array.u.double_ptr;
  58380             for (; k != stop; k += inc) {
  58381                 if (pv[k] == d) {
  58382                     res = k;
  58383                     break;
  58384                 }
  58385             }
  58386         }
  58387         break;
  58388     case JS_CLASS_BIG_INT64_ARRAY:
  58389         if (is_bigint) {
  58390             goto scan64;
  58391         }
  58392         break;
  58393     case JS_CLASS_BIG_UINT64_ARRAY:
  58394         if (is_bigint) {
  58395             const uint64_t *pv;
  58396             uint64_t v;
  58397         scan64:
  58398             pv = p->u.array.u.uint64_ptr;
  58399             v = v64;
  58400             for (; k != stop; k += inc) {
  58401                 if (pv[k] == v) {
  58402                     res = k;
  58403                     break;
  58404                 }
  58405             }
  58406         }
  58407         break;
  58408     }
  58409 
  58410 done:
  58411     if (special == special_includes)
  58412         return JS_NewBool(ctx, res >= 0);
  58413     else
  58414         return JS_NewInt32(ctx, res);
  58415 
  58416 exception:
  58417     return JS_EXCEPTION;
  58418 }
  58419 
  58420 static JSValue js_typed_array_join(JSContext *ctx, JSValueConst this_val,
  58421                                    int argc, JSValueConst *argv, int toLocaleString)
  58422 {
  58423     JSValue sep = JS_UNDEFINED, el;
  58424     StringBuffer b_s, *b = &b_s;
  58425     JSString *s = NULL;
  58426     JSObject *p;
  58427     int i, len, oldlen, newlen;
  58428     int c;
  58429 
  58430     p = get_typed_array(ctx, this_val);
  58431     if (!p)
  58432         return JS_EXCEPTION;
  58433     if (typed_array_is_oob(p))
  58434         return JS_ThrowTypeErrorArrayBufferOOB(ctx);
  58435     len = oldlen = newlen = p->u.array.count;
  58436 
  58437     c = ',';    /* default separator */
  58438     if (!toLocaleString && argc > 0 && !JS_IsUndefined(argv[0])) {
  58439         sep = JS_ToString(ctx, argv[0]);
  58440         if (JS_IsException(sep))
  58441             goto exception;
  58442         s = JS_VALUE_GET_STRING(sep);
  58443         if (s->len == 1 && !s->is_wide_char)
  58444             c = s->u.str8[0];
  58445         else
  58446             c = -1;
  58447         // ToString(sep) can detach or resize the arraybuffer as a side effect
  58448         newlen = p->u.array.count;
  58449         len = min_int(len, newlen);
  58450     }
  58451     string_buffer_init(ctx, b, 0);
  58452 
  58453     /* XXX: optimize with direct access */
  58454     for(i = 0; i < len; i++) {
  58455         if (i > 0) {
  58456             if (c >= 0) {
  58457                 if (string_buffer_putc8(b, c))
  58458                     goto fail;
  58459             } else {
  58460                 if (string_buffer_concat(b, s, 0, s->len))
  58461                     goto fail;
  58462             }
  58463         }
  58464         el = JS_GetPropertyUint32(ctx, this_val, i);
  58465         /* Can return undefined for example if the typed array is detached */
  58466         if (!JS_IsNull(el) && !JS_IsUndefined(el)) {
  58467             if (JS_IsException(el))
  58468                 goto fail;
  58469             if (toLocaleString) {
  58470                 el = JS_ToLocaleStringFree(ctx, el);
  58471             }
  58472             if (string_buffer_concat_value_free(b, el))
  58473                 goto fail;
  58474         }
  58475     }
  58476 
  58477     // add extra separators in case RAB was resized by evil .valueOf method
  58478     i = max_int(1, newlen);
  58479     for(/*empty*/; i < oldlen; i++) {
  58480         if (c >= 0) {
  58481             if (string_buffer_putc8(b, c))
  58482                 goto fail;
  58483         } else {
  58484             if (string_buffer_concat(b, s, 0, s->len))
  58485                 goto fail;
  58486         }
  58487     }
  58488 
  58489     JS_FreeValue(ctx, sep);
  58490     return string_buffer_end(b);
  58491 
  58492 fail:
  58493     string_buffer_free(b);
  58494     JS_FreeValue(ctx, sep);
  58495 exception:
  58496     return JS_EXCEPTION;
  58497 }
  58498 
  58499 static JSValue js_typed_array_reverse(JSContext *ctx, JSValueConst this_val,
  58500                                       int argc, JSValueConst *argv)
  58501 {
  58502     JSObject *p;
  58503     int len;
  58504 
  58505     len = js_typed_array_get_length_unsafe(ctx, this_val);
  58506     if (len < 0)
  58507         return JS_EXCEPTION;
  58508     if (len > 0) {
  58509         p = JS_VALUE_GET_OBJ(this_val);
  58510         switch (typed_array_size_log2(p->class_id)) {
  58511         case 0:
  58512             {
  58513                 uint8_t *p1 = p->u.array.u.uint8_ptr;
  58514                 uint8_t *p2 = p1 + len - 1;
  58515                 while (p1 < p2) {
  58516                     uint8_t v = *p1;
  58517                     *p1++ = *p2;
  58518                     *p2-- = v;
  58519                 }
  58520             }
  58521             break;
  58522         case 1:
  58523             {
  58524                 uint16_t *p1 = p->u.array.u.uint16_ptr;
  58525                 uint16_t *p2 = p1 + len - 1;
  58526                 while (p1 < p2) {
  58527                     uint16_t v = *p1;
  58528                     *p1++ = *p2;
  58529                     *p2-- = v;
  58530                 }
  58531             }
  58532             break;
  58533         case 2:
  58534             {
  58535                 uint32_t *p1 = p->u.array.u.uint32_ptr;
  58536                 uint32_t *p2 = p1 + len - 1;
  58537                 while (p1 < p2) {
  58538                     uint32_t v = *p1;
  58539                     *p1++ = *p2;
  58540                     *p2-- = v;
  58541                 }
  58542             }
  58543             break;
  58544         case 3:
  58545             {
  58546                 uint64_t *p1 = p->u.array.u.uint64_ptr;
  58547                 uint64_t *p2 = p1 + len - 1;
  58548                 while (p1 < p2) {
  58549                     uint64_t v = *p1;
  58550                     *p1++ = *p2;
  58551                     *p2-- = v;
  58552                 }
  58553             }
  58554             break;
  58555         default:
  58556             abort();
  58557         }
  58558     }
  58559     return JS_DupValue(ctx, this_val);
  58560 }
  58561 
  58562 static JSValue js_typed_array_toReversed(JSContext *ctx, JSValueConst this_val,
  58563                                          int argc, JSValueConst *argv)
  58564 {
  58565     JSValue arr, ret;
  58566     JSObject *p;
  58567 
  58568     p = get_typed_array(ctx, this_val);
  58569     if (!p)
  58570         return JS_EXCEPTION;
  58571     arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,
  58572                                         p->class_id, p->u.array.count);
  58573     if (JS_IsException(arr))
  58574         return JS_EXCEPTION;
  58575     ret = js_typed_array_reverse(ctx, arr, argc, argv);
  58576     JS_FreeValue(ctx, arr);
  58577     return ret;
  58578 }
  58579 
  58580 static void slice_memcpy(uint8_t *dst, const uint8_t *src, size_t len)
  58581 {
  58582     if (dst + len <= src || dst >= src + len) {
  58583         /* no overlap: can use memcpy */
  58584         memcpy(dst, src, len);
  58585     } else {
  58586         /* otherwise the spec mandates byte copy */
  58587         while (len-- != 0)
  58588             *dst++ = *src++;
  58589     }
  58590 }
  58591 
  58592 static JSValue js_typed_array_slice(JSContext *ctx, JSValueConst this_val,
  58593                                     int argc, JSValueConst *argv)
  58594 {
  58595     JSValueConst args[2];
  58596     JSValue arr, val;
  58597     JSObject *p, *p1;
  58598     int n, len, start, final, count, shift, space;
  58599 
  58600     arr = JS_UNDEFINED;
  58601     p = get_typed_array(ctx, this_val);
  58602     if (!p)
  58603         goto exception;
  58604     if (typed_array_is_oob(p))
  58605         return JS_ThrowTypeErrorArrayBufferOOB(ctx);
  58606     len = p->u.array.count;
  58607 
  58608     if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))
  58609         goto exception;
  58610     final = len;
  58611     if (!JS_IsUndefined(argv[1])) {
  58612         if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len))
  58613             goto exception;
  58614     }
  58615     count = max_int(final - start, 0);
  58616 
  58617     shift = typed_array_size_log2(p->class_id);
  58618 
  58619     args[0] = this_val;
  58620     args[1] = JS_NewInt32(ctx, count);
  58621     arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
  58622     if (JS_IsException(arr))
  58623         goto exception;
  58624 
  58625     if (count > 0) {
  58626         if (validate_typed_array(ctx, this_val)
  58627         ||  validate_typed_array(ctx, arr))
  58628             goto exception;
  58629 
  58630         p1 = get_typed_array(ctx, arr);
  58631         space = max_int(0, p->u.array.count - start);
  58632         count = min_int(count, space);
  58633         if (p1 != NULL && p->class_id == p1->class_id) {
  58634             slice_memcpy(p1->u.array.u.uint8_ptr,
  58635                          p->u.array.u.uint8_ptr + (start << shift),
  58636                          count << shift);
  58637         } else {
  58638             for (n = 0; n < count; n++) {
  58639                 val = JS_GetPropertyValue(ctx, this_val, JS_NewInt32(ctx, start + n));
  58640                 if (JS_IsException(val))
  58641                     goto exception;
  58642                 if (JS_SetPropertyValue(ctx, arr, JS_NewInt32(ctx, n), val,
  58643                                         JS_PROP_THROW) < 0)
  58644                     goto exception;
  58645             }
  58646         }
  58647     }
  58648     return arr;
  58649 
  58650  exception:
  58651     JS_FreeValue(ctx, arr);
  58652     return JS_EXCEPTION;
  58653 }
  58654 
  58655 static JSValue js_typed_array_subarray(JSContext *ctx, JSValueConst this_val,
  58656                                        int argc, JSValueConst *argv)
  58657 {
  58658     JSValueConst args[4];
  58659     JSValue arr, ta_buffer;
  58660     JSTypedArray *ta;
  58661     JSObject *p;
  58662     int len, start, final, count, shift, offset;
  58663     BOOL is_auto;
  58664         
  58665     p = get_typed_array(ctx, this_val);
  58666     if (!p)
  58667         goto exception;
  58668     len = p->u.array.count;
  58669     if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))
  58670         goto exception;
  58671 
  58672     shift = typed_array_size_log2(p->class_id);
  58673     ta = p->u.typed_array;
  58674     /* Read byteOffset (ta->offset) even if detached */
  58675     offset = ta->offset + (start << shift);
  58676 
  58677     final = len;
  58678     if (JS_IsUndefined(argv[1])) {
  58679         is_auto = ta->track_rab;
  58680     } else {
  58681         is_auto = FALSE;
  58682         if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len))
  58683             goto exception;
  58684     } 
  58685     count = max_int(final - start, 0);
  58686     ta_buffer = js_typed_array_get_buffer(ctx, this_val);
  58687     if (JS_IsException(ta_buffer))
  58688         goto exception;
  58689     args[0] = this_val;
  58690     args[1] = ta_buffer;
  58691     args[2] = JS_NewInt32(ctx, offset);
  58692     args[3] = JS_NewInt32(ctx, count);
  58693     arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, is_auto ? 3 : 4, args);
  58694     JS_FreeValue(ctx, ta_buffer);
  58695     return arr;
  58696 
  58697  exception:
  58698     return JS_EXCEPTION;
  58699 }
  58700 
  58701 /* TypedArray.prototype.sort */
  58702 
  58703 static int js_cmp_doubles(double x, double y)
  58704 {
  58705     if (isnan(x))    return isnan(y) ? 0 : +1;
  58706     if (isnan(y))    return -1;
  58707     if (x < y)       return -1;
  58708     if (x > y)       return 1;
  58709     if (x != 0)      return 0;
  58710     if (signbit(x))  return signbit(y) ? 0 : -1;
  58711     else             return signbit(y) ? 1 : 0;
  58712 }
  58713 
  58714 static int js_TA_cmp_int8(const void *a, const void *b, void *opaque) {
  58715     return *(const int8_t *)a - *(const int8_t *)b;
  58716 }
  58717 
  58718 static int js_TA_cmp_uint8(const void *a, const void *b, void *opaque) {
  58719     return *(const uint8_t *)a - *(const uint8_t *)b;
  58720 }
  58721 
  58722 static int js_TA_cmp_int16(const void *a, const void *b, void *opaque) {
  58723     return *(const int16_t *)a - *(const int16_t *)b;
  58724 }
  58725 
  58726 static int js_TA_cmp_uint16(const void *a, const void *b, void *opaque) {
  58727     return *(const uint16_t *)a - *(const uint16_t *)b;
  58728 }
  58729 
  58730 static int js_TA_cmp_int32(const void *a, const void *b, void *opaque) {
  58731     int32_t x = *(const int32_t *)a;
  58732     int32_t y = *(const int32_t *)b;
  58733     return (y < x) - (y > x);
  58734 }
  58735 
  58736 static int js_TA_cmp_uint32(const void *a, const void *b, void *opaque) {
  58737     uint32_t x = *(const uint32_t *)a;
  58738     uint32_t y = *(const uint32_t *)b;
  58739     return (y < x) - (y > x);
  58740 }
  58741 
  58742 static int js_TA_cmp_int64(const void *a, const void *b, void *opaque) {
  58743     int64_t x = *(const int64_t *)a;
  58744     int64_t y = *(const int64_t *)b;
  58745     return (y < x) - (y > x);
  58746 }
  58747 
  58748 static int js_TA_cmp_uint64(const void *a, const void *b, void *opaque) {
  58749     uint64_t x = *(const uint64_t *)a;
  58750     uint64_t y = *(const uint64_t *)b;
  58751     return (y < x) - (y > x);
  58752 }
  58753 
  58754 static int js_TA_cmp_float16(const void *a, const void *b, void *opaque) {
  58755     return js_cmp_doubles(fromfp16(*(const uint16_t *)a),
  58756                           fromfp16(*(const uint16_t *)b));
  58757 }
  58758 
  58759 static int js_TA_cmp_float32(const void *a, const void *b, void *opaque) {
  58760     return js_cmp_doubles(*(const float *)a, *(const float *)b);
  58761 }
  58762 
  58763 static int js_TA_cmp_float64(const void *a, const void *b, void *opaque) {
  58764     return js_cmp_doubles(*(const double *)a, *(const double *)b);
  58765 }
  58766 
  58767 static JSValue js_TA_get_int8(JSContext *ctx, const void *a) {
  58768     return JS_NewInt32(ctx, *(const int8_t *)a);
  58769 }
  58770 
  58771 static JSValue js_TA_get_uint8(JSContext *ctx, const void *a) {
  58772     return JS_NewInt32(ctx, *(const uint8_t *)a);
  58773 }
  58774 
  58775 static JSValue js_TA_get_int16(JSContext *ctx, const void *a) {
  58776     return JS_NewInt32(ctx, *(const int16_t *)a);
  58777 }
  58778 
  58779 static JSValue js_TA_get_uint16(JSContext *ctx, const void *a) {
  58780     return JS_NewInt32(ctx, *(const uint16_t *)a);
  58781 }
  58782 
  58783 static JSValue js_TA_get_int32(JSContext *ctx, const void *a) {
  58784     return JS_NewInt32(ctx, *(const int32_t *)a);
  58785 }
  58786 
  58787 static JSValue js_TA_get_uint32(JSContext *ctx, const void *a) {
  58788     return JS_NewUint32(ctx, *(const uint32_t *)a);
  58789 }
  58790 
  58791 static JSValue js_TA_get_int64(JSContext *ctx, const void *a) {
  58792     return JS_NewBigInt64(ctx, *(int64_t *)a);
  58793 }
  58794 
  58795 static JSValue js_TA_get_uint64(JSContext *ctx, const void *a) {
  58796     return JS_NewBigUint64(ctx, *(uint64_t *)a);
  58797 }
  58798 
  58799 static JSValue js_TA_get_float16(JSContext *ctx, const void *a) {
  58800     return __JS_NewFloat64(ctx, fromfp16(*(const uint16_t *)a));
  58801 }
  58802 
  58803 static JSValue js_TA_get_float32(JSContext *ctx, const void *a) {
  58804     return __JS_NewFloat64(ctx, *(const float *)a);
  58805 }
  58806 
  58807 static JSValue js_TA_get_float64(JSContext *ctx, const void *a) {
  58808     return __JS_NewFloat64(ctx, *(const double *)a);
  58809 }
  58810 
  58811 struct TA_sort_context {
  58812     JSContext *ctx;
  58813     int exception; /* 1 = exception, 2 = detached typed array */
  58814     uint8_t *array;
  58815     JSValueConst cmp;
  58816     JSValue (*getfun)(JSContext *ctx, const void *a);
  58817     int elt_size;
  58818 };
  58819 
  58820 static int js_TA_cmp_generic(const void *a, const void *b, void *opaque) {
  58821     struct TA_sort_context *psc = opaque;
  58822     JSContext *ctx = psc->ctx;
  58823     uint32_t a_idx, b_idx;
  58824     JSValueConst argv[2];
  58825     JSValue res;
  58826     int cmp;
  58827     
  58828     cmp = 0;
  58829     if (!psc->exception) {
  58830         /* Note: the typed array can be detached without causing an
  58831            error */
  58832         a_idx = *(uint32_t *)a;
  58833         b_idx = *(uint32_t *)b;
  58834         argv[0] = psc->getfun(ctx, psc->array +
  58835                               a_idx * (size_t)psc->elt_size);
  58836         argv[1] = psc->getfun(ctx, psc->array +
  58837                               b_idx * (size_t)(psc->elt_size));
  58838         res = JS_Call(ctx, psc->cmp, JS_UNDEFINED, 2, argv);
  58839         if (JS_IsException(res)) {
  58840             psc->exception = 1;
  58841             goto done;
  58842         }
  58843         if (JS_VALUE_GET_TAG(res) == JS_TAG_INT) {
  58844             int val = JS_VALUE_GET_INT(res);
  58845             cmp = (val > 0) - (val < 0);
  58846         } else {
  58847             double val;
  58848             if (JS_ToFloat64Free(ctx, &val, res) < 0) {
  58849                 psc->exception = 1;
  58850                 goto done;
  58851             } else {
  58852                 cmp = (val > 0) - (val < 0);
  58853             }
  58854         }
  58855         if (cmp == 0) {
  58856             /* make sort stable: compare array offsets */
  58857             cmp = (a_idx > b_idx) - (a_idx < b_idx);
  58858         }
  58859     done:
  58860         JS_FreeValue(ctx, (JSValue)argv[0]);
  58861         JS_FreeValue(ctx, (JSValue)argv[1]);
  58862     }
  58863     return cmp;
  58864 }
  58865 
  58866 static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val,
  58867                                    int argc, JSValueConst *argv)
  58868 {
  58869     JSObject *p;
  58870     int len;
  58871     size_t elt_size;
  58872     struct TA_sort_context tsc;
  58873     int (*cmpfun)(const void *a, const void *b, void *opaque);
  58874 
  58875     tsc.ctx = ctx;
  58876     tsc.exception = 0;
  58877     tsc.cmp = argv[0];
  58878 
  58879     if (!JS_IsUndefined(tsc.cmp) && check_function(ctx, tsc.cmp))
  58880         return JS_EXCEPTION;
  58881     len = js_typed_array_get_length_unsafe(ctx, this_val);
  58882     if (len < 0)
  58883         return JS_EXCEPTION;
  58884 
  58885     if (len > 1) {
  58886         p = JS_VALUE_GET_OBJ(this_val);
  58887         switch (p->class_id) {
  58888         case JS_CLASS_INT8_ARRAY:
  58889             tsc.getfun = js_TA_get_int8;
  58890             cmpfun = js_TA_cmp_int8;
  58891             break;
  58892         case JS_CLASS_UINT8C_ARRAY:
  58893         case JS_CLASS_UINT8_ARRAY:
  58894             tsc.getfun = js_TA_get_uint8;
  58895             cmpfun = js_TA_cmp_uint8;
  58896             break;
  58897         case JS_CLASS_INT16_ARRAY:
  58898             tsc.getfun = js_TA_get_int16;
  58899             cmpfun = js_TA_cmp_int16;
  58900             break;
  58901         case JS_CLASS_UINT16_ARRAY:
  58902             tsc.getfun = js_TA_get_uint16;
  58903             cmpfun = js_TA_cmp_uint16;
  58904             break;
  58905         case JS_CLASS_INT32_ARRAY:
  58906             tsc.getfun = js_TA_get_int32;
  58907             cmpfun = js_TA_cmp_int32;
  58908             break;
  58909         case JS_CLASS_UINT32_ARRAY:
  58910             tsc.getfun = js_TA_get_uint32;
  58911             cmpfun = js_TA_cmp_uint32;
  58912             break;
  58913         case JS_CLASS_BIG_INT64_ARRAY:
  58914             tsc.getfun = js_TA_get_int64;
  58915             cmpfun = js_TA_cmp_int64;
  58916             break;
  58917         case JS_CLASS_BIG_UINT64_ARRAY:
  58918             tsc.getfun = js_TA_get_uint64;
  58919             cmpfun = js_TA_cmp_uint64;
  58920             break;
  58921         case JS_CLASS_FLOAT16_ARRAY:
  58922             tsc.getfun = js_TA_get_float16;
  58923             cmpfun = js_TA_cmp_float16;
  58924             break;
  58925         case JS_CLASS_FLOAT32_ARRAY:
  58926             tsc.getfun = js_TA_get_float32;
  58927             cmpfun = js_TA_cmp_float32;
  58928             break;
  58929         case JS_CLASS_FLOAT64_ARRAY:
  58930             tsc.getfun = js_TA_get_float64;
  58931             cmpfun = js_TA_cmp_float64;
  58932             break;
  58933         default:
  58934             abort();
  58935         }
  58936         elt_size = 1 << typed_array_size_log2(p->class_id);
  58937         if (!JS_IsUndefined(tsc.cmp)) {
  58938             uint32_t *array_idx;
  58939             void *array;
  58940             size_t i, j;
  58941 
  58942             /* the array must be copied because the comparison
  58943                function may modify it */
  58944             array = js_malloc(ctx, len * elt_size);
  58945             if (!array)
  58946                 return JS_EXCEPTION;
  58947             memcpy(array, p->u.array.u.ptr, len * elt_size);
  58948             
  58949             /* array_idx is needed to have a stable sort */
  58950             array_idx = js_malloc(ctx, len * sizeof(array_idx[0]));
  58951             if (!array_idx) {
  58952                 js_free(ctx, array);
  58953                 return JS_EXCEPTION;
  58954             }
  58955             for(i = 0; i < len; i++)
  58956                 array_idx[i] = i;
  58957             tsc.elt_size = elt_size;
  58958             tsc.array = array;
  58959             rqsort(array_idx, len, sizeof(array_idx[0]),
  58960                    js_TA_cmp_generic, &tsc);
  58961             if (tsc.exception) {
  58962                 if (tsc.exception == 1) {
  58963                     js_free(ctx, array_idx);
  58964                     js_free(ctx, array);
  58965                     return JS_EXCEPTION;
  58966                 }
  58967                 /* detached typed array during the sort: no error */
  58968             } else {
  58969                 void *array_ptr = p->u.array.u.ptr;
  58970                 len = min_int(len, p->u.array.count);
  58971                 switch(elt_size) {
  58972                 case 1:
  58973                     for(i = 0; i < len; i++) {
  58974                         j = array_idx[i];
  58975                         ((uint8_t *)array_ptr)[i] = ((uint8_t *)array)[j];
  58976                     }
  58977                     break;
  58978                 case 2:
  58979                     for(i = 0; i < len; i++) {
  58980                         j = array_idx[i];
  58981                         ((uint16_t *)array_ptr)[i] = ((uint16_t *)array)[j];
  58982                     }
  58983                     break;
  58984                 case 4:
  58985                     for(i = 0; i < len; i++) {
  58986                         j = array_idx[i];
  58987                         ((uint32_t *)array_ptr)[i] = ((uint32_t *)array)[j];
  58988                     }
  58989                     break;
  58990                 case 8:
  58991                     for(i = 0; i < len; i++) {
  58992                         j = array_idx[i];
  58993                         ((uint64_t *)array_ptr)[i] = ((uint64_t *)array)[j];
  58994                     }
  58995                     break;
  58996                 default:
  58997                     abort();
  58998                 }
  58999             }
  59000             js_free(ctx, array_idx);
  59001             js_free(ctx, array);
  59002         } else {
  59003             rqsort(p->u.array.u.ptr, len, elt_size, cmpfun, &tsc);
  59004             if (tsc.exception)
  59005                 return JS_EXCEPTION;
  59006         }
  59007     }
  59008     return JS_DupValue(ctx, this_val);
  59009 }
  59010 
  59011 static JSValue js_typed_array_toSorted(JSContext *ctx, JSValueConst this_val,
  59012                                        int argc, JSValueConst *argv)
  59013 {
  59014     JSValue arr, ret;
  59015     JSObject *p;
  59016 
  59017     p = get_typed_array(ctx, this_val);
  59018     if (!p)
  59019         return JS_EXCEPTION;
  59020     arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,
  59021                                         p->class_id, p->u.array.count);
  59022     if (JS_IsException(arr))
  59023         return JS_EXCEPTION;
  59024     ret = js_typed_array_sort(ctx, arr, argc, argv);
  59025     JS_FreeValue(ctx, arr);
  59026     return ret;
  59027 }
  59028 
  59029 /* Uint8Array base64/hex (tc39 proposal-arraybuffer-base64) */
  59030 
  59031 enum {
  59032     B64_ALPHABET_BASE64 = 0,
  59033     B64_ALPHABET_BASE64URL = 1,
  59034 };
  59035 
  59036 enum {
  59037     B64_LAST_LOOSE = 0,
  59038     B64_LAST_STRICT = 1,
  59039     B64_LAST_STOP_BEFORE_PARTIAL = 2,
  59040 };
  59041 
  59042 static const unsigned char b64_enc[64] = {
  59043     'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
  59044     'Q','R','S','T','U','V','W','X','Y','Z',
  59045     'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p',
  59046     'q','r','s','t','u','v','w','x','y','z',
  59047     '0','1','2','3','4','5','6','7','8','9',
  59048     '+','/'
  59049 };
  59050 
  59051 static const unsigned char b64url_enc[64] = {
  59052     'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
  59053     'Q','R','S','T','U','V','W','X','Y','Z',
  59054     'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p',
  59055     'q','r','s','t','u','v','w','x','y','z',
  59056     '0','1','2','3','4','5','6','7','8','9',
  59057     '-','_'
  59058 };
  59059 
  59060 #define K_WS 64
  59061 #define K_ER 65
  59062 
  59063 static const uint8_t b64_dec[256] = {
  59064  [  0]=K_ER, [  1]=K_ER, [  2]=K_ER, [  3]=K_ER, [  4]=K_ER, [  5]=K_ER, [  6]=K_ER, [  7]=K_ER,
  59065  [  8]=K_ER, [  9]=K_WS, [ 10]=K_WS, [ 11]=K_ER, [ 12]=K_WS, [ 13]=K_WS, [ 14]=K_ER, [ 15]=K_ER,
  59066  [ 16]=K_ER, [ 17]=K_ER, [ 18]=K_ER, [ 19]=K_ER, [ 20]=K_ER, [ 21]=K_ER, [ 22]=K_ER, [ 23]=K_ER,
  59067  [ 24]=K_ER, [ 25]=K_ER, [ 26]=K_ER, [ 27]=K_ER, [ 28]=K_ER, [ 29]=K_ER, [ 30]=K_ER, [ 31]=K_ER,
  59068  [' ']=K_WS, ['!']=K_ER, ['"']=K_ER, ['#']=K_ER, ['$']=K_ER, ['%']=K_ER, ['&']=K_ER, [ 39]=K_ER,
  59069  ['(']=K_ER, [')']=K_ER, ['*']=K_ER, ['+']=  62, [',']=K_ER, ['-']=K_ER, ['.']=K_ER, ['/']=  63,
  59070  ['0']=  52, ['1']=  53, ['2']=  54, ['3']=  55, ['4']=  56, ['5']=  57, ['6']=  58, ['7']=  59,
  59071  ['8']=  60, ['9']=  61, [':']=K_ER, [';']=K_ER, ['<']=K_ER, ['=']=K_ER, ['>']=K_ER, ['?']=K_ER,
  59072  ['@']=K_ER, ['A']=   0, ['B']=   1, ['C']=   2, ['D']=   3, ['E']=   4, ['F']=   5, ['G']=   6,
  59073  ['H']=   7, ['I']=   8, ['J']=   9, ['K']=  10, ['L']=  11, ['M']=  12, ['N']=  13, ['O']=  14,
  59074  ['P']=  15, ['Q']=  16, ['R']=  17, ['S']=  18, ['T']=  19, ['U']=  20, ['V']=  21, ['W']=  22,
  59075  ['X']=  23, ['Y']=  24, ['Z']=  25, ['[']=K_ER, [ 92]=K_ER, [']']=K_ER, ['^']=K_ER, ['_']=K_ER,
  59076  ['`']=K_ER, ['a']=  26, ['b']=  27, ['c']=  28, ['d']=  29, ['e']=  30, ['f']=  31, ['g']=  32,
  59077  ['h']=  33, ['i']=  34, ['j']=  35, ['k']=  36, ['l']=  37, ['m']=  38, ['n']=  39, ['o']=  40,
  59078  ['p']=  41, ['q']=  42, ['r']=  43, ['s']=  44, ['t']=  45, ['u']=  46, ['v']=  47, ['w']=  48,
  59079  ['x']=  49, ['y']=  50, ['z']=  51, ['{']=K_ER, ['|']=K_ER, ['}']=K_ER, ['~']=K_ER, [127]=K_ER,
  59080  [128]=K_ER, [129]=K_ER, [130]=K_ER, [131]=K_ER, [132]=K_ER, [133]=K_ER, [134]=K_ER, [135]=K_ER,
  59081  [136]=K_ER, [137]=K_ER, [138]=K_ER, [139]=K_ER, [140]=K_ER, [141]=K_ER, [142]=K_ER, [143]=K_ER,
  59082  [144]=K_ER, [145]=K_ER, [146]=K_ER, [147]=K_ER, [148]=K_ER, [149]=K_ER, [150]=K_ER, [151]=K_ER,
  59083  [152]=K_ER, [153]=K_ER, [154]=K_ER, [155]=K_ER, [156]=K_ER, [157]=K_ER, [158]=K_ER, [159]=K_ER,
  59084  [160]=K_ER, [161]=K_ER, [162]=K_ER, [163]=K_ER, [164]=K_ER, [165]=K_ER, [166]=K_ER, [167]=K_ER,
  59085  [168]=K_ER, [169]=K_ER, [170]=K_ER, [171]=K_ER, [172]=K_ER, [173]=K_ER, [174]=K_ER, [175]=K_ER,
  59086  [176]=K_ER, [177]=K_ER, [178]=K_ER, [179]=K_ER, [180]=K_ER, [181]=K_ER, [182]=K_ER, [183]=K_ER,
  59087  [184]=K_ER, [185]=K_ER, [186]=K_ER, [187]=K_ER, [188]=K_ER, [189]=K_ER, [190]=K_ER, [191]=K_ER,
  59088  [192]=K_ER, [193]=K_ER, [194]=K_ER, [195]=K_ER, [196]=K_ER, [197]=K_ER, [198]=K_ER, [199]=K_ER,
  59089  [200]=K_ER, [201]=K_ER, [202]=K_ER, [203]=K_ER, [204]=K_ER, [205]=K_ER, [206]=K_ER, [207]=K_ER,
  59090  [208]=K_ER, [209]=K_ER, [210]=K_ER, [211]=K_ER, [212]=K_ER, [213]=K_ER, [214]=K_ER, [215]=K_ER,
  59091  [216]=K_ER, [217]=K_ER, [218]=K_ER, [219]=K_ER, [220]=K_ER, [221]=K_ER, [222]=K_ER, [223]=K_ER,
  59092  [224]=K_ER, [225]=K_ER, [226]=K_ER, [227]=K_ER, [228]=K_ER, [229]=K_ER, [230]=K_ER, [231]=K_ER,
  59093  [232]=K_ER, [233]=K_ER, [234]=K_ER, [235]=K_ER, [236]=K_ER, [237]=K_ER, [238]=K_ER, [239]=K_ER,
  59094  [240]=K_ER, [241]=K_ER, [242]=K_ER, [243]=K_ER, [244]=K_ER, [245]=K_ER, [246]=K_ER, [247]=K_ER,
  59095  [248]=K_ER, [249]=K_ER, [250]=K_ER, [251]=K_ER, [252]=K_ER, [253]=K_ER, [254]=K_ER, [255]=K_ER,
  59096 };
  59097 
  59098 static const uint8_t b64url_dec[256] = {
  59099  [  0]=K_ER, [  1]=K_ER, [  2]=K_ER, [  3]=K_ER, [  4]=K_ER, [  5]=K_ER, [  6]=K_ER, [  7]=K_ER,
  59100  [  8]=K_ER, [  9]=K_WS, [ 10]=K_WS, [ 11]=K_ER, [ 12]=K_WS, [ 13]=K_WS, [ 14]=K_ER, [ 15]=K_ER,
  59101  [ 16]=K_ER, [ 17]=K_ER, [ 18]=K_ER, [ 19]=K_ER, [ 20]=K_ER, [ 21]=K_ER, [ 22]=K_ER, [ 23]=K_ER,
  59102  [ 24]=K_ER, [ 25]=K_ER, [ 26]=K_ER, [ 27]=K_ER, [ 28]=K_ER, [ 29]=K_ER, [ 30]=K_ER, [ 31]=K_ER,
  59103  [' ']=K_WS, ['!']=K_ER, ['"']=K_ER, ['#']=K_ER, ['$']=K_ER, ['%']=K_ER, ['&']=K_ER, [ 39]=K_ER,
  59104  ['(']=K_ER, [')']=K_ER, ['*']=K_ER, ['+']=K_ER, [',']=K_ER, ['-']=  62, ['.']=K_ER, ['/']=K_ER,
  59105  ['0']=  52, ['1']=  53, ['2']=  54, ['3']=  55, ['4']=  56, ['5']=  57, ['6']=  58, ['7']=  59,
  59106  ['8']=  60, ['9']=  61, [':']=K_ER, [';']=K_ER, ['<']=K_ER, ['=']=K_ER, ['>']=K_ER, ['?']=K_ER,
  59107  ['@']=K_ER, ['A']=   0, ['B']=   1, ['C']=   2, ['D']=   3, ['E']=   4, ['F']=   5, ['G']=   6,
  59108  ['H']=   7, ['I']=   8, ['J']=   9, ['K']=  10, ['L']=  11, ['M']=  12, ['N']=  13, ['O']=  14,
  59109  ['P']=  15, ['Q']=  16, ['R']=  17, ['S']=  18, ['T']=  19, ['U']=  20, ['V']=  21, ['W']=  22,
  59110  ['X']=  23, ['Y']=  24, ['Z']=  25, ['[']=K_ER, [ 92]=K_ER, [']']=K_ER, ['^']=K_ER, ['_']=  63,
  59111  ['`']=K_ER, ['a']=  26, ['b']=  27, ['c']=  28, ['d']=  29, ['e']=  30, ['f']=  31, ['g']=  32,
  59112  ['h']=  33, ['i']=  34, ['j']=  35, ['k']=  36, ['l']=  37, ['m']=  38, ['n']=  39, ['o']=  40,
  59113  ['p']=  41, ['q']=  42, ['r']=  43, ['s']=  44, ['t']=  45, ['u']=  46, ['v']=  47, ['w']=  48,
  59114  ['x']=  49, ['y']=  50, ['z']=  51, ['{']=K_ER, ['|']=K_ER, ['}']=K_ER, ['~']=K_ER, [127]=K_ER,
  59115  [128]=K_ER, [129]=K_ER, [130]=K_ER, [131]=K_ER, [132]=K_ER, [133]=K_ER, [134]=K_ER, [135]=K_ER,
  59116  [136]=K_ER, [137]=K_ER, [138]=K_ER, [139]=K_ER, [140]=K_ER, [141]=K_ER, [142]=K_ER, [143]=K_ER,
  59117  [144]=K_ER, [145]=K_ER, [146]=K_ER, [147]=K_ER, [148]=K_ER, [149]=K_ER, [150]=K_ER, [151]=K_ER,
  59118  [152]=K_ER, [153]=K_ER, [154]=K_ER, [155]=K_ER, [156]=K_ER, [157]=K_ER, [158]=K_ER, [159]=K_ER,
  59119  [160]=K_ER, [161]=K_ER, [162]=K_ER, [163]=K_ER, [164]=K_ER, [165]=K_ER, [166]=K_ER, [167]=K_ER,
  59120  [168]=K_ER, [169]=K_ER, [170]=K_ER, [171]=K_ER, [172]=K_ER, [173]=K_ER, [174]=K_ER, [175]=K_ER,
  59121  [176]=K_ER, [177]=K_ER, [178]=K_ER, [179]=K_ER, [180]=K_ER, [181]=K_ER, [182]=K_ER, [183]=K_ER,
  59122  [184]=K_ER, [185]=K_ER, [186]=K_ER, [187]=K_ER, [188]=K_ER, [189]=K_ER, [190]=K_ER, [191]=K_ER,
  59123  [192]=K_ER, [193]=K_ER, [194]=K_ER, [195]=K_ER, [196]=K_ER, [197]=K_ER, [198]=K_ER, [199]=K_ER,
  59124  [200]=K_ER, [201]=K_ER, [202]=K_ER, [203]=K_ER, [204]=K_ER, [205]=K_ER, [206]=K_ER, [207]=K_ER,
  59125  [208]=K_ER, [209]=K_ER, [210]=K_ER, [211]=K_ER, [212]=K_ER, [213]=K_ER, [214]=K_ER, [215]=K_ER,
  59126  [216]=K_ER, [217]=K_ER, [218]=K_ER, [219]=K_ER, [220]=K_ER, [221]=K_ER, [222]=K_ER, [223]=K_ER,
  59127  [224]=K_ER, [225]=K_ER, [226]=K_ER, [227]=K_ER, [228]=K_ER, [229]=K_ER, [230]=K_ER, [231]=K_ER,
  59128  [232]=K_ER, [233]=K_ER, [234]=K_ER, [235]=K_ER, [236]=K_ER, [237]=K_ER, [238]=K_ER, [239]=K_ER,
  59129  [240]=K_ER, [241]=K_ER, [242]=K_ER, [243]=K_ER, [244]=K_ER, [245]=K_ER, [246]=K_ER, [247]=K_ER,
  59130  [248]=K_ER, [249]=K_ER, [250]=K_ER, [251]=K_ER, [252]=K_ER, [253]=K_ER, [254]=K_ER, [255]=K_ER,
  59131 };
  59132  
  59133 static size_t b64_encode(const uint8_t *src, size_t len, char *dst,
  59134                          const unsigned char *alpha)
  59135 {
  59136     size_t i, j;
  59137 
  59138     for (i = 0, j = 0; i + 3 <= len; i += 3, j += 4) {
  59139         uint32_t v = 65536*src[i] + 256*src[i + 1] + src[i + 2];
  59140         dst[j + 0] = alpha[(v >> 18) & 63];
  59141         dst[j + 1] = alpha[(v >> 12) & 63];
  59142         dst[j + 2] = alpha[(v >> 6) & 63];
  59143         dst[j + 3] = alpha[v & 63];
  59144     }
  59145 
  59146     size_t rem = len - i;
  59147     if (rem == 1) {
  59148         uint32_t v = 65536*src[i];
  59149         dst[j++] = alpha[(v >> 18) & 63];
  59150         dst[j++] = alpha[(v >> 12) & 63];
  59151         dst[j++] = '=';
  59152         dst[j++] = '=';
  59153     } else if (rem == 2) {
  59154         uint32_t v = 65536*src[i] + 256*src[i + 1];
  59155         dst[j++] = alpha[(v >> 18) & 63];
  59156         dst[j++] = alpha[(v >> 12) & 63];
  59157         dst[j++] = alpha[(v >> 6) & 63];
  59158         dst[j++] = '=';
  59159     }
  59160     return j;
  59161 }
  59162 
  59163 static size_t b64_skip_ws(const char *src, size_t len, size_t index,
  59164                           const uint8_t *dec_table)
  59165 {
  59166     while (index < len && dec_table[(unsigned char)src[index]] == K_WS)
  59167         index++;
  59168     return index;
  59169 }
  59170 
  59171 /* Implements the FromBase64 abstract operation.
  59172    src/src_len: the input string (must be ASCII/latin1)
  59173    dst/max_len: output buffer
  59174    flags: b64_flags or b64_flags_url (selects valid characters)
  59175    last_chunk: B64_LAST_LOOSE, B64_LAST_STRICT, or B64_LAST_STOP_BEFORE_PARTIAL
  59176    *p_read: set to number of input characters consumed
  59177    *p_err: set to 1 on error, 0 on success
  59178    Returns: number of bytes written to dst */
  59179 static size_t from_base64(const char *src, size_t src_len,
  59180                           uint8_t *dst, size_t max_len,
  59181                           const uint8_t *dec_table, int last_chunk,
  59182                           size_t *p_read, int *p_err)
  59183 {
  59184     size_t read = 0, written = 0;
  59185     uint32_t v, acc = 0;
  59186     int seen = 0;
  59187     size_t index = 0;
  59188     uint8_t ch;
  59189     
  59190     *p_err = 0;
  59191 
  59192     if (max_len == 0) {
  59193         *p_read = 0;
  59194         return 0;
  59195     }
  59196 
  59197     for (;;) {
  59198         if (seen == 0) {
  59199             /* Fast path: decode complete groups of 4 valid characters.
  59200                Breaks out on whitespace, padding, invalid chars, or capacity. */
  59201             while (index + 4 <= src_len && written + 3 <= max_len) {
  59202                 uint32_t v0, v1, v2, v3;
  59203                 v0 = dec_table[(unsigned char)src[index]];
  59204                 v1 = dec_table[(unsigned char)src[index + 1]];
  59205                 v2 = dec_table[(unsigned char)src[index + 2]];
  59206                 v3 = dec_table[(unsigned char)src[index + 3]];
  59207                 if ((v0 | v1 | v2 | v3) >= 64)
  59208                     break;
  59209                 v = (v0 << 18) | (v1 << 12) | (v2 << 6) | v3;
  59210                 dst[written]     = (uint8_t)(v >> 16);
  59211                 dst[written + 1] = (uint8_t)(v >> 8);
  59212                 dst[written + 2] = (uint8_t)(v);
  59213                 written += 3;
  59214                 index += 4;
  59215             }
  59216             read = index;
  59217             
  59218             if (written >= max_len) {
  59219                 *p_read = read;
  59220                 return written;
  59221             }
  59222         }
  59223         
  59224         /* Slow path: handle whitespace, padding, partial groups, capacity. */
  59225         index = b64_skip_ws(src, src_len, index, dec_table);
  59226 
  59227         if (index == src_len) {
  59228             if (seen > 0) {
  59229                 if (last_chunk == B64_LAST_STOP_BEFORE_PARTIAL) {
  59230                     *p_read = read;
  59231                     return written;
  59232                 }
  59233                 if (last_chunk == B64_LAST_STRICT) {
  59234                     *p_err = 1;
  59235                     return 0;
  59236                 }
  59237                 /* loose */
  59238                 if (seen == 1) {
  59239                     *p_err = 1;
  59240                     return 0;
  59241                 }
  59242                 break;
  59243             }
  59244             *p_read = src_len;
  59245             return written;
  59246         }
  59247 
  59248         ch = src[index++];
  59249 
  59250         if (ch == '=') {
  59251             if (seen < 2) {
  59252                 *p_err = 1;
  59253                 return 0;
  59254             }
  59255             index = b64_skip_ws(src, src_len, index, dec_table);
  59256             if (seen == 2) {
  59257                 if (index == src_len) {
  59258                     if (last_chunk == B64_LAST_STOP_BEFORE_PARTIAL) {
  59259                         *p_read = read;
  59260                         return written;
  59261                     }
  59262                     *p_err = 1;
  59263                     return 0;
  59264                 }
  59265                 if (src[index] == '=') {
  59266                     index++;
  59267                     index = b64_skip_ws(src, src_len, index, dec_table);
  59268                 } else {
  59269                     *p_err = 1;
  59270                     return 0;
  59271                 }
  59272             }
  59273             /* After padding, only whitespace is allowed */
  59274             if (index != src_len) {
  59275                 *p_err = 1;
  59276                 return 0;
  59277             }
  59278             if (last_chunk == B64_LAST_STRICT) {
  59279                 uint32_t mask = (seen == 2) ? 0xF : 0x3;
  59280                 if (acc & mask) {
  59281                     *p_err = 1;
  59282                     return 0;
  59283                 }
  59284             }
  59285             break;
  59286         }
  59287 
  59288         v = dec_table[ch];
  59289         if (v >= 64) {
  59290             *p_err = 1;
  59291             return 0;
  59292         }
  59293 
  59294         /* Check remaining capacity before committing to this group */
  59295         {
  59296             size_t remaining = max_len - written;
  59297             if ((remaining == 1 && seen == 2) ||
  59298                     (remaining == 2 && seen == 3)) {
  59299                 *p_read = read;
  59300                 return written;
  59301             }
  59302         }
  59303 
  59304         acc = (acc << 6) | v;
  59305         seen++;
  59306 
  59307         if (seen == 4) {
  59308             dst[written]     = (uint8_t)(acc >> 16);
  59309             dst[written + 1] = (uint8_t)(acc >> 8);
  59310             dst[written + 2] = (uint8_t)(acc);
  59311             written += 3;
  59312             acc = 0;
  59313             seen = 0;
  59314             read = index;
  59315             if (written >= max_len) {
  59316                 *p_read = read;
  59317                 return written;
  59318             }
  59319         }
  59320     }
  59321 
  59322     if (seen == 2) {
  59323         dst[written++] = (uint8_t)(acc >> 4);
  59324     } else if (seen == 3) {
  59325         dst[written]     = (uint8_t)(acc >> 10);
  59326         dst[written + 1] = (uint8_t)(acc >> 2);
  59327         written += 2;
  59328     }
  59329     *p_read = src_len;
  59330     return written;
  59331 }
  59332 
  59333 /* Hex helpers */
  59334 static const char u8a_hex_digits[] = "0123456789abcdef";
  59335 
  59336 static size_t u8a_hex_encode(const uint8_t *src, size_t len, char *dst)
  59337 {
  59338     for (size_t i = 0; i < len; i++) {
  59339         dst[i * 2]     = u8a_hex_digits[src[i] >> 4];
  59340         dst[i * 2 + 1] = u8a_hex_digits[src[i] & 0xF];
  59341     }
  59342     return len * 2;
  59343 }
  59344 
  59345 /* Decode hex string to bytes.
  59346    Returns bytes written. Sets *p_read to chars consumed, *p_err on error. */
  59347 static size_t u8a_hex_decode(const char *src, size_t src_len,
  59348                              uint8_t *dst, size_t max_len,
  59349                              size_t *p_read, int *p_err)
  59350 {
  59351     size_t written = 0, i = 0;
  59352     *p_err = 0;
  59353 
  59354     if (src_len & 1) {
  59355         *p_err = 1;
  59356         return 0;
  59357     }
  59358 
  59359     while (i < src_len && written < max_len) {
  59360         int hi = from_hex(src[i]);
  59361         int lo = from_hex(src[i + 1]);
  59362         if (hi < 0 || lo < 0) {
  59363             *p_err = 1;
  59364             return 0;
  59365         }
  59366         dst[written++] = (uint8_t)((hi << 4) | lo);
  59367         i += 2;
  59368     }
  59369 
  59370     *p_read = i;
  59371     return written;
  59372 }
  59373 
  59374 static JSValue JS_NewUint8ArrayCopy(JSContext *ctx, const uint8_t *buf, size_t len)
  59375 {
  59376     JSValue buffer, obj;
  59377     JSArrayBuffer *abuf;
  59378 
  59379     buffer = js_array_buffer_constructor3(ctx, JS_UNDEFINED, len, NULL,
  59380                                           JS_CLASS_ARRAY_BUFFER,
  59381                                           (uint8_t *)buf,
  59382                                           js_array_buffer_free, NULL,
  59383                                           TRUE);
  59384     if (JS_IsException(buffer))
  59385         return JS_EXCEPTION;
  59386     obj = js_create_from_ctor(ctx, JS_UNDEFINED, JS_CLASS_UINT8_ARRAY);
  59387     if (JS_IsException(obj)) {
  59388         JS_FreeValue(ctx, buffer);
  59389         return JS_EXCEPTION;
  59390     }
  59391     abuf = js_get_array_buffer(ctx, buffer);
  59392     assert(abuf != NULL);
  59393     if (typed_array_init(ctx, obj, buffer, 0, abuf->byte_length, /*track_rab*/FALSE)) {
  59394         // 'buffer' is freed on error above.
  59395         JS_FreeValue(ctx, obj);
  59396         return JS_EXCEPTION;
  59397     }
  59398     return obj;
  59399 }
  59400 
  59401 /* Validate that this_val is a Uint8Array (type check only, no detach check).
  59402    Returns the JSObject pointer or NULL on error (throws). */
  59403 static JSObject *check_uint8array(JSContext *ctx, JSValueConst this_val)
  59404 {
  59405     JSObject *p;
  59406 
  59407     if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
  59408         goto fail;
  59409     p = JS_VALUE_GET_OBJ(this_val);
  59410     if (p->class_id != JS_CLASS_UINT8_ARRAY)
  59411         goto fail;
  59412     return p;
  59413 fail:
  59414     JS_ThrowTypeError(ctx, "not a Uint8Array");
  59415     return NULL;
  59416 }
  59417 
  59418 /* Get the data pointer and length of a Uint8Array, checking for detached
  59419    buffers. Must be called after options are read (per spec ordering).
  59420    Returns 0 on success, -1 on error (throws). */
  59421 static int get_uint8array_bytes(JSContext *ctx, JSObject *p,
  59422                                 uint8_t **pdata, size_t *plen)
  59423 {
  59424     if (typed_array_is_oob(p)) {
  59425         JS_ThrowTypeErrorArrayBufferOOB(ctx);
  59426         *pdata = NULL; /* fail safe */
  59427         *plen = 0;
  59428         return -1;
  59429     }
  59430     *pdata = p->u.array.u.uint8_ptr;
  59431     *plen = p->u.array.count;
  59432     return 0;
  59433 }
  59434 
  59435 /* Validate options is undefined or an object (GetOptionsObject).
  59436    Returns 0 on success, -1 on error (throws). */
  59437 static int check_options_object(JSContext *ctx, JSValueConst options)
  59438 {
  59439     if (JS_IsUndefined(options))
  59440         return 0;
  59441     if (!JS_IsObject(options)) {
  59442         JS_ThrowTypeError(ctx, "options must be an object");
  59443         return -1;
  59444     }
  59445     return 0;
  59446 }
  59447 
  59448 /* Parse the 'alphabet' option from an options object.
  59449    Returns B64_ALPHABET_BASE64 or B64_ALPHABET_BASE64URL, or -1 on error. */
  59450 static int parse_alphabet_option(JSContext *ctx, JSValueConst options)
  59451 {
  59452     JSValue val;
  59453     const char *str;
  59454     int ret;
  59455 
  59456     if (JS_IsUndefined(options))
  59457         return B64_ALPHABET_BASE64;
  59458 
  59459     val = JS_GetProperty(ctx, options, JS_ATOM_alphabet);
  59460     if (JS_IsException(val))
  59461         return -1;
  59462     if (JS_IsUndefined(val))
  59463         return B64_ALPHABET_BASE64;
  59464     if (!JS_IsString(val)) {
  59465         JS_FreeValue(ctx, val);
  59466         JS_ThrowTypeError(ctx, "expected string for alphabet");
  59467         return -1;
  59468     }
  59469 
  59470     str = JS_ToCString(ctx, val);
  59471     JS_FreeValue(ctx, val);
  59472     if (!str)
  59473         return -1;
  59474 
  59475     if (!strcmp(str, "base64"))
  59476         ret = B64_ALPHABET_BASE64;
  59477     else if (!strcmp(str, "base64url"))
  59478         ret = B64_ALPHABET_BASE64URL;
  59479     else {
  59480         JS_ThrowTypeError(ctx, "invalid alphabet");
  59481         ret = -1;
  59482     }
  59483     JS_FreeCString(ctx, str);
  59484     return ret;
  59485 }
  59486 
  59487 /* Parse the 'lastChunkHandling' option. Returns mode or -1 on error. */
  59488 static int parse_last_chunk_option(JSContext *ctx, JSValueConst options)
  59489 {
  59490     JSValue val;
  59491     const char *str;
  59492     int ret;
  59493 
  59494     if (JS_IsUndefined(options))
  59495         return B64_LAST_LOOSE;
  59496 
  59497     val = JS_GetProperty(ctx, options, JS_ATOM_lastChunkHandling);
  59498     if (JS_IsException(val))
  59499         return -1;
  59500     if (JS_IsUndefined(val))
  59501         return B64_LAST_LOOSE;
  59502     if (!JS_IsString(val)) {
  59503         JS_FreeValue(ctx, val);
  59504         JS_ThrowTypeError(ctx, "expected string for lastChunkHandling");
  59505         return -1;
  59506     }
  59507 
  59508     str = JS_ToCString(ctx, val);
  59509     JS_FreeValue(ctx, val);
  59510     if (!str)
  59511         return -1;
  59512 
  59513     if (!strcmp(str, "loose"))
  59514         ret = B64_LAST_LOOSE;
  59515     else if (!strcmp(str, "strict"))
  59516         ret = B64_LAST_STRICT;
  59517     else if (!strcmp(str, "stop-before-partial"))
  59518         ret = B64_LAST_STOP_BEFORE_PARTIAL;
  59519     else {
  59520         JS_ThrowTypeError(ctx, "invalid lastChunkHandling option");
  59521         ret = -1;
  59522     }
  59523     JS_FreeCString(ctx, str);
  59524     return ret;
  59525 }
  59526 
  59527 /* Uint8Array.prototype.toBase64([options]) */
  59528 static JSValue js_uint8array_to_base64(JSContext *ctx, JSValueConst this_val,
  59529                                        int argc, JSValueConst *argv)
  59530 {
  59531     uint8_t *data;
  59532     size_t len;
  59533     JSValueConst options;
  59534     JSObject *p;
  59535     int alphabet, omit_padding;
  59536     size_t out_len, written;
  59537     JSString *ostr;
  59538     char *dst;
  59539 
  59540     p = check_uint8array(ctx, this_val);
  59541     if (!p)
  59542         return JS_EXCEPTION;
  59543 
  59544     options = argc > 0 ? argv[0] : JS_UNDEFINED;
  59545     if (check_options_object(ctx, options))
  59546         return JS_EXCEPTION;
  59547     alphabet = parse_alphabet_option(ctx, options);
  59548     if (alphabet < 0)
  59549         return JS_EXCEPTION;
  59550 
  59551     omit_padding = 0;
  59552     if (!JS_IsUndefined(options)) {
  59553         JSValue op_val = JS_GetProperty(ctx, options, JS_ATOM_omitPadding);
  59554         if (JS_IsException(op_val))
  59555             return JS_EXCEPTION;
  59556         omit_padding = JS_ToBool(ctx, op_val);
  59557         JS_FreeValue(ctx, op_val);
  59558     }
  59559 
  59560     if (get_uint8array_bytes(ctx, p, &data, &len))
  59561         return JS_EXCEPTION;
  59562 
  59563     out_len = 4 * ((len + 2) / 3);
  59564 
  59565     if (unlikely(out_len > JS_STRING_LEN_MAX))
  59566         return JS_ThrowRangeError(ctx, "output too large");
  59567 
  59568     ostr = js_alloc_string(ctx, out_len, 0);
  59569     if (!ostr)
  59570         return JS_EXCEPTION;
  59571 
  59572     dst = (char *)ostr->u.str8;
  59573     written = b64_encode(data, len, dst,
  59574                          alphabet == B64_ALPHABET_BASE64URL ? b64url_enc : b64_enc);
  59575     if (omit_padding) {
  59576         while (written > 0 && dst[written - 1] == '=')
  59577             written--;
  59578     }
  59579     dst[written] = '\0';
  59580 
  59581     ostr->len = written;
  59582     return JS_MKPTR(JS_TAG_STRING, ostr);
  59583 }
  59584 
  59585 /* Uint8Array.prototype.toHex() */
  59586 static JSValue js_uint8array_to_hex(JSContext *ctx, JSValueConst this_val,
  59587                                     int argc, JSValueConst *argv)
  59588 {
  59589     uint8_t *data;
  59590     size_t len, out_len;
  59591     JSObject *p;
  59592     JSString *ostr;
  59593 
  59594     p = check_uint8array(ctx, this_val);
  59595     if (!p)
  59596         return JS_EXCEPTION;
  59597     if (get_uint8array_bytes(ctx, p, &data, &len))
  59598         return JS_EXCEPTION;
  59599 
  59600     out_len = len * 2;
  59601     if (unlikely(out_len > JS_STRING_LEN_MAX))
  59602         return JS_ThrowRangeError(ctx, "output too large");
  59603 
  59604     ostr = js_alloc_string(ctx, out_len, 0);
  59605     if (!ostr)
  59606         return JS_EXCEPTION;
  59607 
  59608     u8a_hex_encode(data, len, (char *)ostr->u.str8);
  59609     ostr->u.str8[out_len] = '\0';
  59610     return JS_MKPTR(JS_TAG_STRING, ostr);
  59611 }
  59612 
  59613 /* Uint8Array.fromBase64(string[, options]) */
  59614 static JSValue js_uint8array_from_base64(JSContext *ctx, JSValueConst this_val,
  59615                                          int argc, JSValueConst *argv)
  59616 {
  59617     const char *str;
  59618     size_t str_len, read_pos, decoded_len, out_cap;
  59619     int alphabet, last_chunk, err;
  59620     uint8_t *buf;
  59621     JSValue result;
  59622     JSValueConst options;
  59623     
  59624     if (!JS_IsString(argv[0]))
  59625         return JS_ThrowTypeError(ctx, "expected string");
  59626 
  59627     str = JS_ToCStringLen(ctx, &str_len, argv[0]);
  59628     if (!str)
  59629         return JS_EXCEPTION;
  59630 
  59631     options = argc > 1 ? argv[1] : JS_UNDEFINED;
  59632     if (check_options_object(ctx, options)) {
  59633         JS_FreeCString(ctx, str);
  59634         return JS_EXCEPTION;
  59635     }
  59636     alphabet = parse_alphabet_option(ctx, options);
  59637     if (alphabet < 0) {
  59638         JS_FreeCString(ctx, str);
  59639         return JS_EXCEPTION;
  59640     }
  59641     last_chunk = parse_last_chunk_option(ctx, options);
  59642     if (last_chunk < 0) {
  59643         JS_FreeCString(ctx, str);
  59644         return JS_EXCEPTION;
  59645     }
  59646 
  59647     out_cap = (str_len / 4) * 3 + 3;
  59648     buf = js_malloc(ctx, out_cap);
  59649     if (!buf) {
  59650         JS_FreeCString(ctx, str);
  59651         return JS_EXCEPTION;
  59652     }
  59653 
  59654     decoded_len = from_base64(str, str_len, buf, out_cap,
  59655                               alphabet == B64_ALPHABET_BASE64URL
  59656                                   ? b64url_dec : b64_dec,
  59657                               last_chunk, &read_pos, &err);
  59658     JS_FreeCString(ctx, str);
  59659 
  59660     if (err) {
  59661         js_free(ctx, buf);
  59662         return JS_ThrowSyntaxError(ctx, "invalid base64 string");
  59663     }
  59664 
  59665     result = JS_NewUint8ArrayCopy(ctx, buf, decoded_len);
  59666     js_free(ctx, buf);
  59667     return result;
  59668 }
  59669 
  59670 /* Uint8Array.fromHex(string) */
  59671 static JSValue js_uint8array_from_hex(JSContext *ctx, JSValueConst this_val,
  59672                                       int argc, JSValueConst *argv)
  59673 {
  59674     const char *str;
  59675     size_t str_len, read_pos, decoded_len, out_cap;
  59676     int err;
  59677     uint8_t *buf;
  59678     JSValue result;
  59679 
  59680     if (!JS_IsString(argv[0]))
  59681         return JS_ThrowTypeError(ctx, "expected string");
  59682 
  59683     str = JS_ToCStringLen(ctx, &str_len, argv[0]);
  59684     if (!str)
  59685         return JS_EXCEPTION;
  59686 
  59687     out_cap = str_len / 2 + 1;
  59688     buf = js_malloc(ctx, out_cap);
  59689     if (!buf) {
  59690         JS_FreeCString(ctx, str);
  59691         return JS_EXCEPTION;
  59692     }
  59693 
  59694     decoded_len = u8a_hex_decode(str, str_len, buf, out_cap, &read_pos, &err);
  59695     JS_FreeCString(ctx, str);
  59696 
  59697     if (err) {
  59698         js_free(ctx, buf);
  59699         return JS_ThrowSyntaxError(ctx, "invalid hex string");
  59700     }
  59701 
  59702     /* XXX: could avoid the copy */
  59703     result = JS_NewUint8ArrayCopy(ctx, buf, decoded_len);
  59704     js_free(ctx, buf);
  59705     return result;
  59706 }
  59707 
  59708 /* Return a { read, written } result object */
  59709 static JSValue js_make_read_written(JSContext *ctx, size_t read, size_t written)
  59710 {
  59711     JSValue obj = JS_NewObject(ctx);
  59712     if (JS_IsException(obj))
  59713         return JS_EXCEPTION;
  59714     if (JS_DefinePropertyValueStr(ctx, obj, "read",
  59715                                   JS_NewUint32(ctx, read), JS_PROP_C_W_E) < 0)
  59716         goto fail;
  59717     if (JS_DefinePropertyValueStr(ctx, obj, "written",
  59718                                   JS_NewUint32(ctx, written), JS_PROP_C_W_E) < 0)
  59719         goto fail;
  59720     return obj;
  59721 fail:
  59722     JS_FreeValue(ctx, obj);
  59723     return JS_EXCEPTION;
  59724 }
  59725 
  59726 /* Uint8Array.prototype.setFromBase64(string[, options]) */
  59727 static JSValue js_uint8array_set_from_base64(JSContext *ctx,
  59728                                              JSValueConst this_val,
  59729                                              int argc, JSValueConst *argv)
  59730 {
  59731     uint8_t *data;
  59732     size_t len;
  59733     const char *str;
  59734     size_t str_len, read_pos, decoded_len;
  59735     JSObject *p;
  59736     int alphabet, last_chunk, err;
  59737     JSValueConst options;
  59738 
  59739     p = check_uint8array(ctx, this_val);
  59740     if (!p)
  59741         return JS_EXCEPTION;
  59742 
  59743     if (!JS_IsString(argv[0]))
  59744         return JS_ThrowTypeError(ctx, "expected string");
  59745 
  59746     str = JS_ToCStringLen(ctx, &str_len, argv[0]);
  59747     if (!str)
  59748         return JS_EXCEPTION;
  59749 
  59750     options = argc > 1 ? argv[1] : JS_UNDEFINED;
  59751     if (check_options_object(ctx, options)) {
  59752         JS_FreeCString(ctx, str);
  59753         return JS_EXCEPTION;
  59754     }
  59755     alphabet = parse_alphabet_option(ctx, options);
  59756     if (alphabet < 0) {
  59757         JS_FreeCString(ctx, str);
  59758         return JS_EXCEPTION;
  59759     }
  59760     last_chunk = parse_last_chunk_option(ctx, options);
  59761     if (last_chunk < 0) {
  59762         JS_FreeCString(ctx, str);
  59763         return JS_EXCEPTION;
  59764     }
  59765 
  59766     if (get_uint8array_bytes(ctx, p, &data, &len)) {
  59767         JS_FreeCString(ctx, str);
  59768         return JS_EXCEPTION;
  59769     }
  59770 
  59771     decoded_len = from_base64(str, str_len, data, len,
  59772                               alphabet == B64_ALPHABET_BASE64URL
  59773                                   ? b64url_dec : b64_dec,
  59774                               last_chunk, &read_pos, &err);
  59775     JS_FreeCString(ctx, str);
  59776 
  59777     if (err)
  59778         return JS_ThrowSyntaxError(ctx, "invalid base64 string");
  59779 
  59780     return js_make_read_written(ctx, read_pos, decoded_len);
  59781 }
  59782 
  59783 /* Uint8Array.prototype.setFromHex(string) */
  59784 static JSValue js_uint8array_set_from_hex(JSContext *ctx,
  59785                                           JSValueConst this_val,
  59786                                           int argc, JSValueConst *argv)
  59787 {
  59788     uint8_t *data;
  59789     size_t len;
  59790     const char *str;
  59791     size_t str_len, read_pos, decoded_len;
  59792     JSObject *p;
  59793     int err;
  59794 
  59795     p = check_uint8array(ctx, this_val);
  59796     if (!p)
  59797         return JS_EXCEPTION;
  59798 
  59799     if (!JS_IsString(argv[0]))
  59800         return JS_ThrowTypeError(ctx, "expected string");
  59801 
  59802     str = JS_ToCStringLen(ctx, &str_len, argv[0]);
  59803     if (!str)
  59804         return JS_EXCEPTION;
  59805 
  59806     if (get_uint8array_bytes(ctx, p, &data, &len)) {
  59807         JS_FreeCString(ctx, str);
  59808         return JS_EXCEPTION;
  59809     }
  59810 
  59811     decoded_len = u8a_hex_decode(str, str_len, data, len, &read_pos, &err);
  59812     JS_FreeCString(ctx, str);
  59813 
  59814     if (err)
  59815         return JS_ThrowSyntaxError(ctx, "invalid hex string");
  59816 
  59817     return js_make_read_written(ctx, read_pos, decoded_len);
  59818 }
  59819 
  59820 static const JSCFunctionListEntry js_typed_array_base_funcs[] = {
  59821     JS_CFUNC_DEF("from", 1, js_typed_array_from ),
  59822     JS_CFUNC_DEF("of", 0, js_typed_array_of ),
  59823     JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
  59824 };
  59825 
  59826 static const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = {
  59827     JS_CGETSET_DEF("length", js_typed_array_get_length, NULL ),
  59828     JS_CFUNC_DEF("at", 1, js_typed_array_at ),
  59829     JS_CFUNC_DEF("with", 2, js_typed_array_with ),
  59830     JS_CGETSET_DEF("buffer", js_typed_array_get_buffer, NULL ),
  59831     JS_CGETSET_DEF("byteLength", js_typed_array_get_byteLength, NULL ),
  59832     JS_CGETSET_DEF("byteOffset", js_typed_array_get_byteOffset, NULL ),
  59833     JS_CFUNC_DEF("set", 1, js_typed_array_set ),
  59834     JS_CFUNC_MAGIC_DEF("values", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_VALUE ),
  59835     JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
  59836     JS_CFUNC_MAGIC_DEF("keys", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_KEY ),
  59837     JS_CFUNC_MAGIC_DEF("entries", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE ),
  59838     JS_CGETSET_DEF("[Symbol.toStringTag]", js_typed_array_get_toStringTag, NULL ),
  59839     JS_CFUNC_DEF("copyWithin", 2, js_typed_array_copyWithin ),
  59840     JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every | special_TA ),
  59841     JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some | special_TA ),
  59842     JS_CFUNC_MAGIC_DEF("forEach", 1, js_array_every, special_forEach | special_TA ),
  59843     JS_CFUNC_MAGIC_DEF("map", 1, js_array_every, special_map | special_TA ),
  59844     JS_CFUNC_MAGIC_DEF("filter", 1, js_array_every, special_filter | special_TA ),
  59845     JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce | special_TA ),
  59846     JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight | special_TA ),
  59847     JS_CFUNC_DEF("fill", 1, js_typed_array_fill ),
  59848     JS_CFUNC_MAGIC_DEF("find", 1, js_typed_array_find, ArrayFind ),
  59849     JS_CFUNC_MAGIC_DEF("findIndex", 1, js_typed_array_find, ArrayFindIndex ),
  59850     JS_CFUNC_MAGIC_DEF("findLast", 1, js_typed_array_find, ArrayFindLast ),
  59851     JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_typed_array_find, ArrayFindLastIndex ),
  59852     JS_CFUNC_DEF("reverse", 0, js_typed_array_reverse ),
  59853     JS_CFUNC_DEF("toReversed", 0, js_typed_array_toReversed ),
  59854     JS_CFUNC_DEF("slice", 2, js_typed_array_slice ),
  59855     JS_CFUNC_DEF("subarray", 2, js_typed_array_subarray ),
  59856     JS_CFUNC_DEF("sort", 1, js_typed_array_sort ),
  59857     JS_CFUNC_DEF("toSorted", 1, js_typed_array_toSorted ),
  59858     JS_CFUNC_MAGIC_DEF("join", 1, js_typed_array_join, 0 ),
  59859     JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_typed_array_join, 1 ),
  59860     JS_CFUNC_MAGIC_DEF("indexOf", 1, js_typed_array_indexOf, special_indexOf ),
  59861     JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_typed_array_indexOf, special_lastIndexOf ),
  59862     JS_CFUNC_MAGIC_DEF("includes", 1, js_typed_array_indexOf, special_includes ),
  59863     //JS_ALIAS_BASE_DEF("toString", "toString", 2 /* Array.prototype. */), @@@
  59864 };
  59865 
  59866 static const JSCFunctionListEntry js_typed_array_funcs[] = {
  59867     JS_PROP_INT32_DEF("BYTES_PER_ELEMENT", 1, 0),
  59868     JS_PROP_INT32_DEF("BYTES_PER_ELEMENT", 2, 0),
  59869     JS_PROP_INT32_DEF("BYTES_PER_ELEMENT", 4, 0),
  59870     JS_PROP_INT32_DEF("BYTES_PER_ELEMENT", 8, 0),
  59871 };
  59872 
  59873 static const JSCFunctionListEntry js_uint8array_proto_funcs[] = {
  59874     JS_PROP_INT32_DEF("BYTES_PER_ELEMENT", 1, 0),
  59875     JS_CFUNC_DEF("toBase64", 0, js_uint8array_to_base64),
  59876     JS_CFUNC_DEF("toHex", 0, js_uint8array_to_hex),
  59877     JS_CFUNC_DEF("setFromBase64", 1, js_uint8array_set_from_base64),
  59878     JS_CFUNC_DEF("setFromHex", 1, js_uint8array_set_from_hex),
  59879 };
  59880 
  59881 static const JSCFunctionListEntry js_uint8array_funcs[] = {
  59882     JS_PROP_INT32_DEF("BYTES_PER_ELEMENT", 1, 0),
  59883     JS_CFUNC_DEF("fromBase64", 1, js_uint8array_from_base64),
  59884     JS_CFUNC_DEF("fromHex", 1, js_uint8array_from_hex),
  59885 };
  59886 
  59887 static JSValue js_typed_array_base_constructor(JSContext *ctx,
  59888                                                JSValueConst this_val,
  59889                                                int argc, JSValueConst *argv)
  59890 {
  59891     return JS_ThrowTypeError(ctx, "cannot be called");
  59892 }
  59893 
  59894 /* 'obj' must be an allocated typed array object */
  59895 static int typed_array_init(JSContext *ctx, JSValueConst obj,
  59896                             JSValue buffer, uint64_t offset, uint64_t len,
  59897                             BOOL track_rab)
  59898 {
  59899     JSTypedArray *ta;
  59900     JSObject *p, *pbuffer;
  59901     JSArrayBuffer *abuf;
  59902     int size_log2;
  59903 
  59904     p = JS_VALUE_GET_OBJ(obj);
  59905     size_log2 = typed_array_size_log2(p->class_id);
  59906     ta = js_malloc(ctx, sizeof(*ta));
  59907     if (!ta) {
  59908         JS_FreeValue(ctx, buffer);
  59909         return -1;
  59910     }
  59911     pbuffer = JS_VALUE_GET_OBJ(buffer);
  59912     abuf = pbuffer->u.array_buffer;
  59913     ta->obj = p;
  59914     ta->buffer = pbuffer;
  59915     ta->offset = offset;
  59916     ta->length = len << size_log2;
  59917     ta->track_rab = track_rab;
  59918     list_add_tail(&ta->link, &abuf->array_list);
  59919     p->u.typed_array = ta;
  59920     p->u.array.count = len;
  59921     p->u.array.u.ptr = abuf->data + offset;
  59922     return 0;
  59923 }
  59924 
  59925 JSValue JS_NewTypedArraySimple(JSContext *ctx, JSValue array_buf, size_t bytes_per_element)
  59926 {
  59927     JSValue obj;
  59928     JSObject *p;
  59929     JSArrayBuffer *abuf = NULL;
  59930 
  59931     if (bytes_per_element != 1) {
  59932         JS_FreeValue(ctx, array_buf);
  59933         return JS_ThrowRangeError(ctx, "only byte arrays are supported");
  59934     }
  59935     if (JS_VALUE_GET_TAG(array_buf) != JS_TAG_OBJECT) {
  59936         JS_FreeValue(ctx, array_buf);
  59937         return JS_ThrowTypeError(ctx, "expected array buffer");
  59938     }
  59939     p = JS_VALUE_GET_OBJ(array_buf);
  59940     if (p->class_id != JS_CLASS_ARRAY_BUFFER) {
  59941         JS_FreeValue(ctx, array_buf);
  59942         return JS_ThrowTypeError(ctx, "expected array buffer");
  59943     }
  59944     abuf = p->u.array_buffer;
  59945     if (abuf->detached) {
  59946         JS_FreeValue(ctx, array_buf);
  59947         return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
  59948     }
  59949     obj = JS_NewObjectClass(ctx, JS_CLASS_UINT8_ARRAY);
  59950     if (JS_IsException(obj)) {
  59951         JS_FreeValue(ctx, array_buf);
  59952         return JS_EXCEPTION;
  59953     }
  59954     if (typed_array_init(ctx, obj, array_buf, 0, abuf->byte_length, FALSE)) {
  59955         JS_FreeValue(ctx, obj);
  59956         return JS_EXCEPTION;
  59957     }
  59958     return obj;
  59959 }
  59960 
  59961 
  59962 static JSValue js_array_from_iterator(JSContext *ctx, uint32_t *plen,
  59963                                       JSValueConst obj, JSValueConst method)
  59964 {
  59965     JSValue arr, iter, next_method = JS_UNDEFINED, val;
  59966     BOOL done;
  59967     uint32_t k;
  59968 
  59969     *plen = 0;
  59970     arr = JS_NewArray(ctx);
  59971     if (JS_IsException(arr))
  59972         return arr;
  59973     iter = JS_GetIterator2(ctx, obj, method);
  59974     if (JS_IsException(iter))
  59975         goto fail;
  59976     next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
  59977     if (JS_IsException(next_method))
  59978         goto fail;
  59979     k = 0;
  59980     for(;;) {
  59981         val = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
  59982         if (JS_IsException(val))
  59983             goto fail;
  59984         if (done)
  59985             break;
  59986         if (JS_CreateDataPropertyUint32(ctx, arr, k, val, JS_PROP_THROW) < 0)
  59987             goto fail;
  59988         k++;
  59989     }
  59990     JS_FreeValue(ctx, next_method);
  59991     JS_FreeValue(ctx, iter);
  59992     *plen = k;
  59993     return arr;
  59994  fail:
  59995     JS_FreeValue(ctx, next_method);
  59996     JS_FreeValue(ctx, iter);
  59997     JS_FreeValue(ctx, arr);
  59998     return JS_EXCEPTION;
  59999 }
  60000 
  60001 static JSValue js_typed_array_constructor_obj(JSContext *ctx,
  60002                                               JSValueConst new_target,
  60003                                               JSValueConst obj,
  60004                                               int classid)
  60005 {
  60006     JSValue iter, ret, arr = JS_UNDEFINED, val, buffer;
  60007     uint32_t i;
  60008     int size_log2;
  60009     int64_t len;
  60010 
  60011     size_log2 = typed_array_size_log2(classid);
  60012     ret = js_create_from_ctor(ctx, new_target, classid);
  60013     if (JS_IsException(ret))
  60014         return JS_EXCEPTION;
  60015 
  60016     iter = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
  60017     if (JS_IsException(iter))
  60018         goto fail;
  60019     if (!JS_IsUndefined(iter) && !JS_IsNull(iter)) {
  60020         uint32_t len1;
  60021         arr = js_array_from_iterator(ctx, &len1, obj, iter);
  60022         JS_FreeValue(ctx, iter);
  60023         if (JS_IsException(arr))
  60024             goto fail;
  60025         len = len1;
  60026     } else {
  60027         if (js_get_length64(ctx, &len, obj))
  60028             goto fail;
  60029         arr = JS_DupValue(ctx, obj);
  60030     }
  60031 
  60032     buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,
  60033                                           len << size_log2,
  60034                                           NULL);
  60035     if (JS_IsException(buffer))
  60036         goto fail;
  60037     if (typed_array_init(ctx, ret, buffer, 0, len, /*track_rab*/FALSE))
  60038         goto fail;
  60039 
  60040     for(i = 0; i < len; i++) {
  60041         val = JS_GetPropertyUint32(ctx, arr, i);
  60042         if (JS_IsException(val))
  60043             goto fail;
  60044         if (JS_SetPropertyUint32(ctx, ret, i, val) < 0)
  60045             goto fail;
  60046     }
  60047     JS_FreeValue(ctx, arr);
  60048     return ret;
  60049  fail:
  60050     JS_FreeValue(ctx, arr);
  60051     JS_FreeValue(ctx, ret);
  60052     return JS_EXCEPTION;
  60053 }
  60054 
  60055 static JSValue js_typed_array_constructor_ta(JSContext *ctx,
  60056                                              JSValueConst new_target,
  60057                                              JSValueConst src_obj,
  60058                                              int classid, uint32_t len)
  60059 {
  60060     JSObject *p, *src_buffer;
  60061     JSTypedArray *ta;
  60062     JSValue obj, buffer;
  60063     uint32_t i;
  60064     int size_log2;
  60065     JSArrayBuffer *src_abuf, *abuf;
  60066 
  60067     obj = js_create_from_ctor(ctx, new_target, classid);
  60068     if (JS_IsException(obj))
  60069         return obj;
  60070     p = JS_VALUE_GET_OBJ(src_obj);
  60071     if (typed_array_is_oob(p)) {
  60072         JS_ThrowTypeErrorArrayBufferOOB(ctx);
  60073         goto fail;
  60074     }
  60075     size_log2 = typed_array_size_log2(classid);
  60076     buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,
  60077                                           (uint64_t)len << size_log2,
  60078                                           NULL);
  60079     if (JS_IsException(buffer))
  60080         goto fail;
  60081     /* necessary because it could have been detached */
  60082     if (typed_array_is_oob(p)) {
  60083         JS_FreeValue(ctx, buffer);
  60084         JS_ThrowTypeErrorArrayBufferOOB(ctx);
  60085         goto fail;
  60086     }
  60087     abuf = JS_GetOpaque(buffer, JS_CLASS_ARRAY_BUFFER);
  60088     if (typed_array_init(ctx, obj, buffer, 0, len, /*track_rab*/FALSE))
  60089         goto fail;
  60090     ta = p->u.typed_array;
  60091     src_buffer = ta->buffer;
  60092     src_abuf = src_buffer->u.array_buffer;
  60093     if (p->class_id == classid &&
  60094         (int64_t)ta->offset + (int64_t)abuf->byte_length <= src_abuf->byte_length) {
  60095         /* same type and no overflow: copy the content */
  60096         memcpy(abuf->data, src_abuf->data + ta->offset, abuf->byte_length);
  60097     } else {
  60098         for(i = 0; i < len; i++) {
  60099             JSValue val;
  60100             val = JS_GetPropertyUint32(ctx, src_obj, i);
  60101             if (JS_IsException(val))
  60102                 goto fail;
  60103             if (JS_SetPropertyUint32(ctx, obj, i, val) < 0)
  60104                 goto fail;
  60105         }
  60106     }
  60107     return obj;
  60108  fail:
  60109     JS_FreeValue(ctx, obj);
  60110     return JS_EXCEPTION;
  60111 }
  60112 
  60113 static JSValue js_typed_array_constructor(JSContext *ctx,
  60114                                           JSValueConst new_target,
  60115                                           int argc, JSValueConst *argv,
  60116                                           int classid)
  60117 {
  60118     BOOL track_rab = FALSE;
  60119     JSValue buffer, obj;
  60120     JSArrayBuffer *abuf;
  60121     int size_log2;
  60122     uint64_t len, offset;
  60123 
  60124     size_log2 = typed_array_size_log2(classid);
  60125     if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT) {
  60126         if (JS_ToIndex(ctx, &len, argv[0]))
  60127             return JS_EXCEPTION;
  60128         obj = js_create_from_ctor(ctx, new_target, classid);
  60129         if (JS_IsException(obj))
  60130             return JS_EXCEPTION;
  60131         buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,
  60132                                               len << size_log2,
  60133                                               NULL);
  60134         if (JS_IsException(buffer))
  60135             goto fail;
  60136         offset = 0;
  60137     } else {
  60138         JSObject *p = JS_VALUE_GET_OBJ(argv[0]);
  60139         if (p->class_id == JS_CLASS_ARRAY_BUFFER ||
  60140             p->class_id == JS_CLASS_SHARED_ARRAY_BUFFER) {
  60141             obj = js_create_from_ctor(ctx, new_target, classid);
  60142             if (JS_IsException(obj))
  60143                 return JS_EXCEPTION;
  60144             if (JS_ToIndex(ctx, &offset, argv[1]))
  60145                 goto fail;
  60146             if ((offset & ((1 << size_log2) - 1)) != 0)
  60147                 goto invalid_offset;
  60148             abuf = p->u.array_buffer;
  60149             if (JS_IsUndefined(argv[2])) {
  60150                 if (abuf->detached) {
  60151                     JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
  60152                     goto fail;
  60153                 }
  60154                 if (offset > abuf->byte_length) {
  60155                 invalid_offset:
  60156                     JS_ThrowRangeError(ctx, "invalid offset");
  60157                     goto fail;
  60158                 }
  60159                 track_rab = array_buffer_is_resizable(abuf);
  60160                 if (!track_rab) {
  60161                     if ((abuf->byte_length & ((1 << size_log2) - 1)) != 0)
  60162                         goto invalid_length;
  60163                 }
  60164                 len = (abuf->byte_length - offset) >> size_log2;
  60165             } else {
  60166                 if (JS_ToIndex(ctx, &len, argv[2]))
  60167                     goto fail;
  60168                 if (abuf->detached) {
  60169                     JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
  60170                     goto fail;
  60171                 }
  60172                 if ((offset + (len << size_log2)) > abuf->byte_length) {
  60173                 invalid_length:
  60174                     JS_ThrowRangeError(ctx, "invalid length");
  60175                     goto fail;
  60176                 }
  60177             }
  60178             buffer = JS_DupValue(ctx, argv[0]);
  60179         } else {
  60180             if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
  60181                 p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
  60182                 return js_typed_array_constructor_ta(ctx, new_target, argv[0],
  60183                                                      classid, p->u.array.count);
  60184             } else {
  60185                 return js_typed_array_constructor_obj(ctx, new_target, argv[0], classid);
  60186             }
  60187         }
  60188     }
  60189     if (typed_array_init(ctx, obj, buffer, offset, len, track_rab))
  60190         goto fail;
  60191     return obj;
  60192  fail:
  60193     JS_FreeValue(ctx, obj);
  60194     return JS_EXCEPTION;
  60195 }
  60196 
  60197 static void js_typed_array_finalizer(JSRuntime *rt, JSValue val)
  60198 {
  60199     JSObject *p = JS_VALUE_GET_OBJ(val);
  60200     JSTypedArray *ta = p->u.typed_array;
  60201     if (ta) {
  60202         /* during the GC the finalizers are called in an arbitrary
  60203            order so the ArrayBuffer finalizer may have been called */
  60204         if (ta->link.next) {
  60205             list_del(&ta->link);
  60206         }
  60207         JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
  60208         js_free_rt(rt, ta);
  60209     }
  60210 }
  60211 
  60212 static void js_typed_array_mark(JSRuntime *rt, JSValueConst val,
  60213                                 JS_MarkFunc *mark_func)
  60214 {
  60215     JSObject *p = JS_VALUE_GET_OBJ(val);
  60216     JSTypedArray *ta = p->u.typed_array;
  60217     if (ta) {
  60218         JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer), mark_func);
  60219     }
  60220 }
  60221 
  60222 static JSValue js_dataview_constructor(JSContext *ctx,
  60223                                        JSValueConst new_target,
  60224                                        int argc, JSValueConst *argv)
  60225 {
  60226     BOOL recompute_len = FALSE;
  60227     BOOL track_rab = FALSE;
  60228     JSArrayBuffer *abuf;
  60229     uint64_t offset;
  60230     uint32_t len;
  60231     JSValueConst buffer;
  60232     JSValue obj;
  60233     JSTypedArray *ta;
  60234     JSObject *p;
  60235 
  60236     buffer = argv[0];
  60237     abuf = js_get_array_buffer(ctx, buffer);
  60238     if (!abuf)
  60239         return JS_EXCEPTION;
  60240     offset = 0;
  60241     if (argc > 1) {
  60242         if (JS_ToIndex(ctx, &offset, argv[1]))
  60243             return JS_EXCEPTION;
  60244     }
  60245     if (abuf->detached)
  60246         return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
  60247     if (offset > abuf->byte_length)
  60248         return JS_ThrowRangeError(ctx, "invalid byteOffset");
  60249     len = abuf->byte_length - offset;
  60250     if (argc > 2 && !JS_IsUndefined(argv[2])) {
  60251         uint64_t l;
  60252         if (JS_ToIndex(ctx, &l, argv[2]))
  60253             return JS_EXCEPTION;
  60254         if (l > len)
  60255             return JS_ThrowRangeError(ctx, "invalid byteLength");
  60256         len = l;
  60257     } else {
  60258         recompute_len = TRUE;
  60259         track_rab = array_buffer_is_resizable(abuf);
  60260     }
  60261 
  60262     obj = js_create_from_ctor(ctx, new_target, JS_CLASS_DATAVIEW);
  60263     if (JS_IsException(obj))
  60264         return JS_EXCEPTION;
  60265     if (abuf->detached) {
  60266         /* could have been detached in js_create_from_ctor() */
  60267         JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
  60268         goto fail;
  60269     }
  60270     // RAB could have been resized in js_create_from_ctor()
  60271     if (offset > abuf->byte_length) {
  60272         goto out_of_bound;
  60273     } else if (recompute_len) {
  60274         len = abuf->byte_length - offset;
  60275     } else if (offset + len > abuf->byte_length) {
  60276     out_of_bound:
  60277         JS_ThrowRangeError(ctx, "invalid byteOffset or byteLength");
  60278         goto fail;
  60279     }
  60280     ta = js_malloc(ctx, sizeof(*ta));
  60281     if (!ta) {
  60282     fail:
  60283         JS_FreeValue(ctx, obj);
  60284         return JS_EXCEPTION;
  60285     }
  60286     p = JS_VALUE_GET_OBJ(obj);
  60287     ta->obj = p;
  60288     ta->buffer = JS_VALUE_GET_OBJ(JS_DupValue(ctx, buffer));
  60289     ta->offset = offset;
  60290     ta->length = len;
  60291     ta->track_rab = track_rab;
  60292     list_add_tail(&ta->link, &abuf->array_list);
  60293     p->u.typed_array = ta;
  60294     return obj;
  60295 }
  60296 
  60297 // is the DataView out of bounds relative to its parent arraybuffer?
  60298 static BOOL dataview_is_oob(JSObject *p)
  60299 {
  60300     JSArrayBuffer *abuf;
  60301     JSTypedArray *ta;
  60302 
  60303     assert(p->class_id == JS_CLASS_DATAVIEW);
  60304     ta = p->u.typed_array;
  60305     abuf = ta->buffer->u.array_buffer;
  60306     if (abuf->detached)
  60307         return TRUE;
  60308     if (ta->offset > abuf->byte_length)
  60309         return TRUE;
  60310     if (ta->track_rab)
  60311         return FALSE;
  60312     return (int64_t)ta->offset + ta->length > abuf->byte_length;
  60313 }
  60314 
  60315 static JSObject *get_dataview(JSContext *ctx, JSValueConst this_val)
  60316 {
  60317     JSObject *p;
  60318     if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
  60319         goto fail;
  60320     p = JS_VALUE_GET_OBJ(this_val);
  60321     if (p->class_id != JS_CLASS_DATAVIEW) {
  60322     fail:
  60323         JS_ThrowTypeError(ctx, "not a DataView");
  60324         return NULL;
  60325     }
  60326     return p;
  60327 }
  60328 
  60329 static JSValue js_dataview_get_buffer(JSContext *ctx, JSValueConst this_val)
  60330 {
  60331     JSObject *p;
  60332     JSTypedArray *ta;
  60333     p = get_dataview(ctx, this_val);
  60334     if (!p)
  60335         return JS_EXCEPTION;
  60336     ta = p->u.typed_array;
  60337     return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
  60338 }
  60339 
  60340 static JSValue js_dataview_get_byteLength(JSContext *ctx, JSValueConst this_val)
  60341 {
  60342     JSArrayBuffer *abuf;
  60343     JSTypedArray *ta;
  60344     JSObject *p;
  60345 
  60346     p = get_dataview(ctx, this_val);
  60347     if (!p)
  60348         return JS_EXCEPTION;
  60349     if (dataview_is_oob(p))
  60350         return JS_ThrowTypeErrorArrayBufferOOB(ctx);
  60351     ta = p->u.typed_array;
  60352     if (ta->track_rab) {
  60353         abuf = ta->buffer->u.array_buffer;
  60354         return JS_NewUint32(ctx, abuf->byte_length - ta->offset);
  60355     }
  60356     return JS_NewUint32(ctx, ta->length);
  60357 }
  60358 
  60359 static JSValue js_dataview_get_byteOffset(JSContext *ctx, JSValueConst this_val)
  60360 {
  60361     JSTypedArray *ta;
  60362     JSObject *p;
  60363 
  60364     p = get_dataview(ctx, this_val);
  60365     if (!p)
  60366         return JS_EXCEPTION;
  60367     if (dataview_is_oob(p))
  60368         return JS_ThrowTypeErrorArrayBufferOOB(ctx);
  60369     ta = p->u.typed_array;
  60370     return JS_NewUint32(ctx, ta->offset);
  60371 }
  60372 
  60373 static JSValue js_dataview_getValue(JSContext *ctx,
  60374                                     JSValueConst this_obj,
  60375                                     int argc, JSValueConst *argv, int class_id)
  60376 {
  60377     JSTypedArray *ta;
  60378     JSArrayBuffer *abuf;
  60379     BOOL littleEndian, is_swap;
  60380     int size;
  60381     uint8_t *ptr;
  60382     uint32_t v;
  60383     uint64_t pos;
  60384 
  60385     ta = JS_GetOpaque2(ctx, this_obj, JS_CLASS_DATAVIEW);
  60386     if (!ta)
  60387         return JS_EXCEPTION;
  60388     size = 1 << typed_array_size_log2(class_id);
  60389     if (JS_ToIndex(ctx, &pos, argv[0]))
  60390         return JS_EXCEPTION;
  60391     littleEndian = argc > 1 && JS_ToBool(ctx, argv[1]);
  60392     is_swap = littleEndian ^ !is_be();
  60393     abuf = ta->buffer->u.array_buffer;
  60394     if (abuf->detached)
  60395         return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
  60396     // order matters: this check should come before the next one
  60397     if ((pos + size) > ta->length)
  60398         return JS_ThrowRangeError(ctx, "out of bound");
  60399     // test262 expects a TypeError for this and V8, in its infinite wisdom,
  60400     // throws a "detached array buffer" exception, but IMO that doesn't make
  60401     // sense because the buffer is not in fact detached, it's still there
  60402     if ((int64_t)ta->offset + ta->length > abuf->byte_length)
  60403         return JS_ThrowTypeError(ctx, "out of bound");
  60404     ptr = abuf->data + ta->offset + pos;
  60405 
  60406     switch(class_id) {
  60407     case JS_CLASS_INT8_ARRAY:
  60408         return JS_NewInt32(ctx, *(int8_t *)ptr);
  60409     case JS_CLASS_UINT8_ARRAY:
  60410         return JS_NewInt32(ctx, *(uint8_t *)ptr);
  60411     case JS_CLASS_INT16_ARRAY:
  60412         v = get_u16(ptr);
  60413         if (is_swap)
  60414             v = bswap16(v);
  60415         return JS_NewInt32(ctx, (int16_t)v);
  60416     case JS_CLASS_UINT16_ARRAY:
  60417         v = get_u16(ptr);
  60418         if (is_swap)
  60419             v = bswap16(v);
  60420         return JS_NewInt32(ctx, v);
  60421     case JS_CLASS_INT32_ARRAY:
  60422         v = get_u32(ptr);
  60423         if (is_swap)
  60424             v = bswap32(v);
  60425         return JS_NewInt32(ctx, v);
  60426     case JS_CLASS_UINT32_ARRAY:
  60427         v = get_u32(ptr);
  60428         if (is_swap)
  60429             v = bswap32(v);
  60430         return JS_NewUint32(ctx, v);
  60431     case JS_CLASS_BIG_INT64_ARRAY:
  60432         {
  60433             uint64_t v;
  60434             v = get_u64(ptr);
  60435             if (is_swap)
  60436                 v = bswap64(v);
  60437             return JS_NewBigInt64(ctx, v);
  60438         }
  60439         break;
  60440     case JS_CLASS_BIG_UINT64_ARRAY:
  60441         {
  60442             uint64_t v;
  60443             v = get_u64(ptr);
  60444             if (is_swap)
  60445                 v = bswap64(v);
  60446             return JS_NewBigUint64(ctx, v);
  60447         }
  60448         break;
  60449     case JS_CLASS_FLOAT16_ARRAY:
  60450         {
  60451             uint16_t v;
  60452             v = get_u16(ptr);
  60453             if (is_swap)
  60454                 v = bswap16(v);
  60455             return __JS_NewFloat64(ctx, fromfp16(v));
  60456         }
  60457     case JS_CLASS_FLOAT32_ARRAY:
  60458         {
  60459             union {
  60460                 float f;
  60461                 uint32_t i;
  60462             } u;
  60463             v = get_u32(ptr);
  60464             if (is_swap)
  60465                 v = bswap32(v);
  60466             u.i = v;
  60467             return __JS_NewFloat64(ctx, u.f);
  60468         }
  60469     case JS_CLASS_FLOAT64_ARRAY:
  60470         {
  60471             union {
  60472                 double f;
  60473                 uint64_t i;
  60474             } u;
  60475             u.i = get_u64(ptr);
  60476             if (is_swap)
  60477                 u.i = bswap64(u.i);
  60478             return __JS_NewFloat64(ctx, u.f);
  60479         }
  60480     default:
  60481         abort();
  60482     }
  60483 }
  60484 
  60485 static JSValue js_dataview_setValue(JSContext *ctx,
  60486                                     JSValueConst this_obj,
  60487                                     int argc, JSValueConst *argv, int class_id)
  60488 {
  60489     JSTypedArray *ta;
  60490     JSArrayBuffer *abuf;
  60491     BOOL littleEndian, is_swap;
  60492     int size;
  60493     uint8_t *ptr;
  60494     uint64_t v64;
  60495     uint32_t v;
  60496     uint64_t pos;
  60497     JSValueConst val;
  60498 
  60499     ta = JS_GetOpaque2(ctx, this_obj, JS_CLASS_DATAVIEW);
  60500     if (!ta)
  60501         return JS_EXCEPTION;
  60502     size = 1 << typed_array_size_log2(class_id);
  60503     if (JS_ToIndex(ctx, &pos, argv[0]))
  60504         return JS_EXCEPTION;
  60505     val = argv[1];
  60506     v = 0; /* avoid warning */
  60507     v64 = 0; /* avoid warning */
  60508     if (class_id <= JS_CLASS_UINT32_ARRAY) {
  60509         if (JS_ToUint32(ctx, &v, val))
  60510             return JS_EXCEPTION;
  60511     } else if (class_id <= JS_CLASS_BIG_UINT64_ARRAY) {
  60512         if (JS_ToBigInt64(ctx, (int64_t *)&v64, val))
  60513             return JS_EXCEPTION;
  60514     } else {
  60515         double d;
  60516         if (JS_ToFloat64(ctx, &d, val))
  60517             return JS_EXCEPTION;
  60518         if (class_id == JS_CLASS_FLOAT16_ARRAY) {
  60519             v = tofp16(d);
  60520         } else if (class_id == JS_CLASS_FLOAT32_ARRAY) {
  60521             union {
  60522                 float f;
  60523                 uint32_t i;
  60524             } u;
  60525             u.f = d;
  60526             v = u.i;
  60527         } else {
  60528             JSFloat64Union u;
  60529             u.d = d;
  60530             v64 = u.u64;
  60531         }
  60532     }
  60533     littleEndian = argc > 2 && JS_ToBool(ctx, argv[2]);
  60534     is_swap = littleEndian ^ !is_be();
  60535     abuf = ta->buffer->u.array_buffer;
  60536     if (abuf->detached)
  60537         return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
  60538     // order matters: this check should come before the next one
  60539     if ((pos + size) > ta->length)
  60540         return JS_ThrowRangeError(ctx, "out of bound");
  60541     // test262 expects a TypeError for this and V8, in its infinite wisdom,
  60542     // throws a "detached array buffer" exception, but IMO that doesn't make
  60543     // sense because the buffer is not in fact detached, it's still there
  60544     if ((int64_t)ta->offset + ta->length > abuf->byte_length)
  60545         return JS_ThrowTypeError(ctx, "out of bound");
  60546     ptr = abuf->data + ta->offset + pos;
  60547 
  60548     switch(class_id) {
  60549     case JS_CLASS_INT8_ARRAY:
  60550     case JS_CLASS_UINT8_ARRAY:
  60551         *ptr = v;
  60552         break;
  60553     case JS_CLASS_INT16_ARRAY:
  60554     case JS_CLASS_UINT16_ARRAY:
  60555     case JS_CLASS_FLOAT16_ARRAY:
  60556         if (is_swap)
  60557             v = bswap16(v);
  60558         put_u16(ptr, v);
  60559         break;
  60560     case JS_CLASS_INT32_ARRAY:
  60561     case JS_CLASS_UINT32_ARRAY:
  60562     case JS_CLASS_FLOAT32_ARRAY:
  60563         if (is_swap)
  60564             v = bswap32(v);
  60565         put_u32(ptr, v);
  60566         break;
  60567     case JS_CLASS_BIG_INT64_ARRAY:
  60568     case JS_CLASS_BIG_UINT64_ARRAY:
  60569     case JS_CLASS_FLOAT64_ARRAY:
  60570         if (is_swap)
  60571             v64 = bswap64(v64);
  60572         put_u64(ptr, v64);
  60573         break;
  60574     default:
  60575         abort();
  60576     }
  60577     return JS_UNDEFINED;
  60578 }
  60579 
  60580 static const JSCFunctionListEntry js_dataview_proto_funcs[] = {
  60581     JS_CGETSET_DEF("buffer", js_dataview_get_buffer, NULL ),
  60582     JS_CGETSET_DEF("byteLength", js_dataview_get_byteLength, NULL ),
  60583     JS_CGETSET_DEF("byteOffset", js_dataview_get_byteOffset, NULL ),
  60584     JS_CFUNC_MAGIC_DEF("getInt8", 1, js_dataview_getValue, JS_CLASS_INT8_ARRAY ),
  60585     JS_CFUNC_MAGIC_DEF("getUint8", 1, js_dataview_getValue, JS_CLASS_UINT8_ARRAY ),
  60586     JS_CFUNC_MAGIC_DEF("getInt16", 1, js_dataview_getValue, JS_CLASS_INT16_ARRAY ),
  60587     JS_CFUNC_MAGIC_DEF("getUint16", 1, js_dataview_getValue, JS_CLASS_UINT16_ARRAY ),
  60588     JS_CFUNC_MAGIC_DEF("getInt32", 1, js_dataview_getValue, JS_CLASS_INT32_ARRAY ),
  60589     JS_CFUNC_MAGIC_DEF("getUint32", 1, js_dataview_getValue, JS_CLASS_UINT32_ARRAY ),
  60590     JS_CFUNC_MAGIC_DEF("getBigInt64", 1, js_dataview_getValue, JS_CLASS_BIG_INT64_ARRAY ),
  60591     JS_CFUNC_MAGIC_DEF("getBigUint64", 1, js_dataview_getValue, JS_CLASS_BIG_UINT64_ARRAY ),
  60592     JS_CFUNC_MAGIC_DEF("getFloat16", 1, js_dataview_getValue, JS_CLASS_FLOAT16_ARRAY ),
  60593     JS_CFUNC_MAGIC_DEF("getFloat32", 1, js_dataview_getValue, JS_CLASS_FLOAT32_ARRAY ),
  60594     JS_CFUNC_MAGIC_DEF("getFloat64", 1, js_dataview_getValue, JS_CLASS_FLOAT64_ARRAY ),
  60595     JS_CFUNC_MAGIC_DEF("setInt8", 2, js_dataview_setValue, JS_CLASS_INT8_ARRAY ),
  60596     JS_CFUNC_MAGIC_DEF("setUint8", 2, js_dataview_setValue, JS_CLASS_UINT8_ARRAY ),
  60597     JS_CFUNC_MAGIC_DEF("setInt16", 2, js_dataview_setValue, JS_CLASS_INT16_ARRAY ),
  60598     JS_CFUNC_MAGIC_DEF("setUint16", 2, js_dataview_setValue, JS_CLASS_UINT16_ARRAY ),
  60599     JS_CFUNC_MAGIC_DEF("setInt32", 2, js_dataview_setValue, JS_CLASS_INT32_ARRAY ),
  60600     JS_CFUNC_MAGIC_DEF("setUint32", 2, js_dataview_setValue, JS_CLASS_UINT32_ARRAY ),
  60601     JS_CFUNC_MAGIC_DEF("setBigInt64", 2, js_dataview_setValue, JS_CLASS_BIG_INT64_ARRAY ),
  60602     JS_CFUNC_MAGIC_DEF("setBigUint64", 2, js_dataview_setValue, JS_CLASS_BIG_UINT64_ARRAY ),
  60603     JS_CFUNC_MAGIC_DEF("setFloat16", 2, js_dataview_setValue, JS_CLASS_FLOAT16_ARRAY ),
  60604     JS_CFUNC_MAGIC_DEF("setFloat32", 2, js_dataview_setValue, JS_CLASS_FLOAT32_ARRAY ),
  60605     JS_CFUNC_MAGIC_DEF("setFloat64", 2, js_dataview_setValue, JS_CLASS_FLOAT64_ARRAY ),
  60606     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "DataView", JS_PROP_CONFIGURABLE ),
  60607 };
  60608 
  60609 /* Atomics */
  60610 #ifdef CONFIG_ATOMICS
  60611 
  60612 typedef enum AtomicsOpEnum {
  60613     ATOMICS_OP_ADD,
  60614     ATOMICS_OP_AND,
  60615     ATOMICS_OP_OR,
  60616     ATOMICS_OP_SUB,
  60617     ATOMICS_OP_XOR,
  60618     ATOMICS_OP_EXCHANGE,
  60619     ATOMICS_OP_COMPARE_EXCHANGE,
  60620     ATOMICS_OP_LOAD,
  60621 } AtomicsOpEnum;
  60622 
  60623 static JSObject *js_atomics_get_buf(JSContext *ctx, 
  60624                                     JSValueConst obj, JSValueConst idx_val,
  60625                                     uint64_t *pidx, int is_waitable)
  60626 {
  60627     JSObject *p;
  60628     JSTypedArray *ta;
  60629     JSArrayBuffer *abuf;
  60630     uint64_t idx;
  60631     BOOL err;
  60632     int old_len;
  60633 
  60634     if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
  60635         goto fail;
  60636     p = JS_VALUE_GET_OBJ(obj);
  60637     if (is_waitable)
  60638         err = (p->class_id != JS_CLASS_INT32_ARRAY &&
  60639                p->class_id != JS_CLASS_BIG_INT64_ARRAY);
  60640     else
  60641         err = !(p->class_id >= JS_CLASS_INT8_ARRAY &&
  60642                 p->class_id <= JS_CLASS_BIG_UINT64_ARRAY);
  60643     if (err) {
  60644     fail:
  60645         JS_ThrowTypeError(ctx, "integer TypedArray expected");
  60646         return NULL;
  60647     }
  60648     ta = p->u.typed_array;
  60649     abuf = ta->buffer->u.array_buffer;
  60650     if (!abuf->shared) {
  60651         if (is_waitable == 2) {
  60652             JS_ThrowTypeError(ctx, "not a SharedArrayBuffer TypedArray");
  60653             return NULL;
  60654         }
  60655         if (abuf->detached) {
  60656             JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
  60657             return NULL;
  60658         }
  60659     }
  60660     old_len = p->u.array.count;
  60661     
  60662     if (JS_ToIndex(ctx, &idx, idx_val)) {
  60663         return NULL;
  60664     }
  60665 
  60666     if (idx >= old_len)
  60667         goto oob;
  60668 
  60669     if (is_waitable != 1) {
  60670         /* RevalidateAtomicAccess() */
  60671         if (typed_array_is_oob(p)) {
  60672             JS_ThrowTypeErrorArrayBufferOOB(ctx);
  60673             return NULL;
  60674         }
  60675         if (idx >= p->u.array.count) {
  60676         oob:
  60677             JS_ThrowRangeError(ctx, "out-of-bound access");
  60678             return NULL;
  60679         }
  60680     }
  60681 
  60682     *pidx = idx;
  60683     return p;
  60684 }
  60685 
  60686 static JSValue js_atomics_op(JSContext *ctx,
  60687                              JSValueConst this_obj,
  60688                              int argc, JSValueConst *argv, int op)
  60689 {
  60690     int size_log2;
  60691     uint64_t v, a, rep_val, idx;
  60692     void *ptr;
  60693     JSValue ret;
  60694     JSObject *p;
  60695     
  60696     p = js_atomics_get_buf(ctx, argv[0], argv[1], &idx, 0);
  60697     if (!p)
  60698         return JS_EXCEPTION;
  60699     size_log2 = typed_array_size_log2(p->class_id);
  60700     rep_val = 0;
  60701     if (op == ATOMICS_OP_LOAD) {
  60702         v = 0;
  60703     } else {
  60704         if (size_log2 == 3) {
  60705             int64_t v64;
  60706             if (JS_ToBigInt64(ctx, &v64, argv[2]))
  60707                 return JS_EXCEPTION;
  60708             v = v64;
  60709             if (op == ATOMICS_OP_COMPARE_EXCHANGE) {
  60710                 if (JS_ToBigInt64(ctx, &v64, argv[3]))
  60711                     return JS_EXCEPTION;
  60712                 rep_val = v64;
  60713             }
  60714         } else {
  60715                 uint32_t v32;
  60716                 if (JS_ToUint32(ctx, &v32, argv[2]))
  60717                     return JS_EXCEPTION;
  60718                 v = v32;
  60719                 if (op == ATOMICS_OP_COMPARE_EXCHANGE) {
  60720                     if (JS_ToUint32(ctx, &v32, argv[3]))
  60721                         return JS_EXCEPTION;
  60722                     rep_val = v32;
  60723                 }
  60724         }
  60725         if (typed_array_is_oob(p))
  60726             return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
  60727         if (idx >= p->u.array.count)
  60728             return JS_ThrowRangeError(ctx, "out-of-bound access");
  60729     }
  60730     ptr = p->u.array.u.uint8_ptr + ((uintptr_t)idx << size_log2);
  60731     
  60732     switch(op | (size_log2 << 3)) {
  60733 
  60734 #define OP(op_name, func_name)                          \
  60735     case ATOMICS_OP_ ## op_name | (0 << 3):             \
  60736        a = func_name((_Atomic(uint8_t) *)ptr, v);       \
  60737        break;                                           \
  60738     case ATOMICS_OP_ ## op_name | (1 << 3):             \
  60739         a = func_name((_Atomic(uint16_t) *)ptr, v);     \
  60740         break;                                          \
  60741     case ATOMICS_OP_ ## op_name | (2 << 3):             \
  60742         a = func_name((_Atomic(uint32_t) *)ptr, v);     \
  60743         break;                                          \
  60744     case ATOMICS_OP_ ## op_name | (3 << 3):             \
  60745         a = func_name((_Atomic(uint64_t) *)ptr, v);     \
  60746         break;
  60747 
  60748         OP(ADD, atomic_fetch_add)
  60749         OP(AND, atomic_fetch_and)
  60750         OP(OR, atomic_fetch_or)
  60751         OP(SUB, atomic_fetch_sub)
  60752         OP(XOR, atomic_fetch_xor)
  60753         OP(EXCHANGE, atomic_exchange)
  60754 #undef OP
  60755 
  60756     case ATOMICS_OP_LOAD | (0 << 3):
  60757         a = atomic_load((_Atomic(uint8_t) *)ptr);
  60758         break;
  60759     case ATOMICS_OP_LOAD | (1 << 3):
  60760         a = atomic_load((_Atomic(uint16_t) *)ptr);
  60761         break;
  60762     case ATOMICS_OP_LOAD | (2 << 3):
  60763         a = atomic_load((_Atomic(uint32_t) *)ptr);
  60764         break;
  60765     case ATOMICS_OP_LOAD | (3 << 3):
  60766         a = atomic_load((_Atomic(uint64_t) *)ptr);
  60767         break;
  60768 
  60769     case ATOMICS_OP_COMPARE_EXCHANGE | (0 << 3):
  60770         {
  60771             uint8_t v1 = v;
  60772             atomic_compare_exchange_strong((_Atomic(uint8_t) *)ptr, &v1, rep_val);
  60773             a = v1;
  60774         }
  60775         break;
  60776     case ATOMICS_OP_COMPARE_EXCHANGE | (1 << 3):
  60777         {
  60778             uint16_t v1 = v;
  60779             atomic_compare_exchange_strong((_Atomic(uint16_t) *)ptr, &v1, rep_val);
  60780             a = v1;
  60781         }
  60782         break;
  60783     case ATOMICS_OP_COMPARE_EXCHANGE | (2 << 3):
  60784         {
  60785             uint32_t v1 = v;
  60786             atomic_compare_exchange_strong((_Atomic(uint32_t) *)ptr, &v1, rep_val);
  60787             a = v1;
  60788         }
  60789         break;
  60790     case ATOMICS_OP_COMPARE_EXCHANGE | (3 << 3):
  60791         {
  60792             uint64_t v1 = v;
  60793             atomic_compare_exchange_strong((_Atomic(uint64_t) *)ptr, &v1, rep_val);
  60794             a = v1;
  60795         }
  60796         break;
  60797     default:
  60798         abort();
  60799     }
  60800 
  60801     switch(p->class_id) {
  60802     case JS_CLASS_INT8_ARRAY:
  60803         a = (int8_t)a;
  60804         goto done;
  60805     case JS_CLASS_UINT8_ARRAY:
  60806         a = (uint8_t)a;
  60807         goto done;
  60808     case JS_CLASS_INT16_ARRAY:
  60809         a = (int16_t)a;
  60810         goto done;
  60811     case JS_CLASS_UINT16_ARRAY:
  60812         a = (uint16_t)a;
  60813         goto done;
  60814     case JS_CLASS_INT32_ARRAY:
  60815     done:
  60816         ret = JS_NewInt32(ctx, a);
  60817         break;
  60818     case JS_CLASS_UINT32_ARRAY:
  60819         ret = JS_NewUint32(ctx, a);
  60820         break;
  60821     case JS_CLASS_BIG_INT64_ARRAY:
  60822         ret = JS_NewBigInt64(ctx, a);
  60823         break;
  60824     case JS_CLASS_BIG_UINT64_ARRAY:
  60825         ret = JS_NewBigUint64(ctx, a);
  60826         break;
  60827     default:
  60828         abort();
  60829     }
  60830     return ret;
  60831 }
  60832 
  60833 static JSValue js_atomics_store(JSContext *ctx,
  60834                                 JSValueConst this_obj,
  60835                                 int argc, JSValueConst *argv)
  60836 {
  60837     int size_log2;
  60838     void *ptr;
  60839     JSValue ret;
  60840     JSObject *p;
  60841     uint64_t idx;
  60842     int64_t v;
  60843 
  60844     p = js_atomics_get_buf(ctx, argv[0], argv[1], &idx, 0);
  60845     if (!p)
  60846         return JS_EXCEPTION;
  60847     size_log2 = typed_array_size_log2(p->class_id);
  60848     if (size_log2 == 3) {
  60849         ret = JS_ToBigIntFree(ctx, JS_DupValue(ctx, argv[2]));
  60850         if (JS_IsException(ret))
  60851             return ret;
  60852         if (JS_ToBigInt64(ctx, &v, ret)) {
  60853             JS_FreeValue(ctx, ret);
  60854             return JS_EXCEPTION;
  60855         }
  60856     } else {
  60857         uint32_t v32;
  60858         /* XXX: spec, would be simpler to return the written value */
  60859         ret = JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[2]));
  60860         if (JS_IsException(ret))
  60861             return ret;
  60862         if (JS_ToUint32(ctx, &v32, ret)) {
  60863             JS_FreeValue(ctx, ret);
  60864             return JS_EXCEPTION;
  60865         }
  60866         v = v32;
  60867     }
  60868     if (typed_array_is_oob(p))
  60869         return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
  60870     if (idx >= p->u.array.count)
  60871         return JS_ThrowRangeError(ctx, "out-of-bound access");
  60872 
  60873     ptr = p->u.array.u.uint8_ptr + ((uintptr_t)idx << size_log2);
  60874     
  60875     switch(size_log2) {
  60876     case 0:
  60877         atomic_store((_Atomic(uint8_t) *)ptr, v);
  60878         break;
  60879     case 1:
  60880         atomic_store((_Atomic(uint16_t) *)ptr, v);
  60881         break;
  60882     case 2:
  60883         atomic_store((_Atomic(uint32_t) *)ptr, v);
  60884         break;
  60885     case 3:
  60886         atomic_store((_Atomic(uint64_t) *)ptr, v);
  60887         break;
  60888     default:
  60889         abort();
  60890     }
  60891     return ret;
  60892 }
  60893 
  60894 static JSValue js_atomics_isLockFree(JSContext *ctx,
  60895                                      JSValueConst this_obj,
  60896                                      int argc, JSValueConst *argv)
  60897 {
  60898     int v, ret;
  60899     if (JS_ToInt32Sat(ctx, &v, argv[0]))
  60900         return JS_EXCEPTION;
  60901     ret = (v == 1 || v == 2 || v == 4 || v == 8);
  60902     return JS_NewBool(ctx, ret);
  60903 }
  60904 
  60905 typedef struct JSAtomicsWaiter {
  60906     struct list_head link;
  60907     BOOL linked;
  60908     pthread_cond_t cond;
  60909     int32_t *ptr;
  60910 } JSAtomicsWaiter;
  60911 
  60912 static pthread_mutex_t js_atomics_mutex = PTHREAD_MUTEX_INITIALIZER;
  60913 static struct list_head js_atomics_waiter_list =
  60914     LIST_HEAD_INIT(js_atomics_waiter_list);
  60915 
  60916 #if defined(__aarch64__)
  60917 static inline void cpu_pause(void)
  60918 {
  60919     asm volatile("yield" ::: "memory");
  60920 }
  60921 #elif defined(__x86_64) || defined(__i386__)
  60922 static inline void cpu_pause(void)
  60923 {
  60924     asm volatile("pause" ::: "memory");
  60925 }
  60926 #else
  60927 static inline void cpu_pause(void)
  60928 {
  60929 }
  60930 #endif
  60931 
  60932 // no-op: Atomics.pause() is not allowed to block or yield to another
  60933 // thread, only to hint the CPU that it should back off for a bit;
  60934 // the amount of work we do here is a good enough substitute
  60935 static JSValue js_atomics_pause(JSContext *ctx, JSValueConst this_obj,
  60936                                 int argc, JSValueConst *argv)
  60937 {
  60938     double d;
  60939 
  60940     if (argc > 0) {
  60941         switch (JS_VALUE_GET_NORM_TAG(argv[0])) {
  60942         case JS_TAG_FLOAT64: // accepted if and only if fraction == 0.0
  60943             d = JS_VALUE_GET_FLOAT64(argv[0]);
  60944             if (isfinite(d))
  60945                 if (0 == modf(d, &d))
  60946                     break;
  60947             // fallthru
  60948         default:
  60949             return JS_ThrowTypeError(ctx, "not an integral number");
  60950         case JS_TAG_UNDEFINED:
  60951         case JS_TAG_INT:
  60952             break;
  60953         }
  60954     }
  60955     cpu_pause();
  60956     return JS_UNDEFINED;
  60957 }
  60958 
  60959 static JSValue js_atomics_wait(JSContext *ctx,
  60960                                JSValueConst this_obj,
  60961                                int argc, JSValueConst *argv)
  60962 {
  60963     JSObject *p;
  60964     int64_t v;
  60965     int32_t v32;
  60966     uint64_t idx;
  60967     void *ptr;
  60968     int64_t timeout;
  60969     struct timespec ts;
  60970     JSAtomicsWaiter waiter_s, *waiter;
  60971     int ret, size_log2, res;
  60972     double d;
  60973 
  60974     p = js_atomics_get_buf(ctx, argv[0], argv[1], &idx, 2);
  60975     if (!p)
  60976         return JS_EXCEPTION;
  60977     size_log2 = typed_array_size_log2(p->class_id);
  60978     ptr = p->u.array.u.uint8_ptr + ((uintptr_t)idx << size_log2);
  60979     
  60980     /* 'argv[0]' is a SharedArrayBuffer so it cannot be detached nor reduced */
  60981     if (size_log2 == 3) {
  60982         if (JS_ToBigInt64(ctx, &v, argv[2]))
  60983             return JS_EXCEPTION;
  60984     } else {
  60985         if (JS_ToInt32(ctx, &v32, argv[2]))
  60986             return JS_EXCEPTION;
  60987         v = v32;
  60988     }
  60989     if (JS_ToFloat64(ctx, &d, argv[3]))
  60990         return JS_EXCEPTION;
  60991     /* must use INT64_MAX + 1 because INT64_MAX cannot be exactly represented as a double */
  60992     if (isnan(d) || d >= 0x1p63)
  60993         timeout = INT64_MAX;
  60994     else if (d < 0)
  60995         timeout = 0;
  60996     else
  60997         timeout = (int64_t)d;
  60998     if (!ctx->rt->can_block)
  60999         return JS_ThrowTypeError(ctx, "cannot block in this thread");
  61000 
  61001     /* XXX: inefficient if large number of waiters, should hash on
  61002        'ptr' value */
  61003     /* XXX: use Linux futexes when available ? */
  61004     pthread_mutex_lock(&js_atomics_mutex);
  61005     if (size_log2 == 3) {
  61006         res = *(int64_t *)ptr != v;
  61007     } else {
  61008         res = *(int32_t *)ptr != v;
  61009     }
  61010     if (res) {
  61011         pthread_mutex_unlock(&js_atomics_mutex);
  61012         return JS_AtomToString(ctx, JS_ATOM_not_equal);
  61013     }
  61014 
  61015     waiter = &waiter_s;
  61016     waiter->ptr = ptr;
  61017     pthread_cond_init(&waiter->cond, NULL);
  61018     waiter->linked = TRUE;
  61019     list_add_tail(&waiter->link, &js_atomics_waiter_list);
  61020 
  61021     if (timeout == INT64_MAX) {
  61022         pthread_cond_wait(&waiter->cond, &js_atomics_mutex);
  61023         ret = 0;
  61024     } else {
  61025         /* XXX: use clock monotonic */
  61026         clock_gettime(CLOCK_REALTIME, &ts);
  61027         ts.tv_sec += timeout / 1000;
  61028         ts.tv_nsec += (timeout % 1000) * 1000000;
  61029         if (ts.tv_nsec >= 1000000000) {
  61030             ts.tv_nsec -= 1000000000;
  61031             ts.tv_sec++;
  61032         }
  61033         ret = pthread_cond_timedwait(&waiter->cond, &js_atomics_mutex,
  61034                                      &ts);
  61035     }
  61036     if (waiter->linked)
  61037         list_del(&waiter->link);
  61038     pthread_mutex_unlock(&js_atomics_mutex);
  61039     pthread_cond_destroy(&waiter->cond);
  61040     if (ret == ETIMEDOUT) {
  61041         return JS_AtomToString(ctx, JS_ATOM_timed_out);
  61042     } else {
  61043         return JS_AtomToString(ctx, JS_ATOM_ok);
  61044     }
  61045 }
  61046 
  61047 static JSValue js_atomics_notify(JSContext *ctx,
  61048                                  JSValueConst this_obj,
  61049                                  int argc, JSValueConst *argv)
  61050 {
  61051     struct list_head *el, *el1, waiter_list;
  61052     int32_t count, n;
  61053     uint64_t idx;
  61054     int size_log2;
  61055     void *ptr;
  61056     JSAtomicsWaiter *waiter;
  61057     JSArrayBuffer *abuf;
  61058     JSObject *p;
  61059     
  61060     p = js_atomics_get_buf(ctx, argv[0], argv[1], &idx, 1);
  61061     if (!p)
  61062         return JS_EXCEPTION;
  61063     size_log2 = typed_array_size_log2(p->class_id);
  61064     
  61065     if (JS_IsUndefined(argv[2])) {
  61066         count = INT32_MAX;
  61067     } else {
  61068         if (JS_ToInt32Clamp(ctx, &count, argv[2], 0, INT32_MAX, 0))
  61069             return JS_EXCEPTION;
  61070     }
  61071 
  61072     n = 0;
  61073     abuf = p->u.typed_array->buffer->u.array_buffer;
  61074     if (abuf->shared && count > 0) {
  61075         /* 'argv[0]' is a SharedArrayBuffer so it cannot be detached nor reduced */
  61076         ptr = p->u.array.u.uint8_ptr + ((uintptr_t)idx << size_log2);
  61077         pthread_mutex_lock(&js_atomics_mutex);
  61078         init_list_head(&waiter_list);
  61079         list_for_each_safe(el, el1, &js_atomics_waiter_list) {
  61080             waiter = list_entry(el, JSAtomicsWaiter, link);
  61081             if (waiter->ptr == ptr) {
  61082                 list_del(&waiter->link);
  61083                 waiter->linked = FALSE;
  61084                 list_add_tail(&waiter->link, &waiter_list);
  61085                 n++;
  61086                 if (n >= count)
  61087                     break;
  61088             }
  61089         }
  61090         list_for_each(el, &waiter_list) {
  61091             waiter = list_entry(el, JSAtomicsWaiter, link);
  61092             pthread_cond_signal(&waiter->cond);
  61093         }
  61094         pthread_mutex_unlock(&js_atomics_mutex);
  61095     }
  61096     return JS_NewInt32(ctx, n);
  61097 }
  61098 
  61099 static const JSCFunctionListEntry js_atomics_funcs[] = {
  61100     JS_CFUNC_MAGIC_DEF("add", 3, js_atomics_op, ATOMICS_OP_ADD ),
  61101     JS_CFUNC_MAGIC_DEF("and", 3, js_atomics_op, ATOMICS_OP_AND ),
  61102     JS_CFUNC_MAGIC_DEF("or", 3, js_atomics_op, ATOMICS_OP_OR ),
  61103     JS_CFUNC_MAGIC_DEF("sub", 3, js_atomics_op, ATOMICS_OP_SUB ),
  61104     JS_CFUNC_MAGIC_DEF("xor", 3, js_atomics_op, ATOMICS_OP_XOR ),
  61105     JS_CFUNC_MAGIC_DEF("exchange", 3, js_atomics_op, ATOMICS_OP_EXCHANGE ),
  61106     JS_CFUNC_MAGIC_DEF("compareExchange", 4, js_atomics_op, ATOMICS_OP_COMPARE_EXCHANGE ),
  61107     JS_CFUNC_MAGIC_DEF("load", 2, js_atomics_op, ATOMICS_OP_LOAD ),
  61108     JS_CFUNC_DEF("store", 3, js_atomics_store ),
  61109     JS_CFUNC_DEF("isLockFree", 1, js_atomics_isLockFree ),
  61110     JS_CFUNC_DEF("pause", 0, js_atomics_pause ),
  61111     JS_CFUNC_DEF("wait", 4, js_atomics_wait ),
  61112     JS_CFUNC_DEF("notify", 3, js_atomics_notify ),
  61113     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Atomics", JS_PROP_CONFIGURABLE ),
  61114 };
  61115 
  61116 static const JSCFunctionListEntry js_atomics_obj[] = {
  61117     JS_OBJECT_DEF("Atomics", js_atomics_funcs, countof(js_atomics_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
  61118 };
  61119 
  61120 static int JS_AddIntrinsicAtomics(JSContext *ctx)
  61121 {
  61122     /* add Atomics as autoinit object */
  61123     return JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_atomics_obj, countof(js_atomics_obj));
  61124 }
  61125 
  61126 #endif /* CONFIG_ATOMICS */
  61127 
  61128 int JS_AddIntrinsicTypedArrays(JSContext *ctx)
  61129 {
  61130     JSValue typed_array_base_func, typed_array_base_proto, obj;
  61131     int i, ret;
  61132 
  61133     obj = JS_NewCConstructor(ctx, JS_CLASS_ARRAY_BUFFER, "ArrayBuffer",
  61134                                     js_array_buffer_constructor, 1, JS_CFUNC_constructor, 0,
  61135                                     JS_UNDEFINED,
  61136                                     js_array_buffer_funcs, countof(js_array_buffer_funcs),
  61137                                     js_array_buffer_proto_funcs, countof(js_array_buffer_proto_funcs),
  61138                                     0);
  61139     if (JS_IsException(obj))
  61140         return -1;
  61141     JS_FreeValue(ctx, obj);
  61142 
  61143     obj = JS_NewCConstructor(ctx, JS_CLASS_SHARED_ARRAY_BUFFER, "SharedArrayBuffer",
  61144                                     js_shared_array_buffer_constructor, 1, JS_CFUNC_constructor, 0,
  61145                                     JS_UNDEFINED,
  61146                                     js_shared_array_buffer_funcs, countof(js_shared_array_buffer_funcs),
  61147                                     js_shared_array_buffer_proto_funcs, countof(js_shared_array_buffer_proto_funcs),
  61148                                     0);
  61149     if (JS_IsException(obj))
  61150         return -1;
  61151     JS_FreeValue(ctx, obj);
  61152 
  61153 
  61154     typed_array_base_func =
  61155         JS_NewCConstructor(ctx, -1, "TypedArray",
  61156                                   js_typed_array_base_constructor, 0, JS_CFUNC_constructor_or_func, 0,
  61157                                   JS_UNDEFINED,
  61158                                   js_typed_array_base_funcs, countof(js_typed_array_base_funcs),
  61159                                   js_typed_array_base_proto_funcs, countof(js_typed_array_base_proto_funcs),
  61160                                   JS_NEW_CTOR_NO_GLOBAL);
  61161     if (JS_IsException(typed_array_base_func))
  61162         return -1;
  61163 
  61164     /* TypedArray.prototype.toString must be the same object as Array.prototype.toString */
  61165     obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_toString);
  61166     if (JS_IsException(obj))
  61167         goto fail;
  61168     /* XXX: should use alias method in JSCFunctionListEntry */ //@@@
  61169     typed_array_base_proto = JS_GetProperty(ctx, typed_array_base_func, JS_ATOM_prototype);
  61170     if (JS_IsException(typed_array_base_proto))
  61171         goto fail;
  61172     ret = JS_DefinePropertyValue(ctx, typed_array_base_proto, JS_ATOM_toString, obj,
  61173                                  JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
  61174     JS_FreeValue(ctx, typed_array_base_proto);
  61175     if (ret < 0)
  61176         goto fail;
  61177     
  61178     /* Used to squelch a -Wcast-function-type warning. */
  61179     JSCFunctionType ft = { .generic_magic = js_typed_array_constructor };
  61180     for(i = JS_CLASS_UINT8C_ARRAY; i < JS_CLASS_UINT8C_ARRAY + JS_TYPED_ARRAY_COUNT; i++) {
  61181         char buf[ATOM_GET_STR_BUF_SIZE];
  61182         const char *name;
  61183             
  61184         name = JS_AtomGetStr(ctx, buf, sizeof(buf),
  61185                              JS_ATOM_Uint8ClampedArray + i - JS_CLASS_UINT8C_ARRAY);
  61186         if (i == JS_CLASS_UINT8_ARRAY) {
  61187             obj = JS_NewCConstructor(ctx, i, name,
  61188                                      ft.generic, 3, JS_CFUNC_constructor_magic, i,
  61189                                      typed_array_base_func,
  61190                                      js_uint8array_funcs, countof(js_uint8array_funcs),
  61191                                      js_uint8array_proto_funcs, countof(js_uint8array_proto_funcs),
  61192                                      0);
  61193         } else {
  61194             const JSCFunctionListEntry *bpe = js_typed_array_funcs + typed_array_size_log2(i);
  61195             obj = JS_NewCConstructor(ctx, i, name,
  61196                                      ft.generic, 3, JS_CFUNC_constructor_magic, i,
  61197                                      typed_array_base_func,
  61198                                      bpe, 1,
  61199                                      bpe, 1,
  61200                                      0);
  61201         }
  61202         if (JS_IsException(obj)) {
  61203         fail:
  61204             JS_FreeValue(ctx, typed_array_base_func);
  61205             return -1;
  61206         }
  61207         JS_FreeValue(ctx, obj);
  61208     }
  61209     JS_FreeValue(ctx, typed_array_base_func);
  61210 
  61211     /* DataView */
  61212     obj = JS_NewCConstructor(ctx, JS_CLASS_DATAVIEW, "DataView",
  61213                                     js_dataview_constructor, 1, JS_CFUNC_constructor, 0,
  61214                                     JS_UNDEFINED,
  61215                                     NULL, 0,
  61216                                     js_dataview_proto_funcs, countof(js_dataview_proto_funcs),
  61217                                     0);
  61218     if (JS_IsException(obj))
  61219         return -1;
  61220     JS_FreeValue(ctx, obj);
  61221 
  61222     /* Atomics */
  61223 #ifdef CONFIG_ATOMICS
  61224     if (JS_AddIntrinsicAtomics(ctx))
  61225         return -1;
  61226 #endif
  61227     return 0;
  61228 }
  61229 
  61230 /* WeakRef */
  61231 
  61232 typedef struct JSWeakRefData {
  61233     JSWeakRefHeader weakref_header;
  61234     JSValue target;
  61235 } JSWeakRefData;
  61236 
  61237 static void js_weakref_finalizer(JSRuntime *rt, JSValue val)
  61238 {
  61239     JSWeakRefData *wrd = JS_GetOpaque(val, JS_CLASS_WEAK_REF);
  61240     if (!wrd)
  61241         return;
  61242     js_weakref_free(rt, wrd->target);
  61243     list_del(&wrd->weakref_header.link);
  61244     js_free_rt(rt, wrd);
  61245 }
  61246 
  61247 static void weakref_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh)
  61248 {
  61249     JSWeakRefData *wrd = container_of(wh, JSWeakRefData, weakref_header);
  61250 
  61251     if (!js_weakref_is_live(wrd->target)) {
  61252         js_weakref_free(rt, wrd->target);
  61253         wrd->target = JS_UNDEFINED;
  61254     }
  61255 }
  61256 
  61257 static JSValue js_weakref_constructor(JSContext *ctx, JSValueConst new_target,
  61258                                       int argc, JSValueConst *argv)
  61259 {
  61260     JSValueConst arg;
  61261     JSValue obj;
  61262 
  61263     if (JS_IsUndefined(new_target))
  61264         return JS_ThrowTypeError(ctx, "constructor requires 'new'");
  61265     arg = argv[0];
  61266     if (!js_weakref_is_target(arg))
  61267         return JS_ThrowTypeError(ctx, "invalid target");
  61268     obj = js_create_from_ctor(ctx, new_target, JS_CLASS_WEAK_REF);
  61269     if (JS_IsException(obj))
  61270         return JS_EXCEPTION;
  61271     JSWeakRefData *wrd = js_mallocz(ctx, sizeof(*wrd));
  61272     if (!wrd) {
  61273         JS_FreeValue(ctx, obj);
  61274         return JS_EXCEPTION;
  61275     }
  61276     wrd->target = js_weakref_new(ctx, arg);
  61277     wrd->weakref_header.weakref_type = JS_WEAKREF_TYPE_WEAKREF;
  61278     list_add_tail(&wrd->weakref_header.link, &ctx->rt->weakref_list);
  61279     JS_SetOpaque(obj, wrd);
  61280     return obj;
  61281 }
  61282 
  61283 static JSValue js_weakref_deref(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
  61284 {
  61285     JSWeakRefData *wrd = JS_GetOpaque2(ctx, this_val, JS_CLASS_WEAK_REF);
  61286     if (!wrd)
  61287         return JS_EXCEPTION;
  61288     if (js_weakref_is_live(wrd->target)) 
  61289         return JS_DupValue(ctx, wrd->target);
  61290     else
  61291         return JS_UNDEFINED;
  61292 }
  61293 
  61294 static const JSCFunctionListEntry js_weakref_proto_funcs[] = {
  61295     JS_CFUNC_DEF("deref", 0, js_weakref_deref ),
  61296     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakRef", JS_PROP_CONFIGURABLE ),
  61297 };
  61298 
  61299 static const JSClassShortDef js_weakref_class_def[] = {
  61300     { JS_ATOM_WeakRef, js_weakref_finalizer, NULL }, /* JS_CLASS_WEAK_REF */
  61301 };
  61302 
  61303 typedef struct JSFinRecEntry {
  61304     struct list_head link;
  61305     JSValue target;
  61306     JSValue held_val;
  61307     JSValue token;
  61308 } JSFinRecEntry;
  61309 
  61310 typedef struct JSFinalizationRegistryData {
  61311     JSWeakRefHeader weakref_header;
  61312     struct list_head entries; /* list of JSFinRecEntry.link */
  61313     JSContext *realm;
  61314     JSValue cb;
  61315 } JSFinalizationRegistryData;
  61316 
  61317 static void js_finrec_finalizer(JSRuntime *rt, JSValue val)
  61318 {
  61319     JSFinalizationRegistryData *frd = JS_GetOpaque(val, JS_CLASS_FINALIZATION_REGISTRY);
  61320     if (frd) {
  61321         struct list_head *el, *el1;
  61322         list_for_each_safe(el, el1, &frd->entries) {
  61323             JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link);
  61324             js_weakref_free(rt, fre->target);
  61325             js_weakref_free(rt, fre->token);
  61326             JS_FreeValueRT(rt, fre->held_val);
  61327             js_free_rt(rt, fre);
  61328         }
  61329         JS_FreeValueRT(rt, frd->cb);
  61330         JS_FreeContext(frd->realm);
  61331         list_del(&frd->weakref_header.link);
  61332         js_free_rt(rt, frd);
  61333     }
  61334 }
  61335 
  61336 static void js_finrec_mark(JSRuntime *rt, JSValueConst val,
  61337                            JS_MarkFunc *mark_func)
  61338 {
  61339     JSFinalizationRegistryData *frd = JS_GetOpaque(val, JS_CLASS_FINALIZATION_REGISTRY);
  61340     struct list_head *el;
  61341     if (frd) {
  61342         list_for_each(el, &frd->entries) {
  61343             JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link);
  61344             JS_MarkValue(rt, fre->held_val, mark_func);
  61345         }
  61346         JS_MarkValue(rt, frd->cb, mark_func);
  61347         mark_func(rt, &frd->realm->header);
  61348     }
  61349 }
  61350 
  61351 static JSValue js_finrec_job(JSContext *ctx, int argc, JSValueConst *argv)
  61352 {
  61353     return JS_Call(ctx, argv[0], JS_UNDEFINED, 1, &argv[1]);
  61354 }
  61355 
  61356 static void finrec_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh)
  61357 {
  61358     JSFinalizationRegistryData *frd = container_of(wh, JSFinalizationRegistryData, weakref_header);
  61359     struct list_head *el, *el1;
  61360 
  61361     list_for_each_safe(el, el1, &frd->entries) {
  61362         JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link);
  61363 
  61364         if (!js_weakref_is_live(fre->token)) {
  61365             js_weakref_free(rt, fre->token);
  61366             fre->token = JS_UNDEFINED;
  61367         }
  61368 
  61369         if (!js_weakref_is_live(fre->target)) {
  61370             JSValueConst args[2];
  61371             args[0] = frd->cb;
  61372             args[1] = fre->held_val;
  61373             /* no exception is raised to avoid recursing into the GC */
  61374             JS_EnqueueJob2(frd->realm, js_finrec_job, 2, args, TRUE);
  61375                 
  61376             js_weakref_free(rt, fre->target);
  61377             js_weakref_free(rt, fre->token);
  61378             JS_FreeValueRT(rt, fre->held_val);
  61379             list_del(&fre->link);
  61380             js_free_rt(rt, fre);
  61381         }
  61382     }
  61383 }
  61384 
  61385 static JSValue js_finrec_constructor(JSContext *ctx, JSValueConst new_target,
  61386                                      int argc, JSValueConst *argv)
  61387 {
  61388     JSValueConst cb;
  61389     JSValue obj;
  61390     JSFinalizationRegistryData *frd;
  61391     
  61392     if (JS_IsUndefined(new_target))
  61393         return JS_ThrowTypeError(ctx, "constructor requires 'new'");
  61394     cb = argv[0];
  61395     if (!JS_IsFunction(ctx, cb))
  61396         return JS_ThrowTypeError(ctx, "argument must be a function");
  61397 
  61398     obj = js_create_from_ctor(ctx, new_target, JS_CLASS_FINALIZATION_REGISTRY);
  61399     if (JS_IsException(obj))
  61400         return JS_EXCEPTION;
  61401     frd = js_mallocz(ctx, sizeof(*frd));
  61402     if (!frd) {
  61403         JS_FreeValue(ctx, obj);
  61404         return JS_EXCEPTION;
  61405     }
  61406     frd->weakref_header.weakref_type = JS_WEAKREF_TYPE_FINREC;
  61407     list_add_tail(&frd->weakref_header.link, &ctx->rt->weakref_list);
  61408     init_list_head(&frd->entries);
  61409     frd->realm = JS_DupContext(ctx);
  61410     frd->cb = JS_DupValue(ctx, cb);
  61411     JS_SetOpaque(obj, frd);
  61412     return obj;
  61413 }
  61414 
  61415 static JSValue js_finrec_register(JSContext *ctx, JSValueConst this_val,
  61416                                   int argc, JSValueConst *argv)
  61417 {
  61418     JSValueConst target, held_val, token;
  61419     JSFinalizationRegistryData *frd;
  61420     JSFinRecEntry *fre;
  61421 
  61422     frd = JS_GetOpaque2(ctx, this_val, JS_CLASS_FINALIZATION_REGISTRY);
  61423     if (!frd)
  61424         return JS_EXCEPTION;
  61425     target = argv[0];
  61426     held_val = argv[1];
  61427     token = argc > 2 ? argv[2] : JS_UNDEFINED;
  61428 
  61429     if (!js_weakref_is_target(target))
  61430         return JS_ThrowTypeError(ctx, "invalid target");
  61431     if (js_same_value(ctx, target, held_val))
  61432         return JS_ThrowTypeError(ctx, "held value cannot be the target");
  61433     if (!JS_IsUndefined(token) && !js_weakref_is_target(token))
  61434         return JS_ThrowTypeError(ctx, "invalid unregister token");
  61435     fre = js_malloc(ctx, sizeof(*fre));
  61436     if (!fre)
  61437         return JS_EXCEPTION;
  61438     fre->target = js_weakref_new(ctx, target);
  61439     fre->held_val = JS_DupValue(ctx, held_val);
  61440     fre->token = js_weakref_new(ctx, token);
  61441     list_add_tail(&fre->link, &frd->entries);
  61442     return JS_UNDEFINED;
  61443 }
  61444 
  61445 static JSValue js_finrec_unregister(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
  61446 {
  61447     JSFinalizationRegistryData *frd = JS_GetOpaque2(ctx, this_val, JS_CLASS_FINALIZATION_REGISTRY);
  61448     JSValueConst token;
  61449     BOOL removed;
  61450     struct list_head *el, *el1;
  61451 
  61452     if (!frd)
  61453         return JS_EXCEPTION;
  61454     token = argv[0];
  61455     if (!js_weakref_is_target(token))
  61456         return JS_ThrowTypeError(ctx, "invalid unregister token");
  61457 
  61458     removed = FALSE;
  61459     list_for_each_safe(el, el1, &frd->entries) {
  61460         JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link);
  61461         if (js_weakref_is_live(fre->token) && js_same_value(ctx, fre->token, token)) {
  61462             js_weakref_free(ctx->rt, fre->target);
  61463             js_weakref_free(ctx->rt, fre->token);
  61464             JS_FreeValue(ctx, fre->held_val);
  61465             list_del(&fre->link);
  61466             js_free(ctx, fre);
  61467             removed = TRUE;
  61468         }
  61469     }
  61470     return JS_NewBool(ctx, removed);
  61471 }
  61472 
  61473 static const JSCFunctionListEntry js_finrec_proto_funcs[] = {
  61474     JS_CFUNC_DEF("register", 2, js_finrec_register ),
  61475     JS_CFUNC_DEF("unregister", 1, js_finrec_unregister ),
  61476     JS_PROP_STRING_DEF("[Symbol.toStringTag]", "FinalizationRegistry", JS_PROP_CONFIGURABLE ),
  61477 };
  61478 
  61479 static const JSClassShortDef js_finrec_class_def[] = {
  61480     { JS_ATOM_FinalizationRegistry, js_finrec_finalizer, js_finrec_mark }, /* JS_CLASS_FINALIZATION_REGISTRY */
  61481 };
  61482 
  61483 int JS_AddIntrinsicWeakRef(JSContext *ctx)
  61484 {
  61485     JSRuntime *rt = ctx->rt;
  61486     JSValue obj;
  61487     
  61488     /* WeakRef */
  61489     if (!JS_IsRegisteredClass(rt, JS_CLASS_WEAK_REF)) {
  61490         if (init_class_range(rt, js_weakref_class_def, JS_CLASS_WEAK_REF,
  61491                              countof(js_weakref_class_def)))
  61492             return -1;
  61493     }
  61494     obj = JS_NewCConstructor(ctx, JS_CLASS_WEAK_REF, "WeakRef",
  61495                              js_weakref_constructor, 1, JS_CFUNC_constructor_or_func, 0,
  61496                              JS_UNDEFINED,
  61497                              NULL, 0,
  61498                              js_weakref_proto_funcs, countof(js_weakref_proto_funcs),
  61499                              0);
  61500     if (JS_IsException(obj))
  61501         return -1;
  61502     JS_FreeValue(ctx, obj);
  61503 
  61504     /* FinalizationRegistry */
  61505     if (!JS_IsRegisteredClass(rt, JS_CLASS_FINALIZATION_REGISTRY)) {
  61506         if (init_class_range(rt, js_finrec_class_def, JS_CLASS_FINALIZATION_REGISTRY,
  61507                              countof(js_finrec_class_def)))
  61508             return -1;
  61509     }
  61510 
  61511     obj = JS_NewCConstructor(ctx, JS_CLASS_FINALIZATION_REGISTRY, "FinalizationRegistry",
  61512                              js_finrec_constructor, 1, JS_CFUNC_constructor_or_func, 0,
  61513                              JS_UNDEFINED,
  61514                              NULL, 0,
  61515                              js_finrec_proto_funcs, countof(js_finrec_proto_funcs),
  61516                              0);
  61517     if (JS_IsException(obj))
  61518         return -1;
  61519     JS_FreeValue(ctx, obj);
  61520     return 0;
  61521 }