Coverage Report

Created: 2025-07-23 07:12

/src/quickjs/quickjs.c
Line
Count
Source (jump to first uncovered line)
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
16
#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
6.90k
#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
111
/* test the GC by forcing it before each object allocation */
112
//#define FORCE_GC_AT_MALLOC
113
114
#ifdef CONFIG_ATOMICS
115
#include <pthread.h>
116
#include <stdatomic.h>
117
#include <errno.h>
118
#endif
119
120
enum {
121
    /* classid tag        */    /* union usage   | properties */
122
    JS_CLASS_OBJECT = 1,        /* must be first */
123
    JS_CLASS_ARRAY,             /* u.array       | length */
124
    JS_CLASS_ERROR,
125
    JS_CLASS_NUMBER,            /* u.object_data */
126
    JS_CLASS_STRING,            /* u.object_data */
127
    JS_CLASS_BOOLEAN,           /* u.object_data */
128
    JS_CLASS_SYMBOL,            /* u.object_data */
129
    JS_CLASS_ARGUMENTS,         /* u.array       | length */
130
    JS_CLASS_MAPPED_ARGUMENTS,  /*               | length */
131
    JS_CLASS_DATE,              /* u.object_data */
132
    JS_CLASS_MODULE_NS,
133
    JS_CLASS_C_FUNCTION,        /* u.cfunc */
134
    JS_CLASS_BYTECODE_FUNCTION, /* u.func */
135
    JS_CLASS_BOUND_FUNCTION,    /* u.bound_function */
136
    JS_CLASS_C_FUNCTION_DATA,   /* u.c_function_data_record */
137
    JS_CLASS_GENERATOR_FUNCTION, /* u.func */
138
    JS_CLASS_FOR_IN_ITERATOR,   /* u.for_in_iterator */
139
    JS_CLASS_REGEXP,            /* u.regexp */
140
    JS_CLASS_ARRAY_BUFFER,      /* u.array_buffer */
141
    JS_CLASS_SHARED_ARRAY_BUFFER, /* u.array_buffer */
142
    JS_CLASS_UINT8C_ARRAY,      /* u.array (typed_array) */
143
    JS_CLASS_INT8_ARRAY,        /* u.array (typed_array) */
144
    JS_CLASS_UINT8_ARRAY,       /* u.array (typed_array) */
145
    JS_CLASS_INT16_ARRAY,       /* u.array (typed_array) */
146
    JS_CLASS_UINT16_ARRAY,      /* u.array (typed_array) */
147
    JS_CLASS_INT32_ARRAY,       /* u.array (typed_array) */
148
    JS_CLASS_UINT32_ARRAY,      /* u.array (typed_array) */
149
    JS_CLASS_BIG_INT64_ARRAY,   /* u.array (typed_array) */
150
    JS_CLASS_BIG_UINT64_ARRAY,  /* u.array (typed_array) */
151
    JS_CLASS_FLOAT16_ARRAY,     /* u.array (typed_array) */
152
    JS_CLASS_FLOAT32_ARRAY,     /* u.array (typed_array) */
153
    JS_CLASS_FLOAT64_ARRAY,     /* u.array (typed_array) */
154
    JS_CLASS_DATAVIEW,          /* u.typed_array */
155
    JS_CLASS_BIG_INT,           /* u.object_data */
156
    JS_CLASS_MAP,               /* u.map_state */
157
    JS_CLASS_SET,               /* u.map_state */
158
    JS_CLASS_WEAKMAP,           /* u.map_state */
159
    JS_CLASS_WEAKSET,           /* u.map_state */
160
    JS_CLASS_MAP_ITERATOR,      /* u.map_iterator_data */
161
    JS_CLASS_SET_ITERATOR,      /* u.map_iterator_data */
162
    JS_CLASS_ARRAY_ITERATOR,    /* u.array_iterator_data */
163
    JS_CLASS_STRING_ITERATOR,   /* u.array_iterator_data */
164
    JS_CLASS_REGEXP_STRING_ITERATOR,   /* u.regexp_string_iterator_data */
165
    JS_CLASS_GENERATOR,         /* u.generator_data */
166
    JS_CLASS_PROXY,             /* u.proxy_data */
167
    JS_CLASS_PROMISE,           /* u.promise_data */
168
    JS_CLASS_PROMISE_RESOLVE_FUNCTION,  /* u.promise_function_data */
169
    JS_CLASS_PROMISE_REJECT_FUNCTION,   /* u.promise_function_data */
170
    JS_CLASS_ASYNC_FUNCTION,            /* u.func */
171
    JS_CLASS_ASYNC_FUNCTION_RESOLVE,    /* u.async_function_data */
172
    JS_CLASS_ASYNC_FUNCTION_REJECT,     /* u.async_function_data */
173
    JS_CLASS_ASYNC_FROM_SYNC_ITERATOR,  /* u.async_from_sync_iterator_data */
174
    JS_CLASS_ASYNC_GENERATOR_FUNCTION,  /* u.func */
175
    JS_CLASS_ASYNC_GENERATOR,   /* u.async_generator_data */
176
    JS_CLASS_WEAK_REF,
177
    JS_CLASS_FINALIZATION_REGISTRY,
178
    
179
    JS_CLASS_INIT_COUNT, /* last entry for predefined classes */
180
};
181
182
/* number of typed array types */
183
26
#define JS_TYPED_ARRAY_COUNT  (JS_CLASS_FLOAT64_ARRAY - JS_CLASS_UINT8C_ARRAY + 1)
184
static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT];
185
48
#define typed_array_size_log2(classid)  (typed_array_size_log2[(classid)- JS_CLASS_UINT8C_ARRAY])
186
187
typedef enum JSErrorEnum {
188
    JS_EVAL_ERROR,
189
    JS_RANGE_ERROR,
190
    JS_REFERENCE_ERROR,
191
    JS_SYNTAX_ERROR,
192
    JS_TYPE_ERROR,
193
    JS_URI_ERROR,
194
    JS_INTERNAL_ERROR,
195
    JS_AGGREGATE_ERROR,
196
197
    JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */
198
} JSErrorEnum;
199
200
/* the variable and scope indexes must fit on 16 bits. The (-1) and
201
   ARG_SCOPE_END values are reserved. */
202
4
#define JS_MAX_LOCAL_VARS 65534
203
5
#define JS_STACK_SIZE_MAX 65534
204
765
#define JS_STRING_LEN_MAX ((1 << 30) - 1)
205
206
/* strings <= this length are not concatenated using ropes. if too
207
   small, the rope memory overhead becomes high. */
208
0
#define JS_STRING_ROPE_SHORT_LEN  512
209
/* specific threshold for initial rope use */
210
0
#define JS_STRING_ROPE_SHORT2_LEN 8192
211
/* rope depth at which we rebalance */
212
0
#define JS_STRING_ROPE_MAX_DEPTH 60
213
214
#define __exception __attribute__((warn_unused_result))
215
216
typedef struct JSShape JSShape;
217
typedef struct JSString JSString;
218
typedef struct JSString JSAtomStruct;
219
typedef struct JSObject JSObject;
220
221
4.15k
#define JS_VALUE_GET_OBJ(v) ((JSObject *)JS_VALUE_GET_PTR(v))
222
2.89k
#define JS_VALUE_GET_STRING(v) ((JSString *)JS_VALUE_GET_PTR(v))
223
0
#define JS_VALUE_GET_STRING_ROPE(v) ((JSStringRope *)JS_VALUE_GET_PTR(v))
224
225
typedef enum {
226
    JS_GC_PHASE_NONE,
227
    JS_GC_PHASE_DECREF,
228
    JS_GC_PHASE_REMOVE_CYCLES,
229
} JSGCPhaseEnum;
230
231
typedef enum OPCodeEnum OPCodeEnum;
232
233
struct JSRuntime {
234
    JSMallocFunctions mf;
235
    JSMallocState malloc_state;
236
    const char *rt_info;
237
238
    int atom_hash_size; /* power of two */
239
    int atom_count;
240
    int atom_size;
241
    int atom_count_resize; /* resize hash table at this count */
242
    uint32_t *atom_hash;
243
    JSAtomStruct **atom_array;
244
    int atom_free_index; /* 0 = none */
245
246
    int class_count;    /* size of class_array */
247
    JSClass *class_array;
248
249
    struct list_head context_list; /* list of JSContext.link */
250
    /* list of JSGCObjectHeader.link. List of allocated GC objects (used
251
       by the garbage collector) */
252
    struct list_head gc_obj_list;
253
    /* list of JSGCObjectHeader.link. Used during JS_FreeValueRT() */
254
    struct list_head gc_zero_ref_count_list;
255
    struct list_head tmp_obj_list; /* used during GC */
256
    JSGCPhaseEnum gc_phase : 8;
257
    size_t malloc_gc_threshold;
258
    struct list_head weakref_list; /* list of JSWeakRefHeader.link */
259
#ifdef DUMP_LEAKS
260
    struct list_head string_list; /* list of JSString.link */
261
#endif
262
    /* stack limitation */
263
    uintptr_t stack_size; /* in bytes, 0 if no limit */
264
    uintptr_t stack_top;
265
    uintptr_t stack_limit; /* lower stack limit */
266
267
    JSValue current_exception;
268
    /* true if the current exception cannot be catched */
269
    BOOL current_exception_is_uncatchable : 8;
270
    /* true if inside an out of memory error, to avoid recursing */
271
    BOOL in_out_of_memory : 8;
272
273
    struct JSStackFrame *current_stack_frame;
274
275
    JSInterruptHandler *interrupt_handler;
276
    void *interrupt_opaque;
277
278
    JSHostPromiseRejectionTracker *host_promise_rejection_tracker;
279
    void *host_promise_rejection_tracker_opaque;
280
281
    struct list_head job_list; /* list of JSJobEntry.link */
282
283
    JSModuleNormalizeFunc *module_normalize_func;
284
    BOOL module_loader_has_attr;
285
    union {
286
        JSModuleLoaderFunc *module_loader_func;
287
        JSModuleLoaderFunc2 *module_loader_func2;
288
    } u;
289
    JSModuleCheckSupportedImportAttributes *module_check_attrs;
290
    void *module_loader_opaque;
291
    /* timestamp for internal use in module evaluation */
292
    int64_t module_async_evaluation_next_timestamp;
293
294
    BOOL can_block : 8; /* TRUE if Atomics.wait can block */
295
    /* used to allocate, free and clone SharedArrayBuffers */
296
    JSSharedArrayBufferFunctions sab_funcs;
297
    /* see JS_SetStripInfo() */
298
    uint8_t strip_flags;
299
    
300
    /* Shape hash table */
301
    int shape_hash_bits;
302
    int shape_hash_size;
303
    int shape_hash_count; /* number of hashed shapes */
304
    JSShape **shape_hash;
305
    void *user_opaque;
306
};
307
308
struct JSClass {
309
    uint32_t class_id; /* 0 means free entry */
310
    JSAtom class_name;
311
    JSClassFinalizer *finalizer;
312
    JSClassGCMark *gc_mark;
313
    JSClassCall *call;
314
    /* pointers for exotic behavior, can be NULL if none are present */
315
    const JSClassExoticMethods *exotic;
316
};
317
318
12
#define JS_MODE_STRICT (1 << 0)
319
3
#define JS_MODE_ASYNC  (1 << 2) /* async function */
320
1
#define JS_MODE_BACKTRACE_BARRIER (1 << 3) /* stop backtrace before this frame */
321
322
typedef struct JSStackFrame {
323
    struct JSStackFrame *prev_frame; /* NULL if first stack frame */
324
    JSValue cur_func; /* current function, JS_UNDEFINED if the frame is detached */
325
    JSValue *arg_buf; /* arguments */
326
    JSValue *var_buf; /* variables */
327
    struct list_head var_ref_list; /* list of JSVarRef.var_ref_link */
328
    const uint8_t *cur_pc; /* only used in bytecode functions : PC of the
329
                        instruction after the call */
330
    int arg_count;
331
    int js_mode; /* not supported for C functions */
332
    /* only used in generators. Current stack pointer value. NULL if
333
       the function is running. */
334
    JSValue *cur_sp;
335
} JSStackFrame;
336
337
typedef enum {
338
    JS_GC_OBJ_TYPE_JS_OBJECT,
339
    JS_GC_OBJ_TYPE_FUNCTION_BYTECODE,
340
    JS_GC_OBJ_TYPE_SHAPE,
341
    JS_GC_OBJ_TYPE_VAR_REF,
342
    JS_GC_OBJ_TYPE_ASYNC_FUNCTION,
343
    JS_GC_OBJ_TYPE_JS_CONTEXT,
344
    JS_GC_OBJ_TYPE_MODULE,
345
} JSGCObjectTypeEnum;
346
347
/* header for GC objects. GC objects are C data structures with a
348
   reference count that can reference other GC objects. JS Objects are
349
   a particular type of GC object. */
350
struct JSGCObjectHeader {
351
    int ref_count; /* must come first, 32-bit */
352
    JSGCObjectTypeEnum gc_obj_type : 4;
353
    uint8_t mark : 4; /* used by the GC */
354
    uint8_t dummy1; /* not used by the GC */
355
    uint16_t dummy2; /* not used by the GC */
356
    struct list_head link;
357
};
358
359
typedef enum {
360
    JS_WEAKREF_TYPE_MAP,
361
    JS_WEAKREF_TYPE_WEAKREF,
362
    JS_WEAKREF_TYPE_FINREC,
363
} JSWeakRefHeaderTypeEnum;
364
365
typedef struct {
366
    struct list_head link;
367
    JSWeakRefHeaderTypeEnum weakref_type;
368
} JSWeakRefHeader;
369
370
typedef struct JSVarRef {
371
    union {
372
        JSGCObjectHeader header; /* must come first */
373
        struct {
374
            int __gc_ref_count; /* corresponds to header.ref_count */
375
            uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
376
            uint8_t is_detached;
377
        };
378
    };
379
    JSValue *pvalue; /* pointer to the value, either on the stack or
380
                        to 'value' */
381
    union {
382
        JSValue value; /* used when is_detached = TRUE */
383
        struct {
384
            struct list_head var_ref_link; /* JSStackFrame.var_ref_list list */
385
            struct JSAsyncFunctionState *async_func; /* != NULL if async stack frame */
386
        }; /* used when is_detached = FALSE */
387
    };
388
} JSVarRef;
389
390
/* bigint */
391
392
#if JS_LIMB_BITS == 32
393
394
typedef int32_t js_slimb_t;
395
typedef uint32_t js_limb_t;
396
typedef int64_t js_sdlimb_t;
397
typedef uint64_t js_dlimb_t;
398
399
#define JS_LIMB_DIGITS 9
400
401
#else
402
403
typedef __int128 int128_t;
404
typedef unsigned __int128 uint128_t;
405
typedef int64_t js_slimb_t;
406
typedef uint64_t js_limb_t;
407
typedef int128_t js_sdlimb_t;
408
typedef uint128_t js_dlimb_t;
409
410
0
#define JS_LIMB_DIGITS 19
411
412
#endif
413
414
typedef struct JSBigInt {
415
    JSRefCountHeader header; /* must come first, 32-bit */
416
    uint32_t len; /* number of limbs, >= 1 */
417
    js_limb_t tab[]; /* two's complement representation, always
418
                        normalized so that 'len' is the minimum
419
                        possible length >= 1 */
420
} JSBigInt;
421
422
/* this bigint structure can hold a 64 bit integer */
423
typedef struct {
424
    js_limb_t big_int_buf[sizeof(JSBigInt) / sizeof(js_limb_t)]; /* for JSBigInt */
425
    /* must come just after */
426
    js_limb_t tab[(64 + JS_LIMB_BITS - 1) / JS_LIMB_BITS];
427
} JSBigIntBuf;
428
    
429
typedef enum {
430
    JS_AUTOINIT_ID_PROTOTYPE,
431
    JS_AUTOINIT_ID_MODULE_NS,
432
    JS_AUTOINIT_ID_PROP,
433
} JSAutoInitIDEnum;
434
435
/* must be large enough to have a negligible runtime cost and small
436
   enough to call the interrupt callback often. */
437
2
#define JS_INTERRUPT_COUNTER_INIT 10000
438
439
struct JSContext {
440
    JSGCObjectHeader header; /* must come first */
441
    JSRuntime *rt;
442
    struct list_head link;
443
444
    uint16_t binary_object_count;
445
    int binary_object_size;
446
447
    JSShape *array_shape;   /* initial shape for Array objects */
448
449
    JSValue *class_proto;
450
    JSValue function_proto;
451
    JSValue function_ctor;
452
    JSValue array_ctor;
453
    JSValue regexp_ctor;
454
    JSValue promise_ctor;
455
    JSValue native_error_proto[JS_NATIVE_ERROR_COUNT];
456
    JSValue iterator_proto;
457
    JSValue async_iterator_proto;
458
    JSValue array_proto_values;
459
    JSValue throw_type_error;
460
    JSValue eval_obj;
461
462
    JSValue global_obj; /* global object */
463
    JSValue global_var_obj; /* contains the global let/const definitions */
464
465
    uint64_t random_state;
466
467
    /* when the counter reaches zero, JSRutime.interrupt_handler is called */
468
    int interrupt_counter;
469
470
    struct list_head loaded_modules; /* list of JSModuleDef.link */
471
472
    /* if NULL, RegExp compilation is not supported */
473
    JSValue (*compile_regexp)(JSContext *ctx, JSValueConst pattern,
474
                              JSValueConst flags);
475
    /* if NULL, eval is not supported */
476
    JSValue (*eval_internal)(JSContext *ctx, JSValueConst this_obj,
477
                             const char *input, size_t input_len,
478
                             const char *filename, int flags, int scope_idx);
479
    void *user_opaque;
480
};
481
482
typedef union JSFloat64Union {
483
    double d;
484
    uint64_t u64;
485
    uint32_t u32[2];
486
} JSFloat64Union;
487
488
enum {
489
    JS_ATOM_TYPE_STRING = 1,
490
    JS_ATOM_TYPE_GLOBAL_SYMBOL,
491
    JS_ATOM_TYPE_SYMBOL,
492
    JS_ATOM_TYPE_PRIVATE,
493
};
494
495
typedef enum {
496
    JS_ATOM_KIND_STRING,
497
    JS_ATOM_KIND_SYMBOL,
498
    JS_ATOM_KIND_PRIVATE,
499
} JSAtomKindEnum;
500
501
3.74k
#define JS_ATOM_HASH_MASK  ((1 << 30) - 1)
502
2
#define JS_ATOM_HASH_PRIVATE JS_ATOM_HASH_MASK
503
504
struct JSString {
505
    JSRefCountHeader header; /* must come first, 32-bit */
506
    uint32_t len : 31;
507
    uint8_t is_wide_char : 1; /* 0 = 8 bits, 1 = 16 bits characters */
508
    /* for JS_ATOM_TYPE_SYMBOL: hash = weakref_count, atom_type = 3,
509
       for JS_ATOM_TYPE_PRIVATE: hash = JS_ATOM_HASH_PRIVATE, atom_type = 3
510
       XXX: could change encoding to have one more bit in hash */
511
    uint32_t hash : 30;
512
    uint8_t atom_type : 2; /* != 0 if atom, JS_ATOM_TYPE_x */
513
    uint32_t hash_next; /* atom_index for JS_ATOM_TYPE_SYMBOL */
514
#ifdef DUMP_LEAKS
515
    struct list_head link; /* string list */
516
#endif
517
    union {
518
        uint8_t str8[0]; /* 8 bit strings will get an extra null terminator */
519
        uint16_t str16[0];
520
    } u;
521
};
522
523
typedef struct JSStringRope {
524
    JSRefCountHeader header; /* must come first, 32-bit */
525
    uint32_t len;
526
    uint8_t is_wide_char; /* 0 = 8 bits, 1 = 16 bits characters */
527
    uint8_t depth; /* max depth of the rope tree */
528
    /* XXX: could reduce memory usage by using a direct pointer with
529
       bit 0 to select rope or string */
530
    JSValue left;
531
    JSValue right; /* might be the empty string */
532
} JSStringRope;
533
534
typedef struct JSClosureVar {
535
    uint8_t is_local : 1;
536
    uint8_t is_arg : 1;
537
    uint8_t is_const : 1;
538
    uint8_t is_lexical : 1;
539
    uint8_t var_kind : 4; /* see JSVarKindEnum */
540
    /* 8 bits available */
541
    uint16_t var_idx; /* is_local = TRUE: index to a normal variable of the
542
                    parent function. otherwise: index to a closure
543
                    variable of the parent function */
544
    JSAtom var_name;
545
} JSClosureVar;
546
547
0
#define ARG_SCOPE_INDEX 1
548
9
#define ARG_SCOPE_END (-2)
549
550
typedef struct JSVarScope {
551
    int parent;  /* index into fd->scopes of the enclosing scope */
552
    int first;   /* index into fd->vars of the last variable in this scope */
553
} JSVarScope;
554
555
typedef enum {
556
    /* XXX: add more variable kinds here instead of using bit fields */
557
    JS_VAR_NORMAL,
558
    JS_VAR_FUNCTION_DECL, /* lexical var with function declaration */
559
    JS_VAR_NEW_FUNCTION_DECL, /* lexical var with async/generator
560
                                 function declaration */
561
    JS_VAR_CATCH,
562
    JS_VAR_FUNCTION_NAME, /* function expression name */
563
    JS_VAR_PRIVATE_FIELD,
564
    JS_VAR_PRIVATE_METHOD,
565
    JS_VAR_PRIVATE_GETTER,
566
    JS_VAR_PRIVATE_SETTER, /* must come after JS_VAR_PRIVATE_GETTER */
567
    JS_VAR_PRIVATE_GETTER_SETTER, /* must come after JS_VAR_PRIVATE_SETTER */
568
} JSVarKindEnum;
569
570
/* XXX: could use a different structure in bytecode functions to save
571
   memory */
572
typedef struct JSVarDef {
573
    JSAtom var_name;
574
    /* index into fd->scopes of this variable lexical scope */
575
    int scope_level;
576
    /* during compilation:
577
        - if scope_level = 0: scope in which the variable is defined
578
        - if scope_level != 0: index into fd->vars of the next
579
          variable in the same or enclosing lexical scope
580
       in a bytecode function:
581
       index into fd->vars of the next
582
       variable in the same or enclosing lexical scope
583
    */
584
    int scope_next;
585
    uint8_t is_const : 1;
586
    uint8_t is_lexical : 1;
587
    uint8_t is_captured : 1;
588
    uint8_t is_static_private : 1; /* only used during private class field parsing */
589
    uint8_t var_kind : 4; /* see JSVarKindEnum */
590
    /* only used during compilation: function pool index for lexical
591
       variables with var_kind =
592
       JS_VAR_FUNCTION_DECL/JS_VAR_NEW_FUNCTION_DECL or scope level of
593
       the definition of the 'var' variables (they have scope_level =
594
       0) */
595
    int func_pool_idx : 24; /* only used during compilation : index in
596
                               the constant pool for hoisted function
597
                               definition */
598
} JSVarDef;
599
600
/* for the encoding of the pc2line table */
601
37
#define PC2LINE_BASE     (-1)
602
38
#define PC2LINE_RANGE    5
603
19
#define PC2LINE_OP_FIRST 1
604
9
#define PC2LINE_DIFF_PC_MAX ((255 - PC2LINE_OP_FIRST) / PC2LINE_RANGE)
605
606
typedef enum JSFunctionKindEnum {
607
    JS_FUNC_NORMAL = 0,
608
    JS_FUNC_GENERATOR = (1 << 0),
609
    JS_FUNC_ASYNC = (1 << 1),
610
    JS_FUNC_ASYNC_GENERATOR = (JS_FUNC_GENERATOR | JS_FUNC_ASYNC),
611
} JSFunctionKindEnum;
612
613
typedef struct JSFunctionBytecode {
614
    JSGCObjectHeader header; /* must come first */
615
    uint8_t js_mode;
616
    uint8_t has_prototype : 1; /* true if a prototype field is necessary */
617
    uint8_t has_simple_parameter_list : 1;
618
    uint8_t is_derived_class_constructor : 1;
619
    /* true if home_object needs to be initialized */
620
    uint8_t need_home_object : 1;
621
    uint8_t func_kind : 2;
622
    uint8_t new_target_allowed : 1;
623
    uint8_t super_call_allowed : 1;
624
    uint8_t super_allowed : 1;
625
    uint8_t arguments_allowed : 1;
626
    uint8_t has_debug : 1;
627
    uint8_t read_only_bytecode : 1;
628
    uint8_t is_direct_or_indirect_eval : 1; /* used by JS_GetScriptOrModuleName() */
629
    /* XXX: 10 bits available */
630
    uint8_t *byte_code_buf; /* (self pointer) */
631
    int byte_code_len;
632
    JSAtom func_name;
633
    JSVarDef *vardefs; /* arguments + local variables (arg_count + var_count) (self pointer) */
634
    JSClosureVar *closure_var; /* list of variables in the closure (self pointer) */
635
    uint16_t arg_count;
636
    uint16_t var_count;
637
    uint16_t defined_arg_count; /* for length function property */
638
    uint16_t stack_size; /* maximum stack size */
639
    JSContext *realm; /* function realm */
640
    JSValue *cpool; /* constant pool (self pointer) */
641
    int cpool_count;
642
    int closure_var_count;
643
    struct {
644
        /* debug info, move to separate structure to save memory? */
645
        JSAtom filename;
646
        int source_len; 
647
        int pc2line_len;
648
        uint8_t *pc2line_buf;
649
        char *source;
650
    } debug;
651
} JSFunctionBytecode;
652
653
typedef struct JSBoundFunction {
654
    JSValue func_obj;
655
    JSValue this_val;
656
    int argc;
657
    JSValue argv[0];
658
} JSBoundFunction;
659
660
typedef enum JSIteratorKindEnum {
661
    JS_ITERATOR_KIND_KEY,
662
    JS_ITERATOR_KIND_VALUE,
663
    JS_ITERATOR_KIND_KEY_AND_VALUE,
664
} JSIteratorKindEnum;
665
666
typedef struct JSForInIterator {
667
    JSValue obj;
668
    uint32_t idx;
669
    uint32_t atom_count;
670
    uint8_t in_prototype_chain;
671
    uint8_t is_array;
672
    JSPropertyEnum *tab_atom; /* is_array = FALSE */
673
} JSForInIterator;
674
675
typedef struct JSRegExp {
676
    JSString *pattern;
677
    JSString *bytecode; /* also contains the flags */
678
} JSRegExp;
679
680
typedef struct JSProxyData {
681
    JSValue target;
682
    JSValue handler;
683
    uint8_t is_func;
684
    uint8_t is_revoked;
685
} JSProxyData;
686
687
typedef struct JSArrayBuffer {
688
    int byte_length; /* 0 if detached */
689
    uint8_t detached;
690
    uint8_t shared; /* if shared, the array buffer cannot be detached */
691
    uint8_t *data; /* NULL if detached */
692
    struct list_head array_list;
693
    void *opaque;
694
    JSFreeArrayBufferDataFunc *free_func;
695
} JSArrayBuffer;
696
697
typedef struct JSTypedArray {
698
    struct list_head link; /* link to arraybuffer */
699
    JSObject *obj; /* back pointer to the TypedArray/DataView object */
700
    JSObject *buffer; /* based array buffer */
701
    uint32_t offset; /* offset in the array buffer */
702
    uint32_t length; /* length in the array buffer */
703
} JSTypedArray;
704
705
typedef struct JSAsyncFunctionState {
706
    JSGCObjectHeader header;
707
    JSValue this_val; /* 'this' argument */
708
    int argc; /* number of function arguments */
709
    BOOL throw_flag; /* used to throw an exception in JS_CallInternal() */
710
    BOOL is_completed; /* TRUE if the function has returned. The stack
711
                          frame is no longer valid */
712
    JSValue resolving_funcs[2]; /* only used in JS async functions */
713
    JSStackFrame frame;
714
} JSAsyncFunctionState;
715
716
typedef enum {
717
   /* binary operators */
718
   JS_OVOP_ADD,
719
   JS_OVOP_SUB,
720
   JS_OVOP_MUL,
721
   JS_OVOP_DIV,
722
   JS_OVOP_MOD,
723
   JS_OVOP_POW,
724
   JS_OVOP_OR,
725
   JS_OVOP_AND,
726
   JS_OVOP_XOR,
727
   JS_OVOP_SHL,
728
   JS_OVOP_SAR,
729
   JS_OVOP_SHR,
730
   JS_OVOP_EQ,
731
   JS_OVOP_LESS,
732
733
   JS_OVOP_BINARY_COUNT,
734
   /* unary operators */
735
   JS_OVOP_POS = JS_OVOP_BINARY_COUNT,
736
   JS_OVOP_NEG,
737
   JS_OVOP_INC,
738
   JS_OVOP_DEC,
739
   JS_OVOP_NOT,
740
741
   JS_OVOP_COUNT,
742
} JSOverloadableOperatorEnum;
743
744
typedef struct {
745
    uint32_t operator_index;
746
    JSObject *ops[JS_OVOP_BINARY_COUNT]; /* self operators */
747
} JSBinaryOperatorDefEntry;
748
749
typedef struct {
750
    int count;
751
    JSBinaryOperatorDefEntry *tab;
752
} JSBinaryOperatorDef;
753
754
typedef struct {
755
    uint32_t operator_counter;
756
    BOOL is_primitive; /* OperatorSet for a primitive type */
757
    /* NULL if no operator is defined */
758
    JSObject *self_ops[JS_OVOP_COUNT]; /* self operators */
759
    JSBinaryOperatorDef left;
760
    JSBinaryOperatorDef right;
761
} JSOperatorSetData;
762
763
typedef struct JSReqModuleEntry {
764
    JSAtom module_name;
765
    JSModuleDef *module; /* used using resolution */
766
    JSValue attributes; /* JS_UNDEFINED or an object contains the attributes as key/value */
767
} JSReqModuleEntry;
768
769
typedef enum JSExportTypeEnum {
770
    JS_EXPORT_TYPE_LOCAL,
771
    JS_EXPORT_TYPE_INDIRECT,
772
} JSExportTypeEnum;
773
774
typedef struct JSExportEntry {
775
    union {
776
        struct {
777
            int var_idx; /* closure variable index */
778
            JSVarRef *var_ref; /* if != NULL, reference to the variable */
779
        } local; /* for local export */
780
        int req_module_idx; /* module for indirect export */
781
    } u;
782
    JSExportTypeEnum export_type;
783
    JSAtom local_name; /* '*' if export ns from. not used for local
784
                          export after compilation */
785
    JSAtom export_name; /* exported variable name */
786
} JSExportEntry;
787
788
typedef struct JSStarExportEntry {
789
    int req_module_idx; /* in req_module_entries */
790
} JSStarExportEntry;
791
792
typedef struct JSImportEntry {
793
    int var_idx; /* closure variable index */
794
    BOOL is_star; /* import_name = '*' is a valid import name, so need a flag */
795
    JSAtom import_name;
796
    int req_module_idx; /* in req_module_entries */
797
} JSImportEntry;
798
799
typedef enum {
800
    JS_MODULE_STATUS_UNLINKED,
801
    JS_MODULE_STATUS_LINKING,
802
    JS_MODULE_STATUS_LINKED,
803
    JS_MODULE_STATUS_EVALUATING,
804
    JS_MODULE_STATUS_EVALUATING_ASYNC,
805
    JS_MODULE_STATUS_EVALUATED,
806
} JSModuleStatus;
807
808
struct JSModuleDef {
809
    JSGCObjectHeader header; /* must come first */
810
    JSAtom module_name;
811
    struct list_head link;
812
813
    JSReqModuleEntry *req_module_entries;
814
    int req_module_entries_count;
815
    int req_module_entries_size;
816
817
    JSExportEntry *export_entries;
818
    int export_entries_count;
819
    int export_entries_size;
820
821
    JSStarExportEntry *star_export_entries;
822
    int star_export_entries_count;
823
    int star_export_entries_size;
824
825
    JSImportEntry *import_entries;
826
    int import_entries_count;
827
    int import_entries_size;
828
829
    JSValue module_ns;
830
    JSValue func_obj; /* only used for JS modules */
831
    JSModuleInitFunc *init_func; /* only used for C modules */
832
    BOOL has_tla : 8; /* true if func_obj contains await */
833
    BOOL resolved : 8;
834
    BOOL func_created : 8;
835
    JSModuleStatus status : 8;
836
    /* temp use during js_module_link() & js_module_evaluate() */
837
    int dfs_index, dfs_ancestor_index;
838
    JSModuleDef *stack_prev;
839
    /* temp use during js_module_evaluate() */
840
    JSModuleDef **async_parent_modules;
841
    int async_parent_modules_count;
842
    int async_parent_modules_size;
843
    int pending_async_dependencies;
844
    BOOL async_evaluation; /* true: async_evaluation_timestamp corresponds to [[AsyncEvaluationOrder]] 
845
                              false: [[AsyncEvaluationOrder]] is UNSET or DONE */
846
    int64_t async_evaluation_timestamp;
847
    JSModuleDef *cycle_root;
848
    JSValue promise; /* corresponds to spec field: capability */
849
    JSValue resolving_funcs[2]; /* corresponds to spec field: capability */
850
851
    /* true if evaluation yielded an exception. It is saved in
852
       eval_exception */
853
    BOOL eval_has_exception : 8;
854
    JSValue eval_exception;
855
    JSValue meta_obj; /* for import.meta */
856
    JSValue private_value; /* private value for C modules */
857
};
858
859
typedef struct JSJobEntry {
860
    struct list_head link;
861
    JSContext *realm;
862
    JSJobFunc *job_func;
863
    int argc;
864
    JSValue argv[0];
865
} JSJobEntry;
866
867
typedef struct JSProperty {
868
    union {
869
        JSValue value;      /* JS_PROP_NORMAL */
870
        struct {            /* JS_PROP_GETSET */
871
            JSObject *getter; /* NULL if undefined */
872
            JSObject *setter; /* NULL if undefined */
873
        } getset;
874
        JSVarRef *var_ref;  /* JS_PROP_VARREF */
875
        struct {            /* JS_PROP_AUTOINIT */
876
            /* in order to use only 2 pointers, we compress the realm
877
               and the init function pointer */
878
            uintptr_t realm_and_id; /* realm and init_id (JS_AUTOINIT_ID_x)
879
                                       in the 2 low bits */
880
            void *opaque;
881
        } init;
882
    } u;
883
} JSProperty;
884
885
326
#define JS_PROP_INITIAL_SIZE 2
886
328
#define JS_PROP_INITIAL_HASH_SIZE 4 /* must be a power of two */
887
#define JS_ARRAY_INITIAL_SIZE 2
888
889
typedef struct JSShapeProperty {
890
    uint32_t hash_next : 26; /* 0 if last in list */
891
    uint32_t flags : 6;   /* JS_PROP_XXX */
892
    JSAtom atom; /* JS_ATOM_NULL = free property entry */
893
} JSShapeProperty;
894
895
struct JSShape {
896
    /* hash table of size hash_mask + 1 before the start of the
897
       structure (see prop_hash_end()). */
898
    JSGCObjectHeader header;
899
    /* true if the shape is inserted in the shape hash table. If not,
900
       JSShape.hash is not valid */
901
    uint8_t is_hashed;
902
    /* If true, the shape may have small array index properties 'n' with 0
903
       <= n <= 2^31-1. If false, the shape is guaranteed not to have
904
       small array index properties */
905
    uint8_t has_small_array_index;
906
    uint32_t hash; /* current hash value */
907
    uint32_t prop_hash_mask;
908
    int prop_size; /* allocated properties */
909
    int prop_count; /* include deleted properties */
910
    int deleted_prop_count;
911
    JSShape *shape_hash_next; /* in JSRuntime.shape_hash[h] list */
912
    JSObject *proto;
913
    JSShapeProperty prop[0]; /* prop_size elements */
914
};
915
916
struct JSObject {
917
    union {
918
        JSGCObjectHeader header;
919
        struct {
920
            int __gc_ref_count; /* corresponds to header.ref_count */
921
            uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */
922
923
            uint8_t extensible : 1;
924
            uint8_t free_mark : 1; /* only used when freeing objects with cycles */
925
            uint8_t is_exotic : 1; /* TRUE if object has exotic property handlers */
926
            uint8_t fast_array : 1; /* TRUE if u.array is used for get/put (for JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS and typed arrays) */
927
            uint8_t is_constructor : 1; /* TRUE if object is a constructor function */
928
            uint8_t has_immutable_prototype : 1; /* cannot modify the prototype */
929
            uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */
930
            uint8_t is_HTMLDDA : 1; /* specific annex B IsHtmlDDA behavior */
931
            uint16_t class_id; /* see JS_CLASS_x */
932
        };
933
    };
934
    /* count the number of weak references to this object. The object
935
       structure is freed only if header.ref_count = 0 and
936
       weakref_count = 0 */
937
    uint32_t weakref_count; 
938
    JSShape *shape; /* prototype and property names + flag */
939
    JSProperty *prop; /* array of properties */
940
    union {
941
        void *opaque;
942
        struct JSBoundFunction *bound_function; /* JS_CLASS_BOUND_FUNCTION */
943
        struct JSCFunctionDataRecord *c_function_data_record; /* JS_CLASS_C_FUNCTION_DATA */
944
        struct JSForInIterator *for_in_iterator; /* JS_CLASS_FOR_IN_ITERATOR */
945
        struct JSArrayBuffer *array_buffer; /* JS_CLASS_ARRAY_BUFFER, JS_CLASS_SHARED_ARRAY_BUFFER */
946
        struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_DATAVIEW */
947
        struct JSMapState *map_state;   /* JS_CLASS_MAP..JS_CLASS_WEAKSET */
948
        struct JSMapIteratorData *map_iterator_data; /* JS_CLASS_MAP_ITERATOR, JS_CLASS_SET_ITERATOR */
949
        struct JSArrayIteratorData *array_iterator_data; /* JS_CLASS_ARRAY_ITERATOR, JS_CLASS_STRING_ITERATOR */
950
        struct JSRegExpStringIteratorData *regexp_string_iterator_data; /* JS_CLASS_REGEXP_STRING_ITERATOR */
951
        struct JSGeneratorData *generator_data; /* JS_CLASS_GENERATOR */
952
        struct JSProxyData *proxy_data; /* JS_CLASS_PROXY */
953
        struct JSPromiseData *promise_data; /* JS_CLASS_PROMISE */
954
        struct JSPromiseFunctionData *promise_function_data; /* JS_CLASS_PROMISE_RESOLVE_FUNCTION, JS_CLASS_PROMISE_REJECT_FUNCTION */
955
        struct JSAsyncFunctionState *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */
956
        struct JSAsyncFromSyncIteratorData *async_from_sync_iterator_data; /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */
957
        struct JSAsyncGeneratorData *async_generator_data; /* JS_CLASS_ASYNC_GENERATOR */
958
        struct { /* JS_CLASS_BYTECODE_FUNCTION: 12/24 bytes */
959
            /* also used by JS_CLASS_GENERATOR_FUNCTION, JS_CLASS_ASYNC_FUNCTION and JS_CLASS_ASYNC_GENERATOR_FUNCTION */
960
            struct JSFunctionBytecode *function_bytecode;
961
            JSVarRef **var_refs;
962
            JSObject *home_object; /* for 'super' access */
963
        } func;
964
        struct { /* JS_CLASS_C_FUNCTION: 12/20 bytes */
965
            JSContext *realm;
966
            JSCFunctionType c_function;
967
            uint8_t length;
968
            uint8_t cproto;
969
            int16_t magic;
970
        } cfunc;
971
        /* array part for fast arrays and typed arrays */
972
        struct { /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS, JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
973
            union {
974
                uint32_t size;          /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */
975
                struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
976
            } u1;
977
            union {
978
                JSValue *values;        /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */
979
                void *ptr;              /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */
980
                int8_t *int8_ptr;       /* JS_CLASS_INT8_ARRAY */
981
                uint8_t *uint8_ptr;     /* JS_CLASS_UINT8_ARRAY, JS_CLASS_UINT8C_ARRAY */
982
                int16_t *int16_ptr;     /* JS_CLASS_INT16_ARRAY */
983
                uint16_t *uint16_ptr;   /* JS_CLASS_UINT16_ARRAY */
984
                int32_t *int32_ptr;     /* JS_CLASS_INT32_ARRAY */
985
                uint32_t *uint32_ptr;   /* JS_CLASS_UINT32_ARRAY */
986
                int64_t *int64_ptr;     /* JS_CLASS_INT64_ARRAY */
987
                uint64_t *uint64_ptr;   /* JS_CLASS_UINT64_ARRAY */
988
                uint16_t *fp16_ptr;     /* JS_CLASS_FLOAT16_ARRAY */
989
                float *float_ptr;       /* JS_CLASS_FLOAT32_ARRAY */
990
                double *double_ptr;     /* JS_CLASS_FLOAT64_ARRAY */
991
            } u;
992
            uint32_t count; /* <= 2^31-1. 0 for a detached typed array */
993
        } array;    /* 12/20 bytes */
994
        JSRegExp regexp;    /* JS_CLASS_REGEXP: 8/16 bytes */
995
        JSValue object_data;    /* for JS_SetObjectData(): 8/16/16 bytes */
996
    } u;
997
};
998
999
typedef struct JSMapRecord {
1000
    int ref_count; /* used during enumeration to avoid freeing the record */
1001
    BOOL empty : 8; /* TRUE if the record is deleted */
1002
    struct list_head link;
1003
    struct JSMapRecord *hash_next;
1004
    JSValue key;
1005
    JSValue value;
1006
} JSMapRecord;
1007
1008
typedef struct JSMapState {
1009
    BOOL is_weak; /* TRUE if WeakSet/WeakMap */
1010
    struct list_head records; /* list of JSMapRecord.link */
1011
    uint32_t record_count;
1012
    JSMapRecord **hash_table;
1013
    int hash_bits;
1014
    uint32_t hash_size; /* = 2 ^ hash_bits */
1015
    uint32_t record_count_threshold; /* count at which a hash table
1016
                                        resize is needed */
1017
    JSWeakRefHeader weakref_header; /* only used if is_weak = TRUE */
1018
} JSMapState;
1019
1020
enum {
1021
    __JS_ATOM_NULL = JS_ATOM_NULL,
1022
#define DEF(name, str) JS_ATOM_ ## name,
1023
#include "quickjs-atom.h"
1024
#undef DEF
1025
    JS_ATOM_END,
1026
};
1027
62
#define JS_ATOM_LAST_KEYWORD JS_ATOM_super
1028
54
#define JS_ATOM_LAST_STRICT_KEYWORD JS_ATOM_yield
1029
1030
static const char js_atom_init[] =
1031
#define DEF(name, str) str "\0"
1032
#include "quickjs-atom.h"
1033
#undef DEF
1034
;
1035
1036
typedef enum OPCodeFormat {
1037
#define FMT(f) OP_FMT_ ## f,
1038
#define DEF(id, size, n_pop, n_push, f)
1039
#include "quickjs-opcode.h"
1040
#undef DEF
1041
#undef FMT
1042
} OPCodeFormat;
1043
1044
enum OPCodeEnum {
1045
#define FMT(f)
1046
#define DEF(id, size, n_pop, n_push, f) OP_ ## id,
1047
#define def(id, size, n_pop, n_push, f)
1048
#include "quickjs-opcode.h"
1049
#undef def
1050
#undef DEF
1051
#undef FMT
1052
    OP_COUNT, /* excluding temporary opcodes */
1053
    /* temporary opcodes : overlap with the short opcodes */
1054
    OP_TEMP_START = OP_nop + 1,
1055
    OP___dummy = OP_TEMP_START - 1,
1056
#define FMT(f)
1057
#define DEF(id, size, n_pop, n_push, f)
1058
#define def(id, size, n_pop, n_push, f) OP_ ## id,
1059
#include "quickjs-opcode.h"
1060
#undef def
1061
#undef DEF
1062
#undef FMT
1063
    OP_TEMP_END,
1064
};
1065
1066
static int JS_InitAtoms(JSRuntime *rt);
1067
static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
1068
                               int atom_type);
1069
static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p);
1070
static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b);
1071
static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
1072
                                  JSValueConst this_obj,
1073
                                  int argc, JSValueConst *argv, int flags);
1074
static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj,
1075
                                      JSValueConst this_obj,
1076
                                      int argc, JSValueConst *argv, int flags);
1077
static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
1078
                               JSValueConst this_obj, JSValueConst new_target,
1079
                               int argc, JSValue *argv, int flags);
1080
static JSValue JS_CallConstructorInternal(JSContext *ctx,
1081
                                          JSValueConst func_obj,
1082
                                          JSValueConst new_target,
1083
                                          int argc, JSValue *argv, int flags);
1084
static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj,
1085
                           int argc, JSValueConst *argv);
1086
static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
1087
                             int argc, JSValueConst *argv);
1088
static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
1089
                                            JSValue val, BOOL is_array_ctor);
1090
static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
1091
                             JSValueConst val, int flags, int scope_idx);
1092
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...);
1093
static __maybe_unused void JS_DumpAtoms(JSRuntime *rt);
1094
static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p);
1095
static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt);
1096
static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p);
1097
static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p);
1098
static __maybe_unused void JS_DumpValueRT(JSRuntime *rt, const char *str, JSValueConst val);
1099
static __maybe_unused void JS_DumpValue(JSContext *ctx, const char *str, JSValueConst val);
1100
static __maybe_unused void JS_DumpShapes(JSRuntime *rt);
1101
static void js_dump_value_write(void *opaque, const char *buf, size_t len);
1102
static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
1103
                                 int argc, JSValueConst *argv, int magic);
1104
static void js_array_finalizer(JSRuntime *rt, JSValue val);
1105
static void js_array_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
1106
static void js_object_data_finalizer(JSRuntime *rt, JSValue val);
1107
static void js_object_data_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
1108
static void js_c_function_finalizer(JSRuntime *rt, JSValue val);
1109
static void js_c_function_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);
1110
static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val);
1111
static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
1112
                                JS_MarkFunc *mark_func);
1113
static void js_bound_function_finalizer(JSRuntime *rt, JSValue val);
1114
static void js_bound_function_mark(JSRuntime *rt, JSValueConst val,
1115
                                JS_MarkFunc *mark_func);
1116
static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val);
1117
static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val,
1118
                                JS_MarkFunc *mark_func);
1119
static void js_regexp_finalizer(JSRuntime *rt, JSValue val);
1120
static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val);
1121
static void js_typed_array_finalizer(JSRuntime *rt, JSValue val);
1122
static void js_typed_array_mark(JSRuntime *rt, JSValueConst val,
1123
                                JS_MarkFunc *mark_func);
1124
static void js_proxy_finalizer(JSRuntime *rt, JSValue val);
1125
static void js_proxy_mark(JSRuntime *rt, JSValueConst val,
1126
                                JS_MarkFunc *mark_func);
1127
static void js_map_finalizer(JSRuntime *rt, JSValue val);
1128
static void js_map_mark(JSRuntime *rt, JSValueConst val,
1129
                                JS_MarkFunc *mark_func);
1130
static void js_map_iterator_finalizer(JSRuntime *rt, JSValue val);
1131
static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val,
1132
                                JS_MarkFunc *mark_func);
1133
static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val);
1134
static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val,
1135
                                JS_MarkFunc *mark_func);
1136
static void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val);
1137
static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val,
1138
                                JS_MarkFunc *mark_func);
1139
static void js_generator_finalizer(JSRuntime *rt, JSValue obj);
1140
static void js_generator_mark(JSRuntime *rt, JSValueConst val,
1141
                                JS_MarkFunc *mark_func);
1142
static void js_promise_finalizer(JSRuntime *rt, JSValue val);
1143
static void js_promise_mark(JSRuntime *rt, JSValueConst val,
1144
                                JS_MarkFunc *mark_func);
1145
static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val);
1146
static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
1147
                                JS_MarkFunc *mark_func);
1148
1149
0
#define HINT_STRING  0
1150
0
#define HINT_NUMBER  1
1151
0
#define HINT_NONE    2
1152
0
#define HINT_FORCE_ORDINARY (1 << 4) // don't try Symbol.toPrimitive
1153
static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint);
1154
static JSValue JS_ToStringFree(JSContext *ctx, JSValue val);
1155
static int JS_ToBoolFree(JSContext *ctx, JSValue val);
1156
static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val);
1157
static int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val);
1158
static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val);
1159
static JSValue js_new_string8_len(JSContext *ctx, const char *buf, int len);
1160
static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
1161
                                 JSValueConst flags);
1162
static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor,
1163
                                              JSValue pattern, JSValue bc);
1164
static void gc_decref(JSRuntime *rt);
1165
static int JS_NewClass1(JSRuntime *rt, JSClassID class_id,
1166
                        const JSClassDef *class_def, JSAtom name);
1167
1168
typedef enum JSStrictEqModeEnum {
1169
    JS_EQ_STRICT,
1170
    JS_EQ_SAME_VALUE,
1171
    JS_EQ_SAME_VALUE_ZERO,
1172
} JSStrictEqModeEnum;
1173
1174
static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
1175
                          JSStrictEqModeEnum eq_mode);
1176
static BOOL js_strict_eq(JSContext *ctx, JSValueConst op1, JSValueConst op2);
1177
static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2);
1178
static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2);
1179
static JSValue JS_ToObject(JSContext *ctx, JSValueConst val);
1180
static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val);
1181
static JSProperty *add_property(JSContext *ctx,
1182
                                JSObject *p, JSAtom prop, int prop_flags);
1183
static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val);
1184
JSValue JS_ThrowOutOfMemory(JSContext *ctx);
1185
static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx);
1186
1187
static int js_resolve_proxy(JSContext *ctx, JSValueConst *pval, int throw_exception);
1188
static int JS_CreateProperty(JSContext *ctx, JSObject *p,
1189
                             JSAtom prop, JSValueConst val,
1190
                             JSValueConst getter, JSValueConst setter,
1191
                             int flags);
1192
static int js_string_memcmp(const JSString *p1, int pos1, const JSString *p2,
1193
                            int pos2, int len);
1194
static JSValue js_array_buffer_constructor3(JSContext *ctx,
1195
                                            JSValueConst new_target,
1196
                                            uint64_t len, JSClassID class_id,
1197
                                            uint8_t *buf,
1198
                                            JSFreeArrayBufferDataFunc *free_func,
1199
                                            void *opaque, BOOL alloc_flag);
1200
static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj);
1201
static JSValue js_typed_array_constructor(JSContext *ctx,
1202
                                          JSValueConst this_val,
1203
                                          int argc, JSValueConst *argv,
1204
                                          int classid);
1205
static JSValue js_typed_array_constructor_ta(JSContext *ctx,
1206
                                             JSValueConst new_target,
1207
                                             JSValueConst src_obj,
1208
                                             int classid);
1209
static BOOL typed_array_is_detached(JSContext *ctx, JSObject *p);
1210
static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p);
1211
static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx);
1212
static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx,
1213
                             BOOL is_arg);
1214
static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s);
1215
static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s);
1216
static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
1217
                                          JSValueConst this_obj,
1218
                                          int argc, JSValueConst *argv,
1219
                                          int flags);
1220
static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val);
1221
static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,
1222
                                           JS_MarkFunc *mark_func);
1223
static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
1224
                               const char *input, size_t input_len,
1225
                               const char *filename, int flags, int scope_idx);
1226
static void js_free_module_def(JSRuntime *rt, JSModuleDef *m);
1227
static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
1228
                               JS_MarkFunc *mark_func);
1229
static JSValue js_import_meta(JSContext *ctx);
1230
static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier, JSValueConst options);
1231
static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref);
1232
static JSValue js_new_promise_capability(JSContext *ctx,
1233
                                         JSValue *resolving_funcs,
1234
                                         JSValueConst ctor);
1235
static __exception int perform_promise_then(JSContext *ctx,
1236
                                            JSValueConst promise,
1237
                                            JSValueConst *resolve_reject,
1238
                                            JSValueConst *cap_resolving_funcs);
1239
static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
1240
                                  int argc, JSValueConst *argv, int magic);
1241
static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val,
1242
                               int argc, JSValueConst *argv);
1243
static int js_string_compare(JSContext *ctx,
1244
                             const JSString *p1, const JSString *p2);
1245
static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val);
1246
static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
1247
                               JSValue prop, JSValue val, int flags);
1248
static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val);
1249
static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val);
1250
static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val);
1251
static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc,
1252
                                     JSObject *p, JSAtom prop);
1253
static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc);
1254
static void JS_AddIntrinsicBasicObjects(JSContext *ctx);
1255
static void js_free_shape(JSRuntime *rt, JSShape *sh);
1256
static void js_free_shape_null(JSRuntime *rt, JSShape *sh);
1257
static int js_shape_prepare_update(JSContext *ctx, JSObject *p,
1258
                                   JSShapeProperty **pprs);
1259
static int init_shape_hash(JSRuntime *rt);
1260
static __exception int js_get_length32(JSContext *ctx, uint32_t *pres,
1261
                                       JSValueConst obj);
1262
static __exception int js_get_length64(JSContext *ctx, int64_t *pres,
1263
                                       JSValueConst obj);
1264
static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len);
1265
static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
1266
                               JSValueConst array_arg);
1267
static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj,
1268
                              JSValue **arrpp, uint32_t *countp);
1269
static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx,
1270
                                              JSValueConst sync_iter);
1271
static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val);
1272
static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val,
1273
                                    JS_MarkFunc *mark_func);
1274
static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj,
1275
                                       JSValueConst this_val,
1276
                                       int argc, JSValueConst *argv, int flags);
1277
static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val);
1278
static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
1279
                          JSGCObjectTypeEnum type);
1280
static void remove_gc_object(JSGCObjectHeader *h);
1281
static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
1282
static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
1283
                                 void *opaque);
1284
static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,
1285
                                               JSAtom atom, void *opaque);
1286
static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val,
1287
                                 int argc, JSValueConst *argv, int is_map);
1288
static void map_delete_weakrefs(JSRuntime *rt, JSWeakRefHeader *wh);
1289
static void weakref_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh);
1290
static void finrec_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh);
1291
static void JS_RunGCInternal(JSRuntime *rt, BOOL remove_weak_objects);
1292
static JSValue js_array_from_iterator(JSContext *ctx, uint32_t *plen,
1293
                                      JSValueConst obj, JSValueConst method);
1294
static int js_string_find_invalid_codepoint(JSString *p);
1295
static JSValue js_regexp_toString(JSContext *ctx, JSValueConst this_val,
1296
                                  int argc, JSValueConst *argv);
1297
static JSValue get_date_string(JSContext *ctx, JSValueConst this_val,
1298
                               int argc, JSValueConst *argv, int magic);
1299
static JSValue js_error_toString(JSContext *ctx, JSValueConst this_val,
1300
                                 int argc, JSValueConst *argv);
1301
1302
static const JSClassExoticMethods js_arguments_exotic_methods;
1303
static const JSClassExoticMethods js_string_exotic_methods;
1304
static const JSClassExoticMethods js_proxy_exotic_methods;
1305
static const JSClassExoticMethods js_module_ns_exotic_methods;
1306
static JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT;
1307
1308
static void js_trigger_gc(JSRuntime *rt, size_t size)
1309
474
{
1310
474
    BOOL force_gc;
1311
#ifdef FORCE_GC_AT_MALLOC
1312
    force_gc = TRUE;
1313
#else
1314
474
    force_gc = ((rt->malloc_state.malloc_size + size) >
1315
474
                rt->malloc_gc_threshold);
1316
474
#endif
1317
474
    if (force_gc) {
1318
#ifdef DUMP_GC
1319
        printf("GC: size=%" PRIu64 "\n",
1320
               (uint64_t)rt->malloc_state.malloc_size);
1321
#endif
1322
0
        JS_RunGC(rt);
1323
0
        rt->malloc_gc_threshold = rt->malloc_state.malloc_size +
1324
0
            (rt->malloc_state.malloc_size >> 1);
1325
0
    }
1326
474
}
1327
1328
static size_t js_malloc_usable_size_unknown(const void *ptr)
1329
0
{
1330
0
    return 0;
1331
0
}
1332
1333
void *js_malloc_rt(JSRuntime *rt, size_t size)
1334
3.40k
{
1335
3.40k
    return rt->mf.js_malloc(&rt->malloc_state, size);
1336
3.40k
}
1337
1338
void js_free_rt(JSRuntime *rt, void *ptr)
1339
3.50k
{
1340
3.50k
    rt->mf.js_free(&rt->malloc_state, ptr);
1341
3.50k
}
1342
1343
void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size)
1344
786
{
1345
786
    return rt->mf.js_realloc(&rt->malloc_state, ptr, size);
1346
786
}
1347
1348
size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr)
1349
109
{
1350
109
    return rt->mf.js_malloc_usable_size(ptr);
1351
109
}
1352
1353
void *js_mallocz_rt(JSRuntime *rt, size_t size)
1354
58
{
1355
58
    void *ptr;
1356
58
    ptr = js_malloc_rt(rt, size);
1357
58
    if (!ptr)
1358
0
        return NULL;
1359
58
    return memset(ptr, 0, size);
1360
58
}
1361
1362
/* Throw out of memory in case of error */
1363
void *js_malloc(JSContext *ctx, size_t size)
1364
2.11k
{
1365
2.11k
    void *ptr;
1366
2.11k
    ptr = js_malloc_rt(ctx->rt, size);
1367
2.11k
    if (unlikely(!ptr)) {
1368
0
        JS_ThrowOutOfMemory(ctx);
1369
0
        return NULL;
1370
0
    }
1371
2.11k
    return ptr;
1372
2.11k
}
1373
1374
/* Throw out of memory in case of error */
1375
void *js_mallocz(JSContext *ctx, size_t size)
1376
42
{
1377
42
    void *ptr;
1378
42
    ptr = js_mallocz_rt(ctx->rt, size);
1379
42
    if (unlikely(!ptr)) {
1380
0
        JS_ThrowOutOfMemory(ctx);
1381
0
        return NULL;
1382
0
    }
1383
42
    return ptr;
1384
42
}
1385
1386
void js_free(JSContext *ctx, void *ptr)
1387
489
{
1388
489
    js_free_rt(ctx->rt, ptr);
1389
489
}
1390
1391
/* Throw out of memory in case of error */
1392
void *js_realloc(JSContext *ctx, void *ptr, size_t size)
1393
518
{
1394
518
    void *ret;
1395
518
    ret = js_realloc_rt(ctx->rt, ptr, size);
1396
518
    if (unlikely(!ret && size != 0)) {
1397
0
        JS_ThrowOutOfMemory(ctx);
1398
0
        return NULL;
1399
0
    }
1400
518
    return ret;
1401
518
}
1402
1403
/* store extra allocated size in *pslack if successful */
1404
void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack)
1405
109
{
1406
109
    void *ret;
1407
109
    ret = js_realloc_rt(ctx->rt, ptr, size);
1408
109
    if (unlikely(!ret && size != 0)) {
1409
0
        JS_ThrowOutOfMemory(ctx);
1410
0
        return NULL;
1411
0
    }
1412
109
    if (pslack) {
1413
109
        size_t new_size = js_malloc_usable_size_rt(ctx->rt, ret);
1414
109
        *pslack = (new_size > size) ? new_size - size : 0;
1415
109
    }
1416
109
    return ret;
1417
109
}
1418
1419
size_t js_malloc_usable_size(JSContext *ctx, const void *ptr)
1420
0
{
1421
0
    return js_malloc_usable_size_rt(ctx->rt, ptr);
1422
0
}
1423
1424
/* Throw out of memory exception in case of error */
1425
char *js_strndup(JSContext *ctx, const char *s, size_t n)
1426
4
{
1427
4
    char *ptr;
1428
4
    ptr = js_malloc(ctx, n + 1);
1429
4
    if (ptr) {
1430
4
        memcpy(ptr, s, n);
1431
4
        ptr[n] = '\0';
1432
4
    }
1433
4
    return ptr;
1434
4
}
1435
1436
char *js_strdup(JSContext *ctx, const char *str)
1437
4
{
1438
4
    return js_strndup(ctx, str, strlen(str));
1439
4
}
1440
1441
static no_inline int js_realloc_array(JSContext *ctx, void **parray,
1442
                                      int elem_size, int *psize, int req_size)
1443
109
{
1444
109
    int new_size;
1445
109
    size_t slack;
1446
109
    void *new_array;
1447
    /* XXX: potential arithmetic overflow */
1448
109
    new_size = max_int(req_size, *psize * 3 / 2);
1449
109
    new_array = js_realloc2(ctx, *parray, new_size * elem_size, &slack);
1450
109
    if (!new_array)
1451
0
        return -1;
1452
109
    new_size += slack / elem_size;
1453
109
    *psize = new_size;
1454
109
    *parray = new_array;
1455
109
    return 0;
1456
109
}
1457
1458
/* resize the array and update its size if req_size > *psize */
1459
static inline int js_resize_array(JSContext *ctx, void **parray, int elem_size,
1460
                                  int *psize, int req_size)
1461
450
{
1462
450
    if (unlikely(req_size > *psize))
1463
109
        return js_realloc_array(ctx, parray, elem_size, psize, req_size);
1464
341
    else
1465
341
        return 0;
1466
450
}
1467
1468
static inline void js_dbuf_init(JSContext *ctx, DynBuf *s)
1469
23
{
1470
23
    dbuf_init2(s, ctx->rt, (DynBufReallocFunc *)js_realloc_rt);
1471
23
}
1472
1473
1.79k
static inline int is_digit(int c) {
1474
1.79k
    return c >= '0' && c <= '9';
1475
1.79k
}
1476
1477
575
static inline int string_get(const JSString *p, int idx) {
1478
575
    return p->is_wide_char ? p->u.str16[idx] : p->u.str8[idx];
1479
575
}
1480
1481
typedef struct JSClassShortDef {
1482
    JSAtom class_name;
1483
    JSClassFinalizer *finalizer;
1484
    JSClassGCMark *gc_mark;
1485
} JSClassShortDef;
1486
1487
static JSClassShortDef const js_std_class_def[] = {
1488
    { JS_ATOM_Object, NULL, NULL },                             /* JS_CLASS_OBJECT */
1489
    { JS_ATOM_Array, js_array_finalizer, js_array_mark },       /* JS_CLASS_ARRAY */
1490
    { JS_ATOM_Error, NULL, NULL }, /* JS_CLASS_ERROR */
1491
    { JS_ATOM_Number, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_NUMBER */
1492
    { JS_ATOM_String, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_STRING */
1493
    { JS_ATOM_Boolean, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BOOLEAN */
1494
    { JS_ATOM_Symbol, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_SYMBOL */
1495
    { JS_ATOM_Arguments, js_array_finalizer, js_array_mark },   /* JS_CLASS_ARGUMENTS */
1496
    { JS_ATOM_Arguments, NULL, NULL },                          /* JS_CLASS_MAPPED_ARGUMENTS */
1497
    { JS_ATOM_Date, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_DATE */
1498
    { JS_ATOM_Object, NULL, NULL },                             /* JS_CLASS_MODULE_NS */
1499
    { JS_ATOM_Function, js_c_function_finalizer, js_c_function_mark }, /* JS_CLASS_C_FUNCTION */
1500
    { JS_ATOM_Function, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_BYTECODE_FUNCTION */
1501
    { JS_ATOM_Function, js_bound_function_finalizer, js_bound_function_mark }, /* JS_CLASS_BOUND_FUNCTION */
1502
    { JS_ATOM_Function, js_c_function_data_finalizer, js_c_function_data_mark }, /* JS_CLASS_C_FUNCTION_DATA */
1503
    { JS_ATOM_GeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_GENERATOR_FUNCTION */
1504
    { JS_ATOM_ForInIterator, js_for_in_iterator_finalizer, js_for_in_iterator_mark },      /* JS_CLASS_FOR_IN_ITERATOR */
1505
    { JS_ATOM_RegExp, js_regexp_finalizer, NULL },                              /* JS_CLASS_REGEXP */
1506
    { JS_ATOM_ArrayBuffer, js_array_buffer_finalizer, NULL },                   /* JS_CLASS_ARRAY_BUFFER */
1507
    { JS_ATOM_SharedArrayBuffer, js_array_buffer_finalizer, NULL },             /* JS_CLASS_SHARED_ARRAY_BUFFER */
1508
    { JS_ATOM_Uint8ClampedArray, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT8C_ARRAY */
1509
    { JS_ATOM_Int8Array, js_typed_array_finalizer, js_typed_array_mark },       /* JS_CLASS_INT8_ARRAY */
1510
    { JS_ATOM_Uint8Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_UINT8_ARRAY */
1511
    { JS_ATOM_Int16Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_INT16_ARRAY */
1512
    { JS_ATOM_Uint16Array, js_typed_array_finalizer, js_typed_array_mark },     /* JS_CLASS_UINT16_ARRAY */
1513
    { JS_ATOM_Int32Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_INT32_ARRAY */
1514
    { JS_ATOM_Uint32Array, js_typed_array_finalizer, js_typed_array_mark },     /* JS_CLASS_UINT32_ARRAY */
1515
    { JS_ATOM_BigInt64Array, js_typed_array_finalizer, js_typed_array_mark },   /* JS_CLASS_BIG_INT64_ARRAY */
1516
    { JS_ATOM_BigUint64Array, js_typed_array_finalizer, js_typed_array_mark },  /* JS_CLASS_BIG_UINT64_ARRAY */
1517
    { JS_ATOM_Float16Array, js_typed_array_finalizer, js_typed_array_mark },    /* JS_CLASS_FLOAT16_ARRAY */
1518
    { JS_ATOM_Float32Array, js_typed_array_finalizer, js_typed_array_mark },    /* JS_CLASS_FLOAT32_ARRAY */
1519
    { JS_ATOM_Float64Array, js_typed_array_finalizer, js_typed_array_mark },    /* JS_CLASS_FLOAT64_ARRAY */
1520
    { JS_ATOM_DataView, js_typed_array_finalizer, js_typed_array_mark },        /* JS_CLASS_DATAVIEW */
1521
    { JS_ATOM_BigInt, js_object_data_finalizer, js_object_data_mark },      /* JS_CLASS_BIG_INT */
1522
    { JS_ATOM_Map, js_map_finalizer, js_map_mark },             /* JS_CLASS_MAP */
1523
    { JS_ATOM_Set, js_map_finalizer, js_map_mark },             /* JS_CLASS_SET */
1524
    { JS_ATOM_WeakMap, js_map_finalizer, js_map_mark },         /* JS_CLASS_WEAKMAP */
1525
    { JS_ATOM_WeakSet, js_map_finalizer, js_map_mark },         /* JS_CLASS_WEAKSET */
1526
    { JS_ATOM_Map_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_MAP_ITERATOR */
1527
    { JS_ATOM_Set_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_SET_ITERATOR */
1528
    { JS_ATOM_Array_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_ARRAY_ITERATOR */
1529
    { JS_ATOM_String_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_STRING_ITERATOR */
1530
    { JS_ATOM_RegExp_String_Iterator, js_regexp_string_iterator_finalizer, js_regexp_string_iterator_mark }, /* JS_CLASS_REGEXP_STRING_ITERATOR */
1531
    { JS_ATOM_Generator, js_generator_finalizer, js_generator_mark }, /* JS_CLASS_GENERATOR */
1532
};
1533
1534
static int init_class_range(JSRuntime *rt, JSClassShortDef const *tab,
1535
                            int start, int count)
1536
10
{
1537
10
    JSClassDef cm_s, *cm = &cm_s;
1538
10
    int i, class_id;
1539
1540
122
    for(i = 0; i < count; i++) {
1541
112
        class_id = i + start;
1542
112
        memset(cm, 0, sizeof(*cm));
1543
112
        cm->finalizer = tab[i].finalizer;
1544
112
        cm->gc_mark = tab[i].gc_mark;
1545
112
        if (JS_NewClass1(rt, class_id, cm, tab[i].class_name) < 0)
1546
0
            return -1;
1547
112
    }
1548
10
    return 0;
1549
10
}
1550
1551
#if !defined(CONFIG_STACK_CHECK)
1552
/* no stack limitation */
1553
static inline uintptr_t js_get_stack_pointer(void)
1554
{
1555
    return 0;
1556
}
1557
1558
static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
1559
{
1560
    return FALSE;
1561
}
1562
#else
1563
/* Note: OS and CPU dependent */
1564
static inline uintptr_t js_get_stack_pointer(void)
1565
91
{
1566
91
    return (uintptr_t)__builtin_frame_address(0);
1567
91
}
1568
1569
static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
1570
89
{
1571
89
    uintptr_t sp;
1572
89
    sp = js_get_stack_pointer() - alloca_size;
1573
89
    return unlikely(sp < rt->stack_limit);
1574
89
}
1575
#endif
1576
1577
JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
1578
2
{
1579
2
    JSRuntime *rt;
1580
2
    JSMallocState ms;
1581
1582
2
    memset(&ms, 0, sizeof(ms));
1583
2
    ms.opaque = opaque;
1584
2
    ms.malloc_limit = -1;
1585
1586
2
    rt = mf->js_malloc(&ms, sizeof(JSRuntime));
1587
2
    if (!rt)
1588
0
        return NULL;
1589
2
    memset(rt, 0, sizeof(*rt));
1590
2
    rt->mf = *mf;
1591
2
    if (!rt->mf.js_malloc_usable_size) {
1592
        /* use dummy function if none provided */
1593
0
        rt->mf.js_malloc_usable_size = js_malloc_usable_size_unknown;
1594
0
    }
1595
2
    rt->malloc_state = ms;
1596
2
    rt->malloc_gc_threshold = 256 * 1024;
1597
1598
2
    init_list_head(&rt->context_list);
1599
2
    init_list_head(&rt->gc_obj_list);
1600
2
    init_list_head(&rt->gc_zero_ref_count_list);
1601
2
    rt->gc_phase = JS_GC_PHASE_NONE;
1602
2
    init_list_head(&rt->weakref_list);
1603
1604
#ifdef DUMP_LEAKS
1605
    init_list_head(&rt->string_list);
1606
#endif
1607
2
    init_list_head(&rt->job_list);
1608
1609
2
    if (JS_InitAtoms(rt))
1610
0
        goto fail;
1611
1612
    /* create the object, array and function classes */
1613
2
    if (init_class_range(rt, js_std_class_def, JS_CLASS_OBJECT,
1614
2
                         countof(js_std_class_def)) < 0)
1615
0
        goto fail;
1616
2
    rt->class_array[JS_CLASS_ARGUMENTS].exotic = &js_arguments_exotic_methods;
1617
2
    rt->class_array[JS_CLASS_STRING].exotic = &js_string_exotic_methods;
1618
2
    rt->class_array[JS_CLASS_MODULE_NS].exotic = &js_module_ns_exotic_methods;
1619
1620
2
    rt->class_array[JS_CLASS_C_FUNCTION].call = js_call_c_function;
1621
2
    rt->class_array[JS_CLASS_C_FUNCTION_DATA].call = js_c_function_data_call;
1622
2
    rt->class_array[JS_CLASS_BOUND_FUNCTION].call = js_call_bound_function;
1623
2
    rt->class_array[JS_CLASS_GENERATOR_FUNCTION].call = js_generator_function_call;
1624
2
    if (init_shape_hash(rt))
1625
0
        goto fail;
1626
1627
2
    rt->stack_size = JS_DEFAULT_STACK_SIZE;
1628
2
    JS_UpdateStackTop(rt);
1629
1630
2
    rt->current_exception = JS_UNINITIALIZED;
1631
1632
2
    return rt;
1633
0
 fail:
1634
0
    JS_FreeRuntime(rt);
1635
0
    return NULL;
1636
2
}
1637
1638
void *JS_GetRuntimeOpaque(JSRuntime *rt)
1639
4
{
1640
4
    return rt->user_opaque;
1641
4
}
1642
1643
void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque)
1644
4
{
1645
4
    rt->user_opaque = opaque;
1646
4
}
1647
1648
/* default memory allocation functions with memory limitation */
1649
static size_t js_def_malloc_usable_size(const void *ptr)
1650
8.46k
{
1651
#if defined(__APPLE__)
1652
    return malloc_size(ptr);
1653
#elif defined(_WIN32)
1654
    return _msize((void *)ptr);
1655
#elif defined(EMSCRIPTEN)
1656
    return 0;
1657
#elif defined(__linux__) || defined(__GLIBC__)
1658
    return malloc_usable_size((void *)ptr);
1659
#else
1660
    /* change this to `return 0;` if compilation fails */
1661
    return malloc_usable_size((void *)ptr);
1662
#endif
1663
8.46k
}
1664
1665
static void *js_def_malloc(JSMallocState *s, size_t size)
1666
3.45k
{
1667
3.45k
    void *ptr;
1668
1669
    /* Do not allocate zero bytes: behavior is platform dependent */
1670
3.45k
    assert(size != 0);
1671
1672
3.45k
    if (unlikely(s->malloc_size + size > s->malloc_limit))
1673
0
        return NULL;
1674
1675
3.45k
    ptr = malloc(size);
1676
3.45k
    if (!ptr)
1677
0
        return NULL;
1678
1679
3.45k
    s->malloc_count++;
1680
3.45k
    s->malloc_size += js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
1681
3.45k
    return ptr;
1682
3.45k
}
1683
1684
static void js_def_free(JSMallocState *s, void *ptr)
1685
3.50k
{
1686
3.50k
    if (!ptr)
1687
64
        return;
1688
1689
3.44k
    s->malloc_count--;
1690
3.44k
    s->malloc_size -= js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD;
1691
3.44k
    free(ptr);
1692
3.44k
}
1693
1694
static void *js_def_realloc(JSMallocState *s, void *ptr, size_t size)
1695
786
{
1696
786
    size_t old_size;
1697
1698
786
    if (!ptr) {
1699
51
        if (size == 0)
1700
0
            return NULL;
1701
51
        return js_def_malloc(s, size);
1702
51
    }
1703
735
    old_size = js_def_malloc_usable_size(ptr);
1704
735
    if (size == 0) {
1705
12
        s->malloc_count--;
1706
12
        s->malloc_size -= old_size + MALLOC_OVERHEAD;
1707
12
        free(ptr);
1708
12
        return NULL;
1709
12
    }
1710
723
    if (s->malloc_size + size - old_size > s->malloc_limit)
1711
0
        return NULL;
1712
1713
723
    ptr = realloc(ptr, size);
1714
723
    if (!ptr)
1715
0
        return NULL;
1716
1717
723
    s->malloc_size += js_def_malloc_usable_size(ptr) - old_size;
1718
723
    return ptr;
1719
723
}
1720
1721
static const JSMallocFunctions def_malloc_funcs = {
1722
    js_def_malloc,
1723
    js_def_free,
1724
    js_def_realloc,
1725
    js_def_malloc_usable_size,
1726
};
1727
1728
JSRuntime *JS_NewRuntime(void)
1729
2
{
1730
2
    return JS_NewRuntime2(&def_malloc_funcs, NULL);
1731
2
}
1732
1733
void JS_SetMemoryLimit(JSRuntime *rt, size_t limit)
1734
2
{
1735
2
    rt->malloc_state.malloc_limit = limit;
1736
2
}
1737
1738
/* use -1 to disable automatic GC */
1739
void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold)
1740
0
{
1741
0
    rt->malloc_gc_threshold = gc_threshold;
1742
0
}
1743
1744
#define malloc(s) malloc_is_forbidden(s)
1745
#define free(p) free_is_forbidden(p)
1746
#define realloc(p,s) realloc_is_forbidden(p,s)
1747
1748
void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque)
1749
2
{
1750
2
    rt->interrupt_handler = cb;
1751
2
    rt->interrupt_opaque = opaque;
1752
2
}
1753
1754
void JS_SetCanBlock(JSRuntime *rt, BOOL can_block)
1755
0
{
1756
0
    rt->can_block = can_block;
1757
0
}
1758
1759
void JS_SetSharedArrayBufferFunctions(JSRuntime *rt,
1760
                                      const JSSharedArrayBufferFunctions *sf)
1761
0
{
1762
0
    rt->sab_funcs = *sf;
1763
0
}
1764
1765
void JS_SetStripInfo(JSRuntime *rt, int flags)
1766
0
{
1767
0
    rt->strip_flags = flags;
1768
0
}
1769
1770
int JS_GetStripInfo(JSRuntime *rt)
1771
0
{
1772
0
    return rt->strip_flags;
1773
0
}
1774
1775
/* return 0 if OK, < 0 if exception */
1776
int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func,
1777
                  int argc, JSValueConst *argv)
1778
0
{
1779
0
    JSRuntime *rt = ctx->rt;
1780
0
    JSJobEntry *e;
1781
0
    int i;
1782
1783
0
    e = js_malloc(ctx, sizeof(*e) + argc * sizeof(JSValue));
1784
0
    if (!e)
1785
0
        return -1;
1786
0
    e->realm = JS_DupContext(ctx);
1787
0
    e->job_func = job_func;
1788
0
    e->argc = argc;
1789
0
    for(i = 0; i < argc; i++) {
1790
0
        e->argv[i] = JS_DupValue(ctx, argv[i]);
1791
0
    }
1792
0
    list_add_tail(&e->link, &rt->job_list);
1793
0
    return 0;
1794
0
}
1795
1796
BOOL JS_IsJobPending(JSRuntime *rt)
1797
0
{
1798
0
    return !list_empty(&rt->job_list);
1799
0
}
1800
1801
/* return < 0 if exception, 0 if no job pending, 1 if a job was
1802
   executed successfully. The context of the job is stored in '*pctx'
1803
   if pctx != NULL. It may be NULL if the context was already
1804
   destroyed or if no job was pending. The 'pctx' parameter is now
1805
   absolete. */
1806
int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx)
1807
1
{
1808
1
    JSContext *ctx;
1809
1
    JSJobEntry *e;
1810
1
    JSValue res;
1811
1
    int i, ret;
1812
1813
1
    if (list_empty(&rt->job_list)) {
1814
1
        if (pctx)
1815
0
            *pctx = NULL;
1816
1
        return 0;
1817
1
    }
1818
1819
    /* get the first pending job and execute it */
1820
0
    e = list_entry(rt->job_list.next, JSJobEntry, link);
1821
0
    list_del(&e->link);
1822
0
    ctx = e->realm;
1823
0
    res = e->job_func(ctx, e->argc, (JSValueConst *)e->argv);
1824
0
    for(i = 0; i < e->argc; i++)
1825
0
        JS_FreeValue(ctx, e->argv[i]);
1826
0
    if (JS_IsException(res))
1827
0
        ret = -1;
1828
0
    else
1829
0
        ret = 1;
1830
0
    JS_FreeValue(ctx, res);
1831
0
    js_free(ctx, e);
1832
0
    if (pctx) {
1833
0
        if (ctx->header.ref_count > 1)
1834
0
            *pctx = ctx;
1835
0
        else
1836
0
            *pctx = NULL;
1837
0
    }
1838
0
    JS_FreeContext(ctx);
1839
0
    return ret;
1840
1
}
1841
1842
static inline uint32_t atom_get_free(const JSAtomStruct *p)
1843
1.21k
{
1844
1.21k
    return (uintptr_t)p >> 1;
1845
1.21k
}
1846
1847
static inline BOOL atom_is_free(const JSAtomStruct *p)
1848
1.48k
{
1849
1.48k
    return (uintptr_t)p & 1;
1850
1.48k
}
1851
1852
static inline JSAtomStruct *atom_set_free(uint32_t v)
1853
2.17k
{
1854
2.17k
    return (JSAtomStruct *)(((uintptr_t)v << 1) | 1);
1855
2.17k
}
1856
1857
/* Note: the string contents are uninitialized */
1858
static JSString *js_alloc_string_rt(JSRuntime *rt, int max_len, int is_wide_char)
1859
1.22k
{
1860
1.22k
    JSString *str;
1861
1.22k
    str = js_malloc_rt(rt, sizeof(JSString) + (max_len << is_wide_char) + 1 - is_wide_char);
1862
1.22k
    if (unlikely(!str))
1863
0
        return NULL;
1864
1.22k
    str->header.ref_count = 1;
1865
1.22k
    str->is_wide_char = is_wide_char;
1866
1.22k
    str->len = max_len;
1867
1.22k
    str->atom_type = 0;
1868
1.22k
    str->hash = 0;          /* optional but costless */
1869
1.22k
    str->hash_next = 0;     /* optional */
1870
#ifdef DUMP_LEAKS
1871
    list_add_tail(&str->link, &rt->string_list);
1872
#endif
1873
1.22k
    return str;
1874
1.22k
}
1875
1876
static JSString *js_alloc_string(JSContext *ctx, int max_len, int is_wide_char)
1877
767
{
1878
767
    JSString *p;
1879
767
    p = js_alloc_string_rt(ctx->rt, max_len, is_wide_char);
1880
767
    if (unlikely(!p)) {
1881
0
        JS_ThrowOutOfMemory(ctx);
1882
0
        return NULL;
1883
0
    }
1884
767
    return p;
1885
767
}
1886
1887
/* same as JS_FreeValueRT() but faster */
1888
static inline void js_free_string(JSRuntime *rt, JSString *str)
1889
6
{
1890
6
    if (--str->header.ref_count <= 0) {
1891
2
        if (str->atom_type) {
1892
0
            JS_FreeAtomStruct(rt, str);
1893
2
        } else {
1894
#ifdef DUMP_LEAKS
1895
            list_del(&str->link);
1896
#endif
1897
2
            js_free_rt(rt, str);
1898
2
        }
1899
2
    }
1900
6
}
1901
1902
void JS_SetRuntimeInfo(JSRuntime *rt, const char *s)
1903
0
{
1904
0
    if (rt)
1905
0
        rt->rt_info = s;
1906
0
}
1907
1908
void JS_FreeRuntime(JSRuntime *rt)
1909
2
{
1910
2
    struct list_head *el, *el1;
1911
2
    int i;
1912
1913
2
    JS_FreeValueRT(rt, rt->current_exception);
1914
1915
2
    list_for_each_safe(el, el1, &rt->job_list) {
1916
0
        JSJobEntry *e = list_entry(el, JSJobEntry, link);
1917
0
        for(i = 0; i < e->argc; i++)
1918
0
            JS_FreeValueRT(rt, e->argv[i]);
1919
0
        JS_FreeContext(e->realm);
1920
0
        js_free_rt(rt, e);
1921
0
    }
1922
2
    init_list_head(&rt->job_list);
1923
1924
    /* don't remove the weak objects to avoid create new jobs with
1925
       FinalizationRegistry */
1926
2
    JS_RunGCInternal(rt, FALSE);
1927
1928
#ifdef DUMP_LEAKS
1929
    /* leaking objects */
1930
    {
1931
        BOOL header_done;
1932
        JSGCObjectHeader *p;
1933
        int count;
1934
1935
        /* remove the internal refcounts to display only the object
1936
           referenced externally */
1937
        list_for_each(el, &rt->gc_obj_list) {
1938
            p = list_entry(el, JSGCObjectHeader, link);
1939
            p->mark = 0;
1940
        }
1941
        gc_decref(rt);
1942
1943
        header_done = FALSE;
1944
        list_for_each(el, &rt->gc_obj_list) {
1945
            p = list_entry(el, JSGCObjectHeader, link);
1946
            if (p->ref_count != 0) {
1947
                if (!header_done) {
1948
                    printf("Object leaks:\n");
1949
                    JS_DumpObjectHeader(rt);
1950
                    header_done = TRUE;
1951
                }
1952
                JS_DumpGCObject(rt, p);
1953
            }
1954
        }
1955
1956
        count = 0;
1957
        list_for_each(el, &rt->gc_obj_list) {
1958
            p = list_entry(el, JSGCObjectHeader, link);
1959
            if (p->ref_count == 0) {
1960
                count++;
1961
            }
1962
        }
1963
        if (count != 0)
1964
            printf("Secondary object leaks: %d\n", count);
1965
    }
1966
#endif
1967
2
    assert(list_empty(&rt->gc_obj_list));
1968
2
    assert(list_empty(&rt->weakref_list));
1969
1970
    /* free the classes */
1971
172
    for(i = 0; i < rt->class_count; i++) {
1972
170
        JSClass *cl = &rt->class_array[i];
1973
170
        if (cl->class_id != 0) {
1974
114
            JS_FreeAtomRT(rt, cl->class_name);
1975
114
        }
1976
170
    }
1977
2
    js_free_rt(rt, rt->class_array);
1978
1979
#ifdef DUMP_LEAKS
1980
    /* only the atoms defined in JS_InitAtoms() should be left */
1981
    {
1982
        BOOL header_done = FALSE;
1983
1984
        for(i = 0; i < rt->atom_size; i++) {
1985
            JSAtomStruct *p = rt->atom_array[i];
1986
            if (!atom_is_free(p) /* && p->str*/) {
1987
                if (i >= JS_ATOM_END || p->header.ref_count != 1) {
1988
                    if (!header_done) {
1989
                        header_done = TRUE;
1990
                        if (rt->rt_info) {
1991
                            printf("%s:1: atom leakage:", rt->rt_info);
1992
                        } else {
1993
                            printf("Atom leaks:\n"
1994
                                   "    %6s %6s %s\n",
1995
                                   "ID", "REFCNT", "NAME");
1996
                        }
1997
                    }
1998
                    if (rt->rt_info) {
1999
                        printf(" ");
2000
                    } else {
2001
                        printf("    %6u %6u ", i, p->header.ref_count);
2002
                    }
2003
                    switch (p->atom_type) {
2004
                    case JS_ATOM_TYPE_STRING:
2005
                        JS_DumpString(rt, p);
2006
                        break;
2007
                    case JS_ATOM_TYPE_GLOBAL_SYMBOL:
2008
                        printf("Symbol.for(");
2009
                        JS_DumpString(rt, p);
2010
                        printf(")");
2011
                        break;
2012
                    case JS_ATOM_TYPE_SYMBOL:
2013
                        if (p->hash != JS_ATOM_HASH_PRIVATE) {
2014
                            printf("Symbol(");
2015
                            JS_DumpString(rt, p);
2016
                            printf(")");
2017
                        } else {
2018
                            printf("Private(");
2019
                            JS_DumpString(rt, p);
2020
                            printf(")");
2021
                        }
2022
                        break;
2023
                    }
2024
                    if (rt->rt_info) {
2025
                        printf(":%u", p->header.ref_count);
2026
                    } else {
2027
                        printf("\n");
2028
                    }
2029
                }
2030
            }
2031
        }
2032
        if (rt->rt_info && header_done)
2033
            printf("\n");
2034
    }
2035
#endif
2036
2037
    /* free the atoms */
2038
1.42k
    for(i = 0; i < rt->atom_size; i++) {
2039
1.42k
        JSAtomStruct *p = rt->atom_array[i];
2040
1.42k
        if (!atom_is_free(p)) {
2041
#ifdef DUMP_LEAKS
2042
            list_del(&p->link);
2043
#endif
2044
460
            js_free_rt(rt, p);
2045
460
        }
2046
1.42k
    }
2047
2
    js_free_rt(rt, rt->atom_array);
2048
2
    js_free_rt(rt, rt->atom_hash);
2049
2
    js_free_rt(rt, rt->shape_hash);
2050
#ifdef DUMP_LEAKS
2051
    if (!list_empty(&rt->string_list)) {
2052
        if (rt->rt_info) {
2053
            printf("%s:1: string leakage:", rt->rt_info);
2054
        } else {
2055
            printf("String leaks:\n"
2056
                   "    %6s %s\n",
2057
                   "REFCNT", "VALUE");
2058
        }
2059
        list_for_each_safe(el, el1, &rt->string_list) {
2060
            JSString *str = list_entry(el, JSString, link);
2061
            if (rt->rt_info) {
2062
                printf(" ");
2063
            } else {
2064
                printf("    %6u ", str->header.ref_count);
2065
            }
2066
            JS_DumpString(rt, str);
2067
            if (rt->rt_info) {
2068
                printf(":%u", str->header.ref_count);
2069
            } else {
2070
                printf("\n");
2071
            }
2072
            list_del(&str->link);
2073
            js_free_rt(rt, str);
2074
        }
2075
        if (rt->rt_info)
2076
            printf("\n");
2077
    }
2078
    {
2079
        JSMallocState *s = &rt->malloc_state;
2080
        if (s->malloc_count > 1) {
2081
            if (rt->rt_info)
2082
                printf("%s:1: ", rt->rt_info);
2083
            printf("Memory leak: %"PRIu64" bytes lost in %"PRIu64" block%s\n",
2084
                   (uint64_t)(s->malloc_size - sizeof(JSRuntime)),
2085
                   (uint64_t)(s->malloc_count - 1), &"s"[s->malloc_count == 2]);
2086
        }
2087
    }
2088
#endif
2089
2090
2
    {
2091
2
        JSMallocState ms = rt->malloc_state;
2092
2
        rt->mf.js_free(&ms, rt);
2093
2
    }
2094
2
}
2095
2096
JSContext *JS_NewContextRaw(JSRuntime *rt)
2097
2
{
2098
2
    JSContext *ctx;
2099
2
    int i;
2100
2101
2
    ctx = js_mallocz_rt(rt, sizeof(JSContext));
2102
2
    if (!ctx)
2103
0
        return NULL;
2104
2
    ctx->header.ref_count = 1;
2105
2
    add_gc_object(rt, &ctx->header, JS_GC_OBJ_TYPE_JS_CONTEXT);
2106
2107
2
    ctx->class_proto = js_malloc_rt(rt, sizeof(ctx->class_proto[0]) *
2108
2
                                    rt->class_count);
2109
2
    if (!ctx->class_proto) {
2110
0
        js_free_rt(rt, ctx);
2111
0
        return NULL;
2112
0
    }
2113
2
    ctx->rt = rt;
2114
2
    list_add_tail(&ctx->link, &rt->context_list);
2115
116
    for(i = 0; i < rt->class_count; i++)
2116
114
        ctx->class_proto[i] = JS_NULL;
2117
2
    ctx->array_ctor = JS_NULL;
2118
2
    ctx->regexp_ctor = JS_NULL;
2119
2
    ctx->promise_ctor = JS_NULL;
2120
2
    init_list_head(&ctx->loaded_modules);
2121
2122
2
    JS_AddIntrinsicBasicObjects(ctx);
2123
2
    return ctx;
2124
2
}
2125
2126
JSContext *JS_NewContext(JSRuntime *rt)
2127
2
{
2128
2
    JSContext *ctx;
2129
2130
2
    ctx = JS_NewContextRaw(rt);
2131
2
    if (!ctx)
2132
0
        return NULL;
2133
2134
2
    JS_AddIntrinsicBaseObjects(ctx);
2135
2
    JS_AddIntrinsicDate(ctx);
2136
2
    JS_AddIntrinsicEval(ctx);
2137
2
    JS_AddIntrinsicStringNormalize(ctx);
2138
2
    JS_AddIntrinsicRegExp(ctx);
2139
2
    JS_AddIntrinsicJSON(ctx);
2140
2
    JS_AddIntrinsicProxy(ctx);
2141
2
    JS_AddIntrinsicMapSet(ctx);
2142
2
    JS_AddIntrinsicTypedArrays(ctx);
2143
2
    JS_AddIntrinsicPromise(ctx);
2144
2
    JS_AddIntrinsicWeakRef(ctx);
2145
2
    return ctx;
2146
2
}
2147
2148
void *JS_GetContextOpaque(JSContext *ctx)
2149
0
{
2150
0
    return ctx->user_opaque;
2151
0
}
2152
2153
void JS_SetContextOpaque(JSContext *ctx, void *opaque)
2154
0
{
2155
0
    ctx->user_opaque = opaque;
2156
0
}
2157
2158
/* set the new value and free the old value after (freeing the value
2159
   can reallocate the object data) */
2160
static inline void set_value(JSContext *ctx, JSValue *pval, JSValue new_val)
2161
208
{
2162
208
    JSValue old_val;
2163
208
    old_val = *pval;
2164
208
    *pval = new_val;
2165
208
    JS_FreeValue(ctx, old_val);
2166
208
}
2167
2168
void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj)
2169
2
{
2170
2
    JSRuntime *rt = ctx->rt;
2171
2
    assert(class_id < rt->class_count);
2172
2
    set_value(ctx, &ctx->class_proto[class_id], obj);
2173
2
}
2174
2175
JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id)
2176
0
{
2177
0
    JSRuntime *rt = ctx->rt;
2178
0
    assert(class_id < rt->class_count);
2179
0
    return JS_DupValue(ctx, ctx->class_proto[class_id]);
2180
0
}
2181
2182
typedef enum JSFreeModuleEnum {
2183
    JS_FREE_MODULE_ALL,
2184
    JS_FREE_MODULE_NOT_RESOLVED,
2185
} JSFreeModuleEnum;
2186
2187
/* XXX: would be more efficient with separate module lists */
2188
static void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag)
2189
2
{
2190
2
    struct list_head *el, *el1;
2191
2
    list_for_each_safe(el, el1, &ctx->loaded_modules) {
2192
0
        JSModuleDef *m = list_entry(el, JSModuleDef, link);
2193
0
        if (flag == JS_FREE_MODULE_ALL ||
2194
0
            (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved)) {
2195
            /* warning: the module may be referenced elsewhere. It
2196
               could be simpler to use an array instead of a list for
2197
               'ctx->loaded_modules' */
2198
0
            list_del(&m->link);
2199
0
            m->link.prev = NULL;
2200
0
            m->link.next = NULL;
2201
0
            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
2202
0
        }
2203
0
    }
2204
2
}
2205
2206
JSContext *JS_DupContext(JSContext *ctx)
2207
1.08k
{
2208
1.08k
    ctx->header.ref_count++;
2209
1.08k
    return ctx;
2210
1.08k
}
2211
2212
/* used by the GC */
2213
static void JS_MarkContext(JSRuntime *rt, JSContext *ctx,
2214
                           JS_MarkFunc *mark_func)
2215
4
{
2216
4
    int i;
2217
4
    struct list_head *el;
2218
2219
16
    list_for_each(el, &ctx->loaded_modules) {
2220
16
        JSModuleDef *m = list_entry(el, JSModuleDef, link);
2221
16
        JS_MarkValue(rt, JS_MKPTR(JS_TAG_MODULE, m), mark_func);
2222
16
    }
2223
2224
4
    JS_MarkValue(rt, ctx->global_obj, mark_func);
2225
4
    JS_MarkValue(rt, ctx->global_var_obj, mark_func);
2226
2227
4
    JS_MarkValue(rt, ctx->throw_type_error, mark_func);
2228
4
    JS_MarkValue(rt, ctx->eval_obj, mark_func);
2229
2230
4
    JS_MarkValue(rt, ctx->array_proto_values, mark_func);
2231
36
    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
2232
32
        JS_MarkValue(rt, ctx->native_error_proto[i], mark_func);
2233
32
    }
2234
344
    for(i = 0; i < rt->class_count; i++) {
2235
340
        JS_MarkValue(rt, ctx->class_proto[i], mark_func);
2236
340
    }
2237
4
    JS_MarkValue(rt, ctx->iterator_proto, mark_func);
2238
4
    JS_MarkValue(rt, ctx->async_iterator_proto, mark_func);
2239
4
    JS_MarkValue(rt, ctx->promise_ctor, mark_func);
2240
4
    JS_MarkValue(rt, ctx->array_ctor, mark_func);
2241
4
    JS_MarkValue(rt, ctx->regexp_ctor, mark_func);
2242
4
    JS_MarkValue(rt, ctx->function_ctor, mark_func);
2243
4
    JS_MarkValue(rt, ctx->function_proto, mark_func);
2244
2245
4
    if (ctx->array_shape)
2246
4
        mark_func(rt, &ctx->array_shape->header);
2247
4
}
2248
2249
void JS_FreeContext(JSContext *ctx)
2250
1.08k
{
2251
1.08k
    JSRuntime *rt = ctx->rt;
2252
1.08k
    int i;
2253
2254
1.08k
    if (--ctx->header.ref_count > 0)
2255
1.08k
        return;
2256
2
    assert(ctx->header.ref_count == 0);
2257
2258
#ifdef DUMP_ATOMS
2259
    JS_DumpAtoms(ctx->rt);
2260
#endif
2261
#ifdef DUMP_SHAPES
2262
    JS_DumpShapes(ctx->rt);
2263
#endif
2264
#ifdef DUMP_OBJECTS
2265
    {
2266
        struct list_head *el;
2267
        JSGCObjectHeader *p;
2268
        printf("JSObjects: {\n");
2269
        JS_DumpObjectHeader(ctx->rt);
2270
        list_for_each(el, &rt->gc_obj_list) {
2271
            p = list_entry(el, JSGCObjectHeader, link);
2272
            JS_DumpGCObject(rt, p);
2273
        }
2274
        printf("}\n");
2275
    }
2276
#endif
2277
#ifdef DUMP_MEM
2278
    {
2279
        JSMemoryUsage stats;
2280
        JS_ComputeMemoryUsage(rt, &stats);
2281
        JS_DumpMemoryUsage(stdout, &stats, rt);
2282
    }
2283
#endif
2284
2285
2
    js_free_modules(ctx, JS_FREE_MODULE_ALL);
2286
2287
2
    JS_FreeValue(ctx, ctx->global_obj);
2288
2
    JS_FreeValue(ctx, ctx->global_var_obj);
2289
2290
2
    JS_FreeValue(ctx, ctx->throw_type_error);
2291
2
    JS_FreeValue(ctx, ctx->eval_obj);
2292
2293
2
    JS_FreeValue(ctx, ctx->array_proto_values);
2294
18
    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
2295
16
        JS_FreeValue(ctx, ctx->native_error_proto[i]);
2296
16
    }
2297
172
    for(i = 0; i < rt->class_count; i++) {
2298
170
        JS_FreeValue(ctx, ctx->class_proto[i]);
2299
170
    }
2300
2
    js_free_rt(rt, ctx->class_proto);
2301
2
    JS_FreeValue(ctx, ctx->iterator_proto);
2302
2
    JS_FreeValue(ctx, ctx->async_iterator_proto);
2303
2
    JS_FreeValue(ctx, ctx->promise_ctor);
2304
2
    JS_FreeValue(ctx, ctx->array_ctor);
2305
2
    JS_FreeValue(ctx, ctx->regexp_ctor);
2306
2
    JS_FreeValue(ctx, ctx->function_ctor);
2307
2
    JS_FreeValue(ctx, ctx->function_proto);
2308
2309
2
    js_free_shape_null(ctx->rt, ctx->array_shape);
2310
2311
2
    list_del(&ctx->link);
2312
2
    remove_gc_object(&ctx->header);
2313
2
    js_free_rt(ctx->rt, ctx);
2314
2
}
2315
2316
JSRuntime *JS_GetRuntime(JSContext *ctx)
2317
7
{
2318
7
    return ctx->rt;
2319
7
}
2320
2321
static void update_stack_limit(JSRuntime *rt)
2322
4
{
2323
4
    if (rt->stack_size == 0) {
2324
0
        rt->stack_limit = 0; /* no limit */
2325
4
    } else {
2326
4
        rt->stack_limit = rt->stack_top - rt->stack_size;
2327
4
    }
2328
4
}
2329
2330
void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size)
2331
2
{
2332
2
    rt->stack_size = stack_size;
2333
2
    update_stack_limit(rt);
2334
2
}
2335
2336
void JS_UpdateStackTop(JSRuntime *rt)
2337
2
{
2338
2
    rt->stack_top = js_get_stack_pointer();
2339
2
    update_stack_limit(rt);
2340
2
}
2341
2342
static inline BOOL is_strict_mode(JSContext *ctx)
2343
0
{
2344
0
    JSStackFrame *sf = ctx->rt->current_stack_frame;
2345
0
    return (sf && (sf->js_mode & JS_MODE_STRICT));
2346
0
}
2347
2348
/* JSAtom support */
2349
2350
4.26k
#define JS_ATOM_TAG_INT (1U << 31)
2351
0
#define JS_ATOM_MAX_INT (JS_ATOM_TAG_INT - 1)
2352
8
#define JS_ATOM_MAX     ((1U << 30) - 1)
2353
2354
/* return the max count from the hash size */
2355
4
#define JS_ATOM_COUNT_RESIZE(n) ((n) * 2)
2356
2357
static inline BOOL __JS_AtomIsConst(JSAtom v)
2358
7.96k
{
2359
#if defined(DUMP_LEAKS) && DUMP_LEAKS > 1
2360
        return (int32_t)v <= 0;
2361
#else
2362
7.96k
        return (int32_t)v < JS_ATOM_END;
2363
7.96k
#endif
2364
7.96k
}
2365
2366
static inline BOOL __JS_AtomIsTaggedInt(JSAtom v)
2367
4.26k
{
2368
4.26k
    return (v & JS_ATOM_TAG_INT) != 0;
2369
4.26k
}
2370
2371
static inline JSAtom __JS_AtomFromUInt32(uint32_t v)
2372
0
{
2373
0
    return v | JS_ATOM_TAG_INT;
2374
0
}
2375
2376
static inline uint32_t __JS_AtomToUInt32(JSAtom atom)
2377
0
{
2378
0
    return atom & ~JS_ATOM_TAG_INT;
2379
0
}
2380
2381
static inline int is_num(int c)
2382
575
{
2383
575
    return c >= '0' && c <= '9';
2384
575
}
2385
2386
/* return TRUE if the string is a number n with 0 <= n <= 2^32-1 */
2387
static inline BOOL is_num_string(uint32_t *pval, const JSString *p)
2388
767
{
2389
767
    uint32_t n;
2390
767
    uint64_t n64;
2391
767
    int c, i, len;
2392
2393
767
    len = p->len;
2394
767
    if (len == 0 || len > 10)
2395
192
        return FALSE;
2396
575
    c = string_get(p, 0);
2397
575
    if (is_num(c)) {
2398
0
        if (c == '0') {
2399
0
            if (len != 1)
2400
0
                return FALSE;
2401
0
            n = 0;
2402
0
        } else {
2403
0
            n = c - '0';
2404
0
            for(i = 1; i < len; i++) {
2405
0
                c = string_get(p, i);
2406
0
                if (!is_num(c))
2407
0
                    return FALSE;
2408
0
                n64 = (uint64_t)n * 10 + (c - '0');
2409
0
                if ((n64 >> 32) != 0)
2410
0
                    return FALSE;
2411
0
                n = n64;
2412
0
            }
2413
0
        }
2414
0
        *pval = n;
2415
0
        return TRUE;
2416
575
    } else {
2417
575
        return FALSE;
2418
575
    }
2419
575
}
2420
2421
/* XXX: could use faster version ? */
2422
static inline uint32_t hash_string8(const uint8_t *str, size_t len, uint32_t h)
2423
2.99k
{
2424
2.99k
    size_t i;
2425
2426
27.4k
    for(i = 0; i < len; i++)
2427
24.4k
        h = h * 263 + str[i];
2428
2.99k
    return h;
2429
2.99k
}
2430
2431
static inline uint32_t hash_string16(const uint16_t *str,
2432
                                     size_t len, uint32_t h)
2433
0
{
2434
0
    size_t i;
2435
2436
0
    for(i = 0; i < len; i++)
2437
0
        h = h * 263 + str[i];
2438
0
    return h;
2439
0
}
2440
2441
static uint32_t hash_string(const JSString *str, uint32_t h)
2442
1.18k
{
2443
1.18k
    if (str->is_wide_char)
2444
0
        h = hash_string16(str->u.str16, str->len, h);
2445
1.18k
    else
2446
1.18k
        h = hash_string8(str->u.str8, str->len, h);
2447
1.18k
    return h;
2448
1.18k
}
2449
2450
static uint32_t hash_string_rope(JSValueConst val, uint32_t h)
2451
0
{
2452
0
    if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
2453
0
        return hash_string(JS_VALUE_GET_STRING(val), h);
2454
0
    } else {
2455
0
        JSStringRope *r = JS_VALUE_GET_STRING_ROPE(val);
2456
0
        h = hash_string_rope(r->left, h);
2457
0
        return hash_string_rope(r->right, h);
2458
0
    }
2459
0
}
2460
2461
static __maybe_unused void JS_DumpChar(FILE *fo, int c, int sep)
2462
0
{
2463
0
    if (c == sep || c == '\\') {
2464
0
        fputc('\\', fo);
2465
0
        fputc(c, fo);
2466
0
    } else if (c >= ' ' && c <= 126) {
2467
0
        fputc(c, fo);
2468
0
    } else if (c == '\n') {
2469
0
        fputc('\\', fo);
2470
0
        fputc('n', fo);
2471
0
    } else {
2472
0
        fprintf(fo, "\\u%04x", c);
2473
0
    }
2474
0
}
2475
2476
static __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p)
2477
0
{
2478
0
    int i, sep;
2479
0
2480
0
    if (p == NULL) {
2481
0
        printf("<null>");
2482
0
        return;
2483
0
    }
2484
0
    printf("%d", p->header.ref_count);
2485
0
    sep = (p->header.ref_count == 1) ? '\"' : '\'';
2486
0
    putchar(sep);
2487
0
    for(i = 0; i < p->len; i++) {
2488
0
        JS_DumpChar(stdout, string_get(p, i), sep);
2489
0
    }
2490
0
    putchar(sep);
2491
0
}
2492
2493
static __maybe_unused void JS_DumpAtoms(JSRuntime *rt)
2494
0
{
2495
0
    JSAtomStruct *p;
2496
0
    int h, i;
2497
0
    /* This only dumps hashed atoms, not JS_ATOM_TYPE_SYMBOL atoms */
2498
0
    printf("JSAtom count=%d size=%d hash_size=%d:\n",
2499
0
           rt->atom_count, rt->atom_size, rt->atom_hash_size);
2500
0
    printf("JSAtom hash table: {\n");
2501
0
    for(i = 0; i < rt->atom_hash_size; i++) {
2502
0
        h = rt->atom_hash[i];
2503
0
        if (h) {
2504
0
            printf("  %d:", i);
2505
0
            while (h) {
2506
0
                p = rt->atom_array[h];
2507
0
                printf(" ");
2508
0
                JS_DumpString(rt, p);
2509
0
                h = p->hash_next;
2510
0
            }
2511
0
            printf("\n");
2512
0
        }
2513
0
    }
2514
0
    printf("}\n");
2515
0
    printf("JSAtom table: {\n");
2516
0
    for(i = 0; i < rt->atom_size; i++) {
2517
0
        p = rt->atom_array[i];
2518
0
        if (!atom_is_free(p)) {
2519
0
            printf("  %d: { %d %08x ", i, p->atom_type, p->hash);
2520
0
            if (!(p->len == 0 && p->is_wide_char != 0))
2521
0
                JS_DumpString(rt, p);
2522
0
            printf(" %d }\n", p->hash_next);
2523
0
        }
2524
0
    }
2525
0
    printf("}\n");
2526
0
}
2527
2528
static int JS_ResizeAtomHash(JSRuntime *rt, int new_hash_size)
2529
4
{
2530
4
    JSAtomStruct *p;
2531
4
    uint32_t new_hash_mask, h, i, hash_next1, j, *new_hash;
2532
2533
4
    assert((new_hash_size & (new_hash_size - 1)) == 0); /* power of two */
2534
4
    new_hash_mask = new_hash_size - 1;
2535
4
    new_hash = js_mallocz_rt(rt, sizeof(rt->atom_hash[0]) * new_hash_size);
2536
4
    if (!new_hash)
2537
0
        return -1;
2538
516
    for(i = 0; i < rt->atom_hash_size; i++) {
2539
512
        h = rt->atom_hash[i];
2540
1.50k
        while (h != 0) {
2541
994
            p = rt->atom_array[h];
2542
994
            hash_next1 = p->hash_next;
2543
            /* add in new hash table */
2544
994
            j = p->hash & new_hash_mask;
2545
994
            p->hash_next = new_hash[j];
2546
994
            new_hash[j] = h;
2547
994
            h = hash_next1;
2548
994
        }
2549
512
    }
2550
4
    js_free_rt(rt, rt->atom_hash);
2551
4
    rt->atom_hash = new_hash;
2552
4
    rt->atom_hash_size = new_hash_size;
2553
4
    rt->atom_count_resize = JS_ATOM_COUNT_RESIZE(new_hash_size);
2554
    //    JS_DumpAtoms(rt);
2555
4
    return 0;
2556
4
}
2557
2558
static int JS_InitAtoms(JSRuntime *rt)
2559
2
{
2560
2
    int i, len, atom_type;
2561
2
    const char *p;
2562
2563
2
    rt->atom_hash_size = 0;
2564
2
    rt->atom_hash = NULL;
2565
2
    rt->atom_count = 0;
2566
2
    rt->atom_size = 0;
2567
2
    rt->atom_free_index = 0;
2568
2
    if (JS_ResizeAtomHash(rt, 256))     /* there are at least 195 predefined atoms */
2569
0
        return -1;
2570
2571
2
    p = js_atom_init;
2572
460
    for(i = 1; i < JS_ATOM_END; i++) {
2573
458
        if (i == JS_ATOM_Private_brand)
2574
2
            atom_type = JS_ATOM_TYPE_PRIVATE;
2575
456
        else if (i >= JS_ATOM_Symbol_toPrimitive)
2576
26
            atom_type = JS_ATOM_TYPE_SYMBOL;
2577
430
        else
2578
430
            atom_type = JS_ATOM_TYPE_STRING;
2579
458
        len = strlen(p);
2580
458
        if (__JS_NewAtomInit(rt, p, len, atom_type) == JS_ATOM_NULL)
2581
0
            return -1;
2582
458
        p = p + len + 1;
2583
458
    }
2584
2
    return 0;
2585
2
}
2586
2587
static JSAtom JS_DupAtomRT(JSRuntime *rt, JSAtom v)
2588
114
{
2589
114
    JSAtomStruct *p;
2590
2591
114
    if (!__JS_AtomIsConst(v)) {
2592
2
        p = rt->atom_array[v];
2593
2
        p->header.ref_count++;
2594
2
    }
2595
114
    return v;
2596
114
}
2597
2598
JSAtom JS_DupAtom(JSContext *ctx, JSAtom v)
2599
2.43k
{
2600
2.43k
    JSRuntime *rt;
2601
2.43k
    JSAtomStruct *p;
2602
2603
2.43k
    if (!__JS_AtomIsConst(v)) {
2604
1.10k
        rt = ctx->rt;
2605
1.10k
        p = rt->atom_array[v];
2606
1.10k
        p->header.ref_count++;
2607
1.10k
    }
2608
2.43k
    return v;
2609
2.43k
}
2610
2611
static JSAtomKindEnum JS_AtomGetKind(JSContext *ctx, JSAtom v)
2612
8
{
2613
8
    JSRuntime *rt;
2614
8
    JSAtomStruct *p;
2615
2616
8
    rt = ctx->rt;
2617
8
    if (__JS_AtomIsTaggedInt(v))
2618
0
        return JS_ATOM_KIND_STRING;
2619
8
    p = rt->atom_array[v];
2620
8
    switch(p->atom_type) {
2621
8
    case JS_ATOM_TYPE_STRING:
2622
8
        return JS_ATOM_KIND_STRING;
2623
0
    case JS_ATOM_TYPE_GLOBAL_SYMBOL:
2624
0
        return JS_ATOM_KIND_SYMBOL;
2625
0
    case JS_ATOM_TYPE_SYMBOL:
2626
0
        if (p->hash == JS_ATOM_HASH_PRIVATE)
2627
0
            return JS_ATOM_KIND_PRIVATE;
2628
0
        else
2629
0
            return JS_ATOM_KIND_SYMBOL;
2630
0
    default:
2631
0
        abort();
2632
8
    }
2633
8
}
2634
2635
static BOOL JS_AtomIsString(JSContext *ctx, JSAtom v)
2636
0
{
2637
0
    return JS_AtomGetKind(ctx, v) == JS_ATOM_KIND_STRING;
2638
0
}
2639
2640
static JSAtom js_get_atom_index(JSRuntime *rt, JSAtomStruct *p)
2641
0
{
2642
0
    uint32_t i = p->hash_next;  /* atom_index */
2643
0
    if (p->atom_type != JS_ATOM_TYPE_SYMBOL) {
2644
0
        JSAtomStruct *p1;
2645
2646
0
        i = rt->atom_hash[p->hash & (rt->atom_hash_size - 1)];
2647
0
        p1 = rt->atom_array[i];
2648
0
        while (p1 != p) {
2649
0
            assert(i != 0);
2650
0
            i = p1->hash_next;
2651
0
            p1 = rt->atom_array[i];
2652
0
        }
2653
0
    }
2654
0
    return i;
2655
0
}
2656
2657
/* string case (internal). Return JS_ATOM_NULL if error. 'str' is
2658
   freed. */
2659
static JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type)
2660
1.21k
{
2661
1.21k
    uint32_t h, h1, i;
2662
1.21k
    JSAtomStruct *p;
2663
1.21k
    int len;
2664
2665
#if 0
2666
    printf("__JS_NewAtom: ");  JS_DumpString(rt, str); printf("\n");
2667
#endif
2668
1.21k
    if (atom_type < JS_ATOM_TYPE_SYMBOL) {
2669
        /* str is not NULL */
2670
1.18k
        if (str->atom_type == atom_type) {
2671
            /* str is the atom, return its index */
2672
0
            i = js_get_atom_index(rt, str);
2673
            /* reduce string refcount and increase atom's unless constant */
2674
0
            if (__JS_AtomIsConst(i))
2675
0
                str->header.ref_count--;
2676
0
            return i;
2677
0
        }
2678
        /* try and locate an already registered atom */
2679
1.18k
        len = str->len;
2680
1.18k
        h = hash_string(str, atom_type);
2681
1.18k
        h &= JS_ATOM_HASH_MASK;
2682
1.18k
        h1 = h & (rt->atom_hash_size - 1);
2683
1.18k
        i = rt->atom_hash[h1];
2684
2.43k
        while (i != 0) {
2685
1.25k
            p = rt->atom_array[i];
2686
1.25k
            if (p->hash == h &&
2687
1.25k
                p->atom_type == atom_type &&
2688
1.25k
                p->len == len &&
2689
1.25k
                js_string_memcmp(p, 0, str, 0, len) == 0) {
2690
6
                if (!__JS_AtomIsConst(i))
2691
6
                    p->header.ref_count++;
2692
6
                goto done;
2693
6
            }
2694
1.24k
            i = p->hash_next;
2695
1.24k
        }
2696
1.18k
    } else {
2697
28
        h1 = 0; /* avoid warning */
2698
28
        if (atom_type == JS_ATOM_TYPE_SYMBOL) {
2699
26
            h = 0;
2700
26
        } else {
2701
2
            h = JS_ATOM_HASH_PRIVATE;
2702
2
            atom_type = JS_ATOM_TYPE_SYMBOL;
2703
2
        }
2704
28
    }
2705
2706
1.21k
    if (rt->atom_free_index == 0) {
2707
        /* allow new atom entries */
2708
8
        uint32_t new_size, start;
2709
8
        JSAtomStruct **new_array;
2710
2711
        /* alloc new with size progression 3/2:
2712
           4 6 9 13 19 28 42 63 94 141 211 316 474 711 1066 1599 2398 3597 5395 8092
2713
           preallocating space for predefined atoms (at least 195).
2714
         */
2715
8
        new_size = max_int(211, rt->atom_size * 3 / 2);
2716
8
        if (new_size > JS_ATOM_MAX)
2717
0
            goto fail;
2718
        /* XXX: should use realloc2 to use slack space */
2719
8
        new_array = js_realloc_rt(rt, rt->atom_array, sizeof(*new_array) * new_size);
2720
8
        if (!new_array)
2721
0
            goto fail;
2722
        /* Note: the atom 0 is not used */
2723
8
        start = rt->atom_size;
2724
8
        if (start == 0) {
2725
            /* JS_ATOM_NULL entry */
2726
2
            p = js_mallocz_rt(rt, sizeof(JSAtomStruct));
2727
2
            if (!p) {
2728
0
                js_free_rt(rt, new_array);
2729
0
                goto fail;
2730
0
            }
2731
2
            p->header.ref_count = 1;  /* not refcounted */
2732
2
            p->atom_type = JS_ATOM_TYPE_SYMBOL;
2733
#ifdef DUMP_LEAKS
2734
            list_add_tail(&p->link, &rt->string_list);
2735
#endif
2736
2
            new_array[0] = p;
2737
2
            rt->atom_count++;
2738
2
            start = 1;
2739
2
        }
2740
8
        rt->atom_size = new_size;
2741
8
        rt->atom_array = new_array;
2742
8
        rt->atom_free_index = start;
2743
1.42k
        for(i = start; i < new_size; i++) {
2744
1.42k
            uint32_t next;
2745
1.42k
            if (i == (new_size - 1))
2746
8
                next = 0;
2747
1.41k
            else
2748
1.41k
                next = i + 1;
2749
1.42k
            rt->atom_array[i] = atom_set_free(next);
2750
1.42k
        }
2751
8
    }
2752
2753
1.21k
    if (str) {
2754
1.21k
        if (str->atom_type == 0) {
2755
1.21k
            p = str;
2756
1.21k
            p->atom_type = atom_type;
2757
1.21k
        } else {
2758
0
            p = js_malloc_rt(rt, sizeof(JSString) +
2759
0
                             (str->len << str->is_wide_char) +
2760
0
                             1 - str->is_wide_char);
2761
0
            if (unlikely(!p))
2762
0
                goto fail;
2763
0
            p->header.ref_count = 1;
2764
0
            p->is_wide_char = str->is_wide_char;
2765
0
            p->len = str->len;
2766
#ifdef DUMP_LEAKS
2767
            list_add_tail(&p->link, &rt->string_list);
2768
#endif
2769
0
            memcpy(p->u.str8, str->u.str8, (str->len << str->is_wide_char) +
2770
0
                   1 - str->is_wide_char);
2771
0
            js_free_string(rt, str);
2772
0
        }
2773
1.21k
    } else {
2774
0
        p = js_malloc_rt(rt, sizeof(JSAtomStruct)); /* empty wide string */
2775
0
        if (!p)
2776
0
            return JS_ATOM_NULL;
2777
0
        p->header.ref_count = 1;
2778
0
        p->is_wide_char = 1;    /* Hack to represent NULL as a JSString */
2779
0
        p->len = 0;
2780
#ifdef DUMP_LEAKS
2781
        list_add_tail(&p->link, &rt->string_list);
2782
#endif
2783
0
    }
2784
2785
    /* use an already free entry */
2786
1.21k
    i = rt->atom_free_index;
2787
1.21k
    rt->atom_free_index = atom_get_free(rt->atom_array[i]);
2788
1.21k
    rt->atom_array[i] = p;
2789
2790
1.21k
    p->hash = h;
2791
1.21k
    p->hash_next = i;   /* atom_index */
2792
1.21k
    p->atom_type = atom_type;
2793
2794
1.21k
    rt->atom_count++;
2795
2796
1.21k
    if (atom_type != JS_ATOM_TYPE_SYMBOL) {
2797
1.18k
        p->hash_next = rt->atom_hash[h1];
2798
1.18k
        rt->atom_hash[h1] = i;
2799
1.18k
        if (unlikely(rt->atom_count >= rt->atom_count_resize))
2800
2
            JS_ResizeAtomHash(rt, rt->atom_hash_size * 2);
2801
1.18k
    }
2802
2803
    //    JS_DumpAtoms(rt);
2804
1.21k
    return i;
2805
2806
0
 fail:
2807
0
    i = JS_ATOM_NULL;
2808
6
 done:
2809
6
    if (str)
2810
6
        js_free_string(rt, str);
2811
6
    return i;
2812
0
}
2813
2814
/* only works with zero terminated 8 bit strings */
2815
static JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,
2816
                               int atom_type)
2817
460
{
2818
460
    JSString *p;
2819
460
    p = js_alloc_string_rt(rt, len, 0);
2820
460
    if (!p)
2821
0
        return JS_ATOM_NULL;
2822
460
    memcpy(p->u.str8, str, len);
2823
460
    p->u.str8[len] = '\0';
2824
460
    return __JS_NewAtom(rt, p, atom_type);
2825
460
}
2826
2827
/* Warning: str must be ASCII only */
2828
static JSAtom __JS_FindAtom(JSRuntime *rt, const char *str, size_t len,
2829
                            int atom_type)
2830
1.80k
{
2831
1.80k
    uint32_t h, h1, i;
2832
1.80k
    JSAtomStruct *p;
2833
2834
1.80k
    h = hash_string8((const uint8_t *)str, len, JS_ATOM_TYPE_STRING);
2835
1.80k
    h &= JS_ATOM_HASH_MASK;
2836
1.80k
    h1 = h & (rt->atom_hash_size - 1);
2837
1.80k
    i = rt->atom_hash[h1];
2838
3.55k
    while (i != 0) {
2839
2.80k
        p = rt->atom_array[i];
2840
2.80k
        if (p->hash == h &&
2841
2.80k
            p->atom_type == JS_ATOM_TYPE_STRING &&
2842
2.80k
            p->len == len &&
2843
2.80k
            p->is_wide_char == 0 &&
2844
2.80k
            memcmp(p->u.str8, str, len) == 0) {
2845
1.04k
            if (!__JS_AtomIsConst(i))
2846
588
                p->header.ref_count++;
2847
1.04k
            return i;
2848
1.04k
        }
2849
1.75k
        i = p->hash_next;
2850
1.75k
    }
2851
753
    return JS_ATOM_NULL;
2852
1.80k
}
2853
2854
static void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p)
2855
753
{
2856
#if 0   /* JS_ATOM_NULL is not refcounted: __JS_AtomIsConst() includes 0 */
2857
    if (unlikely(i == JS_ATOM_NULL)) {
2858
        p->header.ref_count = INT32_MAX / 2;
2859
        return;
2860
    }
2861
#endif
2862
753
    uint32_t i = p->hash_next;  /* atom_index */
2863
753
    if (p->atom_type != JS_ATOM_TYPE_SYMBOL) {
2864
753
        JSAtomStruct *p0, *p1;
2865
753
        uint32_t h0;
2866
2867
753
        h0 = p->hash & (rt->atom_hash_size - 1);
2868
753
        i = rt->atom_hash[h0];
2869
753
        p1 = rt->atom_array[i];
2870
753
        if (p1 == p) {
2871
473
            rt->atom_hash[h0] = p1->hash_next;
2872
473
        } else {
2873
384
            for(;;) {
2874
384
                assert(i != 0);
2875
384
                p0 = p1;
2876
384
                i = p1->hash_next;
2877
384
                p1 = rt->atom_array[i];
2878
384
                if (p1 == p) {
2879
280
                    p0->hash_next = p1->hash_next;
2880
280
                    break;
2881
280
                }
2882
384
            }
2883
280
        }
2884
753
    }
2885
    /* insert in free atom list */
2886
753
    rt->atom_array[i] = atom_set_free(rt->atom_free_index);
2887
753
    rt->atom_free_index = i;
2888
    /* free the string structure */
2889
#ifdef DUMP_LEAKS
2890
    list_del(&p->link);
2891
#endif
2892
753
    if (p->atom_type == JS_ATOM_TYPE_SYMBOL &&
2893
753
        p->hash != JS_ATOM_HASH_PRIVATE && p->hash != 0) {
2894
        /* live weak references are still present on this object: keep
2895
           it */
2896
753
    } else {
2897
753
        js_free_rt(rt, p);
2898
753
    }
2899
753
    rt->atom_count--;
2900
753
    assert(rt->atom_count >= 0);
2901
753
}
2902
2903
static void __JS_FreeAtom(JSRuntime *rt, uint32_t i)
2904
2.45k
{
2905
2.45k
    JSAtomStruct *p;
2906
2907
2.45k
    p = rt->atom_array[i];
2908
2.45k
    if (--p->header.ref_count > 0)
2909
1.86k
        return;
2910
587
    JS_FreeAtomStruct(rt, p);
2911
587
}
2912
2913
/* Warning: 'p' is freed */
2914
static JSAtom JS_NewAtomStr(JSContext *ctx, JSString *p)
2915
757
{
2916
757
    JSRuntime *rt = ctx->rt;
2917
757
    uint32_t n;
2918
757
    if (is_num_string(&n, p)) {
2919
0
        if (n <= JS_ATOM_MAX_INT) {
2920
0
            js_free_string(rt, p);
2921
0
            return __JS_AtomFromUInt32(n);
2922
0
        }
2923
0
    }
2924
    /* XXX: should generate an exception */
2925
757
    return __JS_NewAtom(rt, p, JS_ATOM_TYPE_STRING);
2926
757
}
2927
2928
/* XXX: optimize */
2929
static size_t count_ascii(const uint8_t *buf, size_t len)
2930
2.55k
{
2931
2.55k
    const uint8_t *p, *p_end;
2932
2.55k
    p = buf;
2933
2.55k
    p_end = buf + len;
2934
23.7k
    while (p < p_end && *p < 128)
2935
21.1k
        p++;
2936
2.55k
    return p - buf;
2937
2.55k
}
2938
2939
/* str is UTF-8 encoded */
2940
JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len)
2941
1.79k
{
2942
1.79k
    JSValue val;
2943
2944
1.79k
    if (len == 0 ||
2945
1.79k
        (!is_digit(*str) &&
2946
1.79k
         count_ascii((const uint8_t *)str, len) == len)) {
2947
1.79k
        JSAtom atom = __JS_FindAtom(ctx->rt, str, len, JS_ATOM_TYPE_STRING);
2948
1.79k
        if (atom)
2949
1.04k
            return atom;
2950
1.79k
    }
2951
751
    val = JS_NewStringLen(ctx, str, len);
2952
751
    if (JS_IsException(val))
2953
0
        return JS_ATOM_NULL;
2954
751
    return JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(val));
2955
751
}
2956
2957
JSAtom JS_NewAtom(JSContext *ctx, const char *str)
2958
1.76k
{
2959
1.76k
    return JS_NewAtomLen(ctx, str, strlen(str));
2960
1.76k
}
2961
2962
JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n)
2963
0
{
2964
0
    if (n <= JS_ATOM_MAX_INT) {
2965
0
        return __JS_AtomFromUInt32(n);
2966
0
    } else {
2967
0
        char buf[11];
2968
0
        JSValue val;
2969
0
        size_t len;
2970
0
        len = u32toa(buf, n);
2971
0
        val = js_new_string8_len(ctx, buf, len);
2972
0
        if (JS_IsException(val))
2973
0
            return JS_ATOM_NULL;
2974
0
        return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),
2975
0
                            JS_ATOM_TYPE_STRING);
2976
0
    }
2977
0
}
2978
2979
static JSAtom JS_NewAtomInt64(JSContext *ctx, int64_t n)
2980
0
{
2981
0
    if ((uint64_t)n <= JS_ATOM_MAX_INT) {
2982
0
        return __JS_AtomFromUInt32((uint32_t)n);
2983
0
    } else {
2984
0
        char buf[24];
2985
0
        JSValue val;
2986
0
        size_t len;
2987
0
        len = i64toa(buf, n);
2988
0
        val = js_new_string8_len(ctx, buf, len);
2989
0
        if (JS_IsException(val))
2990
0
            return JS_ATOM_NULL;
2991
0
        return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),
2992
0
                            JS_ATOM_TYPE_STRING);
2993
0
    }
2994
0
}
2995
2996
/* 'p' is freed */
2997
static JSValue JS_NewSymbol(JSContext *ctx, JSString *p, int atom_type)
2998
0
{
2999
0
    JSRuntime *rt = ctx->rt;
3000
0
    JSAtom atom;
3001
0
    atom = __JS_NewAtom(rt, p, atom_type);
3002
0
    if (atom == JS_ATOM_NULL)
3003
0
        return JS_ThrowOutOfMemory(ctx);
3004
0
    return JS_MKPTR(JS_TAG_SYMBOL, rt->atom_array[atom]);
3005
0
}
3006
3007
/* descr must be a non-numeric string atom */
3008
static JSValue JS_NewSymbolFromAtom(JSContext *ctx, JSAtom descr,
3009
                                    int atom_type)
3010
0
{
3011
0
    JSRuntime *rt = ctx->rt;
3012
0
    JSString *p;
3013
3014
0
    assert(!__JS_AtomIsTaggedInt(descr));
3015
0
    assert(descr < rt->atom_size);
3016
0
    p = rt->atom_array[descr];
3017
0
    JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
3018
0
    return JS_NewSymbol(ctx, p, atom_type);
3019
0
}
3020
3021
#define ATOM_GET_STR_BUF_SIZE 64
3022
3023
/* Should only be used for debug. */
3024
static const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size,
3025
                                   JSAtom atom)
3026
59
{
3027
59
    if (__JS_AtomIsTaggedInt(atom)) {
3028
0
        snprintf(buf, buf_size, "%u", __JS_AtomToUInt32(atom));
3029
59
    } else {
3030
59
        JSAtomStruct *p;
3031
59
        assert(atom < rt->atom_size);
3032
59
        if (atom == JS_ATOM_NULL) {
3033
0
            snprintf(buf, buf_size, "<null>");
3034
59
        } else {
3035
59
            int i, c;
3036
59
            char *q;
3037
59
            JSString *str;
3038
3039
59
            q = buf;
3040
59
            p = rt->atom_array[atom];
3041
59
            assert(!atom_is_free(p));
3042
59
            str = p;
3043
59
            if (str) {
3044
59
                if (!str->is_wide_char) {
3045
                    /* special case ASCII strings */
3046
59
                    c = 0;
3047
815
                    for(i = 0; i < str->len; i++) {
3048
756
                        c |= str->u.str8[i];
3049
756
                    }
3050
59
                    if (c < 0x80)
3051
59
                        return (const char *)str->u.str8;
3052
59
                }
3053
0
                for(i = 0; i < str->len; i++) {
3054
0
                    c = string_get(str, i);
3055
0
                    if ((q - buf) >= buf_size - UTF8_CHAR_LEN_MAX)
3056
0
                        break;
3057
0
                    if (c < 128) {
3058
0
                        *q++ = c;
3059
0
                    } else {
3060
0
                        q += unicode_to_utf8((uint8_t *)q, c);
3061
0
                    }
3062
0
                }
3063
0
            }
3064
0
            *q = '\0';
3065
0
        }
3066
59
    }
3067
0
    return buf;
3068
59
}
3069
3070
static const char *JS_AtomGetStr(JSContext *ctx, char *buf, int buf_size, JSAtom atom)
3071
59
{
3072
59
    return JS_AtomGetStrRT(ctx->rt, buf, buf_size, atom);
3073
59
}
3074
3075
static JSValue __JS_AtomToValue(JSContext *ctx, JSAtom atom, BOOL force_string)
3076
2.34k
{
3077
2.34k
    char buf[ATOM_GET_STR_BUF_SIZE];
3078
3079
2.34k
    if (__JS_AtomIsTaggedInt(atom)) {
3080
0
        size_t len = u32toa(buf, __JS_AtomToUInt32(atom));
3081
0
        return js_new_string8_len(ctx, buf, len);
3082
2.34k
    } else {
3083
2.34k
        JSRuntime *rt = ctx->rt;
3084
2.34k
        JSAtomStruct *p;
3085
2.34k
        assert(atom < rt->atom_size);
3086
2.34k
        p = rt->atom_array[atom];
3087
2.34k
        if (p->atom_type == JS_ATOM_TYPE_STRING) {
3088
2.32k
            goto ret_string;
3089
2.32k
        } else if (force_string) {
3090
0
            if (p->len == 0 && p->is_wide_char != 0) {
3091
                /* no description string */
3092
0
                p = rt->atom_array[JS_ATOM_empty_string];
3093
0
            }
3094
2.32k
        ret_string:
3095
2.32k
            return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
3096
26
        } else {
3097
26
            return JS_DupValue(ctx, JS_MKPTR(JS_TAG_SYMBOL, p));
3098
26
        }
3099
2.34k
    }
3100
2.34k
}
3101
3102
JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom)
3103
26
{
3104
26
    return __JS_AtomToValue(ctx, atom, FALSE);
3105
26
}
3106
3107
JSValue JS_AtomToString(JSContext *ctx, JSAtom atom)
3108
2.32k
{
3109
2.32k
    return __JS_AtomToValue(ctx, atom, TRUE);
3110
2.32k
}
3111
3112
/* return TRUE if the atom is an array index (i.e. 0 <= index <=
3113
   2^32-2 and return its value */
3114
static BOOL JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom)
3115
14
{
3116
14
    if (__JS_AtomIsTaggedInt(atom)) {
3117
0
        *pval = __JS_AtomToUInt32(atom);
3118
0
        return TRUE;
3119
14
    } else {
3120
14
        JSRuntime *rt = ctx->rt;
3121
14
        JSAtomStruct *p;
3122
14
        uint32_t val;
3123
3124
14
        assert(atom < rt->atom_size);
3125
14
        p = rt->atom_array[atom];
3126
14
        if (p->atom_type == JS_ATOM_TYPE_STRING &&
3127
14
            is_num_string(&val, p) && val != -1) {
3128
0
            *pval = val;
3129
0
            return TRUE;
3130
14
        } else {
3131
14
            *pval = 0;
3132
14
            return FALSE;
3133
14
        }
3134
14
    }
3135
14
}
3136
3137
/* This test must be fast if atom is not a numeric index (e.g. a
3138
   method name). Return JS_UNDEFINED if not a numeric
3139
   index. JS_EXCEPTION can also be returned. */
3140
static JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom)
3141
0
{
3142
0
    JSRuntime *rt = ctx->rt;
3143
0
    JSAtomStruct *p1;
3144
0
    JSString *p;
3145
0
    int c, ret;
3146
0
    JSValue num, str;
3147
3148
0
    if (__JS_AtomIsTaggedInt(atom))
3149
0
        return JS_NewInt32(ctx, __JS_AtomToUInt32(atom));
3150
0
    assert(atom < rt->atom_size);
3151
0
    p1 = rt->atom_array[atom];
3152
0
    if (p1->atom_type != JS_ATOM_TYPE_STRING)
3153
0
        return JS_UNDEFINED;
3154
0
    switch(atom) {
3155
0
    case JS_ATOM_minus_zero:
3156
0
        return __JS_NewFloat64(ctx, -0.0);
3157
0
    case JS_ATOM_Infinity:
3158
0
        return __JS_NewFloat64(ctx, INFINITY);
3159
0
    case JS_ATOM_minus_Infinity:
3160
0
        return __JS_NewFloat64(ctx, -INFINITY);
3161
0
    case JS_ATOM_NaN:
3162
0
        return __JS_NewFloat64(ctx, NAN);
3163
0
    default:
3164
0
        break;
3165
0
    }
3166
0
    p = p1;
3167
0
    if (p->len == 0)
3168
0
        return JS_UNDEFINED;
3169
0
    c = string_get(p, 0);
3170
0
    if (!is_num(c) && c != '-')
3171
0
        return JS_UNDEFINED;
3172
    /* this is ECMA CanonicalNumericIndexString primitive */
3173
0
    num = JS_ToNumber(ctx, JS_MKPTR(JS_TAG_STRING, p));
3174
0
    if (JS_IsException(num))
3175
0
        return num;
3176
0
    str = JS_ToString(ctx, num);
3177
0
    if (JS_IsException(str)) {
3178
0
        JS_FreeValue(ctx, num);
3179
0
        return str;
3180
0
    }
3181
0
    ret = js_string_compare(ctx, p, JS_VALUE_GET_STRING(str));
3182
0
    JS_FreeValue(ctx, str);
3183
0
    if (ret == 0) {
3184
0
        return num;
3185
0
    } else {
3186
0
        JS_FreeValue(ctx, num);
3187
0
        return JS_UNDEFINED;
3188
0
    }
3189
0
}
3190
3191
/* return -1 if exception or TRUE/FALSE */
3192
static int JS_AtomIsNumericIndex(JSContext *ctx, JSAtom atom)
3193
0
{
3194
0
    JSValue num;
3195
0
    num = JS_AtomIsNumericIndex1(ctx, atom);
3196
0
    if (likely(JS_IsUndefined(num)))
3197
0
        return FALSE;
3198
0
    if (JS_IsException(num))
3199
0
        return -1;
3200
0
    JS_FreeValue(ctx, num);
3201
0
    return TRUE;
3202
0
}
3203
3204
void JS_FreeAtom(JSContext *ctx, JSAtom v)
3205
1.91k
{
3206
1.91k
    if (!__JS_AtomIsConst(v))
3207
1.34k
        __JS_FreeAtom(ctx->rt, v);
3208
1.91k
}
3209
3210
void JS_FreeAtomRT(JSRuntime *rt, JSAtom v)
3211
2.44k
{
3212
2.44k
    if (!__JS_AtomIsConst(v))
3213
1.10k
        __JS_FreeAtom(rt, v);
3214
2.44k
}
3215
3216
/* return TRUE if 'v' is a symbol with a string description */
3217
static BOOL JS_AtomSymbolHasDescription(JSContext *ctx, JSAtom v)
3218
0
{
3219
0
    JSRuntime *rt;
3220
0
    JSAtomStruct *p;
3221
3222
0
    rt = ctx->rt;
3223
0
    if (__JS_AtomIsTaggedInt(v))
3224
0
        return FALSE;
3225
0
    p = rt->atom_array[v];
3226
0
    return (((p->atom_type == JS_ATOM_TYPE_SYMBOL &&
3227
0
              p->hash != JS_ATOM_HASH_PRIVATE) ||
3228
0
             p->atom_type == JS_ATOM_TYPE_GLOBAL_SYMBOL) &&
3229
0
            !(p->len == 0 && p->is_wide_char != 0));
3230
0
}
3231
3232
/* free with JS_FreeCString() */
3233
const char *JS_AtomToCStringLen(JSContext *ctx, size_t *plen, JSAtom atom)
3234
12
{
3235
12
    JSValue str;
3236
12
    const char *cstr;
3237
3238
12
    str = JS_AtomToString(ctx, atom);
3239
12
    if (JS_IsException(str)) {
3240
0
        if (plen)
3241
0
            *plen = 0;
3242
0
        return NULL;
3243
0
    }
3244
12
    cstr = JS_ToCStringLen(ctx, plen, str);
3245
12
    JS_FreeValue(ctx, str);
3246
12
    return cstr;
3247
12
}
3248
3249
/* return a string atom containing name concatenated with str1 */
3250
static JSAtom js_atom_concat_str(JSContext *ctx, JSAtom name, const char *str1)
3251
0
{
3252
0
    JSValue str;
3253
0
    JSAtom atom;
3254
0
    const char *cstr;
3255
0
    char *cstr2;
3256
0
    size_t len, len1;
3257
3258
0
    str = JS_AtomToString(ctx, name);
3259
0
    if (JS_IsException(str))
3260
0
        return JS_ATOM_NULL;
3261
0
    cstr = JS_ToCStringLen(ctx, &len, str);
3262
0
    if (!cstr)
3263
0
        goto fail;
3264
0
    len1 = strlen(str1);
3265
0
    cstr2 = js_malloc(ctx, len + len1 + 1);
3266
0
    if (!cstr2)
3267
0
        goto fail;
3268
0
    memcpy(cstr2, cstr, len);
3269
0
    memcpy(cstr2 + len, str1, len1);
3270
0
    cstr2[len + len1] = '\0';
3271
0
    atom = JS_NewAtomLen(ctx, cstr2, len + len1);
3272
0
    js_free(ctx, cstr2);
3273
0
    JS_FreeCString(ctx, cstr);
3274
0
    JS_FreeValue(ctx, str);
3275
0
    return atom;
3276
0
 fail:
3277
0
    JS_FreeCString(ctx, cstr);
3278
0
    JS_FreeValue(ctx, str);
3279
0
    return JS_ATOM_NULL;
3280
0
}
3281
3282
static JSAtom js_atom_concat_num(JSContext *ctx, JSAtom name, uint32_t n)
3283
0
{
3284
0
    char buf[16];
3285
0
    size_t len;
3286
0
    len = u32toa(buf, n);
3287
0
    buf[len] = '\0';
3288
0
    return js_atom_concat_str(ctx, name, buf);
3289
0
}
3290
3291
static inline BOOL JS_IsEmptyString(JSValueConst v)
3292
0
{
3293
0
    return JS_VALUE_GET_TAG(v) == JS_TAG_STRING && JS_VALUE_GET_STRING(v)->len == 0;
3294
0
}
3295
3296
/* JSClass support */
3297
3298
#ifdef CONFIG_ATOMICS
3299
static pthread_mutex_t js_class_id_mutex = PTHREAD_MUTEX_INITIALIZER;
3300
#endif
3301
3302
/* a new class ID is allocated if *pclass_id != 0 */
3303
JSClassID JS_NewClassID(JSClassID *pclass_id)
3304
2
{
3305
2
    JSClassID class_id;
3306
2
#ifdef CONFIG_ATOMICS
3307
2
    pthread_mutex_lock(&js_class_id_mutex);
3308
2
#endif
3309
2
    class_id = *pclass_id;
3310
2
    if (class_id == 0) {
3311
1
        class_id = js_class_id_alloc++;
3312
1
        *pclass_id = class_id;
3313
1
    }
3314
2
#ifdef CONFIG_ATOMICS
3315
2
    pthread_mutex_unlock(&js_class_id_mutex);
3316
2
#endif
3317
2
    return class_id;
3318
2
}
3319
3320
JSClassID JS_GetClassID(JSValue v)
3321
0
{
3322
0
    JSObject *p;
3323
0
    if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT)
3324
0
        return JS_INVALID_CLASS_ID;
3325
0
    p = JS_VALUE_GET_OBJ(v);
3326
0
    return p->class_id;
3327
0
}
3328
3329
BOOL JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id)
3330
8
{
3331
8
    return (class_id < rt->class_count &&
3332
8
            rt->class_array[class_id].class_id != 0);
3333
8
}
3334
3335
/* create a new object internal class. Return -1 if error, 0 if
3336
   OK. The finalizer can be NULL if none is needed. */
3337
static int JS_NewClass1(JSRuntime *rt, JSClassID class_id,
3338
                        const JSClassDef *class_def, JSAtom name)
3339
114
{
3340
114
    int new_size, i;
3341
114
    JSClass *cl, *new_class_array;
3342
114
    struct list_head *el;
3343
3344
114
    if (class_id >= (1 << 16))
3345
0
        return -1;
3346
114
    if (class_id < rt->class_count &&
3347
114
        rt->class_array[class_id].class_id != 0)
3348
0
        return -1;
3349
3350
114
    if (class_id >= rt->class_count) {
3351
4
        new_size = max_int(JS_CLASS_INIT_COUNT,
3352
4
                           max_int(class_id + 1, rt->class_count * 3 / 2));
3353
3354
        /* reallocate the context class prototype array, if any */
3355
4
        list_for_each(el, &rt->context_list) {
3356
2
            JSContext *ctx = list_entry(el, JSContext, link);
3357
2
            JSValue *new_tab;
3358
2
            new_tab = js_realloc_rt(rt, ctx->class_proto,
3359
2
                                    sizeof(ctx->class_proto[0]) * new_size);
3360
2
            if (!new_tab)
3361
0
                return -1;
3362
58
            for(i = rt->class_count; i < new_size; i++)
3363
56
                new_tab[i] = JS_NULL;
3364
2
            ctx->class_proto = new_tab;
3365
2
        }
3366
        /* reallocate the class array */
3367
4
        new_class_array = js_realloc_rt(rt, rt->class_array,
3368
4
                                        sizeof(JSClass) * new_size);
3369
4
        if (!new_class_array)
3370
0
            return -1;
3371
4
        memset(new_class_array + rt->class_count, 0,
3372
4
               (new_size - rt->class_count) * sizeof(JSClass));
3373
4
        rt->class_array = new_class_array;
3374
4
        rt->class_count = new_size;
3375
4
    }
3376
114
    cl = &rt->class_array[class_id];
3377
114
    cl->class_id = class_id;
3378
114
    cl->class_name = JS_DupAtomRT(rt, name);
3379
114
    cl->finalizer = class_def->finalizer;
3380
114
    cl->gc_mark = class_def->gc_mark;
3381
114
    cl->call = class_def->call;
3382
114
    cl->exotic = class_def->exotic;
3383
114
    return 0;
3384
114
}
3385
3386
int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def)
3387
2
{
3388
2
    int ret, len;
3389
2
    JSAtom name;
3390
3391
2
    len = strlen(class_def->class_name);
3392
2
    name = __JS_FindAtom(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
3393
2
    if (name == JS_ATOM_NULL) {
3394
2
        name = __JS_NewAtomInit(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);
3395
2
        if (name == JS_ATOM_NULL)
3396
0
            return -1;
3397
2
    }
3398
2
    ret = JS_NewClass1(rt, class_id, class_def, name);
3399
2
    JS_FreeAtomRT(rt, name);
3400
2
    return ret;
3401
2
}
3402
3403
static JSValue js_new_string8_len(JSContext *ctx, const char *buf, int len)
3404
763
{
3405
763
    JSString *str;
3406
3407
763
    if (len <= 0) {
3408
2
        return JS_AtomToString(ctx, JS_ATOM_empty_string);
3409
2
    }
3410
761
    str = js_alloc_string(ctx, len, 0);
3411
761
    if (!str)
3412
0
        return JS_EXCEPTION;
3413
761
    memcpy(str->u.str8, buf, len);
3414
761
    str->u.str8[len] = '\0';
3415
761
    return JS_MKPTR(JS_TAG_STRING, str);
3416
761
}
3417
3418
static JSValue js_new_string8(JSContext *ctx, const char *buf)
3419
0
{
3420
0
    return js_new_string8_len(ctx, buf, strlen(buf));
3421
0
}
3422
3423
static JSValue js_new_string16_len(JSContext *ctx, const uint16_t *buf, int len)
3424
0
{
3425
0
    JSString *str;
3426
0
    str = js_alloc_string(ctx, len, 1);
3427
0
    if (!str)
3428
0
        return JS_EXCEPTION;
3429
0
    memcpy(str->u.str16, buf, len * 2);
3430
0
    return JS_MKPTR(JS_TAG_STRING, str);
3431
0
}
3432
3433
static JSValue js_new_string_char(JSContext *ctx, uint16_t c)
3434
0
{
3435
0
    if (c < 0x100) {
3436
0
        uint8_t ch8 = c;
3437
0
        return js_new_string8_len(ctx, (const char *)&ch8, 1);
3438
0
    } else {
3439
0
        uint16_t ch16 = c;
3440
0
        return js_new_string16_len(ctx, &ch16, 1);
3441
0
    }
3442
0
}
3443
3444
static JSValue js_sub_string(JSContext *ctx, JSString *p, int start, int end)
3445
0
{
3446
0
    int len = end - start;
3447
0
    if (start == 0 && end == p->len) {
3448
0
        return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
3449
0
    }
3450
0
    if (p->is_wide_char && len > 0) {
3451
0
        JSString *str;
3452
0
        int i;
3453
0
        uint16_t c = 0;
3454
0
        for (i = start; i < end; i++) {
3455
0
            c |= p->u.str16[i];
3456
0
        }
3457
0
        if (c > 0xFF)
3458
0
            return js_new_string16_len(ctx, p->u.str16 + start, len);
3459
3460
0
        str = js_alloc_string(ctx, len, 0);
3461
0
        if (!str)
3462
0
            return JS_EXCEPTION;
3463
0
        for (i = 0; i < len; i++) {
3464
0
            str->u.str8[i] = p->u.str16[start + i];
3465
0
        }
3466
0
        str->u.str8[len] = '\0';
3467
0
        return JS_MKPTR(JS_TAG_STRING, str);
3468
0
    } else {
3469
0
        return js_new_string8_len(ctx, (const char *)(p->u.str8 + start), len);
3470
0
    }
3471
0
}
3472
3473
typedef struct StringBuffer {
3474
    JSContext *ctx;
3475
    JSString *str;
3476
    int len;
3477
    int size;
3478
    int is_wide_char;
3479
    int error_status;
3480
} StringBuffer;
3481
3482
/* It is valid to call string_buffer_end() and all string_buffer functions even
3483
   if string_buffer_init() or another string_buffer function returns an error.
3484
   If the error_status is set, string_buffer_end() returns JS_EXCEPTION.
3485
 */
3486
static int string_buffer_init2(JSContext *ctx, StringBuffer *s, int size,
3487
                               int is_wide)
3488
4
{
3489
4
    s->ctx = ctx;
3490
4
    s->size = size;
3491
4
    s->len = 0;
3492
4
    s->is_wide_char = is_wide;
3493
4
    s->error_status = 0;
3494
4
    s->str = js_alloc_string(ctx, size, is_wide);
3495
4
    if (unlikely(!s->str)) {
3496
0
        s->size = 0;
3497
0
        return s->error_status = -1;
3498
0
    }
3499
#ifdef DUMP_LEAKS
3500
    /* the StringBuffer may reallocate the JSString, only link it at the end */
3501
    list_del(&s->str->link);
3502
#endif
3503
4
    return 0;
3504
4
}
3505
3506
static inline int string_buffer_init(JSContext *ctx, StringBuffer *s, int size)
3507
4
{
3508
4
    return string_buffer_init2(ctx, s, size, 0);
3509
4
}
3510
3511
static void string_buffer_free(StringBuffer *s)
3512
0
{
3513
0
    js_free(s->ctx, s->str);
3514
0
    s->str = NULL;
3515
0
}
3516
3517
static int string_buffer_set_error(StringBuffer *s)
3518
0
{
3519
0
    js_free(s->ctx, s->str);
3520
0
    s->str = NULL;
3521
0
    s->size = 0;
3522
0
    s->len = 0;
3523
0
    return s->error_status = -1;
3524
0
}
3525
3526
static no_inline int string_buffer_widen(StringBuffer *s, int size)
3527
0
{
3528
0
    JSString *str;
3529
0
    size_t slack;
3530
0
    int i;
3531
3532
0
    if (s->error_status)
3533
0
        return -1;
3534
3535
0
    str = js_realloc2(s->ctx, s->str, sizeof(JSString) + (size << 1), &slack);
3536
0
    if (!str)
3537
0
        return string_buffer_set_error(s);
3538
0
    size += slack >> 1;
3539
0
    for(i = s->len; i-- > 0;) {
3540
0
        str->u.str16[i] = str->u.str8[i];
3541
0
    }
3542
0
    s->is_wide_char = 1;
3543
0
    s->size = size;
3544
0
    s->str = str;
3545
0
    return 0;
3546
0
}
3547
3548
static no_inline int string_buffer_realloc(StringBuffer *s, int new_len, int c)
3549
0
{
3550
0
    JSString *new_str;
3551
0
    int new_size;
3552
0
    size_t new_size_bytes, slack;
3553
3554
0
    if (s->error_status)
3555
0
        return -1;
3556
3557
0
    if (new_len > JS_STRING_LEN_MAX) {
3558
0
        JS_ThrowInternalError(s->ctx, "string too long");
3559
0
        return string_buffer_set_error(s);
3560
0
    }
3561
0
    new_size = min_int(max_int(new_len, s->size * 3 / 2), JS_STRING_LEN_MAX);
3562
0
    if (!s->is_wide_char && c >= 0x100) {
3563
0
        return string_buffer_widen(s, new_size);
3564
0
    }
3565
0
    new_size_bytes = sizeof(JSString) + (new_size << s->is_wide_char) + 1 - s->is_wide_char;
3566
0
    new_str = js_realloc2(s->ctx, s->str, new_size_bytes, &slack);
3567
0
    if (!new_str)
3568
0
        return string_buffer_set_error(s);
3569
0
    new_size = min_int(new_size + (slack >> s->is_wide_char), JS_STRING_LEN_MAX);
3570
0
    s->size = new_size;
3571
0
    s->str = new_str;
3572
0
    return 0;
3573
0
}
3574
3575
static no_inline int string_buffer_putc_slow(StringBuffer *s, uint32_t c)
3576
0
{
3577
0
    if (unlikely(s->len >= s->size)) {
3578
0
        if (string_buffer_realloc(s, s->len + 1, c))
3579
0
            return -1;
3580
0
    }
3581
0
    if (s->is_wide_char) {
3582
0
        s->str->u.str16[s->len++] = c;
3583
0
    } else if (c < 0x100) {
3584
0
        s->str->u.str8[s->len++] = c;
3585
0
    } else {
3586
0
        if (string_buffer_widen(s, s->size))
3587
0
            return -1;
3588
0
        s->str->u.str16[s->len++] = c;
3589
0
    }
3590
0
    return 0;
3591
0
}
3592
3593
/* 0 <= c <= 0xff */
3594
static int string_buffer_putc8(StringBuffer *s, uint32_t c)
3595
0
{
3596
0
    if (unlikely(s->len >= s->size)) {
3597
0
        if (string_buffer_realloc(s, s->len + 1, c))
3598
0
            return -1;
3599
0
    }
3600
0
    if (s->is_wide_char) {
3601
0
        s->str->u.str16[s->len++] = c;
3602
0
    } else {
3603
0
        s->str->u.str8[s->len++] = c;
3604
0
    }
3605
0
    return 0;
3606
0
}
3607
3608
/* 0 <= c <= 0xffff */
3609
static int string_buffer_putc16(StringBuffer *s, uint32_t c)
3610
10
{
3611
10
    if (likely(s->len < s->size)) {
3612
10
        if (s->is_wide_char) {
3613
0
            s->str->u.str16[s->len++] = c;
3614
0
            return 0;
3615
10
        } else if (c < 0x100) {
3616
10
            s->str->u.str8[s->len++] = c;
3617
10
            return 0;
3618
10
        }
3619
10
    }
3620
0
    return string_buffer_putc_slow(s, c);
3621
10
}
3622
3623
/* 0 <= c <= 0x10ffff */
3624
static int string_buffer_putc(StringBuffer *s, uint32_t c)
3625
10
{
3626
10
    if (unlikely(c >= 0x10000)) {
3627
        /* surrogate pair */
3628
0
        if (string_buffer_putc16(s, get_hi_surrogate(c)))
3629
0
            return -1;
3630
0
        c = get_lo_surrogate(c);
3631
0
    }
3632
10
    return string_buffer_putc16(s, c);
3633
10
}
3634
3635
static int string_getc(const JSString *p, int *pidx)
3636
0
{
3637
0
    int idx, c, c1;
3638
0
    idx = *pidx;
3639
0
    if (p->is_wide_char) {
3640
0
        c = p->u.str16[idx++];
3641
0
        if (is_hi_surrogate(c) && idx < p->len) {
3642
0
            c1 = p->u.str16[idx];
3643
0
            if (is_lo_surrogate(c1)) {
3644
0
                c = from_surrogate(c, c1);
3645
0
                idx++;
3646
0
            }
3647
0
        }
3648
0
    } else {
3649
0
        c = p->u.str8[idx++];
3650
0
    }
3651
0
    *pidx = idx;
3652
0
    return c;
3653
0
}
3654
3655
static int string_buffer_write8(StringBuffer *s, const uint8_t *p, int len)
3656
0
{
3657
0
    int i;
3658
3659
0
    if (s->len + len > s->size) {
3660
0
        if (string_buffer_realloc(s, s->len + len, 0))
3661
0
            return -1;
3662
0
    }
3663
0
    if (s->is_wide_char) {
3664
0
        for (i = 0; i < len; i++) {
3665
0
            s->str->u.str16[s->len + i] = p[i];
3666
0
        }
3667
0
        s->len += len;
3668
0
    } else {
3669
0
        memcpy(&s->str->u.str8[s->len], p, len);
3670
0
        s->len += len;
3671
0
    }
3672
0
    return 0;
3673
0
}
3674
3675
static int string_buffer_write16(StringBuffer *s, const uint16_t *p, int len)
3676
0
{
3677
0
    int c = 0, i;
3678
3679
0
    for (i = 0; i < len; i++) {
3680
0
        c |= p[i];
3681
0
    }
3682
0
    if (s->len + len > s->size) {
3683
0
        if (string_buffer_realloc(s, s->len + len, c))
3684
0
            return -1;
3685
0
    } else if (!s->is_wide_char && c >= 0x100) {
3686
0
        if (string_buffer_widen(s, s->size))
3687
0
            return -1;
3688
0
    }
3689
0
    if (s->is_wide_char) {
3690
0
        memcpy(&s->str->u.str16[s->len], p, len << 1);
3691
0
        s->len += len;
3692
0
    } else {
3693
0
        for (i = 0; i < len; i++) {
3694
0
            s->str->u.str8[s->len + i] = p[i];
3695
0
        }
3696
0
        s->len += len;
3697
0
    }
3698
0
    return 0;
3699
0
}
3700
3701
/* appending an ASCII string */
3702
static int string_buffer_puts8(StringBuffer *s, const char *str)
3703
0
{
3704
0
    return string_buffer_write8(s, (const uint8_t *)str, strlen(str));
3705
0
}
3706
3707
static int string_buffer_concat(StringBuffer *s, const JSString *p,
3708
                                uint32_t from, uint32_t to)
3709
0
{
3710
0
    if (to <= from)
3711
0
        return 0;
3712
0
    if (p->is_wide_char)
3713
0
        return string_buffer_write16(s, p->u.str16 + from, to - from);
3714
0
    else
3715
0
        return string_buffer_write8(s, p->u.str8 + from, to - from);
3716
0
}
3717
3718
static int string_buffer_concat_value(StringBuffer *s, JSValueConst v)
3719
0
{
3720
0
    JSString *p;
3721
0
    JSValue v1;
3722
0
    int res;
3723
3724
0
    if (s->error_status) {
3725
        /* prevent exception overload */
3726
0
        return -1;
3727
0
    }
3728
0
    if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) {
3729
0
        if (JS_VALUE_GET_TAG(v) == JS_TAG_STRING_ROPE) {
3730
0
            JSStringRope *r = JS_VALUE_GET_STRING_ROPE(v);
3731
            /* recursion is acceptable because the rope depth is bounded */
3732
0
            if (string_buffer_concat_value(s, r->left))
3733
0
                return -1;
3734
0
            return string_buffer_concat_value(s, r->right);
3735
0
        } else {
3736
0
            v1 = JS_ToString(s->ctx, v);
3737
0
            if (JS_IsException(v1))
3738
0
                return string_buffer_set_error(s);
3739
0
            p = JS_VALUE_GET_STRING(v1);
3740
0
            res = string_buffer_concat(s, p, 0, p->len);
3741
0
            JS_FreeValue(s->ctx, v1);
3742
0
            return res;
3743
0
        }
3744
0
    }
3745
0
    p = JS_VALUE_GET_STRING(v);
3746
0
    return string_buffer_concat(s, p, 0, p->len);
3747
0
}
3748
3749
static int string_buffer_concat_value_free(StringBuffer *s, JSValue v)
3750
0
{
3751
0
    JSString *p;
3752
0
    int res;
3753
3754
0
    if (s->error_status) {
3755
        /* prevent exception overload */
3756
0
        JS_FreeValue(s->ctx, v);
3757
0
        return -1;
3758
0
    }
3759
0
    if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) {
3760
0
        v = JS_ToStringFree(s->ctx, v);
3761
0
        if (JS_IsException(v))
3762
0
            return string_buffer_set_error(s);
3763
0
    }
3764
0
    p = JS_VALUE_GET_STRING(v);
3765
0
    res = string_buffer_concat(s, p, 0, p->len);
3766
0
    JS_FreeValue(s->ctx, v);
3767
0
    return res;
3768
0
}
3769
3770
static int string_buffer_fill(StringBuffer *s, int c, int count)
3771
0
{
3772
    /* XXX: optimize */
3773
0
    if (s->len + count > s->size) {
3774
0
        if (string_buffer_realloc(s, s->len + count, c))
3775
0
            return -1;
3776
0
    }
3777
0
    while (count-- > 0) {
3778
0
        if (string_buffer_putc16(s, c))
3779
0
            return -1;
3780
0
    }
3781
0
    return 0;
3782
0
}
3783
3784
static JSValue string_buffer_end(StringBuffer *s)
3785
4
{
3786
4
    JSString *str;
3787
4
    str = s->str;
3788
4
    if (s->error_status)
3789
0
        return JS_EXCEPTION;
3790
4
    if (s->len == 0) {
3791
0
        js_free(s->ctx, str);
3792
0
        s->str = NULL;
3793
0
        return JS_AtomToString(s->ctx, JS_ATOM_empty_string);
3794
0
    }
3795
4
    if (s->len < s->size) {
3796
        /* smaller size so js_realloc should not fail, but OK if it does */
3797
        /* XXX: should add some slack to avoid unnecessary calls */
3798
        /* XXX: might need to use malloc+free to ensure smaller size */
3799
4
        str = js_realloc_rt(s->ctx->rt, str, sizeof(JSString) +
3800
4
                            (s->len << s->is_wide_char) + 1 - s->is_wide_char);
3801
4
        if (str == NULL)
3802
0
            str = s->str;
3803
4
        s->str = str;
3804
4
    }
3805
4
    if (!s->is_wide_char)
3806
4
        str->u.str8[s->len] = 0;
3807
#ifdef DUMP_LEAKS
3808
    list_add_tail(&str->link, &s->ctx->rt->string_list);
3809
#endif
3810
4
    str->is_wide_char = s->is_wide_char;
3811
4
    str->len = s->len;
3812
4
    s->str = NULL;
3813
4
    return JS_MKPTR(JS_TAG_STRING, str);
3814
4
}
3815
3816
/* create a string from a UTF-8 buffer */
3817
JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len)
3818
763
{
3819
763
    const uint8_t *p, *p_end, *p_start, *p_next;
3820
763
    uint32_t c;
3821
763
    StringBuffer b_s, *b = &b_s;
3822
763
    size_t len1;
3823
3824
763
    p_start = (const uint8_t *)buf;
3825
763
    p_end = p_start + buf_len;
3826
763
    len1 = count_ascii(p_start, buf_len);
3827
763
    p = p_start + len1;
3828
763
    if (len1 > JS_STRING_LEN_MAX)
3829
0
        return JS_ThrowInternalError(ctx, "string too long");
3830
763
    if (p == p_end) {
3831
        /* ASCII string */
3832
763
        return js_new_string8_len(ctx, buf, buf_len);
3833
763
    } else {
3834
0
        if (string_buffer_init(ctx, b, buf_len))
3835
0
            goto fail;
3836
0
        string_buffer_write8(b, p_start, len1);
3837
0
        while (p < p_end) {
3838
0
            if (*p < 128) {
3839
0
                string_buffer_putc8(b, *p++);
3840
0
            } else {
3841
                /* parse utf-8 sequence, return 0xFFFFFFFF for error */
3842
0
                c = unicode_from_utf8(p, p_end - p, &p_next);
3843
0
                if (c < 0x10000) {
3844
0
                    p = p_next;
3845
0
                } else if (c <= 0x10FFFF) {
3846
0
                    p = p_next;
3847
                    /* surrogate pair */
3848
0
                    string_buffer_putc16(b, get_hi_surrogate(c));
3849
0
                    c = get_lo_surrogate(c);
3850
0
                } else {
3851
                    /* invalid char */
3852
0
                    c = 0xfffd;
3853
                    /* skip the invalid chars */
3854
                    /* XXX: seems incorrect. Why not just use c = *p++; ? */
3855
0
                    while (p < p_end && (*p >= 0x80 && *p < 0xc0))
3856
0
                        p++;
3857
0
                    if (p < p_end) {
3858
0
                        p++;
3859
0
                        while (p < p_end && (*p >= 0x80 && *p < 0xc0))
3860
0
                            p++;
3861
0
                    }
3862
0
                }
3863
0
                string_buffer_putc16(b, c);
3864
0
            }
3865
0
        }
3866
0
    }
3867
0
    return string_buffer_end(b);
3868
3869
0
 fail:
3870
0
    string_buffer_free(b);
3871
0
    return JS_EXCEPTION;
3872
763
}
3873
3874
static JSValue JS_ConcatString3(JSContext *ctx, const char *str1,
3875
                                JSValue str2, const char *str3)
3876
0
{
3877
0
    StringBuffer b_s, *b = &b_s;
3878
0
    int len1, len3;
3879
0
    JSString *p;
3880
3881
0
    if (unlikely(JS_VALUE_GET_TAG(str2) != JS_TAG_STRING)) {
3882
0
        str2 = JS_ToStringFree(ctx, str2);
3883
0
        if (JS_IsException(str2))
3884
0
            goto fail;
3885
0
    }
3886
0
    p = JS_VALUE_GET_STRING(str2);
3887
0
    len1 = strlen(str1);
3888
0
    len3 = strlen(str3);
3889
3890
0
    if (string_buffer_init2(ctx, b, len1 + p->len + len3, p->is_wide_char))
3891
0
        goto fail;
3892
3893
0
    string_buffer_write8(b, (const uint8_t *)str1, len1);
3894
0
    string_buffer_concat(b, p, 0, p->len);
3895
0
    string_buffer_write8(b, (const uint8_t *)str3, len3);
3896
3897
0
    JS_FreeValue(ctx, str2);
3898
0
    return string_buffer_end(b);
3899
3900
0
 fail:
3901
0
    JS_FreeValue(ctx, str2);
3902
0
    return JS_EXCEPTION;
3903
0
}
3904
3905
JSValue JS_NewAtomString(JSContext *ctx, const char *str)
3906
16
{
3907
16
    JSAtom atom = JS_NewAtom(ctx, str);
3908
16
    if (atom == JS_ATOM_NULL)
3909
0
        return JS_EXCEPTION;
3910
16
    JSValue val = JS_AtomToString(ctx, atom);
3911
16
    JS_FreeAtom(ctx, atom);
3912
16
    return val;
3913
16
}
3914
3915
/* return (NULL, 0) if exception. */
3916
/* return pointer into a JSString with a live ref_count */
3917
/* cesu8 determines if non-BMP1 codepoints are encoded as 1 or 2 utf-8 sequences */
3918
const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, BOOL cesu8)
3919
12
{
3920
12
    JSValue val;
3921
12
    JSString *str, *str_new;
3922
12
    int pos, len, c, c1;
3923
12
    uint8_t *q;
3924
3925
12
    if (JS_VALUE_GET_TAG(val1) != JS_TAG_STRING) {
3926
0
        val = JS_ToString(ctx, val1);
3927
0
        if (JS_IsException(val))
3928
0
            goto fail;
3929
12
    } else {
3930
12
        val = JS_DupValue(ctx, val1);
3931
12
    }
3932
3933
12
    str = JS_VALUE_GET_STRING(val);
3934
12
    len = str->len;
3935
12
    if (!str->is_wide_char) {
3936
12
        const uint8_t *src = str->u.str8;
3937
12
        int count;
3938
3939
        /* count the number of non-ASCII characters */
3940
        /* Scanning the whole string is required for ASCII strings,
3941
           and computing the number of non-ASCII bytes is less expensive
3942
           than testing each byte, hence this method is faster for ASCII
3943
           strings, which is the most common case.
3944
         */
3945
12
        count = 0;
3946
76
        for (pos = 0; pos < len; pos++) {
3947
64
            count += src[pos] >> 7;
3948
64
        }
3949
12
        if (count == 0) {
3950
12
            if (plen)
3951
0
                *plen = len;
3952
12
            return (const char *)src;
3953
12
        }
3954
0
        str_new = js_alloc_string(ctx, len + count, 0);
3955
0
        if (!str_new)
3956
0
            goto fail;
3957
0
        q = str_new->u.str8;
3958
0
        for (pos = 0; pos < len; pos++) {
3959
0
            c = src[pos];
3960
0
            if (c < 0x80) {
3961
0
                *q++ = c;
3962
0
            } else {
3963
0
                *q++ = (c >> 6) | 0xc0;
3964
0
                *q++ = (c & 0x3f) | 0x80;
3965
0
            }
3966
0
        }
3967
0
    } else {
3968
0
        const uint16_t *src = str->u.str16;
3969
        /* Allocate 3 bytes per 16 bit code point. Surrogate pairs may
3970
           produce 4 bytes but use 2 code points.
3971
         */
3972
0
        str_new = js_alloc_string(ctx, len * 3, 0);
3973
0
        if (!str_new)
3974
0
            goto fail;
3975
0
        q = str_new->u.str8;
3976
0
        pos = 0;
3977
0
        while (pos < len) {
3978
0
            c = src[pos++];
3979
0
            if (c < 0x80) {
3980
0
                *q++ = c;
3981
0
            } else {
3982
0
                if (is_hi_surrogate(c)) {
3983
0
                    if (pos < len && !cesu8) {
3984
0
                        c1 = src[pos];
3985
0
                        if (is_lo_surrogate(c1)) {
3986
0
                            pos++;
3987
0
                            c = from_surrogate(c, c1);
3988
0
                        } else {
3989
                            /* Keep unmatched surrogate code points */
3990
                            /* c = 0xfffd; */ /* error */
3991
0
                        }
3992
0
                    } else {
3993
                        /* Keep unmatched surrogate code points */
3994
                        /* c = 0xfffd; */ /* error */
3995
0
                    }
3996
0
                }
3997
0
                q += unicode_to_utf8(q, c);
3998
0
            }
3999
0
        }
4000
0
    }
4001
4002
0
    *q = '\0';
4003
0
    str_new->len = q - str_new->u.str8;
4004
0
    JS_FreeValue(ctx, val);
4005
0
    if (plen)
4006
0
        *plen = str_new->len;
4007
0
    return (const char *)str_new->u.str8;
4008
0
 fail:
4009
0
    if (plen)
4010
0
        *plen = 0;
4011
0
    return NULL;
4012
12
}
4013
4014
void JS_FreeCString(JSContext *ctx, const char *ptr)
4015
13
{
4016
13
    JSString *p;
4017
13
    if (!ptr)
4018
1
        return;
4019
    /* purposely removing constness */
4020
12
    p = container_of(ptr, JSString, u);
4021
12
    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
4022
12
}
4023
4024
static int memcmp16_8(const uint16_t *src1, const uint8_t *src2, int len)
4025
0
{
4026
0
    int c, i;
4027
0
    for(i = 0; i < len; i++) {
4028
0
        c = src1[i] - src2[i];
4029
0
        if (c != 0)
4030
0
            return c;
4031
0
    }
4032
0
    return 0;
4033
0
}
4034
4035
static int memcmp16(const uint16_t *src1, const uint16_t *src2, int len)
4036
0
{
4037
0
    int c, i;
4038
0
    for(i = 0; i < len; i++) {
4039
0
        c = src1[i] - src2[i];
4040
0
        if (c != 0)
4041
0
            return c;
4042
0
    }
4043
0
    return 0;
4044
0
}
4045
4046
static int js_string_memcmp(const JSString *p1, int pos1, const JSString *p2,
4047
                            int pos2, int len)
4048
978
{
4049
978
    int res;
4050
4051
978
    if (likely(!p1->is_wide_char)) {
4052
978
        if (likely(!p2->is_wide_char))
4053
978
            res = memcmp(p1->u.str8 + pos1, p2->u.str8 + pos2, len);
4054
0
        else
4055
0
            res = -memcmp16_8(p2->u.str16 + pos2, p1->u.str8 + pos1, len);
4056
978
    } else {
4057
0
        if (!p2->is_wide_char)
4058
0
            res = memcmp16_8(p1->u.str16 + pos1, p2->u.str8 + pos2, len);
4059
0
        else
4060
0
            res = memcmp16(p1->u.str16 + pos1, p2->u.str16 + pos2, len);
4061
0
    }
4062
978
    return res;
4063
978
}
4064
4065
/* return < 0, 0 or > 0 */
4066
static int js_string_compare(JSContext *ctx,
4067
                             const JSString *p1, const JSString *p2)
4068
972
{
4069
972
    int res, len;
4070
972
    len = min_int(p1->len, p2->len);
4071
972
    res = js_string_memcmp(p1, 0, p2, 0, len);
4072
972
    if (res == 0) {
4073
12
        if (p1->len == p2->len)
4074
0
            res = 0;
4075
12
        else if (p1->len < p2->len)
4076
6
            res = -1;
4077
6
        else
4078
6
            res = 1;
4079
12
    }
4080
972
    return res;
4081
972
}
4082
4083
static void copy_str16(uint16_t *dst, const JSString *p, int offset, int len)
4084
0
{
4085
0
    if (p->is_wide_char) {
4086
0
        memcpy(dst, p->u.str16 + offset, len * 2);
4087
0
    } else {
4088
0
        const uint8_t *src1 = p->u.str8 + offset;
4089
0
        int i;
4090
4091
0
        for(i = 0; i < len; i++)
4092
0
            dst[i] = src1[i];
4093
0
    }
4094
0
}
4095
4096
static JSValue JS_ConcatString1(JSContext *ctx,
4097
                                const JSString *p1, const JSString *p2)
4098
0
{
4099
0
    JSString *p;
4100
0
    uint32_t len;
4101
0
    int is_wide_char;
4102
4103
0
    len = p1->len + p2->len;
4104
0
    if (len > JS_STRING_LEN_MAX)
4105
0
        return JS_ThrowInternalError(ctx, "string too long");
4106
0
    is_wide_char = p1->is_wide_char | p2->is_wide_char;
4107
0
    p = js_alloc_string(ctx, len, is_wide_char);
4108
0
    if (!p)
4109
0
        return JS_EXCEPTION;
4110
0
    if (!is_wide_char) {
4111
0
        memcpy(p->u.str8, p1->u.str8, p1->len);
4112
0
        memcpy(p->u.str8 + p1->len, p2->u.str8, p2->len);
4113
0
        p->u.str8[len] = '\0';
4114
0
    } else {
4115
0
        copy_str16(p->u.str16, p1, 0, p1->len);
4116
0
        copy_str16(p->u.str16 + p1->len, p2, 0, p2->len);
4117
0
    }
4118
0
    return JS_MKPTR(JS_TAG_STRING, p);
4119
0
}
4120
4121
0
static BOOL JS_ConcatStringInPlace(JSContext *ctx, JSString *p1, JSValueConst op2) {
4122
0
    if (JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {
4123
0
        JSString *p2 = JS_VALUE_GET_STRING(op2);
4124
0
        size_t size1;
4125
4126
0
        if (p2->len == 0)
4127
0
            return TRUE;
4128
0
        if (p1->header.ref_count != 1)
4129
0
            return FALSE;
4130
0
        size1 = js_malloc_usable_size(ctx, p1);
4131
0
        if (p1->is_wide_char) {
4132
0
            if (size1 >= sizeof(*p1) + ((p1->len + p2->len) << 1)) {
4133
0
                if (p2->is_wide_char) {
4134
0
                    memcpy(p1->u.str16 + p1->len, p2->u.str16, p2->len << 1);
4135
0
                    p1->len += p2->len;
4136
0
                    return TRUE;
4137
0
                } else {
4138
0
                    size_t i;
4139
0
                    for (i = 0; i < p2->len; i++) {
4140
0
                        p1->u.str16[p1->len++] = p2->u.str8[i];
4141
0
                    }
4142
0
                    return TRUE;
4143
0
                }
4144
0
            }
4145
0
        } else if (!p2->is_wide_char) {
4146
0
            if (size1 >= sizeof(*p1) + p1->len + p2->len + 1) {
4147
0
                memcpy(p1->u.str8 + p1->len, p2->u.str8, p2->len);
4148
0
                p1->len += p2->len;
4149
0
                p1->u.str8[p1->len] = '\0';
4150
0
                return TRUE;
4151
0
            }
4152
0
        }
4153
0
    }
4154
0
    return FALSE;
4155
0
}
4156
4157
static JSValue JS_ConcatString2(JSContext *ctx, JSValue op1, JSValue op2)
4158
0
{
4159
0
    JSValue ret;
4160
0
    JSString *p1, *p2;
4161
0
    p1 = JS_VALUE_GET_STRING(op1);
4162
0
    if (JS_ConcatStringInPlace(ctx, p1, op2)) {
4163
0
        JS_FreeValue(ctx, op2);
4164
0
        return op1;
4165
0
    }
4166
0
    p2 = JS_VALUE_GET_STRING(op2);
4167
0
    ret = JS_ConcatString1(ctx, p1, p2);
4168
0
    JS_FreeValue(ctx, op1);
4169
0
    JS_FreeValue(ctx, op2);
4170
0
    return ret;
4171
0
}
4172
4173
/* Return the character at position 'idx'. 'val' must be a string or rope */
4174
static int string_rope_get(JSValueConst val, uint32_t idx)
4175
0
{
4176
0
    if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
4177
0
        return string_get(JS_VALUE_GET_STRING(val), idx);
4178
0
    } else {
4179
0
        JSStringRope *r = JS_VALUE_GET_STRING_ROPE(val);
4180
0
        uint32_t len;
4181
0
        if (JS_VALUE_GET_TAG(r->left) == JS_TAG_STRING)
4182
0
            len = JS_VALUE_GET_STRING(r->left)->len;
4183
0
        else
4184
0
            len = JS_VALUE_GET_STRING_ROPE(r->left)->len;
4185
0
        if (idx < len)
4186
0
            return string_rope_get(r->left, idx);
4187
0
        else
4188
0
            return string_rope_get(r->right, idx - len);
4189
0
    }
4190
0
}
4191
4192
typedef struct {
4193
    JSValueConst stack[JS_STRING_ROPE_MAX_DEPTH];
4194
    int stack_len;
4195
} JSStringRopeIter;
4196
4197
static void string_rope_iter_init(JSStringRopeIter *s, JSValueConst val)
4198
0
{
4199
0
    s->stack_len = 0;
4200
0
    s->stack[s->stack_len++] = val;
4201
0
}
4202
4203
/* iterate thru a rope and return the strings in order */
4204
static JSString *string_rope_iter_next(JSStringRopeIter *s)
4205
0
{
4206
0
    JSValueConst val;
4207
0
    JSStringRope *r;
4208
4209
0
    if (s->stack_len == 0)
4210
0
        return NULL;
4211
0
    val = s->stack[--s->stack_len];
4212
0
    for(;;) {
4213
0
        if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING)
4214
0
            return JS_VALUE_GET_STRING(val);
4215
0
        r = JS_VALUE_GET_STRING_ROPE(val);
4216
0
        assert(s->stack_len < JS_STRING_ROPE_MAX_DEPTH);
4217
0
        s->stack[s->stack_len++] = r->right;
4218
0
        val = r->left;
4219
0
    }
4220
0
}
4221
4222
static uint32_t string_rope_get_len(JSValueConst val)
4223
0
{
4224
0
    if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING)
4225
0
        return JS_VALUE_GET_STRING(val)->len;
4226
0
    else
4227
0
        return JS_VALUE_GET_STRING_ROPE(val)->len;
4228
0
}
4229
4230
static int js_string_rope_compare(JSContext *ctx, JSValueConst op1,
4231
                                  JSValueConst op2, BOOL eq_only)
4232
0
{
4233
0
    uint32_t len1, len2, len, pos1, pos2, l;
4234
0
    int res;
4235
0
    JSStringRopeIter it1, it2;
4236
0
    JSString *p1, *p2;
4237
    
4238
0
    len1 = string_rope_get_len(op1);
4239
0
    len2 = string_rope_get_len(op2);
4240
    /* no need to go further for equality test if
4241
       different length */
4242
0
    if (eq_only && len1 != len2)
4243
0
        return 1; 
4244
0
    len = min_uint32(len1, len2);
4245
0
    string_rope_iter_init(&it1, op1);
4246
0
    string_rope_iter_init(&it2, op2);
4247
0
    p1 = string_rope_iter_next(&it1);
4248
0
    p2 = string_rope_iter_next(&it2);
4249
0
    pos1 = 0;
4250
0
    pos2 = 0;
4251
0
    while (len != 0) {
4252
0
        l = min_uint32(p1->len - pos1, p2->len - pos2);
4253
0
        l = min_uint32(l, len);
4254
0
        res = js_string_memcmp(p1, pos1, p2, pos2, l);
4255
0
        if (res != 0)
4256
0
            return res;
4257
0
        len -= l;
4258
0
        pos1 += l;
4259
0
        if (pos1 >= p1->len) {
4260
0
            p1 = string_rope_iter_next(&it1);
4261
0
            pos1 = 0;
4262
0
        }
4263
0
        pos2 += l;
4264
0
        if (pos2 >= p2->len) {
4265
0
            p2 = string_rope_iter_next(&it2);
4266
0
            pos2 = 0;
4267
0
        }
4268
0
    }
4269
4270
0
    if (len1 == len2)
4271
0
        res = 0;
4272
0
    else if (len1 < len2)
4273
0
        res = -1;
4274
0
    else
4275
0
        res = 1;
4276
0
    return res;
4277
0
}
4278
4279
/* 'rope' must be a rope. return a string and modify the rope so that
4280
   it won't need to be linearized again. */
4281
static JSValue js_linearize_string_rope(JSContext *ctx, JSValue rope)
4282
0
{
4283
0
    StringBuffer b_s, *b = &b_s;
4284
0
    JSStringRope *r;
4285
0
    JSValue ret;
4286
    
4287
0
    r = JS_VALUE_GET_STRING_ROPE(rope);
4288
4289
    /* check whether it is already linearized */
4290
0
    if (JS_VALUE_GET_TAG(r->right) == JS_TAG_STRING &&
4291
0
        JS_VALUE_GET_STRING(r->right)->len == 0) {
4292
0
        ret = JS_DupValue(ctx, r->left);
4293
0
        JS_FreeValue(ctx, rope);
4294
0
        return ret;
4295
0
    }
4296
0
    if (string_buffer_init2(ctx, b, r->len, r->is_wide_char))
4297
0
        goto fail;
4298
0
    if (string_buffer_concat_value(b, rope))
4299
0
        goto fail;
4300
0
    ret = string_buffer_end(b);
4301
0
    if (r->header.ref_count > 1) {
4302
        /* update the rope so that it won't need to be linearized again */
4303
0
        JS_FreeValue(ctx, r->left);
4304
0
        JS_FreeValue(ctx, r->right);
4305
0
        r->left = JS_DupValue(ctx, ret);
4306
0
        r->right = JS_AtomToString(ctx, JS_ATOM_empty_string);
4307
0
    }
4308
0
    JS_FreeValue(ctx, rope);
4309
0
    return ret;
4310
0
 fail:
4311
0
    JS_FreeValue(ctx, rope);
4312
0
    return JS_EXCEPTION;
4313
0
}
4314
4315
static JSValue js_rebalancee_string_rope(JSContext *ctx, JSValueConst rope);
4316
4317
/* op1 and op2 must be strings or string ropes */
4318
static JSValue js_new_string_rope(JSContext *ctx, JSValue op1, JSValue op2)
4319
0
{
4320
0
    uint32_t len;
4321
0
    int is_wide_char, depth;
4322
0
    JSStringRope *r;
4323
0
    JSValue res;
4324
    
4325
0
    if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING) {
4326
0
        JSString *p1 = JS_VALUE_GET_STRING(op1);
4327
0
        len = p1->len;
4328
0
        is_wide_char = p1->is_wide_char;
4329
0
        depth = 0;
4330
0
    } else {
4331
0
        JSStringRope *r1 = JS_VALUE_GET_STRING_ROPE(op1);
4332
0
        len = r1->len;
4333
0
        is_wide_char = r1->is_wide_char;
4334
0
        depth = r1->depth;
4335
0
    }
4336
4337
0
    if (JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {
4338
0
        JSString *p2 = JS_VALUE_GET_STRING(op2);
4339
0
        len += p2->len;
4340
0
        is_wide_char |= p2->is_wide_char;
4341
0
    } else {
4342
0
        JSStringRope *r2 = JS_VALUE_GET_STRING_ROPE(op2);
4343
0
        len += r2->len;
4344
0
        is_wide_char |= r2->is_wide_char;
4345
0
        depth = max_int(depth, r2->depth);
4346
0
    }
4347
0
    if (len > JS_STRING_LEN_MAX) {
4348
0
        JS_ThrowInternalError(ctx, "string too long");
4349
0
        goto fail;
4350
0
    }
4351
0
    r = js_malloc(ctx, sizeof(*r));
4352
0
    if (!r)
4353
0
        goto fail;
4354
0
    r->header.ref_count = 1;
4355
0
    r->len = len;
4356
0
    r->is_wide_char = is_wide_char;
4357
0
    r->depth = depth + 1;
4358
0
    r->left = op1;
4359
0
    r->right = op2;
4360
0
    res = JS_MKPTR(JS_TAG_STRING_ROPE, r);
4361
0
    if (r->depth > JS_STRING_ROPE_MAX_DEPTH) {
4362
0
        JSValue res2;
4363
#ifdef DUMP_ROPE_REBALANCE
4364
        printf("rebalance: initial depth=%d\n", r->depth);
4365
#endif
4366
0
        res2 = js_rebalancee_string_rope(ctx, res);
4367
#ifdef DUMP_ROPE_REBALANCE
4368
        if (JS_VALUE_GET_TAG(res2) == JS_TAG_STRING_ROPE) 
4369
            printf("rebalance: final depth=%d\n", JS_VALUE_GET_STRING_ROPE(res2)->depth);
4370
#endif
4371
0
        JS_FreeValue(ctx, res);
4372
0
        return res2;
4373
0
    } else {
4374
0
        return res;
4375
0
    }
4376
0
 fail:
4377
0
    JS_FreeValue(ctx, op1);
4378
0
    JS_FreeValue(ctx, op2);
4379
0
    return JS_EXCEPTION;
4380
0
}
4381
4382
0
#define ROPE_N_BUCKETS 44
4383
4384
/* Fibonacii numbers starting from F_2 */
4385
static const uint32_t rope_bucket_len[ROPE_N_BUCKETS] = {
4386
          1,          2,          3,          5,
4387
          8,         13,         21,         34,
4388
         55,         89,        144,        233,
4389
        377,        610,        987,       1597,
4390
       2584,       4181,       6765,      10946,
4391
      17711,      28657,      46368,      75025,
4392
     121393,     196418,     317811,     514229,
4393
     832040,    1346269,    2178309,    3524578,
4394
    5702887,    9227465,   14930352,   24157817,
4395
   39088169,   63245986,  102334155,  165580141,
4396
  267914296,  433494437,  701408733, 1134903170, /* > JS_STRING_LEN_MAX */
4397
};
4398
4399
static int js_rebalancee_string_rope_rec(JSContext *ctx, JSValue *buckets,
4400
                                          JSValueConst val)
4401
0
{
4402
0
    if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
4403
0
        JSString *p = JS_VALUE_GET_STRING(val);
4404
0
        uint32_t len, i;
4405
0
        JSValue a, b;
4406
        
4407
0
        len = p->len;
4408
0
        if (len == 0)
4409
0
            return 0; /* nothing to do */
4410
        /* find the bucket i so that rope_bucket_len[i] <= len <
4411
           rope_bucket_len[i + 1] and concatenate the ropes in the
4412
           buckets before */
4413
0
        a = JS_NULL;
4414
0
        i = 0;
4415
0
        while (len >= rope_bucket_len[i + 1]) {
4416
0
            b = buckets[i];
4417
0
            if (!JS_IsNull(b)) {
4418
0
                buckets[i] = JS_NULL;
4419
0
                if (JS_IsNull(a)) {
4420
0
                    a = b;
4421
0
                } else {
4422
0
                    a = js_new_string_rope(ctx, b, a);
4423
0
                    if (JS_IsException(a))
4424
0
                        return -1;
4425
0
                }
4426
0
            }
4427
0
            i++;
4428
0
        }
4429
0
        if (!JS_IsNull(a)) {
4430
0
            a = js_new_string_rope(ctx, a, JS_DupValue(ctx, val));
4431
0
            if (JS_IsException(a))
4432
0
                return -1;
4433
0
        } else {
4434
0
            a = JS_DupValue(ctx, val);
4435
0
        }
4436
0
        while (!JS_IsNull(buckets[i])) {
4437
0
            a = js_new_string_rope(ctx, buckets[i], a);
4438
0
            buckets[i] = JS_NULL;
4439
0
            if (JS_IsException(a))
4440
0
                return -1;
4441
0
            i++;
4442
0
        }
4443
0
        buckets[i] = a;
4444
0
    } else {
4445
0
        JSStringRope *r = JS_VALUE_GET_STRING_ROPE(val);
4446
0
        js_rebalancee_string_rope_rec(ctx, buckets, r->left);
4447
0
        js_rebalancee_string_rope_rec(ctx, buckets, r->right);
4448
0
    }
4449
0
    return 0;
4450
0
}
4451
4452
/* Return a new rope which is balanced. Algorithm from "Ropes: an
4453
   Alternative to Strings", Hans-J. Boehm, Russ Atkinson and Michael
4454
   Plass. */
4455
static JSValue js_rebalancee_string_rope(JSContext *ctx, JSValueConst rope)
4456
0
{
4457
0
    JSValue buckets[ROPE_N_BUCKETS], a, b;
4458
0
    int i;
4459
    
4460
0
    for(i = 0; i < ROPE_N_BUCKETS; i++)
4461
0
        buckets[i] = JS_NULL;
4462
0
    if (js_rebalancee_string_rope_rec(ctx, buckets, rope))
4463
0
        goto fail;
4464
0
    a = JS_NULL;
4465
0
    for(i = 0; i < ROPE_N_BUCKETS; i++) {
4466
0
        b = buckets[i];
4467
0
        if (!JS_IsNull(b)) {
4468
0
            buckets[i] = JS_NULL;
4469
0
            if (JS_IsNull(a)) {
4470
0
                a = b;
4471
0
            } else {
4472
0
                a = js_new_string_rope(ctx, b, a);
4473
0
                if (JS_IsException(a))
4474
0
                    goto fail;
4475
0
            }
4476
0
        }
4477
0
    }
4478
    /* fail safe */
4479
0
    if (JS_IsNull(a))
4480
0
        return JS_AtomToString(ctx, JS_ATOM_empty_string);
4481
0
    else
4482
0
        return a;
4483
0
 fail:
4484
0
    for(i = 0; i < ROPE_N_BUCKETS; i++) {
4485
0
        JS_FreeValue(ctx, buckets[i]);
4486
0
    }
4487
0
    return JS_EXCEPTION;
4488
0
}
4489
4490
/* op1 and op2 are converted to strings. For convenience, op1 or op2 =
4491
   JS_EXCEPTION are accepted and return JS_EXCEPTION.  */
4492
static JSValue JS_ConcatString(JSContext *ctx, JSValue op1, JSValue op2)
4493
0
{
4494
0
    JSString *p1, *p2;
4495
4496
0
    if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_STRING &&
4497
0
                 JS_VALUE_GET_TAG(op1) != JS_TAG_STRING_ROPE)) {
4498
0
        op1 = JS_ToStringFree(ctx, op1);
4499
0
        if (JS_IsException(op1)) {
4500
0
            JS_FreeValue(ctx, op2);
4501
0
            return JS_EXCEPTION;
4502
0
        }
4503
0
    }
4504
0
    if (unlikely(JS_VALUE_GET_TAG(op2) != JS_TAG_STRING &&
4505
0
                 JS_VALUE_GET_TAG(op2) != JS_TAG_STRING_ROPE)) {
4506
0
        op2 = JS_ToStringFree(ctx, op2);
4507
0
        if (JS_IsException(op2)) {
4508
0
            JS_FreeValue(ctx, op1);
4509
0
            return JS_EXCEPTION;
4510
0
        }
4511
0
    }
4512
4513
    /* normal concatenation for short strings */
4514
0
    if (JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {
4515
0
        p2 = JS_VALUE_GET_STRING(op2);
4516
0
        if (p2->len == 0) {
4517
0
            JS_FreeValue(ctx, op2);
4518
0
            return op1;
4519
0
        }
4520
0
        if (p2->len <= JS_STRING_ROPE_SHORT_LEN) {
4521
0
            if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING) {
4522
0
                p1 = JS_VALUE_GET_STRING(op1);
4523
0
                if (p1->len <= JS_STRING_ROPE_SHORT2_LEN) {
4524
0
                    return JS_ConcatString2(ctx, op1, op2);
4525
0
                } else {
4526
0
                    return js_new_string_rope(ctx, op1, op2);
4527
0
                }
4528
0
            } else {
4529
0
                JSStringRope *r1;
4530
0
                r1 = JS_VALUE_GET_STRING_ROPE(op1);
4531
0
                if (JS_VALUE_GET_TAG(r1->right) == JS_TAG_STRING &&
4532
0
                    JS_VALUE_GET_STRING(r1->right)->len <= JS_STRING_ROPE_SHORT_LEN) {
4533
0
                    JSValue val, ret;
4534
0
                    val = JS_ConcatString2(ctx, JS_DupValue(ctx, r1->right), op2);
4535
0
                    if (JS_IsException(val)) {
4536
0
                        JS_FreeValue(ctx, op1);
4537
0
                        return JS_EXCEPTION;
4538
0
                    }
4539
0
                    ret = js_new_string_rope(ctx, JS_DupValue(ctx, r1->left), val);
4540
0
                    JS_FreeValue(ctx, op1);
4541
0
                    return ret;
4542
0
                }
4543
0
            }
4544
0
        }
4545
0
    } else if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING) {
4546
0
        JSStringRope *r2;
4547
0
        p1 = JS_VALUE_GET_STRING(op1);
4548
0
        if (p1->len == 0) {
4549
0
            JS_FreeValue(ctx, op1);
4550
0
            return op2;
4551
0
        }
4552
0
        r2 = JS_VALUE_GET_STRING_ROPE(op2);
4553
0
        if (JS_VALUE_GET_TAG(r2->left) == JS_TAG_STRING &&
4554
0
            JS_VALUE_GET_STRING(r2->left)->len <= JS_STRING_ROPE_SHORT_LEN) {
4555
0
            JSValue val, ret;
4556
0
            val = JS_ConcatString2(ctx, op1, JS_DupValue(ctx, r2->left));
4557
0
            if (JS_IsException(val)) {
4558
0
                JS_FreeValue(ctx, op2);
4559
0
                return JS_EXCEPTION;
4560
0
            }
4561
0
            ret = js_new_string_rope(ctx, val, JS_DupValue(ctx, r2->right));
4562
0
            JS_FreeValue(ctx, op2);
4563
0
            return ret;
4564
0
        }
4565
0
    }
4566
0
    return js_new_string_rope(ctx, op1, op2);
4567
0
}
4568
4569
/* Shape support */
4570
4571
static inline size_t get_shape_size(size_t hash_size, size_t prop_size)
4572
922
{
4573
922
    return hash_size * sizeof(uint32_t) + sizeof(JSShape) +
4574
922
        prop_size * sizeof(JSShapeProperty);
4575
922
}
4576
4577
static inline JSShape *get_shape_from_alloc(void *sh_alloc, size_t hash_size)
4578
922
{
4579
922
    return (JSShape *)(void *)((uint32_t *)sh_alloc + hash_size);
4580
922
}
4581
4582
static inline uint32_t *prop_hash_end(JSShape *sh)
4583
10.8k
{
4584
10.8k
    return (uint32_t *)sh;
4585
10.8k
}
4586
4587
static inline void *get_alloc_from_shape(JSShape *sh)
4588
1.09k
{
4589
1.09k
    return prop_hash_end(sh) - ((intptr_t)sh->prop_hash_mask + 1);
4590
1.09k
}
4591
4592
static inline JSShapeProperty *get_shape_prop(JSShape *sh)
4593
5.97k
{
4594
5.97k
    return sh->prop;
4595
5.97k
}
4596
4597
static int init_shape_hash(JSRuntime *rt)
4598
2
{
4599
2
    rt->shape_hash_bits = 4;   /* 16 shapes */
4600
2
    rt->shape_hash_size = 1 << rt->shape_hash_bits;
4601
2
    rt->shape_hash_count = 0;
4602
2
    rt->shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) *
4603
2
                                   rt->shape_hash_size);
4604
2
    if (!rt->shape_hash)
4605
0
        return -1;
4606
2
    return 0;
4607
2
}
4608
4609
/* same magic hash multiplier as the Linux kernel */
4610
static uint32_t shape_hash(uint32_t h, uint32_t val)
4611
8.38k
{
4612
8.38k
    return (h + val) * 0x9e370001;
4613
8.38k
}
4614
4615
/* truncate the shape hash to 'hash_bits' bits */
4616
static uint32_t get_shape_hash(uint32_t h, int hash_bits)
4617
6.47k
{
4618
6.47k
    return h >> (32 - hash_bits);
4619
6.47k
}
4620
4621
static uint32_t shape_initial_hash(JSObject *proto)
4622
800
{
4623
800
    uint32_t h;
4624
800
    h = shape_hash(1, (uintptr_t)proto);
4625
800
    if (sizeof(proto) > 4)
4626
800
        h = shape_hash(h, (uint64_t)(uintptr_t)proto >> 32);
4627
800
    return h;
4628
800
}
4629
4630
static int resize_shape_hash(JSRuntime *rt, int new_shape_hash_bits)
4631
6
{
4632
6
    int new_shape_hash_size, i;
4633
6
    uint32_t h;
4634
6
    JSShape **new_shape_hash, *sh, *sh_next;
4635
4636
6
    new_shape_hash_size = 1 << new_shape_hash_bits;
4637
6
    new_shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) *
4638
6
                                   new_shape_hash_size);
4639
6
    if (!new_shape_hash)
4640
0
        return -1;
4641
230
    for(i = 0; i < rt->shape_hash_size; i++) {
4642
338
        for(sh = rt->shape_hash[i]; sh != NULL; sh = sh_next) {
4643
114
            sh_next = sh->shape_hash_next;
4644
114
            h = get_shape_hash(sh->hash, new_shape_hash_bits);
4645
114
            sh->shape_hash_next = new_shape_hash[h];
4646
114
            new_shape_hash[h] = sh;
4647
114
        }
4648
224
    }
4649
6
    js_free_rt(rt, rt->shape_hash);
4650
6
    rt->shape_hash_bits = new_shape_hash_bits;
4651
6
    rt->shape_hash_size = new_shape_hash_size;
4652
6
    rt->shape_hash = new_shape_hash;
4653
6
    return 0;
4654
6
}
4655
4656
static void js_shape_hash_link(JSRuntime *rt, JSShape *sh)
4657
1.99k
{
4658
1.99k
    uint32_t h;
4659
1.99k
    h = get_shape_hash(sh->hash, rt->shape_hash_bits);
4660
1.99k
    sh->shape_hash_next = rt->shape_hash[h];
4661
1.99k
    rt->shape_hash[h] = sh;
4662
1.99k
    rt->shape_hash_count++;
4663
1.99k
}
4664
4665
static void js_shape_hash_unlink(JSRuntime *rt, JSShape *sh)
4666
1.99k
{
4667
1.99k
    uint32_t h;
4668
1.99k
    JSShape **psh;
4669
4670
1.99k
    h = get_shape_hash(sh->hash, rt->shape_hash_bits);
4671
1.99k
    psh = &rt->shape_hash[h];
4672
2.01k
    while (*psh != sh)
4673
22
        psh = &(*psh)->shape_hash_next;
4674
1.99k
    *psh = sh->shape_hash_next;
4675
1.99k
    rt->shape_hash_count--;
4676
1.99k
}
4677
4678
/* create a new empty shape with prototype 'proto' */
4679
static no_inline JSShape *js_new_shape2(JSContext *ctx, JSObject *proto,
4680
                                        int hash_size, int prop_size)
4681
328
{
4682
328
    JSRuntime *rt = ctx->rt;
4683
328
    void *sh_alloc;
4684
328
    JSShape *sh;
4685
4686
    /* resize the shape hash table if necessary */
4687
328
    if (2 * (rt->shape_hash_count + 1) > rt->shape_hash_size) {
4688
6
        resize_shape_hash(rt, rt->shape_hash_bits + 1);
4689
6
    }
4690
4691
328
    sh_alloc = js_malloc(ctx, get_shape_size(hash_size, prop_size));
4692
328
    if (!sh_alloc)
4693
0
        return NULL;
4694
328
    sh = get_shape_from_alloc(sh_alloc, hash_size);
4695
328
    sh->header.ref_count = 1;
4696
328
    add_gc_object(rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);
4697
328
    if (proto)
4698
326
        JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, proto));
4699
328
    sh->proto = proto;
4700
328
    memset(prop_hash_end(sh) - hash_size, 0, sizeof(prop_hash_end(sh)[0]) *
4701
328
           hash_size);
4702
328
    sh->prop_hash_mask = hash_size - 1;
4703
328
    sh->prop_size = prop_size;
4704
328
    sh->prop_count = 0;
4705
328
    sh->deleted_prop_count = 0;
4706
4707
    /* insert in the hash table */
4708
328
    sh->hash = shape_initial_hash(proto);
4709
328
    sh->is_hashed = TRUE;
4710
328
    sh->has_small_array_index = FALSE;
4711
328
    js_shape_hash_link(ctx->rt, sh);
4712
328
    return sh;
4713
328
}
4714
4715
static JSShape *js_new_shape(JSContext *ctx, JSObject *proto)
4716
326
{
4717
326
    return js_new_shape2(ctx, proto, JS_PROP_INITIAL_HASH_SIZE,
4718
326
                         JS_PROP_INITIAL_SIZE);
4719
326
}
4720
4721
/* The shape is cloned. The new shape is not inserted in the shape
4722
   hash table */
4723
static JSShape *js_clone_shape(JSContext *ctx, JSShape *sh1)
4724
173
{
4725
173
    JSShape *sh;
4726
173
    void *sh_alloc, *sh_alloc1;
4727
173
    size_t size;
4728
173
    JSShapeProperty *pr;
4729
173
    uint32_t i, hash_size;
4730
4731
173
    hash_size = sh1->prop_hash_mask + 1;
4732
173
    size = get_shape_size(hash_size, sh1->prop_size);
4733
173
    sh_alloc = js_malloc(ctx, size);
4734
173
    if (!sh_alloc)
4735
0
        return NULL;
4736
173
    sh_alloc1 = get_alloc_from_shape(sh1);
4737
173
    memcpy(sh_alloc, sh_alloc1, size);
4738
173
    sh = get_shape_from_alloc(sh_alloc, hash_size);
4739
173
    sh->header.ref_count = 1;
4740
173
    add_gc_object(ctx->rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);
4741
173
    sh->is_hashed = FALSE;
4742
173
    if (sh->proto) {
4743
164
        JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
4744
164
    }
4745
267
    for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {
4746
94
        JS_DupAtom(ctx, pr->atom);
4747
94
    }
4748
173
    return sh;
4749
173
}
4750
4751
static JSShape *js_dup_shape(JSShape *sh)
4752
558
{
4753
558
    sh->header.ref_count++;
4754
558
    return sh;
4755
558
}
4756
4757
static void js_free_shape0(JSRuntime *rt, JSShape *sh)
4758
501
{
4759
501
    uint32_t i;
4760
501
    JSShapeProperty *pr;
4761
4762
501
    assert(sh->header.ref_count == 0);
4763
501
    if (sh->is_hashed)
4764
485
        js_shape_hash_unlink(rt, sh);
4765
501
    if (sh->proto != NULL) {
4766
490
        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
4767
490
    }
4768
501
    pr = get_shape_prop(sh);
4769
2.39k
    for(i = 0; i < sh->prop_count; i++) {
4770
1.89k
        JS_FreeAtomRT(rt, pr->atom);
4771
1.89k
        pr++;
4772
1.89k
    }
4773
501
    remove_gc_object(&sh->header);
4774
501
    js_free_rt(rt, get_alloc_from_shape(sh));
4775
501
}
4776
4777
static void js_free_shape(JSRuntime *rt, JSShape *sh)
4778
1.05k
{
4779
1.05k
    if (unlikely(--sh->header.ref_count <= 0)) {
4780
501
        js_free_shape0(rt, sh);
4781
501
    }
4782
1.05k
}
4783
4784
static void js_free_shape_null(JSRuntime *rt, JSShape *sh)
4785
2
{
4786
2
    if (sh)
4787
2
        js_free_shape(rt, sh);
4788
2
}
4789
4790
/* make space to hold at least 'count' properties */
4791
static no_inline int resize_properties(JSContext *ctx, JSShape **psh,
4792
                                       JSObject *p, uint32_t count)
4793
421
{
4794
421
    JSShape *sh;
4795
421
    uint32_t new_size, new_hash_size, new_hash_mask, i;
4796
421
    JSShapeProperty *pr;
4797
421
    void *sh_alloc;
4798
421
    intptr_t h;
4799
421
    JSShape *old_sh;
4800
4801
421
    sh = *psh;
4802
421
    new_size = max_int(count, sh->prop_size * 3 / 2);
4803
    /* Reallocate prop array first to avoid crash or size inconsistency
4804
       in case of memory allocation failure */
4805
421
    if (p) {
4806
421
        JSProperty *new_prop;
4807
421
        new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size);
4808
421
        if (unlikely(!new_prop))
4809
0
            return -1;
4810
421
        p->prop = new_prop;
4811
421
    }
4812
421
    new_hash_size = sh->prop_hash_mask + 1;
4813
580
    while (new_hash_size < new_size)
4814
159
        new_hash_size = 2 * new_hash_size;
4815
    /* resize the property shapes. Using js_realloc() is not possible in
4816
       case the GC runs during the allocation */
4817
421
    old_sh = sh;
4818
421
    sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
4819
421
    if (!sh_alloc)
4820
0
        return -1;
4821
421
    sh = get_shape_from_alloc(sh_alloc, new_hash_size);
4822
421
    list_del(&old_sh->header.link);
4823
    /* copy all the shape properties */
4824
421
    memcpy(sh, old_sh,
4825
421
           sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count);
4826
421
    list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
4827
4828
421
    if (new_hash_size != (sh->prop_hash_mask + 1)) {
4829
        /* resize the hash table and the properties */
4830
159
        new_hash_mask = new_hash_size - 1;
4831
159
        sh->prop_hash_mask = new_hash_mask;
4832
159
        memset(prop_hash_end(sh) - new_hash_size, 0,
4833
159
               sizeof(prop_hash_end(sh)[0]) * new_hash_size);
4834
1.65k
        for(i = 0, pr = sh->prop; i < sh->prop_count; i++, pr++) {
4835
1.50k
            if (pr->atom != JS_ATOM_NULL) {
4836
1.50k
                h = ((uintptr_t)pr->atom & new_hash_mask);
4837
1.50k
                pr->hash_next = prop_hash_end(sh)[-h - 1];
4838
1.50k
                prop_hash_end(sh)[-h - 1] = i + 1;
4839
1.50k
            }
4840
1.50k
        }
4841
262
    } else {
4842
        /* just copy the previous hash table */
4843
262
        memcpy(prop_hash_end(sh) - new_hash_size, prop_hash_end(old_sh) - new_hash_size,
4844
262
               sizeof(prop_hash_end(sh)[0]) * new_hash_size);
4845
262
    }
4846
421
    js_free(ctx, get_alloc_from_shape(old_sh));
4847
421
    *psh = sh;
4848
421
    sh->prop_size = new_size;
4849
421
    return 0;
4850
421
}
4851
4852
/* remove the deleted properties. */
4853
static int compact_properties(JSContext *ctx, JSObject *p)
4854
0
{
4855
0
    JSShape *sh, *old_sh;
4856
0
    void *sh_alloc;
4857
0
    intptr_t h;
4858
0
    uint32_t new_hash_size, i, j, new_hash_mask, new_size;
4859
0
    JSShapeProperty *old_pr, *pr;
4860
0
    JSProperty *prop, *new_prop;
4861
4862
0
    sh = p->shape;
4863
0
    assert(!sh->is_hashed);
4864
4865
0
    new_size = max_int(JS_PROP_INITIAL_SIZE,
4866
0
                       sh->prop_count - sh->deleted_prop_count);
4867
0
    assert(new_size <= sh->prop_size);
4868
4869
0
    new_hash_size = sh->prop_hash_mask + 1;
4870
0
    while ((new_hash_size / 2) >= new_size)
4871
0
        new_hash_size = new_hash_size / 2;
4872
0
    new_hash_mask = new_hash_size - 1;
4873
4874
    /* resize the hash table and the properties */
4875
0
    old_sh = sh;
4876
0
    sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
4877
0
    if (!sh_alloc)
4878
0
        return -1;
4879
0
    sh = get_shape_from_alloc(sh_alloc, new_hash_size);
4880
0
    list_del(&old_sh->header.link);
4881
0
    memcpy(sh, old_sh, sizeof(JSShape));
4882
0
    list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
4883
4884
0
    memset(prop_hash_end(sh) - new_hash_size, 0,
4885
0
           sizeof(prop_hash_end(sh)[0]) * new_hash_size);
4886
4887
0
    j = 0;
4888
0
    old_pr = old_sh->prop;
4889
0
    pr = sh->prop;
4890
0
    prop = p->prop;
4891
0
    for(i = 0; i < sh->prop_count; i++) {
4892
0
        if (old_pr->atom != JS_ATOM_NULL) {
4893
0
            pr->atom = old_pr->atom;
4894
0
            pr->flags = old_pr->flags;
4895
0
            h = ((uintptr_t)old_pr->atom & new_hash_mask);
4896
0
            pr->hash_next = prop_hash_end(sh)[-h - 1];
4897
0
            prop_hash_end(sh)[-h - 1] = j + 1;
4898
0
            prop[j] = prop[i];
4899
0
            j++;
4900
0
            pr++;
4901
0
        }
4902
0
        old_pr++;
4903
0
    }
4904
0
    assert(j == (sh->prop_count - sh->deleted_prop_count));
4905
0
    sh->prop_hash_mask = new_hash_mask;
4906
0
    sh->prop_size = new_size;
4907
0
    sh->deleted_prop_count = 0;
4908
0
    sh->prop_count = j;
4909
4910
0
    p->shape = sh;
4911
0
    js_free(ctx, get_alloc_from_shape(old_sh));
4912
4913
    /* reduce the size of the object properties */
4914
0
    new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size);
4915
0
    if (new_prop)
4916
0
        p->prop = new_prop;
4917
0
    return 0;
4918
0
}
4919
4920
static int add_shape_property(JSContext *ctx, JSShape **psh,
4921
                              JSObject *p, JSAtom atom, int prop_flags)
4922
1.80k
{
4923
1.80k
    JSRuntime *rt = ctx->rt;
4924
1.80k
    JSShape *sh = *psh;
4925
1.80k
    JSShapeProperty *pr, *prop;
4926
1.80k
    uint32_t hash_mask, new_shape_hash = 0;
4927
1.80k
    intptr_t h;
4928
4929
    /* update the shape hash */
4930
1.80k
    if (sh->is_hashed) {
4931
1.49k
        js_shape_hash_unlink(rt, sh);
4932
1.49k
        new_shape_hash = shape_hash(shape_hash(sh->hash, atom), prop_flags);
4933
1.49k
    }
4934
4935
1.80k
    if (unlikely(sh->prop_count >= sh->prop_size)) {
4936
421
        if (resize_properties(ctx, psh, p, sh->prop_count + 1)) {
4937
            /* in case of error, reinsert in the hash table.
4938
               sh is still valid if resize_properties() failed */
4939
0
            if (sh->is_hashed)
4940
0
                js_shape_hash_link(rt, sh);
4941
0
            return -1;
4942
0
        }
4943
421
        sh = *psh;
4944
421
    }
4945
1.80k
    if (sh->is_hashed) {
4946
1.49k
        sh->hash = new_shape_hash;
4947
1.49k
        js_shape_hash_link(rt, sh);
4948
1.49k
    }
4949
    /* Initialize the new shape property.
4950
       The object property at p->prop[sh->prop_count] is uninitialized */
4951
1.80k
    prop = get_shape_prop(sh);
4952
1.80k
    pr = &prop[sh->prop_count++];
4953
1.80k
    pr->atom = JS_DupAtom(ctx, atom);
4954
1.80k
    pr->flags = prop_flags;
4955
1.80k
    sh->has_small_array_index |= __JS_AtomIsTaggedInt(atom);
4956
    /* add in hash table */
4957
1.80k
    hash_mask = sh->prop_hash_mask;
4958
1.80k
    h = atom & hash_mask;
4959
1.80k
    pr->hash_next = prop_hash_end(sh)[-h - 1];
4960
1.80k
    prop_hash_end(sh)[-h - 1] = sh->prop_count;
4961
1.80k
    return 0;
4962
1.80k
}
4963
4964
/* find a hashed empty shape matching the prototype. Return NULL if
4965
   not found */
4966
static JSShape *find_hashed_shape_proto(JSRuntime *rt, JSObject *proto)
4967
472
{
4968
472
    JSShape *sh1;
4969
472
    uint32_t h, h1;
4970
4971
472
    h = shape_initial_hash(proto);
4972
472
    h1 = get_shape_hash(h, rt->shape_hash_bits);
4973
545
    for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) {
4974
219
        if (sh1->hash == h &&
4975
219
            sh1->proto == proto &&
4976
219
            sh1->prop_count == 0) {
4977
146
            return sh1;
4978
146
        }
4979
219
    }
4980
326
    return NULL;
4981
472
}
4982
4983
/* find a hashed shape matching sh + (prop, prop_flags). Return NULL if
4984
   not found */
4985
static JSShape *find_hashed_shape_prop(JSRuntime *rt, JSShape *sh,
4986
                                       JSAtom atom, int prop_flags)
4987
1.90k
{
4988
1.90k
    JSShape *sh1;
4989
1.90k
    uint32_t h, h1, i, n;
4990
4991
1.90k
    h = sh->hash;
4992
1.90k
    h = shape_hash(h, atom);
4993
1.90k
    h = shape_hash(h, prop_flags);
4994
1.90k
    h1 = get_shape_hash(h, rt->shape_hash_bits);
4995
2.53k
    for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) {
4996
        /* we test the hash first so that the rest is done only if the
4997
           shapes really match */
4998
1.04k
        if (sh1->hash == h &&
4999
1.04k
            sh1->proto == sh->proto &&
5000
1.04k
            sh1->prop_count == ((n = sh->prop_count) + 1)) {
5001
942
            for(i = 0; i < n; i++) {
5002
532
                if (unlikely(sh1->prop[i].atom != sh->prop[i].atom) ||
5003
532
                    unlikely(sh1->prop[i].flags != sh->prop[i].flags))
5004
0
                    goto next;
5005
532
            }
5006
410
            if (unlikely(sh1->prop[n].atom != atom) ||
5007
410
                unlikely(sh1->prop[n].flags != prop_flags))
5008
0
                goto next;
5009
410
            return sh1;
5010
410
        }
5011
638
    next: ;
5012
638
    }
5013
1.49k
    return NULL;
5014
1.90k
}
5015
5016
static __maybe_unused void JS_DumpShape(JSRuntime *rt, int i, JSShape *sh)
5017
0
{
5018
0
    char atom_buf[ATOM_GET_STR_BUF_SIZE];
5019
0
    int j;
5020
0
5021
0
    /* XXX: should output readable class prototype */
5022
0
    printf("%5d %3d%c %14p %5d %5d", i,
5023
0
           sh->header.ref_count, " *"[sh->is_hashed],
5024
0
           (void *)sh->proto, sh->prop_size, sh->prop_count);
5025
0
    for(j = 0; j < sh->prop_count; j++) {
5026
0
        printf(" %s", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf),
5027
0
                                      sh->prop[j].atom));
5028
0
    }
5029
0
    printf("\n");
5030
0
}
5031
5032
static __maybe_unused void JS_DumpShapes(JSRuntime *rt)
5033
0
{
5034
0
    int i;
5035
0
    JSShape *sh;
5036
0
    struct list_head *el;
5037
0
    JSObject *p;
5038
0
    JSGCObjectHeader *gp;
5039
0
5040
0
    printf("JSShapes: {\n");
5041
0
    printf("%5s %4s %14s %5s %5s %s\n", "SLOT", "REFS", "PROTO", "SIZE", "COUNT", "PROPS");
5042
0
    for(i = 0; i < rt->shape_hash_size; i++) {
5043
0
        for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) {
5044
0
            JS_DumpShape(rt, i, sh);
5045
0
            assert(sh->is_hashed);
5046
0
        }
5047
0
    }
5048
0
    /* dump non-hashed shapes */
5049
0
    list_for_each(el, &rt->gc_obj_list) {
5050
0
        gp = list_entry(el, JSGCObjectHeader, link);
5051
0
        if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
5052
0
            p = (JSObject *)gp;
5053
0
            if (!p->shape->is_hashed) {
5054
0
                JS_DumpShape(rt, -1, p->shape);
5055
0
            }
5056
0
        }
5057
0
    }
5058
0
    printf("}\n");
5059
0
}
5060
5061
static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID class_id)
5062
474
{
5063
474
    JSObject *p;
5064
5065
474
    js_trigger_gc(ctx->rt, sizeof(JSObject));
5066
474
    p = js_malloc(ctx, sizeof(JSObject));
5067
474
    if (unlikely(!p))
5068
0
        goto fail;
5069
474
    p->class_id = class_id;
5070
474
    p->extensible = TRUE;
5071
474
    p->free_mark = 0;
5072
474
    p->is_exotic = 0;
5073
474
    p->fast_array = 0;
5074
474
    p->is_constructor = 0;
5075
474
    p->has_immutable_prototype = 0;
5076
474
    p->tmp_mark = 0;
5077
474
    p->is_HTMLDDA = 0;
5078
474
    p->weakref_count = 0;
5079
474
    p->u.opaque = NULL;
5080
474
    p->shape = sh;
5081
474
    p->prop = js_malloc(ctx, sizeof(JSProperty) * sh->prop_size);
5082
474
    if (unlikely(!p->prop)) {
5083
0
        js_free(ctx, p);
5084
0
    fail:
5085
0
        js_free_shape(ctx->rt, sh);
5086
0
        return JS_EXCEPTION;
5087
0
    }
5088
5089
474
    switch(class_id) {
5090
115
    case JS_CLASS_OBJECT:
5091
115
        break;
5092
4
    case JS_CLASS_ARRAY:
5093
4
        {
5094
4
            JSProperty *pr;
5095
4
            p->is_exotic = 1;
5096
4
            p->fast_array = 1;
5097
4
            p->u.array.u.values = NULL;
5098
4
            p->u.array.count = 0;
5099
4
            p->u.array.u1.size = 0;
5100
            /* the length property is always the first one */
5101
4
            if (likely(sh == ctx->array_shape)) {
5102
2
                pr = &p->prop[0];
5103
2
            } else {
5104
                /* only used for the first array */
5105
                /* cannot fail */
5106
2
                pr = add_property(ctx, p, JS_ATOM_length,
5107
2
                                  JS_PROP_WRITABLE | JS_PROP_LENGTH);
5108
2
            }
5109
4
            pr->u.value = JS_NewInt32(ctx, 0);
5110
4
        }
5111
4
        break;
5112
308
    case JS_CLASS_C_FUNCTION:
5113
308
        p->prop[0].u.value = JS_UNDEFINED;
5114
308
        break;
5115
0
    case JS_CLASS_ARGUMENTS:
5116
0
    case JS_CLASS_UINT8C_ARRAY:
5117
0
    case JS_CLASS_INT8_ARRAY:
5118
0
    case JS_CLASS_UINT8_ARRAY:
5119
0
    case JS_CLASS_INT16_ARRAY:
5120
0
    case JS_CLASS_UINT16_ARRAY:
5121
0
    case JS_CLASS_INT32_ARRAY:
5122
0
    case JS_CLASS_UINT32_ARRAY:
5123
0
    case JS_CLASS_BIG_INT64_ARRAY:
5124
0
    case JS_CLASS_BIG_UINT64_ARRAY:
5125
0
    case JS_CLASS_FLOAT16_ARRAY:
5126
0
    case JS_CLASS_FLOAT32_ARRAY:
5127
0
    case JS_CLASS_FLOAT64_ARRAY:
5128
0
        p->is_exotic = 1;
5129
0
        p->fast_array = 1;
5130
0
        p->u.array.u.ptr = NULL;
5131
0
        p->u.array.count = 0;
5132
0
        break;
5133
0
    case JS_CLASS_DATAVIEW:
5134
0
        p->u.array.u.ptr = NULL;
5135
0
        p->u.array.count = 0;
5136
0
        break;
5137
2
    case JS_CLASS_NUMBER:
5138
4
    case JS_CLASS_STRING:
5139
6
    case JS_CLASS_BOOLEAN:
5140
6
    case JS_CLASS_SYMBOL:
5141
6
    case JS_CLASS_DATE:
5142
6
    case JS_CLASS_BIG_INT:
5143
6
        p->u.object_data = JS_UNDEFINED;
5144
6
        goto set_exotic;
5145
0
    case JS_CLASS_REGEXP:
5146
0
        p->u.regexp.pattern = NULL;
5147
0
        p->u.regexp.bytecode = NULL;
5148
0
        goto set_exotic;
5149
41
    default:
5150
47
    set_exotic:
5151
47
        if (ctx->rt->class_array[class_id].exotic) {
5152
6
            p->is_exotic = 1;
5153
6
        }
5154
47
        break;
5155
474
    }
5156
474
    p->header.ref_count = 1;
5157
474
    add_gc_object(ctx->rt, &p->header, JS_GC_OBJ_TYPE_JS_OBJECT);
5158
474
    return JS_MKPTR(JS_TAG_OBJECT, p);
5159
474
}
5160
5161
static JSObject *get_proto_obj(JSValueConst proto_val)
5162
474
{
5163
474
    if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT)
5164
11
        return NULL;
5165
463
    else
5166
463
        return JS_VALUE_GET_OBJ(proto_val);
5167
474
}
5168
5169
/* WARNING: proto must be an object or JS_NULL */
5170
JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto_val,
5171
                               JSClassID class_id)
5172
472
{
5173
472
    JSShape *sh;
5174
472
    JSObject *proto;
5175
5176
472
    proto = get_proto_obj(proto_val);
5177
472
    sh = find_hashed_shape_proto(ctx->rt, proto);
5178
472
    if (likely(sh)) {
5179
146
        sh = js_dup_shape(sh);
5180
326
    } else {
5181
326
        sh = js_new_shape(ctx, proto);
5182
326
        if (!sh)
5183
0
            return JS_EXCEPTION;
5184
326
    }
5185
472
    return JS_NewObjectFromShape(ctx, sh, class_id);
5186
472
}
5187
5188
#if 0
5189
static JSValue JS_GetObjectData(JSContext *ctx, JSValueConst obj)
5190
{
5191
    JSObject *p;
5192
5193
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
5194
        p = JS_VALUE_GET_OBJ(obj);
5195
        switch(p->class_id) {
5196
        case JS_CLASS_NUMBER:
5197
        case JS_CLASS_STRING:
5198
        case JS_CLASS_BOOLEAN:
5199
        case JS_CLASS_SYMBOL:
5200
        case JS_CLASS_DATE:
5201
        case JS_CLASS_BIG_INT:
5202
            return JS_DupValue(ctx, p->u.object_data);
5203
        }
5204
    }
5205
    return JS_UNDEFINED;
5206
}
5207
#endif
5208
5209
static int JS_SetObjectData(JSContext *ctx, JSValueConst obj, JSValue val)
5210
6
{
5211
6
    JSObject *p;
5212
5213
6
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
5214
6
        p = JS_VALUE_GET_OBJ(obj);
5215
6
        switch(p->class_id) {
5216
2
        case JS_CLASS_NUMBER:
5217
4
        case JS_CLASS_STRING:
5218
6
        case JS_CLASS_BOOLEAN:
5219
6
        case JS_CLASS_SYMBOL:
5220
6
        case JS_CLASS_DATE:
5221
6
        case JS_CLASS_BIG_INT:
5222
6
            JS_FreeValue(ctx, p->u.object_data);
5223
6
            p->u.object_data = val; /* for JS_CLASS_STRING, 'val' must
5224
                                       be JS_TAG_STRING (and not a
5225
                                       rope) */
5226
6
            return 0;
5227
6
        }
5228
6
    }
5229
0
    JS_FreeValue(ctx, val);
5230
0
    if (!JS_IsException(obj))
5231
0
        JS_ThrowTypeError(ctx, "invalid object type");
5232
0
    return -1;
5233
6
}
5234
5235
JSValue JS_NewObjectClass(JSContext *ctx, int class_id)
5236
10
{
5237
10
    return JS_NewObjectProtoClass(ctx, ctx->class_proto[class_id], class_id);
5238
10
}
5239
5240
JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto)
5241
69
{
5242
69
    return JS_NewObjectProtoClass(ctx, proto, JS_CLASS_OBJECT);
5243
69
}
5244
5245
JSValue JS_NewArray(JSContext *ctx)
5246
2
{
5247
2
    return JS_NewObjectFromShape(ctx, js_dup_shape(ctx->array_shape),
5248
2
                                 JS_CLASS_ARRAY);
5249
2
}
5250
5251
JSValue JS_NewObject(JSContext *ctx)
5252
46
{
5253
    /* inline JS_NewObjectClass(ctx, JS_CLASS_OBJECT); */
5254
46
    return JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_OBJECT);
5255
46
}
5256
5257
static void js_function_set_properties(JSContext *ctx, JSValueConst func_obj,
5258
                                       JSAtom name, int len)
5259
326
{
5260
    /* ES6 feature non compatible with ES5.1: length is configurable */
5261
326
    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length, JS_NewInt32(ctx, len),
5262
326
                           JS_PROP_CONFIGURABLE);
5263
326
    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name,
5264
326
                           JS_AtomToString(ctx, name), JS_PROP_CONFIGURABLE);
5265
326
}
5266
5267
static BOOL js_class_has_bytecode(JSClassID class_id)
5268
2
{
5269
2
    return (class_id == JS_CLASS_BYTECODE_FUNCTION ||
5270
2
            class_id == JS_CLASS_GENERATOR_FUNCTION ||
5271
2
            class_id == JS_CLASS_ASYNC_FUNCTION ||
5272
2
            class_id == JS_CLASS_ASYNC_GENERATOR_FUNCTION);
5273
2
}
5274
5275
/* return NULL without exception if not a function or no bytecode */
5276
static JSFunctionBytecode *JS_GetFunctionBytecode(JSValueConst val)
5277
1
{
5278
1
    JSObject *p;
5279
1
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
5280
0
        return NULL;
5281
1
    p = JS_VALUE_GET_OBJ(val);
5282
1
    if (!js_class_has_bytecode(p->class_id))
5283
0
        return NULL;
5284
1
    return p->u.func.function_bytecode;
5285
1
}
5286
5287
static void js_method_set_home_object(JSContext *ctx, JSValueConst func_obj,
5288
                                      JSValueConst home_obj)
5289
0
{
5290
0
    JSObject *p, *p1;
5291
0
    JSFunctionBytecode *b;
5292
5293
0
    if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
5294
0
        return;
5295
0
    p = JS_VALUE_GET_OBJ(func_obj);
5296
0
    if (!js_class_has_bytecode(p->class_id))
5297
0
        return;
5298
0
    b = p->u.func.function_bytecode;
5299
0
    if (b->need_home_object) {
5300
0
        p1 = p->u.func.home_object;
5301
0
        if (p1) {
5302
0
            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
5303
0
        }
5304
0
        if (JS_VALUE_GET_TAG(home_obj) == JS_TAG_OBJECT)
5305
0
            p1 = JS_VALUE_GET_OBJ(JS_DupValue(ctx, home_obj));
5306
0
        else
5307
0
            p1 = NULL;
5308
0
        p->u.func.home_object = p1;
5309
0
    }
5310
0
}
5311
5312
static JSValue js_get_function_name(JSContext *ctx, JSAtom name)
5313
0
{
5314
0
    JSValue name_str;
5315
5316
0
    name_str = JS_AtomToString(ctx, name);
5317
0
    if (JS_AtomSymbolHasDescription(ctx, name)) {
5318
0
        name_str = JS_ConcatString3(ctx, "[", name_str, "]");
5319
0
    }
5320
0
    return name_str;
5321
0
}
5322
5323
/* Modify the name of a method according to the atom and
5324
   'flags'. 'flags' is a bitmask of JS_PROP_HAS_GET and
5325
   JS_PROP_HAS_SET. Also set the home object of the method.
5326
   Return < 0 if exception. */
5327
static int js_method_set_properties(JSContext *ctx, JSValueConst func_obj,
5328
                                    JSAtom name, int flags, JSValueConst home_obj)
5329
0
{
5330
0
    JSValue name_str;
5331
5332
0
    name_str = js_get_function_name(ctx, name);
5333
0
    if (flags & JS_PROP_HAS_GET) {
5334
0
        name_str = JS_ConcatString3(ctx, "get ", name_str, "");
5335
0
    } else if (flags & JS_PROP_HAS_SET) {
5336
0
        name_str = JS_ConcatString3(ctx, "set ", name_str, "");
5337
0
    }
5338
0
    if (JS_IsException(name_str))
5339
0
        return -1;
5340
0
    if (JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name_str,
5341
0
                               JS_PROP_CONFIGURABLE) < 0)
5342
0
        return -1;
5343
0
    js_method_set_home_object(ctx, func_obj, home_obj);
5344
0
    return 0;
5345
0
}
5346
5347
/* Note: at least 'length' arguments will be readable in 'argv' */
5348
static JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func,
5349
                                const char *name,
5350
                                int length, JSCFunctionEnum cproto, int magic,
5351
                                JSValueConst proto_val)
5352
308
{
5353
308
    JSValue func_obj;
5354
308
    JSObject *p;
5355
308
    JSAtom name_atom;
5356
5357
308
    func_obj = JS_NewObjectProtoClass(ctx, proto_val, JS_CLASS_C_FUNCTION);
5358
308
    if (JS_IsException(func_obj))
5359
0
        return func_obj;
5360
308
    p = JS_VALUE_GET_OBJ(func_obj);
5361
308
    p->u.cfunc.realm = JS_DupContext(ctx);
5362
308
    p->u.cfunc.c_function.generic = func;
5363
308
    p->u.cfunc.length = length;
5364
308
    p->u.cfunc.cproto = cproto;
5365
308
    p->u.cfunc.magic = magic;
5366
308
    p->is_constructor = (cproto == JS_CFUNC_constructor ||
5367
308
                         cproto == JS_CFUNC_constructor_magic ||
5368
308
                         cproto == JS_CFUNC_constructor_or_func ||
5369
308
                         cproto == JS_CFUNC_constructor_or_func_magic);
5370
308
    if (!name)
5371
2
        name = "";
5372
308
    name_atom = JS_NewAtom(ctx, name);
5373
308
    if (name_atom == JS_ATOM_NULL) {
5374
0
        JS_FreeValue(ctx, func_obj);
5375
0
        return JS_EXCEPTION;
5376
0
    }
5377
308
    js_function_set_properties(ctx, func_obj, name_atom, length);
5378
308
    JS_FreeAtom(ctx, name_atom);
5379
308
    return func_obj;
5380
308
}
5381
5382
/* Note: at least 'length' arguments will be readable in 'argv' */
5383
JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func,
5384
                         const char *name,
5385
                         int length, JSCFunctionEnum cproto, int magic)
5386
260
{
5387
260
    return JS_NewCFunction3(ctx, func, name, length, cproto, magic,
5388
260
                            ctx->function_proto);
5389
260
}
5390
5391
typedef struct JSCFunctionDataRecord {
5392
    JSCFunctionData *func;
5393
    uint8_t length;
5394
    uint8_t data_len;
5395
    uint16_t magic;
5396
    JSValue data[0];
5397
} JSCFunctionDataRecord;
5398
5399
static void js_c_function_data_finalizer(JSRuntime *rt, JSValue val)
5400
6
{
5401
6
    JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA);
5402
6
    int i;
5403
5404
6
    if (s) {
5405
18
        for(i = 0; i < s->data_len; i++) {
5406
12
            JS_FreeValueRT(rt, s->data[i]);
5407
12
        }
5408
6
        js_free_rt(rt, s);
5409
6
    }
5410
6
}
5411
5412
static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val,
5413
                                    JS_MarkFunc *mark_func)
5414
0
{
5415
0
    JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA);
5416
0
    int i;
5417
5418
0
    if (s) {
5419
0
        for(i = 0; i < s->data_len; i++) {
5420
0
            JS_MarkValue(rt, s->data[i], mark_func);
5421
0
        }
5422
0
    }
5423
0
}
5424
5425
static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj,
5426
                                       JSValueConst this_val,
5427
                                       int argc, JSValueConst *argv, int flags)
5428
6
{
5429
6
    JSCFunctionDataRecord *s = JS_GetOpaque(func_obj, JS_CLASS_C_FUNCTION_DATA);
5430
6
    JSValueConst *arg_buf;
5431
6
    int i;
5432
5433
    /* XXX: could add the function on the stack for debug */
5434
6
    if (unlikely(argc < s->length)) {
5435
0
        arg_buf = alloca(sizeof(arg_buf[0]) * s->length);
5436
0
        for(i = 0; i < argc; i++)
5437
0
            arg_buf[i] = argv[i];
5438
0
        for(i = argc; i < s->length; i++)
5439
0
            arg_buf[i] = JS_UNDEFINED;
5440
6
    } else {
5441
6
        arg_buf = argv;
5442
6
    }
5443
5444
6
    return s->func(ctx, this_val, argc, arg_buf, s->magic, s->data);
5445
6
}
5446
5447
JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,
5448
                            int length, int magic, int data_len,
5449
                            JSValueConst *data)
5450
6
{
5451
6
    JSCFunctionDataRecord *s;
5452
6
    JSValue func_obj;
5453
6
    int i;
5454
5455
6
    func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
5456
6
                                      JS_CLASS_C_FUNCTION_DATA);
5457
6
    if (JS_IsException(func_obj))
5458
0
        return func_obj;
5459
6
    s = js_malloc(ctx, sizeof(*s) + data_len * sizeof(JSValue));
5460
6
    if (!s) {
5461
0
        JS_FreeValue(ctx, func_obj);
5462
0
        return JS_EXCEPTION;
5463
0
    }
5464
6
    s->func = func;
5465
6
    s->length = length;
5466
6
    s->data_len = data_len;
5467
6
    s->magic = magic;
5468
18
    for(i = 0; i < data_len; i++)
5469
12
        s->data[i] = JS_DupValue(ctx, data[i]);
5470
6
    JS_SetOpaque(func_obj, s);
5471
6
    js_function_set_properties(ctx, func_obj,
5472
6
                               JS_ATOM_empty_string, length);
5473
6
    return func_obj;
5474
6
}
5475
5476
static JSContext *js_autoinit_get_realm(JSProperty *pr)
5477
2.28k
{
5478
2.28k
    return (JSContext *)(pr->u.init.realm_and_id & ~3);
5479
2.28k
}
5480
5481
static JSAutoInitIDEnum js_autoinit_get_id(JSProperty *pr)
5482
20
{
5483
20
    return pr->u.init.realm_and_id & 3;
5484
20
}
5485
5486
static void js_autoinit_free(JSRuntime *rt, JSProperty *pr)
5487
768
{
5488
768
    JS_FreeContext(js_autoinit_get_realm(pr));
5489
768
}
5490
5491
static void js_autoinit_mark(JSRuntime *rt, JSProperty *pr,
5492
                             JS_MarkFunc *mark_func)
5493
1.49k
{
5494
1.49k
    mark_func(rt, &js_autoinit_get_realm(pr)->header);
5495
1.49k
}
5496
5497
static void free_property(JSRuntime *rt, JSProperty *pr, int prop_flags)
5498
2.21k
{
5499
2.21k
    if (unlikely(prop_flags & JS_PROP_TMASK)) {
5500
1.01k
        if ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
5501
74
            if (pr->u.getset.getter)
5502
74
                JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
5503
74
            if (pr->u.getset.setter)
5504
6
                JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
5505
944
        } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
5506
196
            free_var_ref(rt, pr->u.var_ref);
5507
748
        } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
5508
748
            js_autoinit_free(rt, pr);
5509
748
        }
5510
1.19k
    } else {
5511
1.19k
        JS_FreeValueRT(rt, pr->u.value);
5512
1.19k
    }
5513
2.21k
}
5514
5515
static force_inline JSShapeProperty *find_own_property1(JSObject *p,
5516
                                                        JSAtom atom)
5517
1
{
5518
1
    JSShape *sh;
5519
1
    JSShapeProperty *pr, *prop;
5520
1
    intptr_t h;
5521
1
    sh = p->shape;
5522
1
    h = (uintptr_t)atom & sh->prop_hash_mask;
5523
1
    h = prop_hash_end(sh)[-h - 1];
5524
1
    prop = get_shape_prop(sh);
5525
1
    while (h) {
5526
0
        pr = &prop[h - 1];
5527
0
        if (likely(pr->atom == atom)) {
5528
0
            return pr;
5529
0
        }
5530
0
        h = pr->hash_next;
5531
0
    }
5532
1
    return NULL;
5533
1
}
5534
5535
static force_inline JSShapeProperty *find_own_property(JSProperty **ppr,
5536
                                                       JSObject *p,
5537
                                                       JSAtom atom)
5538
2.10k
{
5539
2.10k
    JSShape *sh;
5540
2.10k
    JSShapeProperty *pr, *prop;
5541
2.10k
    intptr_t h;
5542
2.10k
    sh = p->shape;
5543
2.10k
    h = (uintptr_t)atom & sh->prop_hash_mask;
5544
2.10k
    h = prop_hash_end(sh)[-h - 1];
5545
2.10k
    prop = get_shape_prop(sh);
5546
2.89k
    while (h) {
5547
848
        pr = &prop[h - 1];
5548
848
        if (likely(pr->atom == atom)) {
5549
56
            *ppr = &p->prop[h - 1];
5550
            /* the compiler should be able to assume that pr != NULL here */
5551
56
            return pr;
5552
56
        }
5553
792
        h = pr->hash_next;
5554
792
    }
5555
2.04k
    *ppr = NULL;
5556
2.04k
    return NULL;
5557
2.10k
}
5558
5559
/* indicate that the object may be part of a function prototype cycle */
5560
static void set_cycle_flag(JSContext *ctx, JSValueConst obj)
5561
188
{
5562
188
}
5563
5564
static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref)
5565
396
{
5566
396
    if (var_ref) {
5567
396
        assert(var_ref->header.ref_count > 0);
5568
396
        if (--var_ref->header.ref_count == 0) {
5569
200
            if (var_ref->is_detached) {
5570
200
                JS_FreeValueRT(rt, var_ref->value);
5571
200
            } else {
5572
0
                list_del(&var_ref->var_ref_link); /* still on the stack */
5573
0
                if (var_ref->async_func)
5574
0
                    async_func_free(rt, var_ref->async_func);
5575
0
            }
5576
200
            remove_gc_object(&var_ref->header);
5577
200
            js_free_rt(rt, var_ref);
5578
200
        }
5579
396
    }
5580
396
}
5581
5582
static void js_array_finalizer(JSRuntime *rt, JSValue val)
5583
4
{
5584
4
    JSObject *p = JS_VALUE_GET_OBJ(val);
5585
4
    int i;
5586
5587
4
    for(i = 0; i < p->u.array.count; i++) {
5588
0
        JS_FreeValueRT(rt, p->u.array.u.values[i]);
5589
0
    }
5590
4
    js_free_rt(rt, p->u.array.u.values);
5591
4
}
5592
5593
static void js_array_mark(JSRuntime *rt, JSValueConst val,
5594
                          JS_MarkFunc *mark_func)
5595
8
{
5596
8
    JSObject *p = JS_VALUE_GET_OBJ(val);
5597
8
    int i;
5598
5599
8
    for(i = 0; i < p->u.array.count; i++) {
5600
0
        JS_MarkValue(rt, p->u.array.u.values[i], mark_func);
5601
0
    }
5602
8
}
5603
5604
static void js_object_data_finalizer(JSRuntime *rt, JSValue val)
5605
6
{
5606
6
    JSObject *p = JS_VALUE_GET_OBJ(val);
5607
6
    JS_FreeValueRT(rt, p->u.object_data);
5608
6
    p->u.object_data = JS_UNDEFINED;
5609
6
}
5610
5611
static void js_object_data_mark(JSRuntime *rt, JSValueConst val,
5612
                                JS_MarkFunc *mark_func)
5613
12
{
5614
12
    JSObject *p = JS_VALUE_GET_OBJ(val);
5615
12
    JS_MarkValue(rt, p->u.object_data, mark_func);
5616
12
}
5617
5618
static void js_c_function_finalizer(JSRuntime *rt, JSValue val)
5619
308
{
5620
308
    JSObject *p = JS_VALUE_GET_OBJ(val);
5621
5622
308
    if (p->u.cfunc.realm)
5623
308
        JS_FreeContext(p->u.cfunc.realm);
5624
308
}
5625
5626
static void js_c_function_mark(JSRuntime *rt, JSValueConst val,
5627
                               JS_MarkFunc *mark_func)
5628
616
{
5629
616
    JSObject *p = JS_VALUE_GET_OBJ(val);
5630
5631
616
    if (p->u.cfunc.realm)
5632
616
        mark_func(rt, &p->u.cfunc.realm->header);
5633
616
}
5634
5635
static void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val)
5636
3
{
5637
3
    JSObject *p1, *p = JS_VALUE_GET_OBJ(val);
5638
3
    JSFunctionBytecode *b;
5639
3
    JSVarRef **var_refs;
5640
3
    int i;
5641
5642
3
    p1 = p->u.func.home_object;
5643
3
    if (p1) {
5644
0
        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, p1));
5645
0
    }
5646
3
    b = p->u.func.function_bytecode;
5647
3
    if (b) {
5648
3
        var_refs = p->u.func.var_refs;
5649
3
        if (var_refs) {
5650
6
            for(i = 0; i < b->closure_var_count; i++)
5651
4
                free_var_ref(rt, var_refs[i]);
5652
2
            js_free_rt(rt, var_refs);
5653
2
        }
5654
3
        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b));
5655
3
    }
5656
3
}
5657
5658
static void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,
5659
                                      JS_MarkFunc *mark_func)
5660
6
{
5661
6
    JSObject *p = JS_VALUE_GET_OBJ(val);
5662
6
    JSVarRef **var_refs = p->u.func.var_refs;
5663
6
    JSFunctionBytecode *b = p->u.func.function_bytecode;
5664
6
    int i;
5665
5666
6
    if (p->u.func.home_object) {
5667
0
        JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object),
5668
0
                     mark_func);
5669
0
    }
5670
6
    if (b) {
5671
6
        if (var_refs) {
5672
12
            for(i = 0; i < b->closure_var_count; i++) {
5673
8
                JSVarRef *var_ref = var_refs[i];
5674
8
                if (var_ref) {
5675
8
                    mark_func(rt, &var_ref->header);
5676
8
                }
5677
8
            }
5678
4
        }
5679
        /* must mark the function bytecode because template objects may be
5680
           part of a cycle */
5681
6
        JS_MarkValue(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b), mark_func);
5682
6
    }
5683
6
}
5684
5685
static void js_bound_function_finalizer(JSRuntime *rt, JSValue val)
5686
0
{
5687
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
5688
0
    JSBoundFunction *bf = p->u.bound_function;
5689
0
    int i;
5690
5691
0
    JS_FreeValueRT(rt, bf->func_obj);
5692
0
    JS_FreeValueRT(rt, bf->this_val);
5693
0
    for(i = 0; i < bf->argc; i++) {
5694
0
        JS_FreeValueRT(rt, bf->argv[i]);
5695
0
    }
5696
0
    js_free_rt(rt, bf);
5697
0
}
5698
5699
static void js_bound_function_mark(JSRuntime *rt, JSValueConst val,
5700
                                JS_MarkFunc *mark_func)
5701
0
{
5702
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
5703
0
    JSBoundFunction *bf = p->u.bound_function;
5704
0
    int i;
5705
5706
0
    JS_MarkValue(rt, bf->func_obj, mark_func);
5707
0
    JS_MarkValue(rt, bf->this_val, mark_func);
5708
0
    for(i = 0; i < bf->argc; i++)
5709
0
        JS_MarkValue(rt, bf->argv[i], mark_func);
5710
0
}
5711
5712
static void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val)
5713
0
{
5714
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
5715
0
    JSForInIterator *it = p->u.for_in_iterator;
5716
0
    int i;
5717
5718
0
    JS_FreeValueRT(rt, it->obj);
5719
0
    if (!it->is_array) {
5720
0
        for(i = 0; i < it->atom_count; i++) {
5721
0
            JS_FreeAtomRT(rt, it->tab_atom[i].atom);
5722
0
        }
5723
0
        js_free_rt(rt, it->tab_atom);
5724
0
    }
5725
0
    js_free_rt(rt, it);
5726
0
}
5727
5728
static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val,
5729
                                JS_MarkFunc *mark_func)
5730
0
{
5731
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
5732
0
    JSForInIterator *it = p->u.for_in_iterator;
5733
0
    JS_MarkValue(rt, it->obj, mark_func);
5734
0
}
5735
5736
static void free_object(JSRuntime *rt, JSObject *p)
5737
474
{
5738
474
    int i;
5739
474
    JSClassFinalizer *finalizer;
5740
474
    JSShape *sh;
5741
474
    JSShapeProperty *pr;
5742
5743
474
    p->free_mark = 1; /* used to tell the object is invalid when
5744
                         freeing cycles */
5745
    /* free all the fields */
5746
474
    sh = p->shape;
5747
474
    pr = get_shape_prop(sh);
5748
2.68k
    for(i = 0; i < sh->prop_count; i++) {
5749
2.21k
        free_property(rt, &p->prop[i], pr->flags);
5750
2.21k
        pr++;
5751
2.21k
    }
5752
474
    js_free_rt(rt, p->prop);
5753
    /* as an optimization we destroy the shape immediately without
5754
       putting it in gc_zero_ref_count_list */
5755
474
    js_free_shape(rt, sh);
5756
5757
    /* fail safe */
5758
474
    p->shape = NULL;
5759
474
    p->prop = NULL;
5760
5761
474
    finalizer = rt->class_array[p->class_id].finalizer;
5762
474
    if (finalizer)
5763
351
        (*finalizer)(rt, JS_MKPTR(JS_TAG_OBJECT, p));
5764
5765
    /* fail safe */
5766
474
    p->class_id = 0;
5767
474
    p->u.opaque = NULL;
5768
474
    p->u.func.var_refs = NULL;
5769
474
    p->u.func.home_object = NULL;
5770
5771
474
    remove_gc_object(&p->header);
5772
474
    if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES) {
5773
456
        if (p->header.ref_count == 0 && p->weakref_count == 0) {
5774
248
            js_free_rt(rt, p);
5775
248
        } else {
5776
            /* keep the object structure because there are may be
5777
               references to it */
5778
208
            list_add_tail(&p->header.link, &rt->gc_zero_ref_count_list);
5779
208
        }
5780
456
    } else {
5781
        /* keep the object structure in case there are weak references to it */
5782
18
        if (p->weakref_count == 0) {
5783
18
            js_free_rt(rt, p);
5784
18
        } else {
5785
0
            p->header.mark = 0; /* reset the mark so that the weakref can be freed */
5786
0
        }
5787
18
    }
5788
474
}
5789
5790
static void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp)
5791
490
{
5792
490
    switch(gp->gc_obj_type) {
5793
474
    case JS_GC_OBJ_TYPE_JS_OBJECT:
5794
474
        free_object(rt, (JSObject *)gp);
5795
474
        break;
5796
4
    case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
5797
4
        free_function_bytecode(rt, (JSFunctionBytecode *)gp);
5798
4
        break;
5799
3
    case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
5800
3
        __async_func_free(rt, (JSAsyncFunctionState *)gp);
5801
3
        break;
5802
9
    case JS_GC_OBJ_TYPE_MODULE:
5803
9
        js_free_module_def(rt, (JSModuleDef *)gp);
5804
9
        break;
5805
0
    default:
5806
0
        abort();
5807
490
    }
5808
490
}
5809
5810
static void free_zero_refcount(JSRuntime *rt)
5811
16
{
5812
16
    struct list_head *el;
5813
16
    JSGCObjectHeader *p;
5814
5815
16
    rt->gc_phase = JS_GC_PHASE_DECREF;
5816
38
    for(;;) {
5817
38
        el = rt->gc_zero_ref_count_list.next;
5818
38
        if (el == &rt->gc_zero_ref_count_list)
5819
16
            break;
5820
22
        p = list_entry(el, JSGCObjectHeader, link);
5821
22
        assert(p->ref_count == 0);
5822
22
        free_gc_object(rt, p);
5823
22
    }
5824
16
    rt->gc_phase = JS_GC_PHASE_NONE;
5825
16
}
5826
5827
/* called with the ref_count of 'v' reaches zero. */
5828
void __JS_FreeValueRT(JSRuntime *rt, JSValue v)
5829
659
{
5830
659
    uint32_t tag = JS_VALUE_GET_TAG(v);
5831
5832
#ifdef DUMP_FREE
5833
    {
5834
        printf("Freeing ");
5835
        if (tag == JS_TAG_OBJECT) {
5836
            JS_DumpObject(rt, JS_VALUE_GET_OBJ(v));
5837
        } else {
5838
            JS_DumpValueShort(rt, v);
5839
            printf("\n");
5840
        }
5841
    }
5842
#endif
5843
5844
659
    switch(tag) {
5845
180
    case JS_TAG_STRING:
5846
180
        {
5847
180
            JSString *p = JS_VALUE_GET_STRING(v);
5848
180
            if (p->atom_type) {
5849
166
                JS_FreeAtomStruct(rt, p);
5850
166
            } else {
5851
#ifdef DUMP_LEAKS
5852
                list_del(&p->link);
5853
#endif
5854
14
                js_free_rt(rt, p);
5855
14
            }
5856
180
        }
5857
180
        break;
5858
0
    case JS_TAG_STRING_ROPE:
5859
        /* Note: recursion is acceptable because the rope depth is bounded */
5860
0
        {
5861
0
            JSStringRope *p = JS_VALUE_GET_STRING_ROPE(v);
5862
0
            JS_FreeValueRT(rt, p->left);
5863
0
            JS_FreeValueRT(rt, p->right);
5864
0
            js_free_rt(rt, p);
5865
0
        }
5866
0
        break;
5867
474
    case JS_TAG_OBJECT:
5868
478
    case JS_TAG_FUNCTION_BYTECODE:
5869
479
    case JS_TAG_MODULE:
5870
479
        {
5871
479
            JSGCObjectHeader *p = JS_VALUE_GET_PTR(v);
5872
479
            if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {
5873
19
                list_del(&p->link);
5874
19
                list_add(&p->link, &rt->gc_zero_ref_count_list);
5875
19
                p->mark = 1; /* indicate that the object is about to be freed */
5876
19
                if (rt->gc_phase == JS_GC_PHASE_NONE) {
5877
13
                    free_zero_refcount(rt);
5878
13
                }
5879
19
            }
5880
479
        }
5881
479
        break;
5882
0
    case JS_TAG_BIG_INT:
5883
0
        {
5884
0
            JSBigInt *p = JS_VALUE_GET_PTR(v);
5885
0
            js_free_rt(rt, p);
5886
0
        }
5887
0
        break;
5888
0
    case JS_TAG_SYMBOL:
5889
0
        {
5890
0
            JSAtomStruct *p = JS_VALUE_GET_PTR(v);
5891
0
            JS_FreeAtomStruct(rt, p);
5892
0
        }
5893
0
        break;
5894
0
    default:
5895
0
        abort();
5896
659
    }
5897
659
}
5898
5899
void __JS_FreeValue(JSContext *ctx, JSValue v)
5900
138
{
5901
138
    __JS_FreeValueRT(ctx->rt, v);
5902
138
}
5903
5904
/* garbage collection */
5905
5906
static void gc_remove_weak_objects(JSRuntime *rt)
5907
0
{
5908
0
    struct list_head *el;
5909
5910
    /* add the freed objects to rt->gc_zero_ref_count_list so that
5911
       rt->weakref_list is not modified while we traverse it */
5912
0
    rt->gc_phase = JS_GC_PHASE_DECREF; 
5913
        
5914
0
    list_for_each(el, &rt->weakref_list) {
5915
0
        JSWeakRefHeader *wh = list_entry(el, JSWeakRefHeader, link);
5916
0
        switch(wh->weakref_type) {
5917
0
        case JS_WEAKREF_TYPE_MAP:
5918
0
            map_delete_weakrefs(rt, wh);
5919
0
            break;
5920
0
        case JS_WEAKREF_TYPE_WEAKREF:
5921
0
            weakref_delete_weakref(rt, wh);
5922
0
            break;
5923
0
        case JS_WEAKREF_TYPE_FINREC:
5924
0
            finrec_delete_weakref(rt, wh);
5925
0
            break;
5926
0
        default:
5927
0
            abort();
5928
0
        }
5929
0
    }
5930
5931
0
    rt->gc_phase = JS_GC_PHASE_NONE;
5932
    /* free the freed objects here. */
5933
0
    free_zero_refcount(rt);
5934
0
}
5935
5936
static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
5937
                          JSGCObjectTypeEnum type)
5938
1.19k
{
5939
1.19k
    h->mark = 0;
5940
1.19k
    h->gc_obj_type = type;
5941
1.19k
    list_add_tail(&h->link, &rt->gc_obj_list);
5942
1.19k
}
5943
5944
static void remove_gc_object(JSGCObjectHeader *h)
5945
1.19k
{
5946
1.19k
    list_del(&h->link);
5947
1.19k
}
5948
5949
void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
5950
3.33k
{
5951
3.33k
    if (JS_VALUE_HAS_REF_COUNT(val)) {
5952
2.02k
        switch(JS_VALUE_GET_TAG(val)) {
5953
1.23k
        case JS_TAG_OBJECT:
5954
1.23k
        case JS_TAG_FUNCTION_BYTECODE:
5955
1.25k
        case JS_TAG_MODULE:
5956
1.25k
            mark_func(rt, JS_VALUE_GET_PTR(val));
5957
1.25k
            break;
5958
766
        default:
5959
766
            break;
5960
2.02k
        }
5961
2.02k
    }
5962
3.33k
}
5963
5964
static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp,
5965
                          JS_MarkFunc *mark_func)
5966
1.60k
{
5967
1.60k
    switch(gp->gc_obj_type) {
5968
912
    case JS_GC_OBJ_TYPE_JS_OBJECT:
5969
912
        {
5970
912
            JSObject *p = (JSObject *)gp;
5971
912
            JSShapeProperty *prs;
5972
912
            JSShape *sh;
5973
912
            int i;
5974
912
            sh = p->shape;
5975
912
            mark_func(rt, &sh->header);
5976
            /* mark all the fields */
5977
912
            prs = get_shape_prop(sh);
5978
5.27k
            for(i = 0; i < sh->prop_count; i++) {
5979
4.36k
                JSProperty *pr = &p->prop[i];
5980
4.36k
                if (prs->atom != JS_ATOM_NULL) {
5981
4.36k
                    if (prs->flags & JS_PROP_TMASK) {
5982
2.03k
                        if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
5983
148
                            if (pr->u.getset.getter)
5984
148
                                mark_func(rt, &pr->u.getset.getter->header);
5985
148
                            if (pr->u.getset.setter)
5986
12
                                mark_func(rt, &pr->u.getset.setter->header);
5987
1.88k
                        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
5988
                            /* Note: the tag does not matter
5989
                               provided it is a GC object */
5990
392
                            mark_func(rt, &pr->u.var_ref->header);
5991
1.49k
                        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
5992
1.49k
                            js_autoinit_mark(rt, pr, mark_func);
5993
1.49k
                        }
5994
2.32k
                    } else {
5995
2.32k
                        JS_MarkValue(rt, pr->u.value, mark_func);
5996
2.32k
                    }
5997
4.36k
                }
5998
4.36k
                prs++;
5999
4.36k
            }
6000
6001
912
            if (p->class_id != JS_CLASS_OBJECT) {
6002
682
                JSClassGCMark *gc_mark;
6003
682
                gc_mark = rt->class_array[p->class_id].gc_mark;
6004
682
                if (gc_mark)
6005
660
                    gc_mark(rt, JS_MKPTR(JS_TAG_OBJECT, p), mark_func);
6006
682
            }
6007
912
        }
6008
912
        break;
6009
8
    case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
6010
        /* the template objects can be part of a cycle */
6011
8
        {
6012
8
            JSFunctionBytecode *b = (JSFunctionBytecode *)gp;
6013
8
            int i;
6014
12
            for(i = 0; i < b->cpool_count; i++) {
6015
4
                JS_MarkValue(rt, b->cpool[i], mark_func);
6016
4
            }
6017
8
            if (b->realm)
6018
8
                mark_func(rt, &b->realm->header);
6019
8
        }
6020
8
        break;
6021
400
    case JS_GC_OBJ_TYPE_VAR_REF:
6022
400
        {
6023
400
            JSVarRef *var_ref = (JSVarRef *)gp;
6024
400
            if (var_ref->is_detached) {
6025
400
                JS_MarkValue(rt, *var_ref->pvalue, mark_func);
6026
400
            } else if (var_ref->async_func) {
6027
0
                mark_func(rt, &var_ref->async_func->header);
6028
0
            }
6029
400
        }
6030
400
        break;
6031
0
    case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
6032
0
        {
6033
0
            JSAsyncFunctionState *s = (JSAsyncFunctionState *)gp;
6034
0
            JSStackFrame *sf = &s->frame;
6035
0
            JSValue *sp;
6036
6037
0
            if (!s->is_completed) {
6038
0
                JS_MarkValue(rt, sf->cur_func, mark_func);
6039
0
                JS_MarkValue(rt, s->this_val, mark_func);
6040
                /* sf->cur_sp = NULL if the function is running */
6041
0
                if (sf->cur_sp) {
6042
                    /* if the function is running, cur_sp is not known so we
6043
                       cannot mark the stack. Marking the variables is not needed
6044
                       because a running function cannot be part of a removable
6045
                       cycle */
6046
0
                    for(sp = sf->arg_buf; sp < sf->cur_sp; sp++)
6047
0
                        JS_MarkValue(rt, *sp, mark_func);
6048
0
                }
6049
0
            }
6050
0
            JS_MarkValue(rt, s->resolving_funcs[0], mark_func);
6051
0
            JS_MarkValue(rt, s->resolving_funcs[1], mark_func);
6052
0
        }
6053
0
        break;
6054
264
    case JS_GC_OBJ_TYPE_SHAPE:
6055
264
        {
6056
264
            JSShape *sh = (JSShape *)gp;
6057
264
            if (sh->proto != NULL) {
6058
242
                mark_func(rt, &sh->proto->header);
6059
242
            }
6060
264
        }
6061
264
        break;
6062
4
    case JS_GC_OBJ_TYPE_JS_CONTEXT:
6063
4
        {
6064
4
            JSContext *ctx = (JSContext *)gp;
6065
4
            JS_MarkContext(rt, ctx, mark_func);
6066
4
        }
6067
4
        break;
6068
16
    case JS_GC_OBJ_TYPE_MODULE:
6069
16
        {
6070
16
            JSModuleDef *m = (JSModuleDef *)gp;
6071
16
            js_mark_module_def(rt, m, mark_func);
6072
16
        }
6073
16
        break;
6074
0
    default:
6075
0
        abort();
6076
1.60k
    }
6077
1.60k
}
6078
6079
static void gc_decref_child(JSRuntime *rt, JSGCObjectHeader *p)
6080
2.74k
{
6081
2.74k
    assert(p->ref_count > 0);
6082
2.74k
    p->ref_count--;
6083
2.74k
    if (p->ref_count == 0 && p->mark == 1) {
6084
353
        list_del(&p->link);
6085
353
        list_add_tail(&p->link, &rt->tmp_obj_list);
6086
353
    }
6087
2.74k
}
6088
6089
static void gc_decref(JSRuntime *rt)
6090
2
{
6091
2
    struct list_head *el, *el1;
6092
2
    JSGCObjectHeader *p;
6093
6094
2
    init_list_head(&rt->tmp_obj_list);
6095
6096
    /* decrement the refcount of all the children of all the GC
6097
       objects and move the GC objects with zero refcount to
6098
       tmp_obj_list */
6099
802
    list_for_each_safe(el, el1, &rt->gc_obj_list) {
6100
802
        p = list_entry(el, JSGCObjectHeader, link);
6101
802
        assert(p->mark == 0);
6102
802
        mark_children(rt, p, gc_decref_child);
6103
802
        p->mark = 1;
6104
802
        if (p->ref_count == 0) {
6105
449
            list_del(&p->link);
6106
449
            list_add_tail(&p->link, &rt->tmp_obj_list);
6107
449
        }
6108
802
    }
6109
2
}
6110
6111
static void gc_scan_incref_child(JSRuntime *rt, JSGCObjectHeader *p)
6112
0
{
6113
0
    p->ref_count++;
6114
0
    if (p->ref_count == 1) {
6115
        /* ref_count was 0: remove from tmp_obj_list and add at the
6116
           end of gc_obj_list */
6117
0
        list_del(&p->link);
6118
0
        list_add_tail(&p->link, &rt->gc_obj_list);
6119
0
        p->mark = 0; /* reset the mark for the next GC call */
6120
0
    }
6121
0
}
6122
6123
static void gc_scan_incref_child2(JSRuntime *rt, JSGCObjectHeader *p)
6124
2.74k
{
6125
2.74k
    p->ref_count++;
6126
2.74k
}
6127
6128
static void gc_scan(JSRuntime *rt)
6129
2
{
6130
2
    struct list_head *el;
6131
2
    JSGCObjectHeader *p;
6132
6133
    /* keep the objects with a refcount > 0 and their children. */
6134
2
    list_for_each(el, &rt->gc_obj_list) {
6135
0
        p = list_entry(el, JSGCObjectHeader, link);
6136
0
        assert(p->ref_count > 0);
6137
0
        p->mark = 0; /* reset the mark for the next GC call */
6138
0
        mark_children(rt, p, gc_scan_incref_child);
6139
0
    }
6140
6141
    /* restore the refcount of the objects to be deleted. */
6142
802
    list_for_each(el, &rt->tmp_obj_list) {
6143
802
        p = list_entry(el, JSGCObjectHeader, link);
6144
802
        mark_children(rt, p, gc_scan_incref_child2);
6145
802
    }
6146
2
}
6147
6148
static void gc_free_cycles(JSRuntime *rt)
6149
2
{
6150
2
    struct list_head *el, *el1;
6151
2
    JSGCObjectHeader *p;
6152
#ifdef DUMP_GC_FREE
6153
    BOOL header_done = FALSE;
6154
#endif
6155
6156
2
    rt->gc_phase = JS_GC_PHASE_REMOVE_CYCLES;
6157
6158
743
    for(;;) {
6159
743
        el = rt->tmp_obj_list.next;
6160
743
        if (el == &rt->tmp_obj_list)
6161
2
            break;
6162
741
        p = list_entry(el, JSGCObjectHeader, link);
6163
        /* Only need to free the GC object associated with JS values
6164
           or async functions. The rest will be automatically removed
6165
           because they must be referenced by them. */
6166
741
        switch(p->gc_obj_type) {
6167
456
        case JS_GC_OBJ_TYPE_JS_OBJECT:
6168
460
        case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
6169
460
        case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
6170
468
        case JS_GC_OBJ_TYPE_MODULE:
6171
#ifdef DUMP_GC_FREE
6172
            if (!header_done) {
6173
                printf("Freeing cycles:\n");
6174
                JS_DumpObjectHeader(rt);
6175
                header_done = TRUE;
6176
            }
6177
            JS_DumpGCObject(rt, p);
6178
#endif
6179
468
            free_gc_object(rt, p);
6180
468
            break;
6181
273
        default:
6182
273
            list_del(&p->link);
6183
273
            list_add_tail(&p->link, &rt->gc_zero_ref_count_list);
6184
273
            break;
6185
741
        }
6186
741
    }
6187
2
    rt->gc_phase = JS_GC_PHASE_NONE;
6188
6189
219
    list_for_each_safe(el, el1, &rt->gc_zero_ref_count_list) {
6190
219
        p = list_entry(el, JSGCObjectHeader, link);
6191
219
        assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT ||
6192
219
               p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE ||
6193
219
               p->gc_obj_type == JS_GC_OBJ_TYPE_ASYNC_FUNCTION ||
6194
219
               p->gc_obj_type == JS_GC_OBJ_TYPE_MODULE);
6195
219
        if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT &&
6196
219
            ((JSObject *)p)->weakref_count != 0) {
6197
            /* keep the object because there are weak references to it */
6198
0
            p->mark = 0;
6199
219
        } else {
6200
219
            js_free_rt(rt, p);
6201
219
        }
6202
219
    }
6203
6204
2
    init_list_head(&rt->gc_zero_ref_count_list);
6205
2
}
6206
6207
static void JS_RunGCInternal(JSRuntime *rt, BOOL remove_weak_objects)
6208
2
{
6209
2
    if (remove_weak_objects) {
6210
        /* free the weakly referenced object or symbol structures, delete
6211
           the associated Map/Set entries and queue the finalization
6212
           registry callbacks. */
6213
0
        gc_remove_weak_objects(rt);
6214
0
    }
6215
    
6216
    /* decrement the reference of the children of each object. mark =
6217
       1 after this pass. */
6218
2
    gc_decref(rt);
6219
6220
    /* keep the GC objects with a non zero refcount and their childs */
6221
2
    gc_scan(rt);
6222
6223
    /* free the GC objects in a cycle */
6224
2
    gc_free_cycles(rt);
6225
2
}
6226
6227
void JS_RunGC(JSRuntime *rt)
6228
0
{
6229
0
    JS_RunGCInternal(rt, TRUE);
6230
0
}
6231
6232
/* Return false if not an object or if the object has already been
6233
   freed (zombie objects are visible in finalizers when freeing
6234
   cycles). */
6235
BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj)
6236
0
{
6237
0
    JSObject *p;
6238
0
    if (!JS_IsObject(obj))
6239
0
        return FALSE;
6240
0
    p = JS_VALUE_GET_OBJ(obj);
6241
0
    return !p->free_mark;
6242
0
}
6243
6244
/* Compute memory used by various object types */
6245
/* XXX: poor man's approach to handling multiply referenced objects */
6246
typedef struct JSMemoryUsage_helper {
6247
    double memory_used_count;
6248
    double str_count;
6249
    double str_size;
6250
    int64_t js_func_count;
6251
    double js_func_size;
6252
    int64_t js_func_code_size;
6253
    int64_t js_func_pc2line_count;
6254
    int64_t js_func_pc2line_size;
6255
} JSMemoryUsage_helper;
6256
6257
static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp);
6258
6259
static void compute_jsstring_size(JSString *str, JSMemoryUsage_helper *hp)
6260
0
{
6261
0
    if (!str->atom_type) {  /* atoms are handled separately */
6262
0
        double s_ref_count = str->header.ref_count;
6263
0
        hp->str_count += 1 / s_ref_count;
6264
0
        hp->str_size += ((sizeof(*str) + (str->len << str->is_wide_char) +
6265
0
                          1 - str->is_wide_char) / s_ref_count);
6266
0
    }
6267
0
}
6268
6269
static void compute_bytecode_size(JSFunctionBytecode *b, JSMemoryUsage_helper *hp)
6270
0
{
6271
0
    int memory_used_count, js_func_size, i;
6272
6273
0
    memory_used_count = 0;
6274
0
    js_func_size = offsetof(JSFunctionBytecode, debug);
6275
0
    if (b->vardefs) {
6276
0
        js_func_size += (b->arg_count + b->var_count) * sizeof(*b->vardefs);
6277
0
    }
6278
0
    if (b->cpool) {
6279
0
        js_func_size += b->cpool_count * sizeof(*b->cpool);
6280
0
        for (i = 0; i < b->cpool_count; i++) {
6281
0
            JSValueConst val = b->cpool[i];
6282
0
            compute_value_size(val, hp);
6283
0
        }
6284
0
    }
6285
0
    if (b->closure_var) {
6286
0
        js_func_size += b->closure_var_count * sizeof(*b->closure_var);
6287
0
    }
6288
0
    if (!b->read_only_bytecode && b->byte_code_buf) {
6289
0
        hp->js_func_code_size += b->byte_code_len;
6290
0
    }
6291
0
    if (b->has_debug) {
6292
0
        js_func_size += sizeof(*b) - offsetof(JSFunctionBytecode, debug);
6293
0
        if (b->debug.source) {
6294
0
            memory_used_count++;
6295
0
            js_func_size += b->debug.source_len + 1;
6296
0
        }
6297
0
        if (b->debug.pc2line_len) {
6298
0
            memory_used_count++;
6299
0
            hp->js_func_pc2line_count += 1;
6300
0
            hp->js_func_pc2line_size += b->debug.pc2line_len;
6301
0
        }
6302
0
    }
6303
0
    hp->js_func_size += js_func_size;
6304
0
    hp->js_func_count += 1;
6305
0
    hp->memory_used_count += memory_used_count;
6306
0
}
6307
6308
static void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp)
6309
0
{
6310
0
    switch(JS_VALUE_GET_TAG(val)) {
6311
0
    case JS_TAG_STRING:
6312
0
        compute_jsstring_size(JS_VALUE_GET_STRING(val), hp);
6313
0
        break;
6314
0
    case JS_TAG_BIG_INT:
6315
        /* should track JSBigInt usage */
6316
0
        break;
6317
0
    }
6318
0
}
6319
6320
void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
6321
0
{
6322
0
    struct list_head *el, *el1;
6323
0
    int i;
6324
0
    JSMemoryUsage_helper mem = { 0 }, *hp = &mem;
6325
6326
0
    memset(s, 0, sizeof(*s));
6327
0
    s->malloc_count = rt->malloc_state.malloc_count;
6328
0
    s->malloc_size = rt->malloc_state.malloc_size;
6329
0
    s->malloc_limit = rt->malloc_state.malloc_limit;
6330
6331
0
    s->memory_used_count = 2; /* rt + rt->class_array */
6332
0
    s->memory_used_size = sizeof(JSRuntime) + sizeof(JSValue) * rt->class_count;
6333
6334
0
    list_for_each(el, &rt->context_list) {
6335
0
        JSContext *ctx = list_entry(el, JSContext, link);
6336
0
        JSShape *sh = ctx->array_shape;
6337
0
        s->memory_used_count += 2; /* ctx + ctx->class_proto */
6338
0
        s->memory_used_size += sizeof(JSContext) +
6339
0
            sizeof(JSValue) * rt->class_count;
6340
0
        s->binary_object_count += ctx->binary_object_count;
6341
0
        s->binary_object_size += ctx->binary_object_size;
6342
6343
        /* the hashed shapes are counted separately */
6344
0
        if (sh && !sh->is_hashed) {
6345
0
            int hash_size = sh->prop_hash_mask + 1;
6346
0
            s->shape_count++;
6347
0
            s->shape_size += get_shape_size(hash_size, sh->prop_size);
6348
0
        }
6349
0
        list_for_each(el1, &ctx->loaded_modules) {
6350
0
            JSModuleDef *m = list_entry(el1, JSModuleDef, link);
6351
0
            s->memory_used_count += 1;
6352
0
            s->memory_used_size += sizeof(*m);
6353
0
            if (m->req_module_entries) {
6354
0
                s->memory_used_count += 1;
6355
0
                s->memory_used_size += m->req_module_entries_count * sizeof(*m->req_module_entries);
6356
0
            }
6357
0
            if (m->export_entries) {
6358
0
                s->memory_used_count += 1;
6359
0
                s->memory_used_size += m->export_entries_count * sizeof(*m->export_entries);
6360
0
                for (i = 0; i < m->export_entries_count; i++) {
6361
0
                    JSExportEntry *me = &m->export_entries[i];
6362
0
                    if (me->export_type == JS_EXPORT_TYPE_LOCAL && me->u.local.var_ref) {
6363
                        /* potential multiple count */
6364
0
                        s->memory_used_count += 1;
6365
0
                        compute_value_size(me->u.local.var_ref->value, hp);
6366
0
                    }
6367
0
                }
6368
0
            }
6369
0
            if (m->star_export_entries) {
6370
0
                s->memory_used_count += 1;
6371
0
                s->memory_used_size += m->star_export_entries_count * sizeof(*m->star_export_entries);
6372
0
            }
6373
0
            if (m->import_entries) {
6374
0
                s->memory_used_count += 1;
6375
0
                s->memory_used_size += m->import_entries_count * sizeof(*m->import_entries);
6376
0
            }
6377
0
            compute_value_size(m->module_ns, hp);
6378
0
            compute_value_size(m->func_obj, hp);
6379
0
        }
6380
0
    }
6381
6382
0
    list_for_each(el, &rt->gc_obj_list) {
6383
0
        JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link);
6384
0
        JSObject *p;
6385
0
        JSShape *sh;
6386
0
        JSShapeProperty *prs;
6387
6388
        /* XXX: could count the other GC object types too */
6389
0
        if (gp->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE) {
6390
0
            compute_bytecode_size((JSFunctionBytecode *)gp, hp);
6391
0
            continue;
6392
0
        } else if (gp->gc_obj_type != JS_GC_OBJ_TYPE_JS_OBJECT) {
6393
0
            continue;
6394
0
        }
6395
0
        p = (JSObject *)gp;
6396
0
        sh = p->shape;
6397
0
        s->obj_count++;
6398
0
        if (p->prop) {
6399
0
            s->memory_used_count++;
6400
0
            s->prop_size += sh->prop_size * sizeof(*p->prop);
6401
0
            s->prop_count += sh->prop_count;
6402
0
            prs = get_shape_prop(sh);
6403
0
            for(i = 0; i < sh->prop_count; i++) {
6404
0
                JSProperty *pr = &p->prop[i];
6405
0
                if (prs->atom != JS_ATOM_NULL && !(prs->flags & JS_PROP_TMASK)) {
6406
0
                    compute_value_size(pr->u.value, hp);
6407
0
                }
6408
0
                prs++;
6409
0
            }
6410
0
        }
6411
        /* the hashed shapes are counted separately */
6412
0
        if (!sh->is_hashed) {
6413
0
            int hash_size = sh->prop_hash_mask + 1;
6414
0
            s->shape_count++;
6415
0
            s->shape_size += get_shape_size(hash_size, sh->prop_size);
6416
0
        }
6417
6418
0
        switch(p->class_id) {
6419
0
        case JS_CLASS_ARRAY:             /* u.array | length */
6420
0
        case JS_CLASS_ARGUMENTS:         /* u.array | length */
6421
0
            s->array_count++;
6422
0
            if (p->fast_array) {
6423
0
                s->fast_array_count++;
6424
0
                if (p->u.array.u.values) {
6425
0
                    s->memory_used_count++;
6426
0
                    s->memory_used_size += p->u.array.count *
6427
0
                        sizeof(*p->u.array.u.values);
6428
0
                    s->fast_array_elements += p->u.array.count;
6429
0
                    for (i = 0; i < p->u.array.count; i++) {
6430
0
                        compute_value_size(p->u.array.u.values[i], hp);
6431
0
                    }
6432
0
                }
6433
0
            }
6434
0
            break;
6435
0
        case JS_CLASS_NUMBER:            /* u.object_data */
6436
0
        case JS_CLASS_STRING:            /* u.object_data */
6437
0
        case JS_CLASS_BOOLEAN:           /* u.object_data */
6438
0
        case JS_CLASS_SYMBOL:            /* u.object_data */
6439
0
        case JS_CLASS_DATE:              /* u.object_data */
6440
0
        case JS_CLASS_BIG_INT:           /* u.object_data */
6441
0
            compute_value_size(p->u.object_data, hp);
6442
0
            break;
6443
0
        case JS_CLASS_C_FUNCTION:        /* u.cfunc */
6444
0
            s->c_func_count++;
6445
0
            break;
6446
0
        case JS_CLASS_BYTECODE_FUNCTION: /* u.func */
6447
0
            {
6448
0
                JSFunctionBytecode *b = p->u.func.function_bytecode;
6449
0
                JSVarRef **var_refs = p->u.func.var_refs;
6450
                /* home_object: object will be accounted for in list scan */
6451
0
                if (var_refs) {
6452
0
                    s->memory_used_count++;
6453
0
                    s->js_func_size += b->closure_var_count * sizeof(*var_refs);
6454
0
                    for (i = 0; i < b->closure_var_count; i++) {
6455
0
                        if (var_refs[i]) {
6456
0
                            double ref_count = var_refs[i]->header.ref_count;
6457
0
                            s->memory_used_count += 1 / ref_count;
6458
0
                            s->js_func_size += sizeof(*var_refs[i]) / ref_count;
6459
                            /* handle non object closed values */
6460
0
                            if (var_refs[i]->pvalue == &var_refs[i]->value) {
6461
                                /* potential multiple count */
6462
0
                                compute_value_size(var_refs[i]->value, hp);
6463
0
                            }
6464
0
                        }
6465
0
                    }
6466
0
                }
6467
0
            }
6468
0
            break;
6469
0
        case JS_CLASS_BOUND_FUNCTION:    /* u.bound_function */
6470
0
            {
6471
0
                JSBoundFunction *bf = p->u.bound_function;
6472
                /* func_obj and this_val are objects */
6473
0
                for (i = 0; i < bf->argc; i++) {
6474
0
                    compute_value_size(bf->argv[i], hp);
6475
0
                }
6476
0
                s->memory_used_count += 1;
6477
0
                s->memory_used_size += sizeof(*bf) + bf->argc * sizeof(*bf->argv);
6478
0
            }
6479
0
            break;
6480
0
        case JS_CLASS_C_FUNCTION_DATA:   /* u.c_function_data_record */
6481
0
            {
6482
0
                JSCFunctionDataRecord *fd = p->u.c_function_data_record;
6483
0
                if (fd) {
6484
0
                    for (i = 0; i < fd->data_len; i++) {
6485
0
                        compute_value_size(fd->data[i], hp);
6486
0
                    }
6487
0
                    s->memory_used_count += 1;
6488
0
                    s->memory_used_size += sizeof(*fd) + fd->data_len * sizeof(*fd->data);
6489
0
                }
6490
0
            }
6491
0
            break;
6492
0
        case JS_CLASS_REGEXP:            /* u.regexp */
6493
0
            compute_jsstring_size(p->u.regexp.pattern, hp);
6494
0
            compute_jsstring_size(p->u.regexp.bytecode, hp);
6495
0
            break;
6496
6497
0
        case JS_CLASS_FOR_IN_ITERATOR:   /* u.for_in_iterator */
6498
0
            {
6499
0
                JSForInIterator *it = p->u.for_in_iterator;
6500
0
                if (it) {
6501
0
                    compute_value_size(it->obj, hp);
6502
0
                    s->memory_used_count += 1;
6503
0
                    s->memory_used_size += sizeof(*it);
6504
0
                }
6505
0
            }
6506
0
            break;
6507
0
        case JS_CLASS_ARRAY_BUFFER:      /* u.array_buffer */
6508
0
        case JS_CLASS_SHARED_ARRAY_BUFFER: /* u.array_buffer */
6509
0
            {
6510
0
                JSArrayBuffer *abuf = p->u.array_buffer;
6511
0
                if (abuf) {
6512
0
                    s->memory_used_count += 1;
6513
0
                    s->memory_used_size += sizeof(*abuf);
6514
0
                    if (abuf->data) {
6515
0
                        s->memory_used_count += 1;
6516
0
                        s->memory_used_size += abuf->byte_length;
6517
0
                    }
6518
0
                }
6519
0
            }
6520
0
            break;
6521
0
        case JS_CLASS_GENERATOR:         /* u.generator_data */
6522
0
        case JS_CLASS_UINT8C_ARRAY:      /* u.typed_array / u.array */
6523
0
        case JS_CLASS_INT8_ARRAY:        /* u.typed_array / u.array */
6524
0
        case JS_CLASS_UINT8_ARRAY:       /* u.typed_array / u.array */
6525
0
        case JS_CLASS_INT16_ARRAY:       /* u.typed_array / u.array */
6526
0
        case JS_CLASS_UINT16_ARRAY:      /* u.typed_array / u.array */
6527
0
        case JS_CLASS_INT32_ARRAY:       /* u.typed_array / u.array */
6528
0
        case JS_CLASS_UINT32_ARRAY:      /* u.typed_array / u.array */
6529
0
        case JS_CLASS_BIG_INT64_ARRAY:   /* u.typed_array / u.array */
6530
0
        case JS_CLASS_BIG_UINT64_ARRAY:  /* u.typed_array / u.array */
6531
0
        case JS_CLASS_FLOAT16_ARRAY:     /* u.typed_array / u.array */
6532
0
        case JS_CLASS_FLOAT32_ARRAY:     /* u.typed_array / u.array */
6533
0
        case JS_CLASS_FLOAT64_ARRAY:     /* u.typed_array / u.array */
6534
0
        case JS_CLASS_DATAVIEW:          /* u.typed_array */
6535
0
        case JS_CLASS_MAP:               /* u.map_state */
6536
0
        case JS_CLASS_SET:               /* u.map_state */
6537
0
        case JS_CLASS_WEAKMAP:           /* u.map_state */
6538
0
        case JS_CLASS_WEAKSET:           /* u.map_state */
6539
0
        case JS_CLASS_MAP_ITERATOR:      /* u.map_iterator_data */
6540
0
        case JS_CLASS_SET_ITERATOR:      /* u.map_iterator_data */
6541
0
        case JS_CLASS_ARRAY_ITERATOR:    /* u.array_iterator_data */
6542
0
        case JS_CLASS_STRING_ITERATOR:   /* u.array_iterator_data */
6543
0
        case JS_CLASS_PROXY:             /* u.proxy_data */
6544
0
        case JS_CLASS_PROMISE:           /* u.promise_data */
6545
0
        case JS_CLASS_PROMISE_RESOLVE_FUNCTION:  /* u.promise_function_data */
6546
0
        case JS_CLASS_PROMISE_REJECT_FUNCTION:   /* u.promise_function_data */
6547
0
        case JS_CLASS_ASYNC_FUNCTION_RESOLVE:    /* u.async_function_data */
6548
0
        case JS_CLASS_ASYNC_FUNCTION_REJECT:     /* u.async_function_data */
6549
0
        case JS_CLASS_ASYNC_FROM_SYNC_ITERATOR:  /* u.async_from_sync_iterator_data */
6550
0
        case JS_CLASS_ASYNC_GENERATOR:   /* u.async_generator_data */
6551
            /* TODO */
6552
0
        default:
6553
            /* XXX: class definition should have an opaque block size */
6554
0
            if (p->u.opaque) {
6555
0
                s->memory_used_count += 1;
6556
0
            }
6557
0
            break;
6558
0
        }
6559
0
    }
6560
0
    s->obj_size += s->obj_count * sizeof(JSObject);
6561
6562
    /* hashed shapes */
6563
0
    s->memory_used_count++; /* rt->shape_hash */
6564
0
    s->memory_used_size += sizeof(rt->shape_hash[0]) * rt->shape_hash_size;
6565
0
    for(i = 0; i < rt->shape_hash_size; i++) {
6566
0
        JSShape *sh;
6567
0
        for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) {
6568
0
            int hash_size = sh->prop_hash_mask + 1;
6569
0
            s->shape_count++;
6570
0
            s->shape_size += get_shape_size(hash_size, sh->prop_size);
6571
0
        }
6572
0
    }
6573
6574
    /* atoms */
6575
0
    s->memory_used_count += 2; /* rt->atom_array, rt->atom_hash */
6576
0
    s->atom_count = rt->atom_count;
6577
0
    s->atom_size = sizeof(rt->atom_array[0]) * rt->atom_size +
6578
0
        sizeof(rt->atom_hash[0]) * rt->atom_hash_size;
6579
0
    for(i = 0; i < rt->atom_size; i++) {
6580
0
        JSAtomStruct *p = rt->atom_array[i];
6581
0
        if (!atom_is_free(p)) {
6582
0
            s->atom_size += (sizeof(*p) + (p->len << p->is_wide_char) +
6583
0
                             1 - p->is_wide_char);
6584
0
        }
6585
0
    }
6586
0
    s->str_count = round(mem.str_count);
6587
0
    s->str_size = round(mem.str_size);
6588
0
    s->js_func_count = mem.js_func_count;
6589
0
    s->js_func_size = round(mem.js_func_size);
6590
0
    s->js_func_code_size = mem.js_func_code_size;
6591
0
    s->js_func_pc2line_count = mem.js_func_pc2line_count;
6592
0
    s->js_func_pc2line_size = mem.js_func_pc2line_size;
6593
0
    s->memory_used_count += round(mem.memory_used_count) +
6594
0
        s->atom_count + s->str_count +
6595
0
        s->obj_count + s->shape_count +
6596
0
        s->js_func_count + s->js_func_pc2line_count;
6597
0
    s->memory_used_size += s->atom_size + s->str_size +
6598
0
        s->obj_size + s->prop_size + s->shape_size +
6599
0
        s->js_func_size + s->js_func_code_size + s->js_func_pc2line_size;
6600
0
}
6601
6602
void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt)
6603
0
{
6604
0
    fprintf(fp, "QuickJS memory usage -- " CONFIG_VERSION " version, %d-bit, malloc limit: %"PRId64"\n\n",
6605
0
            (int)sizeof(void *) * 8, s->malloc_limit);
6606
0
#if 1
6607
0
    if (rt) {
6608
0
        static const struct {
6609
0
            const char *name;
6610
0
            size_t size;
6611
0
        } object_types[] = {
6612
0
            { "JSRuntime", sizeof(JSRuntime) },
6613
0
            { "JSContext", sizeof(JSContext) },
6614
0
            { "JSObject", sizeof(JSObject) },
6615
0
            { "JSString", sizeof(JSString) },
6616
0
            { "JSFunctionBytecode", sizeof(JSFunctionBytecode) },
6617
0
        };
6618
0
        int i, usage_size_ok = 0;
6619
0
        for(i = 0; i < countof(object_types); i++) {
6620
0
            unsigned int size = object_types[i].size;
6621
0
            void *p = js_malloc_rt(rt, size);
6622
0
            if (p) {
6623
0
                unsigned int size1 = js_malloc_usable_size_rt(rt, p);
6624
0
                if (size1 >= size) {
6625
0
                    usage_size_ok = 1;
6626
0
                    fprintf(fp, "  %3u + %-2u  %s\n",
6627
0
                            size, size1 - size, object_types[i].name);
6628
0
                }
6629
0
                js_free_rt(rt, p);
6630
0
            }
6631
0
        }
6632
0
        if (!usage_size_ok) {
6633
0
            fprintf(fp, "  malloc_usable_size unavailable\n");
6634
0
        }
6635
0
        {
6636
0
            int obj_classes[JS_CLASS_INIT_COUNT + 1] = { 0 };
6637
0
            int class_id;
6638
0
            struct list_head *el;
6639
0
            list_for_each(el, &rt->gc_obj_list) {
6640
0
                JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link);
6641
0
                JSObject *p;
6642
0
                if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
6643
0
                    p = (JSObject *)gp;
6644
0
                    obj_classes[min_uint32(p->class_id, JS_CLASS_INIT_COUNT)]++;
6645
0
                }
6646
0
            }
6647
0
            fprintf(fp, "\n" "JSObject classes\n");
6648
0
            if (obj_classes[0])
6649
0
                fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[0], 0, "none");
6650
0
            for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) {
6651
0
                if (obj_classes[class_id] && class_id < rt->class_count) {
6652
0
                    char buf[ATOM_GET_STR_BUF_SIZE];
6653
0
                    fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[class_id], class_id,
6654
0
                            JS_AtomGetStrRT(rt, buf, sizeof(buf), rt->class_array[class_id].class_name));
6655
0
                }
6656
0
            }
6657
0
            if (obj_classes[JS_CLASS_INIT_COUNT])
6658
0
                fprintf(fp, "  %5d  %2.0d %s\n", obj_classes[JS_CLASS_INIT_COUNT], 0, "other");
6659
0
        }
6660
0
        fprintf(fp, "\n");
6661
0
    }
6662
0
#endif
6663
0
    fprintf(fp, "%-20s %8s %8s\n", "NAME", "COUNT", "SIZE");
6664
6665
0
    if (s->malloc_count) {
6666
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per block)\n",
6667
0
                "memory allocated", s->malloc_count, s->malloc_size,
6668
0
                (double)s->malloc_size / s->malloc_count);
6669
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%d overhead, %0.1f average slack)\n",
6670
0
                "memory used", s->memory_used_count, s->memory_used_size,
6671
0
                MALLOC_OVERHEAD, ((double)(s->malloc_size - s->memory_used_size) /
6672
0
                                  s->memory_used_count));
6673
0
    }
6674
0
    if (s->atom_count) {
6675
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per atom)\n",
6676
0
                "atoms", s->atom_count, s->atom_size,
6677
0
                (double)s->atom_size / s->atom_count);
6678
0
    }
6679
0
    if (s->str_count) {
6680
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per string)\n",
6681
0
                "strings", s->str_count, s->str_size,
6682
0
                (double)s->str_size / s->str_count);
6683
0
    }
6684
0
    if (s->obj_count) {
6685
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per object)\n",
6686
0
                "objects", s->obj_count, s->obj_size,
6687
0
                (double)s->obj_size / s->obj_count);
6688
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per object)\n",
6689
0
                "  properties", s->prop_count, s->prop_size,
6690
0
                (double)s->prop_count / s->obj_count);
6691
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per shape)\n",
6692
0
                "  shapes", s->shape_count, s->shape_size,
6693
0
                (double)s->shape_size / s->shape_count);
6694
0
    }
6695
0
    if (s->js_func_count) {
6696
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n",
6697
0
                "bytecode functions", s->js_func_count, s->js_func_size);
6698
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per function)\n",
6699
0
                "  bytecode", s->js_func_count, s->js_func_code_size,
6700
0
                (double)s->js_func_code_size / s->js_func_count);
6701
0
        if (s->js_func_pc2line_count) {
6702
0
            fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per function)\n",
6703
0
                    "  pc2line", s->js_func_pc2line_count,
6704
0
                    s->js_func_pc2line_size,
6705
0
                    (double)s->js_func_pc2line_size / s->js_func_pc2line_count);
6706
0
        }
6707
0
    }
6708
0
    if (s->c_func_count) {
6709
0
        fprintf(fp, "%-20s %8"PRId64"\n", "C functions", s->c_func_count);
6710
0
    }
6711
0
    if (s->array_count) {
6712
0
        fprintf(fp, "%-20s %8"PRId64"\n", "arrays", s->array_count);
6713
0
        if (s->fast_array_count) {
6714
0
            fprintf(fp, "%-20s %8"PRId64"\n", "  fast arrays", s->fast_array_count);
6715
0
            fprintf(fp, "%-20s %8"PRId64" %8"PRId64"  (%0.1f per fast array)\n",
6716
0
                    "  elements", s->fast_array_elements,
6717
0
                    s->fast_array_elements * (int)sizeof(JSValue),
6718
0
                    (double)s->fast_array_elements / s->fast_array_count);
6719
0
        }
6720
0
    }
6721
0
    if (s->binary_object_count) {
6722
0
        fprintf(fp, "%-20s %8"PRId64" %8"PRId64"\n",
6723
0
                "binary objects", s->binary_object_count, s->binary_object_size);
6724
0
    }
6725
0
}
6726
6727
JSValue JS_GetGlobalObject(JSContext *ctx)
6728
2
{
6729
2
    return JS_DupValue(ctx, ctx->global_obj);
6730
2
}
6731
6732
/* WARNING: obj is freed */
6733
JSValue JS_Throw(JSContext *ctx, JSValue obj)
6734
4
{
6735
4
    JSRuntime *rt = ctx->rt;
6736
4
    JS_FreeValue(ctx, rt->current_exception);
6737
4
    rt->current_exception = obj;
6738
4
    rt->current_exception_is_uncatchable = FALSE;
6739
4
    return JS_EXCEPTION;
6740
4
}
6741
6742
/* return the pending exception (cannot be called twice). */
6743
JSValue JS_GetException(JSContext *ctx)
6744
1
{
6745
1
    JSValue val;
6746
1
    JSRuntime *rt = ctx->rt;
6747
1
    val = rt->current_exception;
6748
1
    rt->current_exception = JS_UNINITIALIZED;
6749
1
    return val;
6750
1
}
6751
6752
JS_BOOL JS_HasException(JSContext *ctx)
6753
0
{
6754
0
    return !JS_IsUninitialized(ctx->rt->current_exception);
6755
0
}
6756
6757
static void dbuf_put_leb128(DynBuf *s, uint32_t v)
6758
35
{
6759
35
    uint32_t a;
6760
38
    for(;;) {
6761
38
        a = v & 0x7f;
6762
38
        v >>= 7;
6763
38
        if (v != 0) {
6764
3
            dbuf_putc(s, a | 0x80);
6765
35
        } else {
6766
35
            dbuf_putc(s, a);
6767
35
            break;
6768
35
        }
6769
38
    }
6770
35
}
6771
6772
static void dbuf_put_sleb128(DynBuf *s, int32_t v1)
6773
9
{
6774
9
    uint32_t v = v1;
6775
9
    dbuf_put_leb128(s, (2 * v) ^ -(v >> 31));
6776
9
}
6777
6778
static int get_leb128(uint32_t *pval, const uint8_t *buf,
6779
                      const uint8_t *buf_end)
6780
23
{
6781
23
    const uint8_t *ptr = buf;
6782
23
    uint32_t v, a, i;
6783
23
    v = 0;
6784
26
    for(i = 0; i < 5; i++) {
6785
26
        if (unlikely(ptr >= buf_end))
6786
0
            break;
6787
26
        a = *ptr++;
6788
26
        v |= (a & 0x7f) << (i * 7);
6789
26
        if (!(a & 0x80)) {
6790
23
            *pval = v;
6791
23
            return ptr - buf;
6792
23
        }
6793
26
    }
6794
0
    *pval = 0;
6795
0
    return -1;
6796
23
}
6797
6798
static int get_sleb128(int32_t *pval, const uint8_t *buf,
6799
                       const uint8_t *buf_end)
6800
1
{
6801
1
    int ret;
6802
1
    uint32_t val;
6803
1
    ret = get_leb128(&val, buf, buf_end);
6804
1
    if (ret < 0) {
6805
0
        *pval = 0;
6806
0
        return -1;
6807
0
    }
6808
1
    *pval = (val >> 1) ^ -(val & 1);
6809
1
    return ret;
6810
1
}
6811
6812
/* use pc_value = -1 to get the position of the function definition */
6813
static int find_line_num(JSContext *ctx, JSFunctionBytecode *b,
6814
                         uint32_t pc_value, int *pcol_num)
6815
1
{
6816
1
    const uint8_t *p_end, *p;
6817
1
    int new_line_num, line_num, pc, v, ret, new_col_num, col_num;
6818
1
    uint32_t val;
6819
1
    unsigned int op;
6820
6821
1
    if (!b->has_debug || !b->debug.pc2line_buf)
6822
0
        goto fail; /* function was stripped */
6823
6824
1
    p = b->debug.pc2line_buf;
6825
1
    p_end = p + b->debug.pc2line_len;
6826
6827
    /* get the function line and column numbers */
6828
1
    ret = get_leb128(&val, p, p_end);
6829
1
    if (ret < 0)
6830
0
        goto fail;
6831
1
    p += ret;
6832
1
    line_num = val + 1;
6833
6834
1
    ret = get_leb128(&val, p, p_end);
6835
1
    if (ret < 0)
6836
0
        goto fail;
6837
1
    p += ret;
6838
1
    col_num = val + 1;
6839
6840
1
    if (pc_value != -1) {
6841
1
        pc = 0;
6842
1
        while (p < p_end) {
6843
1
            op = *p++;
6844
1
            if (op == 0) {
6845
0
                ret = get_leb128(&val, p, p_end);
6846
0
                if (ret < 0)
6847
0
                    goto fail;
6848
0
                pc += val;
6849
0
                p += ret;
6850
0
                ret = get_sleb128(&v, p, p_end);
6851
0
                if (ret < 0)
6852
0
                    goto fail;
6853
0
                p += ret;
6854
0
                new_line_num = line_num + v;
6855
1
            } else {
6856
1
                op -= PC2LINE_OP_FIRST;
6857
1
                pc += (op / PC2LINE_RANGE);
6858
1
                new_line_num = line_num + (op % PC2LINE_RANGE) + PC2LINE_BASE;
6859
1
            }
6860
1
            ret = get_sleb128(&v, p, p_end);
6861
1
            if (ret < 0)
6862
0
                goto fail;
6863
1
            p += ret;
6864
1
            new_col_num = col_num + v;
6865
            
6866
1
            if (pc_value < pc)
6867
1
                goto done;
6868
0
            line_num = new_line_num;
6869
0
            col_num = new_col_num;
6870
0
        }
6871
1
    }
6872
1
 done:
6873
1
    *pcol_num = col_num;
6874
1
    return line_num;
6875
0
 fail:
6876
0
    *pcol_num = 0;
6877
0
    return 0;
6878
1
}
6879
6880
/* in order to avoid executing arbitrary code during the stack trace
6881
   generation, we only look at simple 'name' properties containing a
6882
   string. */
6883
static const char *get_func_name(JSContext *ctx, JSValueConst func)
6884
1
{
6885
1
    JSProperty *pr;
6886
1
    JSShapeProperty *prs;
6887
1
    JSValueConst val;
6888
6889
1
    if (JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)
6890
0
        return NULL;
6891
1
    prs = find_own_property(&pr, JS_VALUE_GET_OBJ(func), JS_ATOM_name);
6892
1
    if (!prs)
6893
1
        return NULL;
6894
0
    if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
6895
0
        return NULL;
6896
0
    val = pr->u.value;
6897
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
6898
0
        return NULL;
6899
0
    return JS_ToCString(ctx, val);
6900
0
}
6901
6902
1
#define JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL (1 << 0)
6903
6904
/* if filename != NULL, an additional level is added with the filename
6905
   and line number information (used for parse error). */
6906
static void build_backtrace(JSContext *ctx, JSValueConst error_obj,
6907
                            const char *filename, int line_num, int col_num,
6908
                            int backtrace_flags)
6909
4
{
6910
4
    JSStackFrame *sf;
6911
4
    JSValue str;
6912
4
    DynBuf dbuf;
6913
4
    const char *func_name_str;
6914
4
    const char *str1;
6915
4
    JSObject *p;
6916
6917
4
    if (!JS_IsObject(error_obj))
6918
0
        return; /* protection in the out of memory case */
6919
    
6920
4
    js_dbuf_init(ctx, &dbuf);
6921
4
    if (filename) {
6922
1
        dbuf_printf(&dbuf, "    at %s", filename);
6923
1
        if (line_num != -1)
6924
1
            dbuf_printf(&dbuf, ":%d:%d", line_num, col_num);
6925
1
        dbuf_putc(&dbuf, '\n');
6926
1
        str = JS_NewString(ctx, filename);
6927
1
        if (JS_IsException(str))
6928
0
            return;
6929
        /* Note: SpiderMonkey does that, could update once there is a standard */
6930
1
        if (JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_fileName, str,
6931
1
                                   JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0 ||
6932
1
            JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_lineNumber, JS_NewInt32(ctx, line_num),
6933
1
                                   JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0 ||
6934
1
            JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_columnNumber, JS_NewInt32(ctx, col_num),
6935
1
                                   JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0) {
6936
0
            return;
6937
0
        }
6938
1
    }
6939
5
    for(sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) {
6940
1
        if (sf->js_mode & JS_MODE_BACKTRACE_BARRIER)
6941
0
            break;
6942
1
        if (backtrace_flags & JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL) {
6943
0
            backtrace_flags &= ~JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL;
6944
0
            continue;
6945
0
        }
6946
1
        func_name_str = get_func_name(ctx, sf->cur_func);
6947
1
        if (!func_name_str || func_name_str[0] == '\0')
6948
1
            str1 = "<anonymous>";
6949
0
        else
6950
0
            str1 = func_name_str;
6951
1
        dbuf_printf(&dbuf, "    at %s", str1);
6952
1
        JS_FreeCString(ctx, func_name_str);
6953
6954
1
        p = JS_VALUE_GET_OBJ(sf->cur_func);
6955
1
        if (js_class_has_bytecode(p->class_id)) {
6956
1
            JSFunctionBytecode *b;
6957
1
            const char *atom_str;
6958
1
            int line_num1, col_num1;
6959
6960
1
            b = p->u.func.function_bytecode;
6961
1
            if (b->has_debug) {
6962
1
                line_num1 = find_line_num(ctx, b,
6963
1
                                          sf->cur_pc - b->byte_code_buf - 1, &col_num1);
6964
1
                atom_str = JS_AtomToCString(ctx, b->debug.filename);
6965
1
                dbuf_printf(&dbuf, " (%s",
6966
1
                            atom_str ? atom_str : "<null>");
6967
1
                JS_FreeCString(ctx, atom_str);
6968
1
                if (line_num1 != 0)
6969
1
                    dbuf_printf(&dbuf, ":%d:%d", line_num1, col_num1);
6970
1
                dbuf_putc(&dbuf, ')');
6971
1
            }
6972
1
        } else {
6973
0
            dbuf_printf(&dbuf, " (native)");
6974
0
        }
6975
1
        dbuf_putc(&dbuf, '\n');
6976
1
    }
6977
4
    dbuf_putc(&dbuf, '\0');
6978
4
    if (dbuf_error(&dbuf))
6979
0
        str = JS_NULL;
6980
4
    else
6981
4
        str = JS_NewString(ctx, (char *)dbuf.buf);
6982
4
    dbuf_free(&dbuf);
6983
4
    JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_stack, str,
6984
4
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6985
4
}
6986
6987
/* Note: it is important that no exception is returned by this function */
6988
static BOOL is_backtrace_needed(JSContext *ctx, JSValueConst obj)
6989
1
{
6990
1
    JSObject *p;
6991
1
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
6992
0
        return FALSE;
6993
1
    p = JS_VALUE_GET_OBJ(obj);
6994
1
    if (p->class_id != JS_CLASS_ERROR)
6995
0
        return FALSE;
6996
1
    if (find_own_property1(p, JS_ATOM_stack))
6997
0
        return FALSE;
6998
1
    return TRUE;
6999
1
}
7000
7001
JSValue JS_NewError(JSContext *ctx)
7002
0
{
7003
0
    return JS_NewObjectClass(ctx, JS_CLASS_ERROR);
7004
0
}
7005
7006
static JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num,
7007
                              const char *fmt, va_list ap, BOOL add_backtrace)
7008
4
{
7009
4
    char buf[256];
7010
4
    JSValue obj, ret;
7011
7012
4
    vsnprintf(buf, sizeof(buf), fmt, ap);
7013
4
    obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[error_num],
7014
4
                                 JS_CLASS_ERROR);
7015
4
    if (unlikely(JS_IsException(obj))) {
7016
        /* out of memory: throw JS_NULL to avoid recursing */
7017
0
        obj = JS_NULL;
7018
4
    } else {
7019
4
        JS_DefinePropertyValue(ctx, obj, JS_ATOM_message,
7020
4
                               JS_NewString(ctx, buf),
7021
4
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
7022
4
        if (add_backtrace) {
7023
2
            build_backtrace(ctx, obj, NULL, 0, 0, 0);
7024
2
        }
7025
4
    }
7026
4
    ret = JS_Throw(ctx, obj);
7027
4
    return ret;
7028
4
}
7029
7030
static JSValue JS_ThrowError(JSContext *ctx, JSErrorEnum error_num,
7031
                             const char *fmt, va_list ap)
7032
3
{
7033
3
    JSRuntime *rt = ctx->rt;
7034
3
    JSStackFrame *sf;
7035
3
    BOOL add_backtrace;
7036
7037
    /* the backtrace is added later if called from a bytecode function */
7038
3
    sf = rt->current_stack_frame;
7039
3
    add_backtrace = !rt->in_out_of_memory &&
7040
3
        (!sf || (JS_GetFunctionBytecode(sf->cur_func) == NULL));
7041
3
    return JS_ThrowError2(ctx, error_num, fmt, ap, add_backtrace);
7042
3
}
7043
7044
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...)
7045
0
{
7046
0
    JSValue val;
7047
0
    va_list ap;
7048
7049
0
    va_start(ap, fmt);
7050
0
    val = JS_ThrowError(ctx, JS_SYNTAX_ERROR, fmt, ap);
7051
0
    va_end(ap);
7052
0
    return val;
7053
0
}
7054
7055
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...)
7056
2
{
7057
2
    JSValue val;
7058
2
    va_list ap;
7059
7060
2
    va_start(ap, fmt);
7061
2
    val = JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);
7062
2
    va_end(ap);
7063
2
    return val;
7064
2
}
7065
7066
static int __attribute__((format(printf, 3, 4))) JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, const char *fmt, ...)
7067
0
{
7068
0
    va_list ap;
7069
7070
0
    if ((flags & JS_PROP_THROW) ||
7071
0
        ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
7072
0
        va_start(ap, fmt);
7073
0
        JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);
7074
0
        va_end(ap);
7075
0
        return -1;
7076
0
    } else {
7077
0
        return FALSE;
7078
0
    }
7079
0
}
7080
7081
/* never use it directly */
7082
static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowTypeErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
7083
0
{
7084
0
    char buf[ATOM_GET_STR_BUF_SIZE];
7085
0
    return JS_ThrowTypeError(ctx, fmt,
7086
0
                             JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
7087
0
}
7088
7089
/* never use it directly */
7090
static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowSyntaxErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
7091
0
{
7092
0
    char buf[ATOM_GET_STR_BUF_SIZE];
7093
0
    return JS_ThrowSyntaxError(ctx, fmt,
7094
0
                             JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
7095
0
}
7096
7097
/* %s is replaced by 'atom'. The macro is used so that gcc can check
7098
    the format string. */
7099
0
#define JS_ThrowTypeErrorAtom(ctx, fmt, atom) __JS_ThrowTypeErrorAtom(ctx, atom, fmt, "")
7100
0
#define JS_ThrowSyntaxErrorAtom(ctx, fmt, atom) __JS_ThrowSyntaxErrorAtom(ctx, atom, fmt, "")
7101
7102
static int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int flags, JSAtom atom)
7103
0
{
7104
0
    if ((flags & JS_PROP_THROW) ||
7105
0
        ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
7106
0
        JS_ThrowTypeErrorAtom(ctx, "'%s' is read-only", atom);
7107
0
        return -1;
7108
0
    } else {
7109
0
        return FALSE;
7110
0
    }
7111
0
}
7112
7113
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...)
7114
1
{
7115
1
    JSValue val;
7116
1
    va_list ap;
7117
7118
1
    va_start(ap, fmt);
7119
1
    val = JS_ThrowError(ctx, JS_REFERENCE_ERROR, fmt, ap);
7120
1
    va_end(ap);
7121
1
    return val;
7122
1
}
7123
7124
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...)
7125
0
{
7126
0
    JSValue val;
7127
0
    va_list ap;
7128
7129
0
    va_start(ap, fmt);
7130
0
    val = JS_ThrowError(ctx, JS_RANGE_ERROR, fmt, ap);
7131
0
    va_end(ap);
7132
0
    return val;
7133
0
}
7134
7135
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...)
7136
0
{
7137
0
    JSValue val;
7138
0
    va_list ap;
7139
7140
0
    va_start(ap, fmt);
7141
0
    val = JS_ThrowError(ctx, JS_INTERNAL_ERROR, fmt, ap);
7142
0
    va_end(ap);
7143
0
    return val;
7144
0
}
7145
7146
JSValue JS_ThrowOutOfMemory(JSContext *ctx)
7147
0
{
7148
0
    JSRuntime *rt = ctx->rt;
7149
0
    if (!rt->in_out_of_memory) {
7150
0
        rt->in_out_of_memory = TRUE;
7151
0
        JS_ThrowInternalError(ctx, "out of memory");
7152
0
        rt->in_out_of_memory = FALSE;
7153
0
    }
7154
0
    return JS_EXCEPTION;
7155
0
}
7156
7157
static JSValue JS_ThrowStackOverflow(JSContext *ctx)
7158
0
{
7159
0
    return JS_ThrowInternalError(ctx, "stack overflow");
7160
0
}
7161
7162
static JSValue JS_ThrowTypeErrorNotAnObject(JSContext *ctx)
7163
0
{
7164
0
    return JS_ThrowTypeError(ctx, "not an object");
7165
0
}
7166
7167
static JSValue JS_ThrowTypeErrorNotASymbol(JSContext *ctx)
7168
0
{
7169
0
    return JS_ThrowTypeError(ctx, "not a symbol");
7170
0
}
7171
7172
static JSValue JS_ThrowReferenceErrorNotDefined(JSContext *ctx, JSAtom name)
7173
1
{
7174
1
    char buf[ATOM_GET_STR_BUF_SIZE];
7175
1
    return JS_ThrowReferenceError(ctx, "'%s' is not defined",
7176
1
                                  JS_AtomGetStr(ctx, buf, sizeof(buf), name));
7177
1
}
7178
7179
static JSValue JS_ThrowReferenceErrorUninitialized(JSContext *ctx, JSAtom name)
7180
0
{
7181
0
    char buf[ATOM_GET_STR_BUF_SIZE];
7182
0
    return JS_ThrowReferenceError(ctx, "%s is not initialized",
7183
0
                                  name == JS_ATOM_NULL ? "lexical variable" :
7184
0
                                  JS_AtomGetStr(ctx, buf, sizeof(buf), name));
7185
0
}
7186
7187
static JSValue JS_ThrowReferenceErrorUninitialized2(JSContext *ctx,
7188
                                                    JSFunctionBytecode *b,
7189
                                                    int idx, BOOL is_ref)
7190
0
{
7191
0
    JSAtom atom = JS_ATOM_NULL;
7192
0
    if (is_ref) {
7193
0
        atom = b->closure_var[idx].var_name;
7194
0
    } else {
7195
        /* not present if the function is stripped and contains no eval() */
7196
0
        if (b->vardefs)
7197
0
            atom = b->vardefs[b->arg_count + idx].var_name;
7198
0
    }
7199
0
    return JS_ThrowReferenceErrorUninitialized(ctx, atom);
7200
0
}
7201
7202
static JSValue JS_ThrowTypeErrorInvalidClass(JSContext *ctx, int class_id)
7203
0
{
7204
0
    JSRuntime *rt = ctx->rt;
7205
0
    JSAtom name;
7206
0
    name = rt->class_array[class_id].class_name;
7207
0
    return JS_ThrowTypeErrorAtom(ctx, "%s object expected", name);
7208
0
}
7209
7210
static void JS_ThrowInterrupted(JSContext *ctx)
7211
0
{
7212
0
    JS_ThrowInternalError(ctx, "interrupted");
7213
0
    JS_SetUncatchableException(ctx, TRUE);
7214
0
}
7215
7216
static no_inline __exception int __js_poll_interrupts(JSContext *ctx)
7217
2
{
7218
2
    JSRuntime *rt = ctx->rt;
7219
2
    ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT;
7220
2
    if (rt->interrupt_handler) {
7221
2
        if (rt->interrupt_handler(rt, rt->interrupt_opaque)) {
7222
0
            JS_ThrowInterrupted(ctx);
7223
0
            return -1;
7224
0
        }
7225
2
    }
7226
2
    return 0;
7227
2
}
7228
7229
static inline __exception int js_poll_interrupts(JSContext *ctx)
7230
24
{
7231
24
    if (unlikely(--ctx->interrupt_counter <= 0)) {
7232
2
        return __js_poll_interrupts(ctx);
7233
22
    } else {
7234
22
        return 0;
7235
22
    }
7236
24
}
7237
7238
static void JS_SetImmutablePrototype(JSContext *ctx, JSValueConst obj)
7239
2
{
7240
2
    JSObject *p;
7241
2
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
7242
0
        return;
7243
2
    p = JS_VALUE_GET_OBJ(obj);
7244
2
    p->has_immutable_prototype = TRUE;
7245
2
}
7246
7247
/* Return -1 (exception) or TRUE/FALSE. 'throw_flag' = FALSE indicates
7248
   that it is called from Reflect.setPrototypeOf(). */
7249
static int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj,
7250
                                   JSValueConst proto_val,
7251
                                   BOOL throw_flag)
7252
0
{
7253
0
    JSObject *proto, *p, *p1;
7254
0
    JSShape *sh;
7255
7256
0
    if (throw_flag) {
7257
0
        if (JS_VALUE_GET_TAG(obj) == JS_TAG_NULL ||
7258
0
            JS_VALUE_GET_TAG(obj) == JS_TAG_UNDEFINED)
7259
0
            goto not_obj;
7260
0
    } else {
7261
0
        if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
7262
0
            goto not_obj;
7263
0
    }
7264
0
    p = JS_VALUE_GET_OBJ(obj);
7265
0
    if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT) {
7266
0
        if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_NULL) {
7267
0
        not_obj:
7268
0
            JS_ThrowTypeErrorNotAnObject(ctx);
7269
0
            return -1;
7270
0
        }
7271
0
        proto = NULL;
7272
0
    } else {
7273
0
        proto = JS_VALUE_GET_OBJ(proto_val);
7274
0
    }
7275
7276
0
    if (throw_flag && JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
7277
0
        return TRUE;
7278
7279
0
    if (unlikely(p->is_exotic)) {
7280
0
        const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
7281
0
        int ret;
7282
0
        if (em && em->set_prototype) {
7283
0
            ret = em->set_prototype(ctx, obj, proto_val);
7284
0
            if (ret == 0 && throw_flag) {
7285
0
                JS_ThrowTypeError(ctx, "proxy: bad prototype");
7286
0
                return -1;
7287
0
            } else {
7288
0
                return ret;
7289
0
            }
7290
0
        }
7291
0
    }
7292
7293
0
    sh = p->shape;
7294
0
    if (sh->proto == proto)
7295
0
        return TRUE;
7296
0
    if (unlikely(p->has_immutable_prototype)) {
7297
0
        if (throw_flag) {
7298
0
            JS_ThrowTypeError(ctx, "prototype is immutable");
7299
0
            return -1;
7300
0
        } else {
7301
0
            return FALSE;
7302
0
        }
7303
0
    }
7304
0
    if (unlikely(!p->extensible)) {
7305
0
        if (throw_flag) {
7306
0
            JS_ThrowTypeError(ctx, "object is not extensible");
7307
0
            return -1;
7308
0
        } else {
7309
0
            return FALSE;
7310
0
        }
7311
0
    }
7312
0
    if (proto) {
7313
        /* check if there is a cycle */
7314
0
        p1 = proto;
7315
0
        do {
7316
0
            if (p1 == p) {
7317
0
                if (throw_flag) {
7318
0
                    JS_ThrowTypeError(ctx, "circular prototype chain");
7319
0
                    return -1;
7320
0
                } else {
7321
0
                    return FALSE;
7322
0
                }
7323
0
            }
7324
            /* Note: for Proxy objects, proto is NULL */
7325
0
            p1 = p1->shape->proto;
7326
0
        } while (p1 != NULL);
7327
0
        JS_DupValue(ctx, proto_val);
7328
0
    }
7329
7330
0
    if (js_shape_prepare_update(ctx, p, NULL))
7331
0
        return -1;
7332
0
    sh = p->shape;
7333
0
    if (sh->proto)
7334
0
        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto));
7335
0
    sh->proto = proto;
7336
0
    return TRUE;
7337
0
}
7338
7339
/* return -1 (exception) or TRUE/FALSE */
7340
int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val)
7341
0
{
7342
0
    return JS_SetPrototypeInternal(ctx, obj, proto_val, TRUE);
7343
0
}
7344
7345
/* Only works for primitive types, otherwise return JS_NULL. */
7346
static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val)
7347
0
{
7348
0
    switch(JS_VALUE_GET_NORM_TAG(val)) {
7349
0
    case JS_TAG_SHORT_BIG_INT:
7350
0
    case JS_TAG_BIG_INT:
7351
0
        val = ctx->class_proto[JS_CLASS_BIG_INT];
7352
0
        break;
7353
0
    case JS_TAG_INT:
7354
0
    case JS_TAG_FLOAT64:
7355
0
        val = ctx->class_proto[JS_CLASS_NUMBER];
7356
0
        break;
7357
0
    case JS_TAG_BOOL:
7358
0
        val = ctx->class_proto[JS_CLASS_BOOLEAN];
7359
0
        break;
7360
0
    case JS_TAG_STRING:
7361
0
    case JS_TAG_STRING_ROPE:
7362
0
        val = ctx->class_proto[JS_CLASS_STRING];
7363
0
        break;
7364
0
    case JS_TAG_SYMBOL:
7365
0
        val = ctx->class_proto[JS_CLASS_SYMBOL];
7366
0
        break;
7367
0
    case JS_TAG_OBJECT:
7368
0
    case JS_TAG_NULL:
7369
0
    case JS_TAG_UNDEFINED:
7370
0
    default:
7371
0
        val = JS_NULL;
7372
0
        break;
7373
0
    }
7374
0
    return val;
7375
0
}
7376
7377
/* Return an Object, JS_NULL or JS_EXCEPTION in case of exotic object. */
7378
JSValue JS_GetPrototype(JSContext *ctx, JSValueConst obj)
7379
0
{
7380
0
    JSValue val;
7381
0
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
7382
0
        JSObject *p;
7383
0
        p = JS_VALUE_GET_OBJ(obj);
7384
0
        if (unlikely(p->is_exotic)) {
7385
0
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
7386
0
            if (em && em->get_prototype) {
7387
0
                return em->get_prototype(ctx, obj);
7388
0
            }
7389
0
        }
7390
0
        p = p->shape->proto;
7391
0
        if (!p)
7392
0
            val = JS_NULL;
7393
0
        else
7394
0
            val = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7395
0
    } else {
7396
0
        val = JS_DupValue(ctx, JS_GetPrototypePrimitive(ctx, obj));
7397
0
    }
7398
0
    return val;
7399
0
}
7400
7401
static JSValue JS_GetPrototypeFree(JSContext *ctx, JSValue obj)
7402
0
{
7403
0
    JSValue obj1;
7404
0
    obj1 = JS_GetPrototype(ctx, obj);
7405
0
    JS_FreeValue(ctx, obj);
7406
0
    return obj1;
7407
0
}
7408
7409
/* return TRUE, FALSE or (-1) in case of exception */
7410
static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val,
7411
                                   JSValueConst obj)
7412
0
{
7413
0
    JSValue obj_proto;
7414
0
    JSObject *proto;
7415
0
    const JSObject *p, *proto1;
7416
0
    BOOL ret;
7417
7418
0
    if (!JS_IsFunction(ctx, obj))
7419
0
        return FALSE;
7420
0
    p = JS_VALUE_GET_OBJ(obj);
7421
0
    if (p->class_id == JS_CLASS_BOUND_FUNCTION) {
7422
0
        JSBoundFunction *s = p->u.bound_function;
7423
0
        return JS_IsInstanceOf(ctx, val, s->func_obj);
7424
0
    }
7425
7426
    /* Only explicitly boxed values are instances of constructors */
7427
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
7428
0
        return FALSE;
7429
0
    obj_proto = JS_GetProperty(ctx, obj, JS_ATOM_prototype);
7430
0
    if (JS_VALUE_GET_TAG(obj_proto) != JS_TAG_OBJECT) {
7431
0
        if (!JS_IsException(obj_proto))
7432
0
            JS_ThrowTypeError(ctx, "operand 'prototype' property is not an object");
7433
0
        ret = -1;
7434
0
        goto done;
7435
0
    }
7436
0
    proto = JS_VALUE_GET_OBJ(obj_proto);
7437
0
    p = JS_VALUE_GET_OBJ(val);
7438
0
    for(;;) {
7439
0
        proto1 = p->shape->proto;
7440
0
        if (!proto1) {
7441
            /* slow case if exotic object in the prototype chain */
7442
0
            if (unlikely(p->is_exotic && !p->fast_array)) {
7443
0
                JSValue obj1;
7444
0
                obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, (JSObject *)p));
7445
0
                for(;;) {
7446
0
                    obj1 = JS_GetPrototypeFree(ctx, obj1);
7447
0
                    if (JS_IsException(obj1)) {
7448
0
                        ret = -1;
7449
0
                        break;
7450
0
                    }
7451
0
                    if (JS_IsNull(obj1)) {
7452
0
                        ret = FALSE;
7453
0
                        break;
7454
0
                    }
7455
0
                    if (proto == JS_VALUE_GET_OBJ(obj1)) {
7456
0
                        JS_FreeValue(ctx, obj1);
7457
0
                        ret = TRUE;
7458
0
                        break;
7459
0
                    }
7460
                    /* must check for timeout to avoid infinite loop */
7461
0
                    if (js_poll_interrupts(ctx)) {
7462
0
                        JS_FreeValue(ctx, obj1);
7463
0
                        ret = -1;
7464
0
                        break;
7465
0
                    }
7466
0
                }
7467
0
            } else {
7468
0
                ret = FALSE;
7469
0
            }
7470
0
            break;
7471
0
        }
7472
0
        p = proto1;
7473
0
        if (proto == p) {
7474
0
            ret = TRUE;
7475
0
            break;
7476
0
        }
7477
0
    }
7478
0
done:
7479
0
    JS_FreeValue(ctx, obj_proto);
7480
0
    return ret;
7481
0
}
7482
7483
/* return TRUE, FALSE or (-1) in case of exception */
7484
int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj)
7485
0
{
7486
0
    JSValue method;
7487
7488
0
    if (!JS_IsObject(obj))
7489
0
        goto fail;
7490
0
    method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_hasInstance);
7491
0
    if (JS_IsException(method))
7492
0
        return -1;
7493
0
    if (!JS_IsNull(method) && !JS_IsUndefined(method)) {
7494
0
        JSValue ret;
7495
0
        ret = JS_CallFree(ctx, method, obj, 1, &val);
7496
0
        return JS_ToBoolFree(ctx, ret);
7497
0
    }
7498
7499
    /* legacy case */
7500
0
    if (!JS_IsFunction(ctx, obj)) {
7501
0
    fail:
7502
0
        JS_ThrowTypeError(ctx, "invalid 'instanceof' right operand");
7503
0
        return -1;
7504
0
    }
7505
0
    return JS_OrdinaryIsInstanceOf(ctx, val, obj);
7506
0
}
7507
7508
/* return the value associated to the autoinit property or an exception */
7509
typedef JSValue JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
7510
7511
static JSAutoInitFunc *js_autoinit_func_table[] = {
7512
    js_instantiate_prototype, /* JS_AUTOINIT_ID_PROTOTYPE */
7513
    js_module_ns_autoinit, /* JS_AUTOINIT_ID_MODULE_NS */
7514
    JS_InstantiateFunctionListItem2, /* JS_AUTOINIT_ID_PROP */
7515
};
7516
7517
/* warning: 'prs' is reallocated after it */
7518
static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop,
7519
                               JSProperty *pr, JSShapeProperty *prs)
7520
20
{
7521
20
    JSValue val;
7522
20
    JSContext *realm;
7523
20
    JSAutoInitFunc *func;
7524
20
    JSAutoInitIDEnum id;
7525
    
7526
20
    if (js_shape_prepare_update(ctx, p, &prs))
7527
0
        return -1;
7528
7529
20
    realm = js_autoinit_get_realm(pr);
7530
20
    id = js_autoinit_get_id(pr);
7531
20
    func = js_autoinit_func_table[id];
7532
    /* 'func' shall not modify the object properties 'pr' */
7533
20
    val = func(realm, p, prop, pr->u.init.opaque);
7534
20
    js_autoinit_free(ctx->rt, pr);
7535
20
    prs->flags &= ~JS_PROP_TMASK;
7536
20
    pr->u.value = JS_UNDEFINED;
7537
20
    if (JS_IsException(val))
7538
0
        return -1;
7539
20
    if (id == JS_AUTOINIT_ID_MODULE_NS &&
7540
20
        JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
7541
        /* WARNING: a varref is returned as a string  ! */
7542
0
        prs->flags |= JS_PROP_VARREF;
7543
0
        pr->u.var_ref = JS_VALUE_GET_PTR(val);
7544
0
        pr->u.var_ref->header.ref_count++;
7545
20
    } else {
7546
20
        pr->u.value = val;
7547
20
    }
7548
20
    return 0;
7549
20
}
7550
7551
JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
7552
                               JSAtom prop, JSValueConst this_obj,
7553
                               BOOL throw_ref_error)
7554
29
{
7555
29
    JSObject *p;
7556
29
    JSProperty *pr;
7557
29
    JSShapeProperty *prs;
7558
29
    uint32_t tag;
7559
7560
29
    tag = JS_VALUE_GET_TAG(obj);
7561
29
    if (unlikely(tag != JS_TAG_OBJECT)) {
7562
0
        switch(tag) {
7563
0
        case JS_TAG_NULL:
7564
0
            return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of null", prop);
7565
0
        case JS_TAG_UNDEFINED:
7566
0
            return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of undefined", prop);
7567
0
        case JS_TAG_EXCEPTION:
7568
0
            return JS_EXCEPTION;
7569
0
        case JS_TAG_STRING:
7570
0
            {
7571
0
                JSString *p1 = JS_VALUE_GET_STRING(obj);
7572
0
                if (__JS_AtomIsTaggedInt(prop)) {
7573
0
                    uint32_t idx;
7574
0
                    idx = __JS_AtomToUInt32(prop);
7575
0
                    if (idx < p1->len) {
7576
0
                        return js_new_string_char(ctx, string_get(p1, idx));
7577
0
                    }
7578
0
                } else if (prop == JS_ATOM_length) {
7579
0
                    return JS_NewInt32(ctx, p1->len);
7580
0
                }
7581
0
            }
7582
0
            break;
7583
0
        case JS_TAG_STRING_ROPE:
7584
0
            {
7585
0
                JSStringRope *p1 = JS_VALUE_GET_STRING_ROPE(obj);
7586
0
                if (__JS_AtomIsTaggedInt(prop)) {
7587
0
                    uint32_t idx;
7588
0
                    idx = __JS_AtomToUInt32(prop);
7589
0
                    if (idx < p1->len) {
7590
0
                        return js_new_string_char(ctx, string_rope_get(obj, idx));
7591
0
                    }
7592
0
                } else if (prop == JS_ATOM_length) {
7593
0
                    return JS_NewInt32(ctx, p1->len);
7594
0
                }
7595
0
            }
7596
0
            break;
7597
0
        default:
7598
0
            break;
7599
0
        }
7600
        /* cannot raise an exception */
7601
0
        p = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj));
7602
0
        if (!p)
7603
0
            return JS_UNDEFINED;
7604
29
    } else {
7605
29
        p = JS_VALUE_GET_OBJ(obj);
7606
29
    }
7607
7608
50
    for(;;) {
7609
50
        prs = find_own_property(&pr, p, prop);
7610
50
        if (prs) {
7611
            /* found */
7612
48
            if (unlikely(prs->flags & JS_PROP_TMASK)) {
7613
20
                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
7614
0
                    if (unlikely(!pr->u.getset.getter)) {
7615
0
                        return JS_UNDEFINED;
7616
0
                    } else {
7617
0
                        JSValue func = JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter);
7618
                        /* Note: the field could be removed in the getter */
7619
0
                        func = JS_DupValue(ctx, func);
7620
0
                        return JS_CallFree(ctx, func, this_obj, 0, NULL);
7621
0
                    }
7622
20
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
7623
0
                    JSValue val = *pr->u.var_ref->pvalue;
7624
0
                    if (unlikely(JS_IsUninitialized(val)))
7625
0
                        return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
7626
0
                    return JS_DupValue(ctx, val);
7627
20
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
7628
                    /* Instantiate property and retry */
7629
20
                    if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
7630
0
                        return JS_EXCEPTION;
7631
20
                    continue;
7632
20
                }
7633
28
            } else {
7634
28
                return JS_DupValue(ctx, pr->u.value);
7635
28
            }
7636
48
        }
7637
2
        if (unlikely(p->is_exotic)) {
7638
            /* exotic behaviors */
7639
0
            if (p->fast_array) {
7640
0
                if (__JS_AtomIsTaggedInt(prop)) {
7641
0
                    uint32_t idx = __JS_AtomToUInt32(prop);
7642
0
                    if (idx < p->u.array.count) {
7643
                        /* we avoid duplicating the code */
7644
0
                        return JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
7645
0
                    } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
7646
0
                               p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
7647
0
                        return JS_UNDEFINED;
7648
0
                    }
7649
0
                } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
7650
0
                           p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
7651
0
                    int ret;
7652
0
                    ret = JS_AtomIsNumericIndex(ctx, prop);
7653
0
                    if (ret != 0) {
7654
0
                        if (ret < 0)
7655
0
                            return JS_EXCEPTION;
7656
0
                        return JS_UNDEFINED;
7657
0
                    }
7658
0
                }
7659
0
            } else {
7660
0
                const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
7661
0
                if (em) {
7662
0
                    if (em->get_property) {
7663
0
                        JSValue obj1, retval;
7664
                        /* XXX: should pass throw_ref_error */
7665
                        /* Note: if 'p' is a prototype, it can be
7666
                           freed in the called function */
7667
0
                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7668
0
                        retval = em->get_property(ctx, obj1, prop, this_obj);
7669
0
                        JS_FreeValue(ctx, obj1);
7670
0
                        return retval;
7671
0
                    }
7672
0
                    if (em->get_own_property) {
7673
0
                        JSPropertyDescriptor desc;
7674
0
                        int ret;
7675
0
                        JSValue obj1;
7676
7677
                        /* Note: if 'p' is a prototype, it can be
7678
                           freed in the called function */
7679
0
                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7680
0
                        ret = em->get_own_property(ctx, &desc, obj1, prop);
7681
0
                        JS_FreeValue(ctx, obj1);
7682
0
                        if (ret < 0)
7683
0
                            return JS_EXCEPTION;
7684
0
                        if (ret) {
7685
0
                            if (desc.flags & JS_PROP_GETSET) {
7686
0
                                JS_FreeValue(ctx, desc.setter);
7687
0
                                return JS_CallFree(ctx, desc.getter, this_obj, 0, NULL);
7688
0
                            } else {
7689
0
                                return desc.value;
7690
0
                            }
7691
0
                        }
7692
0
                    }
7693
0
                }
7694
0
            }
7695
0
        }
7696
2
        p = p->shape->proto;
7697
2
        if (!p)
7698
1
            break;
7699
2
    }
7700
1
    if (unlikely(throw_ref_error)) {
7701
1
        return JS_ThrowReferenceErrorNotDefined(ctx, prop);
7702
1
    } else {
7703
0
        return JS_UNDEFINED;
7704
0
    }
7705
1
}
7706
7707
static JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom)
7708
0
{
7709
0
    return JS_ThrowTypeErrorAtom(ctx, "private class field '%s' does not exist",
7710
0
                                 atom);
7711
0
}
7712
7713
/* Private fields can be added even on non extensible objects or
7714
   Proxies */
7715
static int JS_DefinePrivateField(JSContext *ctx, JSValueConst obj,
7716
                                 JSValueConst name, JSValue val)
7717
0
{
7718
0
    JSObject *p;
7719
0
    JSShapeProperty *prs;
7720
0
    JSProperty *pr;
7721
0
    JSAtom prop;
7722
7723
0
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
7724
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7725
0
        goto fail;
7726
0
    }
7727
    /* safety check */
7728
0
    if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) {
7729
0
        JS_ThrowTypeErrorNotASymbol(ctx);
7730
0
        goto fail;
7731
0
    }
7732
0
    prop = js_symbol_to_atom(ctx, (JSValue)name);
7733
0
    p = JS_VALUE_GET_OBJ(obj);
7734
0
    prs = find_own_property(&pr, p, prop);
7735
0
    if (prs) {
7736
0
        JS_ThrowTypeErrorAtom(ctx, "private class field '%s' already exists",
7737
0
                              prop);
7738
0
        goto fail;
7739
0
    }
7740
0
    pr = add_property(ctx, p, prop, JS_PROP_C_W_E);
7741
0
    if (unlikely(!pr)) {
7742
0
    fail:
7743
0
        JS_FreeValue(ctx, val);
7744
0
        return -1;
7745
0
    }
7746
0
    pr->u.value = val;
7747
0
    return 0;
7748
0
}
7749
7750
static JSValue JS_GetPrivateField(JSContext *ctx, JSValueConst obj,
7751
                                  JSValueConst name)
7752
0
{
7753
0
    JSObject *p;
7754
0
    JSShapeProperty *prs;
7755
0
    JSProperty *pr;
7756
0
    JSAtom prop;
7757
7758
0
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
7759
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
7760
    /* safety check */
7761
0
    if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL))
7762
0
        return JS_ThrowTypeErrorNotASymbol(ctx);
7763
0
    prop = js_symbol_to_atom(ctx, (JSValue)name);
7764
0
    p = JS_VALUE_GET_OBJ(obj);
7765
0
    prs = find_own_property(&pr, p, prop);
7766
0
    if (!prs) {
7767
0
        JS_ThrowTypeErrorPrivateNotFound(ctx, prop);
7768
0
        return JS_EXCEPTION;
7769
0
    }
7770
0
    return JS_DupValue(ctx, pr->u.value);
7771
0
}
7772
7773
static int JS_SetPrivateField(JSContext *ctx, JSValueConst obj,
7774
                              JSValueConst name, JSValue val)
7775
0
{
7776
0
    JSObject *p;
7777
0
    JSShapeProperty *prs;
7778
0
    JSProperty *pr;
7779
0
    JSAtom prop;
7780
7781
0
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
7782
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7783
0
        goto fail;
7784
0
    }
7785
    /* safety check */
7786
0
    if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) {
7787
0
        JS_ThrowTypeErrorNotASymbol(ctx);
7788
0
        goto fail;
7789
0
    }
7790
0
    prop = js_symbol_to_atom(ctx, (JSValue)name);
7791
0
    p = JS_VALUE_GET_OBJ(obj);
7792
0
    prs = find_own_property(&pr, p, prop);
7793
0
    if (!prs) {
7794
0
        JS_ThrowTypeErrorPrivateNotFound(ctx, prop);
7795
0
    fail:
7796
0
        JS_FreeValue(ctx, val);
7797
0
        return -1;
7798
0
    }
7799
0
    set_value(ctx, &pr->u.value, val);
7800
0
    return 0;
7801
0
}
7802
7803
/* add a private brand field to 'home_obj' if not already present and
7804
   if obj is != null add a private brand to it */
7805
static int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj)
7806
0
{
7807
0
    JSObject *p, *p1;
7808
0
    JSShapeProperty *prs;
7809
0
    JSProperty *pr;
7810
0
    JSValue brand;
7811
0
    JSAtom brand_atom;
7812
7813
0
    if (unlikely(JS_VALUE_GET_TAG(home_obj) != JS_TAG_OBJECT)) {
7814
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7815
0
        return -1;
7816
0
    }
7817
0
    p = JS_VALUE_GET_OBJ(home_obj);
7818
0
    prs = find_own_property(&pr, p, JS_ATOM_Private_brand);
7819
0
    if (!prs) {
7820
        /* if the brand is not present, add it */
7821
0
        brand = JS_NewSymbolFromAtom(ctx, JS_ATOM_brand, JS_ATOM_TYPE_PRIVATE);
7822
0
        if (JS_IsException(brand))
7823
0
            return -1;
7824
0
        pr = add_property(ctx, p, JS_ATOM_Private_brand, JS_PROP_C_W_E);
7825
0
        if (!pr) {
7826
0
            JS_FreeValue(ctx, brand);
7827
0
            return -1;
7828
0
        }
7829
0
        pr->u.value = JS_DupValue(ctx, brand);
7830
0
    } else {
7831
0
        brand = JS_DupValue(ctx, pr->u.value);
7832
0
    }
7833
0
    brand_atom = js_symbol_to_atom(ctx, brand);
7834
7835
0
    if (JS_IsObject(obj)) {
7836
0
        p1 = JS_VALUE_GET_OBJ(obj);
7837
0
        prs = find_own_property(&pr, p1, brand_atom);
7838
0
        if (unlikely(prs)) {
7839
0
            JS_FreeAtom(ctx, brand_atom);
7840
0
            JS_ThrowTypeError(ctx, "private method is already present");
7841
0
            return -1;
7842
0
        }
7843
0
        pr = add_property(ctx, p1, brand_atom, JS_PROP_C_W_E);
7844
0
        JS_FreeAtom(ctx, brand_atom);
7845
0
        if (!pr)
7846
0
            return -1;
7847
0
        pr->u.value = JS_UNDEFINED;
7848
0
    } else {
7849
0
        JS_FreeAtom(ctx, brand_atom);
7850
0
    }
7851
0
    return 0;
7852
0
}
7853
7854
/* return a boolean telling if the brand of the home object of 'func'
7855
   is present on 'obj' or -1 in case of exception */
7856
static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func)
7857
0
{
7858
0
    JSObject *p, *p1, *home_obj;
7859
0
    JSShapeProperty *prs;
7860
0
    JSProperty *pr;
7861
0
    JSValueConst brand;
7862
7863
    /* get the home object of 'func' */
7864
0
    if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT))
7865
0
        goto not_obj;
7866
0
    p1 = JS_VALUE_GET_OBJ(func);
7867
0
    if (!js_class_has_bytecode(p1->class_id))
7868
0
        goto not_obj;
7869
0
    home_obj = p1->u.func.home_object;
7870
0
    if (!home_obj)
7871
0
        goto not_obj;
7872
0
    prs = find_own_property(&pr, home_obj, JS_ATOM_Private_brand);
7873
0
    if (!prs) {
7874
0
        JS_ThrowTypeError(ctx, "expecting <brand> private field");
7875
0
        return -1;
7876
0
    }
7877
0
    brand = pr->u.value;
7878
    /* safety check */
7879
0
    if (unlikely(JS_VALUE_GET_TAG(brand) != JS_TAG_SYMBOL))
7880
0
        goto not_obj;
7881
7882
    /* get the brand array of 'obj' */
7883
0
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {
7884
0
    not_obj:
7885
0
        JS_ThrowTypeErrorNotAnObject(ctx);
7886
0
        return -1;
7887
0
    }
7888
0
    p = JS_VALUE_GET_OBJ(obj);
7889
0
    prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, (JSValue)brand));
7890
0
    return (prs != NULL);
7891
0
}
7892
7893
static uint32_t js_string_obj_get_length(JSContext *ctx,
7894
                                         JSValueConst obj)
7895
0
{
7896
0
    JSObject *p;
7897
0
    uint32_t len = 0;
7898
7899
    /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
7900
0
    p = JS_VALUE_GET_OBJ(obj);
7901
0
    if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
7902
0
        JSString *p1 = JS_VALUE_GET_STRING(p->u.object_data);
7903
0
        len = p1->len;
7904
0
    }
7905
0
    return len;
7906
0
}
7907
7908
static int num_keys_cmp(const void *p1, const void *p2, void *opaque)
7909
0
{
7910
0
    JSContext *ctx = opaque;
7911
0
    JSAtom atom1 = ((const JSPropertyEnum *)p1)->atom;
7912
0
    JSAtom atom2 = ((const JSPropertyEnum *)p2)->atom;
7913
0
    uint32_t v1, v2;
7914
0
    BOOL atom1_is_integer, atom2_is_integer;
7915
7916
0
    atom1_is_integer = JS_AtomIsArrayIndex(ctx, &v1, atom1);
7917
0
    atom2_is_integer = JS_AtomIsArrayIndex(ctx, &v2, atom2);
7918
0
    assert(atom1_is_integer && atom2_is_integer);
7919
0
    if (v1 < v2)
7920
0
        return -1;
7921
0
    else if (v1 == v2)
7922
0
        return 0;
7923
0
    else
7924
0
        return 1;
7925
0
}
7926
7927
void JS_FreePropertyEnum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len)
7928
2
{
7929
2
    uint32_t i;
7930
2
    if (tab) {
7931
6
        for(i = 0; i < len; i++)
7932
4
            JS_FreeAtom(ctx, tab[i].atom);
7933
2
        js_free(ctx, tab);
7934
2
    }
7935
2
}
7936
7937
/* return < 0 in case if exception, 0 if OK. ptab and its atoms must
7938
   be freed by the user. */
7939
static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
7940
                                                      JSPropertyEnum **ptab,
7941
                                                      uint32_t *plen,
7942
                                                      JSObject *p, int flags)
7943
2
{
7944
2
    int i, j;
7945
2
    JSShape *sh;
7946
2
    JSShapeProperty *prs;
7947
2
    JSPropertyEnum *tab_atom, *tab_exotic;
7948
2
    JSAtom atom;
7949
2
    uint32_t num_keys_count, str_keys_count, sym_keys_count, atom_count;
7950
2
    uint32_t num_index, str_index, sym_index, exotic_count, exotic_keys_count;
7951
2
    BOOL is_enumerable, num_sorted;
7952
2
    uint32_t num_key;
7953
2
    JSAtomKindEnum kind;
7954
7955
    /* clear pointer for consistency in case of failure */
7956
2
    *ptab = NULL;
7957
2
    *plen = 0;
7958
7959
    /* compute the number of returned properties */
7960
2
    num_keys_count = 0;
7961
2
    str_keys_count = 0;
7962
2
    sym_keys_count = 0;
7963
2
    exotic_keys_count = 0;
7964
2
    exotic_count = 0;
7965
2
    tab_exotic = NULL;
7966
2
    sh = p->shape;
7967
6
    for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
7968
4
        atom = prs->atom;
7969
4
        if (atom != JS_ATOM_NULL) {
7970
4
            is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0);
7971
4
            kind = JS_AtomGetKind(ctx, atom);
7972
4
            if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
7973
4
                ((flags >> kind) & 1) != 0) {
7974
                /* need to raise an exception in case of the module
7975
                   name space (implicit GetOwnProperty) */
7976
4
                if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) &&
7977
4
                    (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY))) {
7978
0
                    JSVarRef *var_ref = p->prop[i].u.var_ref;
7979
0
                    if (unlikely(JS_IsUninitialized(*var_ref->pvalue))) {
7980
0
                        JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
7981
0
                        return -1;
7982
0
                    }
7983
0
                }
7984
4
                if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
7985
0
                    num_keys_count++;
7986
4
                } else if (kind == JS_ATOM_KIND_STRING) {
7987
4
                    str_keys_count++;
7988
4
                } else {
7989
0
                    sym_keys_count++;
7990
0
                }
7991
4
            }
7992
4
        }
7993
4
    }
7994
7995
2
    if (p->is_exotic) {
7996
0
        if (p->fast_array) {
7997
0
            if (flags & JS_GPN_STRING_MASK) {
7998
0
                num_keys_count += p->u.array.count;
7999
0
            }
8000
0
        } else if (p->class_id == JS_CLASS_STRING) {
8001
0
            if (flags & JS_GPN_STRING_MASK) {
8002
0
                num_keys_count += js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
8003
0
            }
8004
0
        } else {
8005
0
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
8006
0
            if (em && em->get_own_property_names) {
8007
0
                if (em->get_own_property_names(ctx, &tab_exotic, &exotic_count,
8008
0
                                               JS_MKPTR(JS_TAG_OBJECT, p)))
8009
0
                    return -1;
8010
0
                for(i = 0; i < exotic_count; i++) {
8011
0
                    atom = tab_exotic[i].atom;
8012
0
                    kind = JS_AtomGetKind(ctx, atom);
8013
0
                    if (((flags >> kind) & 1) != 0) {
8014
0
                        is_enumerable = FALSE;
8015
0
                        if (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY)) {
8016
0
                            JSPropertyDescriptor desc;
8017
0
                            int res;
8018
                            /* set the "is_enumerable" field if necessary */
8019
0
                            res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
8020
0
                            if (res < 0) {
8021
0
                                JS_FreePropertyEnum(ctx, tab_exotic, exotic_count);
8022
0
                                return -1;
8023
0
                            }
8024
0
                            if (res) {
8025
0
                                is_enumerable =
8026
0
                                    ((desc.flags & JS_PROP_ENUMERABLE) != 0);
8027
0
                                js_free_desc(ctx, &desc);
8028
0
                            }
8029
0
                            tab_exotic[i].is_enumerable = is_enumerable;
8030
0
                        }
8031
0
                        if (!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) {
8032
0
                            exotic_keys_count++;
8033
0
                        }
8034
0
                    }
8035
0
                }
8036
0
            }
8037
0
        }
8038
0
    }
8039
8040
    /* fill them */
8041
8042
2
    atom_count = num_keys_count + str_keys_count;
8043
2
    if (atom_count < str_keys_count)
8044
0
        goto add_overflow;
8045
2
    atom_count += sym_keys_count;
8046
2
    if (atom_count < sym_keys_count)
8047
0
        goto add_overflow;
8048
2
    atom_count += exotic_keys_count;
8049
2
    if (atom_count < exotic_keys_count || atom_count > INT32_MAX) {
8050
0
    add_overflow:
8051
0
        JS_ThrowOutOfMemory(ctx);
8052
0
        JS_FreePropertyEnum(ctx, tab_exotic, exotic_count);
8053
0
        return -1;
8054
0
    }
8055
    /* XXX: need generic way to test for js_malloc(ctx, a * b) overflow */
8056
    
8057
    /* avoid allocating 0 bytes */
8058
2
    tab_atom = js_malloc(ctx, sizeof(tab_atom[0]) * max_int(atom_count, 1));
8059
2
    if (!tab_atom) {
8060
0
        JS_FreePropertyEnum(ctx, tab_exotic, exotic_count);
8061
0
        return -1;
8062
0
    }
8063
8064
2
    num_index = 0;
8065
2
    str_index = num_keys_count;
8066
2
    sym_index = str_index + str_keys_count;
8067
8068
2
    num_sorted = TRUE;
8069
2
    sh = p->shape;
8070
6
    for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
8071
4
        atom = prs->atom;
8072
4
        if (atom != JS_ATOM_NULL) {
8073
4
            is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0);
8074
4
            kind = JS_AtomGetKind(ctx, atom);
8075
4
            if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
8076
4
                ((flags >> kind) & 1) != 0) {
8077
4
                if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
8078
0
                    j = num_index++;
8079
0
                    num_sorted = FALSE;
8080
4
                } else if (kind == JS_ATOM_KIND_STRING) {
8081
4
                    j = str_index++;
8082
4
                } else {
8083
0
                    j = sym_index++;
8084
0
                }
8085
4
                tab_atom[j].atom = JS_DupAtom(ctx, atom);
8086
4
                tab_atom[j].is_enumerable = is_enumerable;
8087
4
            }
8088
4
        }
8089
4
    }
8090
8091
2
    if (p->is_exotic) {
8092
0
        int len;
8093
0
        if (p->fast_array) {
8094
0
            if (flags & JS_GPN_STRING_MASK) {
8095
0
                len = p->u.array.count;
8096
0
                goto add_array_keys;
8097
0
            }
8098
0
        } else if (p->class_id == JS_CLASS_STRING) {
8099
0
            if (flags & JS_GPN_STRING_MASK) {
8100
0
                len = js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
8101
0
            add_array_keys:
8102
0
                for(i = 0; i < len; i++) {
8103
0
                    tab_atom[num_index].atom = __JS_AtomFromUInt32(i);
8104
0
                    if (tab_atom[num_index].atom == JS_ATOM_NULL) {
8105
0
                        JS_FreePropertyEnum(ctx, tab_atom, num_index);
8106
0
                        return -1;
8107
0
                    }
8108
0
                    tab_atom[num_index].is_enumerable = TRUE;
8109
0
                    num_index++;
8110
0
                }
8111
0
            }
8112
0
        } else {
8113
            /* Note: exotic keys are not reordered and comes after the object own properties. */
8114
0
            for(i = 0; i < exotic_count; i++) {
8115
0
                atom = tab_exotic[i].atom;
8116
0
                is_enumerable = tab_exotic[i].is_enumerable;
8117
0
                kind = JS_AtomGetKind(ctx, atom);
8118
0
                if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
8119
0
                    ((flags >> kind) & 1) != 0) {
8120
0
                    tab_atom[sym_index].atom = atom;
8121
0
                    tab_atom[sym_index].is_enumerable = is_enumerable;
8122
0
                    sym_index++;
8123
0
                } else {
8124
0
                    JS_FreeAtom(ctx, atom);
8125
0
                }
8126
0
            }
8127
0
            js_free(ctx, tab_exotic);
8128
0
        }
8129
0
    }
8130
8131
2
    assert(num_index == num_keys_count);
8132
2
    assert(str_index == num_keys_count + str_keys_count);
8133
2
    assert(sym_index == atom_count);
8134
8135
2
    if (num_keys_count != 0 && !num_sorted) {
8136
0
        rqsort(tab_atom, num_keys_count, sizeof(tab_atom[0]), num_keys_cmp,
8137
0
               ctx);
8138
0
    }
8139
2
    *ptab = tab_atom;
8140
2
    *plen = atom_count;
8141
2
    return 0;
8142
2
}
8143
8144
int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab,
8145
                           uint32_t *plen, JSValueConst obj, int flags)
8146
0
{
8147
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
8148
0
        JS_ThrowTypeErrorNotAnObject(ctx);
8149
0
        return -1;
8150
0
    }
8151
0
    return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen,
8152
0
                                          JS_VALUE_GET_OBJ(obj), flags);
8153
0
}
8154
8155
/* Return -1 if exception,
8156
   FALSE if the property does not exist, TRUE if it exists. If TRUE is
8157
   returned, the property descriptor 'desc' is filled present. */
8158
static int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc,
8159
                                     JSObject *p, JSAtom prop)
8160
4
{
8161
4
    JSShapeProperty *prs;
8162
4
    JSProperty *pr;
8163
8164
4
retry:
8165
4
    prs = find_own_property(&pr, p, prop);
8166
4
    if (prs) {
8167
4
        if (desc) {
8168
4
            desc->flags = prs->flags & JS_PROP_C_W_E;
8169
4
            desc->getter = JS_UNDEFINED;
8170
4
            desc->setter = JS_UNDEFINED;
8171
4
            desc->value = JS_UNDEFINED;
8172
4
            if (unlikely(prs->flags & JS_PROP_TMASK)) {
8173
0
                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
8174
0
                    desc->flags |= JS_PROP_GETSET;
8175
0
                    if (pr->u.getset.getter)
8176
0
                        desc->getter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
8177
0
                    if (pr->u.getset.setter)
8178
0
                        desc->setter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
8179
0
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
8180
0
                    JSValue val = *pr->u.var_ref->pvalue;
8181
0
                    if (unlikely(JS_IsUninitialized(val))) {
8182
0
                        JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
8183
0
                        return -1;
8184
0
                    }
8185
0
                    desc->value = JS_DupValue(ctx, val);
8186
0
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
8187
                    /* Instantiate property and retry */
8188
0
                    if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
8189
0
                        return -1;
8190
0
                    goto retry;
8191
0
                }
8192
4
            } else {
8193
4
                desc->value = JS_DupValue(ctx, pr->u.value);
8194
4
            }
8195
4
        } else {
8196
            /* for consistency, send the exception even if desc is NULL */
8197
0
            if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF)) {
8198
0
                if (unlikely(JS_IsUninitialized(*pr->u.var_ref->pvalue))) {
8199
0
                    JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
8200
0
                    return -1;
8201
0
                }
8202
0
            } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
8203
                /* nothing to do: delay instantiation until actual value and/or attributes are read */
8204
0
            }
8205
0
        }
8206
4
        return TRUE;
8207
4
    }
8208
0
    if (p->is_exotic) {
8209
0
        if (p->fast_array) {
8210
            /* specific case for fast arrays */
8211
0
            if (__JS_AtomIsTaggedInt(prop)) {
8212
0
                uint32_t idx;
8213
0
                idx = __JS_AtomToUInt32(prop);
8214
0
                if (idx < p->u.array.count) {
8215
0
                    if (desc) {
8216
0
                        desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE |
8217
0
                            JS_PROP_CONFIGURABLE;
8218
0
                        desc->getter = JS_UNDEFINED;
8219
0
                        desc->setter = JS_UNDEFINED;
8220
0
                        desc->value = JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
8221
0
                    }
8222
0
                    return TRUE;
8223
0
                }
8224
0
            }
8225
0
        } else {
8226
0
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
8227
0
            if (em && em->get_own_property) {
8228
0
                return em->get_own_property(ctx, desc,
8229
0
                                            JS_MKPTR(JS_TAG_OBJECT, p), prop);
8230
0
            }
8231
0
        }
8232
0
    }
8233
0
    return FALSE;
8234
0
}
8235
8236
int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc,
8237
                      JSValueConst obj, JSAtom prop)
8238
0
{
8239
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
8240
0
        JS_ThrowTypeErrorNotAnObject(ctx);
8241
0
        return -1;
8242
0
    }
8243
0
    return JS_GetOwnPropertyInternal(ctx, desc, JS_VALUE_GET_OBJ(obj), prop);
8244
0
}
8245
8246
/* return -1 if exception (exotic object only) or TRUE/FALSE */
8247
int JS_IsExtensible(JSContext *ctx, JSValueConst obj)
8248
4
{
8249
4
    JSObject *p;
8250
8251
4
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
8252
0
        return FALSE;
8253
4
    p = JS_VALUE_GET_OBJ(obj);
8254
4
    if (unlikely(p->is_exotic)) {
8255
4
        const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
8256
4
        if (em && em->is_extensible) {
8257
0
            return em->is_extensible(ctx, obj);
8258
0
        }
8259
4
    }
8260
4
    return p->extensible;
8261
4
}
8262
8263
/* return -1 if exception (exotic object only) or TRUE/FALSE */
8264
int JS_PreventExtensions(JSContext *ctx, JSValueConst obj)
8265
2
{
8266
2
    JSObject *p;
8267
8268
2
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
8269
0
        return FALSE;
8270
2
    p = JS_VALUE_GET_OBJ(obj);
8271
2
    if (unlikely(p->is_exotic)) {
8272
0
        const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
8273
0
        if (em && em->prevent_extensions) {
8274
0
            return em->prevent_extensions(ctx, obj);
8275
0
        }
8276
0
    }
8277
2
    p->extensible = FALSE;
8278
2
    return TRUE;
8279
2
}
8280
8281
/* return -1 if exception otherwise TRUE or FALSE */
8282
int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop)
8283
0
{
8284
0
    JSObject *p;
8285
0
    int ret;
8286
0
    JSValue obj1;
8287
8288
0
    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
8289
0
        return FALSE;
8290
0
    p = JS_VALUE_GET_OBJ(obj);
8291
0
    for(;;) {
8292
0
        if (p->is_exotic) {
8293
0
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
8294
0
            if (em && em->has_property) {
8295
                /* has_property can free the prototype */
8296
0
                obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
8297
0
                ret = em->has_property(ctx, obj1, prop);
8298
0
                JS_FreeValue(ctx, obj1);
8299
0
                return ret;
8300
0
            }
8301
0
        }
8302
        /* JS_GetOwnPropertyInternal can free the prototype */
8303
0
        JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
8304
0
        ret = JS_GetOwnPropertyInternal(ctx, NULL, p, prop);
8305
0
        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
8306
0
        if (ret != 0)
8307
0
            return ret;
8308
0
        if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
8309
0
            p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
8310
0
            ret = JS_AtomIsNumericIndex(ctx, prop);
8311
0
            if (ret != 0) {
8312
0
                if (ret < 0)
8313
0
                    return -1;
8314
0
                return FALSE;
8315
0
            }
8316
0
        }
8317
0
        p = p->shape->proto;
8318
0
        if (!p)
8319
0
            break;
8320
0
    }
8321
0
    return FALSE;
8322
0
}
8323
8324
/* val must be a symbol */
8325
static JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val)
8326
0
{
8327
0
    JSAtomStruct *p = JS_VALUE_GET_PTR(val);
8328
0
    return js_get_atom_index(ctx->rt, p);
8329
0
}
8330
8331
/* return JS_ATOM_NULL in case of exception */
8332
JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val)
8333
4
{
8334
4
    JSAtom atom;
8335
4
    uint32_t tag;
8336
4
    tag = JS_VALUE_GET_TAG(val);
8337
4
    if (tag == JS_TAG_INT &&
8338
4
        (uint32_t)JS_VALUE_GET_INT(val) <= JS_ATOM_MAX_INT) {
8339
        /* fast path for integer values */
8340
0
        atom = __JS_AtomFromUInt32(JS_VALUE_GET_INT(val));
8341
4
    } else if (tag == JS_TAG_SYMBOL) {
8342
0
        JSAtomStruct *p = JS_VALUE_GET_PTR(val);
8343
0
        atom = JS_DupAtom(ctx, js_get_atom_index(ctx->rt, p));
8344
4
    } else {
8345
4
        JSValue str;
8346
4
        str = JS_ToPropertyKey(ctx, val);
8347
4
        if (JS_IsException(str))
8348
0
            return JS_ATOM_NULL;
8349
4
        if (JS_VALUE_GET_TAG(str) == JS_TAG_SYMBOL) {
8350
0
            atom = js_symbol_to_atom(ctx, str);
8351
4
        } else {
8352
4
            atom = JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(str));
8353
4
        }
8354
4
    }
8355
4
    return atom;
8356
4
}
8357
8358
static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,
8359
                                   JSValue prop)
8360
0
{
8361
0
    JSAtom atom;
8362
0
    JSValue ret;
8363
8364
0
    if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT &&
8365
0
               JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {
8366
0
        JSObject *p;
8367
0
        uint32_t idx;
8368
        /* fast path for array access */
8369
0
        p = JS_VALUE_GET_OBJ(this_obj);
8370
0
        idx = JS_VALUE_GET_INT(prop);
8371
0
        switch(p->class_id) {
8372
0
        case JS_CLASS_ARRAY:
8373
0
        case JS_CLASS_ARGUMENTS:
8374
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
8375
0
            return JS_DupValue(ctx, p->u.array.u.values[idx]);
8376
0
        case JS_CLASS_INT8_ARRAY:
8377
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
8378
0
            return JS_NewInt32(ctx, p->u.array.u.int8_ptr[idx]);
8379
0
        case JS_CLASS_UINT8C_ARRAY:
8380
0
        case JS_CLASS_UINT8_ARRAY:
8381
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
8382
0
            return JS_NewInt32(ctx, p->u.array.u.uint8_ptr[idx]);
8383
0
        case JS_CLASS_INT16_ARRAY:
8384
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
8385
0
            return JS_NewInt32(ctx, p->u.array.u.int16_ptr[idx]);
8386
0
        case JS_CLASS_UINT16_ARRAY:
8387
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
8388
0
            return JS_NewInt32(ctx, p->u.array.u.uint16_ptr[idx]);
8389
0
        case JS_CLASS_INT32_ARRAY:
8390
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
8391
0
            return JS_NewInt32(ctx, p->u.array.u.int32_ptr[idx]);
8392
0
        case JS_CLASS_UINT32_ARRAY:
8393
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
8394
0
            return JS_NewUint32(ctx, p->u.array.u.uint32_ptr[idx]);
8395
0
        case JS_CLASS_BIG_INT64_ARRAY:
8396
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
8397
0
            return JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]);
8398
0
        case JS_CLASS_BIG_UINT64_ARRAY:
8399
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
8400
0
            return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]);
8401
0
        case JS_CLASS_FLOAT16_ARRAY:
8402
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
8403
0
            return __JS_NewFloat64(ctx, fromfp16(p->u.array.u.fp16_ptr[idx]));
8404
0
        case JS_CLASS_FLOAT32_ARRAY:
8405
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
8406
0
            return __JS_NewFloat64(ctx, p->u.array.u.float_ptr[idx]);
8407
0
        case JS_CLASS_FLOAT64_ARRAY:
8408
0
            if (unlikely(idx >= p->u.array.count)) goto slow_path;
8409
0
            return __JS_NewFloat64(ctx, p->u.array.u.double_ptr[idx]);
8410
0
        default:
8411
0
            goto slow_path;
8412
0
        }
8413
0
    } else {
8414
0
    slow_path:
8415
        /* ToObject() must be done before ToPropertyKey() */
8416
0
        if (JS_IsNull(this_obj) || JS_IsUndefined(this_obj)) {
8417
0
            JS_FreeValue(ctx, prop);
8418
0
            return JS_ThrowTypeError(ctx, "cannot read property of %s", JS_IsNull(this_obj) ? "null" : "undefined");
8419
0
        }
8420
0
        atom = JS_ValueToAtom(ctx, prop);
8421
0
        JS_FreeValue(ctx, prop);
8422
0
        if (unlikely(atom == JS_ATOM_NULL))
8423
0
            return JS_EXCEPTION;
8424
0
        ret = JS_GetProperty(ctx, this_obj, atom);
8425
0
        JS_FreeAtom(ctx, atom);
8426
0
        return ret;
8427
0
    }
8428
0
}
8429
8430
JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
8431
                             uint32_t idx)
8432
0
{
8433
0
    return JS_GetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx));
8434
0
}
8435
8436
/* Check if an object has a generalized numeric property. Return value:
8437
   -1 for exception,
8438
   TRUE if property exists, stored into *pval,
8439
   FALSE if proprty does not exist.
8440
 */
8441
static int JS_TryGetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, JSValue *pval)
8442
0
{
8443
0
    JSValue val = JS_UNDEFINED;
8444
0
    JSAtom prop;
8445
0
    int present;
8446
8447
0
    if (likely((uint64_t)idx <= JS_ATOM_MAX_INT)) {
8448
        /* fast path */
8449
0
        present = JS_HasProperty(ctx, obj, __JS_AtomFromUInt32(idx));
8450
0
        if (present > 0) {
8451
0
            val = JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx));
8452
0
            if (unlikely(JS_IsException(val)))
8453
0
                present = -1;
8454
0
        }
8455
0
    } else {
8456
0
        prop = JS_NewAtomInt64(ctx, idx);
8457
0
        present = -1;
8458
0
        if (likely(prop != JS_ATOM_NULL)) {
8459
0
            present = JS_HasProperty(ctx, obj, prop);
8460
0
            if (present > 0) {
8461
0
                val = JS_GetProperty(ctx, obj, prop);
8462
0
                if (unlikely(JS_IsException(val)))
8463
0
                    present = -1;
8464
0
            }
8465
0
            JS_FreeAtom(ctx, prop);
8466
0
        }
8467
0
    }
8468
0
    *pval = val;
8469
0
    return present;
8470
0
}
8471
8472
static JSValue JS_GetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx)
8473
0
{
8474
0
    JSAtom prop;
8475
0
    JSValue val;
8476
8477
0
    if ((uint64_t)idx <= INT32_MAX) {
8478
        /* fast path for fast arrays */
8479
0
        return JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx));
8480
0
    }
8481
0
    prop = JS_NewAtomInt64(ctx, idx);
8482
0
    if (prop == JS_ATOM_NULL)
8483
0
        return JS_EXCEPTION;
8484
8485
0
    val = JS_GetProperty(ctx, obj, prop);
8486
0
    JS_FreeAtom(ctx, prop);
8487
0
    return val;
8488
0
}
8489
8490
JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj,
8491
                          const char *prop)
8492
0
{
8493
0
    JSAtom atom;
8494
0
    JSValue ret;
8495
0
    atom = JS_NewAtom(ctx, prop);
8496
0
    if (atom == JS_ATOM_NULL)
8497
0
        return JS_EXCEPTION;
8498
0
    ret = JS_GetProperty(ctx, this_obj, atom);
8499
0
    JS_FreeAtom(ctx, atom);
8500
0
    return ret;
8501
0
}
8502
8503
/* Note: the property value is not initialized. Return NULL if memory
8504
   error. */
8505
static JSProperty *add_property(JSContext *ctx,
8506
                                JSObject *p, JSAtom prop, int prop_flags)
8507
2.21k
{
8508
2.21k
    JSShape *sh, *new_sh;
8509
8510
2.21k
    sh = p->shape;
8511
2.21k
    if (sh->is_hashed) {
8512
        /* try to find an existing shape */
8513
1.90k
        new_sh = find_hashed_shape_prop(ctx->rt, sh, prop, prop_flags);
8514
1.90k
        if (new_sh) {
8515
            /* matching shape found: use it */
8516
            /*  the property array may need to be resized */
8517
410
            if (new_sh->prop_size != sh->prop_size) {
8518
94
                JSProperty *new_prop;
8519
94
                new_prop = js_realloc(ctx, p->prop, sizeof(p->prop[0]) *
8520
94
                                      new_sh->prop_size);
8521
94
                if (!new_prop)
8522
0
                    return NULL;
8523
94
                p->prop = new_prop;
8524
94
            }
8525
410
            p->shape = js_dup_shape(new_sh);
8526
410
            js_free_shape(ctx->rt, sh);
8527
410
            return &p->prop[new_sh->prop_count - 1];
8528
1.49k
        } else if (sh->header.ref_count != 1) {
8529
            /* if the shape is shared, clone it */
8530
173
            new_sh = js_clone_shape(ctx, sh);
8531
173
            if (!new_sh)
8532
0
                return NULL;
8533
            /* hash the cloned shape */
8534
173
            new_sh->is_hashed = TRUE;
8535
173
            js_shape_hash_link(ctx->rt, new_sh);
8536
173
            js_free_shape(ctx->rt, p->shape);
8537
173
            p->shape = new_sh;
8538
173
        }
8539
1.90k
    }
8540
1.80k
    assert(p->shape->header.ref_count == 1);
8541
1.80k
    if (add_shape_property(ctx, &p->shape, p, prop, prop_flags))
8542
0
        return NULL;
8543
1.80k
    return &p->prop[p->shape->prop_count - 1];
8544
1.80k
}
8545
8546
/* can be called on Array or Arguments objects. return < 0 if
8547
   memory alloc error. */
8548
static no_inline __exception int convert_fast_array_to_array(JSContext *ctx,
8549
                                                             JSObject *p)
8550
0
{
8551
0
    JSProperty *pr;
8552
0
    JSShape *sh;
8553
0
    JSValue *tab;
8554
0
    uint32_t i, len, new_count;
8555
8556
0
    if (js_shape_prepare_update(ctx, p, NULL))
8557
0
        return -1;
8558
0
    len = p->u.array.count;
8559
    /* resize the properties once to simplify the error handling */
8560
0
    sh = p->shape;
8561
0
    new_count = sh->prop_count + len;
8562
0
    if (new_count > sh->prop_size) {
8563
0
        if (resize_properties(ctx, &p->shape, p, new_count))
8564
0
            return -1;
8565
0
    }
8566
8567
0
    tab = p->u.array.u.values;
8568
0
    for(i = 0; i < len; i++) {
8569
        /* add_property cannot fail here but
8570
           __JS_AtomFromUInt32(i) fails for i > INT32_MAX */
8571
0
        pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E);
8572
0
        pr->u.value = *tab++;
8573
0
    }
8574
0
    js_free(ctx, p->u.array.u.values);
8575
0
    p->u.array.count = 0;
8576
0
    p->u.array.u.values = NULL; /* fail safe */
8577
0
    p->u.array.u1.size = 0;
8578
0
    p->fast_array = 0;
8579
0
    return 0;
8580
0
}
8581
8582
static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom)
8583
0
{
8584
0
    JSShape *sh;
8585
0
    JSShapeProperty *pr, *lpr, *prop;
8586
0
    JSProperty *pr1;
8587
0
    uint32_t lpr_idx;
8588
0
    intptr_t h, h1;
8589
8590
0
 redo:
8591
0
    sh = p->shape;
8592
0
    h1 = atom & sh->prop_hash_mask;
8593
0
    h = prop_hash_end(sh)[-h1 - 1];
8594
0
    prop = get_shape_prop(sh);
8595
0
    lpr = NULL;
8596
0
    lpr_idx = 0;   /* prevent warning */
8597
0
    while (h != 0) {
8598
0
        pr = &prop[h - 1];
8599
0
        if (likely(pr->atom == atom)) {
8600
            /* found ! */
8601
0
            if (!(pr->flags & JS_PROP_CONFIGURABLE))
8602
0
                return FALSE;
8603
            /* realloc the shape if needed */
8604
0
            if (lpr)
8605
0
                lpr_idx = lpr - get_shape_prop(sh);
8606
0
            if (js_shape_prepare_update(ctx, p, &pr))
8607
0
                return -1;
8608
0
            sh = p->shape;
8609
            /* remove property */
8610
0
            if (lpr) {
8611
0
                lpr = get_shape_prop(sh) + lpr_idx;
8612
0
                lpr->hash_next = pr->hash_next;
8613
0
            } else {
8614
0
                prop_hash_end(sh)[-h1 - 1] = pr->hash_next;
8615
0
            }
8616
0
            sh->deleted_prop_count++;
8617
            /* free the entry */
8618
0
            pr1 = &p->prop[h - 1];
8619
0
            free_property(ctx->rt, pr1, pr->flags);
8620
0
            JS_FreeAtom(ctx, pr->atom);
8621
            /* put default values */
8622
0
            pr->flags = 0;
8623
0
            pr->atom = JS_ATOM_NULL;
8624
0
            pr1->u.value = JS_UNDEFINED;
8625
8626
            /* compact the properties if too many deleted properties */
8627
0
            if (sh->deleted_prop_count >= 8 &&
8628
0
                sh->deleted_prop_count >= ((unsigned)sh->prop_count / 2)) {
8629
0
                compact_properties(ctx, p);
8630
0
            }
8631
0
            return TRUE;
8632
0
        }
8633
0
        lpr = pr;
8634
0
        h = pr->hash_next;
8635
0
    }
8636
8637
0
    if (p->is_exotic) {
8638
0
        if (p->fast_array) {
8639
0
            uint32_t idx;
8640
0
            if (JS_AtomIsArrayIndex(ctx, &idx, atom) &&
8641
0
                idx < p->u.array.count) {
8642
0
                if (p->class_id == JS_CLASS_ARRAY ||
8643
0
                    p->class_id == JS_CLASS_ARGUMENTS) {
8644
                    /* Special case deleting the last element of a fast Array */
8645
0
                    if (idx == p->u.array.count - 1) {
8646
0
                        JS_FreeValue(ctx, p->u.array.u.values[idx]);
8647
0
                        p->u.array.count = idx;
8648
0
                        return TRUE;
8649
0
                    }
8650
0
                    if (convert_fast_array_to_array(ctx, p))
8651
0
                        return -1;
8652
0
                    goto redo;
8653
0
                } else {
8654
0
                    return FALSE;
8655
0
                }
8656
0
            }
8657
0
        } else {
8658
0
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
8659
0
            if (em && em->delete_property) {
8660
0
                return em->delete_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), atom);
8661
0
            }
8662
0
        }
8663
0
    }
8664
    /* not found */
8665
0
    return TRUE;
8666
0
}
8667
8668
static int call_setter(JSContext *ctx, JSObject *setter,
8669
                       JSValueConst this_obj, JSValue val, int flags)
8670
0
{
8671
0
    JSValue ret, func;
8672
0
    if (likely(setter)) {
8673
0
        func = JS_MKPTR(JS_TAG_OBJECT, setter);
8674
        /* Note: the field could be removed in the setter */
8675
0
        func = JS_DupValue(ctx, func);
8676
0
        ret = JS_CallFree(ctx, func, this_obj, 1, (JSValueConst *)&val);
8677
0
        JS_FreeValue(ctx, val);
8678
0
        if (JS_IsException(ret))
8679
0
            return -1;
8680
0
        JS_FreeValue(ctx, ret);
8681
0
        return TRUE;
8682
0
    } else {
8683
0
        JS_FreeValue(ctx, val);
8684
0
        if ((flags & JS_PROP_THROW) ||
8685
0
            ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
8686
0
            JS_ThrowTypeError(ctx, "no setter for property");
8687
0
            return -1;
8688
0
        }
8689
0
        return FALSE;
8690
0
    }
8691
0
}
8692
8693
/* set the array length and remove the array elements if necessary. */
8694
static int set_array_length(JSContext *ctx, JSObject *p, JSValue val,
8695
                            int flags)
8696
0
{
8697
0
    uint32_t len, idx, cur_len;
8698
0
    int i, ret;
8699
8700
    /* Note: this call can reallocate the properties of 'p' */
8701
0
    ret = JS_ToArrayLengthFree(ctx, &len, val, FALSE);
8702
0
    if (ret)
8703
0
        return -1;
8704
    /* JS_ToArrayLengthFree() must be done before the read-only test */
8705
0
    if (unlikely(!(p->shape->prop[0].flags & JS_PROP_WRITABLE)))
8706
0
        return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
8707
8708
0
    if (likely(p->fast_array)) {
8709
0
        uint32_t old_len = p->u.array.count;
8710
0
        if (len < old_len) {
8711
0
            for(i = len; i < old_len; i++) {
8712
0
                JS_FreeValue(ctx, p->u.array.u.values[i]);
8713
0
            }
8714
0
            p->u.array.count = len;
8715
0
        }
8716
0
        p->prop[0].u.value = JS_NewUint32(ctx, len);
8717
0
    } else {
8718
        /* Note: length is always a uint32 because the object is an
8719
           array */
8720
0
        JS_ToUint32(ctx, &cur_len, p->prop[0].u.value);
8721
0
        if (len < cur_len) {
8722
0
            uint32_t d;
8723
0
            JSShape *sh;
8724
0
            JSShapeProperty *pr;
8725
8726
0
            d = cur_len - len;
8727
0
            sh = p->shape;
8728
0
            if (d <= sh->prop_count) {
8729
0
                JSAtom atom;
8730
8731
                /* faster to iterate */
8732
0
                while (cur_len > len) {
8733
0
                    atom = JS_NewAtomUInt32(ctx, cur_len - 1);
8734
0
                    ret = delete_property(ctx, p, atom);
8735
0
                    JS_FreeAtom(ctx, atom);
8736
0
                    if (unlikely(!ret)) {
8737
                        /* unlikely case: property is not
8738
                           configurable */
8739
0
                        break;
8740
0
                    }
8741
0
                    cur_len--;
8742
0
                }
8743
0
            } else {
8744
                /* faster to iterate thru all the properties. Need two
8745
                   passes in case one of the property is not
8746
                   configurable */
8747
0
                cur_len = len;
8748
0
                for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count;
8749
0
                    i++, pr++) {
8750
0
                    if (pr->atom != JS_ATOM_NULL &&
8751
0
                        JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) {
8752
0
                        if (idx >= cur_len &&
8753
0
                            !(pr->flags & JS_PROP_CONFIGURABLE)) {
8754
0
                            cur_len = idx + 1;
8755
0
                        }
8756
0
                    }
8757
0
                }
8758
8759
0
                for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count;
8760
0
                    i++, pr++) {
8761
0
                    if (pr->atom != JS_ATOM_NULL &&
8762
0
                        JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) {
8763
0
                        if (idx >= cur_len) {
8764
                            /* remove the property */
8765
0
                            delete_property(ctx, p, pr->atom);
8766
                            /* WARNING: the shape may have been modified */
8767
0
                            sh = p->shape;
8768
0
                            pr = get_shape_prop(sh) + i;
8769
0
                        }
8770
0
                    }
8771
0
                }
8772
0
            }
8773
0
        } else {
8774
0
            cur_len = len;
8775
0
        }
8776
0
        set_value(ctx, &p->prop[0].u.value, JS_NewUint32(ctx, cur_len));
8777
0
        if (unlikely(cur_len > len)) {
8778
0
            return JS_ThrowTypeErrorOrFalse(ctx, flags, "not configurable");
8779
0
        }
8780
0
    }
8781
0
    return TRUE;
8782
0
}
8783
8784
/* return -1 if exception */
8785
static int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len)
8786
0
{
8787
0
    uint32_t new_size;
8788
0
    size_t slack;
8789
0
    JSValue *new_array_prop;
8790
    /* XXX: potential arithmetic overflow */
8791
0
    new_size = max_int(new_len, p->u.array.u1.size * 3 / 2);
8792
0
    new_array_prop = js_realloc2(ctx, p->u.array.u.values, sizeof(JSValue) * new_size, &slack);
8793
0
    if (!new_array_prop)
8794
0
        return -1;
8795
0
    new_size += slack / sizeof(*new_array_prop);
8796
0
    p->u.array.u.values = new_array_prop;
8797
0
    p->u.array.u1.size = new_size;
8798
0
    return 0;
8799
0
}
8800
8801
/* Preconditions: 'p' must be of class JS_CLASS_ARRAY, p->fast_array =
8802
   TRUE and p->extensible = TRUE */
8803
static int add_fast_array_element(JSContext *ctx, JSObject *p,
8804
                                  JSValue val, int flags)
8805
0
{
8806
0
    uint32_t new_len, array_len;
8807
    /* extend the array by one */
8808
    /* XXX: convert to slow array if new_len > 2^31-1 elements */
8809
0
    new_len = p->u.array.count + 1;
8810
    /* update the length if necessary. We assume that if the length is
8811
       not an integer, then if it >= 2^31.  */
8812
0
    if (likely(JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT)) {
8813
0
        array_len = JS_VALUE_GET_INT(p->prop[0].u.value);
8814
0
        if (new_len > array_len) {
8815
0
            if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE))) {
8816
0
                JS_FreeValue(ctx, val);
8817
0
                return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
8818
0
            }
8819
0
            p->prop[0].u.value = JS_NewInt32(ctx, new_len);
8820
0
        }
8821
0
    }
8822
0
    if (unlikely(new_len > p->u.array.u1.size)) {
8823
0
        if (expand_fast_array(ctx, p, new_len)) {
8824
0
            JS_FreeValue(ctx, val);
8825
0
            return -1;
8826
0
        }
8827
0
    }
8828
0
    p->u.array.u.values[new_len - 1] = val;
8829
0
    p->u.array.count = new_len;
8830
0
    return TRUE;
8831
0
}
8832
8833
/* Allocate a new fast array. Its 'length' property is set to zero. It
8834
   maximum size is 2^31-1 elements. For convenience, 'len' is a 64 bit
8835
   integer. WARNING: the content of the array is not initialized. */
8836
static JSValue js_allocate_fast_array(JSContext *ctx, int64_t len)
8837
0
{
8838
0
    JSValue arr;
8839
0
    JSObject *p;
8840
8841
0
    if (len > INT32_MAX)
8842
0
        return JS_ThrowRangeError(ctx, "invalid array length");
8843
0
    arr = JS_NewArray(ctx);
8844
0
    if (JS_IsException(arr))
8845
0
        return arr;
8846
0
    if (len > 0) {
8847
0
        p = JS_VALUE_GET_OBJ(arr);
8848
0
        if (expand_fast_array(ctx, p, len) < 0) {
8849
0
            JS_FreeValue(ctx, arr);
8850
0
            return JS_EXCEPTION;
8851
0
        }
8852
0
        p->u.array.count = len;
8853
0
    }
8854
0
    return arr;
8855
0
}
8856
8857
static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc)
8858
4
{
8859
4
    JS_FreeValue(ctx, desc->getter);
8860
4
    JS_FreeValue(ctx, desc->setter);
8861
4
    JS_FreeValue(ctx, desc->value);
8862
4
}
8863
8864
/* return -1 in case of exception or TRUE or FALSE. Warning: 'val' is
8865
   freed by the function. 'flags' is a bitmask of JS_PROP_NO_ADD,
8866
   JS_PROP_THROW or JS_PROP_THROW_STRICT. If JS_PROP_NO_ADD is set,
8867
   the new property is not added and an error is raised. 'this_obj' is
8868
   the receiver. If obj != this_obj, then obj must be an object
8869
   (Reflect.set case). */
8870
int JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj,
8871
                           JSAtom prop, JSValue val, JSValueConst this_obj, int flags)
8872
18
{
8873
18
    JSObject *p, *p1;
8874
18
    JSShapeProperty *prs;
8875
18
    JSProperty *pr;
8876
18
    uint32_t tag;
8877
18
    JSPropertyDescriptor desc;
8878
18
    int ret;
8879
#if 0
8880
    printf("JS_SetPropertyInternal: "); print_atom(ctx, prop); printf("\n");
8881
#endif
8882
18
    tag = JS_VALUE_GET_TAG(this_obj);
8883
18
    if (unlikely(tag != JS_TAG_OBJECT)) {
8884
0
        if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
8885
0
            p = NULL;
8886
0
            p1 = JS_VALUE_GET_OBJ(obj);
8887
0
            goto prototype_lookup;
8888
0
        } else {
8889
0
            switch(tag) {
8890
0
            case JS_TAG_NULL:
8891
0
                JS_FreeValue(ctx, val);
8892
0
                JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop);
8893
0
                return -1;
8894
0
            case JS_TAG_UNDEFINED:
8895
0
                JS_FreeValue(ctx, val);
8896
0
                JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop);
8897
0
                return -1;
8898
0
            default:
8899
                /* even on a primitive type we can have setters on the prototype */
8900
0
                p = NULL;
8901
0
                p1 = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj));
8902
0
                goto prototype_lookup;
8903
0
            }
8904
0
        }
8905
18
    } else {
8906
18
        p = JS_VALUE_GET_OBJ(this_obj);
8907
18
        p1 = JS_VALUE_GET_OBJ(obj);
8908
18
        if (unlikely(p != p1))
8909
0
            goto retry2;
8910
18
    }
8911
8912
    /* fast path if obj == this_obj */
8913
18
 retry:
8914
18
    prs = find_own_property(&pr, p1, prop);
8915
18
    if (prs) {
8916
0
        if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE |
8917
0
                                  JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) {
8918
            /* fast case */
8919
0
            set_value(ctx, &pr->u.value, val);
8920
0
            return TRUE;
8921
0
        } else if (prs->flags & JS_PROP_LENGTH) {
8922
0
            assert(p->class_id == JS_CLASS_ARRAY);
8923
0
            assert(prop == JS_ATOM_length);
8924
0
            return set_array_length(ctx, p, val, flags);
8925
0
        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
8926
0
            return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);
8927
0
        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
8928
            /* JS_PROP_WRITABLE is always true for variable
8929
               references, but they are write protected in module name
8930
               spaces. */
8931
0
            if (p->class_id == JS_CLASS_MODULE_NS)
8932
0
                goto read_only_prop;
8933
0
            set_value(ctx, pr->u.var_ref->pvalue, val);
8934
0
            return TRUE;
8935
0
        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
8936
            /* Instantiate property and retry (potentially useless) */
8937
0
            if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) {
8938
0
                JS_FreeValue(ctx, val);
8939
0
                return -1;
8940
0
            }
8941
0
            goto retry;
8942
0
        } else {
8943
0
            goto read_only_prop;
8944
0
        }
8945
0
    }
8946
8947
36
    for(;;) {
8948
36
        if (p1->is_exotic) {
8949
0
            if (p1->fast_array) {
8950
0
                if (__JS_AtomIsTaggedInt(prop)) {
8951
0
                    uint32_t idx = __JS_AtomToUInt32(prop);
8952
0
                    if (idx < p1->u.array.count) {
8953
0
                        if (unlikely(p == p1))
8954
0
                            return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val, flags);
8955
0
                        else
8956
0
                            break;
8957
0
                    } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY &&
8958
0
                               p1->class_id <= JS_CLASS_FLOAT64_ARRAY) {
8959
0
                        goto typed_array_oob;
8960
0
                    }
8961
0
                } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY &&
8962
0
                           p1->class_id <= JS_CLASS_FLOAT64_ARRAY) {
8963
0
                    ret = JS_AtomIsNumericIndex(ctx, prop);
8964
0
                    if (ret != 0) {
8965
0
                        if (ret < 0) {
8966
0
                            JS_FreeValue(ctx, val);
8967
0
                            return -1;
8968
0
                        }
8969
0
                    typed_array_oob:
8970
0
                        if (p == p1) {
8971
                            /* must convert the argument even if out of bound access */
8972
0
                            if (p1->class_id == JS_CLASS_BIG_INT64_ARRAY ||
8973
0
                                p1->class_id == JS_CLASS_BIG_UINT64_ARRAY) {
8974
0
                                int64_t v;
8975
0
                                if (JS_ToBigInt64Free(ctx, &v, val))
8976
0
                                    return -1;
8977
0
                            } else {
8978
0
                                val = JS_ToNumberFree(ctx, val);
8979
0
                                JS_FreeValue(ctx, val);
8980
0
                                if (JS_IsException(val))
8981
0
                                    return -1;
8982
0
                            }
8983
0
                        } else {
8984
0
                            JS_FreeValue(ctx, val);
8985
0
                        }
8986
0
                        return TRUE;
8987
0
                    }
8988
0
                }
8989
0
            } else {
8990
0
                const JSClassExoticMethods *em = ctx->rt->class_array[p1->class_id].exotic;
8991
0
                if (em) {
8992
0
                    JSValue obj1;
8993
0
                    if (em->set_property) {
8994
                        /* set_property can free the prototype */
8995
0
                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
8996
0
                        ret = em->set_property(ctx, obj1, prop,
8997
0
                                               val, this_obj, flags);
8998
0
                        JS_FreeValue(ctx, obj1);
8999
0
                        JS_FreeValue(ctx, val);
9000
0
                        return ret;
9001
0
                    }
9002
0
                    if (em->get_own_property) {
9003
                        /* get_own_property can free the prototype */
9004
0
                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
9005
0
                        ret = em->get_own_property(ctx, &desc,
9006
0
                                                   obj1, prop);
9007
0
                        JS_FreeValue(ctx, obj1);
9008
0
                        if (ret < 0) {
9009
0
                            JS_FreeValue(ctx, val);
9010
0
                            return ret;
9011
0
                        }
9012
0
                        if (ret) {
9013
0
                            if (desc.flags & JS_PROP_GETSET) {
9014
0
                                JSObject *setter;
9015
0
                                if (JS_IsUndefined(desc.setter))
9016
0
                                    setter = NULL;
9017
0
                                else
9018
0
                                    setter = JS_VALUE_GET_OBJ(desc.setter);
9019
0
                                ret = call_setter(ctx, setter, this_obj, val, flags);
9020
0
                                JS_FreeValue(ctx, desc.getter);
9021
0
                                JS_FreeValue(ctx, desc.setter);
9022
0
                                return ret;
9023
0
                            } else {
9024
0
                                JS_FreeValue(ctx, desc.value);
9025
0
                                if (!(desc.flags & JS_PROP_WRITABLE))
9026
0
                                    goto read_only_prop;
9027
0
                                if (likely(p == p1)) {
9028
0
                                    ret = JS_DefineProperty(ctx, this_obj, prop, val,
9029
0
                                                            JS_UNDEFINED, JS_UNDEFINED,
9030
0
                                                            JS_PROP_HAS_VALUE);
9031
0
                                    JS_FreeValue(ctx, val);
9032
0
                                    return ret;
9033
0
                                } else {
9034
0
                                    break;
9035
0
                                }
9036
0
                            }
9037
0
                        }
9038
0
                    }
9039
0
                }
9040
0
            }
9041
0
        }
9042
36
        p1 = p1->shape->proto;
9043
36
    prototype_lookup:
9044
36
        if (!p1)
9045
18
            break;
9046
9047
18
    retry2:
9048
18
        prs = find_own_property(&pr, p1, prop);
9049
18
        if (prs) {
9050
0
            if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
9051
0
                return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);
9052
0
            } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
9053
                /* Instantiate property and retry (potentially useless) */
9054
0
                if (JS_AutoInitProperty(ctx, p1, prop, pr, prs))
9055
0
                    return -1;
9056
0
                goto retry2;
9057
0
            } else if (!(prs->flags & JS_PROP_WRITABLE)) {
9058
0
                goto read_only_prop;
9059
0
            } else {
9060
0
                break;
9061
0
            }
9062
0
        }
9063
18
    }
9064
9065
18
    if (unlikely(flags & JS_PROP_NO_ADD)) {
9066
0
        JS_FreeValue(ctx, val);
9067
0
        JS_ThrowReferenceErrorNotDefined(ctx, prop);
9068
0
        return -1;
9069
0
    }
9070
9071
18
    if (unlikely(!p)) {
9072
0
        JS_FreeValue(ctx, val);
9073
0
        return JS_ThrowTypeErrorOrFalse(ctx, flags, "not an object");
9074
0
    }
9075
9076
18
    if (unlikely(!p->extensible)) {
9077
0
        JS_FreeValue(ctx, val);
9078
0
        return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible");
9079
0
    }
9080
9081
18
    if (likely(p == JS_VALUE_GET_OBJ(obj))) {
9082
18
        if (p->is_exotic) {
9083
0
            if (p->class_id == JS_CLASS_ARRAY && p->fast_array &&
9084
0
                __JS_AtomIsTaggedInt(prop)) {
9085
0
                uint32_t idx = __JS_AtomToUInt32(prop);
9086
0
                if (idx == p->u.array.count) {
9087
                    /* fast case */
9088
0
                    return add_fast_array_element(ctx, p, val, flags);
9089
0
                } else {
9090
0
                    goto generic_create_prop;
9091
0
                }
9092
0
            } else {
9093
0
                goto generic_create_prop;
9094
0
            }
9095
18
        } else {
9096
18
            pr = add_property(ctx, p, prop, JS_PROP_C_W_E);
9097
18
            if (unlikely(!pr)) {
9098
0
                JS_FreeValue(ctx, val);
9099
0
                return -1;
9100
0
            }
9101
18
            pr->u.value = val;
9102
18
            return TRUE;
9103
18
        }
9104
18
    } else {
9105
        /* generic case: modify the property in this_obj if it already exists */
9106
0
        ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
9107
0
        if (ret < 0) {
9108
0
            JS_FreeValue(ctx, val);
9109
0
            return ret;
9110
0
        }
9111
0
        if (ret) {
9112
0
            if (desc.flags & JS_PROP_GETSET) {
9113
0
                JS_FreeValue(ctx, desc.getter);
9114
0
                JS_FreeValue(ctx, desc.setter);
9115
0
                JS_FreeValue(ctx, val);
9116
0
                return JS_ThrowTypeErrorOrFalse(ctx, flags, "setter is forbidden");
9117
0
            } else {
9118
0
                JS_FreeValue(ctx, desc.value);
9119
0
                if (!(desc.flags & JS_PROP_WRITABLE) ||
9120
0
                    p->class_id == JS_CLASS_MODULE_NS) {
9121
0
                read_only_prop:
9122
0
                    JS_FreeValue(ctx, val);
9123
0
                    return JS_ThrowTypeErrorReadOnly(ctx, flags, prop);
9124
0
                }
9125
0
            }
9126
0
            ret = JS_DefineProperty(ctx, this_obj, prop, val,
9127
0
                                    JS_UNDEFINED, JS_UNDEFINED,
9128
0
                                    JS_PROP_HAS_VALUE);
9129
0
            JS_FreeValue(ctx, val);
9130
0
            return ret;
9131
0
        } else {
9132
0
        generic_create_prop:
9133
0
            ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED,
9134
0
                                    flags |
9135
0
                                    JS_PROP_HAS_VALUE |
9136
0
                                    JS_PROP_HAS_ENUMERABLE |
9137
0
                                    JS_PROP_HAS_WRITABLE |
9138
0
                                    JS_PROP_HAS_CONFIGURABLE |
9139
0
                                    JS_PROP_C_W_E);
9140
0
            JS_FreeValue(ctx, val);
9141
0
            return ret;
9142
0
        }
9143
0
    }
9144
18
}
9145
9146
/* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */
9147
static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
9148
                               JSValue prop, JSValue val, int flags)
9149
0
{
9150
0
    if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT &&
9151
0
               JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {
9152
0
        JSObject *p;
9153
0
        uint32_t idx;
9154
0
        double d;
9155
0
        int32_t v;
9156
9157
        /* fast path for array access */
9158
0
        p = JS_VALUE_GET_OBJ(this_obj);
9159
0
        idx = JS_VALUE_GET_INT(prop);
9160
0
        switch(p->class_id) {
9161
0
        case JS_CLASS_ARRAY:
9162
0
            if (unlikely(idx >= (uint32_t)p->u.array.count)) {
9163
0
                JSObject *p1;
9164
0
                JSShape *sh1;
9165
9166
                /* fast path to add an element to the array */
9167
0
                if (idx != (uint32_t)p->u.array.count ||
9168
0
                    !p->fast_array || !p->extensible)
9169
0
                    goto slow_path;
9170
                /* check if prototype chain has a numeric property */
9171
0
                p1 = p->shape->proto;
9172
0
                while (p1 != NULL) {
9173
0
                    sh1 = p1->shape;
9174
0
                    if (p1->class_id == JS_CLASS_ARRAY) {
9175
0
                        if (unlikely(!p1->fast_array))
9176
0
                            goto slow_path;
9177
0
                    } else if (p1->class_id == JS_CLASS_OBJECT) {
9178
0
                        if (unlikely(sh1->has_small_array_index))
9179
0
                            goto slow_path;
9180
0
                    } else {
9181
0
                        goto slow_path;
9182
0
                    }
9183
0
                    p1 = sh1->proto;
9184
0
                }
9185
                /* add element */
9186
0
                return add_fast_array_element(ctx, p, val, flags);
9187
0
            }
9188
0
            set_value(ctx, &p->u.array.u.values[idx], val);
9189
0
            break;
9190
0
        case JS_CLASS_ARGUMENTS:
9191
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
9192
0
                goto slow_path;
9193
0
            set_value(ctx, &p->u.array.u.values[idx], val);
9194
0
            break;
9195
0
        case JS_CLASS_UINT8C_ARRAY:
9196
0
            if (JS_ToUint8ClampFree(ctx, &v, val))
9197
0
                return -1;
9198
            /* Note: the conversion can detach the typed array, so the
9199
               array bound check must be done after */
9200
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
9201
0
                goto ta_out_of_bound;
9202
0
            p->u.array.u.uint8_ptr[idx] = v;
9203
0
            break;
9204
0
        case JS_CLASS_INT8_ARRAY:
9205
0
        case JS_CLASS_UINT8_ARRAY:
9206
0
            if (JS_ToInt32Free(ctx, &v, val))
9207
0
                return -1;
9208
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
9209
0
                goto ta_out_of_bound;
9210
0
            p->u.array.u.uint8_ptr[idx] = v;
9211
0
            break;
9212
0
        case JS_CLASS_INT16_ARRAY:
9213
0
        case JS_CLASS_UINT16_ARRAY:
9214
0
            if (JS_ToInt32Free(ctx, &v, val))
9215
0
                return -1;
9216
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
9217
0
                goto ta_out_of_bound;
9218
0
            p->u.array.u.uint16_ptr[idx] = v;
9219
0
            break;
9220
0
        case JS_CLASS_INT32_ARRAY:
9221
0
        case JS_CLASS_UINT32_ARRAY:
9222
0
            if (JS_ToInt32Free(ctx, &v, val))
9223
0
                return -1;
9224
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
9225
0
                goto ta_out_of_bound;
9226
0
            p->u.array.u.uint32_ptr[idx] = v;
9227
0
            break;
9228
0
        case JS_CLASS_BIG_INT64_ARRAY:
9229
0
        case JS_CLASS_BIG_UINT64_ARRAY:
9230
            /* XXX: need specific conversion function */
9231
0
            {
9232
0
                int64_t v;
9233
0
                if (JS_ToBigInt64Free(ctx, &v, val))
9234
0
                    return -1;
9235
0
                if (unlikely(idx >= (uint32_t)p->u.array.count))
9236
0
                    goto ta_out_of_bound;
9237
0
                p->u.array.u.uint64_ptr[idx] = v;
9238
0
            }
9239
0
            break;
9240
0
        case JS_CLASS_FLOAT16_ARRAY:
9241
0
            if (JS_ToFloat64Free(ctx, &d, val))
9242
0
                return -1;
9243
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
9244
0
                goto ta_out_of_bound;
9245
0
            p->u.array.u.fp16_ptr[idx] = tofp16(d);
9246
0
            break;
9247
0
        case JS_CLASS_FLOAT32_ARRAY:
9248
0
            if (JS_ToFloat64Free(ctx, &d, val))
9249
0
                return -1;
9250
0
            if (unlikely(idx >= (uint32_t)p->u.array.count))
9251
0
                goto ta_out_of_bound;
9252
0
            p->u.array.u.float_ptr[idx] = d;
9253
0
            break;
9254
0
        case JS_CLASS_FLOAT64_ARRAY:
9255
0
            if (JS_ToFloat64Free(ctx, &d, val))
9256
0
                return -1;
9257
0
            if (unlikely(idx >= (uint32_t)p->u.array.count)) {
9258
0
            ta_out_of_bound:
9259
0
                return TRUE;
9260
0
            }
9261
0
            p->u.array.u.double_ptr[idx] = d;
9262
0
            break;
9263
0
        default:
9264
0
            goto slow_path;
9265
0
        }
9266
0
        return TRUE;
9267
0
    } else {
9268
0
        JSAtom atom;
9269
0
        int ret;
9270
0
    slow_path:
9271
0
        atom = JS_ValueToAtom(ctx, prop);
9272
0
        JS_FreeValue(ctx, prop);
9273
0
        if (unlikely(atom == JS_ATOM_NULL)) {
9274
0
            JS_FreeValue(ctx, val);
9275
0
            return -1;
9276
0
        }
9277
0
        ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, flags);
9278
0
        JS_FreeAtom(ctx, atom);
9279
0
        return ret;
9280
0
    }
9281
0
}
9282
9283
int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
9284
                         uint32_t idx, JSValue val)
9285
0
{
9286
0
    return JS_SetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx), val,
9287
0
                               JS_PROP_THROW);
9288
0
}
9289
9290
int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj,
9291
                        int64_t idx, JSValue val)
9292
0
{
9293
0
    JSAtom prop;
9294
0
    int res;
9295
9296
0
    if ((uint64_t)idx <= INT32_MAX) {
9297
        /* fast path for fast arrays */
9298
0
        return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val,
9299
0
                                   JS_PROP_THROW);
9300
0
    }
9301
0
    prop = JS_NewAtomInt64(ctx, idx);
9302
0
    if (prop == JS_ATOM_NULL) {
9303
0
        JS_FreeValue(ctx, val);
9304
0
        return -1;
9305
0
    }
9306
0
    res = JS_SetProperty(ctx, this_obj, prop, val);
9307
0
    JS_FreeAtom(ctx, prop);
9308
0
    return res;
9309
0
}
9310
9311
int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj,
9312
                      const char *prop, JSValue val)
9313
14
{
9314
14
    JSAtom atom;
9315
14
    int ret;
9316
14
    atom = JS_NewAtom(ctx, prop);
9317
14
    if (atom == JS_ATOM_NULL) {
9318
0
        JS_FreeValue(ctx, val);
9319
0
        return -1;
9320
0
    }
9321
14
    ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, JS_PROP_THROW);
9322
14
    JS_FreeAtom(ctx, atom);
9323
14
    return ret;
9324
14
}
9325
9326
/* compute the property flags. For each flag: (JS_PROP_HAS_x forces
9327
   it, otherwise def_flags is used)
9328
   Note: makes assumption about the bit pattern of the flags
9329
*/
9330
static int get_prop_flags(int flags, int def_flags)
9331
0
{
9332
0
    int mask;
9333
0
    mask = (flags >> JS_PROP_HAS_SHIFT) & JS_PROP_C_W_E;
9334
0
    return (flags & mask) | (def_flags & ~mask);
9335
0
}
9336
9337
static int JS_CreateProperty(JSContext *ctx, JSObject *p,
9338
                             JSAtom prop, JSValueConst val,
9339
                             JSValueConst getter, JSValueConst setter,
9340
                             int flags)
9341
1.23k
{
9342
1.23k
    JSProperty *pr;
9343
1.23k
    int ret, prop_flags;
9344
9345
    /* add a new property or modify an existing exotic one */
9346
1.23k
    if (p->is_exotic) {
9347
26
        if (p->class_id == JS_CLASS_ARRAY) {
9348
6
            uint32_t idx, len;
9349
9350
6
            if (p->fast_array) {
9351
6
                if (__JS_AtomIsTaggedInt(prop)) {
9352
0
                    idx = __JS_AtomToUInt32(prop);
9353
0
                    if (idx == p->u.array.count) {
9354
0
                        if (!p->extensible)
9355
0
                            goto not_extensible;
9356
0
                        if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET))
9357
0
                            goto convert_to_array;
9358
0
                        prop_flags = get_prop_flags(flags, 0);
9359
0
                        if (prop_flags != JS_PROP_C_W_E)
9360
0
                            goto convert_to_array;
9361
0
                        return add_fast_array_element(ctx, p,
9362
0
                                                      JS_DupValue(ctx, val), flags);
9363
0
                    } else {
9364
0
                        goto convert_to_array;
9365
0
                    }
9366
6
                } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) {
9367
                    /* convert the fast array to normal array */
9368
0
                convert_to_array:
9369
0
                    if (convert_fast_array_to_array(ctx, p))
9370
0
                        return -1;
9371
0
                    goto generic_array;
9372
0
                }
9373
6
            } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) {
9374
0
                JSProperty *plen;
9375
0
                JSShapeProperty *pslen;
9376
0
            generic_array:
9377
                /* update the length field */
9378
0
                plen = &p->prop[0];
9379
0
                JS_ToUint32(ctx, &len, plen->u.value);
9380
0
                if ((idx + 1) > len) {
9381
0
                    pslen = get_shape_prop(p->shape);
9382
0
                    if (unlikely(!(pslen->flags & JS_PROP_WRITABLE)))
9383
0
                        return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
9384
                    /* XXX: should update the length after defining
9385
                       the property */
9386
0
                    len = idx + 1;
9387
0
                    set_value(ctx, &plen->u.value, JS_NewUint32(ctx, len));
9388
0
                }
9389
0
            }
9390
20
        } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
9391
20
                   p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
9392
0
            ret = JS_AtomIsNumericIndex(ctx, prop);
9393
0
            if (ret != 0) {
9394
0
                if (ret < 0)
9395
0
                    return -1;
9396
0
                return JS_ThrowTypeErrorOrFalse(ctx, flags, "cannot create numeric index in typed array");
9397
0
            }
9398
20
        } else if (!(flags & JS_PROP_NO_EXOTIC)) {
9399
12
            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
9400
12
            if (em) {
9401
12
                if (em->define_own_property) {
9402
8
                    return em->define_own_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p),
9403
8
                                                   prop, val, getter, setter, flags);
9404
8
                }
9405
4
                ret = JS_IsExtensible(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
9406
4
                if (ret < 0)
9407
0
                    return -1;
9408
4
                if (!ret)
9409
0
                    goto not_extensible;
9410
4
            }
9411
12
        }
9412
26
    }
9413
9414
1.22k
    if (!p->extensible) {
9415
0
    not_extensible:
9416
0
        return JS_ThrowTypeErrorOrFalse(ctx, flags, "object is not extensible");
9417
0
    }
9418
9419
1.22k
    if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
9420
74
        prop_flags = (flags & (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) |
9421
74
            JS_PROP_GETSET;
9422
1.15k
    } else {
9423
1.15k
        prop_flags = flags & JS_PROP_C_W_E;
9424
1.15k
    }
9425
1.22k
    pr = add_property(ctx, p, prop, prop_flags);
9426
1.22k
    if (unlikely(!pr))
9427
0
        return -1;
9428
1.22k
    if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
9429
74
        pr->u.getset.getter = NULL;
9430
74
        if ((flags & JS_PROP_HAS_GET) && JS_IsFunction(ctx, getter)) {
9431
74
            pr->u.getset.getter =
9432
74
                JS_VALUE_GET_OBJ(JS_DupValue(ctx, getter));
9433
74
        }
9434
74
        pr->u.getset.setter = NULL;
9435
74
        if ((flags & JS_PROP_HAS_SET) && JS_IsFunction(ctx, setter)) {
9436
6
            pr->u.getset.setter =
9437
6
                JS_VALUE_GET_OBJ(JS_DupValue(ctx, setter));
9438
6
        }
9439
1.15k
    } else {
9440
1.15k
        if (flags & JS_PROP_HAS_VALUE) {
9441
1.15k
            pr->u.value = JS_DupValue(ctx, val);
9442
1.15k
        } else {
9443
0
            pr->u.value = JS_UNDEFINED;
9444
0
        }
9445
1.15k
    }
9446
1.22k
    return TRUE;
9447
1.22k
}
9448
9449
/* return FALSE if not OK */
9450
static BOOL check_define_prop_flags(int prop_flags, int flags)
9451
4
{
9452
4
    BOOL has_accessor, is_getset;
9453
9454
4
    if (!(prop_flags & JS_PROP_CONFIGURABLE)) {
9455
0
        if ((flags & (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) ==
9456
0
            (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) {
9457
0
            return FALSE;
9458
0
        }
9459
0
        if ((flags & JS_PROP_HAS_ENUMERABLE) &&
9460
0
            (flags & JS_PROP_ENUMERABLE) != (prop_flags & JS_PROP_ENUMERABLE))
9461
0
            return FALSE;
9462
0
        if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE |
9463
0
                     JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
9464
0
            has_accessor = ((flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) != 0);
9465
0
            is_getset = ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET);
9466
0
            if (has_accessor != is_getset)
9467
0
                return FALSE;
9468
0
            if (!is_getset && !(prop_flags & JS_PROP_WRITABLE)) {
9469
                /* not writable: cannot set the writable bit */
9470
0
                if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
9471
0
                    (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE))
9472
0
                    return FALSE;
9473
0
            }
9474
0
        }
9475
0
    }
9476
4
    return TRUE;
9477
4
}
9478
9479
/* ensure that the shape can be safely modified */
9480
static int js_shape_prepare_update(JSContext *ctx, JSObject *p,
9481
                                   JSShapeProperty **pprs)
9482
24
{
9483
24
    JSShape *sh;
9484
24
    uint32_t idx = 0;    /* prevent warning */
9485
9486
24
    sh = p->shape;
9487
24
    if (sh->is_hashed) {
9488
16
        if (sh->header.ref_count != 1) {
9489
0
            if (pprs)
9490
0
                idx = *pprs - get_shape_prop(sh);
9491
            /* clone the shape (the resulting one is no longer hashed) */
9492
0
            sh = js_clone_shape(ctx, sh);
9493
0
            if (!sh)
9494
0
                return -1;
9495
0
            js_free_shape(ctx->rt, p->shape);
9496
0
            p->shape = sh;
9497
0
            if (pprs)
9498
0
                *pprs = get_shape_prop(sh) + idx;
9499
16
        } else {
9500
16
            js_shape_hash_unlink(ctx->rt, sh);
9501
16
            sh->is_hashed = FALSE;
9502
16
        }
9503
16
    }
9504
24
    return 0;
9505
24
}
9506
9507
static int js_update_property_flags(JSContext *ctx, JSObject *p,
9508
                                    JSShapeProperty **pprs, int flags)
9509
4
{
9510
4
    if (flags != (*pprs)->flags) {
9511
4
        if (js_shape_prepare_update(ctx, p, pprs))
9512
0
            return -1;
9513
4
        (*pprs)->flags = flags;
9514
4
    }
9515
4
    return 0;
9516
4
}
9517
9518
/* allowed flags:
9519
   JS_PROP_CONFIGURABLE, JS_PROP_WRITABLE, JS_PROP_ENUMERABLE
9520
   JS_PROP_HAS_GET, JS_PROP_HAS_SET, JS_PROP_HAS_VALUE,
9521
   JS_PROP_HAS_CONFIGURABLE, JS_PROP_HAS_WRITABLE, JS_PROP_HAS_ENUMERABLE,
9522
   JS_PROP_THROW, JS_PROP_NO_EXOTIC.
9523
   If JS_PROP_THROW is set, return an exception instead of FALSE.
9524
   if JS_PROP_NO_EXOTIC is set, do not call the exotic
9525
   define_own_property callback.
9526
   return -1 (exception), FALSE or TRUE.
9527
*/
9528
int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
9529
                      JSAtom prop, JSValueConst val,
9530
                      JSValueConst getter, JSValueConst setter, int flags)
9531
1.23k
{
9532
1.23k
    JSObject *p;
9533
1.23k
    JSShapeProperty *prs;
9534
1.23k
    JSProperty *pr;
9535
1.23k
    int mask, res;
9536
9537
1.23k
    if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT) {
9538
0
        JS_ThrowTypeErrorNotAnObject(ctx);
9539
0
        return -1;
9540
0
    }
9541
1.23k
    p = JS_VALUE_GET_OBJ(this_obj);
9542
9543
1.23k
 redo_prop_update:
9544
1.23k
    prs = find_own_property(&pr, p, prop);
9545
1.23k
    if (prs) {
9546
        /* the range of the Array length property is always tested before */
9547
4
        if ((prs->flags & JS_PROP_LENGTH) && (flags & JS_PROP_HAS_VALUE)) {
9548
0
            uint32_t array_length;
9549
0
            if (JS_ToArrayLengthFree(ctx, &array_length,
9550
0
                                     JS_DupValue(ctx, val), FALSE)) {
9551
0
                return -1;
9552
0
            }
9553
            /* this code relies on the fact that Uint32 are never allocated */
9554
0
            val = (JSValueConst)JS_NewUint32(ctx, array_length);
9555
            /* prs may have been modified */
9556
0
            prs = find_own_property(&pr, p, prop);
9557
0
            assert(prs != NULL);
9558
0
        }
9559
        /* property already exists */
9560
4
        if (!check_define_prop_flags(prs->flags, flags)) {
9561
0
        not_configurable:
9562
0
            return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
9563
0
        }
9564
9565
4
        if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
9566
            /* Instantiate property and retry */
9567
0
            if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
9568
0
                return -1;
9569
0
            goto redo_prop_update;
9570
0
        }
9571
9572
4
        if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE |
9573
4
                     JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
9574
0
            if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
9575
0
                JSObject *new_getter, *new_setter;
9576
9577
0
                if (JS_IsFunction(ctx, getter)) {
9578
0
                    new_getter = JS_VALUE_GET_OBJ(getter);
9579
0
                } else {
9580
0
                    new_getter = NULL;
9581
0
                }
9582
0
                if (JS_IsFunction(ctx, setter)) {
9583
0
                    new_setter = JS_VALUE_GET_OBJ(setter);
9584
0
                } else {
9585
0
                    new_setter = NULL;
9586
0
                }
9587
9588
0
                if ((prs->flags & JS_PROP_TMASK) != JS_PROP_GETSET) {
9589
0
                    if (js_shape_prepare_update(ctx, p, &prs))
9590
0
                        return -1;
9591
                    /* convert to getset */
9592
0
                    if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
9593
0
                        free_var_ref(ctx->rt, pr->u.var_ref);
9594
0
                    } else {
9595
0
                        JS_FreeValue(ctx, pr->u.value);
9596
0
                    }
9597
0
                    prs->flags = (prs->flags &
9598
0
                                  (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) |
9599
0
                        JS_PROP_GETSET;
9600
0
                    pr->u.getset.getter = NULL;
9601
0
                    pr->u.getset.setter = NULL;
9602
0
                } else {
9603
0
                    if (!(prs->flags & JS_PROP_CONFIGURABLE)) {
9604
0
                        if ((flags & JS_PROP_HAS_GET) &&
9605
0
                            new_getter != pr->u.getset.getter) {
9606
0
                            goto not_configurable;
9607
0
                        }
9608
0
                        if ((flags & JS_PROP_HAS_SET) &&
9609
0
                            new_setter != pr->u.getset.setter) {
9610
0
                            goto not_configurable;
9611
0
                        }
9612
0
                    }
9613
0
                }
9614
0
                if (flags & JS_PROP_HAS_GET) {
9615
0
                    if (pr->u.getset.getter)
9616
0
                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
9617
0
                    if (new_getter)
9618
0
                        JS_DupValue(ctx, getter);
9619
0
                    pr->u.getset.getter = new_getter;
9620
0
                }
9621
0
                if (flags & JS_PROP_HAS_SET) {
9622
0
                    if (pr->u.getset.setter)
9623
0
                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
9624
0
                    if (new_setter)
9625
0
                        JS_DupValue(ctx, setter);
9626
0
                    pr->u.getset.setter = new_setter;
9627
0
                }
9628
0
            } else {
9629
0
                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
9630
                    /* convert to data descriptor */
9631
0
                    if (js_shape_prepare_update(ctx, p, &prs))
9632
0
                        return -1;
9633
0
                    if (pr->u.getset.getter)
9634
0
                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));
9635
0
                    if (pr->u.getset.setter)
9636
0
                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));
9637
0
                    prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
9638
0
                    pr->u.value = JS_UNDEFINED;
9639
0
                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
9640
                    /* Note: JS_PROP_VARREF is always writable */
9641
0
                } else {
9642
0
                    if ((prs->flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 &&
9643
0
                        (flags & JS_PROP_HAS_VALUE)) {
9644
0
                        if (!js_same_value(ctx, val, pr->u.value)) {
9645
0
                            goto not_configurable;
9646
0
                        } else {
9647
0
                            return TRUE;
9648
0
                        }
9649
0
                    }
9650
0
                }
9651
0
                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
9652
0
                    if (flags & JS_PROP_HAS_VALUE) {
9653
0
                        if (p->class_id == JS_CLASS_MODULE_NS) {
9654
                            /* JS_PROP_WRITABLE is always true for variable
9655
                               references, but they are write protected in module name
9656
                               spaces. */
9657
0
                            if (!js_same_value(ctx, val, *pr->u.var_ref->pvalue))
9658
0
                                goto not_configurable;
9659
0
                        } else {
9660
                            /* update the reference */
9661
0
                            set_value(ctx, pr->u.var_ref->pvalue,
9662
0
                                      JS_DupValue(ctx, val));
9663
0
                        }
9664
0
                    }
9665
                    /* if writable is set to false, no longer a
9666
                       reference (for mapped arguments) */
9667
0
                    if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) {
9668
0
                        JSValue val1;
9669
0
                        if (p->class_id == JS_CLASS_MODULE_NS) {
9670
0
                            return JS_ThrowTypeErrorOrFalse(ctx, flags, "module namespace properties have writable = false");
9671
0
                        }
9672
0
                        if (js_shape_prepare_update(ctx, p, &prs))
9673
0
                            return -1;
9674
0
                        val1 = JS_DupValue(ctx, *pr->u.var_ref->pvalue);
9675
0
                        free_var_ref(ctx->rt, pr->u.var_ref);
9676
0
                        pr->u.value = val1;
9677
0
                        prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
9678
0
                    }
9679
0
                } else if (prs->flags & JS_PROP_LENGTH) {
9680
0
                    if (flags & JS_PROP_HAS_VALUE) {
9681
                        /* Note: no JS code is executable because
9682
                           'val' is guaranted to be a Uint32 */
9683
0
                        res = set_array_length(ctx, p, JS_DupValue(ctx, val),
9684
0
                                               flags);
9685
0
                    } else {
9686
0
                        res = TRUE;
9687
0
                    }
9688
                    /* still need to reset the writable flag if
9689
                       needed.  The JS_PROP_LENGTH is kept because the
9690
                       Uint32 test is still done if the length
9691
                       property is read-only. */
9692
0
                    if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
9693
0
                        JS_PROP_HAS_WRITABLE) {
9694
0
                        prs = get_shape_prop(p->shape);
9695
0
                        if (js_update_property_flags(ctx, p, &prs,
9696
0
                                                     prs->flags & ~JS_PROP_WRITABLE))
9697
0
                            return -1;
9698
0
                    }
9699
0
                    return res;
9700
0
                } else {
9701
0
                    if (flags & JS_PROP_HAS_VALUE) {
9702
0
                        JS_FreeValue(ctx, pr->u.value);
9703
0
                        pr->u.value = JS_DupValue(ctx, val);
9704
0
                    }
9705
0
                    if (flags & JS_PROP_HAS_WRITABLE) {
9706
0
                        if (js_update_property_flags(ctx, p, &prs,
9707
0
                                                     (prs->flags & ~JS_PROP_WRITABLE) |
9708
0
                                                     (flags & JS_PROP_WRITABLE)))
9709
0
                            return -1;
9710
0
                    }
9711
0
                }
9712
0
            }
9713
0
        }
9714
4
        mask = 0;
9715
4
        if (flags & JS_PROP_HAS_CONFIGURABLE)
9716
4
            mask |= JS_PROP_CONFIGURABLE;
9717
4
        if (flags & JS_PROP_HAS_ENUMERABLE)
9718
0
            mask |= JS_PROP_ENUMERABLE;
9719
4
        if (js_update_property_flags(ctx, p, &prs,
9720
4
                                     (prs->flags & ~mask) | (flags & mask)))
9721
0
            return -1;
9722
4
        return TRUE;
9723
4
    }
9724
9725
    /* handle modification of fast array elements */
9726
1.23k
    if (p->fast_array) {
9727
6
        uint32_t idx;
9728
6
        uint32_t prop_flags;
9729
6
        if (p->class_id == JS_CLASS_ARRAY) {
9730
6
            if (__JS_AtomIsTaggedInt(prop)) {
9731
0
                idx = __JS_AtomToUInt32(prop);
9732
0
                if (idx < p->u.array.count) {
9733
0
                    prop_flags = get_prop_flags(flags, JS_PROP_C_W_E);
9734
0
                    if (prop_flags != JS_PROP_C_W_E)
9735
0
                        goto convert_to_slow_array;
9736
0
                    if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
9737
0
                    convert_to_slow_array:
9738
0
                        if (convert_fast_array_to_array(ctx, p))
9739
0
                            return -1;
9740
0
                        else
9741
0
                            goto redo_prop_update;
9742
0
                    }
9743
0
                    if (flags & JS_PROP_HAS_VALUE) {
9744
0
                        set_value(ctx, &p->u.array.u.values[idx], JS_DupValue(ctx, val));
9745
0
                    }
9746
0
                    return TRUE;
9747
0
                }
9748
0
            }
9749
6
        } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
9750
0
                   p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
9751
0
            JSValue num;
9752
0
            int ret;
9753
9754
0
            if (!__JS_AtomIsTaggedInt(prop)) {
9755
                /* slow path with to handle all numeric indexes */
9756
0
                num = JS_AtomIsNumericIndex1(ctx, prop);
9757
0
                if (JS_IsUndefined(num))
9758
0
                    goto typed_array_done;
9759
0
                if (JS_IsException(num))
9760
0
                    return -1;
9761
0
                ret = JS_NumberIsInteger(ctx, num);
9762
0
                if (ret < 0) {
9763
0
                    JS_FreeValue(ctx, num);
9764
0
                    return -1;
9765
0
                }
9766
0
                if (!ret) {
9767
0
                    JS_FreeValue(ctx, num);
9768
0
                    return JS_ThrowTypeErrorOrFalse(ctx, flags, "non integer index in typed array");
9769
0
                }
9770
0
                ret = JS_NumberIsNegativeOrMinusZero(ctx, num);
9771
0
                JS_FreeValue(ctx, num);
9772
0
                if (ret) {
9773
0
                    return JS_ThrowTypeErrorOrFalse(ctx, flags, "negative index in typed array");
9774
0
                }
9775
0
                if (!__JS_AtomIsTaggedInt(prop))
9776
0
                    goto typed_array_oob;
9777
0
            }
9778
0
            idx = __JS_AtomToUInt32(prop);
9779
            /* if the typed array is detached, p->u.array.count = 0 */
9780
0
            if (idx >= p->u.array.count) {
9781
0
            typed_array_oob:
9782
0
                return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound index in typed array");
9783
0
            }
9784
0
            prop_flags = get_prop_flags(flags, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
9785
0
            if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET) ||
9786
0
                prop_flags != (JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE)) {
9787
0
                return JS_ThrowTypeErrorOrFalse(ctx, flags, "invalid descriptor flags");
9788
0
            }
9789
0
            if (flags & JS_PROP_HAS_VALUE) {
9790
0
                return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), JS_DupValue(ctx, val), flags);
9791
0
            }
9792
0
            return TRUE;
9793
0
        typed_array_done: ;
9794
0
        }
9795
6
    }
9796
9797
1.23k
    return JS_CreateProperty(ctx, p, prop, val, getter, setter, flags);
9798
1.23k
}
9799
9800
static int JS_DefineAutoInitProperty(JSContext *ctx, JSValueConst this_obj,
9801
                                     JSAtom prop, JSAutoInitIDEnum id,
9802
                                     void *opaque, int flags)
9803
768
{
9804
768
    JSObject *p;
9805
768
    JSProperty *pr;
9806
9807
768
    if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT)
9808
0
        return FALSE;
9809
9810
768
    p = JS_VALUE_GET_OBJ(this_obj);
9811
9812
768
    if (find_own_property(&pr, p, prop)) {
9813
        /* property already exists */
9814
0
        abort();
9815
0
        return FALSE;
9816
0
    }
9817
9818
    /* Specialized CreateProperty */
9819
768
    pr = add_property(ctx, p, prop, (flags & JS_PROP_C_W_E) | JS_PROP_AUTOINIT);
9820
768
    if (unlikely(!pr))
9821
0
        return -1;
9822
768
    pr->u.init.realm_and_id = (uintptr_t)JS_DupContext(ctx);
9823
768
    assert((pr->u.init.realm_and_id & 3) == 0);
9824
768
    assert(id <= 3);
9825
768
    pr->u.init.realm_and_id |= id;
9826
768
    pr->u.init.opaque = opaque;
9827
768
    return TRUE;
9828
768
}
9829
9830
/* shortcut to add or redefine a new property value */
9831
int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj,
9832
                           JSAtom prop, JSValue val, int flags)
9833
1.15k
{
9834
1.15k
    int ret;
9835
1.15k
    ret = JS_DefineProperty(ctx, this_obj, prop, val, JS_UNDEFINED, JS_UNDEFINED,
9836
1.15k
                            flags | JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE);
9837
1.15k
    JS_FreeValue(ctx, val);
9838
1.15k
    return ret;
9839
1.15k
}
9840
9841
int JS_DefinePropertyValueValue(JSContext *ctx, JSValueConst this_obj,
9842
                                JSValue prop, JSValue val, int flags)
9843
0
{
9844
0
    JSAtom atom;
9845
0
    int ret;
9846
0
    atom = JS_ValueToAtom(ctx, prop);
9847
0
    JS_FreeValue(ctx, prop);
9848
0
    if (unlikely(atom == JS_ATOM_NULL)) {
9849
0
        JS_FreeValue(ctx, val);
9850
0
        return -1;
9851
0
    }
9852
0
    ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
9853
0
    JS_FreeAtom(ctx, atom);
9854
0
    return ret;
9855
0
}
9856
9857
int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj,
9858
                                 uint32_t idx, JSValue val, int flags)
9859
0
{
9860
0
    return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewUint32(ctx, idx),
9861
0
                                       val, flags);
9862
0
}
9863
9864
int JS_DefinePropertyValueInt64(JSContext *ctx, JSValueConst this_obj,
9865
                                int64_t idx, JSValue val, int flags)
9866
0
{
9867
0
    return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx),
9868
0
                                       val, flags);
9869
0
}
9870
9871
int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj,
9872
                              const char *prop, JSValue val, int flags)
9873
192
{
9874
192
    JSAtom atom;
9875
192
    int ret;
9876
192
    atom = JS_NewAtom(ctx, prop);
9877
192
    if (atom == JS_ATOM_NULL) {
9878
0
        JS_FreeValue(ctx, val);
9879
0
        return -1;
9880
0
    }
9881
192
    ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
9882
192
    JS_FreeAtom(ctx, atom);
9883
192
    return ret;
9884
192
}
9885
9886
/* shortcut to add getter & setter */
9887
int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj,
9888
                            JSAtom prop, JSValue getter, JSValue setter,
9889
                            int flags)
9890
70
{
9891
70
    int ret;
9892
70
    ret = JS_DefineProperty(ctx, this_obj, prop, JS_UNDEFINED, getter, setter,
9893
70
                            flags | JS_PROP_HAS_GET | JS_PROP_HAS_SET |
9894
70
                            JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE);
9895
70
    JS_FreeValue(ctx, getter);
9896
70
    JS_FreeValue(ctx, setter);
9897
70
    return ret;
9898
70
}
9899
9900
static int JS_CreateDataPropertyUint32(JSContext *ctx, JSValueConst this_obj,
9901
                                       int64_t idx, JSValue val, int flags)
9902
0
{
9903
0
    return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx),
9904
0
                                       val, flags | JS_PROP_CONFIGURABLE |
9905
0
                                       JS_PROP_ENUMERABLE | JS_PROP_WRITABLE);
9906
0
}
9907
9908
9909
/* return TRUE if 'obj' has a non empty 'name' string */
9910
static BOOL js_object_has_name(JSContext *ctx, JSValueConst obj)
9911
0
{
9912
0
    JSProperty *pr;
9913
0
    JSShapeProperty *prs;
9914
0
    JSValueConst val;
9915
0
    JSString *p;
9916
9917
0
    prs = find_own_property(&pr, JS_VALUE_GET_OBJ(obj), JS_ATOM_name);
9918
0
    if (!prs)
9919
0
        return FALSE;
9920
0
    if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
9921
0
        return TRUE;
9922
0
    val = pr->u.value;
9923
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
9924
0
        return TRUE;
9925
0
    p = JS_VALUE_GET_STRING(val);
9926
0
    return (p->len != 0);
9927
0
}
9928
9929
static int JS_DefineObjectName(JSContext *ctx, JSValueConst obj,
9930
                               JSAtom name, int flags)
9931
0
{
9932
0
    if (name != JS_ATOM_NULL
9933
0
    &&  JS_IsObject(obj)
9934
0
    &&  !js_object_has_name(ctx, obj)
9935
0
    &&  JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, JS_AtomToString(ctx, name), flags) < 0) {
9936
0
        return -1;
9937
0
    }
9938
0
    return 0;
9939
0
}
9940
9941
static int JS_DefineObjectNameComputed(JSContext *ctx, JSValueConst obj,
9942
                                       JSValueConst str, int flags)
9943
0
{
9944
0
    if (JS_IsObject(obj) &&
9945
0
        !js_object_has_name(ctx, obj)) {
9946
0
        JSAtom prop;
9947
0
        JSValue name_str;
9948
0
        prop = JS_ValueToAtom(ctx, str);
9949
0
        if (prop == JS_ATOM_NULL)
9950
0
            return -1;
9951
0
        name_str = js_get_function_name(ctx, prop);
9952
0
        JS_FreeAtom(ctx, prop);
9953
0
        if (JS_IsException(name_str))
9954
0
            return -1;
9955
0
        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, name_str, flags) < 0)
9956
0
            return -1;
9957
0
    }
9958
0
    return 0;
9959
0
}
9960
9961
0
#define DEFINE_GLOBAL_LEX_VAR (1 << 7)
9962
0
#define DEFINE_GLOBAL_FUNC_VAR (1 << 6)
9963
9964
static JSValue JS_ThrowSyntaxErrorVarRedeclaration(JSContext *ctx, JSAtom prop)
9965
0
{
9966
0
    return JS_ThrowSyntaxErrorAtom(ctx, "redeclaration of '%s'", prop);
9967
0
}
9968
9969
/* flags is 0, DEFINE_GLOBAL_LEX_VAR or DEFINE_GLOBAL_FUNC_VAR */
9970
/* XXX: could support exotic global object. */
9971
static int JS_CheckDefineGlobalVar(JSContext *ctx, JSAtom prop, int flags)
9972
0
{
9973
0
    JSObject *p;
9974
0
    JSShapeProperty *prs;
9975
9976
0
    p = JS_VALUE_GET_OBJ(ctx->global_obj);
9977
0
    prs = find_own_property1(p, prop);
9978
    /* XXX: should handle JS_PROP_AUTOINIT */
9979
0
    if (flags & DEFINE_GLOBAL_LEX_VAR) {
9980
0
        if (prs && !(prs->flags & JS_PROP_CONFIGURABLE))
9981
0
            goto fail_redeclaration;
9982
0
    } else {
9983
0
        if (!prs && !p->extensible)
9984
0
            goto define_error;
9985
0
        if (flags & DEFINE_GLOBAL_FUNC_VAR) {
9986
0
            if (prs) {
9987
0
                if (!(prs->flags & JS_PROP_CONFIGURABLE) &&
9988
0
                    ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET ||
9989
0
                     ((prs->flags & (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)) !=
9990
0
                      (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)))) {
9991
0
                define_error:
9992
0
                    JS_ThrowTypeErrorAtom(ctx, "cannot define variable '%s'",
9993
0
                                          prop);
9994
0
                    return -1;
9995
0
                }
9996
0
            }
9997
0
        }
9998
0
    }
9999
    /* check if there already is a lexical declaration */
10000
0
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
10001
0
    prs = find_own_property1(p, prop);
10002
0
    if (prs) {
10003
0
    fail_redeclaration:
10004
0
        JS_ThrowSyntaxErrorVarRedeclaration(ctx, prop);
10005
0
        return -1;
10006
0
    }
10007
0
    return 0;
10008
0
}
10009
10010
/* def_flags is (0, DEFINE_GLOBAL_LEX_VAR) |
10011
   JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE */
10012
/* XXX: could support exotic global object. */
10013
static int JS_DefineGlobalVar(JSContext *ctx, JSAtom prop, int def_flags)
10014
0
{
10015
0
    JSObject *p;
10016
0
    JSShapeProperty *prs;
10017
0
    JSProperty *pr;
10018
0
    JSValue val;
10019
0
    int flags;
10020
10021
0
    if (def_flags & DEFINE_GLOBAL_LEX_VAR) {
10022
0
        p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
10023
0
        flags = JS_PROP_ENUMERABLE | (def_flags & JS_PROP_WRITABLE) |
10024
0
            JS_PROP_CONFIGURABLE;
10025
0
        val = JS_UNINITIALIZED;
10026
0
    } else {
10027
0
        p = JS_VALUE_GET_OBJ(ctx->global_obj);
10028
0
        flags = JS_PROP_ENUMERABLE | JS_PROP_WRITABLE |
10029
0
            (def_flags & JS_PROP_CONFIGURABLE);
10030
0
        val = JS_UNDEFINED;
10031
0
    }
10032
0
    prs = find_own_property1(p, prop);
10033
0
    if (prs)
10034
0
        return 0;
10035
0
    if (!p->extensible)
10036
0
        return 0;
10037
0
    pr = add_property(ctx, p, prop, flags);
10038
0
    if (unlikely(!pr))
10039
0
        return -1;
10040
0
    pr->u.value = val;
10041
0
    return 0;
10042
0
}
10043
10044
/* 'def_flags' is 0 or JS_PROP_CONFIGURABLE. */
10045
/* XXX: could support exotic global object. */
10046
static int JS_DefineGlobalFunction(JSContext *ctx, JSAtom prop,
10047
                                   JSValueConst func, int def_flags)
10048
0
{
10049
10050
0
    JSObject *p;
10051
0
    JSShapeProperty *prs;
10052
0
    int flags;
10053
10054
0
    p = JS_VALUE_GET_OBJ(ctx->global_obj);
10055
0
    prs = find_own_property1(p, prop);
10056
0
    flags = JS_PROP_HAS_VALUE | JS_PROP_THROW;
10057
0
    if (!prs || (prs->flags & JS_PROP_CONFIGURABLE)) {
10058
0
        flags |= JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | def_flags |
10059
0
            JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE;
10060
0
    }
10061
0
    if (JS_DefineProperty(ctx, ctx->global_obj, prop, func,
10062
0
                          JS_UNDEFINED, JS_UNDEFINED, flags) < 0)
10063
0
        return -1;
10064
0
    return 0;
10065
0
}
10066
10067
static JSValue JS_GetGlobalVar(JSContext *ctx, JSAtom prop,
10068
                               BOOL throw_ref_error)
10069
5
{
10070
5
    JSObject *p;
10071
5
    JSShapeProperty *prs;
10072
5
    JSProperty *pr;
10073
10074
    /* no exotic behavior is possible in global_var_obj */
10075
5
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
10076
5
    prs = find_own_property(&pr, p, prop);
10077
5
    if (prs) {
10078
        /* XXX: should handle JS_PROP_TMASK properties */
10079
0
        if (unlikely(JS_IsUninitialized(pr->u.value)))
10080
0
            return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
10081
0
        return JS_DupValue(ctx, pr->u.value);
10082
0
    }
10083
5
    return JS_GetPropertyInternal(ctx, ctx->global_obj, prop,
10084
5
                                 ctx->global_obj, throw_ref_error);
10085
5
}
10086
10087
/* construct a reference to a global variable */
10088
static int JS_GetGlobalVarRef(JSContext *ctx, JSAtom prop, JSValue *sp)
10089
0
{
10090
0
    JSObject *p;
10091
0
    JSShapeProperty *prs;
10092
0
    JSProperty *pr;
10093
10094
    /* no exotic behavior is possible in global_var_obj */
10095
0
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
10096
0
    prs = find_own_property(&pr, p, prop);
10097
0
    if (prs) {
10098
        /* XXX: should handle JS_PROP_AUTOINIT properties? */
10099
        /* XXX: conformance: do these tests in
10100
           OP_put_var_ref/OP_get_var_ref ? */
10101
0
        if (unlikely(JS_IsUninitialized(pr->u.value))) {
10102
0
            JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
10103
0
            return -1;
10104
0
        }
10105
0
        if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) {
10106
0
            return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop);
10107
0
        }
10108
0
        sp[0] = JS_DupValue(ctx, ctx->global_var_obj);
10109
0
    } else {
10110
0
        int ret;
10111
0
        ret = JS_HasProperty(ctx, ctx->global_obj, prop);
10112
0
        if (ret < 0)
10113
0
            return -1;
10114
0
        if (ret) {
10115
0
            sp[0] = JS_DupValue(ctx, ctx->global_obj);
10116
0
        } else {
10117
0
            sp[0] = JS_UNDEFINED;
10118
0
        }
10119
0
    }
10120
0
    sp[1] = JS_AtomToValue(ctx, prop);
10121
0
    return 0;
10122
0
}
10123
10124
/* use for strict variable access: test if the variable exists */
10125
static int JS_CheckGlobalVar(JSContext *ctx, JSAtom prop)
10126
0
{
10127
0
    JSObject *p;
10128
0
    JSShapeProperty *prs;
10129
0
    int ret;
10130
10131
    /* no exotic behavior is possible in global_var_obj */
10132
0
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
10133
0
    prs = find_own_property1(p, prop);
10134
0
    if (prs) {
10135
0
        ret = TRUE;
10136
0
    } else {
10137
0
        ret = JS_HasProperty(ctx, ctx->global_obj, prop);
10138
0
        if (ret < 0)
10139
0
            return -1;
10140
0
    }
10141
0
    return ret;
10142
0
}
10143
10144
/* flag = 0: normal variable write
10145
   flag = 1: initialize lexical variable
10146
   flag = 2: normal variable write, strict check was done before
10147
*/
10148
static int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val,
10149
                           int flag)
10150
0
{
10151
0
    JSObject *p;
10152
0
    JSShapeProperty *prs;
10153
0
    JSProperty *pr;
10154
0
    int flags;
10155
10156
    /* no exotic behavior is possible in global_var_obj */
10157
0
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
10158
0
    prs = find_own_property(&pr, p, prop);
10159
0
    if (prs) {
10160
        /* XXX: should handle JS_PROP_AUTOINIT properties? */
10161
0
        if (flag != 1) {
10162
0
            if (unlikely(JS_IsUninitialized(pr->u.value))) {
10163
0
                JS_FreeValue(ctx, val);
10164
0
                JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);
10165
0
                return -1;
10166
0
            }
10167
0
            if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) {
10168
0
                JS_FreeValue(ctx, val);
10169
0
                return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop);
10170
0
            }
10171
0
        }
10172
0
        set_value(ctx, &pr->u.value, val);
10173
0
        return 0;
10174
0
    }
10175
    /* XXX: add a fast path where the property exists and the object
10176
       is not exotic. Otherwise do as in OP_put_ref_value and remove
10177
       JS_PROP_NO_ADD which is no longer necessary */
10178
0
    flags = JS_PROP_THROW_STRICT;
10179
0
    if (is_strict_mode(ctx))
10180
0
        flags |= JS_PROP_NO_ADD;
10181
0
    return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, ctx->global_obj, flags);
10182
0
}
10183
10184
/* return -1, FALSE or TRUE */
10185
static int JS_DeleteGlobalVar(JSContext *ctx, JSAtom prop)
10186
0
{
10187
0
    JSObject *p;
10188
0
    JSShapeProperty *prs;
10189
0
    JSProperty *pr;
10190
0
    int ret;
10191
10192
    /* 9.1.1.4.7 DeleteBinding ( N ) */
10193
0
    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);
10194
0
    prs = find_own_property(&pr, p, prop);
10195
0
    if (prs)
10196
0
        return FALSE; /* lexical variables cannot be deleted */
10197
0
    ret = JS_HasProperty(ctx, ctx->global_obj, prop);
10198
0
    if (ret < 0)
10199
0
        return -1;
10200
0
    if (ret) {
10201
0
        return JS_DeleteProperty(ctx, ctx->global_obj, prop, 0);
10202
0
    } else {
10203
0
        return TRUE;
10204
0
    }
10205
0
}
10206
10207
/* return -1, FALSE or TRUE. return FALSE if not configurable or
10208
   invalid object. return -1 in case of exception.
10209
   flags can be 0, JS_PROP_THROW or JS_PROP_THROW_STRICT */
10210
int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags)
10211
0
{
10212
0
    JSValue obj1;
10213
0
    JSObject *p;
10214
0
    int res;
10215
10216
0
    obj1 = JS_ToObject(ctx, obj);
10217
0
    if (JS_IsException(obj1))
10218
0
        return -1;
10219
0
    p = JS_VALUE_GET_OBJ(obj1);
10220
0
    res = delete_property(ctx, p, prop);
10221
0
    JS_FreeValue(ctx, obj1);
10222
0
    if (res != FALSE)
10223
0
        return res;
10224
0
    if ((flags & JS_PROP_THROW) ||
10225
0
        ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
10226
0
        JS_ThrowTypeError(ctx, "could not delete property");
10227
0
        return -1;
10228
0
    }
10229
0
    return FALSE;
10230
0
}
10231
10232
int JS_DeletePropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, int flags)
10233
0
{
10234
0
    JSAtom prop;
10235
0
    int res;
10236
10237
0
    if ((uint64_t)idx <= JS_ATOM_MAX_INT) {
10238
        /* fast path for fast arrays */
10239
0
        return JS_DeleteProperty(ctx, obj, __JS_AtomFromUInt32(idx), flags);
10240
0
    }
10241
0
    prop = JS_NewAtomInt64(ctx, idx);
10242
0
    if (prop == JS_ATOM_NULL)
10243
0
        return -1;
10244
0
    res = JS_DeleteProperty(ctx, obj, prop, flags);
10245
0
    JS_FreeAtom(ctx, prop);
10246
0
    return res;
10247
0
}
10248
10249
BOOL JS_IsFunction(JSContext *ctx, JSValueConst val)
10250
166
{
10251
166
    JSObject *p;
10252
166
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
10253
68
        return FALSE;
10254
98
    p = JS_VALUE_GET_OBJ(val);
10255
98
    switch(p->class_id) {
10256
0
    case JS_CLASS_BYTECODE_FUNCTION:
10257
0
        return TRUE;
10258
0
    case JS_CLASS_PROXY:
10259
0
        return p->u.proxy_data->is_func;
10260
98
    default:
10261
98
        return (ctx->rt->class_array[p->class_id].call != NULL);
10262
98
    }
10263
98
}
10264
10265
BOOL JS_IsCFunction(JSContext *ctx, JSValueConst val, JSCFunction *func, int magic)
10266
0
{
10267
0
    JSObject *p;
10268
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
10269
0
        return FALSE;
10270
0
    p = JS_VALUE_GET_OBJ(val);
10271
0
    if (p->class_id == JS_CLASS_C_FUNCTION)
10272
0
        return (p->u.cfunc.c_function.generic == func && p->u.cfunc.magic == magic);
10273
0
    else
10274
0
        return FALSE;
10275
0
}
10276
10277
BOOL JS_IsConstructor(JSContext *ctx, JSValueConst val)
10278
0
{
10279
0
    JSObject *p;
10280
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
10281
0
        return FALSE;
10282
0
    p = JS_VALUE_GET_OBJ(val);
10283
0
    return p->is_constructor;
10284
0
}
10285
10286
BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, BOOL val)
10287
2
{
10288
2
    JSObject *p;
10289
2
    if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
10290
0
        return FALSE;
10291
2
    p = JS_VALUE_GET_OBJ(func_obj);
10292
2
    p->is_constructor = val;
10293
2
    return TRUE;
10294
2
}
10295
10296
BOOL JS_IsError(JSContext *ctx, JSValueConst val)
10297
0
{
10298
0
    JSObject *p;
10299
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
10300
0
        return FALSE;
10301
0
    p = JS_VALUE_GET_OBJ(val);
10302
0
    return (p->class_id == JS_CLASS_ERROR);
10303
0
}
10304
10305
/* must be called after JS_Throw() */
10306
void JS_SetUncatchableException(JSContext *ctx, BOOL flag)
10307
0
{
10308
0
    ctx->rt->current_exception_is_uncatchable = flag;
10309
0
}
10310
10311
void JS_SetOpaque(JSValue obj, void *opaque)
10312
30
{
10313
30
   JSObject *p;
10314
30
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
10315
30
        p = JS_VALUE_GET_OBJ(obj);
10316
30
        p->u.opaque = opaque;
10317
30
    }
10318
30
}
10319
10320
/* return NULL if not an object of class class_id */
10321
void *JS_GetOpaque(JSValueConst obj, JSClassID class_id)
10322
51
{
10323
51
    JSObject *p;
10324
51
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
10325
1
        return NULL;
10326
50
    p = JS_VALUE_GET_OBJ(obj);
10327
50
    if (p->class_id != class_id)
10328
0
        return NULL;
10329
50
    return p->u.opaque;
10330
50
}
10331
10332
void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id)
10333
0
{
10334
0
    void *p = JS_GetOpaque(obj, class_id);
10335
0
    if (unlikely(!p)) {
10336
0
        JS_ThrowTypeErrorInvalidClass(ctx, class_id);
10337
0
    }
10338
0
    return p;
10339
0
}
10340
10341
void *JS_GetAnyOpaque(JSValueConst obj, JSClassID *class_id)
10342
0
{
10343
0
    JSObject *p;
10344
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
10345
0
        *class_id = 0;
10346
0
        return NULL;
10347
0
    }
10348
0
    p = JS_VALUE_GET_OBJ(obj);
10349
0
    *class_id = p->class_id;
10350
0
    return p->u.opaque;
10351
0
}
10352
10353
static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint)
10354
0
{
10355
0
    int i;
10356
0
    BOOL force_ordinary;
10357
10358
0
    JSAtom method_name;
10359
0
    JSValue method, ret;
10360
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
10361
0
        return val;
10362
0
    force_ordinary = hint & HINT_FORCE_ORDINARY;
10363
0
    hint &= ~HINT_FORCE_ORDINARY;
10364
0
    if (!force_ordinary) {
10365
0
        method = JS_GetProperty(ctx, val, JS_ATOM_Symbol_toPrimitive);
10366
0
        if (JS_IsException(method))
10367
0
            goto exception;
10368
        /* ECMA says *If exoticToPrim is not undefined* but tests in
10369
           test262 use null as a non callable converter */
10370
0
        if (!JS_IsUndefined(method) && !JS_IsNull(method)) {
10371
0
            JSAtom atom;
10372
0
            JSValue arg;
10373
0
            switch(hint) {
10374
0
            case HINT_STRING:
10375
0
                atom = JS_ATOM_string;
10376
0
                break;
10377
0
            case HINT_NUMBER:
10378
0
                atom = JS_ATOM_number;
10379
0
                break;
10380
0
            default:
10381
0
            case HINT_NONE:
10382
0
                atom = JS_ATOM_default;
10383
0
                break;
10384
0
            }
10385
0
            arg = JS_AtomToString(ctx, atom);
10386
0
            ret = JS_CallFree(ctx, method, val, 1, (JSValueConst *)&arg);
10387
0
            JS_FreeValue(ctx, arg);
10388
0
            if (JS_IsException(ret))
10389
0
                goto exception;
10390
0
            JS_FreeValue(ctx, val);
10391
0
            if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT)
10392
0
                return ret;
10393
0
            JS_FreeValue(ctx, ret);
10394
0
            return JS_ThrowTypeError(ctx, "toPrimitive");
10395
0
        }
10396
0
    }
10397
0
    if (hint != HINT_STRING)
10398
0
        hint = HINT_NUMBER;
10399
0
    for(i = 0; i < 2; i++) {
10400
0
        if ((i ^ hint) == 0) {
10401
0
            method_name = JS_ATOM_toString;
10402
0
        } else {
10403
0
            method_name = JS_ATOM_valueOf;
10404
0
        }
10405
0
        method = JS_GetProperty(ctx, val, method_name);
10406
0
        if (JS_IsException(method))
10407
0
            goto exception;
10408
0
        if (JS_IsFunction(ctx, method)) {
10409
0
            ret = JS_CallFree(ctx, method, val, 0, NULL);
10410
0
            if (JS_IsException(ret))
10411
0
                goto exception;
10412
0
            if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
10413
0
                JS_FreeValue(ctx, val);
10414
0
                return ret;
10415
0
            }
10416
0
            JS_FreeValue(ctx, ret);
10417
0
        } else {
10418
0
            JS_FreeValue(ctx, method);
10419
0
        }
10420
0
    }
10421
0
    JS_ThrowTypeError(ctx, "toPrimitive");
10422
0
exception:
10423
0
    JS_FreeValue(ctx, val);
10424
0
    return JS_EXCEPTION;
10425
0
}
10426
10427
static JSValue JS_ToPrimitive(JSContext *ctx, JSValueConst val, int hint)
10428
0
{
10429
0
    return JS_ToPrimitiveFree(ctx, JS_DupValue(ctx, val), hint);
10430
0
}
10431
10432
void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj)
10433
0
{
10434
0
    JSObject *p;
10435
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
10436
0
        return;
10437
0
    p = JS_VALUE_GET_OBJ(obj);
10438
0
    p->is_HTMLDDA = TRUE;
10439
0
}
10440
10441
static inline BOOL JS_IsHTMLDDA(JSContext *ctx, JSValueConst obj)
10442
0
{
10443
0
    JSObject *p;
10444
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
10445
0
        return FALSE;
10446
0
    p = JS_VALUE_GET_OBJ(obj);
10447
0
    return p->is_HTMLDDA;
10448
0
}
10449
10450
static int JS_ToBoolFree(JSContext *ctx, JSValue val)
10451
0
{
10452
0
    uint32_t tag = JS_VALUE_GET_TAG(val);
10453
0
    switch(tag) {
10454
0
    case JS_TAG_INT:
10455
0
        return JS_VALUE_GET_INT(val) != 0;
10456
0
    case JS_TAG_BOOL:
10457
0
    case JS_TAG_NULL:
10458
0
    case JS_TAG_UNDEFINED:
10459
0
        return JS_VALUE_GET_INT(val);
10460
0
    case JS_TAG_EXCEPTION:
10461
0
        return -1;
10462
0
    case JS_TAG_STRING:
10463
0
        {
10464
0
            BOOL ret = JS_VALUE_GET_STRING(val)->len != 0;
10465
0
            JS_FreeValue(ctx, val);
10466
0
            return ret;
10467
0
        }
10468
0
    case JS_TAG_STRING_ROPE:
10469
0
        {
10470
0
            BOOL ret = JS_VALUE_GET_STRING_ROPE(val)->len != 0;
10471
0
            JS_FreeValue(ctx, val);
10472
0
            return ret;
10473
0
        }
10474
0
    case JS_TAG_SHORT_BIG_INT:
10475
0
        return JS_VALUE_GET_SHORT_BIG_INT(val) != 0;
10476
0
    case JS_TAG_BIG_INT:
10477
0
        {
10478
0
            JSBigInt *p = JS_VALUE_GET_PTR(val);
10479
0
            BOOL ret;
10480
0
            int i;
10481
            
10482
            /* fail safe: we assume it is not necessarily
10483
               normalized. Beginning from the MSB ensures that the
10484
               test is fast. */
10485
0
            ret = FALSE;
10486
0
            for(i = p->len - 1; i >= 0; i--) {
10487
0
                if (p->tab[i] != 0) {
10488
0
                    ret = TRUE;
10489
0
                    break;
10490
0
                }
10491
0
            }
10492
0
            JS_FreeValue(ctx, val);
10493
0
            return ret;
10494
0
        }
10495
0
    case JS_TAG_OBJECT:
10496
0
        {
10497
0
            JSObject *p = JS_VALUE_GET_OBJ(val);
10498
0
            BOOL ret;
10499
0
            ret = !p->is_HTMLDDA;
10500
0
            JS_FreeValue(ctx, val);
10501
0
            return ret;
10502
0
        }
10503
0
        break;
10504
0
    default:
10505
0
        if (JS_TAG_IS_FLOAT64(tag)) {
10506
0
            double d = JS_VALUE_GET_FLOAT64(val);
10507
0
            return !isnan(d) && d != 0;
10508
0
        } else {
10509
0
            JS_FreeValue(ctx, val);
10510
0
            return TRUE;
10511
0
        }
10512
0
    }
10513
0
}
10514
10515
int JS_ToBool(JSContext *ctx, JSValueConst val)
10516
0
{
10517
0
    return JS_ToBoolFree(ctx, JS_DupValue(ctx, val));
10518
0
}
10519
10520
static int skip_spaces(const char *pc)
10521
0
{
10522
0
    const uint8_t *p, *p_next, *p_start;
10523
0
    uint32_t c;
10524
10525
0
    p = p_start = (const uint8_t *)pc;
10526
0
    for (;;) {
10527
0
        c = *p;
10528
0
        if (c < 128) {
10529
0
            if (!((c >= 0x09 && c <= 0x0d) || (c == 0x20)))
10530
0
                break;
10531
0
            p++;
10532
0
        } else {
10533
0
            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
10534
0
            if (!lre_is_space(c))
10535
0
                break;
10536
0
            p = p_next;
10537
0
        }
10538
0
    }
10539
0
    return p - p_start;
10540
0
}
10541
10542
static inline int to_digit(int c)
10543
1.04M
{
10544
1.04M
    if (c >= '0' && c <= '9')
10545
21
        return c - '0';
10546
1.04M
    else if (c >= 'A' && c <= 'Z')
10547
0
        return c - 'A' + 10;
10548
1.04M
    else if (c >= 'a' && c <= 'z')
10549
1.04M
        return c - 'a' + 10;
10550
1
    else
10551
1
        return 36;
10552
1.04M
}
10553
10554
/* bigint support */
10555
10556
0
#define JS_BIGINT_MAX_SIZE ((1024 * 1024) / JS_LIMB_BITS) /* in limbs */
10557
10558
/* it is currently assumed that JS_SHORT_BIG_INT_BITS = JS_LIMB_BITS */
10559
#if JS_SHORT_BIG_INT_BITS == 32
10560
#define JS_SHORT_BIG_INT_MIN INT32_MIN
10561
#define JS_SHORT_BIG_INT_MAX INT32_MAX
10562
#elif JS_SHORT_BIG_INT_BITS == 64
10563
0
#define JS_SHORT_BIG_INT_MIN INT64_MIN
10564
0
#define JS_SHORT_BIG_INT_MAX INT64_MAX
10565
#else
10566
#error unsupported
10567
#endif
10568
10569
0
#define ADDC(res, carry_out, op1, op2, carry_in)        \
10570
0
do {                                                    \
10571
0
    js_limb_t __v, __a, __k, __k1;                      \
10572
0
    __v = (op1);                                        \
10573
0
    __a = __v + (op2);                                  \
10574
0
    __k1 = __a < __v;                                   \
10575
0
    __k = (carry_in);                                   \
10576
0
    __a = __a + __k;                                    \
10577
0
    carry_out = (__a < __k) | __k1;                     \
10578
0
    res = __a;                                          \
10579
0
} while (0)
10580
10581
#if JS_LIMB_BITS == 32
10582
/* a != 0 */
10583
static inline js_limb_t js_limb_clz(js_limb_t a)
10584
{
10585
    return clz32(a);
10586
}
10587
#else
10588
static inline js_limb_t js_limb_clz(js_limb_t a)
10589
0
{
10590
0
    return clz64(a);
10591
0
}
10592
#endif
10593
10594
/* handle a = 0 too */
10595
static inline js_limb_t js_limb_safe_clz(js_limb_t a)
10596
0
{
10597
0
    if (a == 0)
10598
0
        return JS_LIMB_BITS;
10599
0
    else
10600
0
        return js_limb_clz(a);
10601
0
}
10602
10603
static js_limb_t mp_add(js_limb_t *res, const js_limb_t *op1, const js_limb_t *op2,
10604
                     js_limb_t n, js_limb_t carry)
10605
0
{
10606
0
    int i;
10607
0
    for(i = 0;i < n; i++) {
10608
0
        ADDC(res[i], carry, op1[i], op2[i], carry);
10609
0
    }
10610
0
    return carry;
10611
0
}
10612
10613
static js_limb_t mp_sub(js_limb_t *res, const js_limb_t *op1, const js_limb_t *op2,
10614
                        int n, js_limb_t carry)
10615
0
{
10616
0
    int i;
10617
0
    js_limb_t k, a, v, k1;
10618
10619
0
    k = carry;
10620
0
    for(i=0;i<n;i++) {
10621
0
        v = op1[i];
10622
0
        a = v - op2[i];
10623
0
        k1 = a > v;
10624
0
        v = a - k;
10625
0
        k = (v > a) | k1;
10626
0
        res[i] = v;
10627
0
    }
10628
0
    return k;
10629
0
}
10630
10631
/* compute 0 - op2. carry = 0 or 1. */
10632
static js_limb_t mp_neg(js_limb_t *res, const js_limb_t *op2, int n)
10633
0
{
10634
0
    int i;
10635
0
    js_limb_t v, carry;
10636
10637
0
    carry = 1;
10638
0
    for(i=0;i<n;i++) {
10639
0
        v = ~op2[i] + carry;
10640
0
        carry = v < carry;
10641
0
        res[i] = v;
10642
0
    }
10643
0
    return carry;
10644
0
}
10645
10646
/* tabr[] = taba[] * b + l. Return the high carry */
10647
static js_limb_t mp_mul1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,
10648
                      js_limb_t b, js_limb_t l)
10649
0
{
10650
0
    js_limb_t i;
10651
0
    js_dlimb_t t;
10652
10653
0
    for(i = 0; i < n; i++) {
10654
0
        t = (js_dlimb_t)taba[i] * (js_dlimb_t)b + l;
10655
0
        tabr[i] = t;
10656
0
        l = t >> JS_LIMB_BITS;
10657
0
    }
10658
0
    return l;
10659
0
}
10660
10661
static js_limb_t mp_div1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,
10662
                      js_limb_t b, js_limb_t r)
10663
0
{
10664
0
    js_slimb_t i;
10665
0
    js_dlimb_t a1;
10666
0
    for(i = n - 1; i >= 0; i--) {
10667
0
        a1 = ((js_dlimb_t)r << JS_LIMB_BITS) | taba[i];
10668
0
        tabr[i] = a1 / b;
10669
0
        r = a1 % b;
10670
0
    }
10671
0
    return r;
10672
0
}
10673
10674
/* tabr[] += taba[] * b, return the high word. */
10675
static js_limb_t mp_add_mul1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,
10676
                          js_limb_t b)
10677
0
{
10678
0
    js_limb_t i, l;
10679
0
    js_dlimb_t t;
10680
10681
0
    l = 0;
10682
0
    for(i = 0; i < n; i++) {
10683
0
        t = (js_dlimb_t)taba[i] * (js_dlimb_t)b + l + tabr[i];
10684
0
        tabr[i] = t;
10685
0
        l = t >> JS_LIMB_BITS;
10686
0
    }
10687
0
    return l;
10688
0
}
10689
10690
/* size of the result : op1_size + op2_size. */
10691
static void mp_mul_basecase(js_limb_t *result,
10692
                            const js_limb_t *op1, js_limb_t op1_size,
10693
                            const js_limb_t *op2, js_limb_t op2_size)
10694
0
{
10695
0
    int i;
10696
0
    js_limb_t r;
10697
    
10698
0
    result[op1_size] = mp_mul1(result, op1, op1_size, op2[0], 0);
10699
0
    for(i=1;i<op2_size;i++) {
10700
0
        r = mp_add_mul1(result + i, op1, op1_size, op2[i]);
10701
0
        result[i + op1_size] = r;
10702
0
    }
10703
0
}
10704
10705
/* tabr[] -= taba[] * b. Return the value to substract to the high
10706
   word. */
10707
static js_limb_t mp_sub_mul1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,
10708
                          js_limb_t b)
10709
0
{
10710
0
    js_limb_t i, l;
10711
0
    js_dlimb_t t;
10712
10713
0
    l = 0;
10714
0
    for(i = 0; i < n; i++) {
10715
0
        t = tabr[i] - (js_dlimb_t)taba[i] * (js_dlimb_t)b - l;
10716
0
        tabr[i] = t;
10717
0
        l = -(t >> JS_LIMB_BITS);
10718
0
    }
10719
0
    return l;
10720
0
}
10721
10722
/* WARNING: d must be >= 2^(JS_LIMB_BITS-1) */
10723
static inline js_limb_t udiv1norm_init(js_limb_t d)
10724
0
{
10725
0
    js_limb_t a0, a1;
10726
0
    a1 = -d - 1;
10727
0
    a0 = -1;
10728
0
    return (((js_dlimb_t)a1 << JS_LIMB_BITS) | a0) / d;
10729
0
}
10730
10731
/* return the quotient and the remainder in '*pr'of 'a1*2^JS_LIMB_BITS+a0
10732
   / d' with 0 <= a1 < d. */
10733
static inline js_limb_t udiv1norm(js_limb_t *pr, js_limb_t a1, js_limb_t a0,
10734
                                js_limb_t d, js_limb_t d_inv)
10735
0
{
10736
0
    js_limb_t n1m, n_adj, q, r, ah;
10737
0
    js_dlimb_t a;
10738
0
    n1m = ((js_slimb_t)a0 >> (JS_LIMB_BITS - 1));
10739
0
    n_adj = a0 + (n1m & d);
10740
0
    a = (js_dlimb_t)d_inv * (a1 - n1m) + n_adj;
10741
0
    q = (a >> JS_LIMB_BITS) + a1;
10742
    /* compute a - q * r and update q so that the remainder is\
10743
       between 0 and d - 1 */
10744
0
    a = ((js_dlimb_t)a1 << JS_LIMB_BITS) | a0;
10745
0
    a = a - (js_dlimb_t)q * d - d;
10746
0
    ah = a >> JS_LIMB_BITS;
10747
0
    q += 1 + ah;
10748
0
    r = (js_limb_t)a + (ah & d);
10749
0
    *pr = r;
10750
0
    return q;
10751
0
}
10752
10753
0
#define UDIV1NORM_THRESHOLD 3
10754
10755
/* b must be >= 1 << (JS_LIMB_BITS - 1) */
10756
static js_limb_t mp_div1norm(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,
10757
                          js_limb_t b, js_limb_t r)
10758
0
{
10759
0
    js_slimb_t i;
10760
10761
0
    if (n >= UDIV1NORM_THRESHOLD) {
10762
0
        js_limb_t b_inv;
10763
0
        b_inv = udiv1norm_init(b);
10764
0
        for(i = n - 1; i >= 0; i--) {
10765
0
            tabr[i] = udiv1norm(&r, r, taba[i], b, b_inv);
10766
0
        }
10767
0
    } else {
10768
0
        js_dlimb_t a1;
10769
0
        for(i = n - 1; i >= 0; i--) {
10770
0
            a1 = ((js_dlimb_t)r << JS_LIMB_BITS) | taba[i];
10771
0
            tabr[i] = a1 / b;
10772
0
            r = a1 % b;
10773
0
        }
10774
0
    }
10775
0
    return r;
10776
0
}
10777
10778
/* base case division: divides taba[0..na-1] by tabb[0..nb-1]. tabb[nb
10779
   - 1] must be >= 1 << (JS_LIMB_BITS - 1). na - nb must be >= 0. 'taba'
10780
   is modified and contains the remainder (nb limbs). tabq[0..na-nb]
10781
   contains the quotient with tabq[na - nb] <= 1. */
10782
static void mp_divnorm(js_limb_t *tabq, js_limb_t *taba, js_limb_t na,
10783
                       const js_limb_t *tabb, js_limb_t nb)
10784
0
{
10785
0
    js_limb_t r, a, c, q, v, b1, b1_inv, n, dummy_r;
10786
0
    int i, j;
10787
10788
0
    b1 = tabb[nb - 1];
10789
0
    if (nb == 1) {
10790
0
        taba[0] = mp_div1norm(tabq, taba, na, b1, 0);
10791
0
        return;
10792
0
    }
10793
0
    n = na - nb;
10794
10795
0
    if (n >= UDIV1NORM_THRESHOLD)
10796
0
        b1_inv = udiv1norm_init(b1);
10797
0
    else
10798
0
        b1_inv = 0;
10799
10800
    /* first iteration: the quotient is only 0 or 1 */
10801
0
    q = 1;
10802
0
    for(j = nb - 1; j >= 0; j--) {
10803
0
        if (taba[n + j] != tabb[j]) {
10804
0
            if (taba[n + j] < tabb[j])
10805
0
                q = 0;
10806
0
            break;
10807
0
        }
10808
0
    }
10809
0
    tabq[n] = q;
10810
0
    if (q) {
10811
0
        mp_sub(taba + n, taba + n, tabb, nb, 0);
10812
0
    }
10813
10814
0
    for(i = n - 1; i >= 0; i--) {
10815
0
        if (unlikely(taba[i + nb] >= b1)) {
10816
0
            q = -1;
10817
0
        } else if (b1_inv) {
10818
0
            q = udiv1norm(&dummy_r, taba[i + nb], taba[i + nb - 1], b1, b1_inv);
10819
0
        } else {
10820
0
            js_dlimb_t al;
10821
0
            al = ((js_dlimb_t)taba[i + nb] << JS_LIMB_BITS) | taba[i + nb - 1];
10822
0
            q = al / b1;
10823
0
            r = al % b1;
10824
0
        }
10825
0
        r = mp_sub_mul1(taba + i, tabb, nb, q);
10826
10827
0
        v = taba[i + nb];
10828
0
        a = v - r;
10829
0
        c = (a > v);
10830
0
        taba[i + nb] = a;
10831
10832
0
        if (c != 0) {
10833
            /* negative result */
10834
0
            for(;;) {
10835
0
                q--;
10836
0
                c = mp_add(taba + i, taba + i, tabb, nb, 0);
10837
                /* propagate carry and test if positive result */
10838
0
                if (c != 0) {
10839
0
                    if (++taba[i + nb] == 0) {
10840
0
                        break;
10841
0
                    }
10842
0
                }
10843
0
            }
10844
0
        }
10845
0
        tabq[i] = q;
10846
0
    }
10847
0
}
10848
10849
/* 1 <= shift <= JS_LIMB_BITS - 1 */
10850
static js_limb_t mp_shl(js_limb_t *tabr, const js_limb_t *taba, int n,
10851
                        int shift)
10852
0
{
10853
0
    int i;
10854
0
    js_limb_t l, v;
10855
0
    l = 0;
10856
0
    for(i = 0; i < n; i++) {
10857
0
        v = taba[i];
10858
0
        tabr[i] = (v << shift) | l;
10859
0
        l = v >> (JS_LIMB_BITS - shift);
10860
0
    }
10861
0
    return l;
10862
0
}
10863
10864
/* r = (a + high*B^n) >> shift. Return the remainder r (0 <= r < 2^shift). 
10865
   1 <= shift <= LIMB_BITS - 1 */
10866
static js_limb_t mp_shr(js_limb_t *tab_r, const js_limb_t *tab, int n,
10867
                        int shift, js_limb_t high)
10868
0
{
10869
0
    int i;
10870
0
    js_limb_t l, a;
10871
10872
0
    l = high;
10873
0
    for(i = n - 1; i >= 0; i--) {
10874
0
        a = tab[i];
10875
0
        tab_r[i] = (a >> shift) | (l << (JS_LIMB_BITS - shift));
10876
0
        l = a;
10877
0
    }
10878
0
    return l & (((js_limb_t)1 << shift) - 1);
10879
0
}
10880
10881
static JSBigInt *js_bigint_new(JSContext *ctx, int len)
10882
0
{
10883
0
    JSBigInt *r;
10884
0
    if (len > JS_BIGINT_MAX_SIZE) {
10885
0
        JS_ThrowRangeError(ctx, "BigInt is too large to allocate");
10886
0
        return NULL;
10887
0
    }
10888
0
    r = js_malloc(ctx, sizeof(JSBigInt) + len * sizeof(js_limb_t));
10889
0
    if (!r)
10890
0
        return NULL;
10891
0
    r->header.ref_count = 1;
10892
0
    r->len = len;
10893
0
    return r;
10894
0
}
10895
10896
static JSBigInt *js_bigint_set_si(JSBigIntBuf *buf, js_slimb_t a)
10897
0
{
10898
0
    JSBigInt *r = (JSBigInt *)buf->big_int_buf;
10899
0
    r->header.ref_count = 0; /* fail safe */
10900
0
    r->len = 1;
10901
0
    r->tab[0] = a;
10902
0
    return r;
10903
0
}
10904
10905
static JSBigInt *js_bigint_set_si64(JSBigIntBuf *buf, int64_t a)
10906
0
{
10907
0
#if JS_LIMB_BITS == 64
10908
0
    return js_bigint_set_si(buf, a);
10909
#else
10910
    JSBigInt *r = (JSBigInt *)buf->big_int_buf;
10911
    r->header.ref_count = 0; /* fail safe */
10912
    if (a >= INT32_MIN && a <= INT32_MAX) {
10913
        r->len = 1;
10914
        r->tab[0] = a;
10915
    } else {
10916
        r->len = 2;
10917
        r->tab[0] = a;
10918
        r->tab[1] = a >> JS_LIMB_BITS;
10919
    }
10920
    return r;
10921
#endif
10922
0
}
10923
10924
/* val must be a short big int */
10925
static JSBigInt *js_bigint_set_short(JSBigIntBuf *buf, JSValueConst val)
10926
0
{
10927
0
    return js_bigint_set_si(buf, JS_VALUE_GET_SHORT_BIG_INT(val));
10928
0
}
10929
10930
static __maybe_unused void js_bigint_dump1(JSContext *ctx, const char *str,
10931
                                           const js_limb_t *tab, int len)
10932
0
{
10933
0
    int i;
10934
0
    printf("%s: ", str);
10935
0
    for(i = len - 1; i >= 0; i--) {
10936
0
#if JS_LIMB_BITS == 32
10937
0
        printf(" %08x", tab[i]);
10938
0
#else
10939
0
        printf(" %016" PRIx64, tab[i]);
10940
0
#endif
10941
0
    }
10942
0
    printf("\n");
10943
0
}
10944
10945
static __maybe_unused void js_bigint_dump(JSContext *ctx, const char *str,
10946
                                          const JSBigInt *p)
10947
0
{
10948
0
    js_bigint_dump1(ctx, str, p->tab, p->len);
10949
0
}
10950
10951
static JSBigInt *js_bigint_new_si(JSContext *ctx, js_slimb_t a)
10952
0
{
10953
0
    JSBigInt *r;
10954
0
    r = js_bigint_new(ctx, 1);
10955
0
    if (!r)
10956
0
        return NULL;
10957
0
    r->tab[0] = a;
10958
0
    return r;
10959
0
}
10960
10961
static JSBigInt *js_bigint_new_si64(JSContext *ctx, int64_t a)
10962
0
{
10963
0
#if JS_LIMB_BITS == 64
10964
0
    return js_bigint_new_si(ctx, a);
10965
#else
10966
    if (a >= INT32_MIN && a <= INT32_MAX) {
10967
        return js_bigint_new_si(ctx, a);
10968
    } else {
10969
        JSBigInt *r;
10970
        r = js_bigint_new(ctx, 2);
10971
        if (!r)
10972
            return NULL;
10973
        r->tab[0] = a;
10974
        r->tab[1] = a >> 32;
10975
        return r;
10976
    }
10977
#endif
10978
0
}
10979
10980
static JSBigInt *js_bigint_new_ui64(JSContext *ctx, uint64_t a)
10981
0
{
10982
0
    if (a <= INT64_MAX) {
10983
0
        return js_bigint_new_si64(ctx, a);
10984
0
    } else {
10985
0
        JSBigInt *r;
10986
0
        r = js_bigint_new(ctx, (65 + JS_LIMB_BITS - 1) / JS_LIMB_BITS);
10987
0
        if (!r)
10988
0
            return NULL;
10989
0
#if JS_LIMB_BITS == 64
10990
0
        r->tab[0] = a;
10991
0
        r->tab[1] = 0;
10992
#else
10993
        r->tab[0] = a;
10994
        r->tab[1] = a >> 32;
10995
        r->tab[2] = 0;
10996
#endif
10997
0
        return r;
10998
0
    }
10999
0
}
11000
11001
static JSBigInt *js_bigint_new_di(JSContext *ctx, js_sdlimb_t a)
11002
0
{
11003
0
    JSBigInt *r;
11004
0
    if (a == (js_slimb_t)a) {
11005
0
        r = js_bigint_new(ctx, 1);
11006
0
        if (!r)
11007
0
            return NULL;
11008
0
        r->tab[0] = a;
11009
0
    } else {
11010
0
        r = js_bigint_new(ctx, 2);
11011
0
        if (!r)
11012
0
            return NULL;
11013
0
        r->tab[0] = a;
11014
0
        r->tab[1] = a >> JS_LIMB_BITS;
11015
0
    }
11016
0
    return r;
11017
0
}
11018
11019
/* Remove redundant high order limbs. Warning: 'a' may be
11020
   reallocated. Can never fail.
11021
*/
11022
static JSBigInt *js_bigint_normalize1(JSContext *ctx, JSBigInt *a, int l)
11023
0
{
11024
0
    js_limb_t v;
11025
11026
0
    assert(a->header.ref_count == 1);
11027
0
    while (l > 1) {
11028
0
        v = a->tab[l - 1];
11029
0
        if ((v != 0 && v != -1) ||
11030
0
            (v & 1) != (a->tab[l - 2] >> (JS_LIMB_BITS - 1))) {
11031
0
            break;
11032
0
        }
11033
0
        l--;
11034
0
    }
11035
0
    if (l != a->len) {
11036
0
        JSBigInt *a1;
11037
        /* realloc to reduce the size */
11038
0
        a->len = l;
11039
0
        a1 = js_realloc(ctx, a, sizeof(JSBigInt) + l * sizeof(js_limb_t));
11040
0
        if (a1)
11041
0
            a = a1;
11042
0
    }
11043
0
    return a;
11044
0
}
11045
11046
static JSBigInt *js_bigint_normalize(JSContext *ctx, JSBigInt *a)
11047
0
{
11048
0
    return js_bigint_normalize1(ctx, a, a->len);
11049
0
}
11050
11051
/* return 0 or 1 depending on the sign */
11052
static inline int js_bigint_sign(const JSBigInt *a)
11053
0
{
11054
0
    return a->tab[a->len - 1] >> (JS_LIMB_BITS - 1);
11055
0
}
11056
11057
static js_slimb_t js_bigint_get_si_sat(const JSBigInt *a)
11058
0
{
11059
0
    if (a->len == 1) {
11060
0
        return a->tab[0];
11061
0
    } else {
11062
#if JS_LIMB_BITS == 32
11063
        if (js_bigint_sign(a))
11064
            return INT32_MIN;
11065
        else
11066
            return INT32_MAX;
11067
#else
11068
0
        if (js_bigint_sign(a))
11069
0
            return INT64_MIN;
11070
0
        else
11071
0
            return INT64_MAX;
11072
0
#endif
11073
0
    }
11074
0
}
11075
11076
/* add the op1 limb */
11077
static JSBigInt *js_bigint_extend(JSContext *ctx, JSBigInt *r,
11078
                                  js_limb_t op1)
11079
0
{
11080
0
    int n2 = r->len;
11081
0
    if ((op1 != 0 && op1 != -1) ||
11082
0
        (op1 & 1) != r->tab[n2 - 1] >> (JS_LIMB_BITS - 1)) {
11083
0
        JSBigInt *r1;
11084
0
        r1 = js_realloc(ctx, r,
11085
0
                        sizeof(JSBigInt) + (n2 + 1) * sizeof(js_limb_t));
11086
0
        if (!r1) {
11087
0
            js_free(ctx, r);
11088
0
            return NULL;
11089
0
        }
11090
0
        r = r1;
11091
0
        r->len = n2 + 1;
11092
0
        r->tab[n2] = op1;
11093
0
    } else {
11094
        /* otherwise still need to normalize the result */
11095
0
        r = js_bigint_normalize(ctx, r);
11096
0
    }
11097
0
    return r;
11098
0
}
11099
11100
/* return NULL in case of error. Compute a + b (b_neg = 0) or a - b
11101
   (b_neg = 1) */
11102
/* XXX: optimize */
11103
static JSBigInt *js_bigint_add(JSContext *ctx, const JSBigInt *a,
11104
                               const JSBigInt *b, int b_neg)
11105
0
{
11106
0
    JSBigInt *r;
11107
0
    int n1, n2, i;
11108
0
    js_limb_t carry, op1, op2, a_sign, b_sign;
11109
    
11110
0
    n2 = max_int(a->len, b->len);
11111
0
    n1 = min_int(a->len, b->len);
11112
0
    r = js_bigint_new(ctx, n2);
11113
0
    if (!r)
11114
0
        return NULL;
11115
    /* XXX: optimize */
11116
    /* common part */
11117
0
    carry = b_neg;
11118
0
    for(i = 0; i < n1; i++) {
11119
0
        op1 = a->tab[i];
11120
0
        op2 = b->tab[i] ^ (-b_neg);
11121
0
        ADDC(r->tab[i], carry, op1, op2, carry);
11122
0
    }
11123
0
    a_sign = -js_bigint_sign(a);
11124
0
    b_sign = (-js_bigint_sign(b)) ^ (-b_neg);
11125
    /* part with sign extension of one operand  */
11126
0
    if (a->len > b->len) {
11127
0
        for(i = n1; i < n2; i++) {
11128
0
            op1 = a->tab[i];
11129
0
            ADDC(r->tab[i], carry, op1, b_sign, carry);
11130
0
        }
11131
0
    } else if (a->len < b->len) {
11132
0
        for(i = n1; i < n2; i++) {
11133
0
            op2 = b->tab[i] ^ (-b_neg);
11134
0
            ADDC(r->tab[i], carry, a_sign, op2, carry);
11135
0
        }
11136
0
    }
11137
11138
    /* part with sign extension for both operands. Extend the result
11139
       if necessary */
11140
0
    return js_bigint_extend(ctx, r, a_sign + b_sign + carry);
11141
0
}
11142
11143
/* XXX: optimize */
11144
static JSBigInt *js_bigint_neg(JSContext *ctx, const JSBigInt *a)
11145
0
{
11146
0
    JSBigIntBuf buf;
11147
0
    JSBigInt *b;
11148
0
    b = js_bigint_set_si(&buf, 0);
11149
0
    return js_bigint_add(ctx, b, a, 1);
11150
0
}
11151
11152
static JSBigInt *js_bigint_mul(JSContext *ctx, const JSBigInt *a,
11153
                               const JSBigInt *b)
11154
0
{
11155
0
    JSBigInt *r;
11156
    
11157
0
    r = js_bigint_new(ctx, a->len + b->len);
11158
0
    if (!r)
11159
0
        return NULL;
11160
0
    mp_mul_basecase(r->tab, a->tab, a->len, b->tab, b->len);
11161
    /* correct the result if negative operands (no overflow is
11162
       possible) */
11163
0
    if (js_bigint_sign(a))
11164
0
        mp_sub(r->tab + a->len, r->tab + a->len, b->tab, b->len, 0);
11165
0
    if (js_bigint_sign(b))
11166
0
        mp_sub(r->tab + b->len, r->tab + b->len, a->tab, a->len, 0);
11167
0
    return js_bigint_normalize(ctx, r);
11168
0
}
11169
11170
/* return the division or the remainder. 'b' must be != 0. return NULL
11171
   in case of exception (division by zero or memory error) */
11172
static JSBigInt *js_bigint_divrem(JSContext *ctx, const JSBigInt *a,
11173
                                  const JSBigInt *b, BOOL is_rem)
11174
0
{
11175
0
    JSBigInt *r, *q;
11176
0
    js_limb_t *tabb, h;
11177
0
    int na, nb, a_sign, b_sign, shift;
11178
    
11179
0
    if (b->len == 1 && b->tab[0] == 0) {
11180
0
        JS_ThrowRangeError(ctx, "BigInt division by zero");
11181
0
        return NULL;
11182
0
    }
11183
    
11184
0
    a_sign = js_bigint_sign(a);
11185
0
    b_sign = js_bigint_sign(b);
11186
0
    na = a->len;
11187
0
    nb = b->len;
11188
11189
0
    r = js_bigint_new(ctx, na + 2); 
11190
0
    if (!r)
11191
0
        return NULL;
11192
0
    if (a_sign) {
11193
0
        mp_neg(r->tab, a->tab, na);
11194
0
    } else {
11195
0
        memcpy(r->tab, a->tab, na * sizeof(a->tab[0]));
11196
0
    }
11197
    /* normalize */
11198
0
    while (na > 1 && r->tab[na - 1] == 0)
11199
0
        na--;
11200
11201
0
    tabb = js_malloc(ctx, nb * sizeof(tabb[0]));
11202
0
    if (!tabb) {
11203
0
        js_free(ctx, r);
11204
0
        return NULL;
11205
0
    }
11206
0
    if (b_sign) {
11207
0
        mp_neg(tabb, b->tab, nb);
11208
0
    } else {
11209
0
        memcpy(tabb, b->tab, nb * sizeof(tabb[0]));
11210
0
    }
11211
    /* normalize */
11212
0
    while (nb > 1 && tabb[nb - 1] == 0)
11213
0
        nb--;
11214
11215
    /* trivial case if 'a' is small */
11216
0
    if (na < nb) {
11217
0
        js_free(ctx, r);
11218
0
        js_free(ctx, tabb);
11219
0
        if (is_rem) {
11220
            /* r = a */
11221
0
            r = js_bigint_new(ctx, a->len);
11222
0
            if (!r)
11223
0
                return NULL;
11224
0
            memcpy(r->tab, a->tab, a->len * sizeof(a->tab[0])); 
11225
0
            return r;
11226
0
        } else {
11227
            /* q = 0 */
11228
0
            return js_bigint_new_si(ctx, 0);
11229
0
        }
11230
0
    }
11231
11232
    /* normalize 'b' */
11233
0
    shift = js_limb_clz(tabb[nb - 1]);
11234
0
    if (shift != 0) {
11235
0
        mp_shl(tabb, tabb, nb, shift);
11236
0
        h = mp_shl(r->tab, r->tab, na, shift);
11237
0
        if (h != 0)
11238
0
            r->tab[na++] = h;
11239
0
    }
11240
11241
0
    q = js_bigint_new(ctx, na - nb + 2); /* one more limb for the sign */
11242
0
    if (!q) {
11243
0
        js_free(ctx, r);
11244
0
        js_free(ctx, tabb);
11245
0
        return NULL;
11246
0
    }
11247
11248
    //    js_bigint_dump1(ctx, "a", r->tab, na);
11249
    //    js_bigint_dump1(ctx, "b", tabb, nb);
11250
0
    mp_divnorm(q->tab, r->tab, na, tabb, nb);
11251
0
    js_free(ctx, tabb);
11252
11253
0
    if (is_rem) {
11254
0
        js_free(ctx, q);
11255
0
        if (shift != 0)
11256
0
            mp_shr(r->tab, r->tab, nb, shift, 0);
11257
0
        r->tab[nb++] = 0;
11258
0
        if (a_sign)
11259
0
            mp_neg(r->tab, r->tab, nb);
11260
0
        r = js_bigint_normalize1(ctx, r, nb);
11261
0
        return r;
11262
0
    } else {
11263
0
        js_free(ctx, r);
11264
0
        q->tab[na - nb + 1] = 0;
11265
0
        if (a_sign ^ b_sign) {
11266
0
            mp_neg(q->tab, q->tab, q->len);
11267
0
        }
11268
0
        q = js_bigint_normalize(ctx, q);
11269
0
        return q;
11270
0
    }
11271
0
}
11272
11273
/* and, or, xor */
11274
static JSBigInt *js_bigint_logic(JSContext *ctx, const JSBigInt *a,
11275
                                 const JSBigInt *b, OPCodeEnum op)
11276
0
{
11277
0
    JSBigInt *r;
11278
0
    js_limb_t b_sign;
11279
0
    int a_len, b_len, i;
11280
11281
0
    if (a->len < b->len) {
11282
0
        const JSBigInt *tmp;
11283
0
        tmp = a;
11284
0
        a = b;
11285
0
        b = tmp;
11286
0
    }
11287
    /* a_len >= b_len */
11288
0
    a_len = a->len;
11289
0
    b_len = b->len;
11290
0
    b_sign = -js_bigint_sign(b);
11291
11292
0
    r = js_bigint_new(ctx, a_len);
11293
0
    if (!r)
11294
0
        return NULL;
11295
0
    switch(op) {
11296
0
    case OP_or:
11297
0
        for(i = 0; i < b_len; i++) {
11298
0
            r->tab[i] = a->tab[i] | b->tab[i];
11299
0
        }
11300
0
        for(i = b_len; i < a_len; i++) {
11301
0
            r->tab[i] = a->tab[i] | b_sign;
11302
0
        }
11303
0
        break;
11304
0
    case OP_and:
11305
0
        for(i = 0; i < b_len; i++) {
11306
0
            r->tab[i] = a->tab[i] & b->tab[i];
11307
0
        }
11308
0
        for(i = b_len; i < a_len; i++) {
11309
0
            r->tab[i] = a->tab[i] & b_sign;
11310
0
        }
11311
0
        break;
11312
0
    case OP_xor:
11313
0
        for(i = 0; i < b_len; i++) {
11314
0
            r->tab[i] = a->tab[i] ^ b->tab[i];
11315
0
        }
11316
0
        for(i = b_len; i < a_len; i++) {
11317
0
            r->tab[i] = a->tab[i] ^ b_sign;
11318
0
        }
11319
0
        break;
11320
0
    default:
11321
0
        abort();
11322
0
    }
11323
0
    return js_bigint_normalize(ctx, r);
11324
0
}
11325
11326
static JSBigInt *js_bigint_not(JSContext *ctx, const JSBigInt *a)
11327
0
{
11328
0
    JSBigInt *r;
11329
0
    int i;
11330
    
11331
0
    r = js_bigint_new(ctx, a->len);
11332
0
    if (!r)
11333
0
        return NULL;
11334
0
    for(i = 0; i < a->len; i++) {
11335
0
        r->tab[i] = ~a->tab[i];
11336
0
    }
11337
    /* no normalization is needed */
11338
0
    return r;
11339
0
}
11340
11341
static JSBigInt *js_bigint_shl(JSContext *ctx, const JSBigInt *a,
11342
                               unsigned int shift1)
11343
0
{
11344
0
    int d, i, shift;
11345
0
    JSBigInt *r;
11346
0
    js_limb_t l;
11347
11348
0
    if (a->len == 1 && a->tab[0] == 0)
11349
0
        return js_bigint_new_si(ctx, 0); /* zero case */
11350
0
    d = shift1 / JS_LIMB_BITS;
11351
0
    shift = shift1 % JS_LIMB_BITS;
11352
0
    r = js_bigint_new(ctx, a->len + d);
11353
0
    if (!r)
11354
0
        return NULL;
11355
0
    for(i = 0; i < d; i++)
11356
0
        r->tab[i] = 0;
11357
0
    if (shift == 0) {
11358
0
        for(i = 0; i < a->len; i++) {
11359
0
            r->tab[i + d] = a->tab[i];
11360
0
        }
11361
0
    } else {
11362
0
        l = mp_shl(r->tab + d, a->tab, a->len, shift);
11363
0
        if (js_bigint_sign(a))
11364
0
            l |= (js_limb_t)(-1) << shift;
11365
0
        r = js_bigint_extend(ctx, r, l);
11366
0
    }
11367
0
    return r;
11368
0
}
11369
11370
static JSBigInt *js_bigint_shr(JSContext *ctx, const JSBigInt *a,
11371
                               unsigned int shift1)
11372
0
{
11373
0
    int d, i, shift, a_sign, n1;
11374
0
    JSBigInt *r;
11375
11376
0
    d = shift1 / JS_LIMB_BITS;
11377
0
    shift = shift1 % JS_LIMB_BITS;
11378
0
    a_sign = js_bigint_sign(a);
11379
0
    if (d >= a->len)
11380
0
        return js_bigint_new_si(ctx, -a_sign);
11381
0
    n1 = a->len - d;
11382
0
    r = js_bigint_new(ctx, n1);
11383
0
    if (!r)
11384
0
        return NULL;
11385
0
    if (shift == 0) {
11386
0
        for(i = 0; i < n1; i++) {
11387
0
            r->tab[i] = a->tab[i + d];
11388
0
        }
11389
        /* no normalization is needed */
11390
0
    } else {
11391
0
        mp_shr(r->tab, a->tab + d, n1, shift, -a_sign);
11392
0
        r = js_bigint_normalize(ctx, r);
11393
0
    }
11394
0
    return r;
11395
0
}
11396
11397
static JSBigInt *js_bigint_pow(JSContext *ctx, const JSBigInt *a, JSBigInt *b)
11398
0
{
11399
0
    uint32_t e;
11400
0
    int n_bits, i;
11401
0
    JSBigInt *r, *r1;
11402
    
11403
    /* b must be >= 0 */
11404
0
    if (js_bigint_sign(b)) {
11405
0
        JS_ThrowRangeError(ctx, "BigInt negative exponent");
11406
0
        return NULL;
11407
0
    }
11408
0
    if (b->len == 1 && b->tab[0] == 0) {
11409
        /* a^0 = 1 */
11410
0
        return js_bigint_new_si(ctx, 1);
11411
0
    } else if (a->len == 1) {
11412
0
        js_limb_t v;
11413
0
        BOOL is_neg;
11414
11415
0
        v = a->tab[0];
11416
0
        if (v <= 1)
11417
0
            return js_bigint_new_si(ctx, v);
11418
0
        else if (v == -1)
11419
0
            return js_bigint_new_si(ctx, 1 - 2 * (b->tab[0] & 1));
11420
0
        is_neg = (js_slimb_t)v < 0;
11421
0
        if (is_neg)
11422
0
            v = -v;
11423
0
        if ((v & (v - 1)) == 0) {
11424
0
            uint64_t e1;
11425
0
            int n;
11426
            /* v = 2^n */
11427
0
            n = JS_LIMB_BITS - 1 - js_limb_clz(v);
11428
0
            if (b->len > 1)
11429
0
                goto overflow;
11430
0
            if (b->tab[0] > INT32_MAX)
11431
0
                goto overflow;
11432
0
            e = b->tab[0];
11433
0
            e1 = (uint64_t)e * n;
11434
0
            if (e1 > JS_BIGINT_MAX_SIZE * JS_LIMB_BITS)
11435
0
                goto overflow;
11436
0
            e = e1;
11437
0
            if (is_neg)
11438
0
                is_neg = b->tab[0] & 1;
11439
0
            r = js_bigint_new(ctx,
11440
0
                              (e + JS_LIMB_BITS + 1 - is_neg) / JS_LIMB_BITS);
11441
0
            if (!r)
11442
0
                return NULL;
11443
0
            memset(r->tab, 0, sizeof(r->tab[0]) * r->len);
11444
0
            r->tab[e / JS_LIMB_BITS] =
11445
0
                (js_limb_t)(1 - 2 * is_neg) << (e % JS_LIMB_BITS);
11446
0
            return r;
11447
0
        }
11448
0
    }
11449
0
    if (b->len > 1)
11450
0
        goto overflow;
11451
0
    if (b->tab[0] > INT32_MAX)
11452
0
        goto overflow;
11453
0
    e = b->tab[0];
11454
0
    n_bits = 32 - clz32(e);
11455
11456
0
    r = js_bigint_new(ctx, a->len);
11457
0
    if (!r)
11458
0
        return NULL;
11459
0
    memcpy(r->tab, a->tab, a->len * sizeof(a->tab[0]));
11460
0
    for(i = n_bits - 2; i >= 0; i--) {
11461
0
        r1 = js_bigint_mul(ctx, r, r);
11462
0
        if (!r1)
11463
0
            return NULL;
11464
0
        js_free(ctx, r);
11465
0
        r = r1;
11466
0
        if ((e >> i) & 1) {
11467
0
            r1 = js_bigint_mul(ctx, r, a);
11468
0
            if (!r1)
11469
0
                return NULL;
11470
0
            js_free(ctx, r);
11471
0
            r = r1;
11472
0
        }
11473
0
    }
11474
0
    return r;
11475
0
 overflow:
11476
0
    JS_ThrowRangeError(ctx, "BigInt is too large");
11477
0
    return NULL;
11478
0
}
11479
11480
/* return (mant, exp) so that abs(a) ~ mant*2^(exp - (limb_bits -
11481
   1). a must be != 0. */
11482
static uint64_t js_bigint_get_mant_exp(JSContext *ctx,
11483
                                       int *pexp, const JSBigInt *a)
11484
0
{
11485
0
    js_limb_t t[4 - JS_LIMB_BITS / 32], carry, v, low_bits;
11486
0
    int n1, n2, sgn, shift, i, j, e;
11487
0
    uint64_t a1, a0;
11488
11489
0
    n2 = 4 - JS_LIMB_BITS / 32;
11490
0
    n1 = a->len - n2;
11491
0
    sgn = js_bigint_sign(a);
11492
11493
    /* low_bits != 0 if there are a non zero low bit in abs(a) */
11494
0
    low_bits = 0;
11495
0
    carry = sgn;
11496
0
    for(i = 0; i < n1; i++) {
11497
0
        v = (a->tab[i] ^ (-sgn)) + carry;
11498
0
        carry = v < carry;
11499
0
        low_bits |= v;
11500
0
    }
11501
    /* get the n2 high limbs of abs(a) */
11502
0
    for(j = 0; j < n2; j++) {
11503
0
        i = j + n1;
11504
0
        if (i < 0) {
11505
0
            v = 0;
11506
0
        } else {
11507
0
            v = (a->tab[i] ^ (-sgn)) + carry;
11508
0
            carry = v < carry;
11509
0
        }
11510
0
        t[j] = v;
11511
0
    }
11512
    
11513
#if JS_LIMB_BITS == 32
11514
    a1 = ((uint64_t)t[2] << 32) | t[1];
11515
    a0 = (uint64_t)t[0] << 32;
11516
#else
11517
0
    a1 = t[1];
11518
0
    a0 = t[0];
11519
0
#endif
11520
0
    a0 |= (low_bits != 0);
11521
    /* normalize */
11522
0
    if (a1 == 0) {
11523
        /* JS_LIMB_BITS = 64 bit only */
11524
0
        shift = 64;
11525
0
        a1 = a0;
11526
0
        a0 = 0;
11527
0
    } else {
11528
0
        shift = clz64(a1);
11529
0
        if (shift != 0) {
11530
0
            a1 = (a1 << shift) | (a0 >> (64 - shift));
11531
0
            a0 <<= shift;
11532
0
        }
11533
0
    }
11534
0
    a1 |= (a0 != 0); /* keep the bits for the final rounding */
11535
    /* compute the exponent */
11536
0
    e = a->len * JS_LIMB_BITS - shift - 1;
11537
0
    *pexp = e;
11538
0
    return a1;
11539
0
}
11540
11541
/* shift left with round to nearest, ties to even. n >= 1 */
11542
static uint64_t shr_rndn(uint64_t a, int n)
11543
0
{
11544
0
    uint64_t addend = ((a >> n) & 1) + ((1 << (n - 1)) - 1);
11545
0
    return (a + addend) >> n;
11546
0
}
11547
11548
/* convert to float64 with round to nearest, ties to even. Return
11549
   +/-infinity if too large. */
11550
static double js_bigint_to_float64(JSContext *ctx, const JSBigInt *a)
11551
0
{
11552
0
    int sgn, e;
11553
0
    uint64_t mant;
11554
11555
0
    if (a->len == 1) {
11556
        /* fast case, including zero */
11557
0
        return (double)(js_slimb_t)a->tab[0];
11558
0
    }
11559
11560
0
    sgn = js_bigint_sign(a);
11561
0
    mant = js_bigint_get_mant_exp(ctx, &e, a);
11562
0
    if (e > 1023) {
11563
        /* overflow: return infinity */
11564
0
        mant = 0;
11565
0
        e = 1024;
11566
0
    } else {
11567
0
        mant = (mant >> 1) | (mant & 1); /* avoid overflow in rounding */
11568
0
        mant = shr_rndn(mant, 10);
11569
        /* rounding can cause an overflow */
11570
0
        if (mant >= ((uint64_t)1 << 53)) {
11571
0
            mant >>= 1;
11572
0
            e++;
11573
0
        }
11574
0
        mant &= (((uint64_t)1 << 52) - 1);
11575
0
    }
11576
0
    return uint64_as_float64(((uint64_t)sgn << 63) |
11577
0
                             ((uint64_t)(e + 1023) << 52) |
11578
0
                             mant);
11579
0
}
11580
11581
/* return (1, NULL) if not an integer, (2, NULL) if NaN or Infinity,
11582
   (0, n) if an integer, (0, NULL) in case of memory error */
11583
static JSBigInt *js_bigint_from_float64(JSContext *ctx, int *pres, double a1)
11584
0
{
11585
0
    uint64_t a = float64_as_uint64(a1);
11586
0
    int sgn, e, shift;
11587
0
    uint64_t mant;
11588
0
    JSBigIntBuf buf;
11589
0
    JSBigInt *r;
11590
    
11591
0
    sgn = a >> 63;
11592
0
    e = (a >> 52) & ((1 << 11) - 1);
11593
0
    mant = a & (((uint64_t)1 << 52) - 1);
11594
0
    if (e == 2047) {
11595
        /* NaN, Infinity */
11596
0
        *pres = 2;
11597
0
        return NULL;
11598
0
    }
11599
0
    if (e == 0 && mant == 0) {
11600
        /* zero */
11601
0
        *pres = 0;
11602
0
        return js_bigint_new_si(ctx, 0);
11603
0
    }
11604
0
    e -= 1023;
11605
    /* 0 < a < 1 : not an integer */
11606
0
    if (e < 0)
11607
0
        goto not_an_integer;
11608
0
    mant |= (uint64_t)1 << 52;
11609
0
    if (e < 52) {
11610
0
        shift = 52 - e;
11611
        /* check that there is no fractional part */
11612
0
        if (mant & (((uint64_t)1 << shift) - 1)) {
11613
0
        not_an_integer:
11614
0
            *pres = 1;
11615
0
            return NULL;
11616
0
        }
11617
0
        mant >>= shift;
11618
0
        e = 0;
11619
0
    } else {
11620
0
        e -= 52;
11621
0
    }
11622
0
    if (sgn)
11623
0
        mant = -mant;
11624
    /* the integer is mant*2^e */
11625
0
    r = js_bigint_set_si64(&buf, (int64_t)mant);
11626
0
    *pres = 0;
11627
0
    return js_bigint_shl(ctx, r, e);
11628
0
}
11629
11630
/* return -1, 0, 1 or (2) (unordered) */
11631
static int js_bigint_float64_cmp(JSContext *ctx, const JSBigInt *a,
11632
                                 double b)
11633
0
{
11634
0
    int b_sign, a_sign, e, f;
11635
0
    uint64_t mant, b1, a_mant;
11636
    
11637
0
    b1 = float64_as_uint64(b);
11638
0
    b_sign = b1 >> 63;
11639
0
    e = (b1 >> 52) & ((1 << 11) - 1);
11640
0
    mant = b1 & (((uint64_t)1 << 52) - 1);
11641
0
    a_sign = js_bigint_sign(a);
11642
0
    if (e == 2047) {
11643
0
        if (mant != 0) {
11644
            /* NaN */
11645
0
            return 2;
11646
0
        } else {
11647
            /* +/- infinity */
11648
0
            return 2 * b_sign - 1;
11649
0
        }
11650
0
    } else if (e == 0 && mant == 0) {
11651
        /* b = +/-0 */
11652
0
        if (a->len == 1 && a->tab[0] == 0)
11653
0
            return 0;
11654
0
        else
11655
0
            return 1 - 2 * a_sign;
11656
0
    } else if (a->len == 1 && a->tab[0] == 0) {
11657
        /* a = 0, b != 0 */
11658
0
        return 2 * b_sign - 1;
11659
0
    } else if (a_sign != b_sign) {
11660
0
        return 1 - 2 * a_sign;
11661
0
    } else {
11662
0
        e -= 1023;
11663
        /* Note: handling denormals is not necessary because we
11664
           compare to integers hence f >= 0 */
11665
        /* compute f so that 2^f <= abs(a) < 2^(f+1) */
11666
0
        a_mant = js_bigint_get_mant_exp(ctx, &f, a);
11667
0
        if (f != e) {
11668
0
            if (f < e)
11669
0
                return -1;
11670
0
            else
11671
0
                return 1;
11672
0
        } else {
11673
0
            mant = (mant | ((uint64_t)1 << 52)) << 11; /* align to a_mant */
11674
0
            if (a_mant < mant)
11675
0
                return 2 * a_sign - 1;
11676
0
            else if (a_mant > mant)
11677
0
                return 1 - 2 * a_sign;
11678
0
            else
11679
0
                return 0;
11680
0
        }
11681
0
    }
11682
0
}
11683
11684
/* return -1, 0 or 1 */
11685
static int js_bigint_cmp(JSContext *ctx, const JSBigInt *a,
11686
                         const JSBigInt *b)
11687
0
{
11688
0
    int a_sign, b_sign, res, i;
11689
0
    a_sign = js_bigint_sign(a);
11690
0
    b_sign = js_bigint_sign(b);
11691
0
    if (a_sign != b_sign) {
11692
0
        res = 1 - 2 * a_sign;
11693
0
    } else {
11694
        /* we assume the numbers are normalized */
11695
0
        if (a->len != b->len) {
11696
0
            if (a->len < b->len)
11697
0
                res = 2 * a_sign - 1;
11698
0
            else
11699
0
                res = 1 - 2 * a_sign;
11700
0
        } else {
11701
0
            res = 0;
11702
0
            for(i = a->len -1; i >= 0; i--) {
11703
0
                if (a->tab[i] != b->tab[i]) {
11704
0
                    if (a->tab[i] < b->tab[i])
11705
0
                        res = -1;
11706
0
                    else
11707
0
                        res = 1;
11708
0
                    break;
11709
0
                }
11710
0
            }
11711
0
        }
11712
0
    }
11713
0
    return res;
11714
0
}
11715
11716
/* contains 10^i */
11717
static const js_limb_t js_pow_dec[JS_LIMB_DIGITS + 1] = {
11718
    1U,
11719
    10U,
11720
    100U,
11721
    1000U,
11722
    10000U,
11723
    100000U,
11724
    1000000U,
11725
    10000000U,
11726
    100000000U,
11727
    1000000000U,
11728
#if JS_LIMB_BITS == 64
11729
    10000000000U,
11730
    100000000000U,
11731
    1000000000000U,
11732
    10000000000000U,
11733
    100000000000000U,
11734
    1000000000000000U,
11735
    10000000000000000U,
11736
    100000000000000000U,
11737
    1000000000000000000U,
11738
    10000000000000000000U,
11739
#endif
11740
};
11741
11742
/* syntax: [-]digits in base radix. Return NULL if memory error. radix
11743
   = 10, 2, 8 or 16. */
11744
static JSBigInt *js_bigint_from_string(JSContext *ctx,
11745
                                       const char *str, int radix)
11746
0
{
11747
0
    const char *p = str;
11748
0
    int is_neg, n_digits, n_limbs, len, log2_radix, n_bits, i;
11749
0
    JSBigInt *r;
11750
0
    js_limb_t v, c, h;
11751
    
11752
0
    is_neg = 0;
11753
0
    if (*p == '-') {
11754
0
        is_neg = 1;
11755
0
        p++;
11756
0
    }
11757
0
    while (*p == '0')
11758
0
        p++;
11759
0
    n_digits = strlen(p);
11760
0
    log2_radix = 32 - clz32(radix - 1); /* ceil(log2(radix)) */
11761
    /* compute the maximum number of limbs */
11762
    /* XXX: overflow */
11763
0
    if (radix == 10) {
11764
0
        n_bits = (n_digits * 27 + 7) / 8; /* >= ceil(n_digits * log2(10)) */
11765
0
    } else {
11766
0
        n_bits = n_digits * log2_radix;
11767
0
    }
11768
    /* we add one extra bit for the sign */
11769
0
    n_limbs = max_int(1, n_bits / JS_LIMB_BITS + 1);
11770
0
    r = js_bigint_new(ctx, n_limbs);
11771
0
    if (!r)
11772
0
        return NULL;
11773
0
    if (radix == 10) {
11774
0
        int digits_per_limb = JS_LIMB_DIGITS;
11775
0
        len = 1;
11776
0
        r->tab[0] = 0;
11777
0
        for(;;) {
11778
            /* XXX: slow */
11779
0
            v = 0;
11780
0
            for(i = 0; i < digits_per_limb; i++) {
11781
0
                c = to_digit(*p);
11782
0
                if (c >= radix)
11783
0
                    break;
11784
0
                p++;
11785
0
                v = v * 10 + c;
11786
0
            }
11787
0
            if (i == 0)
11788
0
                break;
11789
0
            if (len == 1 && r->tab[0] == 0) {
11790
0
                r->tab[0] = v;
11791
0
            } else {
11792
0
                h = mp_mul1(r->tab, r->tab, len, js_pow_dec[i], v);
11793
0
                if (h != 0) {
11794
0
                    r->tab[len++] = h;
11795
0
                }
11796
0
            }
11797
0
        }
11798
        /* add one extra limb to have the correct sign*/
11799
0
        if ((r->tab[len - 1] >> (JS_LIMB_BITS - 1)) != 0)
11800
0
            r->tab[len++] = 0;
11801
0
        r->len = len;
11802
0
    } else {
11803
0
        unsigned int bit_pos, shift, pos;
11804
        
11805
        /* power of two base: no multiplication is needed */
11806
0
        r->len = n_limbs;
11807
0
        memset(r->tab, 0, sizeof(r->tab[0]) * n_limbs);
11808
0
        for(i = 0; i < n_digits; i++) {
11809
0
            c = to_digit(p[n_digits - 1 - i]);
11810
0
            assert(c < radix);
11811
0
            bit_pos = i * log2_radix;
11812
0
            shift = bit_pos & (JS_LIMB_BITS - 1);
11813
0
            pos = bit_pos / JS_LIMB_BITS;
11814
0
            r->tab[pos] |= c << shift;
11815
            /* if log2_radix does not divide JS_LIMB_BITS, needed an
11816
               additional op */
11817
0
            if (shift + log2_radix > JS_LIMB_BITS) {
11818
0
                r->tab[pos + 1] |= c >> (JS_LIMB_BITS - shift);
11819
0
            }
11820
0
        }
11821
0
    }
11822
0
    r = js_bigint_normalize(ctx, r);
11823
    /* XXX: could do it in place */
11824
0
    if (is_neg) {
11825
0
        JSBigInt *r1;
11826
0
        r1 = js_bigint_neg(ctx, r);
11827
0
        js_free(ctx, r);
11828
0
        r = r1;
11829
0
    }
11830
0
    return r;
11831
0
}
11832
11833
/* 2 <= base <= 36 */
11834
static char const digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
11835
11836
/* special version going backwards */
11837
/* XXX: use dtoa.c */
11838
static char *js_u64toa(char *q, int64_t n, unsigned int base)
11839
0
{
11840
0
    int digit;
11841
0
    if (base == 10) {
11842
        /* division by known base uses multiplication */
11843
0
        do {
11844
0
            digit = (uint64_t)n % 10;
11845
0
            n = (uint64_t)n / 10;
11846
0
            *--q = '0' + digit;
11847
0
        } while (n != 0);
11848
0
    } else {
11849
0
        do {
11850
0
            digit = (uint64_t)n % base;
11851
0
            n = (uint64_t)n / base;
11852
0
            *--q = digits[digit];
11853
0
        } while (n != 0);
11854
0
    }
11855
0
    return q;
11856
0
}
11857
11858
/* len >= 1. 2 <= radix <= 36 */
11859
static char *limb_to_a(char *q, js_limb_t n, unsigned int radix, int len)
11860
0
{
11861
0
    int digit, i;
11862
11863
0
    if (radix == 10) {
11864
        /* specific case with constant divisor */
11865
        /* XXX: optimize */
11866
0
        for(i = 0; i < len; i++) {
11867
0
            digit = (js_limb_t)n % 10;
11868
0
            n = (js_limb_t)n / 10;
11869
0
            *--q = digit + '0';
11870
0
        }
11871
0
    } else {
11872
0
        for(i = 0; i < len; i++) {
11873
0
            digit = (js_limb_t)n % radix;
11874
0
            n = (js_limb_t)n / radix;
11875
0
            *--q = digits[digit];
11876
0
        }
11877
0
    }
11878
0
    return q;
11879
0
}
11880
11881
#define JS_RADIX_MAX 36
11882
11883
static const uint8_t digits_per_limb_table[JS_RADIX_MAX - 1] = {
11884
#if JS_LIMB_BITS == 32
11885
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,
11886
#else
11887
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,
11888
#endif
11889
};
11890
11891
static const js_limb_t radix_base_table[JS_RADIX_MAX - 1] = {
11892
#if JS_LIMB_BITS == 32
11893
 0x00000000, 0xcfd41b91, 0x00000000, 0x48c27395,
11894
 0x81bf1000, 0x75db9c97, 0x40000000, 0xcfd41b91,
11895
 0x3b9aca00, 0x8c8b6d2b, 0x19a10000, 0x309f1021,
11896
 0x57f6c100, 0x98c29b81, 0x00000000, 0x18754571,
11897
 0x247dbc80, 0x3547667b, 0x4c4b4000, 0x6b5a6e1d,
11898
 0x94ace180, 0xcaf18367, 0x0b640000, 0x0e8d4a51,
11899
 0x1269ae40, 0x17179149, 0x1cb91000, 0x23744899,
11900
 0x2b73a840, 0x34e63b41, 0x40000000, 0x4cfa3cc1,
11901
 0x5c13d840, 0x6d91b519, 0x81bf1000,
11902
#else
11903
 0x0000000000000000, 0xa8b8b452291fe821, 0x0000000000000000, 0x6765c793fa10079d,
11904
 0x41c21cb8e1000000, 0x3642798750226111, 0x8000000000000000, 0xa8b8b452291fe821,
11905
 0x8ac7230489e80000, 0x4d28cb56c33fa539, 0x1eca170c00000000, 0x780c7372621bd74d,
11906
 0x1e39a5057d810000, 0x5b27ac993df97701, 0x0000000000000000, 0x27b95e997e21d9f1,
11907
 0x5da0e1e53c5c8000, 0xd2ae3299c1c4aedb, 0x16bcc41e90000000, 0x2d04b7fdd9c0ef49,
11908
 0x5658597bcaa24000, 0xa0e2073737609371, 0x0c29e98000000000, 0x14adf4b7320334b9,
11909
 0x226ed36478bfa000, 0x383d9170b85ff80b, 0x5a3c23e39c000000, 0x8e65137388122bcd,
11910
 0xdd41bb36d259e000, 0x0aee5720ee830681, 0x1000000000000000, 0x172588ad4f5f0981,
11911
 0x211e44f7d02c1000, 0x2ee56725f06e5c71, 0x41c21cb8e1000000,
11912
#endif
11913
};
11914
11915
static JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix)
11916
0
{
11917
0
    if (JS_VALUE_GET_TAG(val) == JS_TAG_SHORT_BIG_INT) {
11918
0
        char buf[66];
11919
0
        int len;
11920
0
        len = i64toa_radix(buf, JS_VALUE_GET_SHORT_BIG_INT(val), radix);
11921
0
        return js_new_string8_len(ctx, buf, len);
11922
0
    } else {
11923
0
        JSBigInt *r, *tmp = NULL;
11924
0
        char *buf, *q, *buf_end;
11925
0
        int is_neg, n_bits, log2_radix, n_digits;
11926
0
        BOOL is_binary_radix;
11927
0
        JSValue res;
11928
        
11929
0
        assert(JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT);
11930
0
        r = JS_VALUE_GET_PTR(val);
11931
0
        if (r->len == 1 && r->tab[0] == 0) {
11932
            /* '0' case */
11933
0
            return js_new_string8_len(ctx, "0", 1);
11934
0
        }
11935
0
        is_binary_radix = ((radix & (radix - 1)) == 0);
11936
0
        is_neg = js_bigint_sign(r);
11937
0
        if (is_neg) {
11938
0
            tmp = js_bigint_neg(ctx, r);
11939
0
            if (!tmp)
11940
0
                return JS_EXCEPTION;
11941
0
            r = tmp;
11942
0
        } else if (!is_binary_radix) {
11943
            /* need to modify 'r' */
11944
0
            tmp = js_bigint_new(ctx, r->len);
11945
0
            if (!tmp)
11946
0
                return JS_EXCEPTION;
11947
0
            memcpy(tmp->tab, r->tab, r->len * sizeof(r->tab[0]));
11948
0
            r = tmp;
11949
0
        }
11950
0
        log2_radix = 31 - clz32(radix); /* floor(log2(radix)) */
11951
0
        n_bits = r->len * JS_LIMB_BITS - js_limb_safe_clz(r->tab[r->len - 1]);
11952
        /* n_digits is exact only if radix is a power of
11953
           two. Otherwise it is >= the exact number of digits */
11954
0
        n_digits = (n_bits + log2_radix - 1) / log2_radix;
11955
        /* XXX: could directly build the JSString */
11956
0
        buf = js_malloc(ctx, n_digits + is_neg + 1);
11957
0
        if (!buf) {
11958
0
            js_free(ctx, tmp);
11959
0
            return JS_EXCEPTION;
11960
0
        }
11961
0
        q = buf + n_digits + is_neg + 1;
11962
0
        *--q = '\0';
11963
0
        buf_end = q;
11964
0
        if (!is_binary_radix) {
11965
0
            int len;
11966
0
            js_limb_t radix_base, v;
11967
0
            radix_base = radix_base_table[radix - 2];
11968
0
            len = r->len;
11969
0
            for(;;) {
11970
                /* remove leading zero limbs */
11971
0
                while (len > 1 && r->tab[len - 1] == 0)
11972
0
                    len--;
11973
0
                if (len == 1 && r->tab[0] < radix_base) {
11974
0
                    v = r->tab[0];
11975
0
                    if (v != 0) {
11976
0
                        q = js_u64toa(q, v, radix);
11977
0
                    }
11978
0
                    break;
11979
0
                } else {
11980
0
                    v = mp_div1(r->tab, r->tab, len, radix_base, 0);
11981
0
                    q = limb_to_a(q, v, radix, digits_per_limb_table[radix - 2]);
11982
0
                }
11983
0
            }
11984
0
        } else {
11985
0
            int i, shift;
11986
0
            unsigned int bit_pos, pos, c;
11987
11988
            /* radix is a power of two */
11989
0
            for(i = 0; i < n_digits; i++) {
11990
0
                bit_pos = i * log2_radix;
11991
0
                pos = bit_pos / JS_LIMB_BITS;
11992
0
                shift = bit_pos % JS_LIMB_BITS;
11993
0
                if (likely((shift + log2_radix) <= JS_LIMB_BITS)) {
11994
0
                    c = r->tab[pos] >> shift;
11995
0
                } else {
11996
0
                    c = (r->tab[pos] >> shift) |
11997
0
                        (r->tab[pos + 1] << (JS_LIMB_BITS - shift));
11998
0
                }
11999
0
                c &= (radix - 1);
12000
0
                *--q = digits[c];
12001
0
            }
12002
0
        }
12003
0
        if (is_neg)
12004
0
            *--q = '-';
12005
0
        js_free(ctx, tmp);
12006
0
        res = js_new_string8_len(ctx, q, buf_end - q);
12007
0
        js_free(ctx, buf);
12008
0
        return res;
12009
0
    }
12010
0
}
12011
12012
/* if possible transform a BigInt to short big and free it, otherwise
12013
   return a normal bigint */
12014
static JSValue JS_CompactBigInt(JSContext *ctx, JSBigInt *p)
12015
0
{
12016
0
    JSValue res;
12017
0
    if (p->len == 1) {
12018
0
        res = __JS_NewShortBigInt(ctx, (js_slimb_t)p->tab[0]);
12019
0
        js_free(ctx, p);
12020
0
        return res;
12021
0
    } else {
12022
0
        return JS_MKPTR(JS_TAG_BIG_INT, p);
12023
0
    }
12024
0
}
12025
12026
1
#define ATOD_INT_ONLY        (1 << 0)
12027
/* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */
12028
1
#define ATOD_ACCEPT_BIN_OCT  (1 << 2)
12029
/* accept O prefix as octal if radix == 0 and properly formed (Annex B) */
12030
1
#define ATOD_ACCEPT_LEGACY_OCTAL  (1 << 4)
12031
/* accept _ between digits as a digit separator */
12032
2
#define ATOD_ACCEPT_UNDERSCORES  (1 << 5)
12033
/* allow a suffix to override the type */
12034
2
#define ATOD_ACCEPT_SUFFIX    (1 << 6)
12035
/* default type */
12036
1
#define ATOD_TYPE_MASK        (3 << 7)
12037
1
#define ATOD_TYPE_FLOAT64     (0 << 7)
12038
0
#define ATOD_TYPE_BIG_INT     (1 << 7)
12039
/* accept -0x1 */
12040
0
#define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10)
12041
12042
/* return an exception in case of memory error. Return JS_NAN if
12043
   invalid syntax */
12044
/* XXX: directly use js_atod() */
12045
static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
12046
                       int radix, int flags)
12047
1
{
12048
1
    const char *p, *p_start;
12049
1
    int sep, is_neg;
12050
1
    BOOL is_float, has_legacy_octal;
12051
1
    int atod_type = flags & ATOD_TYPE_MASK;
12052
1
    char buf1[64], *buf;
12053
1
    int i, j, len;
12054
1
    BOOL buf_allocated = FALSE;
12055
1
    JSValue val;
12056
1
    JSATODTempMem atod_mem;
12057
    
12058
    /* optional separator between digits */
12059
1
    sep = (flags & ATOD_ACCEPT_UNDERSCORES) ? '_' : 256;
12060
1
    has_legacy_octal = FALSE;
12061
12062
1
    p = str;
12063
1
    p_start = p;
12064
1
    is_neg = 0;
12065
1
    if (p[0] == '+') {
12066
0
        p++;
12067
0
        p_start++;
12068
0
        if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN))
12069
0
            goto no_radix_prefix;
12070
1
    } else if (p[0] == '-') {
12071
0
        p++;
12072
0
        p_start++;
12073
0
        is_neg = 1;
12074
0
        if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN))
12075
0
            goto no_radix_prefix;
12076
0
    }
12077
1
    if (p[0] == '0') {
12078
1
        if ((p[1] == 'x' || p[1] == 'X') &&
12079
1
            (radix == 0 || radix == 16)) {
12080
1
            p += 2;
12081
1
            radix = 16;
12082
1
        } else if ((p[1] == 'o' || p[1] == 'O') &&
12083
0
                   radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) {
12084
0
            p += 2;
12085
0
            radix = 8;
12086
0
        } else if ((p[1] == 'b' || p[1] == 'B') &&
12087
0
                   radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) {
12088
0
            p += 2;
12089
0
            radix = 2;
12090
0
        } else if ((p[1] >= '0' && p[1] <= '9') &&
12091
0
                   radix == 0 && (flags & ATOD_ACCEPT_LEGACY_OCTAL)) {
12092
0
            int i;
12093
0
            has_legacy_octal = TRUE;
12094
0
            sep = 256;
12095
0
            for (i = 1; (p[i] >= '0' && p[i] <= '7'); i++)
12096
0
                continue;
12097
0
            if (p[i] == '8' || p[i] == '9')
12098
0
                goto no_prefix;
12099
0
            p += 1;
12100
0
            radix = 8;
12101
0
        } else {
12102
0
            goto no_prefix;
12103
0
        }
12104
        /* there must be a digit after the prefix */
12105
1
        if (to_digit((uint8_t)*p) >= radix)
12106
0
            goto fail;
12107
1
    no_prefix: ;
12108
1
    } else {
12109
0
 no_radix_prefix:
12110
0
        if (!(flags & ATOD_INT_ONLY) &&
12111
0
            (atod_type == ATOD_TYPE_FLOAT64) &&
12112
0
            strstart(p, "Infinity", &p)) {
12113
0
            double d = 1.0 / 0.0;
12114
0
            if (is_neg)
12115
0
                d = -d;
12116
0
            val = JS_NewFloat64(ctx, d);
12117
0
            goto done;
12118
0
        }
12119
0
    }
12120
1
    if (radix == 0)
12121
0
        radix = 10;
12122
1
    is_float = FALSE;
12123
1
    p_start = p;
12124
1.04M
    while (to_digit((uint8_t)*p) < radix
12125
1.04M
           ||  (*p == sep && (radix != 10 ||
12126
0
                              p != p_start + 1 || p[-1] != '0') &&
12127
1.04M
                to_digit((uint8_t)p[1]) < radix)) {
12128
1.04M
        p++;
12129
1.04M
    }
12130
1
    if (!(flags & ATOD_INT_ONLY)) {
12131
1
        if (*p == '.' && (p > p_start || to_digit((uint8_t)p[1]) < radix)) {
12132
0
            is_float = TRUE;
12133
0
            p++;
12134
0
            if (*p == sep)
12135
0
                goto fail;
12136
0
            while (to_digit((uint8_t)*p) < radix ||
12137
0
                   (*p == sep && to_digit((uint8_t)p[1]) < radix))
12138
0
                p++;
12139
0
        }
12140
1
        if (p > p_start &&
12141
1
            (((*p == 'e' || *p == 'E') && radix == 10) ||
12142
1
             ((*p == 'p' || *p == 'P') && (radix == 2 || radix == 8 || radix == 16)))) {
12143
0
            const char *p1 = p + 1;
12144
0
            is_float = TRUE;
12145
0
            if (*p1 == '+') {
12146
0
                p1++;
12147
0
            } else if (*p1 == '-') {
12148
0
                p1++;
12149
0
            }
12150
0
            if (is_digit((uint8_t)*p1)) {
12151
0
                p = p1 + 1;
12152
0
                while (is_digit((uint8_t)*p) || (*p == sep && is_digit((uint8_t)p[1])))
12153
0
                    p++;
12154
0
            }
12155
0
        }
12156
1
    }
12157
1
    if (p == p_start)
12158
0
        goto fail;
12159
12160
1
    buf = buf1;
12161
1
    buf_allocated = FALSE;
12162
1
    len = p - p_start;
12163
1
    if (unlikely((len + 2) > sizeof(buf1))) {
12164
1
        buf = js_malloc_rt(ctx->rt, len + 2); /* no exception raised */
12165
1
        if (!buf)
12166
0
            goto mem_error;
12167
1
        buf_allocated = TRUE;
12168
1
    }
12169
    /* remove the separators and the radix prefixes */
12170
1
    j = 0;
12171
1
    if (is_neg)
12172
0
        buf[j++] = '-';
12173
1.04M
    for (i = 0; i < len; i++) {
12174
1.04M
        if (p_start[i] != '_')
12175
1.04M
            buf[j++] = p_start[i];
12176
1.04M
    }
12177
1
    buf[j] = '\0';
12178
12179
1
    if (flags & ATOD_ACCEPT_SUFFIX) {
12180
1
        if (*p == 'n') {
12181
0
            p++;
12182
0
            atod_type = ATOD_TYPE_BIG_INT;
12183
1
        } else {
12184
1
            if (is_float && radix != 10)
12185
0
                goto fail;
12186
1
        }
12187
1
    } else {
12188
0
        if (atod_type == ATOD_TYPE_FLOAT64) {
12189
0
            if (is_float && radix != 10)
12190
0
                goto fail;
12191
0
        }
12192
0
    }
12193
12194
1
    switch(atod_type) {
12195
1
    case ATOD_TYPE_FLOAT64:
12196
1
        {
12197
1
            double d;
12198
1
            d = js_atod(buf, NULL, radix, is_float ? 0 : JS_ATOD_INT_ONLY,
12199
1
                        &atod_mem);
12200
            /* return int or float64 */
12201
1
            val = JS_NewFloat64(ctx, d);
12202
1
        }
12203
1
        break;
12204
0
    case ATOD_TYPE_BIG_INT:
12205
0
        {
12206
0
            JSBigInt *r;
12207
0
            if (has_legacy_octal || is_float)
12208
0
                goto fail;
12209
0
            r = js_bigint_from_string(ctx, buf, radix);
12210
0
            if (!r)
12211
0
                goto mem_error;
12212
0
            val = JS_CompactBigInt(ctx, r);
12213
0
        }
12214
0
        break;
12215
0
    default:
12216
0
        abort();
12217
1
    }
12218
12219
1
done:
12220
1
    if (buf_allocated)
12221
1
        js_free_rt(ctx->rt, buf);
12222
1
    if (pp)
12223
1
        *pp = p;
12224
1
    return val;
12225
0
 fail:
12226
0
    val = JS_NAN;
12227
0
    goto done;
12228
0
 mem_error:
12229
0
    val = JS_ThrowOutOfMemory(ctx);
12230
0
    goto done;
12231
1
}
12232
12233
typedef enum JSToNumberHintEnum {
12234
    TON_FLAG_NUMBER,
12235
    TON_FLAG_NUMERIC,
12236
} JSToNumberHintEnum;
12237
12238
static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val,
12239
                                   JSToNumberHintEnum flag)
12240
0
{
12241
0
    uint32_t tag;
12242
0
    JSValue ret;
12243
12244
0
 redo:
12245
0
    tag = JS_VALUE_GET_NORM_TAG(val);
12246
0
    switch(tag) {
12247
0
    case JS_TAG_BIG_INT:
12248
0
    case JS_TAG_SHORT_BIG_INT:
12249
0
        if (flag != TON_FLAG_NUMERIC) {
12250
0
            JS_FreeValue(ctx, val);
12251
0
            return JS_ThrowTypeError(ctx, "cannot convert bigint to number");
12252
0
        }
12253
0
        ret = val;
12254
0
        break;
12255
0
    case JS_TAG_FLOAT64:
12256
0
    case JS_TAG_INT:
12257
0
    case JS_TAG_EXCEPTION:
12258
0
        ret = val;
12259
0
        break;
12260
0
    case JS_TAG_BOOL:
12261
0
    case JS_TAG_NULL:
12262
0
        ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));
12263
0
        break;
12264
0
    case JS_TAG_UNDEFINED:
12265
0
        ret = JS_NAN;
12266
0
        break;
12267
0
    case JS_TAG_OBJECT:
12268
0
        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
12269
0
        if (JS_IsException(val))
12270
0
            return JS_EXCEPTION;
12271
0
        goto redo;
12272
0
    case JS_TAG_STRING:
12273
0
    case JS_TAG_STRING_ROPE:
12274
0
        {
12275
0
            const char *str;
12276
0
            const char *p;
12277
0
            size_t len;
12278
12279
0
            str = JS_ToCStringLen(ctx, &len, val);
12280
0
            JS_FreeValue(ctx, val);
12281
0
            if (!str)
12282
0
                return JS_EXCEPTION;
12283
0
            p = str;
12284
0
            p += skip_spaces(p);
12285
0
            if ((p - str) == len) {
12286
0
                ret = JS_NewInt32(ctx, 0);
12287
0
            } else {
12288
0
                int flags = ATOD_ACCEPT_BIN_OCT;
12289
0
                ret = js_atof(ctx, p, &p, 0, flags);
12290
0
                if (!JS_IsException(ret)) {
12291
0
                    p += skip_spaces(p);
12292
0
                    if ((p - str) != len) {
12293
0
                        JS_FreeValue(ctx, ret);
12294
0
                        ret = JS_NAN;
12295
0
                    }
12296
0
                }
12297
0
            }
12298
0
            JS_FreeCString(ctx, str);
12299
0
        }
12300
0
        break;
12301
0
    case JS_TAG_SYMBOL:
12302
0
        JS_FreeValue(ctx, val);
12303
0
        return JS_ThrowTypeError(ctx, "cannot convert symbol to number");
12304
0
    default:
12305
0
        JS_FreeValue(ctx, val);
12306
0
        ret = JS_NAN;
12307
0
        break;
12308
0
    }
12309
0
    return ret;
12310
0
}
12311
12312
static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val)
12313
0
{
12314
0
    return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMBER);
12315
0
}
12316
12317
static JSValue JS_ToNumericFree(JSContext *ctx, JSValue val)
12318
0
{
12319
0
    return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC);
12320
0
}
12321
12322
static JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val)
12323
0
{
12324
0
    return JS_ToNumericFree(ctx, JS_DupValue(ctx, val));
12325
0
}
12326
12327
static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres,
12328
                                          JSValue val)
12329
0
{
12330
0
    double d;
12331
0
    uint32_t tag;
12332
    
12333
0
    val = JS_ToNumberFree(ctx, val);
12334
0
    if (JS_IsException(val))
12335
0
        goto fail;
12336
0
    tag = JS_VALUE_GET_NORM_TAG(val);
12337
0
    switch(tag) {
12338
0
    case JS_TAG_INT:
12339
0
        d = JS_VALUE_GET_INT(val);
12340
0
        break;
12341
0
    case JS_TAG_FLOAT64:
12342
0
        d = JS_VALUE_GET_FLOAT64(val);
12343
0
        break;
12344
0
    default:
12345
0
        abort();
12346
0
    }
12347
0
    *pres = d;
12348
0
    return 0;
12349
0
 fail:
12350
0
    *pres = JS_FLOAT64_NAN;
12351
0
    return -1;
12352
0
}
12353
12354
static inline int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val)
12355
0
{
12356
0
    uint32_t tag;
12357
12358
0
    tag = JS_VALUE_GET_TAG(val);
12359
0
    if (tag <= JS_TAG_NULL) {
12360
0
        *pres = JS_VALUE_GET_INT(val);
12361
0
        return 0;
12362
0
    } else if (JS_TAG_IS_FLOAT64(tag)) {
12363
0
        *pres = JS_VALUE_GET_FLOAT64(val);
12364
0
        return 0;
12365
0
    } else {
12366
0
        return __JS_ToFloat64Free(ctx, pres, val);
12367
0
    }
12368
0
}
12369
12370
int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val)
12371
0
{
12372
0
    return JS_ToFloat64Free(ctx, pres, JS_DupValue(ctx, val));
12373
0
}
12374
12375
static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val)
12376
0
{
12377
0
    return JS_ToNumberFree(ctx, JS_DupValue(ctx, val));
12378
0
}
12379
12380
/* same as JS_ToNumber() but return 0 in case of NaN/Undefined */
12381
static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
12382
0
{
12383
0
    uint32_t tag;
12384
0
    JSValue ret;
12385
12386
0
 redo:
12387
0
    tag = JS_VALUE_GET_NORM_TAG(val);
12388
0
    switch(tag) {
12389
0
    case JS_TAG_INT:
12390
0
    case JS_TAG_BOOL:
12391
0
    case JS_TAG_NULL:
12392
0
    case JS_TAG_UNDEFINED:
12393
0
        ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));
12394
0
        break;
12395
0
    case JS_TAG_FLOAT64:
12396
0
        {
12397
0
            double d = JS_VALUE_GET_FLOAT64(val);
12398
0
            if (isnan(d)) {
12399
0
                ret = JS_NewInt32(ctx, 0);
12400
0
            } else {
12401
                /* convert -0 to +0 */
12402
0
                d = trunc(d) + 0.0;
12403
0
                ret = JS_NewFloat64(ctx, d);
12404
0
            }
12405
0
        }
12406
0
        break;
12407
0
    default:
12408
0
        val = JS_ToNumberFree(ctx, val);
12409
0
        if (JS_IsException(val))
12410
0
            return val;
12411
0
        goto redo;
12412
0
    }
12413
0
    return ret;
12414
0
}
12415
12416
/* Note: the integer value is satured to 32 bits */
12417
static int JS_ToInt32SatFree(JSContext *ctx, int *pres, JSValue val)
12418
0
{
12419
0
    uint32_t tag;
12420
0
    int ret;
12421
12422
0
 redo:
12423
0
    tag = JS_VALUE_GET_NORM_TAG(val);
12424
0
    switch(tag) {
12425
0
    case JS_TAG_INT:
12426
0
    case JS_TAG_BOOL:
12427
0
    case JS_TAG_NULL:
12428
0
    case JS_TAG_UNDEFINED:
12429
0
        ret = JS_VALUE_GET_INT(val);
12430
0
        break;
12431
0
    case JS_TAG_EXCEPTION:
12432
0
        *pres = 0;
12433
0
        return -1;
12434
0
    case JS_TAG_FLOAT64:
12435
0
        {
12436
0
            double d = JS_VALUE_GET_FLOAT64(val);
12437
0
            if (isnan(d)) {
12438
0
                ret = 0;
12439
0
            } else {
12440
0
                if (d < INT32_MIN)
12441
0
                    ret = INT32_MIN;
12442
0
                else if (d > INT32_MAX)
12443
0
                    ret = INT32_MAX;
12444
0
                else
12445
0
                    ret = (int)d;
12446
0
            }
12447
0
        }
12448
0
        break;
12449
0
    default:
12450
0
        val = JS_ToNumberFree(ctx, val);
12451
0
        if (JS_IsException(val)) {
12452
0
            *pres = 0;
12453
0
            return -1;
12454
0
        }
12455
0
        goto redo;
12456
0
    }
12457
0
    *pres = ret;
12458
0
    return 0;
12459
0
}
12460
12461
int JS_ToInt32Sat(JSContext *ctx, int *pres, JSValueConst val)
12462
0
{
12463
0
    return JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val));
12464
0
}
12465
12466
int JS_ToInt32Clamp(JSContext *ctx, int *pres, JSValueConst val,
12467
                    int min, int max, int min_offset)
12468
0
{
12469
0
    int res = JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val));
12470
0
    if (res == 0) {
12471
0
        if (*pres < min) {
12472
0
            *pres += min_offset;
12473
0
            if (*pres < min)
12474
0
                *pres = min;
12475
0
        } else {
12476
0
            if (*pres > max)
12477
0
                *pres = max;
12478
0
        }
12479
0
    }
12480
0
    return res;
12481
0
}
12482
12483
static int JS_ToInt64SatFree(JSContext *ctx, int64_t *pres, JSValue val)
12484
0
{
12485
0
    uint32_t tag;
12486
12487
0
 redo:
12488
0
    tag = JS_VALUE_GET_NORM_TAG(val);
12489
0
    switch(tag) {
12490
0
    case JS_TAG_INT:
12491
0
    case JS_TAG_BOOL:
12492
0
    case JS_TAG_NULL:
12493
0
    case JS_TAG_UNDEFINED:
12494
0
        *pres = JS_VALUE_GET_INT(val);
12495
0
        return 0;
12496
0
    case JS_TAG_EXCEPTION:
12497
0
        *pres = 0;
12498
0
        return -1;
12499
0
    case JS_TAG_FLOAT64:
12500
0
        {
12501
0
            double d = JS_VALUE_GET_FLOAT64(val);
12502
0
            if (isnan(d)) {
12503
0
                *pres = 0;
12504
0
            } else {
12505
0
                if (d < INT64_MIN)
12506
0
                    *pres = INT64_MIN;
12507
0
                else if (d >= 0x1p63) /* must use INT64_MAX + 1 because INT64_MAX cannot be exactly represented as a double */
12508
0
                    *pres = INT64_MAX;
12509
0
                else
12510
0
                    *pres = (int64_t)d;
12511
0
            }
12512
0
        }
12513
0
        return 0;
12514
0
    default:
12515
0
        val = JS_ToNumberFree(ctx, val);
12516
0
        if (JS_IsException(val)) {
12517
0
            *pres = 0;
12518
0
            return -1;
12519
0
        }
12520
0
        goto redo;
12521
0
    }
12522
0
}
12523
12524
int JS_ToInt64Sat(JSContext *ctx, int64_t *pres, JSValueConst val)
12525
0
{
12526
0
    return JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val));
12527
0
}
12528
12529
int JS_ToInt64Clamp(JSContext *ctx, int64_t *pres, JSValueConst val,
12530
                    int64_t min, int64_t max, int64_t neg_offset)
12531
0
{
12532
0
    int res = JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val));
12533
0
    if (res == 0) {
12534
0
        if (*pres < 0)
12535
0
            *pres += neg_offset;
12536
0
        if (*pres < min)
12537
0
            *pres = min;
12538
0
        else if (*pres > max)
12539
0
            *pres = max;
12540
0
    }
12541
0
    return res;
12542
0
}
12543
12544
/* Same as JS_ToInt32Free() but with a 64 bit result. Return (<0, 0)
12545
   in case of exception */
12546
static int JS_ToInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
12547
0
{
12548
0
    uint32_t tag;
12549
0
    int64_t ret;
12550
12551
0
 redo:
12552
0
    tag = JS_VALUE_GET_NORM_TAG(val);
12553
0
    switch(tag) {
12554
0
    case JS_TAG_INT:
12555
0
    case JS_TAG_BOOL:
12556
0
    case JS_TAG_NULL:
12557
0
    case JS_TAG_UNDEFINED:
12558
0
        ret = JS_VALUE_GET_INT(val);
12559
0
        break;
12560
0
    case JS_TAG_FLOAT64:
12561
0
        {
12562
0
            JSFloat64Union u;
12563
0
            double d;
12564
0
            int e;
12565
0
            d = JS_VALUE_GET_FLOAT64(val);
12566
0
            u.d = d;
12567
            /* we avoid doing fmod(x, 2^64) */
12568
0
            e = (u.u64 >> 52) & 0x7ff;
12569
0
            if (likely(e <= (1023 + 62))) {
12570
                /* fast case */
12571
0
                ret = (int64_t)d;
12572
0
            } else if (e <= (1023 + 62 + 53)) {
12573
0
                uint64_t v;
12574
                /* remainder modulo 2^64 */
12575
0
                v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);
12576
0
                ret = v << ((e - 1023) - 52);
12577
                /* take the sign into account */
12578
0
                if (u.u64 >> 63)
12579
0
                    ret = -ret;
12580
0
            } else {
12581
0
                ret = 0; /* also handles NaN and +inf */
12582
0
            }
12583
0
        }
12584
0
        break;
12585
0
    default:
12586
0
        val = JS_ToNumberFree(ctx, val);
12587
0
        if (JS_IsException(val)) {
12588
0
            *pres = 0;
12589
0
            return -1;
12590
0
        }
12591
0
        goto redo;
12592
0
    }
12593
0
    *pres = ret;
12594
0
    return 0;
12595
0
}
12596
12597
int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
12598
0
{
12599
0
    return JS_ToInt64Free(ctx, pres, JS_DupValue(ctx, val));
12600
0
}
12601
12602
int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val)
12603
0
{
12604
0
    if (JS_IsBigInt(ctx, val))
12605
0
        return JS_ToBigInt64(ctx, pres, val);
12606
0
    else
12607
0
        return JS_ToInt64(ctx, pres, val);
12608
0
}
12609
12610
/* return (<0, 0) in case of exception */
12611
static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val)
12612
0
{
12613
0
    uint32_t tag;
12614
0
    int32_t ret;
12615
12616
0
 redo:
12617
0
    tag = JS_VALUE_GET_NORM_TAG(val);
12618
0
    switch(tag) {
12619
0
    case JS_TAG_INT:
12620
0
    case JS_TAG_BOOL:
12621
0
    case JS_TAG_NULL:
12622
0
    case JS_TAG_UNDEFINED:
12623
0
        ret = JS_VALUE_GET_INT(val);
12624
0
        break;
12625
0
    case JS_TAG_FLOAT64:
12626
0
        {
12627
0
            JSFloat64Union u;
12628
0
            double d;
12629
0
            int e;
12630
0
            d = JS_VALUE_GET_FLOAT64(val);
12631
0
            u.d = d;
12632
            /* we avoid doing fmod(x, 2^32) */
12633
0
            e = (u.u64 >> 52) & 0x7ff;
12634
0
            if (likely(e <= (1023 + 30))) {
12635
                /* fast case */
12636
0
                ret = (int32_t)d;
12637
0
            } else if (e <= (1023 + 30 + 53)) {
12638
0
                uint64_t v;
12639
                /* remainder modulo 2^32 */
12640
0
                v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);
12641
0
                v = v << ((e - 1023) - 52 + 32);
12642
0
                ret = v >> 32;
12643
                /* take the sign into account */
12644
0
                if (u.u64 >> 63)
12645
0
                    ret = -ret;
12646
0
            } else {
12647
0
                ret = 0; /* also handles NaN and +inf */
12648
0
            }
12649
0
        }
12650
0
        break;
12651
0
    default:
12652
0
        val = JS_ToNumberFree(ctx, val);
12653
0
        if (JS_IsException(val)) {
12654
0
            *pres = 0;
12655
0
            return -1;
12656
0
        }
12657
0
        goto redo;
12658
0
    }
12659
0
    *pres = ret;
12660
0
    return 0;
12661
0
}
12662
12663
int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val)
12664
0
{
12665
0
    return JS_ToInt32Free(ctx, pres, JS_DupValue(ctx, val));
12666
0
}
12667
12668
static inline int JS_ToUint32Free(JSContext *ctx, uint32_t *pres, JSValue val)
12669
0
{
12670
0
    return JS_ToInt32Free(ctx, (int32_t *)pres, val);
12671
0
}
12672
12673
static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val)
12674
0
{
12675
0
    uint32_t tag;
12676
0
    int res;
12677
12678
0
 redo:
12679
0
    tag = JS_VALUE_GET_NORM_TAG(val);
12680
0
    switch(tag) {
12681
0
    case JS_TAG_INT:
12682
0
    case JS_TAG_BOOL:
12683
0
    case JS_TAG_NULL:
12684
0
    case JS_TAG_UNDEFINED:
12685
0
        res = JS_VALUE_GET_INT(val);
12686
0
        res = max_int(0, min_int(255, res));
12687
0
        break;
12688
0
    case JS_TAG_FLOAT64:
12689
0
        {
12690
0
            double d = JS_VALUE_GET_FLOAT64(val);
12691
0
            if (isnan(d)) {
12692
0
                res = 0;
12693
0
            } else {
12694
0
                if (d < 0)
12695
0
                    res = 0;
12696
0
                else if (d > 255)
12697
0
                    res = 255;
12698
0
                else
12699
0
                    res = lrint(d);
12700
0
            }
12701
0
        }
12702
0
        break;
12703
0
    default:
12704
0
        val = JS_ToNumberFree(ctx, val);
12705
0
        if (JS_IsException(val)) {
12706
0
            *pres = 0;
12707
0
            return -1;
12708
0
        }
12709
0
        goto redo;
12710
0
    }
12711
0
    *pres = res;
12712
0
    return 0;
12713
0
}
12714
12715
static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
12716
                                            JSValue val, BOOL is_array_ctor)
12717
0
{
12718
0
    uint32_t tag, len;
12719
12720
0
    tag = JS_VALUE_GET_TAG(val);
12721
0
    switch(tag) {
12722
0
    case JS_TAG_INT:
12723
0
    case JS_TAG_BOOL:
12724
0
    case JS_TAG_NULL:
12725
0
        {
12726
0
            int v;
12727
0
            v = JS_VALUE_GET_INT(val);
12728
0
            if (v < 0)
12729
0
                goto fail;
12730
0
            len = v;
12731
0
        }
12732
0
        break;
12733
0
    default:
12734
0
        if (JS_TAG_IS_FLOAT64(tag)) {
12735
0
            double d;
12736
0
            d = JS_VALUE_GET_FLOAT64(val);
12737
0
            if (!(d >= 0 && d <= UINT32_MAX))
12738
0
                goto fail;
12739
0
            len = (uint32_t)d;
12740
0
            if (len != d)
12741
0
                goto fail;
12742
0
        } else {
12743
0
            uint32_t len1;
12744
12745
0
            if (is_array_ctor) {
12746
0
                val = JS_ToNumberFree(ctx, val);
12747
0
                if (JS_IsException(val))
12748
0
                    return -1;
12749
                /* cannot recurse because val is a number */
12750
0
                if (JS_ToArrayLengthFree(ctx, &len, val, TRUE))
12751
0
                    return -1;
12752
0
            } else {
12753
                /* legacy behavior: must do the conversion twice and compare */
12754
0
                if (JS_ToUint32(ctx, &len, val)) {
12755
0
                    JS_FreeValue(ctx, val);
12756
0
                    return -1;
12757
0
                }
12758
0
                val = JS_ToNumberFree(ctx, val);
12759
0
                if (JS_IsException(val))
12760
0
                    return -1;
12761
                /* cannot recurse because val is a number */
12762
0
                if (JS_ToArrayLengthFree(ctx, &len1, val, FALSE))
12763
0
                    return -1;
12764
0
                if (len1 != len) {
12765
0
                fail:
12766
0
                    JS_ThrowRangeError(ctx, "invalid array length");
12767
0
                    return -1;
12768
0
                }
12769
0
            }
12770
0
        }
12771
0
        break;
12772
0
    }
12773
0
    *plen = len;
12774
0
    return 0;
12775
0
}
12776
12777
0
#define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1)
12778
12779
static BOOL is_safe_integer(double d)
12780
0
{
12781
0
    return isfinite(d) && floor(d) == d &&
12782
0
        fabs(d) <= (double)MAX_SAFE_INTEGER;
12783
0
}
12784
12785
int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val)
12786
0
{
12787
0
    int64_t v;
12788
0
    if (JS_ToInt64Sat(ctx, &v, val))
12789
0
        return -1;
12790
0
    if (v < 0 || v > MAX_SAFE_INTEGER) {
12791
0
        JS_ThrowRangeError(ctx, "invalid array index");
12792
0
        *plen = 0;
12793
0
        return -1;
12794
0
    }
12795
0
    *plen = v;
12796
0
    return 0;
12797
0
}
12798
12799
/* convert a value to a length between 0 and MAX_SAFE_INTEGER.
12800
   return -1 for exception */
12801
static __exception int JS_ToLengthFree(JSContext *ctx, int64_t *plen,
12802
                                       JSValue val)
12803
0
{
12804
0
    int res = JS_ToInt64Clamp(ctx, plen, val, 0, MAX_SAFE_INTEGER, 0);
12805
0
    JS_FreeValue(ctx, val);
12806
0
    return res;
12807
0
}
12808
12809
/* Note: can return an exception */
12810
static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val)
12811
0
{
12812
0
    double d;
12813
0
    if (!JS_IsNumber(val))
12814
0
        return FALSE;
12815
0
    if (unlikely(JS_ToFloat64(ctx, &d, val)))
12816
0
        return -1;
12817
0
    return isfinite(d) && floor(d) == d;
12818
0
}
12819
12820
static BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val)
12821
0
{
12822
0
    uint32_t tag;
12823
12824
0
    tag = JS_VALUE_GET_NORM_TAG(val);
12825
0
    switch(tag) {
12826
0
    case JS_TAG_INT:
12827
0
        {
12828
0
            int v;
12829
0
            v = JS_VALUE_GET_INT(val);
12830
0
            return (v < 0);
12831
0
        }
12832
0
    case JS_TAG_FLOAT64:
12833
0
        {
12834
0
            JSFloat64Union u;
12835
0
            u.d = JS_VALUE_GET_FLOAT64(val);
12836
0
            return (u.u64 >> 63);
12837
0
        }
12838
0
    case JS_TAG_SHORT_BIG_INT:
12839
0
        return (JS_VALUE_GET_SHORT_BIG_INT(val) < 0);
12840
0
    case JS_TAG_BIG_INT:
12841
0
        {
12842
0
            JSBigInt *p = JS_VALUE_GET_PTR(val);
12843
0
            return js_bigint_sign(p);
12844
0
        }
12845
0
    default:
12846
0
        return FALSE;
12847
0
    }
12848
0
}
12849
12850
static JSValue js_bigint_to_string(JSContext *ctx, JSValueConst val)
12851
0
{
12852
0
    return js_bigint_to_string1(ctx, val, 10);
12853
0
}
12854
12855
static JSValue js_dtoa2(JSContext *ctx,
12856
                        double d, int radix, int n_digits, int flags)
12857
0
{
12858
0
    char static_buf[128], *buf, *tmp_buf;
12859
0
    int len, len_max;
12860
0
    JSValue res;
12861
0
    JSDTOATempMem dtoa_mem;
12862
0
    len_max = js_dtoa_max_len(d, radix, n_digits, flags);
12863
    
12864
    /* longer buffer may be used if radix != 10 */
12865
0
    if (len_max > sizeof(static_buf) - 1) {
12866
0
        tmp_buf = js_malloc(ctx, len_max + 1);
12867
0
        if (!tmp_buf)
12868
0
            return JS_EXCEPTION;
12869
0
        buf = tmp_buf;
12870
0
    } else {
12871
0
        tmp_buf = NULL;
12872
0
        buf = static_buf;
12873
0
    }
12874
0
    len = js_dtoa(buf, d, radix, n_digits, flags, &dtoa_mem);
12875
0
    res = js_new_string8_len(ctx, buf, len);
12876
0
    js_free(ctx, tmp_buf);
12877
0
    return res;
12878
0
}
12879
12880
static JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToPropertyKey)
12881
4
{
12882
4
    uint32_t tag;
12883
4
    char buf[32];
12884
12885
4
    tag = JS_VALUE_GET_NORM_TAG(val);
12886
4
    switch(tag) {
12887
4
    case JS_TAG_STRING:
12888
4
        return JS_DupValue(ctx, val);
12889
0
    case JS_TAG_STRING_ROPE:
12890
0
        return js_linearize_string_rope(ctx, JS_DupValue(ctx, val));
12891
0
    case JS_TAG_INT:
12892
0
        {
12893
0
            size_t len;
12894
0
            len = i32toa(buf, JS_VALUE_GET_INT(val));
12895
0
            return js_new_string8_len(ctx, buf, len);
12896
0
        }
12897
0
        break;
12898
0
    case JS_TAG_BOOL:
12899
0
        return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ?
12900
0
                          JS_ATOM_true : JS_ATOM_false);
12901
0
    case JS_TAG_NULL:
12902
0
        return JS_AtomToString(ctx, JS_ATOM_null);
12903
0
    case JS_TAG_UNDEFINED:
12904
0
        return JS_AtomToString(ctx, JS_ATOM_undefined);
12905
0
    case JS_TAG_EXCEPTION:
12906
0
        return JS_EXCEPTION;
12907
0
    case JS_TAG_OBJECT:
12908
0
        {
12909
0
            JSValue val1, ret;
12910
0
            val1 = JS_ToPrimitive(ctx, val, HINT_STRING);
12911
0
            if (JS_IsException(val1))
12912
0
                return val1;
12913
0
            ret = JS_ToStringInternal(ctx, val1, is_ToPropertyKey);
12914
0
            JS_FreeValue(ctx, val1);
12915
0
            return ret;
12916
0
        }
12917
0
        break;
12918
0
    case JS_TAG_FUNCTION_BYTECODE:
12919
0
        return js_new_string8(ctx, "[function bytecode]");
12920
0
    case JS_TAG_SYMBOL:
12921
0
        if (is_ToPropertyKey) {
12922
0
            return JS_DupValue(ctx, val);
12923
0
        } else {
12924
0
            return JS_ThrowTypeError(ctx, "cannot convert symbol to string");
12925
0
        }
12926
0
    case JS_TAG_FLOAT64:
12927
0
        return js_dtoa2(ctx, JS_VALUE_GET_FLOAT64(val), 10, 0,
12928
0
                        JS_DTOA_FORMAT_FREE);
12929
0
    case JS_TAG_SHORT_BIG_INT:
12930
0
    case JS_TAG_BIG_INT:
12931
0
        return js_bigint_to_string(ctx, val);
12932
0
    default:
12933
0
        return js_new_string8(ctx, "[unsupported type]");
12934
4
    }
12935
4
}
12936
12937
JSValue JS_ToString(JSContext *ctx, JSValueConst val)
12938
0
{
12939
0
    return JS_ToStringInternal(ctx, val, FALSE);
12940
0
}
12941
12942
static JSValue JS_ToStringFree(JSContext *ctx, JSValue val)
12943
0
{
12944
0
    JSValue ret;
12945
0
    ret = JS_ToString(ctx, val);
12946
0
    JS_FreeValue(ctx, val);
12947
0
    return ret;
12948
0
}
12949
12950
static JSValue JS_ToLocaleStringFree(JSContext *ctx, JSValue val)
12951
0
{
12952
0
    if (JS_IsUndefined(val) || JS_IsNull(val))
12953
0
        return JS_ToStringFree(ctx, val);
12954
0
    return JS_InvokeFree(ctx, val, JS_ATOM_toLocaleString, 0, NULL);
12955
0
}
12956
12957
JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val)
12958
4
{
12959
4
    return JS_ToStringInternal(ctx, val, TRUE);
12960
4
}
12961
12962
static JSValue JS_ToStringCheckObject(JSContext *ctx, JSValueConst val)
12963
0
{
12964
0
    uint32_t tag = JS_VALUE_GET_TAG(val);
12965
0
    if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)
12966
0
        return JS_ThrowTypeError(ctx, "null or undefined are forbidden");
12967
0
    return JS_ToString(ctx, val);
12968
0
}
12969
12970
static JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1)
12971
0
{
12972
0
    JSValue val;
12973
0
    JSString *p;
12974
0
    int i;
12975
0
    uint32_t c;
12976
0
    StringBuffer b_s, *b = &b_s;
12977
0
    char buf[16];
12978
12979
0
    val = JS_ToStringCheckObject(ctx, val1);
12980
0
    if (JS_IsException(val))
12981
0
        return val;
12982
0
    p = JS_VALUE_GET_STRING(val);
12983
12984
0
    if (string_buffer_init(ctx, b, p->len + 2))
12985
0
        goto fail;
12986
12987
0
    if (string_buffer_putc8(b, '\"'))
12988
0
        goto fail;
12989
0
    for(i = 0; i < p->len; ) {
12990
0
        c = string_getc(p, &i);
12991
0
        switch(c) {
12992
0
        case '\t':
12993
0
            c = 't';
12994
0
            goto quote;
12995
0
        case '\r':
12996
0
            c = 'r';
12997
0
            goto quote;
12998
0
        case '\n':
12999
0
            c = 'n';
13000
0
            goto quote;
13001
0
        case '\b':
13002
0
            c = 'b';
13003
0
            goto quote;
13004
0
        case '\f':
13005
0
            c = 'f';
13006
0
            goto quote;
13007
0
        case '\"':
13008
0
        case '\\':
13009
0
        quote:
13010
0
            if (string_buffer_putc8(b, '\\'))
13011
0
                goto fail;
13012
0
            if (string_buffer_putc8(b, c))
13013
0
                goto fail;
13014
0
            break;
13015
0
        default:
13016
0
            if (c < 32 || is_surrogate(c)) {
13017
0
                snprintf(buf, sizeof(buf), "\\u%04x", c);
13018
0
                if (string_buffer_puts8(b, buf))
13019
0
                    goto fail;
13020
0
            } else {
13021
0
                if (string_buffer_putc(b, c))
13022
0
                    goto fail;
13023
0
            }
13024
0
            break;
13025
0
        }
13026
0
    }
13027
0
    if (string_buffer_putc8(b, '\"'))
13028
0
        goto fail;
13029
0
    JS_FreeValue(ctx, val);
13030
0
    return string_buffer_end(b);
13031
0
 fail:
13032
0
    JS_FreeValue(ctx, val);
13033
0
    string_buffer_free(b);
13034
0
    return JS_EXCEPTION;
13035
0
}
13036
13037
0
#define JS_PRINT_MAX_DEPTH 8
13038
13039
typedef struct {
13040
    JSRuntime *rt;
13041
    JSContext *ctx; /* may be NULL */
13042
    JSPrintValueOptions options;
13043
    JSPrintValueWrite *write_func;
13044
    void *write_opaque;
13045
    int level;
13046
    JSObject *print_stack[JS_PRINT_MAX_DEPTH]; /* level values */
13047
} JSPrintValueState;
13048
13049
static void js_print_value(JSPrintValueState *s, JSValueConst val);
13050
13051
static void js_putc(JSPrintValueState *s, char c)
13052
0
{
13053
0
    s->write_func(s->write_opaque, &c, 1);
13054
0
}
13055
13056
static void js_puts(JSPrintValueState *s, const char *str)
13057
0
{
13058
0
    s->write_func(s->write_opaque, str, strlen(str));
13059
0
}
13060
13061
static void __attribute__((format(printf, 2, 3))) js_printf(JSPrintValueState *s, const char *fmt, ...)
13062
0
{
13063
0
    va_list ap;
13064
0
    char buf[256];
13065
    
13066
0
    va_start(ap, fmt);
13067
0
    vsnprintf(buf, sizeof(buf), fmt, ap);
13068
0
    va_end(ap);
13069
0
    s->write_func(s->write_opaque, buf, strlen(buf));
13070
0
}
13071
13072
static void js_print_float64(JSPrintValueState *s, double d)
13073
0
{
13074
0
    JSDTOATempMem dtoa_mem;
13075
0
    char buf[32];
13076
0
    int len;
13077
0
    len = js_dtoa(buf, d, 10, 0, JS_DTOA_FORMAT_FREE | JS_DTOA_MINUS_ZERO, &dtoa_mem);
13078
0
    s->write_func(s->write_opaque, buf, len);
13079
0
}
13080
13081
static uint32_t js_string_get_length(JSValueConst val)
13082
0
{
13083
0
    if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
13084
0
        JSString *p = JS_VALUE_GET_STRING(val);
13085
0
        return p->len;
13086
0
    } else if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING_ROPE) {
13087
0
        JSStringRope *r = JS_VALUE_GET_PTR(val);
13088
0
        return r->len;
13089
0
    } else {
13090
0
        return 0;
13091
0
    }
13092
0
}
13093
13094
static void js_dump_char(JSPrintValueState *s, int c, int sep)
13095
0
{
13096
0
    if (c == sep || c == '\\') {
13097
0
        js_putc(s, '\\');
13098
0
        js_putc(s, c);
13099
0
    } else if (c >= ' ' && c <= 126) {
13100
0
        js_putc(s, c);
13101
0
    } else if (c == '\n') {
13102
0
        js_putc(s, '\\');
13103
0
        js_putc(s, 'n');
13104
0
    } else {
13105
0
        js_printf(s, "\\u%04x", c);
13106
0
    }
13107
0
}
13108
13109
static void js_print_string_rec(JSPrintValueState *s, JSValueConst val,
13110
                                int sep, uint32_t pos)
13111
0
{
13112
0
    if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
13113
0
        JSString *p = JS_VALUE_GET_STRING(val);
13114
0
        uint32_t i, len;
13115
0
        if (pos < s->options.max_string_length) {
13116
0
            len = min_uint32(p->len, s->options.max_string_length - pos);
13117
0
            for(i = 0; i < len; i++) {
13118
0
                js_dump_char(s, string_get(p, i), sep);
13119
0
            }
13120
0
        }
13121
0
    } else if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING_ROPE) {
13122
0
        JSStringRope *r = JS_VALUE_GET_PTR(val);
13123
0
        js_print_string_rec(s, r->left, sep, pos);
13124
0
        js_print_string_rec(s, r->right, sep, pos + js_string_get_length(r->left));
13125
0
    } else {
13126
0
        js_printf(s, "<invalid string tag %d>", (int)JS_VALUE_GET_TAG(val));
13127
0
    }
13128
0
}
13129
13130
static void js_print_string(JSPrintValueState *s, JSValueConst val)
13131
0
{
13132
0
    int sep;
13133
0
    if (s->options.raw_dump && JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
13134
0
        JSString *p = JS_VALUE_GET_STRING(val);
13135
0
        js_printf(s, "%d", p->header.ref_count);
13136
0
        sep = (p->header.ref_count == 1) ? '\"' : '\'';
13137
0
    } else {
13138
0
        sep = '\"';
13139
0
    }
13140
0
    js_putc(s, sep);
13141
0
    js_print_string_rec(s, val, sep, 0);
13142
0
    js_putc(s, sep);
13143
0
    if (js_string_get_length(val) > s->options.max_string_length) {
13144
0
        uint32_t n = js_string_get_length(val) - s->options.max_string_length;
13145
0
        js_printf(s, "... %u more character%s", n, n > 1 ? "s" : "");
13146
0
    }
13147
0
}
13148
13149
static void js_print_raw_string2(JSPrintValueState *s, JSValueConst val, BOOL remove_last_lf)
13150
0
{
13151
0
    const char *cstr;
13152
0
    size_t len;
13153
0
    cstr = JS_ToCStringLen(s->ctx, &len, val);
13154
0
    if (cstr) {
13155
0
        if (remove_last_lf && len > 0 && cstr[len - 1] == '\n')
13156
0
            len--;
13157
0
        s->write_func(s->write_opaque, cstr, len);
13158
0
        JS_FreeCString(s->ctx, cstr);
13159
0
    }
13160
0
}
13161
13162
static void js_print_raw_string(JSPrintValueState *s, JSValueConst val)
13163
0
{
13164
0
    js_print_raw_string2(s, val, FALSE);
13165
0
}
13166
13167
static BOOL is_ascii_ident(const JSString *p)
13168
0
{
13169
0
    int i, c;
13170
13171
0
    if (p->len == 0)
13172
0
        return FALSE;
13173
0
    for(i = 0; i < p->len; i++) {
13174
0
        c = string_get(p, i);
13175
0
        if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
13176
0
              (c == '_' || c == '$') || (c >= '0' && c <= '9' && i > 0)))
13177
0
            return FALSE;
13178
0
    }
13179
0
    return TRUE;
13180
0
}
13181
13182
static void js_print_atom(JSPrintValueState *s, JSAtom atom)
13183
0
{
13184
0
    int i;
13185
0
    if (__JS_AtomIsTaggedInt(atom)) {
13186
0
        js_printf(s, "%u", __JS_AtomToUInt32(atom));
13187
0
    } else if (atom == JS_ATOM_NULL) {
13188
0
        js_puts(s, "<null>");
13189
0
    } else {
13190
0
        assert(atom < s->rt->atom_size);
13191
0
        JSString *p;
13192
0
        p = s->rt->atom_array[atom];
13193
0
        if (is_ascii_ident(p)) {
13194
0
            for(i = 0; i < p->len; i++) {
13195
0
                js_putc(s, string_get(p, i));
13196
0
            }
13197
0
        } else {
13198
0
            js_putc(s, '"');
13199
0
            for(i = 0; i < p->len; i++) {
13200
0
                js_dump_char(s, string_get(p, i), '\"');
13201
0
            }
13202
0
            js_putc(s, '"');
13203
0
        }
13204
0
    }
13205
0
}
13206
13207
/* return 0 if invalid length */
13208
static uint32_t js_print_array_get_length(JSObject *p)
13209
0
{
13210
0
    JSProperty *pr;
13211
0
    JSShapeProperty *prs;
13212
0
    JSValueConst val;
13213
13214
0
    prs = find_own_property(&pr, p, JS_ATOM_length);
13215
0
    if (!prs)
13216
0
        return 0;
13217
0
    if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
13218
0
        return 0;
13219
0
    val = pr->u.value;
13220
0
    switch(JS_VALUE_GET_NORM_TAG(val)) {
13221
0
    case JS_TAG_INT:
13222
0
        return JS_VALUE_GET_INT(val);
13223
0
    case JS_TAG_FLOAT64:
13224
0
        return (uint32_t)JS_VALUE_GET_FLOAT64(val);
13225
0
    default:
13226
0
        return 0;
13227
0
    }
13228
0
}
13229
13230
static void js_print_comma(JSPrintValueState *s, int *pcomma_state)
13231
0
{
13232
0
    switch(*pcomma_state) {
13233
0
    case 0:
13234
0
        break;
13235
0
    case 1:
13236
0
        js_printf(s, ", ");
13237
0
        break;
13238
0
    case 2:
13239
0
        js_printf(s, " { ");
13240
0
        break;
13241
0
    }
13242
0
    *pcomma_state = 1;
13243
0
}
13244
13245
static void js_print_more_items(JSPrintValueState *s, int *pcomma_state,
13246
                                uint32_t n)
13247
0
{
13248
0
    js_print_comma(s, pcomma_state);
13249
0
    js_printf(s, "... %u more item%s", n, n > 1 ? "s" : "");
13250
0
}
13251
13252
static void js_print_object(JSPrintValueState *s, JSObject *p)
13253
0
{
13254
0
    JSRuntime *rt = s->rt;
13255
0
    JSShape *sh;
13256
0
    JSShapeProperty *prs;
13257
0
    JSProperty *pr;
13258
0
    int comma_state;
13259
0
    BOOL is_array;
13260
0
    uint32_t i;
13261
    
13262
0
    comma_state = 0;
13263
0
    is_array = FALSE;
13264
0
    if (p->class_id == JS_CLASS_ARRAY) {
13265
0
        is_array = TRUE;
13266
0
        js_printf(s, "[ ");
13267
        /* XXX: print array like properties even if not fast array */
13268
0
        if (p->fast_array) {
13269
0
            uint32_t len, n, len1;
13270
0
            len = js_print_array_get_length(p);
13271
13272
0
            len1 = min_uint32(p->u.array.count, s->options.max_item_count);
13273
0
            for(i = 0; i < len1; i++) {
13274
0
                js_print_comma(s, &comma_state);
13275
0
                js_print_value(s, p->u.array.u.values[i]);
13276
0
            }
13277
0
            if (len1 < p->u.array.count)
13278
0
                js_print_more_items(s, &comma_state, p->u.array.count - len1);
13279
0
            if (p->u.array.count < len) {
13280
0
                n = len - p->u.array.count;
13281
0
                js_print_comma(s, &comma_state);
13282
0
                js_printf(s, "<%u empty item%s>", n, n > 1 ? "s" : "");
13283
0
            }
13284
0
        }
13285
0
    } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
13286
0
        uint32_t size = 1 << typed_array_size_log2(p->class_id);
13287
0
        uint32_t len1;
13288
0
        int64_t v;
13289
13290
0
        js_print_atom(s, rt->class_array[p->class_id].class_name);
13291
0
        js_printf(s, "(%u) [ ", p->u.array.count);
13292
        
13293
0
        is_array = TRUE;
13294
0
        len1 = min_uint32(p->u.array.count, s->options.max_item_count);
13295
0
        for(i = 0; i < len1; i++) {
13296
0
            const uint8_t *ptr = p->u.array.u.uint8_ptr + i * size;
13297
0
            js_print_comma(s, &comma_state);
13298
0
            switch(p->class_id) {
13299
0
            case JS_CLASS_UINT8C_ARRAY:
13300
0
            case JS_CLASS_UINT8_ARRAY:
13301
0
                v = *ptr;
13302
0
                goto ta_int64;
13303
0
            case JS_CLASS_INT8_ARRAY:
13304
0
                v = *(int8_t *)ptr;
13305
0
                goto ta_int64;
13306
0
            case JS_CLASS_INT16_ARRAY:
13307
0
                v = *(int16_t *)ptr;
13308
0
                goto ta_int64;
13309
0
            case JS_CLASS_UINT16_ARRAY:
13310
0
                v = *(uint16_t *)ptr;
13311
0
                goto ta_int64;
13312
0
            case JS_CLASS_INT32_ARRAY:
13313
0
                v = *(int32_t *)ptr;
13314
0
                goto ta_int64;
13315
0
            case JS_CLASS_UINT32_ARRAY:
13316
0
                v = *(uint32_t *)ptr;
13317
0
                goto ta_int64;
13318
0
            case JS_CLASS_BIG_INT64_ARRAY:
13319
0
                v = *(int64_t *)ptr;
13320
0
            ta_int64:
13321
0
                js_printf(s, "%" PRId64, v);
13322
0
                break;
13323
0
            case JS_CLASS_BIG_UINT64_ARRAY:
13324
0
                js_printf(s, "%" PRIu64, *(uint64_t *)ptr);
13325
0
                break;
13326
0
            case JS_CLASS_FLOAT16_ARRAY:
13327
0
                js_print_float64(s, fromfp16(*(uint16_t *)ptr));
13328
0
                break;
13329
0
            case JS_CLASS_FLOAT32_ARRAY:
13330
0
                js_print_float64(s, *(float *)ptr);
13331
0
                break;
13332
0
            case JS_CLASS_FLOAT64_ARRAY:
13333
0
                js_print_float64(s, *(double *)ptr);
13334
0
                break;
13335
0
            }
13336
0
        }
13337
0
        if (len1 < p->u.array.count)
13338
0
            js_print_more_items(s, &comma_state, p->u.array.count - len1);
13339
0
    } else if (p->class_id == JS_CLASS_BYTECODE_FUNCTION ||
13340
0
               (rt->class_array[p->class_id].call != NULL &&
13341
0
                p->class_id != JS_CLASS_PROXY)) {
13342
0
        js_printf(s, "[Function");
13343
        /* XXX: allow dump without ctx */
13344
0
        if (!s->options.raw_dump && s->ctx) {
13345
0
            const char *func_name_str;
13346
0
            js_putc(s, ' ');
13347
0
            func_name_str = get_func_name(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p));
13348
0
            if (!func_name_str || func_name_str[0] == '\0')
13349
0
                js_puts(s, "(anonymous)");
13350
0
            else
13351
0
                js_puts(s, func_name_str);
13352
0
            JS_FreeCString(s->ctx, func_name_str);
13353
0
        }
13354
0
        js_printf(s, "]");
13355
0
        comma_state = 2;
13356
0
    } else if (p->class_id == JS_CLASS_MAP || p->class_id == JS_CLASS_SET) {
13357
0
        JSMapState *ms = p->u.opaque;
13358
0
        struct list_head *el;
13359
        
13360
0
        if (!ms)
13361
0
            goto default_obj;
13362
0
        js_print_atom(s, rt->class_array[p->class_id].class_name);
13363
0
        js_printf(s, "(%u) { ", ms->record_count);
13364
0
        i = 0;
13365
0
        list_for_each(el, &ms->records) {
13366
0
            JSMapRecord *mr = list_entry(el, JSMapRecord, link);
13367
0
            js_print_comma(s, &comma_state);
13368
0
            if (mr->empty)
13369
0
                continue;
13370
0
            js_print_value(s, mr->key);
13371
0
            if (p->class_id == JS_CLASS_MAP) {
13372
0
                js_printf(s, " => ");
13373
0
                js_print_value(s, mr->value);
13374
0
            }
13375
0
            i++;
13376
0
            if (i >= s->options.max_item_count)
13377
0
                break;
13378
0
        }
13379
0
        if (i < ms->record_count)
13380
0
            js_print_more_items(s, &comma_state, ms->record_count - i);
13381
0
    } else if (p->class_id == JS_CLASS_REGEXP && s->ctx && !s->options.raw_dump) {
13382
0
        JSValue str = js_regexp_toString(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), 0, NULL);
13383
0
        if (JS_IsException(str))
13384
0
            goto default_obj;
13385
0
        js_print_raw_string(s, str);
13386
0
        JS_FreeValueRT(s->rt, str);
13387
0
        comma_state = 2;
13388
0
    } else if (p->class_id == JS_CLASS_DATE && s->ctx && !s->options.raw_dump) {
13389
0
        JSValue str = get_date_string(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), 0, NULL, 0x23); /* toISOString() */
13390
0
        if (JS_IsException(str))
13391
0
            goto default_obj;
13392
0
        js_print_raw_string(s, str);
13393
0
        JS_FreeValueRT(s->rt, str);
13394
0
        comma_state = 2;
13395
0
    } else if (p->class_id == JS_CLASS_ERROR && s->ctx && !s->options.raw_dump) {
13396
0
        JSValue str = js_error_toString(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), 0, NULL);
13397
0
        if (JS_IsException(str))
13398
0
            goto default_obj;
13399
0
        js_print_raw_string(s, str);
13400
0
        JS_FreeValueRT(s->rt, str);
13401
        /* dump the stack if present */
13402
0
        str = JS_GetProperty(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), JS_ATOM_stack);
13403
0
        if (JS_IsString(str)) {
13404
0
            js_putc(s, '\n');
13405
            /* XXX: should remove the last '\n' in stack as
13406
               v8. SpiderMonkey does not do it */
13407
0
            js_print_raw_string2(s, str, TRUE);
13408
0
        }
13409
0
        JS_FreeValueRT(s->rt, str);
13410
0
        comma_state = 2;
13411
0
    } else {
13412
0
        default_obj:
13413
0
        if (p->class_id != JS_CLASS_OBJECT) {
13414
0
            js_print_atom(s, rt->class_array[p->class_id].class_name);
13415
0
            js_printf(s, " ");
13416
0
        }
13417
0
        js_printf(s, "{ ");
13418
0
    }
13419
    
13420
0
    sh = p->shape; /* the shape can be NULL while freeing an object */
13421
0
    if (sh) {
13422
0
        uint32_t j;
13423
        
13424
0
        j = 0;
13425
0
        for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
13426
0
            if (prs->atom != JS_ATOM_NULL) {
13427
0
                if (!(prs->flags & JS_PROP_ENUMERABLE) &&
13428
0
                    !s->options.show_hidden) {
13429
0
                    continue;
13430
0
                }
13431
0
                if (j < s->options.max_item_count) {
13432
0
                    pr = &p->prop[i];
13433
0
                    js_print_comma(s, &comma_state);
13434
0
                    js_print_atom(s, prs->atom);
13435
0
                    js_printf(s, ": ");
13436
                    
13437
                    /* XXX: autoinit property */
13438
0
                    if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
13439
0
                        if (s->options.raw_dump) {
13440
0
                            js_printf(s, "[Getter %p Setter %p]",
13441
0
                                    pr->u.getset.getter, pr->u.getset.setter);
13442
0
                        } else {
13443
0
                            if (pr->u.getset.getter && pr->u.getset.setter) {
13444
0
                                js_printf(s, "[Getter/Setter]");
13445
0
                            } else if (pr->u.getset.setter) {
13446
0
                                js_printf(s, "[Setter]");
13447
0
                            } else {
13448
0
                                js_printf(s, "[Getter]");
13449
0
                            }
13450
0
                        }
13451
0
                    } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
13452
0
                        if (s->options.raw_dump) {
13453
0
                            js_printf(s, "[varref %p]", (void *)pr->u.var_ref);
13454
0
                        } else {
13455
0
                            js_print_value(s, *pr->u.var_ref->pvalue);
13456
0
                        }
13457
0
                    } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
13458
0
                        if (s->options.raw_dump) {
13459
0
                            js_printf(s, "[autoinit %p %d %p]",
13460
0
                                    (void *)js_autoinit_get_realm(pr),
13461
0
                                    js_autoinit_get_id(pr),
13462
0
                                    (void *)pr->u.init.opaque);
13463
0
                        } else {
13464
                            /* XXX: could autoinit but need to restart
13465
                               the iteration */
13466
0
                            js_printf(s, "[autoinit]");
13467
0
                        }
13468
0
                    } else {
13469
0
                        js_print_value(s, pr->u.value);
13470
0
                    }
13471
0
                }
13472
0
                j++;
13473
0
            }
13474
0
        }
13475
0
        if (j > s->options.max_item_count)
13476
0
            js_print_more_items(s, &comma_state, j - s->options.max_item_count);
13477
0
    }
13478
0
    if (s->options.raw_dump && js_class_has_bytecode(p->class_id)) {
13479
0
        JSFunctionBytecode *b = p->u.func.function_bytecode;
13480
0
        if (b->closure_var_count) {
13481
0
            JSVarRef **var_refs;
13482
0
            var_refs = p->u.func.var_refs;
13483
            
13484
0
            js_print_comma(s, &comma_state);
13485
0
            js_printf(s, "[[Closure]]: [");
13486
0
            for(i = 0; i < b->closure_var_count; i++) {
13487
0
                if (i != 0)
13488
0
                    js_printf(s, ", ");
13489
0
                js_print_value(s, var_refs[i]->value);
13490
0
            }
13491
0
            js_printf(s, " ]");
13492
0
        }
13493
0
        if (p->u.func.home_object) {
13494
0
            js_print_comma(s, &comma_state);
13495
0
            js_printf(s, "[[HomeObject]]: ");
13496
0
            js_print_value(s, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object));
13497
0
        }
13498
0
    }
13499
13500
0
    if (!is_array) {
13501
0
        if (comma_state != 2) {
13502
0
            js_printf(s, " }");
13503
0
        }
13504
0
    } else {
13505
0
        js_printf(s, " ]");
13506
0
    }
13507
0
}
13508
13509
static int js_print_stack_index(JSPrintValueState *s, JSObject *p)
13510
0
{
13511
0
    int i;
13512
0
    for(i = 0; i < s->level; i++)
13513
0
        if (s->print_stack[i] == p)
13514
0
            return i;
13515
0
    return -1;
13516
0
}
13517
13518
static void js_print_value(JSPrintValueState *s, JSValueConst val)
13519
0
{
13520
0
    uint32_t tag = JS_VALUE_GET_NORM_TAG(val);
13521
0
    const char *str;
13522
13523
0
    switch(tag) {
13524
0
    case JS_TAG_INT:
13525
0
        js_printf(s, "%d", JS_VALUE_GET_INT(val));
13526
0
        break;
13527
0
    case JS_TAG_BOOL:
13528
0
        if (JS_VALUE_GET_BOOL(val))
13529
0
            str = "true";
13530
0
        else
13531
0
            str = "false";
13532
0
        goto print_str;
13533
0
    case JS_TAG_NULL:
13534
0
        str = "null";
13535
0
        goto print_str;
13536
0
    case JS_TAG_EXCEPTION:
13537
0
        str = "exception";
13538
0
        goto print_str;
13539
0
    case JS_TAG_UNINITIALIZED:
13540
0
        str = "uninitialized";
13541
0
        goto print_str;
13542
0
    case JS_TAG_UNDEFINED:
13543
0
        str = "undefined";
13544
0
    print_str:
13545
0
        js_puts(s, str);
13546
0
        break;
13547
0
    case JS_TAG_FLOAT64:
13548
0
        js_print_float64(s, JS_VALUE_GET_FLOAT64(val));
13549
0
        break;
13550
0
    case JS_TAG_SHORT_BIG_INT:
13551
0
        js_printf(s, "%" PRId64 "n", (int64_t)JS_VALUE_GET_SHORT_BIG_INT(val));
13552
0
        break;
13553
0
    case JS_TAG_BIG_INT:
13554
0
        if (!s->options.raw_dump && s->ctx) {
13555
0
            JSValue str = js_bigint_to_string(s->ctx, val);
13556
0
            if (JS_IsException(str))
13557
0
                goto raw_bigint;
13558
0
            js_print_raw_string(s, str);
13559
0
            js_putc(s, 'n');
13560
0
            JS_FreeValueRT(s->rt, str);
13561
0
        } else {
13562
0
            JSBigInt *p;
13563
0
            int sgn, i;
13564
0
        raw_bigint:
13565
0
            p = JS_VALUE_GET_PTR(val);
13566
            /* In order to avoid allocations we just dump the limbs */
13567
0
            sgn = js_bigint_sign(p);
13568
0
            if (sgn)
13569
0
                js_printf(s, "BigInt.asIntN(%d,", p->len * JS_LIMB_BITS);
13570
0
            js_printf(s, "0x");
13571
0
            for(i = p->len - 1; i >= 0; i--) {
13572
0
                if (i != p->len - 1)
13573
0
                    js_putc(s, '_');
13574
#if JS_LIMB_BITS == 32
13575
                js_printf(s, "%08x", p->tab[i]);
13576
#else
13577
0
                js_printf(s, "%016" PRIx64, p->tab[i]);
13578
0
#endif
13579
0
            }
13580
0
            js_putc(s, 'n');
13581
0
            if (sgn)
13582
0
                js_putc(s, ')');
13583
0
        }
13584
0
        break;
13585
0
    case JS_TAG_STRING:
13586
0
    case JS_TAG_STRING_ROPE:
13587
0
        if (s->options.raw_dump && tag == JS_TAG_STRING_ROPE) {
13588
0
            JSStringRope *r = JS_VALUE_GET_STRING_ROPE(val);
13589
0
            js_printf(s, "[rope len=%d depth=%d]", r->len, r->depth);
13590
0
        } else {
13591
0
            js_print_string(s, val);
13592
0
        }
13593
0
        break;
13594
0
    case JS_TAG_FUNCTION_BYTECODE:
13595
0
        {
13596
0
            JSFunctionBytecode *b = JS_VALUE_GET_PTR(val);
13597
0
            js_puts(s, "[bytecode ");
13598
0
            js_print_atom(s, b->func_name);
13599
0
            js_putc(s, ']');
13600
0
        }
13601
0
        break;
13602
0
    case JS_TAG_OBJECT:
13603
0
        {
13604
0
            JSObject *p = JS_VALUE_GET_OBJ(val);
13605
0
            int idx;
13606
0
            idx = js_print_stack_index(s, p);
13607
0
            if (idx >= 0) {
13608
0
                js_printf(s, "[circular %d]", idx);
13609
0
            } else if (s->level < s->options.max_depth) {
13610
0
                s->print_stack[s->level++] = p;
13611
0
                js_print_object(s, JS_VALUE_GET_OBJ(val));
13612
0
                s->level--;
13613
0
            } else {
13614
0
                JSAtom atom = s->rt->class_array[p->class_id].class_name;
13615
0
                js_putc(s, '[');
13616
0
                js_print_atom(s, atom);
13617
0
                if (s->options.raw_dump) {
13618
0
                    js_printf(s, " %p", (void *)p);
13619
0
                }
13620
0
                js_putc(s, ']');
13621
0
            }
13622
0
        }
13623
0
        break;
13624
0
    case JS_TAG_SYMBOL:
13625
0
        {
13626
0
            JSAtomStruct *p = JS_VALUE_GET_PTR(val);
13627
0
            js_puts(s, "Symbol(");
13628
0
            js_print_atom(s, js_get_atom_index(s->rt, p));
13629
0
            js_putc(s, ')');
13630
0
        }
13631
0
        break;
13632
0
    case JS_TAG_MODULE:
13633
0
        js_puts(s, "[module]");
13634
0
        break;
13635
0
    default:
13636
0
        js_printf(s, "[unknown tag %d]", tag);
13637
0
        break;
13638
0
    }
13639
0
}
13640
13641
void JS_PrintValueSetDefaultOptions(JSPrintValueOptions *options)
13642
0
{
13643
0
    memset(options, 0, sizeof(*options));
13644
0
    options->max_depth = 2;
13645
0
    options->max_string_length = 1000;
13646
0
    options->max_item_count = 100;
13647
0
}
13648
13649
static void JS_PrintValueInternal(JSRuntime *rt, JSContext *ctx, 
13650
                                  JSPrintValueWrite *write_func, void *write_opaque,
13651
                                  JSValueConst val, const JSPrintValueOptions *options)
13652
0
{
13653
0
    JSPrintValueState ss, *s = &ss;
13654
0
    if (options)
13655
0
        s->options = *options;
13656
0
    else
13657
0
        JS_PrintValueSetDefaultOptions(&s->options);
13658
0
    if (s->options.max_depth <= 0)
13659
0
        s->options.max_depth = JS_PRINT_MAX_DEPTH;
13660
0
    else
13661
0
        s->options.max_depth = min_int(s->options.max_depth, JS_PRINT_MAX_DEPTH);
13662
0
    if (s->options.max_string_length == 0)
13663
0
        s->options.max_string_length = UINT32_MAX;
13664
0
    if (s->options.max_item_count == 0)
13665
0
        s->options.max_item_count = UINT32_MAX;
13666
0
    s->rt = rt;
13667
0
    s->ctx = ctx;
13668
0
    s->write_func = write_func;
13669
0
    s->write_opaque = write_opaque;
13670
0
    s->level = 0;
13671
0
    js_print_value(s, val);
13672
0
}
13673
13674
void JS_PrintValueRT(JSRuntime *rt, JSPrintValueWrite *write_func, void *write_opaque,
13675
                     JSValueConst val, const JSPrintValueOptions *options)
13676
0
{
13677
0
    JS_PrintValueInternal(rt, NULL, write_func, write_opaque, val, options);
13678
0
}
13679
13680
void JS_PrintValue(JSContext *ctx, JSPrintValueWrite *write_func, void *write_opaque,
13681
                   JSValueConst val, const JSPrintValueOptions *options)
13682
0
{
13683
0
    JS_PrintValueInternal(ctx->rt, ctx, write_func, write_opaque, val, options);
13684
0
}
13685
13686
static void js_dump_value_write(void *opaque, const char *buf, size_t len)
13687
0
{
13688
0
    FILE *fo = opaque;
13689
0
    fwrite(buf, 1, len, fo);
13690
0
}
13691
13692
static __maybe_unused void print_atom(JSContext *ctx, JSAtom atom)
13693
0
{
13694
0
    JSPrintValueState ss, *s = &ss;
13695
0
    memset(s, 0, sizeof(*s));
13696
0
    s->rt = ctx->rt;
13697
0
    s->ctx = ctx;
13698
0
    s->write_func = js_dump_value_write;
13699
0
    s->write_opaque = stdout;
13700
0
    js_print_atom(s, atom);
13701
0
}
13702
13703
static __maybe_unused void JS_DumpValue(JSContext *ctx, const char *str, JSValueConst val)
13704
0
{
13705
0
    printf("%s=", str);
13706
0
    JS_PrintValue(ctx, js_dump_value_write, stdout, val, NULL);
13707
0
    printf("\n");
13708
0
}
13709
13710
static __maybe_unused void JS_DumpValueRT(JSRuntime *rt, const char *str, JSValueConst val)
13711
0
{
13712
0
    printf("%s=", str);
13713
0
    JS_PrintValueRT(rt, js_dump_value_write, stdout, val, NULL);
13714
0
    printf("\n");
13715
0
}
13716
13717
static __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt)
13718
0
{
13719
0
    printf("%14s %4s %4s %14s %s\n",
13720
0
           "ADDRESS", "REFS", "SHRF", "PROTO", "CONTENT");
13721
0
}
13722
13723
/* for debug only: dump an object without side effect */
13724
static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
13725
0
{
13726
0
    JSShape *sh;
13727
0
    JSPrintValueOptions options;
13728
0
    
13729
0
    /* XXX: should encode atoms with special characters */
13730
0
    sh = p->shape; /* the shape can be NULL while freeing an object */
13731
0
    printf("%14p %4d ",
13732
0
           (void *)p,
13733
0
           p->header.ref_count);
13734
0
    if (sh) {
13735
0
        printf("%3d%c %14p ",
13736
0
               sh->header.ref_count,
13737
0
               " *"[sh->is_hashed],
13738
0
               (void *)sh->proto);
13739
0
    } else {
13740
0
        printf("%3s  %14s ", "-", "-");
13741
0
    }
13742
0
13743
0
    JS_PrintValueSetDefaultOptions(&options);
13744
0
    options.max_depth = 1;
13745
0
    options.show_hidden = TRUE;
13746
0
    options.raw_dump = TRUE;
13747
0
    JS_PrintValueRT(rt, js_dump_value_write, stdout, JS_MKPTR(JS_TAG_OBJECT, p), &options);
13748
0
13749
0
    printf("\n");
13750
0
}
13751
13752
static __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p)
13753
0
{
13754
0
    if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {
13755
0
        JS_DumpObject(rt, (JSObject *)p);
13756
0
    } else {
13757
0
        printf("%14p %4d ",
13758
0
               (void *)p,
13759
0
               p->ref_count);
13760
0
        switch(p->gc_obj_type) {
13761
0
        case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:
13762
0
            printf("[function bytecode]");
13763
0
            break;
13764
0
        case JS_GC_OBJ_TYPE_SHAPE:
13765
0
            printf("[shape]");
13766
0
            break;
13767
0
        case JS_GC_OBJ_TYPE_VAR_REF:
13768
0
            printf("[var_ref]");
13769
0
            break;
13770
0
        case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:
13771
0
            printf("[async_function]");
13772
0
            break;
13773
0
        case JS_GC_OBJ_TYPE_JS_CONTEXT:
13774
0
            printf("[js_context]");
13775
0
            break;
13776
0
        case JS_GC_OBJ_TYPE_MODULE:
13777
0
            printf("[module]");
13778
0
            break;
13779
0
        default:
13780
0
            printf("[unknown %d]", p->gc_obj_type);
13781
0
            break;
13782
0
        }
13783
0
        printf("\n");
13784
0
    }
13785
0
}
13786
13787
/* return -1 if exception (proxy case) or TRUE/FALSE */
13788
// TODO: should take flags to make proxy resolution and exceptions optional
13789
int JS_IsArray(JSContext *ctx, JSValueConst val)
13790
0
{
13791
0
    if (js_resolve_proxy(ctx, &val, TRUE))
13792
0
        return -1;
13793
0
    if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {
13794
0
        JSObject *p = JS_VALUE_GET_OBJ(val);
13795
0
        return p->class_id == JS_CLASS_ARRAY;
13796
0
    } else {
13797
0
        return FALSE;
13798
0
    }
13799
0
}
13800
13801
static double js_pow(double a, double b)
13802
0
{
13803
0
    if (unlikely(!isfinite(b)) && fabs(a) == 1) {
13804
        /* not compatible with IEEE 754 */
13805
0
        return JS_FLOAT64_NAN;
13806
0
    } else {
13807
0
        return pow(a, b);
13808
0
    }
13809
0
}
13810
13811
JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)
13812
0
{
13813
0
#if JS_SHORT_BIG_INT_BITS == 64
13814
0
    return __JS_NewShortBigInt(ctx, v);
13815
#else
13816
    if (v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX) {
13817
        return __JS_NewShortBigInt(ctx, v);
13818
    } else {
13819
        JSBigInt *p;
13820
        p = js_bigint_new_si64(ctx, v);
13821
        if (!p)
13822
            return JS_EXCEPTION;
13823
        return JS_MKPTR(JS_TAG_BIG_INT, p);
13824
    }
13825
#endif
13826
0
}
13827
13828
JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
13829
0
{
13830
0
    if (v <= JS_SHORT_BIG_INT_MAX) {
13831
0
        return __JS_NewShortBigInt(ctx, v);
13832
0
    } else {
13833
0
        JSBigInt *p;
13834
0
        p = js_bigint_new_ui64(ctx, v);
13835
0
        if (!p)
13836
0
            return JS_EXCEPTION;
13837
0
        return JS_MKPTR(JS_TAG_BIG_INT, p);
13838
0
    }
13839
0
}
13840
13841
/* return NaN if bad bigint literal */
13842
static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val)
13843
0
{
13844
0
    const char *str, *p;
13845
0
    size_t len;
13846
0
    int flags;
13847
13848
0
    str = JS_ToCStringLen(ctx, &len, val);
13849
0
    JS_FreeValue(ctx, val);
13850
0
    if (!str)
13851
0
        return JS_EXCEPTION;
13852
0
    p = str;
13853
0
    p += skip_spaces(p);
13854
0
    if ((p - str) == len) {
13855
0
        val = JS_NewBigInt64(ctx, 0);
13856
0
    } else {
13857
0
        flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT;
13858
0
        val = js_atof(ctx, p, &p, 0, flags);
13859
0
        p += skip_spaces(p);
13860
0
        if (!JS_IsException(val)) {
13861
0
            if ((p - str) != len) {
13862
0
                JS_FreeValue(ctx, val);
13863
0
                val = JS_NAN;
13864
0
            }
13865
0
        }
13866
0
    }
13867
0
    JS_FreeCString(ctx, str);
13868
0
    return val;
13869
0
}
13870
13871
static JSValue JS_StringToBigIntErr(JSContext *ctx, JSValue val)
13872
0
{
13873
0
    val = JS_StringToBigInt(ctx, val);
13874
0
    if (JS_VALUE_IS_NAN(val))
13875
0
        return JS_ThrowSyntaxError(ctx, "invalid bigint literal");
13876
0
    return val;
13877
0
}
13878
13879
/* JS Numbers are not allowed */
13880
static JSValue JS_ToBigIntFree(JSContext *ctx, JSValue val)
13881
0
{
13882
0
    uint32_t tag;
13883
13884
0
 redo:
13885
0
    tag = JS_VALUE_GET_NORM_TAG(val);
13886
0
    switch(tag) {
13887
0
    case JS_TAG_SHORT_BIG_INT:
13888
0
    case JS_TAG_BIG_INT:
13889
0
        break;
13890
0
    case JS_TAG_INT:
13891
0
    case JS_TAG_NULL:
13892
0
    case JS_TAG_UNDEFINED:
13893
0
    case JS_TAG_FLOAT64:
13894
0
        goto fail;
13895
0
    case JS_TAG_BOOL:
13896
0
        val = __JS_NewShortBigInt(ctx, JS_VALUE_GET_INT(val));
13897
0
        break;
13898
0
    case JS_TAG_STRING:
13899
0
    case JS_TAG_STRING_ROPE:
13900
0
        val = JS_StringToBigIntErr(ctx, val);
13901
0
        if (JS_IsException(val))
13902
0
            return val;
13903
0
        goto redo;
13904
0
    case JS_TAG_OBJECT:
13905
0
        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
13906
0
        if (JS_IsException(val))
13907
0
            return val;
13908
0
        goto redo;
13909
0
    default:
13910
0
    fail:
13911
0
        JS_FreeValue(ctx, val);
13912
0
        return JS_ThrowTypeError(ctx, "cannot convert to bigint");
13913
0
    }
13914
0
    return val;
13915
0
}
13916
13917
static JSValue JS_ToBigInt(JSContext *ctx, JSValueConst val)
13918
0
{
13919
0
    return JS_ToBigIntFree(ctx, JS_DupValue(ctx, val));
13920
0
}
13921
13922
/* XXX: merge with JS_ToInt64Free with a specific flag ? */
13923
static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
13924
0
{
13925
0
    uint64_t res;
13926
13927
0
    val = JS_ToBigIntFree(ctx, val);
13928
0
    if (JS_IsException(val)) {
13929
0
        *pres = 0;
13930
0
        return -1;
13931
0
    }
13932
0
    if (JS_VALUE_GET_TAG(val) == JS_TAG_SHORT_BIG_INT) {
13933
0
        res = JS_VALUE_GET_SHORT_BIG_INT(val);
13934
0
    } else {
13935
0
        JSBigInt *p = JS_VALUE_GET_PTR(val);
13936
        /* return the value mod 2^64 */
13937
0
        res = p->tab[0];
13938
#if JS_LIMB_BITS == 32
13939
        if (p->len >= 2)
13940
            res |= (uint64_t)p->tab[1] << 32;
13941
#endif
13942
0
        JS_FreeValue(ctx, val);
13943
0
    }
13944
0
    *pres = res;
13945
0
    return 0;
13946
0
}
13947
13948
int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
13949
0
{
13950
0
    return JS_ToBigInt64Free(ctx, pres, JS_DupValue(ctx, val));
13951
0
}
13952
13953
static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
13954
                                                     JSValue *sp,
13955
                                                     OPCodeEnum op)
13956
0
{
13957
0
    JSValue op1;
13958
0
    int v;
13959
0
    uint32_t tag;
13960
0
    JSBigIntBuf buf1;
13961
0
    JSBigInt *p1;
13962
13963
0
    op1 = sp[-1];
13964
    /* fast path for float64 */
13965
0
    if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)))
13966
0
        goto handle_float64;
13967
0
    op1 = JS_ToNumericFree(ctx, op1);
13968
0
    if (JS_IsException(op1))
13969
0
        goto exception;
13970
0
    tag = JS_VALUE_GET_TAG(op1);
13971
0
    switch(tag) {
13972
0
    case JS_TAG_INT:
13973
0
        {
13974
0
            int64_t v64;
13975
0
            v64 = JS_VALUE_GET_INT(op1);
13976
0
            switch(op) {
13977
0
            case OP_inc:
13978
0
            case OP_dec:
13979
0
                v = 2 * (op - OP_dec) - 1;
13980
0
                v64 += v;
13981
0
                break;
13982
0
            case OP_plus:
13983
0
                break;
13984
0
            case OP_neg:
13985
0
                if (v64 == 0) {
13986
0
                    sp[-1] = __JS_NewFloat64(ctx, -0.0);
13987
0
                    return 0;
13988
0
                } else {
13989
0
                    v64 = -v64;
13990
0
                }
13991
0
                break;
13992
0
            default:
13993
0
                abort();
13994
0
            }
13995
0
            sp[-1] = JS_NewInt64(ctx, v64);
13996
0
        }
13997
0
        break;
13998
0
    case JS_TAG_SHORT_BIG_INT:
13999
0
        {
14000
0
            int64_t v;
14001
0
            v = JS_VALUE_GET_SHORT_BIG_INT(op1);
14002
0
            switch(op) {
14003
0
            case OP_plus:
14004
0
                JS_ThrowTypeError(ctx, "bigint argument with unary +");
14005
0
                goto exception;
14006
0
            case OP_inc:
14007
0
                if (v == JS_SHORT_BIG_INT_MAX)
14008
0
                    goto bigint_slow_case;
14009
0
                sp[-1] = __JS_NewShortBigInt(ctx, v + 1);
14010
0
                break;
14011
0
            case OP_dec:
14012
0
                if (v == JS_SHORT_BIG_INT_MIN)
14013
0
                    goto bigint_slow_case;
14014
0
                sp[-1] = __JS_NewShortBigInt(ctx, v - 1);
14015
0
                break;
14016
0
            case OP_neg:
14017
0
                v = JS_VALUE_GET_SHORT_BIG_INT(op1);
14018
0
                if (v == JS_SHORT_BIG_INT_MIN) {
14019
0
                bigint_slow_case:
14020
0
                    p1 = js_bigint_set_short(&buf1, op1);
14021
0
                    goto bigint_slow_case1;
14022
0
                }
14023
0
                sp[-1] = __JS_NewShortBigInt(ctx, -v);
14024
0
                break;
14025
0
            default:
14026
0
                abort();
14027
0
            }
14028
0
        }
14029
0
        break;
14030
0
    case JS_TAG_BIG_INT:
14031
0
        {
14032
0
            JSBigInt *r;
14033
0
            p1 = JS_VALUE_GET_PTR(op1);
14034
0
        bigint_slow_case1:
14035
0
            switch(op) {
14036
0
            case OP_plus:
14037
0
                JS_ThrowTypeError(ctx, "bigint argument with unary +");
14038
0
                JS_FreeValue(ctx, op1);
14039
0
                goto exception;
14040
0
            case OP_inc:
14041
0
            case OP_dec:
14042
0
                {
14043
0
                    JSBigIntBuf buf2;
14044
0
                    JSBigInt *p2;
14045
0
                    p2 = js_bigint_set_si(&buf2, 2 * (op - OP_dec) - 1);
14046
0
                    r = js_bigint_add(ctx, p1, p2, 0);
14047
0
                }
14048
0
                break;
14049
0
            case OP_neg:
14050
0
                r = js_bigint_neg(ctx, p1);
14051
0
                break;
14052
0
            case OP_not:
14053
0
                r = js_bigint_not(ctx, p1);
14054
0
                break;
14055
0
            default:
14056
0
                abort();
14057
0
            }
14058
0
            JS_FreeValue(ctx, op1);
14059
0
            if (!r)
14060
0
                goto exception;
14061
0
            sp[-1] = JS_CompactBigInt(ctx, r);
14062
0
        }
14063
0
        break;
14064
0
    default:
14065
0
    handle_float64:
14066
0
        {
14067
0
            double d;
14068
0
            d = JS_VALUE_GET_FLOAT64(op1);
14069
0
            switch(op) {
14070
0
            case OP_inc:
14071
0
            case OP_dec:
14072
0
                v = 2 * (op - OP_dec) - 1;
14073
0
                d += v;
14074
0
                break;
14075
0
            case OP_plus:
14076
0
                break;
14077
0
            case OP_neg:
14078
0
                d = -d;
14079
0
                break;
14080
0
            default:
14081
0
                abort();
14082
0
            }
14083
0
            sp[-1] = __JS_NewFloat64(ctx, d);
14084
0
        }
14085
0
        break;
14086
0
    }
14087
0
    return 0;
14088
0
 exception:
14089
0
    sp[-1] = JS_UNDEFINED;
14090
0
    return -1;
14091
0
}
14092
14093
static __exception int js_post_inc_slow(JSContext *ctx,
14094
                                        JSValue *sp, OPCodeEnum op)
14095
0
{
14096
0
    JSValue op1;
14097
14098
    /* XXX: allow custom operators */
14099
0
    op1 = sp[-1];
14100
0
    op1 = JS_ToNumericFree(ctx, op1);
14101
0
    if (JS_IsException(op1)) {
14102
0
        sp[-1] = JS_UNDEFINED;
14103
0
        return -1;
14104
0
    }
14105
0
    sp[-1] = op1;
14106
0
    sp[0] = JS_DupValue(ctx, op1);
14107
0
    return js_unary_arith_slow(ctx, sp + 1, op - OP_post_dec + OP_dec);
14108
0
}
14109
14110
static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
14111
0
{
14112
0
    JSValue op1;
14113
14114
0
    op1 = sp[-1];
14115
0
    op1 = JS_ToNumericFree(ctx, op1);
14116
0
    if (JS_IsException(op1))
14117
0
        goto exception;
14118
0
    if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT) {
14119
0
        sp[-1] = __JS_NewShortBigInt(ctx, ~JS_VALUE_GET_SHORT_BIG_INT(op1));
14120
0
    } else if (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) {
14121
0
        JSBigInt *r;
14122
0
        r = js_bigint_not(ctx, JS_VALUE_GET_PTR(op1));
14123
0
        JS_FreeValue(ctx, op1);
14124
0
        if (!r)
14125
0
            goto exception;
14126
0
        sp[-1] = JS_CompactBigInt(ctx, r);
14127
0
    } else {
14128
0
        int32_t v1;
14129
0
        if (unlikely(JS_ToInt32Free(ctx, &v1, op1)))
14130
0
            goto exception;
14131
0
        sp[-1] = JS_NewInt32(ctx, ~v1);
14132
0
    }
14133
0
    return 0;
14134
0
 exception:
14135
0
    sp[-1] = JS_UNDEFINED;
14136
0
    return -1;
14137
0
}
14138
14139
static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,
14140
                                                      OPCodeEnum op)
14141
0
{
14142
0
    JSValue op1, op2;
14143
0
    uint32_t tag1, tag2;
14144
0
    double d1, d2;
14145
14146
0
    op1 = sp[-2];
14147
0
    op2 = sp[-1];
14148
0
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
14149
0
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
14150
    /* fast path for float operations */
14151
0
    if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) {
14152
0
        d1 = JS_VALUE_GET_FLOAT64(op1);
14153
0
        d2 = JS_VALUE_GET_FLOAT64(op2);
14154
0
        goto handle_float64;
14155
0
    }
14156
    /* fast path for short big int operations */
14157
0
    if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) {
14158
0
        js_slimb_t v1, v2;
14159
0
        js_sdlimb_t v;
14160
0
        v1 = JS_VALUE_GET_SHORT_BIG_INT(op1);
14161
0
        v2 = JS_VALUE_GET_SHORT_BIG_INT(op2);
14162
0
        switch(op) {
14163
0
        case OP_sub:
14164
0
            v = (js_sdlimb_t)v1 - (js_sdlimb_t)v2;
14165
0
            break;
14166
0
        case OP_mul:
14167
0
            v = (js_sdlimb_t)v1 * (js_sdlimb_t)v2;
14168
0
            break;
14169
0
        case OP_div:
14170
0
            if (v2 == 0 ||
14171
0
                ((js_limb_t)v1 == (js_limb_t)1 << (JS_LIMB_BITS - 1) &&
14172
0
                 v2 == -1)) {
14173
0
                goto slow_big_int;
14174
0
            }
14175
0
            sp[-2] = __JS_NewShortBigInt(ctx, v1 / v2);
14176
0
            return 0;
14177
0
        case OP_mod:
14178
0
            if (v2 == 0 ||
14179
0
                ((js_limb_t)v1 == (js_limb_t)1 << (JS_LIMB_BITS - 1) &&
14180
0
                 v2 == -1)) {
14181
0
                goto slow_big_int;
14182
0
            }
14183
0
            sp[-2] = __JS_NewShortBigInt(ctx, v1 % v2);
14184
0
            return 0;
14185
0
        case OP_pow:
14186
0
            goto slow_big_int;
14187
0
        default:
14188
0
            abort();
14189
0
        }
14190
0
        if (likely(v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX)) {
14191
0
            sp[-2] = __JS_NewShortBigInt(ctx, v);
14192
0
        } else {
14193
0
            JSBigInt *r = js_bigint_new_di(ctx, v);
14194
0
            if (!r)
14195
0
                goto exception;
14196
0
            sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r);
14197
0
        }
14198
0
        return 0;
14199
0
    }
14200
0
    op1 = JS_ToNumericFree(ctx, op1);
14201
0
    if (JS_IsException(op1)) {
14202
0
        JS_FreeValue(ctx, op2);
14203
0
        goto exception;
14204
0
    }
14205
0
    op2 = JS_ToNumericFree(ctx, op2);
14206
0
    if (JS_IsException(op2)) {
14207
0
        JS_FreeValue(ctx, op1);
14208
0
        goto exception;
14209
0
    }
14210
0
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
14211
0
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
14212
14213
0
    if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
14214
0
        int32_t v1, v2;
14215
0
        int64_t v;
14216
0
        v1 = JS_VALUE_GET_INT(op1);
14217
0
        v2 = JS_VALUE_GET_INT(op2);
14218
0
        switch(op) {
14219
0
        case OP_sub:
14220
0
            v = (int64_t)v1 - (int64_t)v2;
14221
0
            break;
14222
0
        case OP_mul:
14223
0
            v = (int64_t)v1 * (int64_t)v2;
14224
0
            if (v == 0 && (v1 | v2) < 0) {
14225
0
                sp[-2] = __JS_NewFloat64(ctx, -0.0);
14226
0
                return 0;
14227
0
            }
14228
0
            break;
14229
0
        case OP_div:
14230
0
            sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2);
14231
0
            return 0;
14232
0
        case OP_mod:
14233
0
            if (v1 < 0 || v2 <= 0) {
14234
0
                sp[-2] = JS_NewFloat64(ctx, fmod(v1, v2));
14235
0
                return 0;
14236
0
            } else {
14237
0
                v = (int64_t)v1 % (int64_t)v2;
14238
0
            }
14239
0
            break;
14240
0
        case OP_pow:
14241
0
            sp[-2] = JS_NewFloat64(ctx, js_pow(v1, v2));
14242
0
            return 0;
14243
0
        default:
14244
0
            abort();
14245
0
        }
14246
0
        sp[-2] = JS_NewInt64(ctx, v);
14247
0
    } else if ((tag1 == JS_TAG_SHORT_BIG_INT || tag1 == JS_TAG_BIG_INT) &&
14248
0
               (tag2 == JS_TAG_SHORT_BIG_INT || tag2 == JS_TAG_BIG_INT)) {
14249
0
        JSBigInt *p1, *p2, *r;
14250
0
        JSBigIntBuf buf1, buf2;
14251
0
    slow_big_int:
14252
        /* bigint result */
14253
0
        if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT)
14254
0
            p1 = js_bigint_set_short(&buf1, op1);
14255
0
        else
14256
0
            p1 = JS_VALUE_GET_PTR(op1);
14257
0
        if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT)
14258
0
            p2 = js_bigint_set_short(&buf2, op2);
14259
0
        else
14260
0
            p2 = JS_VALUE_GET_PTR(op2);
14261
0
        switch(op) {
14262
0
        case OP_add:
14263
0
            r = js_bigint_add(ctx, p1, p2, 0);
14264
0
            break;
14265
0
        case OP_sub:
14266
0
            r = js_bigint_add(ctx, p1, p2, 1);
14267
0
            break;
14268
0
        case OP_mul:
14269
0
            r = js_bigint_mul(ctx, p1, p2);
14270
0
            break;
14271
0
        case OP_div:
14272
0
            r = js_bigint_divrem(ctx, p1, p2, FALSE);
14273
0
            break;
14274
0
        case OP_mod:
14275
0
            r = js_bigint_divrem(ctx, p1, p2, TRUE);
14276
0
            break;
14277
0
        case OP_pow:
14278
0
            r = js_bigint_pow(ctx, p1, p2);
14279
0
            break;
14280
0
        default:
14281
0
            abort();
14282
0
        }
14283
0
        JS_FreeValue(ctx, op1);
14284
0
        JS_FreeValue(ctx, op2);
14285
0
        if (!r)
14286
0
            goto exception;
14287
0
        sp[-2] = JS_CompactBigInt(ctx, r);
14288
0
    } else {
14289
0
        double dr;
14290
        /* float64 result */
14291
0
        if (JS_ToFloat64Free(ctx, &d1, op1)) {
14292
0
            JS_FreeValue(ctx, op2);
14293
0
            goto exception;
14294
0
        }
14295
0
        if (JS_ToFloat64Free(ctx, &d2, op2))
14296
0
            goto exception;
14297
0
    handle_float64:
14298
0
        switch(op) {
14299
0
        case OP_sub:
14300
0
            dr = d1 - d2;
14301
0
            break;
14302
0
        case OP_mul:
14303
0
            dr = d1 * d2;
14304
0
            break;
14305
0
        case OP_div:
14306
0
            dr = d1 / d2;
14307
0
            break;
14308
0
        case OP_mod:
14309
0
            dr = fmod(d1, d2);
14310
0
            break;
14311
0
        case OP_pow:
14312
0
            dr = js_pow(d1, d2);
14313
0
            break;
14314
0
        default:
14315
0
            abort();
14316
0
        }
14317
0
        sp[-2] = __JS_NewFloat64(ctx, dr);
14318
0
    }
14319
0
    return 0;
14320
0
 exception:
14321
0
    sp[-2] = JS_UNDEFINED;
14322
0
    sp[-1] = JS_UNDEFINED;
14323
0
    return -1;
14324
0
}
14325
14326
static inline BOOL tag_is_string(uint32_t tag)
14327
0
{
14328
0
    return tag == JS_TAG_STRING || tag == JS_TAG_STRING_ROPE;
14329
0
}
14330
14331
static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
14332
0
{
14333
0
    JSValue op1, op2;
14334
0
    uint32_t tag1, tag2;
14335
14336
0
    op1 = sp[-2];
14337
0
    op2 = sp[-1];
14338
14339
0
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
14340
0
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
14341
    /* fast path for float64 */
14342
0
    if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) {
14343
0
        double d1, d2;
14344
0
        d1 = JS_VALUE_GET_FLOAT64(op1);
14345
0
        d2 = JS_VALUE_GET_FLOAT64(op2);
14346
0
        sp[-2] = __JS_NewFloat64(ctx, d1 + d2);
14347
0
        return 0;
14348
0
    }
14349
    /* fast path for short bigint */
14350
0
    if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) {
14351
0
        js_slimb_t v1, v2;
14352
0
        js_sdlimb_t v;
14353
0
        v1 = JS_VALUE_GET_SHORT_BIG_INT(op1);
14354
0
        v2 = JS_VALUE_GET_SHORT_BIG_INT(op2);
14355
0
        v = (js_sdlimb_t)v1 + (js_sdlimb_t)v2;
14356
0
        if (likely(v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX)) {
14357
0
            sp[-2] = __JS_NewShortBigInt(ctx, v);
14358
0
        } else {
14359
0
            JSBigInt *r = js_bigint_new_di(ctx, v);
14360
0
            if (!r)
14361
0
                goto exception;
14362
0
            sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r);
14363
0
        }
14364
0
        return 0;
14365
0
    }
14366
    
14367
0
    if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) {
14368
0
        op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
14369
0
        if (JS_IsException(op1)) {
14370
0
            JS_FreeValue(ctx, op2);
14371
0
            goto exception;
14372
0
        }
14373
14374
0
        op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
14375
0
        if (JS_IsException(op2)) {
14376
0
            JS_FreeValue(ctx, op1);
14377
0
            goto exception;
14378
0
        }
14379
0
        tag1 = JS_VALUE_GET_NORM_TAG(op1);
14380
0
        tag2 = JS_VALUE_GET_NORM_TAG(op2);
14381
0
    }
14382
14383
0
    if (tag_is_string(tag1) || tag_is_string(tag2)) {
14384
0
        sp[-2] = JS_ConcatString(ctx, op1, op2);
14385
0
        if (JS_IsException(sp[-2]))
14386
0
            goto exception;
14387
0
        return 0;
14388
0
    }
14389
14390
0
    op1 = JS_ToNumericFree(ctx, op1);
14391
0
    if (JS_IsException(op1)) {
14392
0
        JS_FreeValue(ctx, op2);
14393
0
        goto exception;
14394
0
    }
14395
0
    op2 = JS_ToNumericFree(ctx, op2);
14396
0
    if (JS_IsException(op2)) {
14397
0
        JS_FreeValue(ctx, op1);
14398
0
        goto exception;
14399
0
    }
14400
0
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
14401
0
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
14402
14403
0
    if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
14404
0
        int32_t v1, v2;
14405
0
        int64_t v;
14406
0
        v1 = JS_VALUE_GET_INT(op1);
14407
0
        v2 = JS_VALUE_GET_INT(op2);
14408
0
        v = (int64_t)v1 + (int64_t)v2;
14409
0
        sp[-2] = JS_NewInt64(ctx, v);
14410
0
    } else if ((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) &&
14411
0
               (tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT)) {
14412
0
        JSBigInt *p1, *p2, *r;
14413
0
        JSBigIntBuf buf1, buf2;
14414
        /* bigint result */
14415
0
        if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT)
14416
0
            p1 = js_bigint_set_short(&buf1, op1);
14417
0
        else
14418
0
            p1 = JS_VALUE_GET_PTR(op1);
14419
0
        if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT)
14420
0
            p2 = js_bigint_set_short(&buf2, op2);
14421
0
        else
14422
0
            p2 = JS_VALUE_GET_PTR(op2);
14423
0
        r = js_bigint_add(ctx, p1, p2, 0);
14424
0
        JS_FreeValue(ctx, op1);
14425
0
        JS_FreeValue(ctx, op2);
14426
0
        if (!r)
14427
0
            goto exception;
14428
0
        sp[-2] = JS_CompactBigInt(ctx, r);
14429
0
    } else {
14430
0
        double d1, d2;
14431
        /* float64 result */
14432
0
        if (JS_ToFloat64Free(ctx, &d1, op1)) {
14433
0
            JS_FreeValue(ctx, op2);
14434
0
            goto exception;
14435
0
        }
14436
0
        if (JS_ToFloat64Free(ctx, &d2, op2))
14437
0
            goto exception;
14438
0
        sp[-2] = __JS_NewFloat64(ctx, d1 + d2);
14439
0
    }
14440
0
    return 0;
14441
0
 exception:
14442
0
    sp[-2] = JS_UNDEFINED;
14443
0
    sp[-1] = JS_UNDEFINED;
14444
0
    return -1;
14445
0
}
14446
14447
static no_inline __exception int js_binary_logic_slow(JSContext *ctx,
14448
                                                      JSValue *sp,
14449
                                                      OPCodeEnum op)
14450
0
{
14451
0
    JSValue op1, op2;
14452
0
    uint32_t tag1, tag2;
14453
0
    uint32_t v1, v2, r;
14454
14455
0
    op1 = sp[-2];
14456
0
    op2 = sp[-1];
14457
0
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
14458
0
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
14459
14460
0
    if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) {
14461
0
        js_slimb_t v1, v2, v;
14462
0
        js_sdlimb_t vd;
14463
0
        v1 = JS_VALUE_GET_SHORT_BIG_INT(op1);
14464
0
        v2 = JS_VALUE_GET_SHORT_BIG_INT(op2);
14465
        /* bigint fast path */
14466
0
        switch(op) {
14467
0
        case OP_and:
14468
0
            v = v1 & v2;
14469
0
            break;
14470
0
        case OP_or:
14471
0
            v = v1 | v2;
14472
0
            break;
14473
0
        case OP_xor:
14474
0
            v = v1 ^ v2;
14475
0
            break;
14476
0
        case OP_sar:
14477
0
            if (v2 > (JS_LIMB_BITS - 1)) {
14478
0
                goto slow_big_int;
14479
0
            } else if (v2 < 0) {
14480
0
                if (v2 < -(JS_LIMB_BITS - 1))
14481
0
                    goto slow_big_int;
14482
0
                v2 = -v2;
14483
0
                goto bigint_shl;
14484
0
            }
14485
0
        bigint_sar:
14486
0
            v = v1 >> v2;
14487
0
            break;
14488
0
        case OP_shl:
14489
0
            if (v2 > (JS_LIMB_BITS - 1)) {
14490
0
                goto slow_big_int;
14491
0
            } else if (v2 < 0) {
14492
0
                if (v2 < -(JS_LIMB_BITS - 1))
14493
0
                    goto slow_big_int;
14494
0
                v2 = -v2;
14495
0
                goto bigint_sar;
14496
0
            }
14497
0
        bigint_shl:
14498
0
            vd = (js_dlimb_t)v1 << v2;
14499
0
            if (likely(vd >= JS_SHORT_BIG_INT_MIN &&
14500
0
                       vd <= JS_SHORT_BIG_INT_MAX)) {
14501
0
                v = vd;
14502
0
            } else {
14503
0
                JSBigInt *r = js_bigint_new_di(ctx, vd);
14504
0
                if (!r)
14505
0
                    goto exception;
14506
0
                sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r);
14507
0
                return 0;
14508
0
            }
14509
0
            break;
14510
0
        default:
14511
0
            abort();
14512
0
        }
14513
0
        sp[-2] = __JS_NewShortBigInt(ctx, v);
14514
0
        return 0;
14515
0
    }
14516
0
    op1 = JS_ToNumericFree(ctx, op1);
14517
0
    if (JS_IsException(op1)) {
14518
0
        JS_FreeValue(ctx, op2);
14519
0
        goto exception;
14520
0
    }
14521
0
    op2 = JS_ToNumericFree(ctx, op2);
14522
0
    if (JS_IsException(op2)) {
14523
0
        JS_FreeValue(ctx, op1);
14524
0
        goto exception;
14525
0
    }
14526
14527
0
    tag1 = JS_VALUE_GET_TAG(op1);
14528
0
    tag2 = JS_VALUE_GET_TAG(op2);
14529
0
    if ((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) &&
14530
0
        (tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT)) {
14531
0
        JSBigInt *p1, *p2, *r;
14532
0
        JSBigIntBuf buf1, buf2;
14533
0
    slow_big_int:
14534
0
        if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT)
14535
0
            p1 = js_bigint_set_short(&buf1, op1);
14536
0
        else
14537
0
            p1 = JS_VALUE_GET_PTR(op1);
14538
0
        if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT)
14539
0
            p2 = js_bigint_set_short(&buf2, op2);
14540
0
        else
14541
0
            p2 = JS_VALUE_GET_PTR(op2);
14542
0
        switch(op) {
14543
0
        case OP_and:
14544
0
        case OP_or:
14545
0
        case OP_xor:
14546
0
            r = js_bigint_logic(ctx, p1, p2, op);
14547
0
            break;
14548
0
        case OP_shl:
14549
0
        case OP_sar:
14550
0
            {
14551
0
                js_slimb_t shift;
14552
0
                shift = js_bigint_get_si_sat(p2);
14553
0
                if (shift > INT32_MAX)
14554
0
                    shift = INT32_MAX;
14555
0
                else if (shift < -INT32_MAX)
14556
0
                    shift = -INT32_MAX;
14557
0
                if (op == OP_sar)
14558
0
                    shift = -shift;
14559
0
                if (shift >= 0)
14560
0
                    r = js_bigint_shl(ctx, p1, shift);
14561
0
                else
14562
0
                    r = js_bigint_shr(ctx, p1, -shift);
14563
0
            }
14564
0
            break;
14565
0
        default:
14566
0
            abort();
14567
0
        }
14568
0
        JS_FreeValue(ctx, op1);
14569
0
        JS_FreeValue(ctx, op2);
14570
0
        if (!r)
14571
0
            goto exception;
14572
0
        sp[-2] = JS_CompactBigInt(ctx, r);
14573
0
    } else {
14574
0
        if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {
14575
0
            JS_FreeValue(ctx, op2);
14576
0
            goto exception;
14577
0
        }
14578
0
        if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2)))
14579
0
            goto exception;
14580
0
        switch(op) {
14581
0
        case OP_shl:
14582
0
            r = v1 << (v2 & 0x1f);
14583
0
            break;
14584
0
        case OP_sar:
14585
0
            r = (int)v1 >> (v2 & 0x1f);
14586
0
            break;
14587
0
        case OP_and:
14588
0
            r = v1 & v2;
14589
0
            break;
14590
0
        case OP_or:
14591
0
            r = v1 | v2;
14592
0
            break;
14593
0
        case OP_xor:
14594
0
            r = v1 ^ v2;
14595
0
            break;
14596
0
        default:
14597
0
            abort();
14598
0
        }
14599
0
        sp[-2] = JS_NewInt32(ctx, r);
14600
0
    }
14601
0
    return 0;
14602
0
 exception:
14603
0
    sp[-2] = JS_UNDEFINED;
14604
0
    sp[-1] = JS_UNDEFINED;
14605
0
    return -1;
14606
0
}
14607
14608
/* op1 must be a bigint or int. */
14609
static JSBigInt *JS_ToBigIntBuf(JSContext *ctx, JSBigIntBuf *buf1,
14610
                                JSValue op1)
14611
0
{
14612
0
    JSBigInt *p1;
14613
    
14614
0
    switch(JS_VALUE_GET_TAG(op1)) {
14615
0
    case JS_TAG_INT:
14616
0
        p1 = js_bigint_set_si(buf1, JS_VALUE_GET_INT(op1));
14617
0
        break;
14618
0
    case JS_TAG_SHORT_BIG_INT:
14619
0
        p1 = js_bigint_set_short(buf1, op1);
14620
0
        break;
14621
0
    case JS_TAG_BIG_INT:
14622
0
        p1 = JS_VALUE_GET_PTR(op1);
14623
0
        break;
14624
0
    default:
14625
0
        abort();
14626
0
    }
14627
0
    return p1;
14628
0
}
14629
14630
/* op1 and op2 must be numeric types and at least one must be a
14631
   bigint. No exception is generated. */
14632
static int js_compare_bigint(JSContext *ctx, OPCodeEnum op,
14633
                             JSValue op1, JSValue op2)
14634
0
{
14635
0
    int res, val, tag1, tag2;
14636
0
    JSBigIntBuf buf1, buf2;
14637
0
    JSBigInt *p1, *p2;
14638
    
14639
0
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
14640
0
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
14641
0
    if ((tag1 == JS_TAG_SHORT_BIG_INT || tag1 == JS_TAG_INT) &&
14642
0
        (tag2 == JS_TAG_SHORT_BIG_INT || tag2 == JS_TAG_INT)) {
14643
        /* fast path */
14644
0
        js_slimb_t v1, v2;
14645
0
        if (tag1 == JS_TAG_INT)
14646
0
            v1 = JS_VALUE_GET_INT(op1);
14647
0
        else
14648
0
            v1 = JS_VALUE_GET_SHORT_BIG_INT(op1);
14649
0
        if (tag2 == JS_TAG_INT)
14650
0
            v2 = JS_VALUE_GET_INT(op2);
14651
0
        else
14652
0
            v2 = JS_VALUE_GET_SHORT_BIG_INT(op2);
14653
0
        val = (v1 > v2) - (v1 < v2);
14654
0
    } else {
14655
0
        if (tag1 == JS_TAG_FLOAT64) {
14656
0
            p2 = JS_ToBigIntBuf(ctx, &buf2, op2);
14657
0
            val = js_bigint_float64_cmp(ctx, p2, JS_VALUE_GET_FLOAT64(op1));
14658
0
            if (val == 2)
14659
0
                goto unordered;
14660
0
            val = -val;
14661
0
        } else if (tag2 == JS_TAG_FLOAT64) {
14662
0
            p1 = JS_ToBigIntBuf(ctx, &buf1, op1);
14663
0
            val = js_bigint_float64_cmp(ctx, p1, JS_VALUE_GET_FLOAT64(op2));
14664
0
            if (val == 2) {
14665
0
            unordered:
14666
0
                JS_FreeValue(ctx, op1);
14667
0
                JS_FreeValue(ctx, op2);
14668
0
                return FALSE;
14669
0
            }
14670
0
        } else {
14671
0
            p1 = JS_ToBigIntBuf(ctx, &buf1, op1);
14672
0
            p2 = JS_ToBigIntBuf(ctx, &buf2, op2);
14673
0
            val = js_bigint_cmp(ctx, p1, p2);
14674
0
        }
14675
0
        JS_FreeValue(ctx, op1);
14676
0
        JS_FreeValue(ctx, op2);
14677
0
    }
14678
14679
0
    switch(op) {
14680
0
    case OP_lt:
14681
0
        res = val < 0;
14682
0
        break;
14683
0
    case OP_lte:
14684
0
        res = val <= 0;
14685
0
        break;
14686
0
    case OP_gt:
14687
0
        res = val > 0;
14688
0
        break;
14689
0
    case OP_gte:
14690
0
        res = val >= 0;
14691
0
        break;
14692
0
    case OP_eq:
14693
0
        res = val == 0;
14694
0
        break;
14695
0
    default:
14696
0
        abort();
14697
0
    }
14698
0
    return res;
14699
0
}
14700
14701
static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
14702
                                        OPCodeEnum op)
14703
0
{
14704
0
    JSValue op1, op2;
14705
0
    int res;
14706
0
    uint32_t tag1, tag2;
14707
14708
0
    op1 = sp[-2];
14709
0
    op2 = sp[-1];
14710
0
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
14711
0
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
14712
0
    op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER);
14713
0
    if (JS_IsException(op1)) {
14714
0
        JS_FreeValue(ctx, op2);
14715
0
        goto exception;
14716
0
    }
14717
0
    op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER);
14718
0
    if (JS_IsException(op2)) {
14719
0
        JS_FreeValue(ctx, op1);
14720
0
        goto exception;
14721
0
    }
14722
0
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
14723
0
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
14724
14725
0
    if (tag_is_string(tag1) && tag_is_string(tag2)) {
14726
0
        if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) {
14727
0
            res = js_string_compare(ctx, JS_VALUE_GET_STRING(op1),
14728
0
                                    JS_VALUE_GET_STRING(op2));
14729
0
        } else {
14730
0
            res = js_string_rope_compare(ctx, op1, op2, FALSE);
14731
0
        }
14732
0
        switch(op) {
14733
0
        case OP_lt:
14734
0
            res = (res < 0);
14735
0
            break;
14736
0
        case OP_lte:
14737
0
            res = (res <= 0);
14738
0
            break;
14739
0
        case OP_gt:
14740
0
            res = (res > 0);
14741
0
            break;
14742
0
        default:
14743
0
        case OP_gte:
14744
0
            res = (res >= 0);
14745
0
            break;
14746
0
        }
14747
0
        JS_FreeValue(ctx, op1);
14748
0
        JS_FreeValue(ctx, op2);
14749
0
    } else if ((tag1 <= JS_TAG_NULL || tag1 == JS_TAG_FLOAT64) &&
14750
0
               (tag2 <= JS_TAG_NULL || tag2 == JS_TAG_FLOAT64)) {
14751
        /* fast path for float64/int */
14752
0
        goto float64_compare;
14753
0
    } else {
14754
0
        if ((((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) &&
14755
0
              tag_is_string(tag2)) ||
14756
0
             ((tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) &&
14757
0
              tag_is_string(tag1)))) {
14758
0
            if (tag_is_string(tag1)) {
14759
0
                op1 = JS_StringToBigInt(ctx, op1);
14760
0
                if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT &&
14761
0
                    JS_VALUE_GET_TAG(op1) != JS_TAG_SHORT_BIG_INT)
14762
0
                    goto invalid_bigint_string;
14763
0
            }
14764
0
            if (tag_is_string(tag2)) {
14765
0
                op2 = JS_StringToBigInt(ctx, op2);
14766
0
                if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT &&
14767
0
                    JS_VALUE_GET_TAG(op2) != JS_TAG_SHORT_BIG_INT) {
14768
0
                invalid_bigint_string:
14769
0
                    JS_FreeValue(ctx, op1);
14770
0
                    JS_FreeValue(ctx, op2);
14771
0
                    res = FALSE;
14772
0
                    goto done;
14773
0
                }
14774
0
            }
14775
0
        } else {
14776
0
            op1 = JS_ToNumericFree(ctx, op1);
14777
0
            if (JS_IsException(op1)) {
14778
0
                JS_FreeValue(ctx, op2);
14779
0
                goto exception;
14780
0
            }
14781
0
            op2 = JS_ToNumericFree(ctx, op2);
14782
0
            if (JS_IsException(op2)) {
14783
0
                JS_FreeValue(ctx, op1);
14784
0
                goto exception;
14785
0
            }
14786
0
        }
14787
14788
0
        tag1 = JS_VALUE_GET_NORM_TAG(op1);
14789
0
        tag2 = JS_VALUE_GET_NORM_TAG(op2);
14790
14791
0
        if (tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT ||
14792
0
            tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) {
14793
0
            res = js_compare_bigint(ctx, op, op1, op2);
14794
0
        } else {
14795
0
            double d1, d2;
14796
14797
0
        float64_compare:
14798
            /* can use floating point comparison */
14799
0
            if (tag1 == JS_TAG_FLOAT64) {
14800
0
                d1 = JS_VALUE_GET_FLOAT64(op1);
14801
0
            } else {
14802
0
                d1 = JS_VALUE_GET_INT(op1);
14803
0
            }
14804
0
            if (tag2 == JS_TAG_FLOAT64) {
14805
0
                d2 = JS_VALUE_GET_FLOAT64(op2);
14806
0
            } else {
14807
0
                d2 = JS_VALUE_GET_INT(op2);
14808
0
            }
14809
0
            switch(op) {
14810
0
            case OP_lt:
14811
0
                res = (d1 < d2); /* if NaN return false */
14812
0
                break;
14813
0
            case OP_lte:
14814
0
                res = (d1 <= d2); /* if NaN return false */
14815
0
                break;
14816
0
            case OP_gt:
14817
0
                res = (d1 > d2); /* if NaN return false */
14818
0
                break;
14819
0
            default:
14820
0
            case OP_gte:
14821
0
                res = (d1 >= d2); /* if NaN return false */
14822
0
                break;
14823
0
            }
14824
0
        }
14825
0
    }
14826
0
 done:
14827
0
    sp[-2] = JS_NewBool(ctx, res);
14828
0
    return 0;
14829
0
 exception:
14830
0
    sp[-2] = JS_UNDEFINED;
14831
0
    sp[-1] = JS_UNDEFINED;
14832
0
    return -1;
14833
0
}
14834
14835
static BOOL tag_is_number(uint32_t tag)
14836
0
{
14837
0
    return (tag == JS_TAG_INT || 
14838
0
            tag == JS_TAG_FLOAT64 ||
14839
0
            tag == JS_TAG_BIG_INT || tag == JS_TAG_SHORT_BIG_INT);
14840
0
}
14841
14842
static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
14843
                                            BOOL is_neq)
14844
0
{
14845
0
    JSValue op1, op2;
14846
0
    int res;
14847
0
    uint32_t tag1, tag2;
14848
14849
0
    op1 = sp[-2];
14850
0
    op2 = sp[-1];
14851
0
 redo:
14852
0
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
14853
0
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
14854
0
    if (tag_is_number(tag1) && tag_is_number(tag2)) {
14855
0
        if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {
14856
0
            res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);
14857
0
        } else if ((tag1 == JS_TAG_FLOAT64 &&
14858
0
                    (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64)) ||
14859
0
                   (tag2 == JS_TAG_FLOAT64 &&
14860
0
                    (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64))) {
14861
0
            double d1, d2;
14862
0
            if (tag1 == JS_TAG_FLOAT64) {
14863
0
                d1 = JS_VALUE_GET_FLOAT64(op1);
14864
0
            } else {
14865
0
                d1 = JS_VALUE_GET_INT(op1);
14866
0
            }
14867
0
            if (tag2 == JS_TAG_FLOAT64) {
14868
0
                d2 = JS_VALUE_GET_FLOAT64(op2);
14869
0
            } else {
14870
0
                d2 = JS_VALUE_GET_INT(op2);
14871
0
            }
14872
0
            res = (d1 == d2);
14873
0
        } else {
14874
0
            res = js_compare_bigint(ctx, OP_eq, op1, op2);
14875
0
        }
14876
0
    } else if (tag1 == tag2) {
14877
0
        res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
14878
0
    } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) ||
14879
0
               (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) {
14880
0
        res = TRUE;
14881
0
    } else if (tag_is_string(tag1) && tag_is_string(tag2)) {
14882
        /* needed when comparing strings and ropes */
14883
0
        res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
14884
0
    } else if ((tag_is_string(tag1) && tag_is_number(tag2)) ||
14885
0
               (tag_is_string(tag2) && tag_is_number(tag1))) {
14886
14887
0
        if (tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT ||
14888
0
            tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) {
14889
0
            if (tag_is_string(tag1)) {
14890
0
                op1 = JS_StringToBigInt(ctx, op1);
14891
0
                if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT &&
14892
0
                    JS_VALUE_GET_TAG(op1) != JS_TAG_SHORT_BIG_INT)
14893
0
                    goto invalid_bigint_string;
14894
0
            }
14895
0
            if (tag_is_string(tag2)) {
14896
0
                op2 = JS_StringToBigInt(ctx, op2);
14897
0
                if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT &&
14898
0
                    JS_VALUE_GET_TAG(op2) != JS_TAG_SHORT_BIG_INT ) {
14899
0
                invalid_bigint_string:
14900
0
                    JS_FreeValue(ctx, op1);
14901
0
                    JS_FreeValue(ctx, op2);
14902
0
                    res = FALSE;
14903
0
                    goto done;
14904
0
                }
14905
0
            }
14906
0
        } else {
14907
0
            op1 = JS_ToNumericFree(ctx, op1);
14908
0
            if (JS_IsException(op1)) {
14909
0
                JS_FreeValue(ctx, op2);
14910
0
                goto exception;
14911
0
            }
14912
0
            op2 = JS_ToNumericFree(ctx, op2);
14913
0
            if (JS_IsException(op2)) {
14914
0
                JS_FreeValue(ctx, op1);
14915
0
                goto exception;
14916
0
            }
14917
0
        }
14918
0
        res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);
14919
0
    } else if (tag1 == JS_TAG_BOOL) {
14920
0
        op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1));
14921
0
        goto redo;
14922
0
    } else if (tag2 == JS_TAG_BOOL) {
14923
0
        op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2));
14924
0
        goto redo;
14925
0
    } else if ((tag1 == JS_TAG_OBJECT &&
14926
0
                (tag_is_number(tag2) || tag_is_string(tag2) || tag2 == JS_TAG_SYMBOL)) ||
14927
0
               (tag2 == JS_TAG_OBJECT &&
14928
0
                (tag_is_number(tag1) || tag_is_string(tag1) || tag1 == JS_TAG_SYMBOL))) {
14929
0
        op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
14930
0
        if (JS_IsException(op1)) {
14931
0
            JS_FreeValue(ctx, op2);
14932
0
            goto exception;
14933
0
        }
14934
0
        op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
14935
0
        if (JS_IsException(op2)) {
14936
0
            JS_FreeValue(ctx, op1);
14937
0
            goto exception;
14938
0
        }
14939
0
        goto redo;
14940
0
    } else {
14941
        /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */
14942
0
        if ((JS_IsHTMLDDA(ctx, op1) &&
14943
0
             (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) ||
14944
0
            (JS_IsHTMLDDA(ctx, op2) &&
14945
0
             (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) {
14946
0
            res = TRUE;
14947
0
        } else {
14948
0
            res = FALSE;
14949
0
        }
14950
0
        JS_FreeValue(ctx, op1);
14951
0
        JS_FreeValue(ctx, op2);
14952
0
    }
14953
0
 done:
14954
0
    sp[-2] = JS_NewBool(ctx, res ^ is_neq);
14955
0
    return 0;
14956
0
 exception:
14957
0
    sp[-2] = JS_UNDEFINED;
14958
0
    sp[-1] = JS_UNDEFINED;
14959
0
    return -1;
14960
0
}
14961
14962
static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp)
14963
0
{
14964
0
    JSValue op1, op2;
14965
0
    uint32_t v1, v2, r;
14966
14967
0
    op1 = sp[-2];
14968
0
    op2 = sp[-1];
14969
0
    op1 = JS_ToNumericFree(ctx, op1);
14970
0
    if (JS_IsException(op1)) {
14971
0
        JS_FreeValue(ctx, op2);
14972
0
        goto exception;
14973
0
    }
14974
0
    op2 = JS_ToNumericFree(ctx, op2);
14975
0
    if (JS_IsException(op2)) {
14976
0
        JS_FreeValue(ctx, op1);
14977
0
        goto exception;
14978
0
    }
14979
0
    if (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT ||
14980
0
        JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT ||
14981
0
        JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_INT ||
14982
0
        JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT) {
14983
0
        JS_ThrowTypeError(ctx, "bigint operands are forbidden for >>>");
14984
0
        JS_FreeValue(ctx, op1);
14985
0
        JS_FreeValue(ctx, op2);
14986
0
        goto exception;
14987
0
    }
14988
    /* cannot give an exception */
14989
0
    JS_ToUint32Free(ctx, &v1, op1);
14990
0
    JS_ToUint32Free(ctx, &v2, op2);
14991
0
    r = v1 >> (v2 & 0x1f);
14992
0
    sp[-2] = JS_NewUint32(ctx, r);
14993
0
    return 0;
14994
0
 exception:
14995
0
    sp[-2] = JS_UNDEFINED;
14996
0
    sp[-1] = JS_UNDEFINED;
14997
0
    return -1;
14998
0
}
14999
15000
/* XXX: Should take JSValueConst arguments */
15001
static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
15002
                          JSStrictEqModeEnum eq_mode)
15003
0
{
15004
0
    BOOL res;
15005
0
    int tag1, tag2;
15006
0
    double d1, d2;
15007
15008
0
    tag1 = JS_VALUE_GET_NORM_TAG(op1);
15009
0
    tag2 = JS_VALUE_GET_NORM_TAG(op2);
15010
0
    switch(tag1) {
15011
0
    case JS_TAG_BOOL:
15012
0
        if (tag1 != tag2) {
15013
0
            res = FALSE;
15014
0
        } else {
15015
0
            res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);
15016
0
            goto done_no_free;
15017
0
        }
15018
0
        break;
15019
0
    case JS_TAG_NULL:
15020
0
    case JS_TAG_UNDEFINED:
15021
0
        res = (tag1 == tag2);
15022
0
        break;
15023
0
    case JS_TAG_STRING:
15024
0
    case JS_TAG_STRING_ROPE:
15025
0
        {
15026
0
            if (!tag_is_string(tag2)) {
15027
0
                res = FALSE;
15028
0
            } else if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) {
15029
0
                res = (js_string_compare(ctx, JS_VALUE_GET_STRING(op1),
15030
0
                                         JS_VALUE_GET_STRING(op2)) == 0);
15031
0
            } else {
15032
0
                res = (js_string_rope_compare(ctx, op1, op2, TRUE) == 0);
15033
0
            }
15034
0
        }
15035
0
        break;
15036
0
    case JS_TAG_SYMBOL:
15037
0
        {
15038
0
            JSAtomStruct *p1, *p2;
15039
0
            if (tag1 != tag2) {
15040
0
                res = FALSE;
15041
0
            } else {
15042
0
                p1 = JS_VALUE_GET_PTR(op1);
15043
0
                p2 = JS_VALUE_GET_PTR(op2);
15044
0
                res = (p1 == p2);
15045
0
            }
15046
0
        }
15047
0
        break;
15048
0
    case JS_TAG_OBJECT:
15049
0
        if (tag1 != tag2)
15050
0
            res = FALSE;
15051
0
        else
15052
0
            res = JS_VALUE_GET_OBJ(op1) == JS_VALUE_GET_OBJ(op2);
15053
0
        break;
15054
0
    case JS_TAG_INT:
15055
0
        d1 = JS_VALUE_GET_INT(op1);
15056
0
        if (tag2 == JS_TAG_INT) {
15057
0
            d2 = JS_VALUE_GET_INT(op2);
15058
0
            goto number_test;
15059
0
        } else if (tag2 == JS_TAG_FLOAT64) {
15060
0
            d2 = JS_VALUE_GET_FLOAT64(op2);
15061
0
            goto number_test;
15062
0
        } else {
15063
0
            res = FALSE;
15064
0
        }
15065
0
        break;
15066
0
    case JS_TAG_FLOAT64:
15067
0
        d1 = JS_VALUE_GET_FLOAT64(op1);
15068
0
        if (tag2 == JS_TAG_FLOAT64) {
15069
0
            d2 = JS_VALUE_GET_FLOAT64(op2);
15070
0
        } else if (tag2 == JS_TAG_INT) {
15071
0
            d2 = JS_VALUE_GET_INT(op2);
15072
0
        } else {
15073
0
            res = FALSE;
15074
0
            break;
15075
0
        }
15076
0
    number_test:
15077
0
        if (unlikely(eq_mode >= JS_EQ_SAME_VALUE)) {
15078
0
            JSFloat64Union u1, u2;
15079
            /* NaN is not always normalized, so this test is necessary */
15080
0
            if (isnan(d1) || isnan(d2)) {
15081
0
                res = isnan(d1) == isnan(d2);
15082
0
            } else if (eq_mode == JS_EQ_SAME_VALUE_ZERO) {
15083
0
                res = (d1 == d2); /* +0 == -0 */
15084
0
            } else {
15085
0
                u1.d = d1;
15086
0
                u2.d = d2;
15087
0
                res = (u1.u64 == u2.u64); /* +0 != -0 */
15088
0
            }
15089
0
        } else {
15090
0
            res = (d1 == d2); /* if NaN return false and +0 == -0 */
15091
0
        }
15092
0
        goto done_no_free;
15093
0
    case JS_TAG_SHORT_BIG_INT:
15094
0
    case JS_TAG_BIG_INT:
15095
0
        {
15096
0
            JSBigIntBuf buf1, buf2;
15097
0
            JSBigInt *p1, *p2;
15098
15099
0
            if (tag2 != JS_TAG_SHORT_BIG_INT &&
15100
0
                tag2 != JS_TAG_BIG_INT) {
15101
0
                res = FALSE;
15102
0
                break;
15103
0
            }
15104
            
15105
0
            if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT)
15106
0
                p1 = js_bigint_set_short(&buf1, op1);
15107
0
            else
15108
0
                p1 = JS_VALUE_GET_PTR(op1);
15109
0
            if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT)
15110
0
                p2 = js_bigint_set_short(&buf2, op2);
15111
0
            else
15112
0
                p2 = JS_VALUE_GET_PTR(op2);
15113
0
            res = (js_bigint_cmp(ctx, p1, p2) == 0);
15114
0
        }
15115
0
        break;
15116
0
    default:
15117
0
        res = FALSE;
15118
0
        break;
15119
0
    }
15120
0
    JS_FreeValue(ctx, op1);
15121
0
    JS_FreeValue(ctx, op2);
15122
0
 done_no_free:
15123
0
    return res;
15124
0
}
15125
15126
static BOOL js_strict_eq(JSContext *ctx, JSValueConst op1, JSValueConst op2)
15127
0
{
15128
0
    return js_strict_eq2(ctx,
15129
0
                         JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),
15130
0
                         JS_EQ_STRICT);
15131
0
}
15132
15133
BOOL JS_StrictEq(JSContext *ctx, JSValueConst op1, JSValueConst op2)
15134
0
{
15135
0
    return js_strict_eq(ctx, op1, op2);
15136
0
}
15137
15138
static BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2)
15139
0
{
15140
0
    return js_strict_eq2(ctx,
15141
0
                         JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),
15142
0
                         JS_EQ_SAME_VALUE);
15143
0
}
15144
15145
BOOL JS_SameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2)
15146
0
{
15147
0
    return js_same_value(ctx, op1, op2);
15148
0
}
15149
15150
static BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2)
15151
0
{
15152
0
    return js_strict_eq2(ctx,
15153
0
                         JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),
15154
0
                         JS_EQ_SAME_VALUE_ZERO);
15155
0
}
15156
15157
BOOL JS_SameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2)
15158
0
{
15159
0
    return js_same_value_zero(ctx, op1, op2);
15160
0
}
15161
15162
static no_inline int js_strict_eq_slow(JSContext *ctx, JSValue *sp,
15163
                                       BOOL is_neq)
15164
0
{
15165
0
    BOOL res;
15166
0
    res = js_strict_eq2(ctx, sp[-2], sp[-1], JS_EQ_STRICT);
15167
0
    sp[-2] = JS_NewBool(ctx, res ^ is_neq);
15168
0
    return 0;
15169
0
}
15170
15171
static __exception int js_operator_in(JSContext *ctx, JSValue *sp)
15172
0
{
15173
0
    JSValue op1, op2;
15174
0
    JSAtom atom;
15175
0
    int ret;
15176
15177
0
    op1 = sp[-2];
15178
0
    op2 = sp[-1];
15179
15180
0
    if (JS_VALUE_GET_TAG(op2) != JS_TAG_OBJECT) {
15181
0
        JS_ThrowTypeError(ctx, "invalid 'in' operand");
15182
0
        return -1;
15183
0
    }
15184
0
    atom = JS_ValueToAtom(ctx, op1);
15185
0
    if (unlikely(atom == JS_ATOM_NULL))
15186
0
        return -1;
15187
0
    ret = JS_HasProperty(ctx, op2, atom);
15188
0
    JS_FreeAtom(ctx, atom);
15189
0
    if (ret < 0)
15190
0
        return -1;
15191
0
    JS_FreeValue(ctx, op1);
15192
0
    JS_FreeValue(ctx, op2);
15193
0
    sp[-2] = JS_NewBool(ctx, ret);
15194
0
    return 0;
15195
0
}
15196
15197
static __exception int js_operator_private_in(JSContext *ctx, JSValue *sp)
15198
0
{
15199
0
    JSValue op1, op2;
15200
0
    int ret;
15201
15202
0
    op1 = sp[-2]; /* object */
15203
0
    op2 = sp[-1]; /* field name or method function */
15204
15205
0
    if (JS_VALUE_GET_TAG(op1) != JS_TAG_OBJECT) {
15206
0
        JS_ThrowTypeError(ctx, "invalid 'in' operand");
15207
0
        return -1;
15208
0
    }
15209
0
    if (JS_IsObject(op2)) {
15210
        /* method: use the brand */
15211
0
        ret = JS_CheckBrand(ctx, op1, op2);
15212
0
        if (ret < 0)
15213
0
            return -1;
15214
0
    } else {
15215
0
        JSAtom atom;
15216
0
        JSObject *p;
15217
0
        JSShapeProperty *prs;
15218
0
        JSProperty *pr;
15219
        /* field */
15220
0
        atom = JS_ValueToAtom(ctx, op2);
15221
0
        if (unlikely(atom == JS_ATOM_NULL))
15222
0
            return -1;
15223
0
        p = JS_VALUE_GET_OBJ(op1);
15224
0
        prs = find_own_property(&pr, p, atom);
15225
0
        JS_FreeAtom(ctx, atom);
15226
0
        ret = (prs != NULL);
15227
0
    }
15228
0
    JS_FreeValue(ctx, op1);
15229
0
    JS_FreeValue(ctx, op2);
15230
0
    sp[-2] = JS_NewBool(ctx, ret);
15231
0
    return 0;
15232
0
}
15233
15234
static __exception int js_has_unscopable(JSContext *ctx, JSValueConst obj,
15235
                                         JSAtom atom)
15236
0
{
15237
0
    JSValue arr, val;
15238
0
    int ret;
15239
15240
0
    arr = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_unscopables);
15241
0
    if (JS_IsException(arr))
15242
0
        return -1;
15243
0
    ret = 0;
15244
0
    if (JS_IsObject(arr)) {
15245
0
        val = JS_GetProperty(ctx, arr, atom);
15246
0
        ret = JS_ToBoolFree(ctx, val);
15247
0
    }
15248
0
    JS_FreeValue(ctx, arr);
15249
0
    return ret;
15250
0
}
15251
15252
static __exception int js_operator_instanceof(JSContext *ctx, JSValue *sp)
15253
0
{
15254
0
    JSValue op1, op2;
15255
0
    BOOL ret;
15256
15257
0
    op1 = sp[-2];
15258
0
    op2 = sp[-1];
15259
0
    ret = JS_IsInstanceOf(ctx, op1, op2);
15260
0
    if (ret < 0)
15261
0
        return ret;
15262
0
    JS_FreeValue(ctx, op1);
15263
0
    JS_FreeValue(ctx, op2);
15264
0
    sp[-2] = JS_NewBool(ctx, ret);
15265
0
    return 0;
15266
0
}
15267
15268
static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1)
15269
0
{
15270
0
    JSAtom atom;
15271
0
    uint32_t tag;
15272
15273
0
    tag = JS_VALUE_GET_NORM_TAG(op1);
15274
0
    switch(tag) {
15275
0
    case JS_TAG_SHORT_BIG_INT:
15276
0
    case JS_TAG_BIG_INT:
15277
0
        atom = JS_ATOM_bigint;
15278
0
        break;
15279
0
    case JS_TAG_INT:
15280
0
    case JS_TAG_FLOAT64:
15281
0
        atom = JS_ATOM_number;
15282
0
        break;
15283
0
    case JS_TAG_UNDEFINED:
15284
0
        atom = JS_ATOM_undefined;
15285
0
        break;
15286
0
    case JS_TAG_BOOL:
15287
0
        atom = JS_ATOM_boolean;
15288
0
        break;
15289
0
    case JS_TAG_STRING:
15290
0
    case JS_TAG_STRING_ROPE:
15291
0
        atom = JS_ATOM_string;
15292
0
        break;
15293
0
    case JS_TAG_OBJECT:
15294
0
        {
15295
0
            JSObject *p;
15296
0
            p = JS_VALUE_GET_OBJ(op1);
15297
0
            if (unlikely(p->is_HTMLDDA))
15298
0
                atom = JS_ATOM_undefined;
15299
0
            else if (JS_IsFunction(ctx, op1))
15300
0
                atom = JS_ATOM_function;
15301
0
            else
15302
0
                goto obj_type;
15303
0
        }
15304
0
        break;
15305
0
    case JS_TAG_NULL:
15306
0
    obj_type:
15307
0
        atom = JS_ATOM_object;
15308
0
        break;
15309
0
    case JS_TAG_SYMBOL:
15310
0
        atom = JS_ATOM_symbol;
15311
0
        break;
15312
0
    default:
15313
0
        atom = JS_ATOM_unknown;
15314
0
        break;
15315
0
    }
15316
0
    return atom;
15317
0
}
15318
15319
static __exception int js_operator_delete(JSContext *ctx, JSValue *sp)
15320
0
{
15321
0
    JSValue op1, op2;
15322
0
    JSAtom atom;
15323
0
    int ret;
15324
15325
0
    op1 = sp[-2];
15326
0
    op2 = sp[-1];
15327
0
    atom = JS_ValueToAtom(ctx, op2);
15328
0
    if (unlikely(atom == JS_ATOM_NULL))
15329
0
        return -1;
15330
0
    ret = JS_DeleteProperty(ctx, op1, atom, JS_PROP_THROW_STRICT);
15331
0
    JS_FreeAtom(ctx, atom);
15332
0
    if (unlikely(ret < 0))
15333
0
        return -1;
15334
0
    JS_FreeValue(ctx, op1);
15335
0
    JS_FreeValue(ctx, op2);
15336
0
    sp[-2] = JS_NewBool(ctx, ret);
15337
0
    return 0;
15338
0
}
15339
15340
/* XXX: not 100% compatible, but mozilla seems to use a similar
15341
   implementation to ensure that caller in non strict mode does not
15342
   throw (ES5 compatibility) */
15343
static JSValue js_throw_type_error(JSContext *ctx, JSValueConst this_val,
15344
                                   int argc, JSValueConst *argv)
15345
0
{
15346
0
    JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
15347
0
    if (!b || (b->js_mode & JS_MODE_STRICT) || !b->has_prototype || argc >= 1) {
15348
0
        return JS_ThrowTypeError(ctx, "invalid property access");
15349
0
    }
15350
0
    return JS_UNDEFINED;
15351
0
}
15352
15353
static JSValue js_function_proto_fileName(JSContext *ctx,
15354
                                          JSValueConst this_val)
15355
0
{
15356
0
    JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
15357
0
    if (b && b->has_debug) {
15358
0
        return JS_AtomToString(ctx, b->debug.filename);
15359
0
    }
15360
0
    return JS_UNDEFINED;
15361
0
}
15362
15363
static JSValue js_function_proto_lineNumber(JSContext *ctx,
15364
                                            JSValueConst this_val, int is_col)
15365
0
{
15366
0
    JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);
15367
0
    if (b && b->has_debug) {
15368
0
        int line_num, col_num;
15369
0
        line_num = find_line_num(ctx, b, -1, &col_num);
15370
0
        if (is_col)
15371
0
            return JS_NewInt32(ctx, col_num);
15372
0
        else
15373
0
            return JS_NewInt32(ctx, line_num);
15374
0
    }
15375
0
    return JS_UNDEFINED;
15376
0
}
15377
15378
static int js_arguments_define_own_property(JSContext *ctx,
15379
                                            JSValueConst this_obj,
15380
                                            JSAtom prop, JSValueConst val,
15381
                                            JSValueConst getter, JSValueConst setter, int flags)
15382
0
{
15383
0
    JSObject *p;
15384
0
    uint32_t idx;
15385
0
    p = JS_VALUE_GET_OBJ(this_obj);
15386
    /* convert to normal array when redefining an existing numeric field */
15387
0
    if (p->fast_array && JS_AtomIsArrayIndex(ctx, &idx, prop) &&
15388
0
        idx < p->u.array.count) {
15389
0
        if (convert_fast_array_to_array(ctx, p))
15390
0
            return -1;
15391
0
    }
15392
    /* run the default define own property */
15393
0
    return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter,
15394
0
                             flags | JS_PROP_NO_EXOTIC);
15395
0
}
15396
15397
static const JSClassExoticMethods js_arguments_exotic_methods = {
15398
    .define_own_property = js_arguments_define_own_property,
15399
};
15400
15401
static JSValue js_build_arguments(JSContext *ctx, int argc, JSValueConst *argv)
15402
0
{
15403
0
    JSValue val, *tab;
15404
0
    JSProperty *pr;
15405
0
    JSObject *p;
15406
0
    int i;
15407
15408
0
    val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
15409
0
                                 JS_CLASS_ARGUMENTS);
15410
0
    if (JS_IsException(val))
15411
0
        return val;
15412
0
    p = JS_VALUE_GET_OBJ(val);
15413
15414
    /* add the length field (cannot fail) */
15415
0
    pr = add_property(ctx, p, JS_ATOM_length,
15416
0
                      JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
15417
0
    if (unlikely(!pr))
15418
0
        goto fail;
15419
0
    pr->u.value = JS_NewInt32(ctx, argc);
15420
15421
    /* initialize the fast array part */
15422
0
    tab = NULL;
15423
0
    if (argc > 0) {
15424
0
        tab = js_malloc(ctx, sizeof(tab[0]) * argc);
15425
0
        if (!tab)
15426
0
            goto fail;
15427
0
        for(i = 0; i < argc; i++) {
15428
0
            tab[i] = JS_DupValue(ctx, argv[i]);
15429
0
        }
15430
0
    }
15431
0
    p->u.array.u.values = tab;
15432
0
    p->u.array.count = argc;
15433
15434
0
    JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator,
15435
0
                           JS_DupValue(ctx, ctx->array_proto_values),
15436
0
                           JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
15437
    /* add callee property to throw a TypeError in strict mode */
15438
0
    JS_DefineProperty(ctx, val, JS_ATOM_callee, JS_UNDEFINED,
15439
0
                      ctx->throw_type_error, ctx->throw_type_error,
15440
0
                      JS_PROP_HAS_GET | JS_PROP_HAS_SET);
15441
0
    return val;
15442
0
 fail:
15443
0
    JS_FreeValue(ctx, val);
15444
0
    return JS_EXCEPTION;
15445
0
}
15446
15447
0
#define GLOBAL_VAR_OFFSET 0x40000000
15448
0
#define ARGUMENT_VAR_OFFSET 0x20000000
15449
15450
/* legacy arguments object: add references to the function arguments */
15451
static JSValue js_build_mapped_arguments(JSContext *ctx, int argc,
15452
                                         JSValueConst *argv,
15453
                                         JSStackFrame *sf, int arg_count)
15454
0
{
15455
0
    JSValue val;
15456
0
    JSProperty *pr;
15457
0
    JSObject *p;
15458
0
    int i;
15459
15460
0
    val = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
15461
0
                                 JS_CLASS_MAPPED_ARGUMENTS);
15462
0
    if (JS_IsException(val))
15463
0
        return val;
15464
0
    p = JS_VALUE_GET_OBJ(val);
15465
15466
    /* add the length field (cannot fail) */
15467
0
    pr = add_property(ctx, p, JS_ATOM_length,
15468
0
                      JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
15469
0
    if (unlikely(!pr))
15470
0
        goto fail;
15471
0
    pr->u.value = JS_NewInt32(ctx, argc);
15472
15473
0
    for(i = 0; i < arg_count; i++) {
15474
0
        JSVarRef *var_ref;
15475
0
        var_ref = get_var_ref(ctx, sf, i, TRUE);
15476
0
        if (!var_ref)
15477
0
            goto fail;
15478
0
        pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E | JS_PROP_VARREF);
15479
0
        if (!pr) {
15480
0
            free_var_ref(ctx->rt, var_ref);
15481
0
            goto fail;
15482
0
        }
15483
0
        pr->u.var_ref = var_ref;
15484
0
    }
15485
15486
    /* the arguments not mapped to the arguments of the function can
15487
       be normal properties */
15488
0
    for(i = arg_count; i < argc; i++) {
15489
0
        if (JS_DefinePropertyValueUint32(ctx, val, i,
15490
0
                                         JS_DupValue(ctx, argv[i]),
15491
0
                                         JS_PROP_C_W_E) < 0)
15492
0
            goto fail;
15493
0
    }
15494
15495
0
    JS_DefinePropertyValue(ctx, val, JS_ATOM_Symbol_iterator,
15496
0
                           JS_DupValue(ctx, ctx->array_proto_values),
15497
0
                           JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
15498
    /* callee returns this function in non strict mode */
15499
0
    JS_DefinePropertyValue(ctx, val, JS_ATOM_callee,
15500
0
                           JS_DupValue(ctx, ctx->rt->current_stack_frame->cur_func),
15501
0
                           JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
15502
0
    return val;
15503
0
 fail:
15504
0
    JS_FreeValue(ctx, val);
15505
0
    return JS_EXCEPTION;
15506
0
}
15507
15508
static JSValue js_build_rest(JSContext *ctx, int first, int argc, JSValueConst *argv)
15509
0
{
15510
0
    JSValue val;
15511
0
    int i, ret;
15512
15513
0
    val = JS_NewArray(ctx);
15514
0
    if (JS_IsException(val))
15515
0
        return val;
15516
0
    for (i = first; i < argc; i++) {
15517
0
        ret = JS_DefinePropertyValueUint32(ctx, val, i - first,
15518
0
                                           JS_DupValue(ctx, argv[i]),
15519
0
                                           JS_PROP_C_W_E);
15520
0
        if (ret < 0) {
15521
0
            JS_FreeValue(ctx, val);
15522
0
            return JS_EXCEPTION;
15523
0
        }
15524
0
    }
15525
0
    return val;
15526
0
}
15527
15528
static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
15529
0
{
15530
0
    JSObject *p, *p1;
15531
0
    JSPropertyEnum *tab_atom;
15532
0
    int i;
15533
0
    JSValue enum_obj;
15534
0
    JSForInIterator *it;
15535
0
    uint32_t tag, tab_atom_count;
15536
15537
0
    tag = JS_VALUE_GET_TAG(obj);
15538
0
    if (tag != JS_TAG_OBJECT && tag != JS_TAG_NULL && tag != JS_TAG_UNDEFINED) {
15539
0
        obj = JS_ToObjectFree(ctx, obj);
15540
0
    }
15541
15542
0
    it = js_malloc(ctx, sizeof(*it));
15543
0
    if (!it) {
15544
0
        JS_FreeValue(ctx, obj);
15545
0
        return JS_EXCEPTION;
15546
0
    }
15547
0
    enum_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_FOR_IN_ITERATOR);
15548
0
    if (JS_IsException(enum_obj)) {
15549
0
        js_free(ctx, it);
15550
0
        JS_FreeValue(ctx, obj);
15551
0
        return JS_EXCEPTION;
15552
0
    }
15553
0
    it->is_array = FALSE;
15554
0
    it->obj = obj;
15555
0
    it->idx = 0;
15556
0
    it->tab_atom = NULL;
15557
0
    it->atom_count = 0;
15558
0
    it->in_prototype_chain = FALSE;
15559
0
    p1 = JS_VALUE_GET_OBJ(enum_obj);
15560
0
    p1->u.for_in_iterator = it;
15561
15562
0
    if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)
15563
0
        return enum_obj;
15564
15565
0
    p = JS_VALUE_GET_OBJ(obj);
15566
0
    if (p->fast_array) {
15567
0
        JSShape *sh;
15568
0
        JSShapeProperty *prs;
15569
        /* check that there are no enumerable normal fields */
15570
0
        sh = p->shape;
15571
0
        for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {
15572
0
            if (prs->flags & JS_PROP_ENUMERABLE)
15573
0
                goto normal_case;
15574
0
        }
15575
        /* for fast arrays, we only store the number of elements */
15576
0
        it->is_array = TRUE;
15577
0
        it->atom_count = p->u.array.count;
15578
0
    } else {
15579
0
    normal_case:
15580
0
        if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
15581
0
                                           JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
15582
0
            JS_FreeValue(ctx, enum_obj);
15583
0
            return JS_EXCEPTION;
15584
0
        }
15585
0
        it->tab_atom = tab_atom;
15586
0
        it->atom_count = tab_atom_count;
15587
0
    }
15588
0
    return enum_obj;
15589
0
}
15590
15591
/* obj -> enum_obj */
15592
static __exception int js_for_in_start(JSContext *ctx, JSValue *sp)
15593
0
{
15594
0
    sp[-1] = build_for_in_iterator(ctx, sp[-1]);
15595
0
    if (JS_IsException(sp[-1]))
15596
0
        return -1;
15597
0
    return 0;
15598
0
}
15599
15600
/* return -1 if exception, 0 if slow case, 1 if the enumeration is finished */
15601
static __exception int js_for_in_prepare_prototype_chain_enum(JSContext *ctx,
15602
                                                              JSValueConst enum_obj)
15603
0
{
15604
0
    JSObject *p;
15605
0
    JSForInIterator *it;
15606
0
    JSPropertyEnum *tab_atom;
15607
0
    uint32_t tab_atom_count, i;
15608
0
    JSValue obj1;
15609
15610
0
    p = JS_VALUE_GET_OBJ(enum_obj);
15611
0
    it = p->u.for_in_iterator;
15612
15613
    /* check if there are enumerable properties in the prototype chain (fast path) */
15614
0
    obj1 = JS_DupValue(ctx, it->obj);
15615
0
    for(;;) {
15616
0
        obj1 = JS_GetPrototypeFree(ctx, obj1);
15617
0
        if (JS_IsNull(obj1))
15618
0
            break;
15619
0
        if (JS_IsException(obj1))
15620
0
            goto fail;
15621
0
        if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
15622
0
                                           JS_VALUE_GET_OBJ(obj1),
15623
0
                                           JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) {
15624
0
            JS_FreeValue(ctx, obj1);
15625
0
            goto fail;
15626
0
        }
15627
0
        JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count);
15628
0
        if (tab_atom_count != 0) {
15629
0
            JS_FreeValue(ctx, obj1);
15630
0
            goto slow_path;
15631
0
        }
15632
        /* must check for timeout to avoid infinite loop */
15633
0
        if (js_poll_interrupts(ctx)) {
15634
0
            JS_FreeValue(ctx, obj1);
15635
0
            goto fail;
15636
0
        }
15637
0
    }
15638
0
    JS_FreeValue(ctx, obj1);
15639
0
    return 1;
15640
15641
0
 slow_path:
15642
    /* add the visited properties, even if they are not enumerable */
15643
0
    if (it->is_array) {
15644
0
        if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
15645
0
                                           JS_VALUE_GET_OBJ(it->obj),
15646
0
                                           JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
15647
0
            goto fail;
15648
0
        }
15649
0
        it->is_array = FALSE;
15650
0
        it->tab_atom = tab_atom;
15651
0
        it->atom_count = tab_atom_count;
15652
0
    }
15653
15654
0
    for(i = 0; i < it->atom_count; i++) {
15655
0
        if (JS_DefinePropertyValue(ctx, enum_obj, it->tab_atom[i].atom, JS_NULL, JS_PROP_ENUMERABLE) < 0)
15656
0
            goto fail;
15657
0
    }
15658
0
    return 0;
15659
0
 fail:
15660
0
    return -1;
15661
0
}
15662
15663
/* enum_obj -> enum_obj value done */
15664
static __exception int js_for_in_next(JSContext *ctx, JSValue *sp)
15665
0
{
15666
0
    JSValueConst enum_obj;
15667
0
    JSObject *p;
15668
0
    JSAtom prop;
15669
0
    JSForInIterator *it;
15670
0
    JSPropertyEnum *tab_atom;
15671
0
    uint32_t tab_atom_count;
15672
0
    int ret;
15673
15674
0
    enum_obj = sp[-1];
15675
    /* fail safe */
15676
0
    if (JS_VALUE_GET_TAG(enum_obj) != JS_TAG_OBJECT)
15677
0
        goto done;
15678
0
    p = JS_VALUE_GET_OBJ(enum_obj);
15679
0
    if (p->class_id != JS_CLASS_FOR_IN_ITERATOR)
15680
0
        goto done;
15681
0
    it = p->u.for_in_iterator;
15682
15683
0
    for(;;) {
15684
0
        if (it->idx >= it->atom_count) {
15685
0
            if (JS_IsNull(it->obj) || JS_IsUndefined(it->obj))
15686
0
                goto done; /* not an object */
15687
            /* no more property in the current object: look in the prototype */
15688
0
            if (!it->in_prototype_chain) {
15689
0
                ret = js_for_in_prepare_prototype_chain_enum(ctx, enum_obj);
15690
0
                if (ret < 0)
15691
0
                    return -1;
15692
0
                if (ret)
15693
0
                    goto done;
15694
0
                it->in_prototype_chain = TRUE;
15695
0
            }
15696
0
            it->obj = JS_GetPrototypeFree(ctx, it->obj);
15697
0
            if (JS_IsException(it->obj))
15698
0
                return -1;
15699
0
            if (JS_IsNull(it->obj))
15700
0
                goto done; /* no more prototype */
15701
15702
            /* must check for timeout to avoid infinite loop */
15703
0
            if (js_poll_interrupts(ctx))
15704
0
                return -1;
15705
15706
0
            if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
15707
0
                                               JS_VALUE_GET_OBJ(it->obj),
15708
0
                                               JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
15709
0
                return -1;
15710
0
            }
15711
0
            JS_FreePropertyEnum(ctx, it->tab_atom, it->atom_count);
15712
0
            it->tab_atom = tab_atom;
15713
0
            it->atom_count = tab_atom_count;
15714
0
            it->idx = 0;
15715
0
        } else {
15716
0
            if (it->is_array) {
15717
0
                prop = __JS_AtomFromUInt32(it->idx);
15718
0
                it->idx++;
15719
0
            } else {
15720
0
                BOOL is_enumerable;
15721
0
                prop = it->tab_atom[it->idx].atom;
15722
0
                is_enumerable = it->tab_atom[it->idx].is_enumerable;
15723
0
                it->idx++;
15724
0
                if (it->in_prototype_chain) {
15725
                    /* slow case: we are in the prototype chain */
15726
0
                    ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(enum_obj), prop);
15727
0
                    if (ret < 0)
15728
0
                        return ret;
15729
0
                    if (ret)
15730
0
                        continue; /* already visited */
15731
                    /* add to the visited property list */
15732
0
                    if (JS_DefinePropertyValue(ctx, enum_obj, prop, JS_NULL,
15733
0
                                               JS_PROP_ENUMERABLE) < 0)
15734
0
                        return -1;
15735
0
                }
15736
0
                if (!is_enumerable)
15737
0
                    continue;
15738
0
            }
15739
            /* check if the property was deleted */
15740
0
            ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(it->obj), prop);
15741
0
            if (ret < 0)
15742
0
                return ret;
15743
0
            if (ret)
15744
0
                break;
15745
0
        }
15746
0
    }
15747
    /* return the property */
15748
0
    sp[0] = JS_AtomToValue(ctx, prop);
15749
0
    sp[1] = JS_FALSE;
15750
0
    return 0;
15751
0
 done:
15752
    /* return the end */
15753
0
    sp[0] = JS_UNDEFINED;
15754
0
    sp[1] = JS_TRUE;
15755
0
    return 0;
15756
0
}
15757
15758
static JSValue JS_GetIterator2(JSContext *ctx, JSValueConst obj,
15759
                               JSValueConst method)
15760
0
{
15761
0
    JSValue enum_obj;
15762
15763
0
    enum_obj = JS_Call(ctx, method, obj, 0, NULL);
15764
0
    if (JS_IsException(enum_obj))
15765
0
        return enum_obj;
15766
0
    if (!JS_IsObject(enum_obj)) {
15767
0
        JS_FreeValue(ctx, enum_obj);
15768
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
15769
0
    }
15770
0
    return enum_obj;
15771
0
}
15772
15773
static JSValue JS_GetIterator(JSContext *ctx, JSValueConst obj, BOOL is_async)
15774
0
{
15775
0
    JSValue method, ret, sync_iter;
15776
15777
0
    if (is_async) {
15778
0
        method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_asyncIterator);
15779
0
        if (JS_IsException(method))
15780
0
            return method;
15781
0
        if (JS_IsUndefined(method) || JS_IsNull(method)) {
15782
0
            method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
15783
0
            if (JS_IsException(method))
15784
0
                return method;
15785
0
            sync_iter = JS_GetIterator2(ctx, obj, method);
15786
0
            JS_FreeValue(ctx, method);
15787
0
            if (JS_IsException(sync_iter))
15788
0
                return sync_iter;
15789
0
            ret = JS_CreateAsyncFromSyncIterator(ctx, sync_iter);
15790
0
            JS_FreeValue(ctx, sync_iter);
15791
0
            return ret;
15792
0
        }
15793
0
    } else {
15794
0
        method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
15795
0
        if (JS_IsException(method))
15796
0
            return method;
15797
0
    }
15798
0
    if (!JS_IsFunction(ctx, method)) {
15799
0
        JS_FreeValue(ctx, method);
15800
0
        return JS_ThrowTypeError(ctx, "value is not iterable");
15801
0
    }
15802
0
    ret = JS_GetIterator2(ctx, obj, method);
15803
0
    JS_FreeValue(ctx, method);
15804
0
    return ret;
15805
0
}
15806
15807
/* return *pdone = 2 if the iterator object is not parsed */
15808
static JSValue JS_IteratorNext2(JSContext *ctx, JSValueConst enum_obj,
15809
                                JSValueConst method,
15810
                                int argc, JSValueConst *argv, int *pdone)
15811
0
{
15812
0
    JSValue obj;
15813
15814
    /* fast path for the built-in iterators (avoid creating the
15815
       intermediate result object) */
15816
0
    if (JS_IsObject(method)) {
15817
0
        JSObject *p = JS_VALUE_GET_OBJ(method);
15818
0
        if (p->class_id == JS_CLASS_C_FUNCTION &&
15819
0
            p->u.cfunc.cproto == JS_CFUNC_iterator_next) {
15820
0
            JSCFunctionType func;
15821
0
            JSValueConst args[1];
15822
15823
            /* in case the function expects one argument */
15824
0
            if (argc == 0) {
15825
0
                args[0] = JS_UNDEFINED;
15826
0
                argv = args;
15827
0
            }
15828
0
            func = p->u.cfunc.c_function;
15829
0
            return func.iterator_next(ctx, enum_obj, argc, argv,
15830
0
                                      pdone, p->u.cfunc.magic);
15831
0
        }
15832
0
    }
15833
0
    obj = JS_Call(ctx, method, enum_obj, argc, argv);
15834
0
    if (JS_IsException(obj))
15835
0
        goto fail;
15836
0
    if (!JS_IsObject(obj)) {
15837
0
        JS_FreeValue(ctx, obj);
15838
0
        JS_ThrowTypeError(ctx, "iterator must return an object");
15839
0
        goto fail;
15840
0
    }
15841
0
    *pdone = 2;
15842
0
    return obj;
15843
0
 fail:
15844
0
    *pdone = FALSE;
15845
0
    return JS_EXCEPTION;
15846
0
}
15847
15848
/* Note: always return JS_UNDEFINED when *pdone = TRUE. */
15849
static JSValue JS_IteratorNext(JSContext *ctx, JSValueConst enum_obj,
15850
                               JSValueConst method,
15851
                               int argc, JSValueConst *argv, BOOL *pdone)
15852
0
{
15853
0
    JSValue obj, value, done_val;
15854
0
    int done;
15855
15856
0
    obj = JS_IteratorNext2(ctx, enum_obj, method, argc, argv, &done);
15857
0
    if (JS_IsException(obj))
15858
0
        goto fail;
15859
0
    if (likely(done == 0)) {
15860
0
        *pdone = FALSE;
15861
0
        return obj;
15862
0
    } else if (done != 2) {
15863
0
        JS_FreeValue(ctx, obj);
15864
0
        *pdone = TRUE;
15865
0
        return JS_UNDEFINED;
15866
0
    } else {
15867
0
        done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);
15868
0
        if (JS_IsException(done_val))
15869
0
            goto fail;
15870
0
        *pdone = JS_ToBoolFree(ctx, done_val);
15871
0
        value = JS_UNDEFINED;
15872
0
        if (!*pdone) {
15873
0
            value = JS_GetProperty(ctx, obj, JS_ATOM_value);
15874
0
        }
15875
0
        JS_FreeValue(ctx, obj);
15876
0
        return value;
15877
0
    }
15878
0
 fail:
15879
0
    JS_FreeValue(ctx, obj);
15880
0
    *pdone = FALSE;
15881
0
    return JS_EXCEPTION;
15882
0
}
15883
15884
/* return < 0 in case of exception */
15885
static int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj,
15886
                            BOOL is_exception_pending)
15887
0
{
15888
0
    JSValue method, ret, ex_obj;
15889
0
    int res;
15890
15891
0
    if (is_exception_pending) {
15892
0
        ex_obj = ctx->rt->current_exception;
15893
0
        ctx->rt->current_exception = JS_UNINITIALIZED;
15894
0
        res = -1;
15895
0
    } else {
15896
0
        ex_obj = JS_UNDEFINED;
15897
0
        res = 0;
15898
0
    }
15899
0
    method = JS_GetProperty(ctx, enum_obj, JS_ATOM_return);
15900
0
    if (JS_IsException(method)) {
15901
0
        res = -1;
15902
0
        goto done;
15903
0
    }
15904
0
    if (JS_IsUndefined(method) || JS_IsNull(method)) {
15905
0
        goto done;
15906
0
    }
15907
0
    ret = JS_CallFree(ctx, method, enum_obj, 0, NULL);
15908
0
    if (!is_exception_pending) {
15909
0
        if (JS_IsException(ret)) {
15910
0
            res = -1;
15911
0
        } else if (!JS_IsObject(ret)) {
15912
0
            JS_ThrowTypeErrorNotAnObject(ctx);
15913
0
            res = -1;
15914
0
        }
15915
0
    }
15916
0
    JS_FreeValue(ctx, ret);
15917
0
 done:
15918
0
    if (is_exception_pending) {
15919
0
        JS_Throw(ctx, ex_obj);
15920
0
    }
15921
0
    return res;
15922
0
}
15923
15924
/* obj -> enum_rec (3 slots) */
15925
static __exception int js_for_of_start(JSContext *ctx, JSValue *sp,
15926
                                       BOOL is_async)
15927
0
{
15928
0
    JSValue op1, obj, method;
15929
0
    op1 = sp[-1];
15930
0
    obj = JS_GetIterator(ctx, op1, is_async);
15931
0
    if (JS_IsException(obj))
15932
0
        return -1;
15933
0
    JS_FreeValue(ctx, op1);
15934
0
    sp[-1] = obj;
15935
0
    method = JS_GetProperty(ctx, obj, JS_ATOM_next);
15936
0
    if (JS_IsException(method))
15937
0
        return -1;
15938
0
    sp[0] = method;
15939
0
    return 0;
15940
0
}
15941
15942
/* enum_rec [objs] -> enum_rec [objs] value done. There are 'offset'
15943
   objs. If 'done' is true or in case of exception, 'enum_rec' is set
15944
   to undefined. If 'done' is true, 'value' is always set to
15945
   undefined. */
15946
static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset)
15947
0
{
15948
0
    JSValue value = JS_UNDEFINED;
15949
0
    int done = 1;
15950
15951
0
    if (likely(!JS_IsUndefined(sp[offset]))) {
15952
0
        value = JS_IteratorNext(ctx, sp[offset], sp[offset + 1], 0, NULL, &done);
15953
0
        if (JS_IsException(value))
15954
0
            done = -1;
15955
0
        if (done) {
15956
            /* value is JS_UNDEFINED or JS_EXCEPTION */
15957
            /* replace the iteration object with undefined */
15958
0
            JS_FreeValue(ctx, sp[offset]);
15959
0
            sp[offset] = JS_UNDEFINED;
15960
0
            if (done < 0) {
15961
0
                return -1;
15962
0
            } else {
15963
0
                JS_FreeValue(ctx, value);
15964
0
                value = JS_UNDEFINED;
15965
0
            }
15966
0
        }
15967
0
    }
15968
0
    sp[0] = value;
15969
0
    sp[1] = JS_NewBool(ctx, done);
15970
0
    return 0;
15971
0
}
15972
15973
static __exception int js_for_await_of_next(JSContext *ctx, JSValue *sp)
15974
0
{
15975
0
    JSValue obj, iter, next;
15976
15977
0
    sp[-1] = JS_UNDEFINED; /* disable the catch offset so that
15978
                              exceptions do not close the iterator */
15979
0
    iter = sp[-3];
15980
0
    next = sp[-2];
15981
0
    obj = JS_Call(ctx, next, iter, 0, NULL);
15982
0
    if (JS_IsException(obj))
15983
0
        return -1;
15984
0
    sp[0] = obj;
15985
0
    return 0;
15986
0
}
15987
15988
static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValueConst obj,
15989
                                           BOOL *pdone)
15990
0
{
15991
0
    JSValue done_val, value;
15992
0
    BOOL done;
15993
0
    done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);
15994
0
    if (JS_IsException(done_val))
15995
0
        goto fail;
15996
0
    done = JS_ToBoolFree(ctx, done_val);
15997
0
    value = JS_GetProperty(ctx, obj, JS_ATOM_value);
15998
0
    if (JS_IsException(value))
15999
0
        goto fail;
16000
0
    *pdone = done;
16001
0
    return value;
16002
0
 fail:
16003
0
    *pdone = FALSE;
16004
0
    return JS_EXCEPTION;
16005
0
}
16006
16007
static __exception int js_iterator_get_value_done(JSContext *ctx, JSValue *sp)
16008
0
{
16009
0
    JSValue obj, value;
16010
0
    BOOL done;
16011
0
    obj = sp[-1];
16012
0
    if (!JS_IsObject(obj)) {
16013
0
        JS_ThrowTypeError(ctx, "iterator must return an object");
16014
0
        return -1;
16015
0
    }
16016
0
    value = JS_IteratorGetCompleteValue(ctx, obj, &done);
16017
0
    if (JS_IsException(value))
16018
0
        return -1;
16019
0
    JS_FreeValue(ctx, obj);
16020
    /* put again the catch offset so that exceptions close the
16021
       iterator */
16022
0
    sp[-2] = JS_NewCatchOffset(ctx, 0); 
16023
0
    sp[-1] = value;
16024
0
    sp[0] = JS_NewBool(ctx, done);
16025
0
    return 0;
16026
0
}
16027
16028
static JSValue js_create_iterator_result(JSContext *ctx,
16029
                                         JSValue val,
16030
                                         BOOL done)
16031
0
{
16032
0
    JSValue obj;
16033
0
    obj = JS_NewObject(ctx);
16034
0
    if (JS_IsException(obj)) {
16035
0
        JS_FreeValue(ctx, val);
16036
0
        return obj;
16037
0
    }
16038
0
    if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_value,
16039
0
                               val, JS_PROP_C_W_E) < 0) {
16040
0
        goto fail;
16041
0
    }
16042
0
    if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_done,
16043
0
                               JS_NewBool(ctx, done), JS_PROP_C_W_E) < 0) {
16044
0
    fail:
16045
0
        JS_FreeValue(ctx, obj);
16046
0
        return JS_EXCEPTION;
16047
0
    }
16048
0
    return obj;
16049
0
}
16050
16051
static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val,
16052
                                      int argc, JSValueConst *argv,
16053
                                      BOOL *pdone, int magic);
16054
16055
static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val,
16056
                                        int argc, JSValueConst *argv, int magic);
16057
16058
static BOOL js_is_fast_array(JSContext *ctx, JSValueConst obj)
16059
0
{
16060
    /* Try and handle fast arrays explicitly */
16061
0
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
16062
0
        JSObject *p = JS_VALUE_GET_OBJ(obj);
16063
0
        if (p->class_id == JS_CLASS_ARRAY && p->fast_array) {
16064
0
            return TRUE;
16065
0
        }
16066
0
    }
16067
0
    return FALSE;
16068
0
}
16069
16070
/* Access an Array's internal JSValue array if available */
16071
static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj,
16072
                              JSValue **arrpp, uint32_t *countp)
16073
0
{
16074
    /* Try and handle fast arrays explicitly */
16075
0
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
16076
0
        JSObject *p = JS_VALUE_GET_OBJ(obj);
16077
0
        if (p->class_id == JS_CLASS_ARRAY && p->fast_array) {
16078
0
            *countp = p->u.array.count;
16079
0
            *arrpp = p->u.array.u.values;
16080
0
            return TRUE;
16081
0
        }
16082
0
    }
16083
0
    return FALSE;
16084
0
}
16085
16086
static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp)
16087
0
{
16088
0
    JSValue iterator, enumobj, method, value;
16089
0
    int is_array_iterator;
16090
0
    JSValue *arrp;
16091
0
    uint32_t i, count32, pos;
16092
16093
0
    if (JS_VALUE_GET_TAG(sp[-2]) != JS_TAG_INT) {
16094
0
        JS_ThrowInternalError(ctx, "invalid index for append");
16095
0
        return -1;
16096
0
    }
16097
16098
0
    pos = JS_VALUE_GET_INT(sp[-2]);
16099
16100
    /* XXX: further optimisations:
16101
       - use ctx->array_proto_values?
16102
       - check if array_iterator_prototype next method is built-in and
16103
         avoid constructing actual iterator object?
16104
       - build this into js_for_of_start and use in all `for (x of o)` loops
16105
     */
16106
0
    iterator = JS_GetProperty(ctx, sp[-1], JS_ATOM_Symbol_iterator);
16107
0
    if (JS_IsException(iterator))
16108
0
        return -1;
16109
0
    is_array_iterator = JS_IsCFunction(ctx, iterator,
16110
0
                                       (JSCFunction *)js_create_array_iterator,
16111
0
                                       JS_ITERATOR_KIND_VALUE);
16112
0
    JS_FreeValue(ctx, iterator);
16113
16114
0
    enumobj = JS_GetIterator(ctx, sp[-1], FALSE);
16115
0
    if (JS_IsException(enumobj))
16116
0
        return -1;
16117
0
    method = JS_GetProperty(ctx, enumobj, JS_ATOM_next);
16118
0
    if (JS_IsException(method)) {
16119
0
        JS_FreeValue(ctx, enumobj);
16120
0
        return -1;
16121
0
    }
16122
0
    if (is_array_iterator
16123
0
    &&  JS_IsCFunction(ctx, method, (JSCFunction *)js_array_iterator_next, 0)
16124
0
    &&  js_get_fast_array(ctx, sp[-1], &arrp, &count32)) {
16125
0
        uint32_t len;
16126
0
        if (js_get_length32(ctx, &len, sp[-1]))
16127
0
            goto exception;
16128
        /* if len > count32, the elements >= count32 might be read in
16129
           the prototypes and might have side effects */
16130
0
        if (len != count32)
16131
0
            goto general_case;
16132
        /* Handle fast arrays explicitly */
16133
0
        for (i = 0; i < count32; i++) {
16134
0
            if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++,
16135
0
                                             JS_DupValue(ctx, arrp[i]), JS_PROP_C_W_E) < 0)
16136
0
                goto exception;
16137
0
        }
16138
0
    } else {
16139
0
    general_case:
16140
0
        for (;;) {
16141
0
            BOOL done;
16142
0
            value = JS_IteratorNext(ctx, enumobj, method, 0, NULL, &done);
16143
0
            if (JS_IsException(value))
16144
0
                goto exception;
16145
0
            if (done) {
16146
                /* value is JS_UNDEFINED */
16147
0
                break;
16148
0
            }
16149
0
            if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, value, JS_PROP_C_W_E) < 0)
16150
0
                goto exception;
16151
0
        }
16152
0
    }
16153
    /* Note: could raise an error if too many elements */
16154
0
    sp[-2] = JS_NewInt32(ctx, pos);
16155
0
    JS_FreeValue(ctx, enumobj);
16156
0
    JS_FreeValue(ctx, method);
16157
0
    return 0;
16158
16159
0
exception:
16160
0
    JS_IteratorClose(ctx, enumobj, TRUE);
16161
0
    JS_FreeValue(ctx, enumobj);
16162
0
    JS_FreeValue(ctx, method);
16163
0
    return -1;
16164
0
}
16165
16166
static __exception int JS_CopyDataProperties(JSContext *ctx,
16167
                                             JSValueConst target,
16168
                                             JSValueConst source,
16169
                                             JSValueConst excluded,
16170
                                             BOOL setprop)
16171
0
{
16172
0
    JSPropertyEnum *tab_atom;
16173
0
    JSValue val;
16174
0
    uint32_t i, tab_atom_count;
16175
0
    JSObject *p;
16176
0
    JSObject *pexcl = NULL;
16177
0
    int ret, gpn_flags;
16178
0
    JSPropertyDescriptor desc;
16179
0
    BOOL is_enumerable;
16180
16181
0
    if (JS_VALUE_GET_TAG(source) != JS_TAG_OBJECT)
16182
0
        return 0;
16183
16184
0
    if (JS_VALUE_GET_TAG(excluded) == JS_TAG_OBJECT)
16185
0
        pexcl = JS_VALUE_GET_OBJ(excluded);
16186
16187
0
    p = JS_VALUE_GET_OBJ(source);
16188
16189
0
    gpn_flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK | JS_GPN_ENUM_ONLY;
16190
0
    if (p->is_exotic) {
16191
0
        const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
16192
        /* cannot use JS_GPN_ENUM_ONLY with e.g. proxies because it
16193
           introduces a visible change */
16194
0
        if (em && em->get_own_property_names) {
16195
0
            gpn_flags &= ~JS_GPN_ENUM_ONLY;
16196
0
        }
16197
0
    }
16198
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
16199
0
                                       gpn_flags))
16200
0
        return -1;
16201
16202
0
    for (i = 0; i < tab_atom_count; i++) {
16203
0
        if (pexcl) {
16204
0
            ret = JS_GetOwnPropertyInternal(ctx, NULL, pexcl, tab_atom[i].atom);
16205
0
            if (ret) {
16206
0
                if (ret < 0)
16207
0
                    goto exception;
16208
0
                continue;
16209
0
            }
16210
0
        }
16211
0
        if (!(gpn_flags & JS_GPN_ENUM_ONLY)) {
16212
            /* test if the property is enumerable */
16213
0
            ret = JS_GetOwnPropertyInternal(ctx, &desc, p, tab_atom[i].atom);
16214
0
            if (ret < 0)
16215
0
                goto exception;
16216
0
            if (!ret)
16217
0
                continue;
16218
0
            is_enumerable = (desc.flags & JS_PROP_ENUMERABLE) != 0;
16219
0
            js_free_desc(ctx, &desc);
16220
0
            if (!is_enumerable)
16221
0
                continue;
16222
0
        }
16223
0
        val = JS_GetProperty(ctx, source, tab_atom[i].atom);
16224
0
        if (JS_IsException(val))
16225
0
            goto exception;
16226
0
        if (setprop)
16227
0
            ret = JS_SetProperty(ctx, target, tab_atom[i].atom, val);
16228
0
        else
16229
0
            ret = JS_DefinePropertyValue(ctx, target, tab_atom[i].atom, val,
16230
0
                                         JS_PROP_C_W_E);
16231
0
        if (ret < 0)
16232
0
            goto exception;
16233
0
    }
16234
0
    JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count);
16235
0
    return 0;
16236
0
 exception:
16237
0
    JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count);
16238
0
    return -1;
16239
0
}
16240
16241
/* only valid inside C functions */
16242
static JSValueConst JS_GetActiveFunction(JSContext *ctx)
16243
0
{
16244
0
    return ctx->rt->current_stack_frame->cur_func;
16245
0
}
16246
16247
static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf,
16248
                             int var_idx, BOOL is_arg)
16249
0
{
16250
0
    JSVarRef *var_ref;
16251
0
    struct list_head *el;
16252
0
    JSValue *pvalue;
16253
16254
0
    if (is_arg)
16255
0
        pvalue = &sf->arg_buf[var_idx];
16256
0
    else
16257
0
        pvalue = &sf->var_buf[var_idx];
16258
16259
0
    list_for_each(el, &sf->var_ref_list) {
16260
0
        var_ref = list_entry(el, JSVarRef, var_ref_link);
16261
0
        if (var_ref->pvalue == pvalue) {
16262
0
            var_ref->header.ref_count++;
16263
0
            return var_ref;
16264
0
        }
16265
0
    }
16266
    /* create a new one */
16267
0
    var_ref = js_malloc(ctx, sizeof(JSVarRef));
16268
0
    if (!var_ref)
16269
0
        return NULL;
16270
0
    var_ref->header.ref_count = 1;
16271
0
    add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
16272
0
    var_ref->is_detached = FALSE;
16273
0
    list_add_tail(&var_ref->var_ref_link, &sf->var_ref_list);
16274
0
    if (sf->js_mode & JS_MODE_ASYNC) {
16275
        /* The stack frame is detached and may be destroyed at any
16276
           time so its reference count must be increased. Calling
16277
           close_var_refs() when destroying the stack frame is not
16278
           possible because it would change the graph between the GC
16279
           objects. Another solution could be to temporarily detach
16280
           the JSVarRef of async functions during the GC. It would
16281
           have the advantage of allowing the release of unused stack
16282
           frames in a cycle. */
16283
0
        var_ref->async_func = container_of(sf, JSAsyncFunctionState, frame);
16284
0
        var_ref->async_func->header.ref_count++;
16285
0
    } else {
16286
0
        var_ref->async_func = NULL;
16287
0
    }
16288
0
    var_ref->pvalue = pvalue;
16289
0
    return var_ref;
16290
0
}
16291
16292
static JSValue js_closure2(JSContext *ctx, JSValue func_obj,
16293
                           JSFunctionBytecode *b,
16294
                           JSVarRef **cur_var_refs,
16295
                           JSStackFrame *sf)
16296
0
{
16297
0
    JSObject *p;
16298
0
    JSVarRef **var_refs;
16299
0
    int i;
16300
16301
0
    p = JS_VALUE_GET_OBJ(func_obj);
16302
0
    p->u.func.function_bytecode = b;
16303
0
    p->u.func.home_object = NULL;
16304
0
    p->u.func.var_refs = NULL;
16305
0
    if (b->closure_var_count) {
16306
0
        var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count);
16307
0
        if (!var_refs)
16308
0
            goto fail;
16309
0
        p->u.func.var_refs = var_refs;
16310
0
        for(i = 0; i < b->closure_var_count; i++) {
16311
0
            JSClosureVar *cv = &b->closure_var[i];
16312
0
            JSVarRef *var_ref;
16313
0
            if (cv->is_local) {
16314
                /* reuse the existing variable reference if it already exists */
16315
0
                var_ref = get_var_ref(ctx, sf, cv->var_idx, cv->is_arg);
16316
0
                if (!var_ref)
16317
0
                    goto fail;
16318
0
            } else {
16319
0
                var_ref = cur_var_refs[cv->var_idx];
16320
0
                var_ref->header.ref_count++;
16321
0
            }
16322
0
            var_refs[i] = var_ref;
16323
0
        }
16324
0
    }
16325
0
    return func_obj;
16326
0
 fail:
16327
    /* bfunc is freed when func_obj is freed */
16328
0
    JS_FreeValue(ctx, func_obj);
16329
0
    return JS_EXCEPTION;
16330
0
}
16331
16332
static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque)
16333
0
{
16334
0
    JSValue obj, this_val;
16335
0
    int ret;
16336
16337
0
    this_val = JS_MKPTR(JS_TAG_OBJECT, p);
16338
0
    obj = JS_NewObject(ctx);
16339
0
    if (JS_IsException(obj))
16340
0
        return JS_EXCEPTION;
16341
0
    set_cycle_flag(ctx, obj);
16342
0
    set_cycle_flag(ctx, this_val);
16343
0
    ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_constructor,
16344
0
                                 JS_DupValue(ctx, this_val),
16345
0
                                 JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
16346
0
    if (ret < 0) {
16347
0
        JS_FreeValue(ctx, obj);
16348
0
        return JS_EXCEPTION;
16349
0
    }
16350
0
    return obj;
16351
0
}
16352
16353
static const uint16_t func_kind_to_class_id[] = {
16354
    [JS_FUNC_NORMAL] = JS_CLASS_BYTECODE_FUNCTION,
16355
    [JS_FUNC_GENERATOR] = JS_CLASS_GENERATOR_FUNCTION,
16356
    [JS_FUNC_ASYNC] = JS_CLASS_ASYNC_FUNCTION,
16357
    [JS_FUNC_ASYNC_GENERATOR] = JS_CLASS_ASYNC_GENERATOR_FUNCTION,
16358
};
16359
16360
static JSValue js_closure(JSContext *ctx, JSValue bfunc,
16361
                          JSVarRef **cur_var_refs,
16362
                          JSStackFrame *sf)
16363
0
{
16364
0
    JSFunctionBytecode *b;
16365
0
    JSValue func_obj;
16366
0
    JSAtom name_atom;
16367
16368
0
    b = JS_VALUE_GET_PTR(bfunc);
16369
0
    func_obj = JS_NewObjectClass(ctx, func_kind_to_class_id[b->func_kind]);
16370
0
    if (JS_IsException(func_obj)) {
16371
0
        JS_FreeValue(ctx, bfunc);
16372
0
        return JS_EXCEPTION;
16373
0
    }
16374
0
    func_obj = js_closure2(ctx, func_obj, b, cur_var_refs, sf);
16375
0
    if (JS_IsException(func_obj)) {
16376
        /* bfunc has been freed */
16377
0
        goto fail;
16378
0
    }
16379
0
    name_atom = b->func_name;
16380
0
    if (name_atom == JS_ATOM_NULL)
16381
0
        name_atom = JS_ATOM_empty_string;
16382
0
    js_function_set_properties(ctx, func_obj, name_atom,
16383
0
                               b->defined_arg_count);
16384
16385
0
    if (b->func_kind & JS_FUNC_GENERATOR) {
16386
0
        JSValue proto;
16387
0
        int proto_class_id;
16388
        /* generators have a prototype field which is used as
16389
           prototype for the generator object */
16390
0
        if (b->func_kind == JS_FUNC_ASYNC_GENERATOR)
16391
0
            proto_class_id = JS_CLASS_ASYNC_GENERATOR;
16392
0
        else
16393
0
            proto_class_id = JS_CLASS_GENERATOR;
16394
0
        proto = JS_NewObjectProto(ctx, ctx->class_proto[proto_class_id]);
16395
0
        if (JS_IsException(proto))
16396
0
            goto fail;
16397
0
        JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype, proto,
16398
0
                               JS_PROP_WRITABLE);
16399
0
    } else if (b->has_prototype) {
16400
        /* add the 'prototype' property: delay instantiation to avoid
16401
           creating cycles for every javascript function. The prototype
16402
           object is created on the fly when first accessed */
16403
0
        JS_SetConstructorBit(ctx, func_obj, TRUE);
16404
0
        JS_DefineAutoInitProperty(ctx, func_obj, JS_ATOM_prototype,
16405
0
                                  JS_AUTOINIT_ID_PROTOTYPE, NULL,
16406
0
                                  JS_PROP_WRITABLE);
16407
0
    }
16408
0
    return func_obj;
16409
0
 fail:
16410
    /* bfunc is freed when func_obj is freed */
16411
0
    JS_FreeValue(ctx, func_obj);
16412
0
    return JS_EXCEPTION;
16413
0
}
16414
16415
0
#define JS_DEFINE_CLASS_HAS_HERITAGE     (1 << 0)
16416
16417
static int js_op_define_class(JSContext *ctx, JSValue *sp,
16418
                              JSAtom class_name, int class_flags,
16419
                              JSVarRef **cur_var_refs,
16420
                              JSStackFrame *sf, BOOL is_computed_name)
16421
0
{
16422
0
    JSValue bfunc, parent_class, proto = JS_UNDEFINED;
16423
0
    JSValue ctor = JS_UNDEFINED, parent_proto = JS_UNDEFINED;
16424
0
    JSFunctionBytecode *b;
16425
16426
0
    parent_class = sp[-2];
16427
0
    bfunc = sp[-1];
16428
16429
0
    if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE) {
16430
0
        if (JS_IsNull(parent_class)) {
16431
0
            parent_proto = JS_NULL;
16432
0
            parent_class = JS_DupValue(ctx, ctx->function_proto);
16433
0
        } else {
16434
0
            if (!JS_IsConstructor(ctx, parent_class)) {
16435
0
                JS_ThrowTypeError(ctx, "parent class must be constructor");
16436
0
                goto fail;
16437
0
            }
16438
0
            parent_proto = JS_GetProperty(ctx, parent_class, JS_ATOM_prototype);
16439
0
            if (JS_IsException(parent_proto))
16440
0
                goto fail;
16441
0
            if (!JS_IsNull(parent_proto) && !JS_IsObject(parent_proto)) {
16442
0
                JS_ThrowTypeError(ctx, "parent prototype must be an object or null");
16443
0
                goto fail;
16444
0
            }
16445
0
        }
16446
0
    } else {
16447
        /* parent_class is JS_UNDEFINED in this case */
16448
0
        parent_proto = JS_DupValue(ctx, ctx->class_proto[JS_CLASS_OBJECT]);
16449
0
        parent_class = JS_DupValue(ctx, ctx->function_proto);
16450
0
    }
16451
0
    proto = JS_NewObjectProto(ctx, parent_proto);
16452
0
    if (JS_IsException(proto))
16453
0
        goto fail;
16454
16455
0
    b = JS_VALUE_GET_PTR(bfunc);
16456
0
    assert(b->func_kind == JS_FUNC_NORMAL);
16457
0
    ctor = JS_NewObjectProtoClass(ctx, parent_class,
16458
0
                                  JS_CLASS_BYTECODE_FUNCTION);
16459
0
    if (JS_IsException(ctor))
16460
0
        goto fail;
16461
0
    ctor = js_closure2(ctx, ctor, b, cur_var_refs, sf);
16462
0
    bfunc = JS_UNDEFINED;
16463
0
    if (JS_IsException(ctor))
16464
0
        goto fail;
16465
0
    js_method_set_home_object(ctx, ctor, proto);
16466
0
    JS_SetConstructorBit(ctx, ctor, TRUE);
16467
16468
0
    JS_DefinePropertyValue(ctx, ctor, JS_ATOM_length,
16469
0
                           JS_NewInt32(ctx, b->defined_arg_count),
16470
0
                           JS_PROP_CONFIGURABLE);
16471
16472
0
    if (is_computed_name) {
16473
0
        if (JS_DefineObjectNameComputed(ctx, ctor, sp[-3],
16474
0
                                        JS_PROP_CONFIGURABLE) < 0)
16475
0
            goto fail;
16476
0
    } else {
16477
0
        if (JS_DefineObjectName(ctx, ctor, class_name, JS_PROP_CONFIGURABLE) < 0)
16478
0
            goto fail;
16479
0
    }
16480
16481
    /* the constructor property must be first. It can be overriden by
16482
       computed property names */
16483
0
    if (JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor,
16484
0
                               JS_DupValue(ctx, ctor),
16485
0
                               JS_PROP_CONFIGURABLE |
16486
0
                               JS_PROP_WRITABLE | JS_PROP_THROW) < 0)
16487
0
        goto fail;
16488
    /* set the prototype property */
16489
0
    if (JS_DefinePropertyValue(ctx, ctor, JS_ATOM_prototype,
16490
0
                               JS_DupValue(ctx, proto), JS_PROP_THROW) < 0)
16491
0
        goto fail;
16492
0
    set_cycle_flag(ctx, ctor);
16493
0
    set_cycle_flag(ctx, proto);
16494
16495
0
    JS_FreeValue(ctx, parent_proto);
16496
0
    JS_FreeValue(ctx, parent_class);
16497
16498
0
    sp[-2] = ctor;
16499
0
    sp[-1] = proto;
16500
0
    return 0;
16501
0
 fail:
16502
0
    JS_FreeValue(ctx, parent_class);
16503
0
    JS_FreeValue(ctx, parent_proto);
16504
0
    JS_FreeValue(ctx, bfunc);
16505
0
    JS_FreeValue(ctx, proto);
16506
0
    JS_FreeValue(ctx, ctor);
16507
0
    sp[-2] = JS_UNDEFINED;
16508
0
    sp[-1] = JS_UNDEFINED;
16509
0
    return -1;
16510
0
}
16511
16512
static void close_var_refs(JSRuntime *rt, JSStackFrame *sf)
16513
3
{
16514
3
    struct list_head *el, *el1;
16515
3
    JSVarRef *var_ref;
16516
16517
3
    list_for_each_safe(el, el1, &sf->var_ref_list) {
16518
0
        var_ref = list_entry(el, JSVarRef, var_ref_link);
16519
        /* no need to unlink var_ref->var_ref_link as the list is never used afterwards */
16520
0
        if (var_ref->async_func)
16521
0
            async_func_free(rt, var_ref->async_func);
16522
0
        var_ref->value = JS_DupValueRT(rt, *var_ref->pvalue);
16523
0
        var_ref->pvalue = &var_ref->value;
16524
        /* the reference is no longer to a local variable */
16525
0
        var_ref->is_detached = TRUE;
16526
0
    }
16527
3
}
16528
16529
static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int var_idx)
16530
0
{
16531
0
    JSValue *pvalue;
16532
0
    struct list_head *el, *el1;
16533
0
    JSVarRef *var_ref;
16534
16535
0
    pvalue = &sf->var_buf[var_idx];
16536
0
    list_for_each_safe(el, el1, &sf->var_ref_list) {
16537
0
        var_ref = list_entry(el, JSVarRef, var_ref_link);
16538
0
        if (var_ref->pvalue == pvalue) {
16539
0
            list_del(&var_ref->var_ref_link);
16540
0
            if (var_ref->async_func)
16541
0
                async_func_free(ctx->rt, var_ref->async_func);
16542
0
            var_ref->value = JS_DupValue(ctx, *var_ref->pvalue);
16543
0
            var_ref->pvalue = &var_ref->value;
16544
            /* the reference is no longer to a local variable */
16545
0
            var_ref->is_detached = TRUE;
16546
0
        }
16547
0
    }
16548
0
}
16549
16550
15
#define JS_CALL_FLAG_COPY_ARGV   (1 << 1)
16551
6
#define JS_CALL_FLAG_GENERATOR   (1 << 2)
16552
16553
static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
16554
                                  JSValueConst this_obj,
16555
                                  int argc, JSValueConst *argv, int flags)
16556
0
{
16557
0
    JSRuntime *rt = ctx->rt;
16558
0
    JSCFunctionType func;
16559
0
    JSObject *p;
16560
0
    JSStackFrame sf_s, *sf = &sf_s, *prev_sf;
16561
0
    JSValue ret_val;
16562
0
    JSValueConst *arg_buf;
16563
0
    int arg_count, i;
16564
0
    JSCFunctionEnum cproto;
16565
16566
0
    p = JS_VALUE_GET_OBJ(func_obj);
16567
0
    cproto = p->u.cfunc.cproto;
16568
0
    arg_count = p->u.cfunc.length;
16569
16570
    /* better to always check stack overflow */
16571
0
    if (js_check_stack_overflow(rt, sizeof(arg_buf[0]) * arg_count))
16572
0
        return JS_ThrowStackOverflow(ctx);
16573
16574
0
    prev_sf = rt->current_stack_frame;
16575
0
    sf->prev_frame = prev_sf;
16576
0
    rt->current_stack_frame = sf;
16577
0
    ctx = p->u.cfunc.realm; /* change the current realm */
16578
0
    sf->js_mode = 0;
16579
0
    sf->cur_func = (JSValue)func_obj;
16580
0
    sf->arg_count = argc;
16581
0
    arg_buf = argv;
16582
16583
0
    if (unlikely(argc < arg_count)) {
16584
        /* ensure that at least argc_count arguments are readable */
16585
0
        arg_buf = alloca(sizeof(arg_buf[0]) * arg_count);
16586
0
        for(i = 0; i < argc; i++)
16587
0
            arg_buf[i] = argv[i];
16588
0
        for(i = argc; i < arg_count; i++)
16589
0
            arg_buf[i] = JS_UNDEFINED;
16590
0
        sf->arg_count = arg_count;
16591
0
    }
16592
0
    sf->arg_buf = (JSValue*)arg_buf;
16593
16594
0
    func = p->u.cfunc.c_function;
16595
0
    switch(cproto) {
16596
0
    case JS_CFUNC_constructor:
16597
0
    case JS_CFUNC_constructor_or_func:
16598
0
        if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) {
16599
0
            if (cproto == JS_CFUNC_constructor) {
16600
0
            not_a_constructor:
16601
0
                ret_val = JS_ThrowTypeError(ctx, "must be called with new");
16602
0
                break;
16603
0
            } else {
16604
0
                this_obj = JS_UNDEFINED;
16605
0
            }
16606
0
        }
16607
        /* here this_obj is new_target */
16608
        /* fall thru */
16609
0
    case JS_CFUNC_generic:
16610
0
        ret_val = func.generic(ctx, this_obj, argc, arg_buf);
16611
0
        break;
16612
0
    case JS_CFUNC_constructor_magic:
16613
0
    case JS_CFUNC_constructor_or_func_magic:
16614
0
        if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) {
16615
0
            if (cproto == JS_CFUNC_constructor_magic) {
16616
0
                goto not_a_constructor;
16617
0
            } else {
16618
0
                this_obj = JS_UNDEFINED;
16619
0
            }
16620
0
        }
16621
        /* fall thru */
16622
0
    case JS_CFUNC_generic_magic:
16623
0
        ret_val = func.generic_magic(ctx, this_obj, argc, arg_buf,
16624
0
                                     p->u.cfunc.magic);
16625
0
        break;
16626
0
    case JS_CFUNC_getter:
16627
0
        ret_val = func.getter(ctx, this_obj);
16628
0
        break;
16629
0
    case JS_CFUNC_setter:
16630
0
        ret_val = func.setter(ctx, this_obj, arg_buf[0]);
16631
0
        break;
16632
0
    case JS_CFUNC_getter_magic:
16633
0
        ret_val = func.getter_magic(ctx, this_obj, p->u.cfunc.magic);
16634
0
        break;
16635
0
    case JS_CFUNC_setter_magic:
16636
0
        ret_val = func.setter_magic(ctx, this_obj, arg_buf[0], p->u.cfunc.magic);
16637
0
        break;
16638
0
    case JS_CFUNC_f_f:
16639
0
        {
16640
0
            double d1;
16641
16642
0
            if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) {
16643
0
                ret_val = JS_EXCEPTION;
16644
0
                break;
16645
0
            }
16646
0
            ret_val = JS_NewFloat64(ctx, func.f_f(d1));
16647
0
        }
16648
0
        break;
16649
0
    case JS_CFUNC_f_f_f:
16650
0
        {
16651
0
            double d1, d2;
16652
16653
0
            if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) {
16654
0
                ret_val = JS_EXCEPTION;
16655
0
                break;
16656
0
            }
16657
0
            if (unlikely(JS_ToFloat64(ctx, &d2, arg_buf[1]))) {
16658
0
                ret_val = JS_EXCEPTION;
16659
0
                break;
16660
0
            }
16661
0
            ret_val = JS_NewFloat64(ctx, func.f_f_f(d1, d2));
16662
0
        }
16663
0
        break;
16664
0
    case JS_CFUNC_iterator_next:
16665
0
        {
16666
0
            int done;
16667
0
            ret_val = func.iterator_next(ctx, this_obj, argc, arg_buf,
16668
0
                                         &done, p->u.cfunc.magic);
16669
0
            if (!JS_IsException(ret_val) && done != 2) {
16670
0
                ret_val = js_create_iterator_result(ctx, ret_val, done);
16671
0
            }
16672
0
        }
16673
0
        break;
16674
0
    default:
16675
0
        abort();
16676
0
    }
16677
16678
0
    rt->current_stack_frame = sf->prev_frame;
16679
0
    return ret_val;
16680
0
}
16681
16682
static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj,
16683
                                      JSValueConst this_obj,
16684
                                      int argc, JSValueConst *argv, int flags)
16685
0
{
16686
0
    JSObject *p;
16687
0
    JSBoundFunction *bf;
16688
0
    JSValueConst *arg_buf, new_target;
16689
0
    int arg_count, i;
16690
16691
0
    p = JS_VALUE_GET_OBJ(func_obj);
16692
0
    bf = p->u.bound_function;
16693
0
    arg_count = bf->argc + argc;
16694
0
    if (js_check_stack_overflow(ctx->rt, sizeof(JSValue) * arg_count))
16695
0
        return JS_ThrowStackOverflow(ctx);
16696
0
    arg_buf = alloca(sizeof(JSValue) * arg_count);
16697
0
    for(i = 0; i < bf->argc; i++) {
16698
0
        arg_buf[i] = bf->argv[i];
16699
0
    }
16700
0
    for(i = 0; i < argc; i++) {
16701
0
        arg_buf[bf->argc + i] = argv[i];
16702
0
    }
16703
0
    if (flags & JS_CALL_FLAG_CONSTRUCTOR) {
16704
0
        new_target = this_obj;
16705
0
        if (js_same_value(ctx, func_obj, new_target))
16706
0
            new_target = bf->func_obj;
16707
0
        return JS_CallConstructor2(ctx, bf->func_obj, new_target,
16708
0
                                   arg_count, arg_buf);
16709
0
    } else {
16710
0
        return JS_Call(ctx, bf->func_obj, bf->this_val,
16711
0
                       arg_count, arg_buf);
16712
0
    }
16713
0
}
16714
16715
/* argument of OP_special_object */
16716
typedef enum {
16717
    OP_SPECIAL_OBJECT_ARGUMENTS,
16718
    OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS,
16719
    OP_SPECIAL_OBJECT_THIS_FUNC,
16720
    OP_SPECIAL_OBJECT_NEW_TARGET,
16721
    OP_SPECIAL_OBJECT_HOME_OBJECT,
16722
    OP_SPECIAL_OBJECT_VAR_OBJECT,
16723
    OP_SPECIAL_OBJECT_IMPORT_META,
16724
} OPSpecialObjectEnum;
16725
16726
0
#define FUNC_RET_AWAIT         0
16727
0
#define FUNC_RET_YIELD         1
16728
0
#define FUNC_RET_YIELD_STAR    2
16729
0
#define FUNC_RET_INITIAL_YIELD 3
16730
16731
/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */
16732
static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
16733
                               JSValueConst this_obj, JSValueConst new_target,
16734
                               int argc, JSValue *argv, int flags)
16735
18
{
16736
18
    JSRuntime *rt = caller_ctx->rt;
16737
18
    JSContext *ctx;
16738
18
    JSObject *p;
16739
18
    JSFunctionBytecode *b;
16740
18
    JSStackFrame sf_s, *sf = &sf_s;
16741
18
    const uint8_t *pc;
16742
18
    int opcode, arg_allocated_size, i;
16743
18
    JSValue *local_buf, *stack_buf, *var_buf, *arg_buf, *sp, ret_val, *pval;
16744
18
    JSVarRef **var_refs;
16745
18
    size_t alloca_size;
16746
16747
#if !DIRECT_DISPATCH
16748
#define SWITCH(pc)      switch (opcode = *pc++)
16749
#define CASE(op)        case op
16750
#define DEFAULT         default
16751
#define BREAK           break
16752
#else
16753
18
    static const void * const dispatch_table[256] = {
16754
4.46k
#define DEF(id, size, n_pop, n_push, f) && case_OP_ ## id,
16755
18
#if SHORT_OPCODES
16756
18
#define def(id, size, n_pop, n_push, f)
16757
#else
16758
#define def(id, size, n_pop, n_push, f) && case_default,
16759
#endif
16760
18
#include "quickjs-opcode.h"
16761
18
        [ OP_COUNT ... 255 ] = &&case_default
16762
18
    };
16763
32
#define SWITCH(pc)      goto *dispatch_table[opcode = *pc++];
16764
32
#define CASE(op)        case_ ## op
16765
18
#define DEFAULT         case_default
16766
26
#define BREAK           SWITCH(pc)
16767
18
#endif
16768
16769
18
    if (js_poll_interrupts(caller_ctx))
16770
0
        return JS_EXCEPTION;
16771
18
    if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)) {
16772
3
        if (flags & JS_CALL_FLAG_GENERATOR) {
16773
3
            JSAsyncFunctionState *s = JS_VALUE_GET_PTR(func_obj);
16774
            /* func_obj get contains a pointer to JSFuncAsyncState */
16775
            /* the stack frame is already allocated */
16776
3
            sf = &s->frame;
16777
3
            p = JS_VALUE_GET_OBJ(sf->cur_func);
16778
3
            b = p->u.func.function_bytecode;
16779
3
            ctx = b->realm;
16780
3
            var_refs = p->u.func.var_refs;
16781
3
            local_buf = arg_buf = sf->arg_buf;
16782
3
            var_buf = sf->var_buf;
16783
3
            stack_buf = sf->var_buf + b->var_count;
16784
3
            sp = sf->cur_sp;
16785
3
            sf->cur_sp = NULL; /* cur_sp is NULL if the function is running */
16786
3
            pc = sf->cur_pc;
16787
3
            sf->prev_frame = rt->current_stack_frame;
16788
3
            rt->current_stack_frame = sf;
16789
3
            if (s->throw_flag)
16790
0
                goto exception;
16791
3
            else
16792
3
                goto restart;
16793
3
        } else {
16794
0
            goto not_a_function;
16795
0
        }
16796
3
    }
16797
15
    p = JS_VALUE_GET_OBJ(func_obj);
16798
15
    if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {
16799
12
        JSClassCall *call_func;
16800
12
        call_func = rt->class_array[p->class_id].call;
16801
12
        if (!call_func) {
16802
0
        not_a_function:
16803
0
            return JS_ThrowTypeError(caller_ctx, "not a function");
16804
0
        }
16805
12
        return call_func(caller_ctx, func_obj, this_obj, argc,
16806
12
                         (JSValueConst *)argv, flags);
16807
12
    }
16808
3
    b = p->u.func.function_bytecode;
16809
16810
3
    if (unlikely(argc < b->arg_count || (flags & JS_CALL_FLAG_COPY_ARGV))) {
16811
3
        arg_allocated_size = b->arg_count;
16812
3
    } else {
16813
0
        arg_allocated_size = 0;
16814
0
    }
16815
16816
3
    alloca_size = sizeof(JSValue) * (arg_allocated_size + b->var_count +
16817
3
                                     b->stack_size);
16818
3
    if (js_check_stack_overflow(rt, alloca_size))
16819
0
        return JS_ThrowStackOverflow(caller_ctx);
16820
16821
3
    sf->js_mode = b->js_mode;
16822
3
    arg_buf = argv;
16823
3
    sf->arg_count = argc;
16824
3
    sf->cur_func = (JSValue)func_obj;
16825
3
    init_list_head(&sf->var_ref_list);
16826
3
    var_refs = p->u.func.var_refs;
16827
16828
3
    local_buf = alloca(alloca_size);
16829
3
    if (unlikely(arg_allocated_size)) {
16830
0
        int n = min_int(argc, b->arg_count);
16831
0
        arg_buf = local_buf;
16832
0
        for(i = 0; i < n; i++)
16833
0
            arg_buf[i] = JS_DupValue(caller_ctx, argv[i]);
16834
0
        for(; i < b->arg_count; i++)
16835
0
            arg_buf[i] = JS_UNDEFINED;
16836
0
        sf->arg_count = b->arg_count;
16837
0
    }
16838
3
    var_buf = local_buf + arg_allocated_size;
16839
3
    sf->var_buf = var_buf;
16840
3
    sf->arg_buf = arg_buf;
16841
16842
3
    for(i = 0; i < b->var_count; i++)
16843
3
        var_buf[i] = JS_UNDEFINED;
16844
16845
3
    stack_buf = var_buf + b->var_count;
16846
3
    sp = stack_buf;
16847
3
    pc = b->byte_code_buf;
16848
3
    sf->prev_frame = rt->current_stack_frame;
16849
3
    rt->current_stack_frame = sf;
16850
3
    ctx = b->realm; /* set the current realm */
16851
16852
6
 restart:
16853
6
    for(;;) {
16854
6
        int call_argc;
16855
6
        JSValue *call_argv;
16856
16857
6
        SWITCH(pc) {
16858
6
        CASE(OP_push_i32):
16859
0
            *sp++ = JS_NewInt32(ctx, get_u32(pc));
16860
0
            pc += 4;
16861
0
            BREAK;
16862
0
        CASE(OP_push_bigint_i32):
16863
0
            *sp++ = __JS_NewShortBigInt(ctx, (int)get_u32(pc));
16864
0
            pc += 4;
16865
0
            BREAK;
16866
0
        CASE(OP_push_const):
16867
0
            *sp++ = JS_DupValue(ctx, b->cpool[get_u32(pc)]);
16868
0
            pc += 4;
16869
0
            BREAK;
16870
0
#if SHORT_OPCODES
16871
0
        CASE(OP_push_minus1):
16872
0
        CASE(OP_push_0):
16873
0
        CASE(OP_push_1):
16874
0
        CASE(OP_push_2):
16875
0
        CASE(OP_push_3):
16876
0
        CASE(OP_push_4):
16877
0
        CASE(OP_push_5):
16878
0
        CASE(OP_push_6):
16879
0
        CASE(OP_push_7):
16880
0
            *sp++ = JS_NewInt32(ctx, opcode - OP_push_0);
16881
0
            BREAK;
16882
0
        CASE(OP_push_i8):
16883
0
            *sp++ = JS_NewInt32(ctx, get_i8(pc));
16884
0
            pc += 1;
16885
0
            BREAK;
16886
0
        CASE(OP_push_i16):
16887
0
            *sp++ = JS_NewInt32(ctx, get_i16(pc));
16888
0
            pc += 2;
16889
0
            BREAK;
16890
0
        CASE(OP_push_const8):
16891
0
            *sp++ = JS_DupValue(ctx, b->cpool[*pc++]);
16892
0
            BREAK;
16893
0
        CASE(OP_fclosure8):
16894
0
            *sp++ = js_closure(ctx, JS_DupValue(ctx, b->cpool[*pc++]), var_refs, sf);
16895
0
            if (unlikely(JS_IsException(sp[-1])))
16896
0
                goto exception;
16897
0
            BREAK;
16898
0
        CASE(OP_push_empty_string):
16899
0
            *sp++ = JS_AtomToString(ctx, JS_ATOM_empty_string);
16900
0
            BREAK;
16901
0
        CASE(OP_get_length):
16902
0
            {
16903
0
                JSValue val;
16904
16905
0
                sf->cur_pc = pc;
16906
0
                val = JS_GetProperty(ctx, sp[-1], JS_ATOM_length);
16907
0
                if (unlikely(JS_IsException(val)))
16908
0
                    goto exception;
16909
0
                JS_FreeValue(ctx, sp[-1]);
16910
0
                sp[-1] = val;
16911
0
            }
16912
0
            BREAK;
16913
0
#endif
16914
0
        CASE(OP_push_atom_value):
16915
0
            *sp++ = JS_AtomToValue(ctx, get_u32(pc));
16916
0
            pc += 4;
16917
0
            BREAK;
16918
2
        CASE(OP_undefined):
16919
2
            *sp++ = JS_UNDEFINED;
16920
2
            BREAK;
16921
2
        CASE(OP_null):
16922
0
            *sp++ = JS_NULL;
16923
0
            BREAK;
16924
6
        CASE(OP_push_this):
16925
            /* OP_push_this is only called at the start of a function */
16926
6
            {
16927
6
                JSValue val;
16928
6
                if (!(b->js_mode & JS_MODE_STRICT)) {
16929
0
                    uint32_t tag = JS_VALUE_GET_TAG(this_obj);
16930
0
                    if (likely(tag == JS_TAG_OBJECT))
16931
0
                        goto normal_this;
16932
0
                    if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) {
16933
0
                        val = JS_DupValue(ctx, ctx->global_obj);
16934
0
                    } else {
16935
0
                        val = JS_ToObject(ctx, this_obj);
16936
0
                        if (JS_IsException(val))
16937
0
                            goto exception;
16938
0
                    }
16939
6
                } else {
16940
6
                normal_this:
16941
6
                    val = JS_DupValue(ctx, this_obj);
16942
6
                }
16943
6
                *sp++ = val;
16944
6
            }
16945
6
            BREAK;
16946
6
        CASE(OP_push_false):
16947
0
            *sp++ = JS_FALSE;
16948
0
            BREAK;
16949
0
        CASE(OP_push_true):
16950
0
            *sp++ = JS_TRUE;
16951
0
            BREAK;
16952
0
        CASE(OP_object):
16953
0
            *sp++ = JS_NewObject(ctx);
16954
0
            if (unlikely(JS_IsException(sp[-1])))
16955
0
                goto exception;
16956
0
            BREAK;
16957
0
        CASE(OP_special_object):
16958
0
            {
16959
0
                int arg = *pc++;
16960
0
                switch(arg) {
16961
0
                case OP_SPECIAL_OBJECT_ARGUMENTS:
16962
0
                    *sp++ = js_build_arguments(ctx, argc, (JSValueConst *)argv);
16963
0
                    if (unlikely(JS_IsException(sp[-1])))
16964
0
                        goto exception;
16965
0
                    break;
16966
0
                case OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS:
16967
0
                    *sp++ = js_build_mapped_arguments(ctx, argc, (JSValueConst *)argv,
16968
0
                                                      sf, min_int(argc, b->arg_count));
16969
0
                    if (unlikely(JS_IsException(sp[-1])))
16970
0
                        goto exception;
16971
0
                    break;
16972
0
                case OP_SPECIAL_OBJECT_THIS_FUNC:
16973
0
                    *sp++ = JS_DupValue(ctx, sf->cur_func);
16974
0
                    break;
16975
0
                case OP_SPECIAL_OBJECT_NEW_TARGET:
16976
0
                    *sp++ = JS_DupValue(ctx, new_target);
16977
0
                    break;
16978
0
                case OP_SPECIAL_OBJECT_HOME_OBJECT:
16979
0
                    {
16980
0
                        JSObject *p1;
16981
0
                        p1 = p->u.func.home_object;
16982
0
                        if (unlikely(!p1))
16983
0
                            *sp++ = JS_UNDEFINED;
16984
0
                        else
16985
0
                            *sp++ = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
16986
0
                    }
16987
0
                    break;
16988
0
                case OP_SPECIAL_OBJECT_VAR_OBJECT:
16989
0
                    *sp++ = JS_NewObjectProto(ctx, JS_NULL);
16990
0
                    if (unlikely(JS_IsException(sp[-1])))
16991
0
                        goto exception;
16992
0
                    break;
16993
0
                case OP_SPECIAL_OBJECT_IMPORT_META:
16994
0
                    *sp++ = js_import_meta(ctx);
16995
0
                    if (unlikely(JS_IsException(sp[-1])))
16996
0
                        goto exception;
16997
0
                    break;
16998
0
                default:
16999
0
                    abort();
17000
0
                }
17001
0
            }
17002
0
            BREAK;
17003
0
        CASE(OP_rest):
17004
0
            {
17005
0
                int first = get_u16(pc);
17006
0
                pc += 2;
17007
0
                *sp++ = js_build_rest(ctx, first, argc, (JSValueConst *)argv);
17008
0
                if (unlikely(JS_IsException(sp[-1])))
17009
0
                    goto exception;
17010
0
            }
17011
0
            BREAK;
17012
17013
0
        CASE(OP_drop):
17014
0
            JS_FreeValue(ctx, sp[-1]);
17015
0
            sp--;
17016
0
            BREAK;
17017
0
        CASE(OP_nip):
17018
0
            JS_FreeValue(ctx, sp[-2]);
17019
0
            sp[-2] = sp[-1];
17020
0
            sp--;
17021
0
            BREAK;
17022
0
        CASE(OP_nip1): /* a b c -> b c */
17023
0
            JS_FreeValue(ctx, sp[-3]);
17024
0
            sp[-3] = sp[-2];
17025
0
            sp[-2] = sp[-1];
17026
0
            sp--;
17027
0
            BREAK;
17028
0
        CASE(OP_dup):
17029
0
            sp[0] = JS_DupValue(ctx, sp[-1]);
17030
0
            sp++;
17031
0
            BREAK;
17032
0
        CASE(OP_dup2): /* a b -> a b a b */
17033
0
            sp[0] = JS_DupValue(ctx, sp[-2]);
17034
0
            sp[1] = JS_DupValue(ctx, sp[-1]);
17035
0
            sp += 2;
17036
0
            BREAK;
17037
0
        CASE(OP_dup3): /* a b c -> a b c a b c */
17038
0
            sp[0] = JS_DupValue(ctx, sp[-3]);
17039
0
            sp[1] = JS_DupValue(ctx, sp[-2]);
17040
0
            sp[2] = JS_DupValue(ctx, sp[-1]);
17041
0
            sp += 3;
17042
0
            BREAK;
17043
0
        CASE(OP_dup1): /* a b -> a a b */
17044
0
            sp[0] = sp[-1];
17045
0
            sp[-1] = JS_DupValue(ctx, sp[-2]);
17046
0
            sp++;
17047
0
            BREAK;
17048
0
        CASE(OP_insert2): /* obj a -> a obj a (dup_x1) */
17049
0
            sp[0] = sp[-1];
17050
0
            sp[-1] = sp[-2];
17051
0
            sp[-2] = JS_DupValue(ctx, sp[0]);
17052
0
            sp++;
17053
0
            BREAK;
17054
0
        CASE(OP_insert3): /* obj prop a -> a obj prop a (dup_x2) */
17055
0
            sp[0] = sp[-1];
17056
0
            sp[-1] = sp[-2];
17057
0
            sp[-2] = sp[-3];
17058
0
            sp[-3] = JS_DupValue(ctx, sp[0]);
17059
0
            sp++;
17060
0
            BREAK;
17061
0
        CASE(OP_insert4): /* this obj prop a -> a this obj prop a */
17062
0
            sp[0] = sp[-1];
17063
0
            sp[-1] = sp[-2];
17064
0
            sp[-2] = sp[-3];
17065
0
            sp[-3] = sp[-4];
17066
0
            sp[-4] = JS_DupValue(ctx, sp[0]);
17067
0
            sp++;
17068
0
            BREAK;
17069
0
        CASE(OP_perm3): /* obj a b -> a obj b (213) */
17070
0
            {
17071
0
                JSValue tmp;
17072
0
                tmp = sp[-2];
17073
0
                sp[-2] = sp[-3];
17074
0
                sp[-3] = tmp;
17075
0
            }
17076
0
            BREAK;
17077
0
        CASE(OP_rot3l): /* x a b -> a b x (231) */
17078
0
            {
17079
0
                JSValue tmp;
17080
0
                tmp = sp[-3];
17081
0
                sp[-3] = sp[-2];
17082
0
                sp[-2] = sp[-1];
17083
0
                sp[-1] = tmp;
17084
0
            }
17085
0
            BREAK;
17086
0
        CASE(OP_rot4l): /* x a b c -> a b c x */
17087
0
            {
17088
0
                JSValue tmp;
17089
0
                tmp = sp[-4];
17090
0
                sp[-4] = sp[-3];
17091
0
                sp[-3] = sp[-2];
17092
0
                sp[-2] = sp[-1];
17093
0
                sp[-1] = tmp;
17094
0
            }
17095
0
            BREAK;
17096
0
        CASE(OP_rot5l): /* x a b c d -> a b c d x */
17097
0
            {
17098
0
                JSValue tmp;
17099
0
                tmp = sp[-5];
17100
0
                sp[-5] = sp[-4];
17101
0
                sp[-4] = sp[-3];
17102
0
                sp[-3] = sp[-2];
17103
0
                sp[-2] = sp[-1];
17104
0
                sp[-1] = tmp;
17105
0
            }
17106
0
            BREAK;
17107
0
        CASE(OP_rot3r): /* a b x -> x a b (312) */
17108
0
            {
17109
0
                JSValue tmp;
17110
0
                tmp = sp[-1];
17111
0
                sp[-1] = sp[-2];
17112
0
                sp[-2] = sp[-3];
17113
0
                sp[-3] = tmp;
17114
0
            }
17115
0
            BREAK;
17116
0
        CASE(OP_perm4): /* obj prop a b -> a obj prop b */
17117
0
            {
17118
0
                JSValue tmp;
17119
0
                tmp = sp[-2];
17120
0
                sp[-2] = sp[-3];
17121
0
                sp[-3] = sp[-4];
17122
0
                sp[-4] = tmp;
17123
0
            }
17124
0
            BREAK;
17125
0
        CASE(OP_perm5): /* this obj prop a b -> a this obj prop b */
17126
0
            {
17127
0
                JSValue tmp;
17128
0
                tmp = sp[-2];
17129
0
                sp[-2] = sp[-3];
17130
0
                sp[-3] = sp[-4];
17131
0
                sp[-4] = sp[-5];
17132
0
                sp[-5] = tmp;
17133
0
            }
17134
0
            BREAK;
17135
0
        CASE(OP_swap): /* a b -> b a */
17136
0
            {
17137
0
                JSValue tmp;
17138
0
                tmp = sp[-2];
17139
0
                sp[-2] = sp[-1];
17140
0
                sp[-1] = tmp;
17141
0
            }
17142
0
            BREAK;
17143
0
        CASE(OP_swap2): /* a b c d -> c d a b */
17144
0
            {
17145
0
                JSValue tmp1, tmp2;
17146
0
                tmp1 = sp[-4];
17147
0
                tmp2 = sp[-3];
17148
0
                sp[-4] = sp[-2];
17149
0
                sp[-3] = sp[-1];
17150
0
                sp[-2] = tmp1;
17151
0
                sp[-1] = tmp2;
17152
0
            }
17153
0
            BREAK;
17154
17155
0
        CASE(OP_fclosure):
17156
0
            {
17157
0
                JSValue bfunc = JS_DupValue(ctx, b->cpool[get_u32(pc)]);
17158
0
                pc += 4;
17159
0
                *sp++ = js_closure(ctx, bfunc, var_refs, sf);
17160
0
                if (unlikely(JS_IsException(sp[-1])))
17161
0
                    goto exception;
17162
0
            }
17163
0
            BREAK;
17164
0
#if SHORT_OPCODES
17165
0
        CASE(OP_call0):
17166
0
        CASE(OP_call1):
17167
0
        CASE(OP_call2):
17168
0
        CASE(OP_call3):
17169
0
            call_argc = opcode - OP_call0;
17170
0
            goto has_call_argc;
17171
0
#endif
17172
0
        CASE(OP_call):
17173
0
        CASE(OP_tail_call):
17174
0
            {
17175
0
                call_argc = get_u16(pc);
17176
0
                pc += 2;
17177
0
                goto has_call_argc;
17178
0
            has_call_argc:
17179
0
                call_argv = sp - call_argc;
17180
0
                sf->cur_pc = pc;
17181
0
                ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED,
17182
0
                                          JS_UNDEFINED, call_argc, call_argv, 0);
17183
0
                if (unlikely(JS_IsException(ret_val)))
17184
0
                    goto exception;
17185
0
                if (opcode == OP_tail_call)
17186
0
                    goto done;
17187
0
                for(i = -1; i < call_argc; i++)
17188
0
                    JS_FreeValue(ctx, call_argv[i]);
17189
0
                sp -= call_argc + 1;
17190
0
                *sp++ = ret_val;
17191
0
            }
17192
0
            BREAK;
17193
0
        CASE(OP_call_constructor):
17194
0
            {
17195
0
                call_argc = get_u16(pc);
17196
0
                pc += 2;
17197
0
                call_argv = sp - call_argc;
17198
0
                sf->cur_pc = pc;
17199
0
                ret_val = JS_CallConstructorInternal(ctx, call_argv[-2],
17200
0
                                                     call_argv[-1],
17201
0
                                                     call_argc, call_argv, 0);
17202
0
                if (unlikely(JS_IsException(ret_val)))
17203
0
                    goto exception;
17204
0
                for(i = -2; i < call_argc; i++)
17205
0
                    JS_FreeValue(ctx, call_argv[i]);
17206
0
                sp -= call_argc + 2;
17207
0
                *sp++ = ret_val;
17208
0
            }
17209
0
            BREAK;
17210
0
        CASE(OP_call_method):
17211
0
        CASE(OP_tail_call_method):
17212
0
            {
17213
0
                call_argc = get_u16(pc);
17214
0
                pc += 2;
17215
0
                call_argv = sp - call_argc;
17216
0
                sf->cur_pc = pc;
17217
0
                ret_val = JS_CallInternal(ctx, call_argv[-1], call_argv[-2],
17218
0
                                          JS_UNDEFINED, call_argc, call_argv, 0);
17219
0
                if (unlikely(JS_IsException(ret_val)))
17220
0
                    goto exception;
17221
0
                if (opcode == OP_tail_call_method)
17222
0
                    goto done;
17223
0
                for(i = -2; i < call_argc; i++)
17224
0
                    JS_FreeValue(ctx, call_argv[i]);
17225
0
                sp -= call_argc + 2;
17226
0
                *sp++ = ret_val;
17227
0
            }
17228
0
            BREAK;
17229
0
        CASE(OP_array_from):
17230
0
            {
17231
0
                int i, ret;
17232
17233
0
                call_argc = get_u16(pc);
17234
0
                pc += 2;
17235
0
                ret_val = JS_NewArray(ctx);
17236
0
                if (unlikely(JS_IsException(ret_val)))
17237
0
                    goto exception;
17238
0
                call_argv = sp - call_argc;
17239
0
                for(i = 0; i < call_argc; i++) {
17240
0
                    ret = JS_DefinePropertyValue(ctx, ret_val, __JS_AtomFromUInt32(i), call_argv[i],
17241
0
                                                 JS_PROP_C_W_E | JS_PROP_THROW);
17242
0
                    call_argv[i] = JS_UNDEFINED;
17243
0
                    if (ret < 0) {
17244
0
                        JS_FreeValue(ctx, ret_val);
17245
0
                        goto exception;
17246
0
                    }
17247
0
                }
17248
0
                sp -= call_argc;
17249
0
                *sp++ = ret_val;
17250
0
            }
17251
0
            BREAK;
17252
17253
0
        CASE(OP_apply):
17254
0
            {
17255
0
                int magic;
17256
0
                magic = get_u16(pc);
17257
0
                pc += 2;
17258
0
                sf->cur_pc = pc;
17259
17260
0
                ret_val = js_function_apply(ctx, sp[-3], 2, (JSValueConst *)&sp[-2], magic);
17261
0
                if (unlikely(JS_IsException(ret_val)))
17262
0
                    goto exception;
17263
0
                JS_FreeValue(ctx, sp[-3]);
17264
0
                JS_FreeValue(ctx, sp[-2]);
17265
0
                JS_FreeValue(ctx, sp[-1]);
17266
0
                sp -= 3;
17267
0
                *sp++ = ret_val;
17268
0
            }
17269
0
            BREAK;
17270
0
        CASE(OP_return):
17271
0
            ret_val = *--sp;
17272
0
            goto done;
17273
3
        CASE(OP_return_undef):
17274
3
            ret_val = JS_UNDEFINED;
17275
3
            goto done;
17276
17277
0
        CASE(OP_check_ctor_return):
17278
            /* return TRUE if 'this' should be returned */
17279
0
            if (!JS_IsObject(sp[-1])) {
17280
0
                if (!JS_IsUndefined(sp[-1])) {
17281
0
                    JS_ThrowTypeError(caller_ctx, "derived class constructor must return an object or undefined");
17282
0
                    goto exception;
17283
0
                }
17284
0
                sp[0] = JS_TRUE;
17285
0
            } else {
17286
0
                sp[0] = JS_FALSE;
17287
0
            }
17288
0
            sp++;
17289
0
            BREAK;
17290
0
        CASE(OP_check_ctor):
17291
0
            if (JS_IsUndefined(new_target)) {
17292
0
            non_ctor_call:
17293
0
                JS_ThrowTypeError(ctx, "class constructors must be invoked with 'new'");
17294
0
                goto exception;
17295
0
            }
17296
0
            BREAK;
17297
0
        CASE(OP_init_ctor):
17298
0
            {
17299
0
                JSValue super, ret;
17300
0
                sf->cur_pc = pc;
17301
0
                if (JS_IsUndefined(new_target))
17302
0
                    goto non_ctor_call;
17303
0
                super = JS_GetPrototype(ctx, func_obj);
17304
0
                if (JS_IsException(super))
17305
0
                    goto exception;
17306
0
                ret = JS_CallConstructor2(ctx, super, new_target, argc, (JSValueConst *)argv);
17307
0
                JS_FreeValue(ctx, super);
17308
0
                if (JS_IsException(ret))
17309
0
                    goto exception;
17310
0
                *sp++ = ret;
17311
0
            }
17312
0
            BREAK;
17313
0
        CASE(OP_check_brand):
17314
0
            {
17315
0
                int ret = JS_CheckBrand(ctx, sp[-2], sp[-1]);
17316
0
                if (ret < 0)
17317
0
                    goto exception;
17318
0
                if (!ret) {
17319
0
                    JS_ThrowTypeError(ctx, "invalid brand on object");
17320
0
                    goto exception;
17321
0
                }
17322
0
            }
17323
0
            BREAK;
17324
0
        CASE(OP_add_brand):
17325
0
            if (JS_AddBrand(ctx, sp[-2], sp[-1]) < 0)
17326
0
                goto exception;
17327
0
            JS_FreeValue(ctx, sp[-2]);
17328
0
            JS_FreeValue(ctx, sp[-1]);
17329
0
            sp -= 2;
17330
0
            BREAK;
17331
17332
0
        CASE(OP_throw):
17333
0
            JS_Throw(ctx, *--sp);
17334
0
            goto exception;
17335
17336
0
        CASE(OP_throw_error):
17337
0
#define JS_THROW_VAR_RO             0
17338
0
#define JS_THROW_VAR_REDECL         1
17339
0
#define JS_THROW_VAR_UNINITIALIZED  2
17340
0
#define JS_THROW_ERROR_DELETE_SUPER   3
17341
0
#define JS_THROW_ERROR_ITERATOR_THROW 4
17342
0
            {
17343
0
                JSAtom atom;
17344
0
                int type;
17345
0
                atom = get_u32(pc);
17346
0
                type = pc[4];
17347
0
                pc += 5;
17348
0
                if (type == JS_THROW_VAR_RO)
17349
0
                    JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, atom);
17350
0
                else
17351
0
                if (type == JS_THROW_VAR_REDECL)
17352
0
                    JS_ThrowSyntaxErrorVarRedeclaration(ctx, atom);
17353
0
                else
17354
0
                if (type == JS_THROW_VAR_UNINITIALIZED)
17355
0
                    JS_ThrowReferenceErrorUninitialized(ctx, atom);
17356
0
                else
17357
0
                if (type == JS_THROW_ERROR_DELETE_SUPER)
17358
0
                    JS_ThrowReferenceError(ctx, "unsupported reference to 'super'");
17359
0
                else
17360
0
                if (type == JS_THROW_ERROR_ITERATOR_THROW)
17361
0
                    JS_ThrowTypeError(ctx, "iterator does not have a throw method");
17362
0
                else
17363
0
                    JS_ThrowInternalError(ctx, "invalid throw var type %d", type);
17364
0
            }
17365
0
            goto exception;
17366
17367
0
        CASE(OP_eval):
17368
0
            {
17369
0
                JSValueConst obj;
17370
0
                int scope_idx;
17371
0
                call_argc = get_u16(pc);
17372
0
                scope_idx = get_u16(pc + 2) + ARG_SCOPE_END;
17373
0
                pc += 4;
17374
0
                call_argv = sp - call_argc;
17375
0
                sf->cur_pc = pc;
17376
0
                if (js_same_value(ctx, call_argv[-1], ctx->eval_obj)) {
17377
0
                    if (call_argc >= 1)
17378
0
                        obj = call_argv[0];
17379
0
                    else
17380
0
                        obj = JS_UNDEFINED;
17381
0
                    ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj,
17382
0
                                            JS_EVAL_TYPE_DIRECT, scope_idx);
17383
0
                } else {
17384
0
                    ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED,
17385
0
                                              JS_UNDEFINED, call_argc, call_argv, 0);
17386
0
                }
17387
0
                if (unlikely(JS_IsException(ret_val)))
17388
0
                    goto exception;
17389
0
                for(i = -1; i < call_argc; i++)
17390
0
                    JS_FreeValue(ctx, call_argv[i]);
17391
0
                sp -= call_argc + 1;
17392
0
                *sp++ = ret_val;
17393
0
            }
17394
0
            BREAK;
17395
            /* could merge with OP_apply */
17396
0
        CASE(OP_apply_eval):
17397
0
            {
17398
0
                int scope_idx;
17399
0
                uint32_t len;
17400
0
                JSValue *tab;
17401
0
                JSValueConst obj;
17402
17403
0
                scope_idx = get_u16(pc) + ARG_SCOPE_END;
17404
0
                pc += 2;
17405
0
                sf->cur_pc = pc;
17406
0
                tab = build_arg_list(ctx, &len, sp[-1]);
17407
0
                if (!tab)
17408
0
                    goto exception;
17409
0
                if (js_same_value(ctx, sp[-2], ctx->eval_obj)) {
17410
0
                    if (len >= 1)
17411
0
                        obj = tab[0];
17412
0
                    else
17413
0
                        obj = JS_UNDEFINED;
17414
0
                    ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj,
17415
0
                                            JS_EVAL_TYPE_DIRECT, scope_idx);
17416
0
                } else {
17417
0
                    ret_val = JS_Call(ctx, sp[-2], JS_UNDEFINED, len,
17418
0
                                      (JSValueConst *)tab);
17419
0
                }
17420
0
                free_arg_list(ctx, tab, len);
17421
0
                if (unlikely(JS_IsException(ret_val)))
17422
0
                    goto exception;
17423
0
                JS_FreeValue(ctx, sp[-2]);
17424
0
                JS_FreeValue(ctx, sp[-1]);
17425
0
                sp -= 2;
17426
0
                *sp++ = ret_val;
17427
0
            }
17428
0
            BREAK;
17429
17430
0
        CASE(OP_regexp):
17431
0
            {
17432
0
                sp[-2] = js_regexp_constructor_internal(ctx, JS_UNDEFINED,
17433
0
                                                        sp[-2], sp[-1]);
17434
0
                sp--;
17435
0
            }
17436
0
            BREAK;
17437
17438
0
        CASE(OP_get_super):
17439
0
            {
17440
0
                JSValue proto;
17441
0
                sf->cur_pc = pc;
17442
0
                proto = JS_GetPrototype(ctx, sp[-1]);
17443
0
                if (JS_IsException(proto))
17444
0
                    goto exception;
17445
0
                JS_FreeValue(ctx, sp[-1]);
17446
0
                sp[-1] = proto;
17447
0
            }
17448
0
            BREAK;
17449
17450
0
        CASE(OP_import):
17451
0
            {
17452
0
                JSValue val;
17453
0
                sf->cur_pc = pc;
17454
0
                val = js_dynamic_import(ctx, sp[-2], sp[-1]);
17455
0
                if (JS_IsException(val))
17456
0
                    goto exception;
17457
0
                JS_FreeValue(ctx, sp[-2]);
17458
0
                JS_FreeValue(ctx, sp[-1]);
17459
0
                sp--;
17460
0
                sp[-1] = val;
17461
0
            }
17462
0
            BREAK;
17463
17464
0
        CASE(OP_check_var):
17465
0
            {
17466
0
                int ret;
17467
0
                JSAtom atom;
17468
0
                atom = get_u32(pc);
17469
0
                pc += 4;
17470
0
                sf->cur_pc = pc;
17471
17472
0
                ret = JS_CheckGlobalVar(ctx, atom);
17473
0
                if (ret < 0)
17474
0
                    goto exception;
17475
0
                *sp++ = JS_NewBool(ctx, ret);
17476
0
            }
17477
0
            BREAK;
17478
17479
0
        CASE(OP_get_var_undef):
17480
5
        CASE(OP_get_var):
17481
5
            {
17482
5
                JSValue val;
17483
5
                JSAtom atom;
17484
5
                atom = get_u32(pc);
17485
5
                pc += 4;
17486
5
                sf->cur_pc = pc;
17487
17488
5
                val = JS_GetGlobalVar(ctx, atom, opcode - OP_get_var_undef);
17489
5
                if (unlikely(JS_IsException(val)))
17490
1
                    goto exception;
17491
4
                *sp++ = val;
17492
4
            }
17493
4
            BREAK;
17494
17495
4
        CASE(OP_put_var):
17496
0
        CASE(OP_put_var_init):
17497
0
            {
17498
0
                int ret;
17499
0
                JSAtom atom;
17500
0
                atom = get_u32(pc);
17501
0
                pc += 4;
17502
0
                sf->cur_pc = pc;
17503
17504
0
                ret = JS_SetGlobalVar(ctx, atom, sp[-1], opcode - OP_put_var);
17505
0
                sp--;
17506
0
                if (unlikely(ret < 0))
17507
0
                    goto exception;
17508
0
            }
17509
0
            BREAK;
17510
17511
0
        CASE(OP_put_var_strict):
17512
0
            {
17513
0
                int ret;
17514
0
                JSAtom atom;
17515
0
                atom = get_u32(pc);
17516
0
                pc += 4;
17517
0
                sf->cur_pc = pc;
17518
17519
                /* sp[-2] is JS_TRUE or JS_FALSE */
17520
0
                if (unlikely(!JS_VALUE_GET_INT(sp[-2]))) {
17521
0
                    JS_ThrowReferenceErrorNotDefined(ctx, atom);
17522
0
                    goto exception;
17523
0
                }
17524
0
                ret = JS_SetGlobalVar(ctx, atom, sp[-1], 2);
17525
0
                sp -= 2;
17526
0
                if (unlikely(ret < 0))
17527
0
                    goto exception;
17528
0
            }
17529
0
            BREAK;
17530
17531
0
        CASE(OP_check_define_var):
17532
0
            {
17533
0
                JSAtom atom;
17534
0
                int flags;
17535
0
                atom = get_u32(pc);
17536
0
                flags = pc[4];
17537
0
                pc += 5;
17538
0
                sf->cur_pc = pc;
17539
0
                if (JS_CheckDefineGlobalVar(ctx, atom, flags))
17540
0
                    goto exception;
17541
0
            }
17542
0
            BREAK;
17543
0
        CASE(OP_define_var):
17544
0
            {
17545
0
                JSAtom atom;
17546
0
                int flags;
17547
0
                atom = get_u32(pc);
17548
0
                flags = pc[4];
17549
0
                pc += 5;
17550
0
                sf->cur_pc = pc;
17551
0
                if (JS_DefineGlobalVar(ctx, atom, flags))
17552
0
                    goto exception;
17553
0
            }
17554
0
            BREAK;
17555
0
        CASE(OP_define_func):
17556
0
            {
17557
0
                JSAtom atom;
17558
0
                int flags;
17559
0
                atom = get_u32(pc);
17560
0
                flags = pc[4];
17561
0
                pc += 5;
17562
0
                sf->cur_pc = pc;
17563
0
                if (JS_DefineGlobalFunction(ctx, atom, sp[-1], flags))
17564
0
                    goto exception;
17565
0
                JS_FreeValue(ctx, sp[-1]);
17566
0
                sp--;
17567
0
            }
17568
0
            BREAK;
17569
17570
0
        CASE(OP_get_loc):
17571
0
            {
17572
0
                int idx;
17573
0
                idx = get_u16(pc);
17574
0
                pc += 2;
17575
0
                sp[0] = JS_DupValue(ctx, var_buf[idx]);
17576
0
                sp++;
17577
0
            }
17578
0
            BREAK;
17579
0
        CASE(OP_put_loc):
17580
0
            {
17581
0
                int idx;
17582
0
                idx = get_u16(pc);
17583
0
                pc += 2;
17584
0
                set_value(ctx, &var_buf[idx], sp[-1]);
17585
0
                sp--;
17586
0
            }
17587
0
            BREAK;
17588
0
        CASE(OP_set_loc):
17589
0
            {
17590
0
                int idx;
17591
0
                idx = get_u16(pc);
17592
0
                pc += 2;
17593
0
                set_value(ctx, &var_buf[idx], JS_DupValue(ctx, sp[-1]));
17594
0
            }
17595
0
            BREAK;
17596
0
        CASE(OP_get_arg):
17597
0
            {
17598
0
                int idx;
17599
0
                idx = get_u16(pc);
17600
0
                pc += 2;
17601
0
                sp[0] = JS_DupValue(ctx, arg_buf[idx]);
17602
0
                sp++;
17603
0
            }
17604
0
            BREAK;
17605
0
        CASE(OP_put_arg):
17606
0
            {
17607
0
                int idx;
17608
0
                idx = get_u16(pc);
17609
0
                pc += 2;
17610
0
                set_value(ctx, &arg_buf[idx], sp[-1]);
17611
0
                sp--;
17612
0
            }
17613
0
            BREAK;
17614
0
        CASE(OP_set_arg):
17615
0
            {
17616
0
                int idx;
17617
0
                idx = get_u16(pc);
17618
0
                pc += 2;
17619
0
                set_value(ctx, &arg_buf[idx], JS_DupValue(ctx, sp[-1]));
17620
0
            }
17621
0
            BREAK;
17622
17623
0
#if SHORT_OPCODES
17624
0
        CASE(OP_get_loc8): *sp++ = JS_DupValue(ctx, var_buf[*pc++]); BREAK;
17625
0
        CASE(OP_put_loc8): set_value(ctx, &var_buf[*pc++], *--sp); BREAK;
17626
0
        CASE(OP_set_loc8): set_value(ctx, &var_buf[*pc++], JS_DupValue(ctx, sp[-1])); BREAK;
17627
17628
0
        CASE(OP_get_loc0): *sp++ = JS_DupValue(ctx, var_buf[0]); BREAK;
17629
0
        CASE(OP_get_loc1): *sp++ = JS_DupValue(ctx, var_buf[1]); BREAK;
17630
0
        CASE(OP_get_loc2): *sp++ = JS_DupValue(ctx, var_buf[2]); BREAK;
17631
0
        CASE(OP_get_loc3): *sp++ = JS_DupValue(ctx, var_buf[3]); BREAK;
17632
0
        CASE(OP_put_loc0): set_value(ctx, &var_buf[0], *--sp); BREAK;
17633
0
        CASE(OP_put_loc1): set_value(ctx, &var_buf[1], *--sp); BREAK;
17634
0
        CASE(OP_put_loc2): set_value(ctx, &var_buf[2], *--sp); BREAK;
17635
0
        CASE(OP_put_loc3): set_value(ctx, &var_buf[3], *--sp); BREAK;
17636
0
        CASE(OP_set_loc0): set_value(ctx, &var_buf[0], JS_DupValue(ctx, sp[-1])); BREAK;
17637
0
        CASE(OP_set_loc1): set_value(ctx, &var_buf[1], JS_DupValue(ctx, sp[-1])); BREAK;
17638
0
        CASE(OP_set_loc2): set_value(ctx, &var_buf[2], JS_DupValue(ctx, sp[-1])); BREAK;
17639
0
        CASE(OP_set_loc3): set_value(ctx, &var_buf[3], JS_DupValue(ctx, sp[-1])); BREAK;
17640
0
        CASE(OP_get_arg0): *sp++ = JS_DupValue(ctx, arg_buf[0]); BREAK;
17641
0
        CASE(OP_get_arg1): *sp++ = JS_DupValue(ctx, arg_buf[1]); BREAK;
17642
0
        CASE(OP_get_arg2): *sp++ = JS_DupValue(ctx, arg_buf[2]); BREAK;
17643
0
        CASE(OP_get_arg3): *sp++ = JS_DupValue(ctx, arg_buf[3]); BREAK;
17644
0
        CASE(OP_put_arg0): set_value(ctx, &arg_buf[0], *--sp); BREAK;
17645
0
        CASE(OP_put_arg1): set_value(ctx, &arg_buf[1], *--sp); BREAK;
17646
0
        CASE(OP_put_arg2): set_value(ctx, &arg_buf[2], *--sp); BREAK;
17647
0
        CASE(OP_put_arg3): set_value(ctx, &arg_buf[3], *--sp); BREAK;
17648
0
        CASE(OP_set_arg0): set_value(ctx, &arg_buf[0], JS_DupValue(ctx, sp[-1])); BREAK;
17649
0
        CASE(OP_set_arg1): set_value(ctx, &arg_buf[1], JS_DupValue(ctx, sp[-1])); BREAK;
17650
0
        CASE(OP_set_arg2): set_value(ctx, &arg_buf[2], JS_DupValue(ctx, sp[-1])); BREAK;
17651
0
        CASE(OP_set_arg3): set_value(ctx, &arg_buf[3], JS_DupValue(ctx, sp[-1])); BREAK;
17652
0
        CASE(OP_get_var_ref0): *sp++ = JS_DupValue(ctx, *var_refs[0]->pvalue); BREAK;
17653
0
        CASE(OP_get_var_ref1): *sp++ = JS_DupValue(ctx, *var_refs[1]->pvalue); BREAK;
17654
0
        CASE(OP_get_var_ref2): *sp++ = JS_DupValue(ctx, *var_refs[2]->pvalue); BREAK;
17655
0
        CASE(OP_get_var_ref3): *sp++ = JS_DupValue(ctx, *var_refs[3]->pvalue); BREAK;
17656
0
        CASE(OP_put_var_ref0): set_value(ctx, var_refs[0]->pvalue, *--sp); BREAK;
17657
0
        CASE(OP_put_var_ref1): set_value(ctx, var_refs[1]->pvalue, *--sp); BREAK;
17658
0
        CASE(OP_put_var_ref2): set_value(ctx, var_refs[2]->pvalue, *--sp); BREAK;
17659
0
        CASE(OP_put_var_ref3): set_value(ctx, var_refs[3]->pvalue, *--sp); BREAK;
17660
0
        CASE(OP_set_var_ref0): set_value(ctx, var_refs[0]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
17661
0
        CASE(OP_set_var_ref1): set_value(ctx, var_refs[1]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
17662
0
        CASE(OP_set_var_ref2): set_value(ctx, var_refs[2]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
17663
0
        CASE(OP_set_var_ref3): set_value(ctx, var_refs[3]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;
17664
0
#endif
17665
17666
0
        CASE(OP_get_var_ref):
17667
0
            {
17668
0
                int idx;
17669
0
                JSValue val;
17670
0
                idx = get_u16(pc);
17671
0
                pc += 2;
17672
0
                val = *var_refs[idx]->pvalue;
17673
0
                sp[0] = JS_DupValue(ctx, val);
17674
0
                sp++;
17675
0
            }
17676
0
            BREAK;
17677
0
        CASE(OP_put_var_ref):
17678
0
            {
17679
0
                int idx;
17680
0
                idx = get_u16(pc);
17681
0
                pc += 2;
17682
0
                set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
17683
0
                sp--;
17684
0
            }
17685
0
            BREAK;
17686
0
        CASE(OP_set_var_ref):
17687
0
            {
17688
0
                int idx;
17689
0
                idx = get_u16(pc);
17690
0
                pc += 2;
17691
0
                set_value(ctx, var_refs[idx]->pvalue, JS_DupValue(ctx, sp[-1]));
17692
0
            }
17693
0
            BREAK;
17694
4
        CASE(OP_get_var_ref_check):
17695
4
            {
17696
4
                int idx;
17697
4
                JSValue val;
17698
4
                idx = get_u16(pc);
17699
4
                pc += 2;
17700
4
                val = *var_refs[idx]->pvalue;
17701
4
                if (unlikely(JS_IsUninitialized(val))) {
17702
0
                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
17703
0
                    goto exception;
17704
0
                }
17705
4
                sp[0] = JS_DupValue(ctx, val);
17706
4
                sp++;
17707
4
            }
17708
4
            BREAK;
17709
4
        CASE(OP_put_var_ref_check):
17710
0
            {
17711
0
                int idx;
17712
0
                idx = get_u16(pc);
17713
0
                pc += 2;
17714
0
                if (unlikely(JS_IsUninitialized(*var_refs[idx]->pvalue))) {
17715
0
                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
17716
0
                    goto exception;
17717
0
                }
17718
0
                set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
17719
0
                sp--;
17720
0
            }
17721
0
            BREAK;
17722
0
        CASE(OP_put_var_ref_check_init):
17723
0
            {
17724
0
                int idx;
17725
0
                idx = get_u16(pc);
17726
0
                pc += 2;
17727
0
                if (unlikely(!JS_IsUninitialized(*var_refs[idx]->pvalue))) {
17728
0
                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
17729
0
                    goto exception;
17730
0
                }
17731
0
                set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
17732
0
                sp--;
17733
0
            }
17734
0
            BREAK;
17735
0
        CASE(OP_set_loc_uninitialized):
17736
0
            {
17737
0
                int idx;
17738
0
                idx = get_u16(pc);
17739
0
                pc += 2;
17740
0
                set_value(ctx, &var_buf[idx], JS_UNINITIALIZED);
17741
0
            }
17742
0
            BREAK;
17743
0
        CASE(OP_get_loc_check):
17744
0
            {
17745
0
                int idx;
17746
0
                idx = get_u16(pc);
17747
0
                pc += 2;
17748
0
                if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
17749
0
                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);
17750
0
                    goto exception;
17751
0
                }
17752
0
                sp[0] = JS_DupValue(ctx, var_buf[idx]);
17753
0
                sp++;
17754
0
            }
17755
0
            BREAK;
17756
0
        CASE(OP_get_loc_checkthis):
17757
0
            {
17758
0
                int idx;
17759
0
                idx = get_u16(pc);
17760
0
                pc += 2;
17761
0
                if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
17762
0
                    JS_ThrowReferenceErrorUninitialized2(caller_ctx, b, idx, FALSE);
17763
0
                    goto exception;
17764
0
                }
17765
0
                sp[0] = JS_DupValue(ctx, var_buf[idx]);
17766
0
                sp++;
17767
0
            }
17768
0
            BREAK;
17769
0
        CASE(OP_put_loc_check):
17770
0
            {
17771
0
                int idx;
17772
0
                idx = get_u16(pc);
17773
0
                pc += 2;
17774
0
                if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
17775
0
                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);
17776
0
                    goto exception;
17777
0
                }
17778
0
                set_value(ctx, &var_buf[idx], sp[-1]);
17779
0
                sp--;
17780
0
            }
17781
0
            BREAK;
17782
0
        CASE(OP_put_loc_check_init):
17783
0
            {
17784
0
                int idx;
17785
0
                idx = get_u16(pc);
17786
0
                pc += 2;
17787
0
                if (unlikely(!JS_IsUninitialized(var_buf[idx]))) {
17788
0
                    JS_ThrowReferenceError(ctx, "'this' can be initialized only once");
17789
0
                    goto exception;
17790
0
                }
17791
0
                set_value(ctx, &var_buf[idx], sp[-1]);
17792
0
                sp--;
17793
0
            }
17794
0
            BREAK;
17795
0
        CASE(OP_close_loc):
17796
0
            {
17797
0
                int idx;
17798
0
                idx = get_u16(pc);
17799
0
                pc += 2;
17800
0
                close_lexical_var(ctx, sf, idx);
17801
0
            }
17802
0
            BREAK;
17803
17804
0
        CASE(OP_make_loc_ref):
17805
0
        CASE(OP_make_arg_ref):
17806
0
        CASE(OP_make_var_ref_ref):
17807
0
            {
17808
0
                JSVarRef *var_ref;
17809
0
                JSProperty *pr;
17810
0
                JSAtom atom;
17811
0
                int idx;
17812
0
                atom = get_u32(pc);
17813
0
                idx = get_u16(pc + 4);
17814
0
                pc += 6;
17815
0
                *sp++ = JS_NewObjectProto(ctx, JS_NULL);
17816
0
                if (unlikely(JS_IsException(sp[-1])))
17817
0
                    goto exception;
17818
0
                if (opcode == OP_make_var_ref_ref) {
17819
0
                    var_ref = var_refs[idx];
17820
0
                    var_ref->header.ref_count++;
17821
0
                } else {
17822
0
                    var_ref = get_var_ref(ctx, sf, idx, opcode == OP_make_arg_ref);
17823
0
                    if (!var_ref)
17824
0
                        goto exception;
17825
0
                }
17826
0
                pr = add_property(ctx, JS_VALUE_GET_OBJ(sp[-1]), atom,
17827
0
                                  JS_PROP_WRITABLE | JS_PROP_VARREF);
17828
0
                if (!pr) {
17829
0
                    free_var_ref(rt, var_ref);
17830
0
                    goto exception;
17831
0
                }
17832
0
                pr->u.var_ref = var_ref;
17833
0
                *sp++ = JS_AtomToValue(ctx, atom);
17834
0
            }
17835
0
            BREAK;
17836
0
        CASE(OP_make_var_ref):
17837
0
            {
17838
0
                JSAtom atom;
17839
0
                atom = get_u32(pc);
17840
0
                pc += 4;
17841
0
                sf->cur_pc = pc;
17842
17843
0
                if (JS_GetGlobalVarRef(ctx, atom, sp))
17844
0
                    goto exception;
17845
0
                sp += 2;
17846
0
            }
17847
0
            BREAK;
17848
17849
0
        CASE(OP_goto):
17850
0
            pc += (int32_t)get_u32(pc);
17851
0
            if (unlikely(js_poll_interrupts(ctx)))
17852
0
                goto exception;
17853
0
            BREAK;
17854
0
#if SHORT_OPCODES
17855
0
        CASE(OP_goto16):
17856
0
            pc += (int16_t)get_u16(pc);
17857
0
            if (unlikely(js_poll_interrupts(ctx)))
17858
0
                goto exception;
17859
0
            BREAK;
17860
0
        CASE(OP_goto8):
17861
0
            pc += (int8_t)pc[0];
17862
0
            if (unlikely(js_poll_interrupts(ctx)))
17863
0
                goto exception;
17864
0
            BREAK;
17865
0
#endif
17866
0
        CASE(OP_if_true):
17867
0
            {
17868
0
                int res;
17869
0
                JSValue op1;
17870
17871
0
                op1 = sp[-1];
17872
0
                pc += 4;
17873
0
                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
17874
0
                    res = JS_VALUE_GET_INT(op1);
17875
0
                } else {
17876
0
                    res = JS_ToBoolFree(ctx, op1);
17877
0
                }
17878
0
                sp--;
17879
0
                if (res) {
17880
0
                    pc += (int32_t)get_u32(pc - 4) - 4;
17881
0
                }
17882
0
                if (unlikely(js_poll_interrupts(ctx)))
17883
0
                    goto exception;
17884
0
            }
17885
0
            BREAK;
17886
0
        CASE(OP_if_false):
17887
0
            {
17888
0
                int res;
17889
0
                JSValue op1;
17890
17891
0
                op1 = sp[-1];
17892
0
                pc += 4;
17893
                /* quick and dirty test for JS_TAG_INT, JS_TAG_BOOL, JS_TAG_NULL and JS_TAG_UNDEFINED */
17894
0
                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
17895
0
                    res = JS_VALUE_GET_INT(op1);
17896
0
                } else {
17897
0
                    res = JS_ToBoolFree(ctx, op1);
17898
0
                }
17899
0
                sp--;
17900
0
                if (!res) {
17901
0
                    pc += (int32_t)get_u32(pc - 4) - 4;
17902
0
                }
17903
0
                if (unlikely(js_poll_interrupts(ctx)))
17904
0
                    goto exception;
17905
0
            }
17906
0
            BREAK;
17907
0
#if SHORT_OPCODES
17908
0
        CASE(OP_if_true8):
17909
0
            {
17910
0
                int res;
17911
0
                JSValue op1;
17912
17913
0
                op1 = sp[-1];
17914
0
                pc += 1;
17915
0
                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
17916
0
                    res = JS_VALUE_GET_INT(op1);
17917
0
                } else {
17918
0
                    res = JS_ToBoolFree(ctx, op1);
17919
0
                }
17920
0
                sp--;
17921
0
                if (res) {
17922
0
                    pc += (int8_t)pc[-1] - 1;
17923
0
                }
17924
0
                if (unlikely(js_poll_interrupts(ctx)))
17925
0
                    goto exception;
17926
0
            }
17927
0
            BREAK;
17928
6
        CASE(OP_if_false8):
17929
6
            {
17930
6
                int res;
17931
6
                JSValue op1;
17932
17933
6
                op1 = sp[-1];
17934
6
                pc += 1;
17935
6
                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
17936
6
                    res = JS_VALUE_GET_INT(op1);
17937
6
                } else {
17938
0
                    res = JS_ToBoolFree(ctx, op1);
17939
0
                }
17940
6
                sp--;
17941
6
                if (!res) {
17942
3
                    pc += (int8_t)pc[-1] - 1;
17943
3
                }
17944
6
                if (unlikely(js_poll_interrupts(ctx)))
17945
0
                    goto exception;
17946
6
            }
17947
6
            BREAK;
17948
6
#endif
17949
6
        CASE(OP_catch):
17950
0
            {
17951
0
                int32_t diff;
17952
0
                diff = get_u32(pc);
17953
0
                sp[0] = JS_NewCatchOffset(ctx, pc + diff - b->byte_code_buf);
17954
0
                sp++;
17955
0
                pc += 4;
17956
0
            }
17957
0
            BREAK;
17958
0
        CASE(OP_gosub):
17959
0
            {
17960
0
                int32_t diff;
17961
0
                diff = get_u32(pc);
17962
                /* XXX: should have a different tag to avoid security flaw */
17963
0
                sp[0] = JS_NewInt32(ctx, pc + 4 - b->byte_code_buf);
17964
0
                sp++;
17965
0
                pc += diff;
17966
0
            }
17967
0
            BREAK;
17968
0
        CASE(OP_ret):
17969
0
            {
17970
0
                JSValue op1;
17971
0
                uint32_t pos;
17972
0
                op1 = sp[-1];
17973
0
                if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_INT))
17974
0
                    goto ret_fail;
17975
0
                pos = JS_VALUE_GET_INT(op1);
17976
0
                if (unlikely(pos >= b->byte_code_len)) {
17977
0
                ret_fail:
17978
0
                    JS_ThrowInternalError(ctx, "invalid ret value");
17979
0
                    goto exception;
17980
0
                }
17981
0
                sp--;
17982
0
                pc = b->byte_code_buf + pos;
17983
0
            }
17984
0
            BREAK;
17985
17986
0
        CASE(OP_for_in_start):
17987
0
            sf->cur_pc = pc;
17988
0
            if (js_for_in_start(ctx, sp))
17989
0
                goto exception;
17990
0
            BREAK;
17991
0
        CASE(OP_for_in_next):
17992
0
            sf->cur_pc = pc;
17993
0
            if (js_for_in_next(ctx, sp))
17994
0
                goto exception;
17995
0
            sp += 2;
17996
0
            BREAK;
17997
0
        CASE(OP_for_of_start):
17998
0
            sf->cur_pc = pc;
17999
0
            if (js_for_of_start(ctx, sp, FALSE))
18000
0
                goto exception;
18001
0
            sp += 1;
18002
0
            *sp++ = JS_NewCatchOffset(ctx, 0);
18003
0
            BREAK;
18004
0
        CASE(OP_for_of_next):
18005
0
            {
18006
0
                int offset = -3 - pc[0];
18007
0
                pc += 1;
18008
0
                sf->cur_pc = pc;
18009
0
                if (js_for_of_next(ctx, sp, offset))
18010
0
                    goto exception;
18011
0
                sp += 2;
18012
0
            }
18013
0
            BREAK;
18014
0
        CASE(OP_for_await_of_next):
18015
0
            sf->cur_pc = pc;
18016
0
            if (js_for_await_of_next(ctx, sp))
18017
0
                goto exception;
18018
0
            sp++;
18019
0
            BREAK;
18020
0
        CASE(OP_for_await_of_start):
18021
0
            sf->cur_pc = pc;
18022
0
            if (js_for_of_start(ctx, sp, TRUE))
18023
0
                goto exception;
18024
0
            sp += 1;
18025
0
            *sp++ = JS_NewCatchOffset(ctx, 0);
18026
0
            BREAK;
18027
0
        CASE(OP_iterator_get_value_done):
18028
0
            sf->cur_pc = pc;
18029
0
            if (js_iterator_get_value_done(ctx, sp))
18030
0
                goto exception;
18031
0
            sp += 1;
18032
0
            BREAK;
18033
0
        CASE(OP_iterator_check_object):
18034
0
            if (unlikely(!JS_IsObject(sp[-1]))) {
18035
0
                JS_ThrowTypeError(ctx, "iterator must return an object");
18036
0
                goto exception;
18037
0
            }
18038
0
            BREAK;
18039
18040
0
        CASE(OP_iterator_close):
18041
            /* iter_obj next catch_offset -> */
18042
0
            sp--; /* drop the catch offset to avoid getting caught by exception */
18043
0
            JS_FreeValue(ctx, sp[-1]); /* drop the next method */
18044
0
            sp--;
18045
0
            if (!JS_IsUndefined(sp[-1])) {
18046
0
                sf->cur_pc = pc;
18047
0
                if (JS_IteratorClose(ctx, sp[-1], FALSE))
18048
0
                    goto exception;
18049
0
                JS_FreeValue(ctx, sp[-1]);
18050
0
            }
18051
0
            sp--;
18052
0
            BREAK;
18053
0
        CASE(OP_nip_catch):
18054
0
            {
18055
0
                JSValue ret_val;
18056
                /* catch_offset ... ret_val -> ret_eval */
18057
0
                ret_val = *--sp;
18058
0
                while (sp > stack_buf &&
18059
0
                       JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_CATCH_OFFSET) {
18060
0
                    JS_FreeValue(ctx, *--sp);
18061
0
                }
18062
0
                if (unlikely(sp == stack_buf)) {
18063
0
                    JS_ThrowInternalError(ctx, "nip_catch");
18064
0
                    JS_FreeValue(ctx, ret_val);
18065
0
                    goto exception;
18066
0
                }
18067
0
                sp[-1] = ret_val;
18068
0
            }
18069
0
            BREAK;
18070
18071
0
        CASE(OP_iterator_next):
18072
            /* stack: iter_obj next catch_offset val */
18073
0
            {
18074
0
                JSValue ret;
18075
0
                sf->cur_pc = pc;
18076
0
                ret = JS_Call(ctx, sp[-3], sp[-4],
18077
0
                              1, (JSValueConst *)(sp - 1));
18078
0
                if (JS_IsException(ret))
18079
0
                    goto exception;
18080
0
                JS_FreeValue(ctx, sp[-1]);
18081
0
                sp[-1] = ret;
18082
0
            }
18083
0
            BREAK;
18084
18085
0
        CASE(OP_iterator_call):
18086
            /* stack: iter_obj next catch_offset val */
18087
0
            {
18088
0
                JSValue method, ret;
18089
0
                BOOL ret_flag;
18090
0
                int flags;
18091
0
                flags = *pc++;
18092
0
                sf->cur_pc = pc;
18093
0
                method = JS_GetProperty(ctx, sp[-4], (flags & 1) ?
18094
0
                                        JS_ATOM_throw : JS_ATOM_return);
18095
0
                if (JS_IsException(method))
18096
0
                    goto exception;
18097
0
                if (JS_IsUndefined(method) || JS_IsNull(method)) {
18098
0
                    ret_flag = TRUE;
18099
0
                } else {
18100
0
                    if (flags & 2) {
18101
                        /* no argument */
18102
0
                        ret = JS_CallFree(ctx, method, sp[-4],
18103
0
                                          0, NULL);
18104
0
                    } else {
18105
0
                        ret = JS_CallFree(ctx, method, sp[-4],
18106
0
                                          1, (JSValueConst *)(sp - 1));
18107
0
                    }
18108
0
                    if (JS_IsException(ret))
18109
0
                        goto exception;
18110
0
                    JS_FreeValue(ctx, sp[-1]);
18111
0
                    sp[-1] = ret;
18112
0
                    ret_flag = FALSE;
18113
0
                }
18114
0
                sp[0] = JS_NewBool(ctx, ret_flag);
18115
0
                sp += 1;
18116
0
            }
18117
0
            BREAK;
18118
18119
0
        CASE(OP_lnot):
18120
0
            {
18121
0
                int res;
18122
0
                JSValue op1;
18123
18124
0
                op1 = sp[-1];
18125
0
                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {
18126
0
                    res = JS_VALUE_GET_INT(op1) != 0;
18127
0
                } else {
18128
0
                    res = JS_ToBoolFree(ctx, op1);
18129
0
                }
18130
0
                sp[-1] = JS_NewBool(ctx, !res);
18131
0
            }
18132
0
            BREAK;
18133
18134
0
        CASE(OP_get_field):
18135
0
            {
18136
0
                JSValue val;
18137
0
                JSAtom atom;
18138
0
                atom = get_u32(pc);
18139
0
                pc += 4;
18140
18141
0
                sf->cur_pc = pc;
18142
0
                val = JS_GetProperty(ctx, sp[-1], atom);
18143
0
                if (unlikely(JS_IsException(val)))
18144
0
                    goto exception;
18145
0
                JS_FreeValue(ctx, sp[-1]);
18146
0
                sp[-1] = val;
18147
0
            }
18148
0
            BREAK;
18149
18150
0
        CASE(OP_get_field2):
18151
0
            {
18152
0
                JSValue val;
18153
0
                JSAtom atom;
18154
0
                atom = get_u32(pc);
18155
0
                pc += 4;
18156
18157
0
                sf->cur_pc = pc;
18158
0
                val = JS_GetProperty(ctx, sp[-1], atom);
18159
0
                if (unlikely(JS_IsException(val)))
18160
0
                    goto exception;
18161
0
                *sp++ = val;
18162
0
            }
18163
0
            BREAK;
18164
18165
4
        CASE(OP_put_field):
18166
4
            {
18167
4
                int ret;
18168
4
                JSAtom atom;
18169
4
                atom = get_u32(pc);
18170
4
                pc += 4;
18171
4
                sf->cur_pc = pc;
18172
18173
4
                ret = JS_SetPropertyInternal(ctx, sp[-2], atom, sp[-1], sp[-2],
18174
4
                                             JS_PROP_THROW_STRICT);
18175
4
                JS_FreeValue(ctx, sp[-2]);
18176
4
                sp -= 2;
18177
4
                if (unlikely(ret < 0))
18178
0
                    goto exception;
18179
4
            }
18180
4
            BREAK;
18181
18182
4
        CASE(OP_private_symbol):
18183
0
            {
18184
0
                JSAtom atom;
18185
0
                JSValue val;
18186
18187
0
                atom = get_u32(pc);
18188
0
                pc += 4;
18189
0
                val = JS_NewSymbolFromAtom(ctx, atom, JS_ATOM_TYPE_PRIVATE);
18190
0
                if (JS_IsException(val))
18191
0
                    goto exception;
18192
0
                *sp++ = val;
18193
0
            }
18194
0
            BREAK;
18195
18196
0
        CASE(OP_get_private_field):
18197
0
            {
18198
0
                JSValue val;
18199
18200
0
                val = JS_GetPrivateField(ctx, sp[-2], sp[-1]);
18201
0
                JS_FreeValue(ctx, sp[-1]);
18202
0
                JS_FreeValue(ctx, sp[-2]);
18203
0
                sp[-2] = val;
18204
0
                sp--;
18205
0
                if (unlikely(JS_IsException(val)))
18206
0
                    goto exception;
18207
0
            }
18208
0
            BREAK;
18209
18210
0
        CASE(OP_put_private_field):
18211
0
            {
18212
0
                int ret;
18213
0
                ret = JS_SetPrivateField(ctx, sp[-3], sp[-1], sp[-2]);
18214
0
                JS_FreeValue(ctx, sp[-3]);
18215
0
                JS_FreeValue(ctx, sp[-1]);
18216
0
                sp -= 3;
18217
0
                if (unlikely(ret < 0))
18218
0
                    goto exception;
18219
0
            }
18220
0
            BREAK;
18221
18222
0
        CASE(OP_define_private_field):
18223
0
            {
18224
0
                int ret;
18225
0
                ret = JS_DefinePrivateField(ctx, sp[-3], sp[-2], sp[-1]);
18226
0
                JS_FreeValue(ctx, sp[-2]);
18227
0
                sp -= 2;
18228
0
                if (unlikely(ret < 0))
18229
0
                    goto exception;
18230
0
            }
18231
0
            BREAK;
18232
18233
0
        CASE(OP_define_field):
18234
0
            {
18235
0
                int ret;
18236
0
                JSAtom atom;
18237
0
                atom = get_u32(pc);
18238
0
                pc += 4;
18239
18240
0
                ret = JS_DefinePropertyValue(ctx, sp[-2], atom, sp[-1],
18241
0
                                             JS_PROP_C_W_E | JS_PROP_THROW);
18242
0
                sp--;
18243
0
                if (unlikely(ret < 0))
18244
0
                    goto exception;
18245
0
            }
18246
0
            BREAK;
18247
18248
0
        CASE(OP_set_name):
18249
0
            {
18250
0
                int ret;
18251
0
                JSAtom atom;
18252
0
                atom = get_u32(pc);
18253
0
                pc += 4;
18254
18255
0
                ret = JS_DefineObjectName(ctx, sp[-1], atom, JS_PROP_CONFIGURABLE);
18256
0
                if (unlikely(ret < 0))
18257
0
                    goto exception;
18258
0
            }
18259
0
            BREAK;
18260
0
        CASE(OP_set_name_computed):
18261
0
            {
18262
0
                int ret;
18263
0
                ret = JS_DefineObjectNameComputed(ctx, sp[-1], sp[-2], JS_PROP_CONFIGURABLE);
18264
0
                if (unlikely(ret < 0))
18265
0
                    goto exception;
18266
0
            }
18267
0
            BREAK;
18268
0
        CASE(OP_set_proto):
18269
0
            {
18270
0
                JSValue proto;
18271
0
                sf->cur_pc = pc;
18272
0
                proto = sp[-1];
18273
0
                if (JS_IsObject(proto) || JS_IsNull(proto)) {
18274
0
                    if (JS_SetPrototypeInternal(ctx, sp[-2], proto, TRUE) < 0)
18275
0
                        goto exception;
18276
0
                }
18277
0
                JS_FreeValue(ctx, proto);
18278
0
                sp--;
18279
0
            }
18280
0
            BREAK;
18281
0
        CASE(OP_set_home_object):
18282
0
            js_method_set_home_object(ctx, sp[-1], sp[-2]);
18283
0
            BREAK;
18284
0
        CASE(OP_define_method):
18285
0
        CASE(OP_define_method_computed):
18286
0
            {
18287
0
                JSValue getter, setter, value;
18288
0
                JSValueConst obj;
18289
0
                JSAtom atom;
18290
0
                int flags, ret, op_flags;
18291
0
                BOOL is_computed;
18292
0
#define OP_DEFINE_METHOD_METHOD 0
18293
0
#define OP_DEFINE_METHOD_GETTER 1
18294
0
#define OP_DEFINE_METHOD_SETTER 2
18295
0
#define OP_DEFINE_METHOD_ENUMERABLE 4
18296
18297
0
                is_computed = (opcode == OP_define_method_computed);
18298
0
                if (is_computed) {
18299
0
                    atom = JS_ValueToAtom(ctx, sp[-2]);
18300
0
                    if (unlikely(atom == JS_ATOM_NULL))
18301
0
                        goto exception;
18302
0
                    opcode += OP_define_method - OP_define_method_computed;
18303
0
                } else {
18304
0
                    atom = get_u32(pc);
18305
0
                    pc += 4;
18306
0
                }
18307
0
                op_flags = *pc++;
18308
18309
0
                obj = sp[-2 - is_computed];
18310
0
                flags = JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE |
18311
0
                    JS_PROP_HAS_ENUMERABLE | JS_PROP_THROW;
18312
0
                if (op_flags & OP_DEFINE_METHOD_ENUMERABLE)
18313
0
                    flags |= JS_PROP_ENUMERABLE;
18314
0
                op_flags &= 3;
18315
0
                value = JS_UNDEFINED;
18316
0
                getter = JS_UNDEFINED;
18317
0
                setter = JS_UNDEFINED;
18318
0
                if (op_flags == OP_DEFINE_METHOD_METHOD) {
18319
0
                    value = sp[-1];
18320
0
                    flags |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE;
18321
0
                } else if (op_flags == OP_DEFINE_METHOD_GETTER) {
18322
0
                    getter = sp[-1];
18323
0
                    flags |= JS_PROP_HAS_GET;
18324
0
                } else {
18325
0
                    setter = sp[-1];
18326
0
                    flags |= JS_PROP_HAS_SET;
18327
0
                }
18328
0
                ret = js_method_set_properties(ctx, sp[-1], atom, flags, obj);
18329
0
                if (ret >= 0) {
18330
0
                    ret = JS_DefineProperty(ctx, obj, atom, value,
18331
0
                                            getter, setter, flags);
18332
0
                }
18333
0
                JS_FreeValue(ctx, sp[-1]);
18334
0
                if (is_computed) {
18335
0
                    JS_FreeAtom(ctx, atom);
18336
0
                    JS_FreeValue(ctx, sp[-2]);
18337
0
                }
18338
0
                sp -= 1 + is_computed;
18339
0
                if (unlikely(ret < 0))
18340
0
                    goto exception;
18341
0
            }
18342
0
            BREAK;
18343
18344
0
        CASE(OP_define_class):
18345
0
        CASE(OP_define_class_computed):
18346
0
            {
18347
0
                int class_flags;
18348
0
                JSAtom atom;
18349
18350
0
                atom = get_u32(pc);
18351
0
                class_flags = pc[4];
18352
0
                pc += 5;
18353
0
                if (js_op_define_class(ctx, sp, atom, class_flags,
18354
0
                                       var_refs, sf,
18355
0
                                       (opcode == OP_define_class_computed)) < 0)
18356
0
                    goto exception;
18357
0
            }
18358
0
            BREAK;
18359
18360
0
        CASE(OP_get_array_el):
18361
0
            {
18362
0
                JSValue val;
18363
18364
0
                sf->cur_pc = pc;
18365
0
                val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
18366
0
                JS_FreeValue(ctx, sp[-2]);
18367
0
                sp[-2] = val;
18368
0
                sp--;
18369
0
                if (unlikely(JS_IsException(val)))
18370
0
                    goto exception;
18371
0
            }
18372
0
            BREAK;
18373
18374
0
        CASE(OP_get_array_el2):
18375
0
            {
18376
0
                JSValue val;
18377
18378
0
                sf->cur_pc = pc;
18379
0
                val = JS_GetPropertyValue(ctx, sp[-2], sp[-1]);
18380
0
                sp[-1] = val;
18381
0
                if (unlikely(JS_IsException(val)))
18382
0
                    goto exception;
18383
0
            }
18384
0
            BREAK;
18385
18386
0
        CASE(OP_get_array_el3):
18387
0
            {
18388
0
                JSValue val;
18389
18390
0
                switch (JS_VALUE_GET_TAG(sp[-2])) {
18391
0
                case JS_TAG_INT:
18392
0
                case JS_TAG_STRING:
18393
0
                case JS_TAG_SYMBOL:
18394
                    /* undefined and null are tested in JS_GetPropertyValue() */
18395
0
                    break;
18396
0
                default:
18397
                    /* must be tested nefore JS_ToPropertyKey */
18398
0
                    if (unlikely(JS_IsUndefined(sp[-2]) || JS_IsNull(sp[-2]))) {
18399
0
                        JS_ThrowTypeError(ctx, "value has no property");
18400
0
                        goto exception;
18401
0
                    }
18402
0
                    sf->cur_pc = pc;
18403
0
                    ret_val = JS_ToPropertyKey(ctx, sp[-1]);
18404
0
                    if (JS_IsException(ret_val))
18405
0
                        goto exception;
18406
0
                    JS_FreeValue(ctx, sp[-1]);
18407
0
                    sp[-1] = ret_val;
18408
0
                    break;
18409
0
                }
18410
0
                sf->cur_pc = pc;
18411
0
                val = JS_GetPropertyValue(ctx, sp[-2], JS_DupValue(ctx, sp[-1]));
18412
0
                *sp++ = val;
18413
0
                if (unlikely(JS_IsException(val)))
18414
0
                    goto exception;
18415
0
            }
18416
0
            BREAK;
18417
            
18418
0
        CASE(OP_get_ref_value):
18419
0
            {
18420
0
                JSValue val;
18421
0
                JSAtom atom;
18422
0
                int ret;
18423
                
18424
0
                sf->cur_pc = pc;
18425
0
                atom = JS_ValueToAtom(ctx, sp[-1]);
18426
0
                if (atom == JS_ATOM_NULL)
18427
0
                    goto exception;
18428
0
                if (unlikely(JS_IsUndefined(sp[-2]))) {
18429
0
                    JS_ThrowReferenceErrorNotDefined(ctx, atom);
18430
0
                    JS_FreeAtom(ctx, atom);
18431
0
                    goto exception;
18432
0
                }
18433
0
                ret = JS_HasProperty(ctx, sp[-2], atom);
18434
0
                if (unlikely(ret <= 0)) {
18435
0
                    if (ret < 0) {
18436
0
                        JS_FreeAtom(ctx, atom);
18437
0
                        goto exception;
18438
0
                    }
18439
0
                    if (is_strict_mode(ctx)) {
18440
0
                        JS_ThrowReferenceErrorNotDefined(ctx, atom);
18441
0
                        JS_FreeAtom(ctx, atom);
18442
0
                        goto exception;
18443
0
                    } 
18444
0
                    val = JS_UNDEFINED;
18445
0
                } else {
18446
0
                    val = JS_GetProperty(ctx, sp[-2], atom);
18447
0
                }
18448
0
                JS_FreeAtom(ctx, atom);
18449
0
                if (unlikely(JS_IsException(val)))
18450
0
                    goto exception;
18451
0
                sp[0] = val;
18452
0
                sp++;
18453
0
            }
18454
0
            BREAK;
18455
18456
0
        CASE(OP_get_super_value):
18457
0
            {
18458
0
                JSValue val;
18459
0
                JSAtom atom;
18460
0
                sf->cur_pc = pc;
18461
0
                atom = JS_ValueToAtom(ctx, sp[-1]);
18462
0
                if (unlikely(atom == JS_ATOM_NULL))
18463
0
                    goto exception;
18464
0
                val = JS_GetPropertyInternal(ctx, sp[-2], atom, sp[-3], FALSE);
18465
0
                JS_FreeAtom(ctx, atom);
18466
0
                if (unlikely(JS_IsException(val)))
18467
0
                    goto exception;
18468
0
                JS_FreeValue(ctx, sp[-1]);
18469
0
                JS_FreeValue(ctx, sp[-2]);
18470
0
                JS_FreeValue(ctx, sp[-3]);
18471
0
                sp[-3] = val;
18472
0
                sp -= 2;
18473
0
            }
18474
0
            BREAK;
18475
18476
0
        CASE(OP_put_array_el):
18477
0
            {
18478
0
                int ret;
18479
18480
0
                sf->cur_pc = pc;
18481
0
                ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT);
18482
0
                JS_FreeValue(ctx, sp[-3]);
18483
0
                sp -= 3;
18484
0
                if (unlikely(ret < 0))
18485
0
                    goto exception;
18486
0
            }
18487
0
            BREAK;
18488
18489
0
        CASE(OP_put_ref_value):
18490
0
            {
18491
0
                int ret;
18492
0
                JSAtom atom;
18493
0
                sf->cur_pc = pc;
18494
0
                atom = JS_ValueToAtom(ctx, sp[-2]);
18495
0
                if (unlikely(atom == JS_ATOM_NULL))
18496
0
                    goto exception;
18497
0
                if (unlikely(JS_IsUndefined(sp[-3]))) {
18498
0
                    if (is_strict_mode(ctx)) {
18499
0
                        JS_ThrowReferenceErrorNotDefined(ctx, atom);
18500
0
                        JS_FreeAtom(ctx, atom);
18501
0
                        goto exception;
18502
0
                    } else {
18503
0
                        sp[-3] = JS_DupValue(ctx, ctx->global_obj);
18504
0
                    }
18505
0
                }
18506
0
                ret = JS_HasProperty(ctx, sp[-3], atom);
18507
0
                if (unlikely(ret <= 0)) {
18508
0
                    if (unlikely(ret < 0)) {
18509
0
                        JS_FreeAtom(ctx, atom);
18510
0
                        goto exception;
18511
0
                    }
18512
0
                    if (is_strict_mode(ctx)) {
18513
0
                        JS_ThrowReferenceErrorNotDefined(ctx, atom);
18514
0
                        JS_FreeAtom(ctx, atom);
18515
0
                        goto exception;
18516
0
                    }
18517
0
                }
18518
0
                ret = JS_SetPropertyInternal(ctx, sp[-3], atom, sp[-1], sp[-3], JS_PROP_THROW_STRICT);
18519
0
                JS_FreeAtom(ctx, atom);
18520
0
                JS_FreeValue(ctx, sp[-2]);
18521
0
                JS_FreeValue(ctx, sp[-3]);
18522
0
                sp -= 3;
18523
0
                if (unlikely(ret < 0))
18524
0
                    goto exception;
18525
0
            }
18526
0
            BREAK;
18527
18528
0
        CASE(OP_put_super_value):
18529
0
            {
18530
0
                int ret;
18531
0
                JSAtom atom;
18532
0
                sf->cur_pc = pc;
18533
0
                if (JS_VALUE_GET_TAG(sp[-3]) != JS_TAG_OBJECT) {
18534
0
                    JS_ThrowTypeErrorNotAnObject(ctx);
18535
0
                    goto exception;
18536
0
                }
18537
0
                atom = JS_ValueToAtom(ctx, sp[-2]);
18538
0
                if (unlikely(atom == JS_ATOM_NULL))
18539
0
                    goto exception;
18540
0
                ret = JS_SetPropertyInternal(ctx, sp[-3], atom, sp[-1], sp[-4],
18541
0
                                             JS_PROP_THROW_STRICT);
18542
0
                JS_FreeAtom(ctx, atom);
18543
0
                JS_FreeValue(ctx, sp[-4]);
18544
0
                JS_FreeValue(ctx, sp[-3]);
18545
0
                JS_FreeValue(ctx, sp[-2]);
18546
0
                sp -= 4;
18547
0
                if (ret < 0)
18548
0
                    goto exception;
18549
0
            }
18550
0
            BREAK;
18551
18552
0
        CASE(OP_define_array_el):
18553
0
            {
18554
0
                int ret;
18555
0
                ret = JS_DefinePropertyValueValue(ctx, sp[-3], JS_DupValue(ctx, sp[-2]), sp[-1],
18556
0
                                                  JS_PROP_C_W_E | JS_PROP_THROW);
18557
0
                sp -= 1;
18558
0
                if (unlikely(ret < 0))
18559
0
                    goto exception;
18560
0
            }
18561
0
            BREAK;
18562
18563
0
        CASE(OP_append):    /* array pos enumobj -- array pos */
18564
0
            {
18565
0
                sf->cur_pc = pc;
18566
0
                if (js_append_enumerate(ctx, sp))
18567
0
                    goto exception;
18568
0
                JS_FreeValue(ctx, *--sp);
18569
0
            }
18570
0
            BREAK;
18571
18572
0
        CASE(OP_copy_data_properties):    /* target source excludeList */
18573
0
            {
18574
                /* stack offsets (-1 based):
18575
                   2 bits for target,
18576
                   3 bits for source,
18577
                   2 bits for exclusionList */
18578
0
                int mask;
18579
18580
0
                mask = *pc++;
18581
0
                sf->cur_pc = pc;
18582
0
                if (JS_CopyDataProperties(ctx, sp[-1 - (mask & 3)],
18583
0
                                          sp[-1 - ((mask >> 2) & 7)],
18584
0
                                          sp[-1 - ((mask >> 5) & 7)], 0))
18585
0
                    goto exception;
18586
0
            }
18587
0
            BREAK;
18588
18589
0
        CASE(OP_add):
18590
0
            {
18591
0
                JSValue op1, op2;
18592
0
                op1 = sp[-2];
18593
0
                op2 = sp[-1];
18594
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18595
0
                    int64_t r;
18596
0
                    r = (int64_t)JS_VALUE_GET_INT(op1) + JS_VALUE_GET_INT(op2);
18597
0
                    if (unlikely((int)r != r))
18598
0
                        goto add_slow;
18599
0
                    sp[-2] = JS_NewInt32(ctx, r);
18600
0
                    sp--;
18601
0
                } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
18602
0
                    sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) +
18603
0
                                             JS_VALUE_GET_FLOAT64(op2));
18604
0
                    sp--;
18605
0
                } else if (JS_IsString(op1) && JS_IsString(op2)) {
18606
0
                    sp[-2] = JS_ConcatString(ctx, op1, op2);
18607
0
                    sp--;
18608
0
                    if (JS_IsException(sp[-1]))
18609
0
                        goto exception;
18610
0
                } else {
18611
0
                add_slow:
18612
0
                    sf->cur_pc = pc;
18613
0
                    if (js_add_slow(ctx, sp))
18614
0
                        goto exception;
18615
0
                    sp--;
18616
0
                }
18617
0
            }
18618
0
            BREAK;
18619
0
        CASE(OP_add_loc):
18620
0
            {
18621
0
                JSValue op2;
18622
0
                JSValue *pv;
18623
0
                int idx;
18624
0
                idx = *pc;
18625
0
                pc += 1;
18626
18627
0
                op2 = sp[-1];
18628
0
                pv = &var_buf[idx];
18629
0
                if (likely(JS_VALUE_IS_BOTH_INT(*pv, op2))) {
18630
0
                    int64_t r;
18631
0
                    r = (int64_t)JS_VALUE_GET_INT(*pv) + JS_VALUE_GET_INT(op2);
18632
0
                    if (unlikely((int)r != r))
18633
0
                        goto add_loc_slow;
18634
0
                    *pv = JS_NewInt32(ctx, r);
18635
0
                    sp--;
18636
0
                } else if (JS_VALUE_IS_BOTH_FLOAT(*pv, op2)) {
18637
0
                    *pv = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(*pv) +
18638
0
                                               JS_VALUE_GET_FLOAT64(op2));
18639
0
                    sp--;
18640
0
                } else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING) {
18641
0
                    sp--;
18642
0
                    sf->cur_pc = pc;
18643
0
                    op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
18644
0
                    if (JS_IsException(op2))
18645
0
                        goto exception;
18646
0
                    if (JS_ConcatStringInPlace(ctx, JS_VALUE_GET_STRING(*pv), op2)) {
18647
0
                        JS_FreeValue(ctx, op2);
18648
0
                    } else {
18649
0
                        op2 = JS_ConcatString(ctx, JS_DupValue(ctx, *pv), op2);
18650
0
                        if (JS_IsException(op2))
18651
0
                            goto exception;
18652
0
                        set_value(ctx, pv, op2);
18653
0
                    }
18654
0
                } else {
18655
0
                    JSValue ops[2];
18656
0
                add_loc_slow:
18657
                    /* In case of exception, js_add_slow frees ops[0]
18658
                       and ops[1], so we must duplicate *pv */
18659
0
                    sf->cur_pc = pc;
18660
0
                    ops[0] = JS_DupValue(ctx, *pv);
18661
0
                    ops[1] = op2;
18662
0
                    sp--;
18663
0
                    if (js_add_slow(ctx, ops + 2))
18664
0
                        goto exception;
18665
0
                    set_value(ctx, pv, ops[0]);
18666
0
                }
18667
0
            }
18668
0
            BREAK;
18669
0
        CASE(OP_sub):
18670
0
            {
18671
0
                JSValue op1, op2;
18672
0
                op1 = sp[-2];
18673
0
                op2 = sp[-1];
18674
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18675
0
                    int64_t r;
18676
0
                    r = (int64_t)JS_VALUE_GET_INT(op1) - JS_VALUE_GET_INT(op2);
18677
0
                    if (unlikely((int)r != r))
18678
0
                        goto binary_arith_slow;
18679
0
                    sp[-2] = JS_NewInt32(ctx, r);
18680
0
                    sp--;
18681
0
                } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
18682
0
                    sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) -
18683
0
                                             JS_VALUE_GET_FLOAT64(op2));
18684
0
                    sp--;
18685
0
                } else {
18686
0
                    goto binary_arith_slow;
18687
0
                }
18688
0
            }
18689
0
            BREAK;
18690
0
        CASE(OP_mul):
18691
0
            {
18692
0
                JSValue op1, op2;
18693
0
                double d;
18694
0
                op1 = sp[-2];
18695
0
                op2 = sp[-1];
18696
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18697
0
                    int32_t v1, v2;
18698
0
                    int64_t r;
18699
0
                    v1 = JS_VALUE_GET_INT(op1);
18700
0
                    v2 = JS_VALUE_GET_INT(op2);
18701
0
                    r = (int64_t)v1 * v2;
18702
0
                    if (unlikely((int)r != r)) {
18703
0
                        d = (double)r;
18704
0
                        goto mul_fp_res;
18705
0
                    }
18706
                    /* need to test zero case for -0 result */
18707
0
                    if (unlikely(r == 0 && (v1 | v2) < 0)) {
18708
0
                        d = -0.0;
18709
0
                        goto mul_fp_res;
18710
0
                    }
18711
0
                    sp[-2] = JS_NewInt32(ctx, r);
18712
0
                    sp--;
18713
0
                } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
18714
0
                    d = JS_VALUE_GET_FLOAT64(op1) * JS_VALUE_GET_FLOAT64(op2);
18715
0
                mul_fp_res:
18716
0
                    sp[-2] = __JS_NewFloat64(ctx, d);
18717
0
                    sp--;
18718
0
                } else {
18719
0
                    goto binary_arith_slow;
18720
0
                }
18721
0
            }
18722
0
            BREAK;
18723
0
        CASE(OP_div):
18724
0
            {
18725
0
                JSValue op1, op2;
18726
0
                op1 = sp[-2];
18727
0
                op2 = sp[-1];
18728
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18729
0
                    int v1, v2;
18730
0
                    v1 = JS_VALUE_GET_INT(op1);
18731
0
                    v2 = JS_VALUE_GET_INT(op2);
18732
0
                    sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2);
18733
0
                    sp--;
18734
0
                } else {
18735
0
                    goto binary_arith_slow;
18736
0
                }
18737
0
            }
18738
0
            BREAK;
18739
0
        CASE(OP_mod):
18740
0
            {
18741
0
                JSValue op1, op2;
18742
0
                op1 = sp[-2];
18743
0
                op2 = sp[-1];
18744
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18745
0
                    int v1, v2, r;
18746
0
                    v1 = JS_VALUE_GET_INT(op1);
18747
0
                    v2 = JS_VALUE_GET_INT(op2);
18748
                    /* We must avoid v2 = 0, v1 = INT32_MIN and v2 =
18749
                       -1 and the cases where the result is -0. */
18750
0
                    if (unlikely(v1 < 0 || v2 <= 0))
18751
0
                        goto binary_arith_slow;
18752
0
                    r = v1 % v2;
18753
0
                    sp[-2] = JS_NewInt32(ctx, r);
18754
0
                    sp--;
18755
0
                } else {
18756
0
                    goto binary_arith_slow;
18757
0
                }
18758
0
            }
18759
0
            BREAK;
18760
0
        CASE(OP_pow):
18761
0
        binary_arith_slow:
18762
0
            sf->cur_pc = pc;
18763
0
            if (js_binary_arith_slow(ctx, sp, opcode))
18764
0
                goto exception;
18765
0
            sp--;
18766
0
            BREAK;
18767
18768
0
        CASE(OP_plus):
18769
0
            {
18770
0
                JSValue op1;
18771
0
                uint32_t tag;
18772
0
                op1 = sp[-1];
18773
0
                tag = JS_VALUE_GET_TAG(op1);
18774
0
                if (tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag)) {
18775
0
                } else {
18776
0
                    sf->cur_pc = pc;
18777
0
                    if (js_unary_arith_slow(ctx, sp, opcode))
18778
0
                        goto exception;
18779
0
                }
18780
0
            }
18781
0
            BREAK;
18782
0
        CASE(OP_neg):
18783
0
            {
18784
0
                JSValue op1;
18785
0
                uint32_t tag;
18786
0
                int val;
18787
0
                double d;
18788
0
                op1 = sp[-1];
18789
0
                tag = JS_VALUE_GET_TAG(op1);
18790
0
                if (tag == JS_TAG_INT) {
18791
0
                    val = JS_VALUE_GET_INT(op1);
18792
                    /* Note: -0 cannot be expressed as integer */
18793
0
                    if (unlikely(val == 0)) {
18794
0
                        d = -0.0;
18795
0
                        goto neg_fp_res;
18796
0
                    }
18797
0
                    if (unlikely(val == INT32_MIN)) {
18798
0
                        d = -(double)val;
18799
0
                        goto neg_fp_res;
18800
0
                    }
18801
0
                    sp[-1] = JS_NewInt32(ctx, -val);
18802
0
                } else if (JS_TAG_IS_FLOAT64(tag)) {
18803
0
                    d = -JS_VALUE_GET_FLOAT64(op1);
18804
0
                neg_fp_res:
18805
0
                    sp[-1] = __JS_NewFloat64(ctx, d);
18806
0
                } else {
18807
0
                    sf->cur_pc = pc;
18808
0
                    if (js_unary_arith_slow(ctx, sp, opcode))
18809
0
                        goto exception;
18810
0
                }
18811
0
            }
18812
0
            BREAK;
18813
0
        CASE(OP_inc):
18814
0
            {
18815
0
                JSValue op1;
18816
0
                int val;
18817
0
                op1 = sp[-1];
18818
0
                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
18819
0
                    val = JS_VALUE_GET_INT(op1);
18820
0
                    if (unlikely(val == INT32_MAX))
18821
0
                        goto inc_slow;
18822
0
                    sp[-1] = JS_NewInt32(ctx, val + 1);
18823
0
                } else {
18824
0
                inc_slow:
18825
0
                    sf->cur_pc = pc;
18826
0
                    if (js_unary_arith_slow(ctx, sp, opcode))
18827
0
                        goto exception;
18828
0
                }
18829
0
            }
18830
0
            BREAK;
18831
0
        CASE(OP_dec):
18832
0
            {
18833
0
                JSValue op1;
18834
0
                int val;
18835
0
                op1 = sp[-1];
18836
0
                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
18837
0
                    val = JS_VALUE_GET_INT(op1);
18838
0
                    if (unlikely(val == INT32_MIN))
18839
0
                        goto dec_slow;
18840
0
                    sp[-1] = JS_NewInt32(ctx, val - 1);
18841
0
                } else {
18842
0
                dec_slow:
18843
0
                    sf->cur_pc = pc;
18844
0
                    if (js_unary_arith_slow(ctx, sp, opcode))
18845
0
                        goto exception;
18846
0
                }
18847
0
            }
18848
0
            BREAK;
18849
0
        CASE(OP_post_inc):
18850
0
        CASE(OP_post_dec):
18851
0
            sf->cur_pc = pc;
18852
0
            if (js_post_inc_slow(ctx, sp, opcode))
18853
0
                goto exception;
18854
0
            sp++;
18855
0
            BREAK;
18856
0
        CASE(OP_inc_loc):
18857
0
            {
18858
0
                JSValue op1;
18859
0
                int val;
18860
0
                int idx;
18861
0
                idx = *pc;
18862
0
                pc += 1;
18863
18864
0
                op1 = var_buf[idx];
18865
0
                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
18866
0
                    val = JS_VALUE_GET_INT(op1);
18867
0
                    if (unlikely(val == INT32_MAX))
18868
0
                        goto inc_loc_slow;
18869
0
                    var_buf[idx] = JS_NewInt32(ctx, val + 1);
18870
0
                } else {
18871
0
                inc_loc_slow:
18872
0
                    sf->cur_pc = pc;
18873
                    /* must duplicate otherwise the variable value may
18874
                       be destroyed before JS code accesses it */
18875
0
                    op1 = JS_DupValue(ctx, op1);
18876
0
                    if (js_unary_arith_slow(ctx, &op1 + 1, OP_inc))
18877
0
                        goto exception;
18878
0
                    set_value(ctx, &var_buf[idx], op1);
18879
0
                }
18880
0
            }
18881
0
            BREAK;
18882
0
        CASE(OP_dec_loc):
18883
0
            {
18884
0
                JSValue op1;
18885
0
                int val;
18886
0
                int idx;
18887
0
                idx = *pc;
18888
0
                pc += 1;
18889
18890
0
                op1 = var_buf[idx];
18891
0
                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
18892
0
                    val = JS_VALUE_GET_INT(op1);
18893
0
                    if (unlikely(val == INT32_MIN))
18894
0
                        goto dec_loc_slow;
18895
0
                    var_buf[idx] = JS_NewInt32(ctx, val - 1);
18896
0
                } else {
18897
0
                dec_loc_slow:
18898
0
                    sf->cur_pc = pc;
18899
                    /* must duplicate otherwise the variable value may
18900
                       be destroyed before JS code accesses it */
18901
0
                    op1 = JS_DupValue(ctx, op1);
18902
0
                    if (js_unary_arith_slow(ctx, &op1 + 1, OP_dec))
18903
0
                        goto exception;
18904
0
                    set_value(ctx, &var_buf[idx], op1);
18905
0
                }
18906
0
            }
18907
0
            BREAK;
18908
0
        CASE(OP_not):
18909
0
            {
18910
0
                JSValue op1;
18911
0
                op1 = sp[-1];
18912
0
                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {
18913
0
                    sp[-1] = JS_NewInt32(ctx, ~JS_VALUE_GET_INT(op1));
18914
0
                } else {
18915
0
                    sf->cur_pc = pc;
18916
0
                    if (js_not_slow(ctx, sp))
18917
0
                        goto exception;
18918
0
                }
18919
0
            }
18920
0
            BREAK;
18921
18922
0
        CASE(OP_shl):
18923
0
            {
18924
0
                JSValue op1, op2;
18925
0
                op1 = sp[-2];
18926
0
                op2 = sp[-1];
18927
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18928
0
                    uint32_t v1, v2;
18929
0
                    v1 = JS_VALUE_GET_INT(op1);
18930
0
                    v2 = JS_VALUE_GET_INT(op2);
18931
0
                    v2 &= 0x1f;
18932
0
                    sp[-2] = JS_NewInt32(ctx, v1 << v2);
18933
0
                    sp--;
18934
0
                } else {
18935
0
                    sf->cur_pc = pc;
18936
0
                    if (js_binary_logic_slow(ctx, sp, opcode))
18937
0
                        goto exception;
18938
0
                    sp--;
18939
0
                }
18940
0
            }
18941
0
            BREAK;
18942
0
        CASE(OP_shr):
18943
0
            {
18944
0
                JSValue op1, op2;
18945
0
                op1 = sp[-2];
18946
0
                op2 = sp[-1];
18947
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18948
0
                    uint32_t v2;
18949
0
                    v2 = JS_VALUE_GET_INT(op2);
18950
0
                    v2 &= 0x1f;
18951
0
                    sp[-2] = JS_NewUint32(ctx,
18952
0
                                          (uint32_t)JS_VALUE_GET_INT(op1) >>
18953
0
                                          v2);
18954
0
                    sp--;
18955
0
                } else {
18956
0
                    sf->cur_pc = pc;
18957
0
                    if (js_shr_slow(ctx, sp))
18958
0
                        goto exception;
18959
0
                    sp--;
18960
0
                }
18961
0
            }
18962
0
            BREAK;
18963
0
        CASE(OP_sar):
18964
0
            {
18965
0
                JSValue op1, op2;
18966
0
                op1 = sp[-2];
18967
0
                op2 = sp[-1];
18968
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18969
0
                    uint32_t v2;
18970
0
                    v2 = JS_VALUE_GET_INT(op2);
18971
0
                    v2 &= 0x1f;
18972
0
                    sp[-2] = JS_NewInt32(ctx,
18973
0
                                          (int)JS_VALUE_GET_INT(op1) >> v2);
18974
0
                    sp--;
18975
0
                } else {
18976
0
                    sf->cur_pc = pc;
18977
0
                    if (js_binary_logic_slow(ctx, sp, opcode))
18978
0
                        goto exception;
18979
0
                    sp--;
18980
0
                }
18981
0
            }
18982
0
            BREAK;
18983
0
        CASE(OP_and):
18984
0
            {
18985
0
                JSValue op1, op2;
18986
0
                op1 = sp[-2];
18987
0
                op2 = sp[-1];
18988
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
18989
0
                    sp[-2] = JS_NewInt32(ctx,
18990
0
                                         JS_VALUE_GET_INT(op1) &
18991
0
                                         JS_VALUE_GET_INT(op2));
18992
0
                    sp--;
18993
0
                } else {
18994
0
                    sf->cur_pc = pc;
18995
0
                    if (js_binary_logic_slow(ctx, sp, opcode))
18996
0
                        goto exception;
18997
0
                    sp--;
18998
0
                }
18999
0
            }
19000
0
            BREAK;
19001
0
        CASE(OP_or):
19002
0
            {
19003
0
                JSValue op1, op2;
19004
0
                op1 = sp[-2];
19005
0
                op2 = sp[-1];
19006
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
19007
0
                    sp[-2] = JS_NewInt32(ctx,
19008
0
                                         JS_VALUE_GET_INT(op1) |
19009
0
                                         JS_VALUE_GET_INT(op2));
19010
0
                    sp--;
19011
0
                } else {
19012
0
                    sf->cur_pc = pc;
19013
0
                    if (js_binary_logic_slow(ctx, sp, opcode))
19014
0
                        goto exception;
19015
0
                    sp--;
19016
0
                }
19017
0
            }
19018
0
            BREAK;
19019
0
        CASE(OP_xor):
19020
0
            {
19021
0
                JSValue op1, op2;
19022
0
                op1 = sp[-2];
19023
0
                op2 = sp[-1];
19024
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
19025
0
                    sp[-2] = JS_NewInt32(ctx,
19026
0
                                         JS_VALUE_GET_INT(op1) ^
19027
0
                                         JS_VALUE_GET_INT(op2));
19028
0
                    sp--;
19029
0
                } else {
19030
0
                    sf->cur_pc = pc;
19031
0
                    if (js_binary_logic_slow(ctx, sp, opcode))
19032
0
                        goto exception;
19033
0
                    sp--;
19034
0
                }
19035
0
            }
19036
0
            BREAK;
19037
19038
19039
0
#define OP_CMP(opcode, binary_op, slow_call)              \
19040
0
            CASE(opcode):                                 \
19041
0
                {                                         \
19042
0
                JSValue op1, op2;                         \
19043
0
                op1 = sp[-2];                             \
19044
0
                op2 = sp[-1];                                   \
19045
0
                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {           \
19046
0
                    sp[-2] = JS_NewBool(ctx, JS_VALUE_GET_INT(op1) binary_op JS_VALUE_GET_INT(op2)); \
19047
0
                    sp--;                                               \
19048
0
                } else {                                                \
19049
0
                    sf->cur_pc = pc;                                    \
19050
0
                    if (slow_call)                                      \
19051
0
                        goto exception;                                 \
19052
0
                    sp--;                                               \
19053
0
                }                                                       \
19054
0
                }                                                       \
19055
0
            BREAK
19056
19057
0
            OP_CMP(OP_lt, <, js_relational_slow(ctx, sp, opcode));
19058
0
            OP_CMP(OP_lte, <=, js_relational_slow(ctx, sp, opcode));
19059
0
            OP_CMP(OP_gt, >, js_relational_slow(ctx, sp, opcode));
19060
0
            OP_CMP(OP_gte, >=, js_relational_slow(ctx, sp, opcode));
19061
0
            OP_CMP(OP_eq, ==, js_eq_slow(ctx, sp, 0));
19062
0
            OP_CMP(OP_neq, !=, js_eq_slow(ctx, sp, 1));
19063
0
            OP_CMP(OP_strict_eq, ==, js_strict_eq_slow(ctx, sp, 0));
19064
0
            OP_CMP(OP_strict_neq, !=, js_strict_eq_slow(ctx, sp, 1));
19065
19066
0
        CASE(OP_in):
19067
0
            sf->cur_pc = pc;
19068
0
            if (js_operator_in(ctx, sp))
19069
0
                goto exception;
19070
0
            sp--;
19071
0
            BREAK;
19072
0
        CASE(OP_private_in):
19073
0
            sf->cur_pc = pc;
19074
0
            if (js_operator_private_in(ctx, sp))
19075
0
                goto exception;
19076
0
            sp--;
19077
0
            BREAK;
19078
0
        CASE(OP_instanceof):
19079
0
            sf->cur_pc = pc;
19080
0
            if (js_operator_instanceof(ctx, sp))
19081
0
                goto exception;
19082
0
            sp--;
19083
0
            BREAK;
19084
0
        CASE(OP_typeof):
19085
0
            {
19086
0
                JSValue op1;
19087
0
                JSAtom atom;
19088
19089
0
                op1 = sp[-1];
19090
0
                atom = js_operator_typeof(ctx, op1);
19091
0
                JS_FreeValue(ctx, op1);
19092
0
                sp[-1] = JS_AtomToString(ctx, atom);
19093
0
            }
19094
0
            BREAK;
19095
0
        CASE(OP_delete):
19096
0
            sf->cur_pc = pc;
19097
0
            if (js_operator_delete(ctx, sp))
19098
0
                goto exception;
19099
0
            sp--;
19100
0
            BREAK;
19101
0
        CASE(OP_delete_var):
19102
0
            {
19103
0
                JSAtom atom;
19104
0
                int ret;
19105
19106
0
                atom = get_u32(pc);
19107
0
                pc += 4;
19108
0
                sf->cur_pc = pc;
19109
19110
0
                ret = JS_DeleteGlobalVar(ctx, atom);
19111
0
                if (unlikely(ret < 0))
19112
0
                    goto exception;
19113
0
                *sp++ = JS_NewBool(ctx, ret);
19114
0
            }
19115
0
            BREAK;
19116
19117
0
        CASE(OP_to_object):
19118
0
            if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_OBJECT) {
19119
0
                sf->cur_pc = pc;
19120
0
                ret_val = JS_ToObject(ctx, sp[-1]);
19121
0
                if (JS_IsException(ret_val))
19122
0
                    goto exception;
19123
0
                JS_FreeValue(ctx, sp[-1]);
19124
0
                sp[-1] = ret_val;
19125
0
            }
19126
0
            BREAK;
19127
19128
0
        CASE(OP_to_propkey):
19129
0
            switch (JS_VALUE_GET_TAG(sp[-1])) {
19130
0
            case JS_TAG_INT:
19131
0
            case JS_TAG_STRING:
19132
0
            case JS_TAG_SYMBOL:
19133
0
                break;
19134
0
            default:
19135
0
                sf->cur_pc = pc;
19136
0
                ret_val = JS_ToPropertyKey(ctx, sp[-1]);
19137
0
                if (JS_IsException(ret_val))
19138
0
                    goto exception;
19139
0
                JS_FreeValue(ctx, sp[-1]);
19140
0
                sp[-1] = ret_val;
19141
0
                break;
19142
0
            }
19143
0
            BREAK;
19144
19145
#if 0
19146
        CASE(OP_to_string):
19147
            if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_STRING) {
19148
                ret_val = JS_ToString(ctx, sp[-1]);
19149
                if (JS_IsException(ret_val))
19150
                    goto exception;
19151
                JS_FreeValue(ctx, sp[-1]);
19152
                sp[-1] = ret_val;
19153
            }
19154
            BREAK;
19155
#endif
19156
0
        CASE(OP_with_get_var):
19157
0
        CASE(OP_with_put_var):
19158
0
        CASE(OP_with_delete_var):
19159
0
        CASE(OP_with_make_ref):
19160
0
        CASE(OP_with_get_ref):
19161
0
            {
19162
0
                JSAtom atom;
19163
0
                int32_t diff;
19164
0
                JSValue obj, val;
19165
0
                int ret, is_with;
19166
0
                atom = get_u32(pc);
19167
0
                diff = get_u32(pc + 4);
19168
0
                is_with = pc[8];
19169
0
                pc += 9;
19170
0
                sf->cur_pc = pc;
19171
19172
0
                obj = sp[-1];
19173
0
                ret = JS_HasProperty(ctx, obj, atom);
19174
0
                if (unlikely(ret < 0))
19175
0
                    goto exception;
19176
0
                if (ret) {
19177
0
                    if (is_with) {
19178
0
                        ret = js_has_unscopable(ctx, obj, atom);
19179
0
                        if (unlikely(ret < 0))
19180
0
                            goto exception;
19181
0
                        if (ret)
19182
0
                            goto no_with;
19183
0
                    }
19184
0
                    switch (opcode) {
19185
0
                    case OP_with_get_var:
19186
                        /* in Object Environment Records, GetBindingValue() calls HasProperty() */
19187
0
                        ret = JS_HasProperty(ctx, obj, atom);
19188
0
                        if (unlikely(ret <= 0)) {
19189
0
                            if (ret < 0)
19190
0
                                goto exception;
19191
0
                            if (is_strict_mode(ctx)) {
19192
0
                                JS_ThrowReferenceErrorNotDefined(ctx, atom);
19193
0
                                goto exception;
19194
0
                            } 
19195
0
                            val = JS_UNDEFINED;
19196
0
                        } else {
19197
0
                            val = JS_GetProperty(ctx, obj, atom);
19198
0
                            if (unlikely(JS_IsException(val)))
19199
0
                                goto exception;
19200
0
                        }
19201
0
                        set_value(ctx, &sp[-1], val);
19202
0
                        break;
19203
0
                    case OP_with_put_var: /* used e.g. in for in/of */
19204
                        /* in Object Environment Records, SetMutableBinding() calls HasProperty() */
19205
0
                        ret = JS_HasProperty(ctx, obj, atom);
19206
0
                        if (unlikely(ret <= 0)) {
19207
0
                            if (ret < 0)
19208
0
                                goto exception;
19209
0
                            if (is_strict_mode(ctx)) {
19210
0
                                JS_ThrowReferenceErrorNotDefined(ctx, atom);
19211
0
                                goto exception;
19212
0
                            } 
19213
0
                        }
19214
0
                        ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2], obj,
19215
0
                                                     JS_PROP_THROW_STRICT);
19216
0
                        JS_FreeValue(ctx, sp[-1]);
19217
0
                        sp -= 2;
19218
0
                        if (unlikely(ret < 0))
19219
0
                            goto exception;
19220
0
                        break;
19221
0
                    case OP_with_delete_var:
19222
0
                        ret = JS_DeleteProperty(ctx, obj, atom, 0);
19223
0
                        if (unlikely(ret < 0))
19224
0
                            goto exception;
19225
0
                        JS_FreeValue(ctx, sp[-1]);
19226
0
                        sp[-1] = JS_NewBool(ctx, ret);
19227
0
                        break;
19228
0
                    case OP_with_make_ref:
19229
                        /* produce a pair object/propname on the stack */
19230
0
                        *sp++ = JS_AtomToValue(ctx, atom);
19231
0
                        break;
19232
0
                    case OP_with_get_ref:
19233
                        /* produce a pair object/method on the stack */
19234
                        /* in Object Environment Records, GetBindingValue() calls HasProperty() */
19235
0
                        ret = JS_HasProperty(ctx, obj, atom);
19236
0
                        if (unlikely(ret < 0))
19237
0
                            goto exception;
19238
0
                        if (!ret) {
19239
0
                            val = JS_UNDEFINED;
19240
0
                        } else {
19241
0
                            val = JS_GetProperty(ctx, obj, atom);
19242
0
                            if (unlikely(JS_IsException(val)))
19243
0
                                goto exception;
19244
0
                        }
19245
0
                        *sp++ = val;
19246
0
                        break;
19247
0
                    }
19248
0
                    pc += diff - 5;
19249
0
                } else {
19250
0
                no_with:
19251
                    /* if not jumping, drop the object argument */
19252
0
                    JS_FreeValue(ctx, sp[-1]);
19253
0
                    sp--;
19254
0
                }
19255
0
            }
19256
0
            BREAK;
19257
19258
0
        CASE(OP_await):
19259
0
            ret_val = JS_NewInt32(ctx, FUNC_RET_AWAIT);
19260
0
            goto done_generator;
19261
0
        CASE(OP_yield):
19262
0
            ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD);
19263
0
            goto done_generator;
19264
0
        CASE(OP_yield_star):
19265
0
        CASE(OP_async_yield_star):
19266
0
            ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD_STAR);
19267
0
            goto done_generator;
19268
2
        CASE(OP_return_async):
19269
2
            ret_val = JS_UNDEFINED;
19270
2
            goto done_generator;
19271
0
        CASE(OP_initial_yield):
19272
0
            ret_val = JS_NewInt32(ctx, FUNC_RET_INITIAL_YIELD);
19273
0
            goto done_generator;
19274
19275
0
        CASE(OP_nop):
19276
0
            BREAK;
19277
0
        CASE(OP_is_undefined_or_null):
19278
0
            if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED ||
19279
0
                JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) {
19280
0
                goto set_true;
19281
0
            } else {
19282
0
                goto free_and_set_false;
19283
0
            }
19284
0
#if SHORT_OPCODES
19285
0
        CASE(OP_is_undefined):
19286
0
            if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED) {
19287
0
                goto set_true;
19288
0
            } else {
19289
0
                goto free_and_set_false;
19290
0
            }
19291
0
        CASE(OP_is_null):
19292
0
            if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) {
19293
0
                goto set_true;
19294
0
            } else {
19295
0
                goto free_and_set_false;
19296
0
            }
19297
            /* XXX: could merge to a single opcode */
19298
0
        CASE(OP_typeof_is_undefined):
19299
            /* different from OP_is_undefined because of isHTMLDDA */
19300
0
            if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_undefined) {
19301
0
                goto free_and_set_true;
19302
0
            } else {
19303
0
                goto free_and_set_false;
19304
0
            }
19305
0
        CASE(OP_typeof_is_function):
19306
0
            if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_function) {
19307
0
                goto free_and_set_true;
19308
0
            } else {
19309
0
                goto free_and_set_false;
19310
0
            }
19311
0
        free_and_set_true:
19312
0
            JS_FreeValue(ctx, sp[-1]);
19313
0
#endif
19314
0
        set_true:
19315
0
            sp[-1] = JS_TRUE;
19316
0
            BREAK;
19317
0
        free_and_set_false:
19318
0
            JS_FreeValue(ctx, sp[-1]);
19319
0
            sp[-1] = JS_FALSE;
19320
0
            BREAK;
19321
0
        CASE(OP_invalid):
19322
0
        DEFAULT:
19323
0
            JS_ThrowInternalError(ctx, "invalid opcode: pc=%u opcode=0x%02x",
19324
0
                                  (int)(pc - b->byte_code_buf - 1), opcode);
19325
0
            goto exception;
19326
0
        }
19327
0
    }
19328
1
 exception:
19329
1
    if (is_backtrace_needed(ctx, rt->current_exception)) {
19330
        /* add the backtrace information now (it is not done
19331
           before if the exception happens in a bytecode
19332
           operation */
19333
1
        sf->cur_pc = pc;
19334
1
        build_backtrace(ctx, rt->current_exception, NULL, 0, 0, 0);
19335
1
    }
19336
1
    if (!rt->current_exception_is_uncatchable) {
19337
1
        while (sp > stack_buf) {
19338
0
            JSValue val = *--sp;
19339
0
            JS_FreeValue(ctx, val);
19340
0
            if (JS_VALUE_GET_TAG(val) == JS_TAG_CATCH_OFFSET) {
19341
0
                int pos = JS_VALUE_GET_INT(val);
19342
0
                if (pos == 0) {
19343
                    /* enumerator: close it with a throw */
19344
0
                    JS_FreeValue(ctx, sp[-1]); /* drop the next method */
19345
0
                    sp--;
19346
0
                    JS_IteratorClose(ctx, sp[-1], TRUE);
19347
0
                } else {
19348
0
                    *sp++ = rt->current_exception;
19349
0
                    rt->current_exception = JS_UNINITIALIZED;
19350
0
                    pc = b->byte_code_buf + pos;
19351
0
                    goto restart;
19352
0
                }
19353
0
            }
19354
0
        }
19355
1
    }
19356
1
    ret_val = JS_EXCEPTION;
19357
    /* the local variables are freed by the caller in the generator
19358
       case. Hence the label 'done' should never be reached in a
19359
       generator function. */
19360
1
    if (b->func_kind != JS_FUNC_NORMAL) {
19361
3
    done_generator:
19362
3
        sf->cur_pc = pc;
19363
3
        sf->cur_sp = sp;
19364
3
    } else {
19365
3
    done:
19366
3
        if (unlikely(!list_empty(&sf->var_ref_list))) {
19367
            /* variable references reference the stack: must close them */
19368
0
            close_var_refs(rt, sf);
19369
0
        }
19370
        /* free the local variables and stack */
19371
3
        for(pval = local_buf; pval < sp; pval++) {
19372
0
            JS_FreeValue(ctx, *pval);
19373
0
        }
19374
3
    }
19375
6
    rt->current_stack_frame = sf->prev_frame;
19376
6
    return ret_val;
19377
1
}
19378
19379
JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj,
19380
                int argc, JSValueConst *argv)
19381
15
{
19382
15
    return JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED,
19383
15
                           argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV);
19384
15
}
19385
19386
static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj,
19387
                           int argc, JSValueConst *argv)
19388
0
{
19389
0
    JSValue res = JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED,
19390
0
                                  argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV);
19391
0
    JS_FreeValue(ctx, func_obj);
19392
0
    return res;
19393
0
}
19394
19395
/* warning: the refcount of the context is not incremented. Return
19396
   NULL in case of exception (case of revoked proxy only) */
19397
static JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValueConst func_obj)
19398
0
{
19399
0
    JSObject *p;
19400
0
    JSContext *realm;
19401
19402
0
    if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
19403
0
        return ctx;
19404
0
    p = JS_VALUE_GET_OBJ(func_obj);
19405
0
    switch(p->class_id) {
19406
0
    case JS_CLASS_C_FUNCTION:
19407
0
        realm = p->u.cfunc.realm;
19408
0
        break;
19409
0
    case JS_CLASS_BYTECODE_FUNCTION:
19410
0
    case JS_CLASS_GENERATOR_FUNCTION:
19411
0
    case JS_CLASS_ASYNC_FUNCTION:
19412
0
    case JS_CLASS_ASYNC_GENERATOR_FUNCTION:
19413
0
        {
19414
0
            JSFunctionBytecode *b;
19415
0
            b = p->u.func.function_bytecode;
19416
0
            realm = b->realm;
19417
0
        }
19418
0
        break;
19419
0
    case JS_CLASS_PROXY:
19420
0
        {
19421
0
            JSProxyData *s = p->u.opaque;
19422
0
            if (!s)
19423
0
                return ctx;
19424
0
            if (s->is_revoked) {
19425
0
                JS_ThrowTypeErrorRevokedProxy(ctx);
19426
0
                return NULL;
19427
0
            } else {
19428
0
                realm = JS_GetFunctionRealm(ctx, s->target);
19429
0
            }
19430
0
        }
19431
0
        break;
19432
0
    case JS_CLASS_BOUND_FUNCTION:
19433
0
        {
19434
0
            JSBoundFunction *bf = p->u.bound_function;
19435
0
            realm = JS_GetFunctionRealm(ctx, bf->func_obj);
19436
0
        }
19437
0
        break;
19438
0
    default:
19439
0
        realm = ctx;
19440
0
        break;
19441
0
    }
19442
0
    return realm;
19443
0
}
19444
19445
static JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor,
19446
                                   int class_id)
19447
6
{
19448
6
    JSValue proto, obj;
19449
6
    JSContext *realm;
19450
19451
6
    if (JS_IsUndefined(ctor)) {
19452
6
        proto = JS_DupValue(ctx, ctx->class_proto[class_id]);
19453
6
    } else {
19454
0
        proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);
19455
0
        if (JS_IsException(proto))
19456
0
            return proto;
19457
0
        if (!JS_IsObject(proto)) {
19458
0
            JS_FreeValue(ctx, proto);
19459
0
            realm = JS_GetFunctionRealm(ctx, ctor);
19460
0
            if (!realm)
19461
0
                return JS_EXCEPTION;
19462
0
            proto = JS_DupValue(ctx, realm->class_proto[class_id]);
19463
0
        }
19464
0
    }
19465
6
    obj = JS_NewObjectProtoClass(ctx, proto, class_id);
19466
6
    JS_FreeValue(ctx, proto);
19467
6
    return obj;
19468
6
}
19469
19470
/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */
19471
static JSValue JS_CallConstructorInternal(JSContext *ctx,
19472
                                          JSValueConst func_obj,
19473
                                          JSValueConst new_target,
19474
                                          int argc, JSValue *argv, int flags)
19475
0
{
19476
0
    JSObject *p;
19477
0
    JSFunctionBytecode *b;
19478
19479
0
    if (js_poll_interrupts(ctx))
19480
0
        return JS_EXCEPTION;
19481
0
    flags |= JS_CALL_FLAG_CONSTRUCTOR;
19482
0
    if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT))
19483
0
        goto not_a_function;
19484
0
    p = JS_VALUE_GET_OBJ(func_obj);
19485
0
    if (unlikely(!p->is_constructor))
19486
0
        return JS_ThrowTypeError(ctx, "not a constructor");
19487
0
    if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {
19488
0
        JSClassCall *call_func;
19489
0
        call_func = ctx->rt->class_array[p->class_id].call;
19490
0
        if (!call_func) {
19491
0
        not_a_function:
19492
0
            return JS_ThrowTypeError(ctx, "not a function");
19493
0
        }
19494
0
        return call_func(ctx, func_obj, new_target, argc,
19495
0
                         (JSValueConst *)argv, flags);
19496
0
    }
19497
19498
0
    b = p->u.func.function_bytecode;
19499
0
    if (b->is_derived_class_constructor) {
19500
0
        return JS_CallInternal(ctx, func_obj, JS_UNDEFINED, new_target, argc, argv, flags);
19501
0
    } else {
19502
0
        JSValue obj, ret;
19503
        /* legacy constructor behavior */
19504
0
        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
19505
0
        if (JS_IsException(obj))
19506
0
            return JS_EXCEPTION;
19507
0
        ret = JS_CallInternal(ctx, func_obj, obj, new_target, argc, argv, flags);
19508
0
        if (JS_VALUE_GET_TAG(ret) == JS_TAG_OBJECT ||
19509
0
            JS_IsException(ret)) {
19510
0
            JS_FreeValue(ctx, obj);
19511
0
            return ret;
19512
0
        } else {
19513
0
            JS_FreeValue(ctx, ret);
19514
0
            return obj;
19515
0
        }
19516
0
    }
19517
0
}
19518
19519
JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj,
19520
                            JSValueConst new_target,
19521
                            int argc, JSValueConst *argv)
19522
0
{
19523
0
    return JS_CallConstructorInternal(ctx, func_obj, new_target,
19524
0
                                      argc, (JSValue *)argv,
19525
0
                                      JS_CALL_FLAG_COPY_ARGV);
19526
0
}
19527
19528
JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj,
19529
                           int argc, JSValueConst *argv)
19530
0
{
19531
0
    return JS_CallConstructorInternal(ctx, func_obj, func_obj,
19532
0
                                      argc, (JSValue *)argv,
19533
0
                                      JS_CALL_FLAG_COPY_ARGV);
19534
0
}
19535
19536
JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom,
19537
                  int argc, JSValueConst *argv)
19538
0
{
19539
0
    JSValue func_obj;
19540
0
    func_obj = JS_GetProperty(ctx, this_val, atom);
19541
0
    if (JS_IsException(func_obj))
19542
0
        return func_obj;
19543
0
    return JS_CallFree(ctx, func_obj, this_val, argc, argv);
19544
0
}
19545
19546
static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
19547
                             int argc, JSValueConst *argv)
19548
0
{
19549
0
    JSValue res = JS_Invoke(ctx, this_val, atom, argc, argv);
19550
0
    JS_FreeValue(ctx, this_val);
19551
0
    return res;
19552
0
}
19553
19554
/* JSAsyncFunctionState (used by generator and async functions) */
19555
static JSAsyncFunctionState *async_func_init(JSContext *ctx,
19556
                                             JSValueConst func_obj, JSValueConst this_obj,
19557
                                             int argc, JSValueConst *argv)
19558
3
{
19559
3
    JSAsyncFunctionState *s;
19560
3
    JSObject *p;
19561
3
    JSFunctionBytecode *b;
19562
3
    JSStackFrame *sf;
19563
3
    int local_count, i, arg_buf_len, n;
19564
19565
3
    s = js_mallocz(ctx, sizeof(*s));
19566
3
    if (!s)
19567
0
        return NULL;
19568
3
    s->header.ref_count = 1;
19569
3
    add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION);
19570
19571
3
    sf = &s->frame;
19572
3
    init_list_head(&sf->var_ref_list);
19573
3
    p = JS_VALUE_GET_OBJ(func_obj);
19574
3
    b = p->u.func.function_bytecode;
19575
3
    sf->js_mode = b->js_mode | JS_MODE_ASYNC;
19576
3
    sf->cur_pc = b->byte_code_buf;
19577
3
    arg_buf_len = max_int(b->arg_count, argc);
19578
3
    local_count = arg_buf_len + b->var_count + b->stack_size;
19579
3
    sf->arg_buf = js_malloc(ctx, sizeof(JSValue) * max_int(local_count, 1));
19580
3
    if (!sf->arg_buf) {
19581
0
        js_free(ctx, s);
19582
0
        return NULL;
19583
0
    }
19584
3
    sf->cur_func = JS_DupValue(ctx, func_obj);
19585
3
    s->this_val = JS_DupValue(ctx, this_obj);
19586
3
    s->argc = argc;
19587
3
    sf->arg_count = arg_buf_len;
19588
3
    sf->var_buf = sf->arg_buf + arg_buf_len;
19589
3
    sf->cur_sp = sf->var_buf + b->var_count;
19590
3
    for(i = 0; i < argc; i++)
19591
0
        sf->arg_buf[i] = JS_DupValue(ctx, argv[i]);
19592
3
    n = arg_buf_len + b->var_count;
19593
3
    for(i = argc; i < n; i++)
19594
3
        sf->arg_buf[i] = JS_UNDEFINED;
19595
3
    s->resolving_funcs[0] = JS_UNDEFINED;
19596
3
    s->resolving_funcs[1] = JS_UNDEFINED;
19597
3
    s->is_completed = FALSE;
19598
3
    return s;
19599
3
}
19600
19601
static void async_func_free_frame(JSRuntime *rt, JSAsyncFunctionState *s)
19602
3
{
19603
3
    JSStackFrame *sf = &s->frame;
19604
3
    JSValue *sp;
19605
19606
3
    if (sf->arg_buf) {
19607
        /* cannot free the function if it is running */
19608
3
        assert(sf->cur_sp != NULL);
19609
5
        for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) {
19610
2
            JS_FreeValueRT(rt, *sp);
19611
2
        }
19612
3
        js_free_rt(rt, sf->arg_buf);
19613
3
        sf->arg_buf = NULL;
19614
3
    }
19615
3
    JS_FreeValueRT(rt, sf->cur_func);
19616
3
    JS_FreeValueRT(rt, s->this_val);
19617
3
}
19618
19619
static JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s)
19620
3
{
19621
3
    JSRuntime *rt = ctx->rt;
19622
3
    JSStackFrame *sf = &s->frame;
19623
3
    JSValue func_obj, ret;
19624
19625
3
    assert(!s->is_completed);
19626
3
    if (js_check_stack_overflow(ctx->rt, 0)) {
19627
0
        ret = JS_ThrowStackOverflow(ctx);
19628
3
    } else {
19629
        /* the tag does not matter provided it is not an object */
19630
3
        func_obj = JS_MKPTR(JS_TAG_INT, s);
19631
3
        ret = JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED,
19632
3
                              s->argc, sf->arg_buf, JS_CALL_FLAG_GENERATOR);
19633
3
    }
19634
3
    if (JS_IsException(ret) || JS_IsUndefined(ret)) {
19635
3
        if (JS_IsUndefined(ret)) {
19636
2
            ret = sf->cur_sp[-1];
19637
2
            sf->cur_sp[-1] = JS_UNDEFINED;
19638
2
        }
19639
        /* end of execution */
19640
3
        s->is_completed = TRUE;
19641
19642
        /* close the closure variables. */
19643
3
        close_var_refs(rt, sf);
19644
19645
3
        async_func_free_frame(rt, s);
19646
3
    }
19647
3
    return ret;
19648
3
}
19649
19650
static void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
19651
3
{
19652
    /* cannot close the closure variables here because it would
19653
       potentially modify the object graph */
19654
3
    if (!s->is_completed) {
19655
0
        async_func_free_frame(rt, s);
19656
0
    }
19657
19658
3
    JS_FreeValueRT(rt, s->resolving_funcs[0]);
19659
3
    JS_FreeValueRT(rt, s->resolving_funcs[1]);
19660
19661
3
    remove_gc_object(&s->header);
19662
3
    if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && s->header.ref_count != 0) {
19663
0
        list_add_tail(&s->header.link, &rt->gc_zero_ref_count_list);
19664
3
    } else {
19665
3
        js_free_rt(rt, s);
19666
3
    }
19667
3
}
19668
19669
static void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)
19670
3
{
19671
3
    if (--s->header.ref_count == 0) {
19672
3
        if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {
19673
3
            list_del(&s->header.link);
19674
3
            list_add(&s->header.link, &rt->gc_zero_ref_count_list);
19675
3
            if (rt->gc_phase == JS_GC_PHASE_NONE) {
19676
3
                free_zero_refcount(rt);
19677
3
            }
19678
3
        }
19679
3
    }
19680
3
}
19681
19682
/* Generators */
19683
19684
typedef enum JSGeneratorStateEnum {
19685
    JS_GENERATOR_STATE_SUSPENDED_START,
19686
    JS_GENERATOR_STATE_SUSPENDED_YIELD,
19687
    JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR,
19688
    JS_GENERATOR_STATE_EXECUTING,
19689
    JS_GENERATOR_STATE_COMPLETED,
19690
} JSGeneratorStateEnum;
19691
19692
typedef struct JSGeneratorData {
19693
    JSGeneratorStateEnum state;
19694
    JSAsyncFunctionState *func_state;
19695
} JSGeneratorData;
19696
19697
static void free_generator_stack_rt(JSRuntime *rt, JSGeneratorData *s)
19698
0
{
19699
0
    if (s->state == JS_GENERATOR_STATE_COMPLETED)
19700
0
        return;
19701
0
    if (s->func_state) {
19702
0
        async_func_free(rt, s->func_state);
19703
0
        s->func_state = NULL;
19704
0
    }
19705
0
    s->state = JS_GENERATOR_STATE_COMPLETED;
19706
0
}
19707
19708
static void js_generator_finalizer(JSRuntime *rt, JSValue obj)
19709
0
{
19710
0
    JSGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_GENERATOR);
19711
19712
0
    if (s) {
19713
0
        free_generator_stack_rt(rt, s);
19714
0
        js_free_rt(rt, s);
19715
0
    }
19716
0
}
19717
19718
static void free_generator_stack(JSContext *ctx, JSGeneratorData *s)
19719
0
{
19720
0
    free_generator_stack_rt(ctx->rt, s);
19721
0
}
19722
19723
static void js_generator_mark(JSRuntime *rt, JSValueConst val,
19724
                              JS_MarkFunc *mark_func)
19725
0
{
19726
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
19727
0
    JSGeneratorData *s = p->u.generator_data;
19728
19729
0
    if (!s || !s->func_state)
19730
0
        return;
19731
0
    mark_func(rt, &s->func_state->header);
19732
0
}
19733
19734
/* XXX: use enum */
19735
0
#define GEN_MAGIC_NEXT   0
19736
0
#define GEN_MAGIC_RETURN 1
19737
0
#define GEN_MAGIC_THROW  2
19738
19739
static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
19740
                                 int argc, JSValueConst *argv,
19741
                                 BOOL *pdone, int magic)
19742
0
{
19743
0
    JSGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_GENERATOR);
19744
0
    JSStackFrame *sf;
19745
0
    JSValue ret, func_ret;
19746
19747
0
    *pdone = TRUE;
19748
0
    if (!s)
19749
0
        return JS_ThrowTypeError(ctx, "not a generator");
19750
0
    switch(s->state) {
19751
0
    default:
19752
0
    case JS_GENERATOR_STATE_SUSPENDED_START:
19753
0
        sf = &s->func_state->frame;
19754
0
        if (magic == GEN_MAGIC_NEXT) {
19755
0
            goto exec_no_arg;
19756
0
        } else {
19757
0
            free_generator_stack(ctx, s);
19758
0
            goto done;
19759
0
        }
19760
0
        break;
19761
0
    case JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
19762
0
    case JS_GENERATOR_STATE_SUSPENDED_YIELD:
19763
0
        sf = &s->func_state->frame;
19764
        /* cur_sp[-1] was set to JS_UNDEFINED in the previous call */
19765
0
        ret = JS_DupValue(ctx, argv[0]);
19766
0
        if (magic == GEN_MAGIC_THROW &&
19767
0
            s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) {
19768
0
            JS_Throw(ctx, ret);
19769
0
            s->func_state->throw_flag = TRUE;
19770
0
        } else {
19771
0
            sf->cur_sp[-1] = ret;
19772
0
            sf->cur_sp[0] = JS_NewInt32(ctx, magic);
19773
0
            sf->cur_sp++;
19774
0
        exec_no_arg:
19775
0
            s->func_state->throw_flag = FALSE;
19776
0
        }
19777
0
        s->state = JS_GENERATOR_STATE_EXECUTING;
19778
0
        func_ret = async_func_resume(ctx, s->func_state);
19779
0
        s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD;
19780
0
        if (s->func_state->is_completed) {
19781
            /* finalize the execution in case of exception or normal return */
19782
0
            free_generator_stack(ctx, s);
19783
0
            return func_ret;
19784
0
        } else {
19785
0
            assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT);
19786
            /* get the returned yield value at the top of the stack */
19787
0
            ret = sf->cur_sp[-1];
19788
0
            sf->cur_sp[-1] = JS_UNDEFINED;
19789
0
            if (JS_VALUE_GET_INT(func_ret) == FUNC_RET_YIELD_STAR) {
19790
0
                s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
19791
                /* return (value, done) object */
19792
0
                *pdone = 2;
19793
0
            } else {
19794
0
                *pdone = FALSE;
19795
0
            }
19796
0
        }
19797
0
        break;
19798
0
    case JS_GENERATOR_STATE_COMPLETED:
19799
0
    done:
19800
        /* execution is finished */
19801
0
        switch(magic) {
19802
0
        default:
19803
0
        case GEN_MAGIC_NEXT:
19804
0
            ret = JS_UNDEFINED;
19805
0
            break;
19806
0
        case GEN_MAGIC_RETURN:
19807
0
            ret = JS_DupValue(ctx, argv[0]);
19808
0
            break;
19809
0
        case GEN_MAGIC_THROW:
19810
0
            ret = JS_Throw(ctx, JS_DupValue(ctx, argv[0]));
19811
0
            break;
19812
0
        }
19813
0
        break;
19814
0
    case JS_GENERATOR_STATE_EXECUTING:
19815
0
        ret = JS_ThrowTypeError(ctx, "cannot invoke a running generator");
19816
0
        break;
19817
0
    }
19818
0
    return ret;
19819
0
}
19820
19821
static JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,
19822
                                          JSValueConst this_obj,
19823
                                          int argc, JSValueConst *argv,
19824
                                          int flags)
19825
0
{
19826
0
    JSValue obj, func_ret;
19827
0
    JSGeneratorData *s;
19828
19829
0
    s = js_mallocz(ctx, sizeof(*s));
19830
0
    if (!s)
19831
0
        return JS_EXCEPTION;
19832
0
    s->state = JS_GENERATOR_STATE_SUSPENDED_START;
19833
0
    s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv);
19834
0
    if (!s->func_state) {
19835
0
        s->state = JS_GENERATOR_STATE_COMPLETED;
19836
0
        goto fail;
19837
0
    }
19838
19839
    /* execute the function up to 'OP_initial_yield' */
19840
0
    func_ret = async_func_resume(ctx, s->func_state);
19841
0
    if (JS_IsException(func_ret))
19842
0
        goto fail;
19843
0
    JS_FreeValue(ctx, func_ret);
19844
19845
0
    obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_GENERATOR);
19846
0
    if (JS_IsException(obj))
19847
0
        goto fail;
19848
0
    JS_SetOpaque(obj, s);
19849
0
    return obj;
19850
0
 fail:
19851
0
    free_generator_stack_rt(ctx->rt, s);
19852
0
    js_free(ctx, s);
19853
0
    return JS_EXCEPTION;
19854
0
}
19855
19856
/* AsyncFunction */
19857
19858
static void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val)
19859
0
{
19860
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
19861
0
    JSAsyncFunctionState *s = p->u.async_function_data;
19862
0
    if (s) {
19863
0
        async_func_free(rt, s);
19864
0
    }
19865
0
}
19866
19867
static void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,
19868
                                           JS_MarkFunc *mark_func)
19869
0
{
19870
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
19871
0
    JSAsyncFunctionState *s = p->u.async_function_data;
19872
0
    if (s) {
19873
0
        mark_func(rt, &s->header);
19874
0
    }
19875
0
}
19876
19877
static int js_async_function_resolve_create(JSContext *ctx,
19878
                                            JSAsyncFunctionState *s,
19879
                                            JSValue *resolving_funcs)
19880
0
{
19881
0
    int i;
19882
0
    JSObject *p;
19883
19884
0
    for(i = 0; i < 2; i++) {
19885
0
        resolving_funcs[i] =
19886
0
            JS_NewObjectProtoClass(ctx, ctx->function_proto,
19887
0
                                   JS_CLASS_ASYNC_FUNCTION_RESOLVE + i);
19888
0
        if (JS_IsException(resolving_funcs[i])) {
19889
0
            if (i == 1)
19890
0
                JS_FreeValue(ctx, resolving_funcs[0]);
19891
0
            return -1;
19892
0
        }
19893
0
        p = JS_VALUE_GET_OBJ(resolving_funcs[i]);
19894
0
        s->header.ref_count++;
19895
0
        p->u.async_function_data = s;
19896
0
    }
19897
0
    return 0;
19898
0
}
19899
19900
static void js_async_function_resume(JSContext *ctx, JSAsyncFunctionState *s)
19901
3
{
19902
3
    JSValue func_ret, ret2;
19903
19904
3
    func_ret = async_func_resume(ctx, s);
19905
3
    if (s->is_completed) {
19906
3
        if (JS_IsException(func_ret)) {
19907
1
            JSValue error;
19908
1
        fail:
19909
1
            error = JS_GetException(ctx);
19910
1
            ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED,
19911
1
                           1, (JSValueConst *)&error);
19912
1
            JS_FreeValue(ctx, error);
19913
1
            JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
19914
2
        } else {
19915
            /* normal return */
19916
2
            ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED,
19917
2
                           1, (JSValueConst *)&func_ret);
19918
2
            JS_FreeValue(ctx, func_ret);
19919
2
            JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */
19920
2
        }
19921
3
    } else {
19922
0
        JSValue value, promise, resolving_funcs[2], resolving_funcs1[2];
19923
0
        int i, res;
19924
19925
0
        value = s->frame.cur_sp[-1];
19926
0
        s->frame.cur_sp[-1] = JS_UNDEFINED;
19927
19928
        /* await */
19929
0
        JS_FreeValue(ctx, func_ret); /* not used */
19930
0
        promise = js_promise_resolve(ctx, ctx->promise_ctor,
19931
0
                                     1, (JSValueConst *)&value, 0);
19932
0
        JS_FreeValue(ctx, value);
19933
0
        if (JS_IsException(promise))
19934
0
            goto fail;
19935
0
        if (js_async_function_resolve_create(ctx, s, resolving_funcs)) {
19936
0
            JS_FreeValue(ctx, promise);
19937
0
            goto fail;
19938
0
        }
19939
19940
        /* Note: no need to create 'thrownawayCapability' as in
19941
           the spec */
19942
0
        for(i = 0; i < 2; i++)
19943
0
            resolving_funcs1[i] = JS_UNDEFINED;
19944
0
        res = perform_promise_then(ctx, promise,
19945
0
                                   (JSValueConst *)resolving_funcs,
19946
0
                                   (JSValueConst *)resolving_funcs1);
19947
0
        JS_FreeValue(ctx, promise);
19948
0
        for(i = 0; i < 2; i++)
19949
0
            JS_FreeValue(ctx, resolving_funcs[i]);
19950
0
        if (res)
19951
0
            goto fail;
19952
0
    }
19953
3
}
19954
19955
static JSValue js_async_function_resolve_call(JSContext *ctx,
19956
                                              JSValueConst func_obj,
19957
                                              JSValueConst this_obj,
19958
                                              int argc, JSValueConst *argv,
19959
                                              int flags)
19960
0
{
19961
0
    JSObject *p = JS_VALUE_GET_OBJ(func_obj);
19962
0
    JSAsyncFunctionState *s = p->u.async_function_data;
19963
0
    BOOL is_reject = p->class_id - JS_CLASS_ASYNC_FUNCTION_RESOLVE;
19964
0
    JSValueConst arg;
19965
19966
0
    if (argc > 0)
19967
0
        arg = argv[0];
19968
0
    else
19969
0
        arg = JS_UNDEFINED;
19970
0
    s->throw_flag = is_reject;
19971
0
    if (is_reject) {
19972
0
        JS_Throw(ctx, JS_DupValue(ctx, arg));
19973
0
    } else {
19974
        /* return value of await */
19975
0
        s->frame.cur_sp[-1] = JS_DupValue(ctx, arg);
19976
0
    }
19977
0
    js_async_function_resume(ctx, s);
19978
0
    return JS_UNDEFINED;
19979
0
}
19980
19981
static JSValue js_async_function_call(JSContext *ctx, JSValueConst func_obj,
19982
                                      JSValueConst this_obj,
19983
                                      int argc, JSValueConst *argv, int flags)
19984
3
{
19985
3
    JSValue promise;
19986
3
    JSAsyncFunctionState *s;
19987
19988
3
    s = async_func_init(ctx, func_obj, this_obj, argc, argv);
19989
3
    if (!s)
19990
0
        return JS_EXCEPTION;
19991
19992
3
    promise = JS_NewPromiseCapability(ctx, s->resolving_funcs);
19993
3
    if (JS_IsException(promise)) {
19994
0
        async_func_free(ctx->rt, s);
19995
0
        return JS_EXCEPTION;
19996
0
    }
19997
19998
3
    js_async_function_resume(ctx, s);
19999
20000
3
    async_func_free(ctx->rt, s);
20001
20002
3
    return promise;
20003
3
}
20004
20005
/* AsyncGenerator */
20006
20007
typedef enum JSAsyncGeneratorStateEnum {
20008
    JS_ASYNC_GENERATOR_STATE_SUSPENDED_START,
20009
    JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD,
20010
    JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR,
20011
    JS_ASYNC_GENERATOR_STATE_EXECUTING,
20012
    JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN,
20013
    JS_ASYNC_GENERATOR_STATE_COMPLETED,
20014
} JSAsyncGeneratorStateEnum;
20015
20016
typedef struct JSAsyncGeneratorRequest {
20017
    struct list_head link;
20018
    /* completion */
20019
    int completion_type; /* GEN_MAGIC_x */
20020
    JSValue result;
20021
    /* promise capability */
20022
    JSValue promise;
20023
    JSValue resolving_funcs[2];
20024
} JSAsyncGeneratorRequest;
20025
20026
typedef struct JSAsyncGeneratorData {
20027
    JSObject *generator; /* back pointer to the object (const) */
20028
    JSAsyncGeneratorStateEnum state;
20029
    /* func_state is NULL is state AWAITING_RETURN and COMPLETED */
20030
    JSAsyncFunctionState *func_state;
20031
    struct list_head queue; /* list of JSAsyncGeneratorRequest.link */
20032
} JSAsyncGeneratorData;
20033
20034
static void js_async_generator_free(JSRuntime *rt,
20035
                                    JSAsyncGeneratorData *s)
20036
0
{
20037
0
    struct list_head *el, *el1;
20038
0
    JSAsyncGeneratorRequest *req;
20039
20040
0
    list_for_each_safe(el, el1, &s->queue) {
20041
0
        req = list_entry(el, JSAsyncGeneratorRequest, link);
20042
0
        JS_FreeValueRT(rt, req->result);
20043
0
        JS_FreeValueRT(rt, req->promise);
20044
0
        JS_FreeValueRT(rt, req->resolving_funcs[0]);
20045
0
        JS_FreeValueRT(rt, req->resolving_funcs[1]);
20046
0
        js_free_rt(rt, req);
20047
0
    }
20048
0
    if (s->func_state)
20049
0
        async_func_free(rt, s->func_state);
20050
0
    js_free_rt(rt, s);
20051
0
}
20052
20053
static void js_async_generator_finalizer(JSRuntime *rt, JSValue obj)
20054
0
{
20055
0
    JSAsyncGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_ASYNC_GENERATOR);
20056
20057
0
    if (s) {
20058
0
        js_async_generator_free(rt, s);
20059
0
    }
20060
0
}
20061
20062
static void js_async_generator_mark(JSRuntime *rt, JSValueConst val,
20063
                                    JS_MarkFunc *mark_func)
20064
0
{
20065
0
    JSAsyncGeneratorData *s = JS_GetOpaque(val, JS_CLASS_ASYNC_GENERATOR);
20066
0
    struct list_head *el;
20067
0
    JSAsyncGeneratorRequest *req;
20068
0
    if (s) {
20069
0
        list_for_each(el, &s->queue) {
20070
0
            req = list_entry(el, JSAsyncGeneratorRequest, link);
20071
0
            JS_MarkValue(rt, req->result, mark_func);
20072
0
            JS_MarkValue(rt, req->promise, mark_func);
20073
0
            JS_MarkValue(rt, req->resolving_funcs[0], mark_func);
20074
0
            JS_MarkValue(rt, req->resolving_funcs[1], mark_func);
20075
0
        }
20076
0
        if (s->func_state) {
20077
0
            mark_func(rt, &s->func_state->header);
20078
0
        }
20079
0
    }
20080
0
}
20081
20082
static JSValue js_async_generator_resolve_function(JSContext *ctx,
20083
                                          JSValueConst this_obj,
20084
                                          int argc, JSValueConst *argv,
20085
                                          int magic, JSValue *func_data);
20086
20087
static int js_async_generator_resolve_function_create(JSContext *ctx,
20088
                                                      JSValueConst generator,
20089
                                                      JSValue *resolving_funcs,
20090
                                                      BOOL is_resume_next)
20091
0
{
20092
0
    int i;
20093
0
    JSValue func;
20094
20095
0
    for(i = 0; i < 2; i++) {
20096
0
        func = JS_NewCFunctionData(ctx, js_async_generator_resolve_function, 1,
20097
0
                                   i + is_resume_next * 2, 1, &generator);
20098
0
        if (JS_IsException(func)) {
20099
0
            if (i == 1)
20100
0
                JS_FreeValue(ctx, resolving_funcs[0]);
20101
0
            return -1;
20102
0
        }
20103
0
        resolving_funcs[i] = func;
20104
0
    }
20105
0
    return 0;
20106
0
}
20107
20108
static int js_async_generator_await(JSContext *ctx,
20109
                                    JSAsyncGeneratorData *s,
20110
                                    JSValueConst value)
20111
0
{
20112
0
    JSValue promise, resolving_funcs[2], resolving_funcs1[2];
20113
0
    int i, res;
20114
20115
0
    promise = js_promise_resolve(ctx, ctx->promise_ctor,
20116
0
                                 1, &value, 0);
20117
0
    if (JS_IsException(promise))
20118
0
        goto fail;
20119
20120
0
    if (js_async_generator_resolve_function_create(ctx, JS_MKPTR(JS_TAG_OBJECT, s->generator),
20121
0
                                                   resolving_funcs, FALSE)) {
20122
0
        JS_FreeValue(ctx, promise);
20123
0
        goto fail;
20124
0
    }
20125
20126
    /* Note: no need to create 'thrownawayCapability' as in
20127
       the spec */
20128
0
    for(i = 0; i < 2; i++)
20129
0
        resolving_funcs1[i] = JS_UNDEFINED;
20130
0
    res = perform_promise_then(ctx, promise,
20131
0
                               (JSValueConst *)resolving_funcs,
20132
0
                               (JSValueConst *)resolving_funcs1);
20133
0
    JS_FreeValue(ctx, promise);
20134
0
    for(i = 0; i < 2; i++)
20135
0
        JS_FreeValue(ctx, resolving_funcs[i]);
20136
0
    if (res)
20137
0
        goto fail;
20138
0
    return 0;
20139
0
 fail:
20140
0
    return -1;
20141
0
}
20142
20143
static void js_async_generator_resolve_or_reject(JSContext *ctx,
20144
                                                 JSAsyncGeneratorData *s,
20145
                                                 JSValueConst result,
20146
                                                 int is_reject)
20147
0
{
20148
0
    JSAsyncGeneratorRequest *next;
20149
0
    JSValue ret;
20150
20151
0
    next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link);
20152
0
    list_del(&next->link);
20153
0
    ret = JS_Call(ctx, next->resolving_funcs[is_reject], JS_UNDEFINED, 1,
20154
0
                  &result);
20155
0
    JS_FreeValue(ctx, ret);
20156
0
    JS_FreeValue(ctx, next->result);
20157
0
    JS_FreeValue(ctx, next->promise);
20158
0
    JS_FreeValue(ctx, next->resolving_funcs[0]);
20159
0
    JS_FreeValue(ctx, next->resolving_funcs[1]);
20160
0
    js_free(ctx, next);
20161
0
}
20162
20163
static void js_async_generator_resolve(JSContext *ctx,
20164
                                       JSAsyncGeneratorData *s,
20165
                                       JSValueConst value,
20166
                                       BOOL done)
20167
0
{
20168
0
    JSValue result;
20169
0
    result = js_create_iterator_result(ctx, JS_DupValue(ctx, value), done);
20170
    /* XXX: better exception handling ? */
20171
0
    js_async_generator_resolve_or_reject(ctx, s, result, 0);
20172
0
    JS_FreeValue(ctx, result);
20173
0
 }
20174
20175
static void js_async_generator_reject(JSContext *ctx,
20176
                                       JSAsyncGeneratorData *s,
20177
                                       JSValueConst exception)
20178
0
{
20179
0
    js_async_generator_resolve_or_reject(ctx, s, exception, 1);
20180
0
}
20181
20182
static void js_async_generator_complete(JSContext *ctx,
20183
                                        JSAsyncGeneratorData *s)
20184
0
{
20185
0
    if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED) {
20186
0
        s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
20187
0
        async_func_free(ctx->rt, s->func_state);
20188
0
        s->func_state = NULL;
20189
0
    }
20190
0
}
20191
20192
static int js_async_generator_completed_return(JSContext *ctx,
20193
                                               JSAsyncGeneratorData *s,
20194
                                               JSValueConst value)
20195
0
{
20196
0
    JSValue promise, resolving_funcs[2], resolving_funcs1[2];
20197
0
    int res;
20198
20199
    // Can fail looking up JS_ATOM_constructor when is_reject==0.
20200
0
    promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, &value,
20201
0
                                 /*is_reject*/0);
20202
    // A poisoned .constructor property is observable and the resulting
20203
    // exception should be delivered to the catch handler.
20204
0
    if (JS_IsException(promise)) {
20205
0
        JSValue err = JS_GetException(ctx);
20206
0
        promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, (JSValueConst *)&err,
20207
0
                                     /*is_reject*/1);
20208
0
        JS_FreeValue(ctx, err);
20209
0
        if (JS_IsException(promise))
20210
0
            return -1;
20211
0
    }
20212
0
    if (js_async_generator_resolve_function_create(ctx,
20213
0
                                                   JS_MKPTR(JS_TAG_OBJECT, s->generator),
20214
0
                                                   resolving_funcs1,
20215
0
                                                   TRUE)) {
20216
0
        JS_FreeValue(ctx, promise);
20217
0
        return -1;
20218
0
    }
20219
0
    resolving_funcs[0] = JS_UNDEFINED;
20220
0
    resolving_funcs[1] = JS_UNDEFINED;
20221
0
    res = perform_promise_then(ctx, promise,
20222
0
                               (JSValueConst *)resolving_funcs1,
20223
0
                               (JSValueConst *)resolving_funcs);
20224
0
    JS_FreeValue(ctx, resolving_funcs1[0]);
20225
0
    JS_FreeValue(ctx, resolving_funcs1[1]);
20226
0
    JS_FreeValue(ctx, promise);
20227
0
    return res;
20228
0
}
20229
20230
static void js_async_generator_resume_next(JSContext *ctx,
20231
                                           JSAsyncGeneratorData *s)
20232
0
{
20233
0
    JSAsyncGeneratorRequest *next;
20234
0
    JSValue func_ret, value;
20235
20236
0
    for(;;) {
20237
0
        if (list_empty(&s->queue))
20238
0
            break;
20239
0
        next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link);
20240
0
        switch(s->state) {
20241
0
        case JS_ASYNC_GENERATOR_STATE_EXECUTING:
20242
            /* only happens when restarting execution after await() */
20243
0
            goto resume_exec;
20244
0
        case JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN:
20245
0
            goto done;
20246
0
        case JS_ASYNC_GENERATOR_STATE_SUSPENDED_START:
20247
0
            if (next->completion_type == GEN_MAGIC_NEXT) {
20248
0
                goto exec_no_arg;
20249
0
            } else {
20250
0
                js_async_generator_complete(ctx, s);
20251
0
            }
20252
0
            break;
20253
0
        case JS_ASYNC_GENERATOR_STATE_COMPLETED:
20254
0
            if (next->completion_type == GEN_MAGIC_NEXT) {
20255
0
                js_async_generator_resolve(ctx, s, JS_UNDEFINED, TRUE);
20256
0
            } else if (next->completion_type == GEN_MAGIC_RETURN) {
20257
0
                s->state = JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN;
20258
0
                js_async_generator_completed_return(ctx, s, next->result);
20259
0
            } else {
20260
0
                js_async_generator_reject(ctx, s, next->result);
20261
0
            }
20262
0
            goto done;
20263
0
        case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD:
20264
0
        case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
20265
0
            value = JS_DupValue(ctx, next->result);
20266
0
            if (next->completion_type == GEN_MAGIC_THROW &&
20267
0
                s->state == JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD) {
20268
0
                JS_Throw(ctx, value);
20269
0
                s->func_state->throw_flag = TRUE;
20270
0
            } else {
20271
                /* 'yield' returns a value. 'yield *' also returns a value
20272
                   in case the 'throw' method is called */
20273
0
                s->func_state->frame.cur_sp[-1] = value;
20274
0
                s->func_state->frame.cur_sp[0] =
20275
0
                    JS_NewInt32(ctx, next->completion_type);
20276
0
                s->func_state->frame.cur_sp++;
20277
0
            exec_no_arg:
20278
0
                s->func_state->throw_flag = FALSE;
20279
0
            }
20280
0
            s->state = JS_ASYNC_GENERATOR_STATE_EXECUTING;
20281
0
        resume_exec:
20282
0
            func_ret = async_func_resume(ctx, s->func_state);
20283
0
            if (s->func_state->is_completed) {
20284
0
                if (JS_IsException(func_ret)) {
20285
0
                    value = JS_GetException(ctx);
20286
0
                    js_async_generator_complete(ctx, s);
20287
0
                    js_async_generator_reject(ctx, s, value);
20288
0
                    JS_FreeValue(ctx, value);
20289
0
                } else {
20290
                    /* end of function */
20291
0
                    js_async_generator_complete(ctx, s);
20292
0
                    js_async_generator_resolve(ctx, s, func_ret, TRUE);
20293
0
                    JS_FreeValue(ctx, func_ret);
20294
0
                }
20295
0
            } else {
20296
0
                int func_ret_code, ret;
20297
0
                assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT);
20298
0
                func_ret_code = JS_VALUE_GET_INT(func_ret);
20299
0
                value = s->func_state->frame.cur_sp[-1];
20300
0
                s->func_state->frame.cur_sp[-1] = JS_UNDEFINED;
20301
0
                switch(func_ret_code) {
20302
0
                case FUNC_RET_YIELD:
20303
0
                case FUNC_RET_YIELD_STAR:
20304
0
                    if (func_ret_code == FUNC_RET_YIELD_STAR)
20305
0
                        s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
20306
0
                    else
20307
0
                        s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD;
20308
0
                    js_async_generator_resolve(ctx, s, value, FALSE);
20309
0
                    JS_FreeValue(ctx, value);
20310
0
                    break;
20311
0
                case FUNC_RET_AWAIT:
20312
0
                    ret = js_async_generator_await(ctx, s, value);
20313
0
                    JS_FreeValue(ctx, value);
20314
0
                    if (ret < 0) {
20315
                        /* exception: throw it */
20316
0
                        s->func_state->throw_flag = TRUE;
20317
0
                        goto resume_exec;
20318
0
                    }
20319
0
                    goto done;
20320
0
                default:
20321
0
                    abort();
20322
0
                }
20323
0
            }
20324
0
            break;
20325
0
        default:
20326
0
            abort();
20327
0
        }
20328
0
    }
20329
0
 done: ;
20330
0
}
20331
20332
static JSValue js_async_generator_resolve_function(JSContext *ctx,
20333
                                                   JSValueConst this_obj,
20334
                                                   int argc, JSValueConst *argv,
20335
                                                   int magic, JSValue *func_data)
20336
0
{
20337
0
    BOOL is_reject = magic & 1;
20338
0
    JSAsyncGeneratorData *s = JS_GetOpaque(func_data[0], JS_CLASS_ASYNC_GENERATOR);
20339
0
    JSValueConst arg = argv[0];
20340
20341
    /* XXX: what if s == NULL */
20342
20343
0
    if (magic >= 2) {
20344
        /* resume next case in AWAITING_RETURN state */
20345
0
        assert(s->state == JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN ||
20346
0
               s->state == JS_ASYNC_GENERATOR_STATE_COMPLETED);
20347
0
        s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;
20348
0
        if (is_reject) {
20349
0
            js_async_generator_reject(ctx, s, arg);
20350
0
        } else {
20351
0
            js_async_generator_resolve(ctx, s, arg, TRUE);
20352
0
        }
20353
0
    } else {
20354
        /* restart function execution after await() */
20355
0
        assert(s->state == JS_ASYNC_GENERATOR_STATE_EXECUTING);
20356
0
        s->func_state->throw_flag = is_reject;
20357
0
        if (is_reject) {
20358
0
            JS_Throw(ctx, JS_DupValue(ctx, arg));
20359
0
        } else {
20360
            /* return value of await */
20361
0
            s->func_state->frame.cur_sp[-1] = JS_DupValue(ctx, arg);
20362
0
        }
20363
0
        js_async_generator_resume_next(ctx, s);
20364
0
    }
20365
0
    return JS_UNDEFINED;
20366
0
}
20367
20368
/* magic = GEN_MAGIC_x */
20369
static JSValue js_async_generator_next(JSContext *ctx, JSValueConst this_val,
20370
                                       int argc, JSValueConst *argv,
20371
                                       int magic)
20372
0
{
20373
0
    JSAsyncGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_GENERATOR);
20374
0
    JSValue promise, resolving_funcs[2];
20375
0
    JSAsyncGeneratorRequest *req;
20376
20377
0
    promise = JS_NewPromiseCapability(ctx, resolving_funcs);
20378
0
    if (JS_IsException(promise))
20379
0
        return JS_EXCEPTION;
20380
0
    if (!s) {
20381
0
        JSValue err, res2;
20382
0
        JS_ThrowTypeError(ctx, "not an AsyncGenerator object");
20383
0
        err = JS_GetException(ctx);
20384
0
        res2 = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
20385
0
                       1, (JSValueConst *)&err);
20386
0
        JS_FreeValue(ctx, err);
20387
0
        JS_FreeValue(ctx, res2);
20388
0
        JS_FreeValue(ctx, resolving_funcs[0]);
20389
0
        JS_FreeValue(ctx, resolving_funcs[1]);
20390
0
        return promise;
20391
0
    }
20392
0
    req = js_mallocz(ctx, sizeof(*req));
20393
0
    if (!req)
20394
0
        goto fail;
20395
0
    req->completion_type = magic;
20396
0
    req->result = JS_DupValue(ctx, argv[0]);
20397
0
    req->promise = JS_DupValue(ctx, promise);
20398
0
    req->resolving_funcs[0] = resolving_funcs[0];
20399
0
    req->resolving_funcs[1] = resolving_funcs[1];
20400
0
    list_add_tail(&req->link, &s->queue);
20401
0
    if (s->state != JS_ASYNC_GENERATOR_STATE_EXECUTING) {
20402
0
        js_async_generator_resume_next(ctx, s);
20403
0
    }
20404
0
    return promise;
20405
0
 fail:
20406
0
    JS_FreeValue(ctx, resolving_funcs[0]);
20407
0
    JS_FreeValue(ctx, resolving_funcs[1]);
20408
0
    JS_FreeValue(ctx, promise);
20409
0
    return JS_EXCEPTION;
20410
0
}
20411
20412
static JSValue js_async_generator_function_call(JSContext *ctx, JSValueConst func_obj,
20413
                                                JSValueConst this_obj,
20414
                                                int argc, JSValueConst *argv,
20415
                                                int flags)
20416
0
{
20417
0
    JSValue obj, func_ret;
20418
0
    JSAsyncGeneratorData *s;
20419
20420
0
    s = js_mallocz(ctx, sizeof(*s));
20421
0
    if (!s)
20422
0
        return JS_EXCEPTION;
20423
0
    s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_START;
20424
0
    init_list_head(&s->queue);
20425
0
    s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv);
20426
0
    if (!s->func_state)
20427
0
        goto fail;
20428
    /* execute the function up to 'OP_initial_yield' (no yield nor
20429
       await are possible) */
20430
0
    func_ret = async_func_resume(ctx, s->func_state);
20431
0
    if (JS_IsException(func_ret))
20432
0
        goto fail;
20433
0
    JS_FreeValue(ctx, func_ret);
20434
20435
0
    obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_ASYNC_GENERATOR);
20436
0
    if (JS_IsException(obj))
20437
0
        goto fail;
20438
0
    s->generator = JS_VALUE_GET_OBJ(obj);
20439
0
    JS_SetOpaque(obj, s);
20440
0
    return obj;
20441
0
 fail:
20442
0
    js_async_generator_free(ctx->rt, s);
20443
0
    return JS_EXCEPTION;
20444
0
}
20445
20446
/* JS parser */
20447
20448
enum {
20449
    TOK_NUMBER = -128,
20450
    TOK_STRING,
20451
    TOK_TEMPLATE,
20452
    TOK_IDENT,
20453
    TOK_REGEXP,
20454
    /* warning: order matters (see js_parse_assign_expr) */
20455
    TOK_MUL_ASSIGN,
20456
    TOK_DIV_ASSIGN,
20457
    TOK_MOD_ASSIGN,
20458
    TOK_PLUS_ASSIGN,
20459
    TOK_MINUS_ASSIGN,
20460
    TOK_SHL_ASSIGN,
20461
    TOK_SAR_ASSIGN,
20462
    TOK_SHR_ASSIGN,
20463
    TOK_AND_ASSIGN,
20464
    TOK_XOR_ASSIGN,
20465
    TOK_OR_ASSIGN,
20466
    TOK_POW_ASSIGN,
20467
    TOK_LAND_ASSIGN,
20468
    TOK_LOR_ASSIGN,
20469
    TOK_DOUBLE_QUESTION_MARK_ASSIGN,
20470
    TOK_DEC,
20471
    TOK_INC,
20472
    TOK_SHL,
20473
    TOK_SAR,
20474
    TOK_SHR,
20475
    TOK_LT,
20476
    TOK_LTE,
20477
    TOK_GT,
20478
    TOK_GTE,
20479
    TOK_EQ,
20480
    TOK_STRICT_EQ,
20481
    TOK_NEQ,
20482
    TOK_STRICT_NEQ,
20483
    TOK_LAND,
20484
    TOK_LOR,
20485
    TOK_POW,
20486
    TOK_ARROW,
20487
    TOK_ELLIPSIS,
20488
    TOK_DOUBLE_QUESTION_MARK,
20489
    TOK_QUESTION_MARK_DOT,
20490
    TOK_ERROR,
20491
    TOK_PRIVATE_NAME,
20492
    TOK_EOF,
20493
    /* keywords: WARNING: same order as atoms */
20494
    TOK_NULL, /* must be first */
20495
    TOK_FALSE,
20496
    TOK_TRUE,
20497
    TOK_IF,
20498
    TOK_ELSE,
20499
    TOK_RETURN,
20500
    TOK_VAR,
20501
    TOK_THIS,
20502
    TOK_DELETE,
20503
    TOK_VOID,
20504
    TOK_TYPEOF,
20505
    TOK_NEW,
20506
    TOK_IN,
20507
    TOK_INSTANCEOF,
20508
    TOK_DO,
20509
    TOK_WHILE,
20510
    TOK_FOR,
20511
    TOK_BREAK,
20512
    TOK_CONTINUE,
20513
    TOK_SWITCH,
20514
    TOK_CASE,
20515
    TOK_DEFAULT,
20516
    TOK_THROW,
20517
    TOK_TRY,
20518
    TOK_CATCH,
20519
    TOK_FINALLY,
20520
    TOK_FUNCTION,
20521
    TOK_DEBUGGER,
20522
    TOK_WITH,
20523
    /* FutureReservedWord */
20524
    TOK_CLASS,
20525
    TOK_CONST,
20526
    TOK_ENUM,
20527
    TOK_EXPORT,
20528
    TOK_EXTENDS,
20529
    TOK_IMPORT,
20530
    TOK_SUPER,
20531
    /* FutureReservedWords when parsing strict mode code */
20532
    TOK_IMPLEMENTS,
20533
    TOK_INTERFACE,
20534
    TOK_LET,
20535
    TOK_PACKAGE,
20536
    TOK_PRIVATE,
20537
    TOK_PROTECTED,
20538
    TOK_PUBLIC,
20539
    TOK_STATIC,
20540
    TOK_YIELD,
20541
    TOK_AWAIT, /* must be last */
20542
    TOK_OF,     /* only used for js_parse_skip_parens_token() */
20543
};
20544
20545
68
#define TOK_FIRST_KEYWORD   TOK_NULL
20546
31
#define TOK_LAST_KEYWORD    TOK_AWAIT
20547
20548
/* unicode code points */
20549
#define CP_NBSP 0x00a0
20550
#define CP_BOM  0xfeff
20551
20552
0
#define CP_LS   0x2028
20553
0
#define CP_PS   0x2029
20554
20555
typedef struct BlockEnv {
20556
    struct BlockEnv *prev;
20557
    JSAtom label_name; /* JS_ATOM_NULL if none */
20558
    int label_break; /* -1 if none */
20559
    int label_cont; /* -1 if none */
20560
    int drop_count; /* number of stack elements to drop */
20561
    int label_finally; /* -1 if none */
20562
    int scope_level;
20563
    uint8_t has_iterator : 1;
20564
    uint8_t is_regular_stmt : 1; /* i.e. not a loop statement */
20565
} BlockEnv;
20566
20567
typedef struct JSGlobalVar {
20568
    int cpool_idx; /* if >= 0, index in the constant pool for hoisted
20569
                      function defintion*/
20570
    uint8_t force_init : 1; /* force initialization to undefined */
20571
    uint8_t is_lexical : 1; /* global let/const definition */
20572
    uint8_t is_const   : 1; /* const definition */
20573
    int scope_level;    /* scope of definition */
20574
    JSAtom var_name;  /* variable name */
20575
} JSGlobalVar;
20576
20577
typedef struct RelocEntry {
20578
    struct RelocEntry *next;
20579
    uint32_t addr; /* address to patch */
20580
    int size;   /* address size: 1, 2 or 4 bytes */
20581
} RelocEntry;
20582
20583
typedef struct JumpSlot {
20584
    int op;
20585
    int size;
20586
    int pos;
20587
    int label;
20588
} JumpSlot;
20589
20590
typedef struct LabelSlot {
20591
    int ref_count;
20592
    int pos;    /* phase 1 address, -1 means not resolved yet */
20593
    int pos2;   /* phase 2 address, -1 means not resolved yet */
20594
    int addr;   /* phase 3 address, -1 means not resolved yet */
20595
    RelocEntry *first_reloc;
20596
} LabelSlot;
20597
20598
typedef struct LineNumberSlot {
20599
    uint32_t pc;
20600
    uint32_t source_pos;
20601
} LineNumberSlot;
20602
20603
typedef struct {
20604
    /* last source position */
20605
    const uint8_t *ptr;
20606
    int line_num;
20607
    int col_num;
20608
    const uint8_t *buf_start;
20609
} GetLineColCache;
20610
20611
typedef enum JSParseFunctionEnum {
20612
    JS_PARSE_FUNC_STATEMENT,
20613
    JS_PARSE_FUNC_VAR,
20614
    JS_PARSE_FUNC_EXPR,
20615
    JS_PARSE_FUNC_ARROW,
20616
    JS_PARSE_FUNC_GETTER,
20617
    JS_PARSE_FUNC_SETTER,
20618
    JS_PARSE_FUNC_METHOD,
20619
    JS_PARSE_FUNC_CLASS_STATIC_INIT,
20620
    JS_PARSE_FUNC_CLASS_CONSTRUCTOR,
20621
    JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR,
20622
} JSParseFunctionEnum;
20623
20624
typedef enum JSParseExportEnum {
20625
    JS_PARSE_EXPORT_NONE,
20626
    JS_PARSE_EXPORT_NAMED,
20627
    JS_PARSE_EXPORT_DEFAULT,
20628
} JSParseExportEnum;
20629
20630
typedef struct JSFunctionDef {
20631
    JSContext *ctx;
20632
    struct JSFunctionDef *parent;
20633
    int parent_cpool_idx; /* index in the constant pool of the parent
20634
                             or -1 if none */
20635
    int parent_scope_level; /* scope level in parent at point of definition */
20636
    struct list_head child_list; /* list of JSFunctionDef.link */
20637
    struct list_head link;
20638
20639
    BOOL is_eval; /* TRUE if eval code */
20640
    int eval_type; /* only valid if is_eval = TRUE */
20641
    BOOL is_global_var; /* TRUE if variables are not defined locally:
20642
                           eval global, eval module or non strict eval */
20643
    BOOL is_func_expr; /* TRUE if function expression */
20644
    BOOL has_home_object; /* TRUE if the home object is available */
20645
    BOOL has_prototype; /* true if a prototype field is necessary */
20646
    BOOL has_simple_parameter_list;
20647
    BOOL has_parameter_expressions; /* if true, an argument scope is created */
20648
    BOOL has_use_strict; /* to reject directive in special cases */
20649
    BOOL has_eval_call; /* true if the function contains a call to eval() */
20650
    BOOL has_arguments_binding; /* true if the 'arguments' binding is
20651
                                   available in the function */
20652
    BOOL has_this_binding; /* true if the 'this' and new.target binding are
20653
                              available in the function */
20654
    BOOL new_target_allowed; /* true if the 'new.target' does not
20655
                                throw a syntax error */
20656
    BOOL super_call_allowed; /* true if super() is allowed */
20657
    BOOL super_allowed; /* true if super. or super[] is allowed */
20658
    BOOL arguments_allowed; /* true if the 'arguments' identifier is allowed */
20659
    BOOL is_derived_class_constructor;
20660
    BOOL in_function_body;
20661
    JSFunctionKindEnum func_kind : 8;
20662
    JSParseFunctionEnum func_type : 8;
20663
    uint8_t js_mode; /* bitmap of JS_MODE_x */
20664
    JSAtom func_name; /* JS_ATOM_NULL if no name */
20665
20666
    JSVarDef *vars;
20667
    int var_size; /* allocated size for vars[] */
20668
    int var_count;
20669
    JSVarDef *args;
20670
    int arg_size; /* allocated size for args[] */
20671
    int arg_count; /* number of arguments */
20672
    int defined_arg_count;
20673
    int var_object_idx; /* -1 if none */
20674
    int arg_var_object_idx; /* -1 if none (var object for the argument scope) */
20675
    int arguments_var_idx; /* -1 if none */
20676
    int arguments_arg_idx; /* argument variable definition in argument scope,
20677
                              -1 if none */
20678
    int func_var_idx; /* variable containing the current function (-1
20679
                         if none, only used if is_func_expr is true) */
20680
    int eval_ret_idx; /* variable containing the return value of the eval, -1 if none */
20681
    int this_var_idx; /* variable containg the 'this' value, -1 if none */
20682
    int new_target_var_idx; /* variable containg the 'new.target' value, -1 if none */
20683
    int this_active_func_var_idx; /* variable containg the 'this.active_func' value, -1 if none */
20684
    int home_object_var_idx;
20685
    BOOL need_home_object;
20686
20687
    int scope_level;    /* index into fd->scopes if the current lexical scope */
20688
    int scope_first;    /* index into vd->vars of first lexically scoped variable */
20689
    int scope_size;     /* allocated size of fd->scopes array */
20690
    int scope_count;    /* number of entries used in the fd->scopes array */
20691
    JSVarScope *scopes;
20692
    JSVarScope def_scope_array[4];
20693
    int body_scope; /* scope of the body of the function or eval */
20694
20695
    int global_var_count;
20696
    int global_var_size;
20697
    JSGlobalVar *global_vars;
20698
20699
    DynBuf byte_code;
20700
    int last_opcode_pos; /* -1 if no last opcode */
20701
    const uint8_t *last_opcode_source_ptr;
20702
    BOOL use_short_opcodes; /* true if short opcodes are used in byte_code */
20703
20704
    LabelSlot *label_slots;
20705
    int label_size; /* allocated size for label_slots[] */
20706
    int label_count;
20707
    BlockEnv *top_break; /* break/continue label stack */
20708
20709
    /* constant pool (strings, functions, numbers) */
20710
    JSValue *cpool;
20711
    int cpool_count;
20712
    int cpool_size;
20713
20714
    /* list of variables in the closure */
20715
    int closure_var_count;
20716
    int closure_var_size;
20717
    JSClosureVar *closure_var;
20718
20719
    JumpSlot *jump_slots;
20720
    int jump_size;
20721
    int jump_count;
20722
20723
    LineNumberSlot *line_number_slots;
20724
    int line_number_size;
20725
    int line_number_count;
20726
    int line_number_last;
20727
    int line_number_last_pc;
20728
20729
    /* pc2line table */
20730
    BOOL strip_debug : 1; /* strip all debug info (implies strip_source = TRUE) */
20731
    BOOL strip_source : 1; /* strip only source code */
20732
    JSAtom filename;
20733
    uint32_t source_pos; /* pointer in the eval() source */
20734
    GetLineColCache *get_line_col_cache; /* XXX: could remove to save memory */
20735
    DynBuf pc2line;
20736
20737
    char *source;  /* raw source, utf-8 encoded */
20738
    int source_len;
20739
20740
    JSModuleDef *module; /* != NULL when parsing a module */
20741
    BOOL has_await; /* TRUE if await is used (used in module eval) */
20742
} JSFunctionDef;
20743
20744
typedef struct JSToken {
20745
    int val;
20746
    const uint8_t *ptr; /* position in the source */
20747
    union {
20748
        struct {
20749
            JSValue str;
20750
            int sep;
20751
        } str;
20752
        struct {
20753
            JSValue val;
20754
        } num;
20755
        struct {
20756
            JSAtom atom;
20757
            BOOL has_escape;
20758
            BOOL is_reserved;
20759
        } ident;
20760
        struct {
20761
            JSValue body;
20762
            JSValue flags;
20763
        } regexp;
20764
    } u;
20765
} JSToken;
20766
20767
typedef struct JSParseState {
20768
    JSContext *ctx;
20769
    const char *filename;
20770
    JSToken token;
20771
    BOOL got_lf; /* true if got line feed before the current token */
20772
    const uint8_t *last_ptr;
20773
    const uint8_t *buf_start;
20774
    const uint8_t *buf_ptr;
20775
    const uint8_t *buf_end;
20776
20777
    /* current function code */
20778
    JSFunctionDef *cur_func;
20779
    BOOL is_module; /* parsing a module */
20780
    BOOL allow_html_comments;
20781
    BOOL ext_json; /* true if accepting JSON superset */
20782
    GetLineColCache get_line_col_cache;
20783
} JSParseState;
20784
20785
typedef struct JSOpCode {
20786
#ifdef DUMP_BYTECODE
20787
    const char *name;
20788
#endif
20789
    uint8_t size; /* in bytes */
20790
    /* the opcodes remove n_pop items from the top of the stack, then
20791
       pushes n_push items */
20792
    uint8_t n_pop;
20793
    uint8_t n_push;
20794
    uint8_t fmt;
20795
} JSOpCode;
20796
20797
static const JSOpCode opcode_info[OP_COUNT + (OP_TEMP_END - OP_TEMP_START)] = {
20798
#define FMT(f)
20799
#ifdef DUMP_BYTECODE
20800
#define DEF(id, size, n_pop, n_push, f) { #id, size, n_pop, n_push, OP_FMT_ ## f },
20801
#else
20802
#define DEF(id, size, n_pop, n_push, f) { size, n_pop, n_push, OP_FMT_ ## f },
20803
#endif
20804
#include "quickjs-opcode.h"
20805
#undef DEF
20806
#undef FMT
20807
};
20808
20809
#if SHORT_OPCODES
20810
/* After the final compilation pass, short opcodes are used. Their
20811
   opcodes overlap with the temporary opcodes which cannot appear in
20812
   the final bytecode. Their description is after the temporary
20813
   opcodes in opcode_info[]. */
20814
#define short_opcode_info(op)           \
20815
114
    opcode_info[(op) >= OP_TEMP_START ? \
20816
114
                (op) + (OP_TEMP_END - OP_TEMP_START) : (op)]
20817
#else
20818
#define short_opcode_info(op) opcode_info[op]
20819
#endif
20820
20821
static __exception int next_token(JSParseState *s);
20822
20823
static void free_token(JSParseState *s, JSToken *token)
20824
64
{
20825
64
    switch(token->val) {
20826
1
    case TOK_NUMBER:
20827
1
        JS_FreeValue(s->ctx, token->u.num.val);
20828
1
        break;
20829
4
    case TOK_STRING:
20830
4
    case TOK_TEMPLATE:
20831
4
        JS_FreeValue(s->ctx, token->u.str.str);
20832
4
        break;
20833
0
    case TOK_REGEXP:
20834
0
        JS_FreeValue(s->ctx, token->u.regexp.body);
20835
0
        JS_FreeValue(s->ctx, token->u.regexp.flags);
20836
0
        break;
20837
27
    case TOK_IDENT:
20838
27
    case TOK_PRIVATE_NAME:
20839
27
        JS_FreeAtom(s->ctx, token->u.ident.atom);
20840
27
        break;
20841
32
    default:
20842
32
        if (token->val >= TOK_FIRST_KEYWORD &&
20843
32
            token->val <= TOK_LAST_KEYWORD) {
20844
4
            JS_FreeAtom(s->ctx, token->u.ident.atom);
20845
4
        }
20846
32
        break;
20847
64
    }
20848
64
}
20849
20850
static void __attribute((unused)) dump_token(JSParseState *s,
20851
                                             const JSToken *token)
20852
0
{
20853
0
    switch(token->val) {
20854
0
    case TOK_NUMBER:
20855
0
        {
20856
0
            double d;
20857
0
            JS_ToFloat64(s->ctx, &d, token->u.num.val);  /* no exception possible */
20858
0
            printf("number: %.14g\n", d);
20859
0
        }
20860
0
        break;
20861
0
    case TOK_IDENT:
20862
0
    dump_atom:
20863
0
        {
20864
0
            char buf[ATOM_GET_STR_BUF_SIZE];
20865
0
            printf("ident: '%s'\n",
20866
0
                   JS_AtomGetStr(s->ctx, buf, sizeof(buf), token->u.ident.atom));
20867
0
        }
20868
0
        break;
20869
0
    case TOK_STRING:
20870
0
        {
20871
0
            const char *str;
20872
0
            /* XXX: quote the string */
20873
0
            str = JS_ToCString(s->ctx, token->u.str.str);
20874
0
            printf("string: '%s'\n", str);
20875
0
            JS_FreeCString(s->ctx, str);
20876
0
        }
20877
0
        break;
20878
0
    case TOK_TEMPLATE:
20879
0
        {
20880
0
            const char *str;
20881
0
            str = JS_ToCString(s->ctx, token->u.str.str);
20882
0
            printf("template: `%s`\n", str);
20883
0
            JS_FreeCString(s->ctx, str);
20884
0
        }
20885
0
        break;
20886
0
    case TOK_REGEXP:
20887
0
        {
20888
0
            const char *str, *str2;
20889
0
            str = JS_ToCString(s->ctx, token->u.regexp.body);
20890
0
            str2 = JS_ToCString(s->ctx, token->u.regexp.flags);
20891
0
            printf("regexp: '%s' '%s'\n", str, str2);
20892
0
            JS_FreeCString(s->ctx, str);
20893
0
            JS_FreeCString(s->ctx, str2);
20894
0
        }
20895
0
        break;
20896
0
    case TOK_EOF:
20897
0
        printf("eof\n");
20898
0
        break;
20899
0
    default:
20900
0
        if (s->token.val >= TOK_NULL && s->token.val <= TOK_LAST_KEYWORD) {
20901
0
            goto dump_atom;
20902
0
        } else if (s->token.val >= 256) {
20903
0
            printf("token: %d\n", token->val);
20904
0
        } else {
20905
0
            printf("token: '%c'\n", token->val);
20906
0
        }
20907
0
        break;
20908
0
    }
20909
0
}
20910
20911
/* return the zero based line and column number in the source. */
20912
/* Note: we no longer support '\r' as line terminator */
20913
static int get_line_col(int *pcol_num, const uint8_t *buf, size_t len)
20914
13
{
20915
13
    int line_num, col_num, c;
20916
13
    size_t i;
20917
    
20918
13
    line_num = 0;
20919
13
    col_num = 0;
20920
1.04M
    for(i = 0; i < len; i++) {
20921
1.04M
        c = buf[i];
20922
1.04M
        if (c == '\n') {
20923
7
            line_num++;
20924
7
            col_num = 0;
20925
1.04M
        } else if (c < 0x80 || c >= 0xc0) {
20926
1.04M
            col_num++;
20927
1.04M
        }
20928
1.04M
    }
20929
13
    *pcol_num = col_num;
20930
13
    return line_num;
20931
13
}
20932
20933
static int get_line_col_cached(GetLineColCache *s, int *pcol_num, const uint8_t *ptr)
20934
12
{
20935
12
    int line_num, col_num;
20936
12
    if (ptr >= s->ptr) {
20937
12
        line_num = get_line_col(&col_num, s->ptr, ptr - s->ptr);
20938
12
        if (line_num == 0) {
20939
7
            s->col_num += col_num;
20940
7
        } else {
20941
5
            s->line_num += line_num;
20942
5
            s->col_num = col_num;
20943
5
        }
20944
12
    } else {
20945
0
        line_num = get_line_col(&col_num, ptr, s->ptr - ptr);
20946
0
        if (line_num == 0) {
20947
0
            s->col_num -= col_num;
20948
0
        } else {
20949
0
            const uint8_t *p;
20950
0
            s->line_num -= line_num;
20951
            /* find the absolute column position */
20952
0
            col_num = 0;
20953
0
            for(p = ptr - 1; p >= s->buf_start; p--) {
20954
0
                if (*p == '\n') {
20955
0
                    break;
20956
0
                } else if (*p < 0x80 || *p >= 0xc0) {
20957
0
                    col_num++;
20958
0
                }
20959
0
            }
20960
0
            s->col_num = col_num;
20961
0
        }
20962
0
    }
20963
12
    s->ptr = ptr;
20964
12
    *pcol_num = s->col_num;
20965
12
    return s->line_num;
20966
12
}
20967
20968
/* 'ptr' is the position of the error in the source */
20969
static int js_parse_error_v(JSParseState *s, const uint8_t *ptr, const char *fmt, va_list ap)
20970
1
{
20971
1
    JSContext *ctx = s->ctx;
20972
1
    int line_num, col_num;
20973
1
    line_num = get_line_col(&col_num, s->buf_start, ptr - s->buf_start);
20974
1
    JS_ThrowError2(ctx, JS_SYNTAX_ERROR, fmt, ap, FALSE);
20975
1
    build_backtrace(ctx, ctx->rt->current_exception, s->filename,
20976
1
                    line_num + 1, col_num + 1, 0);
20977
1
    return -1;
20978
1
}
20979
20980
static __attribute__((format(printf, 3, 4))) int js_parse_error_pos(JSParseState *s, const uint8_t *ptr, const char *fmt, ...)
20981
0
{
20982
0
    va_list ap;
20983
0
    int ret;
20984
    
20985
0
    va_start(ap, fmt);
20986
0
    ret = js_parse_error_v(s, ptr, fmt, ap);
20987
0
    va_end(ap);
20988
0
    return ret;
20989
0
}
20990
20991
static __attribute__((format(printf, 2, 3))) int js_parse_error(JSParseState *s, const char *fmt, ...)
20992
1
{
20993
1
    va_list ap;
20994
1
    int ret;
20995
    
20996
1
    va_start(ap, fmt);
20997
1
    ret = js_parse_error_v(s, s->token.ptr, fmt, ap);
20998
1
    va_end(ap);
20999
1
    return ret;
21000
1
}
21001
21002
static int js_parse_expect(JSParseState *s, int tok)
21003
2
{
21004
2
    if (s->token.val != tok) {
21005
        /* XXX: dump token correctly in all cases */
21006
0
        return js_parse_error(s, "expecting '%c'", tok);
21007
0
    }
21008
2
    return next_token(s);
21009
2
}
21010
21011
static int js_parse_expect_semi(JSParseState *s)
21012
10
{
21013
10
    if (s->token.val != ';') {
21014
        /* automatic insertion of ';' */
21015
2
        if (s->token.val == TOK_EOF || s->token.val == '}' || s->got_lf) {
21016
2
            return 0;
21017
2
        }
21018
0
        return js_parse_error(s, "expecting '%c'", ';');
21019
2
    }
21020
8
    return next_token(s);
21021
10
}
21022
21023
static int js_parse_error_reserved_identifier(JSParseState *s)
21024
0
{
21025
0
    char buf1[ATOM_GET_STR_BUF_SIZE];
21026
0
    return js_parse_error(s, "'%s' is a reserved identifier",
21027
0
                          JS_AtomGetStr(s->ctx, buf1, sizeof(buf1),
21028
0
                                        s->token.u.ident.atom));
21029
0
}
21030
21031
static __exception int js_parse_template_part(JSParseState *s, const uint8_t *p)
21032
0
{
21033
0
    uint32_t c;
21034
0
    StringBuffer b_s, *b = &b_s;
21035
0
    JSValue str;
21036
21037
    /* p points to the first byte of the template part */
21038
0
    if (string_buffer_init(s->ctx, b, 32))
21039
0
        goto fail;
21040
0
    for(;;) {
21041
0
        if (p >= s->buf_end)
21042
0
            goto unexpected_eof;
21043
0
        c = *p++;
21044
0
        if (c == '`') {
21045
            /* template end part */
21046
0
            break;
21047
0
        }
21048
0
        if (c == '$' && *p == '{') {
21049
            /* template start or middle part */
21050
0
            p++;
21051
0
            break;
21052
0
        }
21053
0
        if (c == '\\') {
21054
0
            if (string_buffer_putc8(b, c))
21055
0
                goto fail;
21056
0
            if (p >= s->buf_end)
21057
0
                goto unexpected_eof;
21058
0
            c = *p++;
21059
0
        }
21060
        /* newline sequences are normalized as single '\n' bytes */
21061
0
        if (c == '\r') {
21062
0
            if (*p == '\n')
21063
0
                p++;
21064
0
            c = '\n';
21065
0
        }
21066
0
        if (c >= 0x80) {
21067
0
            const uint8_t *p_next;
21068
0
            c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
21069
0
            if (c > 0x10FFFF) {
21070
0
                js_parse_error_pos(s, p - 1, "invalid UTF-8 sequence");
21071
0
                goto fail;
21072
0
            }
21073
0
            p = p_next;
21074
0
        }
21075
0
        if (string_buffer_putc(b, c))
21076
0
            goto fail;
21077
0
    }
21078
0
    str = string_buffer_end(b);
21079
0
    if (JS_IsException(str))
21080
0
        return -1;
21081
0
    s->token.val = TOK_TEMPLATE;
21082
0
    s->token.u.str.sep = c;
21083
0
    s->token.u.str.str = str;
21084
0
    s->buf_ptr = p;
21085
0
    return 0;
21086
21087
0
 unexpected_eof:
21088
0
    js_parse_error(s, "unexpected end of string");
21089
0
 fail:
21090
0
    string_buffer_free(b);
21091
0
    return -1;
21092
0
}
21093
21094
static __exception int js_parse_string(JSParseState *s, int sep,
21095
                                       BOOL do_throw, const uint8_t *p,
21096
                                       JSToken *token, const uint8_t **pp)
21097
4
{
21098
4
    int ret;
21099
4
    uint32_t c;
21100
4
    StringBuffer b_s, *b = &b_s;
21101
4
    const uint8_t *p_escape;
21102
4
    JSValue str;
21103
21104
    /* string */
21105
4
    if (string_buffer_init(s->ctx, b, 32))
21106
0
        goto fail;
21107
14
    for(;;) {
21108
14
        if (p >= s->buf_end)
21109
0
            goto invalid_char;
21110
14
        c = *p;
21111
14
        if (c < 0x20) {
21112
0
            if (sep == '`') {
21113
0
                if (c == '\r') {
21114
0
                    if (p[1] == '\n')
21115
0
                        p++;
21116
0
                    c = '\n';
21117
0
                }
21118
                /* do not update s->line_num */
21119
0
            } else if (c == '\n' || c == '\r')
21120
0
                goto invalid_char;
21121
0
        }
21122
14
        p++;
21123
14
        if (c == sep)
21124
4
            break;
21125
10
        if (c == '$' && *p == '{' && sep == '`') {
21126
            /* template start or middle part */
21127
0
            p++;
21128
0
            break;
21129
0
        }
21130
10
        if (c == '\\') {
21131
0
            p_escape = p - 1;
21132
0
            c = *p;
21133
            /* XXX: need a specific JSON case to avoid
21134
               accepting invalid escapes */
21135
0
            switch(c) {
21136
0
            case '\0':
21137
0
                if (p >= s->buf_end)
21138
0
                    goto invalid_char;
21139
0
                p++;
21140
0
                break;
21141
0
            case '\'':
21142
0
            case '\"':
21143
0
            case '\\':
21144
0
                p++;
21145
0
                break;
21146
0
            case '\r':  /* accept DOS and MAC newline sequences */
21147
0
                if (p[1] == '\n') {
21148
0
                    p++;
21149
0
                }
21150
                /* fall thru */
21151
0
            case '\n':
21152
                /* ignore escaped newline sequence */
21153
0
                p++;
21154
0
                continue;
21155
0
            default:
21156
0
                if (c >= '0' && c <= '9') {
21157
0
                    if (!(s->cur_func->js_mode & JS_MODE_STRICT) && sep != '`')
21158
0
                        goto parse_escape;
21159
0
                    if (c == '0' && !(p[1] >= '0' && p[1] <= '9')) {
21160
0
                        p++;
21161
0
                        c = '\0';
21162
0
                    } else {
21163
0
                        if (c >= '8' || sep == '`') {
21164
                            /* Note: according to ES2021, \8 and \9 are not
21165
                               accepted in strict mode or in templates. */
21166
0
                            goto invalid_escape;
21167
0
                        } else {
21168
0
                            if (do_throw)
21169
0
                                js_parse_error_pos(s, p_escape, "octal escape sequences are not allowed in strict mode");
21170
0
                        }
21171
0
                        goto fail;
21172
0
                    }
21173
0
                } else if (c >= 0x80) {
21174
0
                    const uint8_t *p_next;
21175
0
                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
21176
0
                    if (c > 0x10FFFF) {
21177
0
                        goto invalid_utf8;
21178
0
                    }
21179
0
                    p = p_next;
21180
                    /* LS or PS are skipped */
21181
0
                    if (c == CP_LS || c == CP_PS)
21182
0
                        continue;
21183
0
                } else {
21184
0
                parse_escape:
21185
0
                    ret = lre_parse_escape(&p, TRUE);
21186
0
                    if (ret == -1) {
21187
0
                    invalid_escape:
21188
0
                        if (do_throw)
21189
0
                            js_parse_error_pos(s, p_escape, "malformed escape sequence in string literal");
21190
0
                        goto fail;
21191
0
                    } else if (ret < 0) {
21192
                        /* ignore the '\' (could output a warning) */
21193
0
                        p++;
21194
0
                    } else {
21195
0
                        c = ret;
21196
0
                    }
21197
0
                }
21198
0
                break;
21199
0
            }
21200
10
        } else if (c >= 0x80) {
21201
0
            const uint8_t *p_next;
21202
0
            c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
21203
0
            if (c > 0x10FFFF)
21204
0
                goto invalid_utf8;
21205
0
            p = p_next;
21206
0
        }
21207
10
        if (string_buffer_putc(b, c))
21208
0
            goto fail;
21209
10
    }
21210
4
    str = string_buffer_end(b);
21211
4
    if (JS_IsException(str))
21212
0
        return -1;
21213
4
    token->val = TOK_STRING;
21214
4
    token->u.str.sep = c;
21215
4
    token->u.str.str = str;
21216
4
    *pp = p;
21217
4
    return 0;
21218
21219
0
 invalid_utf8:
21220
0
    if (do_throw)
21221
0
        js_parse_error(s, "invalid UTF-8 sequence");
21222
0
    goto fail;
21223
0
 invalid_char:
21224
0
    if (do_throw)
21225
0
        js_parse_error(s, "unexpected end of string");
21226
0
 fail:
21227
0
    string_buffer_free(b);
21228
0
    return -1;
21229
0
}
21230
21231
49
static inline BOOL token_is_pseudo_keyword(JSParseState *s, JSAtom atom) {
21232
49
    return s->token.val == TOK_IDENT && s->token.u.ident.atom == atom &&
21233
49
        !s->token.u.ident.has_escape;
21234
49
}
21235
21236
static __exception int js_parse_regexp(JSParseState *s)
21237
0
{
21238
0
    const uint8_t *p;
21239
0
    BOOL in_class;
21240
0
    StringBuffer b_s, *b = &b_s;
21241
0
    StringBuffer b2_s, *b2 = &b2_s;
21242
0
    uint32_t c;
21243
0
    JSValue body_str, flags_str;
21244
21245
0
    p = s->buf_ptr;
21246
0
    p++;
21247
0
    in_class = FALSE;
21248
0
    if (string_buffer_init(s->ctx, b, 32))
21249
0
        return -1;
21250
0
    if (string_buffer_init(s->ctx, b2, 1))
21251
0
        goto fail;
21252
0
    for(;;) {
21253
0
        if (p >= s->buf_end) {
21254
0
        eof_error:
21255
0
            js_parse_error(s, "unexpected end of regexp");
21256
0
            goto fail;
21257
0
        }
21258
0
        c = *p++;
21259
0
        if (c == '\n' || c == '\r') {
21260
0
            goto eol_error;
21261
0
        } else if (c == '/') {
21262
0
            if (!in_class)
21263
0
                break;
21264
0
        } else if (c == '[') {
21265
0
            in_class = TRUE;
21266
0
        } else if (c == ']') {
21267
            /* XXX: incorrect as the first character in a class */
21268
0
            in_class = FALSE;
21269
0
        } else if (c == '\\') {
21270
0
            if (string_buffer_putc8(b, c))
21271
0
                goto fail;
21272
0
            c = *p++;
21273
0
            if (c == '\n' || c == '\r')
21274
0
                goto eol_error;
21275
0
            else if (c == '\0' && p >= s->buf_end)
21276
0
                goto eof_error;
21277
0
            else if (c >= 0x80) {
21278
0
                const uint8_t *p_next;
21279
0
                c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
21280
0
                if (c > 0x10FFFF) {
21281
0
                    goto invalid_utf8;
21282
0
                }
21283
0
                p = p_next;
21284
0
                if (c == CP_LS || c == CP_PS)
21285
0
                    goto eol_error;
21286
0
            }
21287
0
        } else if (c >= 0x80) {
21288
0
            const uint8_t *p_next;
21289
0
            c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
21290
0
            if (c > 0x10FFFF) {
21291
0
            invalid_utf8:
21292
0
                js_parse_error_pos(s, p - 1, "invalid UTF-8 sequence");
21293
0
                goto fail;
21294
0
            }
21295
            /* LS or PS are considered as line terminator */
21296
0
            if (c == CP_LS || c == CP_PS) {
21297
0
            eol_error:
21298
0
                js_parse_error_pos(s, p - 1, "unexpected line terminator in regexp");
21299
0
                goto fail;
21300
0
            }
21301
0
            p = p_next;
21302
0
        }
21303
0
        if (string_buffer_putc(b, c))
21304
0
            goto fail;
21305
0
    }
21306
21307
    /* flags */
21308
0
    for(;;) {
21309
0
        const uint8_t *p_next = p;
21310
0
        c = *p_next++;
21311
0
        if (c >= 0x80) {
21312
0
            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);
21313
0
            if (c > 0x10FFFF) {
21314
0
                p++;
21315
0
                goto invalid_utf8;
21316
0
            }
21317
0
        }
21318
0
        if (!lre_js_is_ident_next(c))
21319
0
            break;
21320
0
        if (string_buffer_putc(b2, c))
21321
0
            goto fail;
21322
0
        p = p_next;
21323
0
    }
21324
21325
0
    body_str = string_buffer_end(b);
21326
0
    flags_str = string_buffer_end(b2);
21327
0
    if (JS_IsException(body_str) ||
21328
0
        JS_IsException(flags_str)) {
21329
0
        JS_FreeValue(s->ctx, body_str);
21330
0
        JS_FreeValue(s->ctx, flags_str);
21331
0
        return -1;
21332
0
    }
21333
0
    s->token.val = TOK_REGEXP;
21334
0
    s->token.u.regexp.body = body_str;
21335
0
    s->token.u.regexp.flags = flags_str;
21336
0
    s->buf_ptr = p;
21337
0
    return 0;
21338
0
 fail:
21339
0
    string_buffer_free(b);
21340
0
    string_buffer_free(b2);
21341
0
    return -1;
21342
0
}
21343
21344
static __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize,
21345
                                     char *static_buf)
21346
0
{
21347
0
    char *buf, *new_buf;
21348
0
    size_t size, new_size;
21349
21350
0
    buf = *pbuf;
21351
0
    size = *psize;
21352
0
    if (size >= (SIZE_MAX / 3) * 2)
21353
0
        new_size = SIZE_MAX;
21354
0
    else
21355
0
        new_size = size + (size >> 1);
21356
0
    if (buf == static_buf) {
21357
0
        new_buf = js_malloc(ctx, new_size);
21358
0
        if (!new_buf)
21359
0
            return -1;
21360
0
        memcpy(new_buf, buf, size);
21361
0
    } else {
21362
0
        new_buf = js_realloc(ctx, buf, new_size);
21363
0
        if (!new_buf)
21364
0
            return -1;
21365
0
    }
21366
0
    *pbuf = new_buf;
21367
0
    *psize = new_size;
21368
0
    return 0;
21369
0
}
21370
21371
/* convert a TOK_IDENT to a keyword when needed */
21372
static void update_token_ident(JSParseState *s)
21373
31
{
21374
31
    if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD ||
21375
31
        (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD &&
21376
27
         (s->cur_func->js_mode & JS_MODE_STRICT)) ||
21377
31
        (s->token.u.ident.atom == JS_ATOM_yield &&
21378
27
         ((s->cur_func->func_kind & JS_FUNC_GENERATOR) ||
21379
0
          (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
21380
0
           !s->cur_func->in_function_body && s->cur_func->parent &&
21381
0
           (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) ||
21382
31
        (s->token.u.ident.atom == JS_ATOM_await &&
21383
27
         (s->is_module ||
21384
0
          (s->cur_func->func_kind & JS_FUNC_ASYNC) ||
21385
0
          s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT ||
21386
0
          (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
21387
0
           !s->cur_func->in_function_body && s->cur_func->parent &&
21388
0
           ((s->cur_func->parent->func_kind & JS_FUNC_ASYNC) ||
21389
4
            s->cur_func->parent->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))))) {
21390
4
        if (s->token.u.ident.has_escape) {
21391
0
            s->token.u.ident.is_reserved = TRUE;
21392
0
            s->token.val = TOK_IDENT;
21393
4
        } else {
21394
            /* The keywords atoms are pre allocated */
21395
4
            s->token.val = s->token.u.ident.atom - 1 + TOK_FIRST_KEYWORD;
21396
4
        }
21397
4
    }
21398
31
}
21399
21400
/* if the current token is an identifier or keyword, reparse it
21401
   according to the current function type */
21402
static void reparse_ident_token(JSParseState *s)
21403
0
{
21404
0
    if (s->token.val == TOK_IDENT ||
21405
0
        (s->token.val >= TOK_FIRST_KEYWORD &&
21406
0
         s->token.val <= TOK_LAST_KEYWORD)) {
21407
0
        s->token.val = TOK_IDENT;
21408
0
        s->token.u.ident.is_reserved = FALSE;
21409
0
        update_token_ident(s);
21410
0
    }
21411
0
}
21412
21413
/* 'c' is the first character. Return JS_ATOM_NULL in case of error */
21414
static JSAtom parse_ident(JSParseState *s, const uint8_t **pp,
21415
                          BOOL *pident_has_escape, int c, BOOL is_private)
21416
31
{
21417
31
    const uint8_t *p, *p1;
21418
31
    char ident_buf[128], *buf;
21419
31
    size_t ident_size, ident_pos;
21420
31
    JSAtom atom;
21421
21422
31
    p = *pp;
21423
31
    buf = ident_buf;
21424
31
    ident_size = sizeof(ident_buf);
21425
31
    ident_pos = 0;
21426
31
    if (is_private)
21427
0
        buf[ident_pos++] = '#';
21428
130
    for(;;) {
21429
130
        p1 = p;
21430
21431
130
        if (c < 128) {
21432
130
            buf[ident_pos++] = c;
21433
130
        } else {
21434
0
            ident_pos += unicode_to_utf8((uint8_t*)buf + ident_pos, c);
21435
0
        }
21436
130
        c = *p1++;
21437
130
        if (c == '\\' && *p1 == 'u') {
21438
0
            c = lre_parse_escape(&p1, TRUE);
21439
0
            *pident_has_escape = TRUE;
21440
130
        } else if (c >= 128) {
21441
0
            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
21442
0
        }
21443
130
        if (!lre_js_is_ident_next(c))
21444
31
            break;
21445
99
        p = p1;
21446
99
        if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
21447
0
            if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) {
21448
0
                atom = JS_ATOM_NULL;
21449
0
                goto done;
21450
0
            }
21451
0
        }
21452
99
    }
21453
31
    atom = JS_NewAtomLen(s->ctx, buf, ident_pos);
21454
31
 done:
21455
31
    if (unlikely(buf != ident_buf))
21456
0
        js_free(s->ctx, buf);
21457
31
    *pp = p;
21458
31
    return atom;
21459
31
}
21460
21461
21462
static __exception int next_token(JSParseState *s)
21463
63
{
21464
63
    const uint8_t *p;
21465
63
    int c;
21466
63
    BOOL ident_has_escape;
21467
63
    JSAtom atom;
21468
21469
63
    if (js_check_stack_overflow(s->ctx->rt, 0)) {
21470
0
        return js_parse_error(s, "stack overflow");
21471
0
    }
21472
21473
63
    free_token(s, &s->token);
21474
21475
63
    p = s->last_ptr = s->buf_ptr;
21476
63
    s->got_lf = FALSE;
21477
101
 redo:
21478
101
    s->token.ptr = p;
21479
101
    c = *p;
21480
101
    switch(c) {
21481
4
    case 0:
21482
4
        if (p >= s->buf_end) {
21483
4
            s->token.val = TOK_EOF;
21484
4
        } else {
21485
0
            goto def_token;
21486
0
        }
21487
4
        break;
21488
4
    case '`':
21489
0
        if (js_parse_template_part(s, p + 1))
21490
0
            goto fail;
21491
0
        p = s->buf_ptr;
21492
0
        break;
21493
4
    case '\'':
21494
4
    case '\"':
21495
4
        if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))
21496
0
            goto fail;
21497
4
        break;
21498
4
    case '\r':  /* accept DOS and MAC newline sequences */
21499
0
        if (p[1] == '\n') {
21500
0
            p++;
21501
0
        }
21502
        /* fall thru */
21503
9
    case '\n':
21504
9
        p++;
21505
9
    line_terminator:
21506
9
        s->got_lf = TRUE;
21507
9
        goto redo;
21508
0
    case '\f':
21509
0
    case '\v':
21510
28
    case ' ':
21511
28
    case '\t':
21512
28
        p++;
21513
28
        goto redo;
21514
1
    case '/':
21515
1
        if (p[1] == '*') {
21516
            /* comment */
21517
0
            p += 2;
21518
0
            for(;;) {
21519
0
                if (*p == '\0' && p >= s->buf_end) {
21520
0
                    js_parse_error(s, "unexpected end of comment");
21521
0
                    goto fail;
21522
0
                }
21523
0
                if (p[0] == '*' && p[1] == '/') {
21524
0
                    p += 2;
21525
0
                    break;
21526
0
                }
21527
0
                if (*p == '\n' || *p == '\r') {
21528
0
                    s->got_lf = TRUE; /* considered as LF for ASI */
21529
0
                    p++;
21530
0
                } else if (*p >= 0x80) {
21531
0
                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
21532
0
                    if (c == CP_LS || c == CP_PS) {
21533
0
                        s->got_lf = TRUE; /* considered as LF for ASI */
21534
0
                    } else if (c == -1) {
21535
0
                        p++; /* skip invalid UTF-8 */
21536
0
                    }
21537
0
                } else {
21538
0
                    p++;
21539
0
                }
21540
0
            }
21541
0
            goto redo;
21542
1
        } else if (p[1] == '/') {
21543
            /* line comment */
21544
1
            p += 2;
21545
1
        skip_line_comment:
21546
1.04M
            for(;;) {
21547
1.04M
                if (*p == '\0' && p >= s->buf_end)
21548
1
                    break;
21549
1.04M
                if (*p == '\r' || *p == '\n')
21550
0
                    break;
21551
1.04M
                if (*p >= 0x80) {
21552
0
                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
21553
                    /* LS or PS are considered as line terminator */
21554
0
                    if (c == CP_LS || c == CP_PS) {
21555
0
                        break;
21556
0
                    } else if (c == -1) {
21557
0
                        p++; /* skip invalid UTF-8 */
21558
0
                    }
21559
1.04M
                } else {
21560
1.04M
                    p++;
21561
1.04M
                }
21562
1.04M
            }
21563
1
            goto redo;
21564
1
        } else if (p[1] == '=') {
21565
0
            p += 2;
21566
0
            s->token.val = TOK_DIV_ASSIGN;
21567
0
        } else {
21568
0
            p++;
21569
0
            s->token.val = c;
21570
0
        }
21571
0
        break;
21572
0
    case '\\':
21573
0
        if (p[1] == 'u') {
21574
0
            const uint8_t *p1 = p + 1;
21575
0
            int c1 = lre_parse_escape(&p1, TRUE);
21576
0
            if (c1 >= 0 && lre_js_is_ident_first(c1)) {
21577
0
                c = c1;
21578
0
                p = p1;
21579
0
                ident_has_escape = TRUE;
21580
0
                goto has_ident;
21581
0
            } else {
21582
                /* XXX: syntax error? */
21583
0
            }
21584
0
        }
21585
0
        goto def_token;
21586
5
    case 'a': case 'b': case 'c': case 'd':
21587
13
    case 'e': case 'f': case 'g': case 'h':
21588
17
    case 'i': case 'j': case 'k': case 'l':
21589
23
    case 'm': case 'n': case 'o': case 'p':
21590
29
    case 'q': case 'r': case 's': case 't':
21591
29
    case 'u': case 'v': case 'w': case 'x':
21592
29
    case 'y': case 'z':
21593
29
    case 'A': case 'B': case 'C': case 'D':
21594
30
    case 'E': case 'F': case 'G': case 'H':
21595
31
    case 'I': case 'J': case 'K': case 'L':
21596
31
    case 'M': case 'N': case 'O': case 'P':
21597
31
    case 'Q': case 'R': case 'S': case 'T':
21598
31
    case 'U': case 'V': case 'W': case 'X':
21599
31
    case 'Y': case 'Z':
21600
31
    case '_':
21601
31
    case '$':
21602
        /* identifier */
21603
31
        p++;
21604
31
        ident_has_escape = FALSE;
21605
31
    has_ident:
21606
31
        atom = parse_ident(s, &p, &ident_has_escape, c, FALSE);
21607
31
        if (atom == JS_ATOM_NULL)
21608
0
            goto fail;
21609
31
        s->token.u.ident.atom = atom;
21610
31
        s->token.u.ident.has_escape = ident_has_escape;
21611
31
        s->token.u.ident.is_reserved = FALSE;
21612
31
        s->token.val = TOK_IDENT;
21613
31
        update_token_ident(s);
21614
31
        break;
21615
0
    case '#':
21616
        /* private name */
21617
0
        {
21618
0
            const uint8_t *p1;
21619
0
            p++;
21620
0
            p1 = p;
21621
0
            c = *p1++;
21622
0
            if (c == '\\' && *p1 == 'u') {
21623
0
                c = lre_parse_escape(&p1, TRUE);
21624
0
            } else if (c >= 128) {
21625
0
                c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);
21626
0
            }
21627
0
            if (!lre_js_is_ident_first(c)) {
21628
0
                js_parse_error(s, "invalid first character of private name");
21629
0
                goto fail;
21630
0
            }
21631
0
            p = p1;
21632
0
            ident_has_escape = FALSE; /* not used */
21633
0
            atom = parse_ident(s, &p, &ident_has_escape, c, TRUE);
21634
0
            if (atom == JS_ATOM_NULL)
21635
0
                goto fail;
21636
0
            s->token.u.ident.atom = atom;
21637
0
            s->token.val = TOK_PRIVATE_NAME;
21638
0
        }
21639
0
        break;
21640
4
    case '.':
21641
4
        if (p[1] == '.' && p[2] == '.') {
21642
0
            p += 3;
21643
0
            s->token.val = TOK_ELLIPSIS;
21644
0
            break;
21645
0
        }
21646
4
        if (p[1] >= '0' && p[1] <= '9') {
21647
0
            goto parse_number;
21648
4
        } else {
21649
4
            goto def_token;
21650
4
        }
21651
0
        break;
21652
1
    case '0':
21653
        /* in strict mode, octal literals are not accepted */
21654
1
        if (is_digit(p[1]) && (s->cur_func->js_mode & JS_MODE_STRICT)) {
21655
0
            js_parse_error(s, "octal literals are deprecated in strict mode");
21656
0
            goto fail;
21657
0
        }
21658
1
        goto parse_number;
21659
1
    case '1': case '2': case '3': case '4':
21660
0
    case '5': case '6': case '7': case '8':
21661
0
    case '9':
21662
        /* number */
21663
1
    parse_number:
21664
1
        {
21665
1
            JSValue ret;
21666
1
            const uint8_t *p1;
21667
1
            int flags;
21668
1
            flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL |
21669
1
                ATOD_ACCEPT_UNDERSCORES | ATOD_ACCEPT_SUFFIX;
21670
1
            ret = js_atof(s->ctx, (const char *)p, (const char **)&p, 0,
21671
1
                          flags);
21672
1
            if (JS_IsException(ret))
21673
0
                goto fail;
21674
            /* reject `10instanceof Number` */
21675
1
            if (JS_VALUE_IS_NAN(ret) ||
21676
1
                lre_js_is_ident_next(unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1))) {
21677
0
                JS_FreeValue(s->ctx, ret);
21678
0
                js_parse_error(s, "invalid number literal");
21679
0
                goto fail;
21680
0
            }
21681
1
            s->token.val = TOK_NUMBER;
21682
1
            s->token.u.num.val = ret;
21683
1
        }
21684
0
        break;
21685
4
    case '*':
21686
4
        if (p[1] == '=') {
21687
0
            p += 2;
21688
0
            s->token.val = TOK_MUL_ASSIGN;
21689
4
        } else if (p[1] == '*') {
21690
0
            if (p[2] == '=') {
21691
0
                p += 3;
21692
0
                s->token.val = TOK_POW_ASSIGN;
21693
0
            } else {
21694
0
                p += 2;
21695
0
                s->token.val = TOK_POW;
21696
0
            }
21697
4
        } else {
21698
4
            goto def_token;
21699
4
        }
21700
0
        break;
21701
0
    case '%':
21702
0
        if (p[1] == '=') {
21703
0
            p += 2;
21704
0
            s->token.val = TOK_MOD_ASSIGN;
21705
0
        } else {
21706
0
            goto def_token;
21707
0
        }
21708
0
        break;
21709
0
    case '+':
21710
0
        if (p[1] == '=') {
21711
0
            p += 2;
21712
0
            s->token.val = TOK_PLUS_ASSIGN;
21713
0
        } else if (p[1] == '+') {
21714
0
            p += 2;
21715
0
            s->token.val = TOK_INC;
21716
0
        } else {
21717
0
            goto def_token;
21718
0
        }
21719
0
        break;
21720
1
    case '-':
21721
1
        if (p[1] == '=') {
21722
0
            p += 2;
21723
0
            s->token.val = TOK_MINUS_ASSIGN;
21724
1
        } else if (p[1] == '-') {
21725
0
            if (s->allow_html_comments && p[2] == '>' &&
21726
0
                (s->got_lf || s->last_ptr == s->buf_start)) {
21727
                /* Annex B: `-->` at beginning of line is an html comment end.
21728
                   It extends to the end of the line.
21729
                 */
21730
0
                goto skip_line_comment;
21731
0
            }
21732
0
            p += 2;
21733
0
            s->token.val = TOK_DEC;
21734
1
        } else {
21735
1
            goto def_token;
21736
1
        }
21737
0
        break;
21738
0
    case '<':
21739
0
        if (p[1] == '=') {
21740
0
            p += 2;
21741
0
            s->token.val = TOK_LTE;
21742
0
        } else if (p[1] == '<') {
21743
0
            if (p[2] == '=') {
21744
0
                p += 3;
21745
0
                s->token.val = TOK_SHL_ASSIGN;
21746
0
            } else {
21747
0
                p += 2;
21748
0
                s->token.val = TOK_SHL;
21749
0
            }
21750
0
        } else if (s->allow_html_comments &&
21751
0
                   p[1] == '!' && p[2] == '-' && p[3] == '-') {
21752
            /* Annex B: handle `<!--` single line html comments */
21753
0
            goto skip_line_comment;
21754
0
        } else {
21755
0
            goto def_token;
21756
0
        }
21757
0
        break;
21758
0
    case '>':
21759
0
        if (p[1] == '=') {
21760
0
            p += 2;
21761
0
            s->token.val = TOK_GTE;
21762
0
        } else if (p[1] == '>') {
21763
0
            if (p[2] == '>') {
21764
0
                if (p[3] == '=') {
21765
0
                    p += 4;
21766
0
                    s->token.val = TOK_SHR_ASSIGN;
21767
0
                } else {
21768
0
                    p += 3;
21769
0
                    s->token.val = TOK_SHR;
21770
0
                }
21771
0
            } else if (p[2] == '=') {
21772
0
                p += 3;
21773
0
                s->token.val = TOK_SAR_ASSIGN;
21774
0
            } else {
21775
0
                p += 2;
21776
0
                s->token.val = TOK_SAR;
21777
0
            }
21778
0
        } else {
21779
0
            goto def_token;
21780
0
        }
21781
0
        break;
21782
4
    case '=':
21783
4
        if (p[1] == '=') {
21784
0
            if (p[2] == '=') {
21785
0
                p += 3;
21786
0
                s->token.val = TOK_STRICT_EQ;
21787
0
            } else {
21788
0
                p += 2;
21789
0
                s->token.val = TOK_EQ;
21790
0
            }
21791
4
        } else if (p[1] == '>') {
21792
0
            p += 2;
21793
0
            s->token.val = TOK_ARROW;
21794
4
        } else {
21795
4
            goto def_token;
21796
4
        }
21797
0
        break;
21798
0
    case '!':
21799
0
        if (p[1] == '=') {
21800
0
            if (p[2] == '=') {
21801
0
                p += 3;
21802
0
                s->token.val = TOK_STRICT_NEQ;
21803
0
            } else {
21804
0
                p += 2;
21805
0
                s->token.val = TOK_NEQ;
21806
0
            }
21807
0
        } else {
21808
0
            goto def_token;
21809
0
        }
21810
0
        break;
21811
0
    case '&':
21812
0
        if (p[1] == '=') {
21813
0
            p += 2;
21814
0
            s->token.val = TOK_AND_ASSIGN;
21815
0
        } else if (p[1] == '&') {
21816
0
            if (p[2] == '=') {
21817
0
                p += 3;
21818
0
                s->token.val = TOK_LAND_ASSIGN;
21819
0
            } else {
21820
0
                p += 2;
21821
0
                s->token.val = TOK_LAND;
21822
0
            }
21823
0
        } else {
21824
0
            goto def_token;
21825
0
        }
21826
0
        break;
21827
0
    case '^':
21828
0
        if (p[1] == '=') {
21829
0
            p += 2;
21830
0
            s->token.val = TOK_XOR_ASSIGN;
21831
0
        } else {
21832
0
            goto def_token;
21833
0
        }
21834
0
        break;
21835
0
    case '|':
21836
0
        if (p[1] == '=') {
21837
0
            p += 2;
21838
0
            s->token.val = TOK_OR_ASSIGN;
21839
0
        } else if (p[1] == '|') {
21840
0
            if (p[2] == '=') {
21841
0
                p += 3;
21842
0
                s->token.val = TOK_LOR_ASSIGN;
21843
0
            } else {
21844
0
                p += 2;
21845
0
                s->token.val = TOK_LOR;
21846
0
            }
21847
0
        } else {
21848
0
            goto def_token;
21849
0
        }
21850
0
        break;
21851
0
    case '?':
21852
0
        if (p[1] == '?') {
21853
0
            if (p[2] == '=') {
21854
0
                p += 3;
21855
0
                s->token.val = TOK_DOUBLE_QUESTION_MARK_ASSIGN;
21856
0
            } else {
21857
0
                p += 2;
21858
0
                s->token.val = TOK_DOUBLE_QUESTION_MARK;
21859
0
            }
21860
0
        } else if (p[1] == '.' && !(p[2] >= '0' && p[2] <= '9')) {
21861
0
            p += 2;
21862
0
            s->token.val = TOK_QUESTION_MARK_DOT;
21863
0
        } else {
21864
0
            goto def_token;
21865
0
        }
21866
0
        break;
21867
10
    default:
21868
10
        if (c >= 128) {
21869
            /* unicode value */
21870
0
            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
21871
0
            switch(c) {
21872
0
            case CP_PS:
21873
0
            case CP_LS:
21874
                /* XXX: should avoid incrementing line_number, but
21875
                   needed to handle HTML comments */
21876
0
                goto line_terminator;
21877
0
            default:
21878
0
                if (lre_is_space(c)) {
21879
0
                    goto redo;
21880
0
                } else if (lre_js_is_ident_first(c)) {
21881
0
                    ident_has_escape = FALSE;
21882
0
                    goto has_ident;
21883
0
                } else {
21884
0
                    js_parse_error(s, "unexpected character");
21885
0
                    goto fail;
21886
0
                }
21887
0
            }
21888
0
        }
21889
23
    def_token:
21890
23
        s->token.val = c;
21891
23
        p++;
21892
23
        break;
21893
101
    }
21894
63
    s->buf_ptr = p;
21895
21896
    //    dump_token(s, &s->token);
21897
63
    return 0;
21898
21899
0
 fail:
21900
0
    s->token.val = TOK_ERROR;
21901
0
    return -1;
21902
101
}
21903
21904
/* 'c' is the first character. Return JS_ATOM_NULL in case of error */
21905
/* XXX: accept unicode identifiers as JSON5 ? */
21906
static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c)
21907
0
{
21908
0
    const uint8_t *p;
21909
0
    char ident_buf[128], *buf;
21910
0
    size_t ident_size, ident_pos;
21911
0
    JSAtom atom;
21912
21913
0
    p = *pp;
21914
0
    buf = ident_buf;
21915
0
    ident_size = sizeof(ident_buf);
21916
0
    ident_pos = 0;
21917
0
    for(;;) {
21918
0
        buf[ident_pos++] = c;
21919
0
        c = *p;
21920
0
        if (c >= 128 || !lre_is_id_continue_byte(c))
21921
0
            break;
21922
0
        p++;
21923
0
        if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
21924
0
            if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) {
21925
0
                atom = JS_ATOM_NULL;
21926
0
                goto done;
21927
0
            }
21928
0
        }
21929
0
    }
21930
0
    atom = JS_NewAtomLen(s->ctx, buf, ident_pos);
21931
0
 done:
21932
0
    if (unlikely(buf != ident_buf))
21933
0
        js_free(s->ctx, buf);
21934
0
    *pp = p;
21935
0
    return atom;
21936
0
}
21937
21938
static int json_parse_string(JSParseState *s, const uint8_t **pp, int sep)
21939
0
{
21940
0
    const uint8_t *p, *p_next;
21941
0
    int i;
21942
0
    uint32_t c;
21943
0
    StringBuffer b_s, *b = &b_s;
21944
21945
0
    if (string_buffer_init(s->ctx, b, 32))
21946
0
        goto fail;
21947
21948
0
    p = *pp;
21949
0
    for(;;) {
21950
0
        if (p >= s->buf_end) {
21951
0
            goto end_of_input;
21952
0
        }
21953
0
        c = *p++;
21954
0
        if (c == sep)
21955
0
            break;
21956
0
        if (c < 0x20) {
21957
0
            js_parse_error_pos(s, p - 1, "Bad control character in string literal");
21958
0
            goto fail;
21959
0
        }
21960
0
        if (c == '\\') {
21961
0
            c = *p++;
21962
0
            switch(c) {
21963
0
            case 'b':   c = '\b'; break;
21964
0
            case 'f':   c = '\f'; break;
21965
0
            case 'n':   c = '\n'; break;
21966
0
            case 'r':   c = '\r'; break;
21967
0
            case 't':   c = '\t'; break;
21968
0
            case '\\':  break;
21969
0
            case '/':   break; 
21970
0
            case 'u':
21971
0
                c = 0;
21972
0
                for(i = 0; i < 4; i++) {
21973
0
                    int h = from_hex(*p++);
21974
0
                    if (h < 0) {
21975
0
                        js_parse_error_pos(s, p - 1, "Bad Unicode escape");
21976
0
                        goto fail;
21977
0
                    }
21978
0
                    c = (c << 4) | h;
21979
0
                }
21980
0
                break;
21981
0
            case '\n':
21982
0
                if (s->ext_json)
21983
0
                    continue;
21984
0
                goto bad_escape;
21985
0
            case 'v':
21986
0
                if (s->ext_json) {
21987
0
                    c = '\v';
21988
0
                    break;
21989
0
                }
21990
0
                goto bad_escape;
21991
0
            default:
21992
0
                if (c == sep)
21993
0
                    break;
21994
0
                if (p > s->buf_end)
21995
0
                    goto end_of_input;
21996
0
            bad_escape:
21997
0
                js_parse_error_pos(s, p - 1, "Bad escaped character");
21998
0
                goto fail;
21999
0
            }
22000
0
        } else
22001
0
        if (c >= 0x80) {
22002
0
            c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);
22003
0
            if (c > 0x10FFFF) {
22004
0
                js_parse_error_pos(s, p - 1, "Bad UTF-8 sequence");
22005
0
                goto fail;
22006
0
            }
22007
0
            p = p_next;
22008
0
        }
22009
0
        if (string_buffer_putc(b, c))
22010
0
            goto fail;
22011
0
    }
22012
0
    s->token.val = TOK_STRING;
22013
0
    s->token.u.str.sep = sep;
22014
0
    s->token.u.str.str = string_buffer_end(b);
22015
0
    *pp = p;
22016
0
    return 0;
22017
22018
0
 end_of_input:
22019
0
    js_parse_error(s, "Unexpected end of JSON input");
22020
0
 fail:
22021
0
    string_buffer_free(b);
22022
0
    return -1;
22023
0
}
22024
22025
static int json_parse_number(JSParseState *s, const uint8_t **pp)
22026
0
{
22027
0
    const uint8_t *p = *pp;
22028
0
    const uint8_t *p_start = p;
22029
0
    int radix;
22030
0
    double d;
22031
0
    JSATODTempMem atod_mem;
22032
    
22033
0
    if (*p == '+' || *p == '-')
22034
0
        p++;
22035
22036
0
    if (!is_digit(*p)) {
22037
0
        if (s->ext_json) {
22038
0
            if (strstart((const char *)p, "Infinity", (const char **)&p)) {
22039
0
                d = 1.0 / 0.0;
22040
0
                if (*p_start == '-')
22041
0
                    d = -d;
22042
0
                goto done;
22043
0
            } else if (strstart((const char *)p, "NaN", (const char **)&p)) {
22044
0
                d = NAN;
22045
0
                goto done;
22046
0
            } else if (*p != '.') {
22047
0
                goto unexpected_token;
22048
0
            }
22049
0
        } else {
22050
0
            goto unexpected_token;
22051
0
        }
22052
0
    }
22053
22054
0
    if (p[0] == '0') {
22055
0
        if (s->ext_json) {
22056
            /* also accepts base 16, 8 and 2 prefix for integers */
22057
0
            radix = 10;
22058
0
            if (p[1] == 'x' || p[1] == 'X') {
22059
0
                p += 2;
22060
0
                radix = 16;
22061
0
            } else if ((p[1] == 'o' || p[1] == 'O')) {
22062
0
                p += 2;
22063
0
                radix = 8;
22064
0
            } else if ((p[1] == 'b' || p[1] == 'B')) {
22065
0
                p += 2;
22066
0
                radix = 2;
22067
0
            }
22068
0
            if (radix != 10) {
22069
                /* prefix is present */
22070
0
                if (to_digit(*p) >= radix) {
22071
0
                unexpected_token:
22072
0
                    return js_parse_error_pos(s, p, "Unexpected token '%c'", *p);
22073
0
                }
22074
0
                d = js_atod((const char *)p_start, (const char **)&p, 0,
22075
0
                            JS_ATOD_INT_ONLY | JS_ATOD_ACCEPT_BIN_OCT, &atod_mem);
22076
0
                goto done;
22077
0
            }
22078
0
        }
22079
0
        if (is_digit(p[1]))
22080
0
            return js_parse_error_pos(s, p, "Unexpected number");
22081
0
    }
22082
22083
0
    while (is_digit(*p))
22084
0
        p++;
22085
22086
0
    if (*p == '.') {
22087
0
        p++;
22088
0
        if (!is_digit(*p))
22089
0
            return js_parse_error_pos(s, p, "Unterminated fractional number");
22090
0
        while (is_digit(*p))
22091
0
            p++;
22092
0
    }
22093
0
    if (*p == 'e' || *p == 'E') {
22094
0
        p++;
22095
0
        if (*p == '+' || *p == '-')
22096
0
            p++;
22097
0
        if (!is_digit(*p))
22098
0
            return js_parse_error_pos(s, p, "Exponent part is missing a number");
22099
0
        while (is_digit(*p))
22100
0
            p++;
22101
0
    }
22102
0
    d = js_atod((const char *)p_start, NULL, 10, 0, &atod_mem);
22103
0
 done:
22104
0
    s->token.val = TOK_NUMBER;
22105
0
    s->token.u.num.val = JS_NewFloat64(s->ctx, d);
22106
0
    *pp = p;
22107
0
    return 0;
22108
0
}
22109
22110
static __exception int json_next_token(JSParseState *s)
22111
0
{
22112
0
    const uint8_t *p;
22113
0
    int c;
22114
0
    JSAtom atom;
22115
22116
0
    if (js_check_stack_overflow(s->ctx->rt, 0)) {
22117
0
        return js_parse_error(s, "stack overflow");
22118
0
    }
22119
22120
0
    free_token(s, &s->token);
22121
22122
0
    p = s->last_ptr = s->buf_ptr;
22123
0
 redo:
22124
0
    s->token.ptr = p;
22125
0
    c = *p;
22126
0
    switch(c) {
22127
0
    case 0:
22128
0
        if (p >= s->buf_end) {
22129
0
            s->token.val = TOK_EOF;
22130
0
        } else {
22131
0
            goto def_token;
22132
0
        }
22133
0
        break;
22134
0
    case '\'':
22135
0
        if (!s->ext_json) {
22136
            /* JSON does not accept single quoted strings */
22137
0
            goto def_token;
22138
0
        }
22139
        /* fall through */
22140
0
    case '\"':
22141
0
        p++;
22142
0
        if (json_parse_string(s, &p, c))
22143
0
            goto fail;
22144
0
        break;
22145
0
    case '\r':  /* accept DOS and MAC newline sequences */
22146
0
        if (p[1] == '\n') {
22147
0
            p++;
22148
0
        }
22149
        /* fall thru */
22150
0
    case '\n':
22151
0
        p++;
22152
0
        goto redo;
22153
0
    case '\f':
22154
0
    case '\v':
22155
0
        if (!s->ext_json) {
22156
            /* JSONWhitespace does not match <VT>, nor <FF> */
22157
0
            goto def_token;
22158
0
        }
22159
        /* fall through */
22160
0
    case ' ':
22161
0
    case '\t':
22162
0
        p++;
22163
0
        goto redo;
22164
0
    case '/':
22165
0
        if (!s->ext_json) {
22166
            /* JSON does not accept comments */
22167
0
            goto def_token;
22168
0
        }
22169
0
        if (p[1] == '*') {
22170
            /* comment */
22171
0
            p += 2;
22172
0
            for(;;) {
22173
0
                if (*p == '\0' && p >= s->buf_end) {
22174
0
                    js_parse_error(s, "unexpected end of comment");
22175
0
                    goto fail;
22176
0
                }
22177
0
                if (p[0] == '*' && p[1] == '/') {
22178
0
                    p += 2;
22179
0
                    break;
22180
0
                }
22181
0
                if (*p >= 0x80) {
22182
0
                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
22183
0
                    if (c == -1) {
22184
0
                        p++; /* skip invalid UTF-8 */
22185
0
                    }
22186
0
                } else {
22187
0
                    p++;
22188
0
                }
22189
0
            }
22190
0
            goto redo;
22191
0
        } else if (p[1] == '/') {
22192
            /* line comment */
22193
0
            p += 2;
22194
0
            for(;;) {
22195
0
                if (*p == '\0' && p >= s->buf_end)
22196
0
                    break;
22197
0
                if (*p == '\r' || *p == '\n')
22198
0
                    break;
22199
0
                if (*p >= 0x80) {
22200
0
                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
22201
                    /* LS or PS are considered as line terminator */
22202
0
                    if (c == CP_LS || c == CP_PS) {
22203
0
                        break;
22204
0
                    } else if (c == -1) {
22205
0
                        p++; /* skip invalid UTF-8 */
22206
0
                    }
22207
0
                } else {
22208
0
                    p++;
22209
0
                }
22210
0
            }
22211
0
            goto redo;
22212
0
        } else {
22213
0
            goto def_token;
22214
0
        }
22215
0
        break;
22216
0
    case 'a': case 'b': case 'c': case 'd':
22217
0
    case 'e': case 'f': case 'g': case 'h':
22218
0
    case 'i': case 'j': case 'k': case 'l':
22219
0
    case 'm': case 'n': case 'o': case 'p':
22220
0
    case 'q': case 'r': case 's': case 't':
22221
0
    case 'u': case 'v': case 'w': case 'x':
22222
0
    case 'y': case 'z':
22223
0
    case 'A': case 'B': case 'C': case 'D':
22224
0
    case 'E': case 'F': case 'G': case 'H':
22225
0
    case 'I': case 'J': case 'K': case 'L':
22226
0
    case 'M': case 'N': case 'O': case 'P':
22227
0
    case 'Q': case 'R': case 'S': case 'T':
22228
0
    case 'U': case 'V': case 'W': case 'X':
22229
0
    case 'Y': case 'Z':
22230
0
    case '_':
22231
0
    case '$':
22232
0
        p++;
22233
0
        atom = json_parse_ident(s, &p, c);
22234
0
        if (atom == JS_ATOM_NULL)
22235
0
            goto fail;
22236
0
        s->token.u.ident.atom = atom;
22237
0
        s->token.u.ident.has_escape = FALSE;
22238
0
        s->token.u.ident.is_reserved = FALSE;
22239
0
        s->token.val = TOK_IDENT;
22240
0
        break;
22241
0
    case '+':
22242
0
        if (!s->ext_json)
22243
0
            goto def_token;
22244
0
        goto parse_number;
22245
0
    case '.':
22246
0
        if (s->ext_json && is_digit(p[1]))
22247
0
            goto parse_number;
22248
0
        else
22249
0
            goto def_token;
22250
0
    case '-':
22251
0
    case '0':
22252
0
    case '1': case '2': case '3': case '4':
22253
0
    case '5': case '6': case '7': case '8':
22254
0
    case '9':
22255
        /* number */
22256
0
    parse_number:
22257
0
        if (json_parse_number(s, &p))
22258
0
            goto fail;
22259
0
        break;
22260
0
    default:
22261
0
        if (c >= 128) {
22262
0
            js_parse_error(s, "unexpected character");
22263
0
            goto fail;
22264
0
        }
22265
0
    def_token:
22266
0
        s->token.val = c;
22267
0
        p++;
22268
0
        break;
22269
0
    }
22270
0
    s->buf_ptr = p;
22271
22272
    //    dump_token(s, &s->token);
22273
0
    return 0;
22274
22275
0
 fail:
22276
0
    s->token.val = TOK_ERROR;
22277
0
    return -1;
22278
0
}
22279
22280
0
static int match_identifier(const uint8_t *p, const char *s) {
22281
0
    uint32_t c;
22282
0
    while (*s) {
22283
0
        if ((uint8_t)*s++ != *p++)
22284
0
            return 0;
22285
0
    }
22286
0
    c = *p;
22287
0
    if (c >= 128)
22288
0
        c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
22289
0
    return !lre_js_is_ident_next(c);
22290
0
}
22291
22292
/* simple_next_token() is used to check for the next token in simple cases.
22293
   It is only used for ':' and '=>', 'let' or 'function' look-ahead.
22294
   (*pp) is only set if TOK_IMPORT is returned for JS_DetectModule()
22295
   Whitespace and comments are skipped correctly.
22296
   Then the next token is analyzed, only for specific words.
22297
   Return values:
22298
   - '\n' if !no_line_terminator
22299
   - TOK_ARROW, TOK_IN, TOK_IMPORT, TOK_OF, TOK_EXPORT, TOK_FUNCTION
22300
   - TOK_IDENT is returned for other identifiers and keywords
22301
   - otherwise the next character or unicode codepoint is returned.
22302
 */
22303
static int simple_next_token(const uint8_t **pp, BOOL no_line_terminator)
22304
20
{
22305
20
    const uint8_t *p;
22306
20
    uint32_t c;
22307
22308
    /* skip spaces and comments */
22309
20
    p = *pp;
22310
25
    for (;;) {
22311
25
        switch(c = *p++) {
22312
0
        case '\r':
22313
2
        case '\n':
22314
2
            if (no_line_terminator)
22315
1
                return '\n';
22316
1
            continue;
22317
4
        case ' ':
22318
4
        case '\t':
22319
4
        case '\v':
22320
4
        case '\f':
22321
4
            continue;
22322
0
        case '/':
22323
0
            if (*p == '/') {
22324
0
                if (no_line_terminator)
22325
0
                    return '\n';
22326
0
                while (*p && *p != '\r' && *p != '\n')
22327
0
                    p++;
22328
0
                continue;
22329
0
            }
22330
0
            if (*p == '*') {
22331
0
                while (*++p) {
22332
0
                    if ((*p == '\r' || *p == '\n') && no_line_terminator)
22333
0
                        return '\n';
22334
0
                    if (*p == '*' && p[1] == '/') {
22335
0
                        p += 2;
22336
0
                        break;
22337
0
                    }
22338
0
                }
22339
0
                continue;
22340
0
            }
22341
0
            break;
22342
0
        case '=':
22343
0
            if (*p == '>')
22344
0
                return TOK_ARROW;
22345
0
            break;
22346
0
        case 'i':
22347
0
            if (match_identifier(p, "n"))
22348
0
                return TOK_IN;
22349
0
            if (match_identifier(p, "mport")) {
22350
0
                *pp = p + 5;
22351
0
                return TOK_IMPORT;
22352
0
            }
22353
0
            return TOK_IDENT;
22354
0
        case 'o':
22355
0
            if (match_identifier(p, "f"))
22356
0
                return TOK_OF;
22357
0
            return TOK_IDENT;
22358
0
        case 'e':
22359
0
            if (match_identifier(p, "xport"))
22360
0
                return TOK_EXPORT;
22361
0
            return TOK_IDENT;
22362
0
        case 'f':
22363
0
            if (match_identifier(p, "unction"))
22364
0
                return TOK_FUNCTION;
22365
0
            return TOK_IDENT;
22366
0
        case '\\':
22367
0
            if (*p == 'u') {
22368
0
                if (lre_js_is_ident_first(lre_parse_escape(&p, TRUE)))
22369
0
                    return TOK_IDENT;
22370
0
            }
22371
0
            break;
22372
19
        default:
22373
19
            if (c >= 128) {
22374
0
                c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p);
22375
0
                if (no_line_terminator && (c == CP_PS || c == CP_LS))
22376
0
                    return '\n';
22377
0
            }
22378
19
            if (lre_is_space(c))
22379
0
                continue;
22380
19
            if (lre_js_is_ident_first(c))
22381
1
                return TOK_IDENT;
22382
18
            break;
22383
25
        }
22384
18
        return c;
22385
25
    }
22386
20
}
22387
22388
static int peek_token(JSParseState *s, BOOL no_line_terminator)
22389
20
{
22390
20
    const uint8_t *p = s->buf_ptr;
22391
20
    return simple_next_token(&p, no_line_terminator);
22392
20
}
22393
22394
static void skip_shebang(const uint8_t **pp, const uint8_t *buf_end)
22395
4
{
22396
4
    const uint8_t *p = *pp;
22397
4
    int c;
22398
22399
4
    if (p[0] == '#' && p[1] == '!') {
22400
0
        p += 2;
22401
0
        while (p < buf_end) {
22402
0
            if (*p == '\n' || *p == '\r') {
22403
0
                break;
22404
0
            } else if (*p >= 0x80) {
22405
0
                c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
22406
0
                if (c == CP_LS || c == CP_PS) {
22407
0
                    break;
22408
0
                } else if (c == -1) {
22409
0
                    p++; /* skip invalid UTF-8 */
22410
0
                }
22411
0
            } else {
22412
0
                p++;
22413
0
            }
22414
0
        }
22415
0
        *pp = p;
22416
0
    }
22417
4
}
22418
22419
/* return true if 'input' contains the source of a module
22420
   (heuristic). 'input' must be a zero terminated.
22421
22422
   Heuristic: skip comments and expect 'import' keyword not followed
22423
   by '(' or '.' or export keyword.
22424
*/
22425
BOOL JS_DetectModule(const char *input, size_t input_len)
22426
0
{
22427
0
    const uint8_t *p = (const uint8_t *)input;
22428
0
    int tok;
22429
22430
0
    skip_shebang(&p, p + input_len);
22431
0
    switch(simple_next_token(&p, FALSE)) {
22432
0
    case TOK_IMPORT:
22433
0
        tok = simple_next_token(&p, FALSE);
22434
0
        return (tok != '.' && tok != '(');
22435
0
    case TOK_EXPORT:
22436
0
        return TRUE;
22437
0
    default:
22438
0
        return FALSE;
22439
0
    }
22440
0
}
22441
22442
8
static inline int get_prev_opcode(JSFunctionDef *fd) {
22443
8
    if (fd->last_opcode_pos < 0 || dbuf_error(&fd->byte_code))
22444
0
        return OP_invalid;
22445
8
    else
22446
8
        return fd->byte_code.buf[fd->last_opcode_pos];
22447
8
}
22448
22449
0
static BOOL js_is_live_code(JSParseState *s) {
22450
0
    switch (get_prev_opcode(s->cur_func)) {
22451
0
    case OP_tail_call:
22452
0
    case OP_tail_call_method:
22453
0
    case OP_return:
22454
0
    case OP_return_undef:
22455
0
    case OP_return_async:
22456
0
    case OP_throw:
22457
0
    case OP_throw_error:
22458
0
    case OP_goto:
22459
0
#if SHORT_OPCODES
22460
0
    case OP_goto8:
22461
0
    case OP_goto16:
22462
0
#endif
22463
0
    case OP_ret:
22464
0
        return FALSE;
22465
0
    default:
22466
0
        return TRUE;
22467
0
    }
22468
0
}
22469
22470
static void emit_u8(JSParseState *s, uint8_t val)
22471
0
{
22472
0
    dbuf_putc(&s->cur_func->byte_code, val);
22473
0
}
22474
22475
static void emit_u16(JSParseState *s, uint16_t val)
22476
13
{
22477
13
    dbuf_put_u16(&s->cur_func->byte_code, val);
22478
13
}
22479
22480
static void emit_u32(JSParseState *s, uint32_t val)
22481
15
{
22482
15
    dbuf_put_u32(&s->cur_func->byte_code, val);
22483
15
}
22484
22485
static void emit_source_pos(JSParseState *s, const uint8_t *source_ptr)
22486
21
{
22487
21
    JSFunctionDef *fd = s->cur_func;
22488
21
    DynBuf *bc = &fd->byte_code;
22489
22490
21
    if (unlikely(fd->last_opcode_source_ptr != source_ptr)) {
22491
14
        dbuf_putc(bc, OP_line_num);
22492
14
        dbuf_put_u32(bc, source_ptr - s->buf_start);
22493
14
        fd->last_opcode_source_ptr = source_ptr;
22494
14
    }
22495
21
}
22496
22497
static void emit_op(JSParseState *s, uint8_t val)
22498
40
{
22499
40
    JSFunctionDef *fd = s->cur_func;
22500
40
    DynBuf *bc = &fd->byte_code;
22501
22502
40
    fd->last_opcode_pos = bc->size;
22503
40
    dbuf_putc(bc, val);
22504
40
}
22505
22506
static void emit_atom(JSParseState *s, JSAtom name)
22507
4
{
22508
4
    DynBuf *bc = &s->cur_func->byte_code;
22509
4
    if (dbuf_realloc(bc, bc->size + 4))
22510
0
        return; /* not enough memory : don't duplicate the atom */
22511
4
    put_u32(bc->buf + bc->size, JS_DupAtom(s->ctx, name));
22512
4
    bc->size += 4;
22513
4
}
22514
22515
static int update_label(JSFunctionDef *s, int label, int delta)
22516
12
{
22517
12
    LabelSlot *ls;
22518
22519
12
    assert(label >= 0 && label < s->label_count);
22520
12
    ls = &s->label_slots[label];
22521
12
    ls->ref_count += delta;
22522
12
    assert(ls->ref_count >= 0);
22523
12
    return ls->ref_count;
22524
12
}
22525
22526
static int new_label_fd(JSFunctionDef *fd)
22527
5
{
22528
5
    int label;
22529
5
    LabelSlot *ls;
22530
22531
5
    if (js_resize_array(fd->ctx, (void *)&fd->label_slots,
22532
5
                        sizeof(fd->label_slots[0]),
22533
5
                        &fd->label_size, fd->label_count + 1))
22534
0
        return -1;
22535
5
    label = fd->label_count++;
22536
5
    ls = &fd->label_slots[label];
22537
5
    ls->ref_count = 0;
22538
5
    ls->pos = -1;
22539
5
    ls->pos2 = -1;
22540
5
    ls->addr = -1;
22541
5
    ls->first_reloc = NULL;
22542
5
    return label;
22543
5
}
22544
22545
static int new_label(JSParseState *s)
22546
2
{
22547
2
    int label;
22548
2
    label = new_label_fd(s->cur_func);
22549
2
    if (unlikely(label < 0)) {
22550
0
        dbuf_set_error(&s->cur_func->byte_code);
22551
0
    }
22552
2
    return label;
22553
2
}
22554
22555
/* don't update the last opcode and don't emit line number info */
22556
static void emit_label_raw(JSParseState *s, int label)
22557
0
{
22558
0
    emit_u8(s, OP_label);
22559
0
    emit_u32(s, label);
22560
0
    s->cur_func->label_slots[label].pos = s->cur_func->byte_code.size;
22561
0
}
22562
22563
/* return the label ID offset */
22564
static int emit_label(JSParseState *s, int label)
22565
1
{
22566
1
    if (label >= 0) {
22567
1
        emit_op(s, OP_label);
22568
1
        emit_u32(s, label);
22569
1
        s->cur_func->label_slots[label].pos = s->cur_func->byte_code.size;
22570
1
        return s->cur_func->byte_code.size - 4;
22571
1
    } else {
22572
0
        return -1;
22573
0
    }
22574
1
}
22575
22576
/* return label or -1 if dead code */
22577
static int emit_goto(JSParseState *s, int opcode, int label)
22578
0
{
22579
0
    if (js_is_live_code(s)) {
22580
0
        if (label < 0) {
22581
0
            label = new_label(s);
22582
0
            if (label < 0)
22583
0
                return -1;
22584
0
        }
22585
0
        emit_op(s, opcode);
22586
0
        emit_u32(s, label);
22587
0
        s->cur_func->label_slots[label].ref_count++;
22588
0
        return label;
22589
0
    }
22590
0
    return -1;
22591
0
}
22592
22593
/* return the constant pool index. 'val' is not duplicated. */
22594
static int cpool_add(JSParseState *s, JSValue val)
22595
1
{
22596
1
    JSFunctionDef *fd = s->cur_func;
22597
22598
1
    if (js_resize_array(s->ctx, (void *)&fd->cpool, sizeof(fd->cpool[0]),
22599
1
                        &fd->cpool_size, fd->cpool_count + 1))
22600
0
        return -1;
22601
1
    fd->cpool[fd->cpool_count++] = val;
22602
1
    return fd->cpool_count - 1;
22603
1
}
22604
22605
static __exception int emit_push_const(JSParseState *s, JSValueConst val,
22606
                                       BOOL as_atom)
22607
1
{
22608
1
    int idx;
22609
22610
1
    if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING && as_atom) {
22611
0
        JSAtom atom;
22612
        /* warning: JS_NewAtomStr frees the string value */
22613
0
        JS_DupValue(s->ctx, val);
22614
0
        atom = JS_NewAtomStr(s->ctx, JS_VALUE_GET_STRING(val));
22615
0
        if (atom != JS_ATOM_NULL && !__JS_AtomIsTaggedInt(atom)) {
22616
0
            emit_op(s, OP_push_atom_value);
22617
0
            emit_u32(s, atom);
22618
0
            return 0;
22619
0
        }
22620
0
    }
22621
22622
1
    idx = cpool_add(s, JS_DupValue(s->ctx, val));
22623
1
    if (idx < 0)
22624
0
        return -1;
22625
1
    emit_op(s, OP_push_const);
22626
1
    emit_u32(s, idx);
22627
1
    return 0;
22628
1
}
22629
22630
/* return the variable index or -1 if not found,
22631
   add ARGUMENT_VAR_OFFSET for argument variables */
22632
static int find_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
22633
9
{
22634
9
    int i;
22635
9
    for(i = fd->arg_count; i-- > 0;) {
22636
0
        if (fd->args[i].var_name == name)
22637
0
            return i | ARGUMENT_VAR_OFFSET;
22638
0
    }
22639
9
    return -1;
22640
9
}
22641
22642
static int find_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
22643
9
{
22644
9
    int i;
22645
9
    for(i = fd->var_count; i-- > 0;) {
22646
0
        if (fd->vars[i].var_name == name && fd->vars[i].scope_level == 0)
22647
0
            return i;
22648
0
    }
22649
9
    return find_arg(ctx, fd, name);
22650
9
}
22651
22652
/* find a variable declaration in a given scope */
22653
static int find_var_in_scope(JSContext *ctx, JSFunctionDef *fd,
22654
                             JSAtom name, int scope_level)
22655
0
{
22656
0
    int scope_idx;
22657
0
    for(scope_idx = fd->scopes[scope_level].first; scope_idx >= 0;
22658
0
        scope_idx = fd->vars[scope_idx].scope_next) {
22659
0
        if (fd->vars[scope_idx].scope_level != scope_level)
22660
0
            break;
22661
0
        if (fd->vars[scope_idx].var_name == name)
22662
0
            return scope_idx;
22663
0
    }
22664
0
    return -1;
22665
0
}
22666
22667
/* return true if scope == parent_scope or if scope is a child of
22668
   parent_scope */
22669
static BOOL is_child_scope(JSContext *ctx, JSFunctionDef *fd,
22670
                           int scope, int parent_scope)
22671
0
{
22672
0
    while (scope >= 0) {
22673
0
        if (scope == parent_scope)
22674
0
            return TRUE;
22675
0
        scope = fd->scopes[scope].parent;
22676
0
    }
22677
0
    return FALSE;
22678
0
}
22679
22680
/* find a 'var' declaration in the same scope or a child scope */
22681
static int find_var_in_child_scope(JSContext *ctx, JSFunctionDef *fd,
22682
                                   JSAtom name, int scope_level)
22683
0
{
22684
0
    int i;
22685
0
    for(i = 0; i < fd->var_count; i++) {
22686
0
        JSVarDef *vd = &fd->vars[i];
22687
0
        if (vd->var_name == name && vd->scope_level == 0) {
22688
0
            if (is_child_scope(ctx, fd, vd->scope_next,
22689
0
                               scope_level))
22690
0
                return i;
22691
0
        }
22692
0
    }
22693
0
    return -1;
22694
0
}
22695
22696
22697
static JSGlobalVar *find_global_var(JSFunctionDef *fd, JSAtom name)
22698
0
{
22699
0
    int i;
22700
0
    for(i = 0; i < fd->global_var_count; i++) {
22701
0
        JSGlobalVar *hf = &fd->global_vars[i];
22702
0
        if (hf->var_name == name)
22703
0
            return hf;
22704
0
    }
22705
0
    return NULL;
22706
22707
0
}
22708
22709
static JSGlobalVar *find_lexical_global_var(JSFunctionDef *fd, JSAtom name)
22710
0
{
22711
0
    JSGlobalVar *hf = find_global_var(fd, name);
22712
0
    if (hf && hf->is_lexical)
22713
0
        return hf;
22714
0
    else
22715
0
        return NULL;
22716
0
}
22717
22718
static int find_lexical_decl(JSContext *ctx, JSFunctionDef *fd, JSAtom name,
22719
                             int scope_idx, BOOL check_catch_var)
22720
0
{
22721
0
    while (scope_idx >= 0) {
22722
0
        JSVarDef *vd = &fd->vars[scope_idx];
22723
0
        if (vd->var_name == name &&
22724
0
            (vd->is_lexical || (vd->var_kind == JS_VAR_CATCH &&
22725
0
                                check_catch_var)))
22726
0
            return scope_idx;
22727
0
        scope_idx = vd->scope_next;
22728
0
    }
22729
22730
0
    if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_GLOBAL) {
22731
0
        if (find_lexical_global_var(fd, name))
22732
0
            return GLOBAL_VAR_OFFSET;
22733
0
    }
22734
0
    return -1;
22735
0
}
22736
22737
4
static int push_scope(JSParseState *s) {
22738
4
    if (s->cur_func) {
22739
4
        JSFunctionDef *fd = s->cur_func;
22740
4
        int scope = fd->scope_count;
22741
        /* XXX: should check for scope overflow */
22742
4
        if ((fd->scope_count + 1) > fd->scope_size) {
22743
0
            int new_size;
22744
0
            size_t slack;
22745
0
            JSVarScope *new_buf;
22746
            /* XXX: potential arithmetic overflow */
22747
0
            new_size = max_int(fd->scope_count + 1, fd->scope_size * 3 / 2);
22748
0
            if (fd->scopes == fd->def_scope_array) {
22749
0
                new_buf = js_realloc2(s->ctx, NULL, new_size * sizeof(*fd->scopes), &slack);
22750
0
                if (!new_buf)
22751
0
                    return -1;
22752
0
                memcpy(new_buf, fd->scopes, fd->scope_count * sizeof(*fd->scopes));
22753
0
            } else {
22754
0
                new_buf = js_realloc2(s->ctx, fd->scopes, new_size * sizeof(*fd->scopes), &slack);
22755
0
                if (!new_buf)
22756
0
                    return -1;
22757
0
            }
22758
0
            new_size += slack / sizeof(*new_buf);
22759
0
            fd->scopes = new_buf;
22760
0
            fd->scope_size = new_size;
22761
0
        }
22762
4
        fd->scope_count++;
22763
4
        fd->scopes[scope].parent = fd->scope_level;
22764
4
        fd->scopes[scope].first = fd->scope_first;
22765
4
        emit_op(s, OP_enter_scope);
22766
4
        emit_u16(s, scope);
22767
4
        return fd->scope_level = scope;
22768
4
    }
22769
0
    return 0;
22770
4
}
22771
22772
static int get_first_lexical_var(JSFunctionDef *fd, int scope)
22773
0
{
22774
0
    while (scope >= 0) {
22775
0
        int scope_idx = fd->scopes[scope].first;
22776
0
        if (scope_idx >= 0)
22777
0
            return scope_idx;
22778
0
        scope = fd->scopes[scope].parent;
22779
0
    }
22780
0
    return -1;
22781
0
}
22782
22783
0
static void pop_scope(JSParseState *s) {
22784
0
    if (s->cur_func) {
22785
        /* disable scoped variables */
22786
0
        JSFunctionDef *fd = s->cur_func;
22787
0
        int scope = fd->scope_level;
22788
0
        emit_op(s, OP_leave_scope);
22789
0
        emit_u16(s, scope);
22790
0
        fd->scope_level = fd->scopes[scope].parent;
22791
0
        fd->scope_first = get_first_lexical_var(fd, fd->scope_level);
22792
0
    }
22793
0
}
22794
22795
static void close_scopes(JSParseState *s, int scope, int scope_stop)
22796
0
{
22797
0
    while (scope > scope_stop) {
22798
0
        emit_op(s, OP_leave_scope);
22799
0
        emit_u16(s, scope);
22800
0
        scope = s->cur_func->scopes[scope].parent;
22801
0
    }
22802
0
}
22803
22804
/* return the variable index or -1 if error */
22805
static int add_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
22806
0
{
22807
0
    JSVarDef *vd;
22808
22809
    /* the local variable indexes are currently stored on 16 bits */
22810
0
    if (fd->var_count >= JS_MAX_LOCAL_VARS) {
22811
0
        JS_ThrowInternalError(ctx, "too many local variables");
22812
0
        return -1;
22813
0
    }
22814
0
    if (js_resize_array(ctx, (void **)&fd->vars, sizeof(fd->vars[0]),
22815
0
                        &fd->var_size, fd->var_count + 1))
22816
0
        return -1;
22817
0
    vd = &fd->vars[fd->var_count++];
22818
0
    memset(vd, 0, sizeof(*vd));
22819
0
    vd->var_name = JS_DupAtom(ctx, name);
22820
0
    vd->func_pool_idx = -1;
22821
0
    return fd->var_count - 1;
22822
0
}
22823
22824
static int add_scope_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name,
22825
                         JSVarKindEnum var_kind)
22826
0
{
22827
0
    int idx = add_var(ctx, fd, name);
22828
0
    if (idx >= 0) {
22829
0
        JSVarDef *vd = &fd->vars[idx];
22830
0
        vd->var_kind = var_kind;
22831
0
        vd->scope_level = fd->scope_level;
22832
0
        vd->scope_next = fd->scope_first;
22833
0
        fd->scopes[fd->scope_level].first = idx;
22834
0
        fd->scope_first = idx;
22835
0
    }
22836
0
    return idx;
22837
0
}
22838
22839
static int add_func_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
22840
0
{
22841
0
    int idx = fd->func_var_idx;
22842
0
    if (idx < 0 && (idx = add_var(ctx, fd, name)) >= 0) {
22843
0
        fd->func_var_idx = idx;
22844
0
        fd->vars[idx].var_kind = JS_VAR_FUNCTION_NAME;
22845
0
        if (fd->js_mode & JS_MODE_STRICT)
22846
0
            fd->vars[idx].is_const = TRUE;
22847
0
    }
22848
0
    return idx;
22849
0
}
22850
22851
static int add_arguments_var(JSContext *ctx, JSFunctionDef *fd)
22852
0
{
22853
0
    int idx = fd->arguments_var_idx;
22854
0
    if (idx < 0 && (idx = add_var(ctx, fd, JS_ATOM_arguments)) >= 0) {
22855
0
        fd->arguments_var_idx = idx;
22856
0
    }
22857
0
    return idx;
22858
0
}
22859
22860
/* add an argument definition in the argument scope. Only needed when
22861
   "eval()" may be called in the argument scope. Return 0 if OK. */
22862
static int add_arguments_arg(JSContext *ctx, JSFunctionDef *fd)
22863
0
{
22864
0
    int idx;
22865
0
    if (fd->arguments_arg_idx < 0) {
22866
0
        idx = find_var_in_scope(ctx, fd, JS_ATOM_arguments, ARG_SCOPE_INDEX);
22867
0
        if (idx < 0) {
22868
            /* XXX: the scope links are not fully updated. May be an
22869
               issue if there are child scopes of the argument
22870
               scope */
22871
0
            idx = add_var(ctx, fd, JS_ATOM_arguments);
22872
0
            if (idx < 0)
22873
0
                return -1;
22874
0
            fd->vars[idx].scope_next = fd->scopes[ARG_SCOPE_INDEX].first;
22875
0
            fd->scopes[ARG_SCOPE_INDEX].first = idx;
22876
0
            fd->vars[idx].scope_level = ARG_SCOPE_INDEX;
22877
0
            fd->vars[idx].is_lexical = TRUE;
22878
22879
0
            fd->arguments_arg_idx = idx;
22880
0
        }
22881
0
    }
22882
0
    return 0;
22883
0
}
22884
22885
static int add_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
22886
0
{
22887
0
    JSVarDef *vd;
22888
22889
    /* the local variable indexes are currently stored on 16 bits */
22890
0
    if (fd->arg_count >= JS_MAX_LOCAL_VARS) {
22891
0
        JS_ThrowInternalError(ctx, "too many arguments");
22892
0
        return -1;
22893
0
    }
22894
0
    if (js_resize_array(ctx, (void **)&fd->args, sizeof(fd->args[0]),
22895
0
                        &fd->arg_size, fd->arg_count + 1))
22896
0
        return -1;
22897
0
    vd = &fd->args[fd->arg_count++];
22898
0
    memset(vd, 0, sizeof(*vd));
22899
0
    vd->var_name = JS_DupAtom(ctx, name);
22900
0
    vd->func_pool_idx = -1;
22901
0
    return fd->arg_count - 1;
22902
0
}
22903
22904
/* add a global variable definition */
22905
static JSGlobalVar *add_global_var(JSContext *ctx, JSFunctionDef *s,
22906
                                     JSAtom name)
22907
0
{
22908
0
    JSGlobalVar *hf;
22909
22910
0
    if (js_resize_array(ctx, (void **)&s->global_vars,
22911
0
                        sizeof(s->global_vars[0]),
22912
0
                        &s->global_var_size, s->global_var_count + 1))
22913
0
        return NULL;
22914
0
    hf = &s->global_vars[s->global_var_count++];
22915
0
    hf->cpool_idx = -1;
22916
0
    hf->force_init = FALSE;
22917
0
    hf->is_lexical = FALSE;
22918
0
    hf->is_const = FALSE;
22919
0
    hf->scope_level = s->scope_level;
22920
0
    hf->var_name = JS_DupAtom(ctx, name);
22921
0
    return hf;
22922
0
}
22923
22924
typedef enum {
22925
    JS_VAR_DEF_WITH,
22926
    JS_VAR_DEF_LET,
22927
    JS_VAR_DEF_CONST,
22928
    JS_VAR_DEF_FUNCTION_DECL, /* function declaration */
22929
    JS_VAR_DEF_NEW_FUNCTION_DECL, /* async/generator function declaration */
22930
    JS_VAR_DEF_CATCH,
22931
    JS_VAR_DEF_VAR,
22932
} JSVarDefEnum;
22933
22934
static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
22935
                      JSVarDefEnum var_def_type)
22936
0
{
22937
0
    JSContext *ctx = s->ctx;
22938
0
    JSVarDef *vd;
22939
0
    int idx;
22940
22941
0
    switch (var_def_type) {
22942
0
    case JS_VAR_DEF_WITH:
22943
0
        idx = add_scope_var(ctx, fd, name, JS_VAR_NORMAL);
22944
0
        break;
22945
22946
0
    case JS_VAR_DEF_LET:
22947
0
    case JS_VAR_DEF_CONST:
22948
0
    case JS_VAR_DEF_FUNCTION_DECL:
22949
0
    case JS_VAR_DEF_NEW_FUNCTION_DECL:
22950
0
        idx = find_lexical_decl(ctx, fd, name, fd->scope_first, TRUE);
22951
0
        if (idx >= 0) {
22952
0
            if (idx < GLOBAL_VAR_OFFSET) {
22953
0
                if (fd->vars[idx].scope_level == fd->scope_level) {
22954
                    /* same scope: in non strict mode, functions
22955
                       can be redefined (annex B.3.3.4). */
22956
0
                    if (!(!(fd->js_mode & JS_MODE_STRICT) &&
22957
0
                          var_def_type == JS_VAR_DEF_FUNCTION_DECL &&
22958
0
                          fd->vars[idx].var_kind == JS_VAR_FUNCTION_DECL)) {
22959
0
                        goto redef_lex_error;
22960
0
                    }
22961
0
                } else if (fd->vars[idx].var_kind == JS_VAR_CATCH && (fd->vars[idx].scope_level + 2) == fd->scope_level) {
22962
0
                    goto redef_lex_error;
22963
0
                }
22964
0
            } else {
22965
0
                if (fd->scope_level == fd->body_scope) {
22966
0
                redef_lex_error:
22967
                    /* redefining a scoped var in the same scope: error */
22968
0
                    return js_parse_error(s, "invalid redefinition of lexical identifier");
22969
0
                }
22970
0
            }
22971
0
        }
22972
0
        if (var_def_type != JS_VAR_DEF_FUNCTION_DECL &&
22973
0
            var_def_type != JS_VAR_DEF_NEW_FUNCTION_DECL &&
22974
0
            fd->scope_level == fd->body_scope &&
22975
0
            find_arg(ctx, fd, name) >= 0) {
22976
            /* lexical variable redefines a parameter name */
22977
0
            return js_parse_error(s, "invalid redefinition of parameter name");
22978
0
        }
22979
22980
0
        if (find_var_in_child_scope(ctx, fd, name, fd->scope_level) >= 0) {
22981
0
            return js_parse_error(s, "invalid redefinition of a variable");
22982
0
        }
22983
22984
0
        if (fd->is_global_var) {
22985
0
            JSGlobalVar *hf;
22986
0
            hf = find_global_var(fd, name);
22987
0
            if (hf && is_child_scope(ctx, fd, hf->scope_level,
22988
0
                                     fd->scope_level)) {
22989
0
                return js_parse_error(s, "invalid redefinition of global identifier");
22990
0
            }
22991
0
        }
22992
22993
0
        if (fd->is_eval &&
22994
0
            (fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
22995
0
             fd->eval_type == JS_EVAL_TYPE_MODULE) &&
22996
0
            fd->scope_level == fd->body_scope) {
22997
0
            JSGlobalVar *hf;
22998
0
            hf = add_global_var(s->ctx, fd, name);
22999
0
            if (!hf)
23000
0
                return -1;
23001
0
            hf->is_lexical = TRUE;
23002
0
            hf->is_const = (var_def_type == JS_VAR_DEF_CONST);
23003
0
            idx = GLOBAL_VAR_OFFSET;
23004
0
        } else {
23005
0
            JSVarKindEnum var_kind;
23006
0
            if (var_def_type == JS_VAR_DEF_FUNCTION_DECL)
23007
0
                var_kind = JS_VAR_FUNCTION_DECL;
23008
0
            else if (var_def_type == JS_VAR_DEF_NEW_FUNCTION_DECL)
23009
0
                var_kind = JS_VAR_NEW_FUNCTION_DECL;
23010
0
            else
23011
0
                var_kind = JS_VAR_NORMAL;
23012
0
            idx = add_scope_var(ctx, fd, name, var_kind);
23013
0
            if (idx >= 0) {
23014
0
                vd = &fd->vars[idx];
23015
0
                vd->is_lexical = 1;
23016
0
                vd->is_const = (var_def_type == JS_VAR_DEF_CONST);
23017
0
            }
23018
0
        }
23019
0
        break;
23020
23021
0
    case JS_VAR_DEF_CATCH:
23022
0
        idx = add_scope_var(ctx, fd, name, JS_VAR_CATCH);
23023
0
        break;
23024
23025
0
    case JS_VAR_DEF_VAR:
23026
0
        if (find_lexical_decl(ctx, fd, name, fd->scope_first,
23027
0
                              FALSE) >= 0) {
23028
0
       invalid_lexical_redefinition:
23029
            /* error to redefine a var that inside a lexical scope */
23030
0
            return js_parse_error(s, "invalid redefinition of lexical identifier");
23031
0
        }
23032
0
        if (fd->is_global_var) {
23033
0
            JSGlobalVar *hf;
23034
0
            hf = find_global_var(fd, name);
23035
0
            if (hf && hf->is_lexical && hf->scope_level == fd->scope_level &&
23036
0
                fd->eval_type == JS_EVAL_TYPE_MODULE) {
23037
0
                goto invalid_lexical_redefinition;
23038
0
            }
23039
0
            hf = add_global_var(s->ctx, fd, name);
23040
0
            if (!hf)
23041
0
                return -1;
23042
0
            idx = GLOBAL_VAR_OFFSET;
23043
0
        } else {
23044
            /* if the variable already exists, don't add it again  */
23045
0
            idx = find_var(ctx, fd, name);
23046
0
            if (idx >= 0)
23047
0
                break;
23048
0
            idx = add_var(ctx, fd, name);
23049
0
            if (idx >= 0) {
23050
0
                if (name == JS_ATOM_arguments && fd->has_arguments_binding)
23051
0
                    fd->arguments_var_idx = idx;
23052
0
                fd->vars[idx].scope_next = fd->scope_level;
23053
0
            }
23054
0
        }
23055
0
        break;
23056
0
    default:
23057
0
        abort();
23058
0
    }
23059
0
    return idx;
23060
0
}
23061
23062
/* add a private field variable in the current scope */
23063
static int add_private_class_field(JSParseState *s, JSFunctionDef *fd,
23064
                                   JSAtom name, JSVarKindEnum var_kind, BOOL is_static)
23065
0
{
23066
0
    JSContext *ctx = s->ctx;
23067
0
    JSVarDef *vd;
23068
0
    int idx;
23069
23070
0
    idx = add_scope_var(ctx, fd, name, var_kind);
23071
0
    if (idx < 0)
23072
0
        return idx;
23073
0
    vd = &fd->vars[idx];
23074
0
    vd->is_lexical = 1;
23075
0
    vd->is_const = 1;
23076
0
    vd->is_static_private = is_static;
23077
0
    return idx;
23078
0
}
23079
23080
static __exception int js_parse_expr(JSParseState *s);
23081
static __exception int js_parse_function_decl(JSParseState *s,
23082
                                              JSParseFunctionEnum func_type,
23083
                                              JSFunctionKindEnum func_kind,
23084
                                              JSAtom func_name, const uint8_t *ptr);
23085
static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s);
23086
static __exception int js_parse_function_decl2(JSParseState *s,
23087
                                               JSParseFunctionEnum func_type,
23088
                                               JSFunctionKindEnum func_kind,
23089
                                               JSAtom func_name,
23090
                                               const uint8_t *ptr,
23091
                                               JSParseExportEnum export_flag,
23092
                                               JSFunctionDef **pfd);
23093
static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags);
23094
static __exception int js_parse_assign_expr(JSParseState *s);
23095
static __exception int js_parse_unary(JSParseState *s, int parse_flags);
23096
static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
23097
                             JSAtom label_name,
23098
                             int label_break, int label_cont,
23099
                             int drop_count);
23100
static void pop_break_entry(JSFunctionDef *fd);
23101
static JSExportEntry *add_export_entry(JSParseState *s, JSModuleDef *m,
23102
                                       JSAtom local_name, JSAtom export_name,
23103
                                       JSExportTypeEnum export_type);
23104
23105
/* Note: all the fields are already sealed except length */
23106
static int seal_template_obj(JSContext *ctx, JSValueConst obj)
23107
0
{
23108
0
    JSObject *p;
23109
0
    JSShapeProperty *prs;
23110
23111
0
    p = JS_VALUE_GET_OBJ(obj);
23112
0
    prs = find_own_property1(p, JS_ATOM_length);
23113
0
    if (prs) {
23114
0
        if (js_update_property_flags(ctx, p, &prs,
23115
0
                                     prs->flags & ~(JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)))
23116
0
            return -1;
23117
0
    }
23118
0
    p->extensible = FALSE;
23119
0
    return 0;
23120
0
}
23121
23122
static __exception int js_parse_template(JSParseState *s, int call, int *argc)
23123
0
{
23124
0
    JSContext *ctx = s->ctx;
23125
0
    JSValue raw_array, template_object;
23126
0
    JSToken cooked;
23127
0
    int depth, ret;
23128
23129
0
    raw_array = JS_UNDEFINED; /* avoid warning */
23130
0
    template_object = JS_UNDEFINED; /* avoid warning */
23131
0
    if (call) {
23132
        /* Create a template object: an array of cooked strings */
23133
        /* Create an array of raw strings and store it to the raw property */
23134
0
        template_object = JS_NewArray(ctx);
23135
0
        if (JS_IsException(template_object))
23136
0
            return -1;
23137
        //        pool_idx = s->cur_func->cpool_count;
23138
0
        ret = emit_push_const(s, template_object, 0);
23139
0
        JS_FreeValue(ctx, template_object);
23140
0
        if (ret)
23141
0
            return -1;
23142
0
        raw_array = JS_NewArray(ctx);
23143
0
        if (JS_IsException(raw_array))
23144
0
            return -1;
23145
0
        if (JS_DefinePropertyValue(ctx, template_object, JS_ATOM_raw,
23146
0
                                   raw_array, JS_PROP_THROW) < 0) {
23147
0
            return -1;
23148
0
        }
23149
0
    }
23150
23151
0
    depth = 0;
23152
0
    while (s->token.val == TOK_TEMPLATE) {
23153
0
        const uint8_t *p = s->token.ptr + 1;
23154
0
        cooked = s->token;
23155
0
        if (call) {
23156
0
            if (JS_DefinePropertyValueUint32(ctx, raw_array, depth,
23157
0
                                             JS_DupValue(ctx, s->token.u.str.str),
23158
0
                                             JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) {
23159
0
                return -1;
23160
0
            }
23161
            /* re-parse the string with escape sequences but do not throw a
23162
               syntax error if it contains invalid sequences
23163
             */
23164
0
            if (js_parse_string(s, '`', FALSE, p, &cooked, &p)) {
23165
0
                cooked.u.str.str = JS_UNDEFINED;
23166
0
            }
23167
0
            if (JS_DefinePropertyValueUint32(ctx, template_object, depth,
23168
0
                                             cooked.u.str.str,
23169
0
                                             JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) {
23170
0
                return -1;
23171
0
            }
23172
0
        } else {
23173
0
            JSString *str;
23174
            /* re-parse the string with escape sequences and throw a
23175
               syntax error if it contains invalid sequences
23176
             */
23177
0
            JS_FreeValue(ctx, s->token.u.str.str);
23178
0
            s->token.u.str.str = JS_UNDEFINED;
23179
0
            if (js_parse_string(s, '`', TRUE, p, &cooked, &p))
23180
0
                return -1;
23181
0
            str = JS_VALUE_GET_STRING(cooked.u.str.str);
23182
0
            if (str->len != 0 || depth == 0) {
23183
0
                ret = emit_push_const(s, cooked.u.str.str, 1);
23184
0
                JS_FreeValue(s->ctx, cooked.u.str.str);
23185
0
                if (ret)
23186
0
                    return -1;
23187
0
                if (depth == 0) {
23188
0
                    if (s->token.u.str.sep == '`')
23189
0
                        goto done1;
23190
0
                    emit_op(s, OP_get_field2);
23191
0
                    emit_atom(s, JS_ATOM_concat);
23192
0
                }
23193
0
                depth++;
23194
0
            } else {
23195
0
                JS_FreeValue(s->ctx, cooked.u.str.str);
23196
0
            }
23197
0
        }
23198
0
        if (s->token.u.str.sep == '`')
23199
0
            goto done;
23200
0
        if (next_token(s))
23201
0
            return -1;
23202
0
        if (js_parse_expr(s))
23203
0
            return -1;
23204
0
        depth++;
23205
0
        if (s->token.val != '}') {
23206
0
            return js_parse_error(s, "expected '}' after template expression");
23207
0
        }
23208
        /* XXX: should convert to string at this stage? */
23209
0
        free_token(s, &s->token);
23210
        /* Resume TOK_TEMPLATE parsing (s->token.line_num and
23211
         * s->token.ptr are OK) */
23212
0
        s->got_lf = FALSE;
23213
0
        if (js_parse_template_part(s, s->buf_ptr))
23214
0
            return -1;
23215
0
    }
23216
0
    return js_parse_expect(s, TOK_TEMPLATE);
23217
23218
0
 done:
23219
0
    if (call) {
23220
        /* Seal the objects */
23221
0
        seal_template_obj(ctx, raw_array);
23222
0
        seal_template_obj(ctx, template_object);
23223
0
        *argc = depth + 1;
23224
0
    } else {
23225
0
        emit_op(s, OP_call_method);
23226
0
        emit_u16(s, depth - 1);
23227
0
    }
23228
0
 done1:
23229
0
    return next_token(s);
23230
0
}
23231
23232
23233
0
#define PROP_TYPE_IDENT 0
23234
0
#define PROP_TYPE_VAR   1
23235
0
#define PROP_TYPE_GET   2
23236
0
#define PROP_TYPE_SET   3
23237
0
#define PROP_TYPE_STAR  4
23238
0
#define PROP_TYPE_ASYNC 5
23239
0
#define PROP_TYPE_ASYNC_STAR 6
23240
23241
0
#define PROP_TYPE_PRIVATE (1 << 4)
23242
23243
static BOOL token_is_ident(int tok)
23244
8
{
23245
    /* Accept keywords and reserved words as property names */
23246
8
    return (tok == TOK_IDENT ||
23247
8
            (tok >= TOK_FIRST_KEYWORD &&
23248
0
             tok <= TOK_LAST_KEYWORD));
23249
8
}
23250
23251
/* if the property is an expression, name = JS_ATOM_NULL */
23252
static int __exception js_parse_property_name(JSParseState *s,
23253
                                              JSAtom *pname,
23254
                                              BOOL allow_method, BOOL allow_var,
23255
                                              BOOL allow_private)
23256
0
{
23257
0
    int is_private = 0;
23258
0
    BOOL is_non_reserved_ident;
23259
0
    JSAtom name;
23260
0
    int prop_type;
23261
23262
0
    prop_type = PROP_TYPE_IDENT;
23263
0
    if (allow_method) {
23264
        /* if allow_private is true (for class field parsing) and
23265
           get/set is following by ';' (or LF with ASI), then it
23266
           is a field name */
23267
0
        if ((token_is_pseudo_keyword(s, JS_ATOM_get) ||
23268
0
             token_is_pseudo_keyword(s, JS_ATOM_set)) &&
23269
0
            (!allow_private || peek_token(s, TRUE) != '\n')) {
23270
            /* get x(), set x() */
23271
0
            name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
23272
0
            if (next_token(s))
23273
0
                goto fail1;
23274
0
            if (s->token.val == ':' || s->token.val == ',' ||
23275
0
                s->token.val == '}' || s->token.val == '(' ||
23276
0
                s->token.val == '=' ||
23277
0
                (s->token.val == ';' && allow_private)) {
23278
0
                is_non_reserved_ident = TRUE;
23279
0
                goto ident_found;
23280
0
            }
23281
0
            prop_type = PROP_TYPE_GET + (name == JS_ATOM_set);
23282
0
            JS_FreeAtom(s->ctx, name);
23283
0
        } else if (s->token.val == '*') {
23284
0
            if (next_token(s))
23285
0
                goto fail;
23286
0
            prop_type = PROP_TYPE_STAR;
23287
0
        } else if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
23288
0
                   peek_token(s, TRUE) != '\n') {
23289
0
            name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
23290
0
            if (next_token(s))
23291
0
                goto fail1;
23292
0
            if (s->token.val == ':' || s->token.val == ',' ||
23293
0
                s->token.val == '}' || s->token.val == '(' ||
23294
0
                s->token.val == '=') {
23295
0
                is_non_reserved_ident = TRUE;
23296
0
                goto ident_found;
23297
0
            }
23298
0
            JS_FreeAtom(s->ctx, name);
23299
0
            if (s->token.val == '*') {
23300
0
                if (next_token(s))
23301
0
                    goto fail;
23302
0
                prop_type = PROP_TYPE_ASYNC_STAR;
23303
0
            } else {
23304
0
                prop_type = PROP_TYPE_ASYNC;
23305
0
            }
23306
0
        }
23307
0
    }
23308
23309
0
    if (token_is_ident(s->token.val)) {
23310
        /* variable can only be a non-reserved identifier */
23311
0
        is_non_reserved_ident =
23312
0
            (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved);
23313
        /* keywords and reserved words have a valid atom */
23314
0
        name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
23315
0
        if (next_token(s))
23316
0
            goto fail1;
23317
0
    ident_found:
23318
0
        if (is_non_reserved_ident &&
23319
0
            prop_type == PROP_TYPE_IDENT && allow_var) {
23320
0
            if (!(s->token.val == ':' ||
23321
0
                  (s->token.val == '(' && allow_method))) {
23322
0
                prop_type = PROP_TYPE_VAR;
23323
0
            }
23324
0
        }
23325
0
    } else if (s->token.val == TOK_STRING) {
23326
0
        name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
23327
0
        if (name == JS_ATOM_NULL)
23328
0
            goto fail;
23329
0
        if (next_token(s))
23330
0
            goto fail1;
23331
0
    } else if (s->token.val == TOK_NUMBER) {
23332
0
        JSValue val;
23333
0
        val = s->token.u.num.val;
23334
0
        name = JS_ValueToAtom(s->ctx, val);
23335
0
        if (name == JS_ATOM_NULL)
23336
0
            goto fail;
23337
0
        if (next_token(s))
23338
0
            goto fail1;
23339
0
    } else if (s->token.val == '[') {
23340
0
        if (next_token(s))
23341
0
            goto fail;
23342
0
        if (js_parse_expr(s))
23343
0
            goto fail;
23344
0
        if (js_parse_expect(s, ']'))
23345
0
            goto fail;
23346
0
        name = JS_ATOM_NULL;
23347
0
    } else if (s->token.val == TOK_PRIVATE_NAME && allow_private) {
23348
0
        name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
23349
0
        if (next_token(s))
23350
0
            goto fail1;
23351
0
        is_private = PROP_TYPE_PRIVATE;
23352
0
    } else {
23353
0
        goto invalid_prop;
23354
0
    }
23355
0
    if (prop_type != PROP_TYPE_IDENT && prop_type != PROP_TYPE_VAR &&
23356
0
        s->token.val != '(') {
23357
0
        JS_FreeAtom(s->ctx, name);
23358
0
    invalid_prop:
23359
0
        js_parse_error(s, "invalid property name");
23360
0
        goto fail;
23361
0
    }
23362
0
    *pname = name;
23363
0
    return prop_type | is_private;
23364
0
 fail1:
23365
0
    JS_FreeAtom(s->ctx, name);
23366
0
 fail:
23367
0
    *pname = JS_ATOM_NULL;
23368
0
    return -1;
23369
0
}
23370
23371
typedef struct JSParsePos {
23372
    BOOL got_lf;
23373
    const uint8_t *ptr;
23374
} JSParsePos;
23375
23376
static int js_parse_get_pos(JSParseState *s, JSParsePos *sp)
23377
0
{
23378
0
    sp->ptr = s->token.ptr;
23379
0
    sp->got_lf = s->got_lf;
23380
0
    return 0;
23381
0
}
23382
23383
static __exception int js_parse_seek_token(JSParseState *s, const JSParsePos *sp)
23384
0
{
23385
0
    s->buf_ptr = sp->ptr;
23386
0
    s->got_lf = sp->got_lf;
23387
0
    return next_token(s);
23388
0
}
23389
23390
/* return TRUE if a regexp literal is allowed after this token */
23391
static BOOL is_regexp_allowed(int tok)
23392
0
{
23393
0
    switch (tok) {
23394
0
    case TOK_NUMBER:
23395
0
    case TOK_STRING:
23396
0
    case TOK_REGEXP:
23397
0
    case TOK_DEC:
23398
0
    case TOK_INC:
23399
0
    case TOK_NULL:
23400
0
    case TOK_FALSE:
23401
0
    case TOK_TRUE:
23402
0
    case TOK_THIS:
23403
0
    case ')':
23404
0
    case ']':
23405
0
    case '}': /* XXX: regexp may occur after */
23406
0
    case TOK_IDENT:
23407
0
        return FALSE;
23408
0
    default:
23409
0
        return TRUE;
23410
0
    }
23411
0
}
23412
23413
0
#define SKIP_HAS_SEMI       (1 << 0)
23414
0
#define SKIP_HAS_ELLIPSIS   (1 << 1)
23415
0
#define SKIP_HAS_ASSIGNMENT (1 << 2)
23416
23417
static BOOL has_lf_in_range(const uint8_t *p1, const uint8_t *p2)
23418
0
{
23419
0
    const uint8_t *tmp;
23420
0
    if (p1 > p2) {
23421
0
        tmp = p1;
23422
0
        p1 = p2;
23423
0
        p2 = tmp;
23424
0
    }
23425
0
    return (memchr(p1, '\n', p2 - p1) != NULL);
23426
0
}
23427
23428
/* XXX: improve speed with early bailout */
23429
/* XXX: no longer works if regexps are present. Could use previous
23430
   regexp parsing heuristics to handle most cases */
23431
static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_terminator)
23432
0
{
23433
0
    char state[256];
23434
0
    size_t level = 0;
23435
0
    JSParsePos pos;
23436
0
    int last_tok, tok = TOK_EOF;
23437
0
    int c, tok_len, bits = 0;
23438
0
    const uint8_t *last_token_ptr;
23439
    
23440
    /* protect from underflow */
23441
0
    state[level++] = 0;
23442
23443
0
    js_parse_get_pos(s, &pos);
23444
0
    last_tok = 0;
23445
0
    for (;;) {
23446
0
        switch(s->token.val) {
23447
0
        case '(':
23448
0
        case '[':
23449
0
        case '{':
23450
0
            if (level >= sizeof(state))
23451
0
                goto done;
23452
0
            state[level++] = s->token.val;
23453
0
            break;
23454
0
        case ')':
23455
0
            if (state[--level] != '(')
23456
0
                goto done;
23457
0
            break;
23458
0
        case ']':
23459
0
            if (state[--level] != '[')
23460
0
                goto done;
23461
0
            break;
23462
0
        case '}':
23463
0
            c = state[--level];
23464
0
            if (c == '`') {
23465
                /* continue the parsing of the template */
23466
0
                free_token(s, &s->token);
23467
                /* Resume TOK_TEMPLATE parsing (s->token.line_num and
23468
                 * s->token.ptr are OK) */
23469
0
                s->got_lf = FALSE;
23470
0
                if (js_parse_template_part(s, s->buf_ptr))
23471
0
                    goto done;
23472
0
                goto handle_template;
23473
0
            } else if (c != '{') {
23474
0
                goto done;
23475
0
            }
23476
0
            break;
23477
0
        case TOK_TEMPLATE:
23478
0
        handle_template:
23479
0
            if (s->token.u.str.sep != '`') {
23480
                /* '${' inside the template : closing '}' and continue
23481
                   parsing the template */
23482
0
                if (level >= sizeof(state))
23483
0
                    goto done;
23484
0
                state[level++] = '`';
23485
0
            }
23486
0
            break;
23487
0
        case TOK_EOF:
23488
0
            goto done;
23489
0
        case ';':
23490
0
            if (level == 2) {
23491
0
                bits |= SKIP_HAS_SEMI;
23492
0
            }
23493
0
            break;
23494
0
        case TOK_ELLIPSIS:
23495
0
            if (level == 2) {
23496
0
                bits |= SKIP_HAS_ELLIPSIS;
23497
0
            }
23498
0
            break;
23499
0
        case '=':
23500
0
            bits |= SKIP_HAS_ASSIGNMENT;
23501
0
            break;
23502
23503
0
        case TOK_DIV_ASSIGN:
23504
0
            tok_len = 2;
23505
0
            goto parse_regexp;
23506
0
        case '/':
23507
0
            tok_len = 1;
23508
0
        parse_regexp:
23509
0
            if (is_regexp_allowed(last_tok)) {
23510
0
                s->buf_ptr -= tok_len;
23511
0
                if (js_parse_regexp(s)) {
23512
                    /* XXX: should clear the exception */
23513
0
                    goto done;
23514
0
                }
23515
0
            }
23516
0
            break;
23517
0
        }
23518
        /* last_tok is only used to recognize regexps */
23519
0
        if (s->token.val == TOK_IDENT &&
23520
0
            (token_is_pseudo_keyword(s, JS_ATOM_of) ||
23521
0
             token_is_pseudo_keyword(s, JS_ATOM_yield))) {
23522
0
            last_tok = TOK_OF;
23523
0
        } else {
23524
0
            last_tok = s->token.val;
23525
0
        }
23526
0
        last_token_ptr = s->token.ptr;
23527
0
        if (next_token(s)) {
23528
            /* XXX: should clear the exception generated by next_token() */
23529
0
            break;
23530
0
        }
23531
0
        if (level <= 1) {
23532
0
            tok = s->token.val;
23533
0
            if (token_is_pseudo_keyword(s, JS_ATOM_of))
23534
0
                tok = TOK_OF;
23535
0
            if (no_line_terminator && has_lf_in_range(last_token_ptr, s->token.ptr))
23536
0
                tok = '\n';
23537
0
            break;
23538
0
        }
23539
0
    }
23540
0
 done:
23541
0
    if (pbits) {
23542
0
        *pbits = bits;
23543
0
    }
23544
0
    if (js_parse_seek_token(s, &pos))
23545
0
        return -1;
23546
0
    return tok;
23547
0
}
23548
23549
static void set_object_name(JSParseState *s, JSAtom name)
23550
0
{
23551
0
    JSFunctionDef *fd = s->cur_func;
23552
0
    int opcode;
23553
23554
0
    opcode = get_prev_opcode(fd);
23555
0
    if (opcode == OP_set_name) {
23556
        /* XXX: should free atom after OP_set_name? */
23557
0
        fd->byte_code.size = fd->last_opcode_pos;
23558
0
        fd->last_opcode_pos = -1;
23559
0
        emit_op(s, OP_set_name);
23560
0
        emit_atom(s, name);
23561
0
    } else if (opcode == OP_set_class_name) {
23562
0
        int define_class_pos;
23563
0
        JSAtom atom;
23564
0
        define_class_pos = fd->last_opcode_pos + 1 -
23565
0
            get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
23566
0
        assert(fd->byte_code.buf[define_class_pos] == OP_define_class);
23567
        /* for consistency we free the previous atom which is
23568
           JS_ATOM_empty_string */
23569
0
        atom = get_u32(fd->byte_code.buf + define_class_pos + 1);
23570
0
        JS_FreeAtom(s->ctx, atom);
23571
0
        put_u32(fd->byte_code.buf + define_class_pos + 1,
23572
0
                JS_DupAtom(s->ctx, name));
23573
0
        fd->last_opcode_pos = -1;
23574
0
    }
23575
0
}
23576
23577
static void set_object_name_computed(JSParseState *s)
23578
0
{
23579
0
    JSFunctionDef *fd = s->cur_func;
23580
0
    int opcode;
23581
23582
0
    opcode = get_prev_opcode(fd);
23583
0
    if (opcode == OP_set_name) {
23584
        /* XXX: should free atom after OP_set_name? */
23585
0
        fd->byte_code.size = fd->last_opcode_pos;
23586
0
        fd->last_opcode_pos = -1;
23587
0
        emit_op(s, OP_set_name_computed);
23588
0
    } else if (opcode == OP_set_class_name) {
23589
0
        int define_class_pos;
23590
0
        define_class_pos = fd->last_opcode_pos + 1 -
23591
0
            get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
23592
0
        assert(fd->byte_code.buf[define_class_pos] == OP_define_class);
23593
0
        fd->byte_code.buf[define_class_pos] = OP_define_class_computed;
23594
0
        fd->last_opcode_pos = -1;
23595
0
    }
23596
0
}
23597
23598
static __exception int js_parse_object_literal(JSParseState *s)
23599
0
{
23600
0
    JSAtom name = JS_ATOM_NULL;
23601
0
    const uint8_t *start_ptr;
23602
0
    int prop_type;
23603
0
    BOOL has_proto;
23604
23605
0
    if (next_token(s))
23606
0
        goto fail;
23607
    /* XXX: add an initial length that will be patched back */
23608
0
    emit_op(s, OP_object);
23609
0
    has_proto = FALSE;
23610
0
    while (s->token.val != '}') {
23611
        /* specific case for getter/setter */
23612
0
        start_ptr = s->token.ptr;
23613
23614
0
        if (s->token.val == TOK_ELLIPSIS) {
23615
0
            if (next_token(s))
23616
0
                return -1;
23617
0
            if (js_parse_assign_expr(s))
23618
0
                return -1;
23619
0
            emit_op(s, OP_null);  /* dummy excludeList */
23620
0
            emit_op(s, OP_copy_data_properties);
23621
0
            emit_u8(s, 2 | (1 << 2) | (0 << 5));
23622
0
            emit_op(s, OP_drop); /* pop excludeList */
23623
0
            emit_op(s, OP_drop); /* pop src object */
23624
0
            goto next;
23625
0
        }
23626
23627
0
        prop_type = js_parse_property_name(s, &name, TRUE, TRUE, FALSE);
23628
0
        if (prop_type < 0)
23629
0
            goto fail;
23630
23631
0
        if (prop_type == PROP_TYPE_VAR) {
23632
            /* shortcut for x: x */
23633
0
            emit_op(s, OP_scope_get_var);
23634
0
            emit_atom(s, name);
23635
0
            emit_u16(s, s->cur_func->scope_level);
23636
0
            emit_op(s, OP_define_field);
23637
0
            emit_atom(s, name);
23638
0
        } else if (s->token.val == '(') {
23639
0
            BOOL is_getset = (prop_type == PROP_TYPE_GET ||
23640
0
                              prop_type == PROP_TYPE_SET);
23641
0
            JSParseFunctionEnum func_type;
23642
0
            JSFunctionKindEnum func_kind;
23643
0
            int op_flags;
23644
23645
0
            func_kind = JS_FUNC_NORMAL;
23646
0
            if (is_getset) {
23647
0
                func_type = JS_PARSE_FUNC_GETTER + prop_type - PROP_TYPE_GET;
23648
0
            } else {
23649
0
                func_type = JS_PARSE_FUNC_METHOD;
23650
0
                if (prop_type == PROP_TYPE_STAR)
23651
0
                    func_kind = JS_FUNC_GENERATOR;
23652
0
                else if (prop_type == PROP_TYPE_ASYNC)
23653
0
                    func_kind = JS_FUNC_ASYNC;
23654
0
                else if (prop_type == PROP_TYPE_ASYNC_STAR)
23655
0
                    func_kind = JS_FUNC_ASYNC_GENERATOR;
23656
0
            }
23657
0
            if (js_parse_function_decl(s, func_type, func_kind, JS_ATOM_NULL,
23658
0
                                       start_ptr))
23659
0
                goto fail;
23660
0
            if (name == JS_ATOM_NULL) {
23661
0
                emit_op(s, OP_define_method_computed);
23662
0
            } else {
23663
0
                emit_op(s, OP_define_method);
23664
0
                emit_atom(s, name);
23665
0
            }
23666
0
            if (is_getset) {
23667
0
                op_flags = OP_DEFINE_METHOD_GETTER +
23668
0
                    prop_type - PROP_TYPE_GET;
23669
0
            } else {
23670
0
                op_flags = OP_DEFINE_METHOD_METHOD;
23671
0
            }
23672
0
            emit_u8(s, op_flags | OP_DEFINE_METHOD_ENUMERABLE);
23673
0
        } else {
23674
0
            if (name == JS_ATOM_NULL) {
23675
                /* must be done before evaluating expr */
23676
0
                emit_op(s, OP_to_propkey);
23677
0
            }
23678
0
            if (js_parse_expect(s, ':'))
23679
0
                goto fail;
23680
0
            if (js_parse_assign_expr(s))
23681
0
                goto fail;
23682
0
            if (name == JS_ATOM_NULL) {
23683
0
                set_object_name_computed(s);
23684
0
                emit_op(s, OP_define_array_el);
23685
0
                emit_op(s, OP_drop);
23686
0
            } else if (name == JS_ATOM___proto__) {
23687
0
                if (has_proto) {
23688
0
                    js_parse_error(s, "duplicate __proto__ property name");
23689
0
                    goto fail;
23690
0
                }
23691
0
                emit_op(s, OP_set_proto);
23692
0
                has_proto = TRUE;
23693
0
            } else {
23694
0
                set_object_name(s, name);
23695
0
                emit_op(s, OP_define_field);
23696
0
                emit_atom(s, name);
23697
0
            }
23698
0
        }
23699
0
        JS_FreeAtom(s->ctx, name);
23700
0
    next:
23701
0
        name = JS_ATOM_NULL;
23702
0
        if (s->token.val != ',')
23703
0
            break;
23704
0
        if (next_token(s))
23705
0
            goto fail;
23706
0
    }
23707
0
    if (js_parse_expect(s, '}'))
23708
0
        goto fail;
23709
0
    return 0;
23710
0
 fail:
23711
0
    JS_FreeAtom(s->ctx, name);
23712
0
    return -1;
23713
0
}
23714
23715
/* allow the 'in' binary operator */
23716
7
#define PF_IN_ACCEPTED  (1 << 0)
23717
/* allow function calls parsing in js_parse_postfix_expr() */
23718
22
#define PF_POSTFIX_CALL (1 << 1)
23719
/* allow the exponentiation operator in js_parse_unary() */
23720
22
#define PF_POW_ALLOWED  (1 << 2)
23721
/* forbid the exponentiation operator in js_parse_unary() */
23722
12
#define PF_POW_FORBIDDEN (1 << 3)
23723
23724
static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags);
23725
static void emit_class_field_init(JSParseState *s);
23726
static JSFunctionDef *js_new_function_def(JSContext *ctx,
23727
                                          JSFunctionDef *parent,
23728
                                          BOOL is_eval,
23729
                                          BOOL is_func_expr,
23730
                                          const char *filename,
23731
                                          const uint8_t *source_ptr,
23732
                                          GetLineColCache *get_line_col_cache);
23733
static void emit_return(JSParseState *s, BOOL hasval);
23734
23735
static __exception int js_parse_left_hand_side_expr(JSParseState *s)
23736
0
{
23737
0
    return js_parse_postfix_expr(s, PF_POSTFIX_CALL);
23738
0
}
23739
23740
static __exception int js_parse_class_default_ctor(JSParseState *s,
23741
                                                   BOOL has_super,
23742
                                                   JSFunctionDef **pfd)
23743
0
{
23744
0
    JSParseFunctionEnum func_type;
23745
0
    JSFunctionDef *fd = s->cur_func;
23746
0
    int idx;
23747
23748
0
    fd = js_new_function_def(s->ctx, fd, FALSE, FALSE, s->filename,
23749
0
                             s->token.ptr, &s->get_line_col_cache);
23750
0
    if (!fd)
23751
0
        return -1;
23752
23753
0
    s->cur_func = fd;
23754
0
    fd->has_home_object = TRUE;
23755
0
    fd->super_allowed = TRUE;
23756
0
    fd->has_prototype = FALSE;
23757
0
    fd->has_this_binding = TRUE;
23758
0
    fd->new_target_allowed = TRUE;
23759
23760
0
    push_scope(s);  /* enter body scope */
23761
0
    fd->body_scope = fd->scope_level;
23762
0
    if (has_super) {
23763
0
        fd->is_derived_class_constructor = TRUE;
23764
0
        fd->super_call_allowed = TRUE;
23765
0
        fd->arguments_allowed = TRUE;
23766
0
        fd->has_arguments_binding = TRUE;
23767
0
        func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR;
23768
0
        emit_op(s, OP_init_ctor);
23769
        // TODO(bnoordhuis) roll into OP_init_ctor
23770
0
        emit_op(s, OP_scope_put_var_init);
23771
0
        emit_atom(s, JS_ATOM_this);
23772
0
        emit_u16(s, 0);
23773
0
        emit_class_field_init(s);
23774
0
    } else {
23775
0
        func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;
23776
        /* error if not invoked as a constructor */
23777
0
        emit_op(s, OP_check_ctor);
23778
0
        emit_class_field_init(s);
23779
0
    }
23780
23781
0
    fd->func_kind = JS_FUNC_NORMAL;
23782
0
    fd->func_type = func_type;
23783
0
    emit_return(s, FALSE);
23784
23785
0
    s->cur_func = fd->parent;
23786
0
    if (pfd)
23787
0
        *pfd = fd;
23788
23789
    /* the real object will be set at the end of the compilation */
23790
0
    idx = cpool_add(s, JS_NULL);
23791
0
    fd->parent_cpool_idx = idx;
23792
23793
0
    return 0;
23794
0
}
23795
23796
/* find field in the current scope */
23797
static int find_private_class_field(JSContext *ctx, JSFunctionDef *fd,
23798
                                    JSAtom name, int scope_level)
23799
0
{
23800
0
    int idx;
23801
0
    idx = fd->scopes[scope_level].first;
23802
0
    while (idx != -1) {
23803
0
        if (fd->vars[idx].scope_level != scope_level)
23804
0
            break;
23805
0
        if (fd->vars[idx].var_name == name)
23806
0
            return idx;
23807
0
        idx = fd->vars[idx].scope_next;
23808
0
    }
23809
0
    return -1;
23810
0
}
23811
23812
/* initialize the class fields, called by the constructor. Note:
23813
   super() can be called in an arrow function, so <this> and
23814
   <class_fields_init> can be variable references */
23815
static void emit_class_field_init(JSParseState *s)
23816
0
{
23817
0
    int label_next;
23818
23819
0
    emit_op(s, OP_scope_get_var);
23820
0
    emit_atom(s, JS_ATOM_class_fields_init);
23821
0
    emit_u16(s, s->cur_func->scope_level);
23822
23823
    /* no need to call the class field initializer if not defined */
23824
0
    emit_op(s, OP_dup);
23825
0
    label_next = emit_goto(s, OP_if_false, -1);
23826
23827
0
    emit_op(s, OP_scope_get_var);
23828
0
    emit_atom(s, JS_ATOM_this);
23829
0
    emit_u16(s, 0);
23830
23831
0
    emit_op(s, OP_swap);
23832
23833
0
    emit_op(s, OP_call_method);
23834
0
    emit_u16(s, 0);
23835
23836
0
    emit_label(s, label_next);
23837
0
    emit_op(s, OP_drop);
23838
0
}
23839
23840
/* build a private setter function name from the private getter name */
23841
static JSAtom get_private_setter_name(JSContext *ctx, JSAtom name)
23842
0
{
23843
0
    return js_atom_concat_str(ctx, name, "<set>");
23844
0
}
23845
23846
typedef struct {
23847
    JSFunctionDef *fields_init_fd;
23848
    int computed_fields_count;
23849
    BOOL need_brand;
23850
    int brand_push_pos;
23851
    BOOL is_static;
23852
} ClassFieldsDef;
23853
23854
static __exception int emit_class_init_start(JSParseState *s,
23855
                                             ClassFieldsDef *cf)
23856
0
{
23857
0
    int label_add_brand;
23858
23859
0
    cf->fields_init_fd = js_parse_function_class_fields_init(s);
23860
0
    if (!cf->fields_init_fd)
23861
0
        return -1;
23862
23863
0
    s->cur_func = cf->fields_init_fd;
23864
23865
0
    if (!cf->is_static) {
23866
        /* add the brand to the newly created instance */
23867
        /* XXX: would be better to add the code only if needed, maybe in a
23868
           later pass */
23869
0
        emit_op(s, OP_push_false); /* will be patched later */
23870
0
        cf->brand_push_pos = cf->fields_init_fd->last_opcode_pos;
23871
0
        label_add_brand = emit_goto(s, OP_if_false, -1);
23872
23873
0
        emit_op(s, OP_scope_get_var);
23874
0
        emit_atom(s, JS_ATOM_this);
23875
0
        emit_u16(s, 0);
23876
23877
0
        emit_op(s, OP_scope_get_var);
23878
0
        emit_atom(s, JS_ATOM_home_object);
23879
0
        emit_u16(s, 0);
23880
23881
0
        emit_op(s, OP_add_brand);
23882
23883
0
        emit_label(s, label_add_brand);
23884
0
    }
23885
0
    s->cur_func = s->cur_func->parent;
23886
0
    return 0;
23887
0
}
23888
23889
static void emit_class_init_end(JSParseState *s, ClassFieldsDef *cf)
23890
0
{
23891
0
    int cpool_idx;
23892
23893
0
    s->cur_func = cf->fields_init_fd;
23894
0
    emit_op(s, OP_return_undef);
23895
0
    s->cur_func = s->cur_func->parent;
23896
23897
0
    cpool_idx = cpool_add(s, JS_NULL);
23898
0
    cf->fields_init_fd->parent_cpool_idx = cpool_idx;
23899
0
    emit_op(s, OP_fclosure);
23900
0
    emit_u32(s, cpool_idx);
23901
0
    emit_op(s, OP_set_home_object);
23902
0
}
23903
23904
23905
static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
23906
                                      JSParseExportEnum export_flag)
23907
0
{
23908
0
    JSContext *ctx = s->ctx;
23909
0
    JSFunctionDef *fd = s->cur_func;
23910
0
    JSAtom name = JS_ATOM_NULL, class_name = JS_ATOM_NULL, class_name1;
23911
0
    JSAtom class_var_name = JS_ATOM_NULL;
23912
0
    JSFunctionDef *method_fd, *ctor_fd;
23913
0
    int saved_js_mode, class_name_var_idx, prop_type, ctor_cpool_offset;
23914
0
    int class_flags = 0, i, define_class_offset;
23915
0
    BOOL is_static, is_private;
23916
0
    const uint8_t *class_start_ptr = s->token.ptr;
23917
0
    const uint8_t *start_ptr;
23918
0
    ClassFieldsDef class_fields[2];
23919
23920
    /* classes are parsed and executed in strict mode */
23921
0
    saved_js_mode = fd->js_mode;
23922
0
    fd->js_mode |= JS_MODE_STRICT;
23923
0
    if (next_token(s))
23924
0
        goto fail;
23925
0
    if (s->token.val == TOK_IDENT) {
23926
0
        if (s->token.u.ident.is_reserved) {
23927
0
            js_parse_error_reserved_identifier(s);
23928
0
            goto fail;
23929
0
        }
23930
0
        class_name = JS_DupAtom(ctx, s->token.u.ident.atom);
23931
0
        if (next_token(s))
23932
0
            goto fail;
23933
0
    } else if (!is_class_expr && export_flag != JS_PARSE_EXPORT_DEFAULT) {
23934
0
        js_parse_error(s, "class statement requires a name");
23935
0
        goto fail;
23936
0
    }
23937
0
    if (!is_class_expr) {
23938
0
        if (class_name == JS_ATOM_NULL)
23939
0
            class_var_name = JS_ATOM__default_; /* export default */
23940
0
        else
23941
0
            class_var_name = class_name;
23942
0
        class_var_name = JS_DupAtom(ctx, class_var_name);
23943
0
    }
23944
23945
0
    push_scope(s);
23946
23947
0
    if (s->token.val == TOK_EXTENDS) {
23948
0
        class_flags = JS_DEFINE_CLASS_HAS_HERITAGE;
23949
0
        if (next_token(s))
23950
0
            goto fail;
23951
0
        if (js_parse_left_hand_side_expr(s))
23952
0
            goto fail;
23953
0
    } else {
23954
0
        emit_op(s, OP_undefined);
23955
0
    }
23956
23957
    /* add a 'const' definition for the class name */
23958
0
    if (class_name != JS_ATOM_NULL) {
23959
0
        class_name_var_idx = define_var(s, fd, class_name, JS_VAR_DEF_CONST);
23960
0
        if (class_name_var_idx < 0)
23961
0
            goto fail;
23962
0
    }
23963
23964
0
    if (js_parse_expect(s, '{'))
23965
0
        goto fail;
23966
23967
    /* this scope contains the private fields */
23968
0
    push_scope(s);
23969
23970
0
    emit_op(s, OP_push_const);
23971
0
    ctor_cpool_offset = fd->byte_code.size;
23972
0
    emit_u32(s, 0); /* will be patched at the end of the class parsing */
23973
23974
0
    if (class_name == JS_ATOM_NULL) {
23975
0
        if (class_var_name != JS_ATOM_NULL)
23976
0
            class_name1 = JS_ATOM_default;
23977
0
        else
23978
0
            class_name1 = JS_ATOM_empty_string;
23979
0
    } else {
23980
0
        class_name1 = class_name;
23981
0
    }
23982
23983
0
    emit_op(s, OP_define_class);
23984
0
    emit_atom(s, class_name1);
23985
0
    emit_u8(s, class_flags);
23986
0
    define_class_offset = fd->last_opcode_pos;
23987
23988
0
    for(i = 0; i < 2; i++) {
23989
0
        ClassFieldsDef *cf = &class_fields[i];
23990
0
        cf->fields_init_fd = NULL;
23991
0
        cf->computed_fields_count = 0;
23992
0
        cf->need_brand = FALSE;
23993
0
        cf->is_static = i;
23994
0
    }
23995
23996
0
    ctor_fd = NULL;
23997
0
    while (s->token.val != '}') {
23998
0
        if (s->token.val == ';') {
23999
0
            if (next_token(s))
24000
0
                goto fail;
24001
0
            continue;
24002
0
        }
24003
0
        is_static = FALSE;
24004
0
        if (s->token.val == TOK_STATIC) {
24005
0
            int next = peek_token(s, TRUE);
24006
0
            if (!(next == ';' || next == '}' || next == '(' || next == '='))
24007
0
                is_static = TRUE;
24008
0
        }
24009
0
        prop_type = -1;
24010
0
        if (is_static) {
24011
0
            if (next_token(s))
24012
0
                goto fail;
24013
0
            if (s->token.val == '{') {
24014
0
                ClassFieldsDef *cf = &class_fields[is_static];
24015
0
                JSFunctionDef *init;
24016
0
                if (!cf->fields_init_fd) {
24017
0
                    if (emit_class_init_start(s, cf))
24018
0
                        goto fail;
24019
0
                }
24020
0
                s->cur_func = cf->fields_init_fd;
24021
                /* XXX: could try to avoid creating a new function and
24022
                   reuse 'fields_init_fd' with a specific 'var'
24023
                   scope */
24024
                // stack is now: <empty>
24025
0
                if (js_parse_function_decl2(s, JS_PARSE_FUNC_CLASS_STATIC_INIT,
24026
0
                                            JS_FUNC_NORMAL, JS_ATOM_NULL,
24027
0
                                            s->token.ptr,
24028
0
                                            JS_PARSE_EXPORT_NONE, &init) < 0) {
24029
0
                    goto fail;
24030
0
                }
24031
                // stack is now: fclosure
24032
0
                push_scope(s);
24033
0
                emit_op(s, OP_scope_get_var);
24034
0
                emit_atom(s, JS_ATOM_this);
24035
0
                emit_u16(s, 0);
24036
                // stack is now: fclosure this
24037
0
                emit_op(s, OP_swap);
24038
                // stack is now: this fclosure
24039
0
                emit_op(s, OP_call_method);
24040
0
                emit_u16(s, 0);
24041
                // stack is now: returnvalue
24042
0
                emit_op(s, OP_drop);
24043
                // stack is now: <empty>
24044
0
                pop_scope(s);
24045
0
                s->cur_func = s->cur_func->parent;
24046
0
                continue;
24047
0
            }
24048
            /* allow "static" field name */
24049
0
            if (s->token.val == ';' || s->token.val == '=') {
24050
0
                is_static = FALSE;
24051
0
                name = JS_DupAtom(ctx, JS_ATOM_static);
24052
0
                prop_type = PROP_TYPE_IDENT;
24053
0
            }
24054
0
        }
24055
0
        if (is_static)
24056
0
            emit_op(s, OP_swap);
24057
0
        start_ptr = s->token.ptr;
24058
0
        if (prop_type < 0) {
24059
0
            prop_type = js_parse_property_name(s, &name, TRUE, FALSE, TRUE);
24060
0
            if (prop_type < 0)
24061
0
                goto fail;
24062
0
        }
24063
0
        is_private = prop_type & PROP_TYPE_PRIVATE;
24064
0
        prop_type &= ~PROP_TYPE_PRIVATE;
24065
24066
0
        if ((name == JS_ATOM_constructor && !is_static &&
24067
0
             prop_type != PROP_TYPE_IDENT) ||
24068
0
            (name == JS_ATOM_prototype && is_static) ||
24069
0
            name == JS_ATOM_hash_constructor) {
24070
0
            js_parse_error(s, "invalid method name");
24071
0
            goto fail;
24072
0
        }
24073
0
        if (prop_type == PROP_TYPE_GET || prop_type == PROP_TYPE_SET) {
24074
0
            BOOL is_set = prop_type - PROP_TYPE_GET;
24075
0
            JSFunctionDef *method_fd;
24076
24077
0
            if (is_private) {
24078
0
                int idx, var_kind, is_static1;
24079
0
                idx = find_private_class_field(ctx, fd, name, fd->scope_level);
24080
0
                if (idx >= 0) {
24081
0
                    var_kind = fd->vars[idx].var_kind;
24082
0
                    is_static1 = fd->vars[idx].is_static_private;
24083
0
                    if (var_kind == JS_VAR_PRIVATE_FIELD ||
24084
0
                        var_kind == JS_VAR_PRIVATE_METHOD ||
24085
0
                        var_kind == JS_VAR_PRIVATE_GETTER_SETTER ||
24086
0
                        var_kind == (JS_VAR_PRIVATE_GETTER + is_set) ||
24087
0
                        (var_kind == (JS_VAR_PRIVATE_GETTER + 1 - is_set) &&
24088
0
                         is_static != is_static1)) {
24089
0
                        goto private_field_already_defined;
24090
0
                    }
24091
0
                    fd->vars[idx].var_kind = JS_VAR_PRIVATE_GETTER_SETTER;
24092
0
                } else {
24093
0
                    if (add_private_class_field(s, fd, name,
24094
0
                                                JS_VAR_PRIVATE_GETTER + is_set, is_static) < 0)
24095
0
                        goto fail;
24096
0
                }
24097
0
                class_fields[is_static].need_brand = TRUE;
24098
0
            }
24099
24100
0
            if (js_parse_function_decl2(s, JS_PARSE_FUNC_GETTER + is_set,
24101
0
                                        JS_FUNC_NORMAL, JS_ATOM_NULL,
24102
0
                                        start_ptr,
24103
0
                                        JS_PARSE_EXPORT_NONE, &method_fd))
24104
0
                goto fail;
24105
0
            if (is_private) {
24106
0
                method_fd->need_home_object = TRUE; /* needed for brand check */
24107
0
                emit_op(s, OP_set_home_object);
24108
                /* XXX: missing function name */
24109
0
                emit_op(s, OP_scope_put_var_init);
24110
0
                if (is_set) {
24111
0
                    JSAtom setter_name;
24112
0
                    int ret;
24113
24114
0
                    setter_name = get_private_setter_name(ctx, name);
24115
0
                    if (setter_name == JS_ATOM_NULL)
24116
0
                        goto fail;
24117
0
                    emit_atom(s, setter_name);
24118
0
                    ret = add_private_class_field(s, fd, setter_name,
24119
0
                                                  JS_VAR_PRIVATE_SETTER, is_static);
24120
0
                    JS_FreeAtom(ctx, setter_name);
24121
0
                    if (ret < 0)
24122
0
                        goto fail;
24123
0
                } else {
24124
0
                    emit_atom(s, name);
24125
0
                }
24126
0
                emit_u16(s, s->cur_func->scope_level);
24127
0
            } else {
24128
0
                if (name == JS_ATOM_NULL) {
24129
0
                    emit_op(s, OP_define_method_computed);
24130
0
                } else {
24131
0
                    emit_op(s, OP_define_method);
24132
0
                    emit_atom(s, name);
24133
0
                }
24134
0
                emit_u8(s, OP_DEFINE_METHOD_GETTER + is_set);
24135
0
            }
24136
0
        } else if (prop_type == PROP_TYPE_IDENT && s->token.val != '(') {
24137
0
            ClassFieldsDef *cf = &class_fields[is_static];
24138
0
            JSAtom field_var_name = JS_ATOM_NULL;
24139
24140
            /* class field */
24141
24142
            /* XXX: spec: not consistent with method name checks */
24143
0
            if (name == JS_ATOM_constructor || name == JS_ATOM_prototype) {
24144
0
                js_parse_error(s, "invalid field name");
24145
0
                goto fail;
24146
0
            }
24147
24148
0
            if (is_private) {
24149
0
                if (find_private_class_field(ctx, fd, name,
24150
0
                                             fd->scope_level) >= 0) {
24151
0
                    goto private_field_already_defined;
24152
0
                }
24153
0
                if (add_private_class_field(s, fd, name,
24154
0
                                            JS_VAR_PRIVATE_FIELD, is_static) < 0)
24155
0
                    goto fail;
24156
0
                emit_op(s, OP_private_symbol);
24157
0
                emit_atom(s, name);
24158
0
                emit_op(s, OP_scope_put_var_init);
24159
0
                emit_atom(s, name);
24160
0
                emit_u16(s, s->cur_func->scope_level);
24161
0
            }
24162
24163
0
            if (!cf->fields_init_fd) {
24164
0
                if (emit_class_init_start(s, cf))
24165
0
                    goto fail;
24166
0
            }
24167
0
            if (name == JS_ATOM_NULL ) {
24168
                /* save the computed field name into a variable */
24169
0
                field_var_name = js_atom_concat_num(ctx, JS_ATOM_computed_field + is_static, cf->computed_fields_count);
24170
0
                if (field_var_name == JS_ATOM_NULL)
24171
0
                    goto fail;
24172
0
                if (define_var(s, fd, field_var_name, JS_VAR_DEF_CONST) < 0) {
24173
0
                    JS_FreeAtom(ctx, field_var_name);
24174
0
                    goto fail;
24175
0
                }
24176
0
                emit_op(s, OP_to_propkey);
24177
0
                emit_op(s, OP_scope_put_var_init);
24178
0
                emit_atom(s, field_var_name);
24179
0
                emit_u16(s, s->cur_func->scope_level);
24180
0
            }
24181
0
            s->cur_func = cf->fields_init_fd;
24182
0
            emit_op(s, OP_scope_get_var);
24183
0
            emit_atom(s, JS_ATOM_this);
24184
0
            emit_u16(s, 0);
24185
24186
0
            if (name == JS_ATOM_NULL) {
24187
0
                emit_op(s, OP_scope_get_var);
24188
0
                emit_atom(s, field_var_name);
24189
0
                emit_u16(s, s->cur_func->scope_level);
24190
0
                cf->computed_fields_count++;
24191
0
                JS_FreeAtom(ctx, field_var_name);
24192
0
            } else if (is_private) {
24193
0
                emit_op(s, OP_scope_get_var);
24194
0
                emit_atom(s, name);
24195
0
                emit_u16(s, s->cur_func->scope_level);
24196
0
            }
24197
24198
0
            if (s->token.val == '=') {
24199
0
                if (next_token(s))
24200
0
                    goto fail;
24201
0
                if (js_parse_assign_expr(s))
24202
0
                    goto fail;
24203
0
            } else {
24204
0
                emit_op(s, OP_undefined);
24205
0
            }
24206
0
            if (is_private) {
24207
0
                set_object_name_computed(s);
24208
0
                emit_op(s, OP_define_private_field);
24209
0
            } else if (name == JS_ATOM_NULL) {
24210
0
                set_object_name_computed(s);
24211
0
                emit_op(s, OP_define_array_el);
24212
0
                emit_op(s, OP_drop);
24213
0
            } else {
24214
0
                set_object_name(s, name);
24215
0
                emit_op(s, OP_define_field);
24216
0
                emit_atom(s, name);
24217
0
            }
24218
0
            s->cur_func = s->cur_func->parent;
24219
0
            if (js_parse_expect_semi(s))
24220
0
                goto fail;
24221
0
        } else {
24222
0
            JSParseFunctionEnum func_type;
24223
0
            JSFunctionKindEnum func_kind;
24224
24225
0
            func_type = JS_PARSE_FUNC_METHOD;
24226
0
            func_kind = JS_FUNC_NORMAL;
24227
0
            if (prop_type == PROP_TYPE_STAR) {
24228
0
                func_kind = JS_FUNC_GENERATOR;
24229
0
            } else if (prop_type == PROP_TYPE_ASYNC) {
24230
0
                func_kind = JS_FUNC_ASYNC;
24231
0
            } else if (prop_type == PROP_TYPE_ASYNC_STAR) {
24232
0
                func_kind = JS_FUNC_ASYNC_GENERATOR;
24233
0
            } else if (name == JS_ATOM_constructor && !is_static) {
24234
0
                if (ctor_fd) {
24235
0
                    js_parse_error(s, "property constructor appears more than once");
24236
0
                    goto fail;
24237
0
                }
24238
0
                if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE)
24239
0
                    func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR;
24240
0
                else
24241
0
                    func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;
24242
0
            }
24243
0
            if (is_private) {
24244
0
                class_fields[is_static].need_brand = TRUE;
24245
0
            }
24246
0
            if (js_parse_function_decl2(s, func_type, func_kind, JS_ATOM_NULL, start_ptr, JS_PARSE_EXPORT_NONE, &method_fd))
24247
0
                goto fail;
24248
0
            if (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR ||
24249
0
                func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) {
24250
0
                ctor_fd = method_fd;
24251
0
            } else if (is_private) {
24252
0
                method_fd->need_home_object = TRUE; /* needed for brand check */
24253
0
                if (find_private_class_field(ctx, fd, name,
24254
0
                                             fd->scope_level) >= 0) {
24255
0
                private_field_already_defined:
24256
0
                    js_parse_error(s, "private class field is already defined");
24257
0
                    goto fail;
24258
0
                }
24259
0
                if (add_private_class_field(s, fd, name,
24260
0
                                            JS_VAR_PRIVATE_METHOD, is_static) < 0)
24261
0
                    goto fail;
24262
0
                emit_op(s, OP_set_home_object);
24263
0
                emit_op(s, OP_set_name);
24264
0
                emit_atom(s, name);
24265
0
                emit_op(s, OP_scope_put_var_init);
24266
0
                emit_atom(s, name);
24267
0
                emit_u16(s, s->cur_func->scope_level);
24268
0
            } else {
24269
0
                if (name == JS_ATOM_NULL) {
24270
0
                    emit_op(s, OP_define_method_computed);
24271
0
                } else {
24272
0
                    emit_op(s, OP_define_method);
24273
0
                    emit_atom(s, name);
24274
0
                }
24275
0
                emit_u8(s, OP_DEFINE_METHOD_METHOD);
24276
0
            }
24277
0
        }
24278
0
        if (is_static)
24279
0
            emit_op(s, OP_swap);
24280
0
        JS_FreeAtom(ctx, name);
24281
0
        name = JS_ATOM_NULL;
24282
0
    }
24283
24284
0
    if (s->token.val != '}') {
24285
0
        js_parse_error(s, "expecting '%c'", '}');
24286
0
        goto fail;
24287
0
    }
24288
24289
0
    if (!ctor_fd) {
24290
0
        if (js_parse_class_default_ctor(s, class_flags & JS_DEFINE_CLASS_HAS_HERITAGE, &ctor_fd))
24291
0
            goto fail;
24292
0
    }
24293
    /* patch the constant pool index for the constructor */
24294
0
    put_u32(fd->byte_code.buf + ctor_cpool_offset, ctor_fd->parent_cpool_idx);
24295
24296
    /* store the class source code in the constructor. */
24297
0
    if (!fd->strip_source) {
24298
0
        js_free(ctx, ctor_fd->source);
24299
0
        ctor_fd->source_len = s->buf_ptr - class_start_ptr;
24300
0
        ctor_fd->source = js_strndup(ctx, (const char *)class_start_ptr,
24301
0
                                     ctor_fd->source_len);
24302
0
        if (!ctor_fd->source)
24303
0
            goto fail;
24304
0
    }
24305
24306
    /* consume the '}' */
24307
0
    if (next_token(s))
24308
0
        goto fail;
24309
24310
0
    {
24311
0
        ClassFieldsDef *cf = &class_fields[0];
24312
0
        int var_idx;
24313
24314
0
        if (cf->need_brand) {
24315
            /* add a private brand to the prototype */
24316
0
            emit_op(s, OP_dup);
24317
0
            emit_op(s, OP_null);
24318
0
            emit_op(s, OP_swap);
24319
0
            emit_op(s, OP_add_brand);
24320
24321
            /* define the brand field in 'this' of the initializer */
24322
0
            if (!cf->fields_init_fd) {
24323
0
                if (emit_class_init_start(s, cf))
24324
0
                    goto fail;
24325
0
            }
24326
            /* patch the start of the function to enable the
24327
               OP_add_brand_instance code */
24328
0
            cf->fields_init_fd->byte_code.buf[cf->brand_push_pos] = OP_push_true;
24329
0
        }
24330
24331
        /* store the function to initialize the fields to that it can be
24332
           referenced by the constructor */
24333
0
        var_idx = define_var(s, fd, JS_ATOM_class_fields_init,
24334
0
                             JS_VAR_DEF_CONST);
24335
0
        if (var_idx < 0)
24336
0
            goto fail;
24337
0
        if (cf->fields_init_fd) {
24338
0
            emit_class_init_end(s, cf);
24339
0
        } else {
24340
0
            emit_op(s, OP_undefined);
24341
0
        }
24342
0
        emit_op(s, OP_scope_put_var_init);
24343
0
        emit_atom(s, JS_ATOM_class_fields_init);
24344
0
        emit_u16(s, s->cur_func->scope_level);
24345
0
    }
24346
24347
    /* drop the prototype */
24348
0
    emit_op(s, OP_drop);
24349
24350
0
    if (class_fields[1].need_brand) {
24351
        /* add a private brand to the class */
24352
0
        emit_op(s, OP_dup);
24353
0
        emit_op(s, OP_dup);
24354
0
        emit_op(s, OP_add_brand);
24355
0
    }
24356
24357
0
    if (class_name != JS_ATOM_NULL) {
24358
        /* store the class name in the scoped class name variable (it
24359
           is independent from the class statement variable
24360
           definition) */
24361
0
        emit_op(s, OP_dup);
24362
0
        emit_op(s, OP_scope_put_var_init);
24363
0
        emit_atom(s, class_name);
24364
0
        emit_u16(s, fd->scope_level);
24365
0
    }
24366
24367
    /* initialize the static fields */
24368
0
    if (class_fields[1].fields_init_fd != NULL) {
24369
0
        ClassFieldsDef *cf = &class_fields[1];
24370
0
        emit_op(s, OP_dup);
24371
0
        emit_class_init_end(s, cf);
24372
0
        emit_op(s, OP_call_method);
24373
0
        emit_u16(s, 0);
24374
0
        emit_op(s, OP_drop);
24375
0
    }
24376
24377
0
    pop_scope(s);
24378
0
    pop_scope(s);
24379
24380
    /* the class statements have a block level scope */
24381
0
    if (class_var_name != JS_ATOM_NULL) {
24382
0
        if (define_var(s, fd, class_var_name, JS_VAR_DEF_LET) < 0)
24383
0
            goto fail;
24384
0
        emit_op(s, OP_scope_put_var_init);
24385
0
        emit_atom(s, class_var_name);
24386
0
        emit_u16(s, fd->scope_level);
24387
0
    } else {
24388
0
        if (class_name == JS_ATOM_NULL) {
24389
            /* cannot use OP_set_name because the name of the class
24390
               must be defined before the static initializers are
24391
               executed */
24392
0
            emit_op(s, OP_set_class_name);
24393
0
            emit_u32(s, fd->last_opcode_pos + 1 - define_class_offset);
24394
0
        }
24395
0
    }
24396
24397
0
    if (export_flag != JS_PARSE_EXPORT_NONE) {
24398
0
        if (!add_export_entry(s, fd->module,
24399
0
                              class_var_name,
24400
0
                              export_flag == JS_PARSE_EXPORT_NAMED ? class_var_name : JS_ATOM_default,
24401
0
                              JS_EXPORT_TYPE_LOCAL))
24402
0
            goto fail;
24403
0
    }
24404
24405
0
    JS_FreeAtom(ctx, class_name);
24406
0
    JS_FreeAtom(ctx, class_var_name);
24407
0
    fd->js_mode = saved_js_mode;
24408
0
    return 0;
24409
0
 fail:
24410
0
    JS_FreeAtom(ctx, name);
24411
0
    JS_FreeAtom(ctx, class_name);
24412
0
    JS_FreeAtom(ctx, class_var_name);
24413
0
    fd->js_mode = saved_js_mode;
24414
0
    return -1;
24415
0
}
24416
24417
static __exception int js_parse_array_literal(JSParseState *s)
24418
0
{
24419
0
    uint32_t idx;
24420
0
    BOOL need_length;
24421
24422
0
    if (next_token(s))
24423
0
        return -1;
24424
    /* small regular arrays are created on the stack */
24425
0
    idx = 0;
24426
0
    while (s->token.val != ']' && idx < 32) {
24427
0
        if (s->token.val == ',' || s->token.val == TOK_ELLIPSIS)
24428
0
            break;
24429
0
        if (js_parse_assign_expr(s))
24430
0
            return -1;
24431
0
        idx++;
24432
        /* accept trailing comma */
24433
0
        if (s->token.val == ',') {
24434
0
            if (next_token(s))
24435
0
                return -1;
24436
0
        } else
24437
0
        if (s->token.val != ']')
24438
0
            goto done;
24439
0
    }
24440
0
    emit_op(s, OP_array_from);
24441
0
    emit_u16(s, idx);
24442
24443
    /* larger arrays and holes are handled with explicit indices */
24444
0
    need_length = FALSE;
24445
0
    while (s->token.val != ']' && idx < 0x7fffffff) {
24446
0
        if (s->token.val == TOK_ELLIPSIS)
24447
0
            break;
24448
0
        need_length = TRUE;
24449
0
        if (s->token.val != ',') {
24450
0
            if (js_parse_assign_expr(s))
24451
0
                return -1;
24452
0
            emit_op(s, OP_define_field);
24453
0
            emit_u32(s, __JS_AtomFromUInt32(idx));
24454
0
            need_length = FALSE;
24455
0
        }
24456
0
        idx++;
24457
        /* accept trailing comma */
24458
0
        if (s->token.val == ',') {
24459
0
            if (next_token(s))
24460
0
                return -1;
24461
0
        }
24462
0
    }
24463
0
    if (s->token.val == ']') {
24464
0
        if (need_length) {
24465
            /* Set the length: Cannot use OP_define_field because
24466
               length is not configurable */
24467
0
            emit_op(s, OP_dup);
24468
0
            emit_op(s, OP_push_i32);
24469
0
            emit_u32(s, idx);
24470
0
            emit_op(s, OP_put_field);
24471
0
            emit_atom(s, JS_ATOM_length);
24472
0
        }
24473
0
        goto done;
24474
0
    }
24475
24476
    /* huge arrays and spread elements require a dynamic index on the stack */
24477
0
    emit_op(s, OP_push_i32);
24478
0
    emit_u32(s, idx);
24479
24480
    /* stack has array, index */
24481
0
    while (s->token.val != ']') {
24482
0
        if (s->token.val == TOK_ELLIPSIS) {
24483
0
            if (next_token(s))
24484
0
                return -1;
24485
0
            if (js_parse_assign_expr(s))
24486
0
                return -1;
24487
0
#if 1
24488
0
            emit_op(s, OP_append);
24489
#else
24490
            int label_next, label_done;
24491
            label_next = new_label(s);
24492
            label_done = new_label(s);
24493
            /* enumerate object */
24494
            emit_op(s, OP_for_of_start);
24495
            emit_op(s, OP_rot5l);
24496
            emit_op(s, OP_rot5l);
24497
            emit_label(s, label_next);
24498
            /* on stack: enum_rec array idx */
24499
            emit_op(s, OP_for_of_next);
24500
            emit_u8(s, 2);
24501
            emit_goto(s, OP_if_true, label_done);
24502
            /* append element */
24503
            /* enum_rec array idx val -> enum_rec array new_idx */
24504
            emit_op(s, OP_define_array_el);
24505
            emit_op(s, OP_inc);
24506
            emit_goto(s, OP_goto, label_next);
24507
            emit_label(s, label_done);
24508
            /* close enumeration */
24509
            emit_op(s, OP_drop); /* drop undef val */
24510
            emit_op(s, OP_nip1); /* drop enum_rec */
24511
            emit_op(s, OP_nip1);
24512
            emit_op(s, OP_nip1);
24513
#endif
24514
0
        } else {
24515
0
            need_length = TRUE;
24516
0
            if (s->token.val != ',') {
24517
0
                if (js_parse_assign_expr(s))
24518
0
                    return -1;
24519
                /* a idx val */
24520
0
                emit_op(s, OP_define_array_el);
24521
0
                need_length = FALSE;
24522
0
            }
24523
0
            emit_op(s, OP_inc);
24524
0
        }
24525
0
        if (s->token.val != ',')
24526
0
            break;
24527
0
        if (next_token(s))
24528
0
            return -1;
24529
0
    }
24530
0
    if (need_length) {
24531
        /* Set the length: cannot use OP_define_field because
24532
           length is not configurable */
24533
0
        emit_op(s, OP_dup1);    /* array length - array array length */
24534
0
        emit_op(s, OP_put_field);
24535
0
        emit_atom(s, JS_ATOM_length);
24536
0
    } else {
24537
0
        emit_op(s, OP_drop);    /* array length - array */
24538
0
    }
24539
0
done:
24540
0
    return js_parse_expect(s, ']');
24541
0
}
24542
24543
/* XXX: remove */
24544
static BOOL has_with_scope(JSFunctionDef *s, int scope_level)
24545
0
{
24546
    /* check if scope chain contains a with statement */
24547
0
    while (s) {
24548
0
        int scope_idx = s->scopes[scope_level].first;
24549
0
        while (scope_idx >= 0) {
24550
0
            JSVarDef *vd = &s->vars[scope_idx];
24551
24552
0
            if (vd->var_name == JS_ATOM__with_)
24553
0
                return TRUE;
24554
0
            scope_idx = vd->scope_next;
24555
0
        }
24556
        /* check parent scopes */
24557
0
        scope_level = s->parent_scope_level;
24558
0
        s = s->parent;
24559
0
    }
24560
0
    return FALSE;
24561
0
}
24562
24563
static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,
24564
                                  JSAtom *pname, int *plabel, int *pdepth, BOOL keep,
24565
                                  int tok)
24566
4
{
24567
4
    JSFunctionDef *fd;
24568
4
    int opcode, scope, label, depth;
24569
4
    JSAtom name;
24570
24571
    /* we check the last opcode to get the lvalue type */
24572
4
    fd = s->cur_func;
24573
4
    scope = 0;
24574
4
    name = JS_ATOM_NULL;
24575
4
    label = -1;
24576
4
    depth = 0;
24577
4
    switch(opcode = get_prev_opcode(fd)) {
24578
0
    case OP_scope_get_var:
24579
0
        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
24580
0
        scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
24581
0
        if ((name == JS_ATOM_arguments || name == JS_ATOM_eval) &&
24582
0
            (fd->js_mode & JS_MODE_STRICT)) {
24583
0
            return js_parse_error(s, "invalid lvalue in strict mode");
24584
0
        }
24585
0
        if (name == JS_ATOM_this || name == JS_ATOM_new_target)
24586
0
            goto invalid_lvalue;
24587
0
        depth = 2;  /* will generate OP_get_ref_value */
24588
0
        break;
24589
4
    case OP_get_field:
24590
4
        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
24591
4
        depth = 1;
24592
4
        break;
24593
0
    case OP_scope_get_private_field:
24594
0
        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
24595
0
        scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
24596
0
        depth = 1;
24597
0
        break;
24598
0
    case OP_get_array_el:
24599
0
        depth = 2;
24600
0
        break;
24601
0
    case OP_get_super_value:
24602
0
        depth = 3;
24603
0
        break;
24604
0
    default:
24605
0
    invalid_lvalue:
24606
0
        if (tok == TOK_FOR) {
24607
0
            return js_parse_error(s, "invalid for in/of left hand-side");
24608
0
        } else if (tok == TOK_INC || tok == TOK_DEC) {
24609
0
            return js_parse_error(s, "invalid increment/decrement operand");
24610
0
        } else if (tok == '[' || tok == '{') {
24611
0
            return js_parse_error(s, "invalid destructuring target");
24612
0
        } else {
24613
0
            return js_parse_error(s, "invalid assignment left-hand side");
24614
0
        }
24615
4
    }
24616
    /* remove the last opcode */
24617
4
    fd->byte_code.size = fd->last_opcode_pos;
24618
4
    fd->last_opcode_pos = -1;
24619
24620
4
    if (keep) {
24621
        /* get the value but keep the object/fields on the stack */
24622
0
        switch(opcode) {
24623
0
        case OP_scope_get_var:
24624
0
            label = new_label(s);
24625
0
            if (label < 0)
24626
0
                return -1;
24627
0
            emit_op(s, OP_scope_make_ref);
24628
0
            emit_atom(s, name);
24629
0
            emit_u32(s, label);
24630
0
            emit_u16(s, scope);
24631
0
            update_label(fd, label, 1);
24632
0
            emit_op(s, OP_get_ref_value);
24633
0
            opcode = OP_get_ref_value;
24634
0
            break;
24635
0
        case OP_get_field:
24636
0
            emit_op(s, OP_get_field2);
24637
0
            emit_atom(s, name);
24638
0
            break;
24639
0
        case OP_scope_get_private_field:
24640
0
            emit_op(s, OP_scope_get_private_field2);
24641
0
            emit_atom(s, name);
24642
0
            emit_u16(s, scope);
24643
0
            break;
24644
0
        case OP_get_array_el:
24645
0
            emit_op(s, OP_get_array_el3);
24646
0
            break;
24647
0
        case OP_get_super_value:
24648
0
            emit_op(s, OP_to_propkey);
24649
0
            emit_op(s, OP_dup3);
24650
0
            emit_op(s, OP_get_super_value);
24651
0
            break;
24652
0
        default:
24653
0
            abort();
24654
0
        }
24655
4
    } else {
24656
4
        switch(opcode) {
24657
0
        case OP_scope_get_var:
24658
0
            label = new_label(s);
24659
0
            if (label < 0)
24660
0
                return -1;
24661
0
            emit_op(s, OP_scope_make_ref);
24662
0
            emit_atom(s, name);
24663
0
            emit_u32(s, label);
24664
0
            emit_u16(s, scope);
24665
0
            update_label(fd, label, 1);
24666
0
            opcode = OP_get_ref_value;
24667
0
            break;
24668
4
        default:
24669
4
            break;
24670
4
        }
24671
4
    }
24672
24673
4
    *popcode = opcode;
24674
4
    *pscope = scope;
24675
    /* name has refcount for OP_get_field and OP_get_ref_value,
24676
       and JS_ATOM_NULL for other opcodes */
24677
4
    *pname = name;
24678
4
    *plabel = label;
24679
4
    if (pdepth)
24680
0
        *pdepth = depth;
24681
4
    return 0;
24682
4
}
24683
24684
typedef enum {
24685
    PUT_LVALUE_NOKEEP, /* [depth] v -> */
24686
    PUT_LVALUE_NOKEEP_DEPTH, /* [depth] v -> , keep depth (currently
24687
                                just disable optimizations) */
24688
    PUT_LVALUE_KEEP_TOP,  /* [depth] v -> v */
24689
    PUT_LVALUE_KEEP_SECOND, /* [depth] v0 v -> v0 */
24690
    PUT_LVALUE_NOKEEP_BOTTOM, /* v [depth] -> */
24691
} PutLValueEnum;
24692
24693
/* name has a live reference. 'is_let' is only used with opcode =
24694
   OP_scope_get_var which is never generated by get_lvalue(). */
24695
static void put_lvalue(JSParseState *s, int opcode, int scope,
24696
                       JSAtom name, int label, PutLValueEnum special,
24697
                       BOOL is_let)
24698
4
{
24699
4
    switch(opcode) {
24700
4
    case OP_get_field:
24701
4
    case OP_scope_get_private_field:
24702
        /* depth = 1 */
24703
4
        switch(special) {
24704
0
        case PUT_LVALUE_NOKEEP:
24705
0
        case PUT_LVALUE_NOKEEP_DEPTH:
24706
0
            break;
24707
4
        case PUT_LVALUE_KEEP_TOP:
24708
4
            emit_op(s, OP_insert2); /* obj v -> v obj v */
24709
4
            break;
24710
0
        case PUT_LVALUE_KEEP_SECOND:
24711
0
            emit_op(s, OP_perm3); /* obj v0 v -> v0 obj v */
24712
0
            break;
24713
0
        case PUT_LVALUE_NOKEEP_BOTTOM:
24714
0
            emit_op(s, OP_swap);
24715
0
            break;
24716
0
        default:
24717
0
            abort();
24718
4
        }
24719
4
        break;
24720
4
    case OP_get_array_el:
24721
0
    case OP_get_ref_value:
24722
        /* depth = 2 */
24723
0
        if (opcode == OP_get_ref_value) {
24724
0
            JS_FreeAtom(s->ctx, name);
24725
0
            emit_label(s, label);
24726
0
        }
24727
0
        switch(special) {
24728
0
        case PUT_LVALUE_NOKEEP:
24729
0
            emit_op(s, OP_nop); /* will trigger optimization */
24730
0
            break;
24731
0
        case PUT_LVALUE_NOKEEP_DEPTH:
24732
0
            break;
24733
0
        case PUT_LVALUE_KEEP_TOP:
24734
0
            emit_op(s, OP_insert3); /* obj prop v -> v obj prop v */
24735
0
            break;
24736
0
        case PUT_LVALUE_KEEP_SECOND:
24737
0
            emit_op(s, OP_perm4); /* obj prop v0 v -> v0 obj prop v */
24738
0
            break;
24739
0
        case PUT_LVALUE_NOKEEP_BOTTOM:
24740
0
            emit_op(s, OP_rot3l);
24741
0
            break;
24742
0
        default:
24743
0
            abort();
24744
0
        }
24745
0
        break;
24746
0
    case OP_get_super_value:
24747
        /* depth = 3 */
24748
0
        switch(special) {
24749
0
        case PUT_LVALUE_NOKEEP:
24750
0
        case PUT_LVALUE_NOKEEP_DEPTH:
24751
0
            break;
24752
0
        case PUT_LVALUE_KEEP_TOP:
24753
0
            emit_op(s, OP_insert4); /* this obj prop v -> v this obj prop v */
24754
0
            break;
24755
0
        case PUT_LVALUE_KEEP_SECOND:
24756
0
            emit_op(s, OP_perm5); /* this obj prop v0 v -> v0 this obj prop v */
24757
0
            break;
24758
0
        case PUT_LVALUE_NOKEEP_BOTTOM:
24759
0
            emit_op(s, OP_rot4l);
24760
0
            break;
24761
0
        default:
24762
0
            abort();
24763
0
        }
24764
0
        break;
24765
0
    default:
24766
0
        break;
24767
4
    }
24768
24769
4
    switch(opcode) {
24770
0
    case OP_scope_get_var:  /* val -- */
24771
0
        assert(special == PUT_LVALUE_NOKEEP ||
24772
0
               special == PUT_LVALUE_NOKEEP_DEPTH);
24773
0
        emit_op(s, is_let ? OP_scope_put_var_init : OP_scope_put_var);
24774
0
        emit_u32(s, name);  /* has refcount */
24775
0
        emit_u16(s, scope);
24776
0
        break;
24777
4
    case OP_get_field:
24778
4
        emit_op(s, OP_put_field);
24779
4
        emit_u32(s, name);  /* name has refcount */
24780
4
        break;
24781
0
    case OP_scope_get_private_field:
24782
0
        emit_op(s, OP_scope_put_private_field);
24783
0
        emit_u32(s, name);  /* name has refcount */
24784
0
        emit_u16(s, scope);
24785
0
        break;
24786
0
    case OP_get_array_el:
24787
0
        emit_op(s, OP_put_array_el);
24788
0
        break;
24789
0
    case OP_get_ref_value:
24790
0
        emit_op(s, OP_put_ref_value);
24791
0
        break;
24792
0
    case OP_get_super_value:
24793
0
        emit_op(s, OP_put_super_value);
24794
0
        break;
24795
0
    default:
24796
0
        abort();
24797
4
    }
24798
4
}
24799
24800
static __exception int js_parse_expr_paren(JSParseState *s)
24801
0
{
24802
0
    if (js_parse_expect(s, '('))
24803
0
        return -1;
24804
0
    if (js_parse_expr(s))
24805
0
        return -1;
24806
0
    if (js_parse_expect(s, ')'))
24807
0
        return -1;
24808
0
    return 0;
24809
0
}
24810
24811
static int js_unsupported_keyword(JSParseState *s, JSAtom atom)
24812
0
{
24813
0
    char buf[ATOM_GET_STR_BUF_SIZE];
24814
0
    return js_parse_error(s, "unsupported keyword: %s",
24815
0
                          JS_AtomGetStr(s->ctx, buf, sizeof(buf), atom));
24816
0
}
24817
24818
static __exception int js_define_var(JSParseState *s, JSAtom name, int tok)
24819
0
{
24820
0
    JSFunctionDef *fd = s->cur_func;
24821
0
    JSVarDefEnum var_def_type;
24822
24823
0
    if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) {
24824
0
        return js_parse_error(s, "yield is a reserved identifier");
24825
0
    }
24826
0
    if ((name == JS_ATOM_arguments || name == JS_ATOM_eval)
24827
0
    &&  (fd->js_mode & JS_MODE_STRICT)) {
24828
0
        return js_parse_error(s, "invalid variable name in strict mode");
24829
0
    }
24830
0
    if (name == JS_ATOM_let
24831
0
    &&  (tok == TOK_LET || tok == TOK_CONST)) {
24832
0
        return js_parse_error(s, "invalid lexical variable name");
24833
0
    }
24834
0
    switch(tok) {
24835
0
    case TOK_LET:
24836
0
        var_def_type = JS_VAR_DEF_LET;
24837
0
        break;
24838
0
    case TOK_CONST:
24839
0
        var_def_type = JS_VAR_DEF_CONST;
24840
0
        break;
24841
0
    case TOK_VAR:
24842
0
        var_def_type = JS_VAR_DEF_VAR;
24843
0
        break;
24844
0
    case TOK_CATCH:
24845
0
        var_def_type = JS_VAR_DEF_CATCH;
24846
0
        break;
24847
0
    default:
24848
0
        abort();
24849
0
    }
24850
0
    if (define_var(s, fd, name, var_def_type) < 0)
24851
0
        return -1;
24852
0
    return 0;
24853
0
}
24854
24855
static void js_emit_spread_code(JSParseState *s, int depth)
24856
0
{
24857
0
    int label_rest_next, label_rest_done;
24858
24859
    /* XXX: could check if enum object is an actual array and optimize
24860
       slice extraction. enumeration record and target array are in a
24861
       different order from OP_append case. */
24862
    /* enum_rec xxx -- enum_rec xxx array 0 */
24863
0
    emit_op(s, OP_array_from);
24864
0
    emit_u16(s, 0);
24865
0
    emit_op(s, OP_push_i32);
24866
0
    emit_u32(s, 0);
24867
0
    emit_label(s, label_rest_next = new_label(s));
24868
0
    emit_op(s, OP_for_of_next);
24869
0
    emit_u8(s, 2 + depth);
24870
0
    label_rest_done = emit_goto(s, OP_if_true, -1);
24871
    /* array idx val -- array idx */
24872
0
    emit_op(s, OP_define_array_el);
24873
0
    emit_op(s, OP_inc);
24874
0
    emit_goto(s, OP_goto, label_rest_next);
24875
0
    emit_label(s, label_rest_done);
24876
    /* enum_rec xxx array idx undef -- enum_rec xxx array */
24877
0
    emit_op(s, OP_drop);
24878
0
    emit_op(s, OP_drop);
24879
0
}
24880
24881
static int js_parse_check_duplicate_parameter(JSParseState *s, JSAtom name)
24882
0
{
24883
    /* Check for duplicate parameter names */
24884
0
    JSFunctionDef *fd = s->cur_func;
24885
0
    int i;
24886
0
    for (i = 0; i < fd->arg_count; i++) {
24887
0
        if (fd->args[i].var_name == name)
24888
0
            goto duplicate;
24889
0
    }
24890
0
    for (i = 0; i < fd->var_count; i++) {
24891
0
        if (fd->vars[i].var_name == name)
24892
0
            goto duplicate;
24893
0
    }
24894
0
    return 0;
24895
24896
0
duplicate:
24897
0
    return js_parse_error(s, "duplicate parameter names not allowed in this context");
24898
0
}
24899
24900
/* tok = TOK_VAR, TOK_LET or TOK_CONST. Return whether a reference
24901
   must be taken to the variable for proper 'with' or global variable
24902
   evaluation */
24903
/* Note: this function is needed only because variable references are
24904
   not yet optimized in destructuring */
24905
static BOOL need_var_reference(JSParseState *s, int tok)
24906
0
{
24907
0
    JSFunctionDef *fd = s->cur_func;
24908
0
    if (tok != TOK_VAR)
24909
0
        return FALSE; /* no reference for let/const */
24910
0
    if (fd->js_mode & JS_MODE_STRICT) {
24911
0
        if (!fd->is_global_var)
24912
0
            return FALSE; /* local definitions in strict mode in function or direct eval */
24913
0
        if (s->is_module)
24914
0
            return FALSE; /* in a module global variables are like closure variables */
24915
0
    }
24916
0
    return TRUE;
24917
0
}
24918
24919
static JSAtom js_parse_destructuring_var(JSParseState *s, int tok, int is_arg)
24920
0
{
24921
0
    JSAtom name;
24922
24923
0
    if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)
24924
0
    ||  ((s->cur_func->js_mode & JS_MODE_STRICT) &&
24925
0
         (s->token.u.ident.atom == JS_ATOM_eval || s->token.u.ident.atom == JS_ATOM_arguments))) {
24926
0
        js_parse_error(s, "invalid destructuring target");
24927
0
        return JS_ATOM_NULL;
24928
0
    }
24929
0
    name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
24930
0
    if (is_arg && js_parse_check_duplicate_parameter(s, name))
24931
0
        goto fail;
24932
0
    if (next_token(s))
24933
0
        goto fail;
24934
24935
0
    return name;
24936
0
fail:
24937
0
    JS_FreeAtom(s->ctx, name);
24938
0
    return JS_ATOM_NULL;
24939
0
}
24940
24941
/* Return -1 if error, 0 if no initializer, 1 if an initializer is
24942
   present at the top level. */
24943
static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
24944
                                        int hasval, int has_ellipsis,
24945
                                        BOOL allow_initializer, BOOL export_flag)
24946
0
{
24947
0
    int label_parse, label_assign, label_done, label_lvalue, depth_lvalue;
24948
0
    int start_addr, assign_addr;
24949
0
    JSAtom prop_name, var_name;
24950
0
    int opcode, scope, tok1, skip_bits;
24951
0
    BOOL has_initializer;
24952
24953
0
    if (has_ellipsis < 0) {
24954
        /* pre-parse destructuration target for spread detection */
24955
0
        js_parse_skip_parens_token(s, &skip_bits, FALSE);
24956
0
        has_ellipsis = skip_bits & SKIP_HAS_ELLIPSIS;
24957
0
    }
24958
24959
0
    label_parse = new_label(s);
24960
0
    label_assign = new_label(s);
24961
24962
0
    start_addr = s->cur_func->byte_code.size;
24963
0
    if (hasval) {
24964
        /* consume value from the stack */
24965
0
        emit_op(s, OP_dup);
24966
0
        emit_op(s, OP_undefined);
24967
0
        emit_op(s, OP_strict_eq);
24968
0
        emit_goto(s, OP_if_true, label_parse);
24969
0
        emit_label(s, label_assign);
24970
0
    } else {
24971
0
        emit_goto(s, OP_goto, label_parse);
24972
0
        emit_label(s, label_assign);
24973
        /* leave value on the stack */
24974
0
        emit_op(s, OP_dup);
24975
0
    }
24976
0
    assign_addr = s->cur_func->byte_code.size;
24977
0
    if (s->token.val == '{') {
24978
0
        if (next_token(s))
24979
0
            return -1;
24980
        /* throw an exception if the value cannot be converted to an object */
24981
0
        emit_op(s, OP_to_object);
24982
0
        if (has_ellipsis) {
24983
            /* add excludeList on stack just below src object */
24984
0
            emit_op(s, OP_object);
24985
0
            emit_op(s, OP_swap);
24986
0
        }
24987
0
        while (s->token.val != '}') {
24988
0
            int prop_type;
24989
0
            if (s->token.val == TOK_ELLIPSIS) {
24990
0
                if (!has_ellipsis) {
24991
0
                    JS_ThrowInternalError(s->ctx, "unexpected ellipsis token");
24992
0
                    return -1;
24993
0
                }
24994
0
                if (next_token(s))
24995
0
                    return -1;
24996
0
                if (tok) {
24997
0
                    var_name = js_parse_destructuring_var(s, tok, is_arg);
24998
0
                    if (var_name == JS_ATOM_NULL)
24999
0
                        return -1;
25000
0
                    if (need_var_reference(s, tok)) {
25001
                        /* Must make a reference for proper `with` semantics */
25002
0
                        emit_op(s, OP_scope_get_var);
25003
0
                        emit_atom(s, var_name);
25004
0
                        emit_u16(s, s->cur_func->scope_level);
25005
0
                        JS_FreeAtom(s->ctx, var_name);
25006
0
                        goto lvalue0;
25007
0
                    } else {
25008
0
                        opcode = OP_scope_get_var;
25009
0
                        scope = s->cur_func->scope_level;
25010
0
                        label_lvalue = -1;
25011
0
                        depth_lvalue = 0;
25012
0
                    }
25013
0
                } else {
25014
0
                    if (js_parse_left_hand_side_expr(s))
25015
0
                        return -1;
25016
0
                lvalue0:
25017
0
                    if (get_lvalue(s, &opcode, &scope, &var_name,
25018
0
                                   &label_lvalue, &depth_lvalue, FALSE, '{'))
25019
0
                        return -1;
25020
0
                }
25021
0
                if (s->token.val != '}') {
25022
0
                    js_parse_error(s, "assignment rest property must be last");
25023
0
                    goto var_error;
25024
0
                }
25025
0
                emit_op(s, OP_object);  /* target */
25026
0
                emit_op(s, OP_copy_data_properties);
25027
0
                emit_u8(s, 0 | ((depth_lvalue + 1) << 2) | ((depth_lvalue + 2) << 5));
25028
0
                goto set_val;
25029
0
            }
25030
0
            prop_type = js_parse_property_name(s, &prop_name, FALSE, TRUE, FALSE);
25031
0
            if (prop_type < 0)
25032
0
                return -1;
25033
0
            var_name = JS_ATOM_NULL;
25034
0
            if (prop_type == PROP_TYPE_IDENT) {
25035
0
                if (next_token(s))
25036
0
                    goto prop_error;
25037
0
                if ((s->token.val == '[' || s->token.val == '{')
25038
0
                    &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' ||
25039
0
                         tok1 == '=' || tok1 == '}')) {
25040
0
                    if (prop_name == JS_ATOM_NULL) {
25041
                        /* computed property name on stack */
25042
0
                        if (has_ellipsis) {
25043
                            /* define the property in excludeList */
25044
0
                            emit_op(s, OP_to_propkey); /* avoid calling ToString twice */
25045
0
                            emit_op(s, OP_perm3); /* TOS: src excludeList prop */
25046
0
                            emit_op(s, OP_null); /* TOS: src excludeList prop null */
25047
0
                            emit_op(s, OP_define_array_el); /* TOS: src excludeList prop */
25048
0
                            emit_op(s, OP_perm3); /* TOS: excludeList src prop */
25049
0
                        }
25050
                        /* get the computed property from the source object */
25051
0
                        emit_op(s, OP_get_array_el2);
25052
0
                    } else {
25053
                        /* named property */
25054
0
                        if (has_ellipsis) {
25055
                            /* define the property in excludeList */
25056
0
                            emit_op(s, OP_swap); /* TOS: src excludeList */
25057
0
                            emit_op(s, OP_null); /* TOS: src excludeList null */
25058
0
                            emit_op(s, OP_define_field); /* TOS: src excludeList */
25059
0
                            emit_atom(s, prop_name);
25060
0
                            emit_op(s, OP_swap); /* TOS: excludeList src */
25061
0
                        }
25062
                        /* get the named property from the source object */
25063
0
                        emit_op(s, OP_get_field2);
25064
0
                        emit_u32(s, prop_name);
25065
0
                    }
25066
0
                    if (js_parse_destructuring_element(s, tok, is_arg, TRUE, -1, TRUE, export_flag) < 0)
25067
0
                        return -1;
25068
0
                    if (s->token.val == '}')
25069
0
                        break;
25070
                    /* accept a trailing comma before the '}' */
25071
0
                    if (js_parse_expect(s, ','))
25072
0
                        return -1;
25073
0
                    continue;
25074
0
                }
25075
0
                if (prop_name == JS_ATOM_NULL) {
25076
0
                    emit_op(s, OP_to_propkey);
25077
0
                    if (has_ellipsis) {
25078
                        /* define the property in excludeList */
25079
0
                        emit_op(s, OP_perm3);
25080
0
                        emit_op(s, OP_null);
25081
0
                        emit_op(s, OP_define_array_el);
25082
0
                        emit_op(s, OP_perm3);
25083
0
                    }
25084
                    /* source prop -- source source prop */
25085
0
                    emit_op(s, OP_dup1);
25086
0
                } else {
25087
0
                    if (has_ellipsis) {
25088
                        /* define the property in excludeList */
25089
0
                        emit_op(s, OP_swap);
25090
0
                        emit_op(s, OP_null);
25091
0
                        emit_op(s, OP_define_field);
25092
0
                        emit_atom(s, prop_name);
25093
0
                        emit_op(s, OP_swap);
25094
0
                    }
25095
                    /* source -- source source */
25096
0
                    emit_op(s, OP_dup);
25097
0
                }
25098
0
                if (tok) {
25099
0
                    var_name = js_parse_destructuring_var(s, tok, is_arg);
25100
0
                    if (var_name == JS_ATOM_NULL)
25101
0
                        goto prop_error;
25102
0
                    if (need_var_reference(s, tok)) {
25103
                        /* Must make a reference for proper `with` semantics */
25104
0
                        emit_op(s, OP_scope_get_var);
25105
0
                        emit_atom(s, var_name);
25106
0
                        emit_u16(s, s->cur_func->scope_level);
25107
0
                        JS_FreeAtom(s->ctx, var_name);
25108
0
                        goto lvalue1;
25109
0
                    } else {
25110
                        /* no need to make a reference for let/const */
25111
0
                        opcode = OP_scope_get_var;
25112
0
                        scope = s->cur_func->scope_level;
25113
0
                        label_lvalue = -1;
25114
0
                        depth_lvalue = 0;
25115
0
                    }
25116
0
                } else {
25117
0
                    if (js_parse_left_hand_side_expr(s))
25118
0
                        goto prop_error;
25119
0
                lvalue1:
25120
0
                    if (get_lvalue(s, &opcode, &scope, &var_name,
25121
0
                                   &label_lvalue, &depth_lvalue, FALSE, '{'))
25122
0
                        goto prop_error;
25123
                    /* swap ref and lvalue object if any */
25124
0
                    if (prop_name == JS_ATOM_NULL) {
25125
0
                        switch(depth_lvalue) {
25126
0
                        case 1:
25127
                            /* source prop x -> x source prop */
25128
0
                            emit_op(s, OP_rot3r);
25129
0
                            break;
25130
0
                        case 2:
25131
                            /* source prop x y -> x y source prop */
25132
0
                            emit_op(s, OP_swap2);   /* t p2 s p1 */
25133
0
                            break;
25134
0
                        case 3:
25135
                            /* source prop x y z -> x y z source prop */
25136
0
                            emit_op(s, OP_rot5l);
25137
0
                            emit_op(s, OP_rot5l);
25138
0
                            break;
25139
0
                        }
25140
0
                    } else {
25141
0
                        switch(depth_lvalue) {
25142
0
                        case 1:
25143
                            /* source x -> x source */
25144
0
                            emit_op(s, OP_swap);
25145
0
                            break;
25146
0
                        case 2:
25147
                            /* source x y -> x y source */
25148
0
                            emit_op(s, OP_rot3l);
25149
0
                            break;
25150
0
                        case 3:
25151
                            /* source x y z -> x y z source */
25152
0
                            emit_op(s, OP_rot4l);
25153
0
                            break;
25154
0
                        }
25155
0
                    }
25156
0
                }
25157
0
                if (prop_name == JS_ATOM_NULL) {
25158
                    /* computed property name on stack */
25159
                    /* XXX: should have OP_get_array_el2x with depth */
25160
                    /* source prop -- val */
25161
0
                    emit_op(s, OP_get_array_el);
25162
0
                } else {
25163
                    /* named property */
25164
                    /* XXX: should have OP_get_field2x with depth */
25165
                    /* source -- val */
25166
0
                    emit_op(s, OP_get_field);
25167
0
                    emit_u32(s, prop_name);
25168
0
                }
25169
0
            } else {
25170
                /* prop_type = PROP_TYPE_VAR, cannot be a computed property */
25171
0
                if (is_arg && js_parse_check_duplicate_parameter(s, prop_name))
25172
0
                    goto prop_error;
25173
0
                if ((s->cur_func->js_mode & JS_MODE_STRICT) &&
25174
0
                    (prop_name == JS_ATOM_eval || prop_name == JS_ATOM_arguments)) {
25175
0
                    js_parse_error(s, "invalid destructuring target");
25176
0
                    goto prop_error;
25177
0
                }
25178
0
                if (has_ellipsis) {
25179
                    /* define the property in excludeList */
25180
0
                    emit_op(s, OP_swap);
25181
0
                    emit_op(s, OP_null);
25182
0
                    emit_op(s, OP_define_field);
25183
0
                    emit_atom(s, prop_name);
25184
0
                    emit_op(s, OP_swap);
25185
0
                }
25186
0
                if (!tok || need_var_reference(s, tok)) {
25187
                    /* generate reference */
25188
                    /* source -- source source */
25189
0
                    emit_op(s, OP_dup);
25190
0
                    emit_op(s, OP_scope_get_var);
25191
0
                    emit_atom(s, prop_name);
25192
0
                    emit_u16(s, s->cur_func->scope_level);
25193
0
                    goto lvalue1;
25194
0
                } else {
25195
                    /* no need to make a reference for let/const */
25196
0
                    var_name = JS_DupAtom(s->ctx, prop_name);
25197
0
                    opcode = OP_scope_get_var;
25198
0
                    scope = s->cur_func->scope_level;
25199
0
                    label_lvalue = -1;
25200
0
                    depth_lvalue = 0;
25201
                    
25202
                    /* source -- source val */
25203
0
                    emit_op(s, OP_get_field2);
25204
0
                    emit_u32(s, prop_name);
25205
0
                }
25206
0
            }
25207
0
        set_val:
25208
0
            if (tok) {
25209
0
                if (js_define_var(s, var_name, tok))
25210
0
                    goto var_error;
25211
0
                if (export_flag) {
25212
0
                    if (!add_export_entry(s, s->cur_func->module, var_name, var_name,
25213
0
                                          JS_EXPORT_TYPE_LOCAL))
25214
0
                        goto var_error;
25215
0
                }
25216
0
                scope = s->cur_func->scope_level; /* XXX: check */
25217
0
            }
25218
0
            if (s->token.val == '=') {  /* handle optional default value */
25219
0
                int label_hasval;
25220
0
                emit_op(s, OP_dup);
25221
0
                emit_op(s, OP_undefined);
25222
0
                emit_op(s, OP_strict_eq);
25223
0
                label_hasval = emit_goto(s, OP_if_false, -1);
25224
0
                if (next_token(s))
25225
0
                    goto var_error;
25226
0
                emit_op(s, OP_drop);
25227
0
                if (js_parse_assign_expr(s))
25228
0
                    goto var_error;
25229
0
                if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
25230
0
                    set_object_name(s, var_name);
25231
0
                emit_label(s, label_hasval);
25232
0
            }
25233
            /* store value into lvalue object */
25234
0
            put_lvalue(s, opcode, scope, var_name, label_lvalue,
25235
0
                       PUT_LVALUE_NOKEEP_DEPTH,
25236
0
                       (tok == TOK_CONST || tok == TOK_LET));
25237
0
            if (s->token.val == '}')
25238
0
                break;
25239
            /* accept a trailing comma before the '}' */
25240
0
            if (js_parse_expect(s, ','))
25241
0
                return -1;
25242
0
        }
25243
        /* drop the source object */
25244
0
        emit_op(s, OP_drop);
25245
0
        if (has_ellipsis) {
25246
0
            emit_op(s, OP_drop); /* pop excludeList */
25247
0
        }
25248
0
        if (next_token(s))
25249
0
            return -1;
25250
0
    } else if (s->token.val == '[') {
25251
0
        BOOL has_spread;
25252
0
        int enum_depth;
25253
0
        BlockEnv block_env;
25254
25255
0
        if (next_token(s))
25256
0
            return -1;
25257
        /* the block environment is only needed in generators in case
25258
           'yield' triggers a 'return' */
25259
0
        push_break_entry(s->cur_func, &block_env,
25260
0
                         JS_ATOM_NULL, -1, -1, 2);
25261
0
        block_env.has_iterator = TRUE;
25262
0
        emit_op(s, OP_for_of_start);
25263
0
        has_spread = FALSE;
25264
0
        while (s->token.val != ']') {
25265
            /* get the next value */
25266
0
            if (s->token.val == TOK_ELLIPSIS) {
25267
0
                if (next_token(s))
25268
0
                    return -1;
25269
0
                if (s->token.val == ',' || s->token.val == ']')
25270
0
                    return js_parse_error(s, "missing binding pattern...");
25271
0
                has_spread = TRUE;
25272
0
            }
25273
0
            if (s->token.val == ',') {
25274
                /* do nothing, skip the value, has_spread is false */
25275
0
                emit_op(s, OP_for_of_next);
25276
0
                emit_u8(s, 0);
25277
0
                emit_op(s, OP_drop);
25278
0
                emit_op(s, OP_drop);
25279
0
            } else if ((s->token.val == '[' || s->token.val == '{')
25280
0
                   &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' ||
25281
0
                        tok1 == '=' || tok1 == ']')) {
25282
0
                if (has_spread) {
25283
0
                    if (tok1 == '=')
25284
0
                        return js_parse_error(s, "rest element cannot have a default value");
25285
0
                    js_emit_spread_code(s, 0);
25286
0
                } else {
25287
0
                    emit_op(s, OP_for_of_next);
25288
0
                    emit_u8(s, 0);
25289
0
                    emit_op(s, OP_drop);
25290
0
                }
25291
0
                if (js_parse_destructuring_element(s, tok, is_arg, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE, export_flag) < 0)
25292
0
                    return -1;
25293
0
            } else {
25294
0
                var_name = JS_ATOM_NULL;
25295
0
                if (tok) {
25296
0
                    var_name = js_parse_destructuring_var(s, tok, is_arg);
25297
0
                    if (var_name == JS_ATOM_NULL)
25298
0
                        goto var_error;
25299
0
                    if (js_define_var(s, var_name, tok))
25300
0
                        goto var_error;
25301
0
                    if (need_var_reference(s, tok)) {
25302
                        /* Must make a reference for proper `with` semantics */
25303
0
                        emit_op(s, OP_scope_get_var);
25304
0
                        emit_atom(s, var_name);
25305
0
                        emit_u16(s, s->cur_func->scope_level);
25306
0
                        JS_FreeAtom(s->ctx, var_name);
25307
0
                        goto lvalue2;
25308
0
                    } else {
25309
                        /* no need to make a reference for let/const */
25310
0
                        opcode = OP_scope_get_var;
25311
0
                        scope = s->cur_func->scope_level;
25312
0
                        label_lvalue = -1;
25313
0
                        enum_depth = 0;
25314
0
                    }
25315
0
                } else {
25316
0
                    if (js_parse_left_hand_side_expr(s))
25317
0
                        return -1;
25318
0
                lvalue2:
25319
0
                    if (get_lvalue(s, &opcode, &scope, &var_name,
25320
0
                                   &label_lvalue, &enum_depth, FALSE, '[')) {
25321
0
                        return -1;
25322
0
                    }
25323
0
                }
25324
0
                if (has_spread) {
25325
0
                    js_emit_spread_code(s, enum_depth);
25326
0
                } else {
25327
0
                    emit_op(s, OP_for_of_next);
25328
0
                    emit_u8(s, enum_depth);
25329
0
                    emit_op(s, OP_drop);
25330
0
                }
25331
0
                if (s->token.val == '=' && !has_spread) {
25332
                    /* handle optional default value */
25333
0
                    int label_hasval;
25334
0
                    emit_op(s, OP_dup);
25335
0
                    emit_op(s, OP_undefined);
25336
0
                    emit_op(s, OP_strict_eq);
25337
0
                    label_hasval = emit_goto(s, OP_if_false, -1);
25338
0
                    if (next_token(s))
25339
0
                        goto var_error;
25340
0
                    emit_op(s, OP_drop);
25341
0
                    if (js_parse_assign_expr(s))
25342
0
                        goto var_error;
25343
0
                    if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
25344
0
                        set_object_name(s, var_name);
25345
0
                    emit_label(s, label_hasval);
25346
0
                }
25347
                /* store value into lvalue object */
25348
0
                put_lvalue(s, opcode, scope, var_name,
25349
0
                           label_lvalue, PUT_LVALUE_NOKEEP_DEPTH,
25350
0
                           (tok == TOK_CONST || tok == TOK_LET));
25351
0
            }
25352
0
            if (s->token.val == ']')
25353
0
                break;
25354
0
            if (has_spread)
25355
0
                return js_parse_error(s, "rest element must be the last one");
25356
            /* accept a trailing comma before the ']' */
25357
0
            if (js_parse_expect(s, ','))
25358
0
                return -1;
25359
0
        }
25360
        /* close iterator object:
25361
           if completed, enum_obj has been replaced by undefined */
25362
0
        emit_op(s, OP_iterator_close);
25363
0
        pop_break_entry(s->cur_func);
25364
0
        if (next_token(s))
25365
0
            return -1;
25366
0
    } else {
25367
0
        return js_parse_error(s, "invalid assignment syntax");
25368
0
    }
25369
0
    if (s->token.val == '=' && allow_initializer) {
25370
0
        label_done = emit_goto(s, OP_goto, -1);
25371
0
        if (next_token(s))
25372
0
            return -1;
25373
0
        emit_label(s, label_parse);
25374
0
        if (hasval)
25375
0
            emit_op(s, OP_drop);
25376
0
        if (js_parse_assign_expr(s))
25377
0
            return -1;
25378
0
        emit_goto(s, OP_goto, label_assign);
25379
0
        emit_label(s, label_done);
25380
0
        has_initializer = TRUE;
25381
0
    } else {
25382
        /* normally hasval is true except if
25383
           js_parse_skip_parens_token() was wrong in the parsing */
25384
        //        assert(hasval);
25385
0
        if (!hasval) {
25386
0
            js_parse_error(s, "too complicated destructuring expression");
25387
0
            return -1;
25388
0
        }
25389
        /* remove test and decrement label ref count */
25390
0
        memset(s->cur_func->byte_code.buf + start_addr, OP_nop,
25391
0
               assign_addr - start_addr);
25392
0
        s->cur_func->label_slots[label_parse].ref_count--;
25393
0
        has_initializer = FALSE;
25394
0
    }
25395
0
    return has_initializer;
25396
25397
0
 prop_error:
25398
0
    JS_FreeAtom(s->ctx, prop_name);
25399
0
 var_error:
25400
0
    JS_FreeAtom(s->ctx, var_name);
25401
0
    return -1;
25402
0
}
25403
25404
typedef enum FuncCallType {
25405
    FUNC_CALL_NORMAL,
25406
    FUNC_CALL_NEW,
25407
    FUNC_CALL_SUPER_CTOR,
25408
    FUNC_CALL_TEMPLATE,
25409
} FuncCallType;
25410
25411
static void optional_chain_test(JSParseState *s, int *poptional_chaining_label,
25412
                                int drop_count)
25413
0
{
25414
0
    int label_next, i;
25415
0
    if (*poptional_chaining_label < 0)
25416
0
        *poptional_chaining_label = new_label(s);
25417
   /* XXX: could be more efficient with a specific opcode */
25418
0
    emit_op(s, OP_dup);
25419
0
    emit_op(s, OP_is_undefined_or_null);
25420
0
    label_next = emit_goto(s, OP_if_false, -1);
25421
0
    for(i = 0; i < drop_count; i++)
25422
0
        emit_op(s, OP_drop);
25423
0
    emit_op(s, OP_undefined);
25424
0
    emit_goto(s, OP_goto, *poptional_chaining_label);
25425
0
    emit_label(s, label_next);
25426
0
}
25427
25428
/* allowed parse_flags: PF_POSTFIX_CALL */
25429
static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
25430
11
{
25431
11
    FuncCallType call_type;
25432
11
    int optional_chaining_label;
25433
11
    BOOL accept_lparen = (parse_flags & PF_POSTFIX_CALL) != 0;
25434
11
    const uint8_t *op_token_ptr;
25435
    
25436
11
    call_type = FUNC_CALL_NORMAL;
25437
11
    switch(s->token.val) {
25438
1
    case TOK_NUMBER:
25439
1
        {
25440
1
            JSValue val;
25441
1
            val = s->token.u.num.val;
25442
25443
1
            if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) {
25444
0
                emit_op(s, OP_push_i32);
25445
0
                emit_u32(s, JS_VALUE_GET_INT(val));
25446
1
            } else if (JS_VALUE_GET_TAG(val) == JS_TAG_SHORT_BIG_INT) {
25447
0
                int64_t v;
25448
0
                v = JS_VALUE_GET_SHORT_BIG_INT(val);
25449
0
                if (v >= INT32_MIN && v <= INT32_MAX) {
25450
0
                    emit_op(s, OP_push_bigint_i32);
25451
0
                    emit_u32(s, v);
25452
0
                } else {
25453
0
                    goto large_number;
25454
0
                }
25455
1
            } else {
25456
1
            large_number:
25457
1
                if (emit_push_const(s, val, 0) < 0)
25458
0
                    return -1;
25459
1
            }
25460
1
        }
25461
1
        if (next_token(s))
25462
0
            return -1;
25463
1
        break;
25464
1
    case TOK_TEMPLATE:
25465
0
        if (js_parse_template(s, 0, NULL))
25466
0
            return -1;
25467
0
        break;
25468
0
    case TOK_STRING:
25469
0
        if (emit_push_const(s, s->token.u.str.str, 1))
25470
0
            return -1;
25471
0
        if (next_token(s))
25472
0
            return -1;
25473
0
        break;
25474
25475
0
    case TOK_DIV_ASSIGN:
25476
0
        s->buf_ptr -= 2;
25477
0
        goto parse_regexp;
25478
0
    case '/':
25479
0
        s->buf_ptr--;
25480
0
    parse_regexp:
25481
0
        {
25482
0
            JSValue str;
25483
0
            int ret;
25484
0
            if (!s->ctx->compile_regexp)
25485
0
                return js_parse_error(s, "RegExp are not supported");
25486
            /* the previous token is '/' or '/=', so no need to free */
25487
0
            if (js_parse_regexp(s))
25488
0
                return -1;
25489
0
            ret = emit_push_const(s, s->token.u.regexp.body, 0);
25490
0
            str = s->ctx->compile_regexp(s->ctx, s->token.u.regexp.body,
25491
0
                                         s->token.u.regexp.flags);
25492
0
            if (JS_IsException(str)) {
25493
                /* add the line number info */
25494
0
                int line_num, col_num;
25495
0
                line_num = get_line_col(&col_num, s->buf_start, s->token.ptr - s->buf_start);
25496
0
                build_backtrace(s->ctx, s->ctx->rt->current_exception,
25497
0
                                s->filename, line_num + 1, col_num + 1, 0);
25498
0
                return -1;
25499
0
            }
25500
0
            ret = emit_push_const(s, str, 0);
25501
0
            JS_FreeValue(s->ctx, str);
25502
0
            if (ret)
25503
0
                return -1;
25504
            /* we use a specific opcode to be sure the correct
25505
               function is called (otherwise the bytecode would have
25506
               to be verified by the RegExp constructor) */
25507
0
            emit_op(s, OP_regexp);
25508
0
            if (next_token(s))
25509
0
                return -1;
25510
0
        }
25511
0
        break;
25512
0
    case '(':
25513
0
        if (js_parse_expr_paren(s))
25514
0
            return -1;
25515
0
        break;
25516
0
    case TOK_FUNCTION:
25517
0
        if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR,
25518
0
                                   JS_FUNC_NORMAL, JS_ATOM_NULL,
25519
0
                                   s->token.ptr))
25520
0
            return -1;
25521
0
        break;
25522
0
    case TOK_CLASS:
25523
0
        if (js_parse_class(s, TRUE, JS_PARSE_EXPORT_NONE))
25524
0
            return -1;
25525
0
        break;
25526
0
    case TOK_NULL:
25527
0
        if (next_token(s))
25528
0
            return -1;
25529
0
        emit_op(s, OP_null);
25530
0
        break;
25531
0
    case TOK_THIS:
25532
0
        if (next_token(s))
25533
0
            return -1;
25534
0
        emit_op(s, OP_scope_get_var);
25535
0
        emit_atom(s, JS_ATOM_this);
25536
0
        emit_u16(s, 0);
25537
0
        break;
25538
0
    case TOK_FALSE:
25539
0
        if (next_token(s))
25540
0
            return -1;
25541
0
        emit_op(s, OP_push_false);
25542
0
        break;
25543
0
    case TOK_TRUE:
25544
0
        if (next_token(s))
25545
0
            return -1;
25546
0
        emit_op(s, OP_push_true);
25547
0
        break;
25548
9
    case TOK_IDENT:
25549
9
        {
25550
9
            JSAtom name;
25551
9
            const uint8_t *source_ptr;
25552
9
            if (s->token.u.ident.is_reserved) {
25553
0
                return js_parse_error_reserved_identifier(s);
25554
0
            }
25555
9
            source_ptr = s->token.ptr;
25556
9
            if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
25557
9
                peek_token(s, TRUE) != '\n') {
25558
0
                if (next_token(s))
25559
0
                    return -1;
25560
0
                if (s->token.val == TOK_FUNCTION) {
25561
0
                    if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR,
25562
0
                                               JS_FUNC_ASYNC, JS_ATOM_NULL,
25563
0
                                               source_ptr))
25564
0
                        return -1;
25565
0
                } else {
25566
0
                    name = JS_DupAtom(s->ctx, JS_ATOM_async);
25567
0
                    goto do_get_var;
25568
0
                }
25569
9
            } else {
25570
9
                if (s->token.u.ident.atom == JS_ATOM_arguments &&
25571
9
                    !s->cur_func->arguments_allowed) {
25572
0
                    js_parse_error(s, "'arguments' identifier is not allowed in class field initializer");
25573
0
                    return -1;
25574
0
                }
25575
9
                name = JS_DupAtom(s->ctx, s->token.u.ident.atom);
25576
9
                if (next_token(s)) {
25577
0
                    JS_FreeAtom(s->ctx, name);
25578
0
                    return -1;
25579
0
                }
25580
9
            do_get_var:
25581
9
                emit_source_pos(s, source_ptr);
25582
9
                emit_op(s, OP_scope_get_var);
25583
9
                emit_u32(s, name);
25584
9
                emit_u16(s, s->cur_func->scope_level);
25585
9
            }
25586
9
        }
25587
9
        break;
25588
9
    case '{':
25589
0
    case '[':
25590
0
        if (s->token.val == '{') {
25591
0
            if (js_parse_object_literal(s))
25592
0
                return -1;
25593
0
        } else {
25594
0
            if (js_parse_array_literal(s))
25595
0
                return -1;
25596
0
        }
25597
0
        break;
25598
0
    case TOK_NEW:
25599
0
        if (next_token(s))
25600
0
            return -1;
25601
0
        if (s->token.val == '.') {
25602
0
            if (next_token(s))
25603
0
                return -1;
25604
0
            if (!token_is_pseudo_keyword(s, JS_ATOM_target))
25605
0
                return js_parse_error(s, "expecting target");
25606
0
            if (!s->cur_func->new_target_allowed)
25607
0
                return js_parse_error(s, "new.target only allowed within functions");
25608
0
            if (next_token(s))
25609
0
                return -1;
25610
0
            emit_op(s, OP_scope_get_var);
25611
0
            emit_atom(s, JS_ATOM_new_target);
25612
0
            emit_u16(s, 0);
25613
0
        } else {
25614
0
            if (js_parse_postfix_expr(s, 0))
25615
0
                return -1;
25616
0
            accept_lparen = TRUE;
25617
0
            if (s->token.val != '(') {
25618
                /* new operator on an object */
25619
0
                emit_source_pos(s, s->token.ptr);
25620
0
                emit_op(s, OP_dup);
25621
0
                emit_op(s, OP_call_constructor);
25622
0
                emit_u16(s, 0);
25623
0
            } else {
25624
0
                call_type = FUNC_CALL_NEW;
25625
0
            }
25626
0
        }
25627
0
        break;
25628
0
    case TOK_SUPER:
25629
0
        if (next_token(s))
25630
0
            return -1;
25631
0
        if (s->token.val == '(') {
25632
0
            if (!s->cur_func->super_call_allowed)
25633
0
                return js_parse_error(s, "super() is only valid in a derived class constructor");
25634
0
            call_type = FUNC_CALL_SUPER_CTOR;
25635
0
        } else if (s->token.val == '.' || s->token.val == '[') {
25636
0
            if (!s->cur_func->super_allowed)
25637
0
                return js_parse_error(s, "'super' is only valid in a method");
25638
0
            emit_op(s, OP_scope_get_var);
25639
0
            emit_atom(s, JS_ATOM_this);
25640
0
            emit_u16(s, 0);
25641
0
            emit_op(s, OP_scope_get_var);
25642
0
            emit_atom(s, JS_ATOM_home_object);
25643
0
            emit_u16(s, 0);
25644
0
            emit_op(s, OP_get_super);
25645
0
        } else {
25646
0
            return js_parse_error(s, "invalid use of 'super'");
25647
0
        }
25648
0
        break;
25649
0
    case TOK_IMPORT:
25650
0
        if (next_token(s))
25651
0
            return -1;
25652
0
        if (s->token.val == '.') {
25653
0
            if (next_token(s))
25654
0
                return -1;
25655
0
            if (!token_is_pseudo_keyword(s, JS_ATOM_meta))
25656
0
                return js_parse_error(s, "meta expected");
25657
0
            if (!s->is_module)
25658
0
                return js_parse_error(s, "import.meta only valid in module code");
25659
0
            if (next_token(s))
25660
0
                return -1;
25661
0
            emit_op(s, OP_special_object);
25662
0
            emit_u8(s, OP_SPECIAL_OBJECT_IMPORT_META);
25663
0
        } else {
25664
0
            if (js_parse_expect(s, '('))
25665
0
                return -1;
25666
0
            if (!accept_lparen)
25667
0
                return js_parse_error(s, "invalid use of 'import()'");
25668
0
            if (js_parse_assign_expr(s))
25669
0
                return -1;
25670
0
            if (s->token.val == ',') {
25671
0
                if (next_token(s))
25672
0
                    return -1;
25673
0
                if (s->token.val != ')') {
25674
0
                    if (js_parse_assign_expr(s))
25675
0
                        return -1;
25676
                    /* accept a trailing comma */
25677
0
                    if (s->token.val == ',') {
25678
0
                        if (next_token(s))
25679
0
                            return -1;
25680
0
                    }
25681
0
                } else {
25682
0
                    emit_op(s, OP_undefined);
25683
0
                }
25684
0
            } else {
25685
0
                emit_op(s, OP_undefined);
25686
0
            }
25687
0
            if (js_parse_expect(s, ')'))
25688
0
                return -1;
25689
0
            emit_op(s, OP_import);
25690
0
        }
25691
0
        break;
25692
1
    default:
25693
1
        return js_parse_error(s, "unexpected token in expression: '%.*s'",
25694
1
                              (int)(s->buf_ptr - s->token.ptr), s->token.ptr);
25695
11
    }
25696
25697
10
    optional_chaining_label = -1;
25698
14
    for(;;) {
25699
14
        JSFunctionDef *fd = s->cur_func;
25700
14
        BOOL has_optional_chain = FALSE;
25701
25702
14
        if (s->token.val == TOK_QUESTION_MARK_DOT) {
25703
0
            if ((parse_flags & PF_POSTFIX_CALL) == 0)
25704
0
                return js_parse_error(s, "new keyword cannot be used with an optional chain");
25705
0
            op_token_ptr = s->token.ptr;
25706
            /* optional chaining */
25707
0
            if (next_token(s))
25708
0
                return -1;
25709
0
            has_optional_chain = TRUE;
25710
0
            if (s->token.val == '(' && accept_lparen) {
25711
0
                goto parse_func_call;
25712
0
            } else if (s->token.val == '[') {
25713
0
                goto parse_array_access;
25714
0
            } else {
25715
0
                goto parse_property;
25716
0
            }
25717
14
        } else if (s->token.val == TOK_TEMPLATE &&
25718
14
                   call_type == FUNC_CALL_NORMAL) {
25719
0
            if (optional_chaining_label >= 0) {
25720
0
                return js_parse_error(s, "template literal cannot appear in an optional chain");
25721
0
            }
25722
0
            call_type = FUNC_CALL_TEMPLATE;
25723
0
            op_token_ptr = s->token.ptr; /* XXX: check if right position */
25724
0
            goto parse_func_call2;
25725
14
        } else if (s->token.val == '(' && accept_lparen) {
25726
0
            int opcode, arg_count, drop_count;
25727
25728
            /* function call */
25729
0
        parse_func_call:
25730
0
            op_token_ptr = s->token.ptr;
25731
0
            if (next_token(s))
25732
0
                return -1;
25733
25734
0
            if (call_type == FUNC_CALL_NORMAL) {
25735
0
            parse_func_call2:
25736
0
                switch(opcode = get_prev_opcode(fd)) {
25737
0
                case OP_get_field:
25738
                    /* keep the object on the stack */
25739
0
                    fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;
25740
0
                    drop_count = 2;
25741
0
                    break;
25742
0
                case OP_get_field_opt_chain:
25743
0
                    {
25744
0
                        int opt_chain_label, next_label;
25745
0
                        opt_chain_label = get_u32(fd->byte_code.buf +
25746
0
                                                  fd->last_opcode_pos + 1 + 4 + 1);
25747
                        /* keep the object on the stack */
25748
0
                        fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;
25749
0
                        fd->byte_code.size = fd->last_opcode_pos + 1 + 4;
25750
0
                        next_label = emit_goto(s, OP_goto, -1);
25751
0
                        emit_label(s, opt_chain_label);
25752
                        /* need an additional undefined value for the
25753
                           case where the optional field does not
25754
                           exists */
25755
0
                        emit_op(s, OP_undefined);
25756
0
                        emit_label(s, next_label);
25757
0
                        drop_count = 2;
25758
0
                        opcode = OP_get_field;
25759
0
                    }
25760
0
                    break;
25761
0
                case OP_scope_get_private_field:
25762
                    /* keep the object on the stack */
25763
0
                    fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_private_field2;
25764
0
                    drop_count = 2;
25765
0
                    break;
25766
0
                case OP_get_array_el:
25767
                    /* keep the object on the stack */
25768
0
                    fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;
25769
0
                    drop_count = 2;
25770
0
                    break;
25771
0
                case OP_get_array_el_opt_chain:
25772
0
                    {
25773
0
                        int opt_chain_label, next_label;
25774
0
                        opt_chain_label = get_u32(fd->byte_code.buf +
25775
0
                                                  fd->last_opcode_pos + 1 + 1);
25776
                        /* keep the object on the stack */
25777
0
                        fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;
25778
0
                        fd->byte_code.size = fd->last_opcode_pos + 1;
25779
0
                        next_label = emit_goto(s, OP_goto, -1);
25780
0
                        emit_label(s, opt_chain_label);
25781
                        /* need an additional undefined value for the
25782
                           case where the optional field does not
25783
                           exists */
25784
0
                        emit_op(s, OP_undefined);
25785
0
                        emit_label(s, next_label);
25786
0
                        drop_count = 2;
25787
0
                        opcode = OP_get_array_el;
25788
0
                    }
25789
0
                    break;
25790
0
                case OP_scope_get_var:
25791
0
                    {
25792
0
                        JSAtom name;
25793
0
                        int scope;
25794
0
                        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
25795
0
                        scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
25796
0
                        if (name == JS_ATOM_eval && call_type == FUNC_CALL_NORMAL && !has_optional_chain) {
25797
                            /* direct 'eval' */
25798
0
                            opcode = OP_eval;
25799
0
                        } else {
25800
                            /* verify if function name resolves to a simple
25801
                               get_loc/get_arg: a function call inside a `with`
25802
                               statement can resolve to a method call of the
25803
                               `with` context object
25804
                             */
25805
                            /* XXX: always generate the OP_scope_get_ref
25806
                               and remove it in variable resolution
25807
                               pass ? */
25808
0
                            if (has_with_scope(fd, scope)) {
25809
0
                                opcode = OP_scope_get_ref;
25810
0
                                fd->byte_code.buf[fd->last_opcode_pos] = opcode;
25811
0
                            }
25812
0
                        }
25813
0
                        drop_count = 1;
25814
0
                    }
25815
0
                    break;
25816
0
                case OP_get_super_value:
25817
0
                    fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el;
25818
                    /* on stack: this func_obj */
25819
0
                    opcode = OP_get_array_el;
25820
0
                    drop_count = 2;
25821
0
                    break;
25822
0
                default:
25823
0
                    opcode = OP_invalid;
25824
0
                    drop_count = 1;
25825
0
                    break;
25826
0
                }
25827
0
                if (has_optional_chain) {
25828
0
                    optional_chain_test(s, &optional_chaining_label,
25829
0
                                        drop_count);
25830
0
                }
25831
0
            } else {
25832
0
                opcode = OP_invalid;
25833
0
            }
25834
25835
0
            if (call_type == FUNC_CALL_TEMPLATE) {
25836
0
                if (js_parse_template(s, 1, &arg_count))
25837
0
                    return -1;
25838
0
                goto emit_func_call;
25839
0
            } else if (call_type == FUNC_CALL_SUPER_CTOR) {
25840
0
                emit_op(s, OP_scope_get_var);
25841
0
                emit_atom(s, JS_ATOM_this_active_func);
25842
0
                emit_u16(s, 0);
25843
25844
0
                emit_op(s, OP_get_super);
25845
25846
0
                emit_op(s, OP_scope_get_var);
25847
0
                emit_atom(s, JS_ATOM_new_target);
25848
0
                emit_u16(s, 0);
25849
0
            } else if (call_type == FUNC_CALL_NEW) {
25850
0
                emit_op(s, OP_dup); /* new.target = function */
25851
0
            }
25852
25853
            /* parse arguments */
25854
0
            arg_count = 0;
25855
0
            while (s->token.val != ')') {
25856
0
                if (arg_count >= 65535) {
25857
0
                    return js_parse_error(s, "Too many call arguments");
25858
0
                }
25859
0
                if (s->token.val == TOK_ELLIPSIS)
25860
0
                    break;
25861
0
                if (js_parse_assign_expr(s))
25862
0
                    return -1;
25863
0
                arg_count++;
25864
0
                if (s->token.val == ')')
25865
0
                    break;
25866
                /* accept a trailing comma before the ')' */
25867
0
                if (js_parse_expect(s, ','))
25868
0
                    return -1;
25869
0
            }
25870
0
            if (s->token.val == TOK_ELLIPSIS) {
25871
0
                emit_op(s, OP_array_from);
25872
0
                emit_u16(s, arg_count);
25873
0
                emit_op(s, OP_push_i32);
25874
0
                emit_u32(s, arg_count);
25875
25876
                /* on stack: array idx */
25877
0
                while (s->token.val != ')') {
25878
0
                    if (s->token.val == TOK_ELLIPSIS) {
25879
0
                        if (next_token(s))
25880
0
                            return -1;
25881
0
                        if (js_parse_assign_expr(s))
25882
0
                            return -1;
25883
0
#if 1
25884
                        /* XXX: could pass is_last indicator? */
25885
0
                        emit_op(s, OP_append);
25886
#else
25887
                        int label_next, label_done;
25888
                        label_next = new_label(s);
25889
                        label_done = new_label(s);
25890
                        /* push enumerate object below array/idx pair */
25891
                        emit_op(s, OP_for_of_start);
25892
                        emit_op(s, OP_rot5l);
25893
                        emit_op(s, OP_rot5l);
25894
                        emit_label(s, label_next);
25895
                        /* on stack: enum_rec array idx */
25896
                        emit_op(s, OP_for_of_next);
25897
                        emit_u8(s, 2);
25898
                        emit_goto(s, OP_if_true, label_done);
25899
                        /* append element */
25900
                        /* enum_rec array idx val -> enum_rec array new_idx */
25901
                        emit_op(s, OP_define_array_el);
25902
                        emit_op(s, OP_inc);
25903
                        emit_goto(s, OP_goto, label_next);
25904
                        emit_label(s, label_done);
25905
                        /* close enumeration, drop enum_rec and idx */
25906
                        emit_op(s, OP_drop); /* drop undef */
25907
                        emit_op(s, OP_nip1); /* drop enum_rec */
25908
                        emit_op(s, OP_nip1);
25909
                        emit_op(s, OP_nip1);
25910
#endif
25911
0
                    } else {
25912
0
                        if (js_parse_assign_expr(s))
25913
0
                            return -1;
25914
                        /* array idx val */
25915
0
                        emit_op(s, OP_define_array_el);
25916
0
                        emit_op(s, OP_inc);
25917
0
                    }
25918
0
                    if (s->token.val == ')')
25919
0
                        break;
25920
                    /* accept a trailing comma before the ')' */
25921
0
                    if (js_parse_expect(s, ','))
25922
0
                        return -1;
25923
0
                }
25924
0
                if (next_token(s))
25925
0
                    return -1;
25926
                /* drop the index */
25927
0
                emit_op(s, OP_drop);
25928
25929
0
                emit_source_pos(s, op_token_ptr);
25930
                /* apply function call */
25931
0
                switch(opcode) {
25932
0
                case OP_get_field:
25933
0
                case OP_scope_get_private_field:
25934
0
                case OP_get_array_el:
25935
0
                case OP_scope_get_ref:
25936
                    /* obj func array -> func obj array */
25937
0
                    emit_op(s, OP_perm3);
25938
0
                    emit_op(s, OP_apply);
25939
0
                    emit_u16(s, call_type == FUNC_CALL_NEW);
25940
0
                    break;
25941
0
                case OP_eval:
25942
0
                    emit_op(s, OP_apply_eval);
25943
0
                    emit_u16(s, fd->scope_level);
25944
0
                    fd->has_eval_call = TRUE;
25945
0
                    break;
25946
0
                default:
25947
0
                    if (call_type == FUNC_CALL_SUPER_CTOR) {
25948
0
                        emit_op(s, OP_apply);
25949
0
                        emit_u16(s, 1);
25950
                        /* set the 'this' value */
25951
0
                        emit_op(s, OP_dup);
25952
0
                        emit_op(s, OP_scope_put_var_init);
25953
0
                        emit_atom(s, JS_ATOM_this);
25954
0
                        emit_u16(s, 0);
25955
25956
0
                        emit_class_field_init(s);
25957
0
                    } else if (call_type == FUNC_CALL_NEW) {
25958
                        /* obj func array -> func obj array */
25959
0
                        emit_op(s, OP_perm3);
25960
0
                        emit_op(s, OP_apply);
25961
0
                        emit_u16(s, 1);
25962
0
                    } else {
25963
                        /* func array -> func undef array */
25964
0
                        emit_op(s, OP_undefined);
25965
0
                        emit_op(s, OP_swap);
25966
0
                        emit_op(s, OP_apply);
25967
0
                        emit_u16(s, 0);
25968
0
                    }
25969
0
                    break;
25970
0
                }
25971
0
            } else {
25972
0
                if (next_token(s))
25973
0
                    return -1;
25974
0
            emit_func_call:
25975
0
                emit_source_pos(s, op_token_ptr);
25976
0
                switch(opcode) {
25977
0
                case OP_get_field:
25978
0
                case OP_scope_get_private_field:
25979
0
                case OP_get_array_el:
25980
0
                case OP_scope_get_ref:
25981
0
                    emit_op(s, OP_call_method);
25982
0
                    emit_u16(s, arg_count);
25983
0
                    break;
25984
0
                case OP_eval:
25985
0
                    emit_op(s, OP_eval);
25986
0
                    emit_u16(s, arg_count);
25987
0
                    emit_u16(s, fd->scope_level);
25988
0
                    fd->has_eval_call = TRUE;
25989
0
                    break;
25990
0
                default:
25991
0
                    if (call_type == FUNC_CALL_SUPER_CTOR) {
25992
0
                        emit_op(s, OP_call_constructor);
25993
0
                        emit_u16(s, arg_count);
25994
25995
                        /* set the 'this' value */
25996
0
                        emit_op(s, OP_dup);
25997
0
                        emit_op(s, OP_scope_put_var_init);
25998
0
                        emit_atom(s, JS_ATOM_this);
25999
0
                        emit_u16(s, 0);
26000
26001
0
                        emit_class_field_init(s);
26002
0
                    } else if (call_type == FUNC_CALL_NEW) {
26003
0
                        emit_op(s, OP_call_constructor);
26004
0
                        emit_u16(s, arg_count);
26005
0
                    } else {
26006
0
                        emit_op(s, OP_call);
26007
0
                        emit_u16(s, arg_count);
26008
0
                    }
26009
0
                    break;
26010
0
                }
26011
0
            }
26012
0
            call_type = FUNC_CALL_NORMAL;
26013
14
        } else if (s->token.val == '.') {
26014
4
            op_token_ptr = s->token.ptr;
26015
4
            if (next_token(s))
26016
0
                return -1;
26017
4
        parse_property:
26018
4
            emit_source_pos(s, op_token_ptr);
26019
4
            if (s->token.val == TOK_PRIVATE_NAME) {
26020
                /* private class field */
26021
0
                if (get_prev_opcode(fd) == OP_get_super) {
26022
0
                    return js_parse_error(s, "private class field forbidden after super");
26023
0
                }
26024
0
                if (has_optional_chain) {
26025
0
                    optional_chain_test(s, &optional_chaining_label, 1);
26026
0
                }
26027
0
                emit_op(s, OP_scope_get_private_field);
26028
0
                emit_atom(s, s->token.u.ident.atom);
26029
0
                emit_u16(s, s->cur_func->scope_level);
26030
4
            } else {
26031
4
                if (!token_is_ident(s->token.val)) {
26032
0
                    return js_parse_error(s, "expecting field name");
26033
0
                }
26034
4
                if (get_prev_opcode(fd) == OP_get_super) {
26035
0
                    JSValue val;
26036
0
                    int ret;
26037
0
                    val = JS_AtomToValue(s->ctx, s->token.u.ident.atom);
26038
0
                    ret = emit_push_const(s, val, 1);
26039
0
                    JS_FreeValue(s->ctx, val);
26040
0
                    if (ret)
26041
0
                        return -1;
26042
0
                    emit_op(s, OP_get_super_value);
26043
4
                } else {
26044
4
                    if (has_optional_chain) {
26045
0
                        optional_chain_test(s, &optional_chaining_label, 1);
26046
0
                    }
26047
4
                    emit_op(s, OP_get_field);
26048
4
                    emit_atom(s, s->token.u.ident.atom);
26049
4
                }
26050
4
            }
26051
4
            if (next_token(s))
26052
0
                return -1;
26053
10
        } else if (s->token.val == '[') {
26054
0
            int prev_op;
26055
0
            op_token_ptr = s->token.ptr;
26056
0
        parse_array_access:
26057
0
            prev_op = get_prev_opcode(fd);
26058
0
            if (has_optional_chain) {
26059
0
                optional_chain_test(s, &optional_chaining_label, 1);
26060
0
            }
26061
0
            if (next_token(s))
26062
0
                return -1;
26063
0
            if (js_parse_expr(s))
26064
0
                return -1;
26065
0
            if (js_parse_expect(s, ']'))
26066
0
                return -1;
26067
0
            emit_source_pos(s, op_token_ptr);
26068
0
            if (prev_op == OP_get_super) {
26069
0
                emit_op(s, OP_get_super_value);
26070
0
            } else {
26071
0
                emit_op(s, OP_get_array_el);
26072
0
            }
26073
10
        } else {
26074
10
            break;
26075
10
        }
26076
14
    }
26077
10
    if (optional_chaining_label >= 0) {
26078
0
        JSFunctionDef *fd = s->cur_func;
26079
0
        int opcode;
26080
0
        emit_label_raw(s, optional_chaining_label);
26081
        /* modify the last opcode so that it is an indicator of an
26082
           optional chain */
26083
0
        opcode = get_prev_opcode(fd);
26084
0
        if (opcode == OP_get_field || opcode == OP_get_array_el) {
26085
0
            if (opcode == OP_get_field)
26086
0
                opcode = OP_get_field_opt_chain;
26087
0
            else
26088
0
                opcode = OP_get_array_el_opt_chain;
26089
0
            fd->byte_code.buf[fd->last_opcode_pos] = opcode;
26090
0
        } else {
26091
0
            fd->last_opcode_pos = -1;
26092
0
        }
26093
0
    }
26094
10
    return 0;
26095
10
}
26096
26097
static __exception int js_parse_delete(JSParseState *s)
26098
0
{
26099
0
    JSFunctionDef *fd = s->cur_func;
26100
0
    JSAtom name;
26101
0
    int opcode;
26102
26103
0
    if (next_token(s))
26104
0
        return -1;
26105
0
    if (js_parse_unary(s, PF_POW_FORBIDDEN))
26106
0
        return -1;
26107
0
    switch(opcode = get_prev_opcode(fd)) {
26108
0
    case OP_get_field:
26109
0
    case OP_get_field_opt_chain:
26110
0
        {
26111
0
            JSValue val;
26112
0
            int ret, opt_chain_label, next_label;
26113
0
            if (opcode == OP_get_field_opt_chain) {
26114
0
                opt_chain_label = get_u32(fd->byte_code.buf +
26115
0
                                          fd->last_opcode_pos + 1 + 4 + 1);
26116
0
            } else {
26117
0
                opt_chain_label = -1;
26118
0
            }
26119
0
            name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
26120
0
            fd->byte_code.size = fd->last_opcode_pos;
26121
0
            val = JS_AtomToValue(s->ctx, name);
26122
0
            ret = emit_push_const(s, val, 1);
26123
0
            JS_FreeValue(s->ctx, val);
26124
0
            JS_FreeAtom(s->ctx, name);
26125
0
            if (ret)
26126
0
                return ret;
26127
0
            emit_op(s, OP_delete);
26128
0
            if (opt_chain_label >= 0) {
26129
0
                next_label = emit_goto(s, OP_goto, -1);
26130
0
                emit_label(s, opt_chain_label);
26131
                /* if the optional chain is not taken, return 'true' */
26132
0
                emit_op(s, OP_drop);
26133
0
                emit_op(s, OP_push_true);
26134
0
                emit_label(s, next_label);
26135
0
            }
26136
0
            fd->last_opcode_pos = -1;
26137
0
        }
26138
0
        break;
26139
0
    case OP_get_array_el:
26140
0
        fd->byte_code.size = fd->last_opcode_pos;
26141
0
        fd->last_opcode_pos = -1;
26142
0
        emit_op(s, OP_delete);
26143
0
        break;
26144
0
    case OP_get_array_el_opt_chain:
26145
0
        {
26146
0
            int opt_chain_label, next_label;
26147
0
            opt_chain_label = get_u32(fd->byte_code.buf +
26148
0
                                      fd->last_opcode_pos + 1 + 1);
26149
0
            fd->byte_code.size = fd->last_opcode_pos;
26150
0
            emit_op(s, OP_delete);
26151
0
            next_label = emit_goto(s, OP_goto, -1);
26152
0
            emit_label(s, opt_chain_label);
26153
            /* if the optional chain is not taken, return 'true' */
26154
0
            emit_op(s, OP_drop);
26155
0
            emit_op(s, OP_push_true);
26156
0
            emit_label(s, next_label);
26157
0
            fd->last_opcode_pos = -1;
26158
0
        }
26159
0
        break;
26160
0
    case OP_scope_get_var:
26161
        /* 'delete this': this is not a reference */
26162
0
        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
26163
0
        if (name == JS_ATOM_this || name == JS_ATOM_new_target)
26164
0
            goto ret_true;
26165
0
        if (fd->js_mode & JS_MODE_STRICT) {
26166
0
            return js_parse_error(s, "cannot delete a direct reference in strict mode");
26167
0
        } else {
26168
0
            fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_delete_var;
26169
0
        }
26170
0
        break;
26171
0
    case OP_scope_get_private_field:
26172
0
        return js_parse_error(s, "cannot delete a private class field");
26173
0
    case OP_get_super_value:
26174
0
        fd->byte_code.size = fd->last_opcode_pos;
26175
0
        fd->last_opcode_pos = -1;
26176
0
        emit_op(s, OP_throw_error);
26177
0
        emit_atom(s, JS_ATOM_NULL);
26178
0
        emit_u8(s, JS_THROW_ERROR_DELETE_SUPER);
26179
0
        break;
26180
0
    default:
26181
0
    ret_true:
26182
0
        emit_op(s, OP_drop);
26183
0
        emit_op(s, OP_push_true);
26184
0
        break;
26185
0
    }
26186
0
    return 0;
26187
0
}
26188
26189
/* allowed parse_flags: PF_POW_ALLOWED, PF_POW_FORBIDDEN */
26190
static __exception int js_parse_unary(JSParseState *s, int parse_flags)
26191
12
{
26192
12
    int op;
26193
12
    const uint8_t *op_token_ptr;
26194
26195
12
    switch(s->token.val) {
26196
0
    case '+':
26197
1
    case '-':
26198
1
    case '!':
26199
1
    case '~':
26200
1
    case TOK_VOID:
26201
1
        op_token_ptr = s->token.ptr;
26202
1
        op = s->token.val;
26203
1
        if (next_token(s))
26204
0
            return -1;
26205
1
        if (js_parse_unary(s, PF_POW_FORBIDDEN))
26206
0
            return -1;
26207
1
        switch(op) {
26208
1
        case '-':
26209
1
            emit_source_pos(s, op_token_ptr);
26210
1
            emit_op(s, OP_neg);
26211
1
            break;
26212
0
        case '+':
26213
0
            emit_source_pos(s, op_token_ptr);
26214
0
            emit_op(s, OP_plus);
26215
0
            break;
26216
0
        case '!':
26217
0
            emit_op(s, OP_lnot);
26218
0
            break;
26219
0
        case '~':
26220
0
            emit_source_pos(s, op_token_ptr);
26221
0
            emit_op(s, OP_not);
26222
0
            break;
26223
0
        case TOK_VOID:
26224
0
            emit_op(s, OP_drop);
26225
0
            emit_op(s, OP_undefined);
26226
0
            break;
26227
0
        default:
26228
0
            abort();
26229
1
        }
26230
1
        parse_flags = 0;
26231
1
        break;
26232
0
    case TOK_DEC:
26233
0
    case TOK_INC:
26234
0
        {
26235
0
            int opcode, op, scope, label;
26236
0
            JSAtom name;
26237
0
            op = s->token.val;
26238
0
            op_token_ptr = s->token.ptr;
26239
0
            if (next_token(s))
26240
0
                return -1;
26241
0
            if (js_parse_unary(s, 0))
26242
0
                return -1;
26243
0
            if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))
26244
0
                return -1;
26245
0
            emit_source_pos(s, op_token_ptr);
26246
0
            emit_op(s, OP_dec + op - TOK_DEC);
26247
0
            put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP,
26248
0
                       FALSE);
26249
0
        }
26250
0
        break;
26251
0
    case TOK_TYPEOF:
26252
0
        {
26253
0
            JSFunctionDef *fd;
26254
0
            if (next_token(s))
26255
0
                return -1;
26256
0
            if (js_parse_unary(s, PF_POW_FORBIDDEN))
26257
0
                return -1;
26258
            /* reference access should not return an exception, so we
26259
               patch the get_var */
26260
0
            fd = s->cur_func;
26261
0
            if (get_prev_opcode(fd) == OP_scope_get_var) {
26262
0
                fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_var_undef;
26263
0
            }
26264
0
            emit_op(s, OP_typeof);
26265
0
            parse_flags = 0;
26266
0
        }
26267
0
        break;
26268
0
    case TOK_DELETE:
26269
0
        if (js_parse_delete(s))
26270
0
            return -1;
26271
0
        parse_flags = 0;
26272
0
        break;
26273
0
    case TOK_AWAIT:
26274
0
        if (!(s->cur_func->func_kind & JS_FUNC_ASYNC))
26275
0
            return js_parse_error(s, "unexpected 'await' keyword");
26276
0
        if (!s->cur_func->in_function_body)
26277
0
            return js_parse_error(s, "await in default expression");
26278
0
        if (next_token(s))
26279
0
            return -1;
26280
0
        if (js_parse_unary(s, PF_POW_FORBIDDEN))
26281
0
            return -1;
26282
0
        s->cur_func->has_await = TRUE;
26283
0
        emit_op(s, OP_await);
26284
0
        parse_flags = 0;
26285
0
        break;
26286
11
    default:
26287
11
        if (js_parse_postfix_expr(s, PF_POSTFIX_CALL))
26288
1
            return -1;
26289
10
        if (!s->got_lf &&
26290
10
            (s->token.val == TOK_DEC || s->token.val == TOK_INC)) {
26291
0
            int opcode, op, scope, label;
26292
0
            JSAtom name;
26293
0
            op = s->token.val;
26294
0
            op_token_ptr = s->token.ptr;
26295
0
            if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))
26296
0
                return -1;
26297
0
            emit_source_pos(s, op_token_ptr);
26298
0
            emit_op(s, OP_post_dec + op - TOK_DEC);
26299
0
            put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_SECOND,
26300
0
                       FALSE);
26301
0
            if (next_token(s))
26302
0
                return -1;
26303
0
        }
26304
10
        break;
26305
12
    }
26306
11
    if (parse_flags & (PF_POW_ALLOWED | PF_POW_FORBIDDEN)) {
26307
10
        if (s->token.val == TOK_POW) {
26308
            /* Strict ES7 exponentiation syntax rules: To solve
26309
               conficting semantics between different implementations
26310
               regarding the precedence of prefix operators and the
26311
               postifx exponential, ES7 specifies that -2**2 is a
26312
               syntax error. */
26313
0
            if (parse_flags & PF_POW_FORBIDDEN) {
26314
0
                JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'");
26315
0
                return -1;
26316
0
            }
26317
0
            op_token_ptr = s->token.ptr;
26318
0
            if (next_token(s))
26319
0
                return -1;
26320
0
            if (js_parse_unary(s, PF_POW_ALLOWED))
26321
0
                return -1;
26322
0
            emit_source_pos(s, op_token_ptr);
26323
0
            emit_op(s, OP_pow);
26324
0
        }
26325
10
    }
26326
11
    return 0;
26327
11
}
26328
26329
/* allowed parse_flags: PF_IN_ACCEPTED */
26330
static __exception int js_parse_expr_binary(JSParseState *s, int level,
26331
                                            int parse_flags)
26332
99
{
26333
99
    int op, opcode;
26334
99
    const uint8_t *op_token_ptr;
26335
    
26336
99
    if (level == 0) {
26337
11
        return js_parse_unary(s, PF_POW_ALLOWED);
26338
88
    } else if (s->token.val == TOK_PRIVATE_NAME &&
26339
88
               (parse_flags & PF_IN_ACCEPTED) && level == 4 &&
26340
88
               peek_token(s, FALSE) == TOK_IN) {
26341
0
        JSAtom atom;
26342
26343
0
        atom = JS_DupAtom(s->ctx, s->token.u.ident.atom);
26344
0
        if (next_token(s))
26345
0
            goto fail_private_in;
26346
0
        if (s->token.val != TOK_IN)
26347
0
            goto fail_private_in;
26348
0
        if (next_token(s))
26349
0
            goto fail_private_in;
26350
0
        if (js_parse_expr_binary(s, level - 1, parse_flags)) {
26351
0
        fail_private_in:
26352
0
            JS_FreeAtom(s->ctx, atom);
26353
0
            return -1;
26354
0
        }
26355
0
        emit_op(s, OP_scope_in_private_field);
26356
0
        emit_atom(s, atom);
26357
0
        emit_u16(s, s->cur_func->scope_level);
26358
0
        JS_FreeAtom(s->ctx, atom);
26359
0
        return 0;
26360
88
    } else {
26361
88
        if (js_parse_expr_binary(s, level - 1, parse_flags))
26362
8
            return -1;
26363
88
    }
26364
80
    for(;;) {
26365
80
        op = s->token.val;
26366
80
        op_token_ptr = s->token.ptr;
26367
80
        switch(level) {
26368
10
        case 1:
26369
10
            switch(op) {
26370
0
            case '*':
26371
0
                opcode = OP_mul;
26372
0
                break;
26373
0
            case '/':
26374
0
                opcode = OP_div;
26375
0
                break;
26376
0
            case '%':
26377
0
                opcode = OP_mod;
26378
0
                break;
26379
10
            default:
26380
10
                return 0;
26381
10
            }
26382
0
            break;
26383
10
        case 2:
26384
10
            switch(op) {
26385
0
            case '+':
26386
0
                opcode = OP_add;
26387
0
                break;
26388
0
            case '-':
26389
0
                opcode = OP_sub;
26390
0
                break;
26391
10
            default:
26392
10
                return 0;
26393
10
            }
26394
0
            break;
26395
10
        case 3:
26396
10
            switch(op) {
26397
0
            case TOK_SHL:
26398
0
                opcode = OP_shl;
26399
0
                break;
26400
0
            case TOK_SAR:
26401
0
                opcode = OP_sar;
26402
0
                break;
26403
0
            case TOK_SHR:
26404
0
                opcode = OP_shr;
26405
0
                break;
26406
10
            default:
26407
10
                return 0;
26408
10
            }
26409
0
            break;
26410
10
        case 4:
26411
10
            switch(op) {
26412
0
            case '<':
26413
0
                opcode = OP_lt;
26414
0
                break;
26415
0
            case '>':
26416
0
                opcode = OP_gt;
26417
0
                break;
26418
0
            case TOK_LTE:
26419
0
                opcode = OP_lte;
26420
0
                break;
26421
0
            case TOK_GTE:
26422
0
                opcode = OP_gte;
26423
0
                break;
26424
0
            case TOK_INSTANCEOF:
26425
0
                opcode = OP_instanceof;
26426
0
                break;
26427
0
            case TOK_IN:
26428
0
                if (parse_flags & PF_IN_ACCEPTED) {
26429
0
                    opcode = OP_in;
26430
0
                } else {
26431
0
                    return 0;
26432
0
                }
26433
0
                break;
26434
10
            default:
26435
10
                return 0;
26436
10
            }
26437
0
            break;
26438
10
        case 5:
26439
10
            switch(op) {
26440
0
            case TOK_EQ:
26441
0
                opcode = OP_eq;
26442
0
                break;
26443
0
            case TOK_NEQ:
26444
0
                opcode = OP_neq;
26445
0
                break;
26446
0
            case TOK_STRICT_EQ:
26447
0
                opcode = OP_strict_eq;
26448
0
                break;
26449
0
            case TOK_STRICT_NEQ:
26450
0
                opcode = OP_strict_neq;
26451
0
                break;
26452
10
            default:
26453
10
                return 0;
26454
10
            }
26455
0
            break;
26456
10
        case 6:
26457
10
            switch(op) {
26458
0
            case '&':
26459
0
                opcode = OP_and;
26460
0
                break;
26461
10
            default:
26462
10
                return 0;
26463
10
            }
26464
0
            break;
26465
10
        case 7:
26466
10
            switch(op) {
26467
0
            case '^':
26468
0
                opcode = OP_xor;
26469
0
                break;
26470
10
            default:
26471
10
                return 0;
26472
10
            }
26473
0
            break;
26474
10
        case 8:
26475
10
            switch(op) {
26476
0
            case '|':
26477
0
                opcode = OP_or;
26478
0
                break;
26479
10
            default:
26480
10
                return 0;
26481
10
            }
26482
0
            break;
26483
0
        default:
26484
0
            abort();
26485
80
        }
26486
0
        if (next_token(s))
26487
0
            return -1;
26488
0
        if (js_parse_expr_binary(s, level - 1, parse_flags))
26489
0
            return -1;
26490
0
        emit_source_pos(s, op_token_ptr);
26491
0
        emit_op(s, opcode);
26492
0
    }
26493
0
    return 0;
26494
80
}
26495
26496
/* allowed parse_flags: PF_IN_ACCEPTED */
26497
static __exception int js_parse_logical_and_or(JSParseState *s, int op,
26498
                                               int parse_flags)
26499
22
{
26500
22
    int label1;
26501
26502
22
    if (op == TOK_LAND) {
26503
11
        if (js_parse_expr_binary(s, 8, parse_flags))
26504
1
            return -1;
26505
11
    } else {
26506
11
        if (js_parse_logical_and_or(s, TOK_LAND, parse_flags))
26507
1
            return -1;
26508
11
    }
26509
20
    if (s->token.val == op) {
26510
0
        label1 = new_label(s);
26511
26512
0
        for(;;) {
26513
0
            if (next_token(s))
26514
0
                return -1;
26515
0
            emit_op(s, OP_dup);
26516
0
            emit_goto(s, op == TOK_LAND ? OP_if_false : OP_if_true, label1);
26517
0
            emit_op(s, OP_drop);
26518
26519
0
            if (op == TOK_LAND) {
26520
0
                if (js_parse_expr_binary(s, 8, parse_flags))
26521
0
                    return -1;
26522
0
            } else {
26523
0
                if (js_parse_logical_and_or(s, TOK_LAND,
26524
0
                                            parse_flags))
26525
0
                    return -1;
26526
0
            }
26527
0
            if (s->token.val != op) {
26528
0
                if (s->token.val == TOK_DOUBLE_QUESTION_MARK)
26529
0
                    return js_parse_error(s, "cannot mix ?? with && or ||");
26530
0
                break;
26531
0
            }
26532
0
        }
26533
26534
0
        emit_label(s, label1);
26535
0
    }
26536
20
    return 0;
26537
20
}
26538
26539
static __exception int js_parse_coalesce_expr(JSParseState *s, int parse_flags)
26540
11
{
26541
11
    int label1;
26542
26543
11
    if (js_parse_logical_and_or(s, TOK_LOR, parse_flags))
26544
1
        return -1;
26545
10
    if (s->token.val == TOK_DOUBLE_QUESTION_MARK) {
26546
0
        label1 = new_label(s);
26547
0
        for(;;) {
26548
0
            if (next_token(s))
26549
0
                return -1;
26550
26551
0
            emit_op(s, OP_dup);
26552
0
            emit_op(s, OP_is_undefined_or_null);
26553
0
            emit_goto(s, OP_if_false, label1);
26554
0
            emit_op(s, OP_drop);
26555
26556
0
            if (js_parse_expr_binary(s, 8, parse_flags))
26557
0
                return -1;
26558
0
            if (s->token.val != TOK_DOUBLE_QUESTION_MARK)
26559
0
                break;
26560
0
        }
26561
0
        emit_label(s, label1);
26562
0
    }
26563
10
    return 0;
26564
10
}
26565
26566
/* allowed parse_flags: PF_IN_ACCEPTED */
26567
static __exception int js_parse_cond_expr(JSParseState *s, int parse_flags)
26568
11
{
26569
11
    int label1, label2;
26570
26571
11
    if (js_parse_coalesce_expr(s, parse_flags))
26572
1
        return -1;
26573
10
    if (s->token.val == '?') {
26574
0
        if (next_token(s))
26575
0
            return -1;
26576
0
        label1 = emit_goto(s, OP_if_false, -1);
26577
26578
0
        if (js_parse_assign_expr(s))
26579
0
            return -1;
26580
0
        if (js_parse_expect(s, ':'))
26581
0
            return -1;
26582
26583
0
        label2 = emit_goto(s, OP_goto, -1);
26584
26585
0
        emit_label(s, label1);
26586
26587
0
        if (js_parse_assign_expr2(s, parse_flags & PF_IN_ACCEPTED))
26588
0
            return -1;
26589
26590
0
        emit_label(s, label2);
26591
0
    }
26592
10
    return 0;
26593
10
}
26594
26595
/* allowed parse_flags: PF_IN_ACCEPTED */
26596
static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
26597
11
{
26598
11
    int opcode, op, scope, skip_bits;
26599
11
    JSAtom name0 = JS_ATOM_NULL;
26600
11
    JSAtom name;
26601
26602
11
    if (s->token.val == TOK_YIELD) {
26603
0
        BOOL is_star = FALSE, is_async;
26604
26605
0
        if (!(s->cur_func->func_kind & JS_FUNC_GENERATOR))
26606
0
            return js_parse_error(s, "unexpected 'yield' keyword");
26607
0
        if (!s->cur_func->in_function_body)
26608
0
            return js_parse_error(s, "yield in default expression");
26609
0
        if (next_token(s))
26610
0
            return -1;
26611
        /* XXX: is there a better method to detect 'yield' without
26612
           parameters ? */
26613
0
        if (s->token.val != ';' && s->token.val != ')' &&
26614
0
            s->token.val != ']' && s->token.val != '}' &&
26615
0
            s->token.val != ',' && s->token.val != ':' && !s->got_lf) {
26616
0
            if (s->token.val == '*') {
26617
0
                is_star = TRUE;
26618
0
                if (next_token(s))
26619
0
                    return -1;
26620
0
            }
26621
0
            if (js_parse_assign_expr2(s, parse_flags))
26622
0
                return -1;
26623
0
        } else {
26624
0
            emit_op(s, OP_undefined);
26625
0
        }
26626
0
        is_async = (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR);
26627
26628
0
        if (is_star) {
26629
0
            int label_loop, label_return, label_next;
26630
0
            int label_return1, label_yield, label_throw, label_throw1;
26631
0
            int label_throw2;
26632
26633
0
            label_loop = new_label(s);
26634
0
            label_yield = new_label(s);
26635
26636
0
            emit_op(s, is_async ? OP_for_await_of_start : OP_for_of_start);
26637
26638
            /* remove the catch offset (XXX: could avoid pushing back
26639
               undefined) */
26640
0
            emit_op(s, OP_drop);
26641
0
            emit_op(s, OP_undefined);
26642
26643
0
            emit_op(s, OP_undefined); /* initial value */
26644
26645
0
            emit_label(s, label_loop);
26646
0
            emit_op(s, OP_iterator_next);
26647
0
            if (is_async)
26648
0
                emit_op(s, OP_await);
26649
0
            emit_op(s, OP_iterator_check_object);
26650
0
            emit_op(s, OP_get_field2);
26651
0
            emit_atom(s, JS_ATOM_done);
26652
0
            label_next = emit_goto(s, OP_if_true, -1); /* end of loop */
26653
0
            emit_label(s, label_yield);
26654
0
            if (is_async) {
26655
                /* OP_async_yield_star takes the value as parameter */
26656
0
                emit_op(s, OP_get_field);
26657
0
                emit_atom(s, JS_ATOM_value);
26658
0
                emit_op(s, OP_async_yield_star);
26659
0
            } else {
26660
                /* OP_yield_star takes (value, done) as parameter */
26661
0
                emit_op(s, OP_yield_star);
26662
0
            }
26663
0
            emit_op(s, OP_dup);
26664
0
            label_return = emit_goto(s, OP_if_true, -1);
26665
0
            emit_op(s, OP_drop);
26666
0
            emit_goto(s, OP_goto, label_loop);
26667
26668
0
            emit_label(s, label_return);
26669
0
            emit_op(s, OP_push_i32);
26670
0
            emit_u32(s, 2);
26671
0
            emit_op(s, OP_strict_eq);
26672
0
            label_throw = emit_goto(s, OP_if_true, -1);
26673
26674
            /* return handling */
26675
0
            if (is_async)
26676
0
                emit_op(s, OP_await);
26677
0
            emit_op(s, OP_iterator_call);
26678
0
            emit_u8(s, 0);
26679
0
            label_return1 = emit_goto(s, OP_if_true, -1);
26680
0
            if (is_async)
26681
0
                emit_op(s, OP_await);
26682
0
            emit_op(s, OP_iterator_check_object);
26683
0
            emit_op(s, OP_get_field2);
26684
0
            emit_atom(s, JS_ATOM_done);
26685
0
            emit_goto(s, OP_if_false, label_yield);
26686
26687
0
            emit_op(s, OP_get_field);
26688
0
            emit_atom(s, JS_ATOM_value);
26689
26690
0
            emit_label(s, label_return1);
26691
0
            emit_op(s, OP_nip);
26692
0
            emit_op(s, OP_nip);
26693
0
            emit_op(s, OP_nip);
26694
0
            emit_return(s, TRUE);
26695
26696
            /* throw handling */
26697
0
            emit_label(s, label_throw);
26698
0
            emit_op(s, OP_iterator_call);
26699
0
            emit_u8(s, 1);
26700
0
            label_throw1 = emit_goto(s, OP_if_true, -1);
26701
0
            if (is_async)
26702
0
                emit_op(s, OP_await);
26703
0
            emit_op(s, OP_iterator_check_object);
26704
0
            emit_op(s, OP_get_field2);
26705
0
            emit_atom(s, JS_ATOM_done);
26706
0
            emit_goto(s, OP_if_false, label_yield);
26707
0
            emit_goto(s, OP_goto, label_next);
26708
            /* close the iterator and throw a type error exception */
26709
0
            emit_label(s, label_throw1);
26710
0
            emit_op(s, OP_iterator_call);
26711
0
            emit_u8(s, 2);
26712
0
            label_throw2 = emit_goto(s, OP_if_true, -1);
26713
0
            if (is_async)
26714
0
                emit_op(s, OP_await);
26715
0
            emit_label(s, label_throw2);
26716
26717
0
            emit_op(s, OP_throw_error);
26718
0
            emit_atom(s, JS_ATOM_NULL);
26719
0
            emit_u8(s, JS_THROW_ERROR_ITERATOR_THROW);
26720
26721
0
            emit_label(s, label_next);
26722
0
            emit_op(s, OP_get_field);
26723
0
            emit_atom(s, JS_ATOM_value);
26724
0
            emit_op(s, OP_nip); /* keep the value associated with
26725
                                   done = true */
26726
0
            emit_op(s, OP_nip);
26727
0
            emit_op(s, OP_nip);
26728
0
        } else {
26729
0
            int label_next;
26730
26731
0
            if (is_async)
26732
0
                emit_op(s, OP_await);
26733
0
            emit_op(s, OP_yield);
26734
0
            label_next = emit_goto(s, OP_if_false, -1);
26735
0
            emit_return(s, TRUE);
26736
0
            emit_label(s, label_next);
26737
0
        }
26738
0
        return 0;
26739
11
    } else if (s->token.val == '(' &&
26740
11
               js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) {
26741
0
        return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
26742
0
                                      JS_FUNC_NORMAL, JS_ATOM_NULL,
26743
0
                                      s->token.ptr);
26744
11
    } else if (token_is_pseudo_keyword(s, JS_ATOM_async)) {
26745
0
        const uint8_t *source_ptr;
26746
0
        int tok;
26747
0
        JSParsePos pos;
26748
26749
        /* fast test */
26750
0
        tok = peek_token(s, TRUE);
26751
0
        if (tok == TOK_FUNCTION || tok == '\n')
26752
0
            goto next;
26753
26754
0
        source_ptr = s->token.ptr;
26755
0
        js_parse_get_pos(s, &pos);
26756
0
        if (next_token(s))
26757
0
            return -1;
26758
0
        if ((s->token.val == '(' &&
26759
0
             js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) ||
26760
0
            (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
26761
0
             peek_token(s, TRUE) == TOK_ARROW)) {
26762
0
            return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
26763
0
                                          JS_FUNC_ASYNC, JS_ATOM_NULL,
26764
0
                                          source_ptr);
26765
0
        } else {
26766
            /* undo the token parsing */
26767
0
            if (js_parse_seek_token(s, &pos))
26768
0
                return -1;
26769
0
        }
26770
11
    } else if (s->token.val == TOK_IDENT &&
26771
11
               peek_token(s, TRUE) == TOK_ARROW) {
26772
0
        return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
26773
0
                                      JS_FUNC_NORMAL, JS_ATOM_NULL,
26774
0
                                      s->token.ptr);
26775
11
    } else if ((s->token.val == '{' || s->token.val == '[') &&
26776
11
               js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
26777
0
        if (js_parse_destructuring_element(s, 0, 0, FALSE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE, FALSE) < 0)
26778
0
            return -1;
26779
0
        return 0;
26780
0
    }
26781
11
 next:
26782
11
    if (s->token.val == TOK_IDENT) {
26783
        /* name0 is used to check for OP_set_name pattern, not duplicated */
26784
9
        name0 = s->token.u.ident.atom;
26785
9
    }
26786
11
    if (js_parse_cond_expr(s, parse_flags))
26787
1
        return -1;
26788
26789
10
    op = s->token.val;
26790
10
    if (op == '=' || (op >= TOK_MUL_ASSIGN && op <= TOK_POW_ASSIGN)) {
26791
4
        int label;
26792
4
        const uint8_t *op_token_ptr;
26793
4
        op_token_ptr = s->token.ptr;
26794
4
        if (next_token(s))
26795
0
            return -1;
26796
4
        if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, (op != '='), op) < 0)
26797
0
            return -1;
26798
26799
4
        if (js_parse_assign_expr2(s, parse_flags)) {
26800
0
            JS_FreeAtom(s->ctx, name);
26801
0
            return -1;
26802
0
        }
26803
26804
4
        if (op == '=') {
26805
4
            if (opcode == OP_get_ref_value && name == name0) {
26806
0
                set_object_name(s, name);
26807
0
            }
26808
4
        } else {
26809
0
            static const uint8_t assign_opcodes[] = {
26810
0
                OP_mul, OP_div, OP_mod, OP_add, OP_sub,
26811
0
                OP_shl, OP_sar, OP_shr, OP_and, OP_xor, OP_or,
26812
0
                OP_pow,
26813
0
            };
26814
0
            op = assign_opcodes[op - TOK_MUL_ASSIGN];
26815
0
            emit_source_pos(s, op_token_ptr);
26816
0
            emit_op(s, op);
26817
0
        }
26818
4
        put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP, FALSE);
26819
6
    } else if (op >= TOK_LAND_ASSIGN && op <= TOK_DOUBLE_QUESTION_MARK_ASSIGN) {
26820
0
        int label, label1, depth_lvalue, label2;
26821
26822
0
        if (next_token(s))
26823
0
            return -1;
26824
0
        if (get_lvalue(s, &opcode, &scope, &name, &label,
26825
0
                       &depth_lvalue, TRUE, op) < 0)
26826
0
            return -1;
26827
26828
0
        emit_op(s, OP_dup);
26829
0
        if (op == TOK_DOUBLE_QUESTION_MARK_ASSIGN)
26830
0
            emit_op(s, OP_is_undefined_or_null);
26831
0
        label1 = emit_goto(s, op == TOK_LOR_ASSIGN ? OP_if_true : OP_if_false,
26832
0
                           -1);
26833
0
        emit_op(s, OP_drop);
26834
26835
0
        if (js_parse_assign_expr2(s, parse_flags)) {
26836
0
            JS_FreeAtom(s->ctx, name);
26837
0
            return -1;
26838
0
        }
26839
26840
0
        if (opcode == OP_get_ref_value && name == name0) {
26841
0
            set_object_name(s, name);
26842
0
        }
26843
26844
0
        switch(depth_lvalue) {
26845
0
        case 1:
26846
0
            emit_op(s, OP_insert2);
26847
0
            break;
26848
0
        case 2:
26849
0
            emit_op(s, OP_insert3);
26850
0
            break;
26851
0
        case 3:
26852
0
            emit_op(s, OP_insert4);
26853
0
            break;
26854
0
        default:
26855
0
            abort();
26856
0
        }
26857
26858
        /* XXX: we disable the OP_put_ref_value optimization by not
26859
           using put_lvalue() otherwise depth_lvalue is not correct */
26860
0
        put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_NOKEEP_DEPTH,
26861
0
                   FALSE);
26862
0
        label2 = emit_goto(s, OP_goto, -1);
26863
26864
0
        emit_label(s, label1);
26865
26866
        /* remove the lvalue stack entries */
26867
0
        while (depth_lvalue != 0) {
26868
0
            emit_op(s, OP_nip);
26869
0
            depth_lvalue--;
26870
0
        }
26871
26872
0
        emit_label(s, label2);
26873
0
    }
26874
10
    return 0;
26875
10
}
26876
26877
static __exception int js_parse_assign_expr(JSParseState *s)
26878
0
{
26879
0
    return js_parse_assign_expr2(s, PF_IN_ACCEPTED);
26880
0
}
26881
26882
/* allowed parse_flags: PF_IN_ACCEPTED */
26883
static __exception int js_parse_expr2(JSParseState *s, int parse_flags)
26884
7
{
26885
7
    BOOL comma = FALSE;
26886
7
    for(;;) {
26887
7
        if (js_parse_assign_expr2(s, parse_flags))
26888
1
            return -1;
26889
6
        if (comma) {
26890
            /* prevent get_lvalue from using the last expression
26891
               as an lvalue. This also prevents the conversion of
26892
               of get_var to get_ref for method lookup in function
26893
               call inside `with` statement.
26894
             */
26895
0
            s->cur_func->last_opcode_pos = -1;
26896
0
        }
26897
6
        if (s->token.val != ',')
26898
6
            break;
26899
0
        comma = TRUE;
26900
0
        if (next_token(s))
26901
0
            return -1;
26902
0
        emit_op(s, OP_drop);
26903
0
    }
26904
6
    return 0;
26905
7
}
26906
26907
static __exception int js_parse_expr(JSParseState *s)
26908
7
{
26909
7
    return js_parse_expr2(s, PF_IN_ACCEPTED);
26910
7
}
26911
26912
static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
26913
                             JSAtom label_name,
26914
                             int label_break, int label_cont,
26915
                             int drop_count)
26916
2
{
26917
2
    be->prev = fd->top_break;
26918
2
    fd->top_break = be;
26919
2
    be->label_name = label_name;
26920
2
    be->label_break = label_break;
26921
2
    be->label_cont = label_cont;
26922
2
    be->drop_count = drop_count;
26923
2
    be->label_finally = -1;
26924
2
    be->scope_level = fd->scope_level;
26925
2
    be->has_iterator = FALSE;
26926
2
    be->is_regular_stmt = FALSE;
26927
2
}
26928
26929
static void pop_break_entry(JSFunctionDef *fd)
26930
1
{
26931
1
    BlockEnv *be;
26932
1
    be = fd->top_break;
26933
1
    fd->top_break = be->prev;
26934
1
}
26935
26936
static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont)
26937
0
{
26938
0
    BlockEnv *top;
26939
0
    int i, scope_level;
26940
26941
0
    scope_level = s->cur_func->scope_level;
26942
0
    top = s->cur_func->top_break;
26943
0
    while (top != NULL) {
26944
0
        close_scopes(s, scope_level, top->scope_level);
26945
0
        scope_level = top->scope_level;
26946
0
        if (is_cont &&
26947
0
            top->label_cont != -1 &&
26948
0
            (name == JS_ATOM_NULL || top->label_name == name)) {
26949
            /* continue stays inside the same block */
26950
0
            emit_goto(s, OP_goto, top->label_cont);
26951
0
            return 0;
26952
0
        }
26953
0
        if (!is_cont &&
26954
0
            top->label_break != -1 &&
26955
0
            ((name == JS_ATOM_NULL && !top->is_regular_stmt) ||
26956
0
             top->label_name == name)) {
26957
0
            emit_goto(s, OP_goto, top->label_break);
26958
0
            return 0;
26959
0
        }
26960
0
        i = 0;
26961
0
        if (top->has_iterator) {
26962
0
            emit_op(s, OP_iterator_close);
26963
0
            i += 3;
26964
0
        }
26965
0
        for(; i < top->drop_count; i++)
26966
0
            emit_op(s, OP_drop);
26967
0
        if (top->label_finally != -1) {
26968
            /* must push dummy value to keep same stack depth */
26969
0
            emit_op(s, OP_undefined);
26970
0
            emit_goto(s, OP_gosub, top->label_finally);
26971
0
            emit_op(s, OP_drop);
26972
0
        }
26973
0
        top = top->prev;
26974
0
    }
26975
0
    if (name == JS_ATOM_NULL) {
26976
0
        if (is_cont)
26977
0
            return js_parse_error(s, "continue must be inside loop");
26978
0
        else
26979
0
            return js_parse_error(s, "break must be inside loop or switch");
26980
0
    } else {
26981
0
        return js_parse_error(s, "break/continue label not found");
26982
0
    }
26983
0
}
26984
26985
/* execute the finally blocks before return */
26986
static void emit_return(JSParseState *s, BOOL hasval)
26987
3
{
26988
3
    BlockEnv *top;
26989
26990
3
    if (s->cur_func->func_kind != JS_FUNC_NORMAL) {
26991
3
        if (!hasval) {
26992
            /* no value: direct return in case of async generator */
26993
3
            emit_op(s, OP_undefined);
26994
3
            hasval = TRUE;
26995
3
        } else if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
26996
            /* the await must be done before handling the "finally" in
26997
               case it raises an exception */
26998
0
            emit_op(s, OP_await);
26999
0
        }
27000
3
    }
27001
27002
3
    top = s->cur_func->top_break;
27003
3
    while (top != NULL) {
27004
0
        if (top->has_iterator || top->label_finally != -1) {
27005
0
            if (!hasval) {
27006
0
                emit_op(s, OP_undefined);
27007
0
                hasval = TRUE;
27008
0
            }
27009
            /* Remove the stack elements up to and including the catch
27010
               offset. When 'yield' is used in an expression we have
27011
               no easy way to count them, so we use this specific
27012
               instruction instead. */
27013
0
            emit_op(s, OP_nip_catch);
27014
            /* stack: iter_obj next ret_val */
27015
0
            if (top->has_iterator) {
27016
0
                if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
27017
0
                    int label_next, label_next2;
27018
0
                    emit_op(s, OP_nip); /* next */
27019
0
                    emit_op(s, OP_swap);
27020
0
                    emit_op(s, OP_get_field2);
27021
0
                    emit_atom(s, JS_ATOM_return);
27022
                    /* stack: iter_obj return_func */
27023
0
                    emit_op(s, OP_dup);
27024
0
                    emit_op(s, OP_is_undefined_or_null);
27025
0
                    label_next = emit_goto(s, OP_if_true, -1);
27026
0
                    emit_op(s, OP_call_method);
27027
0
                    emit_u16(s, 0);
27028
0
                    emit_op(s, OP_iterator_check_object);
27029
0
                    emit_op(s, OP_await);
27030
0
                    label_next2 = emit_goto(s, OP_goto, -1);
27031
0
                    emit_label(s, label_next);
27032
0
                    emit_op(s, OP_drop);
27033
0
                    emit_label(s, label_next2);
27034
0
                    emit_op(s, OP_drop);
27035
0
                } else {
27036
0
                    emit_op(s, OP_rot3r);
27037
0
                    emit_op(s, OP_undefined); /* dummy catch offset */
27038
0
                    emit_op(s, OP_iterator_close);
27039
0
                }
27040
0
            } else {
27041
                /* execute the "finally" block */
27042
0
                emit_goto(s, OP_gosub, top->label_finally);
27043
0
            }
27044
0
        }
27045
0
        top = top->prev;
27046
0
    }
27047
3
    if (s->cur_func->is_derived_class_constructor) {
27048
0
        int label_return;
27049
27050
        /* 'this' can be uninitialized, so it may be accessed only if
27051
           the derived class constructor does not return an object */
27052
0
        if (hasval) {
27053
0
            emit_op(s, OP_check_ctor_return);
27054
0
            label_return = emit_goto(s, OP_if_false, -1);
27055
0
            emit_op(s, OP_drop);
27056
0
        } else {
27057
0
            label_return = -1;
27058
0
        }
27059
27060
        /* The error should be raised in the caller context, so we use
27061
           a specific opcode */
27062
0
        emit_op(s, OP_scope_get_var_checkthis);
27063
0
        emit_atom(s, JS_ATOM_this);
27064
0
        emit_u16(s, 0);
27065
27066
0
        emit_label(s, label_return);
27067
0
        emit_op(s, OP_return);
27068
3
    } else if (s->cur_func->func_kind != JS_FUNC_NORMAL) {
27069
3
        emit_op(s, OP_return_async);
27070
3
    } else {
27071
0
        emit_op(s, hasval ? OP_return : OP_return_undef);
27072
0
    }
27073
3
}
27074
27075
7
#define DECL_MASK_FUNC  (1 << 0) /* allow normal function declaration */
27076
/* ored with DECL_MASK_FUNC if function declarations are allowed with a label */
27077
7
#define DECL_MASK_FUNC_WITH_LABEL (1 << 1)
27078
7
#define DECL_MASK_OTHER (1 << 2) /* all other declarations */
27079
7
#define DECL_MASK_ALL   (DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL | DECL_MASK_OTHER)
27080
27081
static __exception int js_parse_statement_or_decl(JSParseState *s,
27082
                                                  int decl_mask);
27083
27084
static __exception int js_parse_statement(JSParseState *s)
27085
0
{
27086
0
    return js_parse_statement_or_decl(s, 0);
27087
0
}
27088
27089
static __exception int js_parse_block(JSParseState *s)
27090
0
{
27091
0
    if (js_parse_expect(s, '{'))
27092
0
        return -1;
27093
0
    if (s->token.val != '}') {
27094
0
        push_scope(s);
27095
0
        for(;;) {
27096
0
            if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
27097
0
                return -1;
27098
0
            if (s->token.val == '}')
27099
0
                break;
27100
0
        }
27101
0
        pop_scope(s);
27102
0
    }
27103
0
    if (next_token(s))
27104
0
        return -1;
27105
0
    return 0;
27106
0
}
27107
27108
/* allowed parse_flags: PF_IN_ACCEPTED */
27109
static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
27110
                                    BOOL export_flag)
27111
0
{
27112
0
    JSContext *ctx = s->ctx;
27113
0
    JSFunctionDef *fd = s->cur_func;
27114
0
    JSAtom name = JS_ATOM_NULL;
27115
27116
0
    for (;;) {
27117
0
        if (s->token.val == TOK_IDENT) {
27118
0
            if (s->token.u.ident.is_reserved) {
27119
0
                return js_parse_error_reserved_identifier(s);
27120
0
            }
27121
0
            name = JS_DupAtom(ctx, s->token.u.ident.atom);
27122
0
            if (name == JS_ATOM_let && (tok == TOK_LET || tok == TOK_CONST)) {
27123
0
                js_parse_error(s, "'let' is not a valid lexical identifier");
27124
0
                goto var_error;
27125
0
            }
27126
0
            if (next_token(s))
27127
0
                goto var_error;
27128
0
            if (js_define_var(s, name, tok))
27129
0
                goto var_error;
27130
0
            if (export_flag) {
27131
0
                if (!add_export_entry(s, s->cur_func->module, name, name,
27132
0
                                      JS_EXPORT_TYPE_LOCAL))
27133
0
                    goto var_error;
27134
0
            }
27135
27136
0
            if (s->token.val == '=') {
27137
0
                if (next_token(s))
27138
0
                    goto var_error;
27139
0
                if (need_var_reference(s, tok)) {
27140
                    /* Must make a reference for proper `with` semantics */
27141
0
                    int opcode, scope, label;
27142
0
                    JSAtom name1;
27143
27144
0
                    emit_op(s, OP_scope_get_var);
27145
0
                    emit_atom(s, name);
27146
0
                    emit_u16(s, fd->scope_level);
27147
0
                    if (get_lvalue(s, &opcode, &scope, &name1, &label, NULL, FALSE, '=') < 0)
27148
0
                        goto var_error;
27149
0
                    if (js_parse_assign_expr2(s, parse_flags)) {
27150
0
                        JS_FreeAtom(ctx, name1);
27151
0
                        goto var_error;
27152
0
                    }
27153
0
                    set_object_name(s, name);
27154
0
                    put_lvalue(s, opcode, scope, name1, label,
27155
0
                               PUT_LVALUE_NOKEEP, FALSE);
27156
0
                } else {
27157
0
                    if (js_parse_assign_expr2(s, parse_flags))
27158
0
                        goto var_error;
27159
0
                    set_object_name(s, name);
27160
0
                    emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ?
27161
0
                        OP_scope_put_var_init : OP_scope_put_var);
27162
0
                    emit_atom(s, name);
27163
0
                    emit_u16(s, fd->scope_level);
27164
0
                }
27165
0
            } else {
27166
0
                if (tok == TOK_CONST) {
27167
0
                    js_parse_error(s, "missing initializer for const variable");
27168
0
                    goto var_error;
27169
0
                }
27170
0
                if (tok == TOK_LET) {
27171
                    /* initialize lexical variable upon entering its scope */
27172
0
                    emit_op(s, OP_undefined);
27173
0
                    emit_op(s, OP_scope_put_var_init);
27174
0
                    emit_atom(s, name);
27175
0
                    emit_u16(s, fd->scope_level);
27176
0
                }
27177
0
            }
27178
0
            JS_FreeAtom(ctx, name);
27179
0
        } else {
27180
0
            int skip_bits;
27181
0
            if ((s->token.val == '[' || s->token.val == '{')
27182
0
            &&  js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
27183
0
                emit_op(s, OP_undefined);
27184
0
                if (js_parse_destructuring_element(s, tok, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE, export_flag) < 0)
27185
0
                    return -1;
27186
0
            } else {
27187
0
                return js_parse_error(s, "variable name expected");
27188
0
            }
27189
0
        }
27190
0
        if (s->token.val != ',')
27191
0
            break;
27192
0
        if (next_token(s))
27193
0
            return -1;
27194
0
    }
27195
0
    return 0;
27196
27197
0
 var_error:
27198
0
    JS_FreeAtom(ctx, name);
27199
0
    return -1;
27200
0
}
27201
27202
/* test if the current token is a label. Use simplistic look-ahead scanner */
27203
static BOOL is_label(JSParseState *s)
27204
9
{
27205
9
    return (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
27206
9
            peek_token(s, FALSE) == ':');
27207
9
}
27208
27209
/* test if the current token is a let keyword. Use simplistic look-ahead scanner */
27210
static int is_let(JSParseState *s, int decl_mask)
27211
5
{
27212
5
    int res = FALSE;
27213
5
    const uint8_t *last_token_ptr;
27214
    
27215
5
    if (token_is_pseudo_keyword(s, JS_ATOM_let)) {
27216
0
        JSParsePos pos;
27217
0
        js_parse_get_pos(s, &pos);
27218
0
        for (;;) {
27219
0
            last_token_ptr = s->token.ptr;
27220
0
            if (next_token(s)) {
27221
0
                res = -1;
27222
0
                break;
27223
0
            }
27224
0
            if (s->token.val == '[') {
27225
                /* let [ is a syntax restriction:
27226
                   it never introduces an ExpressionStatement */
27227
0
                res = TRUE;
27228
0
                break;
27229
0
            }
27230
0
            if (s->token.val == '{' ||
27231
0
                (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved) ||
27232
0
                s->token.val == TOK_LET ||
27233
0
                s->token.val == TOK_YIELD ||
27234
0
                s->token.val == TOK_AWAIT) {
27235
                /* Check for possible ASI if not scanning for Declaration */
27236
                /* XXX: should also check that `{` introduces a BindingPattern,
27237
                   but Firefox does not and rejects eval("let=1;let\n{if(1)2;}") */
27238
0
                if (!has_lf_in_range(last_token_ptr, s->token.ptr) ||
27239
0
                    (decl_mask & DECL_MASK_OTHER)) {
27240
0
                    res = TRUE;
27241
0
                    break;
27242
0
                }
27243
0
                break;
27244
0
            }
27245
0
            break;
27246
0
        }
27247
0
        if (js_parse_seek_token(s, &pos)) {
27248
0
            res = -1;
27249
0
        }
27250
0
    }
27251
5
    return res;
27252
5
}
27253
27254
/* XXX: handle IteratorClose when exiting the loop before the
27255
   enumeration is done */
27256
static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
27257
                                          BOOL is_async)
27258
0
{
27259
0
    JSContext *ctx = s->ctx;
27260
0
    JSFunctionDef *fd = s->cur_func;
27261
0
    JSAtom var_name;
27262
0
    BOOL has_initializer, is_for_of, has_destructuring;
27263
0
    int tok, tok1, opcode, scope, block_scope_level;
27264
0
    int label_next, label_expr, label_cont, label_body, label_break;
27265
0
    int pos_next, pos_expr;
27266
0
    BlockEnv break_entry;
27267
27268
0
    has_initializer = FALSE;
27269
0
    has_destructuring = FALSE;
27270
0
    is_for_of = FALSE;
27271
0
    block_scope_level = fd->scope_level;
27272
0
    label_cont = new_label(s);
27273
0
    label_body = new_label(s);
27274
0
    label_break = new_label(s);
27275
0
    label_next = new_label(s);
27276
27277
    /* create scope for the lexical variables declared in the enumeration
27278
       expressions. XXX: Not completely correct because of weird capturing
27279
       semantics in `for (i of o) a.push(function(){return i})` */
27280
0
    push_scope(s);
27281
27282
    /* local for_in scope starts here so individual elements
27283
       can be closed in statement. */
27284
0
    push_break_entry(s->cur_func, &break_entry,
27285
0
                     label_name, label_break, label_cont, 1);
27286
0
    break_entry.scope_level = block_scope_level;
27287
27288
0
    label_expr = emit_goto(s, OP_goto, -1);
27289
27290
0
    pos_next = s->cur_func->byte_code.size;
27291
0
    emit_label(s, label_next);
27292
27293
0
    tok = s->token.val;
27294
0
    switch (is_let(s, DECL_MASK_OTHER)) {
27295
0
    case TRUE:
27296
0
        tok = TOK_LET;
27297
0
        break;
27298
0
    case FALSE:
27299
0
        break;
27300
0
    default:
27301
0
        return -1;
27302
0
    }
27303
0
    if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) {
27304
0
        if (next_token(s))
27305
0
            return -1;
27306
27307
0
        if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
27308
0
            if (s->token.val == '[' || s->token.val == '{') {
27309
0
                if (js_parse_destructuring_element(s, tok, 0, TRUE, -1, FALSE, FALSE) < 0)
27310
0
                    return -1;
27311
0
                has_destructuring = TRUE;
27312
0
            } else {
27313
0
                return js_parse_error(s, "variable name expected");
27314
0
            }
27315
0
            var_name = JS_ATOM_NULL;
27316
0
        } else {
27317
0
            var_name = JS_DupAtom(ctx, s->token.u.ident.atom);
27318
0
            if (next_token(s)) {
27319
0
                JS_FreeAtom(s->ctx, var_name);
27320
0
                return -1;
27321
0
            }
27322
0
            if (js_define_var(s, var_name, tok)) {
27323
0
                JS_FreeAtom(s->ctx, var_name);
27324
0
                return -1;
27325
0
            }
27326
0
            emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ?
27327
0
                    OP_scope_put_var_init : OP_scope_put_var);
27328
0
            emit_atom(s, var_name);
27329
0
            emit_u16(s, fd->scope_level);
27330
0
        }
27331
0
    } else if (!is_async && token_is_pseudo_keyword(s, JS_ATOM_async) &&
27332
0
               peek_token(s, FALSE) == TOK_OF) {
27333
0
        return js_parse_error(s, "'for of' expression cannot start with 'async'");
27334
0
    } else {
27335
0
        int skip_bits;
27336
0
        if ((s->token.val == '[' || s->token.val == '{')
27337
0
        &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == TOK_IN || tok1 == TOK_OF)) {
27338
0
            if (js_parse_destructuring_element(s, 0, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE, FALSE) < 0)
27339
0
                return -1;
27340
0
        } else {
27341
0
            int lvalue_label;
27342
0
            if (js_parse_left_hand_side_expr(s))
27343
0
                return -1;
27344
0
            if (get_lvalue(s, &opcode, &scope, &var_name, &lvalue_label,
27345
0
                           NULL, FALSE, TOK_FOR))
27346
0
                return -1;
27347
0
            put_lvalue(s, opcode, scope, var_name, lvalue_label,
27348
0
                       PUT_LVALUE_NOKEEP_BOTTOM, FALSE);
27349
0
        }
27350
0
        var_name = JS_ATOM_NULL;
27351
0
    }
27352
0
    emit_goto(s, OP_goto, label_body);
27353
27354
0
    pos_expr = s->cur_func->byte_code.size;
27355
0
    emit_label(s, label_expr);
27356
0
    if (s->token.val == '=') {
27357
        /* XXX: potential scoping issue if inside `with` statement */
27358
0
        has_initializer = TRUE;
27359
        /* parse and evaluate initializer prior to evaluating the
27360
           object (only used with "for in" with a non lexical variable
27361
           in non strict mode */
27362
0
        if (next_token(s) || js_parse_assign_expr2(s, 0)) {
27363
0
            JS_FreeAtom(ctx, var_name);
27364
0
            return -1;
27365
0
        }
27366
0
        if (var_name != JS_ATOM_NULL) {
27367
0
            emit_op(s, OP_scope_put_var);
27368
0
            emit_atom(s, var_name);
27369
0
            emit_u16(s, fd->scope_level);
27370
0
        }
27371
0
    }
27372
0
    JS_FreeAtom(ctx, var_name);
27373
27374
0
    if (token_is_pseudo_keyword(s, JS_ATOM_of)) {
27375
0
        break_entry.has_iterator = is_for_of = TRUE;
27376
0
        break_entry.drop_count += 2;
27377
0
        if (has_initializer)
27378
0
            goto initializer_error;
27379
0
    } else if (s->token.val == TOK_IN) {
27380
0
        if (is_async)
27381
0
            return js_parse_error(s, "'for await' loop should be used with 'of'");
27382
0
        if (has_initializer &&
27383
0
            (tok != TOK_VAR || (fd->js_mode & JS_MODE_STRICT) ||
27384
0
             has_destructuring)) {
27385
0
        initializer_error:
27386
0
            return js_parse_error(s, "a declaration in the head of a for-%s loop can't have an initializer",
27387
0
                                  is_for_of ? "of" : "in");
27388
0
        }
27389
0
    } else {
27390
0
        return js_parse_error(s, "expected 'of' or 'in' in for control expression");
27391
0
    }
27392
0
    if (next_token(s))
27393
0
        return -1;
27394
0
    if (is_for_of) {
27395
0
        if (js_parse_assign_expr(s))
27396
0
            return -1;
27397
0
    } else {
27398
0
        if (js_parse_expr(s))
27399
0
            return -1;
27400
0
    }
27401
    /* close the scope after having evaluated the expression so that
27402
       the TDZ values are in the closures */
27403
0
    close_scopes(s, s->cur_func->scope_level, block_scope_level);
27404
0
    if (is_for_of) {
27405
0
        if (is_async)
27406
0
            emit_op(s, OP_for_await_of_start);
27407
0
        else
27408
0
            emit_op(s, OP_for_of_start);
27409
        /* on stack: enum_rec */
27410
0
    } else {
27411
0
        emit_op(s, OP_for_in_start);
27412
        /* on stack: enum_obj */
27413
0
    }
27414
0
    emit_goto(s, OP_goto, label_cont);
27415
27416
0
    if (js_parse_expect(s, ')'))
27417
0
        return -1;
27418
27419
0
    if (OPTIMIZE) {
27420
        /* move the `next` code here */
27421
0
        DynBuf *bc = &s->cur_func->byte_code;
27422
0
        int chunk_size = pos_expr - pos_next;
27423
0
        int offset = bc->size - pos_next;
27424
0
        int i;
27425
0
        dbuf_realloc(bc, bc->size + chunk_size);
27426
0
        dbuf_put(bc, bc->buf + pos_next, chunk_size);
27427
0
        memset(bc->buf + pos_next, OP_nop, chunk_size);
27428
        /* `next` part ends with a goto */
27429
0
        s->cur_func->last_opcode_pos = bc->size - 5;
27430
        /* relocate labels */
27431
0
        for (i = label_cont; i < s->cur_func->label_count; i++) {
27432
0
            LabelSlot *ls = &s->cur_func->label_slots[i];
27433
0
            if (ls->pos >= pos_next && ls->pos < pos_expr)
27434
0
                ls->pos += offset;
27435
0
        }
27436
0
    }
27437
27438
0
    emit_label(s, label_body);
27439
0
    if (js_parse_statement(s))
27440
0
        return -1;
27441
27442
0
    close_scopes(s, s->cur_func->scope_level, block_scope_level);
27443
27444
0
    emit_label(s, label_cont);
27445
0
    if (is_for_of) {
27446
0
        if (is_async) {
27447
            /* stack: iter_obj next catch_offset */
27448
            /* call the next method */
27449
0
            emit_op(s, OP_for_await_of_next); 
27450
            /* get the result of the promise */
27451
0
            emit_op(s, OP_await);
27452
            /* unwrap the value and done values */
27453
0
            emit_op(s, OP_iterator_get_value_done);
27454
0
        } else {
27455
0
            emit_op(s, OP_for_of_next);
27456
0
            emit_u8(s, 0);
27457
0
        }
27458
0
    } else {
27459
0
        emit_op(s, OP_for_in_next);
27460
0
    }
27461
    /* on stack: enum_rec / enum_obj value bool */
27462
0
    emit_goto(s, OP_if_false, label_next);
27463
    /* drop the undefined value from for_xx_next */
27464
0
    emit_op(s, OP_drop);
27465
27466
0
    emit_label(s, label_break);
27467
0
    if (is_for_of) {
27468
        /* close and drop enum_rec */
27469
0
        emit_op(s, OP_iterator_close);
27470
0
    } else {
27471
0
        emit_op(s, OP_drop);
27472
0
    }
27473
0
    pop_break_entry(s->cur_func);
27474
0
    pop_scope(s);
27475
0
    return 0;
27476
0
}
27477
27478
static void set_eval_ret_undefined(JSParseState *s)
27479
0
{
27480
0
    if (s->cur_func->eval_ret_idx >= 0) {
27481
0
        emit_op(s, OP_undefined);
27482
0
        emit_op(s, OP_put_loc);
27483
0
        emit_u16(s, s->cur_func->eval_ret_idx);
27484
0
    }
27485
0
}
27486
27487
static __exception int js_parse_statement_or_decl(JSParseState *s,
27488
                                                  int decl_mask)
27489
9
{
27490
9
    JSContext *ctx = s->ctx;
27491
9
    JSAtom label_name;
27492
9
    int tok;
27493
27494
    /* specific label handling */
27495
    /* XXX: support multiple labels on loop statements */
27496
9
    label_name = JS_ATOM_NULL;
27497
9
    if (is_label(s)) {
27498
2
        BlockEnv *be;
27499
27500
2
        label_name = JS_DupAtom(ctx, s->token.u.ident.atom);
27501
27502
2
        for (be = s->cur_func->top_break; be; be = be->prev) {
27503
0
            if (be->label_name == label_name) {
27504
0
                js_parse_error(s, "duplicate label name");
27505
0
                goto fail;
27506
0
            }
27507
0
        }
27508
27509
2
        if (next_token(s))
27510
0
            goto fail;
27511
2
        if (js_parse_expect(s, ':'))
27512
0
            goto fail;
27513
2
        if (s->token.val != TOK_FOR
27514
2
        &&  s->token.val != TOK_DO
27515
2
        &&  s->token.val != TOK_WHILE) {
27516
            /* labelled regular statement */
27517
2
            int label_break, mask;
27518
2
            BlockEnv break_entry;
27519
27520
2
            label_break = new_label(s);
27521
2
            push_break_entry(s->cur_func, &break_entry,
27522
2
                             label_name, label_break, -1, 0);
27523
2
            break_entry.is_regular_stmt = TRUE;
27524
2
            if (!(s->cur_func->js_mode & JS_MODE_STRICT) &&
27525
2
                (decl_mask & DECL_MASK_FUNC_WITH_LABEL)) {
27526
0
                mask = DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL;
27527
2
            } else {
27528
2
                mask = 0;
27529
2
            }
27530
2
            if (js_parse_statement_or_decl(s, mask))
27531
1
                goto fail;
27532
1
            emit_label(s, label_break);
27533
1
            pop_break_entry(s->cur_func);
27534
1
            goto done;
27535
2
        }
27536
2
    }
27537
27538
7
    switch(tok = s->token.val) {
27539
0
    case '{':
27540
0
        if (js_parse_block(s))
27541
0
            goto fail;
27542
0
        break;
27543
0
    case TOK_RETURN:
27544
0
        {
27545
0
            const uint8_t *op_token_ptr;
27546
0
            if (s->cur_func->is_eval) {
27547
0
                js_parse_error(s, "return not in a function");
27548
0
                goto fail;
27549
0
            }
27550
0
            if (s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) {
27551
0
                js_parse_error(s, "return in a static initializer block");
27552
0
                goto fail;
27553
0
            }
27554
0
            op_token_ptr = s->token.ptr;
27555
0
            if (next_token(s))
27556
0
                goto fail;
27557
0
            if (s->token.val != ';' && s->token.val != '}' && !s->got_lf) {
27558
0
                if (js_parse_expr(s))
27559
0
                    goto fail;
27560
0
                emit_source_pos(s, op_token_ptr);
27561
0
                emit_return(s, TRUE);
27562
0
            } else {
27563
0
                emit_source_pos(s, op_token_ptr);
27564
0
                emit_return(s, FALSE);
27565
0
            }
27566
0
            if (js_parse_expect_semi(s))
27567
0
                goto fail;
27568
0
        }
27569
0
        break;
27570
0
    case TOK_THROW:
27571
0
        {
27572
0
            const uint8_t *op_token_ptr;
27573
0
            op_token_ptr = s->token.ptr;
27574
0
            if (next_token(s))
27575
0
                goto fail;
27576
0
            if (s->got_lf) {
27577
0
                js_parse_error(s, "line terminator not allowed after throw");
27578
0
                goto fail;
27579
0
            }
27580
0
            if (js_parse_expr(s))
27581
0
                goto fail;
27582
0
            emit_source_pos(s, op_token_ptr);
27583
0
            emit_op(s, OP_throw);
27584
0
            if (js_parse_expect_semi(s))
27585
0
                goto fail;
27586
0
        }
27587
0
        break;
27588
0
    case TOK_LET:
27589
0
    case TOK_CONST:
27590
0
    haslet:
27591
0
        if (!(decl_mask & DECL_MASK_OTHER)) {
27592
0
            js_parse_error(s, "lexical declarations can't appear in single-statement context");
27593
0
            goto fail;
27594
0
        }
27595
        /* fall thru */
27596
0
    case TOK_VAR:
27597
0
        if (next_token(s))
27598
0
            goto fail;
27599
0
        if (js_parse_var(s, TRUE, tok, FALSE))
27600
0
            goto fail;
27601
0
        if (js_parse_expect_semi(s))
27602
0
            goto fail;
27603
0
        break;
27604
0
    case TOK_IF:
27605
0
        {
27606
0
            int label1, label2, mask;
27607
0
            if (next_token(s))
27608
0
                goto fail;
27609
            /* create a new scope for `let f;if(1) function f(){}` */
27610
0
            push_scope(s);
27611
0
            set_eval_ret_undefined(s);
27612
0
            if (js_parse_expr_paren(s))
27613
0
                goto fail;
27614
0
            label1 = emit_goto(s, OP_if_false, -1);
27615
0
            if (s->cur_func->js_mode & JS_MODE_STRICT)
27616
0
                mask = 0;
27617
0
            else
27618
0
                mask = DECL_MASK_FUNC; /* Annex B.3.4 */
27619
27620
0
            if (js_parse_statement_or_decl(s, mask))
27621
0
                goto fail;
27622
27623
0
            if (s->token.val == TOK_ELSE) {
27624
0
                label2 = emit_goto(s, OP_goto, -1);
27625
0
                if (next_token(s))
27626
0
                    goto fail;
27627
27628
0
                emit_label(s, label1);
27629
0
                if (js_parse_statement_or_decl(s, mask))
27630
0
                    goto fail;
27631
27632
0
                label1 = label2;
27633
0
            }
27634
0
            emit_label(s, label1);
27635
0
            pop_scope(s);
27636
0
        }
27637
0
        break;
27638
0
    case TOK_WHILE:
27639
0
        {
27640
0
            int label_cont, label_break;
27641
0
            BlockEnv break_entry;
27642
27643
0
            label_cont = new_label(s);
27644
0
            label_break = new_label(s);
27645
27646
0
            push_break_entry(s->cur_func, &break_entry,
27647
0
                             label_name, label_break, label_cont, 0);
27648
27649
0
            if (next_token(s))
27650
0
                goto fail;
27651
27652
0
            set_eval_ret_undefined(s);
27653
27654
0
            emit_label(s, label_cont);
27655
0
            if (js_parse_expr_paren(s))
27656
0
                goto fail;
27657
0
            emit_goto(s, OP_if_false, label_break);
27658
27659
0
            if (js_parse_statement(s))
27660
0
                goto fail;
27661
0
            emit_goto(s, OP_goto, label_cont);
27662
27663
0
            emit_label(s, label_break);
27664
27665
0
            pop_break_entry(s->cur_func);
27666
0
        }
27667
0
        break;
27668
0
    case TOK_DO:
27669
0
        {
27670
0
            int label_cont, label_break, label1;
27671
0
            BlockEnv break_entry;
27672
27673
0
            label_cont = new_label(s);
27674
0
            label_break = new_label(s);
27675
0
            label1 = new_label(s);
27676
27677
0
            push_break_entry(s->cur_func, &break_entry,
27678
0
                             label_name, label_break, label_cont, 0);
27679
27680
0
            if (next_token(s))
27681
0
                goto fail;
27682
27683
0
            emit_label(s, label1);
27684
27685
0
            set_eval_ret_undefined(s);
27686
27687
0
            if (js_parse_statement(s))
27688
0
                goto fail;
27689
27690
0
            emit_label(s, label_cont);
27691
0
            if (js_parse_expect(s, TOK_WHILE))
27692
0
                goto fail;
27693
0
            if (js_parse_expr_paren(s))
27694
0
                goto fail;
27695
            /* Insert semicolon if missing */
27696
0
            if (s->token.val == ';') {
27697
0
                if (next_token(s))
27698
0
                    goto fail;
27699
0
            }
27700
0
            emit_goto(s, OP_if_true, label1);
27701
27702
0
            emit_label(s, label_break);
27703
27704
0
            pop_break_entry(s->cur_func);
27705
0
        }
27706
0
        break;
27707
0
    case TOK_FOR:
27708
0
        {
27709
0
            int label_cont, label_break, label_body, label_test;
27710
0
            int pos_cont, pos_body, block_scope_level;
27711
0
            BlockEnv break_entry;
27712
0
            int tok, bits;
27713
0
            BOOL is_async;
27714
27715
0
            if (next_token(s))
27716
0
                goto fail;
27717
27718
0
            set_eval_ret_undefined(s);
27719
0
            bits = 0;
27720
0
            is_async = FALSE;
27721
0
            if (s->token.val == '(') {
27722
0
                js_parse_skip_parens_token(s, &bits, FALSE);
27723
0
            } else if (s->token.val == TOK_AWAIT) {
27724
0
                if (!(s->cur_func->func_kind & JS_FUNC_ASYNC)) {
27725
0
                    js_parse_error(s, "for await is only valid in asynchronous functions");
27726
0
                    goto fail;
27727
0
                }
27728
0
                is_async = TRUE;
27729
0
                if (next_token(s))
27730
0
                    goto fail;
27731
0
                s->cur_func->has_await = TRUE;
27732
0
            }
27733
0
            if (js_parse_expect(s, '('))
27734
0
                goto fail;
27735
27736
0
            if (!(bits & SKIP_HAS_SEMI)) {
27737
                /* parse for/in or for/of */
27738
0
                if (js_parse_for_in_of(s, label_name, is_async))
27739
0
                    goto fail;
27740
0
                break;
27741
0
            }
27742
0
            block_scope_level = s->cur_func->scope_level;
27743
27744
            /* create scope for the lexical variables declared in the initial,
27745
               test and increment expressions */
27746
0
            push_scope(s);
27747
            /* initial expression */
27748
0
            tok = s->token.val;
27749
0
            if (tok != ';') {
27750
0
                switch (is_let(s, DECL_MASK_OTHER)) {
27751
0
                case TRUE:
27752
0
                    tok = TOK_LET;
27753
0
                    break;
27754
0
                case FALSE:
27755
0
                    break;
27756
0
                default:
27757
0
                    goto fail;
27758
0
                }
27759
0
                if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) {
27760
0
                    if (next_token(s))
27761
0
                        goto fail;
27762
0
                    if (js_parse_var(s, FALSE, tok, FALSE))
27763
0
                        goto fail;
27764
0
                } else {
27765
0
                    if (js_parse_expr2(s, FALSE))
27766
0
                        goto fail;
27767
0
                    emit_op(s, OP_drop);
27768
0
                }
27769
27770
                /* close the closures before the first iteration */
27771
0
                close_scopes(s, s->cur_func->scope_level, block_scope_level);
27772
0
            }
27773
0
            if (js_parse_expect(s, ';'))
27774
0
                goto fail;
27775
27776
0
            label_test = new_label(s);
27777
0
            label_cont = new_label(s);
27778
0
            label_body = new_label(s);
27779
0
            label_break = new_label(s);
27780
27781
0
            push_break_entry(s->cur_func, &break_entry,
27782
0
                             label_name, label_break, label_cont, 0);
27783
27784
            /* test expression */
27785
0
            if (s->token.val == ';') {
27786
                /* no test expression */
27787
0
                label_test = label_body;
27788
0
            } else {
27789
0
                emit_label(s, label_test);
27790
0
                if (js_parse_expr(s))
27791
0
                    goto fail;
27792
0
                emit_goto(s, OP_if_false, label_break);
27793
0
            }
27794
0
            if (js_parse_expect(s, ';'))
27795
0
                goto fail;
27796
27797
0
            if (s->token.val == ')') {
27798
                /* no end expression */
27799
0
                break_entry.label_cont = label_cont = label_test;
27800
0
                pos_cont = 0; /* avoid warning */
27801
0
            } else {
27802
                /* skip the end expression */
27803
0
                emit_goto(s, OP_goto, label_body);
27804
27805
0
                pos_cont = s->cur_func->byte_code.size;
27806
0
                emit_label(s, label_cont);
27807
0
                if (js_parse_expr(s))
27808
0
                    goto fail;
27809
0
                emit_op(s, OP_drop);
27810
0
                if (label_test != label_body)
27811
0
                    emit_goto(s, OP_goto, label_test);
27812
0
            }
27813
0
            if (js_parse_expect(s, ')'))
27814
0
                goto fail;
27815
27816
0
            pos_body = s->cur_func->byte_code.size;
27817
0
            emit_label(s, label_body);
27818
0
            if (js_parse_statement(s))
27819
0
                goto fail;
27820
27821
            /* close the closures before the next iteration */
27822
            /* XXX: check continue case */
27823
0
            close_scopes(s, s->cur_func->scope_level, block_scope_level);
27824
27825
0
            if (OPTIMIZE && label_test != label_body && label_cont != label_test) {
27826
                /* move the increment code here */
27827
0
                DynBuf *bc = &s->cur_func->byte_code;
27828
0
                int chunk_size = pos_body - pos_cont;
27829
0
                int offset = bc->size - pos_cont;
27830
0
                int i;
27831
0
                dbuf_realloc(bc, bc->size + chunk_size);
27832
0
                dbuf_put(bc, bc->buf + pos_cont, chunk_size);
27833
0
                memset(bc->buf + pos_cont, OP_nop, chunk_size);
27834
                /* increment part ends with a goto */
27835
0
                s->cur_func->last_opcode_pos = bc->size - 5;
27836
                /* relocate labels */
27837
0
                for (i = label_cont; i < s->cur_func->label_count; i++) {
27838
0
                    LabelSlot *ls = &s->cur_func->label_slots[i];
27839
0
                    if (ls->pos >= pos_cont && ls->pos < pos_body)
27840
0
                        ls->pos += offset;
27841
0
                }
27842
0
            } else {
27843
0
                emit_goto(s, OP_goto, label_cont);
27844
0
            }
27845
27846
0
            emit_label(s, label_break);
27847
27848
0
            pop_break_entry(s->cur_func);
27849
0
            pop_scope(s);
27850
0
        }
27851
0
        break;
27852
0
    case TOK_BREAK:
27853
0
    case TOK_CONTINUE:
27854
0
        {
27855
0
            int is_cont = s->token.val - TOK_BREAK;
27856
0
            int label;
27857
27858
0
            if (next_token(s))
27859
0
                goto fail;
27860
0
            if (!s->got_lf && s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)
27861
0
                label = s->token.u.ident.atom;
27862
0
            else
27863
0
                label = JS_ATOM_NULL;
27864
0
            if (emit_break(s, label, is_cont))
27865
0
                goto fail;
27866
0
            if (label != JS_ATOM_NULL) {
27867
0
                if (next_token(s))
27868
0
                    goto fail;
27869
0
            }
27870
0
            if (js_parse_expect_semi(s))
27871
0
                goto fail;
27872
0
        }
27873
0
        break;
27874
0
    case TOK_SWITCH:
27875
0
        {
27876
0
            int label_case, label_break, label1;
27877
0
            int default_label_pos;
27878
0
            BlockEnv break_entry;
27879
27880
0
            if (next_token(s))
27881
0
                goto fail;
27882
27883
0
            set_eval_ret_undefined(s);
27884
0
            if (js_parse_expr_paren(s))
27885
0
                goto fail;
27886
27887
0
            push_scope(s);
27888
0
            label_break = new_label(s);
27889
0
            push_break_entry(s->cur_func, &break_entry,
27890
0
                             label_name, label_break, -1, 1);
27891
27892
0
            if (js_parse_expect(s, '{'))
27893
0
                goto fail;
27894
27895
0
            default_label_pos = -1;
27896
0
            label_case = -1;
27897
0
            while (s->token.val != '}') {
27898
0
                if (s->token.val == TOK_CASE) {
27899
0
                    label1 = -1;
27900
0
                    if (label_case >= 0) {
27901
                        /* skip the case if needed */
27902
0
                        label1 = emit_goto(s, OP_goto, -1);
27903
0
                    }
27904
0
                    emit_label(s, label_case);
27905
0
                    label_case = -1;
27906
0
                    for (;;) {
27907
                        /* parse a sequence of case clauses */
27908
0
                        if (next_token(s))
27909
0
                            goto fail;
27910
0
                        emit_op(s, OP_dup);
27911
0
                        if (js_parse_expr(s))
27912
0
                            goto fail;
27913
0
                        if (js_parse_expect(s, ':'))
27914
0
                            goto fail;
27915
0
                        emit_op(s, OP_strict_eq);
27916
0
                        if (s->token.val == TOK_CASE) {
27917
0
                            label1 = emit_goto(s, OP_if_true, label1);
27918
0
                        } else {
27919
0
                            label_case = emit_goto(s, OP_if_false, -1);
27920
0
                            emit_label(s, label1);
27921
0
                            break;
27922
0
                        }
27923
0
                    }
27924
0
                } else if (s->token.val == TOK_DEFAULT) {
27925
0
                    if (next_token(s))
27926
0
                        goto fail;
27927
0
                    if (js_parse_expect(s, ':'))
27928
0
                        goto fail;
27929
0
                    if (default_label_pos >= 0) {
27930
0
                        js_parse_error(s, "duplicate default");
27931
0
                        goto fail;
27932
0
                    }
27933
0
                    if (label_case < 0) {
27934
                        /* falling thru direct from switch expression */
27935
0
                        label_case = emit_goto(s, OP_goto, -1);
27936
0
                    }
27937
                    /* Emit a dummy label opcode. Label will be patched after
27938
                       the end of the switch body. Do not use emit_label(s, 0)
27939
                       because it would clobber label 0 address, preventing
27940
                       proper optimizer operation.
27941
                     */
27942
0
                    emit_op(s, OP_label);
27943
0
                    emit_u32(s, 0);
27944
0
                    default_label_pos = s->cur_func->byte_code.size - 4;
27945
0
                } else {
27946
0
                    if (label_case < 0) {
27947
                        /* falling thru direct from switch expression */
27948
0
                        js_parse_error(s, "invalid switch statement");
27949
0
                        goto fail;
27950
0
                    }
27951
0
                    if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
27952
0
                        goto fail;
27953
0
                }
27954
0
            }
27955
0
            if (js_parse_expect(s, '}'))
27956
0
                goto fail;
27957
0
            if (default_label_pos >= 0) {
27958
                /* Ugly patch for the the `default` label, shameful and risky */
27959
0
                put_u32(s->cur_func->byte_code.buf + default_label_pos,
27960
0
                        label_case);
27961
0
                s->cur_func->label_slots[label_case].pos = default_label_pos + 4;
27962
0
            } else {
27963
0
                emit_label(s, label_case);
27964
0
            }
27965
0
            emit_label(s, label_break);
27966
0
            emit_op(s, OP_drop); /* drop the switch expression */
27967
27968
0
            pop_break_entry(s->cur_func);
27969
0
            pop_scope(s);
27970
0
        }
27971
0
        break;
27972
0
    case TOK_TRY:
27973
0
        {
27974
0
            int label_catch, label_catch2, label_finally, label_end;
27975
0
            JSAtom name;
27976
0
            BlockEnv block_env;
27977
27978
0
            set_eval_ret_undefined(s);
27979
0
            if (next_token(s))
27980
0
                goto fail;
27981
0
            label_catch = new_label(s);
27982
0
            label_catch2 = new_label(s);
27983
0
            label_finally = new_label(s);
27984
0
            label_end = new_label(s);
27985
27986
0
            emit_goto(s, OP_catch, label_catch);
27987
27988
0
            push_break_entry(s->cur_func, &block_env,
27989
0
                             JS_ATOM_NULL, -1, -1, 1);
27990
0
            block_env.label_finally = label_finally;
27991
27992
0
            if (js_parse_block(s))
27993
0
                goto fail;
27994
27995
0
            pop_break_entry(s->cur_func);
27996
27997
0
            if (js_is_live_code(s)) {
27998
                /* drop the catch offset */
27999
0
                emit_op(s, OP_drop);
28000
                /* must push dummy value to keep same stack size */
28001
0
                emit_op(s, OP_undefined);
28002
0
                emit_goto(s, OP_gosub, label_finally);
28003
0
                emit_op(s, OP_drop);
28004
28005
0
                emit_goto(s, OP_goto, label_end);
28006
0
            }
28007
28008
0
            if (s->token.val == TOK_CATCH) {
28009
0
                if (next_token(s))
28010
0
                    goto fail;
28011
28012
0
                push_scope(s);  /* catch variable */
28013
0
                emit_label(s, label_catch);
28014
28015
0
                if (s->token.val == '{') {
28016
                    /* support optional-catch-binding feature */
28017
0
                    emit_op(s, OP_drop);    /* pop the exception object */
28018
0
                } else {
28019
0
                    if (js_parse_expect(s, '('))
28020
0
                        goto fail;
28021
0
                    if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
28022
0
                        if (s->token.val == '[' || s->token.val == '{') {
28023
                            /* XXX: TOK_LET is not completely correct */
28024
0
                            if (js_parse_destructuring_element(s, TOK_LET, 0, TRUE, -1, TRUE, FALSE) < 0)
28025
0
                                goto fail;
28026
0
                        } else {
28027
0
                            js_parse_error(s, "identifier expected");
28028
0
                            goto fail;
28029
0
                        }
28030
0
                    } else {
28031
0
                        name = JS_DupAtom(ctx, s->token.u.ident.atom);
28032
0
                        if (next_token(s)
28033
0
                        ||  js_define_var(s, name, TOK_CATCH) < 0) {
28034
0
                            JS_FreeAtom(ctx, name);
28035
0
                            goto fail;
28036
0
                        }
28037
                        /* store the exception value in the catch variable */
28038
0
                        emit_op(s, OP_scope_put_var);
28039
0
                        emit_u32(s, name);
28040
0
                        emit_u16(s, s->cur_func->scope_level);
28041
0
                    }
28042
0
                    if (js_parse_expect(s, ')'))
28043
0
                        goto fail;
28044
0
                }
28045
                /* XXX: should keep the address to nop it out if there is no finally block */
28046
0
                emit_goto(s, OP_catch, label_catch2);
28047
28048
0
                push_scope(s);  /* catch block */
28049
0
                push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL,
28050
0
                                 -1, -1, 1);
28051
0
                block_env.label_finally = label_finally;
28052
28053
0
                if (js_parse_block(s))
28054
0
                    goto fail;
28055
28056
0
                pop_break_entry(s->cur_func);
28057
0
                pop_scope(s);  /* catch block */
28058
0
                pop_scope(s);  /* catch variable */
28059
28060
0
                if (js_is_live_code(s)) {
28061
                    /* drop the catch2 offset */
28062
0
                    emit_op(s, OP_drop);
28063
                    /* XXX: should keep the address to nop it out if there is no finally block */
28064
                    /* must push dummy value to keep same stack size */
28065
0
                    emit_op(s, OP_undefined);
28066
0
                    emit_goto(s, OP_gosub, label_finally);
28067
0
                    emit_op(s, OP_drop);
28068
0
                    emit_goto(s, OP_goto, label_end);
28069
0
                }
28070
                /* catch exceptions thrown in the catch block to execute the
28071
                 * finally clause and rethrow the exception */
28072
0
                emit_label(s, label_catch2);
28073
                /* catch value is at TOS, no need to push undefined */
28074
0
                emit_goto(s, OP_gosub, label_finally);
28075
0
                emit_op(s, OP_throw);
28076
28077
0
            } else if (s->token.val == TOK_FINALLY) {
28078
                /* finally without catch : execute the finally clause
28079
                 * and rethrow the exception */
28080
0
                emit_label(s, label_catch);
28081
                /* catch value is at TOS, no need to push undefined */
28082
0
                emit_goto(s, OP_gosub, label_finally);
28083
0
                emit_op(s, OP_throw);
28084
0
            } else {
28085
0
                js_parse_error(s, "expecting catch or finally");
28086
0
                goto fail;
28087
0
            }
28088
0
            emit_label(s, label_finally);
28089
0
            if (s->token.val == TOK_FINALLY) {
28090
0
                int saved_eval_ret_idx = 0; /* avoid warning */
28091
28092
0
                if (next_token(s))
28093
0
                    goto fail;
28094
                /* on the stack: ret_value gosub_ret_value */
28095
0
                push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL,
28096
0
                                 -1, -1, 2);
28097
28098
0
                if (s->cur_func->eval_ret_idx >= 0) {
28099
                    /* 'finally' updates eval_ret only if not a normal
28100
                       termination */
28101
0
                    saved_eval_ret_idx =
28102
0
                        add_var(s->ctx, s->cur_func, JS_ATOM__ret_);
28103
0
                    if (saved_eval_ret_idx < 0)
28104
0
                        goto fail;
28105
0
                    emit_op(s, OP_get_loc);
28106
0
                    emit_u16(s, s->cur_func->eval_ret_idx);
28107
0
                    emit_op(s, OP_put_loc);
28108
0
                    emit_u16(s, saved_eval_ret_idx);
28109
0
                    set_eval_ret_undefined(s);
28110
0
                }
28111
28112
0
                if (js_parse_block(s))
28113
0
                    goto fail;
28114
28115
0
                if (s->cur_func->eval_ret_idx >= 0) {
28116
0
                    emit_op(s, OP_get_loc);
28117
0
                    emit_u16(s, saved_eval_ret_idx);
28118
0
                    emit_op(s, OP_put_loc);
28119
0
                    emit_u16(s, s->cur_func->eval_ret_idx);
28120
0
                }
28121
0
                pop_break_entry(s->cur_func);
28122
0
            }
28123
0
            emit_op(s, OP_ret);
28124
0
            emit_label(s, label_end);
28125
0
        }
28126
0
        break;
28127
0
    case ';':
28128
        /* empty statement */
28129
0
        if (next_token(s))
28130
0
            goto fail;
28131
0
        break;
28132
0
    case TOK_WITH:
28133
0
        if (s->cur_func->js_mode & JS_MODE_STRICT) {
28134
0
            js_parse_error(s, "invalid keyword: with");
28135
0
            goto fail;
28136
0
        } else {
28137
0
            int with_idx;
28138
28139
0
            if (next_token(s))
28140
0
                goto fail;
28141
28142
0
            if (js_parse_expr_paren(s))
28143
0
                goto fail;
28144
28145
0
            push_scope(s);
28146
0
            with_idx = define_var(s, s->cur_func, JS_ATOM__with_,
28147
0
                                  JS_VAR_DEF_WITH);
28148
0
            if (with_idx < 0)
28149
0
                goto fail;
28150
0
            emit_op(s, OP_to_object);
28151
0
            emit_op(s, OP_put_loc);
28152
0
            emit_u16(s, with_idx);
28153
28154
0
            set_eval_ret_undefined(s);
28155
0
            if (js_parse_statement(s))
28156
0
                goto fail;
28157
28158
            /* Popping scope drops lexical context for the with object variable */
28159
0
            pop_scope(s);
28160
0
        }
28161
0
        break;
28162
0
    case TOK_FUNCTION:
28163
        /* ES6 Annex B.3.2 and B.3.3 semantics */
28164
0
        if (!(decl_mask & DECL_MASK_FUNC))
28165
0
            goto func_decl_error;
28166
0
        if (!(decl_mask & DECL_MASK_OTHER) && peek_token(s, FALSE) == '*')
28167
0
            goto func_decl_error;
28168
0
        goto parse_func_var;
28169
5
    case TOK_IDENT:
28170
5
        if (s->token.u.ident.is_reserved) {
28171
0
            js_parse_error_reserved_identifier(s);
28172
0
            goto fail;
28173
0
        }
28174
        /* Determine if `let` introduces a Declaration or an ExpressionStatement */
28175
5
        switch (is_let(s, decl_mask)) {
28176
0
        case TRUE:
28177
0
            tok = TOK_LET;
28178
0
            goto haslet;
28179
5
        case FALSE:
28180
5
            break;
28181
0
        default:
28182
0
            goto fail;
28183
5
        }
28184
5
        if (token_is_pseudo_keyword(s, JS_ATOM_async) &&
28185
5
            peek_token(s, TRUE) == TOK_FUNCTION) {
28186
0
            if (!(decl_mask & DECL_MASK_OTHER)) {
28187
0
            func_decl_error:
28188
0
                js_parse_error(s, "function declarations can't appear in single-statement context");
28189
0
                goto fail;
28190
0
            }
28191
0
        parse_func_var:
28192
0
            if (js_parse_function_decl(s, JS_PARSE_FUNC_VAR,
28193
0
                                       JS_FUNC_NORMAL, JS_ATOM_NULL,
28194
0
                                       s->token.ptr))
28195
0
                goto fail;
28196
0
            break;
28197
0
        }
28198
5
        goto hasexpr;
28199
28200
5
    case TOK_CLASS:
28201
0
        if (!(decl_mask & DECL_MASK_OTHER)) {
28202
0
            js_parse_error(s, "class declarations can't appear in single-statement context");
28203
0
            goto fail;
28204
0
        }
28205
0
        if (js_parse_class(s, FALSE, JS_PARSE_EXPORT_NONE))
28206
0
            return -1;
28207
0
        break;
28208
28209
0
    case TOK_DEBUGGER:
28210
        /* currently no debugger, so just skip the keyword */
28211
0
        if (next_token(s))
28212
0
            goto fail;
28213
0
        if (js_parse_expect_semi(s))
28214
0
            goto fail;
28215
0
        break;
28216
28217
0
    case TOK_ENUM:
28218
0
    case TOK_EXPORT:
28219
0
    case TOK_EXTENDS:
28220
0
        js_unsupported_keyword(s, s->token.u.ident.atom);
28221
0
        goto fail;
28222
28223
2
    default:
28224
7
    hasexpr:
28225
7
        emit_source_pos(s, s->token.ptr);
28226
7
        if (js_parse_expr(s))
28227
1
            goto fail;
28228
6
        if (s->cur_func->eval_ret_idx >= 0) {
28229
            /* store the expression value so that it can be returned
28230
               by eval() */
28231
0
            emit_op(s, OP_put_loc);
28232
0
            emit_u16(s, s->cur_func->eval_ret_idx);
28233
6
        } else {
28234
6
            emit_op(s, OP_drop); /* drop the result */
28235
6
        }
28236
6
        if (js_parse_expect_semi(s))
28237
0
            goto fail;
28238
6
        break;
28239
7
    }
28240
7
done:
28241
7
    JS_FreeAtom(ctx, label_name);
28242
7
    return 0;
28243
2
fail:
28244
2
    JS_FreeAtom(ctx, label_name);
28245
2
    return -1;
28246
7
}
28247
28248
/* 'name' is freed. The module is referenced by 'ctx->loaded_modules' */
28249
static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name)
28250
9
{
28251
9
    JSModuleDef *m;
28252
9
    m = js_mallocz(ctx, sizeof(*m));
28253
9
    if (!m) {
28254
0
        JS_FreeAtom(ctx, name);
28255
0
        return NULL;
28256
0
    }
28257
9
    m->header.ref_count = 1;
28258
9
    add_gc_object(ctx->rt, &m->header, JS_GC_OBJ_TYPE_MODULE);
28259
9
    m->module_name = name;
28260
9
    m->module_ns = JS_UNDEFINED;
28261
9
    m->func_obj = JS_UNDEFINED;
28262
9
    m->eval_exception = JS_UNDEFINED;
28263
9
    m->meta_obj = JS_UNDEFINED;
28264
9
    m->promise = JS_UNDEFINED;
28265
9
    m->resolving_funcs[0] = JS_UNDEFINED;
28266
9
    m->resolving_funcs[1] = JS_UNDEFINED;
28267
9
    m->private_value = JS_UNDEFINED;
28268
9
    list_add_tail(&m->link, &ctx->loaded_modules);
28269
9
    return m;
28270
9
}
28271
28272
static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,
28273
                               JS_MarkFunc *mark_func)
28274
16
{
28275
16
    int i;
28276
28277
24
    for(i = 0; i < m->req_module_entries_count; i++) {
28278
8
        JSReqModuleEntry *rme = &m->req_module_entries[i];
28279
8
        JS_MarkValue(rt, rme->attributes, mark_func);
28280
8
    }
28281
    
28282
408
    for(i = 0; i < m->export_entries_count; i++) {
28283
392
        JSExportEntry *me = &m->export_entries[i];
28284
392
        if (me->export_type == JS_EXPORT_TYPE_LOCAL &&
28285
392
            me->u.local.var_ref) {
28286
392
            mark_func(rt, &me->u.local.var_ref->header);
28287
392
        }
28288
392
    }
28289
28290
16
    JS_MarkValue(rt, m->module_ns, mark_func);
28291
16
    JS_MarkValue(rt, m->func_obj, mark_func);
28292
16
    JS_MarkValue(rt, m->eval_exception, mark_func);
28293
16
    JS_MarkValue(rt, m->meta_obj, mark_func);
28294
16
    JS_MarkValue(rt, m->promise, mark_func);
28295
16
    JS_MarkValue(rt, m->resolving_funcs[0], mark_func);
28296
16
    JS_MarkValue(rt, m->resolving_funcs[1], mark_func);
28297
16
    JS_MarkValue(rt, m->private_value, mark_func);
28298
16
}
28299
28300
static void js_free_module_def(JSRuntime *rt, JSModuleDef *m)
28301
9
{
28302
9
    int i;
28303
28304
9
    JS_FreeAtomRT(rt, m->module_name);
28305
28306
13
    for(i = 0; i < m->req_module_entries_count; i++) {
28307
4
        JSReqModuleEntry *rme = &m->req_module_entries[i];
28308
4
        JS_FreeAtomRT(rt, rme->module_name);
28309
4
        JS_FreeValueRT(rt, rme->attributes);
28310
4
    }
28311
9
    js_free_rt(rt, m->req_module_entries);
28312
28313
205
    for(i = 0; i < m->export_entries_count; i++) {
28314
196
        JSExportEntry *me = &m->export_entries[i];
28315
196
        if (me->export_type == JS_EXPORT_TYPE_LOCAL)
28316
196
            free_var_ref(rt, me->u.local.var_ref);
28317
196
        JS_FreeAtomRT(rt, me->export_name);
28318
196
        JS_FreeAtomRT(rt, me->local_name);
28319
196
    }
28320
9
    js_free_rt(rt, m->export_entries);
28321
28322
9
    js_free_rt(rt, m->star_export_entries);
28323
28324
13
    for(i = 0; i < m->import_entries_count; i++) {
28325
4
        JSImportEntry *mi = &m->import_entries[i];
28326
4
        JS_FreeAtomRT(rt, mi->import_name);
28327
4
    }
28328
9
    js_free_rt(rt, m->import_entries);
28329
9
    js_free_rt(rt, m->async_parent_modules);
28330
28331
9
    JS_FreeValueRT(rt, m->module_ns);
28332
9
    JS_FreeValueRT(rt, m->func_obj);
28333
9
    JS_FreeValueRT(rt, m->eval_exception);
28334
9
    JS_FreeValueRT(rt, m->meta_obj);
28335
9
    JS_FreeValueRT(rt, m->promise);
28336
9
    JS_FreeValueRT(rt, m->resolving_funcs[0]);
28337
9
    JS_FreeValueRT(rt, m->resolving_funcs[1]);
28338
9
    JS_FreeValueRT(rt, m->private_value);
28339
    /* during the GC the finalizers are called in an arbitrary
28340
       order so the module may no longer be referenced by the JSContext list */
28341
9
    if (m->link.next) {
28342
9
        list_del(&m->link);
28343
9
    }
28344
9
    remove_gc_object(&m->header);
28345
9
    if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && m->header.ref_count != 0) {
28346
8
        list_add_tail(&m->header.link, &rt->gc_zero_ref_count_list);
28347
8
    } else {
28348
1
        js_free_rt(rt, m);
28349
1
    }
28350
9
}
28351
28352
static int add_req_module_entry(JSContext *ctx, JSModuleDef *m,
28353
                                JSAtom module_name)
28354
4
{
28355
4
    JSReqModuleEntry *rme;
28356
28357
4
    if (js_resize_array(ctx, (void **)&m->req_module_entries,
28358
4
                        sizeof(JSReqModuleEntry),
28359
4
                        &m->req_module_entries_size,
28360
4
                        m->req_module_entries_count + 1))
28361
0
        return -1;
28362
4
    rme = &m->req_module_entries[m->req_module_entries_count++];
28363
4
    rme->module_name = JS_DupAtom(ctx, module_name);
28364
4
    rme->module = NULL;
28365
4
    rme->attributes = JS_UNDEFINED;
28366
4
    return m->req_module_entries_count - 1;
28367
4
}
28368
28369
static JSExportEntry *find_export_entry(JSContext *ctx, JSModuleDef *m,
28370
                                        JSAtom export_name)
28371
392
{
28372
392
    JSExportEntry *me;
28373
392
    int i;
28374
11.7k
    for(i = 0; i < m->export_entries_count; i++) {
28375
11.5k
        me = &m->export_entries[i];
28376
11.5k
        if (me->export_name == export_name)
28377
196
            return me;
28378
11.5k
    }
28379
196
    return NULL;
28380
392
}
28381
28382
static JSExportEntry *add_export_entry2(JSContext *ctx,
28383
                                        JSParseState *s, JSModuleDef *m,
28384
                                       JSAtom local_name, JSAtom export_name,
28385
                                       JSExportTypeEnum export_type)
28386
196
{
28387
196
    JSExportEntry *me;
28388
28389
196
    if (find_export_entry(ctx, m, export_name)) {
28390
0
        char buf1[ATOM_GET_STR_BUF_SIZE];
28391
0
        if (s) {
28392
0
            js_parse_error(s, "duplicate exported name '%s'",
28393
0
                           JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name));
28394
0
        } else {
28395
0
            JS_ThrowSyntaxErrorAtom(ctx, "duplicate exported name '%s'", export_name);
28396
0
        }
28397
0
        return NULL;
28398
0
    }
28399
28400
196
    if (js_resize_array(ctx, (void **)&m->export_entries,
28401
196
                        sizeof(JSExportEntry),
28402
196
                        &m->export_entries_size,
28403
196
                        m->export_entries_count + 1))
28404
0
        return NULL;
28405
196
    me = &m->export_entries[m->export_entries_count++];
28406
196
    memset(me, 0, sizeof(*me));
28407
196
    me->local_name = JS_DupAtom(ctx, local_name);
28408
196
    me->export_name = JS_DupAtom(ctx, export_name);
28409
196
    me->export_type = export_type;
28410
196
    return me;
28411
196
}
28412
28413
static JSExportEntry *add_export_entry(JSParseState *s, JSModuleDef *m,
28414
                                       JSAtom local_name, JSAtom export_name,
28415
                                       JSExportTypeEnum export_type)
28416
0
{
28417
0
    return add_export_entry2(s->ctx, s, m, local_name, export_name,
28418
0
                             export_type);
28419
0
}
28420
28421
static int add_star_export_entry(JSContext *ctx, JSModuleDef *m,
28422
                                 int req_module_idx)
28423
0
{
28424
0
    JSStarExportEntry *se;
28425
28426
0
    if (js_resize_array(ctx, (void **)&m->star_export_entries,
28427
0
                        sizeof(JSStarExportEntry),
28428
0
                        &m->star_export_entries_size,
28429
0
                        m->star_export_entries_count + 1))
28430
0
        return -1;
28431
0
    se = &m->star_export_entries[m->star_export_entries_count++];
28432
0
    se->req_module_idx = req_module_idx;
28433
0
    return 0;
28434
0
}
28435
28436
/* create a C module */
28437
JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str,
28438
                           JSModuleInitFunc *func)
28439
4
{
28440
4
    JSModuleDef *m;
28441
4
    JSAtom name;
28442
4
    name = JS_NewAtom(ctx, name_str);
28443
4
    if (name == JS_ATOM_NULL)
28444
0
        return NULL;
28445
4
    m = js_new_module_def(ctx, name);
28446
4
    if (!m)
28447
0
        return NULL;
28448
4
    m->init_func = func;
28449
4
    return m;
28450
4
}
28451
28452
int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name)
28453
196
{
28454
196
    JSExportEntry *me;
28455
196
    JSAtom name;
28456
196
    name = JS_NewAtom(ctx, export_name);
28457
196
    if (name == JS_ATOM_NULL)
28458
0
        return -1;
28459
196
    me = add_export_entry2(ctx, NULL, m, JS_ATOM_NULL, name,
28460
196
                           JS_EXPORT_TYPE_LOCAL);
28461
196
    JS_FreeAtom(ctx, name);
28462
196
    if (!me)
28463
0
        return -1;
28464
196
    else
28465
196
        return 0;
28466
196
}
28467
28468
int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name,
28469
                       JSValue val)
28470
196
{
28471
196
    JSExportEntry *me;
28472
196
    JSAtom name;
28473
196
    name = JS_NewAtom(ctx, export_name);
28474
196
    if (name == JS_ATOM_NULL)
28475
0
        goto fail;
28476
196
    me = find_export_entry(ctx, m, name);
28477
196
    JS_FreeAtom(ctx, name);
28478
196
    if (!me)
28479
0
        goto fail;
28480
196
    set_value(ctx, me->u.local.var_ref->pvalue, val);
28481
196
    return 0;
28482
0
 fail:
28483
0
    JS_FreeValue(ctx, val);
28484
0
    return -1;
28485
196
}
28486
28487
int JS_SetModulePrivateValue(JSContext *ctx, JSModuleDef *m, JSValue val)
28488
0
{
28489
0
    set_value(ctx, &m->private_value, val);
28490
0
    return 0;
28491
0
}
28492
28493
JSValue JS_GetModulePrivateValue(JSContext *ctx, JSModuleDef *m)
28494
0
{
28495
0
    return JS_DupValue(ctx, m->private_value);
28496
0
}
28497
28498
void JS_SetModuleLoaderFunc(JSRuntime *rt,
28499
                            JSModuleNormalizeFunc *module_normalize,
28500
                            JSModuleLoaderFunc *module_loader, void *opaque)
28501
2
{
28502
2
    rt->module_normalize_func = module_normalize;
28503
2
    rt->module_loader_has_attr = FALSE;
28504
2
    rt->u.module_loader_func = module_loader;
28505
2
    rt->module_check_attrs = NULL;
28506
2
    rt->module_loader_opaque = opaque;
28507
2
}
28508
28509
void JS_SetModuleLoaderFunc2(JSRuntime *rt,
28510
                             JSModuleNormalizeFunc *module_normalize,
28511
                             JSModuleLoaderFunc2 *module_loader,
28512
                             JSModuleCheckSupportedImportAttributes *module_check_attrs,
28513
                             void *opaque)
28514
0
{
28515
0
    rt->module_normalize_func = module_normalize;
28516
0
    rt->module_loader_has_attr = TRUE;
28517
0
    rt->u.module_loader_func2 = module_loader;
28518
0
    rt->module_check_attrs = module_check_attrs;
28519
0
    rt->module_loader_opaque = opaque;
28520
0
}
28521
28522
/* default module filename normalizer */
28523
static char *js_default_module_normalize_name(JSContext *ctx,
28524
                                              const char *base_name,
28525
                                              const char *name)
28526
4
{
28527
4
    char *filename, *p;
28528
4
    const char *r;
28529
4
    int cap;
28530
4
    int len;
28531
28532
4
    if (name[0] != '.') {
28533
        /* if no initial dot, the module name is not modified */
28534
4
        return js_strdup(ctx, name);
28535
4
    }
28536
28537
0
    p = strrchr(base_name, '/');
28538
0
    if (p)
28539
0
        len = p - base_name;
28540
0
    else
28541
0
        len = 0;
28542
28543
0
    cap = len + strlen(name) + 1 + 1;
28544
0
    filename = js_malloc(ctx, cap);
28545
0
    if (!filename)
28546
0
        return NULL;
28547
0
    memcpy(filename, base_name, len);
28548
0
    filename[len] = '\0';
28549
28550
    /* we only normalize the leading '..' or '.' */
28551
0
    r = name;
28552
0
    for(;;) {
28553
0
        if (r[0] == '.' && r[1] == '/') {
28554
0
            r += 2;
28555
0
        } else if (r[0] == '.' && r[1] == '.' && r[2] == '/') {
28556
            /* remove the last path element of filename, except if "."
28557
               or ".." */
28558
0
            if (filename[0] == '\0')
28559
0
                break;
28560
0
            p = strrchr(filename, '/');
28561
0
            if (!p)
28562
0
                p = filename;
28563
0
            else
28564
0
                p++;
28565
0
            if (!strcmp(p, ".") || !strcmp(p, ".."))
28566
0
                break;
28567
0
            if (p > filename)
28568
0
                p--;
28569
0
            *p = '\0';
28570
0
            r += 3;
28571
0
        } else {
28572
0
            break;
28573
0
        }
28574
0
    }
28575
0
    if (filename[0] != '\0')
28576
0
        pstrcat(filename, cap, "/");
28577
0
    pstrcat(filename, cap, r);
28578
    //    printf("normalize: %s %s -> %s\n", base_name, name, filename);
28579
0
    return filename;
28580
0
}
28581
28582
static JSModuleDef *js_find_loaded_module(JSContext *ctx, JSAtom name)
28583
4
{
28584
4
    struct list_head *el;
28585
4
    JSModuleDef *m;
28586
28587
    /* first look at the loaded modules */
28588
6
    list_for_each(el, &ctx->loaded_modules) {
28589
6
        m = list_entry(el, JSModuleDef, link);
28590
6
        if (m->module_name == name)
28591
4
            return m;
28592
6
    }
28593
0
    return NULL;
28594
4
}
28595
28596
/* return NULL in case of exception (e.g. module could not be loaded) */
28597
static JSModuleDef *js_host_resolve_imported_module(JSContext *ctx,
28598
                                                    const char *base_cname,
28599
                                                    const char *cname1,
28600
                                                    JSValueConst attributes)
28601
4
{
28602
4
    JSRuntime *rt = ctx->rt;
28603
4
    JSModuleDef *m;
28604
4
    char *cname;
28605
4
    JSAtom module_name;
28606
28607
4
    if (!rt->module_normalize_func) {
28608
4
        cname = js_default_module_normalize_name(ctx, base_cname, cname1);
28609
4
    } else {
28610
0
        cname = rt->module_normalize_func(ctx, base_cname, cname1,
28611
0
                                          rt->module_loader_opaque);
28612
0
    }
28613
4
    if (!cname)
28614
0
        return NULL;
28615
28616
4
    module_name = JS_NewAtom(ctx, cname);
28617
4
    if (module_name == JS_ATOM_NULL) {
28618
0
        js_free(ctx, cname);
28619
0
        return NULL;
28620
0
    }
28621
28622
    /* first look at the loaded modules */
28623
4
    m = js_find_loaded_module(ctx, module_name);
28624
4
    if (m) {
28625
4
        js_free(ctx, cname);
28626
4
        JS_FreeAtom(ctx, module_name);
28627
4
        return m;
28628
4
    }
28629
28630
0
    JS_FreeAtom(ctx, module_name);
28631
28632
    /* load the module */
28633
0
    if (!rt->u.module_loader_func) {
28634
        /* XXX: use a syntax error ? */
28635
0
        JS_ThrowReferenceError(ctx, "could not load module '%s'",
28636
0
                               cname);
28637
0
        js_free(ctx, cname);
28638
0
        return NULL;
28639
0
    }
28640
0
    if (rt->module_loader_has_attr) {
28641
0
        m = rt->u.module_loader_func2(ctx, cname, rt->module_loader_opaque, attributes);
28642
0
    } else {
28643
0
        m = rt->u.module_loader_func(ctx, cname, rt->module_loader_opaque);
28644
0
    }
28645
0
    js_free(ctx, cname);
28646
0
    return m;
28647
0
}
28648
28649
static JSModuleDef *js_host_resolve_imported_module_atom(JSContext *ctx,
28650
                                                         JSAtom base_module_name,
28651
                                                         JSAtom module_name1,
28652
                                                         JSValueConst attributes)
28653
4
{
28654
4
    const char *base_cname, *cname;
28655
4
    JSModuleDef *m;
28656
28657
4
    base_cname = JS_AtomToCString(ctx, base_module_name);
28658
4
    if (!base_cname)
28659
0
        return NULL;
28660
4
    cname = JS_AtomToCString(ctx, module_name1);
28661
4
    if (!cname) {
28662
0
        JS_FreeCString(ctx, base_cname);
28663
0
        return NULL;
28664
0
    }
28665
4
    m = js_host_resolve_imported_module(ctx, base_cname, cname, attributes);
28666
4
    JS_FreeCString(ctx, base_cname);
28667
4
    JS_FreeCString(ctx, cname);
28668
4
    return m;
28669
4
}
28670
28671
typedef struct JSResolveEntry {
28672
    JSModuleDef *module;
28673
    JSAtom name;
28674
} JSResolveEntry;
28675
28676
typedef struct JSResolveState {
28677
    JSResolveEntry *array;
28678
    int size;
28679
    int count;
28680
} JSResolveState;
28681
28682
static int find_resolve_entry(JSResolveState *s,
28683
                              JSModuleDef *m, JSAtom name)
28684
0
{
28685
0
    int i;
28686
0
    for(i = 0; i < s->count; i++) {
28687
0
        JSResolveEntry *re = &s->array[i];
28688
0
        if (re->module == m && re->name == name)
28689
0
            return i;
28690
0
    }
28691
0
    return -1;
28692
0
}
28693
28694
static int add_resolve_entry(JSContext *ctx, JSResolveState *s,
28695
                             JSModuleDef *m, JSAtom name)
28696
0
{
28697
0
    JSResolveEntry *re;
28698
28699
0
    if (js_resize_array(ctx, (void **)&s->array,
28700
0
                        sizeof(JSResolveEntry),
28701
0
                        &s->size, s->count + 1))
28702
0
        return -1;
28703
0
    re = &s->array[s->count++];
28704
0
    re->module = m;
28705
0
    re->name = JS_DupAtom(ctx, name);
28706
0
    return 0;
28707
0
}
28708
28709
typedef enum JSResolveResultEnum {
28710
    JS_RESOLVE_RES_EXCEPTION = -1, /* memory alloc error */
28711
    JS_RESOLVE_RES_FOUND = 0,
28712
    JS_RESOLVE_RES_NOT_FOUND,
28713
    JS_RESOLVE_RES_CIRCULAR,
28714
    JS_RESOLVE_RES_AMBIGUOUS,
28715
} JSResolveResultEnum;
28716
28717
static JSResolveResultEnum js_resolve_export1(JSContext *ctx,
28718
                                              JSModuleDef **pmodule,
28719
                                              JSExportEntry **pme,
28720
                                              JSModuleDef *m,
28721
                                              JSAtom export_name,
28722
                                              JSResolveState *s)
28723
0
{
28724
0
    JSExportEntry *me;
28725
28726
0
    *pmodule = NULL;
28727
0
    *pme = NULL;
28728
0
    if (find_resolve_entry(s, m, export_name) >= 0)
28729
0
        return JS_RESOLVE_RES_CIRCULAR;
28730
0
    if (add_resolve_entry(ctx, s, m, export_name) < 0)
28731
0
        return JS_RESOLVE_RES_EXCEPTION;
28732
0
    me = find_export_entry(ctx, m, export_name);
28733
0
    if (me) {
28734
0
        if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
28735
            /* local export */
28736
0
            *pmodule = m;
28737
0
            *pme = me;
28738
0
            return JS_RESOLVE_RES_FOUND;
28739
0
        } else {
28740
            /* indirect export */
28741
0
            JSModuleDef *m1;
28742
0
            m1 = m->req_module_entries[me->u.req_module_idx].module;
28743
0
            if (me->local_name == JS_ATOM__star_) {
28744
                /* export ns from */
28745
0
                *pmodule = m;
28746
0
                *pme = me;
28747
0
                return JS_RESOLVE_RES_FOUND;
28748
0
            } else {
28749
0
                return js_resolve_export1(ctx, pmodule, pme, m1,
28750
0
                                          me->local_name, s);
28751
0
            }
28752
0
        }
28753
0
    } else {
28754
0
        if (export_name != JS_ATOM_default) {
28755
            /* not found in direct or indirect exports: try star exports */
28756
0
            int i;
28757
28758
0
            for(i = 0; i < m->star_export_entries_count; i++) {
28759
0
                JSStarExportEntry *se = &m->star_export_entries[i];
28760
0
                JSModuleDef *m1, *res_m;
28761
0
                JSExportEntry *res_me;
28762
0
                JSResolveResultEnum ret;
28763
28764
0
                m1 = m->req_module_entries[se->req_module_idx].module;
28765
0
                ret = js_resolve_export1(ctx, &res_m, &res_me, m1,
28766
0
                                         export_name, s);
28767
0
                if (ret == JS_RESOLVE_RES_AMBIGUOUS ||
28768
0
                    ret == JS_RESOLVE_RES_EXCEPTION) {
28769
0
                    return ret;
28770
0
                } else if (ret == JS_RESOLVE_RES_FOUND) {
28771
0
                    if (*pme != NULL) {
28772
0
                        if (*pmodule != res_m ||
28773
0
                            res_me->local_name != (*pme)->local_name) {
28774
0
                            *pmodule = NULL;
28775
0
                            *pme = NULL;
28776
0
                            return JS_RESOLVE_RES_AMBIGUOUS;
28777
0
                        }
28778
0
                    } else {
28779
0
                        *pmodule = res_m;
28780
0
                        *pme = res_me;
28781
0
                    }
28782
0
                }
28783
0
            }
28784
0
            if (*pme != NULL)
28785
0
                return JS_RESOLVE_RES_FOUND;
28786
0
        }
28787
0
        return JS_RESOLVE_RES_NOT_FOUND;
28788
0
    }
28789
0
}
28790
28791
/* If the return value is JS_RESOLVE_RES_FOUND, return the module
28792
  (*pmodule) and the corresponding local export entry
28793
  (*pme). Otherwise return (NULL, NULL) */
28794
static JSResolveResultEnum js_resolve_export(JSContext *ctx,
28795
                                             JSModuleDef **pmodule,
28796
                                             JSExportEntry **pme,
28797
                                             JSModuleDef *m,
28798
                                             JSAtom export_name)
28799
0
{
28800
0
    JSResolveState ss, *s = &ss;
28801
0
    int i;
28802
0
    JSResolveResultEnum ret;
28803
28804
0
    s->array = NULL;
28805
0
    s->size = 0;
28806
0
    s->count = 0;
28807
28808
0
    ret = js_resolve_export1(ctx, pmodule, pme, m, export_name, s);
28809
28810
0
    for(i = 0; i < s->count; i++)
28811
0
        JS_FreeAtom(ctx, s->array[i].name);
28812
0
    js_free(ctx, s->array);
28813
28814
0
    return ret;
28815
0
}
28816
28817
static void js_resolve_export_throw_error(JSContext *ctx,
28818
                                          JSResolveResultEnum res,
28819
                                          JSModuleDef *m, JSAtom export_name)
28820
0
{
28821
0
    char buf1[ATOM_GET_STR_BUF_SIZE];
28822
0
    char buf2[ATOM_GET_STR_BUF_SIZE];
28823
0
    switch(res) {
28824
0
    case JS_RESOLVE_RES_EXCEPTION:
28825
0
        break;
28826
0
    default:
28827
0
    case JS_RESOLVE_RES_NOT_FOUND:
28828
0
        JS_ThrowSyntaxError(ctx, "Could not find export '%s' in module '%s'",
28829
0
                            JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
28830
0
                            JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
28831
0
        break;
28832
0
    case JS_RESOLVE_RES_CIRCULAR:
28833
0
        JS_ThrowSyntaxError(ctx, "circular reference when looking for export '%s' in module '%s'",
28834
0
                            JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
28835
0
                            JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
28836
0
        break;
28837
0
    case JS_RESOLVE_RES_AMBIGUOUS:
28838
0
        JS_ThrowSyntaxError(ctx, "export '%s' in module '%s' is ambiguous",
28839
0
                            JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
28840
0
                            JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
28841
0
        break;
28842
0
    }
28843
0
}
28844
28845
28846
typedef enum {
28847
    EXPORTED_NAME_AMBIGUOUS,
28848
    EXPORTED_NAME_NORMAL,
28849
    EXPORTED_NAME_DELAYED,
28850
} ExportedNameEntryEnum;
28851
28852
typedef struct ExportedNameEntry {
28853
    JSAtom export_name;
28854
    ExportedNameEntryEnum export_type;
28855
    union {
28856
        JSExportEntry *me; /* using when the list is built */
28857
        JSVarRef *var_ref; /* EXPORTED_NAME_NORMAL */
28858
    } u;
28859
} ExportedNameEntry;
28860
28861
typedef struct GetExportNamesState {
28862
    JSModuleDef **modules;
28863
    int modules_size;
28864
    int modules_count;
28865
28866
    ExportedNameEntry *exported_names;
28867
    int exported_names_size;
28868
    int exported_names_count;
28869
} GetExportNamesState;
28870
28871
static int find_exported_name(GetExportNamesState *s, JSAtom name)
28872
196
{
28873
196
    int i;
28874
5.86k
    for(i = 0; i < s->exported_names_count; i++) {
28875
5.67k
        if (s->exported_names[i].export_name == name)
28876
0
            return i;
28877
5.67k
    }
28878
196
    return -1;
28879
196
}
28880
28881
static __exception int get_exported_names(JSContext *ctx,
28882
                                          GetExportNamesState *s,
28883
                                          JSModuleDef *m, BOOL from_star)
28884
4
{
28885
4
    ExportedNameEntry *en;
28886
4
    int i, j;
28887
28888
    /* check circular reference */
28889
4
    for(i = 0; i < s->modules_count; i++) {
28890
0
        if (s->modules[i] == m)
28891
0
            return 0;
28892
0
    }
28893
4
    if (js_resize_array(ctx, (void **)&s->modules, sizeof(s->modules[0]),
28894
4
                        &s->modules_size, s->modules_count + 1))
28895
0
        return -1;
28896
4
    s->modules[s->modules_count++] = m;
28897
28898
200
    for(i = 0; i < m->export_entries_count; i++) {
28899
196
        JSExportEntry *me = &m->export_entries[i];
28900
196
        if (from_star && me->export_name == JS_ATOM_default)
28901
0
            continue;
28902
196
        j = find_exported_name(s, me->export_name);
28903
196
        if (j < 0) {
28904
196
            if (js_resize_array(ctx, (void **)&s->exported_names, sizeof(s->exported_names[0]),
28905
196
                                &s->exported_names_size,
28906
196
                                s->exported_names_count + 1))
28907
0
                return -1;
28908
196
            en = &s->exported_names[s->exported_names_count++];
28909
196
            en->export_name = me->export_name;
28910
            /* avoid a second lookup for simple module exports */
28911
196
            if (from_star || me->export_type != JS_EXPORT_TYPE_LOCAL)
28912
0
                en->u.me = NULL;
28913
196
            else
28914
196
                en->u.me = me;
28915
196
        } else {
28916
0
            en = &s->exported_names[j];
28917
0
            en->u.me = NULL;
28918
0
        }
28919
196
    }
28920
4
    for(i = 0; i < m->star_export_entries_count; i++) {
28921
0
        JSStarExportEntry *se = &m->star_export_entries[i];
28922
0
        JSModuleDef *m1;
28923
0
        m1 = m->req_module_entries[se->req_module_idx].module;
28924
0
        if (get_exported_names(ctx, s, m1, TRUE))
28925
0
            return -1;
28926
0
    }
28927
4
    return 0;
28928
4
}
28929
28930
/* Unfortunately, the spec gives a different behavior from GetOwnProperty ! */
28931
static int js_module_ns_has(JSContext *ctx, JSValueConst obj, JSAtom atom)
28932
0
{
28933
0
    return (find_own_property1(JS_VALUE_GET_OBJ(obj), atom) != NULL);
28934
0
}
28935
28936
static const JSClassExoticMethods js_module_ns_exotic_methods = {
28937
    .has_property = js_module_ns_has,
28938
};
28939
28940
static int exported_names_cmp(const void *p1, const void *p2, void *opaque)
28941
972
{
28942
972
    JSContext *ctx = opaque;
28943
972
    const ExportedNameEntry *me1 = p1;
28944
972
    const ExportedNameEntry *me2 = p2;
28945
972
    JSValue str1, str2;
28946
972
    int ret;
28947
28948
    /* XXX: should avoid allocation memory in atom comparison */
28949
972
    str1 = JS_AtomToString(ctx, me1->export_name);
28950
972
    str2 = JS_AtomToString(ctx, me2->export_name);
28951
972
    if (JS_IsException(str1) || JS_IsException(str2)) {
28952
        /* XXX: raise an error ? */
28953
0
        ret = 0;
28954
972
    } else {
28955
972
        ret = js_string_compare(ctx, JS_VALUE_GET_STRING(str1),
28956
972
                                JS_VALUE_GET_STRING(str2));
28957
972
    }
28958
972
    JS_FreeValue(ctx, str1);
28959
972
    JS_FreeValue(ctx, str2);
28960
972
    return ret;
28961
972
}
28962
28963
static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
28964
                                     void *opaque)
28965
0
{
28966
0
    JSModuleDef *m = opaque;
28967
0
    JSResolveResultEnum res;
28968
0
    JSExportEntry *res_me;
28969
0
    JSModuleDef *res_m;
28970
0
    JSVarRef *var_ref;
28971
28972
0
    res = js_resolve_export(ctx, &res_m, &res_me, m, atom);
28973
0
    if (res != JS_RESOLVE_RES_FOUND) {
28974
        /* fail safe: normally no error should happen here except for memory */
28975
0
        js_resolve_export_throw_error(ctx, res, m, atom);
28976
0
        return JS_EXCEPTION;
28977
0
    }
28978
0
    if (res_me->local_name == JS_ATOM__star_) {
28979
0
        return JS_GetModuleNamespace(ctx, res_m->req_module_entries[res_me->u.req_module_idx].module);
28980
0
    } else {
28981
0
        if (res_me->u.local.var_ref) {
28982
0
            var_ref = res_me->u.local.var_ref;
28983
0
        } else {
28984
0
            JSObject *p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
28985
0
            var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];
28986
0
        }
28987
        /* WARNING: a varref is returned as a string ! */
28988
0
        return JS_MKPTR(JS_TAG_STRING, var_ref);
28989
0
    }
28990
0
}
28991
28992
static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m)
28993
4
{
28994
4
    JSValue obj;
28995
4
    JSObject *p;
28996
4
    GetExportNamesState s_s, *s = &s_s;
28997
4
    int i, ret;
28998
4
    JSProperty *pr;
28999
29000
4
    obj = JS_NewObjectClass(ctx, JS_CLASS_MODULE_NS);
29001
4
    if (JS_IsException(obj))
29002
0
        return obj;
29003
4
    p = JS_VALUE_GET_OBJ(obj);
29004
29005
4
    memset(s, 0, sizeof(*s));
29006
4
    ret = get_exported_names(ctx, s, m, FALSE);
29007
4
    js_free(ctx, s->modules);
29008
4
    if (ret)
29009
0
        goto fail;
29010
29011
    /* Resolve the exported names. The ambiguous exports are removed */
29012
200
    for(i = 0; i < s->exported_names_count; i++) {
29013
196
        ExportedNameEntry *en = &s->exported_names[i];
29014
196
        JSResolveResultEnum res;
29015
196
        JSExportEntry *res_me;
29016
196
        JSModuleDef *res_m;
29017
29018
196
        if (en->u.me) {
29019
196
            res_me = en->u.me; /* fast case: no resolution needed */
29020
196
            res_m = m;
29021
196
            res = JS_RESOLVE_RES_FOUND;
29022
196
        } else {
29023
0
            res = js_resolve_export(ctx, &res_m, &res_me, m,
29024
0
                                    en->export_name);
29025
0
        }
29026
196
        if (res != JS_RESOLVE_RES_FOUND) {
29027
0
            if (res != JS_RESOLVE_RES_AMBIGUOUS) {
29028
0
                js_resolve_export_throw_error(ctx, res, m, en->export_name);
29029
0
                goto fail;
29030
0
            }
29031
0
            en->export_type = EXPORTED_NAME_AMBIGUOUS;
29032
196
        } else {
29033
196
            if (res_me->local_name == JS_ATOM__star_) {
29034
0
                en->export_type = EXPORTED_NAME_DELAYED;
29035
196
            } else {
29036
196
                if (res_me->u.local.var_ref) {
29037
196
                    en->u.var_ref = res_me->u.local.var_ref;
29038
196
                } else {
29039
0
                    JSObject *p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
29040
0
                    en->u.var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];
29041
0
                }
29042
196
                if (en->u.var_ref == NULL)
29043
0
                    en->export_type = EXPORTED_NAME_DELAYED;
29044
196
                else
29045
196
                    en->export_type = EXPORTED_NAME_NORMAL;
29046
196
            }
29047
196
        }
29048
196
    }
29049
29050
    /* sort the exported names */
29051
4
    rqsort(s->exported_names, s->exported_names_count,
29052
4
           sizeof(s->exported_names[0]), exported_names_cmp, ctx);
29053
29054
200
    for(i = 0; i < s->exported_names_count; i++) {
29055
196
        ExportedNameEntry *en = &s->exported_names[i];
29056
196
        switch(en->export_type) {
29057
196
        case EXPORTED_NAME_NORMAL:
29058
196
            {
29059
196
                JSVarRef *var_ref = en->u.var_ref;
29060
196
                pr = add_property(ctx, p, en->export_name,
29061
196
                                  JS_PROP_ENUMERABLE | JS_PROP_WRITABLE |
29062
196
                                  JS_PROP_VARREF);
29063
196
                if (!pr)
29064
0
                    goto fail;
29065
196
                var_ref->header.ref_count++;
29066
196
                pr->u.var_ref = var_ref;
29067
196
            }
29068
0
            break;
29069
0
        case EXPORTED_NAME_DELAYED:
29070
            /* the exported namespace or reference may depend on
29071
               circular references, so we resolve it lazily */
29072
0
            if (JS_DefineAutoInitProperty(ctx, obj,
29073
0
                                          en->export_name,
29074
0
                                          JS_AUTOINIT_ID_MODULE_NS,
29075
0
                                          m, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
29076
0
            break;
29077
0
        default:
29078
0
            break;
29079
196
        }
29080
196
    }
29081
29082
4
    js_free(ctx, s->exported_names);
29083
29084
4
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_Symbol_toStringTag,
29085
4
                           JS_AtomToString(ctx, JS_ATOM_Module),
29086
4
                           0);
29087
29088
4
    p->extensible = FALSE;
29089
4
    return obj;
29090
0
 fail:
29091
0
    js_free(ctx, s->exported_names);
29092
0
    JS_FreeValue(ctx, obj);
29093
0
    return JS_EXCEPTION;
29094
4
}
29095
29096
JSValue JS_GetModuleNamespace(JSContext *ctx, JSModuleDef *m)
29097
4
{
29098
4
    if (JS_IsUndefined(m->module_ns)) {
29099
4
        JSValue val;
29100
4
        val = js_build_module_ns(ctx, m);
29101
4
        if (JS_IsException(val))
29102
0
            return JS_EXCEPTION;
29103
4
        m->module_ns = val;
29104
4
    }
29105
4
    return JS_DupValue(ctx, m->module_ns);
29106
4
}
29107
29108
/* Load all the required modules for module 'm' */
29109
static int js_resolve_module(JSContext *ctx, JSModuleDef *m)
29110
8
{
29111
8
    int i;
29112
8
    JSModuleDef *m1;
29113
29114
8
    if (m->resolved)
29115
0
        return 0;
29116
#ifdef DUMP_MODULE_RESOLVE
29117
    {
29118
        char buf1[ATOM_GET_STR_BUF_SIZE];
29119
        printf("resolving module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
29120
    }
29121
#endif
29122
8
    m->resolved = TRUE;
29123
    /* resolve each requested module */
29124
12
    for(i = 0; i < m->req_module_entries_count; i++) {
29125
4
        JSReqModuleEntry *rme = &m->req_module_entries[i];
29126
4
        m1 = js_host_resolve_imported_module_atom(ctx, m->module_name,
29127
4
                                                  rme->module_name,
29128
4
                                                  rme->attributes);
29129
4
        if (!m1)
29130
0
            return -1;
29131
4
        rme->module = m1;
29132
        /* already done in js_host_resolve_imported_module() except if
29133
           the module was loaded with JS_EvalBinary() */
29134
4
        if (js_resolve_module(ctx, m1) < 0)
29135
0
            return -1;
29136
4
    }
29137
8
    return 0;
29138
8
}
29139
29140
static JSVarRef *js_create_module_var(JSContext *ctx, BOOL is_lexical)
29141
200
{
29142
200
    JSVarRef *var_ref;
29143
200
    var_ref = js_malloc(ctx, sizeof(JSVarRef));
29144
200
    if (!var_ref)
29145
0
        return NULL;
29146
200
    var_ref->header.ref_count = 1;
29147
200
    if (is_lexical)
29148
4
        var_ref->value = JS_UNINITIALIZED;
29149
196
    else
29150
196
        var_ref->value = JS_UNDEFINED;
29151
200
    var_ref->pvalue = &var_ref->value;
29152
200
    var_ref->is_detached = TRUE;
29153
200
    add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);
29154
200
    return var_ref;
29155
200
}
29156
29157
/* Create the <eval> function associated with the module */
29158
static int js_create_module_bytecode_function(JSContext *ctx, JSModuleDef *m)
29159
3
{
29160
3
    JSFunctionBytecode *b;
29161
3
    int i;
29162
3
    JSVarRef **var_refs;
29163
3
    JSValue func_obj, bfunc;
29164
3
    JSObject *p;
29165
29166
3
    bfunc = m->func_obj;
29167
3
    func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
29168
3
                                      JS_CLASS_BYTECODE_FUNCTION);
29169
29170
3
    if (JS_IsException(func_obj))
29171
0
        return -1;
29172
3
    b = JS_VALUE_GET_PTR(bfunc);
29173
29174
3
    p = JS_VALUE_GET_OBJ(func_obj);
29175
3
    p->u.func.function_bytecode = b;
29176
3
    b->header.ref_count++;
29177
3
    p->u.func.home_object = NULL;
29178
3
    p->u.func.var_refs = NULL;
29179
3
    if (b->closure_var_count) {
29180
2
        var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count);
29181
2
        if (!var_refs)
29182
0
            goto fail;
29183
2
        p->u.func.var_refs = var_refs;
29184
29185
        /* create the global variables. The other variables are
29186
           imported from other modules */
29187
6
        for(i = 0; i < b->closure_var_count; i++) {
29188
4
            JSClosureVar *cv = &b->closure_var[i];
29189
4
            JSVarRef *var_ref;
29190
4
            if (cv->is_local) {
29191
4
                var_ref = js_create_module_var(ctx, cv->is_lexical);
29192
4
                if (!var_ref)
29193
0
                    goto fail;
29194
#ifdef DUMP_MODULE_RESOLVE
29195
                printf("local %d: %p\n", i, var_ref);
29196
#endif
29197
4
                var_refs[i] = var_ref;
29198
4
            }
29199
4
        }
29200
2
    }
29201
3
    m->func_obj = func_obj;
29202
3
    JS_FreeValue(ctx, bfunc);
29203
3
    return 0;
29204
0
 fail:
29205
0
    JS_FreeValue(ctx, func_obj);
29206
0
    return -1;
29207
3
}
29208
29209
/* must be done before js_link_module() because of cyclic references */
29210
static int js_create_module_function(JSContext *ctx, JSModuleDef *m)
29211
7
{
29212
7
    BOOL is_c_module;
29213
7
    int i;
29214
7
    JSVarRef *var_ref;
29215
29216
7
    if (m->func_created)
29217
0
        return 0;
29218
29219
7
    is_c_module = (m->init_func != NULL);
29220
29221
7
    if (is_c_module) {
29222
        /* initialize the exported variables */
29223
200
        for(i = 0; i < m->export_entries_count; i++) {
29224
196
            JSExportEntry *me = &m->export_entries[i];
29225
196
            if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
29226
196
                var_ref = js_create_module_var(ctx, FALSE);
29227
196
                if (!var_ref)
29228
0
                    return -1;
29229
196
                me->u.local.var_ref = var_ref;
29230
196
            }
29231
196
        }
29232
4
    } else {
29233
3
        if (js_create_module_bytecode_function(ctx, m))
29234
0
            return -1;
29235
3
    }
29236
7
    m->func_created = TRUE;
29237
29238
    /* do it on the dependencies */
29239
29240
11
    for(i = 0; i < m->req_module_entries_count; i++) {
29241
4
        JSReqModuleEntry *rme = &m->req_module_entries[i];
29242
4
        if (js_create_module_function(ctx, rme->module) < 0)
29243
0
            return -1;
29244
4
    }
29245
29246
7
    return 0;
29247
7
}
29248
29249
29250
/* Prepare a module to be executed by resolving all the imported
29251
   variables. */
29252
static int js_inner_module_linking(JSContext *ctx, JSModuleDef *m,
29253
                                   JSModuleDef **pstack_top, int index)
29254
7
{
29255
7
    int i;
29256
7
    JSImportEntry *mi;
29257
7
    JSModuleDef *m1;
29258
7
    JSVarRef **var_refs, *var_ref;
29259
7
    JSObject *p;
29260
7
    BOOL is_c_module;
29261
7
    JSValue ret_val;
29262
29263
7
    if (js_check_stack_overflow(ctx->rt, 0)) {
29264
0
        JS_ThrowStackOverflow(ctx);
29265
0
        return -1;
29266
0
    }
29267
29268
#ifdef DUMP_MODULE_RESOLVE
29269
    {
29270
        char buf1[ATOM_GET_STR_BUF_SIZE];
29271
        printf("js_inner_module_linking '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
29272
    }
29273
#endif
29274
29275
7
    if (m->status == JS_MODULE_STATUS_LINKING ||
29276
7
        m->status == JS_MODULE_STATUS_LINKED ||
29277
7
        m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
29278
7
        m->status == JS_MODULE_STATUS_EVALUATED)
29279
0
        return index;
29280
29281
7
    assert(m->status == JS_MODULE_STATUS_UNLINKED);
29282
7
    m->status = JS_MODULE_STATUS_LINKING;
29283
7
    m->dfs_index = index;
29284
7
    m->dfs_ancestor_index = index;
29285
7
    index++;
29286
    /* push 'm' on stack */
29287
7
    m->stack_prev = *pstack_top;
29288
7
    *pstack_top = m;
29289
29290
11
    for(i = 0; i < m->req_module_entries_count; i++) {
29291
4
        JSReqModuleEntry *rme = &m->req_module_entries[i];
29292
4
        m1 = rme->module;
29293
4
        index = js_inner_module_linking(ctx, m1, pstack_top, index);
29294
4
        if (index < 0)
29295
0
            goto fail;
29296
4
        assert(m1->status == JS_MODULE_STATUS_LINKING ||
29297
4
               m1->status == JS_MODULE_STATUS_LINKED ||
29298
4
               m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
29299
4
               m1->status == JS_MODULE_STATUS_EVALUATED);
29300
4
        if (m1->status == JS_MODULE_STATUS_LINKING) {
29301
0
            m->dfs_ancestor_index = min_int(m->dfs_ancestor_index,
29302
0
                                            m1->dfs_ancestor_index);
29303
0
        }
29304
4
    }
29305
29306
#ifdef DUMP_MODULE_RESOLVE
29307
    {
29308
        char buf1[ATOM_GET_STR_BUF_SIZE];
29309
        printf("instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
29310
    }
29311
#endif
29312
    /* check the indirect exports */
29313
203
    for(i = 0; i < m->export_entries_count; i++) {
29314
196
        JSExportEntry *me = &m->export_entries[i];
29315
196
        if (me->export_type == JS_EXPORT_TYPE_INDIRECT &&
29316
196
            me->local_name != JS_ATOM__star_) {
29317
0
            JSResolveResultEnum ret;
29318
0
            JSExportEntry *res_me;
29319
0
            JSModuleDef *res_m, *m1;
29320
0
            m1 = m->req_module_entries[me->u.req_module_idx].module;
29321
0
            ret = js_resolve_export(ctx, &res_m, &res_me, m1, me->local_name);
29322
0
            if (ret != JS_RESOLVE_RES_FOUND) {
29323
0
                js_resolve_export_throw_error(ctx, ret, m, me->export_name);
29324
0
                goto fail;
29325
0
            }
29326
0
        }
29327
196
    }
29328
29329
#ifdef DUMP_MODULE_RESOLVE
29330
    {
29331
        printf("exported bindings:\n");
29332
        for(i = 0; i < m->export_entries_count; i++) {
29333
            JSExportEntry *me = &m->export_entries[i];
29334
            printf(" name="); print_atom(ctx, me->export_name);
29335
            printf(" local="); print_atom(ctx, me->local_name);
29336
            printf(" type=%d idx=%d\n", me->export_type, me->u.local.var_idx);
29337
        }
29338
    }
29339
#endif
29340
29341
7
    is_c_module = (m->init_func != NULL);
29342
29343
7
    if (!is_c_module) {
29344
3
        p = JS_VALUE_GET_OBJ(m->func_obj);
29345
3
        var_refs = p->u.func.var_refs;
29346
29347
7
        for(i = 0; i < m->import_entries_count; i++) {
29348
4
            mi = &m->import_entries[i];
29349
#ifdef DUMP_MODULE_RESOLVE
29350
            printf("import var_idx=%d name=", mi->var_idx);
29351
            print_atom(ctx, mi->import_name);
29352
            printf(": ");
29353
#endif
29354
4
            m1 = m->req_module_entries[mi->req_module_idx].module;
29355
4
            if (mi->is_star) {
29356
4
                JSValue val;
29357
                /* name space import */
29358
4
                val = JS_GetModuleNamespace(ctx, m1);
29359
4
                if (JS_IsException(val))
29360
0
                    goto fail;
29361
4
                set_value(ctx, &var_refs[mi->var_idx]->value, val);
29362
#ifdef DUMP_MODULE_RESOLVE
29363
                printf("namespace\n");
29364
#endif
29365
4
            } else {
29366
0
                JSResolveResultEnum ret;
29367
0
                JSExportEntry *res_me;
29368
0
                JSModuleDef *res_m;
29369
0
                JSObject *p1;
29370
29371
0
                ret = js_resolve_export(ctx, &res_m,
29372
0
                                        &res_me, m1, mi->import_name);
29373
0
                if (ret != JS_RESOLVE_RES_FOUND) {
29374
0
                    js_resolve_export_throw_error(ctx, ret, m1, mi->import_name);
29375
0
                    goto fail;
29376
0
                }
29377
0
                if (res_me->local_name == JS_ATOM__star_) {
29378
0
                    JSValue val;
29379
0
                    JSModuleDef *m2;
29380
                    /* name space import from */
29381
0
                    m2 = res_m->req_module_entries[res_me->u.req_module_idx].module;
29382
0
                    val = JS_GetModuleNamespace(ctx, m2);
29383
0
                    if (JS_IsException(val))
29384
0
                        goto fail;
29385
0
                    var_ref = js_create_module_var(ctx, TRUE);
29386
0
                    if (!var_ref) {
29387
0
                        JS_FreeValue(ctx, val);
29388
0
                        goto fail;
29389
0
                    }
29390
0
                    set_value(ctx, &var_ref->value, val);
29391
0
                    var_refs[mi->var_idx] = var_ref;
29392
#ifdef DUMP_MODULE_RESOLVE
29393
                    printf("namespace from\n");
29394
#endif
29395
0
                } else {
29396
0
                    var_ref = res_me->u.local.var_ref;
29397
0
                    if (!var_ref) {
29398
0
                        p1 = JS_VALUE_GET_OBJ(res_m->func_obj);
29399
0
                        var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];
29400
0
                    }
29401
0
                    var_ref->header.ref_count++;
29402
0
                    var_refs[mi->var_idx] = var_ref;
29403
#ifdef DUMP_MODULE_RESOLVE
29404
                    printf("local export (var_ref=%p)\n", var_ref);
29405
#endif
29406
0
                }
29407
0
            }
29408
4
        }
29409
29410
        /* keep the exported variables in the module export entries (they
29411
           are used when the eval function is deleted and cannot be
29412
           initialized before in case imports are exported) */
29413
3
        for(i = 0; i < m->export_entries_count; i++) {
29414
0
            JSExportEntry *me = &m->export_entries[i];
29415
0
            if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
29416
0
                var_ref = var_refs[me->u.local.var_idx];
29417
0
                var_ref->header.ref_count++;
29418
0
                me->u.local.var_ref = var_ref;
29419
0
            }
29420
0
        }
29421
29422
        /* initialize the global variables */
29423
3
        ret_val = JS_Call(ctx, m->func_obj, JS_TRUE, 0, NULL);
29424
3
        if (JS_IsException(ret_val))
29425
0
            goto fail;
29426
3
        JS_FreeValue(ctx, ret_val);
29427
3
    }
29428
29429
7
    assert(m->dfs_ancestor_index <= m->dfs_index);
29430
7
    if (m->dfs_index == m->dfs_ancestor_index) {
29431
7
        for(;;) {
29432
            /* pop m1 from stack */
29433
7
            m1 = *pstack_top;
29434
7
            *pstack_top = m1->stack_prev;
29435
7
            m1->status = JS_MODULE_STATUS_LINKED;
29436
7
            if (m1 == m)
29437
7
                break;
29438
7
        }
29439
7
    }
29440
29441
#ifdef DUMP_MODULE_RESOLVE
29442
    printf("js_inner_module_linking done\n");
29443
#endif
29444
7
    return index;
29445
0
 fail:
29446
0
    return -1;
29447
7
}
29448
29449
/* Prepare a module to be executed by resolving all the imported
29450
   variables. */
29451
static int js_link_module(JSContext *ctx, JSModuleDef *m)
29452
3
{
29453
3
    JSModuleDef *stack_top, *m1;
29454
29455
#ifdef DUMP_MODULE_RESOLVE
29456
    {
29457
        char buf1[ATOM_GET_STR_BUF_SIZE];
29458
        printf("js_link_module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
29459
    }
29460
#endif
29461
3
    assert(m->status == JS_MODULE_STATUS_UNLINKED ||
29462
3
           m->status == JS_MODULE_STATUS_LINKED ||
29463
3
           m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
29464
3
           m->status == JS_MODULE_STATUS_EVALUATED);
29465
3
    stack_top = NULL;
29466
3
    if (js_inner_module_linking(ctx, m, &stack_top, 0) < 0) {
29467
0
        while (stack_top != NULL) {
29468
0
            m1 = stack_top;
29469
0
            assert(m1->status == JS_MODULE_STATUS_LINKING);
29470
0
            m1->status = JS_MODULE_STATUS_UNLINKED;
29471
0
            stack_top = m1->stack_prev;
29472
0
        }
29473
0
        return -1;
29474
0
    }
29475
3
    assert(stack_top == NULL);
29476
3
    assert(m->status == JS_MODULE_STATUS_LINKED ||
29477
3
           m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
29478
3
           m->status == JS_MODULE_STATUS_EVALUATED);
29479
3
    return 0;
29480
3
}
29481
29482
/* return JS_ATOM_NULL if the name cannot be found. Only works with
29483
   not striped bytecode functions. */
29484
JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels)
29485
0
{
29486
0
    JSStackFrame *sf;
29487
0
    JSFunctionBytecode *b;
29488
0
    JSObject *p;
29489
    /* XXX: currently we just use the filename of the englobing
29490
       function from the debug info. May need to add a ScriptOrModule
29491
       info in JSFunctionBytecode. */
29492
0
    sf = ctx->rt->current_stack_frame;
29493
0
    if (!sf)
29494
0
        return JS_ATOM_NULL;
29495
0
    while (n_stack_levels-- > 0) {
29496
0
        sf = sf->prev_frame;
29497
0
        if (!sf)
29498
0
            return JS_ATOM_NULL;
29499
0
    }
29500
0
    for(;;) {
29501
0
        if (JS_VALUE_GET_TAG(sf->cur_func) != JS_TAG_OBJECT)
29502
0
            return JS_ATOM_NULL;
29503
0
        p = JS_VALUE_GET_OBJ(sf->cur_func);
29504
0
        if (!js_class_has_bytecode(p->class_id))
29505
0
            return JS_ATOM_NULL;
29506
0
        b = p->u.func.function_bytecode;
29507
0
        if (!b->is_direct_or_indirect_eval) {
29508
0
            if (!b->has_debug)
29509
0
                return JS_ATOM_NULL;
29510
0
            return JS_DupAtom(ctx, b->debug.filename);
29511
0
        } else {
29512
0
            sf = sf->prev_frame;
29513
0
            if (!sf)
29514
0
                return JS_ATOM_NULL;
29515
0
        }
29516
0
    }
29517
0
}
29518
29519
JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m)
29520
3
{
29521
3
    return JS_DupAtom(ctx, m->module_name);
29522
3
}
29523
29524
JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m)
29525
1
{
29526
1
    JSValue obj;
29527
    /* allocate meta_obj only if requested to save memory */
29528
1
    obj = m->meta_obj;
29529
1
    if (JS_IsUndefined(obj)) {
29530
1
        obj = JS_NewObjectProto(ctx, JS_NULL);
29531
1
        if (JS_IsException(obj))
29532
0
            return JS_EXCEPTION;
29533
1
        m->meta_obj = obj;
29534
1
    }
29535
1
    return JS_DupValue(ctx, obj);
29536
1
}
29537
29538
static JSValue js_import_meta(JSContext *ctx)
29539
0
{
29540
0
    JSAtom filename;
29541
0
    JSModuleDef *m;
29542
29543
0
    filename = JS_GetScriptOrModuleName(ctx, 0);
29544
0
    if (filename == JS_ATOM_NULL)
29545
0
        goto fail;
29546
29547
    /* XXX: inefficient, need to add a module or script pointer in
29548
       JSFunctionBytecode */
29549
0
    m = js_find_loaded_module(ctx, filename);
29550
0
    JS_FreeAtom(ctx, filename);
29551
0
    if (!m) {
29552
0
    fail:
29553
0
        JS_ThrowTypeError(ctx, "import.meta not supported in this context");
29554
0
        return JS_EXCEPTION;
29555
0
    }
29556
0
    return JS_GetImportMeta(ctx, m);
29557
0
}
29558
29559
static JSValue JS_NewModuleValue(JSContext *ctx, JSModuleDef *m)
29560
4
{
29561
4
    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
29562
4
}
29563
29564
static JSValue js_load_module_rejected(JSContext *ctx, JSValueConst this_val,
29565
                                       int argc, JSValueConst *argv, int magic, JSValue *func_data)
29566
0
{
29567
0
    JSValueConst *resolving_funcs = (JSValueConst *)func_data;
29568
0
    JSValueConst error;
29569
0
    JSValue ret;
29570
29571
    /* XXX: check if the test is necessary */
29572
0
    if (argc >= 1)
29573
0
        error = argv[0];
29574
0
    else
29575
0
        error = JS_UNDEFINED;
29576
0
    ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
29577
0
                  1, &error);
29578
0
    JS_FreeValue(ctx, ret);
29579
0
    return JS_UNDEFINED;
29580
0
}
29581
29582
static JSValue js_load_module_fulfilled(JSContext *ctx, JSValueConst this_val,
29583
                                        int argc, JSValueConst *argv, int magic, JSValue *func_data)
29584
0
{
29585
0
    JSValueConst *resolving_funcs = (JSValueConst *)func_data;
29586
0
    JSModuleDef *m = JS_VALUE_GET_PTR(func_data[2]);
29587
0
    JSValue ret, ns;
29588
29589
    /* return the module namespace */
29590
0
    ns = JS_GetModuleNamespace(ctx, m);
29591
0
    if (JS_IsException(ns)) {
29592
0
        JSValue err = JS_GetException(ctx);
29593
0
        js_load_module_rejected(ctx, JS_UNDEFINED, 1, (JSValueConst *)&err, 0, func_data);
29594
0
        return JS_UNDEFINED;
29595
0
    }
29596
0
    ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED,
29597
0
                   1, (JSValueConst *)&ns);
29598
0
    JS_FreeValue(ctx, ret);
29599
0
    JS_FreeValue(ctx, ns);
29600
0
    return JS_UNDEFINED;
29601
0
}
29602
29603
static void JS_LoadModuleInternal(JSContext *ctx, const char *basename,
29604
                                  const char *filename,
29605
                                  JSValueConst *resolving_funcs,
29606
                                  JSValueConst attributes)
29607
0
{
29608
0
    JSValue evaluate_promise;
29609
0
    JSModuleDef *m;
29610
0
    JSValue ret, err, func_obj, evaluate_resolving_funcs[2];
29611
0
    JSValueConst func_data[3];
29612
29613
0
    m = js_host_resolve_imported_module(ctx, basename, filename, attributes);
29614
0
    if (!m)
29615
0
        goto fail;
29616
29617
0
    if (js_resolve_module(ctx, m) < 0) {
29618
0
        js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);
29619
0
        goto fail;
29620
0
    }
29621
29622
    /* Evaluate the module code */
29623
0
    func_obj = JS_NewModuleValue(ctx, m);
29624
0
    evaluate_promise = JS_EvalFunction(ctx, func_obj);
29625
0
    if (JS_IsException(evaluate_promise)) {
29626
0
    fail:
29627
0
        err = JS_GetException(ctx);
29628
0
        ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
29629
0
                      1, (JSValueConst *)&err);
29630
0
        JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
29631
0
        JS_FreeValue(ctx, err);
29632
0
        return;
29633
0
    }
29634
29635
0
    func_obj = JS_NewModuleValue(ctx, m);
29636
0
    func_data[0] = resolving_funcs[0];
29637
0
    func_data[1] = resolving_funcs[1];
29638
0
    func_data[2] = func_obj;
29639
0
    evaluate_resolving_funcs[0] = JS_NewCFunctionData(ctx, js_load_module_fulfilled, 0, 0, 3, func_data);
29640
0
    evaluate_resolving_funcs[1] = JS_NewCFunctionData(ctx, js_load_module_rejected, 0, 0, 3, func_data);
29641
0
    JS_FreeValue(ctx, func_obj);
29642
0
    ret = js_promise_then(ctx, evaluate_promise, 2, (JSValueConst *)evaluate_resolving_funcs);
29643
0
    JS_FreeValue(ctx, ret);
29644
0
    JS_FreeValue(ctx, evaluate_resolving_funcs[0]);
29645
0
    JS_FreeValue(ctx, evaluate_resolving_funcs[1]);
29646
0
    JS_FreeValue(ctx, evaluate_promise);
29647
0
}
29648
29649
/* Return a promise or an exception in case of memory error. Used by
29650
   os.Worker() */
29651
JSValue JS_LoadModule(JSContext *ctx, const char *basename,
29652
                      const char *filename)
29653
0
{
29654
0
    JSValue promise, resolving_funcs[2];
29655
29656
0
    promise = JS_NewPromiseCapability(ctx, resolving_funcs);
29657
0
    if (JS_IsException(promise))
29658
0
        return JS_EXCEPTION;
29659
0
    JS_LoadModuleInternal(ctx, basename, filename,
29660
0
                          (JSValueConst *)resolving_funcs, JS_UNDEFINED);
29661
0
    JS_FreeValue(ctx, resolving_funcs[0]);
29662
0
    JS_FreeValue(ctx, resolving_funcs[1]);
29663
0
    return promise;
29664
0
}
29665
29666
static JSValue js_dynamic_import_job(JSContext *ctx,
29667
                                     int argc, JSValueConst *argv)
29668
0
{
29669
0
    JSValueConst *resolving_funcs = argv;
29670
0
    JSValueConst basename_val = argv[2];
29671
0
    JSValueConst specifier = argv[3];
29672
0
    JSValueConst attributes = argv[4];
29673
0
    const char *basename = NULL, *filename;
29674
0
    JSValue ret, err;
29675
29676
0
    if (!JS_IsString(basename_val)) {
29677
0
        JS_ThrowTypeError(ctx, "no function filename for import()");
29678
0
        goto exception;
29679
0
    }
29680
0
    basename = JS_ToCString(ctx, basename_val);
29681
0
    if (!basename)
29682
0
        goto exception;
29683
29684
0
    filename = JS_ToCString(ctx, specifier);
29685
0
    if (!filename)
29686
0
        goto exception;
29687
29688
0
    JS_LoadModuleInternal(ctx, basename, filename,
29689
0
                          resolving_funcs, attributes);
29690
0
    JS_FreeCString(ctx, filename);
29691
0
    JS_FreeCString(ctx, basename);
29692
0
    return JS_UNDEFINED;
29693
0
 exception:
29694
0
    err = JS_GetException(ctx);
29695
0
    ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
29696
0
                   1, (JSValueConst *)&err);
29697
0
    JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */
29698
0
    JS_FreeValue(ctx, err);
29699
0
    JS_FreeCString(ctx, basename);
29700
0
    return JS_UNDEFINED;
29701
0
}
29702
29703
static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier, JSValueConst options)
29704
0
{
29705
0
    JSAtom basename;
29706
0
    JSValue promise, resolving_funcs[2], basename_val, err, ret;
29707
0
    JSValue specifier_str = JS_UNDEFINED, attributes = JS_UNDEFINED, attributes_obj = JS_UNDEFINED;
29708
0
    JSValueConst args[5];
29709
29710
0
    basename = JS_GetScriptOrModuleName(ctx, 0);
29711
0
    if (basename == JS_ATOM_NULL)
29712
0
        basename_val = JS_NULL;
29713
0
    else
29714
0
        basename_val = JS_AtomToValue(ctx, basename);
29715
0
    JS_FreeAtom(ctx, basename);
29716
0
    if (JS_IsException(basename_val))
29717
0
        return basename_val;
29718
29719
0
    promise = JS_NewPromiseCapability(ctx, resolving_funcs);
29720
0
    if (JS_IsException(promise)) {
29721
0
        JS_FreeValue(ctx, basename_val);
29722
0
        return promise;
29723
0
    }
29724
29725
    /* the string conversion must occur here */
29726
0
    specifier_str = JS_ToString(ctx, specifier);
29727
0
    if (JS_IsException(specifier_str))
29728
0
        goto exception;
29729
    
29730
0
    if (!JS_IsUndefined(options)) {
29731
0
        if (!JS_IsObject(options)) {
29732
0
            JS_ThrowTypeError(ctx, "options must be an object");
29733
0
            goto exception;
29734
0
        }
29735
0
        attributes_obj = JS_GetProperty(ctx, options, JS_ATOM_with);
29736
0
        if (JS_IsException(attributes_obj))
29737
0
            goto exception;
29738
0
        if (!JS_IsUndefined(attributes_obj)) {
29739
0
            JSPropertyEnum *atoms;
29740
0
            uint32_t atoms_len, i;
29741
0
            JSValue val;
29742
            
29743
0
            if (!JS_IsObject(attributes_obj)) {
29744
0
                JS_ThrowTypeError(ctx, "options.with must be an object");
29745
0
                goto exception;
29746
0
            }
29747
0
            attributes = JS_NewObjectProto(ctx, JS_NULL);
29748
0
            if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &atoms_len, JS_VALUE_GET_OBJ(attributes_obj),
29749
0
                                               JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) {
29750
0
                goto exception;
29751
0
            }
29752
0
            for(i = 0; i < atoms_len; i++) {
29753
0
                val = JS_GetProperty(ctx, attributes_obj, atoms[i].atom);
29754
0
                if (JS_IsException(val))
29755
0
                    goto exception1;
29756
0
                if (!JS_IsString(val)) {
29757
0
                    JS_FreeValue(ctx, val);
29758
0
                    JS_ThrowTypeError(ctx, "module attribute values must be strings");
29759
0
                    goto exception1;
29760
0
                }
29761
0
                if (JS_DefinePropertyValue(ctx, attributes,  atoms[i].atom, val,
29762
0
                                           JS_PROP_C_W_E) < 0) {
29763
0
                exception1:
29764
0
                    JS_FreePropertyEnum(ctx, atoms, atoms_len);
29765
0
                    goto exception;
29766
0
                }
29767
0
            }
29768
0
            JS_FreePropertyEnum(ctx, atoms, atoms_len);
29769
0
            if (ctx->rt->module_check_attrs &&
29770
0
                ctx->rt->module_check_attrs(ctx, ctx->rt->module_loader_opaque, attributes) < 0) {
29771
0
                goto exception;
29772
0
            }
29773
0
            JS_FreeValue(ctx, attributes_obj);
29774
0
        }
29775
0
    }
29776
29777
0
    args[0] = resolving_funcs[0];
29778
0
    args[1] = resolving_funcs[1];
29779
0
    args[2] = basename_val;
29780
0
    args[3] = specifier_str;
29781
0
    args[4] = attributes;
29782
    
29783
    /* cannot run JS_LoadModuleInternal synchronously because it would
29784
       cause an unexpected recursion in js_evaluate_module() */
29785
0
    JS_EnqueueJob(ctx, js_dynamic_import_job, 5, args);
29786
0
 done:
29787
0
    JS_FreeValue(ctx, basename_val);
29788
0
    JS_FreeValue(ctx, resolving_funcs[0]);
29789
0
    JS_FreeValue(ctx, resolving_funcs[1]);
29790
0
    JS_FreeValue(ctx, specifier_str);
29791
0
    JS_FreeValue(ctx, attributes);
29792
0
    return promise;
29793
0
 exception:
29794
0
    JS_FreeValue(ctx, attributes_obj);
29795
0
    err = JS_GetException(ctx);
29796
0
    ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,
29797
0
                   1, (JSValueConst *)&err);
29798
0
    JS_FreeValue(ctx, ret);
29799
0
    JS_FreeValue(ctx, err);
29800
0
    goto done;
29801
0
}
29802
29803
static void js_set_module_evaluated(JSContext *ctx, JSModuleDef *m)
29804
0
{
29805
0
    m->status = JS_MODULE_STATUS_EVALUATED;
29806
0
    if (!JS_IsUndefined(m->promise)) {
29807
0
        JSValue value, ret_val;
29808
0
        assert(m->cycle_root == m);
29809
0
        value = JS_UNDEFINED;
29810
0
        ret_val = JS_Call(ctx, m->resolving_funcs[0], JS_UNDEFINED,
29811
0
                          1, (JSValueConst *)&value);
29812
0
        JS_FreeValue(ctx, ret_val);
29813
0
    }
29814
0
}
29815
29816
typedef struct {
29817
    JSModuleDef **tab;
29818
    int count;
29819
    int size;
29820
} ExecModuleList;
29821
29822
/* XXX: slow. Could use a linked list instead of ExecModuleList */
29823
static BOOL find_in_exec_module_list(ExecModuleList *exec_list, JSModuleDef *m)
29824
0
{
29825
0
    int i;
29826
0
    for(i = 0; i < exec_list->count; i++) {
29827
0
        if (exec_list->tab[i] == m)
29828
0
            return TRUE;
29829
0
    }
29830
0
    return FALSE;
29831
0
}
29832
29833
static int gather_available_ancestors(JSContext *ctx, JSModuleDef *module,
29834
                                      ExecModuleList *exec_list)
29835
0
{
29836
0
    int i;
29837
29838
0
    if (js_check_stack_overflow(ctx->rt, 0)) {
29839
0
        JS_ThrowStackOverflow(ctx);
29840
0
        return -1;
29841
0
    }
29842
0
    for(i = 0; i < module->async_parent_modules_count; i++) {
29843
0
        JSModuleDef *m = module->async_parent_modules[i];
29844
0
        if (!find_in_exec_module_list(exec_list, m) &&
29845
0
            !m->cycle_root->eval_has_exception) {
29846
0
            assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC);
29847
0
            assert(!m->eval_has_exception);
29848
0
            assert(m->async_evaluation);
29849
0
            assert(m->pending_async_dependencies > 0);
29850
0
            m->pending_async_dependencies--;
29851
0
            if (m->pending_async_dependencies == 0) {
29852
0
                if (js_resize_array(ctx, (void **)&exec_list->tab, sizeof(exec_list->tab[0]), &exec_list->size, exec_list->count + 1)) {
29853
0
                    return -1;
29854
0
                }
29855
0
                exec_list->tab[exec_list->count++] = m;
29856
0
                if (!m->has_tla) {
29857
0
                    if (gather_available_ancestors(ctx, m, exec_list))
29858
0
                        return -1;
29859
0
                }
29860
0
            }
29861
0
        }
29862
0
    }
29863
0
    return 0;
29864
0
}
29865
29866
static int exec_module_list_cmp(const void *p1, const void *p2, void *opaque)
29867
0
{
29868
0
    JSModuleDef *m1 = *(JSModuleDef **)p1;
29869
0
    JSModuleDef *m2 = *(JSModuleDef **)p2;
29870
0
    return (m1->async_evaluation_timestamp > m2->async_evaluation_timestamp) -
29871
0
        (m1->async_evaluation_timestamp < m2->async_evaluation_timestamp);
29872
0
}
29873
29874
static int js_execute_async_module(JSContext *ctx, JSModuleDef *m);
29875
static int js_execute_sync_module(JSContext *ctx, JSModuleDef *m,
29876
                                  JSValue *pvalue);
29877
#ifdef DUMP_MODULE_EXEC
29878
static void js_dump_module(JSContext *ctx, const char *str, JSModuleDef *m)
29879
{
29880
    char buf1[ATOM_GET_STR_BUF_SIZE];
29881
    static const char *module_status_str[] = { "unlinked", "linking", "linked", "evaluating", "evaluating_async", "evaluated" };
29882
    printf("%s: %s status=%s\n", str, JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name), module_status_str[m->status]);
29883
}
29884
#endif
29885
29886
static JSValue js_async_module_execution_rejected(JSContext *ctx, JSValueConst this_val,
29887
                                                  int argc, JSValueConst *argv, int magic, JSValue *func_data)
29888
0
{
29889
0
    JSModuleDef *module = JS_VALUE_GET_PTR(func_data[0]);
29890
0
    JSValueConst error = argv[0];
29891
0
    int i;
29892
29893
#ifdef DUMP_MODULE_EXEC
29894
    js_dump_module(ctx, __func__, module);
29895
#endif
29896
0
    if (js_check_stack_overflow(ctx->rt, 0))
29897
0
        return JS_ThrowStackOverflow(ctx);
29898
29899
0
    if (module->status == JS_MODULE_STATUS_EVALUATED) {
29900
0
        assert(module->eval_has_exception);
29901
0
        return JS_UNDEFINED;
29902
0
    }
29903
29904
0
    assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC);
29905
0
    assert(!module->eval_has_exception);
29906
0
    assert(module->async_evaluation);
29907
29908
0
    module->eval_has_exception = TRUE;
29909
0
    module->eval_exception = JS_DupValue(ctx, error);
29910
0
    module->status = JS_MODULE_STATUS_EVALUATED;
29911
0
    module->async_evaluation = FALSE;
29912
29913
0
    for(i = 0; i < module->async_parent_modules_count; i++) {
29914
0
        JSModuleDef *m = module->async_parent_modules[i];
29915
0
        JSValue m_obj = JS_NewModuleValue(ctx, m);
29916
0
        js_async_module_execution_rejected(ctx, JS_UNDEFINED, 1, &error, 0,
29917
0
                                           &m_obj);
29918
0
        JS_FreeValue(ctx, m_obj);
29919
0
    }
29920
29921
0
    if (!JS_IsUndefined(module->promise)) {
29922
0
        JSValue ret_val;
29923
0
        assert(module->cycle_root == module);
29924
0
        ret_val = JS_Call(ctx, module->resolving_funcs[1], JS_UNDEFINED,
29925
0
                          1, &error);
29926
0
        JS_FreeValue(ctx, ret_val);
29927
0
    }
29928
0
    return JS_UNDEFINED;
29929
0
}
29930
29931
static JSValue js_async_module_execution_fulfilled(JSContext *ctx, JSValueConst this_val,
29932
                                                   int argc, JSValueConst *argv, int magic, JSValue *func_data)
29933
0
{
29934
0
    JSModuleDef *module = JS_VALUE_GET_PTR(func_data[0]);
29935
0
    ExecModuleList exec_list_s, *exec_list = &exec_list_s;
29936
0
    int i;
29937
29938
#ifdef DUMP_MODULE_EXEC
29939
    js_dump_module(ctx, __func__, module);
29940
#endif
29941
0
    if (module->status == JS_MODULE_STATUS_EVALUATED) {
29942
0
        assert(module->eval_has_exception);
29943
0
        return JS_UNDEFINED;
29944
0
    }
29945
0
    assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC);
29946
0
    assert(!module->eval_has_exception);
29947
0
    assert(module->async_evaluation);
29948
0
    module->async_evaluation = FALSE;
29949
0
    js_set_module_evaluated(ctx, module);
29950
29951
0
    exec_list->tab = NULL;
29952
0
    exec_list->count = 0;
29953
0
    exec_list->size = 0;
29954
29955
0
    if (gather_available_ancestors(ctx, module, exec_list) < 0) {
29956
0
        js_free(ctx, exec_list->tab);
29957
0
        return JS_EXCEPTION;
29958
0
    }
29959
29960
    /* sort by increasing async_evaluation timestamp */
29961
0
    rqsort(exec_list->tab, exec_list->count, sizeof(exec_list->tab[0]),
29962
0
           exec_module_list_cmp, NULL);
29963
29964
0
    for(i = 0; i < exec_list->count; i++) {
29965
0
        JSModuleDef *m = exec_list->tab[i];
29966
#ifdef DUMP_MODULE_EXEC
29967
        printf("  %d/%d", i, exec_list->count); js_dump_module(ctx, "", m);
29968
#endif
29969
0
        if (m->status == JS_MODULE_STATUS_EVALUATED) {
29970
0
            assert(m->eval_has_exception);
29971
0
        } else if (m->has_tla) {
29972
0
            js_execute_async_module(ctx, m);
29973
0
        } else {
29974
0
            JSValue error;
29975
0
            if (js_execute_sync_module(ctx, m, &error) < 0) {
29976
0
                JSValue m_obj = JS_NewModuleValue(ctx, m);
29977
0
                js_async_module_execution_rejected(ctx, JS_UNDEFINED,
29978
0
                                                   1, (JSValueConst *)&error, 0,
29979
0
                                                   &m_obj);
29980
0
                JS_FreeValue(ctx, m_obj);
29981
0
                JS_FreeValue(ctx, error);
29982
0
            } else {
29983
0
                m->async_evaluation = FALSE;
29984
0
                js_set_module_evaluated(ctx, m);
29985
0
            }
29986
0
        }
29987
0
    }
29988
0
    js_free(ctx, exec_list->tab);
29989
0
    return JS_UNDEFINED;
29990
0
}
29991
29992
static int js_execute_async_module(JSContext *ctx, JSModuleDef *m)
29993
0
{
29994
0
    JSValue promise, m_obj;
29995
0
    JSValue resolve_funcs[2], ret_val;
29996
#ifdef DUMP_MODULE_EXEC
29997
    js_dump_module(ctx, __func__, m);
29998
#endif
29999
0
    promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0);
30000
0
    if (JS_IsException(promise))
30001
0
        return -1;
30002
0
    m_obj = JS_NewModuleValue(ctx, m);
30003
0
    resolve_funcs[0] = JS_NewCFunctionData(ctx, js_async_module_execution_fulfilled, 0, 0, 1, (JSValueConst *)&m_obj);
30004
0
    resolve_funcs[1] = JS_NewCFunctionData(ctx, js_async_module_execution_rejected, 0, 0, 1, (JSValueConst *)&m_obj);
30005
0
    ret_val = js_promise_then(ctx, promise, 2, (JSValueConst *)resolve_funcs);
30006
0
    JS_FreeValue(ctx, ret_val);
30007
0
    JS_FreeValue(ctx, m_obj);
30008
0
    JS_FreeValue(ctx, resolve_funcs[0]);
30009
0
    JS_FreeValue(ctx, resolve_funcs[1]);
30010
0
    JS_FreeValue(ctx, promise);
30011
0
    return 0;
30012
0
}
30013
30014
/* return < 0 in case of exception. *pvalue contains the exception. */
30015
static int js_execute_sync_module(JSContext *ctx, JSModuleDef *m,
30016
                                  JSValue *pvalue)
30017
7
{
30018
#ifdef DUMP_MODULE_EXEC
30019
    js_dump_module(ctx, __func__, m);
30020
#endif
30021
7
    if (m->init_func) {
30022
        /* C module init : no asynchronous execution */
30023
4
        if (m->init_func(ctx, m) < 0)
30024
0
            goto fail;
30025
4
    } else {
30026
3
        JSValue promise;
30027
3
        JSPromiseStateEnum state;
30028
30029
3
        promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0);
30030
3
        if (JS_IsException(promise))
30031
0
            goto fail;
30032
3
        state = JS_PromiseState(ctx, promise);
30033
3
        if (state == JS_PROMISE_FULFILLED) {
30034
2
            JS_FreeValue(ctx, promise);
30035
2
        } else if (state == JS_PROMISE_REJECTED) {
30036
1
            *pvalue = JS_PromiseResult(ctx, promise);
30037
1
            JS_FreeValue(ctx, promise);
30038
1
            return -1;
30039
1
        } else {
30040
0
            JS_FreeValue(ctx, promise);
30041
0
            JS_ThrowTypeError(ctx, "promise is pending");
30042
0
        fail:
30043
0
            *pvalue = JS_GetException(ctx);
30044
0
            return -1;
30045
0
        }
30046
3
    }
30047
6
    *pvalue = JS_UNDEFINED;
30048
6
    return 0;
30049
7
}
30050
30051
/* spec: InnerModuleEvaluation. Return (index, JS_UNDEFINED) or (-1,
30052
   exception) */
30053
static int js_inner_module_evaluation(JSContext *ctx, JSModuleDef *m,
30054
                                      int index, JSModuleDef **pstack_top,
30055
                                      JSValue *pvalue)
30056
7
{
30057
7
    JSModuleDef *m1;
30058
7
    int i;
30059
30060
#ifdef DUMP_MODULE_EXEC
30061
    js_dump_module(ctx, __func__, m);
30062
#endif
30063
30064
7
    if (js_check_stack_overflow(ctx->rt, 0)) {
30065
0
        JS_ThrowStackOverflow(ctx);
30066
0
        *pvalue = JS_GetException(ctx);
30067
0
        return -1;
30068
0
    }
30069
30070
7
    if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
30071
7
        m->status == JS_MODULE_STATUS_EVALUATED) {
30072
0
        if (m->eval_has_exception) {
30073
0
            *pvalue = JS_DupValue(ctx, m->eval_exception);
30074
0
            return -1;
30075
0
        } else {
30076
0
            *pvalue = JS_UNDEFINED;
30077
0
            return index;
30078
0
        }
30079
0
    }
30080
7
    if (m->status == JS_MODULE_STATUS_EVALUATING) {
30081
0
        *pvalue = JS_UNDEFINED;
30082
0
        return index;
30083
0
    }
30084
7
    assert(m->status == JS_MODULE_STATUS_LINKED);
30085
30086
7
    m->status = JS_MODULE_STATUS_EVALUATING;
30087
7
    m->dfs_index = index;
30088
7
    m->dfs_ancestor_index = index;
30089
7
    m->pending_async_dependencies = 0;
30090
7
    index++;
30091
    /* push 'm' on stack */
30092
7
    m->stack_prev = *pstack_top;
30093
7
    *pstack_top = m;
30094
30095
11
    for(i = 0; i < m->req_module_entries_count; i++) {
30096
4
        JSReqModuleEntry *rme = &m->req_module_entries[i];
30097
4
        m1 = rme->module;
30098
4
        index = js_inner_module_evaluation(ctx, m1, index, pstack_top, pvalue);
30099
4
        if (index < 0)
30100
0
            return -1;
30101
4
        assert(m1->status == JS_MODULE_STATUS_EVALUATING ||
30102
4
               m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
30103
4
               m1->status == JS_MODULE_STATUS_EVALUATED);
30104
4
        if (m1->status == JS_MODULE_STATUS_EVALUATING) {
30105
0
            m->dfs_ancestor_index = min_int(m->dfs_ancestor_index,
30106
0
                                            m1->dfs_ancestor_index);
30107
4
        } else {
30108
4
            m1 = m1->cycle_root;
30109
4
            assert(m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
30110
4
                   m1->status == JS_MODULE_STATUS_EVALUATED);
30111
4
            if (m1->eval_has_exception) {
30112
0
                *pvalue = JS_DupValue(ctx, m1->eval_exception);
30113
0
                return -1;
30114
0
            }
30115
4
        }
30116
4
        if (m1->async_evaluation) {
30117
0
            m->pending_async_dependencies++;
30118
0
            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)) {
30119
0
                *pvalue = JS_GetException(ctx);
30120
0
                return -1;
30121
0
            }
30122
0
            m1->async_parent_modules[m1->async_parent_modules_count++] = m;
30123
0
        }
30124
4
    }
30125
30126
7
    if (m->pending_async_dependencies > 0) {
30127
0
        assert(!m->async_evaluation);
30128
0
        m->async_evaluation = TRUE;
30129
0
        m->async_evaluation_timestamp =
30130
0
            ctx->rt->module_async_evaluation_next_timestamp++;
30131
7
    } else if (m->has_tla) {
30132
0
        assert(!m->async_evaluation);
30133
0
        m->async_evaluation = TRUE;
30134
0
        m->async_evaluation_timestamp =
30135
0
            ctx->rt->module_async_evaluation_next_timestamp++;
30136
0
        js_execute_async_module(ctx, m);
30137
7
    } else {
30138
7
        if (js_execute_sync_module(ctx, m, pvalue) < 0)
30139
1
            return -1;
30140
7
    }
30141
30142
6
    assert(m->dfs_ancestor_index <= m->dfs_index);
30143
6
    if (m->dfs_index == m->dfs_ancestor_index) {
30144
6
        for(;;) {
30145
            /* pop m1 from stack */
30146
6
            m1 = *pstack_top;
30147
6
            *pstack_top = m1->stack_prev;
30148
6
            if (!m1->async_evaluation) {
30149
6
                m1->status = JS_MODULE_STATUS_EVALUATED;
30150
6
            } else {
30151
0
                m1->status = JS_MODULE_STATUS_EVALUATING_ASYNC;
30152
0
            }
30153
            /* spec bug: cycle_root must be assigned before the test */
30154
6
            m1->cycle_root = m;
30155
6
            if (m1 == m)
30156
6
                break;
30157
6
        }
30158
6
    }
30159
6
    *pvalue = JS_UNDEFINED;
30160
6
    return index;
30161
6
}
30162
30163
/* Run the <eval> function of the module and of all its requested
30164
   modules. Return a promise or an exception. */
30165
static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m)
30166
3
{
30167
3
    JSModuleDef *m1, *stack_top;
30168
3
    JSValue ret_val, result;
30169
30170
#ifdef DUMP_MODULE_EXEC
30171
    js_dump_module(ctx, __func__, m);
30172
#endif
30173
3
    assert(m->status == JS_MODULE_STATUS_LINKED ||
30174
3
           m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
30175
3
           m->status == JS_MODULE_STATUS_EVALUATED);
30176
3
    if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
30177
3
        m->status == JS_MODULE_STATUS_EVALUATED) {
30178
0
        m = m->cycle_root;
30179
0
    }
30180
    /* a promise may be created only on the cycle_root of a cycle */
30181
3
    if (!JS_IsUndefined(m->promise))
30182
0
        return JS_DupValue(ctx, m->promise);
30183
3
    m->promise = JS_NewPromiseCapability(ctx, m->resolving_funcs);
30184
3
    if (JS_IsException(m->promise))
30185
0
        return JS_EXCEPTION;
30186
30187
3
    stack_top = NULL;
30188
3
    if (js_inner_module_evaluation(ctx, m, 0, &stack_top, &result) < 0) {
30189
2
        while (stack_top != NULL) {
30190
1
            m1 = stack_top;
30191
1
            assert(m1->status == JS_MODULE_STATUS_EVALUATING);
30192
1
            m1->status = JS_MODULE_STATUS_EVALUATED;
30193
1
            m1->eval_has_exception = TRUE;
30194
1
            m1->eval_exception = JS_DupValue(ctx, result);
30195
1
            m1->cycle_root = m; /* spec bug: should be present */
30196
1
            stack_top = m1->stack_prev;
30197
1
        }
30198
1
        JS_FreeValue(ctx, result);
30199
1
        assert(m->status == JS_MODULE_STATUS_EVALUATED);
30200
1
        assert(m->eval_has_exception);
30201
1
        ret_val = JS_Call(ctx, m->resolving_funcs[1], JS_UNDEFINED,
30202
1
                          1, (JSValueConst *)&m->eval_exception);
30203
1
        JS_FreeValue(ctx, ret_val);
30204
2
    } else {
30205
#ifdef DUMP_MODULE_EXEC
30206
        js_dump_module(ctx, "  done", m);
30207
#endif
30208
2
        assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||
30209
2
               m->status == JS_MODULE_STATUS_EVALUATED);
30210
2
        assert(!m->eval_has_exception);
30211
2
        if (!m->async_evaluation) {
30212
2
            JSValue value;
30213
2
            assert(m->status == JS_MODULE_STATUS_EVALUATED);
30214
2
            value = JS_UNDEFINED;
30215
2
            ret_val = JS_Call(ctx, m->resolving_funcs[0], JS_UNDEFINED,
30216
2
                              1, (JSValueConst *)&value);
30217
2
            JS_FreeValue(ctx, ret_val);
30218
2
        }
30219
2
        assert(stack_top == NULL);
30220
2
    }
30221
3
    return JS_DupValue(ctx, m->promise);
30222
3
}
30223
30224
static __exception int js_parse_with_clause(JSParseState *s, JSReqModuleEntry *rme)
30225
0
{
30226
0
    JSContext *ctx = s->ctx;
30227
0
    JSAtom key;
30228
0
    int ret;
30229
0
    const uint8_t *key_token_ptr;
30230
    
30231
0
    if (next_token(s))
30232
0
        return -1;
30233
0
    if (js_parse_expect(s, '{'))
30234
0
        return -1;
30235
0
    while (s->token.val != '}') {
30236
0
        key_token_ptr = s->token.ptr;
30237
0
        if (s->token.val == TOK_STRING) {
30238
0
            key = JS_ValueToAtom(ctx, s->token.u.str.str);
30239
0
            if (key == JS_ATOM_NULL)
30240
0
                return -1;
30241
0
        } else {
30242
0
            if (!token_is_ident(s->token.val)) {
30243
0
                js_parse_error(s, "identifier expected");
30244
0
                return -1;
30245
0
            }
30246
0
            key = JS_DupAtom(ctx, s->token.u.ident.atom);
30247
0
        }
30248
0
        if (next_token(s))
30249
0
            return -1;
30250
0
        if (js_parse_expect(s, ':')) {
30251
0
            JS_FreeAtom(ctx, key);
30252
0
            return -1;
30253
0
        }
30254
0
        if (s->token.val != TOK_STRING) {
30255
0
            js_parse_error_pos(s, key_token_ptr, "string expected");
30256
0
            return -1;
30257
0
        }
30258
0
        if (JS_IsUndefined(rme->attributes)) {
30259
0
            JSValue attributes = JS_NewObjectProto(ctx, JS_NULL);
30260
0
            if (JS_IsException(attributes)) {
30261
0
                JS_FreeAtom(ctx, key);
30262
0
                return -1;
30263
0
            }
30264
0
            rme->attributes = attributes;
30265
0
        }
30266
0
        ret = JS_HasProperty(ctx, rme->attributes, key);
30267
0
        if (ret != 0) {
30268
0
            JS_FreeAtom(ctx, key);
30269
0
            if (ret < 0)
30270
0
                return -1;
30271
0
            else
30272
0
                return js_parse_error(s, "duplicate with key");
30273
0
        }
30274
0
        ret = JS_DefinePropertyValue(ctx, rme->attributes, key,
30275
0
                                     JS_DupValue(ctx, s->token.u.str.str), JS_PROP_C_W_E);
30276
0
        JS_FreeAtom(ctx, key);
30277
0
        if (ret < 0)
30278
0
            return -1;
30279
0
        if (next_token(s))
30280
0
            return -1;
30281
0
        if (s->token.val != ',')
30282
0
            break;
30283
0
        if (next_token(s))
30284
0
            return -1;
30285
0
    }
30286
0
    if (!JS_IsUndefined(rme->attributes) &&
30287
0
        ctx->rt->module_check_attrs &&
30288
0
        ctx->rt->module_check_attrs(ctx, ctx->rt->module_loader_opaque, rme->attributes) < 0) {
30289
0
        return -1;
30290
0
    }
30291
0
    return js_parse_expect(s, '}');
30292
0
}
30293
30294
/* return the module index in m->req_module_entries[] or < 0 if error */
30295
static __exception int js_parse_from_clause(JSParseState *s, JSModuleDef *m)
30296
4
{
30297
4
    JSAtom module_name;
30298
4
    int idx;
30299
30300
4
    if (!token_is_pseudo_keyword(s, JS_ATOM_from)) {
30301
0
        js_parse_error(s, "from clause expected");
30302
0
        return -1;
30303
0
    }
30304
4
    if (next_token(s))
30305
0
        return -1;
30306
4
    if (s->token.val != TOK_STRING) {
30307
0
        js_parse_error(s, "string expected");
30308
0
        return -1;
30309
0
    }
30310
4
    module_name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
30311
4
    if (module_name == JS_ATOM_NULL)
30312
0
        return -1;
30313
4
    if (next_token(s)) {
30314
0
        JS_FreeAtom(s->ctx, module_name);
30315
0
        return -1;
30316
0
    }
30317
30318
4
    idx = add_req_module_entry(s->ctx, m, module_name);
30319
4
    JS_FreeAtom(s->ctx, module_name);
30320
4
    if (idx < 0)
30321
0
        return -1;
30322
4
    if (s->token.val == TOK_WITH) {
30323
0
        if (js_parse_with_clause(s, &m->req_module_entries[idx]))
30324
0
            return -1;
30325
0
    }
30326
4
    return idx;
30327
4
}
30328
30329
static __exception int js_parse_export(JSParseState *s)
30330
0
{
30331
0
    JSContext *ctx = s->ctx;
30332
0
    JSModuleDef *m = s->cur_func->module;
30333
0
    JSAtom local_name, export_name;
30334
0
    int first_export, idx, i, tok;
30335
0
    JSExportEntry *me;
30336
30337
0
    if (next_token(s))
30338
0
        return -1;
30339
30340
0
    tok = s->token.val;
30341
0
    if (tok == TOK_CLASS) {
30342
0
        return js_parse_class(s, FALSE, JS_PARSE_EXPORT_NAMED);
30343
0
    } else if (tok == TOK_FUNCTION ||
30344
0
               (token_is_pseudo_keyword(s, JS_ATOM_async) &&
30345
0
                peek_token(s, TRUE) == TOK_FUNCTION)) {
30346
0
        return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT,
30347
0
                                       JS_FUNC_NORMAL, JS_ATOM_NULL,
30348
0
                                       s->token.ptr,
30349
0
                                       JS_PARSE_EXPORT_NAMED, NULL);
30350
0
    }
30351
30352
0
    if (next_token(s))
30353
0
        return -1;
30354
30355
0
    switch(tok) {
30356
0
    case '{':
30357
0
        first_export = m->export_entries_count;
30358
0
        while (s->token.val != '}') {
30359
0
            if (!token_is_ident(s->token.val)) {
30360
0
                js_parse_error(s, "identifier expected");
30361
0
                return -1;
30362
0
            }
30363
0
            local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
30364
0
            export_name = JS_ATOM_NULL;
30365
0
            if (next_token(s))
30366
0
                goto fail;
30367
0
            if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
30368
0
                if (next_token(s))
30369
0
                    goto fail;
30370
0
                if (s->token.val == TOK_STRING) {
30371
0
                    if (js_string_find_invalid_codepoint(JS_VALUE_GET_STRING(s->token.u.str.str)) >= 0) {
30372
0
                        js_parse_error(s, "contains unpaired surrogate");
30373
0
                        goto fail;
30374
0
                    }
30375
0
                    export_name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
30376
0
                    if (export_name == JS_ATOM_NULL)
30377
0
                        goto fail;
30378
0
                } else {
30379
0
                    if (!token_is_ident(s->token.val)) {
30380
0
                        js_parse_error(s, "identifier expected");
30381
0
                        goto fail;
30382
0
                    }
30383
0
                    export_name = JS_DupAtom(ctx, s->token.u.ident.atom);
30384
0
                }
30385
0
                if (next_token(s)) {
30386
0
                fail:
30387
0
                    JS_FreeAtom(ctx, local_name);
30388
0
                fail1:
30389
0
                    JS_FreeAtom(ctx, export_name);
30390
0
                    return -1;
30391
0
                }
30392
0
            } else {
30393
0
                export_name = JS_DupAtom(ctx, local_name);
30394
0
            }
30395
0
            me = add_export_entry(s, m, local_name, export_name,
30396
0
                                  JS_EXPORT_TYPE_LOCAL);
30397
0
            JS_FreeAtom(ctx, local_name);
30398
0
            JS_FreeAtom(ctx, export_name);
30399
0
            if (!me)
30400
0
                return -1;
30401
0
            if (s->token.val != ',')
30402
0
                break;
30403
0
            if (next_token(s))
30404
0
                return -1;
30405
0
        }
30406
0
        if (js_parse_expect(s, '}'))
30407
0
            return -1;
30408
0
        if (token_is_pseudo_keyword(s, JS_ATOM_from)) {
30409
0
            idx = js_parse_from_clause(s, m);
30410
0
            if (idx < 0)
30411
0
                return -1;
30412
0
            for(i = first_export; i < m->export_entries_count; i++) {
30413
0
                me = &m->export_entries[i];
30414
0
                me->export_type = JS_EXPORT_TYPE_INDIRECT;
30415
0
                me->u.req_module_idx = idx;
30416
0
            }
30417
0
        }
30418
0
        break;
30419
0
    case '*':
30420
0
        if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
30421
            /* export ns from */
30422
0
            if (next_token(s))
30423
0
                return -1;
30424
0
            if (!token_is_ident(s->token.val)) {
30425
0
                js_parse_error(s, "identifier expected");
30426
0
                return -1;
30427
0
            }
30428
0
            export_name = JS_DupAtom(ctx, s->token.u.ident.atom);
30429
0
            if (next_token(s))
30430
0
                goto fail1;
30431
0
            idx = js_parse_from_clause(s, m);
30432
0
            if (idx < 0)
30433
0
                goto fail1;
30434
0
            me = add_export_entry(s, m, JS_ATOM__star_, export_name,
30435
0
                                  JS_EXPORT_TYPE_INDIRECT);
30436
0
            JS_FreeAtom(ctx, export_name);
30437
0
            if (!me)
30438
0
                return -1;
30439
0
            me->u.req_module_idx = idx;
30440
0
        } else {
30441
0
            idx = js_parse_from_clause(s, m);
30442
0
            if (idx < 0)
30443
0
                return -1;
30444
0
            if (add_star_export_entry(ctx, m, idx) < 0)
30445
0
                return -1;
30446
0
        }
30447
0
        break;
30448
0
    case TOK_DEFAULT:
30449
0
        if (s->token.val == TOK_CLASS) {
30450
0
            return js_parse_class(s, FALSE, JS_PARSE_EXPORT_DEFAULT);
30451
0
        } else if (s->token.val == TOK_FUNCTION ||
30452
0
                   (token_is_pseudo_keyword(s, JS_ATOM_async) &&
30453
0
                    peek_token(s, TRUE) == TOK_FUNCTION)) {
30454
0
            return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT,
30455
0
                                           JS_FUNC_NORMAL, JS_ATOM_NULL,
30456
0
                                           s->token.ptr,
30457
0
                                           JS_PARSE_EXPORT_DEFAULT, NULL);
30458
0
        } else {
30459
0
            if (js_parse_assign_expr(s))
30460
0
                return -1;
30461
0
        }
30462
        /* set the name of anonymous functions */
30463
0
        set_object_name(s, JS_ATOM_default);
30464
30465
        /* store the value in the _default_ global variable and export
30466
           it */
30467
0
        local_name = JS_ATOM__default_;
30468
0
        if (define_var(s, s->cur_func, local_name, JS_VAR_DEF_LET) < 0)
30469
0
            return -1;
30470
0
        emit_op(s, OP_scope_put_var_init);
30471
0
        emit_atom(s, local_name);
30472
0
        emit_u16(s, 0);
30473
30474
0
        if (!add_export_entry(s, m, local_name, JS_ATOM_default,
30475
0
                              JS_EXPORT_TYPE_LOCAL))
30476
0
            return -1;
30477
0
        break;
30478
0
    case TOK_VAR:
30479
0
    case TOK_LET:
30480
0
    case TOK_CONST:
30481
0
        return js_parse_var(s, TRUE, tok, TRUE);
30482
0
    default:
30483
0
        return js_parse_error(s, "invalid export syntax");
30484
0
    }
30485
0
    return js_parse_expect_semi(s);
30486
0
}
30487
30488
static int add_closure_var(JSContext *ctx, JSFunctionDef *s,
30489
                           BOOL is_local, BOOL is_arg,
30490
                           int var_idx, JSAtom var_name,
30491
                           BOOL is_const, BOOL is_lexical,
30492
                           JSVarKindEnum var_kind);
30493
30494
static int add_import(JSParseState *s, JSModuleDef *m,
30495
                      JSAtom local_name, JSAtom import_name, BOOL is_star)
30496
4
{
30497
4
    JSContext *ctx = s->ctx;
30498
4
    int i, var_idx;
30499
4
    JSImportEntry *mi;
30500
30501
4
    if (local_name == JS_ATOM_arguments || local_name == JS_ATOM_eval)
30502
0
        return js_parse_error(s, "invalid import binding");
30503
30504
4
    if (local_name != JS_ATOM_default) {
30505
6
        for (i = 0; i < s->cur_func->closure_var_count; i++) {
30506
2
            if (s->cur_func->closure_var[i].var_name == local_name)
30507
0
                return js_parse_error(s, "duplicate import binding");
30508
2
        }
30509
4
    }
30510
30511
4
    var_idx = add_closure_var(ctx, s->cur_func, is_star, FALSE,
30512
4
                              m->import_entries_count,
30513
4
                              local_name, TRUE, TRUE, FALSE);
30514
4
    if (var_idx < 0)
30515
0
        return -1;
30516
4
    if (js_resize_array(ctx, (void **)&m->import_entries,
30517
4
                        sizeof(JSImportEntry),
30518
4
                        &m->import_entries_size,
30519
4
                        m->import_entries_count + 1))
30520
0
        return -1;
30521
4
    mi = &m->import_entries[m->import_entries_count++];
30522
4
    mi->import_name = JS_DupAtom(ctx, import_name);
30523
4
    mi->var_idx = var_idx;
30524
4
    mi->is_star = is_star;
30525
4
    return 0;
30526
4
}
30527
30528
static __exception int js_parse_import(JSParseState *s)
30529
4
{
30530
4
    JSContext *ctx = s->ctx;
30531
4
    JSModuleDef *m = s->cur_func->module;
30532
4
    JSAtom local_name, import_name, module_name;
30533
4
    int first_import, i, idx;
30534
30535
4
    if (next_token(s))
30536
0
        return -1;
30537
30538
4
    first_import = m->import_entries_count;
30539
4
    if (s->token.val == TOK_STRING) {
30540
0
        module_name = JS_ValueToAtom(ctx, s->token.u.str.str);
30541
0
        if (module_name == JS_ATOM_NULL)
30542
0
            return -1;
30543
0
        if (next_token(s)) {
30544
0
            JS_FreeAtom(ctx, module_name);
30545
0
            return -1;
30546
0
        }
30547
0
        idx = add_req_module_entry(ctx, m, module_name);
30548
0
        JS_FreeAtom(ctx, module_name);
30549
0
        if (idx < 0)
30550
0
            return -1;
30551
0
        if (s->token.val == TOK_WITH) {
30552
0
            if (js_parse_with_clause(s, &m->req_module_entries[idx]))
30553
0
                return -1;
30554
0
        }
30555
4
    } else {
30556
4
        if (s->token.val == TOK_IDENT) {
30557
0
            if (s->token.u.ident.is_reserved) {
30558
0
                return js_parse_error_reserved_identifier(s);
30559
0
            }
30560
            /* "default" import */
30561
0
            local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
30562
0
            import_name = JS_ATOM_default;
30563
0
            if (next_token(s))
30564
0
                goto fail;
30565
0
            if (add_import(s, m, local_name, import_name, FALSE))
30566
0
                goto fail;
30567
0
            JS_FreeAtom(ctx, local_name);
30568
30569
0
            if (s->token.val != ',')
30570
0
                goto end_import_clause;
30571
0
            if (next_token(s))
30572
0
                return -1;
30573
0
        }
30574
30575
4
        if (s->token.val == '*') {
30576
            /* name space import */
30577
4
            if (next_token(s))
30578
0
                return -1;
30579
4
            if (!token_is_pseudo_keyword(s, JS_ATOM_as))
30580
0
                return js_parse_error(s, "expecting 'as'");
30581
4
            if (next_token(s))
30582
0
                return -1;
30583
4
            if (!token_is_ident(s->token.val)) {
30584
0
                js_parse_error(s, "identifier expected");
30585
0
                return -1;
30586
0
            }
30587
4
            local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
30588
4
            import_name = JS_ATOM__star_;
30589
4
            if (next_token(s))
30590
0
                goto fail;
30591
4
            if (add_import(s, m, local_name, import_name, TRUE))
30592
0
                goto fail;
30593
4
            JS_FreeAtom(ctx, local_name);
30594
4
        } else if (s->token.val == '{') {
30595
0
            if (next_token(s))
30596
0
                return -1;
30597
30598
0
            while (s->token.val != '}') {
30599
0
                BOOL is_string;
30600
0
                if (s->token.val == TOK_STRING) {
30601
0
                    is_string = TRUE;
30602
0
                    if (js_string_find_invalid_codepoint(JS_VALUE_GET_STRING(s->token.u.str.str)) >= 0) {
30603
0
                        js_parse_error(s, "contains unpaired surrogate");
30604
0
                        return -1;
30605
0
                    }
30606
0
                    import_name = JS_ValueToAtom(s->ctx, s->token.u.str.str);
30607
0
                    if (import_name == JS_ATOM_NULL)
30608
0
                        return -1;
30609
0
                } else {
30610
0
                    is_string = FALSE;
30611
0
                    if (!token_is_ident(s->token.val)) {
30612
0
                        js_parse_error(s, "identifier expected");
30613
0
                        return -1;
30614
0
                    }
30615
0
                    import_name = JS_DupAtom(ctx, s->token.u.ident.atom);
30616
0
                }
30617
0
                local_name = JS_ATOM_NULL;
30618
0
                if (next_token(s))
30619
0
                    goto fail;
30620
0
                if (token_is_pseudo_keyword(s, JS_ATOM_as)) {
30621
0
                    if (next_token(s))
30622
0
                        goto fail;
30623
0
                    if (!token_is_ident(s->token.val)) {
30624
0
                        js_parse_error(s, "identifier expected");
30625
0
                        goto fail;
30626
0
                    }
30627
0
                    local_name = JS_DupAtom(ctx, s->token.u.ident.atom);
30628
0
                    if (next_token(s))
30629
0
                        goto fail;
30630
0
                } else {
30631
0
                    if (is_string) {
30632
0
                        js_parse_error(s, "expecting 'as'");
30633
0
                    fail:
30634
0
                        JS_FreeAtom(ctx, local_name);
30635
0
                        JS_FreeAtom(ctx, import_name);
30636
0
                        return -1;
30637
0
                    }
30638
0
                    local_name = JS_DupAtom(ctx, import_name);
30639
0
                }
30640
0
                if (add_import(s, m, local_name, import_name, FALSE))
30641
0
                    goto fail;
30642
0
                JS_FreeAtom(ctx, local_name);
30643
0
                JS_FreeAtom(ctx, import_name);
30644
0
                if (s->token.val != ',')
30645
0
                    break;
30646
0
                if (next_token(s))
30647
0
                    return -1;
30648
0
            }
30649
0
            if (js_parse_expect(s, '}'))
30650
0
                return -1;
30651
0
        }
30652
4
    end_import_clause:
30653
4
        idx = js_parse_from_clause(s, m);
30654
4
        if (idx < 0)
30655
0
            return -1;
30656
4
    }
30657
8
    for(i = first_import; i < m->import_entries_count; i++)
30658
4
        m->import_entries[i].req_module_idx = idx;
30659
30660
4
    return js_parse_expect_semi(s);
30661
4
}
30662
30663
static __exception int js_parse_source_element(JSParseState *s)
30664
11
{
30665
11
    JSFunctionDef *fd = s->cur_func;
30666
11
    int tok;
30667
30668
11
    if (s->token.val == TOK_FUNCTION ||
30669
11
        (token_is_pseudo_keyword(s, JS_ATOM_async) &&
30670
11
         peek_token(s, TRUE) == TOK_FUNCTION)) {
30671
0
        if (js_parse_function_decl(s, JS_PARSE_FUNC_STATEMENT,
30672
0
                                   JS_FUNC_NORMAL, JS_ATOM_NULL,
30673
0
                                   s->token.ptr))
30674
0
            return -1;
30675
11
    } else if (s->token.val == TOK_EXPORT && fd->module) {
30676
0
        if (js_parse_export(s))
30677
0
            return -1;
30678
11
    } else if (s->token.val == TOK_IMPORT && fd->module &&
30679
11
               ((tok = peek_token(s, FALSE)) != '(' && tok != '.'))  {
30680
        /* the peek_token is needed to avoid confusion with ImportCall
30681
           (dynamic import) or import.meta */
30682
4
        if (js_parse_import(s))
30683
0
            return -1;
30684
7
    } else {
30685
7
        if (js_parse_statement_or_decl(s, DECL_MASK_ALL))
30686
1
            return -1;
30687
7
    }
30688
10
    return 0;
30689
11
}
30690
30691
static JSFunctionDef *js_new_function_def(JSContext *ctx,
30692
                                          JSFunctionDef *parent,
30693
                                          BOOL is_eval,
30694
                                          BOOL is_func_expr,
30695
                                          const char *filename,
30696
                                          const uint8_t *source_ptr,
30697
                                          GetLineColCache *get_line_col_cache)
30698
4
{
30699
4
    JSFunctionDef *fd;
30700
30701
4
    fd = js_mallocz(ctx, sizeof(*fd));
30702
4
    if (!fd)
30703
0
        return NULL;
30704
30705
4
    fd->ctx = ctx;
30706
4
    init_list_head(&fd->child_list);
30707
30708
    /* insert in parent list */
30709
4
    fd->parent = parent;
30710
4
    fd->parent_cpool_idx = -1;
30711
4
    if (parent) {
30712
0
        list_add_tail(&fd->link, &parent->child_list);
30713
0
        fd->js_mode = parent->js_mode;
30714
0
        fd->parent_scope_level = parent->scope_level;
30715
0
    }
30716
4
    fd->strip_debug = ((ctx->rt->strip_flags & JS_STRIP_DEBUG) != 0);
30717
4
    fd->strip_source = ((ctx->rt->strip_flags & (JS_STRIP_DEBUG | JS_STRIP_SOURCE)) != 0);
30718
30719
4
    fd->is_eval = is_eval;
30720
4
    fd->is_func_expr = is_func_expr;
30721
4
    js_dbuf_init(ctx, &fd->byte_code);
30722
4
    fd->last_opcode_pos = -1;
30723
4
    fd->func_name = JS_ATOM_NULL;
30724
4
    fd->var_object_idx = -1;
30725
4
    fd->arg_var_object_idx = -1;
30726
4
    fd->arguments_var_idx = -1;
30727
4
    fd->arguments_arg_idx = -1;
30728
4
    fd->func_var_idx = -1;
30729
4
    fd->eval_ret_idx = -1;
30730
4
    fd->this_var_idx = -1;
30731
4
    fd->new_target_var_idx = -1;
30732
4
    fd->this_active_func_var_idx = -1;
30733
4
    fd->home_object_var_idx = -1;
30734
30735
    /* XXX: should distinguish arg, var and var object and body scopes */
30736
4
    fd->scopes = fd->def_scope_array;
30737
4
    fd->scope_size = countof(fd->def_scope_array);
30738
4
    fd->scope_count = 1;
30739
4
    fd->scopes[0].first = -1;
30740
4
    fd->scopes[0].parent = -1;
30741
4
    fd->scope_level = 0;  /* 0: var/arg scope */
30742
4
    fd->scope_first = -1;
30743
4
    fd->body_scope = -1;
30744
30745
4
    fd->filename = JS_NewAtom(ctx, filename);
30746
4
    fd->source_pos = source_ptr - get_line_col_cache->buf_start;
30747
4
    fd->get_line_col_cache = get_line_col_cache;
30748
    
30749
4
    js_dbuf_init(ctx, &fd->pc2line);
30750
    //fd->pc2line_last_line_num = line_num;
30751
    //fd->pc2line_last_pc = 0;
30752
4
    fd->last_opcode_source_ptr = source_ptr;
30753
4
    return fd;
30754
4
}
30755
30756
static void free_bytecode_atoms(JSRuntime *rt,
30757
                                const uint8_t *bc_buf, int bc_len,
30758
                                BOOL use_short_opcodes)
30759
5
{
30760
5
    int pos, len, op;
30761
5
    JSAtom atom;
30762
5
    const JSOpCode *oi;
30763
30764
5
    pos = 0;
30765
49
    while (pos < bc_len) {
30766
44
        op = bc_buf[pos];
30767
44
        if (use_short_opcodes)
30768
42
            oi = &short_opcode_info(op);
30769
2
        else
30770
2
            oi = &opcode_info[op];
30771
30772
44
        len = oi->size;
30773
44
        switch(oi->fmt) {
30774
10
        case OP_FMT_atom:
30775
10
        case OP_FMT_atom_u8:
30776
10
        case OP_FMT_atom_u16:
30777
10
        case OP_FMT_atom_label_u8:
30778
10
        case OP_FMT_atom_label_u16:
30779
10
            if ((pos + 1 + 4) > bc_len)
30780
0
                break; /* may happen if there is not enough memory when emiting bytecode */
30781
10
            atom = get_u32(bc_buf + pos + 1);
30782
10
            JS_FreeAtomRT(rt, atom);
30783
10
            break;
30784
34
        default:
30785
34
            break;
30786
44
        }
30787
44
        pos += len;
30788
44
    }
30789
5
}
30790
30791
static void js_free_function_def(JSContext *ctx, JSFunctionDef *fd)
30792
1
{
30793
1
    int i;
30794
1
    struct list_head *el, *el1;
30795
30796
    /* free the child functions */
30797
1
    list_for_each_safe(el, el1, &fd->child_list) {
30798
0
        JSFunctionDef *fd1;
30799
0
        fd1 = list_entry(el, JSFunctionDef, link);
30800
0
        js_free_function_def(ctx, fd1);
30801
0
    }
30802
30803
1
    free_bytecode_atoms(ctx->rt, fd->byte_code.buf, fd->byte_code.size,
30804
1
                        fd->use_short_opcodes);
30805
1
    dbuf_free(&fd->byte_code);
30806
1
    js_free(ctx, fd->jump_slots);
30807
1
    js_free(ctx, fd->label_slots);
30808
1
    js_free(ctx, fd->line_number_slots);
30809
30810
1
    for(i = 0; i < fd->cpool_count; i++) {
30811
0
        JS_FreeValue(ctx, fd->cpool[i]);
30812
0
    }
30813
1
    js_free(ctx, fd->cpool);
30814
30815
1
    JS_FreeAtom(ctx, fd->func_name);
30816
30817
1
    for(i = 0; i < fd->var_count; i++) {
30818
0
        JS_FreeAtom(ctx, fd->vars[i].var_name);
30819
0
    }
30820
1
    js_free(ctx, fd->vars);
30821
1
    for(i = 0; i < fd->arg_count; i++) {
30822
0
        JS_FreeAtom(ctx, fd->args[i].var_name);
30823
0
    }
30824
1
    js_free(ctx, fd->args);
30825
30826
1
    for(i = 0; i < fd->global_var_count; i++) {
30827
0
        JS_FreeAtom(ctx, fd->global_vars[i].var_name);
30828
0
    }
30829
1
    js_free(ctx, fd->global_vars);
30830
30831
1
    for(i = 0; i < fd->closure_var_count; i++) {
30832
0
        JSClosureVar *cv = &fd->closure_var[i];
30833
0
        JS_FreeAtom(ctx, cv->var_name);
30834
0
    }
30835
1
    js_free(ctx, fd->closure_var);
30836
30837
1
    if (fd->scopes != fd->def_scope_array)
30838
0
        js_free(ctx, fd->scopes);
30839
30840
1
    JS_FreeAtom(ctx, fd->filename);
30841
1
    dbuf_free(&fd->pc2line);
30842
30843
1
    js_free(ctx, fd->source);
30844
30845
1
    if (fd->parent) {
30846
        /* remove in parent list */
30847
0
        list_del(&fd->link);
30848
0
    }
30849
1
    js_free(ctx, fd);
30850
1
}
30851
30852
#ifdef DUMP_BYTECODE
30853
static const char *skip_lines(const char *p, int n) {
30854
    while (n-- > 0 && *p) {
30855
        while (*p && *p++ != '\n')
30856
            continue;
30857
    }
30858
    return p;
30859
}
30860
30861
static void print_lines(const char *source, int line, int line1) {
30862
    const char *s = source;
30863
    const char *p = skip_lines(s, line);
30864
    if (*p) {
30865
        while (line++ < line1) {
30866
            p = skip_lines(s = p, 1);
30867
            printf(";; %.*s", (int)(p - s), s);
30868
            if (!*p) {
30869
                if (p[-1] != '\n')
30870
                    printf("\n");
30871
                break;
30872
            }
30873
        }
30874
    }
30875
}
30876
30877
static void dump_byte_code(JSContext *ctx, int pass,
30878
                           const uint8_t *tab, int len,
30879
                           const JSVarDef *args, int arg_count,
30880
                           const JSVarDef *vars, int var_count,
30881
                           const JSClosureVar *closure_var, int closure_var_count,
30882
                           const JSValue *cpool, uint32_t cpool_count,
30883
                           const char *source,
30884
                           const LabelSlot *label_slots, JSFunctionBytecode *b)
30885
{
30886
    const JSOpCode *oi;
30887
    int pos, pos_next, op, size, idx, addr, line, line1, in_source, line_num;
30888
    uint8_t *bits = js_mallocz(ctx, len * sizeof(*bits));
30889
    BOOL use_short_opcodes = (b != NULL);
30890
30891
    if (b) {
30892
        int col_num;
30893
        line_num = find_line_num(ctx, b, -1, &col_num);
30894
    }
30895
    
30896
    /* scan for jump targets */
30897
    for (pos = 0; pos < len; pos = pos_next) {
30898
        op = tab[pos];
30899
        if (use_short_opcodes)
30900
            oi = &short_opcode_info(op);
30901
        else
30902
            oi = &opcode_info[op];
30903
        pos_next = pos + oi->size;
30904
        if (op < OP_COUNT) {
30905
            switch (oi->fmt) {
30906
#if SHORT_OPCODES
30907
            case OP_FMT_label8:
30908
                pos++;
30909
                addr = (int8_t)tab[pos];
30910
                goto has_addr;
30911
            case OP_FMT_label16:
30912
                pos++;
30913
                addr = (int16_t)get_u16(tab + pos);
30914
                goto has_addr;
30915
#endif
30916
            case OP_FMT_atom_label_u8:
30917
            case OP_FMT_atom_label_u16:
30918
                pos += 4;
30919
                /* fall thru */
30920
            case OP_FMT_label:
30921
            case OP_FMT_label_u16:
30922
                pos++;
30923
                addr = get_u32(tab + pos);
30924
                goto has_addr;
30925
            has_addr:
30926
                if (pass == 1)
30927
                    addr = label_slots[addr].pos;
30928
                if (pass == 2)
30929
                    addr = label_slots[addr].pos2;
30930
                if (pass == 3)
30931
                    addr += pos;
30932
                if (addr >= 0 && addr < len)
30933
                    bits[addr] |= 1;
30934
                break;
30935
            }
30936
        }
30937
    }
30938
    in_source = 0;
30939
    if (source) {
30940
        /* Always print first line: needed if single line */
30941
        print_lines(source, 0, 1);
30942
        in_source = 1;
30943
    }
30944
    line1 = line = 1;
30945
    pos = 0;
30946
    while (pos < len) {
30947
        op = tab[pos];
30948
        if (source && b) {
30949
            int col_num;
30950
            if (b) {
30951
                line1 = find_line_num(ctx, b, pos, &col_num) - line_num + 1;
30952
            } else if (op == OP_line_num) {
30953
                /* XXX: no longer works */
30954
                line1 = get_u32(tab + pos + 1) - line_num + 1;
30955
            }
30956
            if (line1 > line) {
30957
                if (!in_source)
30958
                    printf("\n");
30959
                in_source = 1;
30960
                print_lines(source, line, line1);
30961
                line = line1;
30962
                //bits[pos] |= 2;
30963
            }
30964
        }
30965
        if (in_source)
30966
            printf("\n");
30967
        in_source = 0;
30968
        if (op >= OP_COUNT) {
30969
            printf("invalid opcode (0x%02x)\n", op);
30970
            pos++;
30971
            continue;
30972
        }
30973
        if (use_short_opcodes)
30974
            oi = &short_opcode_info(op);
30975
        else
30976
            oi = &opcode_info[op];
30977
        size = oi->size;
30978
        if (pos + size > len) {
30979
            printf("truncated opcode (0x%02x)\n", op);
30980
            break;
30981
        }
30982
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 16)
30983
        {
30984
            int i, x, x0;
30985
            x = x0 = printf("%5d ", pos);
30986
            for (i = 0; i < size; i++) {
30987
                if (i == 6) {
30988
                    printf("\n%*s", x = x0, "");
30989
                }
30990
                x += printf(" %02X", tab[pos + i]);
30991
            }
30992
            printf("%*s", x0 + 20 - x, "");
30993
        }
30994
#endif
30995
        if (bits[pos]) {
30996
            printf("%5d:  ", pos);
30997
        } else {
30998
            printf("        ");
30999
        }
31000
        printf("%s", oi->name);
31001
        pos++;
31002
        switch(oi->fmt) {
31003
        case OP_FMT_none_int:
31004
            printf(" %d", op - OP_push_0);
31005
            break;
31006
        case OP_FMT_npopx:
31007
            printf(" %d", op - OP_call0);
31008
            break;
31009
        case OP_FMT_u8:
31010
            printf(" %u", get_u8(tab + pos));
31011
            break;
31012
        case OP_FMT_i8:
31013
            printf(" %d", get_i8(tab + pos));
31014
            break;
31015
        case OP_FMT_u16:
31016
        case OP_FMT_npop:
31017
            printf(" %u", get_u16(tab + pos));
31018
            break;
31019
        case OP_FMT_npop_u16:
31020
            printf(" %u,%u", get_u16(tab + pos), get_u16(tab + pos + 2));
31021
            break;
31022
        case OP_FMT_i16:
31023
            printf(" %d", get_i16(tab + pos));
31024
            break;
31025
        case OP_FMT_i32:
31026
            printf(" %d", get_i32(tab + pos));
31027
            break;
31028
        case OP_FMT_u32:
31029
            printf(" %u", get_u32(tab + pos));
31030
            break;
31031
#if SHORT_OPCODES
31032
        case OP_FMT_label8:
31033
            addr = get_i8(tab + pos);
31034
            goto has_addr1;
31035
        case OP_FMT_label16:
31036
            addr = get_i16(tab + pos);
31037
            goto has_addr1;
31038
#endif
31039
        case OP_FMT_label:
31040
            addr = get_u32(tab + pos);
31041
            goto has_addr1;
31042
        has_addr1:
31043
            if (pass == 1)
31044
                printf(" %u:%u", addr, label_slots[addr].pos);
31045
            if (pass == 2)
31046
                printf(" %u:%u", addr, label_slots[addr].pos2);
31047
            if (pass == 3)
31048
                printf(" %u", addr + pos);
31049
            break;
31050
        case OP_FMT_label_u16:
31051
            addr = get_u32(tab + pos);
31052
            if (pass == 1)
31053
                printf(" %u:%u", addr, label_slots[addr].pos);
31054
            if (pass == 2)
31055
                printf(" %u:%u", addr, label_slots[addr].pos2);
31056
            if (pass == 3)
31057
                printf(" %u", addr + pos);
31058
            printf(",%u", get_u16(tab + pos + 4));
31059
            break;
31060
#if SHORT_OPCODES
31061
        case OP_FMT_const8:
31062
            idx = get_u8(tab + pos);
31063
            goto has_pool_idx;
31064
#endif
31065
        case OP_FMT_const:
31066
            idx = get_u32(tab + pos);
31067
            goto has_pool_idx;
31068
        has_pool_idx:
31069
            printf(" %u: ", idx);
31070
            if (idx < cpool_count) {
31071
                JS_PrintValue(ctx, js_dump_value_write, stdout, cpool[idx], NULL);
31072
            }
31073
            break;
31074
        case OP_FMT_atom:
31075
            printf(" ");
31076
            print_atom(ctx, get_u32(tab + pos));
31077
            break;
31078
        case OP_FMT_atom_u8:
31079
            printf(" ");
31080
            print_atom(ctx, get_u32(tab + pos));
31081
            printf(",%d", get_u8(tab + pos + 4));
31082
            break;
31083
        case OP_FMT_atom_u16:
31084
            printf(" ");
31085
            print_atom(ctx, get_u32(tab + pos));
31086
            printf(",%d", get_u16(tab + pos + 4));
31087
            break;
31088
        case OP_FMT_atom_label_u8:
31089
        case OP_FMT_atom_label_u16:
31090
            printf(" ");
31091
            print_atom(ctx, get_u32(tab + pos));
31092
            addr = get_u32(tab + pos + 4);
31093
            if (pass == 1)
31094
                printf(",%u:%u", addr, label_slots[addr].pos);
31095
            if (pass == 2)
31096
                printf(",%u:%u", addr, label_slots[addr].pos2);
31097
            if (pass == 3)
31098
                printf(",%u", addr + pos + 4);
31099
            if (oi->fmt == OP_FMT_atom_label_u8)
31100
                printf(",%u", get_u8(tab + pos + 8));
31101
            else
31102
                printf(",%u", get_u16(tab + pos + 8));
31103
            break;
31104
        case OP_FMT_none_loc:
31105
            idx = (op - OP_get_loc0) % 4;
31106
            goto has_loc;
31107
        case OP_FMT_loc8:
31108
            idx = get_u8(tab + pos);
31109
            goto has_loc;
31110
        case OP_FMT_loc:
31111
            idx = get_u16(tab + pos);
31112
        has_loc:
31113
            printf(" %d: ", idx);
31114
            if (idx < var_count) {
31115
                print_atom(ctx, vars[idx].var_name);
31116
            }
31117
            break;
31118
        case OP_FMT_none_arg:
31119
            idx = (op - OP_get_arg0) % 4;
31120
            goto has_arg;
31121
        case OP_FMT_arg:
31122
            idx = get_u16(tab + pos);
31123
        has_arg:
31124
            printf(" %d: ", idx);
31125
            if (idx < arg_count) {
31126
                print_atom(ctx, args[idx].var_name);
31127
            }
31128
            break;
31129
        case OP_FMT_none_var_ref:
31130
            idx = (op - OP_get_var_ref0) % 4;
31131
            goto has_var_ref;
31132
        case OP_FMT_var_ref:
31133
            idx = get_u16(tab + pos);
31134
        has_var_ref:
31135
            printf(" %d: ", idx);
31136
            if (idx < closure_var_count) {
31137
                print_atom(ctx, closure_var[idx].var_name);
31138
            }
31139
            break;
31140
        default:
31141
            break;
31142
        }
31143
        printf("\n");
31144
        pos += oi->size - 1;
31145
    }
31146
    if (source) {
31147
        if (!in_source)
31148
            printf("\n");
31149
        print_lines(source, line, INT32_MAX);
31150
    }
31151
    js_free(ctx, bits);
31152
}
31153
31154
static __maybe_unused void dump_pc2line(JSContext *ctx, const uint8_t *buf, int len)
31155
{
31156
    const uint8_t *p_end, *p;
31157
    int pc, v, line_num, col_num, ret;
31158
    unsigned int op;
31159
    uint32_t val;
31160
    
31161
    if (len <= 0)
31162
        return;
31163
31164
    printf("%5s %5s %5s\n", "PC", "LINE", "COL");
31165
31166
    p = buf;
31167
    p_end = buf + len;
31168
    
31169
    /* get the function line and column numbers */
31170
    ret = get_leb128(&val, p, p_end);
31171
    if (ret < 0)
31172
        goto fail;
31173
    p += ret;
31174
    line_num = val + 1;
31175
31176
    ret = get_leb128(&val, p, p_end);
31177
    if (ret < 0)
31178
        goto fail;
31179
    p += ret;
31180
    col_num = val + 1;
31181
31182
    printf("%5s %5d %5d\n", "-", line_num, col_num);
31183
    
31184
    pc = 0;
31185
    while (p < p_end) {
31186
        op = *p++;
31187
        if (op == 0) {
31188
            ret = get_leb128(&val, p, p_end);
31189
            if (ret < 0)
31190
                goto fail;
31191
            pc += val;
31192
            p += ret;
31193
            ret = get_sleb128(&v, p, p_end);
31194
            if (ret < 0)
31195
                goto fail;
31196
            p += ret;
31197
            line_num += v;
31198
        } else {
31199
            op -= PC2LINE_OP_FIRST;
31200
            pc += (op / PC2LINE_RANGE);
31201
            line_num += (op % PC2LINE_RANGE) + PC2LINE_BASE;
31202
        }
31203
        ret = get_sleb128(&v, p, p_end);
31204
        if (ret < 0)
31205
            goto fail;
31206
        p += ret;
31207
        col_num += v;
31208
        
31209
        printf("%5d %5d %5d\n", pc, line_num, col_num);
31210
    }
31211
 fail: ;
31212
}
31213
31214
static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionBytecode *b)
31215
{
31216
    int i;
31217
    char atom_buf[ATOM_GET_STR_BUF_SIZE];
31218
    const char *str;
31219
31220
    if (b->has_debug && b->debug.filename != JS_ATOM_NULL) {
31221
        int line_num, col_num;
31222
        str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->debug.filename);
31223
        line_num = find_line_num(ctx, b, -1, &col_num);
31224
        printf("%s:%d:%d: ", str, line_num, col_num);
31225
    }
31226
31227
    str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->func_name);
31228
    printf("function: %s%s\n", &"*"[b->func_kind != JS_FUNC_GENERATOR], str);
31229
    if (b->js_mode) {
31230
        printf("  mode:");
31231
        if (b->js_mode & JS_MODE_STRICT)
31232
            printf(" strict");
31233
        printf("\n");
31234
    }
31235
    if (b->arg_count && b->vardefs) {
31236
        printf("  args:");
31237
        for(i = 0; i < b->arg_count; i++) {
31238
            printf(" %s", JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf),
31239
                                        b->vardefs[i].var_name));
31240
        }
31241
        printf("\n");
31242
    }
31243
    if (b->var_count && b->vardefs) {
31244
        printf("  locals:\n");
31245
        for(i = 0; i < b->var_count; i++) {
31246
            JSVarDef *vd = &b->vardefs[b->arg_count + i];
31247
            printf("%5d: %s %s", i,
31248
                   vd->var_kind == JS_VAR_CATCH ? "catch" :
31249
                   (vd->var_kind == JS_VAR_FUNCTION_DECL ||
31250
                    vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) ? "function" :
31251
                   vd->is_const ? "const" :
31252
                   vd->is_lexical ? "let" : "var",
31253
                   JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), vd->var_name));
31254
            if (vd->scope_level)
31255
                printf(" [level:%d next:%d]", vd->scope_level, vd->scope_next);
31256
            printf("\n");
31257
        }
31258
    }
31259
    if (b->closure_var_count) {
31260
        printf("  closure vars:\n");
31261
        for(i = 0; i < b->closure_var_count; i++) {
31262
            JSClosureVar *cv = &b->closure_var[i];
31263
            printf("%5d: %s %s:%s%d %s\n", i,
31264
                   JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), cv->var_name),
31265
                   cv->is_local ? "local" : "parent",
31266
                   cv->is_arg ? "arg" : "loc", cv->var_idx,
31267
                   cv->is_const ? "const" :
31268
                   cv->is_lexical ? "let" : "var");
31269
        }
31270
    }
31271
    printf("  stack_size: %d\n", b->stack_size);
31272
    printf("  opcodes:\n");
31273
    dump_byte_code(ctx, 3, b->byte_code_buf, b->byte_code_len,
31274
                   b->vardefs, b->arg_count,
31275
                   b->vardefs ? b->vardefs + b->arg_count : NULL, b->var_count,
31276
                   b->closure_var, b->closure_var_count,
31277
                   b->cpool, b->cpool_count,
31278
                   b->has_debug ? b->debug.source : NULL,
31279
                   NULL, b);
31280
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 32)
31281
    if (b->has_debug)
31282
        dump_pc2line(ctx, b->debug.pc2line_buf, b->debug.pc2line_len);
31283
#endif
31284
    printf("\n");
31285
}
31286
#endif
31287
31288
static int add_closure_var(JSContext *ctx, JSFunctionDef *s,
31289
                           BOOL is_local, BOOL is_arg,
31290
                           int var_idx, JSAtom var_name,
31291
                           BOOL is_const, BOOL is_lexical,
31292
                           JSVarKindEnum var_kind)
31293
4
{
31294
4
    JSClosureVar *cv;
31295
31296
    /* the closure variable indexes are currently stored on 16 bits */
31297
4
    if (s->closure_var_count >= JS_MAX_LOCAL_VARS) {
31298
0
        JS_ThrowInternalError(ctx, "too many closure variables");
31299
0
        return -1;
31300
0
    }
31301
31302
4
    if (js_resize_array(ctx, (void **)&s->closure_var,
31303
4
                        sizeof(s->closure_var[0]),
31304
4
                        &s->closure_var_size, s->closure_var_count + 1))
31305
0
        return -1;
31306
4
    cv = &s->closure_var[s->closure_var_count++];
31307
4
    cv->is_local = is_local;
31308
4
    cv->is_arg = is_arg;
31309
4
    cv->is_const = is_const;
31310
4
    cv->is_lexical = is_lexical;
31311
4
    cv->var_kind = var_kind;
31312
4
    cv->var_idx = var_idx;
31313
4
    cv->var_name = JS_DupAtom(ctx, var_name);
31314
4
    return s->closure_var_count - 1;
31315
4
}
31316
31317
static int find_closure_var(JSContext *ctx, JSFunctionDef *s,
31318
                            JSAtom var_name)
31319
0
{
31320
0
    int i;
31321
0
    for(i = 0; i < s->closure_var_count; i++) {
31322
0
        JSClosureVar *cv = &s->closure_var[i];
31323
0
        if (cv->var_name == var_name)
31324
0
            return i;
31325
0
    }
31326
0
    return -1;
31327
0
}
31328
31329
/* 'fd' must be a parent of 's'. Create in 's' a closure referencing a
31330
   local variable (is_local = TRUE) or a closure (is_local = FALSE) in
31331
   'fd' */
31332
static int get_closure_var2(JSContext *ctx, JSFunctionDef *s,
31333
                            JSFunctionDef *fd, BOOL is_local,
31334
                            BOOL is_arg, int var_idx, JSAtom var_name,
31335
                            BOOL is_const, BOOL is_lexical,
31336
                            JSVarKindEnum var_kind)
31337
0
{
31338
0
    int i;
31339
31340
0
    if (fd != s->parent) {
31341
0
        var_idx = get_closure_var2(ctx, s->parent, fd, is_local,
31342
0
                                   is_arg, var_idx, var_name,
31343
0
                                   is_const, is_lexical, var_kind);
31344
0
        if (var_idx < 0)
31345
0
            return -1;
31346
0
        is_local = FALSE;
31347
0
    }
31348
0
    for(i = 0; i < s->closure_var_count; i++) {
31349
0
        JSClosureVar *cv = &s->closure_var[i];
31350
0
        if (cv->var_idx == var_idx && cv->is_arg == is_arg &&
31351
0
            cv->is_local == is_local)
31352
0
            return i;
31353
0
    }
31354
0
    return add_closure_var(ctx, s, is_local, is_arg, var_idx, var_name,
31355
0
                           is_const, is_lexical, var_kind);
31356
0
}
31357
31358
static int get_closure_var(JSContext *ctx, JSFunctionDef *s,
31359
                           JSFunctionDef *fd, BOOL is_arg,
31360
                           int var_idx, JSAtom var_name,
31361
                           BOOL is_const, BOOL is_lexical,
31362
                           JSVarKindEnum var_kind)
31363
0
{
31364
0
    return get_closure_var2(ctx, s, fd, TRUE, is_arg,
31365
0
                            var_idx, var_name, is_const, is_lexical,
31366
0
                            var_kind);
31367
0
}
31368
31369
static int get_with_scope_opcode(int op)
31370
0
{
31371
0
    if (op == OP_scope_get_var_undef)
31372
0
        return OP_with_get_var;
31373
0
    else
31374
0
        return OP_with_get_var + (op - OP_scope_get_var);
31375
0
}
31376
31377
static BOOL can_opt_put_ref_value(const uint8_t *bc_buf, int pos)
31378
0
{
31379
0
    int opcode = bc_buf[pos];
31380
0
    return (bc_buf[pos + 1] == OP_put_ref_value &&
31381
0
            (opcode == OP_insert3 ||
31382
0
             opcode == OP_perm4 ||
31383
0
             opcode == OP_nop ||
31384
0
             opcode == OP_rot3l));
31385
0
}
31386
31387
static BOOL can_opt_put_global_ref_value(const uint8_t *bc_buf, int pos)
31388
0
{
31389
0
    int opcode = bc_buf[pos];
31390
0
    return (bc_buf[pos + 1] == OP_put_ref_value &&
31391
0
            (opcode == OP_insert3 ||
31392
0
             opcode == OP_perm4 ||
31393
0
             opcode == OP_nop ||
31394
0
             opcode == OP_rot3l));
31395
0
}
31396
31397
static int optimize_scope_make_ref(JSContext *ctx, JSFunctionDef *s,
31398
                                   DynBuf *bc, uint8_t *bc_buf,
31399
                                   LabelSlot *ls, int pos_next,
31400
                                   int get_op, int var_idx)
31401
0
{
31402
0
    int label_pos, end_pos, pos;
31403
31404
    /* XXX: should optimize `loc(a) += expr` as `expr add_loc(a)`
31405
       but only if expr does not modify `a`.
31406
       should scan the code between pos_next and label_pos
31407
       for operations that can potentially change `a`:
31408
       OP_scope_make_ref(a), function calls, jumps and gosub.
31409
     */
31410
    /* replace the reference get/put with normal variable
31411
       accesses */
31412
0
    if (bc_buf[pos_next] == OP_get_ref_value) {
31413
0
        dbuf_putc(bc, get_op);
31414
0
        dbuf_put_u16(bc, var_idx);
31415
0
        pos_next++;
31416
0
    }
31417
    /* remove the OP_label to make room for replacement */
31418
    /* label should have a refcount of 0 anyway */
31419
    /* XXX: should avoid this patch by inserting nops in phase 1 */
31420
0
    label_pos = ls->pos;
31421
0
    pos = label_pos - 5;
31422
0
    assert(bc_buf[pos] == OP_label);
31423
    /* label points to an instruction pair:
31424
       - insert3 / put_ref_value
31425
       - perm4 / put_ref_value
31426
       - rot3l / put_ref_value
31427
       - nop / put_ref_value
31428
     */
31429
0
    end_pos = label_pos + 2;
31430
0
    if (bc_buf[label_pos] == OP_insert3)
31431
0
        bc_buf[pos++] = OP_dup;
31432
0
    bc_buf[pos] = get_op + 1;
31433
0
    put_u16(bc_buf + pos + 1, var_idx);
31434
0
    pos += 3;
31435
    /* pad with OP_nop */
31436
0
    while (pos < end_pos)
31437
0
        bc_buf[pos++] = OP_nop;
31438
0
    return pos_next;
31439
0
}
31440
31441
static int optimize_scope_make_global_ref(JSContext *ctx, JSFunctionDef *s,
31442
                                          DynBuf *bc, uint8_t *bc_buf,
31443
                                          LabelSlot *ls, int pos_next,
31444
                                          JSAtom var_name)
31445
0
{
31446
0
    int label_pos, end_pos, pos, op;
31447
0
    BOOL is_strict;
31448
0
    is_strict = ((s->js_mode & JS_MODE_STRICT) != 0);
31449
31450
    /* replace the reference get/put with normal variable
31451
       accesses */
31452
0
    if (is_strict) {
31453
        /* need to check if the variable exists before evaluating the right
31454
           expression */
31455
        /* XXX: need an extra OP_true if destructuring an array */
31456
0
        dbuf_putc(bc, OP_check_var);
31457
0
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
31458
0
    } else {
31459
        /* XXX: need 2 extra OP_true if destructuring an array */
31460
0
    }
31461
0
    if (bc_buf[pos_next] == OP_get_ref_value) {
31462
0
        dbuf_putc(bc, OP_get_var);
31463
0
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
31464
0
        pos_next++;
31465
0
    }
31466
    /* remove the OP_label to make room for replacement */
31467
    /* label should have a refcount of 0 anyway */
31468
    /* XXX: should have emitted several OP_nop to avoid this kludge */
31469
0
    label_pos = ls->pos;
31470
0
    pos = label_pos - 5;
31471
0
    assert(bc_buf[pos] == OP_label);
31472
0
    end_pos = label_pos + 2;
31473
0
    op = bc_buf[label_pos];
31474
0
    if (is_strict) {
31475
0
        if (op != OP_nop) {
31476
0
            switch(op) {
31477
0
            case OP_insert3:
31478
0
                op = OP_insert2;
31479
0
                break;
31480
0
            case OP_perm4:
31481
0
                op = OP_perm3;
31482
0
                break;
31483
0
            case OP_rot3l:
31484
0
                op = OP_swap;
31485
0
                break;
31486
0
            default:
31487
0
                abort();
31488
0
            }
31489
0
            bc_buf[pos++] = op;
31490
0
        }
31491
0
    } else {
31492
0
        if (op == OP_insert3)
31493
0
            bc_buf[pos++] = OP_dup;
31494
0
    }
31495
0
    if (is_strict) {
31496
0
        bc_buf[pos] = OP_put_var_strict;
31497
        /* XXX: need 1 extra OP_drop if destructuring an array */
31498
0
    } else {
31499
0
        bc_buf[pos] = OP_put_var;
31500
        /* XXX: need 2 extra OP_drop if destructuring an array */
31501
0
    }
31502
0
    put_u32(bc_buf + pos + 1, JS_DupAtom(ctx, var_name));
31503
0
    pos += 5;
31504
    /* pad with OP_nop */
31505
0
    while (pos < end_pos)
31506
0
        bc_buf[pos++] = OP_nop;
31507
0
    return pos_next;
31508
0
}
31509
31510
static int add_var_this(JSContext *ctx, JSFunctionDef *fd)
31511
0
{
31512
0
    int idx;
31513
0
    idx = add_var(ctx, fd, JS_ATOM_this);
31514
0
    if (idx >= 0 && fd->is_derived_class_constructor) {
31515
0
        JSVarDef *vd = &fd->vars[idx];
31516
        /* XXX: should have is_this flag or var type */
31517
0
        vd->is_lexical = 1; /* used to trigger 'uninitialized' checks
31518
                               in a derived class constructor */
31519
0
    }
31520
0
    return idx;
31521
0
}
31522
31523
static int resolve_pseudo_var(JSContext *ctx, JSFunctionDef *s,
31524
                               JSAtom var_name)
31525
0
{
31526
0
    int var_idx;
31527
31528
0
    if (!s->has_this_binding)
31529
0
        return -1;
31530
0
    switch(var_name) {
31531
0
    case JS_ATOM_home_object:
31532
        /* 'home_object' pseudo variable */
31533
0
        if (s->home_object_var_idx < 0)
31534
0
            s->home_object_var_idx = add_var(ctx, s, var_name);
31535
0
        var_idx = s->home_object_var_idx;
31536
0
        break;
31537
0
    case JS_ATOM_this_active_func:
31538
        /* 'this.active_func' pseudo variable */
31539
0
        if (s->this_active_func_var_idx < 0)
31540
0
            s->this_active_func_var_idx = add_var(ctx, s, var_name);
31541
0
        var_idx = s->this_active_func_var_idx;
31542
0
        break;
31543
0
    case JS_ATOM_new_target:
31544
        /* 'new.target' pseudo variable */
31545
0
        if (s->new_target_var_idx < 0)
31546
0
            s->new_target_var_idx = add_var(ctx, s, var_name);
31547
0
        var_idx = s->new_target_var_idx;
31548
0
        break;
31549
0
    case JS_ATOM_this:
31550
        /* 'this' pseudo variable */
31551
0
        if (s->this_var_idx < 0)
31552
0
            s->this_var_idx = add_var_this(ctx, s);
31553
0
        var_idx = s->this_var_idx;
31554
0
        break;
31555
0
    default:
31556
0
        var_idx = -1;
31557
0
        break;
31558
0
    }
31559
0
    return var_idx;
31560
0
}
31561
31562
/* test if 'var_name' is in the variable object on the stack. If is it
31563
   the case, handle it and jump to 'label_done' */
31564
static void var_object_test(JSContext *ctx, JSFunctionDef *s,
31565
                            JSAtom var_name, int op, DynBuf *bc,
31566
                            int *plabel_done, BOOL is_with)
31567
0
{
31568
0
    dbuf_putc(bc, get_with_scope_opcode(op));
31569
0
    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
31570
0
    if (*plabel_done < 0) {
31571
0
        *plabel_done = new_label_fd(s);
31572
0
        if (*plabel_done < 0) {
31573
0
            dbuf_set_error(bc);
31574
0
            return;
31575
0
        }
31576
0
    }
31577
0
    dbuf_put_u32(bc, *plabel_done);
31578
0
    dbuf_putc(bc, is_with);
31579
0
    update_label(s, *plabel_done, 1);
31580
0
    s->jump_size++;
31581
0
}
31582
31583
/* return the position of the next opcode */
31584
static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
31585
                             JSAtom var_name, int scope_level, int op,
31586
                             DynBuf *bc, uint8_t *bc_buf,
31587
                             LabelSlot *ls, int pos_next)
31588
9
{
31589
9
    int idx, var_idx, is_put;
31590
9
    int label_done;
31591
9
    JSFunctionDef *fd;
31592
9
    JSVarDef *vd;
31593
9
    BOOL is_pseudo_var, is_arg_scope;
31594
31595
9
    label_done = -1;
31596
31597
    /* XXX: could be simpler to use a specific function to
31598
       resolve the pseudo variables */
31599
9
    is_pseudo_var = (var_name == JS_ATOM_home_object ||
31600
9
                     var_name == JS_ATOM_this_active_func ||
31601
9
                     var_name == JS_ATOM_new_target ||
31602
9
                     var_name == JS_ATOM_this);
31603
31604
    /* resolve local scoped variables */
31605
9
    var_idx = -1;
31606
9
    for (idx = s->scopes[scope_level].first; idx >= 0;) {
31607
0
        vd = &s->vars[idx];
31608
0
        if (vd->var_name == var_name) {
31609
0
            if (op == OP_scope_put_var || op == OP_scope_make_ref) {
31610
0
                if (vd->is_const) {
31611
0
                    dbuf_putc(bc, OP_throw_error);
31612
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
31613
0
                    dbuf_putc(bc, JS_THROW_VAR_RO);
31614
0
                    goto done;
31615
0
                }
31616
0
            }
31617
0
            var_idx = idx;
31618
0
            break;
31619
0
        } else
31620
0
        if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
31621
0
            dbuf_putc(bc, OP_get_loc);
31622
0
            dbuf_put_u16(bc, idx);
31623
0
            var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
31624
0
        }
31625
0
        idx = vd->scope_next;
31626
0
    }
31627
9
    is_arg_scope = (idx == ARG_SCOPE_END);
31628
9
    if (var_idx < 0) {
31629
        /* argument scope: variables are not visible but pseudo
31630
           variables are visible */
31631
9
        if (!is_arg_scope) {
31632
9
            var_idx = find_var(ctx, s, var_name);
31633
9
        }
31634
31635
9
        if (var_idx < 0 && is_pseudo_var)
31636
0
            var_idx = resolve_pseudo_var(ctx, s, var_name);
31637
31638
9
        if (var_idx < 0 && var_name == JS_ATOM_arguments &&
31639
9
            s->has_arguments_binding) {
31640
            /* 'arguments' pseudo variable */
31641
0
            var_idx = add_arguments_var(ctx, s);
31642
0
        }
31643
9
        if (var_idx < 0 && s->is_func_expr && var_name == s->func_name) {
31644
            /* add a new variable with the function name */
31645
0
            var_idx = add_func_var(ctx, s, var_name);
31646
0
        }
31647
9
    }
31648
9
    if (var_idx >= 0) {
31649
0
        if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&
31650
0
            !(var_idx & ARGUMENT_VAR_OFFSET) &&
31651
0
            s->vars[var_idx].is_const) {
31652
            /* only happens when assigning a function expression name
31653
               in strict mode */
31654
0
            dbuf_putc(bc, OP_throw_error);
31655
0
            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
31656
0
            dbuf_putc(bc, JS_THROW_VAR_RO);
31657
0
            goto done;
31658
0
        }
31659
        /* OP_scope_put_var_init is only used to initialize a
31660
           lexical variable, so it is never used in a with or var object. It
31661
           can be used with a closure (module global variable case). */
31662
0
        switch (op) {
31663
0
        case OP_scope_make_ref:
31664
0
            if (!(var_idx & ARGUMENT_VAR_OFFSET) &&
31665
0
                s->vars[var_idx].var_kind == JS_VAR_FUNCTION_NAME) {
31666
                /* Create a dummy object reference for the func_var */
31667
0
                dbuf_putc(bc, OP_object);
31668
0
                dbuf_putc(bc, OP_get_loc);
31669
0
                dbuf_put_u16(bc, var_idx);
31670
0
                dbuf_putc(bc, OP_define_field);
31671
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
31672
0
                dbuf_putc(bc, OP_push_atom_value);
31673
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
31674
0
            } else
31675
0
            if (label_done == -1 && can_opt_put_ref_value(bc_buf, ls->pos)) {
31676
0
                int get_op;
31677
0
                if (var_idx & ARGUMENT_VAR_OFFSET) {
31678
0
                    get_op = OP_get_arg;
31679
0
                    var_idx -= ARGUMENT_VAR_OFFSET;
31680
0
                } else {
31681
0
                    if (s->vars[var_idx].is_lexical)
31682
0
                        get_op = OP_get_loc_check;
31683
0
                    else
31684
0
                        get_op = OP_get_loc;
31685
0
                }
31686
0
                pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,
31687
0
                                                   pos_next, get_op, var_idx);
31688
0
            } else {
31689
                /* Create a dummy object with a named slot that is
31690
                   a reference to the local variable */
31691
0
                if (var_idx & ARGUMENT_VAR_OFFSET) {
31692
0
                    dbuf_putc(bc, OP_make_arg_ref);
31693
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
31694
0
                    dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
31695
0
                } else {
31696
0
                    dbuf_putc(bc, OP_make_loc_ref);
31697
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
31698
0
                    dbuf_put_u16(bc, var_idx);
31699
0
                }
31700
0
            }
31701
0
            break;
31702
0
        case OP_scope_get_ref:
31703
0
            dbuf_putc(bc, OP_undefined);
31704
            /* fall thru */
31705
0
        case OP_scope_get_var_checkthis:
31706
0
        case OP_scope_get_var_undef:
31707
0
        case OP_scope_get_var:
31708
0
        case OP_scope_put_var:
31709
0
        case OP_scope_put_var_init:
31710
0
            is_put = (op == OP_scope_put_var || op == OP_scope_put_var_init);
31711
0
            if (var_idx & ARGUMENT_VAR_OFFSET) {
31712
0
                dbuf_putc(bc, OP_get_arg + is_put);
31713
0
                dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
31714
0
            } else {
31715
0
                if (is_put) {
31716
0
                    if (s->vars[var_idx].is_lexical) {
31717
0
                        if (op == OP_scope_put_var_init) {
31718
                            /* 'this' can only be initialized once */
31719
0
                            if (var_name == JS_ATOM_this)
31720
0
                                dbuf_putc(bc, OP_put_loc_check_init);
31721
0
                            else
31722
0
                                dbuf_putc(bc, OP_put_loc);
31723
0
                        } else {
31724
0
                            dbuf_putc(bc, OP_put_loc_check);
31725
0
                        }
31726
0
                    } else {
31727
0
                        dbuf_putc(bc, OP_put_loc);
31728
0
                    }
31729
0
                } else {
31730
0
                    if (s->vars[var_idx].is_lexical) {
31731
0
                        if (op == OP_scope_get_var_checkthis) {
31732
                            /* only used for 'this' return in derived class constructors */
31733
0
                            dbuf_putc(bc, OP_get_loc_checkthis);
31734
0
                        } else {
31735
0
                            dbuf_putc(bc, OP_get_loc_check);
31736
0
                        }
31737
0
                    } else {
31738
0
                        dbuf_putc(bc, OP_get_loc);
31739
0
                    }
31740
0
                }
31741
0
                dbuf_put_u16(bc, var_idx);
31742
0
            }
31743
0
            break;
31744
0
        case OP_scope_delete_var:
31745
0
            dbuf_putc(bc, OP_push_false);
31746
0
            break;
31747
0
        }
31748
0
        goto done;
31749
0
    }
31750
    /* check eval object */
31751
9
    if (!is_arg_scope && s->var_object_idx >= 0 && !is_pseudo_var) {
31752
0
        dbuf_putc(bc, OP_get_loc);
31753
0
        dbuf_put_u16(bc, s->var_object_idx);
31754
0
        var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
31755
0
    }
31756
    /* check eval object in argument scope */
31757
9
    if (s->arg_var_object_idx >= 0 && !is_pseudo_var) {
31758
0
        dbuf_putc(bc, OP_get_loc);
31759
0
        dbuf_put_u16(bc, s->arg_var_object_idx);
31760
0
        var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
31761
0
    }
31762
31763
    /* check parent scopes */
31764
9
    for (fd = s; fd->parent;) {
31765
0
        scope_level = fd->parent_scope_level;
31766
0
        fd = fd->parent;
31767
0
        for (idx = fd->scopes[scope_level].first; idx >= 0;) {
31768
0
            vd = &fd->vars[idx];
31769
0
            if (vd->var_name == var_name) {
31770
0
                if (op == OP_scope_put_var || op == OP_scope_make_ref) {
31771
0
                    if (vd->is_const) {
31772
0
                        dbuf_putc(bc, OP_throw_error);
31773
0
                        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
31774
0
                        dbuf_putc(bc, JS_THROW_VAR_RO);
31775
0
                        goto done;
31776
0
                    }
31777
0
                }
31778
0
                var_idx = idx;
31779
0
                break;
31780
0
            } else if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
31781
0
                vd->is_captured = 1;
31782
0
                idx = get_closure_var(ctx, s, fd, FALSE, idx, vd->var_name, FALSE, FALSE, JS_VAR_NORMAL);
31783
0
                if (idx >= 0) {
31784
0
                    dbuf_putc(bc, OP_get_var_ref);
31785
0
                    dbuf_put_u16(bc, idx);
31786
0
                    var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
31787
0
                }
31788
0
            }
31789
0
            idx = vd->scope_next;
31790
0
        }
31791
0
        is_arg_scope = (idx == ARG_SCOPE_END);
31792
0
        if (var_idx >= 0)
31793
0
            break;
31794
31795
0
        if (!is_arg_scope) {
31796
0
            var_idx = find_var(ctx, fd, var_name);
31797
0
            if (var_idx >= 0)
31798
0
                break;
31799
0
        }
31800
0
        if (is_pseudo_var) {
31801
0
            var_idx = resolve_pseudo_var(ctx, fd, var_name);
31802
0
            if (var_idx >= 0)
31803
0
                break;
31804
0
        }
31805
0
        if (var_name == JS_ATOM_arguments && fd->has_arguments_binding) {
31806
0
            var_idx = add_arguments_var(ctx, fd);
31807
0
            break;
31808
0
        }
31809
0
        if (fd->is_func_expr && fd->func_name == var_name) {
31810
            /* add a new variable with the function name */
31811
0
            var_idx = add_func_var(ctx, fd, var_name);
31812
0
            break;
31813
0
        }
31814
31815
        /* check eval object */
31816
0
        if (!is_arg_scope && fd->var_object_idx >= 0 && !is_pseudo_var) {
31817
0
            vd = &fd->vars[fd->var_object_idx];
31818
0
            vd->is_captured = 1;
31819
0
            idx = get_closure_var(ctx, s, fd, FALSE,
31820
0
                                  fd->var_object_idx, vd->var_name,
31821
0
                                  FALSE, FALSE, JS_VAR_NORMAL);
31822
0
            dbuf_putc(bc, OP_get_var_ref);
31823
0
            dbuf_put_u16(bc, idx);
31824
0
            var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
31825
0
        }
31826
31827
        /* check eval object in argument scope */
31828
0
        if (fd->arg_var_object_idx >= 0 && !is_pseudo_var) {
31829
0
            vd = &fd->vars[fd->arg_var_object_idx];
31830
0
            vd->is_captured = 1;
31831
0
            idx = get_closure_var(ctx, s, fd, FALSE,
31832
0
                                  fd->arg_var_object_idx, vd->var_name,
31833
0
                                  FALSE, FALSE, JS_VAR_NORMAL);
31834
0
            dbuf_putc(bc, OP_get_var_ref);
31835
0
            dbuf_put_u16(bc, idx);
31836
0
            var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
31837
0
        }
31838
31839
0
        if (fd->is_eval)
31840
0
            break; /* it it necessarily the top level function */
31841
0
    }
31842
31843
    /* check direct eval scope (in the closure of the eval function
31844
       which is necessarily at the top level) */
31845
9
    if (!fd)
31846
0
        fd = s;
31847
9
    if (var_idx < 0 && fd->is_eval) {
31848
9
        int idx1;
31849
19
        for (idx1 = 0; idx1 < fd->closure_var_count; idx1++) {
31850
14
            JSClosureVar *cv = &fd->closure_var[idx1];
31851
14
            if (var_name == cv->var_name) {
31852
4
                if (fd != s) {
31853
0
                    idx = get_closure_var2(ctx, s, fd,
31854
0
                                           FALSE,
31855
0
                                           cv->is_arg, idx1,
31856
0
                                           cv->var_name, cv->is_const,
31857
0
                                           cv->is_lexical, cv->var_kind);
31858
4
                } else {
31859
4
                    idx = idx1;
31860
4
                }
31861
4
                goto has_idx;
31862
10
            } else if ((cv->var_name == JS_ATOM__var_ ||
31863
10
                        cv->var_name == JS_ATOM__arg_var_ ||
31864
10
                        cv->var_name == JS_ATOM__with_) && !is_pseudo_var) {
31865
0
                int is_with = (cv->var_name == JS_ATOM__with_);
31866
0
                if (fd != s) {
31867
0
                    idx = get_closure_var2(ctx, s, fd,
31868
0
                                           FALSE,
31869
0
                                           cv->is_arg, idx1,
31870
0
                                           cv->var_name, FALSE, FALSE,
31871
0
                                           JS_VAR_NORMAL);
31872
0
                } else {
31873
0
                    idx = idx1;
31874
0
                }
31875
0
                dbuf_putc(bc, OP_get_var_ref);
31876
0
                dbuf_put_u16(bc, idx);
31877
0
                var_object_test(ctx, s, var_name, op, bc, &label_done, is_with);
31878
0
            }
31879
14
        }
31880
9
    }
31881
31882
5
    if (var_idx >= 0) {
31883
        /* find the corresponding closure variable */
31884
0
        if (var_idx & ARGUMENT_VAR_OFFSET) {
31885
0
            fd->args[var_idx - ARGUMENT_VAR_OFFSET].is_captured = 1;
31886
0
            idx = get_closure_var(ctx, s, fd,
31887
0
                                  TRUE, var_idx - ARGUMENT_VAR_OFFSET,
31888
0
                                  var_name, FALSE, FALSE, JS_VAR_NORMAL);
31889
0
        } else {
31890
0
            fd->vars[var_idx].is_captured = 1;
31891
0
            idx = get_closure_var(ctx, s, fd,
31892
0
                                  FALSE, var_idx,
31893
0
                                  var_name,
31894
0
                                  fd->vars[var_idx].is_const,
31895
0
                                  fd->vars[var_idx].is_lexical,
31896
0
                                  fd->vars[var_idx].var_kind);
31897
0
        }
31898
0
        if (idx >= 0) {
31899
4
        has_idx:
31900
4
            if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&
31901
4
                s->closure_var[idx].is_const) {
31902
0
                dbuf_putc(bc, OP_throw_error);
31903
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
31904
0
                dbuf_putc(bc, JS_THROW_VAR_RO);
31905
0
                goto done;
31906
0
            }
31907
4
            switch (op) {
31908
0
            case OP_scope_make_ref:
31909
0
                if (s->closure_var[idx].var_kind == JS_VAR_FUNCTION_NAME) {
31910
                    /* Create a dummy object reference for the func_var */
31911
0
                    dbuf_putc(bc, OP_object);
31912
0
                    dbuf_putc(bc, OP_get_var_ref);
31913
0
                    dbuf_put_u16(bc, idx);
31914
0
                    dbuf_putc(bc, OP_define_field);
31915
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
31916
0
                    dbuf_putc(bc, OP_push_atom_value);
31917
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
31918
0
                } else
31919
0
                if (label_done == -1 &&
31920
0
                    can_opt_put_ref_value(bc_buf, ls->pos)) {
31921
0
                    int get_op;
31922
0
                    if (s->closure_var[idx].is_lexical)
31923
0
                        get_op = OP_get_var_ref_check;
31924
0
                    else
31925
0
                        get_op = OP_get_var_ref;
31926
0
                    pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,
31927
0
                                                       pos_next,
31928
0
                                                       get_op, idx);
31929
0
                } else {
31930
                    /* Create a dummy object with a named slot that is
31931
                       a reference to the closure variable */
31932
0
                    dbuf_putc(bc, OP_make_var_ref_ref);
31933
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
31934
0
                    dbuf_put_u16(bc, idx);
31935
0
                }
31936
0
                break;
31937
0
            case OP_scope_get_ref:
31938
                /* XXX: should create a dummy object with a named slot that is
31939
                   a reference to the closure variable */
31940
0
                dbuf_putc(bc, OP_undefined);
31941
                /* fall thru */
31942
0
            case OP_scope_get_var_undef:
31943
4
            case OP_scope_get_var:
31944
4
            case OP_scope_put_var:
31945
4
            case OP_scope_put_var_init:
31946
4
                is_put = (op == OP_scope_put_var ||
31947
4
                          op == OP_scope_put_var_init);
31948
4
                if (is_put) {
31949
0
                    if (s->closure_var[idx].is_lexical) {
31950
0
                        if (op == OP_scope_put_var_init) {
31951
                            /* 'this' can only be initialized once */
31952
0
                            if (var_name == JS_ATOM_this)
31953
0
                                dbuf_putc(bc, OP_put_var_ref_check_init);
31954
0
                            else
31955
0
                                dbuf_putc(bc, OP_put_var_ref);
31956
0
                        } else {
31957
0
                            dbuf_putc(bc, OP_put_var_ref_check);
31958
0
                        }
31959
0
                    } else {
31960
0
                        dbuf_putc(bc, OP_put_var_ref);
31961
0
                    }
31962
4
                } else {
31963
4
                    if (s->closure_var[idx].is_lexical) {
31964
4
                        dbuf_putc(bc, OP_get_var_ref_check);
31965
4
                    } else {
31966
0
                        dbuf_putc(bc, OP_get_var_ref);
31967
0
                    }
31968
4
                }
31969
4
                dbuf_put_u16(bc, idx);
31970
4
                break;
31971
0
            case OP_scope_delete_var:
31972
0
                dbuf_putc(bc, OP_push_false);
31973
0
                break;
31974
4
            }
31975
4
            goto done;
31976
4
        }
31977
0
    }
31978
31979
    /* global variable access */
31980
31981
5
    switch (op) {
31982
0
    case OP_scope_make_ref:
31983
0
        if (label_done == -1 && can_opt_put_global_ref_value(bc_buf, ls->pos)) {
31984
0
            pos_next = optimize_scope_make_global_ref(ctx, s, bc, bc_buf, ls,
31985
0
                                                      pos_next, var_name);
31986
0
        } else {
31987
0
            dbuf_putc(bc, OP_make_var_ref);
31988
0
            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
31989
0
        }
31990
0
        break;
31991
0
    case OP_scope_get_ref:
31992
        /* XXX: should create a dummy object with a named slot that is
31993
           a reference to the global variable */
31994
0
        dbuf_putc(bc, OP_undefined);
31995
0
        dbuf_putc(bc, OP_get_var);
31996
0
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
31997
0
        break;
31998
0
    case OP_scope_get_var_undef:
31999
5
    case OP_scope_get_var:
32000
5
    case OP_scope_put_var:
32001
5
        dbuf_putc(bc, OP_get_var_undef + (op - OP_scope_get_var_undef));
32002
5
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
32003
5
        break;
32004
0
    case OP_scope_put_var_init:
32005
0
        dbuf_putc(bc, OP_put_var_init);
32006
0
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
32007
0
        break;
32008
0
    case OP_scope_delete_var:
32009
0
        dbuf_putc(bc, OP_delete_var);
32010
0
        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
32011
0
        break;
32012
5
    }
32013
9
done:
32014
9
    if (label_done >= 0) {
32015
0
        dbuf_putc(bc, OP_label);
32016
0
        dbuf_put_u32(bc, label_done);
32017
0
        s->label_slots[label_done].pos2 = bc->size;
32018
0
    }
32019
9
    return pos_next;
32020
5
}
32021
32022
/* search in all scopes */
32023
static int find_private_class_field_all(JSContext *ctx, JSFunctionDef *fd,
32024
                                        JSAtom name, int scope_level)
32025
0
{
32026
0
    int idx;
32027
32028
0
    idx = fd->scopes[scope_level].first;
32029
0
    while (idx >= 0) {
32030
0
        if (fd->vars[idx].var_name == name)
32031
0
            return idx;
32032
0
        idx = fd->vars[idx].scope_next;
32033
0
    }
32034
0
    return -1;
32035
0
}
32036
32037
static void get_loc_or_ref(DynBuf *bc, BOOL is_ref, int idx)
32038
0
{
32039
    /* if the field is not initialized, the error is catched when
32040
       accessing it */
32041
0
    if (is_ref)
32042
0
        dbuf_putc(bc, OP_get_var_ref);
32043
0
    else
32044
0
        dbuf_putc(bc, OP_get_loc);
32045
0
    dbuf_put_u16(bc, idx);
32046
0
}
32047
32048
static int resolve_scope_private_field1(JSContext *ctx,
32049
                                        BOOL *pis_ref, int *pvar_kind,
32050
                                        JSFunctionDef *s,
32051
                                        JSAtom var_name, int scope_level)
32052
0
{
32053
0
    int idx, var_kind;
32054
0
    JSFunctionDef *fd;
32055
0
    BOOL is_ref;
32056
32057
0
    fd = s;
32058
0
    is_ref = FALSE;
32059
0
    for(;;) {
32060
0
        idx = find_private_class_field_all(ctx, fd, var_name, scope_level);
32061
0
        if (idx >= 0) {
32062
0
            var_kind = fd->vars[idx].var_kind;
32063
0
            if (is_ref) {
32064
0
                idx = get_closure_var(ctx, s, fd, FALSE, idx, var_name,
32065
0
                                      TRUE, TRUE, JS_VAR_NORMAL);
32066
0
                if (idx < 0)
32067
0
                    return -1;
32068
0
            }
32069
0
            break;
32070
0
        }
32071
0
        scope_level = fd->parent_scope_level;
32072
0
        if (!fd->parent) {
32073
0
            if (fd->is_eval) {
32074
                /* closure of the eval function (top level) */
32075
0
                for (idx = 0; idx < fd->closure_var_count; idx++) {
32076
0
                    JSClosureVar *cv = &fd->closure_var[idx];
32077
0
                    if (cv->var_name == var_name) {
32078
0
                        var_kind = cv->var_kind;
32079
0
                        is_ref = TRUE;
32080
0
                        if (fd != s) {
32081
0
                            idx = get_closure_var2(ctx, s, fd,
32082
0
                                                   FALSE,
32083
0
                                                   cv->is_arg, idx,
32084
0
                                                   cv->var_name, cv->is_const,
32085
0
                                                   cv->is_lexical,
32086
0
                                                   cv->var_kind);
32087
0
                            if (idx < 0)
32088
0
                                return -1;
32089
0
                        }
32090
0
                        goto done;
32091
0
                    }
32092
0
                }
32093
0
            }
32094
            /* XXX: no line number info */
32095
0
            JS_ThrowSyntaxErrorAtom(ctx, "undefined private field '%s'",
32096
0
                                    var_name);
32097
0
            return -1;
32098
0
        } else {
32099
0
            fd = fd->parent;
32100
0
        }
32101
0
        is_ref = TRUE;
32102
0
    }
32103
0
 done:
32104
0
    *pis_ref = is_ref;
32105
0
    *pvar_kind = var_kind;
32106
0
    return idx;
32107
0
}
32108
32109
/* return 0 if OK or -1 if the private field could not be resolved */
32110
static int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s,
32111
                                       JSAtom var_name, int scope_level, int op,
32112
                                       DynBuf *bc)
32113
0
{
32114
0
    int idx, var_kind;
32115
0
    BOOL is_ref;
32116
32117
0
    idx = resolve_scope_private_field1(ctx, &is_ref, &var_kind, s,
32118
0
                                       var_name, scope_level);
32119
0
    if (idx < 0)
32120
0
        return -1;
32121
0
    assert(var_kind != JS_VAR_NORMAL);
32122
0
    switch (op) {
32123
0
    case OP_scope_get_private_field:
32124
0
    case OP_scope_get_private_field2:
32125
0
        switch(var_kind) {
32126
0
        case JS_VAR_PRIVATE_FIELD:
32127
0
            if (op == OP_scope_get_private_field2)
32128
0
                dbuf_putc(bc, OP_dup);
32129
0
            get_loc_or_ref(bc, is_ref, idx);
32130
0
            dbuf_putc(bc, OP_get_private_field);
32131
0
            break;
32132
0
        case JS_VAR_PRIVATE_METHOD:
32133
0
            get_loc_or_ref(bc, is_ref, idx);
32134
0
            dbuf_putc(bc, OP_check_brand);
32135
0
            if (op != OP_scope_get_private_field2)
32136
0
                dbuf_putc(bc, OP_nip);
32137
0
            break;
32138
0
        case JS_VAR_PRIVATE_GETTER:
32139
0
        case JS_VAR_PRIVATE_GETTER_SETTER:
32140
0
            if (op == OP_scope_get_private_field2)
32141
0
                dbuf_putc(bc, OP_dup);
32142
0
            get_loc_or_ref(bc, is_ref, idx);
32143
0
            dbuf_putc(bc, OP_check_brand);
32144
0
            dbuf_putc(bc, OP_call_method);
32145
0
            dbuf_put_u16(bc, 0);
32146
0
            break;
32147
0
        case JS_VAR_PRIVATE_SETTER:
32148
            /* XXX: add clearer error message */
32149
0
            dbuf_putc(bc, OP_throw_error);
32150
0
            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
32151
0
            dbuf_putc(bc, JS_THROW_VAR_RO);
32152
0
            break;
32153
0
        default:
32154
0
            abort();
32155
0
        }
32156
0
        break;
32157
0
    case OP_scope_put_private_field:
32158
0
        switch(var_kind) {
32159
0
        case JS_VAR_PRIVATE_FIELD:
32160
0
            get_loc_or_ref(bc, is_ref, idx);
32161
0
            dbuf_putc(bc, OP_put_private_field);
32162
0
            break;
32163
0
        case JS_VAR_PRIVATE_METHOD:
32164
0
        case JS_VAR_PRIVATE_GETTER:
32165
            /* XXX: add clearer error message */
32166
0
            dbuf_putc(bc, OP_throw_error);
32167
0
            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
32168
0
            dbuf_putc(bc, JS_THROW_VAR_RO);
32169
0
            break;
32170
0
        case JS_VAR_PRIVATE_SETTER:
32171
0
        case JS_VAR_PRIVATE_GETTER_SETTER:
32172
0
            {
32173
0
                JSAtom setter_name = get_private_setter_name(ctx, var_name);
32174
0
                if (setter_name == JS_ATOM_NULL)
32175
0
                    return -1;
32176
0
                idx = resolve_scope_private_field1(ctx, &is_ref,
32177
0
                                                   &var_kind, s,
32178
0
                                                   setter_name, scope_level);
32179
0
                JS_FreeAtom(ctx, setter_name);
32180
0
                if (idx < 0)
32181
0
                    return -1;
32182
0
                assert(var_kind == JS_VAR_PRIVATE_SETTER);
32183
0
                get_loc_or_ref(bc, is_ref, idx);
32184
0
                dbuf_putc(bc, OP_swap);
32185
                /* obj func value */
32186
0
                dbuf_putc(bc, OP_rot3r);
32187
                /* value obj func */
32188
0
                dbuf_putc(bc, OP_check_brand);
32189
0
                dbuf_putc(bc, OP_rot3l);
32190
                /* obj func value */
32191
0
                dbuf_putc(bc, OP_call_method);
32192
0
                dbuf_put_u16(bc, 1);
32193
0
                dbuf_putc(bc, OP_drop);
32194
0
            }
32195
0
            break;
32196
0
        default:
32197
0
            abort();
32198
0
        }
32199
0
        break;
32200
0
    case OP_scope_in_private_field:
32201
0
        get_loc_or_ref(bc, is_ref, idx);
32202
0
        dbuf_putc(bc, OP_private_in);
32203
0
        break;
32204
0
    default:
32205
0
        abort();
32206
0
    }
32207
0
    return 0;
32208
0
}
32209
32210
static void mark_eval_captured_variables(JSContext *ctx, JSFunctionDef *s,
32211
                                         int scope_level)
32212
0
{
32213
0
    int idx;
32214
0
    JSVarDef *vd;
32215
32216
0
    for (idx = s->scopes[scope_level].first; idx >= 0;) {
32217
0
        vd = &s->vars[idx];
32218
0
        vd->is_captured = 1;
32219
0
        idx = vd->scope_next;
32220
0
    }
32221
0
}
32222
32223
/* XXX: should handle the argument scope generically */
32224
static BOOL is_var_in_arg_scope(const JSVarDef *vd)
32225
0
{
32226
0
    return (vd->var_name == JS_ATOM_home_object ||
32227
0
            vd->var_name == JS_ATOM_this_active_func ||
32228
0
            vd->var_name == JS_ATOM_new_target ||
32229
0
            vd->var_name == JS_ATOM_this ||
32230
0
            vd->var_name == JS_ATOM__arg_var_ ||
32231
0
            vd->var_kind == JS_VAR_FUNCTION_NAME);
32232
0
}
32233
32234
static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
32235
0
{
32236
0
    JSFunctionDef *fd;
32237
0
    JSVarDef *vd;
32238
0
    int i, scope_level, scope_idx;
32239
0
    BOOL has_arguments_binding, has_this_binding, is_arg_scope;
32240
32241
    /* in non strict mode, variables are created in the caller's
32242
       environment object */
32243
0
    if (!s->is_eval && !(s->js_mode & JS_MODE_STRICT)) {
32244
0
        s->var_object_idx = add_var(ctx, s, JS_ATOM__var_);
32245
0
        if (s->has_parameter_expressions) {
32246
            /* an additional variable object is needed for the
32247
               argument scope */
32248
0
            s->arg_var_object_idx = add_var(ctx, s, JS_ATOM__arg_var_);
32249
0
        }
32250
0
    }
32251
32252
    /* eval can potentially use 'arguments' so we must define it */
32253
0
    has_this_binding = s->has_this_binding;
32254
0
    if (has_this_binding) {
32255
0
        if (s->this_var_idx < 0)
32256
0
            s->this_var_idx = add_var_this(ctx, s);
32257
0
        if (s->new_target_var_idx < 0)
32258
0
            s->new_target_var_idx = add_var(ctx, s, JS_ATOM_new_target);
32259
0
        if (s->is_derived_class_constructor && s->this_active_func_var_idx < 0)
32260
0
            s->this_active_func_var_idx = add_var(ctx, s, JS_ATOM_this_active_func);
32261
0
        if (s->has_home_object && s->home_object_var_idx < 0)
32262
0
            s->home_object_var_idx = add_var(ctx, s, JS_ATOM_home_object);
32263
0
    }
32264
0
    has_arguments_binding = s->has_arguments_binding;
32265
0
    if (has_arguments_binding) {
32266
0
        add_arguments_var(ctx, s);
32267
        /* also add an arguments binding in the argument scope to
32268
           raise an error if a direct eval in the argument scope tries
32269
           to redefine it */
32270
0
        if (s->has_parameter_expressions && !(s->js_mode & JS_MODE_STRICT))
32271
0
            add_arguments_arg(ctx, s);
32272
0
    }
32273
0
    if (s->is_func_expr && s->func_name != JS_ATOM_NULL)
32274
0
        add_func_var(ctx, s, s->func_name);
32275
32276
    /* eval can use all the variables of the enclosing functions, so
32277
       they must be all put in the closure. The closure variables are
32278
       ordered by scope. It works only because no closure are created
32279
       before. */
32280
0
    assert(s->is_eval || s->closure_var_count == 0);
32281
32282
    /* XXX: inefficient, but eval performance is less critical */
32283
0
    fd = s;
32284
0
    for(;;) {
32285
0
        scope_level = fd->parent_scope_level;
32286
0
        fd = fd->parent;
32287
0
        if (!fd)
32288
0
            break;
32289
        /* add 'this' if it was not previously added */
32290
0
        if (!has_this_binding && fd->has_this_binding) {
32291
0
            if (fd->this_var_idx < 0)
32292
0
                fd->this_var_idx = add_var_this(ctx, fd);
32293
0
            if (fd->new_target_var_idx < 0)
32294
0
                fd->new_target_var_idx = add_var(ctx, fd, JS_ATOM_new_target);
32295
0
            if (fd->is_derived_class_constructor && fd->this_active_func_var_idx < 0)
32296
0
                fd->this_active_func_var_idx = add_var(ctx, fd, JS_ATOM_this_active_func);
32297
0
            if (fd->has_home_object && fd->home_object_var_idx < 0)
32298
0
                fd->home_object_var_idx = add_var(ctx, fd, JS_ATOM_home_object);
32299
0
            has_this_binding = TRUE;
32300
0
        }
32301
        /* add 'arguments' if it was not previously added */
32302
0
        if (!has_arguments_binding && fd->has_arguments_binding) {
32303
0
            add_arguments_var(ctx, fd);
32304
0
            has_arguments_binding = TRUE;
32305
0
        }
32306
        /* add function name */
32307
0
        if (fd->is_func_expr && fd->func_name != JS_ATOM_NULL)
32308
0
            add_func_var(ctx, fd, fd->func_name);
32309
32310
        /* add lexical variables */
32311
0
        scope_idx = fd->scopes[scope_level].first;
32312
0
        while (scope_idx >= 0) {
32313
0
            vd = &fd->vars[scope_idx];
32314
0
            vd->is_captured = 1;
32315
0
            get_closure_var(ctx, s, fd, FALSE, scope_idx,
32316
0
                            vd->var_name, vd->is_const, vd->is_lexical, vd->var_kind);
32317
0
            scope_idx = vd->scope_next;
32318
0
        }
32319
0
        is_arg_scope = (scope_idx == ARG_SCOPE_END);
32320
0
        if (!is_arg_scope) {
32321
            /* add unscoped variables */
32322
            /* XXX: propagate is_const and var_kind too ? */
32323
0
            for(i = 0; i < fd->arg_count; i++) {
32324
0
                vd = &fd->args[i];
32325
0
                if (vd->var_name != JS_ATOM_NULL) {
32326
0
                    get_closure_var(ctx, s, fd,
32327
0
                                    TRUE, i, vd->var_name, FALSE,
32328
0
                                    vd->is_lexical, JS_VAR_NORMAL);
32329
0
                }
32330
0
            }
32331
0
            for(i = 0; i < fd->var_count; i++) {
32332
0
                vd = &fd->vars[i];
32333
                /* do not close top level last result */
32334
0
                if (vd->scope_level == 0 &&
32335
0
                    vd->var_name != JS_ATOM__ret_ &&
32336
0
                    vd->var_name != JS_ATOM_NULL) {
32337
0
                    get_closure_var(ctx, s, fd,
32338
0
                                    FALSE, i, vd->var_name, FALSE,
32339
0
                                    vd->is_lexical, JS_VAR_NORMAL);
32340
0
                }
32341
0
            }
32342
0
        } else {
32343
0
            for(i = 0; i < fd->var_count; i++) {
32344
0
                vd = &fd->vars[i];
32345
                /* do not close top level last result */
32346
0
                if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
32347
0
                    get_closure_var(ctx, s, fd,
32348
0
                                    FALSE, i, vd->var_name, FALSE,
32349
0
                                    vd->is_lexical, JS_VAR_NORMAL);
32350
0
                }
32351
0
            }
32352
0
        }
32353
0
        if (fd->is_eval) {
32354
0
            int idx;
32355
            /* add direct eval variables (we are necessarily at the
32356
               top level) */
32357
0
            for (idx = 0; idx < fd->closure_var_count; idx++) {
32358
0
                JSClosureVar *cv = &fd->closure_var[idx];
32359
0
                get_closure_var2(ctx, s, fd,
32360
0
                                 FALSE, cv->is_arg,
32361
0
                                 idx, cv->var_name, cv->is_const,
32362
0
                                 cv->is_lexical, cv->var_kind);
32363
0
            }
32364
0
        }
32365
0
    }
32366
0
}
32367
32368
static void set_closure_from_var(JSContext *ctx, JSClosureVar *cv,
32369
                                 JSVarDef *vd, int var_idx)
32370
0
{
32371
0
    cv->is_local = TRUE;
32372
0
    cv->is_arg = FALSE;
32373
0
    cv->is_const = vd->is_const;
32374
0
    cv->is_lexical = vd->is_lexical;
32375
0
    cv->var_kind = vd->var_kind;
32376
0
    cv->var_idx = var_idx;
32377
0
    cv->var_name = JS_DupAtom(ctx, vd->var_name);
32378
0
}
32379
32380
/* for direct eval compilation: add references to the variables of the
32381
   calling function */
32382
static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
32383
                                             JSFunctionBytecode *b, int scope_idx)
32384
0
{
32385
0
    int i, count;
32386
0
    JSVarDef *vd;
32387
0
    BOOL is_arg_scope;
32388
32389
0
    count = b->arg_count + b->var_count + b->closure_var_count;
32390
0
    s->closure_var = NULL;
32391
0
    s->closure_var_count = 0;
32392
0
    s->closure_var_size = count;
32393
0
    if (count == 0)
32394
0
        return 0;
32395
0
    s->closure_var = js_malloc(ctx, sizeof(s->closure_var[0]) * count);
32396
0
    if (!s->closure_var)
32397
0
        return -1;
32398
    /* Add lexical variables in scope at the point of evaluation */
32399
0
    for (i = scope_idx; i >= 0;) {
32400
0
        vd = &b->vardefs[b->arg_count + i];
32401
0
        if (vd->scope_level > 0) {
32402
0
            JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
32403
0
            set_closure_from_var(ctx, cv, vd, i);
32404
0
        }
32405
0
        i = vd->scope_next;
32406
0
    }
32407
0
    is_arg_scope = (i == ARG_SCOPE_END);
32408
0
    if (!is_arg_scope) {
32409
        /* Add argument variables */
32410
0
        for(i = 0; i < b->arg_count; i++) {
32411
0
            JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
32412
0
            vd = &b->vardefs[i];
32413
0
            cv->is_local = TRUE;
32414
0
            cv->is_arg = TRUE;
32415
0
            cv->is_const = FALSE;
32416
0
            cv->is_lexical = FALSE;
32417
0
            cv->var_kind = JS_VAR_NORMAL;
32418
0
            cv->var_idx = i;
32419
0
            cv->var_name = JS_DupAtom(ctx, vd->var_name);
32420
0
        }
32421
        /* Add local non lexical variables */
32422
0
        for(i = 0; i < b->var_count; i++) {
32423
0
            vd = &b->vardefs[b->arg_count + i];
32424
0
            if (vd->scope_level == 0 && vd->var_name != JS_ATOM__ret_) {
32425
0
                JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
32426
0
                set_closure_from_var(ctx, cv, vd, i);
32427
0
            }
32428
0
        }
32429
0
    } else {
32430
        /* only add pseudo variables */
32431
0
        for(i = 0; i < b->var_count; i++) {
32432
0
            vd = &b->vardefs[b->arg_count + i];
32433
0
            if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
32434
0
                JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
32435
0
                set_closure_from_var(ctx, cv, vd, i);
32436
0
            }
32437
0
        }
32438
0
    }
32439
0
    for(i = 0; i < b->closure_var_count; i++) {
32440
0
        JSClosureVar *cv0 = &b->closure_var[i];
32441
0
        JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
32442
0
        cv->is_local = FALSE;
32443
0
        cv->is_arg = cv0->is_arg;
32444
0
        cv->is_const = cv0->is_const;
32445
0
        cv->is_lexical = cv0->is_lexical;
32446
0
        cv->var_kind = cv0->var_kind;
32447
0
        cv->var_idx = i;
32448
0
        cv->var_name = JS_DupAtom(ctx, cv0->var_name);
32449
0
    }
32450
0
    return 0;
32451
0
}
32452
32453
typedef struct CodeContext {
32454
    const uint8_t *bc_buf; /* code buffer */
32455
    int bc_len;   /* length of the code buffer */
32456
    int pos;      /* position past the matched code pattern */
32457
    int line_num; /* last visited OP_line_num parameter or -1 */
32458
    int op;
32459
    int idx;
32460
    int label;
32461
    int val;
32462
    JSAtom atom;
32463
} CodeContext;
32464
32465
10
#define M2(op1, op2)            ((op1) | ((op2) << 8))
32466
0
#define M3(op1, op2, op3)       ((op1) | ((op2) << 8) | ((op3) << 16))
32467
0
#define M4(op1, op2, op3, op4)  ((op1) | ((op2) << 8) | ((op3) << 16) | ((op4) << 24))
32468
32469
static BOOL code_match(CodeContext *s, int pos, ...)
32470
24
{
32471
24
    const uint8_t *tab = s->bc_buf;
32472
24
    int op, len, op1, line_num, pos_next;
32473
24
    va_list ap;
32474
24
    BOOL ret = FALSE;
32475
32476
24
    line_num = -1;
32477
24
    va_start(ap, pos);
32478
32479
32
    for(;;) {
32480
32
        op1 = va_arg(ap, int);
32481
32
        if (op1 == -1) {
32482
4
            s->pos = pos;
32483
4
            s->line_num = line_num;
32484
4
            ret = TRUE;
32485
4
            break;
32486
4
        }
32487
29
        for (;;) {
32488
29
            if (pos >= s->bc_len)
32489
0
                goto done;
32490
29
            op = tab[pos];
32491
29
            len = opcode_info[op].size;
32492
29
            pos_next = pos + len;
32493
29
            if (pos_next > s->bc_len)
32494
0
                goto done;
32495
29
            if (op == OP_line_num) {
32496
1
                line_num = get_u32(tab + pos + 1);
32497
1
                pos = pos_next;
32498
28
            } else {
32499
28
                break;
32500
28
            }
32501
29
        }
32502
28
        if (op != op1) {
32503
24
            if (op1 == (uint8_t)op1 || !op)
32504
17
                break;
32505
7
            if (op != (uint8_t)op1
32506
7
            &&  op != (uint8_t)(op1 >> 8)
32507
7
            &&  op != (uint8_t)(op1 >> 16)
32508
7
            &&  op != (uint8_t)(op1 >> 24)) {
32509
3
                break;
32510
3
            }
32511
4
            s->op = op;
32512
4
        }
32513
32514
8
        pos++;
32515
8
        switch(opcode_info[op].fmt) {
32516
0
        case OP_FMT_loc8:
32517
0
        case OP_FMT_u8:
32518
0
            {
32519
0
                int idx = tab[pos];
32520
0
                int arg = va_arg(ap, int);
32521
0
                if (arg == -1) {
32522
0
                    s->idx = idx;
32523
0
                } else {
32524
0
                    if (arg != idx)
32525
0
                        goto done;
32526
0
                }
32527
0
                break;
32528
0
            }
32529
0
        case OP_FMT_u16:
32530
0
        case OP_FMT_npop:
32531
0
        case OP_FMT_loc:
32532
0
        case OP_FMT_arg:
32533
0
        case OP_FMT_var_ref:
32534
0
            {
32535
0
                int idx = get_u16(tab + pos);
32536
0
                int arg = va_arg(ap, int);
32537
0
                if (arg == -1) {
32538
0
                    s->idx = idx;
32539
0
                } else {
32540
0
                    if (arg != idx)
32541
0
                        goto done;
32542
0
                }
32543
0
                break;
32544
0
            }
32545
0
        case OP_FMT_i32:
32546
0
        case OP_FMT_u32:
32547
0
        case OP_FMT_label:
32548
0
        case OP_FMT_const:
32549
0
            {
32550
0
                s->label = get_u32(tab + pos);
32551
0
                break;
32552
0
            }
32553
0
        case OP_FMT_label_u16:
32554
0
            {
32555
0
                s->label = get_u32(tab + pos);
32556
0
                s->val = get_u16(tab + pos + 4);
32557
0
                break;
32558
0
            }
32559
4
        case OP_FMT_atom:
32560
4
            {
32561
4
                s->atom = get_u32(tab + pos);
32562
4
                break;
32563
0
            }
32564
0
        case OP_FMT_atom_u8:
32565
0
            {
32566
0
                s->atom = get_u32(tab + pos);
32567
0
                s->val = get_u8(tab + pos + 4);
32568
0
                break;
32569
0
            }
32570
0
        case OP_FMT_atom_u16:
32571
0
            {
32572
0
                s->atom = get_u32(tab + pos);
32573
0
                s->val = get_u16(tab + pos + 4);
32574
0
                break;
32575
0
            }
32576
0
        case OP_FMT_atom_label_u8:
32577
0
            {
32578
0
                s->atom = get_u32(tab + pos);
32579
0
                s->label = get_u32(tab + pos + 4);
32580
0
                s->val = get_u8(tab + pos + 8);
32581
0
                break;
32582
0
            }
32583
4
        default:
32584
4
            break;
32585
8
        }
32586
8
        pos = pos_next;
32587
8
    }
32588
24
 done:
32589
24
    va_end(ap);
32590
24
    return ret;
32591
24
}
32592
32593
static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, DynBuf *bc)
32594
3
{
32595
3
    int i, idx, label_next = -1;
32596
32597
    /* add the hoisted functions in arguments and local variables */
32598
3
    for(i = 0; i < s->arg_count; i++) {
32599
0
        JSVarDef *vd = &s->args[i];
32600
0
        if (vd->func_pool_idx >= 0) {
32601
0
            dbuf_putc(bc, OP_fclosure);
32602
0
            dbuf_put_u32(bc, vd->func_pool_idx);
32603
0
            dbuf_putc(bc, OP_put_arg);
32604
0
            dbuf_put_u16(bc, i);
32605
0
        }
32606
0
    }
32607
3
    for(i = 0; i < s->var_count; i++) {
32608
0
        JSVarDef *vd = &s->vars[i];
32609
0
        if (vd->scope_level == 0 && vd->func_pool_idx >= 0) {
32610
0
            dbuf_putc(bc, OP_fclosure);
32611
0
            dbuf_put_u32(bc, vd->func_pool_idx);
32612
0
            dbuf_putc(bc, OP_put_loc);
32613
0
            dbuf_put_u16(bc, i);
32614
0
        }
32615
0
    }
32616
32617
    /* the module global variables must be initialized before
32618
       evaluating the module so that the exported functions are
32619
       visible if there are cyclic module references */
32620
3
    if (s->module) {
32621
3
        label_next = new_label_fd(s);
32622
3
        if (label_next < 0) {
32623
0
            dbuf_set_error(bc);
32624
0
            return;
32625
0
        }
32626
        /* if 'this' is true, initialize the global variables and return */
32627
3
        dbuf_putc(bc, OP_push_this);
32628
3
        dbuf_putc(bc, OP_if_false);
32629
3
        dbuf_put_u32(bc, label_next);
32630
3
        update_label(s, label_next, 1);
32631
3
        s->jump_size++;
32632
3
    }
32633
32634
    /* add the global variables (only happens if s->is_global_var is
32635
       true) */
32636
3
    for(i = 0; i < s->global_var_count; i++) {
32637
0
        JSGlobalVar *hf = &s->global_vars[i];
32638
0
        int has_closure = 0;
32639
0
        BOOL force_init = hf->force_init;
32640
        /* we are in an eval, so the closure contains all the
32641
           enclosing variables */
32642
        /* If the outer function has a variable environment,
32643
           create a property for the variable there */
32644
0
        for(idx = 0; idx < s->closure_var_count; idx++) {
32645
0
            JSClosureVar *cv = &s->closure_var[idx];
32646
0
            if (cv->var_name == hf->var_name) {
32647
0
                has_closure = 2;
32648
0
                force_init = FALSE;
32649
0
                break;
32650
0
            }
32651
0
            if (cv->var_name == JS_ATOM__var_ ||
32652
0
                cv->var_name == JS_ATOM__arg_var_) {
32653
0
                dbuf_putc(bc, OP_get_var_ref);
32654
0
                dbuf_put_u16(bc, idx);
32655
0
                has_closure = 1;
32656
0
                force_init = TRUE;
32657
0
                break;
32658
0
            }
32659
0
        }
32660
0
        if (!has_closure) {
32661
0
            int flags;
32662
32663
0
            flags = 0;
32664
0
            if (s->eval_type != JS_EVAL_TYPE_GLOBAL)
32665
0
                flags |= JS_PROP_CONFIGURABLE;
32666
0
            if (hf->cpool_idx >= 0 && !hf->is_lexical) {
32667
                /* global function definitions need a specific handling */
32668
0
                dbuf_putc(bc, OP_fclosure);
32669
0
                dbuf_put_u32(bc, hf->cpool_idx);
32670
32671
0
                dbuf_putc(bc, OP_define_func);
32672
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
32673
0
                dbuf_putc(bc, flags);
32674
32675
0
                goto done_global_var;
32676
0
            } else {
32677
0
                if (hf->is_lexical) {
32678
0
                    flags |= DEFINE_GLOBAL_LEX_VAR;
32679
0
                    if (!hf->is_const)
32680
0
                        flags |= JS_PROP_WRITABLE;
32681
0
                }
32682
0
                dbuf_putc(bc, OP_define_var);
32683
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
32684
0
                dbuf_putc(bc, flags);
32685
0
            }
32686
0
        }
32687
0
        if (hf->cpool_idx >= 0 || force_init) {
32688
0
            if (hf->cpool_idx >= 0) {
32689
0
                dbuf_putc(bc, OP_fclosure);
32690
0
                dbuf_put_u32(bc, hf->cpool_idx);
32691
0
                if (hf->var_name == JS_ATOM__default_) {
32692
                    /* set default export function name */
32693
0
                    dbuf_putc(bc, OP_set_name);
32694
0
                    dbuf_put_u32(bc, JS_DupAtom(ctx, JS_ATOM_default));
32695
0
                }
32696
0
            } else {
32697
0
                dbuf_putc(bc, OP_undefined);
32698
0
            }
32699
0
            if (has_closure == 2) {
32700
0
                dbuf_putc(bc, OP_put_var_ref);
32701
0
                dbuf_put_u16(bc, idx);
32702
0
            } else if (has_closure == 1) {
32703
0
                dbuf_putc(bc, OP_define_field);
32704
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
32705
0
                dbuf_putc(bc, OP_drop);
32706
0
            } else {
32707
                /* XXX: Check if variable is writable and enumerable */
32708
0
                dbuf_putc(bc, OP_put_var);
32709
0
                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
32710
0
            }
32711
0
        }
32712
0
    done_global_var:
32713
0
        JS_FreeAtom(ctx, hf->var_name);
32714
0
    }
32715
32716
3
    if (s->module) {
32717
3
        dbuf_putc(bc, OP_return_undef);
32718
32719
3
        dbuf_putc(bc, OP_label);
32720
3
        dbuf_put_u32(bc, label_next);
32721
3
        s->label_slots[label_next].pos2 = bc->size;
32722
3
    }
32723
32724
3
    js_free(ctx, s->global_vars);
32725
3
    s->global_vars = NULL;
32726
3
    s->global_var_count = 0;
32727
3
    s->global_var_size = 0;
32728
3
}
32729
32730
static int skip_dead_code(JSFunctionDef *s, const uint8_t *bc_buf, int bc_len,
32731
                          int pos, int *linep)
32732
6
{
32733
6
    int op, len, label;
32734
32735
6
    for (; pos < bc_len; pos += len) {
32736
3
        op = bc_buf[pos];
32737
3
        len = opcode_info[op].size;
32738
3
        if (op == OP_line_num) {
32739
0
            *linep = get_u32(bc_buf + pos + 1);
32740
0
        } else
32741
3
        if (op == OP_label) {
32742
3
            label = get_u32(bc_buf + pos + 1);
32743
3
            if (update_label(s, label, 0) > 0)
32744
3
                break;
32745
#if 0
32746
            if (s->label_slots[label].first_reloc) {
32747
                printf("line %d: unreferenced label %d:%d has relocations\n",
32748
                       *linep, label, s->label_slots[label].pos2);
32749
            }
32750
#endif
32751
0
            assert(s->label_slots[label].first_reloc == NULL);
32752
0
        } else {
32753
            /* XXX: output a warning for unreachable code? */
32754
0
            JSAtom atom;
32755
0
            switch(opcode_info[op].fmt) {
32756
0
            case OP_FMT_label:
32757
0
            case OP_FMT_label_u16:
32758
0
                label = get_u32(bc_buf + pos + 1);
32759
0
                update_label(s, label, -1);
32760
0
                break;
32761
0
            case OP_FMT_atom_label_u8:
32762
0
            case OP_FMT_atom_label_u16:
32763
0
                label = get_u32(bc_buf + pos + 5);
32764
0
                update_label(s, label, -1);
32765
                /* fall thru */
32766
0
            case OP_FMT_atom:
32767
0
            case OP_FMT_atom_u8:
32768
0
            case OP_FMT_atom_u16:
32769
0
                atom = get_u32(bc_buf + pos + 1);
32770
0
                JS_FreeAtom(s->ctx, atom);
32771
0
                break;
32772
0
            default:
32773
0
                break;
32774
0
            }
32775
0
        }
32776
3
    }
32777
6
    return pos;
32778
6
}
32779
32780
static int get_label_pos(JSFunctionDef *s, int label)
32781
0
{
32782
0
    int i, pos;
32783
0
    for (i = 0; i < 20; i++) {
32784
0
        pos = s->label_slots[label].pos;
32785
0
        for (;;) {
32786
0
            switch (s->byte_code.buf[pos]) {
32787
0
            case OP_line_num:
32788
0
            case OP_label:
32789
0
                pos += 5;
32790
0
                continue;
32791
0
            case OP_goto:
32792
0
                label = get_u32(s->byte_code.buf + pos + 1);
32793
0
                break;
32794
0
            default:
32795
0
                return pos;
32796
0
            }
32797
0
            break;
32798
0
        }
32799
0
    }
32800
0
    return pos;
32801
0
}
32802
32803
/* convert global variable accesses to local variables or closure
32804
   variables when necessary */
32805
static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
32806
3
{
32807
3
    int pos, pos_next, bc_len, op, len, i, idx, line_num;
32808
3
    uint8_t *bc_buf;
32809
3
    JSAtom var_name;
32810
3
    DynBuf bc_out;
32811
3
    CodeContext cc;
32812
3
    int scope;
32813
32814
3
    cc.bc_buf = bc_buf = s->byte_code.buf;
32815
3
    cc.bc_len = bc_len = s->byte_code.size;
32816
3
    js_dbuf_init(ctx, &bc_out);
32817
32818
    /* first pass for runtime checks (must be done before the
32819
       variables are created) */
32820
3
    for(i = 0; i < s->global_var_count; i++) {
32821
0
        JSGlobalVar *hf = &s->global_vars[i];
32822
0
        int flags;
32823
32824
        /* check if global variable (XXX: simplify) */
32825
0
        for(idx = 0; idx < s->closure_var_count; idx++) {
32826
0
            JSClosureVar *cv = &s->closure_var[idx];
32827
0
            if (cv->var_name == hf->var_name) {
32828
0
                if (s->eval_type == JS_EVAL_TYPE_DIRECT &&
32829
0
                    cv->is_lexical) {
32830
                    /* Check if a lexical variable is
32831
                       redefined as 'var'. XXX: Could abort
32832
                       compilation here, but for consistency
32833
                       with the other checks, we delay the
32834
                       error generation. */
32835
0
                    dbuf_putc(&bc_out, OP_throw_error);
32836
0
                    dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
32837
0
                    dbuf_putc(&bc_out, JS_THROW_VAR_REDECL);
32838
0
                }
32839
0
                goto next;
32840
0
            }
32841
0
            if (cv->var_name == JS_ATOM__var_ ||
32842
0
                cv->var_name == JS_ATOM__arg_var_)
32843
0
                goto next;
32844
0
        }
32845
32846
0
        dbuf_putc(&bc_out, OP_check_define_var);
32847
0
        dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
32848
0
        flags = 0;
32849
0
        if (hf->is_lexical)
32850
0
            flags |= DEFINE_GLOBAL_LEX_VAR;
32851
0
        if (hf->cpool_idx >= 0)
32852
0
            flags |= DEFINE_GLOBAL_FUNC_VAR;
32853
0
        dbuf_putc(&bc_out, flags);
32854
0
    next: ;
32855
0
    }
32856
32857
3
    line_num = 0; /* avoid warning */
32858
51
    for (pos = 0; pos < bc_len; pos = pos_next) {
32859
48
        op = bc_buf[pos];
32860
48
        len = opcode_info[op].size;
32861
48
        pos_next = pos + len;
32862
48
        switch(op) {
32863
13
        case OP_line_num:
32864
13
            line_num = get_u32(bc_buf + pos + 1);
32865
13
            s->line_number_size++;
32866
13
            goto no_change;
32867
32868
0
        case OP_eval: /* convert scope index to adjusted variable index */
32869
0
            {
32870
0
                int call_argc = get_u16(bc_buf + pos + 1);
32871
0
                scope = get_u16(bc_buf + pos + 1 + 2);
32872
0
                mark_eval_captured_variables(ctx, s, scope);
32873
0
                dbuf_putc(&bc_out, op);
32874
0
                dbuf_put_u16(&bc_out, call_argc);
32875
0
                dbuf_put_u16(&bc_out, s->scopes[scope].first - ARG_SCOPE_END);
32876
0
            }
32877
0
            break;
32878
0
        case OP_apply_eval: /* convert scope index to adjusted variable index */
32879
0
            scope = get_u16(bc_buf + pos + 1);
32880
0
            mark_eval_captured_variables(ctx, s, scope);
32881
0
            dbuf_putc(&bc_out, op);
32882
0
            dbuf_put_u16(&bc_out, s->scopes[scope].first - ARG_SCOPE_END);
32883
0
            break;
32884
0
        case OP_scope_get_var_checkthis:
32885
0
        case OP_scope_get_var_undef:
32886
9
        case OP_scope_get_var:
32887
9
        case OP_scope_put_var:
32888
9
        case OP_scope_delete_var:
32889
9
        case OP_scope_get_ref:
32890
9
        case OP_scope_put_var_init:
32891
9
            var_name = get_u32(bc_buf + pos + 1);
32892
9
            scope = get_u16(bc_buf + pos + 5);
32893
9
            pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
32894
9
                                         NULL, NULL, pos_next);
32895
9
            JS_FreeAtom(ctx, var_name);
32896
9
            break;
32897
0
        case OP_scope_make_ref:
32898
0
            {
32899
0
                int label;
32900
0
                LabelSlot *ls;
32901
0
                var_name = get_u32(bc_buf + pos + 1);
32902
0
                label = get_u32(bc_buf + pos + 5);
32903
0
                scope = get_u16(bc_buf + pos + 9);
32904
0
                ls = &s->label_slots[label];
32905
0
                ls->ref_count--;  /* always remove label reference */
32906
0
                pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
32907
0
                                             bc_buf, ls, pos_next);
32908
0
                JS_FreeAtom(ctx, var_name);
32909
0
            }
32910
0
            break;
32911
0
        case OP_scope_get_private_field:
32912
0
        case OP_scope_get_private_field2:
32913
0
        case OP_scope_put_private_field:
32914
0
        case OP_scope_in_private_field:
32915
0
            {
32916
0
                int ret;
32917
0
                var_name = get_u32(bc_buf + pos + 1);
32918
0
                scope = get_u16(bc_buf + pos + 5);
32919
0
                ret = resolve_scope_private_field(ctx, s, var_name, scope, op, &bc_out);
32920
0
                if (ret < 0)
32921
0
                    goto fail;
32922
0
                JS_FreeAtom(ctx, var_name);
32923
0
            }
32924
0
            break;
32925
0
        case OP_gosub:
32926
0
            s->jump_size++;
32927
0
            if (OPTIMIZE) {
32928
                /* remove calls to empty finalizers  */
32929
0
                int label;
32930
0
                LabelSlot *ls;
32931
32932
0
                label = get_u32(bc_buf + pos + 1);
32933
0
                assert(label >= 0 && label < s->label_count);
32934
0
                ls = &s->label_slots[label];
32935
0
                if (code_match(&cc, ls->pos, OP_ret, -1)) {
32936
0
                    ls->ref_count--;
32937
0
                    break;
32938
0
                }
32939
0
            }
32940
0
            goto no_change;
32941
6
        case OP_drop:
32942
6
            if (0) {
32943
                /* remove drops before return_undef */
32944
                /* do not perform this optimization in pass2 because
32945
                   it breaks patterns recognised in resolve_labels */
32946
0
                int pos1 = pos_next;
32947
0
                int line1 = line_num;
32948
0
                while (code_match(&cc, pos1, OP_drop, -1)) {
32949
0
                    if (cc.line_num >= 0) line1 = cc.line_num;
32950
0
                    pos1 = cc.pos;
32951
0
                }
32952
0
                if (code_match(&cc, pos1, OP_return_undef, -1)) {
32953
0
                    pos_next = pos1;
32954
0
                    if (line1 != -1 && line1 != line_num) {
32955
0
                        line_num = line1;
32956
0
                        s->line_number_size++;
32957
0
                        dbuf_putc(&bc_out, OP_line_num);
32958
0
                        dbuf_put_u32(&bc_out, line_num);
32959
0
                    }
32960
0
                    break;
32961
0
                }
32962
0
            }
32963
6
            goto no_change;
32964
6
        case OP_insert3:
32965
0
            if (OPTIMIZE) {
32966
                /* Transformation: insert3 put_array_el|put_ref_value drop -> put_array_el|put_ref_value */
32967
0
                if (code_match(&cc, pos_next, M2(OP_put_array_el, OP_put_ref_value), OP_drop, -1)) {
32968
0
                    dbuf_putc(&bc_out, cc.op);
32969
0
                    pos_next = cc.pos;
32970
0
                    if (cc.line_num != -1 && cc.line_num != line_num) {
32971
0
                        line_num = cc.line_num;
32972
0
                        s->line_number_size++;
32973
0
                        dbuf_putc(&bc_out, OP_line_num);
32974
0
                        dbuf_put_u32(&bc_out, line_num);
32975
0
                    }
32976
0
                    break;
32977
0
                }
32978
0
            }
32979
0
            goto no_change;
32980
32981
0
        case OP_goto:
32982
0
            s->jump_size++;
32983
            /* fall thru */
32984
0
        case OP_tail_call:
32985
0
        case OP_tail_call_method:
32986
0
        case OP_return:
32987
0
        case OP_return_undef:
32988
0
        case OP_throw:
32989
0
        case OP_throw_error:
32990
0
        case OP_ret:
32991
0
            if (OPTIMIZE) {
32992
                /* remove dead code */
32993
0
                int line = -1;
32994
0
                dbuf_put(&bc_out, bc_buf + pos, len);
32995
0
                pos = skip_dead_code(s, bc_buf, bc_len, pos + len, &line);
32996
0
                pos_next = pos;
32997
0
                if (pos < bc_len && line >= 0 && line_num != line) {
32998
0
                    line_num = line;
32999
0
                    s->line_number_size++;
33000
0
                    dbuf_putc(&bc_out, OP_line_num);
33001
0
                    dbuf_put_u32(&bc_out, line_num);
33002
0
                }
33003
0
                break;
33004
0
            }
33005
0
            goto no_change;
33006
33007
1
        case OP_label:
33008
1
            {
33009
1
                int label;
33010
1
                LabelSlot *ls;
33011
33012
1
                label = get_u32(bc_buf + pos + 1);
33013
1
                assert(label >= 0 && label < s->label_count);
33014
1
                ls = &s->label_slots[label];
33015
1
                ls->pos2 = bc_out.size + opcode_info[op].size;
33016
1
            }
33017
0
            goto no_change;
33018
33019
3
        case OP_enter_scope:
33020
3
            {
33021
3
                int scope_idx, scope = get_u16(bc_buf + pos + 1);
33022
33023
3
                if (scope == s->body_scope) {
33024
3
                    instantiate_hoisted_definitions(ctx, s, &bc_out);
33025
3
                }
33026
33027
3
                for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {
33028
0
                    JSVarDef *vd = &s->vars[scope_idx];
33029
0
                    if (vd->scope_level == scope) {
33030
0
                        if (scope_idx != s->arguments_arg_idx) {
33031
0
                            if (vd->var_kind == JS_VAR_FUNCTION_DECL ||
33032
0
                                vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) {
33033
                                /* Initialize lexical variable upon entering scope */
33034
0
                                dbuf_putc(&bc_out, OP_fclosure);
33035
0
                                dbuf_put_u32(&bc_out, vd->func_pool_idx);
33036
0
                                dbuf_putc(&bc_out, OP_put_loc);
33037
0
                                dbuf_put_u16(&bc_out, scope_idx);
33038
0
                            } else {
33039
                                /* XXX: should check if variable can be used
33040
                                   before initialization */
33041
0
                                dbuf_putc(&bc_out, OP_set_loc_uninitialized);
33042
0
                                dbuf_put_u16(&bc_out, scope_idx);
33043
0
                            }
33044
0
                        }
33045
0
                        scope_idx = vd->scope_next;
33046
0
                    } else {
33047
0
                        break;
33048
0
                    }
33049
0
                }
33050
3
            }
33051
3
            break;
33052
33053
0
        case OP_leave_scope:
33054
0
            {
33055
0
                int scope_idx, scope = get_u16(bc_buf + pos + 1);
33056
33057
0
                for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {
33058
0
                    JSVarDef *vd = &s->vars[scope_idx];
33059
0
                    if (vd->scope_level == scope) {
33060
0
                        if (vd->is_captured) {
33061
0
                            dbuf_putc(&bc_out, OP_close_loc);
33062
0
                            dbuf_put_u16(&bc_out, scope_idx);
33063
0
                        }
33064
0
                        scope_idx = vd->scope_next;
33065
0
                    } else {
33066
0
                        break;
33067
0
                    }
33068
0
                }
33069
0
            }
33070
0
            break;
33071
33072
0
        case OP_set_name:
33073
0
            {
33074
                /* remove dummy set_name opcodes */
33075
0
                JSAtom name = get_u32(bc_buf + pos + 1);
33076
0
                if (name == JS_ATOM_NULL)
33077
0
                    break;
33078
0
            }
33079
0
            goto no_change;
33080
33081
0
        case OP_if_false:
33082
0
        case OP_if_true:
33083
0
        case OP_catch:
33084
0
            s->jump_size++;
33085
0
            goto no_change;
33086
33087
0
        case OP_dup:
33088
0
            if (OPTIMIZE) {
33089
                /* Transformation: dup if_false(l1) drop, l1: if_false(l2) -> if_false(l2) */
33090
                /* Transformation: dup if_true(l1) drop, l1: if_true(l2) -> if_true(l2) */
33091
0
                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), OP_drop, -1)) {
33092
0
                    int lab0, lab1, op1, pos1, line1, pos2;
33093
0
                    lab0 = lab1 = cc.label;
33094
0
                    assert(lab1 >= 0 && lab1 < s->label_count);
33095
0
                    op1 = cc.op;
33096
0
                    pos1 = cc.pos;
33097
0
                    line1 = cc.line_num;
33098
0
                    while (code_match(&cc, (pos2 = get_label_pos(s, lab1)), OP_dup, op1, OP_drop, -1)) {
33099
0
                        lab1 = cc.label;
33100
0
                    }
33101
0
                    if (code_match(&cc, pos2, op1, -1)) {
33102
0
                        s->jump_size++;
33103
0
                        update_label(s, lab0, -1);
33104
0
                        update_label(s, cc.label, +1);
33105
0
                        dbuf_putc(&bc_out, op1);
33106
0
                        dbuf_put_u32(&bc_out, cc.label);
33107
0
                        pos_next = pos1;
33108
0
                        if (line1 != -1 && line1 != line_num) {
33109
0
                            line_num = line1;
33110
0
                            s->line_number_size++;
33111
0
                            dbuf_putc(&bc_out, OP_line_num);
33112
0
                            dbuf_put_u32(&bc_out, line_num);
33113
0
                        }
33114
0
                        break;
33115
0
                    }
33116
0
                }
33117
0
            }
33118
0
            goto no_change;
33119
33120
0
        case OP_nop:
33121
            /* remove erased code */
33122
0
            break;
33123
0
        case OP_set_class_name:
33124
            /* only used during parsing */
33125
0
            break;
33126
33127
0
        case OP_get_field_opt_chain: /* equivalent to OP_get_field */
33128
0
            {
33129
0
                JSAtom name = get_u32(bc_buf + pos + 1);
33130
0
                dbuf_putc(&bc_out, OP_get_field);
33131
0
                dbuf_put_u32(&bc_out, name);
33132
0
            }
33133
0
            break;
33134
0
        case OP_get_array_el_opt_chain: /* equivalent to OP_get_array_el */
33135
0
            dbuf_putc(&bc_out, OP_get_array_el);
33136
0
            break;
33137
33138
16
        default:
33139
36
        no_change:
33140
36
            dbuf_put(&bc_out, bc_buf + pos, len);
33141
36
            break;
33142
48
        }
33143
48
    }
33144
33145
    /* set the new byte code */
33146
3
    dbuf_free(&s->byte_code);
33147
3
    s->byte_code = bc_out;
33148
3
    if (dbuf_error(&s->byte_code)) {
33149
0
        JS_ThrowOutOfMemory(ctx);
33150
0
        return -1;
33151
0
    }
33152
3
    return 0;
33153
0
 fail:
33154
    /* continue the copy to keep the atom refcounts consistent */
33155
    /* XXX: find a better solution ? */
33156
0
    for (; pos < bc_len; pos = pos_next) {
33157
0
        op = bc_buf[pos];
33158
0
        len = opcode_info[op].size;
33159
0
        pos_next = pos + len;
33160
0
        dbuf_put(&bc_out, bc_buf + pos, len);
33161
0
    }
33162
0
    dbuf_free(&s->byte_code);
33163
0
    s->byte_code = bc_out;
33164
0
    return -1;
33165
3
}
33166
33167
/* the pc2line table gives a source position for each PC value */
33168
static void add_pc2line_info(JSFunctionDef *s, uint32_t pc, uint32_t source_pos)
33169
32
{
33170
32
    if (s->line_number_slots != NULL
33171
32
    &&  s->line_number_count < s->line_number_size
33172
32
    &&  pc >= s->line_number_last_pc
33173
32
    &&  source_pos != s->line_number_last) {
33174
9
        s->line_number_slots[s->line_number_count].pc = pc;
33175
9
        s->line_number_slots[s->line_number_count].source_pos = source_pos;
33176
9
        s->line_number_count++;
33177
9
        s->line_number_last_pc = pc;
33178
9
        s->line_number_last = source_pos;
33179
9
    }
33180
32
}
33181
33182
/* XXX: could use a more compact storage */
33183
/* XXX: get_line_col_cached() is slow. For more predictable
33184
   performance, line/cols could be stored every N source
33185
   bytes. Alternatively, get_line_col_cached() could be issued in
33186
   emit_source_pos() so that the deltas are more likely to be
33187
   small. */
33188
static void compute_pc2line_info(JSFunctionDef *s)
33189
3
{
33190
3
    if (!s->strip_debug) {
33191
3
        int last_line_num, last_col_num;
33192
3
        uint32_t last_pc = 0;
33193
3
        int i, line_num, col_num;
33194
3
        const uint8_t *buf_start = s->get_line_col_cache->buf_start;
33195
3
        js_dbuf_init(s->ctx, &s->pc2line);
33196
33197
3
        last_line_num = get_line_col_cached(s->get_line_col_cache,
33198
3
                                            &last_col_num,
33199
3
                                            buf_start + s->source_pos);
33200
3
        dbuf_put_leb128(&s->pc2line, last_line_num); /* line number minus 1 */
33201
3
        dbuf_put_leb128(&s->pc2line, last_col_num); /* column number minus 1 */
33202
33203
12
        for (i = 0; i < s->line_number_count; i++) {
33204
9
            uint32_t pc = s->line_number_slots[i].pc;
33205
9
            uint32_t source_pos = s->line_number_slots[i].source_pos;
33206
9
            int diff_pc, diff_line, diff_col;
33207
33208
9
            if (source_pos == -1)
33209
0
                continue;
33210
9
            diff_pc = pc - last_pc;
33211
9
            if (diff_pc < 0)
33212
0
                continue;
33213
33214
9
            line_num = get_line_col_cached(s->get_line_col_cache, &col_num,
33215
9
                                           buf_start + source_pos);
33216
9
            diff_line = line_num - last_line_num;
33217
9
            diff_col = col_num - last_col_num;
33218
9
            if (diff_line == 0 && diff_col == 0)
33219
0
                continue;
33220
33221
9
            if (diff_line >= PC2LINE_BASE &&
33222
9
                diff_line < PC2LINE_BASE + PC2LINE_RANGE &&
33223
9
                diff_pc <= PC2LINE_DIFF_PC_MAX) {
33224
9
                dbuf_putc(&s->pc2line, (diff_line - PC2LINE_BASE) +
33225
9
                          diff_pc * PC2LINE_RANGE + PC2LINE_OP_FIRST);
33226
9
            } else {
33227
                /* longer encoding */
33228
0
                dbuf_putc(&s->pc2line, 0);
33229
0
                dbuf_put_leb128(&s->pc2line, diff_pc);
33230
0
                dbuf_put_sleb128(&s->pc2line, diff_line);
33231
0
            }
33232
9
            dbuf_put_sleb128(&s->pc2line, diff_col);
33233
                
33234
9
            last_pc = pc;
33235
9
            last_line_num = line_num;
33236
9
            last_col_num = col_num;
33237
9
        }
33238
3
    }
33239
3
}
33240
33241
static RelocEntry *add_reloc(JSContext *ctx, LabelSlot *ls, uint32_t addr, int size)
33242
3
{
33243
3
    RelocEntry *re;
33244
3
    re = js_malloc(ctx, sizeof(*re));
33245
3
    if (!re)
33246
0
        return NULL;
33247
3
    re->addr = addr;
33248
3
    re->size = size;
33249
3
    re->next = ls->first_reloc;
33250
3
    ls->first_reloc = re;
33251
3
    return re;
33252
3
}
33253
33254
static BOOL code_has_label(CodeContext *s, int pos, int label)
33255
3
{
33256
3
    while (pos < s->bc_len) {
33257
3
        int op = s->bc_buf[pos];
33258
3
        if (op == OP_line_num) {
33259
0
            pos += 5;
33260
0
            continue;
33261
0
        }
33262
3
        if (op == OP_label) {
33263
0
            int lab = get_u32(s->bc_buf + pos + 1);
33264
0
            if (lab == label)
33265
0
                return TRUE;
33266
0
            pos += 5;
33267
0
            continue;
33268
0
        }
33269
3
        if (op == OP_goto) {
33270
0
            int lab = get_u32(s->bc_buf + pos + 1);
33271
0
            if (lab == label)
33272
0
                return TRUE;
33273
0
        }
33274
3
        break;
33275
3
    }
33276
3
    return FALSE;
33277
3
}
33278
33279
/* return the target label, following the OP_goto jumps
33280
   the first opcode at destination is stored in *pop
33281
 */
33282
static int find_jump_target(JSFunctionDef *s, int label0, int *pop, int *pline)
33283
3
{
33284
3
    int i, pos, op, label;
33285
33286
3
    label = label0;
33287
3
    update_label(s, label, -1);
33288
3
    for (i = 0; i < 10; i++) {
33289
3
        assert(label >= 0 && label < s->label_count);
33290
3
        pos = s->label_slots[label].pos2;
33291
5
        for (;;) {
33292
5
            switch(op = s->byte_code.buf[pos]) {
33293
2
            case OP_line_num:
33294
2
                if (pline)
33295
0
                    *pline = get_u32(s->byte_code.buf + pos + 1);
33296
                /* fall thru */
33297
2
            case OP_label:
33298
2
                pos += opcode_info[op].size;
33299
2
                continue;
33300
0
            case OP_goto:
33301
0
                label = get_u32(s->byte_code.buf + pos + 1);
33302
0
                break;
33303
0
            case OP_drop:
33304
                /* ignore drop opcodes if followed by OP_return_undef */
33305
0
                while (s->byte_code.buf[++pos] == OP_drop)
33306
0
                    continue;
33307
0
                if (s->byte_code.buf[pos] == OP_return_undef)
33308
0
                    op = OP_return_undef;
33309
                /* fall thru */
33310
3
            default:
33311
3
                goto done;
33312
5
            }
33313
0
            break;
33314
5
        }
33315
3
    }
33316
    /* cycle detected, could issue a warning */
33317
    /* XXX: the combination of find_jump_target() and skip_dead_code()
33318
       seems incorrect with cyclic labels. See for exemple:
33319
33320
       for (;;) {
33321
       l:break l;
33322
       l:break l;
33323
       l:break l;
33324
       l:break l;
33325
       }
33326
33327
       Avoiding changing the target is just a workaround and might not
33328
       suffice to completely fix the problem. */
33329
0
    label = label0;
33330
3
 done:
33331
3
    *pop = op;
33332
3
    update_label(s, label, +1);
33333
3
    return label;
33334
0
}
33335
33336
static void push_short_int(DynBuf *bc_out, int val)
33337
0
{
33338
0
#if SHORT_OPCODES
33339
0
    if (val >= -1 && val <= 7) {
33340
0
        dbuf_putc(bc_out, OP_push_0 + val);
33341
0
        return;
33342
0
    }
33343
0
    if (val == (int8_t)val) {
33344
0
        dbuf_putc(bc_out, OP_push_i8);
33345
0
        dbuf_putc(bc_out, val);
33346
0
        return;
33347
0
    }
33348
0
    if (val == (int16_t)val) {
33349
0
        dbuf_putc(bc_out, OP_push_i16);
33350
0
        dbuf_put_u16(bc_out, val);
33351
0
        return;
33352
0
    }
33353
0
#endif
33354
0
    dbuf_putc(bc_out, OP_push_i32);
33355
0
    dbuf_put_u32(bc_out, val);
33356
0
}
33357
33358
static void put_short_code(DynBuf *bc_out, int op, int idx)
33359
0
{
33360
0
#if SHORT_OPCODES
33361
0
    if (idx < 4) {
33362
0
        switch (op) {
33363
0
        case OP_get_loc:
33364
0
            dbuf_putc(bc_out, OP_get_loc0 + idx);
33365
0
            return;
33366
0
        case OP_put_loc:
33367
0
            dbuf_putc(bc_out, OP_put_loc0 + idx);
33368
0
            return;
33369
0
        case OP_set_loc:
33370
0
            dbuf_putc(bc_out, OP_set_loc0 + idx);
33371
0
            return;
33372
0
        case OP_get_arg:
33373
0
            dbuf_putc(bc_out, OP_get_arg0 + idx);
33374
0
            return;
33375
0
        case OP_put_arg:
33376
0
            dbuf_putc(bc_out, OP_put_arg0 + idx);
33377
0
            return;
33378
0
        case OP_set_arg:
33379
0
            dbuf_putc(bc_out, OP_set_arg0 + idx);
33380
0
            return;
33381
0
        case OP_get_var_ref:
33382
0
            dbuf_putc(bc_out, OP_get_var_ref0 + idx);
33383
0
            return;
33384
0
        case OP_put_var_ref:
33385
0
            dbuf_putc(bc_out, OP_put_var_ref0 + idx);
33386
0
            return;
33387
0
        case OP_set_var_ref:
33388
0
            dbuf_putc(bc_out, OP_set_var_ref0 + idx);
33389
0
            return;
33390
0
        case OP_call:
33391
0
            dbuf_putc(bc_out, OP_call0 + idx);
33392
0
            return;
33393
0
        }
33394
0
    }
33395
0
    if (idx < 256) {
33396
0
        switch (op) {
33397
0
        case OP_get_loc:
33398
0
            dbuf_putc(bc_out, OP_get_loc8);
33399
0
            dbuf_putc(bc_out, idx);
33400
0
            return;
33401
0
        case OP_put_loc:
33402
0
            dbuf_putc(bc_out, OP_put_loc8);
33403
0
            dbuf_putc(bc_out, idx);
33404
0
            return;
33405
0
        case OP_set_loc:
33406
0
            dbuf_putc(bc_out, OP_set_loc8);
33407
0
            dbuf_putc(bc_out, idx);
33408
0
            return;
33409
0
        }
33410
0
    }
33411
0
#endif
33412
0
    dbuf_putc(bc_out, op);
33413
0
    dbuf_put_u16(bc_out, idx);
33414
0
}
33415
33416
/* peephole optimizations and resolve goto/labels */
33417
static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
33418
3
{
33419
3
    int pos, pos_next, bc_len, op, op1, len, i, line_num;
33420
3
    const uint8_t *bc_buf;
33421
3
    DynBuf bc_out;
33422
3
    LabelSlot *label_slots, *ls;
33423
3
    RelocEntry *re, *re_next;
33424
3
    CodeContext cc;
33425
3
    int label;
33426
3
#if SHORT_OPCODES
33427
3
    JumpSlot *jp;
33428
3
#endif
33429
33430
3
    label_slots = s->label_slots;
33431
33432
3
    line_num = s->source_pos;
33433
33434
3
    cc.bc_buf = bc_buf = s->byte_code.buf;
33435
3
    cc.bc_len = bc_len = s->byte_code.size;
33436
3
    js_dbuf_init(ctx, &bc_out);
33437
33438
3
#if SHORT_OPCODES
33439
3
    if (s->jump_size) {
33440
3
        s->jump_slots = js_mallocz(s->ctx, sizeof(*s->jump_slots) * s->jump_size);
33441
3
        if (s->jump_slots == NULL)
33442
0
            return -1;
33443
3
    }
33444
3
#endif
33445
    /* XXX: Should skip this phase if not generating SHORT_OPCODES */
33446
3
    if (s->line_number_size && !s->strip_debug) {
33447
3
        s->line_number_slots = js_mallocz(s->ctx, sizeof(*s->line_number_slots) * s->line_number_size);
33448
3
        if (s->line_number_slots == NULL)
33449
0
            return -1;
33450
3
        s->line_number_last = s->source_pos;
33451
3
        s->line_number_last_pc = 0;
33452
3
    }
33453
33454
    /* initialize the 'home_object' variable if needed */
33455
3
    if (s->home_object_var_idx >= 0) {
33456
0
        dbuf_putc(&bc_out, OP_special_object);
33457
0
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_HOME_OBJECT);
33458
0
        put_short_code(&bc_out, OP_put_loc, s->home_object_var_idx);
33459
0
    }
33460
    /* initialize the 'this.active_func' variable if needed */
33461
3
    if (s->this_active_func_var_idx >= 0) {
33462
0
        dbuf_putc(&bc_out, OP_special_object);
33463
0
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_THIS_FUNC);
33464
0
        put_short_code(&bc_out, OP_put_loc, s->this_active_func_var_idx);
33465
0
    }
33466
    /* initialize the 'new.target' variable if needed */
33467
3
    if (s->new_target_var_idx >= 0) {
33468
0
        dbuf_putc(&bc_out, OP_special_object);
33469
0
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_NEW_TARGET);
33470
0
        put_short_code(&bc_out, OP_put_loc, s->new_target_var_idx);
33471
0
    }
33472
    /* initialize the 'this' variable if needed. In a derived class
33473
       constructor, this is initially uninitialized. */
33474
3
    if (s->this_var_idx >= 0) {
33475
0
        if (s->is_derived_class_constructor) {
33476
0
            dbuf_putc(&bc_out, OP_set_loc_uninitialized);
33477
0
            dbuf_put_u16(&bc_out, s->this_var_idx);
33478
0
        } else {
33479
0
            dbuf_putc(&bc_out, OP_push_this);
33480
0
            put_short_code(&bc_out, OP_put_loc, s->this_var_idx);
33481
0
        }
33482
0
    }
33483
    /* initialize the 'arguments' variable if needed */
33484
3
    if (s->arguments_var_idx >= 0) {
33485
0
        if ((s->js_mode & JS_MODE_STRICT) || !s->has_simple_parameter_list) {
33486
0
            dbuf_putc(&bc_out, OP_special_object);
33487
0
            dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_ARGUMENTS);
33488
0
        } else {
33489
0
            dbuf_putc(&bc_out, OP_special_object);
33490
0
            dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS);
33491
0
        }
33492
0
        if (s->arguments_arg_idx >= 0)
33493
0
            put_short_code(&bc_out, OP_set_loc, s->arguments_arg_idx);
33494
0
        put_short_code(&bc_out, OP_put_loc, s->arguments_var_idx);
33495
0
    }
33496
    /* initialize a reference to the current function if needed */
33497
3
    if (s->func_var_idx >= 0) {
33498
0
        dbuf_putc(&bc_out, OP_special_object);
33499
0
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_THIS_FUNC);
33500
0
        put_short_code(&bc_out, OP_put_loc, s->func_var_idx);
33501
0
    }
33502
    /* initialize the variable environment object if needed */
33503
3
    if (s->var_object_idx >= 0) {
33504
0
        dbuf_putc(&bc_out, OP_special_object);
33505
0
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
33506
0
        put_short_code(&bc_out, OP_put_loc, s->var_object_idx);
33507
0
    }
33508
3
    if (s->arg_var_object_idx >= 0) {
33509
0
        dbuf_putc(&bc_out, OP_special_object);
33510
0
        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
33511
0
        put_short_code(&bc_out, OP_put_loc, s->arg_var_object_idx);
33512
0
    }
33513
33514
52
    for (pos = 0; pos < bc_len; pos = pos_next) {
33515
49
        int val;
33516
49
        op = bc_buf[pos];
33517
49
        len = opcode_info[op].size;
33518
49
        pos_next = pos + len;
33519
49
        switch(op) {
33520
13
        case OP_line_num:
33521
            /* line number info (for debug). We put it in a separate
33522
               compressed table to reduce memory usage and get better
33523
               performance */
33524
13
            line_num = get_u32(bc_buf + pos + 1);
33525
13
            break;
33526
33527
4
        case OP_label:
33528
4
            {
33529
4
                label = get_u32(bc_buf + pos + 1);
33530
4
                assert(label >= 0 && label < s->label_count);
33531
4
                ls = &label_slots[label];
33532
4
                assert(ls->addr == -1);
33533
4
                ls->addr = bc_out.size;
33534
                /* resolve the relocation entries */
33535
7
                for(re = ls->first_reloc; re != NULL; re = re_next) {
33536
3
                    int diff = ls->addr - re->addr;
33537
3
                    re_next = re->next;
33538
3
                    switch (re->size) {
33539
0
                    case 4:
33540
0
                        put_u32(bc_out.buf + re->addr, diff);
33541
0
                        break;
33542
0
                    case 2:
33543
0
                        assert(diff == (int16_t)diff);
33544
0
                        put_u16(bc_out.buf + re->addr, diff);
33545
0
                        break;
33546
3
                    case 1:
33547
3
                        assert(diff == (int8_t)diff);
33548
3
                        put_u8(bc_out.buf + re->addr, diff);
33549
3
                        break;
33550
3
                    }
33551
3
                    js_free(ctx, re);
33552
3
                }
33553
4
                ls->first_reloc = NULL;
33554
4
            }
33555
0
            break;
33556
33557
0
        case OP_call:
33558
0
        case OP_call_method:
33559
0
            {
33560
                /* detect and transform tail calls */
33561
0
                int argc;
33562
0
                argc = get_u16(bc_buf + pos + 1);
33563
0
                if (code_match(&cc, pos_next, OP_return, -1)) {
33564
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
33565
0
                    add_pc2line_info(s, bc_out.size, line_num);
33566
0
                    put_short_code(&bc_out, op + 1, argc);
33567
0
                    pos_next = skip_dead_code(s, bc_buf, bc_len, cc.pos, &line_num);
33568
0
                    break;
33569
0
                }
33570
0
                add_pc2line_info(s, bc_out.size, line_num);
33571
0
                put_short_code(&bc_out, op, argc);
33572
0
                break;
33573
0
            }
33574
0
            goto no_change;
33575
33576
0
        case OP_return:
33577
3
        case OP_return_undef:
33578
6
        case OP_return_async:
33579
6
        case OP_throw:
33580
6
        case OP_throw_error:
33581
6
            pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
33582
6
            goto no_change;
33583
33584
0
        case OP_goto:
33585
0
            label = get_u32(bc_buf + pos + 1);
33586
0
        has_goto:
33587
0
            if (OPTIMIZE) {
33588
0
                int line1 = -1;
33589
                /* Use custom matcher because multiple labels can follow */
33590
0
                label = find_jump_target(s, label, &op1, &line1);
33591
0
                if (code_has_label(&cc, pos_next, label)) {
33592
                    /* jump to next instruction: remove jump */
33593
0
                    update_label(s, label, -1);
33594
0
                    break;
33595
0
                }
33596
0
                if (op1 == OP_return || op1 == OP_return_undef || op1 == OP_throw) {
33597
                    /* jump to return/throw: remove jump, append return/throw */
33598
                    /* updating the line number obfuscates assembly listing */
33599
                    //if (line1 != -1) line_num = line1;
33600
0
                    update_label(s, label, -1);
33601
0
                    add_pc2line_info(s, bc_out.size, line_num);
33602
0
                    dbuf_putc(&bc_out, op1);
33603
0
                    pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
33604
0
                    break;
33605
0
                }
33606
                /* XXX: should duplicate single instructions followed by goto or return */
33607
                /* For example, can match one of these followed by return:
33608
                   push_i32 / push_const / push_atom_value / get_var /
33609
                   undefined / null / push_false / push_true / get_ref_value /
33610
                   get_loc / get_arg / get_var_ref
33611
                 */
33612
0
            }
33613
0
            goto has_label;
33614
33615
0
        case OP_gosub:
33616
0
            label = get_u32(bc_buf + pos + 1);
33617
0
            if (0 && OPTIMIZE) {
33618
0
                label = find_jump_target(s, label, &op1, NULL);
33619
0
                if (op1 == OP_ret) {
33620
0
                    update_label(s, label, -1);
33621
                    /* empty finally clause: remove gosub */
33622
0
                    break;
33623
0
                }
33624
0
            }
33625
0
            goto has_label;
33626
33627
0
        case OP_catch:
33628
0
            label = get_u32(bc_buf + pos + 1);
33629
0
            goto has_label;
33630
33631
0
        case OP_if_true:
33632
3
        case OP_if_false:
33633
3
            label = get_u32(bc_buf + pos + 1);
33634
3
            if (OPTIMIZE) {
33635
3
                label = find_jump_target(s, label, &op1, NULL);
33636
                /* transform if_false/if_true(l1) label(l1) -> drop label(l1) */
33637
3
                if (code_has_label(&cc, pos_next, label)) {
33638
0
                    update_label(s, label, -1);
33639
0
                    dbuf_putc(&bc_out, OP_drop);
33640
0
                    break;
33641
0
                }
33642
                /* transform if_false(l1) goto(l2) label(l1) -> if_false(l2) label(l1) */
33643
3
                if (code_match(&cc, pos_next, OP_goto, -1)) {
33644
0
                    int pos1 = cc.pos;
33645
0
                    int line1 = cc.line_num;
33646
0
                    if (code_has_label(&cc, pos1, label)) {
33647
0
                        if (line1 != -1) line_num = line1;
33648
0
                        pos_next = pos1;
33649
0
                        update_label(s, label, -1);
33650
0
                        label = cc.label;
33651
0
                        op ^= OP_if_true ^ OP_if_false;
33652
0
                    }
33653
0
                }
33654
3
            }
33655
3
        has_label:
33656
3
            add_pc2line_info(s, bc_out.size, line_num);
33657
3
            if (op == OP_goto) {
33658
0
                pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
33659
0
            }
33660
3
            assert(label >= 0 && label < s->label_count);
33661
3
            ls = &label_slots[label];
33662
3
#if SHORT_OPCODES
33663
3
            jp = &s->jump_slots[s->jump_count++];
33664
3
            jp->op = op;
33665
3
            jp->size = 4;
33666
3
            jp->pos = bc_out.size + 1;
33667
3
            jp->label = label;
33668
33669
3
            if (ls->addr == -1) {
33670
3
                int diff = ls->pos2 - pos - 1;
33671
3
                if (diff < 128 && (op == OP_if_false || op == OP_if_true || op == OP_goto)) {
33672
3
                    jp->size = 1;
33673
3
                    jp->op = OP_if_false8 + (op - OP_if_false);
33674
3
                    dbuf_putc(&bc_out, OP_if_false8 + (op - OP_if_false));
33675
3
                    dbuf_putc(&bc_out, 0);
33676
3
                    if (!add_reloc(ctx, ls, bc_out.size - 1, 1))
33677
0
                        goto fail;
33678
3
                    break;
33679
3
                }
33680
0
                if (diff < 32768 && op == OP_goto) {
33681
0
                    jp->size = 2;
33682
0
                    jp->op = OP_goto16;
33683
0
                    dbuf_putc(&bc_out, OP_goto16);
33684
0
                    dbuf_put_u16(&bc_out, 0);
33685
0
                    if (!add_reloc(ctx, ls, bc_out.size - 2, 2))
33686
0
                        goto fail;
33687
0
                    break;
33688
0
                }
33689
0
            } else {
33690
0
                int diff = ls->addr - bc_out.size - 1;
33691
0
                if (diff == (int8_t)diff && (op == OP_if_false || op == OP_if_true || op == OP_goto)) {
33692
0
                    jp->size = 1;
33693
0
                    jp->op = OP_if_false8 + (op - OP_if_false);
33694
0
                    dbuf_putc(&bc_out, OP_if_false8 + (op - OP_if_false));
33695
0
                    dbuf_putc(&bc_out, diff);
33696
0
                    break;
33697
0
                }
33698
0
                if (diff == (int16_t)diff && op == OP_goto) {
33699
0
                    jp->size = 2;
33700
0
                    jp->op = OP_goto16;
33701
0
                    dbuf_putc(&bc_out, OP_goto16);
33702
0
                    dbuf_put_u16(&bc_out, diff);
33703
0
                    break;
33704
0
                }
33705
0
            }
33706
0
#endif
33707
0
            dbuf_putc(&bc_out, op);
33708
0
            dbuf_put_u32(&bc_out, ls->addr - bc_out.size);
33709
0
            if (ls->addr == -1) {
33710
                /* unresolved yet: create a new relocation entry */
33711
0
                if (!add_reloc(ctx, ls, bc_out.size - 4, 4))
33712
0
                    goto fail;
33713
0
            }
33714
0
            break;
33715
0
        case OP_with_get_var:
33716
0
        case OP_with_put_var:
33717
0
        case OP_with_delete_var:
33718
0
        case OP_with_make_ref:
33719
0
        case OP_with_get_ref:
33720
0
            {
33721
0
                JSAtom atom;
33722
0
                int is_with;
33723
33724
0
                atom = get_u32(bc_buf + pos + 1);
33725
0
                label = get_u32(bc_buf + pos + 5);
33726
0
                is_with = bc_buf[pos + 9];
33727
0
                if (OPTIMIZE) {
33728
0
                    label = find_jump_target(s, label, &op1, NULL);
33729
0
                }
33730
0
                assert(label >= 0 && label < s->label_count);
33731
0
                ls = &label_slots[label];
33732
0
                add_pc2line_info(s, bc_out.size, line_num);
33733
0
#if SHORT_OPCODES
33734
0
                jp = &s->jump_slots[s->jump_count++];
33735
0
                jp->op = op;
33736
0
                jp->size = 4;
33737
0
                jp->pos = bc_out.size + 5;
33738
0
                jp->label = label;
33739
0
#endif
33740
0
                dbuf_putc(&bc_out, op);
33741
0
                dbuf_put_u32(&bc_out, atom);
33742
0
                dbuf_put_u32(&bc_out, ls->addr - bc_out.size);
33743
0
                if (ls->addr == -1) {
33744
                    /* unresolved yet: create a new relocation entry */
33745
0
                    if (!add_reloc(ctx, ls, bc_out.size - 4, 4))
33746
0
                        goto fail;
33747
0
                }
33748
0
                dbuf_putc(&bc_out, is_with);
33749
0
            }
33750
0
            break;
33751
33752
2
        case OP_drop:
33753
2
            if (OPTIMIZE) {
33754
                /* remove useless drops before return */
33755
2
                if (code_match(&cc, pos_next, OP_return_undef, -1)) {
33756
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
33757
0
                    break;
33758
0
                }
33759
2
            }
33760
2
            goto no_change;
33761
33762
2
        case OP_null:
33763
0
#if SHORT_OPCODES
33764
0
            if (OPTIMIZE) {
33765
                /* transform null strict_eq into is_null */
33766
0
                if (code_match(&cc, pos_next, OP_strict_eq, -1)) {
33767
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
33768
0
                    add_pc2line_info(s, bc_out.size, line_num);
33769
0
                    dbuf_putc(&bc_out, OP_is_null);
33770
0
                    pos_next = cc.pos;
33771
0
                    break;
33772
0
                }
33773
                /* transform null strict_neq if_false/if_true -> is_null if_true/if_false */
33774
0
                if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) {
33775
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
33776
0
                    add_pc2line_info(s, bc_out.size, line_num);
33777
0
                    dbuf_putc(&bc_out, OP_is_null);
33778
0
                    pos_next = cc.pos;
33779
0
                    label = cc.label;
33780
0
                    op = cc.op ^ OP_if_false ^ OP_if_true;
33781
0
                    goto has_label;
33782
0
                }
33783
0
            }
33784
0
#endif
33785
            /* fall thru */
33786
0
        case OP_push_false:
33787
0
        case OP_push_true:
33788
0
            if (OPTIMIZE) {
33789
0
                val = (op == OP_push_true);
33790
0
                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
33791
0
                has_constant_test:
33792
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
33793
0
                    if (val == cc.op - OP_if_false) {
33794
                        /* transform null if_false(l1) -> goto l1 */
33795
                        /* transform false if_false(l1) -> goto l1 */
33796
                        /* transform true if_true(l1) -> goto l1 */
33797
0
                        pos_next = cc.pos;
33798
0
                        op = OP_goto;
33799
0
                        label = cc.label;
33800
0
                        goto has_goto;
33801
0
                    } else {
33802
                        /* transform null if_true(l1) -> nop */
33803
                        /* transform false if_true(l1) -> nop */
33804
                        /* transform true if_false(l1) -> nop */
33805
0
                        pos_next = cc.pos;
33806
0
                        update_label(s, cc.label, -1);
33807
0
                        break;
33808
0
                    }
33809
0
                }
33810
0
            }
33811
0
            goto no_change;
33812
33813
0
        case OP_push_i32:
33814
0
            if (OPTIMIZE) {
33815
                /* transform i32(val) neg -> i32(-val) */
33816
0
                val = get_i32(bc_buf + pos + 1);
33817
0
                if ((val != INT32_MIN && val != 0)
33818
0
                &&  code_match(&cc, pos_next, OP_neg, -1)) {
33819
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
33820
0
                    if (code_match(&cc, cc.pos, OP_drop, -1)) {
33821
0
                        if (cc.line_num >= 0) line_num = cc.line_num;
33822
0
                    } else {
33823
0
                        add_pc2line_info(s, bc_out.size, line_num);
33824
0
                        push_short_int(&bc_out, -val);
33825
0
                    }
33826
0
                    pos_next = cc.pos;
33827
0
                    break;
33828
0
                }
33829
                /* remove push/drop pairs generated by the parser */
33830
0
                if (code_match(&cc, pos_next, OP_drop, -1)) {
33831
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
33832
0
                    pos_next = cc.pos;
33833
0
                    break;
33834
0
                }
33835
                /* Optimize constant tests: `if (0)`, `if (1)`, `if (!0)`... */
33836
0
                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
33837
0
                    val = (val != 0);
33838
0
                    goto has_constant_test;
33839
0
                }
33840
0
                add_pc2line_info(s, bc_out.size, line_num);
33841
0
                push_short_int(&bc_out, val);
33842
0
                break;
33843
0
            }
33844
0
            goto no_change;
33845
33846
0
        case OP_push_bigint_i32:
33847
0
            if (OPTIMIZE) {
33848
                /* transform i32(val) neg -> i32(-val) */
33849
0
                val = get_i32(bc_buf + pos + 1);
33850
0
                if (val != INT32_MIN
33851
0
                &&  code_match(&cc, pos_next, OP_neg, -1)) {
33852
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
33853
0
                    if (code_match(&cc, cc.pos, OP_drop, -1)) {
33854
0
                        if (cc.line_num >= 0) line_num = cc.line_num;
33855
0
                    } else {
33856
0
                        add_pc2line_info(s, bc_out.size, line_num);
33857
0
                        dbuf_putc(&bc_out, OP_push_bigint_i32);
33858
0
                        dbuf_put_u32(&bc_out, -val);
33859
0
                    }
33860
0
                    pos_next = cc.pos;
33861
0
                    break;
33862
0
                }
33863
0
            }
33864
0
            goto no_change;
33865
33866
0
#if SHORT_OPCODES
33867
1
        case OP_push_const:
33868
1
        case OP_fclosure:
33869
1
            if (OPTIMIZE) {
33870
1
                int idx = get_u32(bc_buf + pos + 1);
33871
1
                if (idx < 256) {
33872
1
                    add_pc2line_info(s, bc_out.size, line_num);
33873
1
                    dbuf_putc(&bc_out, OP_push_const8 + op - OP_push_const);
33874
1
                    dbuf_putc(&bc_out, idx);
33875
1
                    break;
33876
1
                }
33877
1
            }
33878
0
            goto no_change;
33879
33880
0
        case OP_get_field:
33881
0
            if (OPTIMIZE) {
33882
0
                JSAtom atom = get_u32(bc_buf + pos + 1);
33883
0
                if (atom == JS_ATOM_length) {
33884
0
                    JS_FreeAtom(ctx, atom);
33885
0
                    add_pc2line_info(s, bc_out.size, line_num);
33886
0
                    dbuf_putc(&bc_out, OP_get_length);
33887
0
                    break;
33888
0
                }
33889
0
            }
33890
0
            goto no_change;
33891
0
#endif
33892
0
        case OP_push_atom_value:
33893
0
            if (OPTIMIZE) {
33894
0
                JSAtom atom = get_u32(bc_buf + pos + 1);
33895
                /* remove push/drop pairs generated by the parser */
33896
0
                if (code_match(&cc, pos_next, OP_drop, -1)) {
33897
0
                    JS_FreeAtom(ctx, atom);
33898
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
33899
0
                    pos_next = cc.pos;
33900
0
                    break;
33901
0
                }
33902
0
#if SHORT_OPCODES
33903
0
                if (atom == JS_ATOM_empty_string) {
33904
0
                    JS_FreeAtom(ctx, atom);
33905
0
                    add_pc2line_info(s, bc_out.size, line_num);
33906
0
                    dbuf_putc(&bc_out, OP_push_empty_string);
33907
0
                    break;
33908
0
                }
33909
0
#endif
33910
0
            }
33911
0
            goto no_change;
33912
33913
0
        case OP_to_propkey:
33914
0
            if (OPTIMIZE) {
33915
                /* remove redundant to_propkey opcodes when storing simple data */
33916
0
                if (code_match(&cc, pos_next, M3(OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_put_array_el, -1)
33917
0
                ||  code_match(&cc, pos_next, M3(OP_push_i32, OP_push_const, OP_push_atom_value), OP_put_array_el, -1)
33918
0
                ||  code_match(&cc, pos_next, M4(OP_undefined, OP_null, OP_push_true, OP_push_false), OP_put_array_el, -1)) {
33919
0
                    break;
33920
0
                }
33921
0
            }
33922
0
            goto no_change;
33923
33924
3
        case OP_undefined:
33925
3
            if (OPTIMIZE) {
33926
                /* remove push/drop pairs generated by the parser */
33927
3
                if (code_match(&cc, pos_next, OP_drop, -1)) {
33928
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
33929
0
                    pos_next = cc.pos;
33930
0
                    break;
33931
0
                }
33932
                /* transform undefined return -> return_undefined */
33933
3
                if (code_match(&cc, pos_next, OP_return, -1)) {
33934
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
33935
0
                    add_pc2line_info(s, bc_out.size, line_num);
33936
0
                    dbuf_putc(&bc_out, OP_return_undef);
33937
0
                    pos_next = cc.pos;
33938
0
                    break;
33939
0
                }
33940
                /* transform undefined if_true(l1)/if_false(l1) -> nop/goto(l1) */
33941
3
                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {
33942
0
                    val = 0;
33943
0
                    goto has_constant_test;
33944
0
                }
33945
3
#if SHORT_OPCODES
33946
                /* transform undefined strict_eq -> is_undefined */
33947
3
                if (code_match(&cc, pos_next, OP_strict_eq, -1)) {
33948
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
33949
0
                    add_pc2line_info(s, bc_out.size, line_num);
33950
0
                    dbuf_putc(&bc_out, OP_is_undefined);
33951
0
                    pos_next = cc.pos;
33952
0
                    break;
33953
0
                }
33954
                /* transform undefined strict_neq if_false/if_true -> is_undefined if_true/if_false */
33955
3
                if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) {
33956
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
33957
0
                    add_pc2line_info(s, bc_out.size, line_num);
33958
0
                    dbuf_putc(&bc_out, OP_is_undefined);
33959
0
                    pos_next = cc.pos;
33960
0
                    label = cc.label;
33961
0
                    op = cc.op ^ OP_if_false ^ OP_if_true;
33962
0
                    goto has_label;
33963
0
                }
33964
3
#endif
33965
3
            }
33966
3
            goto no_change;
33967
33968
4
        case OP_insert2:
33969
4
            if (OPTIMIZE) {
33970
                /* Transformation:
33971
                   insert2 put_field(a) drop -> put_field(a)
33972
                   insert2 put_var_strict(a) drop -> put_var_strict(a)
33973
                */
33974
4
                if (code_match(&cc, pos_next, M2(OP_put_field, OP_put_var_strict), OP_drop, -1)) {
33975
4
                    if (cc.line_num >= 0) line_num = cc.line_num;
33976
4
                    add_pc2line_info(s, bc_out.size, line_num);
33977
4
                    dbuf_putc(&bc_out, cc.op);
33978
4
                    dbuf_put_u32(&bc_out, cc.atom);
33979
4
                    pos_next = cc.pos;
33980
4
                    break;
33981
4
                }
33982
4
            }
33983
0
            goto no_change;
33984
33985
0
        case OP_dup:
33986
0
            if (OPTIMIZE) {
33987
                /* Transformation: dup put_x(n) drop -> put_x(n) */
33988
0
                int op1, line2 = -1;
33989
                /* Transformation: dup put_x(n) -> set_x(n) */
33990
0
                if (code_match(&cc, pos_next, M3(OP_put_loc, OP_put_arg, OP_put_var_ref), -1, -1)) {
33991
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
33992
0
                    op1 = cc.op + 1;  /* put_x -> set_x */
33993
0
                    pos_next = cc.pos;
33994
0
                    if (code_match(&cc, cc.pos, OP_drop, -1)) {
33995
0
                        if (cc.line_num >= 0) line_num = cc.line_num;
33996
0
                        op1 -= 1; /* set_x drop -> put_x */
33997
0
                        pos_next = cc.pos;
33998
0
                        if (code_match(&cc, cc.pos, op1 - 1, cc.idx, -1)) {
33999
0
                            line2 = cc.line_num; /* delay line number update */
34000
0
                            op1 += 1;   /* put_x(n) get_x(n) -> set_x(n) */
34001
0
                            pos_next = cc.pos;
34002
0
                        }
34003
0
                    }
34004
0
                    add_pc2line_info(s, bc_out.size, line_num);
34005
0
                    put_short_code(&bc_out, op1, cc.idx);
34006
0
                    if (line2 >= 0) line_num = line2;
34007
0
                    break;
34008
0
                }
34009
0
            }
34010
0
            goto no_change;
34011
34012
0
        case OP_get_loc:
34013
0
            if (OPTIMIZE) {
34014
                /* transformation:
34015
                   get_loc(n) post_dec put_loc(n) drop -> dec_loc(n)
34016
                   get_loc(n) post_inc put_loc(n) drop -> inc_loc(n)
34017
                   get_loc(n) dec dup put_loc(n) drop -> dec_loc(n)
34018
                   get_loc(n) inc dup put_loc(n) drop -> inc_loc(n)
34019
                 */
34020
0
                int idx;
34021
0
                idx = get_u16(bc_buf + pos + 1);
34022
0
                if (idx >= 256)
34023
0
                    goto no_change;
34024
0
                if (code_match(&cc, pos_next, M2(OP_post_dec, OP_post_inc), OP_put_loc, idx, OP_drop, -1) ||
34025
0
                    code_match(&cc, pos_next, M2(OP_dec, OP_inc), OP_dup, OP_put_loc, idx, OP_drop, -1)) {
34026
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
34027
0
                    add_pc2line_info(s, bc_out.size, line_num);
34028
0
                    dbuf_putc(&bc_out, (cc.op == OP_inc || cc.op == OP_post_inc) ? OP_inc_loc : OP_dec_loc);
34029
0
                    dbuf_putc(&bc_out, idx);
34030
0
                    pos_next = cc.pos;
34031
0
                    break;
34032
0
                }
34033
                /* transformation:
34034
                   get_loc(n) push_atom_value(x) add dup put_loc(n) drop -> push_atom_value(x) add_loc(n)
34035
                 */
34036
0
                if (code_match(&cc, pos_next, OP_push_atom_value, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
34037
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
34038
0
                    add_pc2line_info(s, bc_out.size, line_num);
34039
0
#if SHORT_OPCODES
34040
0
                    if (cc.atom == JS_ATOM_empty_string) {
34041
0
                        JS_FreeAtom(ctx, cc.atom);
34042
0
                        dbuf_putc(&bc_out, OP_push_empty_string);
34043
0
                    } else
34044
0
#endif
34045
0
                    {
34046
0
                        dbuf_putc(&bc_out, OP_push_atom_value);
34047
0
                        dbuf_put_u32(&bc_out, cc.atom);
34048
0
                    }
34049
0
                    dbuf_putc(&bc_out, OP_add_loc);
34050
0
                    dbuf_putc(&bc_out, idx);
34051
0
                    pos_next = cc.pos;
34052
0
                    break;
34053
0
                }
34054
                /* transformation:
34055
                   get_loc(n) push_i32(x) add dup put_loc(n) drop -> push_i32(x) add_loc(n)
34056
                 */
34057
0
                if (code_match(&cc, pos_next, OP_push_i32, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {
34058
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
34059
0
                    add_pc2line_info(s, bc_out.size, line_num);
34060
0
                    push_short_int(&bc_out, cc.label);
34061
0
                    dbuf_putc(&bc_out, OP_add_loc);
34062
0
                    dbuf_putc(&bc_out, idx);
34063
0
                    pos_next = cc.pos;
34064
0
                    break;
34065
0
                }
34066
                /* transformation: XXX: also do these:
34067
                   get_loc(n) get_loc(x) add dup put_loc(n) drop -> get_loc(x) add_loc(n)
34068
                   get_loc(n) get_arg(x) add dup put_loc(n) drop -> get_arg(x) add_loc(n)
34069
                   get_loc(n) get_var_ref(x) add dup put_loc(n) drop -> get_var_ref(x) add_loc(n)
34070
                 */
34071
0
                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)) {
34072
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
34073
0
                    add_pc2line_info(s, bc_out.size, line_num);
34074
0
                    put_short_code(&bc_out, cc.op, cc.idx);
34075
0
                    dbuf_putc(&bc_out, OP_add_loc);
34076
0
                    dbuf_putc(&bc_out, idx);
34077
0
                    pos_next = cc.pos;
34078
0
                    break;
34079
0
                }
34080
0
                add_pc2line_info(s, bc_out.size, line_num);
34081
0
                put_short_code(&bc_out, op, idx);
34082
0
                break;
34083
0
            }
34084
0
            goto no_change;
34085
0
#if SHORT_OPCODES
34086
0
        case OP_get_arg:
34087
0
        case OP_get_var_ref:
34088
0
            if (OPTIMIZE) {
34089
0
                int idx;
34090
0
                idx = get_u16(bc_buf + pos + 1);
34091
0
                add_pc2line_info(s, bc_out.size, line_num);
34092
0
                put_short_code(&bc_out, op, idx);
34093
0
                break;
34094
0
            }
34095
0
            goto no_change;
34096
0
#endif
34097
0
        case OP_put_loc:
34098
0
        case OP_put_arg:
34099
0
        case OP_put_var_ref:
34100
0
            if (OPTIMIZE) {
34101
                /* transformation: put_x(n) get_x(n) -> set_x(n) */
34102
0
                int idx;
34103
0
                idx = get_u16(bc_buf + pos + 1);
34104
0
                if (code_match(&cc, pos_next, op - 1, idx, -1)) {
34105
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
34106
0
                    add_pc2line_info(s, bc_out.size, line_num);
34107
0
                    put_short_code(&bc_out, op + 1, idx);
34108
0
                    pos_next = cc.pos;
34109
0
                    break;
34110
0
                }
34111
0
                add_pc2line_info(s, bc_out.size, line_num);
34112
0
                put_short_code(&bc_out, op, idx);
34113
0
                break;
34114
0
            }
34115
0
            goto no_change;
34116
34117
0
        case OP_post_inc:
34118
0
        case OP_post_dec:
34119
0
            if (OPTIMIZE) {
34120
                /* transformation:
34121
                   post_inc put_x drop -> inc put_x
34122
                   post_inc perm3 put_field drop -> inc put_field
34123
                   post_inc perm3 put_var_strict drop -> inc put_var_strict
34124
                   post_inc perm4 put_array_el drop -> inc put_array_el
34125
                 */
34126
0
                int op1, idx;
34127
0
                if (code_match(&cc, pos_next, M3(OP_put_loc, OP_put_arg, OP_put_var_ref), -1, OP_drop, -1)) {
34128
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
34129
0
                    op1 = cc.op;
34130
0
                    idx = cc.idx;
34131
0
                    pos_next = cc.pos;
34132
0
                    if (code_match(&cc, cc.pos, op1 - 1, idx, -1)) {
34133
0
                        if (cc.line_num >= 0) line_num = cc.line_num;
34134
0
                        op1 += 1;   /* put_x(n) get_x(n) -> set_x(n) */
34135
0
                        pos_next = cc.pos;
34136
0
                    }
34137
0
                    add_pc2line_info(s, bc_out.size, line_num);
34138
0
                    dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
34139
0
                    put_short_code(&bc_out, op1, idx);
34140
0
                    break;
34141
0
                }
34142
0
                if (code_match(&cc, pos_next, OP_perm3, M2(OP_put_field, OP_put_var_strict), OP_drop, -1)) {
34143
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
34144
0
                    add_pc2line_info(s, bc_out.size, line_num);
34145
0
                    dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
34146
0
                    dbuf_putc(&bc_out, cc.op);
34147
0
                    dbuf_put_u32(&bc_out, cc.atom);
34148
0
                    pos_next = cc.pos;
34149
0
                    break;
34150
0
                }
34151
0
                if (code_match(&cc, pos_next, OP_perm4, OP_put_array_el, OP_drop, -1)) {
34152
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
34153
0
                    add_pc2line_info(s, bc_out.size, line_num);
34154
0
                    dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));
34155
0
                    dbuf_putc(&bc_out, OP_put_array_el);
34156
0
                    pos_next = cc.pos;
34157
0
                    break;
34158
0
                }
34159
0
            }
34160
0
            goto no_change;
34161
34162
0
#if SHORT_OPCODES
34163
0
        case OP_typeof:
34164
0
            if (OPTIMIZE) {
34165
                /* simplify typeof tests */
34166
0
                if (code_match(&cc, pos_next, OP_push_atom_value, M4(OP_strict_eq, OP_strict_neq, OP_eq, OP_neq), -1)) {
34167
0
                    if (cc.line_num >= 0) line_num = cc.line_num;
34168
0
                    int op1 = (cc.op == OP_strict_eq || cc.op == OP_eq) ? OP_strict_eq : OP_strict_neq;
34169
0
                    int op2 = -1;
34170
0
                    switch (cc.atom) {
34171
0
                    case JS_ATOM_undefined:
34172
0
                        op2 = OP_typeof_is_undefined;
34173
0
                        break;
34174
0
                    case JS_ATOM_function:
34175
0
                        op2 = OP_typeof_is_function;
34176
0
                        break;
34177
0
                    }
34178
0
                    if (op2 >= 0) {
34179
                        /* transform typeof(s) == "<type>" into is_<type> */
34180
0
                        if (op1 == OP_strict_eq) {
34181
0
                            add_pc2line_info(s, bc_out.size, line_num);
34182
0
                            dbuf_putc(&bc_out, op2);
34183
0
                            JS_FreeAtom(ctx, cc.atom);
34184
0
                            pos_next = cc.pos;
34185
0
                            break;
34186
0
                        }
34187
0
                        if (op1 == OP_strict_neq && code_match(&cc, cc.pos, OP_if_false, -1)) {
34188
                            /* transform typeof(s) != "<type>" if_false into is_<type> if_true */
34189
0
                            if (cc.line_num >= 0) line_num = cc.line_num;
34190
0
                            add_pc2line_info(s, bc_out.size, line_num);
34191
0
                            dbuf_putc(&bc_out, op2);
34192
0
                            JS_FreeAtom(ctx, cc.atom);
34193
0
                            pos_next = cc.pos;
34194
0
                            label = cc.label;
34195
0
                            op = OP_if_true;
34196
0
                            goto has_label;
34197
0
                        }
34198
0
                    }
34199
0
                }
34200
0
            }
34201
0
            goto no_change;
34202
0
#endif
34203
34204
13
        default:
34205
24
        no_change:
34206
24
            add_pc2line_info(s, bc_out.size, line_num);
34207
24
            dbuf_put(&bc_out, bc_buf + pos, len);
34208
24
            break;
34209
49
        }
34210
49
    }
34211
34212
    /* check that there were no missing labels */
34213
7
    for(i = 0; i < s->label_count; i++) {
34214
4
        assert(label_slots[i].first_reloc == NULL);
34215
4
    }
34216
3
#if SHORT_OPCODES
34217
3
    if (OPTIMIZE) {
34218
        /* more jump optimizations */
34219
3
        int patch_offsets = 0;
34220
6
        for (i = 0, jp = s->jump_slots; i < s->jump_count; i++, jp++) {
34221
3
            LabelSlot *ls;
34222
3
            JumpSlot *jp1;
34223
3
            int j, pos, diff, delta;
34224
34225
3
            delta = 3;
34226
3
            switch (op = jp->op) {
34227
0
            case OP_goto16:
34228
0
                delta = 1;
34229
                /* fall thru */
34230
0
            case OP_if_false:
34231
0
            case OP_if_true:
34232
0
            case OP_goto:
34233
0
                pos = jp->pos;
34234
0
                diff = s->label_slots[jp->label].addr - pos;
34235
0
                if (diff >= -128 && diff <= 127 + delta) {
34236
                    //put_u8(bc_out.buf + pos, diff);
34237
0
                    jp->size = 1;
34238
0
                    if (op == OP_goto16) {
34239
0
                        bc_out.buf[pos - 1] = jp->op = OP_goto8;
34240
0
                    } else {
34241
0
                        bc_out.buf[pos - 1] = jp->op = OP_if_false8 + (op - OP_if_false);
34242
0
                    }
34243
0
                    goto shrink;
34244
0
                } else
34245
0
                if (diff == (int16_t)diff && op == OP_goto) {
34246
                    //put_u16(bc_out.buf + pos, diff);
34247
0
                    jp->size = 2;
34248
0
                    delta = 2;
34249
0
                    bc_out.buf[pos - 1] = jp->op = OP_goto16;
34250
0
                shrink:
34251
                    /* XXX: should reduce complexity, using 2 finger copy scheme */
34252
0
                    memmove(bc_out.buf + pos + jp->size, bc_out.buf + pos + jp->size + delta,
34253
0
                            bc_out.size - pos - jp->size - delta);
34254
0
                    bc_out.size -= delta;
34255
0
                    patch_offsets++;
34256
0
                    for (j = 0, ls = s->label_slots; j < s->label_count; j++, ls++) {
34257
0
                        if (ls->addr > pos)
34258
0
                            ls->addr -= delta;
34259
0
                    }
34260
0
                    for (j = i + 1, jp1 = jp + 1; j < s->jump_count; j++, jp1++) {
34261
0
                        if (jp1->pos > pos)
34262
0
                            jp1->pos -= delta;
34263
0
                    }
34264
0
                    for (j = 0; j < s->line_number_count; j++) {
34265
0
                        if (s->line_number_slots[j].pc > pos)
34266
0
                            s->line_number_slots[j].pc -= delta;
34267
0
                    }
34268
0
                    continue;
34269
0
                }
34270
0
                break;
34271
3
            }
34272
3
        }
34273
3
        if (patch_offsets) {
34274
0
            JumpSlot *jp1;
34275
0
            int j;
34276
0
            for (j = 0, jp1 = s->jump_slots; j < s->jump_count; j++, jp1++) {
34277
0
                int diff1 = s->label_slots[jp1->label].addr - jp1->pos;
34278
0
                switch (jp1->size) {
34279
0
                case 1:
34280
0
                    put_u8(bc_out.buf + jp1->pos, diff1);
34281
0
                    break;
34282
0
                case 2:
34283
0
                    put_u16(bc_out.buf + jp1->pos, diff1);
34284
0
                    break;
34285
0
                case 4:
34286
0
                    put_u32(bc_out.buf + jp1->pos, diff1);
34287
0
                    break;
34288
0
                }
34289
0
            }
34290
0
        }
34291
3
    }
34292
3
    js_free(ctx, s->jump_slots);
34293
3
    s->jump_slots = NULL;
34294
3
#endif
34295
3
    js_free(ctx, s->label_slots);
34296
3
    s->label_slots = NULL;
34297
    /* XXX: should delay until copying to runtime bytecode function */
34298
3
    compute_pc2line_info(s);
34299
3
    js_free(ctx, s->line_number_slots);
34300
3
    s->line_number_slots = NULL;
34301
    /* set the new byte code */
34302
3
    dbuf_free(&s->byte_code);
34303
3
    s->byte_code = bc_out;
34304
3
    s->use_short_opcodes = TRUE;
34305
3
    if (dbuf_error(&s->byte_code)) {
34306
0
        JS_ThrowOutOfMemory(ctx);
34307
0
        return -1;
34308
0
    }
34309
3
    return 0;
34310
0
 fail:
34311
    /* XXX: not safe */
34312
0
    dbuf_free(&bc_out);
34313
0
    return -1;
34314
3
}
34315
34316
/* compute the maximum stack size needed by the function */
34317
34318
typedef struct StackSizeState {
34319
    int bc_len;
34320
    int stack_len_max;
34321
    uint16_t *stack_level_tab;
34322
    int32_t *catch_pos_tab;
34323
    int *pc_stack;
34324
    int pc_stack_len;
34325
    int pc_stack_size;
34326
} StackSizeState;
34327
34328
/* 'op' is only used for error indication */
34329
static __exception int ss_check(JSContext *ctx, StackSizeState *s,
34330
                                int pos, int op, int stack_len, int catch_pos)
34331
32
{
34332
32
    if ((unsigned)pos >= s->bc_len) {
34333
0
        JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
34334
0
        return -1;
34335
0
    }
34336
32
    if (stack_len > s->stack_len_max) {
34337
0
        s->stack_len_max = stack_len;
34338
0
        if (s->stack_len_max > JS_STACK_SIZE_MAX) {
34339
0
            JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
34340
0
            return -1;
34341
0
        }
34342
0
    }
34343
32
    if (s->stack_level_tab[pos] != 0xffff) {
34344
        /* already explored: check that the stack size is consistent */
34345
0
        if (s->stack_level_tab[pos] != stack_len) {
34346
0
            JS_ThrowInternalError(ctx, "inconsistent stack size: %d %d (pc=%d)",
34347
0
                                  s->stack_level_tab[pos], stack_len, pos);
34348
0
            return -1;
34349
0
        } else if (s->catch_pos_tab[pos] != catch_pos) {
34350
0
            JS_ThrowInternalError(ctx, "inconsistent catch position: %d %d (pc=%d)",
34351
0
                                  s->catch_pos_tab[pos], catch_pos, pos);
34352
0
            return -1;
34353
0
        } else {
34354
0
            return 0;
34355
0
        }
34356
0
    }
34357
34358
    /* mark as explored and store the stack size */
34359
32
    s->stack_level_tab[pos] = stack_len;
34360
32
    s->catch_pos_tab[pos] = catch_pos;
34361
34362
    /* queue the new PC to explore */
34363
32
    if (js_resize_array(ctx, (void **)&s->pc_stack, sizeof(s->pc_stack[0]),
34364
32
                        &s->pc_stack_size, s->pc_stack_len + 1))
34365
0
        return -1;
34366
32
    s->pc_stack[s->pc_stack_len++] = pos;
34367
32
    return 0;
34368
32
}
34369
34370
static __exception int compute_stack_size(JSContext *ctx,
34371
                                          JSFunctionDef *fd,
34372
                                          int *pstack_size)
34373
3
{
34374
3
    StackSizeState s_s, *s = &s_s;
34375
3
    int i, diff, n_pop, pos_next, stack_len, pos, op, catch_pos, catch_level;
34376
3
    const JSOpCode *oi;
34377
3
    const uint8_t *bc_buf;
34378
34379
3
    bc_buf = fd->byte_code.buf;
34380
3
    s->bc_len = fd->byte_code.size;
34381
    /* bc_len > 0 */
34382
3
    s->stack_level_tab = js_malloc(ctx, sizeof(s->stack_level_tab[0]) *
34383
3
                                   s->bc_len);
34384
3
    if (!s->stack_level_tab)
34385
0
        return -1;
34386
83
    for(i = 0; i < s->bc_len; i++)
34387
80
        s->stack_level_tab[i] = 0xffff;
34388
3
    s->pc_stack = NULL;
34389
3
    s->catch_pos_tab = js_malloc(ctx, sizeof(s->catch_pos_tab[0]) *
34390
3
                                   s->bc_len);
34391
3
    if (!s->catch_pos_tab)
34392
0
        goto fail;
34393
34394
3
    s->stack_len_max = 0;
34395
3
    s->pc_stack_len = 0;
34396
3
    s->pc_stack_size = 0;
34397
34398
    /* breadth-first graph exploration */
34399
3
    if (ss_check(ctx, s, 0, OP_invalid, 0, -1))
34400
0
        goto fail;
34401
34402
35
    while (s->pc_stack_len > 0) {
34403
32
        pos = s->pc_stack[--s->pc_stack_len];
34404
32
        stack_len = s->stack_level_tab[pos];
34405
32
        catch_pos = s->catch_pos_tab[pos];
34406
32
        op = bc_buf[pos];
34407
32
        if (op == 0 || op >= OP_COUNT) {
34408
0
            JS_ThrowInternalError(ctx, "invalid opcode (op=%d, pc=%d)", op, pos);
34409
0
            goto fail;
34410
0
        }
34411
32
        oi = &short_opcode_info(op);
34412
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 64)
34413
        printf("%5d: %10s %5d %5d\n", pos, oi->name, stack_len, catch_pos);
34414
#endif
34415
32
        pos_next = pos + oi->size;
34416
32
        if (pos_next > s->bc_len) {
34417
0
            JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
34418
0
            goto fail;
34419
0
        }
34420
32
        n_pop = oi->n_pop;
34421
        /* call pops a variable number of arguments */
34422
32
        if (oi->fmt == OP_FMT_npop || oi->fmt == OP_FMT_npop_u16) {
34423
0
            n_pop += get_u16(bc_buf + pos + 1);
34424
32
        } else {
34425
32
#if SHORT_OPCODES
34426
32
            if (oi->fmt == OP_FMT_npopx) {
34427
0
                n_pop += op - OP_call0;
34428
0
            }
34429
32
#endif
34430
32
        }
34431
34432
32
        if (stack_len < n_pop) {
34433
0
            JS_ThrowInternalError(ctx, "stack underflow (op=%d, pc=%d)", op, pos);
34434
0
            goto fail;
34435
0
        }
34436
32
        stack_len += oi->n_push - n_pop;
34437
32
        if (stack_len > s->stack_len_max) {
34438
5
            s->stack_len_max = stack_len;
34439
5
            if (s->stack_len_max > JS_STACK_SIZE_MAX) {
34440
0
                JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
34441
0
                goto fail;
34442
0
            }
34443
5
        }
34444
32
        switch(op) {
34445
0
        case OP_tail_call:
34446
0
        case OP_tail_call_method:
34447
0
        case OP_return:
34448
3
        case OP_return_undef:
34449
6
        case OP_return_async:
34450
6
        case OP_throw:
34451
6
        case OP_throw_error:
34452
6
        case OP_ret:
34453
6
            goto done_insn;
34454
0
        case OP_goto:
34455
0
            diff = get_u32(bc_buf + pos + 1);
34456
0
            pos_next = pos + 1 + diff;
34457
0
            break;
34458
0
#if SHORT_OPCODES
34459
0
        case OP_goto16:
34460
0
            diff = (int16_t)get_u16(bc_buf + pos + 1);
34461
0
            pos_next = pos + 1 + diff;
34462
0
            break;
34463
0
        case OP_goto8:
34464
0
            diff = (int8_t)bc_buf[pos + 1];
34465
0
            pos_next = pos + 1 + diff;
34466
0
            break;
34467
0
        case OP_if_true8:
34468
3
        case OP_if_false8:
34469
3
            diff = (int8_t)bc_buf[pos + 1];
34470
3
            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))
34471
0
                goto fail;
34472
3
            break;
34473
3
#endif
34474
3
        case OP_if_true:
34475
0
        case OP_if_false:
34476
0
            diff = get_u32(bc_buf + pos + 1);
34477
0
            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))
34478
0
                goto fail;
34479
0
            break;
34480
0
        case OP_gosub:
34481
0
            diff = get_u32(bc_buf + pos + 1);
34482
0
            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1, catch_pos))
34483
0
                goto fail;
34484
0
            break;
34485
0
        case OP_with_get_var:
34486
0
        case OP_with_delete_var:
34487
0
            diff = get_u32(bc_buf + pos + 5);
34488
0
            if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1, catch_pos))
34489
0
                goto fail;
34490
0
            break;
34491
0
        case OP_with_make_ref:
34492
0
        case OP_with_get_ref:
34493
0
            diff = get_u32(bc_buf + pos + 5);
34494
0
            if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2, catch_pos))
34495
0
                goto fail;
34496
0
            break;
34497
0
        case OP_with_put_var:
34498
0
            diff = get_u32(bc_buf + pos + 5);
34499
0
            if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1, catch_pos))
34500
0
                goto fail;
34501
0
            break;
34502
0
        case OP_catch:
34503
0
            diff = get_u32(bc_buf + pos + 1);
34504
0
            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))
34505
0
                goto fail;
34506
0
            catch_pos = pos;
34507
0
            break;
34508
0
        case OP_for_of_start:
34509
0
        case OP_for_await_of_start:
34510
0
            catch_pos = pos;
34511
0
            break;
34512
            /* we assume the catch offset entry is only removed with
34513
               some op codes */
34514
2
        case OP_drop:
34515
2
            catch_level = stack_len;
34516
2
            goto check_catch;
34517
0
        case OP_nip:
34518
0
            catch_level = stack_len - 1;
34519
0
            goto check_catch;
34520
0
        case OP_nip1:
34521
0
            catch_level = stack_len - 1;
34522
0
            goto check_catch;
34523
0
        case OP_iterator_close:
34524
0
            catch_level = stack_len + 2;
34525
2
        check_catch:
34526
            /* Note: for for_of_start/for_await_of_start we consider
34527
               the catch offset is on the first stack entry instead of
34528
               the thirst */
34529
2
            if (catch_pos >= 0) {
34530
0
                int level;
34531
0
                level = s->stack_level_tab[catch_pos];
34532
0
                if (bc_buf[catch_pos] != OP_catch)
34533
0
                    level++; /* for_of_start, for_wait_of_start */
34534
                /* catch_level = stack_level before op_catch is executed ? */
34535
0
                if (catch_level == level) {
34536
0
                    catch_pos = s->catch_pos_tab[catch_pos];
34537
0
                }
34538
0
            }
34539
2
            break;
34540
0
        case OP_nip_catch:
34541
0
            if (catch_pos < 0) {
34542
0
                JS_ThrowInternalError(ctx, "nip_catch: no catch op (pc=%d)", pos);
34543
0
                goto fail;
34544
0
            }
34545
0
            stack_len = s->stack_level_tab[catch_pos];
34546
0
            if (bc_buf[catch_pos] != OP_catch)
34547
0
                stack_len++; /* for_of_start, for_wait_of_start */
34548
0
            stack_len++; /* no stack overflow is possible by construction */
34549
0
            catch_pos = s->catch_pos_tab[catch_pos];
34550
0
            break;
34551
21
        default:
34552
21
            break;
34553
32
        }
34554
26
        if (ss_check(ctx, s, pos_next, op, stack_len, catch_pos))
34555
0
            goto fail;
34556
32
    done_insn: ;
34557
32
    }
34558
3
    js_free(ctx, s->pc_stack);
34559
3
    js_free(ctx, s->catch_pos_tab);
34560
3
    js_free(ctx, s->stack_level_tab);
34561
3
    *pstack_size = s->stack_len_max;
34562
3
    return 0;
34563
0
 fail:
34564
0
    js_free(ctx, s->pc_stack);
34565
0
    js_free(ctx, s->catch_pos_tab);
34566
0
    js_free(ctx, s->stack_level_tab);
34567
0
    *pstack_size = 0;
34568
0
    return -1;
34569
3
}
34570
34571
static int add_module_variables(JSContext *ctx, JSFunctionDef *fd)
34572
3
{
34573
3
    int i, idx;
34574
3
    JSModuleDef *m = fd->module;
34575
3
    JSExportEntry *me;
34576
3
    JSGlobalVar *hf;
34577
34578
    /* The imported global variables were added as closure variables
34579
       in js_parse_import(). We add here the module global
34580
       variables. */
34581
34582
3
    for(i = 0; i < fd->global_var_count; i++) {
34583
0
        hf = &fd->global_vars[i];
34584
0
        if (add_closure_var(ctx, fd, TRUE, FALSE, i, hf->var_name, hf->is_const,
34585
0
                            hf->is_lexical, FALSE) < 0)
34586
0
            return -1;
34587
0
    }
34588
34589
    /* resolve the variable names of the local exports */
34590
3
    for(i = 0; i < m->export_entries_count; i++) {
34591
0
        me = &m->export_entries[i];
34592
0
        if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
34593
0
            idx = find_closure_var(ctx, fd, me->local_name);
34594
0
            if (idx < 0) {
34595
0
                JS_ThrowSyntaxErrorAtom(ctx, "exported variable '%s' does not exist",
34596
0
                                        me->local_name);
34597
0
                return -1;
34598
0
            }
34599
0
            me->u.local.var_idx = idx;
34600
0
        }
34601
0
    }
34602
3
    return 0;
34603
3
}
34604
34605
/* create a function object from a function definition. The function
34606
   definition is freed. All the child functions are also created. It
34607
   must be done this way to resolve all the variables. */
34608
static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
34609
3
{
34610
3
    JSValue func_obj;
34611
3
    JSFunctionBytecode *b;
34612
3
    struct list_head *el, *el1;
34613
3
    int stack_size, scope, idx;
34614
3
    int function_size, byte_code_offset, cpool_offset;
34615
3
    int closure_var_offset, vardefs_offset;
34616
34617
    /* recompute scope linkage */
34618
9
    for (scope = 0; scope < fd->scope_count; scope++) {
34619
6
        fd->scopes[scope].first = -1;
34620
6
    }
34621
3
    if (fd->has_parameter_expressions) {
34622
        /* special end of variable list marker for the argument scope */
34623
0
        fd->scopes[ARG_SCOPE_INDEX].first = ARG_SCOPE_END;
34624
0
    }
34625
3
    for (idx = 0; idx < fd->var_count; idx++) {
34626
0
        JSVarDef *vd = &fd->vars[idx];
34627
0
        vd->scope_next = fd->scopes[vd->scope_level].first;
34628
0
        fd->scopes[vd->scope_level].first = idx;
34629
0
    }
34630
3
    for (scope = 2; scope < fd->scope_count; scope++) {
34631
0
        JSVarScope *sd = &fd->scopes[scope];
34632
0
        if (sd->first < 0)
34633
0
            sd->first = fd->scopes[sd->parent].first;
34634
0
    }
34635
3
    for (idx = 0; idx < fd->var_count; idx++) {
34636
0
        JSVarDef *vd = &fd->vars[idx];
34637
0
        if (vd->scope_next < 0 && vd->scope_level > 1) {
34638
0
            scope = fd->scopes[vd->scope_level].parent;
34639
0
            vd->scope_next = fd->scopes[scope].first;
34640
0
        }
34641
0
    }
34642
34643
    /* if the function contains an eval call, the closure variables
34644
       are used to compile the eval and they must be ordered by scope,
34645
       so it is necessary to create the closure variables before any
34646
       other variable lookup is done. */
34647
3
    if (fd->has_eval_call)
34648
0
        add_eval_variables(ctx, fd);
34649
34650
    /* add the module global variables in the closure */
34651
3
    if (fd->module) {
34652
3
        if (add_module_variables(ctx, fd))
34653
0
            goto fail;
34654
3
    }
34655
34656
    /* first create all the child functions */
34657
3
    list_for_each_safe(el, el1, &fd->child_list) {
34658
0
        JSFunctionDef *fd1;
34659
0
        int cpool_idx;
34660
34661
0
        fd1 = list_entry(el, JSFunctionDef, link);
34662
0
        cpool_idx = fd1->parent_cpool_idx;
34663
0
        func_obj = js_create_function(ctx, fd1);
34664
0
        if (JS_IsException(func_obj))
34665
0
            goto fail;
34666
        /* save it in the constant pool */
34667
0
        assert(cpool_idx >= 0);
34668
0
        fd->cpool[cpool_idx] = func_obj;
34669
0
    }
34670
34671
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 4)
34672
    if (!fd->strip_debug) {
34673
        printf("pass 1\n");
34674
        dump_byte_code(ctx, 1, fd->byte_code.buf, fd->byte_code.size,
34675
                       fd->args, fd->arg_count, fd->vars, fd->var_count,
34676
                       fd->closure_var, fd->closure_var_count,
34677
                       fd->cpool, fd->cpool_count, fd->source,
34678
                       fd->label_slots, NULL);
34679
        printf("\n");
34680
    }
34681
#endif
34682
34683
3
    if (resolve_variables(ctx, fd))
34684
0
        goto fail;
34685
34686
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 2)
34687
    if (!fd->strip_debug) {
34688
        printf("pass 2\n");
34689
        dump_byte_code(ctx, 2, fd->byte_code.buf, fd->byte_code.size,
34690
                       fd->args, fd->arg_count, fd->vars, fd->var_count,
34691
                       fd->closure_var, fd->closure_var_count,
34692
                       fd->cpool, fd->cpool_count, fd->source,
34693
                       fd->label_slots, NULL);
34694
        printf("\n");
34695
    }
34696
#endif
34697
34698
3
    if (resolve_labels(ctx, fd))
34699
0
        goto fail;
34700
34701
3
    if (compute_stack_size(ctx, fd, &stack_size) < 0)
34702
0
        goto fail;
34703
34704
3
    if (fd->strip_debug) {
34705
0
        function_size = offsetof(JSFunctionBytecode, debug);
34706
3
    } else {
34707
3
        function_size = sizeof(*b);
34708
3
    }
34709
3
    cpool_offset = function_size;
34710
3
    function_size += fd->cpool_count * sizeof(*fd->cpool);
34711
3
    vardefs_offset = function_size;
34712
3
    if (!fd->strip_debug || fd->has_eval_call) {
34713
3
        function_size += (fd->arg_count + fd->var_count) * sizeof(*b->vardefs);
34714
3
    }
34715
3
    closure_var_offset = function_size;
34716
3
    function_size += fd->closure_var_count * sizeof(*fd->closure_var);
34717
3
    byte_code_offset = function_size;
34718
3
    function_size += fd->byte_code.size;
34719
34720
3
    b = js_mallocz(ctx, function_size);
34721
3
    if (!b)
34722
0
        goto fail;
34723
3
    b->header.ref_count = 1;
34724
34725
3
    b->byte_code_buf = (void *)((uint8_t*)b + byte_code_offset);
34726
3
    b->byte_code_len = fd->byte_code.size;
34727
3
    memcpy(b->byte_code_buf, fd->byte_code.buf, fd->byte_code.size);
34728
3
    js_free(ctx, fd->byte_code.buf);
34729
3
    fd->byte_code.buf = NULL;
34730
34731
3
    b->func_name = fd->func_name;
34732
3
    if (fd->arg_count + fd->var_count > 0) {
34733
0
        if (fd->strip_debug && !fd->has_eval_call) {
34734
            /* Strip variable definitions not needed at runtime */
34735
0
            int i;
34736
0
            for(i = 0; i < fd->var_count; i++) {
34737
0
                JS_FreeAtom(ctx, fd->vars[i].var_name);
34738
0
            }
34739
0
            for(i = 0; i < fd->arg_count; i++) {
34740
0
                JS_FreeAtom(ctx, fd->args[i].var_name);
34741
0
            }
34742
0
            for(i = 0; i < fd->closure_var_count; i++) {
34743
0
                JS_FreeAtom(ctx, fd->closure_var[i].var_name);
34744
0
                fd->closure_var[i].var_name = JS_ATOM_NULL;
34745
0
            }
34746
0
        } else {
34747
0
            b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
34748
0
            memcpy_no_ub(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0]));
34749
0
            memcpy_no_ub(b->vardefs + fd->arg_count, fd->vars, fd->var_count * sizeof(fd->vars[0]));
34750
0
        }
34751
0
        b->var_count = fd->var_count;
34752
0
        b->arg_count = fd->arg_count;
34753
0
        b->defined_arg_count = fd->defined_arg_count;
34754
0
        js_free(ctx, fd->args);
34755
0
        js_free(ctx, fd->vars);
34756
0
    }
34757
3
    b->cpool_count = fd->cpool_count;
34758
3
    if (b->cpool_count) {
34759
1
        b->cpool = (void *)((uint8_t*)b + cpool_offset);
34760
1
        memcpy(b->cpool, fd->cpool, b->cpool_count * sizeof(*b->cpool));
34761
1
    }
34762
3
    js_free(ctx, fd->cpool);
34763
3
    fd->cpool = NULL;
34764
34765
3
    b->stack_size = stack_size;
34766
34767
3
    if (fd->strip_debug) {
34768
0
        JS_FreeAtom(ctx, fd->filename);
34769
0
        dbuf_free(&fd->pc2line);    // probably useless
34770
3
    } else {
34771
        /* XXX: source and pc2line info should be packed at the end of the
34772
           JSFunctionBytecode structure, avoiding allocation overhead
34773
         */
34774
3
        b->has_debug = 1;
34775
3
        b->debug.filename = fd->filename;
34776
34777
        //DynBuf pc2line;
34778
        //compute_pc2line_info(fd, &pc2line);
34779
        //js_free(ctx, fd->line_number_slots)
34780
3
        b->debug.pc2line_buf = js_realloc(ctx, fd->pc2line.buf, fd->pc2line.size);
34781
3
        if (!b->debug.pc2line_buf)
34782
0
            b->debug.pc2line_buf = fd->pc2line.buf;
34783
3
        b->debug.pc2line_len = fd->pc2line.size;
34784
3
        b->debug.source = fd->source;
34785
3
        b->debug.source_len = fd->source_len;
34786
3
    }
34787
3
    if (fd->scopes != fd->def_scope_array)
34788
0
        js_free(ctx, fd->scopes);
34789
34790
3
    b->closure_var_count = fd->closure_var_count;
34791
3
    if (b->closure_var_count) {
34792
2
        b->closure_var = (void *)((uint8_t*)b + closure_var_offset);
34793
2
        memcpy(b->closure_var, fd->closure_var, b->closure_var_count * sizeof(*b->closure_var));
34794
2
    }
34795
3
    js_free(ctx, fd->closure_var);
34796
3
    fd->closure_var = NULL;
34797
34798
3
    b->has_prototype = fd->has_prototype;
34799
3
    b->has_simple_parameter_list = fd->has_simple_parameter_list;
34800
3
    b->js_mode = fd->js_mode;
34801
3
    b->is_derived_class_constructor = fd->is_derived_class_constructor;
34802
3
    b->func_kind = fd->func_kind;
34803
3
    b->need_home_object = (fd->home_object_var_idx >= 0 ||
34804
3
                           fd->need_home_object);
34805
3
    b->new_target_allowed = fd->new_target_allowed;
34806
3
    b->super_call_allowed = fd->super_call_allowed;
34807
3
    b->super_allowed = fd->super_allowed;
34808
3
    b->arguments_allowed = fd->arguments_allowed;
34809
3
    b->is_direct_or_indirect_eval = (fd->eval_type == JS_EVAL_TYPE_DIRECT ||
34810
3
                                     fd->eval_type == JS_EVAL_TYPE_INDIRECT);
34811
3
    b->realm = JS_DupContext(ctx);
34812
34813
3
    add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
34814
34815
#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 1)
34816
    if (!fd->strip_debug) {
34817
        js_dump_function_bytecode(ctx, b);
34818
    }
34819
#endif
34820
34821
3
    if (fd->parent) {
34822
        /* remove from parent list */
34823
0
        list_del(&fd->link);
34824
0
    }
34825
34826
3
    js_free(ctx, fd);
34827
3
    return JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);
34828
0
 fail:
34829
0
    js_free_function_def(ctx, fd);
34830
0
    return JS_EXCEPTION;
34831
3
}
34832
34833
static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b)
34834
4
{
34835
4
    int i;
34836
34837
#if 0
34838
    {
34839
        char buf[ATOM_GET_STR_BUF_SIZE];
34840
        printf("freeing %s\n",
34841
               JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
34842
    }
34843
#endif
34844
4
    free_bytecode_atoms(rt, b->byte_code_buf, b->byte_code_len, TRUE);
34845
34846
4
    if (b->vardefs) {
34847
0
        for(i = 0; i < b->arg_count + b->var_count; i++) {
34848
0
            JS_FreeAtomRT(rt, b->vardefs[i].var_name);
34849
0
        }
34850
0
    }
34851
6
    for(i = 0; i < b->cpool_count; i++)
34852
2
        JS_FreeValueRT(rt, b->cpool[i]);
34853
34854
8
    for(i = 0; i < b->closure_var_count; i++) {
34855
4
        JSClosureVar *cv = &b->closure_var[i];
34856
4
        JS_FreeAtomRT(rt, cv->var_name);
34857
4
    }
34858
4
    if (b->realm)
34859
4
        JS_FreeContext(b->realm);
34860
34861
4
    JS_FreeAtomRT(rt, b->func_name);
34862
4
    if (b->has_debug) {
34863
4
        JS_FreeAtomRT(rt, b->debug.filename);
34864
4
        js_free_rt(rt, b->debug.pc2line_buf);
34865
4
        js_free_rt(rt, b->debug.source);
34866
4
    }
34867
34868
4
    remove_gc_object(&b->header);
34869
4
    if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && b->header.ref_count != 0) {
34870
3
        list_add_tail(&b->header.link, &rt->gc_zero_ref_count_list);
34871
3
    } else {
34872
1
        js_free_rt(rt, b);
34873
1
    }
34874
4
}
34875
34876
static __exception int js_parse_directives(JSParseState *s)
34877
4
{
34878
4
    char str[20];
34879
4
    JSParsePos pos;
34880
4
    BOOL has_semi;
34881
34882
4
    if (s->token.val != TOK_STRING)
34883
4
        return 0;
34884
34885
0
    js_parse_get_pos(s, &pos);
34886
34887
0
    while(s->token.val == TOK_STRING) {
34888
        /* Copy actual source string representation */
34889
0
        snprintf(str, sizeof str, "%.*s",
34890
0
                 (int)(s->buf_ptr - s->token.ptr - 2), s->token.ptr + 1);
34891
34892
0
        if (next_token(s))
34893
0
            return -1;
34894
34895
0
        has_semi = FALSE;
34896
0
        switch (s->token.val) {
34897
0
        case ';':
34898
0
            if (next_token(s))
34899
0
                return -1;
34900
0
            has_semi = TRUE;
34901
0
            break;
34902
0
        case '}':
34903
0
        case TOK_EOF:
34904
0
            has_semi = TRUE;
34905
0
            break;
34906
0
        case TOK_NUMBER:
34907
0
        case TOK_STRING:
34908
0
        case TOK_TEMPLATE:
34909
0
        case TOK_IDENT:
34910
0
        case TOK_REGEXP:
34911
0
        case TOK_DEC:
34912
0
        case TOK_INC:
34913
0
        case TOK_NULL:
34914
0
        case TOK_FALSE:
34915
0
        case TOK_TRUE:
34916
0
        case TOK_IF:
34917
0
        case TOK_RETURN:
34918
0
        case TOK_VAR:
34919
0
        case TOK_THIS:
34920
0
        case TOK_DELETE:
34921
0
        case TOK_TYPEOF:
34922
0
        case TOK_NEW:
34923
0
        case TOK_DO:
34924
0
        case TOK_WHILE:
34925
0
        case TOK_FOR:
34926
0
        case TOK_SWITCH:
34927
0
        case TOK_THROW:
34928
0
        case TOK_TRY:
34929
0
        case TOK_FUNCTION:
34930
0
        case TOK_DEBUGGER:
34931
0
        case TOK_WITH:
34932
0
        case TOK_CLASS:
34933
0
        case TOK_CONST:
34934
0
        case TOK_ENUM:
34935
0
        case TOK_EXPORT:
34936
0
        case TOK_IMPORT:
34937
0
        case TOK_SUPER:
34938
0
        case TOK_INTERFACE:
34939
0
        case TOK_LET:
34940
0
        case TOK_PACKAGE:
34941
0
        case TOK_PRIVATE:
34942
0
        case TOK_PROTECTED:
34943
0
        case TOK_PUBLIC:
34944
0
        case TOK_STATIC:
34945
            /* automatic insertion of ';' */
34946
0
            if (s->got_lf)
34947
0
                has_semi = TRUE;
34948
0
            break;
34949
0
        default:
34950
0
            break;
34951
0
        }
34952
0
        if (!has_semi)
34953
0
            break;
34954
0
        if (!strcmp(str, "use strict")) {
34955
0
            s->cur_func->has_use_strict = TRUE;
34956
0
            s->cur_func->js_mode |= JS_MODE_STRICT;
34957
0
        }
34958
0
    }
34959
0
    return js_parse_seek_token(s, &pos);
34960
0
}
34961
34962
/* return TRUE if the keyword is forbidden only in strict mode */
34963
static BOOL is_strict_future_keyword(JSAtom atom)
34964
0
{
34965
0
    return (atom >= JS_ATOM_LAST_KEYWORD + 1 && atom <= JS_ATOM_LAST_STRICT_KEYWORD);
34966
0
}
34967
34968
static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd,
34969
                                         JSAtom func_name)
34970
0
{
34971
0
    JSAtom name;
34972
0
    int i, idx;
34973
34974
0
    if (fd->js_mode & JS_MODE_STRICT) {
34975
0
        if (!fd->has_simple_parameter_list && fd->has_use_strict) {
34976
0
            return js_parse_error(s, "\"use strict\" not allowed in function with default or destructuring parameter");
34977
0
        }
34978
0
        if (func_name == JS_ATOM_eval || func_name == JS_ATOM_arguments ||
34979
0
            is_strict_future_keyword(func_name)) {
34980
0
            return js_parse_error(s, "invalid function name in strict code");
34981
0
        }
34982
0
        for (idx = 0; idx < fd->arg_count; idx++) {
34983
0
            name = fd->args[idx].var_name;
34984
34985
0
            if (name == JS_ATOM_eval || name == JS_ATOM_arguments ||
34986
0
                is_strict_future_keyword(name)) {
34987
0
                return js_parse_error(s, "invalid argument name in strict code");
34988
0
            }
34989
0
        }
34990
0
    }
34991
    /* check async_generator case */
34992
0
    if ((fd->js_mode & JS_MODE_STRICT)
34993
0
    ||  !fd->has_simple_parameter_list
34994
0
    ||  (fd->func_type == JS_PARSE_FUNC_METHOD && fd->func_kind == JS_FUNC_ASYNC)
34995
0
    ||  fd->func_type == JS_PARSE_FUNC_ARROW
34996
0
    ||  fd->func_type == JS_PARSE_FUNC_METHOD) {
34997
0
        for (idx = 0; idx < fd->arg_count; idx++) {
34998
0
            name = fd->args[idx].var_name;
34999
0
            if (name != JS_ATOM_NULL) {
35000
0
                for (i = 0; i < idx; i++) {
35001
0
                    if (fd->args[i].var_name == name)
35002
0
                        goto duplicate;
35003
0
                }
35004
                /* Check if argument name duplicates a destructuring parameter */
35005
                /* XXX: should have a flag for such variables */
35006
0
                for (i = 0; i < fd->var_count; i++) {
35007
0
                    if (fd->vars[i].var_name == name &&
35008
0
                        fd->vars[i].scope_level == 0)
35009
0
                        goto duplicate;
35010
0
                }
35011
0
            }
35012
0
        }
35013
0
    }
35014
0
    return 0;
35015
35016
0
duplicate:
35017
0
    return js_parse_error(s, "duplicate argument names not allowed in this context");
35018
0
}
35019
35020
/* create a function to initialize class fields */
35021
static JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s)
35022
0
{
35023
0
    JSFunctionDef *fd;
35024
35025
0
    fd = js_new_function_def(s->ctx, s->cur_func, FALSE, FALSE,
35026
0
                             s->filename, s->buf_start,
35027
0
                             &s->get_line_col_cache);
35028
0
    if (!fd)
35029
0
        return NULL;
35030
0
    fd->func_name = JS_ATOM_NULL;
35031
0
    fd->has_prototype = FALSE;
35032
0
    fd->has_home_object = TRUE;
35033
35034
0
    fd->has_arguments_binding = FALSE;
35035
0
    fd->has_this_binding = TRUE;
35036
0
    fd->is_derived_class_constructor = FALSE;
35037
0
    fd->new_target_allowed = TRUE;
35038
0
    fd->super_call_allowed = FALSE;
35039
0
    fd->super_allowed = fd->has_home_object;
35040
0
    fd->arguments_allowed = FALSE;
35041
35042
0
    fd->func_kind = JS_FUNC_NORMAL;
35043
0
    fd->func_type = JS_PARSE_FUNC_METHOD;
35044
0
    return fd;
35045
0
}
35046
35047
/* func_name must be JS_ATOM_NULL for JS_PARSE_FUNC_STATEMENT and
35048
   JS_PARSE_FUNC_EXPR, JS_PARSE_FUNC_ARROW and JS_PARSE_FUNC_VAR */
35049
static __exception int js_parse_function_decl2(JSParseState *s,
35050
                                               JSParseFunctionEnum func_type,
35051
                                               JSFunctionKindEnum func_kind,
35052
                                               JSAtom func_name,
35053
                                               const uint8_t *ptr,
35054
                                               JSParseExportEnum export_flag,
35055
                                               JSFunctionDef **pfd)
35056
0
{
35057
0
    JSContext *ctx = s->ctx;
35058
0
    JSFunctionDef *fd = s->cur_func;
35059
0
    BOOL is_expr;
35060
0
    int func_idx, lexical_func_idx = -1;
35061
0
    BOOL has_opt_arg;
35062
0
    BOOL create_func_var = FALSE;
35063
35064
0
    is_expr = (func_type != JS_PARSE_FUNC_STATEMENT &&
35065
0
               func_type != JS_PARSE_FUNC_VAR);
35066
35067
0
    if (func_type == JS_PARSE_FUNC_STATEMENT ||
35068
0
        func_type == JS_PARSE_FUNC_VAR ||
35069
0
        func_type == JS_PARSE_FUNC_EXPR) {
35070
0
        if (func_kind == JS_FUNC_NORMAL &&
35071
0
            token_is_pseudo_keyword(s, JS_ATOM_async) &&
35072
0
            peek_token(s, TRUE) != '\n') {
35073
0
            if (next_token(s))
35074
0
                return -1;
35075
0
            func_kind = JS_FUNC_ASYNC;
35076
0
        }
35077
0
        if (next_token(s))
35078
0
            return -1;
35079
0
        if (s->token.val == '*') {
35080
0
            if (next_token(s))
35081
0
                return -1;
35082
0
            func_kind |= JS_FUNC_GENERATOR;
35083
0
        }
35084
35085
0
        if (s->token.val == TOK_IDENT) {
35086
0
            if (s->token.u.ident.is_reserved ||
35087
0
                (s->token.u.ident.atom == JS_ATOM_yield &&
35088
0
                 func_type == JS_PARSE_FUNC_EXPR &&
35089
0
                 (func_kind & JS_FUNC_GENERATOR)) ||
35090
0
                (s->token.u.ident.atom == JS_ATOM_await &&
35091
0
                 ((func_type == JS_PARSE_FUNC_EXPR &&
35092
0
                   (func_kind & JS_FUNC_ASYNC)) ||
35093
0
                  func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))) {
35094
0
                return js_parse_error_reserved_identifier(s);
35095
0
            }
35096
0
        }
35097
0
        if (s->token.val == TOK_IDENT ||
35098
0
            (((s->token.val == TOK_YIELD && !(fd->js_mode & JS_MODE_STRICT)) ||
35099
0
             (s->token.val == TOK_AWAIT && !s->is_module)) &&
35100
0
             func_type == JS_PARSE_FUNC_EXPR)) {
35101
0
            func_name = JS_DupAtom(ctx, s->token.u.ident.atom);
35102
0
            if (next_token(s)) {
35103
0
                JS_FreeAtom(ctx, func_name);
35104
0
                return -1;
35105
0
            }
35106
0
        } else {
35107
0
            if (func_type != JS_PARSE_FUNC_EXPR &&
35108
0
                export_flag != JS_PARSE_EXPORT_DEFAULT) {
35109
0
                return js_parse_error(s, "function name expected");
35110
0
            }
35111
0
        }
35112
0
    } else if (func_type != JS_PARSE_FUNC_ARROW) {
35113
0
        func_name = JS_DupAtom(ctx, func_name);
35114
0
    }
35115
35116
0
    if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_MODULE &&
35117
0
        (func_type == JS_PARSE_FUNC_STATEMENT || func_type == JS_PARSE_FUNC_VAR)) {
35118
0
        JSGlobalVar *hf;
35119
0
        hf = find_global_var(fd, func_name);
35120
        /* XXX: should check scope chain */
35121
0
        if (hf && hf->scope_level == fd->scope_level) {
35122
0
            js_parse_error(s, "invalid redefinition of global identifier in module code");
35123
0
            JS_FreeAtom(ctx, func_name);
35124
0
            return -1;
35125
0
        }
35126
0
    }
35127
35128
0
    if (func_type == JS_PARSE_FUNC_VAR) {
35129
0
        if (!(fd->js_mode & JS_MODE_STRICT)
35130
0
        && func_kind == JS_FUNC_NORMAL
35131
0
        &&  find_lexical_decl(ctx, fd, func_name, fd->scope_first, FALSE) < 0
35132
0
        &&  !((func_idx = find_var(ctx, fd, func_name)) >= 0 && (func_idx & ARGUMENT_VAR_OFFSET))
35133
0
        &&  !(func_name == JS_ATOM_arguments && fd->has_arguments_binding)) {
35134
0
            create_func_var = TRUE;
35135
0
        }
35136
        /* Create the lexical name here so that the function closure
35137
           contains it */
35138
0
        if (fd->is_eval &&
35139
0
            (fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
35140
0
             fd->eval_type == JS_EVAL_TYPE_MODULE) &&
35141
0
            fd->scope_level == fd->body_scope) {
35142
            /* avoid creating a lexical variable in the global
35143
               scope. XXX: check annex B */
35144
0
            JSGlobalVar *hf;
35145
0
            hf = find_global_var(fd, func_name);
35146
            /* XXX: should check scope chain */
35147
0
            if (hf && hf->scope_level == fd->scope_level) {
35148
0
                js_parse_error(s, "invalid redefinition of global identifier");
35149
0
                JS_FreeAtom(ctx, func_name);
35150
0
                return -1;
35151
0
            }
35152
0
        } else {
35153
            /* Always create a lexical name, fail if at the same scope as
35154
               existing name */
35155
            /* Lexical variable will be initialized upon entering scope */
35156
0
            lexical_func_idx = define_var(s, fd, func_name,
35157
0
                                          func_kind != JS_FUNC_NORMAL ?
35158
0
                                          JS_VAR_DEF_NEW_FUNCTION_DECL :
35159
0
                                          JS_VAR_DEF_FUNCTION_DECL);
35160
0
            if (lexical_func_idx < 0) {
35161
0
                JS_FreeAtom(ctx, func_name);
35162
0
                return -1;
35163
0
            }
35164
0
        }
35165
0
    }
35166
35167
0
    fd = js_new_function_def(ctx, fd, FALSE, is_expr,
35168
0
                             s->filename, ptr,
35169
0
                             &s->get_line_col_cache);
35170
0
    if (!fd) {
35171
0
        JS_FreeAtom(ctx, func_name);
35172
0
        return -1;
35173
0
    }
35174
0
    if (pfd)
35175
0
        *pfd = fd;
35176
0
    s->cur_func = fd;
35177
0
    fd->func_name = func_name;
35178
    /* XXX: test !fd->is_generator is always false */
35179
0
    fd->has_prototype = (func_type == JS_PARSE_FUNC_STATEMENT ||
35180
0
                         func_type == JS_PARSE_FUNC_VAR ||
35181
0
                         func_type == JS_PARSE_FUNC_EXPR) &&
35182
0
                        func_kind == JS_FUNC_NORMAL;
35183
0
    fd->has_home_object = (func_type == JS_PARSE_FUNC_METHOD ||
35184
0
                           func_type == JS_PARSE_FUNC_GETTER ||
35185
0
                           func_type == JS_PARSE_FUNC_SETTER ||
35186
0
                           func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR ||
35187
0
                           func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);
35188
0
    fd->has_arguments_binding = (func_type != JS_PARSE_FUNC_ARROW &&
35189
0
                                 func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT);
35190
0
    fd->has_this_binding = fd->has_arguments_binding;
35191
0
    fd->is_derived_class_constructor = (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);
35192
0
    if (func_type == JS_PARSE_FUNC_ARROW) {
35193
0
        fd->new_target_allowed = fd->parent->new_target_allowed;
35194
0
        fd->super_call_allowed = fd->parent->super_call_allowed;
35195
0
        fd->super_allowed = fd->parent->super_allowed;
35196
0
        fd->arguments_allowed = fd->parent->arguments_allowed;
35197
0
    } else if (func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) {
35198
0
        fd->new_target_allowed = TRUE; // although new.target === undefined
35199
0
        fd->super_call_allowed = FALSE;
35200
0
        fd->super_allowed = TRUE;
35201
0
        fd->arguments_allowed = FALSE;
35202
0
    } else {
35203
0
        fd->new_target_allowed = TRUE;
35204
0
        fd->super_call_allowed = fd->is_derived_class_constructor;
35205
0
        fd->super_allowed = fd->has_home_object;
35206
0
        fd->arguments_allowed = TRUE;
35207
0
    }
35208
35209
    /* fd->in_function_body == FALSE prevents yield/await during the parsing
35210
       of the arguments in generator/async functions. They are parsed as
35211
       regular identifiers for other function kinds. */
35212
0
    fd->func_kind = func_kind;
35213
0
    fd->func_type = func_type;
35214
35215
0
    if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR ||
35216
0
        func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR) {
35217
        /* error if not invoked as a constructor */
35218
0
        emit_op(s, OP_check_ctor);
35219
0
    }
35220
35221
0
    if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) {
35222
0
        emit_class_field_init(s);
35223
0
    }
35224
35225
    /* parse arguments */
35226
0
    fd->has_simple_parameter_list = TRUE;
35227
0
    fd->has_parameter_expressions = FALSE;
35228
0
    has_opt_arg = FALSE;
35229
0
    if (func_type == JS_PARSE_FUNC_ARROW && s->token.val == TOK_IDENT) {
35230
0
        JSAtom name;
35231
0
        if (s->token.u.ident.is_reserved) {
35232
0
            js_parse_error_reserved_identifier(s);
35233
0
            goto fail;
35234
0
        }
35235
0
        name = s->token.u.ident.atom;
35236
0
        if (add_arg(ctx, fd, name) < 0)
35237
0
            goto fail;
35238
0
        fd->defined_arg_count = 1;
35239
0
    } else if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) {
35240
0
        if (s->token.val == '(') {
35241
0
            int skip_bits;
35242
            /* if there is an '=' inside the parameter list, we
35243
               consider there is a parameter expression inside */
35244
0
            js_parse_skip_parens_token(s, &skip_bits, FALSE);
35245
0
            if (skip_bits & SKIP_HAS_ASSIGNMENT)
35246
0
                fd->has_parameter_expressions = TRUE;
35247
0
            if (next_token(s))
35248
0
                goto fail;
35249
0
        } else {
35250
0
            if (js_parse_expect(s, '('))
35251
0
                goto fail;
35252
0
        }
35253
35254
0
        if (fd->has_parameter_expressions) {
35255
0
            fd->scope_level = -1; /* force no parent scope */
35256
0
            if (push_scope(s) < 0)
35257
0
                return -1;
35258
0
        }
35259
35260
0
        while (s->token.val != ')') {
35261
0
            JSAtom name;
35262
0
            BOOL rest = FALSE;
35263
0
            int idx, has_initializer;
35264
35265
0
            if (s->token.val == TOK_ELLIPSIS) {
35266
0
                if (func_type == JS_PARSE_FUNC_SETTER)
35267
0
                    goto fail_accessor;
35268
0
                fd->has_simple_parameter_list = FALSE;
35269
0
                rest = TRUE;
35270
0
                if (next_token(s))
35271
0
                    goto fail;
35272
0
            }
35273
0
            if (s->token.val == '[' || s->token.val == '{') {
35274
0
                fd->has_simple_parameter_list = FALSE;
35275
0
                if (rest) {
35276
0
                    emit_op(s, OP_rest);
35277
0
                    emit_u16(s, fd->arg_count);
35278
0
                } else {
35279
                    /* unnamed arg for destructuring */
35280
0
                    idx = add_arg(ctx, fd, JS_ATOM_NULL);
35281
0
                    emit_op(s, OP_get_arg);
35282
0
                    emit_u16(s, idx);
35283
0
                }
35284
0
                has_initializer = js_parse_destructuring_element(s, fd->has_parameter_expressions ? TOK_LET : TOK_VAR, 1, TRUE, -1, TRUE, FALSE);
35285
0
                if (has_initializer < 0)
35286
0
                    goto fail;
35287
0
                if (has_initializer)
35288
0
                    has_opt_arg = TRUE;
35289
0
                if (!has_opt_arg)
35290
0
                    fd->defined_arg_count++;
35291
0
            } else if (s->token.val == TOK_IDENT) {
35292
0
                if (s->token.u.ident.is_reserved) {
35293
0
                    js_parse_error_reserved_identifier(s);
35294
0
                    goto fail;
35295
0
                }
35296
0
                name = s->token.u.ident.atom;
35297
0
                if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) {
35298
0
                    js_parse_error_reserved_identifier(s);
35299
0
                    goto fail;
35300
0
                }
35301
0
                if (fd->has_parameter_expressions) {
35302
0
                    if (js_parse_check_duplicate_parameter(s, name))
35303
0
                        goto fail;
35304
0
                    if (define_var(s, fd, name, JS_VAR_DEF_LET) < 0)
35305
0
                        goto fail;
35306
0
                }
35307
                /* XXX: could avoid allocating an argument if rest is true */
35308
0
                idx = add_arg(ctx, fd, name);
35309
0
                if (idx < 0)
35310
0
                    goto fail;
35311
0
                if (next_token(s))
35312
0
                    goto fail;
35313
0
                if (rest) {
35314
0
                    emit_op(s, OP_rest);
35315
0
                    emit_u16(s, idx);
35316
0
                    if (fd->has_parameter_expressions) {
35317
0
                        emit_op(s, OP_dup);
35318
0
                        emit_op(s, OP_scope_put_var_init);
35319
0
                        emit_atom(s, name);
35320
0
                        emit_u16(s, fd->scope_level);
35321
0
                    }
35322
0
                    emit_op(s, OP_put_arg);
35323
0
                    emit_u16(s, idx);
35324
0
                    fd->has_simple_parameter_list = FALSE;
35325
0
                    has_opt_arg = TRUE;
35326
0
                } else if (s->token.val == '=') {
35327
0
                    int label;
35328
35329
0
                    fd->has_simple_parameter_list = FALSE;
35330
0
                    has_opt_arg = TRUE;
35331
35332
0
                    if (next_token(s))
35333
0
                        goto fail;
35334
35335
0
                    label = new_label(s);
35336
0
                    emit_op(s, OP_get_arg);
35337
0
                    emit_u16(s, idx);
35338
0
                    emit_op(s, OP_dup);
35339
0
                    emit_op(s, OP_undefined);
35340
0
                    emit_op(s, OP_strict_eq);
35341
0
                    emit_goto(s, OP_if_false, label);
35342
0
                    emit_op(s, OP_drop);
35343
0
                    if (js_parse_assign_expr(s))
35344
0
                        goto fail;
35345
0
                    set_object_name(s, name);
35346
0
                    emit_op(s, OP_dup);
35347
0
                    emit_op(s, OP_put_arg);
35348
0
                    emit_u16(s, idx);
35349
0
                    emit_label(s, label);
35350
0
                    emit_op(s, OP_scope_put_var_init);
35351
0
                    emit_atom(s, name);
35352
0
                    emit_u16(s, fd->scope_level);
35353
0
                } else {
35354
0
                    if (!has_opt_arg) {
35355
0
                        fd->defined_arg_count++;
35356
0
                    }
35357
0
                    if (fd->has_parameter_expressions) {
35358
                        /* copy the argument to the argument scope */
35359
0
                        emit_op(s, OP_get_arg);
35360
0
                        emit_u16(s, idx);
35361
0
                        emit_op(s, OP_scope_put_var_init);
35362
0
                        emit_atom(s, name);
35363
0
                        emit_u16(s, fd->scope_level);
35364
0
                    }
35365
0
                }
35366
0
            } else {
35367
0
                js_parse_error(s, "missing formal parameter");
35368
0
                goto fail;
35369
0
            }
35370
0
            if (rest && s->token.val != ')') {
35371
0
                js_parse_expect(s, ')');
35372
0
                goto fail;
35373
0
            }
35374
0
            if (s->token.val == ')')
35375
0
                break;
35376
0
            if (js_parse_expect(s, ','))
35377
0
                goto fail;
35378
0
        }
35379
0
        if ((func_type == JS_PARSE_FUNC_GETTER && fd->arg_count != 0) ||
35380
0
            (func_type == JS_PARSE_FUNC_SETTER && fd->arg_count != 1)) {
35381
0
        fail_accessor:
35382
0
            js_parse_error(s, "invalid number of arguments for getter or setter");
35383
0
            goto fail;
35384
0
        }
35385
0
    }
35386
35387
0
    if (fd->has_parameter_expressions) {
35388
0
        int idx;
35389
35390
        /* Copy the variables in the argument scope to the variable
35391
           scope (see FunctionDeclarationInstantiation() in spec). The
35392
           normal arguments are already present, so no need to copy
35393
           them. */
35394
0
        idx = fd->scopes[fd->scope_level].first;
35395
0
        while (idx >= 0) {
35396
0
            JSVarDef *vd = &fd->vars[idx];
35397
0
            if (vd->scope_level != fd->scope_level)
35398
0
                break;
35399
0
            if (find_var(ctx, fd, vd->var_name) < 0) {
35400
0
                if (add_var(ctx, fd, vd->var_name) < 0)
35401
0
                    goto fail;
35402
0
                vd = &fd->vars[idx]; /* fd->vars may have been reallocated */
35403
0
                emit_op(s, OP_scope_get_var);
35404
0
                emit_atom(s, vd->var_name);
35405
0
                emit_u16(s, fd->scope_level);
35406
0
                emit_op(s, OP_scope_put_var);
35407
0
                emit_atom(s, vd->var_name);
35408
0
                emit_u16(s, 0);
35409
0
            }
35410
0
            idx = vd->scope_next;
35411
0
        }
35412
35413
        /* the argument scope has no parent, hence we don't use pop_scope(s) */
35414
0
        emit_op(s, OP_leave_scope);
35415
0
        emit_u16(s, fd->scope_level);
35416
35417
        /* set the variable scope as the current scope */
35418
0
        fd->scope_level = 0;
35419
0
        fd->scope_first = fd->scopes[fd->scope_level].first;
35420
0
    }
35421
35422
0
    if (next_token(s))
35423
0
        goto fail;
35424
35425
    /* generator function: yield after the parameters are evaluated */
35426
0
    if (func_kind == JS_FUNC_GENERATOR ||
35427
0
        func_kind == JS_FUNC_ASYNC_GENERATOR)
35428
0
        emit_op(s, OP_initial_yield);
35429
35430
    /* in generators, yield expression is forbidden during the parsing
35431
       of the arguments */
35432
0
    fd->in_function_body = TRUE;
35433
0
    push_scope(s);  /* enter body scope */
35434
0
    fd->body_scope = fd->scope_level;
35435
35436
0
    if (s->token.val == TOK_ARROW && func_type == JS_PARSE_FUNC_ARROW) {
35437
0
        if (next_token(s))
35438
0
            goto fail;
35439
35440
0
        if (s->token.val != '{') {
35441
0
            if (js_parse_function_check_names(s, fd, func_name))
35442
0
                goto fail;
35443
35444
0
            if (js_parse_assign_expr(s))
35445
0
                goto fail;
35446
35447
0
            if (func_kind != JS_FUNC_NORMAL)
35448
0
                emit_op(s, OP_return_async);
35449
0
            else
35450
0
                emit_op(s, OP_return);
35451
35452
0
            if (!fd->strip_source) {
35453
                /* save the function source code */
35454
                /* the end of the function source code is after the last
35455
                   token of the function source stored into s->last_ptr */
35456
0
                fd->source_len = s->last_ptr - ptr;
35457
0
                fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len);
35458
0
                if (!fd->source)
35459
0
                    goto fail;
35460
0
            }
35461
0
            goto done;
35462
0
        }
35463
0
    }
35464
35465
0
    if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) {
35466
0
        if (js_parse_expect(s, '{'))
35467
0
            goto fail;
35468
0
    }
35469
35470
0
    if (js_parse_directives(s))
35471
0
        goto fail;
35472
35473
    /* in strict_mode, check function and argument names */
35474
0
    if (js_parse_function_check_names(s, fd, func_name))
35475
0
        goto fail;
35476
35477
0
    while (s->token.val != '}') {
35478
0
        if (js_parse_source_element(s))
35479
0
            goto fail;
35480
0
    }
35481
0
    if (!fd->strip_source) {
35482
        /* save the function source code */
35483
0
        fd->source_len = s->buf_ptr - ptr;
35484
0
        fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len);
35485
0
        if (!fd->source)
35486
0
            goto fail;
35487
0
    }
35488
35489
0
    if (next_token(s)) {
35490
        /* consume the '}' */
35491
0
        goto fail;
35492
0
    }
35493
35494
    /* in case there is no return, add one */
35495
0
    if (js_is_live_code(s)) {
35496
0
        emit_return(s, FALSE);
35497
0
    }
35498
0
 done:
35499
0
    s->cur_func = fd->parent;
35500
35501
    /* Reparse identifiers after the function is terminated so that
35502
       the token is parsed in the englobing function. It could be done
35503
       by just using next_token() here for normal functions, but it is
35504
       necessary for arrow functions with an expression body. */
35505
0
    reparse_ident_token(s);
35506
35507
    /* create the function object */
35508
0
    {
35509
0
        int idx;
35510
0
        JSAtom func_name = fd->func_name;
35511
35512
        /* the real object will be set at the end of the compilation */
35513
0
        idx = cpool_add(s, JS_NULL);
35514
0
        fd->parent_cpool_idx = idx;
35515
35516
0
        if (is_expr) {
35517
            /* for constructors, no code needs to be generated here */
35518
0
            if (func_type != JS_PARSE_FUNC_CLASS_CONSTRUCTOR &&
35519
0
                func_type != JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR) {
35520
                /* OP_fclosure creates the function object from the bytecode
35521
                   and adds the scope information */
35522
0
                emit_op(s, OP_fclosure);
35523
0
                emit_u32(s, idx);
35524
0
                if (func_name == JS_ATOM_NULL) {
35525
0
                    emit_op(s, OP_set_name);
35526
0
                    emit_u32(s, JS_ATOM_NULL);
35527
0
                }
35528
0
            }
35529
0
        } else if (func_type == JS_PARSE_FUNC_VAR) {
35530
0
            emit_op(s, OP_fclosure);
35531
0
            emit_u32(s, idx);
35532
0
            if (create_func_var) {
35533
0
                if (s->cur_func->is_global_var) {
35534
0
                    JSGlobalVar *hf;
35535
                    /* the global variable must be defined at the start of the
35536
                       function */
35537
0
                    hf = add_global_var(ctx, s->cur_func, func_name);
35538
0
                    if (!hf)
35539
0
                        goto fail;
35540
                    /* it is considered as defined at the top level
35541
                       (needed for annex B.3.3.4 and B.3.3.5
35542
                       checks) */
35543
0
                    hf->scope_level = 0;
35544
0
                    hf->force_init = ((s->cur_func->js_mode & JS_MODE_STRICT) != 0);
35545
                    /* store directly into global var, bypass lexical scope */
35546
0
                    emit_op(s, OP_dup);
35547
0
                    emit_op(s, OP_scope_put_var);
35548
0
                    emit_atom(s, func_name);
35549
0
                    emit_u16(s, 0);
35550
0
                } else {
35551
                    /* do not call define_var to bypass lexical scope check */
35552
0
                    func_idx = find_var(ctx, s->cur_func, func_name);
35553
0
                    if (func_idx < 0) {
35554
0
                        func_idx = add_var(ctx, s->cur_func, func_name);
35555
0
                        if (func_idx < 0)
35556
0
                            goto fail;
35557
0
                    }
35558
                    /* store directly into local var, bypass lexical catch scope */
35559
0
                    emit_op(s, OP_dup);
35560
0
                    emit_op(s, OP_scope_put_var);
35561
0
                    emit_atom(s, func_name);
35562
0
                    emit_u16(s, 0);
35563
0
                }
35564
0
            }
35565
0
            if (lexical_func_idx >= 0) {
35566
                /* lexical variable will be initialized upon entering scope */
35567
0
                s->cur_func->vars[lexical_func_idx].func_pool_idx = idx;
35568
0
                emit_op(s, OP_drop);
35569
0
            } else {
35570
                /* store function object into its lexical name */
35571
                /* XXX: could use OP_put_loc directly */
35572
0
                emit_op(s, OP_scope_put_var_init);
35573
0
                emit_atom(s, func_name);
35574
0
                emit_u16(s, s->cur_func->scope_level);
35575
0
            }
35576
0
        } else {
35577
0
            if (!s->cur_func->is_global_var) {
35578
0
                int var_idx = define_var(s, s->cur_func, func_name, JS_VAR_DEF_VAR);
35579
35580
0
                if (var_idx < 0)
35581
0
                    goto fail;
35582
                /* the variable will be assigned at the top of the function */
35583
0
                if (var_idx & ARGUMENT_VAR_OFFSET) {
35584
0
                    s->cur_func->args[var_idx - ARGUMENT_VAR_OFFSET].func_pool_idx = idx;
35585
0
                } else {
35586
0
                    s->cur_func->vars[var_idx].func_pool_idx = idx;
35587
0
                }
35588
0
            } else {
35589
0
                JSAtom func_var_name;
35590
0
                JSGlobalVar *hf;
35591
0
                if (func_name == JS_ATOM_NULL)
35592
0
                    func_var_name = JS_ATOM__default_; /* export default */
35593
0
                else
35594
0
                    func_var_name = func_name;
35595
                /* the variable will be assigned at the top of the function */
35596
0
                hf = add_global_var(ctx, s->cur_func, func_var_name);
35597
0
                if (!hf)
35598
0
                    goto fail;
35599
0
                hf->cpool_idx = idx;
35600
0
                if (export_flag != JS_PARSE_EXPORT_NONE) {
35601
0
                    if (!add_export_entry(s, s->cur_func->module, func_var_name,
35602
0
                                          export_flag == JS_PARSE_EXPORT_NAMED ? func_var_name : JS_ATOM_default, JS_EXPORT_TYPE_LOCAL))
35603
0
                        goto fail;
35604
0
                }
35605
0
            }
35606
0
        }
35607
0
    }
35608
0
    return 0;
35609
0
 fail:
35610
0
    s->cur_func = fd->parent;
35611
0
    js_free_function_def(ctx, fd);
35612
0
    if (pfd)
35613
0
        *pfd = NULL;
35614
0
    return -1;
35615
0
}
35616
35617
static __exception int js_parse_function_decl(JSParseState *s,
35618
                                              JSParseFunctionEnum func_type,
35619
                                              JSFunctionKindEnum func_kind,
35620
                                              JSAtom func_name,
35621
                                              const uint8_t *ptr)
35622
0
{
35623
0
    return js_parse_function_decl2(s, func_type, func_kind, func_name, ptr,
35624
0
                                   JS_PARSE_EXPORT_NONE, NULL);
35625
0
}
35626
35627
static __exception int js_parse_program(JSParseState *s)
35628
4
{
35629
4
    JSFunctionDef *fd = s->cur_func;
35630
4
    int idx;
35631
35632
4
    if (next_token(s))
35633
0
        return -1;
35634
35635
4
    if (js_parse_directives(s))
35636
0
        return -1;
35637
35638
4
    fd->is_global_var = (fd->eval_type == JS_EVAL_TYPE_GLOBAL) ||
35639
4
        (fd->eval_type == JS_EVAL_TYPE_MODULE) ||
35640
4
        !(fd->js_mode & JS_MODE_STRICT);
35641
35642
4
    if (!s->is_module) {
35643
        /* hidden variable for the return value */
35644
0
        fd->eval_ret_idx = idx = add_var(s->ctx, fd, JS_ATOM__ret_);
35645
0
        if (idx < 0)
35646
0
            return -1;
35647
0
    }
35648
35649
14
    while (s->token.val != TOK_EOF) {
35650
11
        if (js_parse_source_element(s))
35651
1
            return -1;
35652
11
    }
35653
35654
3
    if (!s->is_module) {
35655
        /* return the value of the hidden variable eval_ret_idx  */
35656
0
        if (fd->func_kind == JS_FUNC_ASYNC) {
35657
            /* wrap the return value in an object so that promises can
35658
               be safely returned */
35659
0
            emit_op(s, OP_object);
35660
0
            emit_op(s, OP_dup);
35661
35662
0
            emit_op(s, OP_get_loc);
35663
0
            emit_u16(s, fd->eval_ret_idx);
35664
35665
0
            emit_op(s, OP_put_field);
35666
0
            emit_atom(s, JS_ATOM_value);
35667
0
        } else {
35668
0
            emit_op(s, OP_get_loc);
35669
0
            emit_u16(s, fd->eval_ret_idx);
35670
0
        }
35671
0
        emit_return(s, TRUE);
35672
3
    } else {
35673
3
        emit_return(s, FALSE);
35674
3
    }
35675
35676
3
    return 0;
35677
4
}
35678
35679
static void js_parse_init(JSContext *ctx, JSParseState *s,
35680
                          const char *input, size_t input_len,
35681
                          const char *filename)
35682
4
{
35683
4
    memset(s, 0, sizeof(*s));
35684
4
    s->ctx = ctx;
35685
4
    s->filename = filename;
35686
4
    s->buf_start = s->buf_ptr = (const uint8_t *)input;
35687
4
    s->buf_end = s->buf_ptr + input_len;
35688
4
    s->token.val = ' ';
35689
4
    s->token.ptr = s->buf_ptr;
35690
35691
4
    s->get_line_col_cache.ptr = s->buf_start;
35692
4
    s->get_line_col_cache.buf_start = s->buf_start;
35693
4
    s->get_line_col_cache.line_num = 0;
35694
4
    s->get_line_col_cache.col_num = 0;
35695
4
}
35696
35697
static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj,
35698
                                       JSValueConst this_obj,
35699
                                       JSVarRef **var_refs, JSStackFrame *sf)
35700
3
{
35701
3
    JSValue ret_val;
35702
3
    uint32_t tag;
35703
35704
3
    tag = JS_VALUE_GET_TAG(fun_obj);
35705
3
    if (tag == JS_TAG_FUNCTION_BYTECODE) {
35706
0
        fun_obj = js_closure(ctx, fun_obj, var_refs, sf);
35707
0
        ret_val = JS_CallFree(ctx, fun_obj, this_obj, 0, NULL);
35708
3
    } else if (tag == JS_TAG_MODULE) {
35709
3
        JSModuleDef *m;
35710
3
        m = JS_VALUE_GET_PTR(fun_obj);
35711
        /* the module refcount should be >= 2 */
35712
3
        JS_FreeValue(ctx, fun_obj);
35713
3
        if (js_create_module_function(ctx, m) < 0)
35714
0
            goto fail;
35715
3
        if (js_link_module(ctx, m) < 0)
35716
0
            goto fail;
35717
3
        ret_val = js_evaluate_module(ctx, m);
35718
3
        if (JS_IsException(ret_val)) {
35719
0
        fail:
35720
0
            return JS_EXCEPTION;
35721
0
        }
35722
3
    } else {
35723
0
        JS_FreeValue(ctx, fun_obj);
35724
0
        ret_val = JS_ThrowTypeError(ctx, "bytecode function expected");
35725
0
    }
35726
3
    return ret_val;
35727
3
}
35728
35729
JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj)
35730
3
{
35731
3
    return JS_EvalFunctionInternal(ctx, fun_obj, ctx->global_obj, NULL, NULL);
35732
3
}
35733
35734
/* 'input' must be zero terminated i.e. input[input_len] = '\0'. */
35735
static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
35736
                                 const char *input, size_t input_len,
35737
                                 const char *filename, int flags, int scope_idx)
35738
4
{
35739
4
    JSParseState s1, *s = &s1;
35740
4
    int err, js_mode, eval_type;
35741
4
    JSValue fun_obj, ret_val;
35742
4
    JSStackFrame *sf;
35743
4
    JSVarRef **var_refs;
35744
4
    JSFunctionBytecode *b;
35745
4
    JSFunctionDef *fd;
35746
4
    JSModuleDef *m;
35747
35748
4
    js_parse_init(ctx, s, input, input_len, filename);
35749
4
    skip_shebang(&s->buf_ptr, s->buf_end);
35750
35751
4
    eval_type = flags & JS_EVAL_TYPE_MASK;
35752
4
    m = NULL;
35753
4
    if (eval_type == JS_EVAL_TYPE_DIRECT) {
35754
0
        JSObject *p;
35755
0
        sf = ctx->rt->current_stack_frame;
35756
0
        assert(sf != NULL);
35757
0
        assert(JS_VALUE_GET_TAG(sf->cur_func) == JS_TAG_OBJECT);
35758
0
        p = JS_VALUE_GET_OBJ(sf->cur_func);
35759
0
        assert(js_class_has_bytecode(p->class_id));
35760
0
        b = p->u.func.function_bytecode;
35761
0
        var_refs = p->u.func.var_refs;
35762
0
        js_mode = b->js_mode;
35763
4
    } else {
35764
4
        sf = NULL;
35765
4
        b = NULL;
35766
4
        var_refs = NULL;
35767
4
        js_mode = 0;
35768
4
        if (flags & JS_EVAL_FLAG_STRICT)
35769
0
            js_mode |= JS_MODE_STRICT;
35770
4
        if (eval_type == JS_EVAL_TYPE_MODULE) {
35771
4
            JSAtom module_name = JS_NewAtom(ctx, filename);
35772
4
            if (module_name == JS_ATOM_NULL)
35773
0
                return JS_EXCEPTION;
35774
4
            m = js_new_module_def(ctx, module_name);
35775
4
            if (!m)
35776
0
                return JS_EXCEPTION;
35777
4
            js_mode |= JS_MODE_STRICT;
35778
4
        }
35779
4
    }
35780
4
    fd = js_new_function_def(ctx, NULL, TRUE, FALSE, filename,
35781
4
                             s->buf_start, &s->get_line_col_cache);
35782
4
    if (!fd)
35783
0
        goto fail1;
35784
4
    s->cur_func = fd;
35785
4
    fd->eval_type = eval_type;
35786
4
    fd->has_this_binding = (eval_type != JS_EVAL_TYPE_DIRECT);
35787
4
    if (eval_type == JS_EVAL_TYPE_DIRECT) {
35788
0
        fd->new_target_allowed = b->new_target_allowed;
35789
0
        fd->super_call_allowed = b->super_call_allowed;
35790
0
        fd->super_allowed = b->super_allowed;
35791
0
        fd->arguments_allowed = b->arguments_allowed;
35792
4
    } else {
35793
4
        fd->new_target_allowed = FALSE;
35794
4
        fd->super_call_allowed = FALSE;
35795
4
        fd->super_allowed = FALSE;
35796
4
        fd->arguments_allowed = TRUE;
35797
4
    }
35798
4
    fd->js_mode = js_mode;
35799
4
    fd->func_name = JS_DupAtom(ctx, JS_ATOM__eval_);
35800
4
    if (b) {
35801
0
        if (add_closure_variables(ctx, fd, b, scope_idx))
35802
0
            goto fail;
35803
0
    }
35804
4
    fd->module = m;
35805
4
    if (m != NULL || (flags & JS_EVAL_FLAG_ASYNC)) {
35806
4
        fd->in_function_body = TRUE;
35807
4
        fd->func_kind = JS_FUNC_ASYNC;
35808
4
    }
35809
4
    s->is_module = (m != NULL);
35810
4
    s->allow_html_comments = !s->is_module;
35811
35812
4
    push_scope(s); /* body scope */
35813
4
    fd->body_scope = fd->scope_level;
35814
35815
4
    err = js_parse_program(s);
35816
4
    if (err) {
35817
1
    fail:
35818
1
        free_token(s, &s->token);
35819
1
        js_free_function_def(ctx, fd);
35820
1
        goto fail1;
35821
1
    }
35822
35823
3
    if (m != NULL)
35824
3
        m->has_tla = fd->has_await;
35825
35826
    /* create the function object and all the enclosed functions */
35827
3
    fun_obj = js_create_function(ctx, fd);
35828
3
    if (JS_IsException(fun_obj))
35829
0
        goto fail1;
35830
    /* Could add a flag to avoid resolution if necessary */
35831
3
    if (m) {
35832
3
        m->func_obj = fun_obj;
35833
3
        if (js_resolve_module(ctx, m) < 0)
35834
0
            goto fail1;
35835
3
        fun_obj = JS_NewModuleValue(ctx, m);
35836
3
    }
35837
3
    if (flags & JS_EVAL_FLAG_COMPILE_ONLY) {
35838
3
        ret_val = fun_obj;
35839
3
    } else {
35840
0
        ret_val = JS_EvalFunctionInternal(ctx, fun_obj, this_obj, var_refs, sf);
35841
0
    }
35842
3
    return ret_val;
35843
1
 fail1:
35844
    /* XXX: should free all the unresolved dependencies */
35845
1
    if (m)
35846
1
        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
35847
1
    return JS_EXCEPTION;
35848
3
}
35849
35850
/* the indirection is needed to make 'eval' optional */
35851
static JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
35852
                               const char *input, size_t input_len,
35853
                               const char *filename, int flags, int scope_idx)
35854
4
{
35855
4
    BOOL backtrace_barrier = ((flags & JS_EVAL_FLAG_BACKTRACE_BARRIER) != 0);
35856
4
    int saved_js_mode = 0;
35857
4
    JSValue ret;
35858
    
35859
4
    if (unlikely(!ctx->eval_internal)) {
35860
0
        return JS_ThrowTypeError(ctx, "eval is not supported");
35861
0
    }
35862
4
    if (backtrace_barrier && ctx->rt->current_stack_frame) {
35863
0
        saved_js_mode = ctx->rt->current_stack_frame->js_mode;
35864
0
        ctx->rt->current_stack_frame->js_mode |= JS_MODE_BACKTRACE_BARRIER;
35865
0
    }
35866
4
    ret = ctx->eval_internal(ctx, this_obj, input, input_len, filename,
35867
4
                             flags, scope_idx);
35868
4
    if (backtrace_barrier && ctx->rt->current_stack_frame)
35869
0
        ctx->rt->current_stack_frame->js_mode = saved_js_mode;
35870
4
    return ret;
35871
4
}
35872
35873
static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
35874
                             JSValueConst val, int flags, int scope_idx)
35875
0
{
35876
0
    JSValue ret;
35877
0
    const char *str;
35878
0
    size_t len;
35879
35880
0
    if (!JS_IsString(val))
35881
0
        return JS_DupValue(ctx, val);
35882
0
    str = JS_ToCStringLen(ctx, &len, val);
35883
0
    if (!str)
35884
0
        return JS_EXCEPTION;
35885
0
    ret = JS_EvalInternal(ctx, this_obj, str, len, "<input>", flags, scope_idx);
35886
0
    JS_FreeCString(ctx, str);
35887
0
    return ret;
35888
35889
0
}
35890
35891
JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj,
35892
                    const char *input, size_t input_len,
35893
                    const char *filename, int eval_flags)
35894
4
{
35895
4
    int eval_type = eval_flags & JS_EVAL_TYPE_MASK;
35896
4
    JSValue ret;
35897
35898
4
    assert(eval_type == JS_EVAL_TYPE_GLOBAL ||
35899
4
           eval_type == JS_EVAL_TYPE_MODULE);
35900
4
    ret = JS_EvalInternal(ctx, this_obj, input, input_len, filename,
35901
4
                          eval_flags, -1);
35902
4
    return ret;
35903
4
}
35904
35905
JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
35906
                const char *filename, int eval_flags)
35907
4
{
35908
4
    return JS_EvalThis(ctx, ctx->global_obj, input, input_len, filename,
35909
4
                       eval_flags);
35910
4
}
35911
35912
int JS_ResolveModule(JSContext *ctx, JSValueConst obj)
35913
1
{
35914
1
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
35915
1
        JSModuleDef *m = JS_VALUE_GET_PTR(obj);
35916
1
        if (js_resolve_module(ctx, m) < 0) {
35917
0
            js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);
35918
0
            return -1;
35919
0
        }
35920
1
    }
35921
1
    return 0;
35922
1
}
35923
35924
/*******************************************************************/
35925
/* object list */
35926
35927
typedef struct {
35928
    JSObject *obj;
35929
    uint32_t hash_next; /* -1 if no next entry */
35930
} JSObjectListEntry;
35931
35932
/* XXX: reuse it to optimize weak references */
35933
typedef struct {
35934
    JSObjectListEntry *object_tab;
35935
    int object_count;
35936
    int object_size;
35937
    uint32_t *hash_table;
35938
    uint32_t hash_size;
35939
} JSObjectList;
35940
35941
static void js_object_list_init(JSObjectList *s)
35942
1
{
35943
1
    memset(s, 0, sizeof(*s));
35944
1
}
35945
35946
static uint32_t js_object_list_get_hash(JSObject *p, uint32_t hash_size)
35947
0
{
35948
0
    return ((uintptr_t)p * 3163) & (hash_size - 1);
35949
0
}
35950
35951
static int js_object_list_resize_hash(JSContext *ctx, JSObjectList *s,
35952
                                 uint32_t new_hash_size)
35953
0
{
35954
0
    JSObjectListEntry *e;
35955
0
    uint32_t i, h, *new_hash_table;
35956
35957
0
    new_hash_table = js_malloc(ctx, sizeof(new_hash_table[0]) * new_hash_size);
35958
0
    if (!new_hash_table)
35959
0
        return -1;
35960
0
    js_free(ctx, s->hash_table);
35961
0
    s->hash_table = new_hash_table;
35962
0
    s->hash_size = new_hash_size;
35963
35964
0
    for(i = 0; i < s->hash_size; i++) {
35965
0
        s->hash_table[i] = -1;
35966
0
    }
35967
0
    for(i = 0; i < s->object_count; i++) {
35968
0
        e = &s->object_tab[i];
35969
0
        h = js_object_list_get_hash(e->obj, s->hash_size);
35970
0
        e->hash_next = s->hash_table[h];
35971
0
        s->hash_table[h] = i;
35972
0
    }
35973
0
    return 0;
35974
0
}
35975
35976
/* the reference count of 'obj' is not modified. Return 0 if OK, -1 if
35977
   memory error */
35978
static int js_object_list_add(JSContext *ctx, JSObjectList *s, JSObject *obj)
35979
0
{
35980
0
    JSObjectListEntry *e;
35981
0
    uint32_t h, new_hash_size;
35982
35983
0
    if (js_resize_array(ctx, (void *)&s->object_tab,
35984
0
                        sizeof(s->object_tab[0]),
35985
0
                        &s->object_size, s->object_count + 1))
35986
0
        return -1;
35987
0
    if (unlikely((s->object_count + 1) >= s->hash_size)) {
35988
0
        new_hash_size = max_uint32(s->hash_size, 4);
35989
0
        while (new_hash_size <= s->object_count)
35990
0
            new_hash_size *= 2;
35991
0
        if (js_object_list_resize_hash(ctx, s, new_hash_size))
35992
0
            return -1;
35993
0
    }
35994
0
    e = &s->object_tab[s->object_count++];
35995
0
    h = js_object_list_get_hash(obj, s->hash_size);
35996
0
    e->obj = obj;
35997
0
    e->hash_next = s->hash_table[h];
35998
0
    s->hash_table[h] = s->object_count - 1;
35999
0
    return 0;
36000
0
}
36001
36002
/* return -1 if not present or the object index */
36003
static int js_object_list_find(JSContext *ctx, JSObjectList *s, JSObject *obj)
36004
0
{
36005
0
    JSObjectListEntry *e;
36006
0
    uint32_t h, p;
36007
36008
    /* must test empty size because there is no hash table */
36009
0
    if (s->object_count == 0)
36010
0
        return -1;
36011
0
    h = js_object_list_get_hash(obj, s->hash_size);
36012
0
    p = s->hash_table[h];
36013
0
    while (p != -1) {
36014
0
        e = &s->object_tab[p];
36015
0
        if (e->obj == obj)
36016
0
            return p;
36017
0
        p = e->hash_next;
36018
0
    }
36019
0
    return -1;
36020
0
}
36021
36022
static void js_object_list_end(JSContext *ctx, JSObjectList *s)
36023
1
{
36024
1
    js_free(ctx, s->object_tab);
36025
1
    js_free(ctx, s->hash_table);
36026
1
}
36027
36028
/*******************************************************************/
36029
/* binary object writer & reader */
36030
36031
typedef enum BCTagEnum {
36032
    BC_TAG_NULL = 1,
36033
    BC_TAG_UNDEFINED,
36034
    BC_TAG_BOOL_FALSE,
36035
    BC_TAG_BOOL_TRUE,
36036
    BC_TAG_INT32,
36037
    BC_TAG_FLOAT64,
36038
    BC_TAG_STRING,
36039
    BC_TAG_OBJECT,
36040
    BC_TAG_ARRAY,
36041
    BC_TAG_BIG_INT,
36042
    BC_TAG_TEMPLATE_OBJECT,
36043
    BC_TAG_FUNCTION_BYTECODE,
36044
    BC_TAG_MODULE,
36045
    BC_TAG_TYPED_ARRAY,
36046
    BC_TAG_ARRAY_BUFFER,
36047
    BC_TAG_SHARED_ARRAY_BUFFER,
36048
    BC_TAG_DATE,
36049
    BC_TAG_OBJECT_VALUE,
36050
    BC_TAG_OBJECT_REFERENCE,
36051
} BCTagEnum;
36052
36053
2
#define BC_VERSION 5
36054
36055
typedef struct BCWriterState {
36056
    JSContext *ctx;
36057
    DynBuf dbuf;
36058
    BOOL allow_bytecode : 8;
36059
    BOOL allow_sab : 8;
36060
    BOOL allow_reference : 8;
36061
    uint32_t first_atom;
36062
    uint32_t *atom_to_idx;
36063
    int atom_to_idx_size;
36064
    JSAtom *idx_to_atom;
36065
    int idx_to_atom_count;
36066
    int idx_to_atom_size;
36067
    uint8_t **sab_tab;
36068
    int sab_tab_len;
36069
    int sab_tab_size;
36070
    /* list of referenced objects (used if allow_reference = TRUE) */
36071
    JSObjectList object_list;
36072
} BCWriterState;
36073
36074
#ifdef DUMP_READ_OBJECT
36075
static const char * const bc_tag_str[] = {
36076
    "invalid",
36077
    "null",
36078
    "undefined",
36079
    "false",
36080
    "true",
36081
    "int32",
36082
    "float64",
36083
    "string",
36084
    "object",
36085
    "array",
36086
    "bigint",
36087
    "template",
36088
    "function",
36089
    "module",
36090
    "TypedArray",
36091
    "ArrayBuffer",
36092
    "SharedArrayBuffer",
36093
    "Date",
36094
    "ObjectValue",
36095
    "ObjectReference",
36096
};
36097
#endif
36098
36099
static inline BOOL is_be(void)
36100
6
{
36101
6
    union {
36102
6
        uint16_t a;
36103
6
        uint8_t  b;
36104
6
    } u = {0x100};
36105
6
    return u.b;
36106
6
}
36107
36108
static void bc_put_u8(BCWriterState *s, uint8_t v)
36109
6
{
36110
6
    dbuf_putc(&s->dbuf, v);
36111
6
}
36112
36113
static void bc_put_u16(BCWriterState *s, uint16_t v)
36114
1
{
36115
1
    if (is_be())
36116
0
        v = bswap16(v);
36117
1
    dbuf_put_u16(&s->dbuf, v);
36118
1
}
36119
36120
static __maybe_unused void bc_put_u32(BCWriterState *s, uint32_t v)
36121
0
{
36122
0
    if (is_be())
36123
0
        v = bswap32(v);
36124
0
    dbuf_put_u32(&s->dbuf, v);
36125
0
}
36126
36127
static void bc_put_u64(BCWriterState *s, uint64_t v)
36128
1
{
36129
1
    if (is_be())
36130
0
        v = bswap64(v);
36131
1
    dbuf_put(&s->dbuf, (uint8_t *)&v, sizeof(v));
36132
1
}
36133
36134
static void bc_put_leb128(BCWriterState *s, uint32_t v)
36135
20
{
36136
20
    dbuf_put_leb128(&s->dbuf, v);
36137
20
}
36138
36139
static void bc_put_sleb128(BCWriterState *s, int32_t v)
36140
0
{
36141
0
    dbuf_put_sleb128(&s->dbuf, v);
36142
0
}
36143
36144
static void bc_set_flags(uint32_t *pflags, int *pidx, uint32_t val, int n)
36145
11
{
36146
11
    *pflags = *pflags | (val << *pidx);
36147
11
    *pidx += n;
36148
11
}
36149
36150
static int bc_atom_to_idx(BCWriterState *s, uint32_t *pres, JSAtom atom)
36151
4
{
36152
4
    uint32_t v;
36153
36154
4
    if (atom < s->first_atom || __JS_AtomIsTaggedInt(atom)) {
36155
1
        *pres = atom;
36156
1
        return 0;
36157
1
    }
36158
3
    atom -= s->first_atom;
36159
3
    if (atom < s->atom_to_idx_size && s->atom_to_idx[atom] != 0) {
36160
1
        *pres = s->atom_to_idx[atom];
36161
1
        return 0;
36162
1
    }
36163
2
    if (atom >= s->atom_to_idx_size) {
36164
2
        int old_size, i;
36165
2
        old_size = s->atom_to_idx_size;
36166
2
        if (js_resize_array(s->ctx, (void **)&s->atom_to_idx,
36167
2
                            sizeof(s->atom_to_idx[0]), &s->atom_to_idx_size,
36168
2
                            atom + 1))
36169
0
            return -1;
36170
        /* XXX: could add a specific js_resize_array() function to do it */
36171
564
        for(i = old_size; i < s->atom_to_idx_size; i++)
36172
562
            s->atom_to_idx[i] = 0;
36173
2
    }
36174
2
    if (js_resize_array(s->ctx, (void **)&s->idx_to_atom,
36175
2
                        sizeof(s->idx_to_atom[0]),
36176
2
                        &s->idx_to_atom_size, s->idx_to_atom_count + 1))
36177
0
        goto fail;
36178
36179
2
    v = s->idx_to_atom_count++;
36180
2
    s->idx_to_atom[v] = atom + s->first_atom;
36181
2
    v += s->first_atom;
36182
2
    s->atom_to_idx[atom] = v;
36183
2
    *pres = v;
36184
2
    return 0;
36185
0
 fail:
36186
0
    *pres = 0;
36187
0
    return -1;
36188
2
}
36189
36190
static int bc_put_atom(BCWriterState *s, JSAtom atom)
36191
3
{
36192
3
    uint32_t v;
36193
36194
3
    if (__JS_AtomIsTaggedInt(atom)) {
36195
0
        v = (__JS_AtomToUInt32(atom) << 1) | 1;
36196
3
    } else {
36197
3
        if (bc_atom_to_idx(s, &v, atom))
36198
0
            return -1;
36199
3
        v <<= 1;
36200
3
    }
36201
3
    bc_put_leb128(s, v);
36202
3
    return 0;
36203
3
}
36204
36205
static void bc_byte_swap(uint8_t *bc_buf, int bc_len)
36206
0
{
36207
0
    int pos, len, op, fmt;
36208
36209
0
    pos = 0;
36210
0
    while (pos < bc_len) {
36211
0
        op = bc_buf[pos];
36212
0
        len = short_opcode_info(op).size;
36213
0
        fmt = short_opcode_info(op).fmt;
36214
0
        switch(fmt) {
36215
0
        case OP_FMT_u16:
36216
0
        case OP_FMT_i16:
36217
0
        case OP_FMT_label16:
36218
0
        case OP_FMT_npop:
36219
0
        case OP_FMT_loc:
36220
0
        case OP_FMT_arg:
36221
0
        case OP_FMT_var_ref:
36222
0
            put_u16(bc_buf + pos + 1,
36223
0
                    bswap16(get_u16(bc_buf + pos + 1)));
36224
0
            break;
36225
0
        case OP_FMT_i32:
36226
0
        case OP_FMT_u32:
36227
0
        case OP_FMT_const:
36228
0
        case OP_FMT_label:
36229
0
        case OP_FMT_atom:
36230
0
        case OP_FMT_atom_u8:
36231
0
            put_u32(bc_buf + pos + 1,
36232
0
                    bswap32(get_u32(bc_buf + pos + 1)));
36233
0
            break;
36234
0
        case OP_FMT_atom_u16:
36235
0
        case OP_FMT_label_u16:
36236
0
            put_u32(bc_buf + pos + 1,
36237
0
                    bswap32(get_u32(bc_buf + pos + 1)));
36238
0
            put_u16(bc_buf + pos + 1 + 4,
36239
0
                    bswap16(get_u16(bc_buf + pos + 1 + 4)));
36240
0
            break;
36241
0
        case OP_FMT_atom_label_u8:
36242
0
        case OP_FMT_atom_label_u16:
36243
0
            put_u32(bc_buf + pos + 1,
36244
0
                    bswap32(get_u32(bc_buf + pos + 1)));
36245
0
            put_u32(bc_buf + pos + 1 + 4,
36246
0
                    bswap32(get_u32(bc_buf + pos + 1 + 4)));
36247
0
            if (fmt == OP_FMT_atom_label_u16) {
36248
0
                put_u16(bc_buf + pos + 1 + 4 + 4,
36249
0
                        bswap16(get_u16(bc_buf + pos + 1 + 4 + 4)));
36250
0
            }
36251
0
            break;
36252
0
        case OP_FMT_npop_u16:
36253
0
            put_u16(bc_buf + pos + 1,
36254
0
                    bswap16(get_u16(bc_buf + pos + 1)));
36255
0
            put_u16(bc_buf + pos + 1 + 2,
36256
0
                    bswap16(get_u16(bc_buf + pos + 1 + 2)));
36257
0
            break;
36258
0
        default:
36259
0
            break;
36260
0
        }
36261
0
        pos += len;
36262
0
    }
36263
0
}
36264
36265
static int JS_WriteFunctionBytecode(BCWriterState *s,
36266
                                    const uint8_t *bc_buf1, int bc_len)
36267
1
{
36268
1
    int pos, len, op;
36269
1
    JSAtom atom;
36270
1
    uint8_t *bc_buf;
36271
1
    uint32_t val;
36272
36273
1
    bc_buf = js_malloc(s->ctx, bc_len);
36274
1
    if (!bc_buf)
36275
0
        return -1;
36276
1
    memcpy(bc_buf, bc_buf1, bc_len);
36277
36278
1
    pos = 0;
36279
11
    while (pos < bc_len) {
36280
10
        op = bc_buf[pos];
36281
10
        len = short_opcode_info(op).size;
36282
10
        switch(short_opcode_info(op).fmt) {
36283
1
        case OP_FMT_atom:
36284
1
        case OP_FMT_atom_u8:
36285
1
        case OP_FMT_atom_u16:
36286
1
        case OP_FMT_atom_label_u8:
36287
1
        case OP_FMT_atom_label_u16:
36288
1
            atom = get_u32(bc_buf + pos + 1);
36289
1
            if (bc_atom_to_idx(s, &val, atom))
36290
0
                goto fail;
36291
1
            put_u32(bc_buf + pos + 1, val);
36292
1
            break;
36293
9
        default:
36294
9
            break;
36295
10
        }
36296
10
        pos += len;
36297
10
    }
36298
36299
1
    if (is_be())
36300
0
        bc_byte_swap(bc_buf, bc_len);
36301
36302
1
    dbuf_put(&s->dbuf, bc_buf, bc_len);
36303
36304
1
    js_free(s->ctx, bc_buf);
36305
1
    return 0;
36306
0
 fail:
36307
0
    js_free(s->ctx, bc_buf);
36308
0
    return -1;
36309
1
}
36310
36311
static void JS_WriteString(BCWriterState *s, JSString *p)
36312
2
{
36313
2
    int i;
36314
2
    bc_put_leb128(s, ((uint32_t)p->len << 1) | p->is_wide_char);
36315
2
    if (p->is_wide_char) {
36316
0
        for(i = 0; i < p->len; i++)
36317
0
            bc_put_u16(s, p->u.str16[i]);
36318
2
    } else {
36319
2
        dbuf_put(&s->dbuf, p->u.str8, p->len);
36320
2
    }
36321
2
}
36322
36323
static int JS_WriteBigInt(BCWriterState *s, JSValueConst obj)
36324
0
{
36325
0
    JSBigIntBuf buf;
36326
0
    JSBigInt *p;
36327
0
    uint32_t len, i;
36328
0
    js_limb_t v, b;
36329
0
    int shift;
36330
    
36331
0
    bc_put_u8(s, BC_TAG_BIG_INT);
36332
36333
0
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_SHORT_BIG_INT)
36334
0
        p = js_bigint_set_short(&buf, obj);
36335
0
    else
36336
0
        p = JS_VALUE_GET_PTR(obj);
36337
0
    if (p->len == 1 && p->tab[0] == 0) {
36338
        /* zero case */
36339
0
        len = 0;
36340
0
    } else {
36341
        /* compute the length of the two's complement representation
36342
           in bytes */
36343
0
        len = p->len * (JS_LIMB_BITS / 8);
36344
0
        v = p->tab[p->len - 1];
36345
0
        shift = JS_LIMB_BITS - 8;
36346
0
        while (shift > 0) {
36347
0
            b = (v >> shift) & 0xff;
36348
0
            if (b != 0x00 && b != 0xff)
36349
0
                break;
36350
0
            if ((b & 1) != ((v >> (shift - 1)) & 1))
36351
0
                break;
36352
0
            shift -= 8;
36353
0
            len--;
36354
0
        }
36355
0
    }
36356
0
    bc_put_leb128(s, len);
36357
0
    if (len > 0) {
36358
0
        for(i = 0; i < (len / (JS_LIMB_BITS / 8)); i++) {
36359
#if JS_LIMB_BITS == 32
36360
            bc_put_u32(s, p->tab[i]);
36361
#else
36362
0
            bc_put_u64(s, p->tab[i]);
36363
0
#endif
36364
0
        }
36365
0
        for(i = 0; i < len % (JS_LIMB_BITS / 8); i++) {
36366
0
            bc_put_u8(s, (p->tab[p->len - 1] >> (i * 8)) & 0xff);
36367
0
        }
36368
0
    }
36369
0
    return 0;
36370
0
}
36371
36372
static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj);
36373
36374
static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj)
36375
1
{
36376
1
    JSFunctionBytecode *b = JS_VALUE_GET_PTR(obj);
36377
1
    uint32_t flags;
36378
1
    int idx, i;
36379
36380
1
    bc_put_u8(s, BC_TAG_FUNCTION_BYTECODE);
36381
1
    flags = idx = 0;
36382
1
    bc_set_flags(&flags, &idx, b->has_prototype, 1);
36383
1
    bc_set_flags(&flags, &idx, b->has_simple_parameter_list, 1);
36384
1
    bc_set_flags(&flags, &idx, b->is_derived_class_constructor, 1);
36385
1
    bc_set_flags(&flags, &idx, b->need_home_object, 1);
36386
1
    bc_set_flags(&flags, &idx, b->func_kind, 2);
36387
1
    bc_set_flags(&flags, &idx, b->new_target_allowed, 1);
36388
1
    bc_set_flags(&flags, &idx, b->super_call_allowed, 1);
36389
1
    bc_set_flags(&flags, &idx, b->super_allowed, 1);
36390
1
    bc_set_flags(&flags, &idx, b->arguments_allowed, 1);
36391
1
    bc_set_flags(&flags, &idx, b->has_debug, 1);
36392
1
    bc_set_flags(&flags, &idx, b->is_direct_or_indirect_eval, 1);
36393
1
    assert(idx <= 16);
36394
1
    bc_put_u16(s, flags);
36395
1
    bc_put_u8(s, b->js_mode);
36396
1
    bc_put_atom(s, b->func_name);
36397
36398
1
    bc_put_leb128(s, b->arg_count);
36399
1
    bc_put_leb128(s, b->var_count);
36400
1
    bc_put_leb128(s, b->defined_arg_count);
36401
1
    bc_put_leb128(s, b->stack_size);
36402
1
    bc_put_leb128(s, b->closure_var_count);
36403
1
    bc_put_leb128(s, b->cpool_count);
36404
1
    bc_put_leb128(s, b->byte_code_len);
36405
1
    if (b->vardefs) {
36406
        /* XXX: this field is redundant */
36407
0
        bc_put_leb128(s, b->arg_count + b->var_count);
36408
0
        for(i = 0; i < b->arg_count + b->var_count; i++) {
36409
0
            JSVarDef *vd = &b->vardefs[i];
36410
0
            bc_put_atom(s, vd->var_name);
36411
0
            bc_put_leb128(s, vd->scope_level);
36412
0
            bc_put_leb128(s, vd->scope_next + 1);
36413
0
            flags = idx = 0;
36414
0
            bc_set_flags(&flags, &idx, vd->var_kind, 4);
36415
0
            bc_set_flags(&flags, &idx, vd->is_const, 1);
36416
0
            bc_set_flags(&flags, &idx, vd->is_lexical, 1);
36417
0
            bc_set_flags(&flags, &idx, vd->is_captured, 1);
36418
0
            assert(idx <= 8);
36419
0
            bc_put_u8(s, flags);
36420
0
        }
36421
1
    } else {
36422
1
        bc_put_leb128(s, 0);
36423
1
    }
36424
36425
1
    for(i = 0; i < b->closure_var_count; i++) {
36426
0
        JSClosureVar *cv = &b->closure_var[i];
36427
0
        bc_put_atom(s, cv->var_name);
36428
0
        bc_put_leb128(s, cv->var_idx);
36429
0
        flags = idx = 0;
36430
0
        bc_set_flags(&flags, &idx, cv->is_local, 1);
36431
0
        bc_set_flags(&flags, &idx, cv->is_arg, 1);
36432
0
        bc_set_flags(&flags, &idx, cv->is_const, 1);
36433
0
        bc_set_flags(&flags, &idx, cv->is_lexical, 1);
36434
0
        bc_set_flags(&flags, &idx, cv->var_kind, 4);
36435
0
        assert(idx <= 8);
36436
0
        bc_put_u8(s, flags);
36437
0
    }
36438
36439
1
    if (JS_WriteFunctionBytecode(s, b->byte_code_buf, b->byte_code_len))
36440
0
        goto fail;
36441
36442
1
    if (b->has_debug) {
36443
1
        bc_put_atom(s, b->debug.filename);
36444
1
        bc_put_leb128(s, b->debug.pc2line_len);
36445
1
        dbuf_put(&s->dbuf, b->debug.pc2line_buf, b->debug.pc2line_len);
36446
1
        if (b->debug.source) {
36447
0
            bc_put_leb128(s, b->debug.source_len);
36448
0
            dbuf_put(&s->dbuf, (uint8_t *)b->debug.source, b->debug.source_len);
36449
1
        } else {
36450
1
            bc_put_leb128(s, 0);
36451
1
        }
36452
1
    }
36453
36454
2
    for(i = 0; i < b->cpool_count; i++) {
36455
1
        if (JS_WriteObjectRec(s, b->cpool[i]))
36456
0
            goto fail;
36457
1
    }
36458
1
    return 0;
36459
0
 fail:
36460
0
    return -1;
36461
1
}
36462
36463
static int JS_WriteModule(BCWriterState *s, JSValueConst obj)
36464
1
{
36465
1
    JSModuleDef *m = JS_VALUE_GET_PTR(obj);
36466
1
    int i;
36467
36468
1
    bc_put_u8(s, BC_TAG_MODULE);
36469
1
    bc_put_atom(s, m->module_name);
36470
36471
1
    bc_put_leb128(s, m->req_module_entries_count);
36472
1
    for(i = 0; i < m->req_module_entries_count; i++) {
36473
0
        JSReqModuleEntry *rme = &m->req_module_entries[i];
36474
0
        bc_put_atom(s, rme->module_name);
36475
0
        if (JS_WriteObjectRec(s, rme->attributes))
36476
0
            goto fail;
36477
0
    }
36478
36479
1
    bc_put_leb128(s, m->export_entries_count);
36480
1
    for(i = 0; i < m->export_entries_count; i++) {
36481
0
        JSExportEntry *me = &m->export_entries[i];
36482
0
        bc_put_u8(s, me->export_type);
36483
0
        if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
36484
0
            bc_put_leb128(s, me->u.local.var_idx);
36485
0
        } else {
36486
0
            bc_put_leb128(s, me->u.req_module_idx);
36487
0
            bc_put_atom(s, me->local_name);
36488
0
        }
36489
0
        bc_put_atom(s, me->export_name);
36490
0
    }
36491
36492
1
    bc_put_leb128(s, m->star_export_entries_count);
36493
1
    for(i = 0; i < m->star_export_entries_count; i++) {
36494
0
        JSStarExportEntry *se = &m->star_export_entries[i];
36495
0
        bc_put_leb128(s, se->req_module_idx);
36496
0
    }
36497
36498
1
    bc_put_leb128(s, m->import_entries_count);
36499
1
    for(i = 0; i < m->import_entries_count; i++) {
36500
0
        JSImportEntry *mi = &m->import_entries[i];
36501
0
        bc_put_leb128(s, mi->var_idx);
36502
0
        bc_put_u8(s, mi->is_star);
36503
0
        bc_put_atom(s, mi->import_name);
36504
0
        bc_put_leb128(s, mi->req_module_idx);
36505
0
    }
36506
36507
1
    bc_put_u8(s, m->has_tla);
36508
36509
1
    if (JS_WriteObjectRec(s, m->func_obj))
36510
0
        goto fail;
36511
1
    return 0;
36512
0
 fail:
36513
0
    return -1;
36514
1
}
36515
36516
static int JS_WriteArray(BCWriterState *s, JSValueConst obj)
36517
0
{
36518
0
    JSObject *p = JS_VALUE_GET_OBJ(obj);
36519
0
    uint32_t i, len;
36520
0
    JSValue val;
36521
0
    int ret;
36522
0
    BOOL is_template;
36523
36524
0
    if (s->allow_bytecode && !p->extensible) {
36525
        /* not extensible array: we consider it is a
36526
           template when we are saving bytecode */
36527
0
        bc_put_u8(s, BC_TAG_TEMPLATE_OBJECT);
36528
0
        is_template = TRUE;
36529
0
    } else {
36530
0
        bc_put_u8(s, BC_TAG_ARRAY);
36531
0
        is_template = FALSE;
36532
0
    }
36533
0
    if (js_get_length32(s->ctx, &len, obj))
36534
0
        goto fail1;
36535
0
    bc_put_leb128(s, len);
36536
0
    for(i = 0; i < len; i++) {
36537
0
        val = JS_GetPropertyUint32(s->ctx, obj, i);
36538
0
        if (JS_IsException(val))
36539
0
            goto fail1;
36540
0
        ret = JS_WriteObjectRec(s, val);
36541
0
        JS_FreeValue(s->ctx, val);
36542
0
        if (ret)
36543
0
            goto fail1;
36544
0
    }
36545
0
    if (is_template) {
36546
0
        val = JS_GetProperty(s->ctx, obj, JS_ATOM_raw);
36547
0
        if (JS_IsException(val))
36548
0
            goto fail1;
36549
0
        ret = JS_WriteObjectRec(s, val);
36550
0
        JS_FreeValue(s->ctx, val);
36551
0
        if (ret)
36552
0
            goto fail1;
36553
0
    }
36554
0
    return 0;
36555
0
 fail1:
36556
0
    return -1;
36557
0
}
36558
36559
static int JS_WriteObjectTag(BCWriterState *s, JSValueConst obj)
36560
0
{
36561
0
    JSObject *p = JS_VALUE_GET_OBJ(obj);
36562
0
    uint32_t i, prop_count;
36563
0
    JSShape *sh;
36564
0
    JSShapeProperty *pr;
36565
0
    int pass;
36566
0
    JSAtom atom;
36567
36568
0
    bc_put_u8(s, BC_TAG_OBJECT);
36569
0
    prop_count = 0;
36570
0
    sh = p->shape;
36571
0
    for(pass = 0; pass < 2; pass++) {
36572
0
        if (pass == 1)
36573
0
            bc_put_leb128(s, prop_count);
36574
0
        for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {
36575
0
            atom = pr->atom;
36576
0
            if (atom != JS_ATOM_NULL &&
36577
0
                JS_AtomIsString(s->ctx, atom) &&
36578
0
                (pr->flags & JS_PROP_ENUMERABLE)) {
36579
0
                if (pr->flags & JS_PROP_TMASK) {
36580
0
                    JS_ThrowTypeError(s->ctx, "only value properties are supported");
36581
0
                    goto fail;
36582
0
                }
36583
0
                if (pass == 0) {
36584
0
                    prop_count++;
36585
0
                } else {
36586
0
                    bc_put_atom(s, atom);
36587
0
                    if (JS_WriteObjectRec(s, p->prop[i].u.value))
36588
0
                        goto fail;
36589
0
                }
36590
0
            }
36591
0
        }
36592
0
    }
36593
0
    return 0;
36594
0
 fail:
36595
0
    return -1;
36596
0
}
36597
36598
static int JS_WriteTypedArray(BCWriterState *s, JSValueConst obj)
36599
0
{
36600
0
    JSObject *p = JS_VALUE_GET_OBJ(obj);
36601
0
    JSTypedArray *ta = p->u.typed_array;
36602
36603
0
    bc_put_u8(s, BC_TAG_TYPED_ARRAY);
36604
0
    bc_put_u8(s, p->class_id - JS_CLASS_UINT8C_ARRAY);
36605
0
    bc_put_leb128(s, p->u.array.count);
36606
0
    bc_put_leb128(s, ta->offset);
36607
0
    if (JS_WriteObjectRec(s, JS_MKPTR(JS_TAG_OBJECT, ta->buffer)))
36608
0
        return -1;
36609
0
    return 0;
36610
0
}
36611
36612
static int JS_WriteArrayBuffer(BCWriterState *s, JSValueConst obj)
36613
0
{
36614
0
    JSObject *p = JS_VALUE_GET_OBJ(obj);
36615
0
    JSArrayBuffer *abuf = p->u.array_buffer;
36616
0
    if (abuf->detached) {
36617
0
        JS_ThrowTypeErrorDetachedArrayBuffer(s->ctx);
36618
0
        return -1;
36619
0
    }
36620
0
    bc_put_u8(s, BC_TAG_ARRAY_BUFFER);
36621
0
    bc_put_leb128(s, abuf->byte_length);
36622
0
    dbuf_put(&s->dbuf, abuf->data, abuf->byte_length);
36623
0
    return 0;
36624
0
}
36625
36626
static int JS_WriteSharedArrayBuffer(BCWriterState *s, JSValueConst obj)
36627
0
{
36628
0
    JSObject *p = JS_VALUE_GET_OBJ(obj);
36629
0
    JSArrayBuffer *abuf = p->u.array_buffer;
36630
0
    assert(!abuf->detached); /* SharedArrayBuffer are never detached */
36631
0
    bc_put_u8(s, BC_TAG_SHARED_ARRAY_BUFFER);
36632
0
    bc_put_leb128(s, abuf->byte_length);
36633
0
    bc_put_u64(s, (uintptr_t)abuf->data);
36634
0
    if (js_resize_array(s->ctx, (void **)&s->sab_tab, sizeof(s->sab_tab[0]),
36635
0
                        &s->sab_tab_size, s->sab_tab_len + 1))
36636
0
        return -1;
36637
    /* keep the SAB pointer so that the user can clone it or free it */
36638
0
    s->sab_tab[s->sab_tab_len++] = abuf->data;
36639
0
    return 0;
36640
0
}
36641
36642
static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj)
36643
3
{
36644
3
    uint32_t tag;
36645
36646
3
    if (js_check_stack_overflow(s->ctx->rt, 0)) {
36647
0
        JS_ThrowStackOverflow(s->ctx);
36648
0
        return -1;
36649
0
    }
36650
36651
3
    tag = JS_VALUE_GET_NORM_TAG(obj);
36652
3
    switch(tag) {
36653
0
    case JS_TAG_NULL:
36654
0
        bc_put_u8(s, BC_TAG_NULL);
36655
0
        break;
36656
0
    case JS_TAG_UNDEFINED:
36657
0
        bc_put_u8(s, BC_TAG_UNDEFINED);
36658
0
        break;
36659
0
    case JS_TAG_BOOL:
36660
0
        bc_put_u8(s, BC_TAG_BOOL_FALSE + JS_VALUE_GET_INT(obj));
36661
0
        break;
36662
0
    case JS_TAG_INT:
36663
0
        bc_put_u8(s, BC_TAG_INT32);
36664
0
        bc_put_sleb128(s, JS_VALUE_GET_INT(obj));
36665
0
        break;
36666
1
    case JS_TAG_FLOAT64:
36667
1
        {
36668
1
            JSFloat64Union u;
36669
1
            bc_put_u8(s, BC_TAG_FLOAT64);
36670
1
            u.d = JS_VALUE_GET_FLOAT64(obj);
36671
1
            bc_put_u64(s, u.u64);
36672
1
        }
36673
1
        break;
36674
0
    case JS_TAG_STRING:
36675
0
        {
36676
0
            JSString *p = JS_VALUE_GET_STRING(obj);
36677
0
            bc_put_u8(s, BC_TAG_STRING);
36678
0
            JS_WriteString(s, p);
36679
0
        }
36680
0
        break;
36681
0
    case JS_TAG_STRING_ROPE:
36682
0
        {
36683
0
            JSValue str;
36684
0
            str = JS_ToString(s->ctx, obj);
36685
0
            if (JS_IsException(str))
36686
0
                goto fail;
36687
0
            JS_WriteObjectRec(s, str);
36688
0
            JS_FreeValue(s->ctx, str);
36689
0
        }
36690
0
        break;
36691
1
    case JS_TAG_FUNCTION_BYTECODE:
36692
1
        if (!s->allow_bytecode)
36693
0
            goto invalid_tag;
36694
1
        if (JS_WriteFunctionTag(s, obj))
36695
0
            goto fail;
36696
1
        break;
36697
1
    case JS_TAG_MODULE:
36698
1
        if (!s->allow_bytecode)
36699
0
            goto invalid_tag;
36700
1
        if (JS_WriteModule(s, obj))
36701
0
            goto fail;
36702
1
        break;
36703
1
    case JS_TAG_OBJECT:
36704
0
        {
36705
0
            JSObject *p = JS_VALUE_GET_OBJ(obj);
36706
0
            int ret, idx;
36707
36708
0
            if (s->allow_reference) {
36709
0
                idx = js_object_list_find(s->ctx, &s->object_list, p);
36710
0
                if (idx >= 0) {
36711
0
                    bc_put_u8(s, BC_TAG_OBJECT_REFERENCE);
36712
0
                    bc_put_leb128(s, idx);
36713
0
                    break;
36714
0
                } else {
36715
0
                    if (js_object_list_add(s->ctx, &s->object_list, p))
36716
0
                        goto fail;
36717
0
                }
36718
0
            } else {
36719
0
                if (p->tmp_mark) {
36720
0
                    JS_ThrowTypeError(s->ctx, "circular reference");
36721
0
                    goto fail;
36722
0
                }
36723
0
                p->tmp_mark = 1;
36724
0
            }
36725
0
            switch(p->class_id) {
36726
0
            case JS_CLASS_ARRAY:
36727
0
                ret = JS_WriteArray(s, obj);
36728
0
                break;
36729
0
            case JS_CLASS_OBJECT:
36730
0
                ret = JS_WriteObjectTag(s, obj);
36731
0
                break;
36732
0
            case JS_CLASS_ARRAY_BUFFER:
36733
0
                ret = JS_WriteArrayBuffer(s, obj);
36734
0
                break;
36735
0
            case JS_CLASS_SHARED_ARRAY_BUFFER:
36736
0
                if (!s->allow_sab)
36737
0
                    goto invalid_tag;
36738
0
                ret = JS_WriteSharedArrayBuffer(s, obj);
36739
0
                break;
36740
0
            case JS_CLASS_DATE:
36741
0
                bc_put_u8(s, BC_TAG_DATE);
36742
0
                ret = JS_WriteObjectRec(s, p->u.object_data);
36743
0
                break;
36744
0
            case JS_CLASS_NUMBER:
36745
0
            case JS_CLASS_STRING:
36746
0
            case JS_CLASS_BOOLEAN:
36747
0
            case JS_CLASS_BIG_INT:
36748
0
                bc_put_u8(s, BC_TAG_OBJECT_VALUE);
36749
0
                ret = JS_WriteObjectRec(s, p->u.object_data);
36750
0
                break;
36751
0
            default:
36752
0
                if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
36753
0
                    p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
36754
0
                    ret = JS_WriteTypedArray(s, obj);
36755
0
                } else {
36756
0
                    JS_ThrowTypeError(s->ctx, "unsupported object class");
36757
0
                    ret = -1;
36758
0
                }
36759
0
                break;
36760
0
            }
36761
0
            p->tmp_mark = 0;
36762
0
            if (ret)
36763
0
                goto fail;
36764
0
        }
36765
0
        break;
36766
0
    case JS_TAG_SHORT_BIG_INT:
36767
0
    case JS_TAG_BIG_INT:
36768
0
        if (JS_WriteBigInt(s, obj))
36769
0
            goto fail;
36770
0
        break;
36771
0
    default:
36772
0
    invalid_tag:
36773
0
        JS_ThrowInternalError(s->ctx, "unsupported tag (%d)", tag);
36774
0
        goto fail;
36775
3
    }
36776
3
    return 0;
36777
36778
0
 fail:
36779
0
    return -1;
36780
3
}
36781
36782
/* create the atom table */
36783
static int JS_WriteObjectAtoms(BCWriterState *s)
36784
1
{
36785
1
    JSRuntime *rt = s->ctx->rt;
36786
1
    DynBuf dbuf1;
36787
1
    int i, atoms_size;
36788
36789
1
    dbuf1 = s->dbuf;
36790
1
    js_dbuf_init(s->ctx, &s->dbuf);
36791
1
    bc_put_u8(s, BC_VERSION);
36792
36793
1
    bc_put_leb128(s, s->idx_to_atom_count);
36794
3
    for(i = 0; i < s->idx_to_atom_count; i++) {
36795
2
        JSAtomStruct *p = rt->atom_array[s->idx_to_atom[i]];
36796
2
        JS_WriteString(s, p);
36797
2
    }
36798
    /* XXX: should check for OOM in above phase */
36799
36800
    /* move the atoms at the start */
36801
    /* XXX: could just append dbuf1 data, but it uses more memory if
36802
       dbuf1 is larger than dbuf */
36803
1
    atoms_size = s->dbuf.size;
36804
1
    if (dbuf_realloc(&dbuf1, dbuf1.size + atoms_size))
36805
0
        goto fail;
36806
1
    memmove(dbuf1.buf + atoms_size, dbuf1.buf, dbuf1.size);
36807
1
    memcpy(dbuf1.buf, s->dbuf.buf, atoms_size);
36808
1
    dbuf1.size += atoms_size;
36809
1
    dbuf_free(&s->dbuf);
36810
1
    s->dbuf = dbuf1;
36811
1
    return 0;
36812
0
 fail:
36813
0
    dbuf_free(&dbuf1);
36814
0
    return -1;
36815
1
}
36816
36817
uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj,
36818
                         int flags, uint8_t ***psab_tab, size_t *psab_tab_len)
36819
1
{
36820
1
    BCWriterState ss, *s = &ss;
36821
36822
1
    memset(s, 0, sizeof(*s));
36823
1
    s->ctx = ctx;
36824
1
    s->allow_bytecode = ((flags & JS_WRITE_OBJ_BYTECODE) != 0);
36825
1
    s->allow_sab = ((flags & JS_WRITE_OBJ_SAB) != 0);
36826
1
    s->allow_reference = ((flags & JS_WRITE_OBJ_REFERENCE) != 0);
36827
    /* XXX: could use a different version when bytecode is included */
36828
1
    if (s->allow_bytecode)
36829
1
        s->first_atom = JS_ATOM_END;
36830
0
    else
36831
0
        s->first_atom = 1;
36832
1
    js_dbuf_init(ctx, &s->dbuf);
36833
1
    js_object_list_init(&s->object_list);
36834
36835
1
    if (JS_WriteObjectRec(s, obj))
36836
0
        goto fail;
36837
1
    if (JS_WriteObjectAtoms(s))
36838
0
        goto fail;
36839
1
    js_object_list_end(ctx, &s->object_list);
36840
1
    js_free(ctx, s->atom_to_idx);
36841
1
    js_free(ctx, s->idx_to_atom);
36842
1
    *psize = s->dbuf.size;
36843
1
    if (psab_tab)
36844
0
        *psab_tab = s->sab_tab;
36845
1
    if (psab_tab_len)
36846
0
        *psab_tab_len = s->sab_tab_len;
36847
1
    return s->dbuf.buf;
36848
0
 fail:
36849
0
    js_object_list_end(ctx, &s->object_list);
36850
0
    js_free(ctx, s->atom_to_idx);
36851
0
    js_free(ctx, s->idx_to_atom);
36852
0
    dbuf_free(&s->dbuf);
36853
0
    *psize = 0;
36854
0
    if (psab_tab)
36855
0
        *psab_tab = NULL;
36856
0
    if (psab_tab_len)
36857
0
        *psab_tab_len = 0;
36858
0
    return NULL;
36859
1
}
36860
36861
uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj,
36862
                        int flags)
36863
1
{
36864
1
    return JS_WriteObject2(ctx, psize, obj, flags, NULL, NULL);
36865
1
}
36866
36867
typedef struct BCReaderState {
36868
    JSContext *ctx;
36869
    const uint8_t *buf_start, *ptr, *buf_end;
36870
    uint32_t first_atom;
36871
    uint32_t idx_to_atom_count;
36872
    JSAtom *idx_to_atom;
36873
    int error_state;
36874
    BOOL allow_sab : 8;
36875
    BOOL allow_bytecode : 8;
36876
    BOOL is_rom_data : 8;
36877
    BOOL allow_reference : 8;
36878
    /* object references */
36879
    JSObject **objects;
36880
    int objects_count;
36881
    int objects_size;
36882
36883
#ifdef DUMP_READ_OBJECT
36884
    const uint8_t *ptr_last;
36885
    int level;
36886
#endif
36887
} BCReaderState;
36888
36889
#ifdef DUMP_READ_OBJECT
36890
static void __attribute__((format(printf, 2, 3))) bc_read_trace(BCReaderState *s, const char *fmt, ...) {
36891
    va_list ap;
36892
    int i, n, n0;
36893
36894
    if (!s->ptr_last)
36895
        s->ptr_last = s->buf_start;
36896
36897
    n = n0 = 0;
36898
    if (s->ptr > s->ptr_last || s->ptr == s->buf_start) {
36899
        n0 = printf("%04x: ", (int)(s->ptr_last - s->buf_start));
36900
        n += n0;
36901
    }
36902
    for (i = 0; s->ptr_last < s->ptr; i++) {
36903
        if ((i & 7) == 0 && i > 0) {
36904
            printf("\n%*s", n0, "");
36905
            n = n0;
36906
        }
36907
        n += printf(" %02x", *s->ptr_last++);
36908
    }
36909
    if (*fmt == '}')
36910
        s->level--;
36911
    if (n < 32 + s->level * 2) {
36912
        printf("%*s", 32 + s->level * 2 - n, "");
36913
    }
36914
    va_start(ap, fmt);
36915
    vfprintf(stdout, fmt, ap);
36916
    va_end(ap);
36917
    if (strchr(fmt, '{'))
36918
        s->level++;
36919
}
36920
#else
36921
#define bc_read_trace(...)
36922
#endif
36923
36924
static int bc_read_error_end(BCReaderState *s)
36925
0
{
36926
0
    if (!s->error_state) {
36927
0
        JS_ThrowSyntaxError(s->ctx, "read after the end of the buffer");
36928
0
    }
36929
0
    return s->error_state = -1;
36930
0
}
36931
36932
static int bc_get_u8(BCReaderState *s, uint8_t *pval)
36933
6
{
36934
6
    if (unlikely(s->buf_end - s->ptr < 1)) {
36935
0
        *pval = 0; /* avoid warning */
36936
0
        return bc_read_error_end(s);
36937
0
    }
36938
6
    *pval = *s->ptr++;
36939
6
    return 0;
36940
6
}
36941
36942
static int bc_get_u16(BCReaderState *s, uint16_t *pval)
36943
1
{
36944
1
    uint16_t v;
36945
1
    if (unlikely(s->buf_end - s->ptr < 2)) {
36946
0
        *pval = 0; /* avoid warning */
36947
0
        return bc_read_error_end(s);
36948
0
    }
36949
1
    v = get_u16(s->ptr);
36950
1
    if (is_be())
36951
0
        v = bswap16(v);
36952
1
    *pval = v;
36953
1
    s->ptr += 2;
36954
1
    return 0;
36955
1
}
36956
36957
static __maybe_unused int bc_get_u32(BCReaderState *s, uint32_t *pval)
36958
0
{
36959
0
    uint32_t v;
36960
0
    if (unlikely(s->buf_end - s->ptr < 4)) {
36961
0
        *pval = 0; /* avoid warning */
36962
0
        return bc_read_error_end(s);
36963
0
    }
36964
0
    v = get_u32(s->ptr);
36965
0
    if (is_be())
36966
0
        v = bswap32(v);
36967
0
    *pval = v;
36968
0
    s->ptr += 4;
36969
0
    return 0;
36970
0
}
36971
36972
static int bc_get_u64(BCReaderState *s, uint64_t *pval)
36973
1
{
36974
1
    uint64_t v;
36975
1
    if (unlikely(s->buf_end - s->ptr < 8)) {
36976
0
        *pval = 0; /* avoid warning */
36977
0
        return bc_read_error_end(s);
36978
0
    }
36979
1
    v = get_u64(s->ptr);
36980
1
    if (is_be())
36981
0
        v = bswap64(v);
36982
1
    *pval = v;
36983
1
    s->ptr += 8;
36984
1
    return 0;
36985
1
}
36986
36987
static int bc_get_leb128(BCReaderState *s, uint32_t *pval)
36988
20
{
36989
20
    int ret;
36990
20
    ret = get_leb128(pval, s->ptr, s->buf_end);
36991
20
    if (unlikely(ret < 0))
36992
0
        return bc_read_error_end(s);
36993
20
    s->ptr += ret;
36994
20
    return 0;
36995
20
}
36996
36997
static int bc_get_sleb128(BCReaderState *s, int32_t *pval)
36998
0
{
36999
0
    int ret;
37000
0
    ret = get_sleb128(pval, s->ptr, s->buf_end);
37001
0
    if (unlikely(ret < 0))
37002
0
        return bc_read_error_end(s);
37003
0
    s->ptr += ret;
37004
0
    return 0;
37005
0
}
37006
37007
/* XXX: used to read an `int` with a positive value */
37008
static int bc_get_leb128_int(BCReaderState *s, int *pval)
37009
10
{
37010
10
    return bc_get_leb128(s, (uint32_t *)pval);
37011
10
}
37012
37013
static int bc_get_leb128_u16(BCReaderState *s, uint16_t *pval)
37014
4
{
37015
4
    uint32_t val;
37016
4
    if (bc_get_leb128(s, &val)) {
37017
0
        *pval = 0;
37018
0
        return -1;
37019
0
    }
37020
4
    *pval = val;
37021
4
    return 0;
37022
4
}
37023
37024
static int bc_get_buf(BCReaderState *s, uint8_t *buf, uint32_t buf_len)
37025
2
{
37026
2
    if (buf_len != 0) {
37027
2
        if (unlikely(!buf || s->buf_end - s->ptr < buf_len))
37028
0
            return bc_read_error_end(s);
37029
2
        memcpy(buf, s->ptr, buf_len);
37030
2
        s->ptr += buf_len;
37031
2
    }
37032
2
    return 0;
37033
2
}
37034
37035
static int bc_idx_to_atom(BCReaderState *s, JSAtom *patom, uint32_t idx)
37036
4
{
37037
4
    JSAtom atom;
37038
37039
4
    if (__JS_AtomIsTaggedInt(idx)) {
37040
0
        atom = idx;
37041
4
    } else if (idx < s->first_atom) {
37042
1
        atom = JS_DupAtom(s->ctx, idx);
37043
3
    } else {
37044
3
        idx -= s->first_atom;
37045
3
        if (idx >= s->idx_to_atom_count) {
37046
0
            JS_ThrowSyntaxError(s->ctx, "invalid atom index (pos=%u)",
37047
0
                                (unsigned int)(s->ptr - s->buf_start));
37048
0
            *patom = JS_ATOM_NULL;
37049
0
            return s->error_state = -1;
37050
0
        }
37051
3
        atom = JS_DupAtom(s->ctx, s->idx_to_atom[idx]);
37052
3
    }
37053
4
    *patom = atom;
37054
4
    return 0;
37055
4
}
37056
37057
static int bc_get_atom(BCReaderState *s, JSAtom *patom)
37058
3
{
37059
3
    uint32_t v;
37060
3
    if (bc_get_leb128(s, &v))
37061
0
        return -1;
37062
3
    if (v & 1) {
37063
0
        *patom = __JS_AtomFromUInt32(v >> 1);
37064
0
        return 0;
37065
3
    } else {
37066
3
        return bc_idx_to_atom(s, patom, v >> 1);
37067
3
    }
37068
3
}
37069
37070
static JSString *JS_ReadString(BCReaderState *s)
37071
2
{
37072
2
    uint32_t len;
37073
2
    size_t size;
37074
2
    BOOL is_wide_char;
37075
2
    JSString *p;
37076
37077
2
    if (bc_get_leb128(s, &len))
37078
0
        return NULL;
37079
2
    is_wide_char = len & 1;
37080
2
    len >>= 1;
37081
2
    if (len > JS_STRING_LEN_MAX) {
37082
0
        JS_ThrowInternalError(s->ctx, "string too long");
37083
0
        return NULL;
37084
0
    }
37085
2
    p = js_alloc_string(s->ctx, len, is_wide_char);
37086
2
    if (!p) {
37087
0
        s->error_state = -1;
37088
0
        return NULL;
37089
0
    }
37090
2
    size = (size_t)len << is_wide_char;
37091
2
    if ((s->buf_end - s->ptr) < size) {
37092
0
        bc_read_error_end(s);
37093
0
        js_free_string(s->ctx->rt, p);
37094
0
        return NULL;
37095
0
    }
37096
2
    memcpy(p->u.str8, s->ptr, size);
37097
2
    s->ptr += size;
37098
2
    if (is_wide_char) {
37099
0
        if (is_be()) {
37100
0
            uint32_t i;
37101
0
            for (i = 0; i < len; i++)
37102
0
                p->u.str16[i] = bswap16(p->u.str16[i]);
37103
0
        }
37104
2
    } else {
37105
2
        p->u.str8[size] = '\0'; /* add the trailing zero for 8 bit strings */
37106
2
    }
37107
#ifdef DUMP_READ_OBJECT
37108
    JS_DumpString(s->ctx->rt, p); printf("\n");
37109
#endif
37110
2
    return p;
37111
2
}
37112
37113
static uint32_t bc_get_flags(uint32_t flags, int *pidx, int n)
37114
11
{
37115
11
    uint32_t val;
37116
    /* XXX: this does not work for n == 32 */
37117
11
    val = (flags >> *pidx) & ((1U << n) - 1);
37118
11
    *pidx += n;
37119
11
    return val;
37120
11
}
37121
37122
static int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b,
37123
                                   int byte_code_offset, uint32_t bc_len)
37124
1
{
37125
1
    uint8_t *bc_buf;
37126
1
    int pos, len, op;
37127
1
    JSAtom atom;
37128
1
    uint32_t idx;
37129
37130
1
    if (s->is_rom_data) {
37131
        /* directly use the input buffer */
37132
0
        if (unlikely(s->buf_end - s->ptr < bc_len))
37133
0
            return bc_read_error_end(s);
37134
0
        bc_buf = (uint8_t *)s->ptr;
37135
0
        s->ptr += bc_len;
37136
1
    } else {
37137
1
        bc_buf = (void *)((uint8_t*)b + byte_code_offset);
37138
1
        if (bc_get_buf(s, bc_buf, bc_len))
37139
0
            return -1;
37140
1
    }
37141
1
    b->byte_code_buf = bc_buf;
37142
37143
1
    if (is_be())
37144
0
        bc_byte_swap(bc_buf, bc_len);
37145
37146
1
    pos = 0;
37147
11
    while (pos < bc_len) {
37148
10
        op = bc_buf[pos];
37149
10
        len = short_opcode_info(op).size;
37150
10
        switch(short_opcode_info(op).fmt) {
37151
1
        case OP_FMT_atom:
37152
1
        case OP_FMT_atom_u8:
37153
1
        case OP_FMT_atom_u16:
37154
1
        case OP_FMT_atom_label_u8:
37155
1
        case OP_FMT_atom_label_u16:
37156
1
            idx = get_u32(bc_buf + pos + 1);
37157
1
            if (s->is_rom_data) {
37158
                /* just increment the reference count of the atom */
37159
0
                JS_DupAtom(s->ctx, (JSAtom)idx);
37160
1
            } else {
37161
1
                if (bc_idx_to_atom(s, &atom, idx)) {
37162
                    /* Note: the atoms will be freed up to this position */
37163
0
                    b->byte_code_len = pos;
37164
0
                    return -1;
37165
0
                }
37166
1
                put_u32(bc_buf + pos + 1, atom);
37167
#ifdef DUMP_READ_OBJECT
37168
                bc_read_trace(s, "at %d, fixup atom: ", pos + 1); print_atom(s->ctx, atom); printf("\n");
37169
#endif
37170
1
            }
37171
1
            break;
37172
9
        default:
37173
9
            break;
37174
10
        }
37175
10
        pos += len;
37176
10
    }
37177
1
    return 0;
37178
1
}
37179
37180
static JSValue JS_ReadBigInt(BCReaderState *s)
37181
0
{
37182
0
    JSValue obj = JS_UNDEFINED;
37183
0
    uint32_t len, i, n;
37184
0
    JSBigInt *p;
37185
0
    js_limb_t v;
37186
0
    uint8_t v8;
37187
    
37188
0
    if (bc_get_leb128(s, &len))
37189
0
        goto fail;
37190
0
    bc_read_trace(s, "len=%" PRId64 "\n", (int64_t)len);
37191
0
    if (len == 0) {
37192
        /* zero case */
37193
0
        bc_read_trace(s, "}\n");
37194
0
        return __JS_NewShortBigInt(s->ctx, 0);
37195
0
    }
37196
0
    p = js_bigint_new(s->ctx, (len - 1) / (JS_LIMB_BITS / 8) + 1);
37197
0
    if (!p)
37198
0
        goto fail;
37199
0
    for(i = 0; i < len / (JS_LIMB_BITS / 8); i++) {
37200
#if JS_LIMB_BITS == 32
37201
        if (bc_get_u32(s, &v))
37202
            goto fail;
37203
#else
37204
0
        if (bc_get_u64(s, &v))
37205
0
            goto fail;
37206
0
#endif
37207
0
        p->tab[i] = v;
37208
0
    }
37209
0
    n = len % (JS_LIMB_BITS / 8);
37210
0
    if (n != 0) {
37211
0
        int shift;
37212
0
        v = 0;
37213
0
        for(i = 0; i < n; i++) {
37214
0
            if (bc_get_u8(s, &v8))
37215
0
                goto fail;
37216
0
            v |= (js_limb_t)v8 << (i * 8);
37217
0
        }
37218
0
        shift = JS_LIMB_BITS - n * 8;
37219
        /* extend the sign */
37220
0
        if (shift != 0) {
37221
0
            v = (js_slimb_t)(v << shift) >> shift;
37222
0
        }
37223
0
        p->tab[p->len - 1] = v;
37224
0
    }
37225
0
    bc_read_trace(s, "}\n");
37226
0
    return JS_CompactBigInt(s->ctx, p);
37227
0
 fail:
37228
0
    JS_FreeValue(s->ctx, obj);
37229
0
    return JS_EXCEPTION;
37230
0
}
37231
37232
static JSValue JS_ReadObjectRec(BCReaderState *s);
37233
37234
static int BC_add_object_ref1(BCReaderState *s, JSObject *p)
37235
0
{
37236
0
    if (s->allow_reference) {
37237
0
        if (js_resize_array(s->ctx, (void *)&s->objects,
37238
0
                            sizeof(s->objects[0]),
37239
0
                            &s->objects_size, s->objects_count + 1))
37240
0
            return -1;
37241
0
        s->objects[s->objects_count++] = p;
37242
0
    }
37243
0
    return 0;
37244
0
}
37245
37246
static int BC_add_object_ref(BCReaderState *s, JSValueConst obj)
37247
0
{
37248
0
    return BC_add_object_ref1(s, JS_VALUE_GET_OBJ(obj));
37249
0
}
37250
37251
static JSValue JS_ReadFunctionTag(BCReaderState *s)
37252
1
{
37253
1
    JSContext *ctx = s->ctx;
37254
1
    JSFunctionBytecode bc, *b;
37255
1
    JSValue obj = JS_UNDEFINED;
37256
1
    uint16_t v16;
37257
1
    uint8_t v8;
37258
1
    int idx, i, local_count;
37259
1
    int function_size, cpool_offset, byte_code_offset;
37260
1
    int closure_var_offset, vardefs_offset;
37261
37262
1
    memset(&bc, 0, sizeof(bc));
37263
1
    bc.header.ref_count = 1;
37264
    //bc.gc_header.mark = 0;
37265
37266
1
    if (bc_get_u16(s, &v16))
37267
0
        goto fail;
37268
1
    idx = 0;
37269
1
    bc.has_prototype = bc_get_flags(v16, &idx, 1);
37270
1
    bc.has_simple_parameter_list = bc_get_flags(v16, &idx, 1);
37271
1
    bc.is_derived_class_constructor = bc_get_flags(v16, &idx, 1);
37272
1
    bc.need_home_object = bc_get_flags(v16, &idx, 1);
37273
1
    bc.func_kind = bc_get_flags(v16, &idx, 2);
37274
1
    bc.new_target_allowed = bc_get_flags(v16, &idx, 1);
37275
1
    bc.super_call_allowed = bc_get_flags(v16, &idx, 1);
37276
1
    bc.super_allowed = bc_get_flags(v16, &idx, 1);
37277
1
    bc.arguments_allowed = bc_get_flags(v16, &idx, 1);
37278
1
    bc.has_debug = bc_get_flags(v16, &idx, 1);
37279
1
    bc.is_direct_or_indirect_eval = bc_get_flags(v16, &idx, 1);
37280
1
    bc.read_only_bytecode = s->is_rom_data;
37281
1
    if (bc_get_u8(s, &v8))
37282
0
        goto fail;
37283
1
    bc.js_mode = v8;
37284
1
    if (bc_get_atom(s, &bc.func_name))  //@ atom leak if failure
37285
0
        goto fail;
37286
1
    if (bc_get_leb128_u16(s, &bc.arg_count))
37287
0
        goto fail;
37288
1
    if (bc_get_leb128_u16(s, &bc.var_count))
37289
0
        goto fail;
37290
1
    if (bc_get_leb128_u16(s, &bc.defined_arg_count))
37291
0
        goto fail;
37292
1
    if (bc_get_leb128_u16(s, &bc.stack_size))
37293
0
        goto fail;
37294
1
    if (bc_get_leb128_int(s, &bc.closure_var_count))
37295
0
        goto fail;
37296
1
    if (bc_get_leb128_int(s, &bc.cpool_count))
37297
0
        goto fail;
37298
1
    if (bc_get_leb128_int(s, &bc.byte_code_len))
37299
0
        goto fail;
37300
1
    if (bc_get_leb128_int(s, &local_count))
37301
0
        goto fail;
37302
37303
1
    if (bc.has_debug) {
37304
1
        function_size = sizeof(*b);
37305
1
    } else {
37306
0
        function_size = offsetof(JSFunctionBytecode, debug);
37307
0
    }
37308
1
    cpool_offset = function_size;
37309
1
    function_size += bc.cpool_count * sizeof(*bc.cpool);
37310
1
    vardefs_offset = function_size;
37311
1
    function_size += local_count * sizeof(*bc.vardefs);
37312
1
    closure_var_offset = function_size;
37313
1
    function_size += bc.closure_var_count * sizeof(*bc.closure_var);
37314
1
    byte_code_offset = function_size;
37315
1
    if (!bc.read_only_bytecode) {
37316
1
        function_size += bc.byte_code_len;
37317
1
    }
37318
37319
1
    b = js_mallocz(ctx, function_size);
37320
1
    if (!b)
37321
0
        return JS_EXCEPTION;
37322
37323
1
    memcpy(b, &bc, offsetof(JSFunctionBytecode, debug));
37324
1
    b->header.ref_count = 1;
37325
1
    if (local_count != 0) {
37326
0
        b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
37327
0
    }
37328
1
    if (b->closure_var_count != 0) {
37329
0
        b->closure_var = (void *)((uint8_t*)b + closure_var_offset);
37330
0
    }
37331
1
    if (b->cpool_count != 0) {
37332
1
        b->cpool = (void *)((uint8_t*)b + cpool_offset);
37333
1
    }
37334
37335
1
    add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
37336
37337
1
    obj = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);
37338
37339
#ifdef DUMP_READ_OBJECT
37340
    bc_read_trace(s, "name: "); print_atom(s->ctx, b->func_name); printf("\n");
37341
#endif
37342
1
    bc_read_trace(s, "args=%d vars=%d defargs=%d closures=%d cpool=%d\n",
37343
1
                  b->arg_count, b->var_count, b->defined_arg_count,
37344
1
                  b->closure_var_count, b->cpool_count);
37345
1
    bc_read_trace(s, "stack=%d bclen=%d locals=%d\n",
37346
1
                  b->stack_size, b->byte_code_len, local_count);
37347
37348
1
    if (local_count != 0) {
37349
0
        bc_read_trace(s, "vars {\n");
37350
0
        for(i = 0; i < local_count; i++) {
37351
0
            JSVarDef *vd = &b->vardefs[i];
37352
0
            if (bc_get_atom(s, &vd->var_name))
37353
0
                goto fail;
37354
0
            if (bc_get_leb128_int(s, &vd->scope_level))
37355
0
                goto fail;
37356
0
            if (bc_get_leb128_int(s, &vd->scope_next))
37357
0
                goto fail;
37358
0
            vd->scope_next--;
37359
0
            if (bc_get_u8(s, &v8))
37360
0
                goto fail;
37361
0
            idx = 0;
37362
0
            vd->var_kind = bc_get_flags(v8, &idx, 4);
37363
0
            vd->is_const = bc_get_flags(v8, &idx, 1);
37364
0
            vd->is_lexical = bc_get_flags(v8, &idx, 1);
37365
0
            vd->is_captured = bc_get_flags(v8, &idx, 1);
37366
#ifdef DUMP_READ_OBJECT
37367
            bc_read_trace(s, "name: "); print_atom(s->ctx, vd->var_name); printf("\n");
37368
#endif
37369
0
        }
37370
0
        bc_read_trace(s, "}\n");
37371
0
    }
37372
1
    if (b->closure_var_count != 0) {
37373
0
        bc_read_trace(s, "closure vars {\n");
37374
0
        for(i = 0; i < b->closure_var_count; i++) {
37375
0
            JSClosureVar *cv = &b->closure_var[i];
37376
0
            int var_idx;
37377
0
            if (bc_get_atom(s, &cv->var_name))
37378
0
                goto fail;
37379
0
            if (bc_get_leb128_int(s, &var_idx))
37380
0
                goto fail;
37381
0
            cv->var_idx = var_idx;
37382
0
            if (bc_get_u8(s, &v8))
37383
0
                goto fail;
37384
0
            idx = 0;
37385
0
            cv->is_local = bc_get_flags(v8, &idx, 1);
37386
0
            cv->is_arg = bc_get_flags(v8, &idx, 1);
37387
0
            cv->is_const = bc_get_flags(v8, &idx, 1);
37388
0
            cv->is_lexical = bc_get_flags(v8, &idx, 1);
37389
0
            cv->var_kind = bc_get_flags(v8, &idx, 4);
37390
#ifdef DUMP_READ_OBJECT
37391
            bc_read_trace(s, "name: "); print_atom(s->ctx, cv->var_name); printf("\n");
37392
#endif
37393
0
        }
37394
0
        bc_read_trace(s, "}\n");
37395
0
    }
37396
1
    {
37397
1
        bc_read_trace(s, "bytecode {\n");
37398
1
        if (JS_ReadFunctionBytecode(s, b, byte_code_offset, b->byte_code_len))
37399
0
            goto fail;
37400
1
        bc_read_trace(s, "}\n");
37401
1
    }
37402
1
    if (b->has_debug) {
37403
        /* read optional debug information */
37404
1
        bc_read_trace(s, "debug {\n");
37405
1
        if (bc_get_atom(s, &b->debug.filename))
37406
0
            goto fail;
37407
#ifdef DUMP_READ_OBJECT
37408
        bc_read_trace(s, "filename: "); print_atom(s->ctx, b->debug.filename); printf("\n");
37409
#endif
37410
1
        if (bc_get_leb128_int(s, &b->debug.pc2line_len))
37411
0
            goto fail;
37412
1
        if (b->debug.pc2line_len) {
37413
1
            b->debug.pc2line_buf = js_mallocz(ctx, b->debug.pc2line_len);
37414
1
            if (!b->debug.pc2line_buf)
37415
0
                goto fail;
37416
1
            if (bc_get_buf(s, b->debug.pc2line_buf, b->debug.pc2line_len))
37417
0
                goto fail;
37418
1
        }
37419
1
        if (bc_get_leb128_int(s, &b->debug.source_len))
37420
0
            goto fail;
37421
1
        if (b->debug.source_len) {
37422
0
            bc_read_trace(s, "source: %d bytes\n", b->source_len);
37423
0
            b->debug.source = js_mallocz(ctx, b->debug.source_len);
37424
0
            if (!b->debug.source)
37425
0
                goto fail;
37426
0
            if (bc_get_buf(s, (uint8_t *)b->debug.source, b->debug.source_len))
37427
0
                goto fail;
37428
0
        }
37429
1
        bc_read_trace(s, "}\n");
37430
1
    }
37431
1
    if (b->cpool_count != 0) {
37432
1
        bc_read_trace(s, "cpool {\n");
37433
2
        for(i = 0; i < b->cpool_count; i++) {
37434
1
            JSValue val;
37435
1
            val = JS_ReadObjectRec(s);
37436
1
            if (JS_IsException(val))
37437
0
                goto fail;
37438
1
            b->cpool[i] = val;
37439
1
        }
37440
1
        bc_read_trace(s, "}\n");
37441
1
    }
37442
1
    b->realm = JS_DupContext(ctx);
37443
1
    return obj;
37444
0
 fail:
37445
0
    JS_FreeValue(ctx, obj);
37446
0
    return JS_EXCEPTION;
37447
1
}
37448
37449
static JSValue JS_ReadModule(BCReaderState *s)
37450
1
{
37451
1
    JSContext *ctx = s->ctx;
37452
1
    JSValue obj;
37453
1
    JSModuleDef *m = NULL;
37454
1
    JSAtom module_name;
37455
1
    int i;
37456
1
    uint8_t v8;
37457
37458
1
    if (bc_get_atom(s, &module_name))
37459
0
        goto fail;
37460
#ifdef DUMP_READ_OBJECT
37461
    bc_read_trace(s, "name: "); print_atom(s->ctx, module_name); printf("\n");
37462
#endif
37463
1
    m = js_new_module_def(ctx, module_name);
37464
1
    if (!m)
37465
0
        goto fail;
37466
1
    obj = JS_NewModuleValue(ctx, m);
37467
1
    if (bc_get_leb128_int(s, &m->req_module_entries_count))
37468
0
        goto fail;
37469
1
    if (m->req_module_entries_count != 0) {
37470
0
        m->req_module_entries_size = m->req_module_entries_count;
37471
0
        m->req_module_entries = js_mallocz(ctx, sizeof(m->req_module_entries[0]) * m->req_module_entries_size);
37472
0
        if (!m->req_module_entries)
37473
0
            goto fail;
37474
0
        for(i = 0; i < m->req_module_entries_count; i++) {
37475
0
            JSReqModuleEntry *rme = &m->req_module_entries[i];
37476
0
            JSValue val;
37477
0
            if (bc_get_atom(s, &rme->module_name))
37478
0
                goto fail;
37479
0
            val = JS_ReadObjectRec(s);
37480
0
            if (JS_IsException(val))
37481
0
                goto fail;
37482
0
            rme->attributes = val;
37483
0
        }
37484
0
    }
37485
37486
1
    if (bc_get_leb128_int(s, &m->export_entries_count))
37487
0
        goto fail;
37488
1
    if (m->export_entries_count != 0) {
37489
0
        m->export_entries_size = m->export_entries_count;
37490
0
        m->export_entries = js_mallocz(ctx, sizeof(m->export_entries[0]) * m->export_entries_size);
37491
0
        if (!m->export_entries)
37492
0
            goto fail;
37493
0
        for(i = 0; i < m->export_entries_count; i++) {
37494
0
            JSExportEntry *me = &m->export_entries[i];
37495
0
            if (bc_get_u8(s, &v8))
37496
0
                goto fail;
37497
0
            me->export_type = v8;
37498
0
            if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
37499
0
                if (bc_get_leb128_int(s, &me->u.local.var_idx))
37500
0
                    goto fail;
37501
0
            } else {
37502
0
                if (bc_get_leb128_int(s, &me->u.req_module_idx))
37503
0
                    goto fail;
37504
0
                if (bc_get_atom(s, &me->local_name))
37505
0
                    goto fail;
37506
0
            }
37507
0
            if (bc_get_atom(s, &me->export_name))
37508
0
                goto fail;
37509
0
        }
37510
0
    }
37511
37512
1
    if (bc_get_leb128_int(s, &m->star_export_entries_count))
37513
0
        goto fail;
37514
1
    if (m->star_export_entries_count != 0) {
37515
0
        m->star_export_entries_size = m->star_export_entries_count;
37516
0
        m->star_export_entries = js_mallocz(ctx, sizeof(m->star_export_entries[0]) * m->star_export_entries_size);
37517
0
        if (!m->star_export_entries)
37518
0
            goto fail;
37519
0
        for(i = 0; i < m->star_export_entries_count; i++) {
37520
0
            JSStarExportEntry *se = &m->star_export_entries[i];
37521
0
            if (bc_get_leb128_int(s, &se->req_module_idx))
37522
0
                goto fail;
37523
0
        }
37524
0
    }
37525
37526
1
    if (bc_get_leb128_int(s, &m->import_entries_count))
37527
0
        goto fail;
37528
1
    if (m->import_entries_count != 0) {
37529
0
        m->import_entries_size = m->import_entries_count;
37530
0
        m->import_entries = js_mallocz(ctx, sizeof(m->import_entries[0]) * m->import_entries_size);
37531
0
        if (!m->import_entries)
37532
0
            goto fail;
37533
0
        for(i = 0; i < m->import_entries_count; i++) {
37534
0
            JSImportEntry *mi = &m->import_entries[i];
37535
0
            uint8_t v8;
37536
0
            if (bc_get_leb128_int(s, &mi->var_idx))
37537
0
                goto fail;
37538
0
            if (bc_get_u8(s, &v8))
37539
0
                goto fail;
37540
0
            mi->is_star = (v8 != 0);
37541
0
            if (bc_get_atom(s, &mi->import_name))
37542
0
                goto fail;
37543
0
            if (bc_get_leb128_int(s, &mi->req_module_idx))
37544
0
                goto fail;
37545
0
        }
37546
0
    }
37547
37548
1
    if (bc_get_u8(s, &v8))
37549
0
        goto fail;
37550
1
    m->has_tla = (v8 != 0);
37551
37552
1
    m->func_obj = JS_ReadObjectRec(s);
37553
1
    if (JS_IsException(m->func_obj))
37554
0
        goto fail;
37555
1
    return obj;
37556
0
 fail:
37557
0
    if (m) {
37558
0
        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
37559
0
    }
37560
0
    return JS_EXCEPTION;
37561
1
}
37562
37563
static JSValue JS_ReadObjectTag(BCReaderState *s)
37564
0
{
37565
0
    JSContext *ctx = s->ctx;
37566
0
    JSValue obj;
37567
0
    uint32_t prop_count, i;
37568
0
    JSAtom atom;
37569
0
    JSValue val;
37570
0
    int ret;
37571
37572
0
    obj = JS_NewObject(ctx);
37573
0
    if (BC_add_object_ref(s, obj))
37574
0
        goto fail;
37575
0
    if (bc_get_leb128(s, &prop_count))
37576
0
        goto fail;
37577
0
    for(i = 0; i < prop_count; i++) {
37578
0
        if (bc_get_atom(s, &atom))
37579
0
            goto fail;
37580
#ifdef DUMP_READ_OBJECT
37581
        bc_read_trace(s, "propname: "); print_atom(s->ctx, atom); printf("\n");
37582
#endif
37583
0
        val = JS_ReadObjectRec(s);
37584
0
        if (JS_IsException(val)) {
37585
0
            JS_FreeAtom(ctx, atom);
37586
0
            goto fail;
37587
0
        }
37588
0
        ret = JS_DefinePropertyValue(ctx, obj, atom, val, JS_PROP_C_W_E);
37589
0
        JS_FreeAtom(ctx, atom);
37590
0
        if (ret < 0)
37591
0
            goto fail;
37592
0
    }
37593
0
    return obj;
37594
0
 fail:
37595
0
    JS_FreeValue(ctx, obj);
37596
0
    return JS_EXCEPTION;
37597
0
}
37598
37599
static JSValue JS_ReadArray(BCReaderState *s, int tag)
37600
0
{
37601
0
    JSContext *ctx = s->ctx;
37602
0
    JSValue obj;
37603
0
    uint32_t len, i;
37604
0
    JSValue val;
37605
0
    int ret, prop_flags;
37606
0
    BOOL is_template;
37607
37608
0
    obj = JS_NewArray(ctx);
37609
0
    if (BC_add_object_ref(s, obj))
37610
0
        goto fail;
37611
0
    is_template = (tag == BC_TAG_TEMPLATE_OBJECT);
37612
0
    if (bc_get_leb128(s, &len))
37613
0
        goto fail;
37614
0
    for(i = 0; i < len; i++) {
37615
0
        val = JS_ReadObjectRec(s);
37616
0
        if (JS_IsException(val))
37617
0
            goto fail;
37618
0
        if (is_template)
37619
0
            prop_flags = JS_PROP_ENUMERABLE;
37620
0
        else
37621
0
            prop_flags = JS_PROP_C_W_E;
37622
0
        ret = JS_DefinePropertyValueUint32(ctx, obj, i, val,
37623
0
                                           prop_flags);
37624
0
        if (ret < 0)
37625
0
            goto fail;
37626
0
    }
37627
0
    if (is_template) {
37628
0
        val = JS_ReadObjectRec(s);
37629
0
        if (JS_IsException(val))
37630
0
            goto fail;
37631
0
        if (!JS_IsUndefined(val)) {
37632
0
            ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_raw, val, 0);
37633
0
            if (ret < 0)
37634
0
                goto fail;
37635
0
        }
37636
0
        JS_PreventExtensions(ctx, obj);
37637
0
    }
37638
0
    return obj;
37639
0
 fail:
37640
0
    JS_FreeValue(ctx, obj);
37641
0
    return JS_EXCEPTION;
37642
0
}
37643
37644
static JSValue JS_ReadTypedArray(BCReaderState *s)
37645
0
{
37646
0
    JSContext *ctx = s->ctx;
37647
0
    JSValue obj = JS_UNDEFINED, array_buffer = JS_UNDEFINED;
37648
0
    uint8_t array_tag;
37649
0
    JSValueConst args[3];
37650
0
    uint32_t offset, len, idx;
37651
37652
0
    if (bc_get_u8(s, &array_tag))
37653
0
        return JS_EXCEPTION;
37654
0
    if (array_tag >= JS_TYPED_ARRAY_COUNT)
37655
0
        return JS_ThrowTypeError(ctx, "invalid typed array");
37656
0
    if (bc_get_leb128(s, &len))
37657
0
        return JS_EXCEPTION;
37658
0
    if (bc_get_leb128(s, &offset))
37659
0
        return JS_EXCEPTION;
37660
    /* XXX: this hack could be avoided if the typed array could be
37661
       created before the array buffer */
37662
0
    idx = s->objects_count;
37663
0
    if (BC_add_object_ref1(s, NULL))
37664
0
        goto fail;
37665
0
    array_buffer = JS_ReadObjectRec(s);
37666
0
    if (JS_IsException(array_buffer))
37667
0
        return JS_EXCEPTION;
37668
0
    if (!js_get_array_buffer(ctx, array_buffer)) {
37669
0
        JS_FreeValue(ctx, array_buffer);
37670
0
        return JS_EXCEPTION;
37671
0
    }
37672
0
    args[0] = array_buffer;
37673
0
    args[1] = JS_NewInt64(ctx, offset);
37674
0
    args[2] = JS_NewInt64(ctx, len);
37675
0
    obj = js_typed_array_constructor(ctx, JS_UNDEFINED,
37676
0
                                     3, args,
37677
0
                                     JS_CLASS_UINT8C_ARRAY + array_tag);
37678
0
    if (JS_IsException(obj))
37679
0
        goto fail;
37680
0
    if (s->allow_reference) {
37681
0
        s->objects[idx] = JS_VALUE_GET_OBJ(obj);
37682
0
    }
37683
0
    JS_FreeValue(ctx, array_buffer);
37684
0
    return obj;
37685
0
 fail:
37686
0
    JS_FreeValue(ctx, array_buffer);
37687
0
    JS_FreeValue(ctx, obj);
37688
0
    return JS_EXCEPTION;
37689
0
}
37690
37691
static JSValue JS_ReadArrayBuffer(BCReaderState *s)
37692
0
{
37693
0
    JSContext *ctx = s->ctx;
37694
0
    uint32_t byte_length;
37695
0
    JSValue obj;
37696
37697
0
    if (bc_get_leb128(s, &byte_length))
37698
0
        return JS_EXCEPTION;
37699
0
    if (unlikely(s->buf_end - s->ptr < byte_length)) {
37700
0
        bc_read_error_end(s);
37701
0
        return JS_EXCEPTION;
37702
0
    }
37703
0
    obj = JS_NewArrayBufferCopy(ctx, s->ptr, byte_length);
37704
0
    if (JS_IsException(obj))
37705
0
        goto fail;
37706
0
    if (BC_add_object_ref(s, obj))
37707
0
        goto fail;
37708
0
    s->ptr += byte_length;
37709
0
    return obj;
37710
0
 fail:
37711
0
    JS_FreeValue(ctx, obj);
37712
0
    return JS_EXCEPTION;
37713
0
}
37714
37715
static JSValue JS_ReadSharedArrayBuffer(BCReaderState *s)
37716
0
{
37717
0
    JSContext *ctx = s->ctx;
37718
0
    uint32_t byte_length;
37719
0
    uint8_t *data_ptr;
37720
0
    JSValue obj;
37721
0
    uint64_t u64;
37722
37723
0
    if (bc_get_leb128(s, &byte_length))
37724
0
        return JS_EXCEPTION;
37725
0
    if (bc_get_u64(s, &u64))
37726
0
        return JS_EXCEPTION;
37727
0
    data_ptr = (uint8_t *)(uintptr_t)u64;
37728
    /* the SharedArrayBuffer is cloned */
37729
0
    obj = js_array_buffer_constructor3(ctx, JS_UNDEFINED, byte_length,
37730
0
                                       JS_CLASS_SHARED_ARRAY_BUFFER,
37731
0
                                       data_ptr,
37732
0
                                       NULL, NULL, FALSE);
37733
0
    if (JS_IsException(obj))
37734
0
        goto fail;
37735
0
    if (BC_add_object_ref(s, obj))
37736
0
        goto fail;
37737
0
    return obj;
37738
0
 fail:
37739
0
    JS_FreeValue(ctx, obj);
37740
0
    return JS_EXCEPTION;
37741
0
}
37742
37743
static JSValue JS_ReadDate(BCReaderState *s)
37744
0
{
37745
0
    JSContext *ctx = s->ctx;
37746
0
    JSValue val, obj = JS_UNDEFINED;
37747
37748
0
    val = JS_ReadObjectRec(s);
37749
0
    if (JS_IsException(val))
37750
0
        goto fail;
37751
0
    if (!JS_IsNumber(val)) {
37752
0
        JS_ThrowTypeError(ctx, "Number tag expected for date");
37753
0
        goto fail;
37754
0
    }
37755
0
    obj = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_DATE],
37756
0
                                 JS_CLASS_DATE);
37757
0
    if (JS_IsException(obj))
37758
0
        goto fail;
37759
0
    if (BC_add_object_ref(s, obj))
37760
0
        goto fail;
37761
0
    JS_SetObjectData(ctx, obj, val);
37762
0
    return obj;
37763
0
 fail:
37764
0
    JS_FreeValue(ctx, val);
37765
0
    JS_FreeValue(ctx, obj);
37766
0
    return JS_EXCEPTION;
37767
0
}
37768
37769
static JSValue JS_ReadObjectValue(BCReaderState *s)
37770
0
{
37771
0
    JSContext *ctx = s->ctx;
37772
0
    JSValue val, obj = JS_UNDEFINED;
37773
37774
0
    val = JS_ReadObjectRec(s);
37775
0
    if (JS_IsException(val))
37776
0
        goto fail;
37777
0
    obj = JS_ToObject(ctx, val);
37778
0
    if (JS_IsException(obj))
37779
0
        goto fail;
37780
0
    if (BC_add_object_ref(s, obj))
37781
0
        goto fail;
37782
0
    JS_FreeValue(ctx, val);
37783
0
    return obj;
37784
0
 fail:
37785
0
    JS_FreeValue(ctx, val);
37786
0
    JS_FreeValue(ctx, obj);
37787
0
    return JS_EXCEPTION;
37788
0
}
37789
37790
static JSValue JS_ReadObjectRec(BCReaderState *s)
37791
3
{
37792
3
    JSContext *ctx = s->ctx;
37793
3
    uint8_t tag;
37794
3
    JSValue obj = JS_UNDEFINED;
37795
37796
3
    if (js_check_stack_overflow(ctx->rt, 0))
37797
0
        return JS_ThrowStackOverflow(ctx);
37798
37799
3
    if (bc_get_u8(s, &tag))
37800
0
        return JS_EXCEPTION;
37801
37802
3
    bc_read_trace(s, "%s {\n", bc_tag_str[tag]);
37803
37804
3
    switch(tag) {
37805
0
    case BC_TAG_NULL:
37806
0
        obj = JS_NULL;
37807
0
        break;
37808
0
    case BC_TAG_UNDEFINED:
37809
0
        obj = JS_UNDEFINED;
37810
0
        break;
37811
0
    case BC_TAG_BOOL_FALSE:
37812
0
    case BC_TAG_BOOL_TRUE:
37813
0
        obj = JS_NewBool(ctx, tag - BC_TAG_BOOL_FALSE);
37814
0
        break;
37815
0
    case BC_TAG_INT32:
37816
0
        {
37817
0
            int32_t val;
37818
0
            if (bc_get_sleb128(s, &val))
37819
0
                return JS_EXCEPTION;
37820
0
            bc_read_trace(s, "%d\n", val);
37821
0
            obj = JS_NewInt32(ctx, val);
37822
0
        }
37823
0
        break;
37824
1
    case BC_TAG_FLOAT64:
37825
1
        {
37826
1
            JSFloat64Union u;
37827
1
            if (bc_get_u64(s, &u.u64))
37828
0
                return JS_EXCEPTION;
37829
1
            bc_read_trace(s, "%g\n", u.d);
37830
1
            obj = __JS_NewFloat64(ctx, u.d);
37831
1
        }
37832
0
        break;
37833
0
    case BC_TAG_STRING:
37834
0
        {
37835
0
            JSString *p;
37836
0
            p = JS_ReadString(s);
37837
0
            if (!p)
37838
0
                return JS_EXCEPTION;
37839
0
            obj = JS_MKPTR(JS_TAG_STRING, p);
37840
0
        }
37841
0
        break;
37842
1
    case BC_TAG_FUNCTION_BYTECODE:
37843
1
        if (!s->allow_bytecode)
37844
0
            goto invalid_tag;
37845
1
        obj = JS_ReadFunctionTag(s);
37846
1
        break;
37847
1
    case BC_TAG_MODULE:
37848
1
        if (!s->allow_bytecode)
37849
0
            goto invalid_tag;
37850
1
        obj = JS_ReadModule(s);
37851
1
        break;
37852
0
    case BC_TAG_OBJECT:
37853
0
        obj = JS_ReadObjectTag(s);
37854
0
        break;
37855
0
    case BC_TAG_ARRAY:
37856
0
    case BC_TAG_TEMPLATE_OBJECT:
37857
0
        obj = JS_ReadArray(s, tag);
37858
0
        break;
37859
0
    case BC_TAG_TYPED_ARRAY:
37860
0
        obj = JS_ReadTypedArray(s);
37861
0
        break;
37862
0
    case BC_TAG_ARRAY_BUFFER:
37863
0
        obj = JS_ReadArrayBuffer(s);
37864
0
        break;
37865
0
    case BC_TAG_SHARED_ARRAY_BUFFER:
37866
0
        if (!s->allow_sab || !ctx->rt->sab_funcs.sab_dup)
37867
0
            goto invalid_tag;
37868
0
        obj = JS_ReadSharedArrayBuffer(s);
37869
0
        break;
37870
0
    case BC_TAG_DATE:
37871
0
        obj = JS_ReadDate(s);
37872
0
        break;
37873
0
    case BC_TAG_OBJECT_VALUE:
37874
0
        obj = JS_ReadObjectValue(s);
37875
0
        break;
37876
0
    case BC_TAG_BIG_INT:
37877
0
        obj = JS_ReadBigInt(s);
37878
0
        break;
37879
0
    case BC_TAG_OBJECT_REFERENCE:
37880
0
        {
37881
0
            uint32_t val;
37882
0
            if (!s->allow_reference)
37883
0
                return JS_ThrowSyntaxError(ctx, "object references are not allowed");
37884
0
            if (bc_get_leb128(s, &val))
37885
0
                return JS_EXCEPTION;
37886
0
            bc_read_trace(s, "%u\n", val);
37887
0
            if (val >= s->objects_count) {
37888
0
                return JS_ThrowSyntaxError(ctx, "invalid object reference (%u >= %u)",
37889
0
                                           val, s->objects_count);
37890
0
            }
37891
0
            obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, s->objects[val]));
37892
0
        }
37893
0
        break;
37894
0
    default:
37895
0
    invalid_tag:
37896
0
        return JS_ThrowSyntaxError(ctx, "invalid tag (tag=%d pos=%u)",
37897
0
                                   tag, (unsigned int)(s->ptr - s->buf_start));
37898
3
    }
37899
3
    bc_read_trace(s, "}\n");
37900
3
    return obj;
37901
3
}
37902
37903
static int JS_ReadObjectAtoms(BCReaderState *s)
37904
1
{
37905
1
    uint8_t v8;
37906
1
    JSString *p;
37907
1
    int i;
37908
1
    JSAtom atom;
37909
37910
1
    if (bc_get_u8(s, &v8))
37911
0
        return -1;
37912
1
    if (v8 != BC_VERSION) {
37913
0
        JS_ThrowSyntaxError(s->ctx, "invalid version (%d expected=%d)",
37914
0
                            v8, BC_VERSION);
37915
0
        return -1;
37916
0
    }
37917
1
    if (bc_get_leb128(s, &s->idx_to_atom_count))
37918
0
        return -1;
37919
37920
1
    bc_read_trace(s, "%d atom indexes {\n", s->idx_to_atom_count);
37921
37922
1
    if (s->idx_to_atom_count != 0) {
37923
1
        s->idx_to_atom = js_mallocz(s->ctx, s->idx_to_atom_count *
37924
1
                                    sizeof(s->idx_to_atom[0]));
37925
1
        if (!s->idx_to_atom)
37926
0
            return s->error_state = -1;
37927
1
    }
37928
3
    for(i = 0; i < s->idx_to_atom_count; i++) {
37929
2
        p = JS_ReadString(s);
37930
2
        if (!p)
37931
0
            return -1;
37932
2
        atom = JS_NewAtomStr(s->ctx, p);
37933
2
        if (atom == JS_ATOM_NULL)
37934
0
            return s->error_state = -1;
37935
2
        s->idx_to_atom[i] = atom;
37936
2
        if (s->is_rom_data && (atom != (i + s->first_atom)))
37937
0
            s->is_rom_data = FALSE; /* atoms must be relocated */
37938
2
    }
37939
1
    bc_read_trace(s, "}\n");
37940
1
    return 0;
37941
1
}
37942
37943
static void bc_reader_free(BCReaderState *s)
37944
1
{
37945
1
    int i;
37946
1
    if (s->idx_to_atom) {
37947
3
        for(i = 0; i < s->idx_to_atom_count; i++) {
37948
2
            JS_FreeAtom(s->ctx, s->idx_to_atom[i]);
37949
2
        }
37950
1
        js_free(s->ctx, s->idx_to_atom);
37951
1
    }
37952
1
    js_free(s->ctx, s->objects);
37953
1
}
37954
37955
JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len,
37956
                       int flags)
37957
1
{
37958
1
    BCReaderState ss, *s = &ss;
37959
1
    JSValue obj;
37960
37961
1
    ctx->binary_object_count += 1;
37962
1
    ctx->binary_object_size += buf_len;
37963
37964
1
    memset(s, 0, sizeof(*s));
37965
1
    s->ctx = ctx;
37966
1
    s->buf_start = buf;
37967
1
    s->buf_end = buf + buf_len;
37968
1
    s->ptr = buf;
37969
1
    s->allow_bytecode = ((flags & JS_READ_OBJ_BYTECODE) != 0);
37970
1
    s->is_rom_data = ((flags & JS_READ_OBJ_ROM_DATA) != 0);
37971
1
    s->allow_sab = ((flags & JS_READ_OBJ_SAB) != 0);
37972
1
    s->allow_reference = ((flags & JS_READ_OBJ_REFERENCE) != 0);
37973
1
    if (s->allow_bytecode)
37974
1
        s->first_atom = JS_ATOM_END;
37975
0
    else
37976
0
        s->first_atom = 1;
37977
1
    if (JS_ReadObjectAtoms(s)) {
37978
0
        obj = JS_EXCEPTION;
37979
1
    } else {
37980
1
        obj = JS_ReadObjectRec(s);
37981
1
    }
37982
1
    bc_reader_free(s);
37983
1
    return obj;
37984
1
}
37985
37986
/*******************************************************************/
37987
/* runtime functions & objects */
37988
37989
static JSValue js_string_constructor(JSContext *ctx, JSValueConst this_val,
37990
                                     int argc, JSValueConst *argv);
37991
static JSValue js_boolean_constructor(JSContext *ctx, JSValueConst this_val,
37992
                                      int argc, JSValueConst *argv);
37993
static JSValue js_number_constructor(JSContext *ctx, JSValueConst this_val,
37994
                                     int argc, JSValueConst *argv);
37995
37996
static int check_function(JSContext *ctx, JSValueConst obj)
37997
18
{
37998
18
    if (likely(JS_IsFunction(ctx, obj)))
37999
18
        return 0;
38000
0
    JS_ThrowTypeError(ctx, "not a function");
38001
0
    return -1;
38002
18
}
38003
38004
static int check_exception_free(JSContext *ctx, JSValue obj)
38005
0
{
38006
0
    JS_FreeValue(ctx, obj);
38007
0
    return JS_IsException(obj);
38008
0
}
38009
38010
static JSAtom find_atom(JSContext *ctx, const char *name)
38011
924
{
38012
924
    JSAtom atom;
38013
924
    int len;
38014
38015
924
    if (*name == '[') {
38016
94
        name++;
38017
94
        len = strlen(name) - 1;
38018
        /* We assume 8 bit non null strings, which is the case for these
38019
           symbols */
38020
684
        for(atom = JS_ATOM_Symbol_toPrimitive; atom < JS_ATOM_END; atom++) {
38021
684
            JSAtomStruct *p = ctx->rt->atom_array[atom];
38022
684
            JSString *str = p;
38023
684
            if (str->len == len && !memcmp(str->u.str8, name, len))
38024
94
                return JS_DupAtom(ctx, atom);
38025
684
        }
38026
0
        abort();
38027
830
    } else {
38028
830
        atom = JS_NewAtom(ctx, name);
38029
830
    }
38030
830
    return atom;
38031
924
}
38032
38033
static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,
38034
                                               JSAtom atom, void *opaque)
38035
20
{
38036
20
    const JSCFunctionListEntry *e = opaque;
38037
20
    JSValue val;
38038
38039
20
    switch(e->def_type) {
38040
20
    case JS_DEF_CFUNC:
38041
20
        val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic,
38042
20
                               e->name, e->u.func.length, e->u.func.cproto, e->magic);
38043
20
        break;
38044
0
    case JS_DEF_PROP_STRING:
38045
0
        val = JS_NewAtomString(ctx, e->u.str);
38046
0
        break;
38047
0
    case JS_DEF_OBJECT:
38048
0
        val = JS_NewObject(ctx);
38049
0
        JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len);
38050
0
        break;
38051
0
    default:
38052
0
        abort();
38053
20
    }
38054
20
    return val;
38055
20
}
38056
38057
static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj,
38058
                                          JSAtom atom,
38059
                                          const JSCFunctionListEntry *e)
38060
904
{
38061
904
    JSValue val;
38062
904
    int prop_flags = e->prop_flags;
38063
38064
904
    switch(e->def_type) {
38065
20
    case JS_DEF_ALIAS: /* using autoinit for aliases is not safe */
38066
20
        {
38067
20
            JSAtom atom1 = find_atom(ctx, e->u.alias.name);
38068
20
            switch (e->u.alias.base) {
38069
16
            case -1:
38070
16
                val = JS_GetProperty(ctx, obj, atom1);
38071
16
                break;
38072
4
            case 0:
38073
4
                val = JS_GetProperty(ctx, ctx->global_obj, atom1);
38074
4
                break;
38075
0
            case 1:
38076
0
                val = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], atom1);
38077
0
                break;
38078
0
            default:
38079
0
                abort();
38080
20
            }
38081
20
            JS_FreeAtom(ctx, atom1);
38082
20
            if (atom == JS_ATOM_Symbol_toPrimitive) {
38083
                /* Symbol.toPrimitive functions are not writable */
38084
0
                prop_flags = JS_PROP_CONFIGURABLE;
38085
20
            } else if (atom == JS_ATOM_Symbol_hasInstance) {
38086
                /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */
38087
0
                prop_flags = 0;
38088
0
            }
38089
20
        }
38090
0
        break;
38091
710
    case JS_DEF_CFUNC:
38092
710
        if (atom == JS_ATOM_Symbol_toPrimitive) {
38093
            /* Symbol.toPrimitive functions are not writable */
38094
4
            prop_flags = JS_PROP_CONFIGURABLE;
38095
706
        } else if (atom == JS_ATOM_Symbol_hasInstance) {
38096
            /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */
38097
2
            prop_flags = 0;
38098
2
        }
38099
710
        JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP,
38100
710
                                  (void *)e, prop_flags);
38101
710
        return 0;
38102
30
    case JS_DEF_CGETSET: /* XXX: use autoinit again ? */
38103
70
    case JS_DEF_CGETSET_MAGIC:
38104
70
        {
38105
70
            JSValue getter, setter;
38106
70
            char buf[64];
38107
38108
70
            getter = JS_UNDEFINED;
38109
70
            if (e->u.getset.get.generic) {
38110
70
                snprintf(buf, sizeof(buf), "get %s", e->name);
38111
70
                getter = JS_NewCFunction2(ctx, e->u.getset.get.generic,
38112
70
                                          buf, 0, e->def_type == JS_DEF_CGETSET_MAGIC ? JS_CFUNC_getter_magic : JS_CFUNC_getter,
38113
70
                                          e->magic);
38114
70
            }
38115
70
            setter = JS_UNDEFINED;
38116
70
            if (e->u.getset.set.generic) {
38117
2
                snprintf(buf, sizeof(buf), "set %s", e->name);
38118
2
                setter = JS_NewCFunction2(ctx, e->u.getset.set.generic,
38119
2
                                          buf, 1, e->def_type == JS_DEF_CGETSET_MAGIC ? JS_CFUNC_setter_magic : JS_CFUNC_setter,
38120
2
                                          e->magic);
38121
2
            }
38122
70
            JS_DefinePropertyGetSet(ctx, obj, atom, getter, setter, prop_flags);
38123
70
            return 0;
38124
30
        }
38125
0
        break;
38126
24
    case JS_DEF_PROP_INT32:
38127
24
        val = JS_NewInt32(ctx, e->u.i32);
38128
24
        break;
38129
0
    case JS_DEF_PROP_INT64:
38130
0
        val = JS_NewInt64(ctx, e->u.i64);
38131
0
        break;
38132
20
    case JS_DEF_PROP_DOUBLE:
38133
20
        val = __JS_NewFloat64(ctx, e->u.f64);
38134
20
        break;
38135
2
    case JS_DEF_PROP_UNDEFINED:
38136
2
        val = JS_UNDEFINED;
38137
2
        break;
38138
50
    case JS_DEF_PROP_STRING:
38139
58
    case JS_DEF_OBJECT:
38140
58
        JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP,
38141
58
                                  (void *)e, prop_flags);
38142
58
        return 0;
38143
0
    default:
38144
0
        abort();
38145
904
    }
38146
66
    JS_DefinePropertyValue(ctx, obj, atom, val, prop_flags);
38147
66
    return 0;
38148
904
}
38149
38150
int JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
38151
                               const JSCFunctionListEntry *tab, int len)
38152
118
{
38153
118
    int i, ret;
38154
38155
1.02k
    for (i = 0; i < len; i++) {
38156
904
        const JSCFunctionListEntry *e = &tab[i];
38157
904
        JSAtom atom = find_atom(ctx, e->name);
38158
904
        if (atom == JS_ATOM_NULL)
38159
0
            return -1;
38160
904
        ret = JS_InstantiateFunctionListItem(ctx, obj, atom, e);
38161
904
        JS_FreeAtom(ctx, atom);
38162
904
        if (ret)
38163
0
            return -1;
38164
904
    }
38165
118
    return 0;
38166
118
}
38167
38168
int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m,
38169
                           const JSCFunctionListEntry *tab, int len)
38170
4
{
38171
4
    int i;
38172
194
    for(i = 0; i < len; i++) {
38173
190
        if (JS_AddModuleExport(ctx, m, tab[i].name))
38174
0
            return -1;
38175
190
    }
38176
4
    return 0;
38177
4
}
38178
38179
int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,
38180
                           const JSCFunctionListEntry *tab, int len)
38181
4
{
38182
4
    int i;
38183
4
    JSValue val;
38184
38185
194
    for(i = 0; i < len; i++) {
38186
190
        const JSCFunctionListEntry *e = &tab[i];
38187
190
        switch(e->def_type) {
38188
110
        case JS_DEF_CFUNC:
38189
110
            val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic,
38190
110
                                   e->name, e->u.func.length, e->u.func.cproto, e->magic);
38191
110
            break;
38192
2
        case JS_DEF_PROP_STRING:
38193
2
            val = JS_NewString(ctx, e->u.str);
38194
2
            break;
38195
76
        case JS_DEF_PROP_INT32:
38196
76
            val = JS_NewInt32(ctx, e->u.i32);
38197
76
            break;
38198
0
        case JS_DEF_PROP_INT64:
38199
0
            val = JS_NewInt64(ctx, e->u.i64);
38200
0
            break;
38201
0
        case JS_DEF_PROP_DOUBLE:
38202
0
            val = __JS_NewFloat64(ctx, e->u.f64);
38203
0
            break;
38204
2
        case JS_DEF_OBJECT:
38205
2
            val = JS_NewObject(ctx);
38206
2
            JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len);
38207
2
            break;
38208
0
        default:
38209
0
            abort();
38210
190
        }
38211
190
        if (JS_SetModuleExport(ctx, m, e->name, val))
38212
0
            return -1;
38213
190
    }
38214
4
    return 0;
38215
4
}
38216
38217
/* Note: 'func_obj' is not necessarily a constructor */
38218
static void JS_SetConstructor2(JSContext *ctx,
38219
                               JSValueConst func_obj,
38220
                               JSValueConst proto,
38221
                               int proto_flags, int ctor_flags)
38222
94
{
38223
94
    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype,
38224
94
                           JS_DupValue(ctx, proto), proto_flags);
38225
94
    JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor,
38226
94
                           JS_DupValue(ctx, func_obj),
38227
94
                           ctor_flags);
38228
94
    set_cycle_flag(ctx, func_obj);
38229
94
    set_cycle_flag(ctx, proto);
38230
94
}
38231
38232
void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj,
38233
                       JSValueConst proto)
38234
84
{
38235
84
    JS_SetConstructor2(ctx, func_obj, proto,
38236
84
                       0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
38237
84
}
38238
38239
static void JS_NewGlobalCConstructor2(JSContext *ctx,
38240
                                      JSValue func_obj,
38241
                                      const char *name,
38242
                                      JSValueConst proto)
38243
82
{
38244
82
    JS_DefinePropertyValueStr(ctx, ctx->global_obj, name,
38245
82
                           JS_DupValue(ctx, func_obj),
38246
82
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
38247
82
    JS_SetConstructor(ctx, func_obj, proto);
38248
82
    JS_FreeValue(ctx, func_obj);
38249
82
}
38250
38251
static JSValueConst JS_NewGlobalCConstructor(JSContext *ctx, const char *name,
38252
                                             JSCFunction *func, int length,
38253
                                             JSValueConst proto)
38254
22
{
38255
22
    JSValue func_obj;
38256
22
    func_obj = JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_constructor_or_func, 0);
38257
22
    JS_NewGlobalCConstructor2(ctx, func_obj, name, proto);
38258
22
    return func_obj;
38259
22
}
38260
38261
static JSValueConst JS_NewGlobalCConstructorOnly(JSContext *ctx, const char *name,
38262
                                                 JSCFunction *func, int length,
38263
                                                 JSValueConst proto)
38264
6
{
38265
6
    JSValue func_obj;
38266
6
    func_obj = JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_constructor, 0);
38267
6
    JS_NewGlobalCConstructor2(ctx, func_obj, name, proto);
38268
6
    return func_obj;
38269
6
}
38270
38271
static JSValue js_global_eval(JSContext *ctx, JSValueConst this_val,
38272
                              int argc, JSValueConst *argv)
38273
0
{
38274
0
    return JS_EvalObject(ctx, ctx->global_obj, argv[0], JS_EVAL_TYPE_INDIRECT, -1);
38275
0
}
38276
38277
static JSValue js_global_isNaN(JSContext *ctx, JSValueConst this_val,
38278
                               int argc, JSValueConst *argv)
38279
0
{
38280
0
    double d;
38281
38282
0
    if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
38283
0
        return JS_EXCEPTION;
38284
0
    return JS_NewBool(ctx, isnan(d));
38285
0
}
38286
38287
static JSValue js_global_isFinite(JSContext *ctx, JSValueConst this_val,
38288
                                  int argc, JSValueConst *argv)
38289
0
{
38290
0
    double d;
38291
0
    if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
38292
0
        return JS_EXCEPTION;
38293
0
    return JS_NewBool(ctx, isfinite(d));
38294
0
}
38295
38296
/* Object class */
38297
38298
static JSValue JS_ToObject(JSContext *ctx, JSValueConst val)
38299
0
{
38300
0
    int tag = JS_VALUE_GET_NORM_TAG(val);
38301
0
    JSValue obj;
38302
38303
0
    switch(tag) {
38304
0
    default:
38305
0
    case JS_TAG_NULL:
38306
0
    case JS_TAG_UNDEFINED:
38307
0
        return JS_ThrowTypeError(ctx, "cannot convert to object");
38308
0
    case JS_TAG_OBJECT:
38309
0
    case JS_TAG_EXCEPTION:
38310
0
        return JS_DupValue(ctx, val);
38311
0
    case JS_TAG_SHORT_BIG_INT:
38312
0
    case JS_TAG_BIG_INT:
38313
0
        obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT);
38314
0
        goto set_value;
38315
0
    case JS_TAG_INT:
38316
0
    case JS_TAG_FLOAT64:
38317
0
        obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER);
38318
0
        goto set_value;
38319
0
    case JS_TAG_STRING:
38320
0
    case JS_TAG_STRING_ROPE:
38321
        /* XXX: should call the string constructor */
38322
0
        {
38323
0
            JSValue str;
38324
0
            str = JS_ToString(ctx, val); /* ensure that we never store a rope */
38325
0
            if (JS_IsException(str))
38326
0
                return JS_EXCEPTION;
38327
0
            obj = JS_NewObjectClass(ctx, JS_CLASS_STRING);
38328
0
            if (!JS_IsException(obj)) {
38329
0
                JS_DefinePropertyValue(ctx, obj, JS_ATOM_length,
38330
0
                                       JS_NewInt32(ctx, JS_VALUE_GET_STRING(str)->len), 0);
38331
0
                JS_SetObjectData(ctx, obj, JS_DupValue(ctx, str));
38332
0
            }
38333
0
            JS_FreeValue(ctx, str);
38334
0
            return obj;
38335
0
        }
38336
0
    case JS_TAG_BOOL:
38337
0
        obj = JS_NewObjectClass(ctx, JS_CLASS_BOOLEAN);
38338
0
        goto set_value;
38339
0
    case JS_TAG_SYMBOL:
38340
0
        obj = JS_NewObjectClass(ctx, JS_CLASS_SYMBOL);
38341
0
    set_value:
38342
0
        if (!JS_IsException(obj))
38343
0
            JS_SetObjectData(ctx, obj, JS_DupValue(ctx, val));
38344
0
        return obj;
38345
0
    }
38346
0
}
38347
38348
static JSValue JS_ToObjectFree(JSContext *ctx, JSValue val)
38349
0
{
38350
0
    JSValue obj = JS_ToObject(ctx, val);
38351
0
    JS_FreeValue(ctx, val);
38352
0
    return obj;
38353
0
}
38354
38355
static int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,
38356
                          JSValueConst desc)
38357
0
{
38358
0
    JSValue val, getter, setter;
38359
0
    int flags;
38360
38361
0
    if (!JS_IsObject(desc)) {
38362
0
        JS_ThrowTypeErrorNotAnObject(ctx);
38363
0
        return -1;
38364
0
    }
38365
0
    flags = 0;
38366
0
    val = JS_UNDEFINED;
38367
0
    getter = JS_UNDEFINED;
38368
0
    setter = JS_UNDEFINED;
38369
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_enumerable)) {
38370
0
        JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_enumerable);
38371
0
        if (JS_IsException(prop))
38372
0
            goto fail;
38373
0
        flags |= JS_PROP_HAS_ENUMERABLE;
38374
0
        if (JS_ToBoolFree(ctx, prop))
38375
0
            flags |= JS_PROP_ENUMERABLE;
38376
0
    }
38377
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_configurable)) {
38378
0
        JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_configurable);
38379
0
        if (JS_IsException(prop))
38380
0
            goto fail;
38381
0
        flags |= JS_PROP_HAS_CONFIGURABLE;
38382
0
        if (JS_ToBoolFree(ctx, prop))
38383
0
            flags |= JS_PROP_CONFIGURABLE;
38384
0
    }
38385
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_value)) {
38386
0
        flags |= JS_PROP_HAS_VALUE;
38387
0
        val = JS_GetProperty(ctx, desc, JS_ATOM_value);
38388
0
        if (JS_IsException(val))
38389
0
            goto fail;
38390
0
    }
38391
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_writable)) {
38392
0
        JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_writable);
38393
0
        if (JS_IsException(prop))
38394
0
            goto fail;
38395
0
        flags |= JS_PROP_HAS_WRITABLE;
38396
0
        if (JS_ToBoolFree(ctx, prop))
38397
0
            flags |= JS_PROP_WRITABLE;
38398
0
    }
38399
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_get)) {
38400
0
        flags |= JS_PROP_HAS_GET;
38401
0
        getter = JS_GetProperty(ctx, desc, JS_ATOM_get);
38402
0
        if (JS_IsException(getter) ||
38403
0
            !(JS_IsUndefined(getter) || JS_IsFunction(ctx, getter))) {
38404
0
            JS_ThrowTypeError(ctx, "invalid getter");
38405
0
            goto fail;
38406
0
        }
38407
0
    }
38408
0
    if (JS_HasProperty(ctx, desc, JS_ATOM_set)) {
38409
0
        flags |= JS_PROP_HAS_SET;
38410
0
        setter = JS_GetProperty(ctx, desc, JS_ATOM_set);
38411
0
        if (JS_IsException(setter) ||
38412
0
            !(JS_IsUndefined(setter) || JS_IsFunction(ctx, setter))) {
38413
0
            JS_ThrowTypeError(ctx, "invalid setter");
38414
0
            goto fail;
38415
0
        }
38416
0
    }
38417
0
    if ((flags & (JS_PROP_HAS_SET | JS_PROP_HAS_GET)) &&
38418
0
        (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE))) {
38419
0
        JS_ThrowTypeError(ctx, "cannot have setter/getter and value or writable");
38420
0
        goto fail;
38421
0
    }
38422
0
    d->flags = flags;
38423
0
    d->value = val;
38424
0
    d->getter = getter;
38425
0
    d->setter = setter;
38426
0
    return 0;
38427
0
 fail:
38428
0
    JS_FreeValue(ctx, val);
38429
0
    JS_FreeValue(ctx, getter);
38430
0
    JS_FreeValue(ctx, setter);
38431
0
    return -1;
38432
0
}
38433
38434
static __exception int JS_DefinePropertyDesc(JSContext *ctx, JSValueConst obj,
38435
                                             JSAtom prop, JSValueConst desc,
38436
                                             int flags)
38437
0
{
38438
0
    JSPropertyDescriptor d;
38439
0
    int ret;
38440
38441
0
    if (js_obj_to_desc(ctx, &d, desc) < 0)
38442
0
        return -1;
38443
38444
0
    ret = JS_DefineProperty(ctx, obj, prop,
38445
0
                            d.value, d.getter, d.setter, d.flags | flags);
38446
0
    js_free_desc(ctx, &d);
38447
0
    return ret;
38448
0
}
38449
38450
static __exception int JS_ObjectDefineProperties(JSContext *ctx,
38451
                                                 JSValueConst obj,
38452
                                                 JSValueConst properties)
38453
0
{
38454
0
    JSValue props, desc;
38455
0
    JSObject *p;
38456
0
    JSPropertyEnum *atoms;
38457
0
    uint32_t len, i;
38458
0
    int ret = -1;
38459
38460
0
    if (!JS_IsObject(obj)) {
38461
0
        JS_ThrowTypeErrorNotAnObject(ctx);
38462
0
        return -1;
38463
0
    }
38464
0
    desc = JS_UNDEFINED;
38465
0
    props = JS_ToObject(ctx, properties);
38466
0
    if (JS_IsException(props))
38467
0
        return -1;
38468
0
    p = JS_VALUE_GET_OBJ(props);
38469
    /* XXX: not done in the same order as the spec */
38470
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK) < 0)
38471
0
        goto exception;
38472
0
    for(i = 0; i < len; i++) {
38473
0
        JS_FreeValue(ctx, desc);
38474
0
        desc = JS_GetProperty(ctx, props, atoms[i].atom);
38475
0
        if (JS_IsException(desc))
38476
0
            goto exception;
38477
0
        if (JS_DefinePropertyDesc(ctx, obj, atoms[i].atom, desc, JS_PROP_THROW) < 0)
38478
0
            goto exception;
38479
0
    }
38480
0
    ret = 0;
38481
38482
0
exception:
38483
0
    JS_FreePropertyEnum(ctx, atoms, len);
38484
0
    JS_FreeValue(ctx, props);
38485
0
    JS_FreeValue(ctx, desc);
38486
0
    return ret;
38487
0
}
38488
38489
static JSValue js_object_constructor(JSContext *ctx, JSValueConst new_target,
38490
                                     int argc, JSValueConst *argv)
38491
0
{
38492
0
    JSValue ret;
38493
0
    if (!JS_IsUndefined(new_target) &&
38494
0
        JS_VALUE_GET_OBJ(new_target) !=
38495
0
        JS_VALUE_GET_OBJ(JS_GetActiveFunction(ctx))) {
38496
0
        ret = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
38497
0
    } else {
38498
0
        int tag = JS_VALUE_GET_NORM_TAG(argv[0]);
38499
0
        switch(tag) {
38500
0
        case JS_TAG_NULL:
38501
0
        case JS_TAG_UNDEFINED:
38502
0
            ret = JS_NewObject(ctx);
38503
0
            break;
38504
0
        default:
38505
0
            ret = JS_ToObject(ctx, argv[0]);
38506
0
            break;
38507
0
        }
38508
0
    }
38509
0
    return ret;
38510
0
}
38511
38512
static JSValue js_object_create(JSContext *ctx, JSValueConst this_val,
38513
                                int argc, JSValueConst *argv)
38514
0
{
38515
0
    JSValueConst proto, props;
38516
0
    JSValue obj;
38517
38518
0
    proto = argv[0];
38519
0
    if (!JS_IsObject(proto) && !JS_IsNull(proto))
38520
0
        return JS_ThrowTypeError(ctx, "not a prototype");
38521
0
    obj = JS_NewObjectProto(ctx, proto);
38522
0
    if (JS_IsException(obj))
38523
0
        return JS_EXCEPTION;
38524
0
    props = argv[1];
38525
0
    if (!JS_IsUndefined(props)) {
38526
0
        if (JS_ObjectDefineProperties(ctx, obj, props)) {
38527
0
            JS_FreeValue(ctx, obj);
38528
0
            return JS_EXCEPTION;
38529
0
        }
38530
0
    }
38531
0
    return obj;
38532
0
}
38533
38534
static JSValue js_object_getPrototypeOf(JSContext *ctx, JSValueConst this_val,
38535
                                        int argc, JSValueConst *argv, int magic)
38536
0
{
38537
0
    JSValueConst val;
38538
38539
0
    val = argv[0];
38540
0
    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) {
38541
        /* ES6 feature non compatible with ES5.1: primitive types are
38542
           accepted */
38543
0
        if (magic || JS_VALUE_GET_TAG(val) == JS_TAG_NULL ||
38544
0
            JS_VALUE_GET_TAG(val) == JS_TAG_UNDEFINED)
38545
0
            return JS_ThrowTypeErrorNotAnObject(ctx);
38546
0
    }
38547
0
    return JS_GetPrototype(ctx, val);
38548
0
}
38549
38550
static JSValue js_object_setPrototypeOf(JSContext *ctx, JSValueConst this_val,
38551
                                        int argc, JSValueConst *argv)
38552
0
{
38553
0
    JSValueConst obj;
38554
0
    obj = argv[0];
38555
0
    if (JS_SetPrototypeInternal(ctx, obj, argv[1], TRUE) < 0)
38556
0
        return JS_EXCEPTION;
38557
0
    return JS_DupValue(ctx, obj);
38558
0
}
38559
38560
/* magic = 1 if called as Reflect.defineProperty */
38561
static JSValue js_object_defineProperty(JSContext *ctx, JSValueConst this_val,
38562
                                        int argc, JSValueConst *argv, int magic)
38563
0
{
38564
0
    JSValueConst obj, prop, desc;
38565
0
    int ret, flags;
38566
0
    JSAtom atom;
38567
38568
0
    obj = argv[0];
38569
0
    prop = argv[1];
38570
0
    desc = argv[2];
38571
38572
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
38573
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
38574
0
    atom = JS_ValueToAtom(ctx, prop);
38575
0
    if (unlikely(atom == JS_ATOM_NULL))
38576
0
        return JS_EXCEPTION;
38577
0
    flags = 0;
38578
0
    if (!magic)
38579
0
        flags |= JS_PROP_THROW;
38580
0
    ret = JS_DefinePropertyDesc(ctx, obj, atom, desc, flags);
38581
0
    JS_FreeAtom(ctx, atom);
38582
0
    if (ret < 0) {
38583
0
        return JS_EXCEPTION;
38584
0
    } else if (magic) {
38585
0
        return JS_NewBool(ctx, ret);
38586
0
    } else {
38587
0
        return JS_DupValue(ctx, obj);
38588
0
    }
38589
0
}
38590
38591
static JSValue js_object_defineProperties(JSContext *ctx, JSValueConst this_val,
38592
                                          int argc, JSValueConst *argv)
38593
0
{
38594
    // defineProperties(obj, properties)
38595
0
    JSValueConst obj = argv[0];
38596
38597
0
    if (JS_ObjectDefineProperties(ctx, obj, argv[1]))
38598
0
        return JS_EXCEPTION;
38599
0
    else
38600
0
        return JS_DupValue(ctx, obj);
38601
0
}
38602
38603
/* magic = 1 if called as __defineSetter__ */
38604
static JSValue js_object___defineGetter__(JSContext *ctx, JSValueConst this_val,
38605
                                          int argc, JSValueConst *argv, int magic)
38606
0
{
38607
0
    JSValue obj;
38608
0
    JSValueConst prop, value, get, set;
38609
0
    int ret, flags;
38610
0
    JSAtom atom;
38611
38612
0
    prop = argv[0];
38613
0
    value = argv[1];
38614
38615
0
    obj = JS_ToObject(ctx, this_val);
38616
0
    if (JS_IsException(obj))
38617
0
        return JS_EXCEPTION;
38618
38619
0
    if (check_function(ctx, value)) {
38620
0
        JS_FreeValue(ctx, obj);
38621
0
        return JS_EXCEPTION;
38622
0
    }
38623
0
    atom = JS_ValueToAtom(ctx, prop);
38624
0
    if (unlikely(atom == JS_ATOM_NULL)) {
38625
0
        JS_FreeValue(ctx, obj);
38626
0
        return JS_EXCEPTION;
38627
0
    }
38628
0
    flags = JS_PROP_THROW |
38629
0
        JS_PROP_HAS_ENUMERABLE | JS_PROP_ENUMERABLE |
38630
0
        JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE;
38631
0
    if (magic) {
38632
0
        get = JS_UNDEFINED;
38633
0
        set = value;
38634
0
        flags |= JS_PROP_HAS_SET;
38635
0
    } else {
38636
0
        get = value;
38637
0
        set = JS_UNDEFINED;
38638
0
        flags |= JS_PROP_HAS_GET;
38639
0
    }
38640
0
    ret = JS_DefineProperty(ctx, obj, atom, JS_UNDEFINED, get, set, flags);
38641
0
    JS_FreeValue(ctx, obj);
38642
0
    JS_FreeAtom(ctx, atom);
38643
0
    if (ret < 0) {
38644
0
        return JS_EXCEPTION;
38645
0
    } else {
38646
0
        return JS_UNDEFINED;
38647
0
    }
38648
0
}
38649
38650
static JSValue js_object_getOwnPropertyDescriptor(JSContext *ctx, JSValueConst this_val,
38651
                                                  int argc, JSValueConst *argv, int magic)
38652
0
{
38653
0
    JSValueConst prop;
38654
0
    JSAtom atom;
38655
0
    JSValue ret, obj;
38656
0
    JSPropertyDescriptor desc;
38657
0
    int res, flags;
38658
38659
0
    if (magic) {
38660
        /* Reflect.getOwnPropertyDescriptor case */
38661
0
        if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT)
38662
0
            return JS_ThrowTypeErrorNotAnObject(ctx);
38663
0
        obj = JS_DupValue(ctx, argv[0]);
38664
0
    } else {
38665
0
        obj = JS_ToObject(ctx, argv[0]);
38666
0
        if (JS_IsException(obj))
38667
0
            return obj;
38668
0
    }
38669
0
    prop = argv[1];
38670
0
    atom = JS_ValueToAtom(ctx, prop);
38671
0
    if (unlikely(atom == JS_ATOM_NULL))
38672
0
        goto exception;
38673
0
    ret = JS_UNDEFINED;
38674
0
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
38675
0
        res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), atom);
38676
0
        if (res < 0)
38677
0
            goto exception;
38678
0
        if (res) {
38679
0
            ret = JS_NewObject(ctx);
38680
0
            if (JS_IsException(ret))
38681
0
                goto exception1;
38682
0
            flags = JS_PROP_C_W_E | JS_PROP_THROW;
38683
0
            if (desc.flags & JS_PROP_GETSET) {
38684
0
                if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, desc.getter), flags) < 0
38685
0
                ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, desc.setter), flags) < 0)
38686
0
                    goto exception1;
38687
0
            } else {
38688
0
                if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, desc.value), flags) < 0
38689
0
                ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,
38690
0
                                           JS_NewBool(ctx, desc.flags & JS_PROP_WRITABLE), flags) < 0)
38691
0
                    goto exception1;
38692
0
            }
38693
0
            if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,
38694
0
                                       JS_NewBool(ctx, desc.flags & JS_PROP_ENUMERABLE), flags) < 0
38695
0
            ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
38696
0
                                       JS_NewBool(ctx, desc.flags & JS_PROP_CONFIGURABLE), flags) < 0)
38697
0
                goto exception1;
38698
0
            js_free_desc(ctx, &desc);
38699
0
        }
38700
0
    }
38701
0
    JS_FreeAtom(ctx, atom);
38702
0
    JS_FreeValue(ctx, obj);
38703
0
    return ret;
38704
38705
0
exception1:
38706
0
    js_free_desc(ctx, &desc);
38707
0
    JS_FreeValue(ctx, ret);
38708
0
exception:
38709
0
    JS_FreeAtom(ctx, atom);
38710
0
    JS_FreeValue(ctx, obj);
38711
0
    return JS_EXCEPTION;
38712
0
}
38713
38714
static JSValue js_object_getOwnPropertyDescriptors(JSContext *ctx, JSValueConst this_val,
38715
                                                   int argc, JSValueConst *argv)
38716
0
{
38717
    //getOwnPropertyDescriptors(obj)
38718
0
    JSValue obj, r;
38719
0
    JSObject *p;
38720
0
    JSPropertyEnum *props;
38721
0
    uint32_t len, i;
38722
38723
0
    r = JS_UNDEFINED;
38724
0
    obj = JS_ToObject(ctx, argv[0]);
38725
0
    if (JS_IsException(obj))
38726
0
        return JS_EXCEPTION;
38727
38728
0
    p = JS_VALUE_GET_OBJ(obj);
38729
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p,
38730
0
                               JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK))
38731
0
        goto exception;
38732
0
    r = JS_NewObject(ctx);
38733
0
    if (JS_IsException(r))
38734
0
        goto exception;
38735
0
    for(i = 0; i < len; i++) {
38736
0
        JSValue atomValue, desc;
38737
0
        JSValueConst args[2];
38738
38739
0
        atomValue = JS_AtomToValue(ctx, props[i].atom);
38740
0
        if (JS_IsException(atomValue))
38741
0
            goto exception;
38742
0
        args[0] = obj;
38743
0
        args[1] = atomValue;
38744
0
        desc = js_object_getOwnPropertyDescriptor(ctx, JS_UNDEFINED, 2, args, 0);
38745
0
        JS_FreeValue(ctx, atomValue);
38746
0
        if (JS_IsException(desc))
38747
0
            goto exception;
38748
0
        if (!JS_IsUndefined(desc)) {
38749
0
            if (JS_DefinePropertyValue(ctx, r, props[i].atom, desc,
38750
0
                                       JS_PROP_C_W_E | JS_PROP_THROW) < 0)
38751
0
                goto exception;
38752
0
        }
38753
0
    }
38754
0
    JS_FreePropertyEnum(ctx, props, len);
38755
0
    JS_FreeValue(ctx, obj);
38756
0
    return r;
38757
38758
0
exception:
38759
0
    JS_FreePropertyEnum(ctx, props, len);
38760
0
    JS_FreeValue(ctx, obj);
38761
0
    JS_FreeValue(ctx, r);
38762
0
    return JS_EXCEPTION;
38763
0
}
38764
38765
static JSValue JS_GetOwnPropertyNames2(JSContext *ctx, JSValueConst obj1,
38766
                                       int flags, int kind)
38767
0
{
38768
0
    JSValue obj, r, val, key, value;
38769
0
    JSObject *p;
38770
0
    JSPropertyEnum *atoms;
38771
0
    uint32_t len, i, j;
38772
38773
0
    r = JS_UNDEFINED;
38774
0
    val = JS_UNDEFINED;
38775
0
    obj = JS_ToObject(ctx, obj1);
38776
0
    if (JS_IsException(obj))
38777
0
        return JS_EXCEPTION;
38778
0
    p = JS_VALUE_GET_OBJ(obj);
38779
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, flags & ~JS_GPN_ENUM_ONLY))
38780
0
        goto exception;
38781
0
    r = JS_NewArray(ctx);
38782
0
    if (JS_IsException(r))
38783
0
        goto exception;
38784
0
    for(j = i = 0; i < len; i++) {
38785
0
        JSAtom atom = atoms[i].atom;
38786
0
        if (flags & JS_GPN_ENUM_ONLY) {
38787
0
            JSPropertyDescriptor desc;
38788
0
            int res;
38789
38790
            /* Check if property is still enumerable */
38791
0
            res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
38792
0
            if (res < 0)
38793
0
                goto exception;
38794
0
            if (!res)
38795
0
                continue;
38796
0
            js_free_desc(ctx, &desc);
38797
0
            if (!(desc.flags & JS_PROP_ENUMERABLE))
38798
0
                continue;
38799
0
        }
38800
0
        switch(kind) {
38801
0
        default:
38802
0
        case JS_ITERATOR_KIND_KEY:
38803
0
            val = JS_AtomToValue(ctx, atom);
38804
0
            if (JS_IsException(val))
38805
0
                goto exception;
38806
0
            break;
38807
0
        case JS_ITERATOR_KIND_VALUE:
38808
0
            val = JS_GetProperty(ctx, obj, atom);
38809
0
            if (JS_IsException(val))
38810
0
                goto exception;
38811
0
            break;
38812
0
        case JS_ITERATOR_KIND_KEY_AND_VALUE:
38813
0
            val = JS_NewArray(ctx);
38814
0
            if (JS_IsException(val))
38815
0
                goto exception;
38816
0
            key = JS_AtomToValue(ctx, atom);
38817
0
            if (JS_IsException(key))
38818
0
                goto exception1;
38819
0
            if (JS_CreateDataPropertyUint32(ctx, val, 0, key, JS_PROP_THROW) < 0)
38820
0
                goto exception1;
38821
0
            value = JS_GetProperty(ctx, obj, atom);
38822
0
            if (JS_IsException(value))
38823
0
                goto exception1;
38824
0
            if (JS_CreateDataPropertyUint32(ctx, val, 1, value, JS_PROP_THROW) < 0)
38825
0
                goto exception1;
38826
0
            break;
38827
0
        }
38828
0
        if (JS_CreateDataPropertyUint32(ctx, r, j++, val, 0) < 0)
38829
0
            goto exception;
38830
0
    }
38831
0
    goto done;
38832
38833
0
exception1:
38834
0
    JS_FreeValue(ctx, val);
38835
0
exception:
38836
0
    JS_FreeValue(ctx, r);
38837
0
    r = JS_EXCEPTION;
38838
0
done:
38839
0
    JS_FreePropertyEnum(ctx, atoms, len);
38840
0
    JS_FreeValue(ctx, obj);
38841
0
    return r;
38842
0
}
38843
38844
static JSValue js_object_getOwnPropertyNames(JSContext *ctx, JSValueConst this_val,
38845
                                             int argc, JSValueConst *argv)
38846
0
{
38847
0
    return JS_GetOwnPropertyNames2(ctx, argv[0],
38848
0
                                   JS_GPN_STRING_MASK, JS_ITERATOR_KIND_KEY);
38849
0
}
38850
38851
static JSValue js_object_getOwnPropertySymbols(JSContext *ctx, JSValueConst this_val,
38852
                                             int argc, JSValueConst *argv)
38853
0
{
38854
0
    return JS_GetOwnPropertyNames2(ctx, argv[0],
38855
0
                                   JS_GPN_SYMBOL_MASK, JS_ITERATOR_KIND_KEY);
38856
0
}
38857
38858
static JSValue js_object_keys(JSContext *ctx, JSValueConst this_val,
38859
                              int argc, JSValueConst *argv, int kind)
38860
0
{
38861
0
    return JS_GetOwnPropertyNames2(ctx, argv[0],
38862
0
                                   JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK, kind);
38863
0
}
38864
38865
static JSValue js_object_isExtensible(JSContext *ctx, JSValueConst this_val,
38866
                                      int argc, JSValueConst *argv, int reflect)
38867
0
{
38868
0
    JSValueConst obj;
38869
0
    int ret;
38870
38871
0
    obj = argv[0];
38872
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
38873
0
        if (reflect)
38874
0
            return JS_ThrowTypeErrorNotAnObject(ctx);
38875
0
        else
38876
0
            return JS_FALSE;
38877
0
    }
38878
0
    ret = JS_IsExtensible(ctx, obj);
38879
0
    if (ret < 0)
38880
0
        return JS_EXCEPTION;
38881
0
    else
38882
0
        return JS_NewBool(ctx, ret);
38883
0
}
38884
38885
static JSValue js_object_preventExtensions(JSContext *ctx, JSValueConst this_val,
38886
                                           int argc, JSValueConst *argv, int reflect)
38887
0
{
38888
0
    JSValueConst obj;
38889
0
    int ret;
38890
38891
0
    obj = argv[0];
38892
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {
38893
0
        if (reflect)
38894
0
            return JS_ThrowTypeErrorNotAnObject(ctx);
38895
0
        else
38896
0
            return JS_DupValue(ctx, obj);
38897
0
    }
38898
0
    ret = JS_PreventExtensions(ctx, obj);
38899
0
    if (ret < 0)
38900
0
        return JS_EXCEPTION;
38901
0
    if (reflect) {
38902
0
        return JS_NewBool(ctx, ret);
38903
0
    } else {
38904
0
        if (!ret)
38905
0
            return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
38906
0
        return JS_DupValue(ctx, obj);
38907
0
    }
38908
0
}
38909
38910
static JSValue js_object_hasOwnProperty(JSContext *ctx, JSValueConst this_val,
38911
                                        int argc, JSValueConst *argv)
38912
0
{
38913
0
    JSValue obj;
38914
0
    JSAtom atom;
38915
0
    JSObject *p;
38916
0
    BOOL ret;
38917
38918
0
    atom = JS_ValueToAtom(ctx, argv[0]); /* must be done first */
38919
0
    if (unlikely(atom == JS_ATOM_NULL))
38920
0
        return JS_EXCEPTION;
38921
0
    obj = JS_ToObject(ctx, this_val);
38922
0
    if (JS_IsException(obj)) {
38923
0
        JS_FreeAtom(ctx, atom);
38924
0
        return obj;
38925
0
    }
38926
0
    p = JS_VALUE_GET_OBJ(obj);
38927
0
    ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);
38928
0
    JS_FreeAtom(ctx, atom);
38929
0
    JS_FreeValue(ctx, obj);
38930
0
    if (ret < 0)
38931
0
        return JS_EXCEPTION;
38932
0
    else
38933
0
        return JS_NewBool(ctx, ret);
38934
0
}
38935
38936
static JSValue js_object_hasOwn(JSContext *ctx, JSValueConst this_val,
38937
                                int argc, JSValueConst *argv)
38938
0
{
38939
0
    JSValue obj;
38940
0
    JSAtom atom;
38941
0
    JSObject *p;
38942
0
    BOOL ret;
38943
38944
0
    obj = JS_ToObject(ctx, argv[0]);
38945
0
    if (JS_IsException(obj))
38946
0
        return obj;
38947
0
    atom = JS_ValueToAtom(ctx, argv[1]);
38948
0
    if (unlikely(atom == JS_ATOM_NULL)) {
38949
0
        JS_FreeValue(ctx, obj);
38950
0
        return JS_EXCEPTION;
38951
0
    }
38952
0
    p = JS_VALUE_GET_OBJ(obj);
38953
0
    ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);
38954
0
    JS_FreeAtom(ctx, atom);
38955
0
    JS_FreeValue(ctx, obj);
38956
0
    if (ret < 0)
38957
0
        return JS_EXCEPTION;
38958
0
    else
38959
0
        return JS_NewBool(ctx, ret);
38960
0
}
38961
38962
static JSValue js_object_valueOf(JSContext *ctx, JSValueConst this_val,
38963
                                 int argc, JSValueConst *argv)
38964
0
{
38965
0
    return JS_ToObject(ctx, this_val);
38966
0
}
38967
38968
static JSValue js_object_toString(JSContext *ctx, JSValueConst this_val,
38969
                                  int argc, JSValueConst *argv)
38970
0
{
38971
0
    JSValue obj, tag;
38972
0
    int is_array;
38973
0
    JSAtom atom;
38974
0
    JSObject *p;
38975
38976
0
    if (JS_IsNull(this_val)) {
38977
0
        tag = js_new_string8(ctx, "Null");
38978
0
    } else if (JS_IsUndefined(this_val)) {
38979
0
        tag = js_new_string8(ctx, "Undefined");
38980
0
    } else {
38981
0
        obj = JS_ToObject(ctx, this_val);
38982
0
        if (JS_IsException(obj))
38983
0
            return obj;
38984
0
        is_array = JS_IsArray(ctx, obj);
38985
0
        if (is_array < 0) {
38986
0
            JS_FreeValue(ctx, obj);
38987
0
            return JS_EXCEPTION;
38988
0
        }
38989
0
        if (is_array) {
38990
0
            atom = JS_ATOM_Array;
38991
0
        } else if (JS_IsFunction(ctx, obj)) {
38992
0
            atom = JS_ATOM_Function;
38993
0
        } else {
38994
0
            p = JS_VALUE_GET_OBJ(obj);
38995
0
            switch(p->class_id) {
38996
0
            case JS_CLASS_STRING:
38997
0
            case JS_CLASS_ARGUMENTS:
38998
0
            case JS_CLASS_MAPPED_ARGUMENTS:
38999
0
            case JS_CLASS_ERROR:
39000
0
            case JS_CLASS_BOOLEAN:
39001
0
            case JS_CLASS_NUMBER:
39002
0
            case JS_CLASS_DATE:
39003
0
            case JS_CLASS_REGEXP:
39004
0
                atom = ctx->rt->class_array[p->class_id].class_name;
39005
0
                break;
39006
0
            default:
39007
0
                atom = JS_ATOM_Object;
39008
0
                break;
39009
0
            }
39010
0
        }
39011
0
        tag = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_toStringTag);
39012
0
        JS_FreeValue(ctx, obj);
39013
0
        if (JS_IsException(tag))
39014
0
            return JS_EXCEPTION;
39015
0
        if (!JS_IsString(tag)) {
39016
0
            JS_FreeValue(ctx, tag);
39017
0
            tag = JS_AtomToString(ctx, atom);
39018
0
        }
39019
0
    }
39020
0
    return JS_ConcatString3(ctx, "[object ", tag, "]");
39021
0
}
39022
39023
static JSValue js_object_toLocaleString(JSContext *ctx, JSValueConst this_val,
39024
                                        int argc, JSValueConst *argv)
39025
0
{
39026
0
    return JS_Invoke(ctx, this_val, JS_ATOM_toString, 0, NULL);
39027
0
}
39028
39029
static JSValue js_object_assign(JSContext *ctx, JSValueConst this_val,
39030
                                int argc, JSValueConst *argv)
39031
0
{
39032
    // Object.assign(obj, source1)
39033
0
    JSValue obj, s;
39034
0
    int i;
39035
39036
0
    s = JS_UNDEFINED;
39037
0
    obj = JS_ToObject(ctx, argv[0]);
39038
0
    if (JS_IsException(obj))
39039
0
        goto exception;
39040
0
    for (i = 1; i < argc; i++) {
39041
0
        if (!JS_IsNull(argv[i]) && !JS_IsUndefined(argv[i])) {
39042
0
            s = JS_ToObject(ctx, argv[i]);
39043
0
            if (JS_IsException(s))
39044
0
                goto exception;
39045
0
            if (JS_CopyDataProperties(ctx, obj, s, JS_UNDEFINED, TRUE))
39046
0
                goto exception;
39047
0
            JS_FreeValue(ctx, s);
39048
0
        }
39049
0
    }
39050
0
    return obj;
39051
0
exception:
39052
0
    JS_FreeValue(ctx, obj);
39053
0
    JS_FreeValue(ctx, s);
39054
0
    return JS_EXCEPTION;
39055
0
}
39056
39057
static JSValue js_object_seal(JSContext *ctx, JSValueConst this_val,
39058
                              int argc, JSValueConst *argv, int freeze_flag)
39059
2
{
39060
2
    JSValueConst obj = argv[0];
39061
2
    JSObject *p;
39062
2
    JSPropertyEnum *props;
39063
2
    uint32_t len, i;
39064
2
    int flags, desc_flags, res;
39065
39066
2
    if (!JS_IsObject(obj))
39067
0
        return JS_DupValue(ctx, obj);
39068
39069
2
    res = JS_PreventExtensions(ctx, obj);
39070
2
    if (res < 0)
39071
0
        return JS_EXCEPTION;
39072
2
    if (!res) {
39073
0
        return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
39074
0
    }
39075
39076
2
    p = JS_VALUE_GET_OBJ(obj);
39077
2
    flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK;
39078
2
    if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags))
39079
0
        return JS_EXCEPTION;
39080
39081
6
    for(i = 0; i < len; i++) {
39082
4
        JSPropertyDescriptor desc;
39083
4
        JSAtom prop = props[i].atom;
39084
39085
4
        desc_flags = JS_PROP_THROW | JS_PROP_HAS_CONFIGURABLE;
39086
4
        if (freeze_flag) {
39087
4
            res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
39088
4
            if (res < 0)
39089
0
                goto exception;
39090
4
            if (res) {
39091
4
                if (desc.flags & JS_PROP_WRITABLE)
39092
0
                    desc_flags |= JS_PROP_HAS_WRITABLE;
39093
4
                js_free_desc(ctx, &desc);
39094
4
            }
39095
4
        }
39096
4
        if (JS_DefineProperty(ctx, obj, prop, JS_UNDEFINED,
39097
4
                              JS_UNDEFINED, JS_UNDEFINED, desc_flags) < 0)
39098
0
            goto exception;
39099
4
    }
39100
2
    JS_FreePropertyEnum(ctx, props, len);
39101
2
    return JS_DupValue(ctx, obj);
39102
39103
0
 exception:
39104
0
    JS_FreePropertyEnum(ctx, props, len);
39105
0
    return JS_EXCEPTION;
39106
2
}
39107
39108
static JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val,
39109
                                  int argc, JSValueConst *argv, int is_frozen)
39110
0
{
39111
0
    JSValueConst obj = argv[0];
39112
0
    JSObject *p;
39113
0
    JSPropertyEnum *props;
39114
0
    uint32_t len, i;
39115
0
    int flags, res;
39116
39117
0
    if (!JS_IsObject(obj))
39118
0
        return JS_TRUE;
39119
39120
0
    p = JS_VALUE_GET_OBJ(obj);
39121
0
    flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK;
39122
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags))
39123
0
        return JS_EXCEPTION;
39124
39125
0
    for(i = 0; i < len; i++) {
39126
0
        JSPropertyDescriptor desc;
39127
0
        JSAtom prop = props[i].atom;
39128
39129
0
        res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
39130
0
        if (res < 0)
39131
0
            goto exception;
39132
0
        if (res) {
39133
0
            js_free_desc(ctx, &desc);
39134
0
            if ((desc.flags & JS_PROP_CONFIGURABLE)
39135
0
            ||  (is_frozen && (desc.flags & JS_PROP_WRITABLE))) {
39136
0
                res = FALSE;
39137
0
                goto done;
39138
0
            }
39139
0
        }
39140
0
    }
39141
0
    res = JS_IsExtensible(ctx, obj);
39142
0
    if (res < 0)
39143
0
        return JS_EXCEPTION;
39144
0
    res ^= 1;
39145
0
done:
39146
0
    JS_FreePropertyEnum(ctx, props, len);
39147
0
    return JS_NewBool(ctx, res);
39148
39149
0
exception:
39150
0
    JS_FreePropertyEnum(ctx, props, len);
39151
0
    return JS_EXCEPTION;
39152
0
}
39153
39154
static JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val,
39155
                                     int argc, JSValueConst *argv)
39156
0
{
39157
0
    JSValue obj, iter, next_method = JS_UNDEFINED;
39158
0
    JSValueConst iterable;
39159
0
    BOOL done;
39160
39161
    /*  RequireObjectCoercible() not necessary because it is tested in
39162
        JS_GetIterator() by JS_GetProperty() */
39163
0
    iterable = argv[0];
39164
39165
0
    obj = JS_NewObject(ctx);
39166
0
    if (JS_IsException(obj))
39167
0
        return obj;
39168
39169
0
    iter = JS_GetIterator(ctx, iterable, FALSE);
39170
0
    if (JS_IsException(iter))
39171
0
        goto fail;
39172
0
    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
39173
0
    if (JS_IsException(next_method))
39174
0
        goto fail;
39175
39176
0
    for(;;) {
39177
0
        JSValue key, value, item;
39178
0
        item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
39179
0
        if (JS_IsException(item))
39180
0
            goto fail;
39181
0
        if (done)
39182
0
            break;
39183
39184
0
        key = JS_UNDEFINED;
39185
0
        value = JS_UNDEFINED;
39186
0
        if (!JS_IsObject(item)) {
39187
0
            JS_ThrowTypeErrorNotAnObject(ctx);
39188
0
            goto fail1;
39189
0
        }
39190
0
        key = JS_GetPropertyUint32(ctx, item, 0);
39191
0
        if (JS_IsException(key))
39192
0
            goto fail1;
39193
0
        value = JS_GetPropertyUint32(ctx, item, 1);
39194
0
        if (JS_IsException(value)) {
39195
0
            JS_FreeValue(ctx, key);
39196
0
            goto fail1;
39197
0
        }
39198
0
        if (JS_DefinePropertyValueValue(ctx, obj, key, value,
39199
0
                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0) {
39200
0
        fail1:
39201
0
            JS_FreeValue(ctx, item);
39202
0
            goto fail;
39203
0
        }
39204
0
        JS_FreeValue(ctx, item);
39205
0
    }
39206
0
    JS_FreeValue(ctx, next_method);
39207
0
    JS_FreeValue(ctx, iter);
39208
0
    return obj;
39209
0
 fail:
39210
0
    if (JS_IsObject(iter)) {
39211
        /* close the iterator object, preserving pending exception */
39212
0
        JS_IteratorClose(ctx, iter, TRUE);
39213
0
    }
39214
0
    JS_FreeValue(ctx, next_method);
39215
0
    JS_FreeValue(ctx, iter);
39216
0
    JS_FreeValue(ctx, obj);
39217
0
    return JS_EXCEPTION;
39218
0
}
39219
39220
#if 0
39221
/* Note: corresponds to ECMA spec: CreateDataPropertyOrThrow() */
39222
static JSValue js_object___setOwnProperty(JSContext *ctx, JSValueConst this_val,
39223
                                          int argc, JSValueConst *argv)
39224
{
39225
    int ret;
39226
    ret = JS_DefinePropertyValueValue(ctx, argv[0], JS_DupValue(ctx, argv[1]),
39227
                                      JS_DupValue(ctx, argv[2]),
39228
                                      JS_PROP_C_W_E | JS_PROP_THROW);
39229
    if (ret < 0)
39230
        return JS_EXCEPTION;
39231
    else
39232
        return JS_NewBool(ctx, ret);
39233
}
39234
39235
static JSValue js_object___toObject(JSContext *ctx, JSValueConst this_val,
39236
                                    int argc, JSValueConst *argv)
39237
{
39238
    return JS_ToObject(ctx, argv[0]);
39239
}
39240
39241
static JSValue js_object___toPrimitive(JSContext *ctx, JSValueConst this_val,
39242
                                       int argc, JSValueConst *argv)
39243
{
39244
    int hint = HINT_NONE;
39245
39246
    if (JS_VALUE_GET_TAG(argv[1]) == JS_TAG_INT)
39247
        hint = JS_VALUE_GET_INT(argv[1]);
39248
39249
    return JS_ToPrimitive(ctx, argv[0], hint);
39250
}
39251
#endif
39252
39253
/* return an empty string if not an object */
39254
static JSValue js_object___getClass(JSContext *ctx, JSValueConst this_val,
39255
                                    int argc, JSValueConst *argv)
39256
0
{
39257
0
    JSAtom atom;
39258
0
    JSObject *p;
39259
0
    uint32_t tag;
39260
0
    int class_id;
39261
39262
0
    tag = JS_VALUE_GET_NORM_TAG(argv[0]);
39263
0
    if (tag == JS_TAG_OBJECT) {
39264
0
        p = JS_VALUE_GET_OBJ(argv[0]);
39265
0
        class_id = p->class_id;
39266
0
        if (class_id == JS_CLASS_PROXY && JS_IsFunction(ctx, argv[0]))
39267
0
            class_id = JS_CLASS_BYTECODE_FUNCTION;
39268
0
        atom = ctx->rt->class_array[class_id].class_name;
39269
0
    } else {
39270
0
        atom = JS_ATOM_empty_string;
39271
0
    }
39272
0
    return JS_AtomToString(ctx, atom);
39273
0
}
39274
39275
static JSValue js_object_is(JSContext *ctx, JSValueConst this_val,
39276
                            int argc, JSValueConst *argv)
39277
0
{
39278
0
    return JS_NewBool(ctx, js_same_value(ctx, argv[0], argv[1]));
39279
0
}
39280
39281
#if 0
39282
static JSValue js_object___getObjectData(JSContext *ctx, JSValueConst this_val,
39283
                                         int argc, JSValueConst *argv)
39284
{
39285
    return JS_GetObjectData(ctx, argv[0]);
39286
}
39287
39288
static JSValue js_object___setObjectData(JSContext *ctx, JSValueConst this_val,
39289
                                         int argc, JSValueConst *argv)
39290
{
39291
    if (JS_SetObjectData(ctx, argv[0], JS_DupValue(ctx, argv[1])))
39292
        return JS_EXCEPTION;
39293
    return JS_DupValue(ctx, argv[1]);
39294
}
39295
39296
static JSValue js_object___toPropertyKey(JSContext *ctx, JSValueConst this_val,
39297
                                         int argc, JSValueConst *argv)
39298
{
39299
    return JS_ToPropertyKey(ctx, argv[0]);
39300
}
39301
39302
static JSValue js_object___isObject(JSContext *ctx, JSValueConst this_val,
39303
                                    int argc, JSValueConst *argv)
39304
{
39305
    return JS_NewBool(ctx, JS_IsObject(argv[0]));
39306
}
39307
39308
static JSValue js_object___isSameValueZero(JSContext *ctx, JSValueConst this_val,
39309
                                           int argc, JSValueConst *argv)
39310
{
39311
    return JS_NewBool(ctx, js_same_value_zero(ctx, argv[0], argv[1]));
39312
}
39313
39314
static JSValue js_object___isConstructor(JSContext *ctx, JSValueConst this_val,
39315
                                         int argc, JSValueConst *argv)
39316
{
39317
    return JS_NewBool(ctx, JS_IsConstructor(ctx, argv[0]));
39318
}
39319
#endif
39320
39321
static JSValue JS_SpeciesConstructor(JSContext *ctx, JSValueConst obj,
39322
                                     JSValueConst defaultConstructor)
39323
0
{
39324
0
    JSValue ctor, species;
39325
39326
0
    if (!JS_IsObject(obj))
39327
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
39328
0
    ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);
39329
0
    if (JS_IsException(ctor))
39330
0
        return ctor;
39331
0
    if (JS_IsUndefined(ctor))
39332
0
        return JS_DupValue(ctx, defaultConstructor);
39333
0
    if (!JS_IsObject(ctor)) {
39334
0
        JS_FreeValue(ctx, ctor);
39335
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
39336
0
    }
39337
0
    species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species);
39338
0
    JS_FreeValue(ctx, ctor);
39339
0
    if (JS_IsException(species))
39340
0
        return species;
39341
0
    if (JS_IsUndefined(species) || JS_IsNull(species))
39342
0
        return JS_DupValue(ctx, defaultConstructor);
39343
0
    if (!JS_IsConstructor(ctx, species)) {
39344
0
        JS_FreeValue(ctx, species);
39345
0
        return JS_ThrowTypeError(ctx, "not a constructor");
39346
0
    }
39347
0
    return species;
39348
0
}
39349
39350
#if 0
39351
static JSValue js_object___speciesConstructor(JSContext *ctx, JSValueConst this_val,
39352
                                              int argc, JSValueConst *argv)
39353
{
39354
    return JS_SpeciesConstructor(ctx, argv[0], argv[1]);
39355
}
39356
#endif
39357
39358
static JSValue js_object_get___proto__(JSContext *ctx, JSValueConst this_val)
39359
0
{
39360
0
    JSValue val, ret;
39361
39362
0
    val = JS_ToObject(ctx, this_val);
39363
0
    if (JS_IsException(val))
39364
0
        return val;
39365
0
    ret = JS_GetPrototype(ctx, val);
39366
0
    JS_FreeValue(ctx, val);
39367
0
    return ret;
39368
0
}
39369
39370
static JSValue js_object_set___proto__(JSContext *ctx, JSValueConst this_val,
39371
                                       JSValueConst proto)
39372
0
{
39373
0
    if (JS_IsUndefined(this_val) || JS_IsNull(this_val))
39374
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
39375
0
    if (!JS_IsObject(proto) && !JS_IsNull(proto))
39376
0
        return JS_UNDEFINED;
39377
0
    if (JS_SetPrototypeInternal(ctx, this_val, proto, TRUE) < 0)
39378
0
        return JS_EXCEPTION;
39379
0
    else
39380
0
        return JS_UNDEFINED;
39381
0
}
39382
39383
static JSValue js_object_isPrototypeOf(JSContext *ctx, JSValueConst this_val,
39384
                                       int argc, JSValueConst *argv)
39385
0
{
39386
0
    JSValue obj, v1;
39387
0
    JSValueConst v;
39388
0
    int res;
39389
39390
0
    v = argv[0];
39391
0
    if (!JS_IsObject(v))
39392
0
        return JS_FALSE;
39393
0
    obj = JS_ToObject(ctx, this_val);
39394
0
    if (JS_IsException(obj))
39395
0
        return JS_EXCEPTION;
39396
0
    v1 = JS_DupValue(ctx, v);
39397
0
    for(;;) {
39398
0
        v1 = JS_GetPrototypeFree(ctx, v1);
39399
0
        if (JS_IsException(v1))
39400
0
            goto exception;
39401
0
        if (JS_IsNull(v1)) {
39402
0
            res = FALSE;
39403
0
            break;
39404
0
        }
39405
0
        if (JS_VALUE_GET_OBJ(obj) == JS_VALUE_GET_OBJ(v1)) {
39406
0
            res = TRUE;
39407
0
            break;
39408
0
        }
39409
        /* avoid infinite loop (possible with proxies) */
39410
0
        if (js_poll_interrupts(ctx))
39411
0
            goto exception;
39412
0
    }
39413
0
    JS_FreeValue(ctx, v1);
39414
0
    JS_FreeValue(ctx, obj);
39415
0
    return JS_NewBool(ctx, res);
39416
39417
0
exception:
39418
0
    JS_FreeValue(ctx, v1);
39419
0
    JS_FreeValue(ctx, obj);
39420
0
    return JS_EXCEPTION;
39421
0
}
39422
39423
static JSValue js_object_propertyIsEnumerable(JSContext *ctx, JSValueConst this_val,
39424
                                              int argc, JSValueConst *argv)
39425
0
{
39426
0
    JSValue obj = JS_UNDEFINED, res = JS_EXCEPTION;
39427
0
    JSAtom prop;
39428
0
    JSPropertyDescriptor desc;
39429
0
    int has_prop;
39430
39431
0
    prop = JS_ValueToAtom(ctx, argv[0]);
39432
0
    if (unlikely(prop == JS_ATOM_NULL))
39433
0
        goto exception;
39434
0
    obj = JS_ToObject(ctx, this_val);
39435
0
    if (JS_IsException(obj))
39436
0
        goto exception;
39437
39438
0
    has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);
39439
0
    if (has_prop < 0)
39440
0
        goto exception;
39441
0
    if (has_prop) {
39442
0
        res = JS_NewBool(ctx, desc.flags & JS_PROP_ENUMERABLE);
39443
0
        js_free_desc(ctx, &desc);
39444
0
    } else {
39445
0
        res = JS_FALSE;
39446
0
    }
39447
39448
0
exception:
39449
0
    JS_FreeAtom(ctx, prop);
39450
0
    JS_FreeValue(ctx, obj);
39451
0
    return res;
39452
0
}
39453
39454
static JSValue js_object___lookupGetter__(JSContext *ctx, JSValueConst this_val,
39455
                                          int argc, JSValueConst *argv, int setter)
39456
0
{
39457
0
    JSValue obj, res = JS_EXCEPTION;
39458
0
    JSAtom prop = JS_ATOM_NULL;
39459
0
    JSPropertyDescriptor desc;
39460
0
    int has_prop;
39461
39462
0
    obj = JS_ToObject(ctx, this_val);
39463
0
    if (JS_IsException(obj))
39464
0
        goto exception;
39465
0
    prop = JS_ValueToAtom(ctx, argv[0]);
39466
0
    if (unlikely(prop == JS_ATOM_NULL))
39467
0
        goto exception;
39468
39469
0
    for (;;) {
39470
0
        has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);
39471
0
        if (has_prop < 0)
39472
0
            goto exception;
39473
0
        if (has_prop) {
39474
0
            if (desc.flags & JS_PROP_GETSET)
39475
0
                res = JS_DupValue(ctx, setter ? desc.setter : desc.getter);
39476
0
            else
39477
0
                res = JS_UNDEFINED;
39478
0
            js_free_desc(ctx, &desc);
39479
0
            break;
39480
0
        }
39481
0
        obj = JS_GetPrototypeFree(ctx, obj);
39482
0
        if (JS_IsException(obj))
39483
0
            goto exception;
39484
0
        if (JS_IsNull(obj)) {
39485
0
            res = JS_UNDEFINED;
39486
0
            break;
39487
0
        }
39488
        /* avoid infinite loop (possible with proxies) */
39489
0
        if (js_poll_interrupts(ctx))
39490
0
            goto exception;
39491
0
    }
39492
39493
0
exception:
39494
0
    JS_FreeAtom(ctx, prop);
39495
0
    JS_FreeValue(ctx, obj);
39496
0
    return res;
39497
0
}
39498
39499
static const JSCFunctionListEntry js_object_funcs[] = {
39500
    JS_CFUNC_DEF("create", 2, js_object_create ),
39501
    JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 0 ),
39502
    JS_CFUNC_DEF("setPrototypeOf", 2, js_object_setPrototypeOf ),
39503
    JS_CFUNC_MAGIC_DEF("defineProperty", 3, js_object_defineProperty, 0 ),
39504
    JS_CFUNC_DEF("defineProperties", 2, js_object_defineProperties ),
39505
    JS_CFUNC_DEF("getOwnPropertyNames", 1, js_object_getOwnPropertyNames ),
39506
    JS_CFUNC_DEF("getOwnPropertySymbols", 1, js_object_getOwnPropertySymbols ),
39507
    JS_CFUNC_MAGIC_DEF("groupBy", 2, js_object_groupBy, 0 ),
39508
    JS_CFUNC_MAGIC_DEF("keys", 1, js_object_keys, JS_ITERATOR_KIND_KEY ),
39509
    JS_CFUNC_MAGIC_DEF("values", 1, js_object_keys, JS_ITERATOR_KIND_VALUE ),
39510
    JS_CFUNC_MAGIC_DEF("entries", 1, js_object_keys, JS_ITERATOR_KIND_KEY_AND_VALUE ),
39511
    JS_CFUNC_MAGIC_DEF("isExtensible", 1, js_object_isExtensible, 0 ),
39512
    JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 0 ),
39513
    JS_CFUNC_MAGIC_DEF("getOwnPropertyDescriptor", 2, js_object_getOwnPropertyDescriptor, 0 ),
39514
    JS_CFUNC_DEF("getOwnPropertyDescriptors", 1, js_object_getOwnPropertyDescriptors ),
39515
    JS_CFUNC_DEF("is", 2, js_object_is ),
39516
    JS_CFUNC_DEF("assign", 2, js_object_assign ),
39517
    JS_CFUNC_MAGIC_DEF("seal", 1, js_object_seal, 0 ),
39518
    JS_CFUNC_MAGIC_DEF("freeze", 1, js_object_seal, 1 ),
39519
    JS_CFUNC_MAGIC_DEF("isSealed", 1, js_object_isSealed, 0 ),
39520
    JS_CFUNC_MAGIC_DEF("isFrozen", 1, js_object_isSealed, 1 ),
39521
    JS_CFUNC_DEF("__getClass", 1, js_object___getClass ),
39522
    //JS_CFUNC_DEF("__isObject", 1, js_object___isObject ),
39523
    //JS_CFUNC_DEF("__isConstructor", 1, js_object___isConstructor ),
39524
    //JS_CFUNC_DEF("__toObject", 1, js_object___toObject ),
39525
    //JS_CFUNC_DEF("__setOwnProperty", 3, js_object___setOwnProperty ),
39526
    //JS_CFUNC_DEF("__toPrimitive", 2, js_object___toPrimitive ),
39527
    //JS_CFUNC_DEF("__toPropertyKey", 1, js_object___toPropertyKey ),
39528
    //JS_CFUNC_DEF("__speciesConstructor", 2, js_object___speciesConstructor ),
39529
    //JS_CFUNC_DEF("__isSameValueZero", 2, js_object___isSameValueZero ),
39530
    //JS_CFUNC_DEF("__getObjectData", 1, js_object___getObjectData ),
39531
    //JS_CFUNC_DEF("__setObjectData", 2, js_object___setObjectData ),
39532
    JS_CFUNC_DEF("fromEntries", 1, js_object_fromEntries ),
39533
    JS_CFUNC_DEF("hasOwn", 2, js_object_hasOwn ),
39534
};
39535
39536
static const JSCFunctionListEntry js_object_proto_funcs[] = {
39537
    JS_CFUNC_DEF("toString", 0, js_object_toString ),
39538
    JS_CFUNC_DEF("toLocaleString", 0, js_object_toLocaleString ),
39539
    JS_CFUNC_DEF("valueOf", 0, js_object_valueOf ),
39540
    JS_CFUNC_DEF("hasOwnProperty", 1, js_object_hasOwnProperty ),
39541
    JS_CFUNC_DEF("isPrototypeOf", 1, js_object_isPrototypeOf ),
39542
    JS_CFUNC_DEF("propertyIsEnumerable", 1, js_object_propertyIsEnumerable ),
39543
    JS_CGETSET_DEF("__proto__", js_object_get___proto__, js_object_set___proto__ ),
39544
    JS_CFUNC_MAGIC_DEF("__defineGetter__", 2, js_object___defineGetter__, 0 ),
39545
    JS_CFUNC_MAGIC_DEF("__defineSetter__", 2, js_object___defineGetter__, 1 ),
39546
    JS_CFUNC_MAGIC_DEF("__lookupGetter__", 1, js_object___lookupGetter__, 0 ),
39547
    JS_CFUNC_MAGIC_DEF("__lookupSetter__", 1, js_object___lookupGetter__, 1 ),
39548
};
39549
39550
/* Function class */
39551
39552
static JSValue js_function_proto(JSContext *ctx, JSValueConst this_val,
39553
                                 int argc, JSValueConst *argv)
39554
0
{
39555
0
    return JS_UNDEFINED;
39556
0
}
39557
39558
/* XXX: add a specific eval mode so that Function("}), ({") is rejected */
39559
static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target,
39560
                                       int argc, JSValueConst *argv, int magic)
39561
0
{
39562
0
    JSFunctionKindEnum func_kind = magic;
39563
0
    int i, n, ret;
39564
0
    JSValue s, proto, obj = JS_UNDEFINED;
39565
0
    StringBuffer b_s, *b = &b_s;
39566
39567
0
    string_buffer_init(ctx, b, 0);
39568
0
    string_buffer_putc8(b, '(');
39569
39570
0
    if (func_kind == JS_FUNC_ASYNC || func_kind == JS_FUNC_ASYNC_GENERATOR) {
39571
0
        string_buffer_puts8(b, "async ");
39572
0
    }
39573
0
    string_buffer_puts8(b, "function");
39574
39575
0
    if (func_kind == JS_FUNC_GENERATOR || func_kind == JS_FUNC_ASYNC_GENERATOR) {
39576
0
        string_buffer_putc8(b, '*');
39577
0
    }
39578
0
    string_buffer_puts8(b, " anonymous(");
39579
39580
0
    n = argc - 1;
39581
0
    for(i = 0; i < n; i++) {
39582
0
        if (i != 0) {
39583
0
            string_buffer_putc8(b, ',');
39584
0
        }
39585
0
        if (string_buffer_concat_value(b, argv[i]))
39586
0
            goto fail;
39587
0
    }
39588
0
    string_buffer_puts8(b, "\n) {\n");
39589
0
    if (n >= 0) {
39590
0
        if (string_buffer_concat_value(b, argv[n]))
39591
0
            goto fail;
39592
0
    }
39593
0
    string_buffer_puts8(b, "\n})");
39594
0
    s = string_buffer_end(b);
39595
0
    if (JS_IsException(s))
39596
0
        goto fail1;
39597
39598
0
    obj = JS_EvalObject(ctx, ctx->global_obj, s, JS_EVAL_TYPE_INDIRECT, -1);
39599
0
    JS_FreeValue(ctx, s);
39600
0
    if (JS_IsException(obj))
39601
0
        goto fail1;
39602
0
    if (!JS_IsUndefined(new_target)) {
39603
        /* set the prototype */
39604
0
        proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);
39605
0
        if (JS_IsException(proto))
39606
0
            goto fail1;
39607
0
        if (!JS_IsObject(proto)) {
39608
0
            JSContext *realm;
39609
0
            JS_FreeValue(ctx, proto);
39610
0
            realm = JS_GetFunctionRealm(ctx, new_target);
39611
0
            if (!realm)
39612
0
                goto fail1;
39613
0
            proto = JS_DupValue(ctx, realm->class_proto[func_kind_to_class_id[func_kind]]);
39614
0
        }
39615
0
        ret = JS_SetPrototypeInternal(ctx, obj, proto, TRUE);
39616
0
        JS_FreeValue(ctx, proto);
39617
0
        if (ret < 0)
39618
0
            goto fail1;
39619
0
    }
39620
0
    return obj;
39621
39622
0
 fail:
39623
0
    string_buffer_free(b);
39624
0
 fail1:
39625
0
    JS_FreeValue(ctx, obj);
39626
0
    return JS_EXCEPTION;
39627
0
}
39628
39629
static __exception int js_get_length32(JSContext *ctx, uint32_t *pres,
39630
                                       JSValueConst obj)
39631
0
{
39632
0
    JSValue len_val;
39633
0
    len_val = JS_GetProperty(ctx, obj, JS_ATOM_length);
39634
0
    if (JS_IsException(len_val)) {
39635
0
        *pres = 0;
39636
0
        return -1;
39637
0
    }
39638
0
    return JS_ToUint32Free(ctx, pres, len_val);
39639
0
}
39640
39641
static __exception int js_get_length64(JSContext *ctx, int64_t *pres,
39642
                                       JSValueConst obj)
39643
0
{
39644
0
    JSValue len_val;
39645
0
    len_val = JS_GetProperty(ctx, obj, JS_ATOM_length);
39646
0
    if (JS_IsException(len_val)) {
39647
0
        *pres = 0;
39648
0
        return -1;
39649
0
    }
39650
0
    return JS_ToLengthFree(ctx, pres, len_val);
39651
0
}
39652
39653
static void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len)
39654
0
{
39655
0
    uint32_t i;
39656
0
    for(i = 0; i < len; i++) {
39657
0
        JS_FreeValue(ctx, tab[i]);
39658
0
    }
39659
0
    js_free(ctx, tab);
39660
0
}
39661
39662
/* XXX: should use ValueArray */
39663
static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
39664
                               JSValueConst array_arg)
39665
0
{
39666
0
    uint32_t len, i;
39667
0
    int64_t len64;
39668
0
    JSValue *tab, ret;
39669
0
    JSObject *p;
39670
39671
0
    if (JS_VALUE_GET_TAG(array_arg) != JS_TAG_OBJECT) {
39672
0
        JS_ThrowTypeError(ctx, "not a object");
39673
0
        return NULL;
39674
0
    }
39675
0
    if (js_get_length64(ctx, &len64, array_arg))
39676
0
        return NULL;
39677
0
    if (len64 > JS_MAX_LOCAL_VARS) {
39678
        // XXX: check for stack overflow?
39679
0
        JS_ThrowRangeError(ctx, "too many arguments in function call (only %d allowed)",
39680
0
                           JS_MAX_LOCAL_VARS);
39681
0
        return NULL;
39682
0
    }
39683
0
    len = len64;
39684
    /* avoid allocating 0 bytes */
39685
0
    tab = js_mallocz(ctx, sizeof(tab[0]) * max_uint32(1, len));
39686
0
    if (!tab)
39687
0
        return NULL;
39688
0
    p = JS_VALUE_GET_OBJ(array_arg);
39689
0
    if ((p->class_id == JS_CLASS_ARRAY || p->class_id == JS_CLASS_ARGUMENTS) &&
39690
0
        p->fast_array &&
39691
0
        len == p->u.array.count) {
39692
0
        for(i = 0; i < len; i++) {
39693
0
            tab[i] = JS_DupValue(ctx, p->u.array.u.values[i]);
39694
0
        }
39695
0
    } else {
39696
0
        for(i = 0; i < len; i++) {
39697
0
            ret = JS_GetPropertyUint32(ctx, array_arg, i);
39698
0
            if (JS_IsException(ret)) {
39699
0
                free_arg_list(ctx, tab, i);
39700
0
                return NULL;
39701
0
            }
39702
0
            tab[i] = ret;
39703
0
        }
39704
0
    }
39705
0
    *plen = len;
39706
0
    return tab;
39707
0
}
39708
39709
/* magic value: 0 = normal apply, 1 = apply for constructor, 2 =
39710
   Reflect.apply */
39711
static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
39712
                                 int argc, JSValueConst *argv, int magic)
39713
0
{
39714
0
    JSValueConst this_arg, array_arg;
39715
0
    uint32_t len;
39716
0
    JSValue *tab, ret;
39717
39718
0
    if (check_function(ctx, this_val))
39719
0
        return JS_EXCEPTION;
39720
0
    this_arg = argv[0];
39721
0
    array_arg = argv[1];
39722
0
    if ((JS_VALUE_GET_TAG(array_arg) == JS_TAG_UNDEFINED ||
39723
0
         JS_VALUE_GET_TAG(array_arg) == JS_TAG_NULL) && magic != 2) {
39724
0
        return JS_Call(ctx, this_val, this_arg, 0, NULL);
39725
0
    }
39726
0
    tab = build_arg_list(ctx, &len, array_arg);
39727
0
    if (!tab)
39728
0
        return JS_EXCEPTION;
39729
0
    if (magic & 1) {
39730
0
        ret = JS_CallConstructor2(ctx, this_val, this_arg, len, (JSValueConst *)tab);
39731
0
    } else {
39732
0
        ret = JS_Call(ctx, this_val, this_arg, len, (JSValueConst *)tab);
39733
0
    }
39734
0
    free_arg_list(ctx, tab, len);
39735
0
    return ret;
39736
0
}
39737
39738
static JSValue js_function_call(JSContext *ctx, JSValueConst this_val,
39739
                                int argc, JSValueConst *argv)
39740
0
{
39741
0
    if (argc <= 0) {
39742
0
        return JS_Call(ctx, this_val, JS_UNDEFINED, 0, NULL);
39743
0
    } else {
39744
0
        return JS_Call(ctx, this_val, argv[0], argc - 1, argv + 1);
39745
0
    }
39746
0
}
39747
39748
static JSValue js_function_bind(JSContext *ctx, JSValueConst this_val,
39749
                                int argc, JSValueConst *argv)
39750
0
{
39751
0
    JSBoundFunction *bf;
39752
0
    JSValue func_obj, name1, len_val;
39753
0
    JSObject *p;
39754
0
    int arg_count, i, ret;
39755
39756
0
    if (check_function(ctx, this_val))
39757
0
        return JS_EXCEPTION;
39758
39759
0
    func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
39760
0
                                 JS_CLASS_BOUND_FUNCTION);
39761
0
    if (JS_IsException(func_obj))
39762
0
        return JS_EXCEPTION;
39763
0
    p = JS_VALUE_GET_OBJ(func_obj);
39764
0
    p->is_constructor = JS_IsConstructor(ctx, this_val);
39765
0
    arg_count = max_int(0, argc - 1);
39766
0
    bf = js_malloc(ctx, sizeof(*bf) + arg_count * sizeof(JSValue));
39767
0
    if (!bf)
39768
0
        goto exception;
39769
0
    bf->func_obj = JS_DupValue(ctx, this_val);
39770
0
    bf->this_val = JS_DupValue(ctx, argv[0]);
39771
0
    bf->argc = arg_count;
39772
0
    for(i = 0; i < arg_count; i++) {
39773
0
        bf->argv[i] = JS_DupValue(ctx, argv[i + 1]);
39774
0
    }
39775
0
    p->u.bound_function = bf;
39776
39777
    /* XXX: the spec could be simpler by only using GetOwnProperty */
39778
0
    ret = JS_GetOwnProperty(ctx, NULL, this_val, JS_ATOM_length);
39779
0
    if (ret < 0)
39780
0
        goto exception;
39781
0
    if (!ret) {
39782
0
        len_val = JS_NewInt32(ctx, 0);
39783
0
    } else {
39784
0
        len_val = JS_GetProperty(ctx, this_val, JS_ATOM_length);
39785
0
        if (JS_IsException(len_val))
39786
0
            goto exception;
39787
0
        if (JS_VALUE_GET_TAG(len_val) == JS_TAG_INT) {
39788
            /* most common case */
39789
0
            int len1 = JS_VALUE_GET_INT(len_val);
39790
0
            if (len1 <= arg_count)
39791
0
                len1 = 0;
39792
0
            else
39793
0
                len1 -= arg_count;
39794
0
            len_val = JS_NewInt32(ctx, len1);
39795
0
        } else if (JS_VALUE_GET_NORM_TAG(len_val) == JS_TAG_FLOAT64) {
39796
0
            double d = JS_VALUE_GET_FLOAT64(len_val);
39797
0
            if (isnan(d)) {
39798
0
                d = 0.0;
39799
0
            } else {
39800
0
                d = trunc(d);
39801
0
                if (d <= (double)arg_count)
39802
0
                    d = 0.0;
39803
0
                else
39804
0
                    d -= (double)arg_count; /* also converts -0 to +0 */
39805
0
            }
39806
0
            len_val = JS_NewFloat64(ctx, d);
39807
0
        } else {
39808
0
            JS_FreeValue(ctx, len_val);
39809
0
            len_val = JS_NewInt32(ctx, 0);
39810
0
        }
39811
0
    }
39812
0
    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length,
39813
0
                           len_val, JS_PROP_CONFIGURABLE);
39814
39815
0
    name1 = JS_GetProperty(ctx, this_val, JS_ATOM_name);
39816
0
    if (JS_IsException(name1))
39817
0
        goto exception;
39818
0
    if (!JS_IsString(name1)) {
39819
0
        JS_FreeValue(ctx, name1);
39820
0
        name1 = JS_AtomToString(ctx, JS_ATOM_empty_string);
39821
0
    }
39822
0
    name1 = JS_ConcatString3(ctx, "bound ", name1, "");
39823
0
    if (JS_IsException(name1))
39824
0
        goto exception;
39825
0
    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name1,
39826
0
                           JS_PROP_CONFIGURABLE);
39827
0
    return func_obj;
39828
0
 exception:
39829
0
    JS_FreeValue(ctx, func_obj);
39830
0
    return JS_EXCEPTION;
39831
0
}
39832
39833
static JSValue js_function_toString(JSContext *ctx, JSValueConst this_val,
39834
                                    int argc, JSValueConst *argv)
39835
0
{
39836
0
    JSObject *p;
39837
0
    JSFunctionKindEnum func_kind = JS_FUNC_NORMAL;
39838
39839
0
    if (check_function(ctx, this_val))
39840
0
        return JS_EXCEPTION;
39841
39842
0
    p = JS_VALUE_GET_OBJ(this_val);
39843
0
    if (js_class_has_bytecode(p->class_id)) {
39844
0
        JSFunctionBytecode *b = p->u.func.function_bytecode;
39845
0
        if (b->has_debug && b->debug.source) {
39846
0
            return JS_NewStringLen(ctx, b->debug.source, b->debug.source_len);
39847
0
        }
39848
0
        func_kind = b->func_kind;
39849
0
    }
39850
0
    {
39851
0
        JSValue name;
39852
0
        const char *pref, *suff;
39853
39854
0
        switch(func_kind) {
39855
0
        default:
39856
0
        case JS_FUNC_NORMAL:
39857
0
            pref = "function ";
39858
0
            break;
39859
0
        case JS_FUNC_GENERATOR:
39860
0
            pref = "function *";
39861
0
            break;
39862
0
        case JS_FUNC_ASYNC:
39863
0
            pref = "async function ";
39864
0
            break;
39865
0
        case JS_FUNC_ASYNC_GENERATOR:
39866
0
            pref = "async function *";
39867
0
            break;
39868
0
        }
39869
0
        suff = "() {\n    [native code]\n}";
39870
0
        name = JS_GetProperty(ctx, this_val, JS_ATOM_name);
39871
0
        if (JS_IsUndefined(name))
39872
0
            name = JS_AtomToString(ctx, JS_ATOM_empty_string);
39873
0
        return JS_ConcatString3(ctx, pref, name, suff);
39874
0
    }
39875
0
}
39876
39877
static JSValue js_function_hasInstance(JSContext *ctx, JSValueConst this_val,
39878
                                       int argc, JSValueConst *argv)
39879
0
{
39880
0
    int ret;
39881
0
    ret = JS_OrdinaryIsInstanceOf(ctx, argv[0], this_val);
39882
0
    if (ret < 0)
39883
0
        return JS_EXCEPTION;
39884
0
    else
39885
0
        return JS_NewBool(ctx, ret);
39886
0
}
39887
39888
static const JSCFunctionListEntry js_function_proto_funcs[] = {
39889
    JS_CFUNC_DEF("call", 1, js_function_call ),
39890
    JS_CFUNC_MAGIC_DEF("apply", 2, js_function_apply, 0 ),
39891
    JS_CFUNC_DEF("bind", 1, js_function_bind ),
39892
    JS_CFUNC_DEF("toString", 0, js_function_toString ),
39893
    JS_CFUNC_DEF("[Symbol.hasInstance]", 1, js_function_hasInstance ),
39894
    JS_CGETSET_DEF("fileName", js_function_proto_fileName, NULL ),
39895
    JS_CGETSET_MAGIC_DEF("lineNumber", js_function_proto_lineNumber, NULL, 0 ),
39896
    JS_CGETSET_MAGIC_DEF("columnNumber", js_function_proto_lineNumber, NULL, 1 ),
39897
};
39898
39899
/* Error class */
39900
39901
static JSValue iterator_to_array(JSContext *ctx, JSValueConst items)
39902
0
{
39903
0
    JSValue iter, next_method = JS_UNDEFINED;
39904
0
    JSValue v, r = JS_UNDEFINED;
39905
0
    int64_t k;
39906
0
    BOOL done;
39907
39908
0
    iter = JS_GetIterator(ctx, items, FALSE);
39909
0
    if (JS_IsException(iter))
39910
0
        goto exception;
39911
0
    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
39912
0
    if (JS_IsException(next_method))
39913
0
        goto exception;
39914
0
    r = JS_NewArray(ctx);
39915
0
    if (JS_IsException(r))
39916
0
        goto exception;
39917
0
    for (k = 0;; k++) {
39918
0
        v = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
39919
0
        if (JS_IsException(v))
39920
0
            goto exception_close;
39921
0
        if (done)
39922
0
            break;
39923
0
        if (JS_DefinePropertyValueInt64(ctx, r, k, v,
39924
0
                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)
39925
0
            goto exception_close;
39926
0
    }
39927
0
 done:
39928
0
    JS_FreeValue(ctx, next_method);
39929
0
    JS_FreeValue(ctx, iter);
39930
0
    return r;
39931
0
 exception_close:
39932
0
    JS_IteratorClose(ctx, iter, TRUE);
39933
0
 exception:
39934
0
    JS_FreeValue(ctx, r);
39935
0
    r = JS_EXCEPTION;
39936
0
    goto done;
39937
0
}
39938
39939
static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target,
39940
                                    int argc, JSValueConst *argv, int magic)
39941
0
{
39942
0
    JSValue obj, msg, proto;
39943
0
    JSValueConst message, options;
39944
0
    int arg_index;
39945
39946
0
    if (JS_IsUndefined(new_target))
39947
0
        new_target = JS_GetActiveFunction(ctx);
39948
0
    proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);
39949
0
    if (JS_IsException(proto))
39950
0
        return proto;
39951
0
    if (!JS_IsObject(proto)) {
39952
0
        JSContext *realm;
39953
0
        JSValueConst proto1;
39954
39955
0
        JS_FreeValue(ctx, proto);
39956
0
        realm = JS_GetFunctionRealm(ctx, new_target);
39957
0
        if (!realm)
39958
0
            return JS_EXCEPTION;
39959
0
        if (magic < 0) {
39960
0
            proto1 = realm->class_proto[JS_CLASS_ERROR];
39961
0
        } else {
39962
0
            proto1 = realm->native_error_proto[magic];
39963
0
        }
39964
0
        proto = JS_DupValue(ctx, proto1);
39965
0
    }
39966
0
    obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_ERROR);
39967
0
    JS_FreeValue(ctx, proto);
39968
0
    if (JS_IsException(obj))
39969
0
        return obj;
39970
0
    arg_index = (magic == JS_AGGREGATE_ERROR);
39971
39972
0
    message = argv[arg_index++];
39973
0
    if (!JS_IsUndefined(message)) {
39974
0
        msg = JS_ToString(ctx, message);
39975
0
        if (unlikely(JS_IsException(msg)))
39976
0
            goto exception;
39977
0
        JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, msg,
39978
0
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
39979
0
    }
39980
39981
0
    if (arg_index < argc) {
39982
0
        options = argv[arg_index];
39983
0
        if (JS_IsObject(options)) {
39984
0
            int present = JS_HasProperty(ctx, options, JS_ATOM_cause);
39985
0
            if (present < 0)
39986
0
                goto exception;
39987
0
            if (present) {
39988
0
                JSValue cause = JS_GetProperty(ctx, options, JS_ATOM_cause);
39989
0
                if (JS_IsException(cause))
39990
0
                    goto exception;
39991
0
                JS_DefinePropertyValue(ctx, obj, JS_ATOM_cause, cause,
39992
0
                                       JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
39993
0
            }
39994
0
        }
39995
0
    }
39996
39997
0
    if (magic == JS_AGGREGATE_ERROR) {
39998
0
        JSValue error_list = iterator_to_array(ctx, argv[0]);
39999
0
        if (JS_IsException(error_list))
40000
0
            goto exception;
40001
0
        JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, error_list,
40002
0
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
40003
0
    }
40004
40005
    /* skip the Error() function in the backtrace */
40006
0
    build_backtrace(ctx, obj, NULL, 0, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL);
40007
0
    return obj;
40008
0
 exception:
40009
0
    JS_FreeValue(ctx, obj);
40010
0
    return JS_EXCEPTION;
40011
0
}
40012
40013
static JSValue js_error_toString(JSContext *ctx, JSValueConst this_val,
40014
                                 int argc, JSValueConst *argv)
40015
0
{
40016
0
    JSValue name, msg;
40017
40018
0
    if (!JS_IsObject(this_val))
40019
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
40020
0
    name = JS_GetProperty(ctx, this_val, JS_ATOM_name);
40021
0
    if (JS_IsUndefined(name))
40022
0
        name = JS_AtomToString(ctx, JS_ATOM_Error);
40023
0
    else
40024
0
        name = JS_ToStringFree(ctx, name);
40025
0
    if (JS_IsException(name))
40026
0
        return JS_EXCEPTION;
40027
40028
0
    msg = JS_GetProperty(ctx, this_val, JS_ATOM_message);
40029
0
    if (JS_IsUndefined(msg))
40030
0
        msg = JS_AtomToString(ctx, JS_ATOM_empty_string);
40031
0
    else
40032
0
        msg = JS_ToStringFree(ctx, msg);
40033
0
    if (JS_IsException(msg)) {
40034
0
        JS_FreeValue(ctx, name);
40035
0
        return JS_EXCEPTION;
40036
0
    }
40037
0
    if (!JS_IsEmptyString(name) && !JS_IsEmptyString(msg))
40038
0
        name = JS_ConcatString3(ctx, "", name, ": ");
40039
0
    return JS_ConcatString(ctx, name, msg);
40040
0
}
40041
40042
static const JSCFunctionListEntry js_error_proto_funcs[] = {
40043
    JS_CFUNC_DEF("toString", 0, js_error_toString ),
40044
    JS_PROP_STRING_DEF("name", "Error", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
40045
    JS_PROP_STRING_DEF("message", "", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
40046
};
40047
40048
static JSValue js_error_isError(JSContext *ctx, JSValueConst this_val,
40049
                                int argc, JSValueConst *argv)
40050
0
{
40051
0
    return JS_NewBool(ctx, JS_IsError(ctx, argv[0]));
40052
0
}
40053
40054
static const JSCFunctionListEntry js_error_funcs[] = {
40055
    JS_CFUNC_DEF("isError", 1, js_error_isError),
40056
};
40057
40058
/* AggregateError */
40059
40060
/* used by C code. */
40061
static JSValue js_aggregate_error_constructor(JSContext *ctx,
40062
                                              JSValueConst errors)
40063
0
{
40064
0
    JSValue obj;
40065
40066
0
    obj = JS_NewObjectProtoClass(ctx,
40067
0
                                 ctx->native_error_proto[JS_AGGREGATE_ERROR],
40068
0
                                 JS_CLASS_ERROR);
40069
0
    if (JS_IsException(obj))
40070
0
        return obj;
40071
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, JS_DupValue(ctx, errors),
40072
0
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
40073
0
    return obj;
40074
0
}
40075
40076
/* Array */
40077
40078
static int JS_CopySubArray(JSContext *ctx,
40079
                           JSValueConst obj, int64_t to_pos,
40080
                           int64_t from_pos, int64_t count, int dir)
40081
0
{
40082
0
    JSObject *p;
40083
0
    int64_t i, from, to, len;
40084
0
    JSValue val;
40085
0
    int fromPresent;
40086
40087
0
    p = NULL;
40088
0
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
40089
0
        p = JS_VALUE_GET_OBJ(obj);
40090
0
        if (p->class_id != JS_CLASS_ARRAY || !p->fast_array) {
40091
0
            p = NULL;
40092
0
        }
40093
0
    }
40094
40095
0
    for (i = 0; i < count; ) {
40096
0
        if (dir < 0) {
40097
0
            from = from_pos + count - i - 1;
40098
0
            to = to_pos + count - i - 1;
40099
0
        } else {
40100
0
            from = from_pos + i;
40101
0
            to = to_pos + i;
40102
0
        }
40103
0
        if (p && p->fast_array &&
40104
0
            from >= 0 && from < (len = p->u.array.count)  &&
40105
0
            to >= 0 && to < len) {
40106
0
            int64_t l, j;
40107
            /* Fast path for fast arrays. Since we don't look at the
40108
               prototype chain, we can optimize only the cases where
40109
               all the elements are present in the array. */
40110
0
            l = count - i;
40111
0
            if (dir < 0) {
40112
0
                l = min_int64(l, from + 1);
40113
0
                l = min_int64(l, to + 1);
40114
0
                for(j = 0; j < l; j++) {
40115
0
                    set_value(ctx, &p->u.array.u.values[to - j],
40116
0
                              JS_DupValue(ctx, p->u.array.u.values[from - j]));
40117
0
                }
40118
0
            } else {
40119
0
                l = min_int64(l, len - from);
40120
0
                l = min_int64(l, len - to);
40121
0
                for(j = 0; j < l; j++) {
40122
0
                    set_value(ctx, &p->u.array.u.values[to + j],
40123
0
                              JS_DupValue(ctx, p->u.array.u.values[from + j]));
40124
0
                }
40125
0
            }
40126
0
            i += l;
40127
0
        } else {
40128
0
            fromPresent = JS_TryGetPropertyInt64(ctx, obj, from, &val);
40129
0
            if (fromPresent < 0)
40130
0
                goto exception;
40131
40132
0
            if (fromPresent) {
40133
0
                if (JS_SetPropertyInt64(ctx, obj, to, val) < 0)
40134
0
                    goto exception;
40135
0
            } else {
40136
0
                if (JS_DeletePropertyInt64(ctx, obj, to, JS_PROP_THROW) < 0)
40137
0
                    goto exception;
40138
0
            }
40139
0
            i++;
40140
0
        }
40141
0
    }
40142
0
    return 0;
40143
40144
0
 exception:
40145
0
    return -1;
40146
0
}
40147
40148
static JSValue js_array_constructor(JSContext *ctx, JSValueConst new_target,
40149
                                    int argc, JSValueConst *argv)
40150
0
{
40151
0
    JSValue obj;
40152
0
    int i;
40153
40154
0
    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_ARRAY);
40155
0
    if (JS_IsException(obj))
40156
0
        return obj;
40157
0
    if (argc == 1 && JS_IsNumber(argv[0])) {
40158
0
        uint32_t len;
40159
0
        if (JS_ToArrayLengthFree(ctx, &len, JS_DupValue(ctx, argv[0]), TRUE))
40160
0
            goto fail;
40161
0
        if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, len)) < 0)
40162
0
            goto fail;
40163
0
    } else {
40164
0
        for(i = 0; i < argc; i++) {
40165
0
            if (JS_SetPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i])) < 0)
40166
0
                goto fail;
40167
0
        }
40168
0
    }
40169
0
    return obj;
40170
0
fail:
40171
0
    JS_FreeValue(ctx, obj);
40172
0
    return JS_EXCEPTION;
40173
0
}
40174
40175
static JSValue js_array_from(JSContext *ctx, JSValueConst this_val,
40176
                             int argc, JSValueConst *argv)
40177
0
{
40178
    // from(items, mapfn = void 0, this_arg = void 0)
40179
0
    JSValueConst items = argv[0], mapfn, this_arg;
40180
0
    JSValueConst args[2];
40181
0
    JSValue iter, r, v, v2, arrayLike, next_method, enum_obj;
40182
0
    int64_t k, len;
40183
0
    int done, mapping;
40184
40185
0
    mapping = FALSE;
40186
0
    mapfn = JS_UNDEFINED;
40187
0
    this_arg = JS_UNDEFINED;
40188
0
    r = JS_UNDEFINED;
40189
0
    arrayLike = JS_UNDEFINED;
40190
0
    iter = JS_UNDEFINED;
40191
0
    enum_obj = JS_UNDEFINED;
40192
0
    next_method = JS_UNDEFINED;
40193
40194
0
    if (argc > 1) {
40195
0
        mapfn = argv[1];
40196
0
        if (!JS_IsUndefined(mapfn)) {
40197
0
            if (check_function(ctx, mapfn))
40198
0
                goto exception;
40199
0
            mapping = 1;
40200
0
            if (argc > 2)
40201
0
                this_arg = argv[2];
40202
0
        }
40203
0
    }
40204
0
    iter = JS_GetProperty(ctx, items, JS_ATOM_Symbol_iterator);
40205
0
    if (JS_IsException(iter))
40206
0
        goto exception;
40207
0
    if (!JS_IsUndefined(iter) && !JS_IsNull(iter)) {
40208
0
        if (!JS_IsFunction(ctx, iter)) {
40209
0
            JS_ThrowTypeError(ctx, "value is not iterable");
40210
0
            goto exception;
40211
0
        }
40212
0
        if (JS_IsConstructor(ctx, this_val))
40213
0
            r = JS_CallConstructor(ctx, this_val, 0, NULL);
40214
0
        else
40215
0
            r = JS_NewArray(ctx);
40216
0
        if (JS_IsException(r))
40217
0
            goto exception;
40218
0
        enum_obj = JS_GetIterator2(ctx, items, iter);
40219
0
        if (JS_IsException(enum_obj))
40220
0
            goto exception;
40221
0
        next_method = JS_GetProperty(ctx, enum_obj, JS_ATOM_next);
40222
0
        if (JS_IsException(next_method))
40223
0
            goto exception;
40224
0
        for (k = 0;; k++) {
40225
0
            v = JS_IteratorNext(ctx, enum_obj, next_method, 0, NULL, &done);
40226
0
            if (JS_IsException(v))
40227
0
                goto exception;
40228
0
            if (done)
40229
0
                break;
40230
0
            if (mapping) {
40231
0
                args[0] = v;
40232
0
                args[1] = JS_NewInt32(ctx, k);
40233
0
                v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
40234
0
                JS_FreeValue(ctx, v);
40235
0
                v = v2;
40236
0
                if (JS_IsException(v))
40237
0
                    goto exception_close;
40238
0
            }
40239
0
            if (JS_DefinePropertyValueInt64(ctx, r, k, v,
40240
0
                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)
40241
0
                goto exception_close;
40242
0
        }
40243
0
    } else {
40244
0
        arrayLike = JS_ToObject(ctx, items);
40245
0
        if (JS_IsException(arrayLike))
40246
0
            goto exception;
40247
0
        if (js_get_length64(ctx, &len, arrayLike) < 0)
40248
0
            goto exception;
40249
0
        v = JS_NewInt64(ctx, len);
40250
0
        args[0] = v;
40251
0
        if (JS_IsConstructor(ctx, this_val)) {
40252
0
            r = JS_CallConstructor(ctx, this_val, 1, args);
40253
0
        } else {
40254
0
            r = js_array_constructor(ctx, JS_UNDEFINED, 1, args);
40255
0
        }
40256
0
        JS_FreeValue(ctx, v);
40257
0
        if (JS_IsException(r))
40258
0
            goto exception;
40259
0
        for(k = 0; k < len; k++) {
40260
0
            v = JS_GetPropertyInt64(ctx, arrayLike, k);
40261
0
            if (JS_IsException(v))
40262
0
                goto exception;
40263
0
            if (mapping) {
40264
0
                args[0] = v;
40265
0
                args[1] = JS_NewInt32(ctx, k);
40266
0
                v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
40267
0
                JS_FreeValue(ctx, v);
40268
0
                v = v2;
40269
0
                if (JS_IsException(v))
40270
0
                    goto exception;
40271
0
            }
40272
0
            if (JS_DefinePropertyValueInt64(ctx, r, k, v,
40273
0
                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)
40274
0
                goto exception;
40275
0
        }
40276
0
    }
40277
0
    if (JS_SetProperty(ctx, r, JS_ATOM_length, JS_NewUint32(ctx, k)) < 0)
40278
0
        goto exception;
40279
0
    goto done;
40280
40281
0
 exception_close:
40282
0
    JS_IteratorClose(ctx, enum_obj, TRUE);
40283
0
 exception:
40284
0
    JS_FreeValue(ctx, r);
40285
0
    r = JS_EXCEPTION;
40286
0
 done:
40287
0
    JS_FreeValue(ctx, arrayLike);
40288
0
    JS_FreeValue(ctx, iter);
40289
0
    JS_FreeValue(ctx, enum_obj);
40290
0
    JS_FreeValue(ctx, next_method);
40291
0
    return r;
40292
0
}
40293
40294
static JSValue js_array_of(JSContext *ctx, JSValueConst this_val,
40295
                           int argc, JSValueConst *argv)
40296
0
{
40297
0
    JSValue obj, args[1];
40298
0
    int i;
40299
40300
0
    if (JS_IsConstructor(ctx, this_val)) {
40301
0
        args[0] = JS_NewInt32(ctx, argc);
40302
0
        obj = JS_CallConstructor(ctx, this_val, 1, (JSValueConst *)args);
40303
0
    } else {
40304
0
        obj = JS_NewArray(ctx);
40305
0
    }
40306
0
    if (JS_IsException(obj))
40307
0
        return JS_EXCEPTION;
40308
0
    for(i = 0; i < argc; i++) {
40309
0
        if (JS_CreateDataPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i]),
40310
0
                                        JS_PROP_THROW) < 0) {
40311
0
            goto fail;
40312
0
        }
40313
0
    }
40314
0
    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, argc)) < 0) {
40315
0
    fail:
40316
0
        JS_FreeValue(ctx, obj);
40317
0
        return JS_EXCEPTION;
40318
0
    }
40319
0
    return obj;
40320
0
}
40321
40322
static JSValue js_array_isArray(JSContext *ctx, JSValueConst this_val,
40323
                                int argc, JSValueConst *argv)
40324
0
{
40325
0
    int ret;
40326
0
    ret = JS_IsArray(ctx, argv[0]);
40327
0
    if (ret < 0)
40328
0
        return JS_EXCEPTION;
40329
0
    else
40330
0
        return JS_NewBool(ctx, ret);
40331
0
}
40332
40333
static JSValue js_get_this(JSContext *ctx,
40334
                           JSValueConst this_val)
40335
0
{
40336
0
    return JS_DupValue(ctx, this_val);
40337
0
}
40338
40339
static JSValue JS_ArraySpeciesCreate(JSContext *ctx, JSValueConst obj,
40340
                                     JSValueConst len_val)
40341
0
{
40342
0
    JSValue ctor, ret, species;
40343
0
    int res;
40344
0
    JSContext *realm;
40345
40346
0
    res = JS_IsArray(ctx, obj);
40347
0
    if (res < 0)
40348
0
        return JS_EXCEPTION;
40349
0
    if (!res)
40350
0
        return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);
40351
0
    ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);
40352
0
    if (JS_IsException(ctor))
40353
0
        return ctor;
40354
0
    if (JS_IsConstructor(ctx, ctor)) {
40355
        /* legacy web compatibility */
40356
0
        realm = JS_GetFunctionRealm(ctx, ctor);
40357
0
        if (!realm) {
40358
0
            JS_FreeValue(ctx, ctor);
40359
0
            return JS_EXCEPTION;
40360
0
        }
40361
0
        if (realm != ctx &&
40362
0
            js_same_value(ctx, ctor, realm->array_ctor)) {
40363
0
            JS_FreeValue(ctx, ctor);
40364
0
            ctor = JS_UNDEFINED;
40365
0
        }
40366
0
    }
40367
0
    if (JS_IsObject(ctor)) {
40368
0
        species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species);
40369
0
        JS_FreeValue(ctx, ctor);
40370
0
        if (JS_IsException(species))
40371
0
            return species;
40372
0
        ctor = species;
40373
0
        if (JS_IsNull(ctor))
40374
0
            ctor = JS_UNDEFINED;
40375
0
    }
40376
0
    if (JS_IsUndefined(ctor)) {
40377
0
        return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);
40378
0
    } else {
40379
0
        ret = JS_CallConstructor(ctx, ctor, 1, &len_val);
40380
0
        JS_FreeValue(ctx, ctor);
40381
0
        return ret;
40382
0
    }
40383
0
}
40384
40385
static const JSCFunctionListEntry js_array_funcs[] = {
40386
    JS_CFUNC_DEF("isArray", 1, js_array_isArray ),
40387
    JS_CFUNC_DEF("from", 1, js_array_from ),
40388
    JS_CFUNC_DEF("of", 0, js_array_of ),
40389
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
40390
};
40391
40392
static int JS_isConcatSpreadable(JSContext *ctx, JSValueConst obj)
40393
0
{
40394
0
    JSValue val;
40395
40396
0
    if (!JS_IsObject(obj))
40397
0
        return FALSE;
40398
0
    val = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_isConcatSpreadable);
40399
0
    if (JS_IsException(val))
40400
0
        return -1;
40401
0
    if (!JS_IsUndefined(val))
40402
0
        return JS_ToBoolFree(ctx, val);
40403
0
    return JS_IsArray(ctx, obj);
40404
0
}
40405
40406
static JSValue js_array_at(JSContext *ctx, JSValueConst this_val,
40407
                           int argc, JSValueConst *argv)
40408
0
{
40409
0
    JSValue obj, ret;
40410
0
    int64_t len, idx;
40411
0
    JSValue *arrp;
40412
0
    uint32_t count;
40413
40414
0
    obj = JS_ToObject(ctx, this_val);
40415
0
    if (js_get_length64(ctx, &len, obj))
40416
0
        goto exception;
40417
40418
0
    if (JS_ToInt64Sat(ctx, &idx, argv[0]))
40419
0
        goto exception;
40420
40421
0
    if (idx < 0)
40422
0
        idx = len + idx;
40423
0
    if (idx < 0 || idx >= len) {
40424
0
        ret = JS_UNDEFINED;
40425
0
    } else if (js_get_fast_array(ctx, obj, &arrp, &count) && idx < count) {
40426
0
        ret = JS_DupValue(ctx, arrp[idx]);
40427
0
    } else {
40428
0
        int present = JS_TryGetPropertyInt64(ctx, obj, idx, &ret);
40429
0
        if (present < 0)
40430
0
            goto exception;
40431
0
        if (!present)
40432
0
            ret = JS_UNDEFINED;
40433
0
    }
40434
0
    JS_FreeValue(ctx, obj);
40435
0
    return ret;
40436
0
 exception:
40437
0
    JS_FreeValue(ctx, obj);
40438
0
    return JS_EXCEPTION;
40439
0
}
40440
40441
static JSValue js_array_with(JSContext *ctx, JSValueConst this_val,
40442
                             int argc, JSValueConst *argv)
40443
0
{
40444
0
    JSValue arr, obj, ret, *arrp, *pval;
40445
0
    JSObject *p;
40446
0
    int64_t i, len, idx;
40447
0
    uint32_t count32;
40448
40449
0
    ret = JS_EXCEPTION;
40450
0
    arr = JS_UNDEFINED;
40451
0
    obj = JS_ToObject(ctx, this_val);
40452
0
    if (js_get_length64(ctx, &len, obj))
40453
0
        goto exception;
40454
40455
0
    if (JS_ToInt64Sat(ctx, &idx, argv[0]))
40456
0
        goto exception;
40457
40458
0
    if (idx < 0)
40459
0
        idx = len + idx;
40460
40461
0
    if (idx < 0 || idx >= len) {
40462
0
        JS_ThrowRangeError(ctx, "invalid array index: %" PRId64, idx);
40463
0
        goto exception;
40464
0
    }
40465
40466
0
    arr = js_allocate_fast_array(ctx, len);
40467
0
    if (JS_IsException(arr))
40468
0
        goto exception;
40469
40470
0
    p = JS_VALUE_GET_OBJ(arr);
40471
0
    i = 0;
40472
0
    pval = p->u.array.u.values;
40473
0
    if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
40474
0
        for (; i < idx; i++, pval++)
40475
0
            *pval = JS_DupValue(ctx, arrp[i]);
40476
0
        *pval = JS_DupValue(ctx, argv[1]);
40477
0
        for (i++, pval++; i < len; i++, pval++)
40478
0
            *pval = JS_DupValue(ctx, arrp[i]);
40479
0
    } else {
40480
0
        for (; i < idx; i++, pval++)
40481
0
            if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
40482
0
                goto fill_and_fail;
40483
0
        *pval = JS_DupValue(ctx, argv[1]);
40484
0
        for (i++, pval++; i < len; i++, pval++) {
40485
0
            if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) {
40486
0
            fill_and_fail:
40487
0
                for (; i < len; i++, pval++)
40488
0
                    *pval = JS_UNDEFINED;
40489
0
                goto exception;
40490
0
            }
40491
0
        }
40492
0
    }
40493
40494
0
    if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0)
40495
0
        goto exception;
40496
40497
0
    ret = arr;
40498
0
    arr = JS_UNDEFINED;
40499
40500
0
exception:
40501
0
    JS_FreeValue(ctx, arr);
40502
0
    JS_FreeValue(ctx, obj);
40503
0
    return ret;
40504
0
}
40505
40506
static JSValue js_array_concat(JSContext *ctx, JSValueConst this_val,
40507
                               int argc, JSValueConst *argv)
40508
0
{
40509
0
    JSValue obj, arr, val;
40510
0
    JSValueConst e;
40511
0
    int64_t len, k, n;
40512
0
    int i, res;
40513
40514
0
    arr = JS_UNDEFINED;
40515
0
    obj = JS_ToObject(ctx, this_val);
40516
0
    if (JS_IsException(obj))
40517
0
        goto exception;
40518
40519
0
    arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
40520
0
    if (JS_IsException(arr))
40521
0
        goto exception;
40522
0
    n = 0;
40523
0
    for (i = -1; i < argc; i++) {
40524
0
        if (i < 0)
40525
0
            e = obj;
40526
0
        else
40527
0
            e = argv[i];
40528
40529
0
        res = JS_isConcatSpreadable(ctx, e);
40530
0
        if (res < 0)
40531
0
            goto exception;
40532
0
        if (res) {
40533
0
            if (js_get_length64(ctx, &len, e))
40534
0
                goto exception;
40535
0
            if (n + len > MAX_SAFE_INTEGER) {
40536
0
                JS_ThrowTypeError(ctx, "Array loo long");
40537
0
                goto exception;
40538
0
            }
40539
0
            for (k = 0; k < len; k++, n++) {
40540
0
                res = JS_TryGetPropertyInt64(ctx, e, k, &val);
40541
0
                if (res < 0)
40542
0
                    goto exception;
40543
0
                if (res) {
40544
0
                    if (JS_DefinePropertyValueInt64(ctx, arr, n, val,
40545
0
                                                    JS_PROP_C_W_E | JS_PROP_THROW) < 0)
40546
0
                        goto exception;
40547
0
                }
40548
0
            }
40549
0
        } else {
40550
0
            if (n >= MAX_SAFE_INTEGER) {
40551
0
                JS_ThrowTypeError(ctx, "Array loo long");
40552
0
                goto exception;
40553
0
            }
40554
0
            if (JS_DefinePropertyValueInt64(ctx, arr, n, JS_DupValue(ctx, e),
40555
0
                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)
40556
0
                goto exception;
40557
0
            n++;
40558
0
        }
40559
0
    }
40560
0
    if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0)
40561
0
        goto exception;
40562
40563
0
    JS_FreeValue(ctx, obj);
40564
0
    return arr;
40565
40566
0
exception:
40567
0
    JS_FreeValue(ctx, arr);
40568
0
    JS_FreeValue(ctx, obj);
40569
0
    return JS_EXCEPTION;
40570
0
}
40571
40572
0
#define special_every    0
40573
0
#define special_some     1
40574
#define special_forEach  2
40575
0
#define special_map      3
40576
0
#define special_filter   4
40577
0
#define special_TA       8
40578
40579
static int js_typed_array_get_length_internal(JSContext *ctx, JSValueConst obj);
40580
40581
static JSValue js_typed_array___speciesCreate(JSContext *ctx,
40582
                                              JSValueConst this_val,
40583
                                              int argc, JSValueConst *argv);
40584
40585
static JSValue js_array_every(JSContext *ctx, JSValueConst this_val,
40586
                              int argc, JSValueConst *argv, int special)
40587
0
{
40588
0
    JSValue obj, val, index_val, res, ret;
40589
0
    JSValueConst args[3];
40590
0
    JSValueConst func, this_arg;
40591
0
    int64_t len, k, n;
40592
0
    int present;
40593
40594
0
    ret = JS_UNDEFINED;
40595
0
    val = JS_UNDEFINED;
40596
0
    if (special & special_TA) {
40597
0
        obj = JS_DupValue(ctx, this_val);
40598
0
        len = js_typed_array_get_length_internal(ctx, obj);
40599
0
        if (len < 0)
40600
0
            goto exception;
40601
0
    } else {
40602
0
        obj = JS_ToObject(ctx, this_val);
40603
0
        if (js_get_length64(ctx, &len, obj))
40604
0
            goto exception;
40605
0
    }
40606
0
    func = argv[0];
40607
0
    this_arg = JS_UNDEFINED;
40608
0
    if (argc > 1)
40609
0
        this_arg = argv[1];
40610
40611
0
    if (check_function(ctx, func))
40612
0
        goto exception;
40613
40614
0
    switch (special) {
40615
0
    case special_every:
40616
0
    case special_every | special_TA:
40617
0
        ret = JS_TRUE;
40618
0
        break;
40619
0
    case special_some:
40620
0
    case special_some | special_TA:
40621
0
        ret = JS_FALSE;
40622
0
        break;
40623
0
    case special_map:
40624
        /* XXX: JS_ArraySpeciesCreate should take int64_t */
40625
0
        ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt64(ctx, len));
40626
0
        if (JS_IsException(ret))
40627
0
            goto exception;
40628
0
        break;
40629
0
    case special_filter:
40630
0
        ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
40631
0
        if (JS_IsException(ret))
40632
0
            goto exception;
40633
0
        break;
40634
0
    case special_map | special_TA:
40635
0
        args[0] = obj;
40636
0
        args[1] = JS_NewInt32(ctx, len);
40637
0
        ret = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
40638
0
        if (JS_IsException(ret))
40639
0
            goto exception;
40640
0
        break;
40641
0
    case special_filter | special_TA:
40642
0
        ret = JS_NewArray(ctx);
40643
0
        if (JS_IsException(ret))
40644
0
            goto exception;
40645
0
        break;
40646
0
    }
40647
0
    n = 0;
40648
40649
0
    for(k = 0; k < len; k++) {
40650
0
        if (special & special_TA) {
40651
0
            val = JS_GetPropertyInt64(ctx, obj, k);
40652
0
            if (JS_IsException(val))
40653
0
                goto exception;
40654
0
            present = TRUE;
40655
0
        } else {
40656
0
            present = JS_TryGetPropertyInt64(ctx, obj, k, &val);
40657
0
            if (present < 0)
40658
0
                goto exception;
40659
0
        }
40660
0
        if (present) {
40661
0
            index_val = JS_NewInt64(ctx, k);
40662
0
            if (JS_IsException(index_val))
40663
0
                goto exception;
40664
0
            args[0] = val;
40665
0
            args[1] = index_val;
40666
0
            args[2] = obj;
40667
0
            res = JS_Call(ctx, func, this_arg, 3, args);
40668
0
            JS_FreeValue(ctx, index_val);
40669
0
            if (JS_IsException(res))
40670
0
                goto exception;
40671
0
            switch (special) {
40672
0
            case special_every:
40673
0
            case special_every | special_TA:
40674
0
                if (!JS_ToBoolFree(ctx, res)) {
40675
0
                    ret = JS_FALSE;
40676
0
                    goto done;
40677
0
                }
40678
0
                break;
40679
0
            case special_some:
40680
0
            case special_some | special_TA:
40681
0
                if (JS_ToBoolFree(ctx, res)) {
40682
0
                    ret = JS_TRUE;
40683
0
                    goto done;
40684
0
                }
40685
0
                break;
40686
0
            case special_map:
40687
0
                if (JS_DefinePropertyValueInt64(ctx, ret, k, res,
40688
0
                                                JS_PROP_C_W_E | JS_PROP_THROW) < 0)
40689
0
                    goto exception;
40690
0
                break;
40691
0
            case special_map | special_TA:
40692
0
                if (JS_SetPropertyValue(ctx, ret, JS_NewInt32(ctx, k), res, JS_PROP_THROW) < 0)
40693
0
                    goto exception;
40694
0
                break;
40695
0
            case special_filter:
40696
0
            case special_filter | special_TA:
40697
0
                if (JS_ToBoolFree(ctx, res)) {
40698
0
                    if (JS_DefinePropertyValueInt64(ctx, ret, n++, JS_DupValue(ctx, val),
40699
0
                                                    JS_PROP_C_W_E | JS_PROP_THROW) < 0)
40700
0
                        goto exception;
40701
0
                }
40702
0
                break;
40703
0
            default:
40704
0
                JS_FreeValue(ctx, res);
40705
0
                break;
40706
0
            }
40707
0
            JS_FreeValue(ctx, val);
40708
0
            val = JS_UNDEFINED;
40709
0
        }
40710
0
    }
40711
0
done:
40712
0
    if (special == (special_filter | special_TA)) {
40713
0
        JSValue arr;
40714
0
        args[0] = obj;
40715
0
        args[1] = JS_NewInt32(ctx, n);
40716
0
        arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
40717
0
        if (JS_IsException(arr))
40718
0
            goto exception;
40719
0
        args[0] = ret;
40720
0
        res = JS_Invoke(ctx, arr, JS_ATOM_set, 1, args);
40721
0
        if (check_exception_free(ctx, res))
40722
0
            goto exception;
40723
0
        JS_FreeValue(ctx, ret);
40724
0
        ret = arr;
40725
0
    }
40726
0
    JS_FreeValue(ctx, val);
40727
0
    JS_FreeValue(ctx, obj);
40728
0
    return ret;
40729
40730
0
exception:
40731
0
    JS_FreeValue(ctx, ret);
40732
0
    JS_FreeValue(ctx, val);
40733
0
    JS_FreeValue(ctx, obj);
40734
0
    return JS_EXCEPTION;
40735
0
}
40736
40737
#define special_reduce       0
40738
0
#define special_reduceRight  1
40739
40740
static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val,
40741
                               int argc, JSValueConst *argv, int special)
40742
0
{
40743
0
    JSValue obj, val, index_val, acc, acc1;
40744
0
    JSValueConst args[4];
40745
0
    JSValueConst func;
40746
0
    int64_t len, k, k1;
40747
0
    int present;
40748
40749
0
    acc = JS_UNDEFINED;
40750
0
    val = JS_UNDEFINED;
40751
0
    if (special & special_TA) {
40752
0
        obj = JS_DupValue(ctx, this_val);
40753
0
        len = js_typed_array_get_length_internal(ctx, obj);
40754
0
        if (len < 0)
40755
0
            goto exception;
40756
0
    } else {
40757
0
        obj = JS_ToObject(ctx, this_val);
40758
0
        if (js_get_length64(ctx, &len, obj))
40759
0
            goto exception;
40760
0
    }
40761
0
    func = argv[0];
40762
40763
0
    if (check_function(ctx, func))
40764
0
        goto exception;
40765
40766
0
    k = 0;
40767
0
    if (argc > 1) {
40768
0
        acc = JS_DupValue(ctx, argv[1]);
40769
0
    } else {
40770
0
        for(;;) {
40771
0
            if (k >= len) {
40772
0
                JS_ThrowTypeError(ctx, "empty array");
40773
0
                goto exception;
40774
0
            }
40775
0
            k1 = (special & special_reduceRight) ? len - k - 1 : k;
40776
0
            k++;
40777
0
            if (special & special_TA) {
40778
0
                acc = JS_GetPropertyInt64(ctx, obj, k1);
40779
0
                if (JS_IsException(acc))
40780
0
                    goto exception;
40781
0
                break;
40782
0
            } else {
40783
0
                present = JS_TryGetPropertyInt64(ctx, obj, k1, &acc);
40784
0
                if (present < 0)
40785
0
                    goto exception;
40786
0
                if (present)
40787
0
                    break;
40788
0
            }
40789
0
        }
40790
0
    }
40791
0
    for (; k < len; k++) {
40792
0
        k1 = (special & special_reduceRight) ? len - k - 1 : k;
40793
0
        if (special & special_TA) {
40794
0
            val = JS_GetPropertyInt64(ctx, obj, k1);
40795
0
            if (JS_IsException(val))
40796
0
                goto exception;
40797
0
            present = TRUE;
40798
0
        } else {
40799
0
            present = JS_TryGetPropertyInt64(ctx, obj, k1, &val);
40800
0
            if (present < 0)
40801
0
                goto exception;
40802
0
        }
40803
0
        if (present) {
40804
0
            index_val = JS_NewInt64(ctx, k1);
40805
0
            if (JS_IsException(index_val))
40806
0
                goto exception;
40807
0
            args[0] = acc;
40808
0
            args[1] = val;
40809
0
            args[2] = index_val;
40810
0
            args[3] = obj;
40811
0
            acc1 = JS_Call(ctx, func, JS_UNDEFINED, 4, args);
40812
0
            JS_FreeValue(ctx, index_val);
40813
0
            JS_FreeValue(ctx, val);
40814
0
            val = JS_UNDEFINED;
40815
0
            if (JS_IsException(acc1))
40816
0
                goto exception;
40817
0
            JS_FreeValue(ctx, acc);
40818
0
            acc = acc1;
40819
0
        }
40820
0
    }
40821
0
    JS_FreeValue(ctx, obj);
40822
0
    return acc;
40823
40824
0
exception:
40825
0
    JS_FreeValue(ctx, acc);
40826
0
    JS_FreeValue(ctx, val);
40827
0
    JS_FreeValue(ctx, obj);
40828
0
    return JS_EXCEPTION;
40829
0
}
40830
40831
static JSValue js_array_fill(JSContext *ctx, JSValueConst this_val,
40832
                             int argc, JSValueConst *argv)
40833
0
{
40834
0
    JSValue obj;
40835
0
    int64_t len, start, end;
40836
40837
0
    obj = JS_ToObject(ctx, this_val);
40838
0
    if (js_get_length64(ctx, &len, obj))
40839
0
        goto exception;
40840
40841
0
    start = 0;
40842
0
    if (argc > 1 && !JS_IsUndefined(argv[1])) {
40843
0
        if (JS_ToInt64Clamp(ctx, &start, argv[1], 0, len, len))
40844
0
            goto exception;
40845
0
    }
40846
40847
0
    end = len;
40848
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
40849
0
        if (JS_ToInt64Clamp(ctx, &end, argv[2], 0, len, len))
40850
0
            goto exception;
40851
0
    }
40852
40853
    /* XXX: should special case fast arrays */
40854
0
    while (start < end) {
40855
0
        if (JS_SetPropertyInt64(ctx, obj, start,
40856
0
                                JS_DupValue(ctx, argv[0])) < 0)
40857
0
            goto exception;
40858
0
        start++;
40859
0
    }
40860
0
    return obj;
40861
40862
0
 exception:
40863
0
    JS_FreeValue(ctx, obj);
40864
0
    return JS_EXCEPTION;
40865
0
}
40866
40867
static JSValue js_array_includes(JSContext *ctx, JSValueConst this_val,
40868
                                 int argc, JSValueConst *argv)
40869
0
{
40870
0
    JSValue obj, val;
40871
0
    int64_t len, n;
40872
0
    JSValue *arrp;
40873
0
    uint32_t count;
40874
0
    int res;
40875
40876
0
    obj = JS_ToObject(ctx, this_val);
40877
0
    if (js_get_length64(ctx, &len, obj))
40878
0
        goto exception;
40879
40880
0
    res = FALSE;
40881
0
    if (len > 0) {
40882
0
        n = 0;
40883
0
        if (argc > 1) {
40884
0
            if (JS_ToInt64Clamp(ctx, &n, argv[1], 0, len, len))
40885
0
                goto exception;
40886
0
        }
40887
0
        if (js_get_fast_array(ctx, obj, &arrp, &count)) {
40888
0
            for (; n < count; n++) {
40889
0
                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]),
40890
0
                                  JS_DupValue(ctx, arrp[n]),
40891
0
                                  JS_EQ_SAME_VALUE_ZERO)) {
40892
0
                    res = TRUE;
40893
0
                    goto done;
40894
0
                }
40895
0
            }
40896
0
        }
40897
0
        for (; n < len; n++) {
40898
0
            val = JS_GetPropertyInt64(ctx, obj, n);
40899
0
            if (JS_IsException(val))
40900
0
                goto exception;
40901
0
            if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val,
40902
0
                              JS_EQ_SAME_VALUE_ZERO)) {
40903
0
                res = TRUE;
40904
0
                break;
40905
0
            }
40906
0
        }
40907
0
    }
40908
0
 done:
40909
0
    JS_FreeValue(ctx, obj);
40910
0
    return JS_NewBool(ctx, res);
40911
40912
0
 exception:
40913
0
    JS_FreeValue(ctx, obj);
40914
0
    return JS_EXCEPTION;
40915
0
}
40916
40917
static JSValue js_array_indexOf(JSContext *ctx, JSValueConst this_val,
40918
                                int argc, JSValueConst *argv)
40919
0
{
40920
0
    JSValue obj, val;
40921
0
    int64_t len, n, res;
40922
0
    JSValue *arrp;
40923
0
    uint32_t count;
40924
40925
0
    obj = JS_ToObject(ctx, this_val);
40926
0
    if (js_get_length64(ctx, &len, obj))
40927
0
        goto exception;
40928
40929
0
    res = -1;
40930
0
    if (len > 0) {
40931
0
        n = 0;
40932
0
        if (argc > 1) {
40933
0
            if (JS_ToInt64Clamp(ctx, &n, argv[1], 0, len, len))
40934
0
                goto exception;
40935
0
        }
40936
0
        if (js_get_fast_array(ctx, obj, &arrp, &count)) {
40937
0
            for (; n < count; n++) {
40938
0
                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]),
40939
0
                                  JS_DupValue(ctx, arrp[n]), JS_EQ_STRICT)) {
40940
0
                    res = n;
40941
0
                    goto done;
40942
0
                }
40943
0
            }
40944
0
        }
40945
0
        for (; n < len; n++) {
40946
0
            int present = JS_TryGetPropertyInt64(ctx, obj, n, &val);
40947
0
            if (present < 0)
40948
0
                goto exception;
40949
0
            if (present) {
40950
0
                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_STRICT)) {
40951
0
                    res = n;
40952
0
                    break;
40953
0
                }
40954
0
            }
40955
0
        }
40956
0
    }
40957
0
 done:
40958
0
    JS_FreeValue(ctx, obj);
40959
0
    return JS_NewInt64(ctx, res);
40960
40961
0
 exception:
40962
0
    JS_FreeValue(ctx, obj);
40963
0
    return JS_EXCEPTION;
40964
0
}
40965
40966
static JSValue js_array_lastIndexOf(JSContext *ctx, JSValueConst this_val,
40967
                                    int argc, JSValueConst *argv)
40968
0
{
40969
0
    JSValue obj, val;
40970
0
    int64_t len, n, res;
40971
0
    int present;
40972
40973
0
    obj = JS_ToObject(ctx, this_val);
40974
0
    if (js_get_length64(ctx, &len, obj))
40975
0
        goto exception;
40976
40977
0
    res = -1;
40978
0
    if (len > 0) {
40979
0
        n = len - 1;
40980
0
        if (argc > 1) {
40981
0
            if (JS_ToInt64Clamp(ctx, &n, argv[1], -1, len - 1, len))
40982
0
                goto exception;
40983
0
        }
40984
        /* XXX: should special case fast arrays */
40985
0
        for (; n >= 0; n--) {
40986
0
            present = JS_TryGetPropertyInt64(ctx, obj, n, &val);
40987
0
            if (present < 0)
40988
0
                goto exception;
40989
0
            if (present) {
40990
0
                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_STRICT)) {
40991
0
                    res = n;
40992
0
                    break;
40993
0
                }
40994
0
            }
40995
0
        }
40996
0
    }
40997
0
    JS_FreeValue(ctx, obj);
40998
0
    return JS_NewInt64(ctx, res);
40999
41000
0
 exception:
41001
0
    JS_FreeValue(ctx, obj);
41002
0
    return JS_EXCEPTION;
41003
0
}
41004
41005
enum {
41006
    ArrayFind,
41007
    ArrayFindIndex,
41008
    ArrayFindLast,
41009
    ArrayFindLastIndex,
41010
};
41011
41012
static JSValue js_array_find(JSContext *ctx, JSValueConst this_val,
41013
                             int argc, JSValueConst *argv, int mode)
41014
0
{
41015
0
    JSValueConst func, this_arg;
41016
0
    JSValueConst args[3];
41017
0
    JSValue obj, val, index_val, res;
41018
0
    int64_t len, k, end;
41019
0
    int dir;
41020
41021
0
    index_val = JS_UNDEFINED;
41022
0
    val = JS_UNDEFINED;
41023
0
    obj = JS_ToObject(ctx, this_val);
41024
0
    if (js_get_length64(ctx, &len, obj))
41025
0
        goto exception;
41026
41027
0
    func = argv[0];
41028
0
    if (check_function(ctx, func))
41029
0
        goto exception;
41030
41031
0
    this_arg = JS_UNDEFINED;
41032
0
    if (argc > 1)
41033
0
        this_arg = argv[1];
41034
41035
0
    k = 0;
41036
0
    dir = 1;
41037
0
    end = len;
41038
0
    if (mode == ArrayFindLast || mode == ArrayFindLastIndex) {
41039
0
        k = len - 1;
41040
0
        dir = -1;
41041
0
        end = -1;
41042
0
    }
41043
41044
    // TODO(bnoordhuis) add fast path for fast arrays
41045
0
    for(; k != end; k += dir) {
41046
0
        index_val = JS_NewInt64(ctx, k);
41047
0
        if (JS_IsException(index_val))
41048
0
            goto exception;
41049
0
        val = JS_GetPropertyValue(ctx, obj, index_val);
41050
0
        if (JS_IsException(val))
41051
0
            goto exception;
41052
0
        args[0] = val;
41053
0
        args[1] = index_val;
41054
0
        args[2] = this_val;
41055
0
        res = JS_Call(ctx, func, this_arg, 3, args);
41056
0
        if (JS_IsException(res))
41057
0
            goto exception;
41058
0
        if (JS_ToBoolFree(ctx, res)) {
41059
0
            if (mode == ArrayFindIndex || mode == ArrayFindLastIndex) {
41060
0
                JS_FreeValue(ctx, val);
41061
0
                JS_FreeValue(ctx, obj);
41062
0
                return index_val;
41063
0
            } else {
41064
0
                JS_FreeValue(ctx, index_val);
41065
0
                JS_FreeValue(ctx, obj);
41066
0
                return val;
41067
0
            }
41068
0
        }
41069
0
        JS_FreeValue(ctx, val);
41070
0
        JS_FreeValue(ctx, index_val);
41071
0
    }
41072
0
    JS_FreeValue(ctx, obj);
41073
0
    if (mode == ArrayFindIndex || mode == ArrayFindLastIndex)
41074
0
        return JS_NewInt32(ctx, -1);
41075
0
    else
41076
0
        return JS_UNDEFINED;
41077
41078
0
exception:
41079
0
    JS_FreeValue(ctx, index_val);
41080
0
    JS_FreeValue(ctx, val);
41081
0
    JS_FreeValue(ctx, obj);
41082
0
    return JS_EXCEPTION;
41083
0
}
41084
41085
static JSValue js_array_toString(JSContext *ctx, JSValueConst this_val,
41086
                                 int argc, JSValueConst *argv)
41087
0
{
41088
0
    JSValue obj, method, ret;
41089
41090
0
    obj = JS_ToObject(ctx, this_val);
41091
0
    if (JS_IsException(obj))
41092
0
        return JS_EXCEPTION;
41093
0
    method = JS_GetProperty(ctx, obj, JS_ATOM_join);
41094
0
    if (JS_IsException(method)) {
41095
0
        ret = JS_EXCEPTION;
41096
0
    } else
41097
0
    if (!JS_IsFunction(ctx, method)) {
41098
        /* Use intrinsic Object.prototype.toString */
41099
0
        JS_FreeValue(ctx, method);
41100
0
        ret = js_object_toString(ctx, obj, 0, NULL);
41101
0
    } else {
41102
0
        ret = JS_CallFree(ctx, method, obj, 0, NULL);
41103
0
    }
41104
0
    JS_FreeValue(ctx, obj);
41105
0
    return ret;
41106
0
}
41107
41108
static JSValue js_array_join(JSContext *ctx, JSValueConst this_val,
41109
                             int argc, JSValueConst *argv, int toLocaleString)
41110
0
{
41111
0
    JSValue obj, sep = JS_UNDEFINED, el;
41112
0
    StringBuffer b_s, *b = &b_s;
41113
0
    JSString *p = NULL;
41114
0
    int64_t i, n;
41115
0
    int c;
41116
41117
0
    obj = JS_ToObject(ctx, this_val);
41118
0
    if (js_get_length64(ctx, &n, obj))
41119
0
        goto exception;
41120
41121
0
    c = ',';    /* default separator */
41122
0
    if (!toLocaleString && argc > 0 && !JS_IsUndefined(argv[0])) {
41123
0
        sep = JS_ToString(ctx, argv[0]);
41124
0
        if (JS_IsException(sep))
41125
0
            goto exception;
41126
0
        p = JS_VALUE_GET_STRING(sep);
41127
0
        if (p->len == 1 && !p->is_wide_char)
41128
0
            c = p->u.str8[0];
41129
0
        else
41130
0
            c = -1;
41131
0
    }
41132
0
    string_buffer_init(ctx, b, 0);
41133
41134
0
    for(i = 0; i < n; i++) {
41135
0
        if (i > 0) {
41136
0
            if (c >= 0) {
41137
0
                string_buffer_putc8(b, c);
41138
0
            } else {
41139
0
                string_buffer_concat(b, p, 0, p->len);
41140
0
            }
41141
0
        }
41142
0
        el = JS_GetPropertyUint32(ctx, obj, i);
41143
0
        if (JS_IsException(el))
41144
0
            goto fail;
41145
0
        if (!JS_IsNull(el) && !JS_IsUndefined(el)) {
41146
0
            if (toLocaleString) {
41147
0
                el = JS_ToLocaleStringFree(ctx, el);
41148
0
            }
41149
0
            if (string_buffer_concat_value_free(b, el))
41150
0
                goto fail;
41151
0
        }
41152
0
    }
41153
0
    JS_FreeValue(ctx, sep);
41154
0
    JS_FreeValue(ctx, obj);
41155
0
    return string_buffer_end(b);
41156
41157
0
fail:
41158
0
    string_buffer_free(b);
41159
0
    JS_FreeValue(ctx, sep);
41160
0
exception:
41161
0
    JS_FreeValue(ctx, obj);
41162
0
    return JS_EXCEPTION;
41163
0
}
41164
41165
static JSValue js_array_pop(JSContext *ctx, JSValueConst this_val,
41166
                            int argc, JSValueConst *argv, int shift)
41167
0
{
41168
0
    JSValue obj, res = JS_UNDEFINED;
41169
0
    int64_t len, newLen;
41170
0
    JSValue *arrp;
41171
0
    uint32_t count32;
41172
41173
0
    obj = JS_ToObject(ctx, this_val);
41174
0
    if (js_get_length64(ctx, &len, obj))
41175
0
        goto exception;
41176
0
    newLen = 0;
41177
0
    if (len > 0) {
41178
0
        newLen = len - 1;
41179
        /* Special case fast arrays */
41180
0
        if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
41181
0
            JSObject *p = JS_VALUE_GET_OBJ(obj);
41182
0
            if (shift) {
41183
0
                res = arrp[0];
41184
0
                memmove(arrp, arrp + 1, (count32 - 1) * sizeof(*arrp));
41185
0
                p->u.array.count--;
41186
0
            } else {
41187
0
                res = arrp[count32 - 1];
41188
0
                p->u.array.count--;
41189
0
            }
41190
0
        } else {
41191
0
            if (shift) {
41192
0
                res = JS_GetPropertyInt64(ctx, obj, 0);
41193
0
                if (JS_IsException(res))
41194
0
                    goto exception;
41195
0
                if (JS_CopySubArray(ctx, obj, 0, 1, len - 1, +1))
41196
0
                    goto exception;
41197
0
            } else {
41198
0
                res = JS_GetPropertyInt64(ctx, obj, newLen);
41199
0
                if (JS_IsException(res))
41200
0
                    goto exception;
41201
0
            }
41202
0
            if (JS_DeletePropertyInt64(ctx, obj, newLen, JS_PROP_THROW) < 0)
41203
0
                goto exception;
41204
0
        }
41205
0
    }
41206
0
    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
41207
0
        goto exception;
41208
41209
0
    JS_FreeValue(ctx, obj);
41210
0
    return res;
41211
41212
0
 exception:
41213
0
    JS_FreeValue(ctx, res);
41214
0
    JS_FreeValue(ctx, obj);
41215
0
    return JS_EXCEPTION;
41216
0
}
41217
41218
static JSValue js_array_push(JSContext *ctx, JSValueConst this_val,
41219
                             int argc, JSValueConst *argv, int unshift)
41220
0
{
41221
0
    JSValue obj;
41222
0
    int i;
41223
0
    int64_t len, from, newLen;
41224
41225
0
    obj = JS_ToObject(ctx, this_val);
41226
0
    if (js_get_length64(ctx, &len, obj))
41227
0
        goto exception;
41228
0
    newLen = len + argc;
41229
0
    if (newLen > MAX_SAFE_INTEGER) {
41230
0
        JS_ThrowTypeError(ctx, "Array loo long");
41231
0
        goto exception;
41232
0
    }
41233
0
    from = len;
41234
0
    if (unshift && argc > 0) {
41235
0
        if (JS_CopySubArray(ctx, obj, argc, 0, len, -1))
41236
0
            goto exception;
41237
0
        from = 0;
41238
0
    }
41239
0
    for(i = 0; i < argc; i++) {
41240
0
        if (JS_SetPropertyInt64(ctx, obj, from + i,
41241
0
                                JS_DupValue(ctx, argv[i])) < 0)
41242
0
            goto exception;
41243
0
    }
41244
0
    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
41245
0
        goto exception;
41246
41247
0
    JS_FreeValue(ctx, obj);
41248
0
    return JS_NewInt64(ctx, newLen);
41249
41250
0
 exception:
41251
0
    JS_FreeValue(ctx, obj);
41252
0
    return JS_EXCEPTION;
41253
0
}
41254
41255
static JSValue js_array_reverse(JSContext *ctx, JSValueConst this_val,
41256
                                int argc, JSValueConst *argv)
41257
0
{
41258
0
    JSValue obj, lval, hval;
41259
0
    JSValue *arrp;
41260
0
    int64_t len, l, h;
41261
0
    int l_present, h_present;
41262
0
    uint32_t count32;
41263
41264
0
    lval = JS_UNDEFINED;
41265
0
    obj = JS_ToObject(ctx, this_val);
41266
0
    if (js_get_length64(ctx, &len, obj))
41267
0
        goto exception;
41268
41269
    /* Special case fast arrays */
41270
0
    if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
41271
0
        uint32_t ll, hh;
41272
41273
0
        if (count32 > 1) {
41274
0
            for (ll = 0, hh = count32 - 1; ll < hh; ll++, hh--) {
41275
0
                lval = arrp[ll];
41276
0
                arrp[ll] = arrp[hh];
41277
0
                arrp[hh] = lval;
41278
0
            }
41279
0
        }
41280
0
        return obj;
41281
0
    }
41282
41283
0
    for (l = 0, h = len - 1; l < h; l++, h--) {
41284
0
        l_present = JS_TryGetPropertyInt64(ctx, obj, l, &lval);
41285
0
        if (l_present < 0)
41286
0
            goto exception;
41287
0
        h_present = JS_TryGetPropertyInt64(ctx, obj, h, &hval);
41288
0
        if (h_present < 0)
41289
0
            goto exception;
41290
0
        if (h_present) {
41291
0
            if (JS_SetPropertyInt64(ctx, obj, l, hval) < 0)
41292
0
                goto exception;
41293
41294
0
            if (l_present) {
41295
0
                if (JS_SetPropertyInt64(ctx, obj, h, lval) < 0) {
41296
0
                    lval = JS_UNDEFINED;
41297
0
                    goto exception;
41298
0
                }
41299
0
                lval = JS_UNDEFINED;
41300
0
            } else {
41301
0
                if (JS_DeletePropertyInt64(ctx, obj, h, JS_PROP_THROW) < 0)
41302
0
                    goto exception;
41303
0
            }
41304
0
        } else {
41305
0
            if (l_present) {
41306
0
                if (JS_DeletePropertyInt64(ctx, obj, l, JS_PROP_THROW) < 0)
41307
0
                    goto exception;
41308
0
                if (JS_SetPropertyInt64(ctx, obj, h, lval) < 0) {
41309
0
                    lval = JS_UNDEFINED;
41310
0
                    goto exception;
41311
0
                }
41312
0
                lval = JS_UNDEFINED;
41313
0
            }
41314
0
        }
41315
0
    }
41316
0
    return obj;
41317
41318
0
 exception:
41319
0
    JS_FreeValue(ctx, lval);
41320
0
    JS_FreeValue(ctx, obj);
41321
0
    return JS_EXCEPTION;
41322
0
}
41323
41324
// Note: a.toReversed() is a.slice().reverse() with the twist that a.slice()
41325
// leaves holes in sparse arrays intact whereas a.toReversed() replaces them
41326
// with undefined, thus in effect creating a dense array.
41327
// Does not use Array[@@species], always returns a base Array.
41328
static JSValue js_array_toReversed(JSContext *ctx, JSValueConst this_val,
41329
                                   int argc, JSValueConst *argv)
41330
0
{
41331
0
    JSValue arr, obj, ret, *arrp, *pval;
41332
0
    JSObject *p;
41333
0
    int64_t i, len;
41334
0
    uint32_t count32;
41335
41336
0
    ret = JS_EXCEPTION;
41337
0
    arr = JS_UNDEFINED;
41338
0
    obj = JS_ToObject(ctx, this_val);
41339
0
    if (js_get_length64(ctx, &len, obj))
41340
0
        goto exception;
41341
41342
0
    arr = js_allocate_fast_array(ctx, len);
41343
0
    if (JS_IsException(arr))
41344
0
        goto exception;
41345
41346
0
    if (len > 0) {
41347
0
        p = JS_VALUE_GET_OBJ(arr);
41348
41349
0
        i = len - 1;
41350
0
        pval = p->u.array.u.values;
41351
0
        if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
41352
0
            for (; i >= 0; i--, pval++)
41353
0
                *pval = JS_DupValue(ctx, arrp[i]);
41354
0
        } else {
41355
            // Query order is observable; test262 expects descending order.
41356
0
            for (; i >= 0; i--, pval++) {
41357
0
                if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) {
41358
                    // Exception; initialize remaining elements.
41359
0
                    for (; i >= 0; i--, pval++)
41360
0
                        *pval = JS_UNDEFINED;
41361
0
                    goto exception;
41362
0
                }
41363
0
            }
41364
0
        }
41365
41366
0
        if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0)
41367
0
            goto exception;
41368
0
    }
41369
41370
0
    ret = arr;
41371
0
    arr = JS_UNDEFINED;
41372
41373
0
exception:
41374
0
    JS_FreeValue(ctx, arr);
41375
0
    JS_FreeValue(ctx, obj);
41376
0
    return ret;
41377
0
}
41378
41379
static JSValue js_array_slice(JSContext *ctx, JSValueConst this_val,
41380
                              int argc, JSValueConst *argv, int splice)
41381
0
{
41382
0
    JSValue obj, arr, val, len_val;
41383
0
    int64_t len, start, k, final, n, count, del_count, new_len;
41384
0
    int kPresent;
41385
0
    JSValue *arrp;
41386
0
    uint32_t count32, i, item_count;
41387
41388
0
    arr = JS_UNDEFINED;
41389
0
    obj = JS_ToObject(ctx, this_val);
41390
0
    if (js_get_length64(ctx, &len, obj))
41391
0
        goto exception;
41392
41393
0
    if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
41394
0
        goto exception;
41395
41396
0
    if (splice) {
41397
0
        if (argc == 0) {
41398
0
            item_count = 0;
41399
0
            del_count = 0;
41400
0
        } else
41401
0
        if (argc == 1) {
41402
0
            item_count = 0;
41403
0
            del_count = len - start;
41404
0
        } else {
41405
0
            item_count = argc - 2;
41406
0
            if (JS_ToInt64Clamp(ctx, &del_count, argv[1], 0, len - start, 0))
41407
0
                goto exception;
41408
0
        }
41409
0
        if (len + item_count - del_count > MAX_SAFE_INTEGER) {
41410
0
            JS_ThrowTypeError(ctx, "Array loo long");
41411
0
            goto exception;
41412
0
        }
41413
0
        count = del_count;
41414
0
    } else {
41415
0
        item_count = 0; /* avoid warning */
41416
0
        final = len;
41417
0
        if (!JS_IsUndefined(argv[1])) {
41418
0
            if (JS_ToInt64Clamp(ctx, &final, argv[1], 0, len, len))
41419
0
                goto exception;
41420
0
        }
41421
0
        count = max_int64(final - start, 0);
41422
0
    }
41423
0
    len_val = JS_NewInt64(ctx, count);
41424
0
    arr = JS_ArraySpeciesCreate(ctx, obj, len_val);
41425
0
    JS_FreeValue(ctx, len_val);
41426
0
    if (JS_IsException(arr))
41427
0
        goto exception;
41428
41429
0
    k = start;
41430
0
    final = start + count;
41431
0
    n = 0;
41432
    /* The fast array test on arr ensures that
41433
       JS_CreateDataPropertyUint32() won't modify obj in case arr is
41434
       an exotic object */
41435
    /* Special case fast arrays */
41436
0
    if (js_get_fast_array(ctx, obj, &arrp, &count32) &&
41437
0
        js_is_fast_array(ctx, arr)) {
41438
        /* XXX: should share code with fast array constructor */
41439
0
        for (; k < final && k < count32; k++, n++) {
41440
0
            if (JS_CreateDataPropertyUint32(ctx, arr, n, JS_DupValue(ctx, arrp[k]), JS_PROP_THROW) < 0)
41441
0
                goto exception;
41442
0
        }
41443
0
    }
41444
    /* Copy the remaining elements if any (handle case of inherited properties) */
41445
0
    for (; k < final; k++, n++) {
41446
0
        kPresent = JS_TryGetPropertyInt64(ctx, obj, k, &val);
41447
0
        if (kPresent < 0)
41448
0
            goto exception;
41449
0
        if (kPresent) {
41450
0
            if (JS_CreateDataPropertyUint32(ctx, arr, n, val, JS_PROP_THROW) < 0)
41451
0
                goto exception;
41452
0
        }
41453
0
    }
41454
0
    if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0)
41455
0
        goto exception;
41456
41457
0
    if (splice) {
41458
0
        new_len = len + item_count - del_count;
41459
0
        if (item_count != del_count) {
41460
0
            if (JS_CopySubArray(ctx, obj, start + item_count,
41461
0
                                start + del_count, len - (start + del_count),
41462
0
                                item_count <= del_count ? +1 : -1) < 0)
41463
0
                goto exception;
41464
41465
0
            for (k = len; k-- > new_len; ) {
41466
0
                if (JS_DeletePropertyInt64(ctx, obj, k, JS_PROP_THROW) < 0)
41467
0
                    goto exception;
41468
0
            }
41469
0
        }
41470
0
        for (i = 0; i < item_count; i++) {
41471
0
            if (JS_SetPropertyInt64(ctx, obj, start + i, JS_DupValue(ctx, argv[i + 2])) < 0)
41472
0
                goto exception;
41473
0
        }
41474
0
        if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, new_len)) < 0)
41475
0
            goto exception;
41476
0
    }
41477
0
    JS_FreeValue(ctx, obj);
41478
0
    return arr;
41479
41480
0
 exception:
41481
0
    JS_FreeValue(ctx, obj);
41482
0
    JS_FreeValue(ctx, arr);
41483
0
    return JS_EXCEPTION;
41484
0
}
41485
41486
static JSValue js_array_toSpliced(JSContext *ctx, JSValueConst this_val,
41487
                                  int argc, JSValueConst *argv)
41488
0
{
41489
0
    JSValue arr, obj, ret, *arrp, *pval, *last;
41490
0
    JSObject *p;
41491
0
    int64_t i, j, len, newlen, start, add, del;
41492
0
    uint32_t count32;
41493
41494
0
    pval = NULL;
41495
0
    last = NULL;
41496
0
    ret = JS_EXCEPTION;
41497
0
    arr = JS_UNDEFINED;
41498
41499
0
    obj = JS_ToObject(ctx, this_val);
41500
0
    if (js_get_length64(ctx, &len, obj))
41501
0
        goto exception;
41502
41503
0
    start = 0;
41504
0
    if (argc > 0)
41505
0
        if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
41506
0
            goto exception;
41507
41508
0
    del = 0;
41509
0
    if (argc > 0)
41510
0
        del = len - start;
41511
0
    if (argc > 1)
41512
0
        if (JS_ToInt64Clamp(ctx, &del, argv[1], 0, del, 0))
41513
0
            goto exception;
41514
41515
0
    add = 0;
41516
0
    if (argc > 2)
41517
0
        add = argc - 2;
41518
41519
0
    newlen = len + add - del;
41520
0
    if (newlen > MAX_SAFE_INTEGER) {
41521
0
        JS_ThrowTypeError(ctx, "invalid array length");
41522
0
        goto exception;
41523
0
    }
41524
41525
0
    arr = js_allocate_fast_array(ctx, newlen);
41526
0
    if (JS_IsException(arr))
41527
0
        goto exception;
41528
41529
0
    if (newlen <= 0)
41530
0
        goto done;
41531
41532
0
    p = JS_VALUE_GET_OBJ(arr);
41533
0
    pval = &p->u.array.u.values[0];
41534
0
    last = &p->u.array.u.values[newlen];
41535
41536
0
    if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
41537
0
        for (i = 0; i < start; i++, pval++)
41538
0
            *pval = JS_DupValue(ctx, arrp[i]);
41539
0
        for (j = 0; j < add; j++, pval++)
41540
0
            *pval = JS_DupValue(ctx, argv[2 + j]);
41541
0
        for (i += del; i < len; i++, pval++)
41542
0
            *pval = JS_DupValue(ctx, arrp[i]);
41543
0
    } else {
41544
0
        for (i = 0; i < start; i++, pval++)
41545
0
            if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
41546
0
                goto exception;
41547
0
        for (j = 0; j < add; j++, pval++)
41548
0
            *pval = JS_DupValue(ctx, argv[2 + j]);
41549
0
        for (i += del; i < len; i++, pval++)
41550
0
            if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))
41551
0
                goto exception;
41552
0
    }
41553
41554
0
    assert(pval == last);
41555
41556
0
    if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, newlen)) < 0)
41557
0
        goto exception;
41558
41559
0
done:
41560
0
    ret = arr;
41561
0
    arr = JS_UNDEFINED;
41562
41563
0
exception:
41564
0
    while (pval != last)
41565
0
        *pval++ = JS_UNDEFINED;
41566
41567
0
    JS_FreeValue(ctx, arr);
41568
0
    JS_FreeValue(ctx, obj);
41569
0
    return ret;
41570
0
}
41571
41572
static JSValue js_array_copyWithin(JSContext *ctx, JSValueConst this_val,
41573
                                   int argc, JSValueConst *argv)
41574
0
{
41575
0
    JSValue obj;
41576
0
    int64_t len, from, to, final, count;
41577
41578
0
    obj = JS_ToObject(ctx, this_val);
41579
0
    if (js_get_length64(ctx, &len, obj))
41580
0
        goto exception;
41581
41582
0
    if (JS_ToInt64Clamp(ctx, &to, argv[0], 0, len, len))
41583
0
        goto exception;
41584
41585
0
    if (JS_ToInt64Clamp(ctx, &from, argv[1], 0, len, len))
41586
0
        goto exception;
41587
41588
0
    final = len;
41589
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
41590
0
        if (JS_ToInt64Clamp(ctx, &final, argv[2], 0, len, len))
41591
0
            goto exception;
41592
0
    }
41593
41594
0
    count = min_int64(final - from, len - to);
41595
41596
0
    if (JS_CopySubArray(ctx, obj, to, from, count,
41597
0
                        (from < to && to < from + count) ? -1 : +1))
41598
0
        goto exception;
41599
41600
0
    return obj;
41601
41602
0
 exception:
41603
0
    JS_FreeValue(ctx, obj);
41604
0
    return JS_EXCEPTION;
41605
0
}
41606
41607
static int64_t JS_FlattenIntoArray(JSContext *ctx, JSValueConst target,
41608
                                   JSValueConst source, int64_t sourceLen,
41609
                                   int64_t targetIndex, int depth,
41610
                                   JSValueConst mapperFunction,
41611
                                   JSValueConst thisArg)
41612
0
{
41613
0
    JSValue element;
41614
0
    int64_t sourceIndex, elementLen;
41615
0
    int present, is_array;
41616
41617
0
    if (js_check_stack_overflow(ctx->rt, 0)) {
41618
0
        JS_ThrowStackOverflow(ctx);
41619
0
        return -1;
41620
0
    }
41621
41622
0
    for (sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) {
41623
0
        present = JS_TryGetPropertyInt64(ctx, source, sourceIndex, &element);
41624
0
        if (present < 0)
41625
0
            return -1;
41626
0
        if (!present)
41627
0
            continue;
41628
0
        if (!JS_IsUndefined(mapperFunction)) {
41629
0
            JSValueConst args[3] = { element, JS_NewInt64(ctx, sourceIndex), source };
41630
0
            element = JS_Call(ctx, mapperFunction, thisArg, 3, args);
41631
0
            JS_FreeValue(ctx, (JSValue)args[0]);
41632
0
            JS_FreeValue(ctx, (JSValue)args[1]);
41633
0
            if (JS_IsException(element))
41634
0
                return -1;
41635
0
        }
41636
0
        if (depth > 0) {
41637
0
            is_array = JS_IsArray(ctx, element);
41638
0
            if (is_array < 0)
41639
0
                goto fail;
41640
0
            if (is_array) {
41641
0
                if (js_get_length64(ctx, &elementLen, element) < 0)
41642
0
                    goto fail;
41643
0
                targetIndex = JS_FlattenIntoArray(ctx, target, element,
41644
0
                                                  elementLen, targetIndex,
41645
0
                                                  depth - 1,
41646
0
                                                  JS_UNDEFINED, JS_UNDEFINED);
41647
0
                if (targetIndex < 0)
41648
0
                    goto fail;
41649
0
                JS_FreeValue(ctx, element);
41650
0
                continue;
41651
0
            }
41652
0
        }
41653
0
        if (targetIndex >= MAX_SAFE_INTEGER) {
41654
0
            JS_ThrowTypeError(ctx, "Array too long");
41655
0
            goto fail;
41656
0
        }
41657
0
        if (JS_DefinePropertyValueInt64(ctx, target, targetIndex, element,
41658
0
                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)
41659
0
            return -1;
41660
0
        targetIndex++;
41661
0
    }
41662
0
    return targetIndex;
41663
41664
0
fail:
41665
0
    JS_FreeValue(ctx, element);
41666
0
    return -1;
41667
0
}
41668
41669
static JSValue js_array_flatten(JSContext *ctx, JSValueConst this_val,
41670
                                int argc, JSValueConst *argv, int map)
41671
0
{
41672
0
    JSValue obj, arr;
41673
0
    JSValueConst mapperFunction, thisArg;
41674
0
    int64_t sourceLen;
41675
0
    int depthNum;
41676
41677
0
    arr = JS_UNDEFINED;
41678
0
    obj = JS_ToObject(ctx, this_val);
41679
0
    if (js_get_length64(ctx, &sourceLen, obj))
41680
0
        goto exception;
41681
41682
0
    depthNum = 1;
41683
0
    mapperFunction = JS_UNDEFINED;
41684
0
    thisArg = JS_UNDEFINED;
41685
0
    if (map) {
41686
0
        mapperFunction = argv[0];
41687
0
        if (argc > 1) {
41688
0
            thisArg = argv[1];
41689
0
        }
41690
0
        if (check_function(ctx, mapperFunction))
41691
0
            goto exception;
41692
0
    } else {
41693
0
        if (argc > 0 && !JS_IsUndefined(argv[0])) {
41694
0
            if (JS_ToInt32Sat(ctx, &depthNum, argv[0]) < 0)
41695
0
                goto exception;
41696
0
        }
41697
0
    }
41698
0
    arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));
41699
0
    if (JS_IsException(arr))
41700
0
        goto exception;
41701
0
    if (JS_FlattenIntoArray(ctx, arr, obj, sourceLen, 0, depthNum,
41702
0
                            mapperFunction, thisArg) < 0)
41703
0
        goto exception;
41704
0
    JS_FreeValue(ctx, obj);
41705
0
    return arr;
41706
41707
0
exception:
41708
0
    JS_FreeValue(ctx, obj);
41709
0
    JS_FreeValue(ctx, arr);
41710
0
    return JS_EXCEPTION;
41711
0
}
41712
41713
/* Array sort */
41714
41715
typedef struct ValueSlot {
41716
    JSValue val;
41717
    JSString *str;
41718
    int64_t pos;
41719
} ValueSlot;
41720
41721
struct array_sort_context {
41722
    JSContext *ctx;
41723
    int exception;
41724
    int has_method;
41725
    JSValueConst method;
41726
};
41727
41728
0
static int js_array_cmp_generic(const void *a, const void *b, void *opaque) {
41729
0
    struct array_sort_context *psc = opaque;
41730
0
    JSContext *ctx = psc->ctx;
41731
0
    JSValueConst argv[2];
41732
0
    JSValue res;
41733
0
    ValueSlot *ap = (ValueSlot *)(void *)a;
41734
0
    ValueSlot *bp = (ValueSlot *)(void *)b;
41735
0
    int cmp;
41736
41737
0
    if (psc->exception)
41738
0
        return 0;
41739
41740
0
    if (psc->has_method) {
41741
        /* custom sort function is specified as returning 0 for identical
41742
         * objects: avoid method call overhead.
41743
         */
41744
0
        if (!memcmp(&ap->val, &bp->val, sizeof(ap->val)))
41745
0
            goto cmp_same;
41746
0
        argv[0] = ap->val;
41747
0
        argv[1] = bp->val;
41748
0
        res = JS_Call(ctx, psc->method, JS_UNDEFINED, 2, argv);
41749
0
        if (JS_IsException(res))
41750
0
            goto exception;
41751
0
        if (JS_VALUE_GET_TAG(res) == JS_TAG_INT) {
41752
0
            int val = JS_VALUE_GET_INT(res);
41753
0
            cmp = (val > 0) - (val < 0);
41754
0
        } else {
41755
0
            double val;
41756
0
            if (JS_ToFloat64Free(ctx, &val, res) < 0)
41757
0
                goto exception;
41758
0
            cmp = (val > 0) - (val < 0);
41759
0
        }
41760
0
    } else {
41761
        /* Not supposed to bypass ToString even for identical objects as
41762
         * tested in test262/test/built-ins/Array/prototype/sort/bug_596_1.js
41763
         */
41764
0
        if (!ap->str) {
41765
0
            JSValue str = JS_ToString(ctx, ap->val);
41766
0
            if (JS_IsException(str))
41767
0
                goto exception;
41768
0
            ap->str = JS_VALUE_GET_STRING(str);
41769
0
        }
41770
0
        if (!bp->str) {
41771
0
            JSValue str = JS_ToString(ctx, bp->val);
41772
0
            if (JS_IsException(str))
41773
0
                goto exception;
41774
0
            bp->str = JS_VALUE_GET_STRING(str);
41775
0
        }
41776
0
        cmp = js_string_compare(ctx, ap->str, bp->str);
41777
0
    }
41778
0
    if (cmp != 0)
41779
0
        return cmp;
41780
0
cmp_same:
41781
    /* make sort stable: compare array offsets */
41782
0
    return (ap->pos > bp->pos) - (ap->pos < bp->pos);
41783
41784
0
exception:
41785
0
    psc->exception = 1;
41786
0
    return 0;
41787
0
}
41788
41789
static JSValue js_array_sort(JSContext *ctx, JSValueConst this_val,
41790
                             int argc, JSValueConst *argv)
41791
0
{
41792
0
    struct array_sort_context asc = { ctx, 0, 0, argv[0] };
41793
0
    JSValue obj = JS_UNDEFINED;
41794
0
    ValueSlot *array = NULL;
41795
0
    size_t array_size = 0, pos = 0, n = 0;
41796
0
    int64_t i, len, undefined_count = 0;
41797
0
    int present;
41798
41799
0
    if (!JS_IsUndefined(asc.method)) {
41800
0
        if (check_function(ctx, asc.method))
41801
0
            goto exception;
41802
0
        asc.has_method = 1;
41803
0
    }
41804
0
    obj = JS_ToObject(ctx, this_val);
41805
0
    if (js_get_length64(ctx, &len, obj))
41806
0
        goto exception;
41807
41808
    /* XXX: should special case fast arrays */
41809
0
    for (i = 0; i < len; i++) {
41810
0
        if (pos >= array_size) {
41811
0
            size_t new_size, slack;
41812
0
            ValueSlot *new_array;
41813
0
            new_size = (array_size + (array_size >> 1) + 31) & ~15;
41814
0
            new_array = js_realloc2(ctx, array, new_size * sizeof(*array), &slack);
41815
0
            if (new_array == NULL)
41816
0
                goto exception;
41817
0
            new_size += slack / sizeof(*new_array);
41818
0
            array = new_array;
41819
0
            array_size = new_size;
41820
0
        }
41821
0
        present = JS_TryGetPropertyInt64(ctx, obj, i, &array[pos].val);
41822
0
        if (present < 0)
41823
0
            goto exception;
41824
0
        if (present == 0)
41825
0
            continue;
41826
0
        if (JS_IsUndefined(array[pos].val)) {
41827
0
            undefined_count++;
41828
0
            continue;
41829
0
        }
41830
0
        array[pos].str = NULL;
41831
0
        array[pos].pos = i;
41832
0
        pos++;
41833
0
    }
41834
0
    rqsort(array, pos, sizeof(*array), js_array_cmp_generic, &asc);
41835
0
    if (asc.exception)
41836
0
        goto exception;
41837
41838
    /* XXX: should special case fast arrays */
41839
0
    while (n < pos) {
41840
0
        if (array[n].str)
41841
0
            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, array[n].str));
41842
0
        if (array[n].pos == n) {
41843
0
            JS_FreeValue(ctx, array[n].val);
41844
0
        } else {
41845
0
            if (JS_SetPropertyInt64(ctx, obj, n, array[n].val) < 0) {
41846
0
                n++;
41847
0
                goto exception;
41848
0
            }
41849
0
        }
41850
0
        n++;
41851
0
    }
41852
0
    js_free(ctx, array);
41853
0
    for (i = n; undefined_count-- > 0; i++) {
41854
0
        if (JS_SetPropertyInt64(ctx, obj, i, JS_UNDEFINED) < 0)
41855
0
            goto fail;
41856
0
    }
41857
0
    for (; i < len; i++) {
41858
0
        if (JS_DeletePropertyInt64(ctx, obj, i, JS_PROP_THROW) < 0)
41859
0
            goto fail;
41860
0
    }
41861
0
    return obj;
41862
41863
0
exception:
41864
0
    for (; n < pos; n++) {
41865
0
        JS_FreeValue(ctx, array[n].val);
41866
0
        if (array[n].str)
41867
0
            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, array[n].str));
41868
0
    }
41869
0
    js_free(ctx, array);
41870
0
fail:
41871
0
    JS_FreeValue(ctx, obj);
41872
0
    return JS_EXCEPTION;
41873
0
}
41874
41875
// Note: a.toSorted() is a.slice().sort() with the twist that a.slice()
41876
// leaves holes in sparse arrays intact whereas a.toSorted() replaces them
41877
// with undefined, thus in effect creating a dense array.
41878
// Does not use Array[@@species], always returns a base Array.
41879
static JSValue js_array_toSorted(JSContext *ctx, JSValueConst this_val,
41880
                                 int argc, JSValueConst *argv)
41881
0
{
41882
0
    JSValue arr, obj, ret, *arrp, *pval;
41883
0
    JSObject *p;
41884
0
    int64_t i, len;
41885
0
    uint32_t count32;
41886
0
    int ok;
41887
41888
0
    ok = JS_IsUndefined(argv[0]) || JS_IsFunction(ctx, argv[0]);
41889
0
    if (!ok)
41890
0
        return JS_ThrowTypeError(ctx, "not a function");
41891
41892
0
    ret = JS_EXCEPTION;
41893
0
    arr = JS_UNDEFINED;
41894
0
    obj = JS_ToObject(ctx, this_val);
41895
0
    if (js_get_length64(ctx, &len, obj))
41896
0
        goto exception;
41897
41898
0
    arr = js_allocate_fast_array(ctx, len);
41899
0
    if (JS_IsException(arr))
41900
0
        goto exception;
41901
41902
0
    if (len > 0) {
41903
0
        p = JS_VALUE_GET_OBJ(arr);
41904
0
        i = 0;
41905
0
        pval = p->u.array.u.values;
41906
0
        if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {
41907
0
            for (; i < len; i++, pval++)
41908
0
                *pval = JS_DupValue(ctx, arrp[i]);
41909
0
        } else {
41910
0
            for (; i < len; i++, pval++) {
41911
0
                if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) {
41912
0
                    for (; i < len; i++, pval++)
41913
0
                        *pval = JS_UNDEFINED;
41914
0
                    goto exception;
41915
0
                }
41916
0
            }
41917
0
        }
41918
41919
0
        if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0)
41920
0
            goto exception;
41921
0
    }
41922
41923
0
    ret = js_array_sort(ctx, arr, argc, argv);
41924
0
    if (JS_IsException(ret))
41925
0
        goto exception;
41926
0
    JS_FreeValue(ctx, ret);
41927
41928
0
    ret = arr;
41929
0
    arr = JS_UNDEFINED;
41930
41931
0
exception:
41932
0
    JS_FreeValue(ctx, arr);
41933
0
    JS_FreeValue(ctx, obj);
41934
0
    return ret;
41935
0
}
41936
41937
typedef struct JSArrayIteratorData {
41938
    JSValue obj;
41939
    JSIteratorKindEnum kind;
41940
    uint32_t idx;
41941
} JSArrayIteratorData;
41942
41943
static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val)
41944
0
{
41945
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
41946
0
    JSArrayIteratorData *it = p->u.array_iterator_data;
41947
0
    if (it) {
41948
0
        JS_FreeValueRT(rt, it->obj);
41949
0
        js_free_rt(rt, it);
41950
0
    }
41951
0
}
41952
41953
static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val,
41954
                                   JS_MarkFunc *mark_func)
41955
0
{
41956
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
41957
0
    JSArrayIteratorData *it = p->u.array_iterator_data;
41958
0
    if (it) {
41959
0
        JS_MarkValue(rt, it->obj, mark_func);
41960
0
    }
41961
0
}
41962
41963
static JSValue js_create_array(JSContext *ctx, int len, JSValueConst *tab)
41964
0
{
41965
0
    JSValue obj;
41966
0
    int i;
41967
41968
0
    obj = JS_NewArray(ctx);
41969
0
    if (JS_IsException(obj))
41970
0
        return JS_EXCEPTION;
41971
0
    for(i = 0; i < len; i++) {
41972
0
        if (JS_CreateDataPropertyUint32(ctx, obj, i, JS_DupValue(ctx, tab[i]), 0) < 0) {
41973
0
            JS_FreeValue(ctx, obj);
41974
0
            return JS_EXCEPTION;
41975
0
        }
41976
0
    }
41977
0
    return obj;
41978
0
}
41979
41980
static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val,
41981
                                        int argc, JSValueConst *argv, int magic)
41982
0
{
41983
0
    JSValue enum_obj, arr;
41984
0
    JSArrayIteratorData *it;
41985
0
    JSIteratorKindEnum kind;
41986
0
    int class_id;
41987
41988
0
    kind = magic & 3;
41989
0
    if (magic & 4) {
41990
        /* string iterator case */
41991
0
        arr = JS_ToStringCheckObject(ctx, this_val);
41992
0
        class_id = JS_CLASS_STRING_ITERATOR;
41993
0
    } else {
41994
0
        arr = JS_ToObject(ctx, this_val);
41995
0
        class_id = JS_CLASS_ARRAY_ITERATOR;
41996
0
    }
41997
0
    if (JS_IsException(arr))
41998
0
        goto fail;
41999
0
    enum_obj = JS_NewObjectClass(ctx, class_id);
42000
0
    if (JS_IsException(enum_obj))
42001
0
        goto fail;
42002
0
    it = js_malloc(ctx, sizeof(*it));
42003
0
    if (!it)
42004
0
        goto fail1;
42005
0
    it->obj = arr;
42006
0
    it->kind = kind;
42007
0
    it->idx = 0;
42008
0
    JS_SetOpaque(enum_obj, it);
42009
0
    return enum_obj;
42010
0
 fail1:
42011
0
    JS_FreeValue(ctx, enum_obj);
42012
0
 fail:
42013
0
    JS_FreeValue(ctx, arr);
42014
0
    return JS_EXCEPTION;
42015
0
}
42016
42017
static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val,
42018
                                      int argc, JSValueConst *argv,
42019
                                      BOOL *pdone, int magic)
42020
0
{
42021
0
    JSArrayIteratorData *it;
42022
0
    uint32_t len, idx;
42023
0
    JSValue val, obj;
42024
0
    JSObject *p;
42025
42026
0
    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_ITERATOR);
42027
0
    if (!it)
42028
0
        goto fail1;
42029
0
    if (JS_IsUndefined(it->obj))
42030
0
        goto done;
42031
0
    p = JS_VALUE_GET_OBJ(it->obj);
42032
0
    if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
42033
0
        p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
42034
0
        if (typed_array_is_detached(ctx, p)) {
42035
0
            JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
42036
0
            goto fail1;
42037
0
        }
42038
0
        len = p->u.array.count;
42039
0
    } else {
42040
0
        if (js_get_length32(ctx, &len, it->obj)) {
42041
0
        fail1:
42042
0
            *pdone = FALSE;
42043
0
            return JS_EXCEPTION;
42044
0
        }
42045
0
    }
42046
0
    idx = it->idx;
42047
0
    if (idx >= len) {
42048
0
        JS_FreeValue(ctx, it->obj);
42049
0
        it->obj = JS_UNDEFINED;
42050
0
    done:
42051
0
        *pdone = TRUE;
42052
0
        return JS_UNDEFINED;
42053
0
    }
42054
0
    it->idx = idx + 1;
42055
0
    *pdone = FALSE;
42056
0
    if (it->kind == JS_ITERATOR_KIND_KEY) {
42057
0
        return JS_NewUint32(ctx, idx);
42058
0
    } else {
42059
0
        val = JS_GetPropertyUint32(ctx, it->obj, idx);
42060
0
        if (JS_IsException(val))
42061
0
            return JS_EXCEPTION;
42062
0
        if (it->kind == JS_ITERATOR_KIND_VALUE) {
42063
0
            return val;
42064
0
        } else {
42065
0
            JSValueConst args[2];
42066
0
            JSValue num;
42067
0
            num = JS_NewUint32(ctx, idx);
42068
0
            args[0] = num;
42069
0
            args[1] = val;
42070
0
            obj = js_create_array(ctx, 2, args);
42071
0
            JS_FreeValue(ctx, val);
42072
0
            JS_FreeValue(ctx, num);
42073
0
            return obj;
42074
0
        }
42075
0
    }
42076
0
}
42077
42078
static JSValue js_iterator_proto_iterator(JSContext *ctx, JSValueConst this_val,
42079
                                          int argc, JSValueConst *argv)
42080
0
{
42081
0
    return JS_DupValue(ctx, this_val);
42082
0
}
42083
42084
static const JSCFunctionListEntry js_iterator_proto_funcs[] = {
42085
    JS_CFUNC_DEF("[Symbol.iterator]", 0, js_iterator_proto_iterator ),
42086
};
42087
42088
static const JSCFunctionListEntry js_array_proto_funcs[] = {
42089
    JS_CFUNC_DEF("at", 1, js_array_at ),
42090
    JS_CFUNC_DEF("with", 2, js_array_with ),
42091
    JS_CFUNC_DEF("concat", 1, js_array_concat ),
42092
    JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every ),
42093
    JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some ),
42094
    JS_CFUNC_MAGIC_DEF("forEach", 1, js_array_every, special_forEach ),
42095
    JS_CFUNC_MAGIC_DEF("map", 1, js_array_every, special_map ),
42096
    JS_CFUNC_MAGIC_DEF("filter", 1, js_array_every, special_filter ),
42097
    JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce ),
42098
    JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight ),
42099
    JS_CFUNC_DEF("fill", 1, js_array_fill ),
42100
    JS_CFUNC_MAGIC_DEF("find", 1, js_array_find, ArrayFind ),
42101
    JS_CFUNC_MAGIC_DEF("findIndex", 1, js_array_find, ArrayFindIndex ),
42102
    JS_CFUNC_MAGIC_DEF("findLast", 1, js_array_find, ArrayFindLast ),
42103
    JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_array_find, ArrayFindLastIndex ),
42104
    JS_CFUNC_DEF("indexOf", 1, js_array_indexOf ),
42105
    JS_CFUNC_DEF("lastIndexOf", 1, js_array_lastIndexOf ),
42106
    JS_CFUNC_DEF("includes", 1, js_array_includes ),
42107
    JS_CFUNC_MAGIC_DEF("join", 1, js_array_join, 0 ),
42108
    JS_CFUNC_DEF("toString", 0, js_array_toString ),
42109
    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_array_join, 1 ),
42110
    JS_CFUNC_MAGIC_DEF("pop", 0, js_array_pop, 0 ),
42111
    JS_CFUNC_MAGIC_DEF("push", 1, js_array_push, 0 ),
42112
    JS_CFUNC_MAGIC_DEF("shift", 0, js_array_pop, 1 ),
42113
    JS_CFUNC_MAGIC_DEF("unshift", 1, js_array_push, 1 ),
42114
    JS_CFUNC_DEF("reverse", 0, js_array_reverse ),
42115
    JS_CFUNC_DEF("toReversed", 0, js_array_toReversed ),
42116
    JS_CFUNC_DEF("sort", 1, js_array_sort ),
42117
    JS_CFUNC_DEF("toSorted", 1, js_array_toSorted ),
42118
    JS_CFUNC_MAGIC_DEF("slice", 2, js_array_slice, 0 ),
42119
    JS_CFUNC_MAGIC_DEF("splice", 2, js_array_slice, 1 ),
42120
    JS_CFUNC_DEF("toSpliced", 2, js_array_toSpliced ),
42121
    JS_CFUNC_DEF("copyWithin", 2, js_array_copyWithin ),
42122
    JS_CFUNC_MAGIC_DEF("flatMap", 1, js_array_flatten, 1 ),
42123
    JS_CFUNC_MAGIC_DEF("flat", 0, js_array_flatten, 0 ),
42124
    JS_CFUNC_MAGIC_DEF("values", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE ),
42125
    JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
42126
    JS_CFUNC_MAGIC_DEF("keys", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY ),
42127
    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE ),
42128
};
42129
42130
static const JSCFunctionListEntry js_array_iterator_proto_funcs[] = {
42131
    JS_ITERATOR_NEXT_DEF("next", 0, js_array_iterator_next, 0 ),
42132
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Array Iterator", JS_PROP_CONFIGURABLE ),
42133
};
42134
42135
/* Number */
42136
42137
static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target,
42138
                                     int argc, JSValueConst *argv)
42139
0
{
42140
0
    JSValue val, obj;
42141
0
    if (argc == 0) {
42142
0
        val = JS_NewInt32(ctx, 0);
42143
0
    } else {
42144
0
        val = JS_ToNumeric(ctx, argv[0]);
42145
0
        if (JS_IsException(val))
42146
0
            return val;
42147
0
        switch(JS_VALUE_GET_TAG(val)) {
42148
0
        case JS_TAG_SHORT_BIG_INT:
42149
0
            val = JS_NewInt64(ctx, JS_VALUE_GET_SHORT_BIG_INT(val));
42150
0
            if (JS_IsException(val))
42151
0
                return val;
42152
0
            break;
42153
0
        case JS_TAG_BIG_INT:
42154
0
            {
42155
0
                JSBigInt *p = JS_VALUE_GET_PTR(val);
42156
0
                double d;
42157
0
                d = js_bigint_to_float64(ctx, p);
42158
0
                JS_FreeValue(ctx, val);
42159
0
                val = JS_NewFloat64(ctx, d);
42160
0
            }
42161
0
            break;
42162
0
        default:
42163
0
            break;
42164
0
        }
42165
0
    }
42166
0
    if (!JS_IsUndefined(new_target)) {
42167
0
        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_NUMBER);
42168
0
        if (!JS_IsException(obj))
42169
0
            JS_SetObjectData(ctx, obj, val);
42170
0
        return obj;
42171
0
    } else {
42172
0
        return val;
42173
0
    }
42174
0
}
42175
42176
#if 0
42177
static JSValue js_number___toInteger(JSContext *ctx, JSValueConst this_val,
42178
                                     int argc, JSValueConst *argv)
42179
{
42180
    return JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[0]));
42181
}
42182
42183
static JSValue js_number___toLength(JSContext *ctx, JSValueConst this_val,
42184
                                    int argc, JSValueConst *argv)
42185
{
42186
    int64_t v;
42187
    if (JS_ToLengthFree(ctx, &v, JS_DupValue(ctx, argv[0])))
42188
        return JS_EXCEPTION;
42189
    return JS_NewInt64(ctx, v);
42190
}
42191
#endif
42192
42193
static JSValue js_number_isNaN(JSContext *ctx, JSValueConst this_val,
42194
                               int argc, JSValueConst *argv)
42195
0
{
42196
0
    if (!JS_IsNumber(argv[0]))
42197
0
        return JS_FALSE;
42198
0
    return js_global_isNaN(ctx, this_val, argc, argv);
42199
0
}
42200
42201
static JSValue js_number_isFinite(JSContext *ctx, JSValueConst this_val,
42202
                                  int argc, JSValueConst *argv)
42203
0
{
42204
0
    if (!JS_IsNumber(argv[0]))
42205
0
        return JS_FALSE;
42206
0
    return js_global_isFinite(ctx, this_val, argc, argv);
42207
0
}
42208
42209
static JSValue js_number_isInteger(JSContext *ctx, JSValueConst this_val,
42210
                                   int argc, JSValueConst *argv)
42211
0
{
42212
0
    int ret;
42213
0
    ret = JS_NumberIsInteger(ctx, argv[0]);
42214
0
    if (ret < 0)
42215
0
        return JS_EXCEPTION;
42216
0
    else
42217
0
        return JS_NewBool(ctx, ret);
42218
0
}
42219
42220
static JSValue js_number_isSafeInteger(JSContext *ctx, JSValueConst this_val,
42221
                                       int argc, JSValueConst *argv)
42222
0
{
42223
0
    double d;
42224
0
    if (!JS_IsNumber(argv[0]))
42225
0
        return JS_FALSE;
42226
0
    if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
42227
0
        return JS_EXCEPTION;
42228
0
    return JS_NewBool(ctx, is_safe_integer(d));
42229
0
}
42230
42231
static const JSCFunctionListEntry js_number_funcs[] = {
42232
    /* global ParseInt and parseFloat should be defined already or delayed */
42233
    JS_ALIAS_BASE_DEF("parseInt", "parseInt", 0 ),
42234
    JS_ALIAS_BASE_DEF("parseFloat", "parseFloat", 0 ),
42235
    JS_CFUNC_DEF("isNaN", 1, js_number_isNaN ),
42236
    JS_CFUNC_DEF("isFinite", 1, js_number_isFinite ),
42237
    JS_CFUNC_DEF("isInteger", 1, js_number_isInteger ),
42238
    JS_CFUNC_DEF("isSafeInteger", 1, js_number_isSafeInteger ),
42239
    JS_PROP_DOUBLE_DEF("MAX_VALUE", 1.7976931348623157e+308, 0 ),
42240
    JS_PROP_DOUBLE_DEF("MIN_VALUE", 5e-324, 0 ),
42241
    JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ),
42242
    JS_PROP_DOUBLE_DEF("NEGATIVE_INFINITY", -INFINITY, 0 ),
42243
    JS_PROP_DOUBLE_DEF("POSITIVE_INFINITY", INFINITY, 0 ),
42244
    JS_PROP_DOUBLE_DEF("EPSILON", 2.220446049250313e-16, 0 ), /* ES6 */
42245
    JS_PROP_DOUBLE_DEF("MAX_SAFE_INTEGER", 9007199254740991.0, 0 ), /* ES6 */
42246
    JS_PROP_DOUBLE_DEF("MIN_SAFE_INTEGER", -9007199254740991.0, 0 ), /* ES6 */
42247
    //JS_CFUNC_DEF("__toInteger", 1, js_number___toInteger ),
42248
    //JS_CFUNC_DEF("__toLength", 1, js_number___toLength ),
42249
};
42250
42251
static JSValue js_thisNumberValue(JSContext *ctx, JSValueConst this_val)
42252
0
{
42253
0
    if (JS_IsNumber(this_val))
42254
0
        return JS_DupValue(ctx, this_val);
42255
42256
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
42257
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
42258
0
        if (p->class_id == JS_CLASS_NUMBER) {
42259
0
            if (JS_IsNumber(p->u.object_data))
42260
0
                return JS_DupValue(ctx, p->u.object_data);
42261
0
        }
42262
0
    }
42263
0
    return JS_ThrowTypeError(ctx, "not a number");
42264
0
}
42265
42266
static JSValue js_number_valueOf(JSContext *ctx, JSValueConst this_val,
42267
                                 int argc, JSValueConst *argv)
42268
0
{
42269
0
    return js_thisNumberValue(ctx, this_val);
42270
0
}
42271
42272
static int js_get_radix(JSContext *ctx, JSValueConst val)
42273
0
{
42274
0
    int radix;
42275
0
    if (JS_ToInt32Sat(ctx, &radix, val))
42276
0
        return -1;
42277
0
    if (radix < 2 || radix > 36) {
42278
0
        JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
42279
0
        return -1;
42280
0
    }
42281
0
    return radix;
42282
0
}
42283
42284
static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val,
42285
                                  int argc, JSValueConst *argv, int magic)
42286
0
{
42287
0
    JSValue val;
42288
0
    int base, flags;
42289
0
    double d;
42290
42291
0
    val = js_thisNumberValue(ctx, this_val);
42292
0
    if (JS_IsException(val))
42293
0
        return val;
42294
0
    if (magic || JS_IsUndefined(argv[0])) {
42295
0
        base = 10;
42296
0
    } else {
42297
0
        base = js_get_radix(ctx, argv[0]);
42298
0
        if (base < 0)
42299
0
            goto fail;
42300
0
    }
42301
0
    if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) {
42302
0
        char buf1[70];
42303
0
        int len;
42304
0
        len = i64toa_radix(buf1, JS_VALUE_GET_INT(val), base);
42305
0
        return js_new_string8_len(ctx, buf1, len);
42306
0
    }
42307
0
    if (JS_ToFloat64Free(ctx, &d, val))
42308
0
        return JS_EXCEPTION;
42309
0
    flags = JS_DTOA_FORMAT_FREE;
42310
0
    if (base != 10)
42311
0
        flags |= JS_DTOA_EXP_DISABLED;
42312
0
    return js_dtoa2(ctx, d, base, 0, flags);
42313
0
 fail:
42314
0
    JS_FreeValue(ctx, val);
42315
0
    return JS_EXCEPTION;
42316
0
}
42317
42318
static JSValue js_number_toFixed(JSContext *ctx, JSValueConst this_val,
42319
                                 int argc, JSValueConst *argv)
42320
0
{
42321
0
    JSValue val;
42322
0
    int f, flags;
42323
0
    double d;
42324
42325
0
    val = js_thisNumberValue(ctx, this_val);
42326
0
    if (JS_IsException(val))
42327
0
        return val;
42328
0
    if (JS_ToFloat64Free(ctx, &d, val))
42329
0
        return JS_EXCEPTION;
42330
0
    if (JS_ToInt32Sat(ctx, &f, argv[0]))
42331
0
        return JS_EXCEPTION;
42332
0
    if (f < 0 || f > 100)
42333
0
        return JS_ThrowRangeError(ctx, "invalid number of digits");
42334
0
    if (fabs(d) >= 1e21)
42335
0
        flags = JS_DTOA_FORMAT_FREE;
42336
0
    else
42337
0
        flags = JS_DTOA_FORMAT_FRAC;
42338
0
    return js_dtoa2(ctx, d, 10, f, flags);
42339
0
}
42340
42341
static JSValue js_number_toExponential(JSContext *ctx, JSValueConst this_val,
42342
                                       int argc, JSValueConst *argv)
42343
0
{
42344
0
    JSValue val;
42345
0
    int f, flags;
42346
0
    double d;
42347
42348
0
    val = js_thisNumberValue(ctx, this_val);
42349
0
    if (JS_IsException(val))
42350
0
        return val;
42351
0
    if (JS_ToFloat64Free(ctx, &d, val))
42352
0
        return JS_EXCEPTION;
42353
0
    if (JS_ToInt32Sat(ctx, &f, argv[0]))
42354
0
        return JS_EXCEPTION;
42355
0
    if (!isfinite(d)) {
42356
0
        return JS_ToStringFree(ctx,  __JS_NewFloat64(ctx, d));
42357
0
    }
42358
0
    if (JS_IsUndefined(argv[0])) {
42359
0
        flags = JS_DTOA_FORMAT_FREE;
42360
0
        f = 0;
42361
0
    } else {
42362
0
        if (f < 0 || f > 100)
42363
0
            return JS_ThrowRangeError(ctx, "invalid number of digits");
42364
0
        f++;
42365
0
        flags = JS_DTOA_FORMAT_FIXED;
42366
0
    }
42367
0
    return js_dtoa2(ctx, d, 10, f, flags | JS_DTOA_EXP_ENABLED);
42368
0
}
42369
42370
static JSValue js_number_toPrecision(JSContext *ctx, JSValueConst this_val,
42371
                                     int argc, JSValueConst *argv)
42372
0
{
42373
0
    JSValue val;
42374
0
    int p;
42375
0
    double d;
42376
42377
0
    val = js_thisNumberValue(ctx, this_val);
42378
0
    if (JS_IsException(val))
42379
0
        return val;
42380
0
    if (JS_ToFloat64Free(ctx, &d, val))
42381
0
        return JS_EXCEPTION;
42382
0
    if (JS_IsUndefined(argv[0]))
42383
0
        goto to_string;
42384
0
    if (JS_ToInt32Sat(ctx, &p, argv[0]))
42385
0
        return JS_EXCEPTION;
42386
0
    if (!isfinite(d)) {
42387
0
    to_string:
42388
0
        return JS_ToStringFree(ctx,  __JS_NewFloat64(ctx, d));
42389
0
    }
42390
0
    if (p < 1 || p > 100)
42391
0
        return JS_ThrowRangeError(ctx, "invalid number of digits");
42392
0
    return js_dtoa2(ctx, d, 10, p, JS_DTOA_FORMAT_FIXED);
42393
0
}
42394
42395
static const JSCFunctionListEntry js_number_proto_funcs[] = {
42396
    JS_CFUNC_DEF("toExponential", 1, js_number_toExponential ),
42397
    JS_CFUNC_DEF("toFixed", 1, js_number_toFixed ),
42398
    JS_CFUNC_DEF("toPrecision", 1, js_number_toPrecision ),
42399
    JS_CFUNC_MAGIC_DEF("toString", 1, js_number_toString, 0 ),
42400
    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_number_toString, 1 ),
42401
    JS_CFUNC_DEF("valueOf", 0, js_number_valueOf ),
42402
};
42403
42404
static JSValue js_parseInt(JSContext *ctx, JSValueConst this_val,
42405
                           int argc, JSValueConst *argv)
42406
0
{
42407
0
    const char *str, *p;
42408
0
    int radix, flags;
42409
0
    JSValue ret;
42410
42411
0
    str = JS_ToCString(ctx, argv[0]);
42412
0
    if (!str)
42413
0
        return JS_EXCEPTION;
42414
0
    if (JS_ToInt32(ctx, &radix, argv[1])) {
42415
0
        JS_FreeCString(ctx, str);
42416
0
        return JS_EXCEPTION;
42417
0
    }
42418
0
    if (radix != 0 && (radix < 2 || radix > 36)) {
42419
0
        ret = JS_NAN;
42420
0
    } else {
42421
0
        p = str;
42422
0
        p += skip_spaces(p);
42423
0
        flags = ATOD_INT_ONLY | ATOD_ACCEPT_PREFIX_AFTER_SIGN;
42424
0
        ret = js_atof(ctx, p, NULL, radix, flags);
42425
0
    }
42426
0
    JS_FreeCString(ctx, str);
42427
0
    return ret;
42428
0
}
42429
42430
static JSValue js_parseFloat(JSContext *ctx, JSValueConst this_val,
42431
                             int argc, JSValueConst *argv)
42432
0
{
42433
0
    const char *str, *p;
42434
0
    JSValue ret;
42435
42436
0
    str = JS_ToCString(ctx, argv[0]);
42437
0
    if (!str)
42438
0
        return JS_EXCEPTION;
42439
0
    p = str;
42440
0
    p += skip_spaces(p);
42441
0
    ret = js_atof(ctx, p, NULL, 10, 0);
42442
0
    JS_FreeCString(ctx, str);
42443
0
    return ret;
42444
0
}
42445
42446
/* Boolean */
42447
static JSValue js_boolean_constructor(JSContext *ctx, JSValueConst new_target,
42448
                                     int argc, JSValueConst *argv)
42449
0
{
42450
0
    JSValue val, obj;
42451
0
    val = JS_NewBool(ctx, JS_ToBool(ctx, argv[0]));
42452
0
    if (!JS_IsUndefined(new_target)) {
42453
0
        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_BOOLEAN);
42454
0
        if (!JS_IsException(obj))
42455
0
            JS_SetObjectData(ctx, obj, val);
42456
0
        return obj;
42457
0
    } else {
42458
0
        return val;
42459
0
    }
42460
0
}
42461
42462
static JSValue js_thisBooleanValue(JSContext *ctx, JSValueConst this_val)
42463
0
{
42464
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_BOOL)
42465
0
        return JS_DupValue(ctx, this_val);
42466
42467
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
42468
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
42469
0
        if (p->class_id == JS_CLASS_BOOLEAN) {
42470
0
            if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_BOOL)
42471
0
                return p->u.object_data;
42472
0
        }
42473
0
    }
42474
0
    return JS_ThrowTypeError(ctx, "not a boolean");
42475
0
}
42476
42477
static JSValue js_boolean_toString(JSContext *ctx, JSValueConst this_val,
42478
                                   int argc, JSValueConst *argv)
42479
0
{
42480
0
    JSValue val = js_thisBooleanValue(ctx, this_val);
42481
0
    if (JS_IsException(val))
42482
0
        return val;
42483
0
    return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ?
42484
0
                       JS_ATOM_true : JS_ATOM_false);
42485
0
}
42486
42487
static JSValue js_boolean_valueOf(JSContext *ctx, JSValueConst this_val,
42488
                                  int argc, JSValueConst *argv)
42489
0
{
42490
0
    return js_thisBooleanValue(ctx, this_val);
42491
0
}
42492
42493
static const JSCFunctionListEntry js_boolean_proto_funcs[] = {
42494
    JS_CFUNC_DEF("toString", 0, js_boolean_toString ),
42495
    JS_CFUNC_DEF("valueOf", 0, js_boolean_valueOf ),
42496
};
42497
42498
/* String */
42499
42500
static int js_string_get_own_property(JSContext *ctx,
42501
                                      JSPropertyDescriptor *desc,
42502
                                      JSValueConst obj, JSAtom prop)
42503
0
{
42504
0
    JSObject *p;
42505
0
    JSString *p1;
42506
0
    uint32_t idx, ch;
42507
42508
    /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
42509
0
    if (__JS_AtomIsTaggedInt(prop)) {
42510
0
        p = JS_VALUE_GET_OBJ(obj);
42511
0
        if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
42512
0
            p1 = JS_VALUE_GET_STRING(p->u.object_data);
42513
0
            idx = __JS_AtomToUInt32(prop);
42514
0
            if (idx < p1->len) {
42515
0
                if (desc) {
42516
0
                    ch = string_get(p1, idx);
42517
0
                    desc->flags = JS_PROP_ENUMERABLE;
42518
0
                    desc->value = js_new_string_char(ctx, ch);
42519
0
                    desc->getter = JS_UNDEFINED;
42520
0
                    desc->setter = JS_UNDEFINED;
42521
0
                }
42522
0
                return TRUE;
42523
0
            }
42524
0
        }
42525
0
    }
42526
0
    return FALSE;
42527
0
}
42528
42529
static int js_string_define_own_property(JSContext *ctx,
42530
                                         JSValueConst this_obj,
42531
                                         JSAtom prop, JSValueConst val,
42532
                                         JSValueConst getter,
42533
                                         JSValueConst setter, int flags)
42534
8
{
42535
8
    uint32_t idx;
42536
8
    JSObject *p;
42537
8
    JSString *p1, *p2;
42538
42539
8
    if (__JS_AtomIsTaggedInt(prop)) {
42540
0
        idx = __JS_AtomToUInt32(prop);
42541
0
        p = JS_VALUE_GET_OBJ(this_obj);
42542
0
        if (JS_VALUE_GET_TAG(p->u.object_data) != JS_TAG_STRING)
42543
0
            goto def;
42544
0
        p1 = JS_VALUE_GET_STRING(p->u.object_data);
42545
0
        if (idx >= p1->len)
42546
0
            goto def;
42547
0
        if (!check_define_prop_flags(JS_PROP_ENUMERABLE, flags))
42548
0
            goto fail;
42549
        /* check that the same value is configured */
42550
0
        if (flags & JS_PROP_HAS_VALUE) {
42551
0
            if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
42552
0
                goto fail;
42553
0
            p2 = JS_VALUE_GET_STRING(val);
42554
0
            if (p2->len != 1)
42555
0
                goto fail;
42556
0
            if (string_get(p1, idx) != string_get(p2, 0)) {
42557
0
            fail:
42558
0
                return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
42559
0
            }
42560
0
        }
42561
0
        return TRUE;
42562
8
    } else {
42563
8
    def:
42564
8
        return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter,
42565
8
                                 flags | JS_PROP_NO_EXOTIC);
42566
8
    }
42567
8
}
42568
42569
static int js_string_delete_property(JSContext *ctx,
42570
                                     JSValueConst obj, JSAtom prop)
42571
0
{
42572
0
    uint32_t idx;
42573
42574
0
    if (__JS_AtomIsTaggedInt(prop)) {
42575
0
        idx = __JS_AtomToUInt32(prop);
42576
0
        if (idx < js_string_obj_get_length(ctx, obj)) {
42577
0
            return FALSE;
42578
0
        }
42579
0
    }
42580
0
    return TRUE;
42581
0
}
42582
42583
static const JSClassExoticMethods js_string_exotic_methods = {
42584
    .get_own_property = js_string_get_own_property,
42585
    .define_own_property = js_string_define_own_property,
42586
    .delete_property = js_string_delete_property,
42587
};
42588
42589
static JSValue js_string_constructor(JSContext *ctx, JSValueConst new_target,
42590
                                     int argc, JSValueConst *argv)
42591
0
{
42592
0
    JSValue val, obj;
42593
0
    if (argc == 0) {
42594
0
        val = JS_AtomToString(ctx, JS_ATOM_empty_string);
42595
0
    } else {
42596
0
        if (JS_IsUndefined(new_target) && JS_IsSymbol(argv[0])) {
42597
0
            JSAtomStruct *p = JS_VALUE_GET_PTR(argv[0]);
42598
0
            val = JS_ConcatString3(ctx, "Symbol(", JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p)), ")");
42599
0
        } else {
42600
0
            val = JS_ToString(ctx, argv[0]);
42601
0
        }
42602
0
        if (JS_IsException(val))
42603
0
            return val;
42604
0
    }
42605
0
    if (!JS_IsUndefined(new_target)) {
42606
0
        JSString *p1 = JS_VALUE_GET_STRING(val);
42607
42608
0
        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_STRING);
42609
0
        if (JS_IsException(obj)) {
42610
0
            JS_FreeValue(ctx, val);
42611
0
        } else {
42612
0
            JS_SetObjectData(ctx, obj, val);
42613
0
            JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, JS_NewInt32(ctx, p1->len), 0);
42614
0
        }
42615
0
        return obj;
42616
0
    } else {
42617
0
        return val;
42618
0
    }
42619
0
}
42620
42621
static JSValue js_thisStringValue(JSContext *ctx, JSValueConst this_val)
42622
0
{
42623
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_STRING ||
42624
0
        JS_VALUE_GET_TAG(this_val) == JS_TAG_STRING_ROPE)
42625
0
        return JS_DupValue(ctx, this_val);
42626
42627
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
42628
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
42629
0
        if (p->class_id == JS_CLASS_STRING) {
42630
0
            if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING)
42631
0
                return JS_DupValue(ctx, p->u.object_data);
42632
0
        }
42633
0
    }
42634
0
    return JS_ThrowTypeError(ctx, "not a string");
42635
0
}
42636
42637
static JSValue js_string_fromCharCode(JSContext *ctx, JSValueConst this_val,
42638
                                      int argc, JSValueConst *argv)
42639
0
{
42640
0
    int i;
42641
0
    StringBuffer b_s, *b = &b_s;
42642
42643
0
    string_buffer_init(ctx, b, argc);
42644
42645
0
    for(i = 0; i < argc; i++) {
42646
0
        int32_t c;
42647
0
        if (JS_ToInt32(ctx, &c, argv[i]) || string_buffer_putc16(b, c & 0xffff)) {
42648
0
            string_buffer_free(b);
42649
0
            return JS_EXCEPTION;
42650
0
        }
42651
0
    }
42652
0
    return string_buffer_end(b);
42653
0
}
42654
42655
static JSValue js_string_fromCodePoint(JSContext *ctx, JSValueConst this_val,
42656
                                       int argc, JSValueConst *argv)
42657
0
{
42658
0
    double d;
42659
0
    int i, c;
42660
0
    StringBuffer b_s, *b = &b_s;
42661
42662
    /* XXX: could pre-compute string length if all arguments are JS_TAG_INT */
42663
42664
0
    if (string_buffer_init(ctx, b, argc))
42665
0
        goto fail;
42666
0
    for(i = 0; i < argc; i++) {
42667
0
        if (JS_VALUE_GET_TAG(argv[i]) == JS_TAG_INT) {
42668
0
            c = JS_VALUE_GET_INT(argv[i]);
42669
0
            if (c < 0 || c > 0x10ffff)
42670
0
                goto range_error;
42671
0
        } else {
42672
0
            if (JS_ToFloat64(ctx, &d, argv[i]))
42673
0
                goto fail;
42674
0
            if (isnan(d) || d < 0 || d > 0x10ffff || (c = (int)d) != d)
42675
0
                goto range_error;
42676
0
        }
42677
0
        if (string_buffer_putc(b, c))
42678
0
            goto fail;
42679
0
    }
42680
0
    return string_buffer_end(b);
42681
42682
0
 range_error:
42683
0
    JS_ThrowRangeError(ctx, "invalid code point");
42684
0
 fail:
42685
0
    string_buffer_free(b);
42686
0
    return JS_EXCEPTION;
42687
0
}
42688
42689
static JSValue js_string_raw(JSContext *ctx, JSValueConst this_val,
42690
                             int argc, JSValueConst *argv)
42691
0
{
42692
    // raw(temp,...a)
42693
0
    JSValue cooked, val, raw;
42694
0
    StringBuffer b_s, *b = &b_s;
42695
0
    int64_t i, n;
42696
42697
0
    string_buffer_init(ctx, b, 0);
42698
0
    raw = JS_UNDEFINED;
42699
0
    cooked = JS_ToObject(ctx, argv[0]);
42700
0
    if (JS_IsException(cooked))
42701
0
        goto exception;
42702
0
    raw = JS_ToObjectFree(ctx, JS_GetProperty(ctx, cooked, JS_ATOM_raw));
42703
0
    if (JS_IsException(raw))
42704
0
        goto exception;
42705
0
    if (js_get_length64(ctx, &n, raw) < 0)
42706
0
        goto exception;
42707
42708
0
    for (i = 0; i < n; i++) {
42709
0
        val = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, raw, i));
42710
0
        if (JS_IsException(val))
42711
0
            goto exception;
42712
0
        string_buffer_concat_value_free(b, val);
42713
0
        if (i < n - 1 && i + 1 < argc) {
42714
0
            if (string_buffer_concat_value(b, argv[i + 1]))
42715
0
                goto exception;
42716
0
        }
42717
0
    }
42718
0
    JS_FreeValue(ctx, cooked);
42719
0
    JS_FreeValue(ctx, raw);
42720
0
    return string_buffer_end(b);
42721
42722
0
exception:
42723
0
    JS_FreeValue(ctx, cooked);
42724
0
    JS_FreeValue(ctx, raw);
42725
0
    string_buffer_free(b);
42726
0
    return JS_EXCEPTION;
42727
0
}
42728
42729
/* only used in test262 */
42730
JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val,
42731
                                 int argc, JSValueConst *argv)
42732
0
{
42733
0
    uint32_t start, end, i, n;
42734
0
    StringBuffer b_s, *b = &b_s;
42735
42736
0
    if (JS_ToUint32(ctx, &start, argv[0]) ||
42737
0
        JS_ToUint32(ctx, &end, argv[1]))
42738
0
        return JS_EXCEPTION;
42739
0
    end = min_uint32(end, 0x10ffff + 1);
42740
42741
0
    if (start > end) {
42742
0
        start = end;
42743
0
    }
42744
0
    n = end - start;
42745
0
    if (end > 0x10000) {
42746
0
        n += end - max_uint32(start, 0x10000);
42747
0
    }
42748
0
    if (string_buffer_init2(ctx, b, n, end >= 0x100))
42749
0
        return JS_EXCEPTION;
42750
0
    for(i = start; i < end; i++) {
42751
0
        string_buffer_putc(b, i);
42752
0
    }
42753
0
    return string_buffer_end(b);
42754
0
}
42755
42756
#if 0
42757
static JSValue js_string___isSpace(JSContext *ctx, JSValueConst this_val,
42758
                                   int argc, JSValueConst *argv)
42759
{
42760
    int c;
42761
    if (JS_ToInt32(ctx, &c, argv[0]))
42762
        return JS_EXCEPTION;
42763
    return JS_NewBool(ctx, lre_is_space(c));
42764
}
42765
#endif
42766
42767
static JSValue js_string_charCodeAt(JSContext *ctx, JSValueConst this_val,
42768
                                     int argc, JSValueConst *argv)
42769
0
{
42770
0
    JSValue val, ret;
42771
0
    JSString *p;
42772
0
    int idx, c;
42773
42774
0
    val = JS_ToStringCheckObject(ctx, this_val);
42775
0
    if (JS_IsException(val))
42776
0
        return val;
42777
0
    p = JS_VALUE_GET_STRING(val);
42778
0
    if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
42779
0
        JS_FreeValue(ctx, val);
42780
0
        return JS_EXCEPTION;
42781
0
    }
42782
0
    if (idx < 0 || idx >= p->len) {
42783
0
        ret = JS_NAN;
42784
0
    } else {
42785
0
        c = string_get(p, idx);
42786
0
        ret = JS_NewInt32(ctx, c);
42787
0
    }
42788
0
    JS_FreeValue(ctx, val);
42789
0
    return ret;
42790
0
}
42791
42792
static JSValue js_string_charAt(JSContext *ctx, JSValueConst this_val,
42793
                                int argc, JSValueConst *argv, int is_at)
42794
0
{
42795
0
    JSValue val, ret;
42796
0
    JSString *p;
42797
0
    int idx, c;
42798
42799
0
    val = JS_ToStringCheckObject(ctx, this_val);
42800
0
    if (JS_IsException(val))
42801
0
        return val;
42802
0
    p = JS_VALUE_GET_STRING(val);
42803
0
    if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
42804
0
        JS_FreeValue(ctx, val);
42805
0
        return JS_EXCEPTION;
42806
0
    }
42807
0
    if (idx < 0 && is_at)
42808
0
        idx += p->len;
42809
0
    if (idx < 0 || idx >= p->len) {
42810
0
        if (is_at)
42811
0
            ret = JS_UNDEFINED;
42812
0
        else
42813
0
            ret = JS_AtomToString(ctx, JS_ATOM_empty_string);
42814
0
    } else {
42815
0
        c = string_get(p, idx);
42816
0
        ret = js_new_string_char(ctx, c);
42817
0
    }
42818
0
    JS_FreeValue(ctx, val);
42819
0
    return ret;
42820
0
}
42821
42822
static JSValue js_string_codePointAt(JSContext *ctx, JSValueConst this_val,
42823
                                     int argc, JSValueConst *argv)
42824
0
{
42825
0
    JSValue val, ret;
42826
0
    JSString *p;
42827
0
    int idx, c;
42828
42829
0
    val = JS_ToStringCheckObject(ctx, this_val);
42830
0
    if (JS_IsException(val))
42831
0
        return val;
42832
0
    p = JS_VALUE_GET_STRING(val);
42833
0
    if (JS_ToInt32Sat(ctx, &idx, argv[0])) {
42834
0
        JS_FreeValue(ctx, val);
42835
0
        return JS_EXCEPTION;
42836
0
    }
42837
0
    if (idx < 0 || idx >= p->len) {
42838
0
        ret = JS_UNDEFINED;
42839
0
    } else {
42840
0
        c = string_getc(p, &idx);
42841
0
        ret = JS_NewInt32(ctx, c);
42842
0
    }
42843
0
    JS_FreeValue(ctx, val);
42844
0
    return ret;
42845
0
}
42846
42847
static JSValue js_string_concat(JSContext *ctx, JSValueConst this_val,
42848
                                int argc, JSValueConst *argv)
42849
0
{
42850
0
    JSValue r;
42851
0
    int i;
42852
42853
    /* XXX: Use more efficient method */
42854
    /* XXX: This method is OK if r has a single refcount */
42855
    /* XXX: should use string_buffer? */
42856
0
    r = JS_ToStringCheckObject(ctx, this_val);
42857
0
    for (i = 0; i < argc; i++) {
42858
0
        if (JS_IsException(r))
42859
0
            break;
42860
0
        r = JS_ConcatString(ctx, r, JS_DupValue(ctx, argv[i]));
42861
0
    }
42862
0
    return r;
42863
0
}
42864
42865
static int string_cmp(JSString *p1, JSString *p2, int x1, int x2, int len)
42866
0
{
42867
0
    int i, c1, c2;
42868
0
    for (i = 0; i < len; i++) {
42869
0
        if ((c1 = string_get(p1, x1 + i)) != (c2 = string_get(p2, x2 + i)))
42870
0
            return c1 - c2;
42871
0
    }
42872
0
    return 0;
42873
0
}
42874
42875
static int string_indexof_char(JSString *p, int c, int from)
42876
0
{
42877
    /* assuming 0 <= from <= p->len */
42878
0
    int i, len = p->len;
42879
0
    if (p->is_wide_char) {
42880
0
        for (i = from; i < len; i++) {
42881
0
            if (p->u.str16[i] == c)
42882
0
                return i;
42883
0
        }
42884
0
    } else {
42885
0
        if ((c & ~0xff) == 0) {
42886
0
            for (i = from; i < len; i++) {
42887
0
                if (p->u.str8[i] == (uint8_t)c)
42888
0
                    return i;
42889
0
            }
42890
0
        }
42891
0
    }
42892
0
    return -1;
42893
0
}
42894
42895
static int string_indexof(JSString *p1, JSString *p2, int from)
42896
0
{
42897
    /* assuming 0 <= from <= p1->len */
42898
0
    int c, i, j, len1 = p1->len, len2 = p2->len;
42899
0
    if (len2 == 0)
42900
0
        return from;
42901
0
    for (i = from, c = string_get(p2, 0); i + len2 <= len1; i = j + 1) {
42902
0
        j = string_indexof_char(p1, c, i);
42903
0
        if (j < 0 || j + len2 > len1)
42904
0
            break;
42905
0
        if (!string_cmp(p1, p2, j + 1, 1, len2 - 1))
42906
0
            return j;
42907
0
    }
42908
0
    return -1;
42909
0
}
42910
42911
static int64_t string_advance_index(JSString *p, int64_t index, BOOL unicode)
42912
0
{
42913
0
    if (!unicode || index >= p->len || !p->is_wide_char) {
42914
0
        index++;
42915
0
    } else {
42916
0
        int index32 = (int)index;
42917
0
        string_getc(p, &index32);
42918
0
        index = index32;
42919
0
    }
42920
0
    return index;
42921
0
}
42922
42923
/* return the position of the first invalid character in the string or
42924
   -1 if none */
42925
static int js_string_find_invalid_codepoint(JSString *p)
42926
0
{
42927
0
    int i;
42928
0
    if (!p->is_wide_char)
42929
0
        return -1;
42930
0
    for(i = 0; i < p->len; i++) {
42931
0
        uint32_t c = p->u.str16[i];
42932
0
        if (is_surrogate(c)) {
42933
0
            if (is_hi_surrogate(c) && (i + 1) < p->len
42934
0
            &&  is_lo_surrogate(p->u.str16[i + 1])) {
42935
0
                i++;
42936
0
            } else {
42937
0
                return i;
42938
0
            }
42939
0
        }
42940
0
    }
42941
0
    return -1;
42942
0
}
42943
42944
static JSValue js_string_isWellFormed(JSContext *ctx, JSValueConst this_val,
42945
                                      int argc, JSValueConst *argv)
42946
0
{
42947
0
    JSValue str;
42948
0
    JSString *p;
42949
0
    BOOL ret;
42950
42951
0
    str = JS_ToStringCheckObject(ctx, this_val);
42952
0
    if (JS_IsException(str))
42953
0
        return JS_EXCEPTION;
42954
0
    p = JS_VALUE_GET_STRING(str);
42955
0
    ret = (js_string_find_invalid_codepoint(p) < 0);
42956
0
    JS_FreeValue(ctx, str);
42957
0
    return JS_NewBool(ctx, ret);
42958
0
}
42959
42960
static JSValue js_string_toWellFormed(JSContext *ctx, JSValueConst this_val,
42961
                                      int argc, JSValueConst *argv)
42962
0
{
42963
0
    JSValue str, ret;
42964
0
    JSString *p;
42965
0
    int i;
42966
42967
0
    str = JS_ToStringCheckObject(ctx, this_val);
42968
0
    if (JS_IsException(str))
42969
0
        return JS_EXCEPTION;
42970
42971
0
    p = JS_VALUE_GET_STRING(str);
42972
    /* avoid reallocating the string if it is well-formed */
42973
0
    i = js_string_find_invalid_codepoint(p);
42974
0
    if (i < 0)
42975
0
        return str;
42976
42977
0
    ret = js_new_string16_len(ctx, p->u.str16, p->len);
42978
0
    JS_FreeValue(ctx, str);
42979
0
    if (JS_IsException(ret))
42980
0
        return JS_EXCEPTION;
42981
42982
0
    p = JS_VALUE_GET_STRING(ret);
42983
0
    for (; i < p->len; i++) {
42984
0
        uint32_t c = p->u.str16[i];
42985
0
        if (is_surrogate(c)) {
42986
0
            if (is_hi_surrogate(c) && (i + 1) < p->len
42987
0
            &&  is_lo_surrogate(p->u.str16[i + 1])) {
42988
0
                i++;
42989
0
            } else {
42990
0
                p->u.str16[i] = 0xFFFD;
42991
0
            }
42992
0
        }
42993
0
    }
42994
0
    return ret;
42995
0
}
42996
42997
static JSValue js_string_indexOf(JSContext *ctx, JSValueConst this_val,
42998
                                 int argc, JSValueConst *argv, int lastIndexOf)
42999
0
{
43000
0
    JSValue str, v;
43001
0
    int i, len, v_len, pos, start, stop, ret, inc;
43002
0
    JSString *p;
43003
0
    JSString *p1;
43004
43005
0
    str = JS_ToStringCheckObject(ctx, this_val);
43006
0
    if (JS_IsException(str))
43007
0
        return str;
43008
0
    v = JS_ToString(ctx, argv[0]);
43009
0
    if (JS_IsException(v))
43010
0
        goto fail;
43011
0
    p = JS_VALUE_GET_STRING(str);
43012
0
    p1 = JS_VALUE_GET_STRING(v);
43013
0
    len = p->len;
43014
0
    v_len = p1->len;
43015
0
    if (lastIndexOf) {
43016
0
        pos = len - v_len;
43017
0
        if (argc > 1) {
43018
0
            double d;
43019
0
            if (JS_ToFloat64(ctx, &d, argv[1]))
43020
0
                goto fail;
43021
0
            if (!isnan(d)) {
43022
0
                if (d <= 0)
43023
0
                    pos = 0;
43024
0
                else if (d < pos)
43025
0
                    pos = d;
43026
0
            }
43027
0
        }
43028
0
        start = pos;
43029
0
        stop = 0;
43030
0
        inc = -1;
43031
0
    } else {
43032
0
        pos = 0;
43033
0
        if (argc > 1) {
43034
0
            if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0))
43035
0
                goto fail;
43036
0
        }
43037
0
        start = pos;
43038
0
        stop = len - v_len;
43039
0
        inc = 1;
43040
0
    }
43041
0
    ret = -1;
43042
0
    if (len >= v_len && inc * (stop - start) >= 0) {
43043
0
        for (i = start;; i += inc) {
43044
0
            if (!string_cmp(p, p1, i, 0, v_len)) {
43045
0
                ret = i;
43046
0
                break;
43047
0
            }
43048
0
            if (i == stop)
43049
0
                break;
43050
0
        }
43051
0
    }
43052
0
    JS_FreeValue(ctx, str);
43053
0
    JS_FreeValue(ctx, v);
43054
0
    return JS_NewInt32(ctx, ret);
43055
43056
0
fail:
43057
0
    JS_FreeValue(ctx, str);
43058
0
    JS_FreeValue(ctx, v);
43059
0
    return JS_EXCEPTION;
43060
0
}
43061
43062
/* return < 0 if exception or TRUE/FALSE */
43063
static int js_is_regexp(JSContext *ctx, JSValueConst obj);
43064
43065
static JSValue js_string_includes(JSContext *ctx, JSValueConst this_val,
43066
                                  int argc, JSValueConst *argv, int magic)
43067
0
{
43068
0
    JSValue str, v = JS_UNDEFINED;
43069
0
    int i, len, v_len, pos, start, stop, ret;
43070
0
    JSString *p;
43071
0
    JSString *p1;
43072
43073
0
    str = JS_ToStringCheckObject(ctx, this_val);
43074
0
    if (JS_IsException(str))
43075
0
        return str;
43076
0
    ret = js_is_regexp(ctx, argv[0]);
43077
0
    if (ret) {
43078
0
        if (ret > 0)
43079
0
            JS_ThrowTypeError(ctx, "regexp not supported");
43080
0
        goto fail;
43081
0
    }
43082
0
    v = JS_ToString(ctx, argv[0]);
43083
0
    if (JS_IsException(v))
43084
0
        goto fail;
43085
0
    p = JS_VALUE_GET_STRING(str);
43086
0
    p1 = JS_VALUE_GET_STRING(v);
43087
0
    len = p->len;
43088
0
    v_len = p1->len;
43089
0
    pos = (magic == 2) ? len : 0;
43090
0
    if (argc > 1 && !JS_IsUndefined(argv[1])) {
43091
0
        if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0))
43092
0
            goto fail;
43093
0
    }
43094
0
    len -= v_len;
43095
0
    ret = 0;
43096
0
    if (magic == 0) {
43097
0
        start = pos;
43098
0
        stop = len;
43099
0
    } else {
43100
0
        if (magic == 1) {
43101
0
            if (pos > len)
43102
0
                goto done;
43103
0
        } else {
43104
0
            pos -= v_len;
43105
0
        }
43106
0
        start = stop = pos;
43107
0
    }
43108
0
    if (start >= 0 && start <= stop) {
43109
0
        for (i = start;; i++) {
43110
0
            if (!string_cmp(p, p1, i, 0, v_len)) {
43111
0
                ret = 1;
43112
0
                break;
43113
0
            }
43114
0
            if (i == stop)
43115
0
                break;
43116
0
        }
43117
0
    }
43118
0
 done:
43119
0
    JS_FreeValue(ctx, str);
43120
0
    JS_FreeValue(ctx, v);
43121
0
    return JS_NewBool(ctx, ret);
43122
43123
0
fail:
43124
0
    JS_FreeValue(ctx, str);
43125
0
    JS_FreeValue(ctx, v);
43126
0
    return JS_EXCEPTION;
43127
0
}
43128
43129
static int check_regexp_g_flag(JSContext *ctx, JSValueConst regexp)
43130
0
{
43131
0
    int ret;
43132
0
    JSValue flags;
43133
43134
0
    ret = js_is_regexp(ctx, regexp);
43135
0
    if (ret < 0)
43136
0
        return -1;
43137
0
    if (ret) {
43138
0
        flags = JS_GetProperty(ctx, regexp, JS_ATOM_flags);
43139
0
        if (JS_IsException(flags))
43140
0
            return -1;
43141
0
        if (JS_IsUndefined(flags) || JS_IsNull(flags)) {
43142
0
            JS_ThrowTypeError(ctx, "cannot convert to object");
43143
0
            return -1;
43144
0
        }
43145
0
        flags = JS_ToStringFree(ctx, flags);
43146
0
        if (JS_IsException(flags))
43147
0
            return -1;
43148
0
        ret = string_indexof_char(JS_VALUE_GET_STRING(flags), 'g', 0);
43149
0
        JS_FreeValue(ctx, flags);
43150
0
        if (ret < 0) {
43151
0
            JS_ThrowTypeError(ctx, "regexp must have the 'g' flag");
43152
0
            return -1;
43153
0
        }
43154
0
    }
43155
0
    return 0;
43156
0
}
43157
43158
static JSValue js_string_match(JSContext *ctx, JSValueConst this_val,
43159
                               int argc, JSValueConst *argv, int atom)
43160
0
{
43161
    // match(rx), search(rx), matchAll(rx)
43162
    // atom is JS_ATOM_Symbol_match, JS_ATOM_Symbol_search, or JS_ATOM_Symbol_matchAll
43163
0
    JSValueConst O = this_val, regexp = argv[0], args[2];
43164
0
    JSValue matcher, S, rx, result, str;
43165
0
    int args_len;
43166
43167
0
    if (JS_IsUndefined(O) || JS_IsNull(O))
43168
0
        return JS_ThrowTypeError(ctx, "cannot convert to object");
43169
43170
0
    if (!JS_IsUndefined(regexp) && !JS_IsNull(regexp)) {
43171
0
        matcher = JS_GetProperty(ctx, regexp, atom);
43172
0
        if (JS_IsException(matcher))
43173
0
            return JS_EXCEPTION;
43174
0
        if (atom == JS_ATOM_Symbol_matchAll) {
43175
0
            if (check_regexp_g_flag(ctx, regexp) < 0) {
43176
0
                JS_FreeValue(ctx, matcher);
43177
0
                return JS_EXCEPTION;
43178
0
            }
43179
0
        }
43180
0
        if (!JS_IsUndefined(matcher) && !JS_IsNull(matcher)) {
43181
0
            return JS_CallFree(ctx, matcher, regexp, 1, &O);
43182
0
        }
43183
0
    }
43184
0
    S = JS_ToString(ctx, O);
43185
0
    if (JS_IsException(S))
43186
0
        return JS_EXCEPTION;
43187
0
    args_len = 1;
43188
0
    args[0] = regexp;
43189
0
    str = JS_UNDEFINED;
43190
0
    if (atom == JS_ATOM_Symbol_matchAll) {
43191
0
        str = js_new_string8(ctx, "g");
43192
0
        if (JS_IsException(str))
43193
0
            goto fail;
43194
0
        args[args_len++] = (JSValueConst)str;
43195
0
    }
43196
0
    rx = JS_CallConstructor(ctx, ctx->regexp_ctor, args_len, args);
43197
0
    JS_FreeValue(ctx, str);
43198
0
    if (JS_IsException(rx)) {
43199
0
    fail:
43200
0
        JS_FreeValue(ctx, S);
43201
0
        return JS_EXCEPTION;
43202
0
    }
43203
0
    result = JS_InvokeFree(ctx, rx, atom, 1, (JSValueConst *)&S);
43204
0
    JS_FreeValue(ctx, S);
43205
0
    return result;
43206
0
}
43207
43208
static JSValue js_string___GetSubstitution(JSContext *ctx, JSValueConst this_val,
43209
                                           int argc, JSValueConst *argv)
43210
0
{
43211
    // GetSubstitution(matched, str, position, captures, namedCaptures, rep)
43212
0
    JSValueConst matched, str, captures, namedCaptures, rep;
43213
0
    JSValue capture, name, s;
43214
0
    uint32_t position, len, matched_len, captures_len;
43215
0
    int i, j, j0, k, k1;
43216
0
    int c, c1;
43217
0
    StringBuffer b_s, *b = &b_s;
43218
0
    JSString *sp, *rp;
43219
43220
0
    matched = argv[0];
43221
0
    str = argv[1];
43222
0
    captures = argv[3];
43223
0
    namedCaptures = argv[4];
43224
0
    rep = argv[5];
43225
43226
0
    if (!JS_IsString(rep) || !JS_IsString(str))
43227
0
        return JS_ThrowTypeError(ctx, "not a string");
43228
43229
0
    sp = JS_VALUE_GET_STRING(str);
43230
0
    rp = JS_VALUE_GET_STRING(rep);
43231
43232
0
    string_buffer_init(ctx, b, 0);
43233
43234
0
    captures_len = 0;
43235
0
    if (!JS_IsUndefined(captures)) {
43236
0
        if (js_get_length32(ctx, &captures_len, captures))
43237
0
            goto exception;
43238
0
    }
43239
0
    if (js_get_length32(ctx, &matched_len, matched))
43240
0
        goto exception;
43241
0
    if (JS_ToUint32(ctx, &position, argv[2]) < 0)
43242
0
        goto exception;
43243
43244
0
    len = rp->len;
43245
0
    i = 0;
43246
0
    for(;;) {
43247
0
        j = string_indexof_char(rp, '$', i);
43248
0
        if (j < 0 || j + 1 >= len)
43249
0
            break;
43250
0
        string_buffer_concat(b, rp, i, j);
43251
0
        j0 = j++;
43252
0
        c = string_get(rp, j++);
43253
0
        if (c == '$') {
43254
0
            string_buffer_putc8(b, '$');
43255
0
        } else if (c == '&') {
43256
0
            if (string_buffer_concat_value(b, matched))
43257
0
                goto exception;
43258
0
        } else if (c == '`') {
43259
0
            string_buffer_concat(b, sp, 0, position);
43260
0
        } else if (c == '\'') {
43261
0
            string_buffer_concat(b, sp, position + matched_len, sp->len);
43262
0
        } else if (c >= '0' && c <= '9') {
43263
0
            k = c - '0';
43264
0
            if (j < len) {
43265
0
                c1 = string_get(rp, j);
43266
0
                if (c1 >= '0' && c1 <= '9') {
43267
                    /* This behavior is specified in ES6 and refined in ECMA 2019 */
43268
                    /* ECMA 2019 does not have the extra test, but
43269
                       Test262 S15.5.4.11_A3_T1..3 require this behavior */
43270
0
                    k1 = k * 10 + c1 - '0';
43271
0
                    if (k1 >= 1 && k1 < captures_len) {
43272
0
                        k = k1;
43273
0
                        j++;
43274
0
                    }
43275
0
                }
43276
0
            }
43277
0
            if (k >= 1 && k < captures_len) {
43278
0
                s = JS_GetPropertyInt64(ctx, captures, k);
43279
0
                if (JS_IsException(s))
43280
0
                    goto exception;
43281
0
                if (!JS_IsUndefined(s)) {
43282
0
                    if (string_buffer_concat_value_free(b, s))
43283
0
                        goto exception;
43284
0
                }
43285
0
            } else {
43286
0
                goto norep;
43287
0
            }
43288
0
        } else if (c == '<' && !JS_IsUndefined(namedCaptures)) {
43289
0
            k = string_indexof_char(rp, '>', j);
43290
0
            if (k < 0)
43291
0
                goto norep;
43292
0
            name = js_sub_string(ctx, rp, j, k);
43293
0
            if (JS_IsException(name))
43294
0
                goto exception;
43295
0
            capture = JS_GetPropertyValue(ctx, namedCaptures, name);
43296
0
            if (JS_IsException(capture))
43297
0
                goto exception;
43298
0
            if (!JS_IsUndefined(capture)) {
43299
0
                if (string_buffer_concat_value_free(b, capture))
43300
0
                    goto exception;
43301
0
            }
43302
0
            j = k + 1;
43303
0
        } else {
43304
0
        norep:
43305
0
            string_buffer_concat(b, rp, j0, j);
43306
0
        }
43307
0
        i = j;
43308
0
    }
43309
0
    string_buffer_concat(b, rp, i, rp->len);
43310
0
    return string_buffer_end(b);
43311
0
exception:
43312
0
    string_buffer_free(b);
43313
0
    return JS_EXCEPTION;
43314
0
}
43315
43316
static JSValue js_string_replace(JSContext *ctx, JSValueConst this_val,
43317
                                 int argc, JSValueConst *argv,
43318
                                 int is_replaceAll)
43319
0
{
43320
    // replace(rx, rep)
43321
0
    JSValueConst O = this_val, searchValue = argv[0], replaceValue = argv[1];
43322
0
    JSValueConst args[6];
43323
0
    JSValue str, search_str, replaceValue_str, repl_str;
43324
0
    JSString *sp, *searchp;
43325
0
    StringBuffer b_s, *b = &b_s;
43326
0
    int pos, functionalReplace, endOfLastMatch;
43327
0
    BOOL is_first;
43328
43329
0
    if (JS_IsUndefined(O) || JS_IsNull(O))
43330
0
        return JS_ThrowTypeError(ctx, "cannot convert to object");
43331
43332
0
    search_str = JS_UNDEFINED;
43333
0
    replaceValue_str = JS_UNDEFINED;
43334
0
    repl_str = JS_UNDEFINED;
43335
43336
0
    if (!JS_IsUndefined(searchValue) && !JS_IsNull(searchValue)) {
43337
0
        JSValue replacer;
43338
0
        if (is_replaceAll) {
43339
0
            if (check_regexp_g_flag(ctx, searchValue) < 0)
43340
0
                return JS_EXCEPTION;
43341
0
        }
43342
0
        replacer = JS_GetProperty(ctx, searchValue, JS_ATOM_Symbol_replace);
43343
0
        if (JS_IsException(replacer))
43344
0
            return JS_EXCEPTION;
43345
0
        if (!JS_IsUndefined(replacer) && !JS_IsNull(replacer)) {
43346
0
            args[0] = O;
43347
0
            args[1] = replaceValue;
43348
0
            return JS_CallFree(ctx, replacer, searchValue, 2, args);
43349
0
        }
43350
0
    }
43351
0
    string_buffer_init(ctx, b, 0);
43352
43353
0
    str = JS_ToString(ctx, O);
43354
0
    if (JS_IsException(str))
43355
0
        goto exception;
43356
0
    search_str = JS_ToString(ctx, searchValue);
43357
0
    if (JS_IsException(search_str))
43358
0
        goto exception;
43359
0
    functionalReplace = JS_IsFunction(ctx, replaceValue);
43360
0
    if (!functionalReplace) {
43361
0
        replaceValue_str = JS_ToString(ctx, replaceValue);
43362
0
        if (JS_IsException(replaceValue_str))
43363
0
            goto exception;
43364
0
    }
43365
43366
0
    sp = JS_VALUE_GET_STRING(str);
43367
0
    searchp = JS_VALUE_GET_STRING(search_str);
43368
0
    endOfLastMatch = 0;
43369
0
    is_first = TRUE;
43370
0
    for(;;) {
43371
0
        if (unlikely(searchp->len == 0)) {
43372
0
            if (is_first)
43373
0
                pos = 0;
43374
0
            else if (endOfLastMatch >= sp->len)
43375
0
                pos = -1;
43376
0
            else
43377
0
                pos = endOfLastMatch + 1;
43378
0
        } else {
43379
0
            pos = string_indexof(sp, searchp, endOfLastMatch);
43380
0
        }
43381
0
        if (pos < 0) {
43382
0
            if (is_first) {
43383
0
                string_buffer_free(b);
43384
0
                JS_FreeValue(ctx, search_str);
43385
0
                JS_FreeValue(ctx, replaceValue_str);
43386
0
                return str;
43387
0
            } else {
43388
0
                break;
43389
0
            }
43390
0
        }
43391
0
        if (functionalReplace) {
43392
0
            args[0] = search_str;
43393
0
            args[1] = JS_NewInt32(ctx, pos);
43394
0
            args[2] = str;
43395
0
            repl_str = JS_ToStringFree(ctx, JS_Call(ctx, replaceValue, JS_UNDEFINED, 3, args));
43396
0
        } else {
43397
0
            args[0] = search_str;
43398
0
            args[1] = str;
43399
0
            args[2] = JS_NewInt32(ctx, pos);
43400
0
            args[3] = JS_UNDEFINED;
43401
0
            args[4] = JS_UNDEFINED;
43402
0
            args[5] = replaceValue_str;
43403
0
            repl_str = js_string___GetSubstitution(ctx, JS_UNDEFINED, 6, args);
43404
0
        }
43405
0
        if (JS_IsException(repl_str))
43406
0
            goto exception;
43407
43408
0
        string_buffer_concat(b, sp, endOfLastMatch, pos);
43409
0
        string_buffer_concat_value_free(b, repl_str);
43410
0
        endOfLastMatch = pos + searchp->len;
43411
0
        is_first = FALSE;
43412
0
        if (!is_replaceAll)
43413
0
            break;
43414
0
    }
43415
0
    string_buffer_concat(b, sp, endOfLastMatch, sp->len);
43416
0
    JS_FreeValue(ctx, search_str);
43417
0
    JS_FreeValue(ctx, replaceValue_str);
43418
0
    JS_FreeValue(ctx, str);
43419
0
    return string_buffer_end(b);
43420
43421
0
exception:
43422
0
    string_buffer_free(b);
43423
0
    JS_FreeValue(ctx, search_str);
43424
0
    JS_FreeValue(ctx, replaceValue_str);
43425
0
    JS_FreeValue(ctx, str);
43426
0
    return JS_EXCEPTION;
43427
0
}
43428
43429
static JSValue js_string_split(JSContext *ctx, JSValueConst this_val,
43430
                               int argc, JSValueConst *argv)
43431
0
{
43432
    // split(sep, limit)
43433
0
    JSValueConst O = this_val, separator = argv[0], limit = argv[1];
43434
0
    JSValueConst args[2];
43435
0
    JSValue S, A, R, T;
43436
0
    uint32_t lim, lengthA;
43437
0
    int64_t p, q, s, r, e;
43438
0
    JSString *sp, *rp;
43439
43440
0
    if (JS_IsUndefined(O) || JS_IsNull(O))
43441
0
        return JS_ThrowTypeError(ctx, "cannot convert to object");
43442
43443
0
    S = JS_UNDEFINED;
43444
0
    A = JS_UNDEFINED;
43445
0
    R = JS_UNDEFINED;
43446
43447
0
    if (!JS_IsUndefined(separator) && !JS_IsNull(separator)) {
43448
0
        JSValue splitter;
43449
0
        splitter = JS_GetProperty(ctx, separator, JS_ATOM_Symbol_split);
43450
0
        if (JS_IsException(splitter))
43451
0
            return JS_EXCEPTION;
43452
0
        if (!JS_IsUndefined(splitter) && !JS_IsNull(splitter)) {
43453
0
            args[0] = O;
43454
0
            args[1] = limit;
43455
0
            return JS_CallFree(ctx, splitter, separator, 2, args);
43456
0
        }
43457
0
    }
43458
0
    S = JS_ToString(ctx, O);
43459
0
    if (JS_IsException(S))
43460
0
        goto exception;
43461
0
    A = JS_NewArray(ctx);
43462
0
    if (JS_IsException(A))
43463
0
        goto exception;
43464
0
    lengthA = 0;
43465
0
    if (JS_IsUndefined(limit)) {
43466
0
        lim = 0xffffffff;
43467
0
    } else {
43468
0
        if (JS_ToUint32(ctx, &lim, limit) < 0)
43469
0
            goto exception;
43470
0
    }
43471
0
    sp = JS_VALUE_GET_STRING(S);
43472
0
    s = sp->len;
43473
0
    R = JS_ToString(ctx, separator);
43474
0
    if (JS_IsException(R))
43475
0
        goto exception;
43476
0
    rp = JS_VALUE_GET_STRING(R);
43477
0
    r = rp->len;
43478
0
    p = 0;
43479
0
    if (lim == 0)
43480
0
        goto done;
43481
0
    if (JS_IsUndefined(separator))
43482
0
        goto add_tail;
43483
0
    if (s == 0) {
43484
0
        if (r != 0)
43485
0
            goto add_tail;
43486
0
        goto done;
43487
0
    }
43488
0
    q = p;
43489
0
    for (q = p; (q += !r) <= s - r - !r; q = p = e + r) {
43490
0
        e = string_indexof(sp, rp, q);
43491
0
        if (e < 0)
43492
0
            break;
43493
0
        T = js_sub_string(ctx, sp, p, e);
43494
0
        if (JS_IsException(T))
43495
0
            goto exception;
43496
0
        if (JS_CreateDataPropertyUint32(ctx, A, lengthA++, T, 0) < 0)
43497
0
            goto exception;
43498
0
        if (lengthA == lim)
43499
0
            goto done;
43500
0
    }
43501
0
add_tail:
43502
0
    T = js_sub_string(ctx, sp, p, s);
43503
0
    if (JS_IsException(T))
43504
0
        goto exception;
43505
0
    if (JS_CreateDataPropertyUint32(ctx, A, lengthA++, T,0 ) < 0)
43506
0
        goto exception;
43507
0
done:
43508
0
    JS_FreeValue(ctx, S);
43509
0
    JS_FreeValue(ctx, R);
43510
0
    return A;
43511
43512
0
exception:
43513
0
    JS_FreeValue(ctx, A);
43514
0
    JS_FreeValue(ctx, S);
43515
0
    JS_FreeValue(ctx, R);
43516
0
    return JS_EXCEPTION;
43517
0
}
43518
43519
static JSValue js_string_substring(JSContext *ctx, JSValueConst this_val,
43520
                                   int argc, JSValueConst *argv)
43521
0
{
43522
0
    JSValue str, ret;
43523
0
    int a, b, start, end;
43524
0
    JSString *p;
43525
43526
0
    str = JS_ToStringCheckObject(ctx, this_val);
43527
0
    if (JS_IsException(str))
43528
0
        return str;
43529
0
    p = JS_VALUE_GET_STRING(str);
43530
0
    if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, p->len, 0)) {
43531
0
        JS_FreeValue(ctx, str);
43532
0
        return JS_EXCEPTION;
43533
0
    }
43534
0
    b = p->len;
43535
0
    if (!JS_IsUndefined(argv[1])) {
43536
0
        if (JS_ToInt32Clamp(ctx, &b, argv[1], 0, p->len, 0)) {
43537
0
            JS_FreeValue(ctx, str);
43538
0
            return JS_EXCEPTION;
43539
0
        }
43540
0
    }
43541
0
    if (a < b) {
43542
0
        start = a;
43543
0
        end = b;
43544
0
    } else {
43545
0
        start = b;
43546
0
        end = a;
43547
0
    }
43548
0
    ret = js_sub_string(ctx, p, start, end);
43549
0
    JS_FreeValue(ctx, str);
43550
0
    return ret;
43551
0
}
43552
43553
static JSValue js_string_substr(JSContext *ctx, JSValueConst this_val,
43554
                                int argc, JSValueConst *argv)
43555
0
{
43556
0
    JSValue str, ret;
43557
0
    int a, len, n;
43558
0
    JSString *p;
43559
43560
0
    str = JS_ToStringCheckObject(ctx, this_val);
43561
0
    if (JS_IsException(str))
43562
0
        return str;
43563
0
    p = JS_VALUE_GET_STRING(str);
43564
0
    len = p->len;
43565
0
    if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, len, len)) {
43566
0
        JS_FreeValue(ctx, str);
43567
0
        return JS_EXCEPTION;
43568
0
    }
43569
0
    n = len - a;
43570
0
    if (!JS_IsUndefined(argv[1])) {
43571
0
        if (JS_ToInt32Clamp(ctx, &n, argv[1], 0, len - a, 0)) {
43572
0
            JS_FreeValue(ctx, str);
43573
0
            return JS_EXCEPTION;
43574
0
        }
43575
0
    }
43576
0
    ret = js_sub_string(ctx, p, a, a + n);
43577
0
    JS_FreeValue(ctx, str);
43578
0
    return ret;
43579
0
}
43580
43581
static JSValue js_string_slice(JSContext *ctx, JSValueConst this_val,
43582
                               int argc, JSValueConst *argv)
43583
0
{
43584
0
    JSValue str, ret;
43585
0
    int len, start, end;
43586
0
    JSString *p;
43587
43588
0
    str = JS_ToStringCheckObject(ctx, this_val);
43589
0
    if (JS_IsException(str))
43590
0
        return str;
43591
0
    p = JS_VALUE_GET_STRING(str);
43592
0
    len = p->len;
43593
0
    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len)) {
43594
0
        JS_FreeValue(ctx, str);
43595
0
        return JS_EXCEPTION;
43596
0
    }
43597
0
    end = len;
43598
0
    if (!JS_IsUndefined(argv[1])) {
43599
0
        if (JS_ToInt32Clamp(ctx, &end, argv[1], 0, len, len)) {
43600
0
            JS_FreeValue(ctx, str);
43601
0
            return JS_EXCEPTION;
43602
0
        }
43603
0
    }
43604
0
    ret = js_sub_string(ctx, p, start, max_int(end, start));
43605
0
    JS_FreeValue(ctx, str);
43606
0
    return ret;
43607
0
}
43608
43609
static JSValue js_string_pad(JSContext *ctx, JSValueConst this_val,
43610
                             int argc, JSValueConst *argv, int padEnd)
43611
0
{
43612
0
    JSValue str, v = JS_UNDEFINED;
43613
0
    StringBuffer b_s, *b = &b_s;
43614
0
    JSString *p, *p1 = NULL;
43615
0
    int n, len, c = ' ';
43616
43617
0
    str = JS_ToStringCheckObject(ctx, this_val);
43618
0
    if (JS_IsException(str))
43619
0
        goto fail1;
43620
0
    if (JS_ToInt32Sat(ctx, &n, argv[0]))
43621
0
        goto fail2;
43622
0
    p = JS_VALUE_GET_STRING(str);
43623
0
    len = p->len;
43624
0
    if (len >= n)
43625
0
        return str;
43626
0
    if (argc > 1 && !JS_IsUndefined(argv[1])) {
43627
0
        v = JS_ToString(ctx, argv[1]);
43628
0
        if (JS_IsException(v))
43629
0
            goto fail2;
43630
0
        p1 = JS_VALUE_GET_STRING(v);
43631
0
        if (p1->len == 0) {
43632
0
            JS_FreeValue(ctx, v);
43633
0
            return str;
43634
0
        }
43635
0
        if (p1->len == 1) {
43636
0
            c = string_get(p1, 0);
43637
0
            p1 = NULL;
43638
0
        }
43639
0
    }
43640
0
    if (n > JS_STRING_LEN_MAX) {
43641
0
        JS_ThrowRangeError(ctx, "invalid string length");
43642
0
        goto fail3;
43643
0
    }
43644
0
    if (string_buffer_init(ctx, b, n))
43645
0
        goto fail3;
43646
0
    n -= len;
43647
0
    if (padEnd) {
43648
0
        if (string_buffer_concat(b, p, 0, len))
43649
0
            goto fail;
43650
0
    }
43651
0
    if (p1) {
43652
0
        while (n > 0) {
43653
0
            int chunk = min_int(n, p1->len);
43654
0
            if (string_buffer_concat(b, p1, 0, chunk))
43655
0
                goto fail;
43656
0
            n -= chunk;
43657
0
        }
43658
0
    } else {
43659
0
        if (string_buffer_fill(b, c, n))
43660
0
            goto fail;
43661
0
    }
43662
0
    if (!padEnd) {
43663
0
        if (string_buffer_concat(b, p, 0, len))
43664
0
            goto fail;
43665
0
    }
43666
0
    JS_FreeValue(ctx, v);
43667
0
    JS_FreeValue(ctx, str);
43668
0
    return string_buffer_end(b);
43669
43670
0
fail:
43671
0
    string_buffer_free(b);
43672
0
fail3:
43673
0
    JS_FreeValue(ctx, v);
43674
0
fail2:
43675
0
    JS_FreeValue(ctx, str);
43676
0
fail1:
43677
0
    return JS_EXCEPTION;
43678
0
}
43679
43680
static JSValue js_string_repeat(JSContext *ctx, JSValueConst this_val,
43681
                                int argc, JSValueConst *argv)
43682
0
{
43683
0
    JSValue str;
43684
0
    StringBuffer b_s, *b = &b_s;
43685
0
    JSString *p;
43686
0
    int64_t val;
43687
0
    int n, len;
43688
43689
0
    str = JS_ToStringCheckObject(ctx, this_val);
43690
0
    if (JS_IsException(str))
43691
0
        goto fail;
43692
0
    if (JS_ToInt64Sat(ctx, &val, argv[0]))
43693
0
        goto fail;
43694
0
    if (val < 0 || val > 2147483647) {
43695
0
        JS_ThrowRangeError(ctx, "invalid repeat count");
43696
0
        goto fail;
43697
0
    }
43698
0
    n = val;
43699
0
    p = JS_VALUE_GET_STRING(str);
43700
0
    len = p->len;
43701
0
    if (len == 0 || n == 1)
43702
0
        return str;
43703
    // XXX: potential arithmetic overflow
43704
0
    if (val * len > JS_STRING_LEN_MAX) {
43705
0
        JS_ThrowRangeError(ctx, "invalid string length");
43706
0
        goto fail;
43707
0
    }
43708
0
    if (string_buffer_init2(ctx, b, n * len, p->is_wide_char))
43709
0
        goto fail;
43710
0
    if (len == 1) {
43711
0
        string_buffer_fill(b, string_get(p, 0), n);
43712
0
    } else {
43713
0
        while (n-- > 0) {
43714
0
            string_buffer_concat(b, p, 0, len);
43715
0
        }
43716
0
    }
43717
0
    JS_FreeValue(ctx, str);
43718
0
    return string_buffer_end(b);
43719
43720
0
fail:
43721
0
    JS_FreeValue(ctx, str);
43722
0
    return JS_EXCEPTION;
43723
0
}
43724
43725
static JSValue js_string_trim(JSContext *ctx, JSValueConst this_val,
43726
                              int argc, JSValueConst *argv, int magic)
43727
0
{
43728
0
    JSValue str, ret;
43729
0
    int a, b, len;
43730
0
    JSString *p;
43731
43732
0
    str = JS_ToStringCheckObject(ctx, this_val);
43733
0
    if (JS_IsException(str))
43734
0
        return str;
43735
0
    p = JS_VALUE_GET_STRING(str);
43736
0
    a = 0;
43737
0
    b = len = p->len;
43738
0
    if (magic & 1) {
43739
0
        while (a < len && lre_is_space(string_get(p, a)))
43740
0
            a++;
43741
0
    }
43742
0
    if (magic & 2) {
43743
0
        while (b > a && lre_is_space(string_get(p, b - 1)))
43744
0
            b--;
43745
0
    }
43746
0
    ret = js_sub_string(ctx, p, a, b);
43747
0
    JS_FreeValue(ctx, str);
43748
0
    return ret;
43749
0
}
43750
43751
static JSValue js_string___quote(JSContext *ctx, JSValueConst this_val,
43752
                                 int argc, JSValueConst *argv)
43753
0
{
43754
0
    return JS_ToQuotedString(ctx, this_val);
43755
0
}
43756
43757
/* return 0 if before the first char */
43758
static int string_prevc(JSString *p, int *pidx)
43759
0
{
43760
0
    int idx, c, c1;
43761
43762
0
    idx = *pidx;
43763
0
    if (idx <= 0)
43764
0
        return 0;
43765
0
    idx--;
43766
0
    if (p->is_wide_char) {
43767
0
        c = p->u.str16[idx];
43768
0
        if (is_lo_surrogate(c) && idx > 0) {
43769
0
            c1 = p->u.str16[idx - 1];
43770
0
            if (is_hi_surrogate(c1)) {
43771
0
                c = from_surrogate(c1, c);
43772
0
                idx--;
43773
0
            }
43774
0
        }
43775
0
    } else {
43776
0
        c = p->u.str8[idx];
43777
0
    }
43778
0
    *pidx = idx;
43779
0
    return c;
43780
0
}
43781
43782
static BOOL test_final_sigma(JSString *p, int sigma_pos)
43783
0
{
43784
0
    int k, c1;
43785
43786
    /* before C: skip case ignorable chars and check there is
43787
       a cased letter */
43788
0
    k = sigma_pos;
43789
0
    for(;;) {
43790
0
        c1 = string_prevc(p, &k);
43791
0
        if (!lre_is_case_ignorable(c1))
43792
0
            break;
43793
0
    }
43794
0
    if (!lre_is_cased(c1))
43795
0
        return FALSE;
43796
43797
    /* after C: skip case ignorable chars and check there is
43798
       no cased letter */
43799
0
    k = sigma_pos + 1;
43800
0
    for(;;) {
43801
0
        if (k >= p->len)
43802
0
            return TRUE;
43803
0
        c1 = string_getc(p, &k);
43804
0
        if (!lre_is_case_ignorable(c1))
43805
0
            break;
43806
0
    }
43807
0
    return !lre_is_cased(c1);
43808
0
}
43809
43810
static JSValue js_string_toLowerCase(JSContext *ctx, JSValueConst this_val,
43811
                                     int argc, JSValueConst *argv, int to_lower)
43812
0
{
43813
0
    JSValue val;
43814
0
    StringBuffer b_s, *b = &b_s;
43815
0
    JSString *p;
43816
0
    int i, c, j, l;
43817
0
    uint32_t res[LRE_CC_RES_LEN_MAX];
43818
43819
0
    val = JS_ToStringCheckObject(ctx, this_val);
43820
0
    if (JS_IsException(val))
43821
0
        return val;
43822
0
    p = JS_VALUE_GET_STRING(val);
43823
0
    if (p->len == 0)
43824
0
        return val;
43825
0
    if (string_buffer_init(ctx, b, p->len))
43826
0
        goto fail;
43827
0
    for(i = 0; i < p->len;) {
43828
0
        c = string_getc(p, &i);
43829
0
        if (c == 0x3a3 && to_lower && test_final_sigma(p, i - 1)) {
43830
0
            res[0] = 0x3c2; /* final sigma */
43831
0
            l = 1;
43832
0
        } else {
43833
0
            l = lre_case_conv(res, c, to_lower);
43834
0
        }
43835
0
        for(j = 0; j < l; j++) {
43836
0
            if (string_buffer_putc(b, res[j]))
43837
0
                goto fail;
43838
0
        }
43839
0
    }
43840
0
    JS_FreeValue(ctx, val);
43841
0
    return string_buffer_end(b);
43842
0
 fail:
43843
0
    JS_FreeValue(ctx, val);
43844
0
    string_buffer_free(b);
43845
0
    return JS_EXCEPTION;
43846
0
}
43847
43848
#ifdef CONFIG_ALL_UNICODE
43849
43850
/* return (-1, NULL) if exception, otherwise (len, buf) */
43851
static int JS_ToUTF32String(JSContext *ctx, uint32_t **pbuf, JSValueConst val1)
43852
0
{
43853
0
    JSValue val;
43854
0
    JSString *p;
43855
0
    uint32_t *buf;
43856
0
    int i, j, len;
43857
43858
0
    val = JS_ToString(ctx, val1);
43859
0
    if (JS_IsException(val))
43860
0
        return -1;
43861
0
    p = JS_VALUE_GET_STRING(val);
43862
0
    len = p->len;
43863
    /* UTF32 buffer length is len minus the number of correct surrogates pairs */
43864
0
    buf = js_malloc(ctx, sizeof(buf[0]) * max_int(len, 1));
43865
0
    if (!buf) {
43866
0
        JS_FreeValue(ctx, val);
43867
0
        goto fail;
43868
0
    }
43869
0
    for(i = j = 0; i < len;)
43870
0
        buf[j++] = string_getc(p, &i);
43871
0
    JS_FreeValue(ctx, val);
43872
0
    *pbuf = buf;
43873
0
    return j;
43874
0
 fail:
43875
0
    *pbuf = NULL;
43876
0
    return -1;
43877
0
}
43878
43879
static JSValue JS_NewUTF32String(JSContext *ctx, const uint32_t *buf, int len)
43880
0
{
43881
0
    int i;
43882
0
    StringBuffer b_s, *b = &b_s;
43883
0
    if (string_buffer_init(ctx, b, len))
43884
0
        return JS_EXCEPTION;
43885
0
    for(i = 0; i < len; i++) {
43886
0
        if (string_buffer_putc(b, buf[i]))
43887
0
            goto fail;
43888
0
    }
43889
0
    return string_buffer_end(b);
43890
0
 fail:
43891
0
    string_buffer_free(b);
43892
0
    return JS_EXCEPTION;
43893
0
}
43894
43895
static int js_string_normalize1(JSContext *ctx, uint32_t **pout_buf,
43896
                                JSValueConst val,
43897
                                UnicodeNormalizationEnum n_type)
43898
0
{
43899
0
    int buf_len, out_len;
43900
0
    uint32_t *buf, *out_buf;
43901
43902
0
    buf_len = JS_ToUTF32String(ctx, &buf, val);
43903
0
    if (buf_len < 0)
43904
0
        return -1;
43905
0
    out_len = unicode_normalize(&out_buf, buf, buf_len, n_type,
43906
0
                                ctx->rt, (DynBufReallocFunc *)js_realloc_rt);
43907
0
    js_free(ctx, buf);
43908
0
    if (out_len < 0)
43909
0
        return -1;
43910
0
    *pout_buf = out_buf;
43911
0
    return out_len;
43912
0
}
43913
43914
static JSValue js_string_normalize(JSContext *ctx, JSValueConst this_val,
43915
                                   int argc, JSValueConst *argv)
43916
0
{
43917
0
    const char *form, *p;
43918
0
    size_t form_len;
43919
0
    int is_compat, out_len;
43920
0
    UnicodeNormalizationEnum n_type;
43921
0
    JSValue val;
43922
0
    uint32_t *out_buf;
43923
43924
0
    val = JS_ToStringCheckObject(ctx, this_val);
43925
0
    if (JS_IsException(val))
43926
0
        return val;
43927
43928
0
    if (argc == 0 || JS_IsUndefined(argv[0])) {
43929
0
        n_type = UNICODE_NFC;
43930
0
    } else {
43931
0
        form = JS_ToCStringLen(ctx, &form_len, argv[0]);
43932
0
        if (!form)
43933
0
            goto fail1;
43934
0
        p = form;
43935
0
        if (p[0] != 'N' || p[1] != 'F')
43936
0
            goto bad_form;
43937
0
        p += 2;
43938
0
        is_compat = FALSE;
43939
0
        if (*p == 'K') {
43940
0
            is_compat = TRUE;
43941
0
            p++;
43942
0
        }
43943
0
        if (*p == 'C' || *p == 'D') {
43944
0
            n_type = UNICODE_NFC + is_compat * 2 + (*p - 'C');
43945
0
            if ((p + 1 - form) != form_len)
43946
0
                goto bad_form;
43947
0
        } else {
43948
0
        bad_form:
43949
0
            JS_FreeCString(ctx, form);
43950
0
            JS_ThrowRangeError(ctx, "bad normalization form");
43951
0
        fail1:
43952
0
            JS_FreeValue(ctx, val);
43953
0
            return JS_EXCEPTION;
43954
0
        }
43955
0
        JS_FreeCString(ctx, form);
43956
0
    }
43957
43958
0
    out_len = js_string_normalize1(ctx, &out_buf, val, n_type);
43959
0
    JS_FreeValue(ctx, val);
43960
0
    if (out_len < 0)
43961
0
        return JS_EXCEPTION;
43962
0
    val = JS_NewUTF32String(ctx, out_buf, out_len);
43963
0
    js_free(ctx, out_buf);
43964
0
    return val;
43965
0
}
43966
43967
/* return < 0, 0 or > 0 */
43968
static int js_UTF32_compare(const uint32_t *buf1, int buf1_len,
43969
                            const uint32_t *buf2, int buf2_len)
43970
0
{
43971
0
    int i, len, c, res;
43972
0
    len = min_int(buf1_len, buf2_len);
43973
0
    for(i = 0; i < len; i++) {
43974
        /* Note: range is limited so a subtraction is valid */
43975
0
        c = buf1[i] - buf2[i];
43976
0
        if (c != 0)
43977
0
            return c;
43978
0
    }
43979
0
    if (buf1_len == buf2_len)
43980
0
        res = 0;
43981
0
    else if (buf1_len < buf2_len)
43982
0
        res = -1;
43983
0
    else
43984
0
        res = 1;
43985
0
    return res;
43986
0
}
43987
43988
static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val,
43989
                                       int argc, JSValueConst *argv)
43990
0
{
43991
0
    JSValue a, b;
43992
0
    int cmp, a_len, b_len;
43993
0
    uint32_t *a_buf, *b_buf;
43994
43995
0
    a = JS_ToStringCheckObject(ctx, this_val);
43996
0
    if (JS_IsException(a))
43997
0
        return JS_EXCEPTION;
43998
0
    b = JS_ToString(ctx, argv[0]);
43999
0
    if (JS_IsException(b)) {
44000
0
        JS_FreeValue(ctx, a);
44001
0
        return JS_EXCEPTION;
44002
0
    }
44003
0
    a_len = js_string_normalize1(ctx, &a_buf, a, UNICODE_NFC);
44004
0
    JS_FreeValue(ctx, a);
44005
0
    if (a_len < 0) {
44006
0
        JS_FreeValue(ctx, b);
44007
0
        return JS_EXCEPTION;
44008
0
    }
44009
44010
0
    b_len = js_string_normalize1(ctx, &b_buf, b, UNICODE_NFC);
44011
0
    JS_FreeValue(ctx, b);
44012
0
    if (b_len < 0) {
44013
0
        js_free(ctx, a_buf);
44014
0
        return JS_EXCEPTION;
44015
0
    }
44016
0
    cmp = js_UTF32_compare(a_buf, a_len, b_buf, b_len);
44017
0
    js_free(ctx, a_buf);
44018
0
    js_free(ctx, b_buf);
44019
0
    return JS_NewInt32(ctx, cmp);
44020
0
}
44021
#else /* CONFIG_ALL_UNICODE */
44022
static JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val,
44023
                                       int argc, JSValueConst *argv)
44024
{
44025
    JSValue a, b;
44026
    int cmp;
44027
44028
    a = JS_ToStringCheckObject(ctx, this_val);
44029
    if (JS_IsException(a))
44030
        return JS_EXCEPTION;
44031
    b = JS_ToString(ctx, argv[0]);
44032
    if (JS_IsException(b)) {
44033
        JS_FreeValue(ctx, a);
44034
        return JS_EXCEPTION;
44035
    }
44036
    cmp = js_string_compare(ctx, JS_VALUE_GET_STRING(a), JS_VALUE_GET_STRING(b));
44037
    JS_FreeValue(ctx, a);
44038
    JS_FreeValue(ctx, b);
44039
    return JS_NewInt32(ctx, cmp);
44040
}
44041
#endif /* !CONFIG_ALL_UNICODE */
44042
44043
/* also used for String.prototype.valueOf */
44044
static JSValue js_string_toString(JSContext *ctx, JSValueConst this_val,
44045
                                  int argc, JSValueConst *argv)
44046
0
{
44047
0
    return js_thisStringValue(ctx, this_val);
44048
0
}
44049
44050
#if 0
44051
static JSValue js_string___toStringCheckObject(JSContext *ctx, JSValueConst this_val,
44052
                                               int argc, JSValueConst *argv)
44053
{
44054
    return JS_ToStringCheckObject(ctx, argv[0]);
44055
}
44056
44057
static JSValue js_string___toString(JSContext *ctx, JSValueConst this_val,
44058
                                    int argc, JSValueConst *argv)
44059
{
44060
    return JS_ToString(ctx, argv[0]);
44061
}
44062
44063
static JSValue js_string___advanceStringIndex(JSContext *ctx, JSValueConst
44064
                                              this_val,
44065
                                              int argc, JSValueConst *argv)
44066
{
44067
    JSValue str;
44068
    int idx;
44069
    BOOL is_unicode;
44070
    JSString *p;
44071
44072
    str = JS_ToString(ctx, argv[0]);
44073
    if (JS_IsException(str))
44074
        return str;
44075
    if (JS_ToInt32Sat(ctx, &idx, argv[1])) {
44076
        JS_FreeValue(ctx, str);
44077
        return JS_EXCEPTION;
44078
    }
44079
    is_unicode = JS_ToBool(ctx, argv[2]);
44080
    p = JS_VALUE_GET_STRING(str);
44081
    if (!is_unicode || (unsigned)idx >= p->len || !p->is_wide_char) {
44082
        idx++;
44083
    } else {
44084
        string_getc(p, &idx);
44085
    }
44086
    JS_FreeValue(ctx, str);
44087
    return JS_NewInt32(ctx, idx);
44088
}
44089
#endif
44090
44091
/* String Iterator */
44092
44093
static JSValue js_string_iterator_next(JSContext *ctx, JSValueConst this_val,
44094
                                       int argc, JSValueConst *argv,
44095
                                       BOOL *pdone, int magic)
44096
0
{
44097
0
    JSArrayIteratorData *it;
44098
0
    uint32_t idx, c, start;
44099
0
    JSString *p;
44100
44101
0
    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_STRING_ITERATOR);
44102
0
    if (!it) {
44103
0
        *pdone = FALSE;
44104
0
        return JS_EXCEPTION;
44105
0
    }
44106
0
    if (JS_IsUndefined(it->obj))
44107
0
        goto done;
44108
0
    p = JS_VALUE_GET_STRING(it->obj);
44109
0
    idx = it->idx;
44110
0
    if (idx >= p->len) {
44111
0
        JS_FreeValue(ctx, it->obj);
44112
0
        it->obj = JS_UNDEFINED;
44113
0
    done:
44114
0
        *pdone = TRUE;
44115
0
        return JS_UNDEFINED;
44116
0
    }
44117
44118
0
    start = idx;
44119
0
    c = string_getc(p, (int *)&idx);
44120
0
    it->idx = idx;
44121
0
    *pdone = FALSE;
44122
0
    if (c <= 0xffff) {
44123
0
        return js_new_string_char(ctx, c);
44124
0
    } else {
44125
0
        return js_new_string16_len(ctx, p->u.str16 + start, 2);
44126
0
    }
44127
0
}
44128
44129
/* ES6 Annex B 2.3.2 etc. */
44130
enum {
44131
    magic_string_anchor,
44132
    magic_string_big,
44133
    magic_string_blink,
44134
    magic_string_bold,
44135
    magic_string_fixed,
44136
    magic_string_fontcolor,
44137
    magic_string_fontsize,
44138
    magic_string_italics,
44139
    magic_string_link,
44140
    magic_string_small,
44141
    magic_string_strike,
44142
    magic_string_sub,
44143
    magic_string_sup,
44144
};
44145
44146
static JSValue js_string_CreateHTML(JSContext *ctx, JSValueConst this_val,
44147
                                    int argc, JSValueConst *argv, int magic)
44148
0
{
44149
0
    JSValue str;
44150
0
    const JSString *p;
44151
0
    StringBuffer b_s, *b = &b_s;
44152
0
    static struct { const char *tag, *attr; } const defs[] = {
44153
0
        { "a", "name" }, { "big", NULL }, { "blink", NULL }, { "b", NULL },
44154
0
        { "tt", NULL }, { "font", "color" }, { "font", "size" }, { "i", NULL },
44155
0
        { "a", "href" }, { "small", NULL }, { "strike", NULL },
44156
0
        { "sub", NULL }, { "sup", NULL },
44157
0
    };
44158
44159
0
    str = JS_ToStringCheckObject(ctx, this_val);
44160
0
    if (JS_IsException(str))
44161
0
        return JS_EXCEPTION;
44162
0
    string_buffer_init(ctx, b, 7);
44163
0
    string_buffer_putc8(b, '<');
44164
0
    string_buffer_puts8(b, defs[magic].tag);
44165
0
    if (defs[magic].attr) {
44166
        // r += " " + attr + "=\"" + value + "\"";
44167
0
        JSValue value;
44168
0
        int i;
44169
44170
0
        string_buffer_putc8(b, ' ');
44171
0
        string_buffer_puts8(b, defs[magic].attr);
44172
0
        string_buffer_puts8(b, "=\"");
44173
0
        value = JS_ToStringCheckObject(ctx, argv[0]);
44174
0
        if (JS_IsException(value)) {
44175
0
            JS_FreeValue(ctx, str);
44176
0
            string_buffer_free(b);
44177
0
            return JS_EXCEPTION;
44178
0
        }
44179
0
        p = JS_VALUE_GET_STRING(value);
44180
0
        for (i = 0; i < p->len; i++) {
44181
0
            int c = string_get(p, i);
44182
0
            if (c == '"') {
44183
0
                string_buffer_puts8(b, "&quot;");
44184
0
            } else {
44185
0
                string_buffer_putc16(b, c);
44186
0
            }
44187
0
        }
44188
0
        JS_FreeValue(ctx, value);
44189
0
        string_buffer_putc8(b, '\"');
44190
0
    }
44191
    // return r + ">" + str + "</" + tag + ">";
44192
0
    string_buffer_putc8(b, '>');
44193
0
    string_buffer_concat_value_free(b, str);
44194
0
    string_buffer_puts8(b, "</");
44195
0
    string_buffer_puts8(b, defs[magic].tag);
44196
0
    string_buffer_putc8(b, '>');
44197
0
    return string_buffer_end(b);
44198
0
}
44199
44200
static const JSCFunctionListEntry js_string_funcs[] = {
44201
    JS_CFUNC_DEF("fromCharCode", 1, js_string_fromCharCode ),
44202
    JS_CFUNC_DEF("fromCodePoint", 1, js_string_fromCodePoint ),
44203
    JS_CFUNC_DEF("raw", 1, js_string_raw ),
44204
    //JS_CFUNC_DEF("__toString", 1, js_string___toString ),
44205
    //JS_CFUNC_DEF("__isSpace", 1, js_string___isSpace ),
44206
    //JS_CFUNC_DEF("__toStringCheckObject", 1, js_string___toStringCheckObject ),
44207
    //JS_CFUNC_DEF("__advanceStringIndex", 3, js_string___advanceStringIndex ),
44208
    //JS_CFUNC_DEF("__GetSubstitution", 6, js_string___GetSubstitution ),
44209
};
44210
44211
static const JSCFunctionListEntry js_string_proto_funcs[] = {
44212
    JS_PROP_INT32_DEF("length", 0, JS_PROP_CONFIGURABLE ),
44213
    JS_CFUNC_MAGIC_DEF("at", 1, js_string_charAt, 1 ),
44214
    JS_CFUNC_DEF("charCodeAt", 1, js_string_charCodeAt ),
44215
    JS_CFUNC_MAGIC_DEF("charAt", 1, js_string_charAt, 0 ),
44216
    JS_CFUNC_DEF("concat", 1, js_string_concat ),
44217
    JS_CFUNC_DEF("codePointAt", 1, js_string_codePointAt ),
44218
    JS_CFUNC_DEF("isWellFormed", 0, js_string_isWellFormed ),
44219
    JS_CFUNC_DEF("toWellFormed", 0, js_string_toWellFormed ),
44220
    JS_CFUNC_MAGIC_DEF("indexOf", 1, js_string_indexOf, 0 ),
44221
    JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_string_indexOf, 1 ),
44222
    JS_CFUNC_MAGIC_DEF("includes", 1, js_string_includes, 0 ),
44223
    JS_CFUNC_MAGIC_DEF("endsWith", 1, js_string_includes, 2 ),
44224
    JS_CFUNC_MAGIC_DEF("startsWith", 1, js_string_includes, 1 ),
44225
    JS_CFUNC_MAGIC_DEF("match", 1, js_string_match, JS_ATOM_Symbol_match ),
44226
    JS_CFUNC_MAGIC_DEF("matchAll", 1, js_string_match, JS_ATOM_Symbol_matchAll ),
44227
    JS_CFUNC_MAGIC_DEF("search", 1, js_string_match, JS_ATOM_Symbol_search ),
44228
    JS_CFUNC_DEF("split", 2, js_string_split ),
44229
    JS_CFUNC_DEF("substring", 2, js_string_substring ),
44230
    JS_CFUNC_DEF("substr", 2, js_string_substr ),
44231
    JS_CFUNC_DEF("slice", 2, js_string_slice ),
44232
    JS_CFUNC_DEF("repeat", 1, js_string_repeat ),
44233
    JS_CFUNC_MAGIC_DEF("replace", 2, js_string_replace, 0 ),
44234
    JS_CFUNC_MAGIC_DEF("replaceAll", 2, js_string_replace, 1 ),
44235
    JS_CFUNC_MAGIC_DEF("padEnd", 1, js_string_pad, 1 ),
44236
    JS_CFUNC_MAGIC_DEF("padStart", 1, js_string_pad, 0 ),
44237
    JS_CFUNC_MAGIC_DEF("trim", 0, js_string_trim, 3 ),
44238
    JS_CFUNC_MAGIC_DEF("trimEnd", 0, js_string_trim, 2 ),
44239
    JS_ALIAS_DEF("trimRight", "trimEnd" ),
44240
    JS_CFUNC_MAGIC_DEF("trimStart", 0, js_string_trim, 1 ),
44241
    JS_ALIAS_DEF("trimLeft", "trimStart" ),
44242
    JS_CFUNC_DEF("toString", 0, js_string_toString ),
44243
    JS_CFUNC_DEF("valueOf", 0, js_string_toString ),
44244
    JS_CFUNC_DEF("__quote", 1, js_string___quote ),
44245
    JS_CFUNC_MAGIC_DEF("toLowerCase", 0, js_string_toLowerCase, 1 ),
44246
    JS_CFUNC_MAGIC_DEF("toUpperCase", 0, js_string_toLowerCase, 0 ),
44247
    JS_CFUNC_MAGIC_DEF("toLocaleLowerCase", 0, js_string_toLowerCase, 1 ),
44248
    JS_CFUNC_MAGIC_DEF("toLocaleUpperCase", 0, js_string_toLowerCase, 0 ),
44249
    JS_CFUNC_MAGIC_DEF("[Symbol.iterator]", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE | 4 ),
44250
    /* ES6 Annex B 2.3.2 etc. */
44251
    JS_CFUNC_MAGIC_DEF("anchor", 1, js_string_CreateHTML, magic_string_anchor ),
44252
    JS_CFUNC_MAGIC_DEF("big", 0, js_string_CreateHTML, magic_string_big ),
44253
    JS_CFUNC_MAGIC_DEF("blink", 0, js_string_CreateHTML, magic_string_blink ),
44254
    JS_CFUNC_MAGIC_DEF("bold", 0, js_string_CreateHTML, magic_string_bold ),
44255
    JS_CFUNC_MAGIC_DEF("fixed", 0, js_string_CreateHTML, magic_string_fixed ),
44256
    JS_CFUNC_MAGIC_DEF("fontcolor", 1, js_string_CreateHTML, magic_string_fontcolor ),
44257
    JS_CFUNC_MAGIC_DEF("fontsize", 1, js_string_CreateHTML, magic_string_fontsize ),
44258
    JS_CFUNC_MAGIC_DEF("italics", 0, js_string_CreateHTML, magic_string_italics ),
44259
    JS_CFUNC_MAGIC_DEF("link", 1, js_string_CreateHTML, magic_string_link ),
44260
    JS_CFUNC_MAGIC_DEF("small", 0, js_string_CreateHTML, magic_string_small ),
44261
    JS_CFUNC_MAGIC_DEF("strike", 0, js_string_CreateHTML, magic_string_strike ),
44262
    JS_CFUNC_MAGIC_DEF("sub", 0, js_string_CreateHTML, magic_string_sub ),
44263
    JS_CFUNC_MAGIC_DEF("sup", 0, js_string_CreateHTML, magic_string_sup ),
44264
};
44265
44266
static const JSCFunctionListEntry js_string_iterator_proto_funcs[] = {
44267
    JS_ITERATOR_NEXT_DEF("next", 0, js_string_iterator_next, 0 ),
44268
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "String Iterator", JS_PROP_CONFIGURABLE ),
44269
};
44270
44271
static const JSCFunctionListEntry js_string_proto_normalize[] = {
44272
#ifdef CONFIG_ALL_UNICODE
44273
    JS_CFUNC_DEF("normalize", 0, js_string_normalize ),
44274
#endif
44275
    JS_CFUNC_DEF("localeCompare", 1, js_string_localeCompare ),
44276
};
44277
44278
void JS_AddIntrinsicStringNormalize(JSContext *ctx)
44279
2
{
44280
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING], js_string_proto_normalize,
44281
2
                               countof(js_string_proto_normalize));
44282
2
}
44283
44284
/* Math */
44285
44286
/* precondition: a and b are not NaN */
44287
static double js_fmin(double a, double b)
44288
0
{
44289
0
    if (a == 0 && b == 0) {
44290
0
        JSFloat64Union a1, b1;
44291
0
        a1.d = a;
44292
0
        b1.d = b;
44293
0
        a1.u64 |= b1.u64;
44294
0
        return a1.d;
44295
0
    } else {
44296
0
        return fmin(a, b);
44297
0
    }
44298
0
}
44299
44300
/* precondition: a and b are not NaN */
44301
static double js_fmax(double a, double b)
44302
0
{
44303
0
    if (a == 0 && b == 0) {
44304
0
        JSFloat64Union a1, b1;
44305
0
        a1.d = a;
44306
0
        b1.d = b;
44307
0
        a1.u64 &= b1.u64;
44308
0
        return a1.d;
44309
0
    } else {
44310
0
        return fmax(a, b);
44311
0
    }
44312
0
}
44313
44314
static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,
44315
                               int argc, JSValueConst *argv, int magic)
44316
0
{
44317
0
    BOOL is_max = magic;
44318
0
    double r, a;
44319
0
    int i;
44320
0
    uint32_t tag;
44321
44322
0
    if (unlikely(argc == 0)) {
44323
0
        return __JS_NewFloat64(ctx, is_max ? -1.0 / 0.0 : 1.0 / 0.0);
44324
0
    }
44325
44326
0
    tag = JS_VALUE_GET_TAG(argv[0]);
44327
0
    if (tag == JS_TAG_INT) {
44328
0
        int a1, r1 = JS_VALUE_GET_INT(argv[0]);
44329
0
        for(i = 1; i < argc; i++) {
44330
0
            tag = JS_VALUE_GET_TAG(argv[i]);
44331
0
            if (tag != JS_TAG_INT) {
44332
0
                r = r1;
44333
0
                goto generic_case;
44334
0
            }
44335
0
            a1 = JS_VALUE_GET_INT(argv[i]);
44336
0
            if (is_max)
44337
0
                r1 = max_int(r1, a1);
44338
0
            else
44339
0
                r1 = min_int(r1, a1);
44340
44341
0
        }
44342
0
        return JS_NewInt32(ctx, r1);
44343
0
    } else {
44344
0
        if (JS_ToFloat64(ctx, &r, argv[0]))
44345
0
            return JS_EXCEPTION;
44346
0
        i = 1;
44347
0
    generic_case:
44348
0
        while (i < argc) {
44349
0
            if (JS_ToFloat64(ctx, &a, argv[i]))
44350
0
                return JS_EXCEPTION;
44351
0
            if (!isnan(r)) {
44352
0
                if (isnan(a)) {
44353
0
                    r = a;
44354
0
                } else {
44355
0
                    if (is_max)
44356
0
                        r = js_fmax(r, a);
44357
0
                    else
44358
0
                        r = js_fmin(r, a);
44359
0
                }
44360
0
            }
44361
0
            i++;
44362
0
        }
44363
0
        return JS_NewFloat64(ctx, r);
44364
0
    }
44365
0
}
44366
44367
static double js_math_sign(double a)
44368
0
{
44369
0
    if (isnan(a) || a == 0.0)
44370
0
        return a;
44371
0
    if (a < 0)
44372
0
        return -1;
44373
0
    else
44374
0
        return 1;
44375
0
}
44376
44377
static double js_math_round(double a)
44378
0
{
44379
0
    JSFloat64Union u;
44380
0
    uint64_t frac_mask, one;
44381
0
    unsigned int e, s;
44382
44383
0
    u.d = a;
44384
0
    e = (u.u64 >> 52) & 0x7ff;
44385
0
    if (e < 1023) {
44386
        /* abs(a) < 1 */
44387
0
        if (e == (1023 - 1) && u.u64 != 0xbfe0000000000000) {
44388
            /* abs(a) > 0.5 or a = 0.5: return +/-1.0 */
44389
0
            u.u64 = (u.u64 & ((uint64_t)1 << 63)) | ((uint64_t)1023 << 52);
44390
0
        } else {
44391
            /* return +/-0.0 */
44392
0
            u.u64 &= (uint64_t)1 << 63;
44393
0
        }
44394
0
    } else if (e < (1023 + 52)) {
44395
0
        s = u.u64 >> 63;
44396
0
        one = (uint64_t)1 << (52 - (e - 1023));
44397
0
        frac_mask = one - 1;
44398
0
        u.u64 += (one >> 1) - s;
44399
0
        u.u64 &= ~frac_mask; /* truncate to an integer */
44400
0
    }
44401
    /* otherwise: abs(a) >= 2^52, or NaN, +/-Infinity: no change */
44402
0
    return u.d;
44403
0
}
44404
44405
static JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val,
44406
                             int argc, JSValueConst *argv)
44407
0
{
44408
0
    double r, a;
44409
0
    int i;
44410
44411
0
    r = 0;
44412
0
    if (argc > 0) {
44413
0
        if (JS_ToFloat64(ctx, &r, argv[0]))
44414
0
            return JS_EXCEPTION;
44415
0
        if (argc == 1) {
44416
0
            r = fabs(r);
44417
0
        } else {
44418
            /* use the built-in function to minimize precision loss */
44419
0
            for (i = 1; i < argc; i++) {
44420
0
                if (JS_ToFloat64(ctx, &a, argv[i]))
44421
0
                    return JS_EXCEPTION;
44422
0
                r = hypot(r, a);
44423
0
            }
44424
0
        }
44425
0
    }
44426
0
    return JS_NewFloat64(ctx, r);
44427
0
}
44428
44429
static double js_math_f16round(double a)
44430
0
{
44431
0
    return fromfp16(tofp16(a));
44432
0
}
44433
44434
static double js_math_fround(double a)
44435
0
{
44436
0
    return (float)a;
44437
0
}
44438
44439
static JSValue js_math_imul(JSContext *ctx, JSValueConst this_val,
44440
                            int argc, JSValueConst *argv)
44441
0
{
44442
0
    uint32_t a, b, c;
44443
0
    int32_t d;
44444
44445
0
    if (JS_ToUint32(ctx, &a, argv[0]))
44446
0
        return JS_EXCEPTION;
44447
0
    if (JS_ToUint32(ctx, &b, argv[1]))
44448
0
        return JS_EXCEPTION;
44449
0
    c = a * b;
44450
0
    memcpy(&d, &c, sizeof(d));
44451
0
    return JS_NewInt32(ctx, d);
44452
0
}
44453
44454
static JSValue js_math_clz32(JSContext *ctx, JSValueConst this_val,
44455
                             int argc, JSValueConst *argv)
44456
0
{
44457
0
    uint32_t a, r;
44458
44459
0
    if (JS_ToUint32(ctx, &a, argv[0]))
44460
0
        return JS_EXCEPTION;
44461
0
    if (a == 0)
44462
0
        r = 32;
44463
0
    else
44464
0
        r = clz32(a);
44465
0
    return JS_NewInt32(ctx, r);
44466
0
}
44467
44468
/* xorshift* random number generator by Marsaglia */
44469
static uint64_t xorshift64star(uint64_t *pstate)
44470
0
{
44471
0
    uint64_t x;
44472
0
    x = *pstate;
44473
0
    x ^= x >> 12;
44474
0
    x ^= x << 25;
44475
0
    x ^= x >> 27;
44476
0
    *pstate = x;
44477
0
    return x * 0x2545F4914F6CDD1D;
44478
0
}
44479
44480
static void js_random_init(JSContext *ctx)
44481
2
{
44482
2
    struct timeval tv;
44483
2
    gettimeofday(&tv, NULL);
44484
2
    ctx->random_state = ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec;
44485
    /* the state must be non zero */
44486
2
    if (ctx->random_state == 0)
44487
0
        ctx->random_state = 1;
44488
2
}
44489
44490
static JSValue js_math_random(JSContext *ctx, JSValueConst this_val,
44491
                              int argc, JSValueConst *argv)
44492
0
{
44493
0
    JSFloat64Union u;
44494
0
    uint64_t v;
44495
44496
0
    v = xorshift64star(&ctx->random_state);
44497
    /* 1.0 <= u.d < 2 */
44498
0
    u.u64 = ((uint64_t)0x3ff << 52) | (v >> 12);
44499
0
    return __JS_NewFloat64(ctx, u.d - 1.0);
44500
0
}
44501
44502
static const JSCFunctionListEntry js_math_funcs[] = {
44503
    JS_CFUNC_MAGIC_DEF("min", 2, js_math_min_max, 0 ),
44504
    JS_CFUNC_MAGIC_DEF("max", 2, js_math_min_max, 1 ),
44505
    JS_CFUNC_SPECIAL_DEF("abs", 1, f_f, fabs ),
44506
    JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, floor ),
44507
    JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, ceil ),
44508
    JS_CFUNC_SPECIAL_DEF("round", 1, f_f, js_math_round ),
44509
    JS_CFUNC_SPECIAL_DEF("sqrt", 1, f_f, sqrt ),
44510
44511
    JS_CFUNC_SPECIAL_DEF("acos", 1, f_f, acos ),
44512
    JS_CFUNC_SPECIAL_DEF("asin", 1, f_f, asin ),
44513
    JS_CFUNC_SPECIAL_DEF("atan", 1, f_f, atan ),
44514
    JS_CFUNC_SPECIAL_DEF("atan2", 2, f_f_f, atan2 ),
44515
    JS_CFUNC_SPECIAL_DEF("cos", 1, f_f, cos ),
44516
    JS_CFUNC_SPECIAL_DEF("exp", 1, f_f, exp ),
44517
    JS_CFUNC_SPECIAL_DEF("log", 1, f_f, log ),
44518
    JS_CFUNC_SPECIAL_DEF("pow", 2, f_f_f, js_pow ),
44519
    JS_CFUNC_SPECIAL_DEF("sin", 1, f_f, sin ),
44520
    JS_CFUNC_SPECIAL_DEF("tan", 1, f_f, tan ),
44521
    /* ES6 */
44522
    JS_CFUNC_SPECIAL_DEF("trunc", 1, f_f, trunc ),
44523
    JS_CFUNC_SPECIAL_DEF("sign", 1, f_f, js_math_sign ),
44524
    JS_CFUNC_SPECIAL_DEF("cosh", 1, f_f, cosh ),
44525
    JS_CFUNC_SPECIAL_DEF("sinh", 1, f_f, sinh ),
44526
    JS_CFUNC_SPECIAL_DEF("tanh", 1, f_f, tanh ),
44527
    JS_CFUNC_SPECIAL_DEF("acosh", 1, f_f, acosh ),
44528
    JS_CFUNC_SPECIAL_DEF("asinh", 1, f_f, asinh ),
44529
    JS_CFUNC_SPECIAL_DEF("atanh", 1, f_f, atanh ),
44530
    JS_CFUNC_SPECIAL_DEF("expm1", 1, f_f, expm1 ),
44531
    JS_CFUNC_SPECIAL_DEF("log1p", 1, f_f, log1p ),
44532
    JS_CFUNC_SPECIAL_DEF("log2", 1, f_f, log2 ),
44533
    JS_CFUNC_SPECIAL_DEF("log10", 1, f_f, log10 ),
44534
    JS_CFUNC_SPECIAL_DEF("cbrt", 1, f_f, cbrt ),
44535
    JS_CFUNC_DEF("hypot", 2, js_math_hypot ),
44536
    JS_CFUNC_DEF("random", 0, js_math_random ),
44537
    JS_CFUNC_SPECIAL_DEF("f16round", 1, f_f, js_math_f16round ),
44538
    JS_CFUNC_SPECIAL_DEF("fround", 1, f_f, js_math_fround ),
44539
    JS_CFUNC_DEF("imul", 2, js_math_imul ),
44540
    JS_CFUNC_DEF("clz32", 1, js_math_clz32 ),
44541
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Math", JS_PROP_CONFIGURABLE ),
44542
    JS_PROP_DOUBLE_DEF("E", 2.718281828459045, 0 ),
44543
    JS_PROP_DOUBLE_DEF("LN10", 2.302585092994046, 0 ),
44544
    JS_PROP_DOUBLE_DEF("LN2", 0.6931471805599453, 0 ),
44545
    JS_PROP_DOUBLE_DEF("LOG2E", 1.4426950408889634, 0 ),
44546
    JS_PROP_DOUBLE_DEF("LOG10E", 0.4342944819032518, 0 ),
44547
    JS_PROP_DOUBLE_DEF("PI", 3.141592653589793, 0 ),
44548
    JS_PROP_DOUBLE_DEF("SQRT1_2", 0.7071067811865476, 0 ),
44549
    JS_PROP_DOUBLE_DEF("SQRT2", 1.4142135623730951, 0 ),
44550
};
44551
44552
static const JSCFunctionListEntry js_math_obj[] = {
44553
    JS_OBJECT_DEF("Math", js_math_funcs, countof(js_math_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
44554
};
44555
44556
/* Date */
44557
44558
/* OS dependent. d = argv[0] is in ms from 1970. Return the difference
44559
   between UTC time and local time 'd' in minutes */
44560
static int getTimezoneOffset(int64_t time)
44561
0
{
44562
0
    time_t ti;
44563
0
    int res;
44564
44565
0
    time /= 1000; /* convert to seconds */
44566
0
    if (sizeof(time_t) == 4) {
44567
        /* on 32-bit systems, we need to clamp the time value to the
44568
           range of `time_t`. This is better than truncating values to
44569
           32 bits and hopefully provides the same result as 64-bit
44570
           implementation of localtime_r.
44571
         */
44572
0
        if ((time_t)-1 < 0) {
44573
0
            if (time < INT32_MIN) {
44574
0
                time = INT32_MIN;
44575
0
            } else if (time > INT32_MAX) {
44576
0
                time = INT32_MAX;
44577
0
            }
44578
0
        } else {
44579
0
            if (time < 0) {
44580
0
                time = 0;
44581
0
            } else if (time > UINT32_MAX) {
44582
0
                time = UINT32_MAX;
44583
0
            }
44584
0
        }
44585
0
    }
44586
0
    ti = time;
44587
#if defined(_WIN32)
44588
    {
44589
        struct tm *tm;
44590
        time_t gm_ti, loc_ti;
44591
44592
        tm = gmtime(&ti);
44593
        if (!tm)
44594
            return 0;
44595
        gm_ti = mktime(tm);
44596
44597
        tm = localtime(&ti);
44598
        if (!tm)
44599
            return 0;
44600
        loc_ti = mktime(tm);
44601
44602
        res = (gm_ti - loc_ti) / 60;
44603
    }
44604
#else
44605
0
    {
44606
0
        struct tm tm;
44607
0
        localtime_r(&ti, &tm);
44608
0
        res = -tm.tm_gmtoff / 60;
44609
0
    }
44610
0
#endif
44611
0
    return res;
44612
0
}
44613
44614
#if 0
44615
static JSValue js___date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val,
44616
                                           int argc, JSValueConst *argv)
44617
{
44618
    double dd;
44619
44620
    if (JS_ToFloat64(ctx, &dd, argv[0]))
44621
        return JS_EXCEPTION;
44622
    if (isnan(dd))
44623
        return __JS_NewFloat64(ctx, dd);
44624
    else
44625
        return JS_NewInt32(ctx, getTimezoneOffset((int64_t)dd));
44626
}
44627
44628
static JSValue js_get_prototype_from_ctor(JSContext *ctx, JSValueConst ctor,
44629
                                          JSValueConst def_proto)
44630
{
44631
    JSValue proto;
44632
    proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);
44633
    if (JS_IsException(proto))
44634
        return proto;
44635
    if (!JS_IsObject(proto)) {
44636
        JS_FreeValue(ctx, proto);
44637
        proto = JS_DupValue(ctx, def_proto);
44638
    }
44639
    return proto;
44640
}
44641
44642
/* create a new date object */
44643
static JSValue js___date_create(JSContext *ctx, JSValueConst this_val,
44644
                                int argc, JSValueConst *argv)
44645
{
44646
    JSValue obj, proto;
44647
    proto = js_get_prototype_from_ctor(ctx, argv[0], argv[1]);
44648
    if (JS_IsException(proto))
44649
        return proto;
44650
    obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_DATE);
44651
    JS_FreeValue(ctx, proto);
44652
    if (!JS_IsException(obj))
44653
        JS_SetObjectData(ctx, obj, JS_DupValue(ctx, argv[2]));
44654
    return obj;
44655
}
44656
#endif
44657
44658
/* RegExp */
44659
44660
static void js_regexp_finalizer(JSRuntime *rt, JSValue val)
44661
0
{
44662
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
44663
0
    JSRegExp *re = &p->u.regexp;
44664
0
    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, re->bytecode));
44665
0
    JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, re->pattern));
44666
0
}
44667
44668
/* create a string containing the RegExp bytecode */
44669
static JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,
44670
                                 JSValueConst flags)
44671
0
{
44672
0
    const char *str;
44673
0
    int re_flags, mask;
44674
0
    uint8_t *re_bytecode_buf;
44675
0
    size_t i, len;
44676
0
    int re_bytecode_len;
44677
0
    JSValue ret;
44678
0
    char error_msg[64];
44679
44680
0
    re_flags = 0;
44681
0
    if (!JS_IsUndefined(flags)) {
44682
0
        str = JS_ToCStringLen(ctx, &len, flags);
44683
0
        if (!str)
44684
0
            return JS_EXCEPTION;
44685
        /* XXX: re_flags = LRE_FLAG_OCTAL unless strict mode? */
44686
0
        for (i = 0; i < len; i++) {
44687
0
            switch(str[i]) {
44688
0
            case 'd':
44689
0
                mask = LRE_FLAG_INDICES;
44690
0
                break;
44691
0
            case 'g':
44692
0
                mask = LRE_FLAG_GLOBAL;
44693
0
                break;
44694
0
            case 'i':
44695
0
                mask = LRE_FLAG_IGNORECASE;
44696
0
                break;
44697
0
            case 'm':
44698
0
                mask = LRE_FLAG_MULTILINE;
44699
0
                break;
44700
0
            case 's':
44701
0
                mask = LRE_FLAG_DOTALL;
44702
0
                break;
44703
0
            case 'u':
44704
0
                mask = LRE_FLAG_UNICODE;
44705
0
                break;
44706
0
            case 'v':
44707
0
                mask = LRE_FLAG_UNICODE_SETS;
44708
0
                break;
44709
0
            case 'y':
44710
0
                mask = LRE_FLAG_STICKY;
44711
0
                break;
44712
0
            default:
44713
0
                goto bad_flags;
44714
0
            }
44715
0
            if ((re_flags & mask) != 0) {
44716
0
            bad_flags:
44717
0
                JS_FreeCString(ctx, str);
44718
0
                goto bad_flags1;
44719
0
            }
44720
0
            re_flags |= mask;
44721
0
        }
44722
0
        JS_FreeCString(ctx, str);
44723
0
    }
44724
44725
    /* 'u' and 'v' cannot be both set */
44726
0
    if ((re_flags & LRE_FLAG_UNICODE_SETS) && (re_flags & LRE_FLAG_UNICODE)) {
44727
0
    bad_flags1:
44728
0
        return JS_ThrowSyntaxError(ctx, "invalid regular expression flags");
44729
0
    }
44730
    
44731
0
    str = JS_ToCStringLen2(ctx, &len, pattern, !(re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)));
44732
0
    if (!str)
44733
0
        return JS_EXCEPTION;
44734
0
    re_bytecode_buf = lre_compile(&re_bytecode_len, error_msg,
44735
0
                                  sizeof(error_msg), str, len, re_flags, ctx);
44736
0
    JS_FreeCString(ctx, str);
44737
0
    if (!re_bytecode_buf) {
44738
0
        JS_ThrowSyntaxError(ctx, "%s", error_msg);
44739
0
        return JS_EXCEPTION;
44740
0
    }
44741
44742
0
    ret = js_new_string8_len(ctx, (const char *)re_bytecode_buf, re_bytecode_len);
44743
0
    js_free(ctx, re_bytecode_buf);
44744
0
    return ret;
44745
0
}
44746
44747
/* create a RegExp object from a string containing the RegExp bytecode
44748
   and the source pattern */
44749
static JSValue js_regexp_constructor_internal(JSContext *ctx, JSValueConst ctor,
44750
                                              JSValue pattern, JSValue bc)
44751
0
{
44752
0
    JSValue obj;
44753
0
    JSObject *p;
44754
0
    JSRegExp *re;
44755
44756
    /* sanity check */
44757
0
    if (JS_VALUE_GET_TAG(bc) != JS_TAG_STRING ||
44758
0
        JS_VALUE_GET_TAG(pattern) != JS_TAG_STRING) {
44759
0
        JS_ThrowTypeError(ctx, "string expected");
44760
0
    fail:
44761
0
        JS_FreeValue(ctx, bc);
44762
0
        JS_FreeValue(ctx, pattern);
44763
0
        return JS_EXCEPTION;
44764
0
    }
44765
44766
0
    obj = js_create_from_ctor(ctx, ctor, JS_CLASS_REGEXP);
44767
0
    if (JS_IsException(obj))
44768
0
        goto fail;
44769
0
    p = JS_VALUE_GET_OBJ(obj);
44770
0
    re = &p->u.regexp;
44771
0
    re->pattern = JS_VALUE_GET_STRING(pattern);
44772
0
    re->bytecode = JS_VALUE_GET_STRING(bc);
44773
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0),
44774
0
                           JS_PROP_WRITABLE);
44775
0
    return obj;
44776
0
}
44777
44778
static JSRegExp *js_get_regexp(JSContext *ctx, JSValueConst obj, BOOL throw_error)
44779
0
{
44780
0
    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
44781
0
        JSObject *p = JS_VALUE_GET_OBJ(obj);
44782
0
        if (p->class_id == JS_CLASS_REGEXP)
44783
0
            return &p->u.regexp;
44784
0
    }
44785
0
    if (throw_error) {
44786
0
        JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP);
44787
0
    }
44788
0
    return NULL;
44789
0
}
44790
44791
/* return < 0 if exception or TRUE/FALSE */
44792
static int js_is_regexp(JSContext *ctx, JSValueConst obj)
44793
0
{
44794
0
    JSValue m;
44795
44796
0
    if (!JS_IsObject(obj))
44797
0
        return FALSE;
44798
0
    m = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_match);
44799
0
    if (JS_IsException(m))
44800
0
        return -1;
44801
0
    if (!JS_IsUndefined(m))
44802
0
        return JS_ToBoolFree(ctx, m);
44803
0
    return js_get_regexp(ctx, obj, FALSE) != NULL;
44804
0
}
44805
44806
static JSValue js_regexp_constructor(JSContext *ctx, JSValueConst new_target,
44807
                                     int argc, JSValueConst *argv)
44808
0
{
44809
0
    JSValue pattern, flags, bc, val;
44810
0
    JSValueConst pat, flags1;
44811
0
    JSRegExp *re;
44812
0
    int pat_is_regexp;
44813
44814
0
    pat = argv[0];
44815
0
    flags1 = argv[1];
44816
0
    pat_is_regexp = js_is_regexp(ctx, pat);
44817
0
    if (pat_is_regexp < 0)
44818
0
        return JS_EXCEPTION;
44819
0
    if (JS_IsUndefined(new_target)) {
44820
        /* called as a function */
44821
0
        new_target = JS_GetActiveFunction(ctx);
44822
0
        if (pat_is_regexp && JS_IsUndefined(flags1)) {
44823
0
            JSValue ctor;
44824
0
            BOOL res;
44825
0
            ctor = JS_GetProperty(ctx, pat, JS_ATOM_constructor);
44826
0
            if (JS_IsException(ctor))
44827
0
                return ctor;
44828
0
            res = js_same_value(ctx, ctor, new_target);
44829
0
            JS_FreeValue(ctx, ctor);
44830
0
            if (res)
44831
0
                return JS_DupValue(ctx, pat);
44832
0
        }
44833
0
    }
44834
0
    re = js_get_regexp(ctx, pat, FALSE);
44835
0
    if (re) {
44836
0
        pattern = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
44837
0
        if (JS_IsUndefined(flags1)) {
44838
0
            bc = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->bytecode));
44839
0
            goto no_compilation;
44840
0
        } else {
44841
0
            flags = JS_ToString(ctx, flags1);
44842
0
            if (JS_IsException(flags))
44843
0
                goto fail;
44844
0
        }
44845
0
    } else {
44846
0
        flags = JS_UNDEFINED;
44847
0
        if (pat_is_regexp) {
44848
0
            pattern = JS_GetProperty(ctx, pat, JS_ATOM_source);
44849
0
            if (JS_IsException(pattern))
44850
0
                goto fail;
44851
0
            if (JS_IsUndefined(flags1)) {
44852
0
                flags = JS_GetProperty(ctx, pat, JS_ATOM_flags);
44853
0
                if (JS_IsException(flags))
44854
0
                    goto fail;
44855
0
            } else {
44856
0
                flags = JS_DupValue(ctx, flags1);
44857
0
            }
44858
0
        } else {
44859
0
            pattern = JS_DupValue(ctx, pat);
44860
0
            flags = JS_DupValue(ctx, flags1);
44861
0
        }
44862
0
        if (JS_IsUndefined(pattern)) {
44863
0
            pattern = JS_AtomToString(ctx, JS_ATOM_empty_string);
44864
0
        } else {
44865
0
            val = pattern;
44866
0
            pattern = JS_ToString(ctx, val);
44867
0
            JS_FreeValue(ctx, val);
44868
0
            if (JS_IsException(pattern))
44869
0
                goto fail;
44870
0
        }
44871
0
    }
44872
0
    bc = js_compile_regexp(ctx, pattern, flags);
44873
0
    if (JS_IsException(bc))
44874
0
        goto fail;
44875
0
    JS_FreeValue(ctx, flags);
44876
0
 no_compilation:
44877
0
    return js_regexp_constructor_internal(ctx, new_target, pattern, bc);
44878
0
 fail:
44879
0
    JS_FreeValue(ctx, pattern);
44880
0
    JS_FreeValue(ctx, flags);
44881
0
    return JS_EXCEPTION;
44882
0
}
44883
44884
static JSValue js_regexp_compile(JSContext *ctx, JSValueConst this_val,
44885
                                 int argc, JSValueConst *argv)
44886
0
{
44887
0
    JSRegExp *re1, *re;
44888
0
    JSValueConst pattern1, flags1;
44889
0
    JSValue bc, pattern;
44890
44891
0
    re = js_get_regexp(ctx, this_val, TRUE);
44892
0
    if (!re)
44893
0
        return JS_EXCEPTION;
44894
0
    pattern1 = argv[0];
44895
0
    flags1 = argv[1];
44896
0
    re1 = js_get_regexp(ctx, pattern1, FALSE);
44897
0
    if (re1) {
44898
0
        if (!JS_IsUndefined(flags1))
44899
0
            return JS_ThrowTypeError(ctx, "flags must be undefined");
44900
0
        pattern = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re1->pattern));
44901
0
        bc = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re1->bytecode));
44902
0
    } else {
44903
0
        bc = JS_UNDEFINED;
44904
0
        if (JS_IsUndefined(pattern1))
44905
0
            pattern = JS_AtomToString(ctx, JS_ATOM_empty_string);
44906
0
        else
44907
0
            pattern = JS_ToString(ctx, pattern1);
44908
0
        if (JS_IsException(pattern))
44909
0
            goto fail;
44910
0
        bc = js_compile_regexp(ctx, pattern, flags1);
44911
0
        if (JS_IsException(bc))
44912
0
            goto fail;
44913
0
    }
44914
0
    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
44915
0
    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, re->bytecode));
44916
0
    re->pattern = JS_VALUE_GET_STRING(pattern);
44917
0
    re->bytecode = JS_VALUE_GET_STRING(bc);
44918
0
    if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
44919
0
                       JS_NewInt32(ctx, 0)) < 0)
44920
0
        return JS_EXCEPTION;
44921
0
    return JS_DupValue(ctx, this_val);
44922
0
 fail:
44923
0
    JS_FreeValue(ctx, pattern);
44924
0
    JS_FreeValue(ctx, bc);
44925
0
    return JS_EXCEPTION;
44926
0
}
44927
44928
#if 0
44929
static JSValue js_regexp_get___source(JSContext *ctx, JSValueConst this_val)
44930
{
44931
    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
44932
    if (!re)
44933
        return JS_EXCEPTION;
44934
    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));
44935
}
44936
44937
static JSValue js_regexp_get___flags(JSContext *ctx, JSValueConst this_val)
44938
{
44939
    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
44940
    int flags;
44941
44942
    if (!re)
44943
        return JS_EXCEPTION;
44944
    flags = lre_get_flags(re->bytecode->u.str8);
44945
    return JS_NewInt32(ctx, flags);
44946
}
44947
#endif
44948
44949
static JSValue js_regexp_get_source(JSContext *ctx, JSValueConst this_val)
44950
0
{
44951
0
    JSRegExp *re;
44952
0
    JSString *p;
44953
0
    StringBuffer b_s, *b = &b_s;
44954
0
    int i, n, c, c2, bra;
44955
44956
0
    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
44957
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
44958
44959
0
    if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP]))
44960
0
        goto empty_regex;
44961
44962
0
    re = js_get_regexp(ctx, this_val, TRUE);
44963
0
    if (!re)
44964
0
        return JS_EXCEPTION;
44965
44966
0
    p = re->pattern;
44967
44968
0
    if (p->len == 0) {
44969
0
    empty_regex:
44970
0
        return js_new_string8(ctx, "(?:)");
44971
0
    }
44972
0
    string_buffer_init2(ctx, b, p->len, p->is_wide_char);
44973
44974
    /* Escape '/' and newline sequences as needed */
44975
0
    bra = 0;
44976
0
    for (i = 0, n = p->len; i < n;) {
44977
0
        c2 = -1;
44978
0
        switch (c = string_get(p, i++)) {
44979
0
        case '\\':
44980
0
            if (i < n)
44981
0
                c2 = string_get(p, i++);
44982
0
            break;
44983
0
        case ']':
44984
0
            bra = 0;
44985
0
            break;
44986
0
        case '[':
44987
0
            if (!bra) {
44988
0
                if (i < n && string_get(p, i) == ']')
44989
0
                    c2 = string_get(p, i++);
44990
0
                bra = 1;
44991
0
            }
44992
0
            break;
44993
0
        case '\n':
44994
0
            c = '\\';
44995
0
            c2 = 'n';
44996
0
            break;
44997
0
        case '\r':
44998
0
            c = '\\';
44999
0
            c2 = 'r';
45000
0
            break;
45001
0
        case '/':
45002
0
            if (!bra) {
45003
0
                c = '\\';
45004
0
                c2 = '/';
45005
0
            }
45006
0
            break;
45007
0
        }
45008
0
        string_buffer_putc16(b, c);
45009
0
        if (c2 >= 0)
45010
0
            string_buffer_putc16(b, c2);
45011
0
    }
45012
0
    return string_buffer_end(b);
45013
0
}
45014
45015
static JSValue js_regexp_get_flag(JSContext *ctx, JSValueConst this_val, int mask)
45016
0
{
45017
0
    JSRegExp *re;
45018
0
    int flags;
45019
45020
0
    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
45021
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
45022
45023
0
    re = js_get_regexp(ctx, this_val, FALSE);
45024
0
    if (!re) {
45025
0
        if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP]))
45026
0
            return JS_UNDEFINED;
45027
0
        else
45028
0
            return JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP);
45029
0
    }
45030
45031
0
    flags = lre_get_flags(re->bytecode->u.str8);
45032
0
    return JS_NewBool(ctx, flags & mask);
45033
0
}
45034
45035
0
#define RE_FLAG_COUNT 8
45036
45037
static JSValue js_regexp_get_flags(JSContext *ctx, JSValueConst this_val)
45038
0
{
45039
0
    char str[RE_FLAG_COUNT], *p = str;
45040
0
    int res, i;
45041
0
    static const int flag_atom[RE_FLAG_COUNT] = {
45042
0
        JS_ATOM_hasIndices,
45043
0
        JS_ATOM_global,
45044
0
        JS_ATOM_ignoreCase,
45045
0
        JS_ATOM_multiline,
45046
0
        JS_ATOM_dotAll,
45047
0
        JS_ATOM_unicode,
45048
0
        JS_ATOM_unicodeSets,
45049
0
        JS_ATOM_sticky,
45050
0
    };
45051
0
    static const char flag_char[RE_FLAG_COUNT] = { 'd', 'g', 'i', 'm', 's', 'u', 'v', 'y' };
45052
    
45053
0
    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
45054
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
45055
45056
0
    for(i = 0; i < RE_FLAG_COUNT; i++) {
45057
0
        res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, flag_atom[i]));
45058
0
        if (res < 0)
45059
0
            goto exception;
45060
0
        if (res)
45061
0
            *p++ = flag_char[i];
45062
0
    }
45063
0
    return JS_NewStringLen(ctx, str, p - str);
45064
45065
0
exception:
45066
0
    return JS_EXCEPTION;
45067
0
}
45068
45069
static JSValue js_regexp_toString(JSContext *ctx, JSValueConst this_val,
45070
                                  int argc, JSValueConst *argv)
45071
0
{
45072
0
    JSValue pattern, flags;
45073
0
    StringBuffer b_s, *b = &b_s;
45074
45075
0
    if (!JS_IsObject(this_val))
45076
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
45077
45078
0
    string_buffer_init(ctx, b, 0);
45079
0
    string_buffer_putc8(b, '/');
45080
0
    pattern = JS_GetProperty(ctx, this_val, JS_ATOM_source);
45081
0
    if (string_buffer_concat_value_free(b, pattern))
45082
0
        goto fail;
45083
0
    string_buffer_putc8(b, '/');
45084
0
    flags = JS_GetProperty(ctx, this_val, JS_ATOM_flags);
45085
0
    if (string_buffer_concat_value_free(b, flags))
45086
0
        goto fail;
45087
0
    return string_buffer_end(b);
45088
45089
0
fail:
45090
0
    string_buffer_free(b);
45091
0
    return JS_EXCEPTION;
45092
0
}
45093
45094
int lre_check_stack_overflow(void *opaque, size_t alloca_size)
45095
0
{
45096
0
    JSContext *ctx = opaque;
45097
0
    return js_check_stack_overflow(ctx->rt, alloca_size);
45098
0
}
45099
45100
int lre_check_timeout(void *opaque)
45101
0
{
45102
0
    JSContext *ctx = opaque;
45103
0
    JSRuntime *rt = ctx->rt;
45104
0
    return (rt->interrupt_handler && 
45105
0
            rt->interrupt_handler(rt, rt->interrupt_opaque));
45106
0
}
45107
45108
void *lre_realloc(void *opaque, void *ptr, size_t size)
45109
0
{
45110
0
    JSContext *ctx = opaque;
45111
    /* No JS exception is raised here */
45112
0
    return js_realloc_rt(ctx->rt, ptr, size);
45113
0
}
45114
45115
static JSValue js_regexp_escape(JSContext *ctx, JSValueConst this_val,
45116
                                int argc, JSValueConst *argv)
45117
0
{
45118
0
    JSValue str;
45119
0
    StringBuffer b_s, *b = &b_s;
45120
0
    JSString *p;
45121
0
    uint32_t c, i;
45122
0
    char s[16];
45123
45124
0
    if (!JS_IsString(argv[0]))
45125
0
        return JS_ThrowTypeError(ctx, "not a string");
45126
0
    str = JS_ToString(ctx, argv[0]); /* must call it to linearlize ropes */
45127
0
    if (JS_IsException(str))
45128
0
        return JS_EXCEPTION;
45129
0
    p = JS_VALUE_GET_STRING(str);
45130
0
    string_buffer_init2(ctx, b, 0, p->is_wide_char);
45131
0
    for (i = 0; i < p->len; i++) {
45132
0
        c = string_get(p, i);
45133
0
        if (c < 33) {
45134
0
            if (c >= 9 && c <= 13) {
45135
0
                string_buffer_putc8(b, '\\');
45136
0
                string_buffer_putc8(b, "tnvfr"[c - 9]);
45137
0
            } else {
45138
0
                goto hex2;
45139
0
            }
45140
0
        } else if (c < 128) {
45141
0
            if ((c >= '0' && c <= '9')
45142
0
             || (c >= 'A' && c <= 'Z')
45143
0
             || (c >= 'a' && c <= 'z')) {
45144
0
                if (i == 0)
45145
0
                    goto hex2;
45146
0
            } else if (strchr(",-=<>#&!%:;@~'`\"", c)) {
45147
0
                goto hex2;
45148
0
            } else if (c != '_') {
45149
0
                string_buffer_putc8(b, '\\');
45150
0
            }
45151
0
            string_buffer_putc8(b, c);
45152
0
        } else if (c < 256) {
45153
0
        hex2:
45154
0
            snprintf(s, sizeof(s), "\\x%02x", c);
45155
0
            string_buffer_puts8(b, s);
45156
0
        } else if (is_surrogate(c) || lre_is_space(c)) {
45157
0
            snprintf(s, sizeof(s), "\\u%04x", c);
45158
0
            string_buffer_puts8(b, s);
45159
0
        } else {
45160
0
            string_buffer_putc16(b, c);
45161
0
        }
45162
0
    }
45163
0
    JS_FreeValue(ctx, str);
45164
0
    return string_buffer_end(b);
45165
0
}
45166
45167
static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val,
45168
                              int argc, JSValueConst *argv)
45169
0
{
45170
0
    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
45171
0
    JSString *str;
45172
0
    JSValue t, ret, str_val, obj, val, groups;
45173
0
    JSValue indices, indices_groups;
45174
0
    uint8_t *re_bytecode;
45175
0
    uint8_t **capture, *str_buf;
45176
0
    int rc, capture_count, shift, i, re_flags;
45177
0
    int64_t last_index;
45178
0
    const char *group_name_ptr;
45179
45180
0
    if (!re)
45181
0
        return JS_EXCEPTION;
45182
45183
0
    str_val = JS_ToString(ctx, argv[0]);
45184
0
    if (JS_IsException(str_val))
45185
0
        return JS_EXCEPTION;
45186
45187
0
    ret = JS_EXCEPTION;
45188
0
    obj = JS_NULL;
45189
0
    groups = JS_UNDEFINED;
45190
0
    indices = JS_UNDEFINED;
45191
0
    indices_groups = JS_UNDEFINED;
45192
0
    capture = NULL;
45193
45194
0
    val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex);
45195
0
    if (JS_IsException(val) || JS_ToLengthFree(ctx, &last_index, val))
45196
0
        goto fail;
45197
45198
0
    re_bytecode = re->bytecode->u.str8;
45199
0
    re_flags = lre_get_flags(re_bytecode);
45200
0
    if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {
45201
0
        last_index = 0;
45202
0
    }
45203
0
    str = JS_VALUE_GET_STRING(str_val);
45204
0
    capture_count = lre_get_capture_count(re_bytecode);
45205
0
    if (capture_count > 0) {
45206
0
        capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2);
45207
0
        if (!capture)
45208
0
            goto fail;
45209
0
    }
45210
0
    shift = str->is_wide_char;
45211
0
    str_buf = str->u.str8;
45212
0
    if (last_index > str->len) {
45213
0
        rc = 2;
45214
0
    } else {
45215
0
        rc = lre_exec(capture, re_bytecode,
45216
0
                      str_buf, last_index, str->len,
45217
0
                      shift, ctx);
45218
0
    }
45219
0
    if (rc != 1) {
45220
0
        if (rc >= 0) {
45221
0
            if (rc == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
45222
0
                if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
45223
0
                                   JS_NewInt32(ctx, 0)) < 0)
45224
0
                    goto fail;
45225
0
            }
45226
0
        } else {
45227
0
            if (rc == LRE_RET_TIMEOUT) {
45228
0
                JS_ThrowInterrupted(ctx);
45229
0
            } else {
45230
0
                JS_ThrowInternalError(ctx, "out of memory in regexp execution");
45231
0
            }
45232
0
            goto fail;
45233
0
        }
45234
0
    } else {
45235
0
        int prop_flags;
45236
0
        if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) {
45237
0
            if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
45238
0
                               JS_NewInt32(ctx, (capture[1] - str_buf) >> shift)) < 0)
45239
0
                goto fail;
45240
0
        }
45241
0
        obj = JS_NewArray(ctx);
45242
0
        if (JS_IsException(obj))
45243
0
            goto fail;
45244
0
        prop_flags = JS_PROP_C_W_E | JS_PROP_THROW;
45245
0
        group_name_ptr = lre_get_groupnames(re_bytecode);
45246
0
        if (group_name_ptr) {
45247
0
            groups = JS_NewObjectProto(ctx, JS_NULL);
45248
0
            if (JS_IsException(groups))
45249
0
                goto fail;
45250
0
        }
45251
0
        if (re_flags & LRE_FLAG_INDICES) {
45252
0
            indices = JS_NewArray(ctx);
45253
0
            if (JS_IsException(indices))
45254
0
                goto fail;
45255
0
            if (group_name_ptr) {
45256
0
                indices_groups = JS_NewObjectProto(ctx, JS_NULL);
45257
0
                if (JS_IsException(indices_groups))
45258
0
                    goto fail;
45259
0
            }
45260
0
        }
45261
45262
0
        for(i = 0; i < capture_count; i++) {
45263
0
            const char *name = NULL;
45264
0
            uint8_t **match = &capture[2 * i];
45265
0
            int start = -1;
45266
0
            int end = -1;
45267
0
            JSValue val;
45268
45269
0
            if (group_name_ptr && i > 0) {
45270
0
                if (*group_name_ptr) name = group_name_ptr;
45271
0
                group_name_ptr += strlen(group_name_ptr) + 1;
45272
0
            }
45273
45274
0
            if (match[0] && match[1]) {
45275
0
                start = (match[0] - str_buf) >> shift;
45276
0
                end = (match[1] - str_buf) >> shift;
45277
0
            }
45278
45279
0
            if (!JS_IsUndefined(indices)) {
45280
0
                val = JS_UNDEFINED;
45281
0
                if (start != -1) {
45282
0
                    val = JS_NewArray(ctx);
45283
0
                    if (JS_IsException(val))
45284
0
                        goto fail;
45285
0
                    if (JS_DefinePropertyValueUint32(ctx, val, 0,
45286
0
                                                     JS_NewInt32(ctx, start),
45287
0
                                                     prop_flags) < 0) {
45288
0
                        JS_FreeValue(ctx, val);
45289
0
                        goto fail;
45290
0
                    }
45291
0
                    if (JS_DefinePropertyValueUint32(ctx, val, 1,
45292
0
                                                     JS_NewInt32(ctx, end),
45293
0
                                                     prop_flags) < 0) {
45294
0
                        JS_FreeValue(ctx, val);
45295
0
                        goto fail;
45296
0
                    }
45297
0
                }
45298
0
                if (name && !JS_IsUndefined(indices_groups)) {
45299
0
                    val = JS_DupValue(ctx, val);
45300
0
                    if (JS_DefinePropertyValueStr(ctx, indices_groups,
45301
0
                                                  name, val, prop_flags) < 0) {
45302
0
                        JS_FreeValue(ctx, val);
45303
0
                        goto fail;
45304
0
                    }
45305
0
                }
45306
0
                if (JS_DefinePropertyValueUint32(ctx, indices, i, val,
45307
0
                                                 prop_flags) < 0) {
45308
0
                    goto fail;
45309
0
                }
45310
0
            }
45311
45312
0
            val = JS_UNDEFINED;
45313
0
            if (start != -1) {
45314
0
                val = js_sub_string(ctx, str, start, end);
45315
0
                if (JS_IsException(val))
45316
0
                    goto fail;
45317
0
            }
45318
45319
0
            if (name) {
45320
0
                if (JS_DefinePropertyValueStr(ctx, groups, name,
45321
0
                                              JS_DupValue(ctx, val),
45322
0
                                              prop_flags) < 0) {
45323
0
                    JS_FreeValue(ctx, val);
45324
0
                    goto fail;
45325
0
                }
45326
0
            }
45327
45328
0
            if (JS_DefinePropertyValueUint32(ctx, obj, i, val, prop_flags) < 0)
45329
0
                goto fail;
45330
0
        }
45331
45332
0
        t = JS_NewInt32(ctx, (capture[0] - str_buf) >> shift);
45333
0
        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_index, t, prop_flags) < 0)
45334
0
            goto fail;
45335
45336
0
        t = str_val, str_val = JS_UNDEFINED;
45337
0
        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_input, t, prop_flags) < 0)
45338
0
            goto fail;
45339
45340
0
        t = groups, groups = JS_UNDEFINED;
45341
0
        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_groups,
45342
0
                                   t, prop_flags) < 0) {
45343
0
            goto fail;
45344
0
        }
45345
45346
0
        if (!JS_IsUndefined(indices)) {
45347
0
            t = indices_groups, indices_groups = JS_UNDEFINED;
45348
0
            if (JS_DefinePropertyValue(ctx, indices, JS_ATOM_groups,
45349
0
                                       t, prop_flags) < 0) {
45350
0
                goto fail;
45351
0
            }
45352
0
            t = indices, indices = JS_UNDEFINED;
45353
0
            if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_indices,
45354
0
                                       t, prop_flags) < 0) {
45355
0
                goto fail;
45356
0
            }
45357
0
        }
45358
0
    }
45359
0
    ret = obj;
45360
0
    obj = JS_UNDEFINED;
45361
0
fail:
45362
0
    JS_FreeValue(ctx, indices_groups);
45363
0
    JS_FreeValue(ctx, indices);
45364
0
    JS_FreeValue(ctx, str_val);
45365
0
    JS_FreeValue(ctx, groups);
45366
0
    JS_FreeValue(ctx, obj);
45367
0
    js_free(ctx, capture);
45368
0
    return ret;
45369
0
}
45370
45371
/* delete portions of a string that match a given regex */
45372
static JSValue JS_RegExpDelete(JSContext *ctx, JSValueConst this_val, JSValueConst arg)
45373
0
{
45374
0
    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);
45375
0
    JSString *str;
45376
0
    JSValue str_val, val;
45377
0
    uint8_t *re_bytecode;
45378
0
    int ret;
45379
0
    uint8_t **capture, *str_buf;
45380
0
    int capture_count, shift, re_flags;
45381
0
    int next_src_pos, start, end;
45382
0
    int64_t last_index;
45383
0
    StringBuffer b_s, *b = &b_s;
45384
45385
0
    if (!re)
45386
0
        return JS_EXCEPTION;
45387
45388
0
    string_buffer_init(ctx, b, 0);
45389
45390
0
    capture = NULL;
45391
0
    str_val = JS_ToString(ctx, arg);
45392
0
    if (JS_IsException(str_val))
45393
0
        goto fail;
45394
0
    str = JS_VALUE_GET_STRING(str_val);
45395
0
    re_bytecode = re->bytecode->u.str8;
45396
0
    re_flags = lre_get_flags(re_bytecode);
45397
0
    if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {
45398
0
        last_index = 0;
45399
0
    } else {
45400
0
        val = JS_GetProperty(ctx, this_val, JS_ATOM_lastIndex);
45401
0
        if (JS_IsException(val) || JS_ToLengthFree(ctx, &last_index, val))
45402
0
            goto fail;
45403
0
    }
45404
0
    capture_count = lre_get_capture_count(re_bytecode);
45405
0
    if (capture_count > 0) {
45406
0
        capture = js_malloc(ctx, sizeof(capture[0]) * capture_count * 2);
45407
0
        if (!capture)
45408
0
            goto fail;
45409
0
    }
45410
0
    shift = str->is_wide_char;
45411
0
    str_buf = str->u.str8;
45412
0
    next_src_pos = 0;
45413
0
    for (;;) {
45414
0
        if (last_index > str->len)
45415
0
            break;
45416
45417
0
        ret = lre_exec(capture, re_bytecode,
45418
0
                       str_buf, last_index, str->len, shift, ctx);
45419
0
        if (ret != 1) {
45420
0
            if (ret >= 0) {
45421
0
                if (ret == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {
45422
0
                    if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
45423
0
                                       JS_NewInt32(ctx, 0)) < 0)
45424
0
                        goto fail;
45425
0
                }
45426
0
            } else {
45427
0
                if (ret == LRE_RET_TIMEOUT) {
45428
0
                    JS_ThrowInterrupted(ctx);
45429
0
                } else {
45430
0
                    JS_ThrowInternalError(ctx, "out of memory in regexp execution");
45431
0
                }
45432
0
                goto fail;
45433
0
            }
45434
0
            break;
45435
0
        }
45436
0
        start = (capture[0] - str_buf) >> shift;
45437
0
        end = (capture[1] - str_buf) >> shift;
45438
0
        last_index = end;
45439
0
        if (next_src_pos < start) {
45440
0
            if (string_buffer_concat(b, str, next_src_pos, start))
45441
0
                goto fail;
45442
0
        }
45443
0
        next_src_pos = end;
45444
0
        if (!(re_flags & LRE_FLAG_GLOBAL)) {
45445
0
            if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,
45446
0
                               JS_NewInt32(ctx, end)) < 0)
45447
0
                goto fail;
45448
0
            break;
45449
0
        }
45450
0
        if (end == start) {
45451
0
            if (!(re_flags & LRE_FLAG_UNICODE) || (unsigned)end >= str->len || !str->is_wide_char) {
45452
0
                end++;
45453
0
            } else {
45454
0
                string_getc(str, &end);
45455
0
            }
45456
0
        }
45457
0
        last_index = end;
45458
0
    }
45459
0
    if (string_buffer_concat(b, str, next_src_pos, str->len))
45460
0
        goto fail;
45461
0
    JS_FreeValue(ctx, str_val);
45462
0
    js_free(ctx, capture);
45463
0
    return string_buffer_end(b);
45464
0
fail:
45465
0
    JS_FreeValue(ctx, str_val);
45466
0
    js_free(ctx, capture);
45467
0
    string_buffer_free(b);
45468
0
    return JS_EXCEPTION;
45469
0
}
45470
45471
static JSValue JS_RegExpExec(JSContext *ctx, JSValueConst r, JSValueConst s)
45472
0
{
45473
0
    JSValue method, ret;
45474
45475
0
    method = JS_GetProperty(ctx, r, JS_ATOM_exec);
45476
0
    if (JS_IsException(method))
45477
0
        return method;
45478
0
    if (JS_IsFunction(ctx, method)) {
45479
0
        ret = JS_CallFree(ctx, method, r, 1, &s);
45480
0
        if (JS_IsException(ret))
45481
0
            return ret;
45482
0
        if (!JS_IsObject(ret) && !JS_IsNull(ret)) {
45483
0
            JS_FreeValue(ctx, ret);
45484
0
            return JS_ThrowTypeError(ctx, "RegExp exec method must return an object or null");
45485
0
        }
45486
0
        return ret;
45487
0
    }
45488
0
    JS_FreeValue(ctx, method);
45489
0
    return js_regexp_exec(ctx, r, 1, &s);
45490
0
}
45491
45492
#if 0
45493
static JSValue js_regexp___RegExpExec(JSContext *ctx, JSValueConst this_val,
45494
                                      int argc, JSValueConst *argv)
45495
{
45496
    return JS_RegExpExec(ctx, argv[0], argv[1]);
45497
}
45498
static JSValue js_regexp___RegExpDelete(JSContext *ctx, JSValueConst this_val,
45499
                                        int argc, JSValueConst *argv)
45500
{
45501
    return JS_RegExpDelete(ctx, argv[0], argv[1]);
45502
}
45503
#endif
45504
45505
static JSValue js_regexp_test(JSContext *ctx, JSValueConst this_val,
45506
                              int argc, JSValueConst *argv)
45507
0
{
45508
0
    JSValue val;
45509
0
    BOOL ret;
45510
45511
0
    val = JS_RegExpExec(ctx, this_val, argv[0]);
45512
0
    if (JS_IsException(val))
45513
0
        return JS_EXCEPTION;
45514
0
    ret = !JS_IsNull(val);
45515
0
    JS_FreeValue(ctx, val);
45516
0
    return JS_NewBool(ctx, ret);
45517
0
}
45518
45519
static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val,
45520
                                      int argc, JSValueConst *argv)
45521
0
{
45522
    // [Symbol.match](str)
45523
0
    JSValueConst rx = this_val;
45524
0
    JSValue A, S, flags, result, matchStr;
45525
0
    int global, n, fullUnicode, isEmpty;
45526
0
    JSString *p;
45527
45528
0
    if (!JS_IsObject(rx))
45529
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
45530
45531
0
    A = JS_UNDEFINED;
45532
0
    flags = JS_UNDEFINED;
45533
0
    result = JS_UNDEFINED;
45534
0
    matchStr = JS_UNDEFINED;
45535
0
    S = JS_ToString(ctx, argv[0]);
45536
0
    if (JS_IsException(S))
45537
0
        goto exception;
45538
45539
0
    flags = JS_GetProperty(ctx, rx, JS_ATOM_flags);
45540
0
    if (JS_IsException(flags))
45541
0
        goto exception;
45542
0
    flags = JS_ToStringFree(ctx, flags);
45543
0
    if (JS_IsException(flags))
45544
0
        goto exception;
45545
0
    p = JS_VALUE_GET_STRING(flags);
45546
45547
0
    global = (-1 != string_indexof_char(p, 'g', 0));
45548
0
    if (!global) {
45549
0
        A = JS_RegExpExec(ctx, rx, S);
45550
0
    } else {
45551
0
        fullUnicode = (string_indexof_char(p, 'u', 0) >= 0 ||
45552
0
                       string_indexof_char(p, 'v', 0) >= 0);
45553
45554
0
        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0)
45555
0
            goto exception;
45556
0
        A = JS_NewArray(ctx);
45557
0
        if (JS_IsException(A))
45558
0
            goto exception;
45559
0
        n = 0;
45560
0
        for(;;) {
45561
0
            JS_FreeValue(ctx, result);
45562
0
            result = JS_RegExpExec(ctx, rx, S);
45563
0
            if (JS_IsException(result))
45564
0
                goto exception;
45565
0
            if (JS_IsNull(result))
45566
0
                break;
45567
0
            matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
45568
0
            if (JS_IsException(matchStr))
45569
0
                goto exception;
45570
0
            isEmpty = JS_IsEmptyString(matchStr);
45571
0
            if (JS_DefinePropertyValueInt64(ctx, A, n++, matchStr, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
45572
0
                goto exception;
45573
0
            if (isEmpty) {
45574
0
                int64_t thisIndex, nextIndex;
45575
0
                if (JS_ToLengthFree(ctx, &thisIndex,
45576
0
                                    JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0)
45577
0
                    goto exception;
45578
0
                p = JS_VALUE_GET_STRING(S);
45579
0
                nextIndex = string_advance_index(p, thisIndex, fullUnicode);
45580
0
                if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0)
45581
0
                    goto exception;
45582
0
            }
45583
0
        }
45584
0
        if (n == 0) {
45585
0
            JS_FreeValue(ctx, A);
45586
0
            A = JS_NULL;
45587
0
        }
45588
0
    }
45589
0
    JS_FreeValue(ctx, result);
45590
0
    JS_FreeValue(ctx, flags);
45591
0
    JS_FreeValue(ctx, S);
45592
0
    return A;
45593
45594
0
exception:
45595
0
    JS_FreeValue(ctx, A);
45596
0
    JS_FreeValue(ctx, result);
45597
0
    JS_FreeValue(ctx, flags);
45598
0
    JS_FreeValue(ctx, S);
45599
0
    return JS_EXCEPTION;
45600
0
}
45601
45602
typedef struct JSRegExpStringIteratorData {
45603
    JSValue iterating_regexp;
45604
    JSValue iterated_string;
45605
    BOOL global;
45606
    BOOL unicode;
45607
    BOOL done;
45608
} JSRegExpStringIteratorData;
45609
45610
static void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val)
45611
0
{
45612
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
45613
0
    JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data;
45614
0
    if (it) {
45615
0
        JS_FreeValueRT(rt, it->iterating_regexp);
45616
0
        JS_FreeValueRT(rt, it->iterated_string);
45617
0
        js_free_rt(rt, it);
45618
0
    }
45619
0
}
45620
45621
static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val,
45622
                                           JS_MarkFunc *mark_func)
45623
0
{
45624
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
45625
0
    JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data;
45626
0
    if (it) {
45627
0
        JS_MarkValue(rt, it->iterating_regexp, mark_func);
45628
0
        JS_MarkValue(rt, it->iterated_string, mark_func);
45629
0
    }
45630
0
}
45631
45632
static JSValue js_regexp_string_iterator_next(JSContext *ctx,
45633
                                              JSValueConst this_val,
45634
                                              int argc, JSValueConst *argv,
45635
                                              BOOL *pdone, int magic)
45636
0
{
45637
0
    JSRegExpStringIteratorData *it;
45638
0
    JSValueConst R, S;
45639
0
    JSValue matchStr = JS_UNDEFINED, match = JS_UNDEFINED;
45640
0
    JSString *sp;
45641
45642
0
    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_REGEXP_STRING_ITERATOR);
45643
0
    if (!it)
45644
0
        goto exception;
45645
0
    if (it->done) {
45646
0
        *pdone = TRUE;
45647
0
        return JS_UNDEFINED;
45648
0
    }
45649
0
    R = it->iterating_regexp;
45650
0
    S = it->iterated_string;
45651
0
    match = JS_RegExpExec(ctx, R, S);
45652
0
    if (JS_IsException(match))
45653
0
        goto exception;
45654
0
    if (JS_IsNull(match)) {
45655
0
        it->done = TRUE;
45656
0
        *pdone = TRUE;
45657
0
        return JS_UNDEFINED;
45658
0
    } else if (it->global) {
45659
0
        matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, match, 0));
45660
0
        if (JS_IsException(matchStr))
45661
0
            goto exception;
45662
0
        if (JS_IsEmptyString(matchStr)) {
45663
0
            int64_t thisIndex, nextIndex;
45664
0
            if (JS_ToLengthFree(ctx, &thisIndex,
45665
0
                                JS_GetProperty(ctx, R, JS_ATOM_lastIndex)) < 0)
45666
0
                goto exception;
45667
0
            sp = JS_VALUE_GET_STRING(S);
45668
0
            nextIndex = string_advance_index(sp, thisIndex, it->unicode);
45669
0
            if (JS_SetProperty(ctx, R, JS_ATOM_lastIndex,
45670
0
                               JS_NewInt64(ctx, nextIndex)) < 0)
45671
0
                goto exception;
45672
0
        }
45673
0
        JS_FreeValue(ctx, matchStr);
45674
0
    } else {
45675
0
        it->done = TRUE;
45676
0
    }
45677
0
    *pdone = FALSE;
45678
0
    return match;
45679
0
 exception:
45680
0
    JS_FreeValue(ctx, match);
45681
0
    JS_FreeValue(ctx, matchStr);
45682
0
    *pdone = FALSE;
45683
0
    return JS_EXCEPTION;
45684
0
}
45685
45686
static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val,
45687
                                         int argc, JSValueConst *argv)
45688
0
{
45689
    // [Symbol.matchAll](str)
45690
0
    JSValueConst R = this_val;
45691
0
    JSValue S, C, flags, matcher, iter;
45692
0
    JSValueConst args[2];
45693
0
    JSString *strp;
45694
0
    int64_t lastIndex;
45695
0
    JSRegExpStringIteratorData *it;
45696
45697
0
    if (!JS_IsObject(R))
45698
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
45699
45700
0
    C = JS_UNDEFINED;
45701
0
    flags = JS_UNDEFINED;
45702
0
    matcher = JS_UNDEFINED;
45703
0
    iter = JS_UNDEFINED;
45704
45705
0
    S = JS_ToString(ctx, argv[0]);
45706
0
    if (JS_IsException(S))
45707
0
        goto exception;
45708
0
    C = JS_SpeciesConstructor(ctx, R, ctx->regexp_ctor);
45709
0
    if (JS_IsException(C))
45710
0
        goto exception;
45711
0
    flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, R, JS_ATOM_flags));
45712
0
    if (JS_IsException(flags))
45713
0
        goto exception;
45714
0
    args[0] = R;
45715
0
    args[1] = flags;
45716
0
    matcher = JS_CallConstructor(ctx, C, 2, args);
45717
0
    if (JS_IsException(matcher))
45718
0
        goto exception;
45719
0
    if (JS_ToLengthFree(ctx, &lastIndex,
45720
0
                        JS_GetProperty(ctx, R, JS_ATOM_lastIndex)))
45721
0
        goto exception;
45722
0
    if (JS_SetProperty(ctx, matcher, JS_ATOM_lastIndex,
45723
0
                       JS_NewInt64(ctx, lastIndex)) < 0)
45724
0
        goto exception;
45725
45726
0
    iter = JS_NewObjectClass(ctx, JS_CLASS_REGEXP_STRING_ITERATOR);
45727
0
    if (JS_IsException(iter))
45728
0
        goto exception;
45729
0
    it = js_malloc(ctx, sizeof(*it));
45730
0
    if (!it)
45731
0
        goto exception;
45732
0
    it->iterating_regexp = matcher;
45733
0
    it->iterated_string = S;
45734
0
    strp = JS_VALUE_GET_STRING(flags);
45735
0
    it->global = string_indexof_char(strp, 'g', 0) >= 0;
45736
0
    it->unicode = (string_indexof_char(strp, 'u', 0) >= 0 ||
45737
0
                   string_indexof_char(strp, 'v', 0) >= 0);
45738
0
    it->done = FALSE;
45739
0
    JS_SetOpaque(iter, it);
45740
45741
0
    JS_FreeValue(ctx, C);
45742
0
    JS_FreeValue(ctx, flags);
45743
0
    return iter;
45744
0
 exception:
45745
0
    JS_FreeValue(ctx, S);
45746
0
    JS_FreeValue(ctx, C);
45747
0
    JS_FreeValue(ctx, flags);
45748
0
    JS_FreeValue(ctx, matcher);
45749
0
    JS_FreeValue(ctx, iter);
45750
0
    return JS_EXCEPTION;
45751
0
}
45752
45753
typedef struct ValueBuffer {
45754
    JSContext *ctx;
45755
    JSValue *arr;
45756
    JSValue def[4];
45757
    int len;
45758
    int size;
45759
    int error_status;
45760
} ValueBuffer;
45761
45762
static int value_buffer_init(JSContext *ctx, ValueBuffer *b)
45763
0
{
45764
0
    b->ctx = ctx;
45765
0
    b->len = 0;
45766
0
    b->size = 4;
45767
0
    b->error_status = 0;
45768
0
    b->arr = b->def;
45769
0
    return 0;
45770
0
}
45771
45772
static void value_buffer_free(ValueBuffer *b)
45773
0
{
45774
0
    while (b->len > 0)
45775
0
        JS_FreeValue(b->ctx, b->arr[--b->len]);
45776
0
    if (b->arr != b->def)
45777
0
        js_free(b->ctx, b->arr);
45778
0
    b->arr = b->def;
45779
0
    b->size = 4;
45780
0
}
45781
45782
static int value_buffer_append(ValueBuffer *b, JSValue val)
45783
0
{
45784
0
    if (b->error_status)
45785
0
        return -1;
45786
45787
0
    if (b->len >= b->size) {
45788
0
        int new_size = (b->len + (b->len >> 1) + 31) & ~16;
45789
0
        size_t slack;
45790
0
        JSValue *new_arr;
45791
45792
0
        if (b->arr == b->def) {
45793
0
            new_arr = js_realloc2(b->ctx, NULL, sizeof(*b->arr) * new_size, &slack);
45794
0
            if (new_arr)
45795
0
                memcpy(new_arr, b->def, sizeof b->def);
45796
0
        } else {
45797
0
            new_arr = js_realloc2(b->ctx, b->arr, sizeof(*b->arr) * new_size, &slack);
45798
0
        }
45799
0
        if (!new_arr) {
45800
0
            value_buffer_free(b);
45801
0
            JS_FreeValue(b->ctx, val);
45802
0
            b->error_status = -1;
45803
0
            return -1;
45804
0
        }
45805
0
        new_size += slack / sizeof(*new_arr);
45806
0
        b->arr = new_arr;
45807
0
        b->size = new_size;
45808
0
    }
45809
0
    b->arr[b->len++] = val;
45810
0
    return 0;
45811
0
}
45812
45813
static int js_is_standard_regexp(JSContext *ctx, JSValueConst rx)
45814
0
{
45815
0
    JSValue val;
45816
0
    int res;
45817
45818
0
    val = JS_GetProperty(ctx, rx, JS_ATOM_constructor);
45819
0
    if (JS_IsException(val))
45820
0
        return -1;
45821
    // rx.constructor === RegExp
45822
0
    res = js_same_value(ctx, val, ctx->regexp_ctor);
45823
0
    JS_FreeValue(ctx, val);
45824
0
    if (res) {
45825
0
        val = JS_GetProperty(ctx, rx, JS_ATOM_exec);
45826
0
        if (JS_IsException(val))
45827
0
            return -1;
45828
        // rx.exec === RE_exec
45829
0
        res = JS_IsCFunction(ctx, val, js_regexp_exec, 0);
45830
0
        JS_FreeValue(ctx, val);
45831
0
    }
45832
0
    return res;
45833
0
}
45834
45835
static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
45836
                                        int argc, JSValueConst *argv)
45837
0
{
45838
    // [Symbol.replace](str, rep)
45839
0
    JSValueConst rx = this_val, rep = argv[1];
45840
0
    JSValueConst args[6];
45841
0
    JSValue flags, str, rep_val, matched, tab, rep_str, namedCaptures, res;
45842
0
    JSString *p, *sp, *rp;
45843
0
    StringBuffer b_s, *b = &b_s;
45844
0
    ValueBuffer v_b, *results = &v_b;
45845
0
    int nextSourcePosition, n, j, functionalReplace, is_global, fullUnicode;
45846
0
    uint32_t nCaptures;
45847
0
    int64_t position;
45848
45849
0
    if (!JS_IsObject(rx))
45850
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
45851
45852
0
    string_buffer_init(ctx, b, 0);
45853
0
    value_buffer_init(ctx, results);
45854
45855
0
    rep_val = JS_UNDEFINED;
45856
0
    matched = JS_UNDEFINED;
45857
0
    tab = JS_UNDEFINED;
45858
0
    flags = JS_UNDEFINED;
45859
0
    rep_str = JS_UNDEFINED;
45860
0
    namedCaptures = JS_UNDEFINED;
45861
45862
0
    str = JS_ToString(ctx, argv[0]);
45863
0
    if (JS_IsException(str))
45864
0
        goto exception;
45865
45866
0
    sp = JS_VALUE_GET_STRING(str);
45867
0
    rp = NULL;
45868
0
    functionalReplace = JS_IsFunction(ctx, rep);
45869
0
    if (!functionalReplace) {
45870
0
        rep_val = JS_ToString(ctx, rep);
45871
0
        if (JS_IsException(rep_val))
45872
0
            goto exception;
45873
0
        rp = JS_VALUE_GET_STRING(rep_val);
45874
0
    }
45875
45876
0
    flags = JS_GetProperty(ctx, rx, JS_ATOM_flags);
45877
0
    if (JS_IsException(flags))
45878
0
        goto exception;
45879
0
    flags = JS_ToStringFree(ctx, flags);
45880
0
    if (JS_IsException(flags))
45881
0
        goto exception;
45882
0
    p = JS_VALUE_GET_STRING(flags);
45883
45884
0
    fullUnicode = 0;
45885
0
    is_global = (-1 != string_indexof_char(p, 'g', 0));
45886
0
    if (is_global) {
45887
0
        fullUnicode = (string_indexof_char(p, 'u', 0) >= 0 ||
45888
0
                       string_indexof_char(p, 'v', 0) >= 0);
45889
0
        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0)
45890
0
            goto exception;
45891
0
    }
45892
45893
0
    if (rp && rp->len == 0 && is_global && js_is_standard_regexp(ctx, rx)) {
45894
        /* use faster version for simple cases */
45895
0
        res = JS_RegExpDelete(ctx, rx, str);
45896
0
        goto done;
45897
0
    }
45898
0
    for(;;) {
45899
0
        JSValue result;
45900
0
        result = JS_RegExpExec(ctx, rx, str);
45901
0
        if (JS_IsException(result))
45902
0
            goto exception;
45903
0
        if (JS_IsNull(result))
45904
0
            break;
45905
0
        if (value_buffer_append(results, result) < 0)
45906
0
            goto exception;
45907
0
        if (!is_global)
45908
0
            break;
45909
0
        JS_FreeValue(ctx, matched);
45910
0
        matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
45911
0
        if (JS_IsException(matched))
45912
0
            goto exception;
45913
0
        if (JS_IsEmptyString(matched)) {
45914
            /* always advance of at least one char */
45915
0
            int64_t thisIndex, nextIndex;
45916
0
            if (JS_ToLengthFree(ctx, &thisIndex, JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0)
45917
0
                goto exception;
45918
0
            nextIndex = string_advance_index(sp, thisIndex, fullUnicode);
45919
0
            if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0)
45920
0
                goto exception;
45921
0
        }
45922
0
    }
45923
0
    nextSourcePosition = 0;
45924
0
    for(j = 0; j < results->len; j++) {
45925
0
        JSValueConst result;
45926
0
        result = results->arr[j];
45927
0
        if (js_get_length32(ctx, &nCaptures, result) < 0)
45928
0
            goto exception;
45929
0
        JS_FreeValue(ctx, matched);
45930
0
        matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));
45931
0
        if (JS_IsException(matched))
45932
0
            goto exception;
45933
0
        if (JS_ToLengthFree(ctx, &position, JS_GetProperty(ctx, result, JS_ATOM_index)))
45934
0
            goto exception;
45935
0
        if (position > sp->len)
45936
0
            position = sp->len;
45937
0
        else if (position < 0)
45938
0
            position = 0;
45939
        /* ignore substition if going backward (can happen
45940
           with custom regexp object) */
45941
0
        JS_FreeValue(ctx, tab);
45942
0
        tab = JS_NewArray(ctx);
45943
0
        if (JS_IsException(tab))
45944
0
            goto exception;
45945
0
        if (JS_DefinePropertyValueInt64(ctx, tab, 0, JS_DupValue(ctx, matched),
45946
0
                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)
45947
0
            goto exception;
45948
0
        for(n = 1; n < nCaptures; n++) {
45949
0
            JSValue capN;
45950
0
            capN = JS_GetPropertyInt64(ctx, result, n);
45951
0
            if (JS_IsException(capN))
45952
0
                goto exception;
45953
0
            if (!JS_IsUndefined(capN)) {
45954
0
                capN = JS_ToStringFree(ctx, capN);
45955
0
                if (JS_IsException(capN))
45956
0
                    goto exception;
45957
0
            }
45958
0
            if (JS_DefinePropertyValueInt64(ctx, tab, n, capN,
45959
0
                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)
45960
0
                goto exception;
45961
0
        }
45962
0
        JS_FreeValue(ctx, namedCaptures);
45963
0
        namedCaptures = JS_GetProperty(ctx, result, JS_ATOM_groups);
45964
0
        if (JS_IsException(namedCaptures))
45965
0
            goto exception;
45966
0
        if (functionalReplace) {
45967
0
            if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_NewInt32(ctx, position), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
45968
0
                goto exception;
45969
0
            if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, str), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
45970
0
                goto exception;
45971
0
            if (!JS_IsUndefined(namedCaptures)) {
45972
0
                if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, namedCaptures), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
45973
0
                    goto exception;
45974
0
            }
45975
0
            args[0] = JS_UNDEFINED;
45976
0
            args[1] = tab;
45977
0
            JS_FreeValue(ctx, rep_str);
45978
0
            rep_str = JS_ToStringFree(ctx, js_function_apply(ctx, rep, 2, args, 0));
45979
0
        } else {
45980
0
            JSValue namedCaptures1;
45981
0
            if (!JS_IsUndefined(namedCaptures)) {
45982
0
                namedCaptures1 = JS_ToObject(ctx, namedCaptures);
45983
0
                if (JS_IsException(namedCaptures1))
45984
0
                    goto exception;
45985
0
            } else {
45986
0
                namedCaptures1 = JS_UNDEFINED;
45987
0
            }
45988
0
            args[0] = matched;
45989
0
            args[1] = str;
45990
0
            args[2] = JS_NewInt32(ctx, position);
45991
0
            args[3] = tab;
45992
0
            args[4] = namedCaptures1;
45993
0
            args[5] = rep_val;
45994
0
            JS_FreeValue(ctx, rep_str);
45995
0
            rep_str = js_string___GetSubstitution(ctx, JS_UNDEFINED, 6, args);
45996
0
            JS_FreeValue(ctx, namedCaptures1);
45997
0
        }
45998
0
        if (JS_IsException(rep_str))
45999
0
            goto exception;
46000
0
        if (position >= nextSourcePosition) {
46001
0
            string_buffer_concat(b, sp, nextSourcePosition, position);
46002
0
            string_buffer_concat_value(b, rep_str);
46003
0
            nextSourcePosition = position + JS_VALUE_GET_STRING(matched)->len;
46004
0
        }
46005
0
    }
46006
0
    string_buffer_concat(b, sp, nextSourcePosition, sp->len);
46007
0
    res = string_buffer_end(b);
46008
0
    goto done1;
46009
46010
0
exception:
46011
0
    res = JS_EXCEPTION;
46012
0
done:
46013
0
    string_buffer_free(b);
46014
0
done1:
46015
0
    value_buffer_free(results);
46016
0
    JS_FreeValue(ctx, rep_val);
46017
0
    JS_FreeValue(ctx, matched);
46018
0
    JS_FreeValue(ctx, flags);
46019
0
    JS_FreeValue(ctx, tab);
46020
0
    JS_FreeValue(ctx, rep_str);
46021
0
    JS_FreeValue(ctx, namedCaptures);
46022
0
    JS_FreeValue(ctx, str);
46023
0
    return res;
46024
0
}
46025
46026
static JSValue js_regexp_Symbol_search(JSContext *ctx, JSValueConst this_val,
46027
                                       int argc, JSValueConst *argv)
46028
0
{
46029
0
    JSValueConst rx = this_val;
46030
0
    JSValue str, previousLastIndex, currentLastIndex, result, index;
46031
46032
0
    if (!JS_IsObject(rx))
46033
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
46034
46035
0
    result = JS_UNDEFINED;
46036
0
    currentLastIndex = JS_UNDEFINED;
46037
0
    previousLastIndex = JS_UNDEFINED;
46038
0
    str = JS_ToString(ctx, argv[0]);
46039
0
    if (JS_IsException(str))
46040
0
        goto exception;
46041
46042
0
    previousLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex);
46043
0
    if (JS_IsException(previousLastIndex))
46044
0
        goto exception;
46045
46046
0
    if (!js_same_value(ctx, previousLastIndex, JS_NewInt32(ctx, 0))) {
46047
0
        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0) {
46048
0
            goto exception;
46049
0
        }
46050
0
    }
46051
0
    result = JS_RegExpExec(ctx, rx, str);
46052
0
    if (JS_IsException(result))
46053
0
        goto exception;
46054
0
    currentLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex);
46055
0
    if (JS_IsException(currentLastIndex))
46056
0
        goto exception;
46057
0
    if (js_same_value(ctx, currentLastIndex, previousLastIndex)) {
46058
0
        JS_FreeValue(ctx, previousLastIndex);
46059
0
    } else {
46060
0
        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, previousLastIndex) < 0) {
46061
0
            previousLastIndex = JS_UNDEFINED;
46062
0
            goto exception;
46063
0
        }
46064
0
    }
46065
0
    JS_FreeValue(ctx, str);
46066
0
    JS_FreeValue(ctx, currentLastIndex);
46067
46068
0
    if (JS_IsNull(result)) {
46069
0
        return JS_NewInt32(ctx, -1);
46070
0
    } else {
46071
0
        index = JS_GetProperty(ctx, result, JS_ATOM_index);
46072
0
        JS_FreeValue(ctx, result);
46073
0
        return index;
46074
0
    }
46075
46076
0
exception:
46077
0
    JS_FreeValue(ctx, result);
46078
0
    JS_FreeValue(ctx, str);
46079
0
    JS_FreeValue(ctx, currentLastIndex);
46080
0
    JS_FreeValue(ctx, previousLastIndex);
46081
0
    return JS_EXCEPTION;
46082
0
}
46083
46084
static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val,
46085
                                       int argc, JSValueConst *argv)
46086
0
{
46087
    // [Symbol.split](str, limit)
46088
0
    JSValueConst rx = this_val;
46089
0
    JSValueConst args[2];
46090
0
    JSValue str, ctor, splitter, A, flags, z, sub;
46091
0
    JSString *strp;
46092
0
    uint32_t lim, size, p, q;
46093
0
    int unicodeMatching;
46094
0
    int64_t lengthA, e, numberOfCaptures, i;
46095
46096
0
    if (!JS_IsObject(rx))
46097
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
46098
46099
0
    ctor = JS_UNDEFINED;
46100
0
    splitter = JS_UNDEFINED;
46101
0
    A = JS_UNDEFINED;
46102
0
    flags = JS_UNDEFINED;
46103
0
    z = JS_UNDEFINED;
46104
0
    str = JS_ToString(ctx, argv[0]);
46105
0
    if (JS_IsException(str))
46106
0
        goto exception;
46107
0
    ctor = JS_SpeciesConstructor(ctx, rx, ctx->regexp_ctor);
46108
0
    if (JS_IsException(ctor))
46109
0
        goto exception;
46110
0
    flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_flags));
46111
0
    if (JS_IsException(flags))
46112
0
        goto exception;
46113
0
    strp = JS_VALUE_GET_STRING(flags);
46114
0
    unicodeMatching = (string_indexof_char(strp, 'u', 0) >= 0 ||
46115
0
                       string_indexof_char(strp, 'v', 0) >= 0);
46116
0
    if (string_indexof_char(strp, 'y', 0) < 0) {
46117
0
        flags = JS_ConcatString3(ctx, "", flags, "y");
46118
0
        if (JS_IsException(flags))
46119
0
            goto exception;
46120
0
    }
46121
0
    args[0] = rx;
46122
0
    args[1] = flags;
46123
0
    splitter = JS_CallConstructor(ctx, ctor, 2, args);
46124
0
    if (JS_IsException(splitter))
46125
0
        goto exception;
46126
0
    A = JS_NewArray(ctx);
46127
0
    if (JS_IsException(A))
46128
0
        goto exception;
46129
0
    lengthA = 0;
46130
0
    if (JS_IsUndefined(argv[1])) {
46131
0
        lim = 0xffffffff;
46132
0
    } else {
46133
0
        if (JS_ToUint32(ctx, &lim, argv[1]) < 0)
46134
0
            goto exception;
46135
0
        if (lim == 0)
46136
0
            goto done;
46137
0
    }
46138
0
    strp = JS_VALUE_GET_STRING(str);
46139
0
    p = q = 0;
46140
0
    size = strp->len;
46141
0
    if (size == 0) {
46142
0
        z = JS_RegExpExec(ctx, splitter, str);
46143
0
        if (JS_IsException(z))
46144
0
            goto exception;
46145
0
        if (JS_IsNull(z))
46146
0
            goto add_tail;
46147
0
        goto done;
46148
0
    }
46149
0
    while (q < size) {
46150
0
        if (JS_SetProperty(ctx, splitter, JS_ATOM_lastIndex, JS_NewInt32(ctx, q)) < 0)
46151
0
            goto exception;
46152
0
        JS_FreeValue(ctx, z);
46153
0
        z = JS_RegExpExec(ctx, splitter, str);
46154
0
        if (JS_IsException(z))
46155
0
            goto exception;
46156
0
        if (JS_IsNull(z)) {
46157
0
            q = string_advance_index(strp, q, unicodeMatching);
46158
0
        } else {
46159
0
            if (JS_ToLengthFree(ctx, &e, JS_GetProperty(ctx, splitter, JS_ATOM_lastIndex)))
46160
0
                goto exception;
46161
0
            if (e > size)
46162
0
                e = size;
46163
0
            if (e == p) {
46164
0
                q = string_advance_index(strp, q, unicodeMatching);
46165
0
            } else {
46166
0
                sub = js_sub_string(ctx, strp, p, q);
46167
0
                if (JS_IsException(sub))
46168
0
                    goto exception;
46169
0
                if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub,
46170
0
                                                JS_PROP_C_W_E | JS_PROP_THROW) < 0)
46171
0
                    goto exception;
46172
0
                if (lengthA == lim)
46173
0
                    goto done;
46174
0
                p = e;
46175
0
                if (js_get_length64(ctx, &numberOfCaptures, z))
46176
0
                    goto exception;
46177
0
                for(i = 1; i < numberOfCaptures; i++) {
46178
0
                    sub = JS_GetPropertyInt64(ctx, z, i);
46179
0
                    if (JS_IsException(sub))
46180
0
                        goto exception;
46181
0
                    if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
46182
0
                        goto exception;
46183
0
                    if (lengthA == lim)
46184
0
                        goto done;
46185
0
                }
46186
0
                q = p;
46187
0
            }
46188
0
        }
46189
0
    }
46190
0
add_tail:
46191
0
    if (p > size)
46192
0
        p = size;
46193
0
    sub = js_sub_string(ctx, strp, p, size);
46194
0
    if (JS_IsException(sub))
46195
0
        goto exception;
46196
0
    if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
46197
0
        goto exception;
46198
0
    goto done;
46199
0
exception:
46200
0
    JS_FreeValue(ctx, A);
46201
0
    A = JS_EXCEPTION;
46202
0
done:
46203
0
    JS_FreeValue(ctx, str);
46204
0
    JS_FreeValue(ctx, ctor);
46205
0
    JS_FreeValue(ctx, splitter);
46206
0
    JS_FreeValue(ctx, flags);
46207
0
    JS_FreeValue(ctx, z);
46208
0
    return A;
46209
0
}
46210
46211
static const JSCFunctionListEntry js_regexp_funcs[] = {
46212
    JS_CFUNC_DEF("escape", 1, js_regexp_escape ),
46213
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
46214
    //JS_CFUNC_DEF("__RegExpExec", 2, js_regexp___RegExpExec ),
46215
    //JS_CFUNC_DEF("__RegExpDelete", 2, js_regexp___RegExpDelete ),
46216
};
46217
46218
static const JSCFunctionListEntry js_regexp_proto_funcs[] = {
46219
    JS_CGETSET_DEF("flags", js_regexp_get_flags, NULL ),
46220
    JS_CGETSET_DEF("source", js_regexp_get_source, NULL ),
46221
    JS_CGETSET_MAGIC_DEF("global", js_regexp_get_flag, NULL, LRE_FLAG_GLOBAL ),
46222
    JS_CGETSET_MAGIC_DEF("ignoreCase", js_regexp_get_flag, NULL, LRE_FLAG_IGNORECASE ),
46223
    JS_CGETSET_MAGIC_DEF("multiline", js_regexp_get_flag, NULL, LRE_FLAG_MULTILINE ),
46224
    JS_CGETSET_MAGIC_DEF("dotAll", js_regexp_get_flag, NULL, LRE_FLAG_DOTALL ),
46225
    JS_CGETSET_MAGIC_DEF("unicode", js_regexp_get_flag, NULL, LRE_FLAG_UNICODE ),
46226
    JS_CGETSET_MAGIC_DEF("unicodeSets", js_regexp_get_flag, NULL, LRE_FLAG_UNICODE_SETS ),
46227
    JS_CGETSET_MAGIC_DEF("sticky", js_regexp_get_flag, NULL, LRE_FLAG_STICKY ),
46228
    JS_CGETSET_MAGIC_DEF("hasIndices", js_regexp_get_flag, NULL, LRE_FLAG_INDICES ),
46229
    JS_CFUNC_DEF("exec", 1, js_regexp_exec ),
46230
    JS_CFUNC_DEF("compile", 2, js_regexp_compile ),
46231
    JS_CFUNC_DEF("test", 1, js_regexp_test ),
46232
    JS_CFUNC_DEF("toString", 0, js_regexp_toString ),
46233
    JS_CFUNC_DEF("[Symbol.replace]", 2, js_regexp_Symbol_replace ),
46234
    JS_CFUNC_DEF("[Symbol.match]", 1, js_regexp_Symbol_match ),
46235
    JS_CFUNC_DEF("[Symbol.matchAll]", 1, js_regexp_Symbol_matchAll ),
46236
    JS_CFUNC_DEF("[Symbol.search]", 1, js_regexp_Symbol_search ),
46237
    JS_CFUNC_DEF("[Symbol.split]", 2, js_regexp_Symbol_split ),
46238
    //JS_CGETSET_DEF("__source", js_regexp_get___source, NULL ),
46239
    //JS_CGETSET_DEF("__flags", js_regexp_get___flags, NULL ),
46240
};
46241
46242
static const JSCFunctionListEntry js_regexp_string_iterator_proto_funcs[] = {
46243
    JS_ITERATOR_NEXT_DEF("next", 0, js_regexp_string_iterator_next, 0 ),
46244
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "RegExp String Iterator", JS_PROP_CONFIGURABLE ),
46245
};
46246
46247
void JS_AddIntrinsicRegExpCompiler(JSContext *ctx)
46248
2
{
46249
2
    ctx->compile_regexp = js_compile_regexp;
46250
2
}
46251
46252
void JS_AddIntrinsicRegExp(JSContext *ctx)
46253
2
{
46254
2
    JSValueConst obj;
46255
46256
2
    JS_AddIntrinsicRegExpCompiler(ctx);
46257
46258
2
    ctx->class_proto[JS_CLASS_REGEXP] = JS_NewObject(ctx);
46259
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_REGEXP], js_regexp_proto_funcs,
46260
2
                               countof(js_regexp_proto_funcs));
46261
2
    obj = JS_NewGlobalCConstructor(ctx, "RegExp", js_regexp_constructor, 2,
46262
2
                                   ctx->class_proto[JS_CLASS_REGEXP]);
46263
2
    ctx->regexp_ctor = JS_DupValue(ctx, obj);
46264
2
    JS_SetPropertyFunctionList(ctx, obj, js_regexp_funcs, countof(js_regexp_funcs));
46265
46266
2
    ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR] =
46267
2
        JS_NewObjectProto(ctx, ctx->iterator_proto);
46268
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR],
46269
2
                               js_regexp_string_iterator_proto_funcs,
46270
2
                               countof(js_regexp_string_iterator_proto_funcs));
46271
2
}
46272
46273
/* JSON */
46274
46275
static int json_parse_expect(JSParseState *s, int tok)
46276
0
{
46277
0
    if (s->token.val != tok) {
46278
        /* XXX: dump token correctly in all cases */
46279
0
        return js_parse_error(s, "expecting '%c'", tok);
46280
0
    }
46281
0
    return json_next_token(s);
46282
0
}
46283
46284
static JSValue json_parse_value(JSParseState *s)
46285
0
{
46286
0
    JSContext *ctx = s->ctx;
46287
0
    JSValue val = JS_NULL;
46288
0
    int ret;
46289
46290
0
    switch(s->token.val) {
46291
0
    case '{':
46292
0
        {
46293
0
            JSValue prop_val;
46294
0
            JSAtom prop_name;
46295
46296
0
            if (json_next_token(s))
46297
0
                goto fail;
46298
0
            val = JS_NewObject(ctx);
46299
0
            if (JS_IsException(val))
46300
0
                goto fail;
46301
0
            if (s->token.val != '}') {
46302
0
                for(;;) {
46303
0
                    if (s->token.val == TOK_STRING) {
46304
0
                        prop_name = JS_ValueToAtom(ctx, s->token.u.str.str);
46305
0
                        if (prop_name == JS_ATOM_NULL)
46306
0
                            goto fail;
46307
0
                    } else if (s->ext_json && s->token.val == TOK_IDENT) {
46308
0
                        prop_name = JS_DupAtom(ctx, s->token.u.ident.atom);
46309
0
                    } else {
46310
0
                        js_parse_error(s, "expecting property name");
46311
0
                        goto fail;
46312
0
                    }
46313
0
                    if (json_next_token(s))
46314
0
                        goto fail1;
46315
0
                    if (json_parse_expect(s, ':'))
46316
0
                        goto fail1;
46317
0
                    prop_val = json_parse_value(s);
46318
0
                    if (JS_IsException(prop_val)) {
46319
0
                    fail1:
46320
0
                        JS_FreeAtom(ctx, prop_name);
46321
0
                        goto fail;
46322
0
                    }
46323
0
                    ret = JS_DefinePropertyValue(ctx, val, prop_name,
46324
0
                                                 prop_val, JS_PROP_C_W_E);
46325
0
                    JS_FreeAtom(ctx, prop_name);
46326
0
                    if (ret < 0)
46327
0
                        goto fail;
46328
46329
0
                    if (s->token.val != ',')
46330
0
                        break;
46331
0
                    if (json_next_token(s))
46332
0
                        goto fail;
46333
0
                    if (s->ext_json && s->token.val == '}')
46334
0
                        break;
46335
0
                }
46336
0
            }
46337
0
            if (json_parse_expect(s, '}'))
46338
0
                goto fail;
46339
0
        }
46340
0
        break;
46341
0
    case '[':
46342
0
        {
46343
0
            JSValue el;
46344
0
            uint32_t idx;
46345
46346
0
            if (json_next_token(s))
46347
0
                goto fail;
46348
0
            val = JS_NewArray(ctx);
46349
0
            if (JS_IsException(val))
46350
0
                goto fail;
46351
0
            if (s->token.val != ']') {
46352
0
                idx = 0;
46353
0
                for(;;) {
46354
0
                    el = json_parse_value(s);
46355
0
                    if (JS_IsException(el))
46356
0
                        goto fail;
46357
0
                    ret = JS_DefinePropertyValueUint32(ctx, val, idx, el, JS_PROP_C_W_E);
46358
0
                    if (ret < 0)
46359
0
                        goto fail;
46360
0
                    if (s->token.val != ',')
46361
0
                        break;
46362
0
                    if (json_next_token(s))
46363
0
                        goto fail;
46364
0
                    idx++;
46365
0
                    if (s->ext_json && s->token.val == ']')
46366
0
                        break;
46367
0
                }
46368
0
            }
46369
0
            if (json_parse_expect(s, ']'))
46370
0
                goto fail;
46371
0
        }
46372
0
        break;
46373
0
    case TOK_STRING:
46374
0
        val = JS_DupValue(ctx, s->token.u.str.str);
46375
0
        if (json_next_token(s))
46376
0
            goto fail;
46377
0
        break;
46378
0
    case TOK_NUMBER:
46379
0
        val = s->token.u.num.val;
46380
0
        if (json_next_token(s))
46381
0
            goto fail;
46382
0
        break;
46383
0
    case TOK_IDENT:
46384
0
        if (s->token.u.ident.atom == JS_ATOM_false ||
46385
0
            s->token.u.ident.atom == JS_ATOM_true) {
46386
0
            val = JS_NewBool(ctx, s->token.u.ident.atom == JS_ATOM_true);
46387
0
        } else if (s->token.u.ident.atom == JS_ATOM_null) {
46388
0
            val = JS_NULL;
46389
0
        } else if (s->token.u.ident.atom == JS_ATOM_NaN && s->ext_json) {
46390
            /* Note: json5 identifier handling is ambiguous e.g. is 
46391
               '{ NaN: 1 }' a valid JSON5 production ? */ 
46392
0
            val = JS_NewFloat64(s->ctx, NAN);
46393
0
        } else if (s->token.u.ident.atom == JS_ATOM_Infinity && s->ext_json) {
46394
0
            val = JS_NewFloat64(s->ctx, INFINITY);
46395
0
        } else {
46396
0
            goto def_token;
46397
0
        }
46398
0
        if (json_next_token(s))
46399
0
            goto fail;
46400
0
        break;
46401
0
    default:
46402
0
    def_token:
46403
0
        if (s->token.val == TOK_EOF) {
46404
0
            js_parse_error(s, "Unexpected end of JSON input");
46405
0
        } else {
46406
0
            js_parse_error(s, "unexpected token: '%.*s'",
46407
0
                           (int)(s->buf_ptr - s->token.ptr), s->token.ptr);
46408
0
        }
46409
0
        goto fail;
46410
0
    }
46411
0
    return val;
46412
0
 fail:
46413
0
    JS_FreeValue(ctx, val);
46414
0
    return JS_EXCEPTION;
46415
0
}
46416
46417
JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
46418
                      const char *filename, int flags)
46419
0
{
46420
0
    JSParseState s1, *s = &s1;
46421
0
    JSValue val = JS_UNDEFINED;
46422
46423
0
    js_parse_init(ctx, s, buf, buf_len, filename);
46424
0
    s->ext_json = ((flags & JS_PARSE_JSON_EXT) != 0);
46425
0
    if (json_next_token(s))
46426
0
        goto fail;
46427
0
    val = json_parse_value(s);
46428
0
    if (JS_IsException(val))
46429
0
        goto fail;
46430
0
    if (s->token.val != TOK_EOF) {
46431
0
        if (js_parse_error(s, "unexpected data at the end"))
46432
0
            goto fail;
46433
0
    }
46434
0
    return val;
46435
0
 fail:
46436
0
    JS_FreeValue(ctx, val);
46437
0
    free_token(s, &s->token);
46438
0
    return JS_EXCEPTION;
46439
0
}
46440
46441
JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
46442
                     const char *filename)
46443
0
{
46444
0
    return JS_ParseJSON2(ctx, buf, buf_len, filename, 0);
46445
0
}
46446
46447
static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
46448
                                         JSAtom name, JSValueConst reviver)
46449
0
{
46450
0
    JSValue val, new_el, name_val, res;
46451
0
    JSValueConst args[2];
46452
0
    int ret, is_array;
46453
0
    uint32_t i, len = 0;
46454
0
    JSAtom prop;
46455
0
    JSPropertyEnum *atoms = NULL;
46456
46457
0
    if (js_check_stack_overflow(ctx->rt, 0)) {
46458
0
        return JS_ThrowStackOverflow(ctx);
46459
0
    }
46460
46461
0
    val = JS_GetProperty(ctx, holder, name);
46462
0
    if (JS_IsException(val))
46463
0
        return val;
46464
0
    if (JS_IsObject(val)) {
46465
0
        is_array = JS_IsArray(ctx, val);
46466
0
        if (is_array < 0)
46467
0
            goto fail;
46468
0
        if (is_array) {
46469
0
            if (js_get_length32(ctx, &len, val))
46470
0
                goto fail;
46471
0
        } else {
46472
0
            ret = JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, JS_VALUE_GET_OBJ(val), JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK);
46473
0
            if (ret < 0)
46474
0
                goto fail;
46475
0
        }
46476
0
        for(i = 0; i < len; i++) {
46477
0
            if (is_array) {
46478
0
                prop = JS_NewAtomUInt32(ctx, i);
46479
0
                if (prop == JS_ATOM_NULL)
46480
0
                    goto fail;
46481
0
            } else {
46482
0
                prop = JS_DupAtom(ctx, atoms[i].atom);
46483
0
            }
46484
0
            new_el = internalize_json_property(ctx, val, prop, reviver);
46485
0
            if (JS_IsException(new_el)) {
46486
0
                JS_FreeAtom(ctx, prop);
46487
0
                goto fail;
46488
0
            }
46489
0
            if (JS_IsUndefined(new_el)) {
46490
0
                ret = JS_DeleteProperty(ctx, val, prop, 0);
46491
0
            } else {
46492
0
                ret = JS_DefinePropertyValue(ctx, val, prop, new_el, JS_PROP_C_W_E);
46493
0
            }
46494
0
            JS_FreeAtom(ctx, prop);
46495
0
            if (ret < 0)
46496
0
                goto fail;
46497
0
        }
46498
0
    }
46499
0
    JS_FreePropertyEnum(ctx, atoms, len);
46500
0
    atoms = NULL;
46501
0
    name_val = JS_AtomToValue(ctx, name);
46502
0
    if (JS_IsException(name_val))
46503
0
        goto fail;
46504
0
    args[0] = name_val;
46505
0
    args[1] = val;
46506
0
    res = JS_Call(ctx, reviver, holder, 2, args);
46507
0
    JS_FreeValue(ctx, name_val);
46508
0
    JS_FreeValue(ctx, val);
46509
0
    return res;
46510
0
 fail:
46511
0
    JS_FreePropertyEnum(ctx, atoms, len);
46512
0
    JS_FreeValue(ctx, val);
46513
0
    return JS_EXCEPTION;
46514
0
}
46515
46516
static JSValue js_json_parse(JSContext *ctx, JSValueConst this_val,
46517
                             int argc, JSValueConst *argv)
46518
0
{
46519
0
    JSValue obj, root;
46520
0
    JSValueConst reviver;
46521
0
    const char *str;
46522
0
    size_t len;
46523
46524
0
    str = JS_ToCStringLen(ctx, &len, argv[0]);
46525
0
    if (!str)
46526
0
        return JS_EXCEPTION;
46527
0
    obj = JS_ParseJSON(ctx, str, len, "<input>");
46528
0
    JS_FreeCString(ctx, str);
46529
0
    if (JS_IsException(obj))
46530
0
        return obj;
46531
0
    if (argc > 1 && JS_IsFunction(ctx, argv[1])) {
46532
0
        reviver = argv[1];
46533
0
        root = JS_NewObject(ctx);
46534
0
        if (JS_IsException(root)) {
46535
0
            JS_FreeValue(ctx, obj);
46536
0
            return JS_EXCEPTION;
46537
0
        }
46538
0
        if (JS_DefinePropertyValue(ctx, root, JS_ATOM_empty_string, obj,
46539
0
                                   JS_PROP_C_W_E) < 0) {
46540
0
            JS_FreeValue(ctx, root);
46541
0
            return JS_EXCEPTION;
46542
0
        }
46543
0
        obj = internalize_json_property(ctx, root, JS_ATOM_empty_string,
46544
0
                                        reviver);
46545
0
        JS_FreeValue(ctx, root);
46546
0
    }
46547
0
    return obj;
46548
0
}
46549
46550
typedef struct JSONStringifyContext {
46551
    JSValueConst replacer_func;
46552
    JSValue stack;
46553
    JSValue property_list;
46554
    JSValue gap;
46555
    JSValue empty;
46556
    StringBuffer *b;
46557
} JSONStringifyContext;
46558
46559
0
static JSValue JS_ToQuotedStringFree(JSContext *ctx, JSValue val) {
46560
0
    JSValue r = JS_ToQuotedString(ctx, val);
46561
0
    JS_FreeValue(ctx, val);
46562
0
    return r;
46563
0
}
46564
46565
static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,
46566
                             JSValueConst holder, JSValue val, JSValueConst key)
46567
0
{
46568
0
    JSValue v;
46569
0
    JSValueConst args[2];
46570
46571
    /* check for object.toJSON method */
46572
    /* ECMA specifies this is done only for Object and BigInt */
46573
0
    if (JS_IsObject(val) || JS_IsBigInt(ctx, val)) {
46574
0
        JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON);
46575
0
        if (JS_IsException(f))
46576
0
            goto exception;
46577
0
        if (JS_IsFunction(ctx, f)) {
46578
0
            v = JS_CallFree(ctx, f, val, 1, &key);
46579
0
            JS_FreeValue(ctx, val);
46580
0
            val = v;
46581
0
            if (JS_IsException(val))
46582
0
                goto exception;
46583
0
        } else {
46584
0
            JS_FreeValue(ctx, f);
46585
0
        }
46586
0
    }
46587
46588
0
    if (!JS_IsUndefined(jsc->replacer_func)) {
46589
0
        args[0] = key;
46590
0
        args[1] = val;
46591
0
        v = JS_Call(ctx, jsc->replacer_func, holder, 2, args);
46592
0
        JS_FreeValue(ctx, val);
46593
0
        val = v;
46594
0
        if (JS_IsException(val))
46595
0
            goto exception;
46596
0
    }
46597
46598
0
    switch (JS_VALUE_GET_NORM_TAG(val)) {
46599
0
    case JS_TAG_OBJECT:
46600
0
        if (JS_IsFunction(ctx, val))
46601
0
            break;
46602
0
    case JS_TAG_STRING:
46603
0
    case JS_TAG_STRING_ROPE:
46604
0
    case JS_TAG_INT:
46605
0
    case JS_TAG_FLOAT64:
46606
0
    case JS_TAG_BOOL:
46607
0
    case JS_TAG_NULL:
46608
0
    case JS_TAG_SHORT_BIG_INT:
46609
0
    case JS_TAG_BIG_INT:
46610
0
    case JS_TAG_EXCEPTION:
46611
0
        return val;
46612
0
    default:
46613
0
        break;
46614
0
    }
46615
0
    JS_FreeValue(ctx, val);
46616
0
    return JS_UNDEFINED;
46617
46618
0
exception:
46619
0
    JS_FreeValue(ctx, val);
46620
0
    return JS_EXCEPTION;
46621
0
}
46622
46623
static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
46624
                          JSValueConst holder, JSValue val,
46625
                          JSValueConst indent)
46626
0
{
46627
0
    JSValue indent1, sep, sep1, tab, v, prop;
46628
0
    JSObject *p;
46629
0
    int64_t i, len;
46630
0
    int cl, ret;
46631
0
    BOOL has_content;
46632
46633
0
    indent1 = JS_UNDEFINED;
46634
0
    sep = JS_UNDEFINED;
46635
0
    sep1 = JS_UNDEFINED;
46636
0
    tab = JS_UNDEFINED;
46637
0
    prop = JS_UNDEFINED;
46638
46639
0
    if (js_check_stack_overflow(ctx->rt, 0)) {
46640
0
        JS_ThrowStackOverflow(ctx);
46641
0
        goto exception;
46642
0
    }
46643
46644
0
    if (JS_IsObject(val)) {
46645
0
        p = JS_VALUE_GET_OBJ(val);
46646
0
        cl = p->class_id;
46647
0
        if (cl == JS_CLASS_STRING) {
46648
0
            val = JS_ToStringFree(ctx, val);
46649
0
            if (JS_IsException(val))
46650
0
                goto exception;
46651
0
            goto concat_primitive;
46652
0
        } else if (cl == JS_CLASS_NUMBER) {
46653
0
            val = JS_ToNumberFree(ctx, val);
46654
0
            if (JS_IsException(val))
46655
0
                goto exception;
46656
0
            goto concat_primitive;
46657
0
        } else if (cl == JS_CLASS_BOOLEAN || cl == JS_CLASS_BIG_INT)
46658
0
        {
46659
            /* This will thow the same error as for the primitive object */
46660
0
            set_value(ctx, &val, JS_DupValue(ctx, p->u.object_data));
46661
0
            goto concat_primitive;
46662
0
        }
46663
0
        v = js_array_includes(ctx, jsc->stack, 1, (JSValueConst *)&val);
46664
0
        if (JS_IsException(v))
46665
0
            goto exception;
46666
0
        if (JS_ToBoolFree(ctx, v)) {
46667
0
            JS_ThrowTypeError(ctx, "circular reference");
46668
0
            goto exception;
46669
0
        }
46670
0
        indent1 = JS_ConcatString(ctx, JS_DupValue(ctx, indent), JS_DupValue(ctx, jsc->gap));
46671
0
        if (JS_IsException(indent1))
46672
0
            goto exception;
46673
0
        if (!JS_IsEmptyString(jsc->gap)) {
46674
0
            sep = JS_ConcatString3(ctx, "\n", JS_DupValue(ctx, indent1), "");
46675
0
            if (JS_IsException(sep))
46676
0
                goto exception;
46677
0
            sep1 = js_new_string8(ctx, " ");
46678
0
            if (JS_IsException(sep1))
46679
0
                goto exception;
46680
0
        } else {
46681
0
            sep = JS_DupValue(ctx, jsc->empty);
46682
0
            sep1 = JS_DupValue(ctx, jsc->empty);
46683
0
        }
46684
0
        v = js_array_push(ctx, jsc->stack, 1, (JSValueConst *)&val, 0);
46685
0
        if (check_exception_free(ctx, v))
46686
0
            goto exception;
46687
0
        ret = JS_IsArray(ctx, val);
46688
0
        if (ret < 0)
46689
0
            goto exception;
46690
0
        if (ret) {
46691
0
            if (js_get_length64(ctx, &len, val))
46692
0
                goto exception;
46693
0
            string_buffer_putc8(jsc->b, '[');
46694
0
            for(i = 0; i < len; i++) {
46695
0
                if (i > 0)
46696
0
                    string_buffer_putc8(jsc->b, ',');
46697
0
                string_buffer_concat_value(jsc->b, sep);
46698
0
                v = JS_GetPropertyInt64(ctx, val, i);
46699
0
                if (JS_IsException(v))
46700
0
                    goto exception;
46701
                /* XXX: could do this string conversion only when needed */
46702
0
                prop = JS_ToStringFree(ctx, JS_NewInt64(ctx, i));
46703
0
                if (JS_IsException(prop))
46704
0
                    goto exception;
46705
0
                v = js_json_check(ctx, jsc, val, v, prop);
46706
0
                JS_FreeValue(ctx, prop);
46707
0
                prop = JS_UNDEFINED;
46708
0
                if (JS_IsException(v))
46709
0
                    goto exception;
46710
0
                if (JS_IsUndefined(v))
46711
0
                    v = JS_NULL;
46712
0
                if (js_json_to_str(ctx, jsc, val, v, indent1))
46713
0
                    goto exception;
46714
0
            }
46715
0
            if (len > 0 && !JS_IsEmptyString(jsc->gap)) {
46716
0
                string_buffer_putc8(jsc->b, '\n');
46717
0
                string_buffer_concat_value(jsc->b, indent);
46718
0
            }
46719
0
            string_buffer_putc8(jsc->b, ']');
46720
0
        } else {
46721
0
            if (!JS_IsUndefined(jsc->property_list))
46722
0
                tab = JS_DupValue(ctx, jsc->property_list);
46723
0
            else
46724
0
                tab = js_object_keys(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val, JS_ITERATOR_KIND_KEY);
46725
0
            if (JS_IsException(tab))
46726
0
                goto exception;
46727
0
            if (js_get_length64(ctx, &len, tab))
46728
0
                goto exception;
46729
0
            string_buffer_putc8(jsc->b, '{');
46730
0
            has_content = FALSE;
46731
0
            for(i = 0; i < len; i++) {
46732
0
                JS_FreeValue(ctx, prop);
46733
0
                prop = JS_GetPropertyInt64(ctx, tab, i);
46734
0
                if (JS_IsException(prop))
46735
0
                    goto exception;
46736
0
                v = JS_GetPropertyValue(ctx, val, JS_DupValue(ctx, prop));
46737
0
                if (JS_IsException(v))
46738
0
                    goto exception;
46739
0
                v = js_json_check(ctx, jsc, val, v, prop);
46740
0
                if (JS_IsException(v))
46741
0
                    goto exception;
46742
0
                if (!JS_IsUndefined(v)) {
46743
0
                    if (has_content)
46744
0
                        string_buffer_putc8(jsc->b, ',');
46745
0
                    prop = JS_ToQuotedStringFree(ctx, prop);
46746
0
                    if (JS_IsException(prop)) {
46747
0
                        JS_FreeValue(ctx, v);
46748
0
                        goto exception;
46749
0
                    }
46750
0
                    string_buffer_concat_value(jsc->b, sep);
46751
0
                    string_buffer_concat_value(jsc->b, prop);
46752
0
                    string_buffer_putc8(jsc->b, ':');
46753
0
                    string_buffer_concat_value(jsc->b, sep1);
46754
0
                    if (js_json_to_str(ctx, jsc, val, v, indent1))
46755
0
                        goto exception;
46756
0
                    has_content = TRUE;
46757
0
                }
46758
0
            }
46759
0
            if (has_content && !JS_IsEmptyString(jsc->gap)) {
46760
0
                string_buffer_putc8(jsc->b, '\n');
46761
0
                string_buffer_concat_value(jsc->b, indent);
46762
0
            }
46763
0
            string_buffer_putc8(jsc->b, '}');
46764
0
        }
46765
0
        if (check_exception_free(ctx, js_array_pop(ctx, jsc->stack, 0, NULL, 0)))
46766
0
            goto exception;
46767
0
        JS_FreeValue(ctx, val);
46768
0
        JS_FreeValue(ctx, tab);
46769
0
        JS_FreeValue(ctx, sep);
46770
0
        JS_FreeValue(ctx, sep1);
46771
0
        JS_FreeValue(ctx, indent1);
46772
0
        JS_FreeValue(ctx, prop);
46773
0
        return 0;
46774
0
    }
46775
0
 concat_primitive:
46776
0
    switch (JS_VALUE_GET_NORM_TAG(val)) {
46777
0
    case JS_TAG_STRING:
46778
0
    case JS_TAG_STRING_ROPE:
46779
0
        val = JS_ToQuotedStringFree(ctx, val);
46780
0
        if (JS_IsException(val))
46781
0
            goto exception;
46782
0
        goto concat_value;
46783
0
    case JS_TAG_FLOAT64:
46784
0
        if (!isfinite(JS_VALUE_GET_FLOAT64(val))) {
46785
0
            val = JS_NULL;
46786
0
        }
46787
0
        goto concat_value;
46788
0
    case JS_TAG_INT:
46789
0
    case JS_TAG_BOOL:
46790
0
    case JS_TAG_NULL:
46791
0
    concat_value:
46792
0
        return string_buffer_concat_value_free(jsc->b, val);
46793
0
    case JS_TAG_SHORT_BIG_INT:
46794
0
    case JS_TAG_BIG_INT:
46795
        /* reject big numbers: use toJSON method to override */
46796
0
        JS_ThrowTypeError(ctx, "Do not know how to serialize a BigInt");
46797
0
        goto exception;
46798
0
    default:
46799
0
        JS_FreeValue(ctx, val);
46800
0
        return 0;
46801
0
    }
46802
46803
0
exception:
46804
0
    JS_FreeValue(ctx, val);
46805
0
    JS_FreeValue(ctx, tab);
46806
0
    JS_FreeValue(ctx, sep);
46807
0
    JS_FreeValue(ctx, sep1);
46808
0
    JS_FreeValue(ctx, indent1);
46809
0
    JS_FreeValue(ctx, prop);
46810
0
    return -1;
46811
0
}
46812
46813
JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
46814
                         JSValueConst replacer, JSValueConst space0)
46815
0
{
46816
0
    StringBuffer b_s;
46817
0
    JSONStringifyContext jsc_s, *jsc = &jsc_s;
46818
0
    JSValue val, v, space, ret, wrapper;
46819
0
    int res;
46820
0
    int64_t i, j, n;
46821
46822
0
    jsc->replacer_func = JS_UNDEFINED;
46823
0
    jsc->stack = JS_UNDEFINED;
46824
0
    jsc->property_list = JS_UNDEFINED;
46825
0
    jsc->gap = JS_UNDEFINED;
46826
0
    jsc->b = &b_s;
46827
0
    jsc->empty = JS_AtomToString(ctx, JS_ATOM_empty_string);
46828
0
    ret = JS_UNDEFINED;
46829
0
    wrapper = JS_UNDEFINED;
46830
46831
0
    string_buffer_init(ctx, jsc->b, 0);
46832
0
    jsc->stack = JS_NewArray(ctx);
46833
0
    if (JS_IsException(jsc->stack))
46834
0
        goto exception;
46835
0
    if (JS_IsFunction(ctx, replacer)) {
46836
0
        jsc->replacer_func = replacer;
46837
0
    } else {
46838
0
        res = JS_IsArray(ctx, replacer);
46839
0
        if (res < 0)
46840
0
            goto exception;
46841
0
        if (res) {
46842
            /* XXX: enumeration is not fully correct */
46843
0
            jsc->property_list = JS_NewArray(ctx);
46844
0
            if (JS_IsException(jsc->property_list))
46845
0
                goto exception;
46846
0
            if (js_get_length64(ctx, &n, replacer))
46847
0
                goto exception;
46848
0
            for (i = j = 0; i < n; i++) {
46849
0
                JSValue present;
46850
0
                v = JS_GetPropertyInt64(ctx, replacer, i);
46851
0
                if (JS_IsException(v))
46852
0
                    goto exception;
46853
0
                if (JS_IsObject(v)) {
46854
0
                    JSObject *p = JS_VALUE_GET_OBJ(v);
46855
0
                    if (p->class_id == JS_CLASS_STRING ||
46856
0
                        p->class_id == JS_CLASS_NUMBER) {
46857
0
                        v = JS_ToStringFree(ctx, v);
46858
0
                        if (JS_IsException(v))
46859
0
                            goto exception;
46860
0
                    } else {
46861
0
                        JS_FreeValue(ctx, v);
46862
0
                        continue;
46863
0
                    }
46864
0
                } else if (JS_IsNumber(v)) {
46865
0
                    v = JS_ToStringFree(ctx, v);
46866
0
                    if (JS_IsException(v))
46867
0
                        goto exception;
46868
0
                } else if (!JS_IsString(v)) {
46869
0
                    JS_FreeValue(ctx, v);
46870
0
                    continue;
46871
0
                }
46872
0
                present = js_array_includes(ctx, jsc->property_list,
46873
0
                                            1, (JSValueConst *)&v);
46874
0
                if (JS_IsException(present)) {
46875
0
                    JS_FreeValue(ctx, v);
46876
0
                    goto exception;
46877
0
                }
46878
0
                if (!JS_ToBoolFree(ctx, present)) {
46879
0
                    JS_SetPropertyInt64(ctx, jsc->property_list, j++, v);
46880
0
                } else {
46881
0
                    JS_FreeValue(ctx, v);
46882
0
                }
46883
0
            }
46884
0
        }
46885
0
    }
46886
0
    space = JS_DupValue(ctx, space0);
46887
0
    if (JS_IsObject(space)) {
46888
0
        JSObject *p = JS_VALUE_GET_OBJ(space);
46889
0
        if (p->class_id == JS_CLASS_NUMBER) {
46890
0
            space = JS_ToNumberFree(ctx, space);
46891
0
        } else if (p->class_id == JS_CLASS_STRING) {
46892
0
            space = JS_ToStringFree(ctx, space);
46893
0
        }
46894
0
        if (JS_IsException(space)) {
46895
0
            JS_FreeValue(ctx, space);
46896
0
            goto exception;
46897
0
        }
46898
0
    }
46899
0
    if (JS_IsNumber(space)) {
46900
0
        int n;
46901
0
        if (JS_ToInt32Clamp(ctx, &n, space, 0, 10, 0))
46902
0
            goto exception;
46903
0
        jsc->gap = js_new_string8_len(ctx, "          ", n);
46904
0
    } else if (JS_IsString(space)) {
46905
0
        JSString *p = JS_VALUE_GET_STRING(space);
46906
0
        jsc->gap = js_sub_string(ctx, p, 0, min_int(p->len, 10));
46907
0
    } else {
46908
0
        jsc->gap = JS_DupValue(ctx, jsc->empty);
46909
0
    }
46910
0
    JS_FreeValue(ctx, space);
46911
0
    if (JS_IsException(jsc->gap))
46912
0
        goto exception;
46913
0
    wrapper = JS_NewObject(ctx);
46914
0
    if (JS_IsException(wrapper))
46915
0
        goto exception;
46916
0
    if (JS_DefinePropertyValue(ctx, wrapper, JS_ATOM_empty_string,
46917
0
                               JS_DupValue(ctx, obj), JS_PROP_C_W_E) < 0)
46918
0
        goto exception;
46919
0
    val = JS_DupValue(ctx, obj);
46920
46921
0
    val = js_json_check(ctx, jsc, wrapper, val, jsc->empty);
46922
0
    if (JS_IsException(val))
46923
0
        goto exception;
46924
0
    if (JS_IsUndefined(val)) {
46925
0
        ret = JS_UNDEFINED;
46926
0
        goto done1;
46927
0
    }
46928
0
    if (js_json_to_str(ctx, jsc, wrapper, val, jsc->empty))
46929
0
        goto exception;
46930
46931
0
    ret = string_buffer_end(jsc->b);
46932
0
    goto done;
46933
46934
0
exception:
46935
0
    ret = JS_EXCEPTION;
46936
0
done1:
46937
0
    string_buffer_free(jsc->b);
46938
0
done:
46939
0
    JS_FreeValue(ctx, wrapper);
46940
0
    JS_FreeValue(ctx, jsc->empty);
46941
0
    JS_FreeValue(ctx, jsc->gap);
46942
0
    JS_FreeValue(ctx, jsc->property_list);
46943
0
    JS_FreeValue(ctx, jsc->stack);
46944
0
    return ret;
46945
0
}
46946
46947
static JSValue js_json_stringify(JSContext *ctx, JSValueConst this_val,
46948
                                 int argc, JSValueConst *argv)
46949
0
{
46950
    // stringify(val, replacer, space)
46951
0
    return JS_JSONStringify(ctx, argv[0], argv[1], argv[2]);
46952
0
}
46953
46954
static const JSCFunctionListEntry js_json_funcs[] = {
46955
    JS_CFUNC_DEF("parse", 2, js_json_parse ),
46956
    JS_CFUNC_DEF("stringify", 3, js_json_stringify ),
46957
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "JSON", JS_PROP_CONFIGURABLE ),
46958
};
46959
46960
static const JSCFunctionListEntry js_json_obj[] = {
46961
    JS_OBJECT_DEF("JSON", js_json_funcs, countof(js_json_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
46962
};
46963
46964
void JS_AddIntrinsicJSON(JSContext *ctx)
46965
2
{
46966
    /* add JSON as autoinit object */
46967
2
    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_json_obj, countof(js_json_obj));
46968
2
}
46969
46970
/* Reflect */
46971
46972
static JSValue js_reflect_apply(JSContext *ctx, JSValueConst this_val,
46973
                                int argc, JSValueConst *argv)
46974
0
{
46975
0
    return js_function_apply(ctx, argv[0], max_int(0, argc - 1), argv + 1, 2);
46976
0
}
46977
46978
static JSValue js_reflect_construct(JSContext *ctx, JSValueConst this_val,
46979
                                    int argc, JSValueConst *argv)
46980
0
{
46981
0
    JSValueConst func, array_arg, new_target;
46982
0
    JSValue *tab, ret;
46983
0
    uint32_t len;
46984
46985
0
    func = argv[0];
46986
0
    array_arg = argv[1];
46987
0
    if (argc > 2) {
46988
0
        new_target = argv[2];
46989
0
        if (!JS_IsConstructor(ctx, new_target))
46990
0
            return JS_ThrowTypeError(ctx, "not a constructor");
46991
0
    } else {
46992
0
        new_target = func;
46993
0
    }
46994
0
    tab = build_arg_list(ctx, &len, array_arg);
46995
0
    if (!tab)
46996
0
        return JS_EXCEPTION;
46997
0
    ret = JS_CallConstructor2(ctx, func, new_target, len, (JSValueConst *)tab);
46998
0
    free_arg_list(ctx, tab, len);
46999
0
    return ret;
47000
0
}
47001
47002
static JSValue js_reflect_deleteProperty(JSContext *ctx, JSValueConst this_val,
47003
                                         int argc, JSValueConst *argv)
47004
0
{
47005
0
    JSValueConst obj;
47006
0
    JSAtom atom;
47007
0
    int ret;
47008
47009
0
    obj = argv[0];
47010
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
47011
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
47012
0
    atom = JS_ValueToAtom(ctx, argv[1]);
47013
0
    if (unlikely(atom == JS_ATOM_NULL))
47014
0
        return JS_EXCEPTION;
47015
0
    ret = JS_DeleteProperty(ctx, obj, atom, 0);
47016
0
    JS_FreeAtom(ctx, atom);
47017
0
    if (ret < 0)
47018
0
        return JS_EXCEPTION;
47019
0
    else
47020
0
        return JS_NewBool(ctx, ret);
47021
0
}
47022
47023
static JSValue js_reflect_get(JSContext *ctx, JSValueConst this_val,
47024
                              int argc, JSValueConst *argv)
47025
0
{
47026
0
    JSValueConst obj, prop, receiver;
47027
0
    JSAtom atom;
47028
0
    JSValue ret;
47029
47030
0
    obj = argv[0];
47031
0
    prop = argv[1];
47032
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
47033
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
47034
0
    if (argc > 2)
47035
0
        receiver = argv[2];
47036
0
    else
47037
0
        receiver = obj;
47038
0
    atom = JS_ValueToAtom(ctx, prop);
47039
0
    if (unlikely(atom == JS_ATOM_NULL))
47040
0
        return JS_EXCEPTION;
47041
0
    ret = JS_GetPropertyInternal(ctx, obj, atom, receiver, FALSE);
47042
0
    JS_FreeAtom(ctx, atom);
47043
0
    return ret;
47044
0
}
47045
47046
static JSValue js_reflect_has(JSContext *ctx, JSValueConst this_val,
47047
                              int argc, JSValueConst *argv)
47048
0
{
47049
0
    JSValueConst obj, prop;
47050
0
    JSAtom atom;
47051
0
    int ret;
47052
47053
0
    obj = argv[0];
47054
0
    prop = argv[1];
47055
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
47056
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
47057
0
    atom = JS_ValueToAtom(ctx, prop);
47058
0
    if (unlikely(atom == JS_ATOM_NULL))
47059
0
        return JS_EXCEPTION;
47060
0
    ret = JS_HasProperty(ctx, obj, atom);
47061
0
    JS_FreeAtom(ctx, atom);
47062
0
    if (ret < 0)
47063
0
        return JS_EXCEPTION;
47064
0
    else
47065
0
        return JS_NewBool(ctx, ret);
47066
0
}
47067
47068
static JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val,
47069
                              int argc, JSValueConst *argv)
47070
0
{
47071
0
    JSValueConst obj, prop, val, receiver;
47072
0
    int ret;
47073
0
    JSAtom atom;
47074
47075
0
    obj = argv[0];
47076
0
    prop = argv[1];
47077
0
    val = argv[2];
47078
0
    if (argc > 3)
47079
0
        receiver = argv[3];
47080
0
    else
47081
0
        receiver = obj;
47082
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
47083
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
47084
0
    atom = JS_ValueToAtom(ctx, prop);
47085
0
    if (unlikely(atom == JS_ATOM_NULL))
47086
0
        return JS_EXCEPTION;
47087
0
    ret = JS_SetPropertyInternal(ctx, obj, atom,
47088
0
                                 JS_DupValue(ctx, val), receiver, 0);
47089
0
    JS_FreeAtom(ctx, atom);
47090
0
    if (ret < 0)
47091
0
        return JS_EXCEPTION;
47092
0
    else
47093
0
        return JS_NewBool(ctx, ret);
47094
0
}
47095
47096
static JSValue js_reflect_setPrototypeOf(JSContext *ctx, JSValueConst this_val,
47097
                                         int argc, JSValueConst *argv)
47098
0
{
47099
0
    int ret;
47100
0
    ret = JS_SetPrototypeInternal(ctx, argv[0], argv[1], FALSE);
47101
0
    if (ret < 0)
47102
0
        return JS_EXCEPTION;
47103
0
    else
47104
0
        return JS_NewBool(ctx, ret);
47105
0
}
47106
47107
static JSValue js_reflect_ownKeys(JSContext *ctx, JSValueConst this_val,
47108
                                  int argc, JSValueConst *argv)
47109
0
{
47110
0
    if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT)
47111
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
47112
0
    return JS_GetOwnPropertyNames2(ctx, argv[0],
47113
0
                                   JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK,
47114
0
                                   JS_ITERATOR_KIND_KEY);
47115
0
}
47116
47117
static const JSCFunctionListEntry js_reflect_funcs[] = {
47118
    JS_CFUNC_DEF("apply", 3, js_reflect_apply ),
47119
    JS_CFUNC_DEF("construct", 2, js_reflect_construct ),
47120
    JS_CFUNC_MAGIC_DEF("defineProperty", 3, js_object_defineProperty, 1 ),
47121
    JS_CFUNC_DEF("deleteProperty", 2, js_reflect_deleteProperty ),
47122
    JS_CFUNC_DEF("get", 2, js_reflect_get ),
47123
    JS_CFUNC_MAGIC_DEF("getOwnPropertyDescriptor", 2, js_object_getOwnPropertyDescriptor, 1 ),
47124
    JS_CFUNC_MAGIC_DEF("getPrototypeOf", 1, js_object_getPrototypeOf, 1 ),
47125
    JS_CFUNC_DEF("has", 2, js_reflect_has ),
47126
    JS_CFUNC_MAGIC_DEF("isExtensible", 1, js_object_isExtensible, 1 ),
47127
    JS_CFUNC_DEF("ownKeys", 1, js_reflect_ownKeys ),
47128
    JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 1 ),
47129
    JS_CFUNC_DEF("set", 3, js_reflect_set ),
47130
    JS_CFUNC_DEF("setPrototypeOf", 2, js_reflect_setPrototypeOf ),
47131
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Reflect", JS_PROP_CONFIGURABLE ),
47132
};
47133
47134
static const JSCFunctionListEntry js_reflect_obj[] = {
47135
    JS_OBJECT_DEF("Reflect", js_reflect_funcs, countof(js_reflect_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
47136
};
47137
47138
/* Proxy */
47139
47140
static void js_proxy_finalizer(JSRuntime *rt, JSValue val)
47141
0
{
47142
0
    JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY);
47143
0
    if (s) {
47144
0
        JS_FreeValueRT(rt, s->target);
47145
0
        JS_FreeValueRT(rt, s->handler);
47146
0
        js_free_rt(rt, s);
47147
0
    }
47148
0
}
47149
47150
static void js_proxy_mark(JSRuntime *rt, JSValueConst val,
47151
                          JS_MarkFunc *mark_func)
47152
0
{
47153
0
    JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY);
47154
0
    if (s) {
47155
0
        JS_MarkValue(rt, s->target, mark_func);
47156
0
        JS_MarkValue(rt, s->handler, mark_func);
47157
0
    }
47158
0
}
47159
47160
static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx)
47161
0
{
47162
0
    return JS_ThrowTypeError(ctx, "revoked proxy");
47163
0
}
47164
47165
static JSProxyData *get_proxy_method(JSContext *ctx, JSValue *pmethod,
47166
                                     JSValueConst obj, JSAtom name)
47167
0
{
47168
0
    JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY);
47169
0
    JSValue method;
47170
47171
    /* safer to test recursion in all proxy methods */
47172
0
    if (js_check_stack_overflow(ctx->rt, 0)) {
47173
0
        JS_ThrowStackOverflow(ctx);
47174
0
        return NULL;
47175
0
    }
47176
47177
    /* 's' should never be NULL */
47178
0
    if (s->is_revoked) {
47179
0
        JS_ThrowTypeErrorRevokedProxy(ctx);
47180
0
        return NULL;
47181
0
    }
47182
0
    method = JS_GetProperty(ctx, s->handler, name);
47183
0
    if (JS_IsException(method))
47184
0
        return NULL;
47185
0
    if (JS_IsNull(method))
47186
0
        method = JS_UNDEFINED;
47187
0
    *pmethod = method;
47188
0
    return s;
47189
0
}
47190
47191
static JSValue js_proxy_get_prototype(JSContext *ctx, JSValueConst obj)
47192
0
{
47193
0
    JSProxyData *s;
47194
0
    JSValue method, ret, proto1;
47195
0
    int res;
47196
47197
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_getPrototypeOf);
47198
0
    if (!s)
47199
0
        return JS_EXCEPTION;
47200
0
    if (JS_IsUndefined(method))
47201
0
        return JS_GetPrototype(ctx, s->target);
47202
0
    ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
47203
0
    if (JS_IsException(ret))
47204
0
        return ret;
47205
0
    if (JS_VALUE_GET_TAG(ret) != JS_TAG_NULL &&
47206
0
        JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
47207
0
        goto fail;
47208
0
    }
47209
0
    res = JS_IsExtensible(ctx, s->target);
47210
0
    if (res < 0) {
47211
0
        JS_FreeValue(ctx, ret);
47212
0
        return JS_EXCEPTION;
47213
0
    }
47214
0
    if (!res) {
47215
        /* check invariant */
47216
0
        proto1 = JS_GetPrototype(ctx, s->target);
47217
0
        if (JS_IsException(proto1)) {
47218
0
            JS_FreeValue(ctx, ret);
47219
0
            return JS_EXCEPTION;
47220
0
        }
47221
0
        if (!js_same_value(ctx, proto1, ret)) {
47222
0
            JS_FreeValue(ctx, proto1);
47223
0
        fail:
47224
0
            JS_FreeValue(ctx, ret);
47225
0
            return JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
47226
0
        }
47227
0
        JS_FreeValue(ctx, proto1);
47228
0
    }
47229
0
    return ret;
47230
0
}
47231
47232
static int js_proxy_set_prototype(JSContext *ctx, JSValueConst obj,
47233
                                  JSValueConst proto_val)
47234
0
{
47235
0
    JSProxyData *s;
47236
0
    JSValue method, ret, proto1;
47237
0
    JSValueConst args[2];
47238
0
    BOOL res;
47239
0
    int res2;
47240
47241
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_setPrototypeOf);
47242
0
    if (!s)
47243
0
        return -1;
47244
0
    if (JS_IsUndefined(method))
47245
0
        return JS_SetPrototypeInternal(ctx, s->target, proto_val, FALSE);
47246
0
    args[0] = s->target;
47247
0
    args[1] = proto_val;
47248
0
    ret = JS_CallFree(ctx, method, s->handler, 2, args);
47249
0
    if (JS_IsException(ret))
47250
0
        return -1;
47251
0
    res = JS_ToBoolFree(ctx, ret);
47252
0
    if (!res)
47253
0
        return FALSE;
47254
0
    res2 = JS_IsExtensible(ctx, s->target);
47255
0
    if (res2 < 0)
47256
0
        return -1;
47257
0
    if (!res2) {
47258
0
        proto1 = JS_GetPrototype(ctx, s->target);
47259
0
        if (JS_IsException(proto1))
47260
0
            return -1;
47261
0
        if (!js_same_value(ctx, proto_val, proto1)) {
47262
0
            JS_FreeValue(ctx, proto1);
47263
0
            JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
47264
0
            return -1;
47265
0
        }
47266
0
        JS_FreeValue(ctx, proto1);
47267
0
    }
47268
0
    return TRUE;
47269
0
}
47270
47271
static int js_proxy_is_extensible(JSContext *ctx, JSValueConst obj)
47272
0
{
47273
0
    JSProxyData *s;
47274
0
    JSValue method, ret;
47275
0
    BOOL res;
47276
0
    int res2;
47277
47278
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_isExtensible);
47279
0
    if (!s)
47280
0
        return -1;
47281
0
    if (JS_IsUndefined(method))
47282
0
        return JS_IsExtensible(ctx, s->target);
47283
0
    ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
47284
0
    if (JS_IsException(ret))
47285
0
        return -1;
47286
0
    res = JS_ToBoolFree(ctx, ret);
47287
0
    res2 = JS_IsExtensible(ctx, s->target);
47288
0
    if (res2 < 0)
47289
0
        return res2;
47290
0
    if (res != res2) {
47291
0
        JS_ThrowTypeError(ctx, "proxy: inconsistent isExtensible");
47292
0
        return -1;
47293
0
    }
47294
0
    return res;
47295
0
}
47296
47297
static int js_proxy_prevent_extensions(JSContext *ctx, JSValueConst obj)
47298
0
{
47299
0
    JSProxyData *s;
47300
0
    JSValue method, ret;
47301
0
    BOOL res;
47302
0
    int res2;
47303
47304
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_preventExtensions);
47305
0
    if (!s)
47306
0
        return -1;
47307
0
    if (JS_IsUndefined(method))
47308
0
        return JS_PreventExtensions(ctx, s->target);
47309
0
    ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
47310
0
    if (JS_IsException(ret))
47311
0
        return -1;
47312
0
    res = JS_ToBoolFree(ctx, ret);
47313
0
    if (res) {
47314
0
        res2 = JS_IsExtensible(ctx, s->target);
47315
0
        if (res2 < 0)
47316
0
            return res2;
47317
0
        if (res2) {
47318
0
            JS_ThrowTypeError(ctx, "proxy: inconsistent preventExtensions");
47319
0
            return -1;
47320
0
        }
47321
0
    }
47322
0
    return res;
47323
0
}
47324
47325
static int js_proxy_has(JSContext *ctx, JSValueConst obj, JSAtom atom)
47326
0
{
47327
0
    JSProxyData *s;
47328
0
    JSValue method, ret1, atom_val;
47329
0
    int ret, res;
47330
0
    JSObject *p;
47331
0
    JSValueConst args[2];
47332
0
    BOOL res2;
47333
47334
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_has);
47335
0
    if (!s)
47336
0
        return -1;
47337
0
    if (JS_IsUndefined(method))
47338
0
        return JS_HasProperty(ctx, s->target, atom);
47339
0
    atom_val = JS_AtomToValue(ctx, atom);
47340
0
    if (JS_IsException(atom_val)) {
47341
0
        JS_FreeValue(ctx, method);
47342
0
        return -1;
47343
0
    }
47344
0
    args[0] = s->target;
47345
0
    args[1] = atom_val;
47346
0
    ret1 = JS_CallFree(ctx, method, s->handler, 2, args);
47347
0
    JS_FreeValue(ctx, atom_val);
47348
0
    if (JS_IsException(ret1))
47349
0
        return -1;
47350
0
    ret = JS_ToBoolFree(ctx, ret1);
47351
0
    if (!ret) {
47352
0
        JSPropertyDescriptor desc;
47353
0
        p = JS_VALUE_GET_OBJ(s->target);
47354
0
        res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);
47355
0
        if (res < 0)
47356
0
            return -1;
47357
0
        if (res) {
47358
0
            res2 = !(desc.flags & JS_PROP_CONFIGURABLE);
47359
0
            js_free_desc(ctx, &desc);
47360
0
            if (res2 || !p->extensible) {
47361
0
                JS_ThrowTypeError(ctx, "proxy: inconsistent has");
47362
0
                return -1;
47363
0
            }
47364
0
        }
47365
0
    }
47366
0
    return ret;
47367
0
}
47368
47369
static JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom,
47370
                            JSValueConst receiver)
47371
0
{
47372
0
    JSProxyData *s;
47373
0
    JSValue method, ret, atom_val;
47374
0
    int res;
47375
0
    JSValueConst args[3];
47376
0
    JSPropertyDescriptor desc;
47377
47378
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_get);
47379
0
    if (!s)
47380
0
        return JS_EXCEPTION;
47381
    /* Note: recursion is possible thru the prototype of s->target */
47382
0
    if (JS_IsUndefined(method))
47383
0
        return JS_GetPropertyInternal(ctx, s->target, atom, receiver, FALSE);
47384
0
    atom_val = JS_AtomToValue(ctx, atom);
47385
0
    if (JS_IsException(atom_val)) {
47386
0
        JS_FreeValue(ctx, method);
47387
0
        return JS_EXCEPTION;
47388
0
    }
47389
0
    args[0] = s->target;
47390
0
    args[1] = atom_val;
47391
0
    args[2] = receiver;
47392
0
    ret = JS_CallFree(ctx, method, s->handler, 3, args);
47393
0
    JS_FreeValue(ctx, atom_val);
47394
0
    if (JS_IsException(ret))
47395
0
        return JS_EXCEPTION;
47396
0
    res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
47397
0
    if (res < 0) {
47398
0
        JS_FreeValue(ctx, ret);
47399
0
        return JS_EXCEPTION;
47400
0
    }
47401
0
    if (res) {
47402
0
        if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {
47403
0
            if (!js_same_value(ctx, desc.value, ret)) {
47404
0
                goto fail;
47405
0
            }
47406
0
        } else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET) {
47407
0
            if (JS_IsUndefined(desc.getter) && !JS_IsUndefined(ret)) {
47408
0
            fail:
47409
0
                js_free_desc(ctx, &desc);
47410
0
                JS_FreeValue(ctx, ret);
47411
0
                return JS_ThrowTypeError(ctx, "proxy: inconsistent get");
47412
0
            }
47413
0
        }
47414
0
        js_free_desc(ctx, &desc);
47415
0
    }
47416
0
    return ret;
47417
0
}
47418
47419
static int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom,
47420
                        JSValueConst value, JSValueConst receiver, int flags)
47421
0
{
47422
0
    JSProxyData *s;
47423
0
    JSValue method, ret1, atom_val;
47424
0
    int ret, res;
47425
0
    JSValueConst args[4];
47426
47427
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_set);
47428
0
    if (!s)
47429
0
        return -1;
47430
0
    if (JS_IsUndefined(method)) {
47431
0
        return JS_SetPropertyInternal(ctx, s->target, atom,
47432
0
                                      JS_DupValue(ctx, value), receiver,
47433
0
                                      flags);
47434
0
    }
47435
0
    atom_val = JS_AtomToValue(ctx, atom);
47436
0
    if (JS_IsException(atom_val)) {
47437
0
        JS_FreeValue(ctx, method);
47438
0
        return -1;
47439
0
    }
47440
0
    args[0] = s->target;
47441
0
    args[1] = atom_val;
47442
0
    args[2] = value;
47443
0
    args[3] = receiver;
47444
0
    ret1 = JS_CallFree(ctx, method, s->handler, 4, args);
47445
0
    JS_FreeValue(ctx, atom_val);
47446
0
    if (JS_IsException(ret1))
47447
0
        return -1;
47448
0
    ret = JS_ToBoolFree(ctx, ret1);
47449
0
    if (ret) {
47450
0
        JSPropertyDescriptor desc;
47451
0
        res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
47452
0
        if (res < 0)
47453
0
            return -1;
47454
0
        if (res) {
47455
0
            if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {
47456
0
                if (!js_same_value(ctx, desc.value, value)) {
47457
0
                    goto fail;
47458
0
                }
47459
0
            } else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET && JS_IsUndefined(desc.setter)) {
47460
0
                fail:
47461
0
                    js_free_desc(ctx, &desc);
47462
0
                    JS_ThrowTypeError(ctx, "proxy: inconsistent set");
47463
0
                    return -1;
47464
0
            }
47465
0
            js_free_desc(ctx, &desc);
47466
0
        }
47467
0
    } else {
47468
0
        if ((flags & JS_PROP_THROW) ||
47469
0
            ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
47470
0
            JS_ThrowTypeError(ctx, "proxy: cannot set property");
47471
0
            return -1;
47472
0
        }
47473
0
    }
47474
0
    return ret;
47475
0
}
47476
47477
static JSValue js_create_desc(JSContext *ctx, JSValueConst val,
47478
                              JSValueConst getter, JSValueConst setter,
47479
                              int flags)
47480
0
{
47481
0
    JSValue ret;
47482
0
    ret = JS_NewObject(ctx);
47483
0
    if (JS_IsException(ret))
47484
0
        return ret;
47485
0
    if (flags & JS_PROP_HAS_GET) {
47486
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, getter),
47487
0
                               JS_PROP_C_W_E);
47488
0
    }
47489
0
    if (flags & JS_PROP_HAS_SET) {
47490
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, setter),
47491
0
                               JS_PROP_C_W_E);
47492
0
    }
47493
0
    if (flags & JS_PROP_HAS_VALUE) {
47494
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, val),
47495
0
                               JS_PROP_C_W_E);
47496
0
    }
47497
0
    if (flags & JS_PROP_HAS_WRITABLE) {
47498
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,
47499
0
                               JS_NewBool(ctx, flags & JS_PROP_WRITABLE),
47500
0
                               JS_PROP_C_W_E);
47501
0
    }
47502
0
    if (flags & JS_PROP_HAS_ENUMERABLE) {
47503
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,
47504
0
                               JS_NewBool(ctx, flags & JS_PROP_ENUMERABLE),
47505
0
                               JS_PROP_C_W_E);
47506
0
    }
47507
0
    if (flags & JS_PROP_HAS_CONFIGURABLE) {
47508
0
        JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,
47509
0
                               JS_NewBool(ctx, flags & JS_PROP_CONFIGURABLE),
47510
0
                               JS_PROP_C_W_E);
47511
0
    }
47512
0
    return ret;
47513
0
}
47514
47515
static int js_proxy_get_own_property(JSContext *ctx, JSPropertyDescriptor *pdesc,
47516
                                     JSValueConst obj, JSAtom prop)
47517
0
{
47518
0
    JSProxyData *s;
47519
0
    JSValue method, trap_result_obj, prop_val;
47520
0
    int res, target_desc_ret, ret;
47521
0
    JSObject *p;
47522
0
    JSValueConst args[2];
47523
0
    JSPropertyDescriptor result_desc, target_desc;
47524
47525
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_getOwnPropertyDescriptor);
47526
0
    if (!s)
47527
0
        return -1;
47528
0
    p = JS_VALUE_GET_OBJ(s->target);
47529
0
    if (JS_IsUndefined(method)) {
47530
0
        return JS_GetOwnPropertyInternal(ctx, pdesc, p, prop);
47531
0
    }
47532
0
    prop_val = JS_AtomToValue(ctx, prop);
47533
0
    if (JS_IsException(prop_val)) {
47534
0
        JS_FreeValue(ctx, method);
47535
0
        return -1;
47536
0
    }
47537
0
    args[0] = s->target;
47538
0
    args[1] = prop_val;
47539
0
    trap_result_obj = JS_CallFree(ctx, method, s->handler, 2, args);
47540
0
    JS_FreeValue(ctx, prop_val);
47541
0
    if (JS_IsException(trap_result_obj))
47542
0
        return -1;
47543
0
    if (!JS_IsObject(trap_result_obj) && !JS_IsUndefined(trap_result_obj)) {
47544
0
        JS_FreeValue(ctx, trap_result_obj);
47545
0
        goto fail;
47546
0
    }
47547
0
    target_desc_ret = JS_GetOwnPropertyInternal(ctx, &target_desc, p, prop);
47548
0
    if (target_desc_ret < 0) {
47549
0
        JS_FreeValue(ctx, trap_result_obj);
47550
0
        return -1;
47551
0
    }
47552
0
    if (target_desc_ret)
47553
0
        js_free_desc(ctx, &target_desc);
47554
0
    if (JS_IsUndefined(trap_result_obj)) {
47555
0
        if (target_desc_ret) {
47556
0
            if (!(target_desc.flags & JS_PROP_CONFIGURABLE) || !p->extensible)
47557
0
                goto fail;
47558
0
        }
47559
0
        ret = FALSE;
47560
0
    } else {
47561
0
        int flags1, extensible_target;
47562
0
        extensible_target = JS_IsExtensible(ctx, s->target);
47563
0
        if (extensible_target < 0) {
47564
0
            JS_FreeValue(ctx, trap_result_obj);
47565
0
            return -1;
47566
0
        }
47567
0
        res = js_obj_to_desc(ctx, &result_desc, trap_result_obj);
47568
0
        JS_FreeValue(ctx, trap_result_obj);
47569
0
        if (res < 0)
47570
0
            return -1;
47571
47572
        /* convert the result_desc.flags to property flags */
47573
0
        if (result_desc.flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
47574
0
            result_desc.flags |= JS_PROP_GETSET;
47575
0
        } else {
47576
0
            result_desc.flags |= JS_PROP_NORMAL;
47577
0
        }
47578
0
        result_desc.flags &= (JS_PROP_C_W_E | JS_PROP_TMASK);
47579
        
47580
0
        if (target_desc_ret) {
47581
            /* convert result_desc.flags to defineProperty flags */
47582
0
            flags1 = result_desc.flags | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE;
47583
0
            if (result_desc.flags & JS_PROP_GETSET)
47584
0
                flags1 |= JS_PROP_HAS_GET | JS_PROP_HAS_SET;
47585
0
            else
47586
0
                flags1 |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE;
47587
            /* XXX: not complete check: need to compare value &
47588
               getter/setter as in defineproperty */
47589
0
            if (!check_define_prop_flags(target_desc.flags, flags1))
47590
0
                goto fail1;
47591
0
        } else {
47592
0
            if (!extensible_target)
47593
0
                goto fail1;
47594
0
        }
47595
0
        if (!(result_desc.flags & JS_PROP_CONFIGURABLE)) {
47596
0
            if (!target_desc_ret || (target_desc.flags & JS_PROP_CONFIGURABLE))
47597
0
                goto fail1;
47598
0
            if ((result_desc.flags &
47599
0
                 (JS_PROP_GETSET | JS_PROP_WRITABLE)) == 0 &&
47600
0
                target_desc_ret &&
47601
0
                (target_desc.flags & JS_PROP_WRITABLE) != 0) {
47602
                /* proxy-missing-checks */
47603
0
            fail1:
47604
0
                js_free_desc(ctx, &result_desc);
47605
0
            fail:
47606
0
                JS_ThrowTypeError(ctx, "proxy: inconsistent getOwnPropertyDescriptor");
47607
0
                return -1;
47608
0
            }
47609
0
        }
47610
0
        ret = TRUE;
47611
0
        if (pdesc) {
47612
0
            *pdesc = result_desc;
47613
0
        } else {
47614
0
            js_free_desc(ctx, &result_desc);
47615
0
        }
47616
0
    }
47617
0
    return ret;
47618
0
}
47619
47620
static int js_proxy_define_own_property(JSContext *ctx, JSValueConst obj,
47621
                                        JSAtom prop, JSValueConst val,
47622
                                        JSValueConst getter, JSValueConst setter,
47623
                                        int flags)
47624
0
{
47625
0
    JSProxyData *s;
47626
0
    JSValue method, ret1, prop_val, desc_val;
47627
0
    int res, ret;
47628
0
    JSObject *p;
47629
0
    JSValueConst args[3];
47630
0
    JSPropertyDescriptor desc;
47631
0
    BOOL setting_not_configurable;
47632
47633
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_defineProperty);
47634
0
    if (!s)
47635
0
        return -1;
47636
0
    if (JS_IsUndefined(method)) {
47637
0
        return JS_DefineProperty(ctx, s->target, prop, val, getter, setter, flags);
47638
0
    }
47639
0
    prop_val = JS_AtomToValue(ctx, prop);
47640
0
    if (JS_IsException(prop_val)) {
47641
0
        JS_FreeValue(ctx, method);
47642
0
        return -1;
47643
0
    }
47644
0
    desc_val = js_create_desc(ctx, val, getter, setter, flags);
47645
0
    if (JS_IsException(desc_val)) {
47646
0
        JS_FreeValue(ctx, prop_val);
47647
0
        JS_FreeValue(ctx, method);
47648
0
        return -1;
47649
0
    }
47650
0
    args[0] = s->target;
47651
0
    args[1] = prop_val;
47652
0
    args[2] = desc_val;
47653
0
    ret1 = JS_CallFree(ctx, method, s->handler, 3, args);
47654
0
    JS_FreeValue(ctx, prop_val);
47655
0
    JS_FreeValue(ctx, desc_val);
47656
0
    if (JS_IsException(ret1))
47657
0
        return -1;
47658
0
    ret = JS_ToBoolFree(ctx, ret1);
47659
0
    if (!ret) {
47660
0
        if (flags & JS_PROP_THROW) {
47661
0
            JS_ThrowTypeError(ctx, "proxy: defineProperty exception");
47662
0
            return -1;
47663
0
        } else {
47664
0
            return 0;
47665
0
        }
47666
0
    }
47667
0
    p = JS_VALUE_GET_OBJ(s->target);
47668
0
    res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
47669
0
    if (res < 0)
47670
0
        return -1;
47671
0
    setting_not_configurable = ((flags & (JS_PROP_HAS_CONFIGURABLE |
47672
0
                                          JS_PROP_CONFIGURABLE)) ==
47673
0
                                JS_PROP_HAS_CONFIGURABLE);
47674
0
    if (!res) {
47675
0
        if (!p->extensible || setting_not_configurable)
47676
0
            goto fail;
47677
0
    } else {
47678
0
        if (!check_define_prop_flags(desc.flags, flags))
47679
0
            goto fail1;
47680
        /* do the missing check from check_define_prop_flags() */
47681
0
        if (!(desc.flags & JS_PROP_CONFIGURABLE)) {
47682
0
            if ((desc.flags & JS_PROP_TMASK) == JS_PROP_GETSET) {
47683
0
                if ((flags & JS_PROP_HAS_GET) &&
47684
0
                    !js_same_value(ctx, getter, desc.getter)) {
47685
0
                    goto fail1;
47686
0
                }
47687
0
                if ((flags & JS_PROP_HAS_SET) &&
47688
0
                    !js_same_value(ctx, setter, desc.setter)) {
47689
0
                    goto fail1;
47690
0
                }
47691
0
            } else if (!(desc.flags & JS_PROP_WRITABLE)) {
47692
0
                if ((flags & JS_PROP_HAS_VALUE) &&
47693
0
                    !js_same_value(ctx, val, desc.value)) {
47694
0
                    goto fail1;
47695
0
                }
47696
0
            }
47697
0
        }
47698
47699
        /* additional checks */
47700
0
        if ((desc.flags & JS_PROP_CONFIGURABLE) && setting_not_configurable)
47701
0
            goto fail1;
47702
47703
0
        if ((desc.flags & JS_PROP_TMASK) != JS_PROP_GETSET &&
47704
0
            (desc.flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == JS_PROP_WRITABLE &&
47705
0
            (flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) {
47706
0
        fail1:
47707
0
            js_free_desc(ctx, &desc);
47708
0
        fail:
47709
0
            JS_ThrowTypeError(ctx, "proxy: inconsistent defineProperty");
47710
0
            return -1;
47711
0
        }
47712
0
        js_free_desc(ctx, &desc);
47713
0
    }
47714
0
    return 1;
47715
0
}
47716
47717
static int js_proxy_delete_property(JSContext *ctx, JSValueConst obj,
47718
                                    JSAtom atom)
47719
0
{
47720
0
    JSProxyData *s;
47721
0
    JSValue method, ret, atom_val;
47722
0
    int res, res2, is_extensible;
47723
0
    JSValueConst args[2];
47724
47725
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_deleteProperty);
47726
0
    if (!s)
47727
0
        return -1;
47728
0
    if (JS_IsUndefined(method)) {
47729
0
        return JS_DeleteProperty(ctx, s->target, atom, 0);
47730
0
    }
47731
0
    atom_val = JS_AtomToValue(ctx, atom);;
47732
0
    if (JS_IsException(atom_val)) {
47733
0
        JS_FreeValue(ctx, method);
47734
0
        return -1;
47735
0
    }
47736
0
    args[0] = s->target;
47737
0
    args[1] = atom_val;
47738
0
    ret = JS_CallFree(ctx, method, s->handler, 2, args);
47739
0
    JS_FreeValue(ctx, atom_val);
47740
0
    if (JS_IsException(ret))
47741
0
        return -1;
47742
0
    res = JS_ToBoolFree(ctx, ret);
47743
0
    if (res) {
47744
0
        JSPropertyDescriptor desc;
47745
0
        res2 = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);
47746
0
        if (res2 < 0)
47747
0
            return -1;
47748
0
        if (res2) {
47749
0
            if (!(desc.flags & JS_PROP_CONFIGURABLE))
47750
0
                goto fail;
47751
0
            is_extensible = JS_IsExtensible(ctx, s->target);
47752
0
            if (is_extensible < 0)
47753
0
                goto fail1;
47754
0
            if (!is_extensible) {
47755
                /* proxy-missing-checks */
47756
0
            fail:
47757
0
                JS_ThrowTypeError(ctx, "proxy: inconsistent deleteProperty");
47758
0
            fail1:
47759
0
                js_free_desc(ctx, &desc);
47760
0
                return -1;
47761
0
            }
47762
0
            js_free_desc(ctx, &desc);
47763
0
        }
47764
0
    }
47765
0
    return res;
47766
0
}
47767
47768
/* return the index of the property or -1 if not found */
47769
static int find_prop_key(const JSPropertyEnum *tab, int n, JSAtom atom)
47770
0
{
47771
0
    int i;
47772
0
    for(i = 0; i < n; i++) {
47773
0
        if (tab[i].atom == atom)
47774
0
            return i;
47775
0
    }
47776
0
    return -1;
47777
0
}
47778
47779
static int js_proxy_get_own_property_names(JSContext *ctx,
47780
                                           JSPropertyEnum **ptab,
47781
                                           uint32_t *plen,
47782
                                           JSValueConst obj)
47783
0
{
47784
0
    JSProxyData *s;
47785
0
    JSValue method, prop_array, val;
47786
0
    uint32_t len, i, len2;
47787
0
    JSPropertyEnum *tab, *tab2;
47788
0
    JSAtom atom;
47789
0
    JSPropertyDescriptor desc;
47790
0
    int res, is_extensible, idx;
47791
47792
0
    s = get_proxy_method(ctx, &method, obj, JS_ATOM_ownKeys);
47793
0
    if (!s)
47794
0
        return -1;
47795
0
    if (JS_IsUndefined(method)) {
47796
0
        return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen,
47797
0
                                      JS_VALUE_GET_OBJ(s->target),
47798
0
                                      JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK);
47799
0
    }
47800
0
    prop_array = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);
47801
0
    if (JS_IsException(prop_array))
47802
0
        return -1;
47803
0
    tab = NULL;
47804
0
    len = 0;
47805
0
    tab2 = NULL;
47806
0
    len2 = 0;
47807
0
    if (js_get_length32(ctx, &len, prop_array))
47808
0
        goto fail;
47809
0
    if (len > 0) {
47810
0
        tab = js_mallocz(ctx, sizeof(tab[0]) * len);
47811
0
        if (!tab)
47812
0
            goto fail;
47813
0
    }
47814
0
    for(i = 0; i < len; i++) {
47815
0
        val = JS_GetPropertyUint32(ctx, prop_array, i);
47816
0
        if (JS_IsException(val))
47817
0
            goto fail;
47818
0
        if (!JS_IsString(val) && !JS_IsSymbol(val)) {
47819
0
            JS_FreeValue(ctx, val);
47820
0
            JS_ThrowTypeError(ctx, "proxy: properties must be strings or symbols");
47821
0
            goto fail;
47822
0
        }
47823
0
        atom = JS_ValueToAtom(ctx, val);
47824
0
        JS_FreeValue(ctx, val);
47825
0
        if (atom == JS_ATOM_NULL)
47826
0
            goto fail;
47827
0
        tab[i].atom = atom;
47828
0
        tab[i].is_enumerable = FALSE; /* XXX: redundant? */
47829
0
    }
47830
47831
    /* check duplicate properties (XXX: inefficient, could store the
47832
     * properties an a temporary object to use the hash) */
47833
0
    for(i = 1; i < len; i++) {
47834
0
        if (find_prop_key(tab, i, tab[i].atom) >= 0) {
47835
0
            JS_ThrowTypeError(ctx, "proxy: duplicate property");
47836
0
            goto fail;
47837
0
        }
47838
0
    }
47839
47840
0
    is_extensible = JS_IsExtensible(ctx, s->target);
47841
0
    if (is_extensible < 0)
47842
0
        goto fail;
47843
47844
    /* check if there are non configurable properties */
47845
0
    if (s->is_revoked) {
47846
0
        JS_ThrowTypeErrorRevokedProxy(ctx);
47847
0
        goto fail;
47848
0
    }
47849
0
    if (JS_GetOwnPropertyNamesInternal(ctx, &tab2, &len2, JS_VALUE_GET_OBJ(s->target),
47850
0
                               JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK))
47851
0
        goto fail;
47852
0
    for(i = 0; i < len2; i++) {
47853
0
        if (s->is_revoked) {
47854
0
            JS_ThrowTypeErrorRevokedProxy(ctx);
47855
0
            goto fail;
47856
0
        }
47857
0
        res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target),
47858
0
                                tab2[i].atom);
47859
0
        if (res < 0)
47860
0
            goto fail;
47861
0
        if (res) {  /* safety, property should be found */
47862
0
            js_free_desc(ctx, &desc);
47863
0
            if (!(desc.flags & JS_PROP_CONFIGURABLE) || !is_extensible) {
47864
0
                idx = find_prop_key(tab, len, tab2[i].atom);
47865
0
                if (idx < 0) {
47866
0
                    JS_ThrowTypeError(ctx, "proxy: target property must be present in proxy ownKeys");
47867
0
                    goto fail;
47868
0
                }
47869
                /* mark the property as found */
47870
0
                if (!is_extensible)
47871
0
                    tab[idx].is_enumerable = TRUE;
47872
0
            }
47873
0
        }
47874
0
    }
47875
0
    if (!is_extensible) {
47876
        /* check that all property in 'tab' were checked */
47877
0
        for(i = 0; i < len; i++) {
47878
0
            if (!tab[i].is_enumerable) {
47879
0
                JS_ThrowTypeError(ctx, "proxy: property not present in target were returned by non extensible proxy");
47880
0
                goto fail;
47881
0
            }
47882
0
        }
47883
0
    }
47884
47885
0
    JS_FreePropertyEnum(ctx, tab2, len2);
47886
0
    JS_FreeValue(ctx, prop_array);
47887
0
    *ptab = tab;
47888
0
    *plen = len;
47889
0
    return 0;
47890
0
 fail:
47891
0
    JS_FreePropertyEnum(ctx, tab2, len2);
47892
0
    JS_FreePropertyEnum(ctx, tab, len);
47893
0
    JS_FreeValue(ctx, prop_array);
47894
0
    return -1;
47895
0
}
47896
47897
static JSValue js_proxy_call_constructor(JSContext *ctx, JSValueConst func_obj,
47898
                                         JSValueConst new_target,
47899
                                         int argc, JSValueConst *argv)
47900
0
{
47901
0
    JSProxyData *s;
47902
0
    JSValue method, arg_array, ret;
47903
0
    JSValueConst args[3];
47904
47905
0
    s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_construct);
47906
0
    if (!s)
47907
0
        return JS_EXCEPTION;
47908
0
    if (!JS_IsConstructor(ctx, s->target))
47909
0
        return JS_ThrowTypeError(ctx, "not a constructor");
47910
0
    if (JS_IsUndefined(method))
47911
0
        return JS_CallConstructor2(ctx, s->target, new_target, argc, argv);
47912
0
    arg_array = js_create_array(ctx, argc, argv);
47913
0
    if (JS_IsException(arg_array)) {
47914
0
        ret = JS_EXCEPTION;
47915
0
        goto fail;
47916
0
    }
47917
0
    args[0] = s->target;
47918
0
    args[1] = arg_array;
47919
0
    args[2] = new_target;
47920
0
    ret = JS_Call(ctx, method, s->handler, 3, args);
47921
0
    if (!JS_IsException(ret) && JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {
47922
0
        JS_FreeValue(ctx, ret);
47923
0
        ret = JS_ThrowTypeErrorNotAnObject(ctx);
47924
0
    }
47925
0
 fail:
47926
0
    JS_FreeValue(ctx, method);
47927
0
    JS_FreeValue(ctx, arg_array);
47928
0
    return ret;
47929
0
}
47930
47931
static JSValue js_proxy_call(JSContext *ctx, JSValueConst func_obj,
47932
                             JSValueConst this_obj,
47933
                             int argc, JSValueConst *argv, int flags)
47934
0
{
47935
0
    JSProxyData *s;
47936
0
    JSValue method, arg_array, ret;
47937
0
    JSValueConst args[3];
47938
47939
0
    if (flags & JS_CALL_FLAG_CONSTRUCTOR)
47940
0
        return js_proxy_call_constructor(ctx, func_obj, this_obj, argc, argv);
47941
47942
0
    s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_apply);
47943
0
    if (!s)
47944
0
        return JS_EXCEPTION;
47945
0
    if (!s->is_func) {
47946
0
        JS_FreeValue(ctx, method);
47947
0
        return JS_ThrowTypeError(ctx, "not a function");
47948
0
    }
47949
0
    if (JS_IsUndefined(method))
47950
0
        return JS_Call(ctx, s->target, this_obj, argc, argv);
47951
0
    arg_array = js_create_array(ctx, argc, argv);
47952
0
    if (JS_IsException(arg_array)) {
47953
0
        ret = JS_EXCEPTION;
47954
0
        goto fail;
47955
0
    }
47956
0
    args[0] = s->target;
47957
0
    args[1] = this_obj;
47958
0
    args[2] = arg_array;
47959
0
    ret = JS_Call(ctx, method, s->handler, 3, args);
47960
0
 fail:
47961
0
    JS_FreeValue(ctx, method);
47962
0
    JS_FreeValue(ctx, arg_array);
47963
0
    return ret;
47964
0
}
47965
47966
/* `js_resolve_proxy`: resolve the proxy chain
47967
   `*pval` is updated with to ultimate proxy target
47968
   `throw_exception` controls whether exceptions are thown or not
47969
   - return -1 in case of error
47970
   - otherwise return 0
47971
 */
47972
0
static int js_resolve_proxy(JSContext *ctx, JSValueConst *pval, BOOL throw_exception) {
47973
0
    int depth = 0;
47974
0
    JSObject *p;
47975
0
    JSProxyData *s;
47976
47977
0
    while (JS_VALUE_GET_TAG(*pval) == JS_TAG_OBJECT) {
47978
0
        p = JS_VALUE_GET_OBJ(*pval);
47979
0
        if (p->class_id != JS_CLASS_PROXY)
47980
0
            break;
47981
0
        if (depth++ > 1000) {
47982
0
            if (throw_exception)
47983
0
                JS_ThrowStackOverflow(ctx);
47984
0
            return -1;
47985
0
        }
47986
0
        s = p->u.opaque;
47987
0
        if (s->is_revoked) {
47988
0
            if (throw_exception)
47989
0
                JS_ThrowTypeErrorRevokedProxy(ctx);
47990
0
            return -1;
47991
0
        }
47992
0
        *pval = s->target;
47993
0
    }
47994
0
    return 0;
47995
0
}
47996
47997
static const JSClassExoticMethods js_proxy_exotic_methods = {
47998
    .get_own_property = js_proxy_get_own_property,
47999
    .define_own_property = js_proxy_define_own_property,
48000
    .delete_property = js_proxy_delete_property,
48001
    .get_own_property_names = js_proxy_get_own_property_names,
48002
    .has_property = js_proxy_has,
48003
    .get_property = js_proxy_get,
48004
    .set_property = js_proxy_set,
48005
    .get_prototype = js_proxy_get_prototype,
48006
    .set_prototype = js_proxy_set_prototype,
48007
    .is_extensible = js_proxy_is_extensible,
48008
    .prevent_extensions = js_proxy_prevent_extensions,
48009
};
48010
48011
static JSValue js_proxy_constructor(JSContext *ctx, JSValueConst this_val,
48012
                                    int argc, JSValueConst *argv)
48013
0
{
48014
0
    JSValueConst target, handler;
48015
0
    JSValue obj;
48016
0
    JSProxyData *s;
48017
48018
0
    target = argv[0];
48019
0
    handler = argv[1];
48020
0
    if (JS_VALUE_GET_TAG(target) != JS_TAG_OBJECT ||
48021
0
        JS_VALUE_GET_TAG(handler) != JS_TAG_OBJECT)
48022
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
48023
48024
0
    obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_PROXY);
48025
0
    if (JS_IsException(obj))
48026
0
        return obj;
48027
0
    s = js_malloc(ctx, sizeof(JSProxyData));
48028
0
    if (!s) {
48029
0
        JS_FreeValue(ctx, obj);
48030
0
        return JS_EXCEPTION;
48031
0
    }
48032
0
    s->target = JS_DupValue(ctx, target);
48033
0
    s->handler = JS_DupValue(ctx, handler);
48034
0
    s->is_func = JS_IsFunction(ctx, target);
48035
0
    s->is_revoked = FALSE;
48036
0
    JS_SetOpaque(obj, s);
48037
0
    JS_SetConstructorBit(ctx, obj, JS_IsConstructor(ctx, target));
48038
0
    return obj;
48039
0
}
48040
48041
static JSValue js_proxy_revoke(JSContext *ctx, JSValueConst this_val,
48042
                               int argc, JSValueConst *argv, int magic,
48043
                               JSValue *func_data)
48044
0
{
48045
0
    JSProxyData *s = JS_GetOpaque(func_data[0], JS_CLASS_PROXY);
48046
0
    if (s) {
48047
        /* We do not free the handler and target in case they are
48048
           referenced as constants in the C call stack */
48049
0
        s->is_revoked = TRUE;
48050
0
        JS_FreeValue(ctx, func_data[0]);
48051
0
        func_data[0] = JS_NULL;
48052
0
    }
48053
0
    return JS_UNDEFINED;
48054
0
}
48055
48056
static JSValue js_proxy_revoke_constructor(JSContext *ctx,
48057
                                           JSValueConst proxy_obj)
48058
0
{
48059
0
    return JS_NewCFunctionData(ctx, js_proxy_revoke, 0, 0, 1, &proxy_obj);
48060
0
}
48061
48062
static JSValue js_proxy_revocable(JSContext *ctx, JSValueConst this_val,
48063
                                 int argc, JSValueConst *argv)
48064
0
{
48065
0
    JSValue proxy_obj, revoke_obj = JS_UNDEFINED, obj;
48066
48067
0
    proxy_obj = js_proxy_constructor(ctx, JS_UNDEFINED, argc, argv);
48068
0
    if (JS_IsException(proxy_obj))
48069
0
        goto fail;
48070
0
    revoke_obj = js_proxy_revoke_constructor(ctx, proxy_obj);
48071
0
    if (JS_IsException(revoke_obj))
48072
0
        goto fail;
48073
0
    obj = JS_NewObject(ctx);
48074
0
    if (JS_IsException(obj))
48075
0
        goto fail;
48076
    // XXX: exceptions?
48077
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_proxy, proxy_obj, JS_PROP_C_W_E);
48078
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_revoke, revoke_obj, JS_PROP_C_W_E);
48079
0
    return obj;
48080
0
 fail:
48081
0
    JS_FreeValue(ctx, proxy_obj);
48082
0
    JS_FreeValue(ctx, revoke_obj);
48083
0
    return JS_EXCEPTION;
48084
0
}
48085
48086
static const JSCFunctionListEntry js_proxy_funcs[] = {
48087
    JS_CFUNC_DEF("revocable", 2, js_proxy_revocable ),
48088
};
48089
48090
static const JSClassShortDef js_proxy_class_def[] = {
48091
    { JS_ATOM_Object, js_proxy_finalizer, js_proxy_mark }, /* JS_CLASS_PROXY */
48092
};
48093
48094
void JS_AddIntrinsicProxy(JSContext *ctx)
48095
2
{
48096
2
    JSRuntime *rt = ctx->rt;
48097
2
    JSValue obj1;
48098
48099
2
    if (!JS_IsRegisteredClass(rt, JS_CLASS_PROXY)) {
48100
2
        init_class_range(rt, js_proxy_class_def, JS_CLASS_PROXY,
48101
2
                         countof(js_proxy_class_def));
48102
2
        rt->class_array[JS_CLASS_PROXY].exotic = &js_proxy_exotic_methods;
48103
2
        rt->class_array[JS_CLASS_PROXY].call = js_proxy_call;
48104
2
    }
48105
48106
2
    obj1 = JS_NewCFunction2(ctx, js_proxy_constructor, "Proxy", 2,
48107
2
                            JS_CFUNC_constructor, 0);
48108
2
    JS_SetConstructorBit(ctx, obj1, TRUE);
48109
2
    JS_SetPropertyFunctionList(ctx, obj1, js_proxy_funcs,
48110
2
                               countof(js_proxy_funcs));
48111
2
    JS_DefinePropertyValueStr(ctx, ctx->global_obj, "Proxy",
48112
2
                              obj1, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
48113
2
}
48114
48115
/* Symbol */
48116
48117
static JSValue js_symbol_constructor(JSContext *ctx, JSValueConst new_target,
48118
                                     int argc, JSValueConst *argv)
48119
0
{
48120
0
    JSValue str;
48121
0
    JSString *p;
48122
48123
0
    if (!JS_IsUndefined(new_target))
48124
0
        return JS_ThrowTypeError(ctx, "not a constructor");
48125
0
    if (argc == 0 || JS_IsUndefined(argv[0])) {
48126
0
        p = NULL;
48127
0
    } else {
48128
0
        str = JS_ToString(ctx, argv[0]);
48129
0
        if (JS_IsException(str))
48130
0
            return JS_EXCEPTION;
48131
0
        p = JS_VALUE_GET_STRING(str);
48132
0
    }
48133
0
    return JS_NewSymbol(ctx, p, JS_ATOM_TYPE_SYMBOL);
48134
0
}
48135
48136
static JSValue js_thisSymbolValue(JSContext *ctx, JSValueConst this_val)
48137
0
{
48138
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_SYMBOL)
48139
0
        return JS_DupValue(ctx, this_val);
48140
48141
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
48142
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
48143
0
        if (p->class_id == JS_CLASS_SYMBOL) {
48144
0
            if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_SYMBOL)
48145
0
                return JS_DupValue(ctx, p->u.object_data);
48146
0
        }
48147
0
    }
48148
0
    return JS_ThrowTypeError(ctx, "not a symbol");
48149
0
}
48150
48151
static JSValue js_symbol_toString(JSContext *ctx, JSValueConst this_val,
48152
                                  int argc, JSValueConst *argv)
48153
0
{
48154
0
    JSValue val, ret;
48155
0
    val = js_thisSymbolValue(ctx, this_val);
48156
0
    if (JS_IsException(val))
48157
0
        return val;
48158
    /* XXX: use JS_ToStringInternal() with a flags */
48159
0
    ret = js_string_constructor(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val);
48160
0
    JS_FreeValue(ctx, val);
48161
0
    return ret;
48162
0
}
48163
48164
static JSValue js_symbol_valueOf(JSContext *ctx, JSValueConst this_val,
48165
                                 int argc, JSValueConst *argv)
48166
0
{
48167
0
    return js_thisSymbolValue(ctx, this_val);
48168
0
}
48169
48170
static JSValue js_symbol_get_description(JSContext *ctx, JSValueConst this_val)
48171
0
{
48172
0
    JSValue val, ret;
48173
0
    JSAtomStruct *p;
48174
48175
0
    val = js_thisSymbolValue(ctx, this_val);
48176
0
    if (JS_IsException(val))
48177
0
        return val;
48178
0
    p = JS_VALUE_GET_PTR(val);
48179
0
    if (p->len == 0 && p->is_wide_char != 0) {
48180
0
        ret = JS_UNDEFINED;
48181
0
    } else {
48182
0
        ret = JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p));
48183
0
    }
48184
0
    JS_FreeValue(ctx, val);
48185
0
    return ret;
48186
0
}
48187
48188
static const JSCFunctionListEntry js_symbol_proto_funcs[] = {
48189
    JS_CFUNC_DEF("toString", 0, js_symbol_toString ),
48190
    JS_CFUNC_DEF("valueOf", 0, js_symbol_valueOf ),
48191
    // XXX: should have writable: false
48192
    JS_CFUNC_DEF("[Symbol.toPrimitive]", 1, js_symbol_valueOf ),
48193
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Symbol", JS_PROP_CONFIGURABLE ),
48194
    JS_CGETSET_DEF("description", js_symbol_get_description, NULL ),
48195
};
48196
48197
static JSValue js_symbol_for(JSContext *ctx, JSValueConst this_val,
48198
                             int argc, JSValueConst *argv)
48199
0
{
48200
0
    JSValue str;
48201
48202
0
    str = JS_ToString(ctx, argv[0]);
48203
0
    if (JS_IsException(str))
48204
0
        return JS_EXCEPTION;
48205
0
    return JS_NewSymbol(ctx, JS_VALUE_GET_STRING(str), JS_ATOM_TYPE_GLOBAL_SYMBOL);
48206
0
}
48207
48208
static JSValue js_symbol_keyFor(JSContext *ctx, JSValueConst this_val,
48209
                                int argc, JSValueConst *argv)
48210
0
{
48211
0
    JSAtomStruct *p;
48212
48213
0
    if (!JS_IsSymbol(argv[0]))
48214
0
        return JS_ThrowTypeError(ctx, "not a symbol");
48215
0
    p = JS_VALUE_GET_PTR(argv[0]);
48216
0
    if (p->atom_type != JS_ATOM_TYPE_GLOBAL_SYMBOL)
48217
0
        return JS_UNDEFINED;
48218
0
    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));
48219
0
}
48220
48221
static const JSCFunctionListEntry js_symbol_funcs[] = {
48222
    JS_CFUNC_DEF("for", 1, js_symbol_for ),
48223
    JS_CFUNC_DEF("keyFor", 1, js_symbol_keyFor ),
48224
};
48225
48226
/* Set/Map/WeakSet/WeakMap */
48227
48228
static BOOL js_weakref_is_target(JSValueConst val)
48229
0
{
48230
0
    switch (JS_VALUE_GET_TAG(val)) {
48231
0
    case JS_TAG_OBJECT:
48232
0
        return TRUE;
48233
0
    case JS_TAG_SYMBOL:
48234
0
        {
48235
0
            JSAtomStruct *p = JS_VALUE_GET_PTR(val);
48236
0
            if (p->atom_type == JS_ATOM_TYPE_SYMBOL &&
48237
0
                p->hash != JS_ATOM_HASH_PRIVATE)
48238
0
                return TRUE;
48239
0
        }
48240
0
        break;
48241
0
    default:
48242
0
        break;
48243
0
    }
48244
0
    return FALSE;
48245
0
}
48246
48247
/* JS_UNDEFINED is considered as a live weakref */
48248
/* XXX: add a specific JSWeakRef value type ? */
48249
static BOOL js_weakref_is_live(JSValueConst val)
48250
0
{
48251
0
    int *pref_count;
48252
0
    if (JS_IsUndefined(val))
48253
0
        return TRUE;
48254
0
    pref_count = JS_VALUE_GET_PTR(val);
48255
0
    return (*pref_count != 0);
48256
0
}
48257
48258
/* 'val' can be JS_UNDEFINED */
48259
static void js_weakref_free(JSRuntime *rt, JSValue val)
48260
0
{
48261
0
    if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {
48262
0
        JSObject *p = JS_VALUE_GET_OBJ(val);
48263
0
        assert(p->weakref_count >= 1);
48264
0
        p->weakref_count--;
48265
        /* 'mark' is tested to avoid freeing the object structure when
48266
           it is about to be freed in a cycle or in
48267
           free_zero_refcount() */
48268
0
        if (p->weakref_count == 0 && p->header.ref_count == 0 &&
48269
0
            p->header.mark == 0) {
48270
0
            js_free_rt(rt, p);
48271
0
        }
48272
0
    } else if (JS_VALUE_GET_TAG(val) == JS_TAG_SYMBOL) {
48273
0
        JSString *p = JS_VALUE_GET_STRING(val);
48274
0
        assert(p->hash >= 1);
48275
0
        p->hash--;
48276
0
        if (p->hash == 0 && p->header.ref_count == 0) {
48277
            /* can remove the dummy structure */
48278
0
            js_free_rt(rt, p);
48279
0
        }
48280
0
    }
48281
0
}
48282
48283
/* val must be an object, a symbol or undefined (see
48284
   js_weakref_is_target). */
48285
static JSValue js_weakref_new(JSContext *ctx, JSValueConst val)
48286
0
{
48287
0
    if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {
48288
0
        JSObject *p = JS_VALUE_GET_OBJ(val);
48289
0
        p->weakref_count++;
48290
0
    } else if (JS_VALUE_GET_TAG(val) == JS_TAG_SYMBOL) {
48291
0
        JSString *p = JS_VALUE_GET_STRING(val);
48292
        /* XXX: could return an exception if too many references */
48293
0
        assert(p->hash < JS_ATOM_HASH_MASK - 2);
48294
0
        p->hash++;
48295
0
    } else {
48296
0
        assert(JS_IsUndefined(val));
48297
0
    }
48298
0
    return (JSValue)val;
48299
0
}
48300
48301
0
#define MAGIC_SET (1 << 0)
48302
0
#define MAGIC_WEAK (1 << 1)
48303
48304
static JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target,
48305
                                  int argc, JSValueConst *argv, int magic)
48306
0
{
48307
0
    JSMapState *s;
48308
0
    JSValue obj, adder = JS_UNDEFINED, iter = JS_UNDEFINED, next_method = JS_UNDEFINED;
48309
0
    JSValueConst arr;
48310
0
    BOOL is_set, is_weak;
48311
48312
0
    is_set = magic & MAGIC_SET;
48313
0
    is_weak = ((magic & MAGIC_WEAK) != 0);
48314
0
    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_MAP + magic);
48315
0
    if (JS_IsException(obj))
48316
0
        return JS_EXCEPTION;
48317
0
    s = js_mallocz(ctx, sizeof(*s));
48318
0
    if (!s)
48319
0
        goto fail;
48320
0
    init_list_head(&s->records);
48321
0
    s->is_weak = is_weak;
48322
0
    if (is_weak) {
48323
0
        s->weakref_header.weakref_type = JS_WEAKREF_TYPE_MAP;
48324
0
        list_add_tail(&s->weakref_header.link, &ctx->rt->weakref_list);
48325
0
    }
48326
0
    JS_SetOpaque(obj, s);
48327
0
    s->hash_bits = 1;
48328
0
    s->hash_size = 1U << s->hash_bits;
48329
0
    s->hash_table = js_mallocz(ctx, sizeof(s->hash_table[0]) * s->hash_size);
48330
0
    if (!s->hash_table)
48331
0
        goto fail;
48332
0
    s->record_count_threshold = 4;
48333
48334
0
    arr = JS_UNDEFINED;
48335
0
    if (argc > 0)
48336
0
        arr = argv[0];
48337
0
    if (!JS_IsUndefined(arr) && !JS_IsNull(arr)) {
48338
0
        JSValue item, ret;
48339
0
        BOOL done;
48340
48341
0
        adder = JS_GetProperty(ctx, obj, is_set ? JS_ATOM_add : JS_ATOM_set);
48342
0
        if (JS_IsException(adder))
48343
0
            goto fail;
48344
0
        if (!JS_IsFunction(ctx, adder)) {
48345
0
            JS_ThrowTypeError(ctx, "set/add is not a function");
48346
0
            goto fail;
48347
0
        }
48348
48349
0
        iter = JS_GetIterator(ctx, arr, FALSE);
48350
0
        if (JS_IsException(iter))
48351
0
            goto fail;
48352
0
        next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
48353
0
        if (JS_IsException(next_method))
48354
0
            goto fail;
48355
48356
0
        for(;;) {
48357
0
            item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
48358
0
            if (JS_IsException(item))
48359
0
                goto fail;
48360
0
            if (done)
48361
0
                break;
48362
0
            if (is_set) {
48363
0
                ret = JS_Call(ctx, adder, obj, 1, (JSValueConst *)&item);
48364
0
                if (JS_IsException(ret)) {
48365
0
                    JS_FreeValue(ctx, item);
48366
0
                    goto fail_close;
48367
0
                }
48368
0
            } else {
48369
0
                JSValue key, value;
48370
0
                JSValueConst args[2];
48371
0
                key = JS_UNDEFINED;
48372
0
                value = JS_UNDEFINED;
48373
0
                if (!JS_IsObject(item)) {
48374
0
                    JS_ThrowTypeErrorNotAnObject(ctx);
48375
0
                    goto fail1;
48376
0
                }
48377
0
                key = JS_GetPropertyUint32(ctx, item, 0);
48378
0
                if (JS_IsException(key))
48379
0
                    goto fail1;
48380
0
                value = JS_GetPropertyUint32(ctx, item, 1);
48381
0
                if (JS_IsException(value))
48382
0
                    goto fail1;
48383
0
                args[0] = key;
48384
0
                args[1] = value;
48385
0
                ret = JS_Call(ctx, adder, obj, 2, args);
48386
0
                if (JS_IsException(ret)) {
48387
0
                fail1:
48388
0
                    JS_FreeValue(ctx, item);
48389
0
                    JS_FreeValue(ctx, key);
48390
0
                    JS_FreeValue(ctx, value);
48391
0
                    goto fail_close;
48392
0
                }
48393
0
                JS_FreeValue(ctx, key);
48394
0
                JS_FreeValue(ctx, value);
48395
0
            }
48396
0
            JS_FreeValue(ctx, ret);
48397
0
            JS_FreeValue(ctx, item);
48398
0
        }
48399
0
        JS_FreeValue(ctx, next_method);
48400
0
        JS_FreeValue(ctx, iter);
48401
0
        JS_FreeValue(ctx, adder);
48402
0
    }
48403
0
    return obj;
48404
0
 fail_close:
48405
    /* close the iterator object, preserving pending exception */
48406
0
    JS_IteratorClose(ctx, iter, TRUE);
48407
0
 fail:
48408
0
    JS_FreeValue(ctx, next_method);
48409
0
    JS_FreeValue(ctx, iter);
48410
0
    JS_FreeValue(ctx, adder);
48411
0
    JS_FreeValue(ctx, obj);
48412
0
    return JS_EXCEPTION;
48413
0
}
48414
48415
/* XXX: could normalize strings to speed up comparison */
48416
static JSValueConst map_normalize_key(JSContext *ctx, JSValueConst key)
48417
0
{
48418
0
    uint32_t tag = JS_VALUE_GET_TAG(key);
48419
    /* convert -0.0 to +0.0 */
48420
0
    if (JS_TAG_IS_FLOAT64(tag) && JS_VALUE_GET_FLOAT64(key) == 0.0) {
48421
0
        key = JS_NewInt32(ctx, 0);
48422
0
    }
48423
0
    return key;
48424
0
}
48425
48426
/* hash multipliers, same as the Linux kernel (see Knuth vol 3,
48427
   section 6.4, exercise 9) */
48428
0
#define HASH_MUL32 0x61C88647
48429
0
#define HASH_MUL64 UINT64_C(0x61C8864680B583EB)
48430
48431
static uint32_t map_hash32(uint32_t a, int hash_bits)
48432
0
{
48433
0
    return (a * HASH_MUL32) >> (32 - hash_bits);
48434
0
}
48435
48436
static uint32_t map_hash64(uint64_t a, int hash_bits)
48437
0
{
48438
0
    return (a * HASH_MUL64) >> (64 - hash_bits);
48439
0
}
48440
48441
static uint32_t map_hash_pointer(uintptr_t a, int hash_bits)
48442
0
{
48443
0
#ifdef JS_PTR64
48444
0
    return map_hash64(a, hash_bits);
48445
#else
48446
    return map_hash32(a, hash_bits);
48447
#endif
48448
0
}
48449
48450
/* XXX: better hash ? */
48451
/* precondition: 1 <= hash_bits <= 32 */
48452
static uint32_t map_hash_key(JSValueConst key, int hash_bits)
48453
0
{
48454
0
    uint32_t tag = JS_VALUE_GET_NORM_TAG(key);
48455
0
    uint32_t h;
48456
0
    double d;
48457
0
    JSBigInt *p;
48458
0
    JSBigIntBuf buf;
48459
    
48460
0
    switch(tag) {
48461
0
    case JS_TAG_BOOL:
48462
0
        h = map_hash32(JS_VALUE_GET_INT(key) ^ JS_TAG_BOOL, hash_bits);
48463
0
        break;
48464
0
    case JS_TAG_STRING:
48465
0
        h = map_hash32(hash_string(JS_VALUE_GET_STRING(key), 0) ^ JS_TAG_STRING, hash_bits);
48466
0
        break;
48467
0
    case JS_TAG_STRING_ROPE:
48468
0
        h = map_hash32(hash_string_rope(key, 0) ^ JS_TAG_STRING, hash_bits);
48469
0
        break;
48470
0
    case JS_TAG_OBJECT:
48471
0
    case JS_TAG_SYMBOL:
48472
0
        h = map_hash_pointer((uintptr_t)JS_VALUE_GET_PTR(key) ^ tag, hash_bits);
48473
0
        break;
48474
0
    case JS_TAG_INT:
48475
0
        d = JS_VALUE_GET_INT(key);
48476
0
        goto hash_float64;
48477
0
    case JS_TAG_FLOAT64:
48478
0
        d = JS_VALUE_GET_FLOAT64(key);
48479
        /* normalize the NaN */
48480
0
        if (isnan(d))
48481
0
            d = JS_FLOAT64_NAN;
48482
0
    hash_float64:
48483
0
        h = map_hash64(float64_as_uint64(d) ^ JS_TAG_FLOAT64, hash_bits);
48484
0
        break;
48485
0
    case JS_TAG_SHORT_BIG_INT:
48486
0
        p = js_bigint_set_short(&buf, key);
48487
0
        goto hash_bigint;
48488
0
    case JS_TAG_BIG_INT:
48489
0
        p = JS_VALUE_GET_PTR(key);
48490
0
    hash_bigint:
48491
0
        {
48492
0
            int i;
48493
0
            h = 1;
48494
0
            for(i = p->len - 1; i >= 0; i--) {
48495
0
                h = h * 263 + p->tab[i];
48496
0
            }
48497
            /* the final step is necessary otherwise h mod n only
48498
               depends of p->tab[i] mod n */
48499
0
            h = map_hash32(h ^ JS_TAG_BIG_INT, hash_bits);
48500
0
        }
48501
0
        break;
48502
0
    default:
48503
0
        h = 0;
48504
0
        break;
48505
0
    }
48506
0
    return h;
48507
0
}
48508
48509
static JSMapRecord *map_find_record(JSContext *ctx, JSMapState *s,
48510
                                    JSValueConst key)
48511
0
{
48512
0
    JSMapRecord *mr;
48513
0
    uint32_t h;
48514
0
    h = map_hash_key(key, s->hash_bits);
48515
0
    for(mr = s->hash_table[h]; mr != NULL; mr = mr->hash_next) {
48516
0
        if (mr->empty || (s->is_weak && !js_weakref_is_live(mr->key))) {
48517
            /* cannot match */
48518
0
        } else {
48519
0
            if (js_same_value_zero(ctx, mr->key, key))
48520
0
                return mr;
48521
0
        }
48522
0
    }
48523
0
    return NULL;
48524
0
}
48525
48526
static void map_hash_resize(JSContext *ctx, JSMapState *s)
48527
0
{
48528
0
    uint32_t new_hash_size, h;
48529
0
    int new_hash_bits;
48530
0
    struct list_head *el;
48531
0
    JSMapRecord *mr, **new_hash_table;
48532
48533
    /* XXX: no reporting of memory allocation failure */
48534
0
    new_hash_bits = min_int(s->hash_bits + 1, 31);
48535
0
    new_hash_size = 1U << new_hash_bits;
48536
0
    new_hash_table = js_realloc(ctx, s->hash_table,
48537
0
                                sizeof(new_hash_table[0]) * new_hash_size);
48538
0
    if (!new_hash_table)
48539
0
        return;
48540
48541
0
    memset(new_hash_table, 0, sizeof(new_hash_table[0]) * new_hash_size);
48542
48543
0
    list_for_each(el, &s->records) {
48544
0
        mr = list_entry(el, JSMapRecord, link);
48545
0
        if (mr->empty || (s->is_weak && !js_weakref_is_live(mr->key))) {
48546
0
        } else {
48547
0
            h = map_hash_key(mr->key, new_hash_bits);
48548
0
            mr->hash_next = new_hash_table[h];
48549
0
            new_hash_table[h] = mr;
48550
0
        }
48551
0
    }
48552
0
    s->hash_table = new_hash_table;
48553
0
    s->hash_bits = new_hash_bits;
48554
0
    s->hash_size = new_hash_size;
48555
0
    s->record_count_threshold = new_hash_size * 2;
48556
0
}
48557
48558
static JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s,
48559
                                   JSValueConst key)
48560
0
{
48561
0
    uint32_t h;
48562
0
    JSMapRecord *mr;
48563
48564
0
    mr = js_malloc(ctx, sizeof(*mr));
48565
0
    if (!mr)
48566
0
        return NULL;
48567
0
    mr->ref_count = 1;
48568
0
    mr->empty = FALSE;
48569
0
    if (s->is_weak) {
48570
0
        mr->key = js_weakref_new(ctx, key);
48571
0
    } else {
48572
0
        mr->key = JS_DupValue(ctx, key);
48573
0
    }
48574
0
    h = map_hash_key(key, s->hash_bits);
48575
0
    mr->hash_next = s->hash_table[h];
48576
0
    s->hash_table[h] = mr;
48577
0
    list_add_tail(&mr->link, &s->records);
48578
0
    s->record_count++;
48579
0
    if (s->record_count >= s->record_count_threshold) {
48580
0
        map_hash_resize(ctx, s);
48581
0
    }
48582
0
    return mr;
48583
0
}
48584
48585
/* warning: the record must be removed from the hash table before */
48586
static void map_delete_record(JSRuntime *rt, JSMapState *s, JSMapRecord *mr)
48587
0
{
48588
0
    if (mr->empty)
48589
0
        return;
48590
    
48591
0
    if (s->is_weak) {
48592
0
        js_weakref_free(rt, mr->key);
48593
0
    } else {
48594
0
        JS_FreeValueRT(rt, mr->key);
48595
0
    }
48596
0
    JS_FreeValueRT(rt, mr->value);
48597
0
    if (--mr->ref_count == 0) {
48598
0
        list_del(&mr->link);
48599
0
        js_free_rt(rt, mr);
48600
0
    } else {
48601
        /* keep a zombie record for iterators */
48602
0
        mr->empty = TRUE;
48603
0
        mr->key = JS_UNDEFINED;
48604
0
        mr->value = JS_UNDEFINED;
48605
0
    }
48606
0
    s->record_count--;
48607
0
}
48608
48609
static void map_decref_record(JSRuntime *rt, JSMapRecord *mr)
48610
0
{
48611
0
    if (--mr->ref_count == 0) {
48612
        /* the record can be safely removed */
48613
0
        assert(mr->empty);
48614
0
        list_del(&mr->link);
48615
0
        js_free_rt(rt, mr);
48616
0
    }
48617
0
}
48618
48619
static void map_delete_weakrefs(JSRuntime *rt, JSWeakRefHeader *wh)
48620
0
{
48621
0
    JSMapState *s = container_of(wh, JSMapState, weakref_header);
48622
0
    struct list_head *el, *el1;
48623
0
    JSMapRecord *mr1, **pmr;
48624
0
    uint32_t h;
48625
48626
0
    list_for_each_safe(el, el1, &s->records) {
48627
0
        JSMapRecord *mr = list_entry(el, JSMapRecord, link);
48628
0
        if (!js_weakref_is_live(mr->key)) {
48629
48630
            /* even if key is not live it can be hashed as a pointer */
48631
0
            h = map_hash_key(mr->key, s->hash_bits);
48632
0
            pmr = &s->hash_table[h];
48633
0
            for(;;) {
48634
0
                mr1 = *pmr;
48635
                /* the entry may already be removed from the hash
48636
                   table if the map was resized */
48637
0
                if (mr1 == NULL)
48638
0
                    goto done; 
48639
0
                if (mr1 == mr)
48640
0
                    break;
48641
0
                pmr = &mr1->hash_next;
48642
0
            }
48643
            /* remove from the hash table */
48644
0
            *pmr = mr1->hash_next;
48645
0
        done:
48646
0
            map_delete_record(rt, s, mr);
48647
0
        }
48648
0
    }
48649
0
}
48650
48651
static JSValue js_map_set(JSContext *ctx, JSValueConst this_val,
48652
                          int argc, JSValueConst *argv, int magic)
48653
0
{
48654
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
48655
0
    JSMapRecord *mr;
48656
0
    JSValueConst key, value;
48657
48658
0
    if (!s)
48659
0
        return JS_EXCEPTION;
48660
0
    key = map_normalize_key(ctx, argv[0]);
48661
0
    if (s->is_weak && !js_weakref_is_target(key))
48662
0
        return JS_ThrowTypeError(ctx, "invalid value used as %s key", (magic & MAGIC_SET) ? "WeakSet" : "WeakMap");
48663
0
    if (magic & MAGIC_SET)
48664
0
        value = JS_UNDEFINED;
48665
0
    else
48666
0
        value = argv[1];
48667
0
    mr = map_find_record(ctx, s, key);
48668
0
    if (mr) {
48669
0
        JS_FreeValue(ctx, mr->value);
48670
0
    } else {
48671
0
        mr = map_add_record(ctx, s, key);
48672
0
        if (!mr)
48673
0
            return JS_EXCEPTION;
48674
0
    }
48675
0
    mr->value = JS_DupValue(ctx, value);
48676
0
    return JS_DupValue(ctx, this_val);
48677
0
}
48678
48679
static JSValue js_map_get(JSContext *ctx, JSValueConst this_val,
48680
                          int argc, JSValueConst *argv, int magic)
48681
0
{
48682
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
48683
0
    JSMapRecord *mr;
48684
0
    JSValueConst key;
48685
48686
0
    if (!s)
48687
0
        return JS_EXCEPTION;
48688
0
    key = map_normalize_key(ctx, argv[0]);
48689
0
    mr = map_find_record(ctx, s, key);
48690
0
    if (!mr)
48691
0
        return JS_UNDEFINED;
48692
0
    else
48693
0
        return JS_DupValue(ctx, mr->value);
48694
0
}
48695
48696
static JSValue js_map_has(JSContext *ctx, JSValueConst this_val,
48697
                          int argc, JSValueConst *argv, int magic)
48698
0
{
48699
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
48700
0
    JSMapRecord *mr;
48701
0
    JSValueConst key;
48702
48703
0
    if (!s)
48704
0
        return JS_EXCEPTION;
48705
0
    key = map_normalize_key(ctx, argv[0]);
48706
0
    mr = map_find_record(ctx, s, key);
48707
0
    return JS_NewBool(ctx, mr != NULL);
48708
0
}
48709
48710
static JSValue js_map_delete(JSContext *ctx, JSValueConst this_val,
48711
                             int argc, JSValueConst *argv, int magic)
48712
0
{
48713
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
48714
0
    JSMapRecord *mr, **pmr;
48715
0
    JSValueConst key;
48716
0
    uint32_t h;
48717
48718
0
    if (!s)
48719
0
        return JS_EXCEPTION;
48720
0
    key = map_normalize_key(ctx, argv[0]);
48721
    
48722
0
    h = map_hash_key(key, s->hash_bits);
48723
0
    pmr = &s->hash_table[h];
48724
0
    for(;;) {
48725
0
        mr = *pmr;
48726
0
        if (mr == NULL)
48727
0
            return JS_FALSE;
48728
0
        if (mr->empty || (s->is_weak && !js_weakref_is_live(mr->key))) {
48729
            /* not valid */
48730
0
        } else {
48731
0
            if (js_same_value_zero(ctx, mr->key, key))
48732
0
                break;
48733
0
        }
48734
0
        pmr = &mr->hash_next;
48735
0
    }
48736
48737
    /* remove from the hash table */
48738
0
    *pmr = mr->hash_next;
48739
    
48740
0
    map_delete_record(ctx->rt, s, mr);
48741
0
    return JS_TRUE;
48742
0
}
48743
48744
static JSValue js_map_clear(JSContext *ctx, JSValueConst this_val,
48745
                            int argc, JSValueConst *argv, int magic)
48746
0
{
48747
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
48748
0
    struct list_head *el, *el1;
48749
0
    JSMapRecord *mr;
48750
48751
0
    if (!s)
48752
0
        return JS_EXCEPTION;
48753
48754
    /* remove from the hash table */
48755
0
    memset(s->hash_table, 0, sizeof(s->hash_table[0]) * s->hash_size);
48756
    
48757
0
    list_for_each_safe(el, el1, &s->records) {
48758
0
        mr = list_entry(el, JSMapRecord, link);
48759
0
        map_delete_record(ctx->rt, s, mr);
48760
0
    }
48761
0
    return JS_UNDEFINED;
48762
0
}
48763
48764
static JSValue js_map_get_size(JSContext *ctx, JSValueConst this_val, int magic)
48765
0
{
48766
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
48767
0
    if (!s)
48768
0
        return JS_EXCEPTION;
48769
0
    return JS_NewUint32(ctx, s->record_count);
48770
0
}
48771
48772
static JSValue js_map_forEach(JSContext *ctx, JSValueConst this_val,
48773
                              int argc, JSValueConst *argv, int magic)
48774
0
{
48775
0
    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
48776
0
    JSValueConst func, this_arg;
48777
0
    JSValue ret, args[3];
48778
0
    struct list_head *el;
48779
0
    JSMapRecord *mr;
48780
48781
0
    if (!s)
48782
0
        return JS_EXCEPTION;
48783
0
    func = argv[0];
48784
0
    if (argc > 1)
48785
0
        this_arg = argv[1];
48786
0
    else
48787
0
        this_arg = JS_UNDEFINED;
48788
0
    if (check_function(ctx, func))
48789
0
        return JS_EXCEPTION;
48790
    /* Note: the list can be modified while traversing it, but the
48791
       current element is locked */
48792
0
    el = s->records.next;
48793
0
    while (el != &s->records) {
48794
0
        mr = list_entry(el, JSMapRecord, link);
48795
0
        if (!mr->empty) {
48796
0
            mr->ref_count++;
48797
            /* must duplicate in case the record is deleted */
48798
0
            args[1] = JS_DupValue(ctx, mr->key);
48799
0
            if (magic)
48800
0
                args[0] = args[1];
48801
0
            else
48802
0
                args[0] = JS_DupValue(ctx, mr->value);
48803
0
            args[2] = (JSValue)this_val;
48804
0
            ret = JS_Call(ctx, func, this_arg, 3, (JSValueConst *)args);
48805
0
            JS_FreeValue(ctx, args[0]);
48806
0
            if (!magic)
48807
0
                JS_FreeValue(ctx, args[1]);
48808
0
            el = el->next;
48809
0
            map_decref_record(ctx->rt, mr);
48810
0
            if (JS_IsException(ret))
48811
0
                return ret;
48812
0
            JS_FreeValue(ctx, ret);
48813
0
        } else {
48814
0
            el = el->next;
48815
0
        }
48816
0
    }
48817
0
    return JS_UNDEFINED;
48818
0
}
48819
48820
static JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val,
48821
                                 int argc, JSValueConst *argv, int is_map)
48822
0
{
48823
0
    JSValueConst cb, args[2];
48824
0
    JSValue res, iter, next, groups, key, v, prop;
48825
0
    JSAtom key_atom = JS_ATOM_NULL;
48826
0
    int64_t idx;
48827
0
    BOOL done;
48828
48829
    // "is function?" check must be observed before argv[0] is accessed
48830
0
    cb = argv[1];
48831
0
    if (check_function(ctx, cb))
48832
0
        return JS_EXCEPTION;
48833
48834
0
    iter = JS_GetIterator(ctx, argv[0], /*is_async*/FALSE);
48835
0
    if (JS_IsException(iter))
48836
0
        return JS_EXCEPTION;
48837
48838
0
    key = JS_UNDEFINED;
48839
0
    key_atom = JS_ATOM_NULL;
48840
0
    v = JS_UNDEFINED;
48841
0
    prop = JS_UNDEFINED;
48842
0
    groups = JS_UNDEFINED;
48843
48844
0
    next = JS_GetProperty(ctx, iter, JS_ATOM_next);
48845
0
    if (JS_IsException(next))
48846
0
        goto exception;
48847
48848
0
    if (is_map) {
48849
0
        groups = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, 0);
48850
0
    } else {
48851
0
        groups = JS_NewObjectProto(ctx, JS_NULL);
48852
0
    }
48853
0
    if (JS_IsException(groups))
48854
0
        goto exception;
48855
48856
0
    for (idx = 0; ; idx++) {
48857
0
        if (idx >= MAX_SAFE_INTEGER) {
48858
0
            JS_ThrowTypeError(ctx, "too many elements");
48859
0
            goto iterator_close_exception;
48860
0
        }
48861
0
        v = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);
48862
0
        if (JS_IsException(v))
48863
0
            goto exception;
48864
0
        if (done)
48865
0
            break; // v is JS_UNDEFINED
48866
48867
0
        args[0] = v;
48868
0
        args[1] = JS_NewInt64(ctx, idx);
48869
0
        key = JS_Call(ctx, cb, ctx->global_obj, 2, args);
48870
0
        if (JS_IsException(key))
48871
0
            goto iterator_close_exception;
48872
48873
0
        if (is_map) {
48874
0
            prop = js_map_get(ctx, groups, 1, (JSValueConst *)&key, 0);
48875
0
        } else {
48876
0
            key_atom = JS_ValueToAtom(ctx, key);
48877
0
            JS_FreeValue(ctx, key);
48878
0
            key = JS_UNDEFINED;
48879
0
            if (key_atom == JS_ATOM_NULL)
48880
0
                goto iterator_close_exception;
48881
0
            prop = JS_GetProperty(ctx, groups, key_atom);
48882
0
        }
48883
0
        if (JS_IsException(prop))
48884
0
            goto exception;
48885
48886
0
        if (JS_IsUndefined(prop)) {
48887
0
            prop = JS_NewArray(ctx);
48888
0
            if (JS_IsException(prop))
48889
0
                goto exception;
48890
0
            if (is_map) {
48891
0
                args[0] = key;
48892
0
                args[1] = prop;
48893
0
                res = js_map_set(ctx, groups, 2, args, 0);
48894
0
                if (JS_IsException(res))
48895
0
                    goto exception;
48896
0
                JS_FreeValue(ctx, res);
48897
0
            } else {
48898
0
                prop = JS_DupValue(ctx, prop);
48899
0
                if (JS_DefinePropertyValue(ctx, groups, key_atom, prop,
48900
0
                                           JS_PROP_C_W_E) < 0) {
48901
0
                    goto exception;
48902
0
                }
48903
0
            }
48904
0
        }
48905
0
        res = js_array_push(ctx, prop, 1, (JSValueConst *)&v, /*unshift*/0);
48906
0
        if (JS_IsException(res))
48907
0
            goto exception;
48908
        // res is an int64
48909
48910
0
        JS_FreeValue(ctx, prop);
48911
0
        JS_FreeValue(ctx, key);
48912
0
        JS_FreeAtom(ctx, key_atom);
48913
0
        JS_FreeValue(ctx, v);
48914
0
        prop = JS_UNDEFINED;
48915
0
        key = JS_UNDEFINED;
48916
0
        key_atom = JS_ATOM_NULL;
48917
0
        v = JS_UNDEFINED;
48918
0
    }
48919
48920
0
    JS_FreeValue(ctx, iter);
48921
0
    JS_FreeValue(ctx, next);
48922
0
    return groups;
48923
48924
0
 iterator_close_exception:
48925
0
    JS_IteratorClose(ctx, iter, TRUE);
48926
0
 exception:
48927
0
    JS_FreeAtom(ctx, key_atom);
48928
0
    JS_FreeValue(ctx, prop);
48929
0
    JS_FreeValue(ctx, key);
48930
0
    JS_FreeValue(ctx, v);
48931
0
    JS_FreeValue(ctx, groups);
48932
0
    JS_FreeValue(ctx, iter);
48933
0
    JS_FreeValue(ctx, next);
48934
0
    return JS_EXCEPTION;
48935
0
}
48936
48937
static void js_map_finalizer(JSRuntime *rt, JSValue val)
48938
0
{
48939
0
    JSObject *p;
48940
0
    JSMapState *s;
48941
0
    struct list_head *el, *el1;
48942
0
    JSMapRecord *mr;
48943
48944
0
    p = JS_VALUE_GET_OBJ(val);
48945
0
    s = p->u.map_state;
48946
0
    if (s) {
48947
        /* if the object is deleted we are sure that no iterator is
48948
           using it */
48949
0
        list_for_each_safe(el, el1, &s->records) {
48950
0
            mr = list_entry(el, JSMapRecord, link);
48951
0
            if (!mr->empty) {
48952
0
                if (s->is_weak)
48953
0
                    js_weakref_free(rt, mr->key);
48954
0
                else
48955
0
                    JS_FreeValueRT(rt, mr->key);
48956
0
                JS_FreeValueRT(rt, mr->value);
48957
0
            }
48958
0
            js_free_rt(rt, mr);
48959
0
        }
48960
0
        js_free_rt(rt, s->hash_table);
48961
0
        if (s->is_weak) {
48962
0
            list_del(&s->weakref_header.link);
48963
0
        }
48964
0
        js_free_rt(rt, s);
48965
0
    }
48966
0
}
48967
48968
static void js_map_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)
48969
0
{
48970
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
48971
0
    JSMapState *s;
48972
0
    struct list_head *el;
48973
0
    JSMapRecord *mr;
48974
48975
0
    s = p->u.map_state;
48976
0
    if (s) {
48977
0
        list_for_each(el, &s->records) {
48978
0
            mr = list_entry(el, JSMapRecord, link);
48979
0
            if (!s->is_weak)
48980
0
                JS_MarkValue(rt, mr->key, mark_func);
48981
0
            JS_MarkValue(rt, mr->value, mark_func);
48982
0
        }
48983
0
    }
48984
0
}
48985
48986
/* Map Iterator */
48987
48988
typedef struct JSMapIteratorData {
48989
    JSValue obj;
48990
    JSIteratorKindEnum kind;
48991
    JSMapRecord *cur_record;
48992
} JSMapIteratorData;
48993
48994
static void js_map_iterator_finalizer(JSRuntime *rt, JSValue val)
48995
0
{
48996
0
    JSObject *p;
48997
0
    JSMapIteratorData *it;
48998
48999
0
    p = JS_VALUE_GET_OBJ(val);
49000
0
    it = p->u.map_iterator_data;
49001
0
    if (it) {
49002
        /* During the GC sweep phase the Map finalizer may be
49003
           called before the Map iterator finalizer */
49004
0
        if (JS_IsLiveObject(rt, it->obj) && it->cur_record) {
49005
0
            map_decref_record(rt, it->cur_record);
49006
0
        }
49007
0
        JS_FreeValueRT(rt, it->obj);
49008
0
        js_free_rt(rt, it);
49009
0
    }
49010
0
}
49011
49012
static void js_map_iterator_mark(JSRuntime *rt, JSValueConst val,
49013
                                 JS_MarkFunc *mark_func)
49014
0
{
49015
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
49016
0
    JSMapIteratorData *it;
49017
0
    it = p->u.map_iterator_data;
49018
0
    if (it) {
49019
        /* the record is already marked by the object */
49020
0
        JS_MarkValue(rt, it->obj, mark_func);
49021
0
    }
49022
0
}
49023
49024
static JSValue js_create_map_iterator(JSContext *ctx, JSValueConst this_val,
49025
                                      int argc, JSValueConst *argv, int magic)
49026
0
{
49027
0
    JSIteratorKindEnum kind;
49028
0
    JSMapState *s;
49029
0
    JSMapIteratorData *it;
49030
0
    JSValue enum_obj;
49031
49032
0
    kind = magic >> 2;
49033
0
    magic &= 3;
49034
0
    s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);
49035
0
    if (!s)
49036
0
        return JS_EXCEPTION;
49037
0
    enum_obj = JS_NewObjectClass(ctx, JS_CLASS_MAP_ITERATOR + magic);
49038
0
    if (JS_IsException(enum_obj))
49039
0
        goto fail;
49040
0
    it = js_malloc(ctx, sizeof(*it));
49041
0
    if (!it) {
49042
0
        JS_FreeValue(ctx, enum_obj);
49043
0
        goto fail;
49044
0
    }
49045
0
    it->obj = JS_DupValue(ctx, this_val);
49046
0
    it->kind = kind;
49047
0
    it->cur_record = NULL;
49048
0
    JS_SetOpaque(enum_obj, it);
49049
0
    return enum_obj;
49050
0
 fail:
49051
0
    return JS_EXCEPTION;
49052
0
}
49053
49054
static JSValue js_map_iterator_next(JSContext *ctx, JSValueConst this_val,
49055
                                    int argc, JSValueConst *argv,
49056
                                    BOOL *pdone, int magic)
49057
0
{
49058
0
    JSMapIteratorData *it;
49059
0
    JSMapState *s;
49060
0
    JSMapRecord *mr;
49061
0
    struct list_head *el;
49062
49063
0
    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP_ITERATOR + magic);
49064
0
    if (!it) {
49065
0
        *pdone = FALSE;
49066
0
        return JS_EXCEPTION;
49067
0
    }
49068
0
    if (JS_IsUndefined(it->obj))
49069
0
        goto done;
49070
0
    s = JS_GetOpaque(it->obj, JS_CLASS_MAP + magic);
49071
0
    assert(s != NULL);
49072
0
    if (!it->cur_record) {
49073
0
        el = s->records.next;
49074
0
    } else {
49075
0
        mr = it->cur_record;
49076
0
        el = mr->link.next;
49077
0
        map_decref_record(ctx->rt, mr); /* the record can be freed here */
49078
0
    }
49079
0
    for(;;) {
49080
0
        if (el == &s->records) {
49081
            /* no more record  */
49082
0
            it->cur_record = NULL;
49083
0
            JS_FreeValue(ctx, it->obj);
49084
0
            it->obj = JS_UNDEFINED;
49085
0
        done:
49086
            /* end of enumeration */
49087
0
            *pdone = TRUE;
49088
0
            return JS_UNDEFINED;
49089
0
        }
49090
0
        mr = list_entry(el, JSMapRecord, link);
49091
0
        if (!mr->empty)
49092
0
            break;
49093
        /* get the next record */
49094
0
        el = mr->link.next;
49095
0
    }
49096
49097
    /* lock the record so that it won't be freed */
49098
0
    mr->ref_count++;
49099
0
    it->cur_record = mr;
49100
0
    *pdone = FALSE;
49101
49102
0
    if (it->kind == JS_ITERATOR_KIND_KEY) {
49103
0
        return JS_DupValue(ctx, mr->key);
49104
0
    } else {
49105
0
        JSValueConst args[2];
49106
0
        args[0] = mr->key;
49107
0
        if (magic)
49108
0
            args[1] = mr->key;
49109
0
        else
49110
0
            args[1] = mr->value;
49111
0
        if (it->kind == JS_ITERATOR_KIND_VALUE) {
49112
0
            return JS_DupValue(ctx, args[1]);
49113
0
        } else {
49114
0
            return js_create_array(ctx, 2, args);
49115
0
        }
49116
0
    }
49117
0
}
49118
49119
static const JSCFunctionListEntry js_map_funcs[] = {
49120
    JS_CFUNC_MAGIC_DEF("groupBy", 2, js_object_groupBy, 1 ),
49121
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
49122
};
49123
49124
static const JSCFunctionListEntry js_map_proto_funcs[] = {
49125
    JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, 0 ),
49126
    JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, 0 ),
49127
    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, 0 ),
49128
    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, 0 ),
49129
    JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, 0 ),
49130
    JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, 0),
49131
    JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, 0 ),
49132
    JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_VALUE << 2) | 0 ),
49133
    JS_CFUNC_MAGIC_DEF("keys", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | 0 ),
49134
    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | 0 ),
49135
    JS_ALIAS_DEF("[Symbol.iterator]", "entries" ),
49136
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Map", JS_PROP_CONFIGURABLE ),
49137
};
49138
49139
static const JSCFunctionListEntry js_map_iterator_proto_funcs[] = {
49140
    JS_ITERATOR_NEXT_DEF("next", 0, js_map_iterator_next, 0 ),
49141
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Map Iterator", JS_PROP_CONFIGURABLE ),
49142
};
49143
49144
static const JSCFunctionListEntry js_set_proto_funcs[] = {
49145
    JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET ),
49146
    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET ),
49147
    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET ),
49148
    JS_CFUNC_MAGIC_DEF("clear", 0, js_map_clear, MAGIC_SET ),
49149
    JS_CGETSET_MAGIC_DEF("size", js_map_get_size, NULL, MAGIC_SET ),
49150
    JS_CFUNC_MAGIC_DEF("forEach", 1, js_map_forEach, MAGIC_SET ),
49151
    JS_CFUNC_MAGIC_DEF("values", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | MAGIC_SET ),
49152
    JS_ALIAS_DEF("keys", "values" ),
49153
    JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
49154
    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | MAGIC_SET ),
49155
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set", JS_PROP_CONFIGURABLE ),
49156
};
49157
49158
static const JSCFunctionListEntry js_set_iterator_proto_funcs[] = {
49159
    JS_ITERATOR_NEXT_DEF("next", 0, js_map_iterator_next, MAGIC_SET ),
49160
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Set Iterator", JS_PROP_CONFIGURABLE ),
49161
};
49162
49163
static const JSCFunctionListEntry js_weak_map_proto_funcs[] = {
49164
    JS_CFUNC_MAGIC_DEF("set", 2, js_map_set, MAGIC_WEAK ),
49165
    JS_CFUNC_MAGIC_DEF("get", 1, js_map_get, MAGIC_WEAK ),
49166
    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_WEAK ),
49167
    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_WEAK ),
49168
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakMap", JS_PROP_CONFIGURABLE ),
49169
};
49170
49171
static const JSCFunctionListEntry js_weak_set_proto_funcs[] = {
49172
    JS_CFUNC_MAGIC_DEF("add", 1, js_map_set, MAGIC_SET | MAGIC_WEAK ),
49173
    JS_CFUNC_MAGIC_DEF("has", 1, js_map_has, MAGIC_SET | MAGIC_WEAK ),
49174
    JS_CFUNC_MAGIC_DEF("delete", 1, js_map_delete, MAGIC_SET | MAGIC_WEAK ),
49175
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakSet", JS_PROP_CONFIGURABLE ),
49176
};
49177
49178
static const JSCFunctionListEntry * const js_map_proto_funcs_ptr[6] = {
49179
    js_map_proto_funcs,
49180
    js_set_proto_funcs,
49181
    js_weak_map_proto_funcs,
49182
    js_weak_set_proto_funcs,
49183
    js_map_iterator_proto_funcs,
49184
    js_set_iterator_proto_funcs,
49185
};
49186
49187
static const uint8_t js_map_proto_funcs_count[6] = {
49188
    countof(js_map_proto_funcs),
49189
    countof(js_set_proto_funcs),
49190
    countof(js_weak_map_proto_funcs),
49191
    countof(js_weak_set_proto_funcs),
49192
    countof(js_map_iterator_proto_funcs),
49193
    countof(js_set_iterator_proto_funcs),
49194
};
49195
49196
void JS_AddIntrinsicMapSet(JSContext *ctx)
49197
2
{
49198
2
    int i;
49199
2
    JSValue obj1;
49200
2
    char buf[ATOM_GET_STR_BUF_SIZE];
49201
49202
10
    for(i = 0; i < 4; i++) {
49203
8
        const char *name = JS_AtomGetStr(ctx, buf, sizeof(buf),
49204
8
                                         JS_ATOM_Map + i);
49205
8
        ctx->class_proto[JS_CLASS_MAP + i] = JS_NewObject(ctx);
49206
8
        JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP + i],
49207
8
                                   js_map_proto_funcs_ptr[i],
49208
8
                                   js_map_proto_funcs_count[i]);
49209
8
        obj1 = JS_NewCFunctionMagic(ctx, js_map_constructor, name, 0,
49210
8
                                    JS_CFUNC_constructor_magic, i);
49211
8
        if (i < 2) {
49212
4
            JS_SetPropertyFunctionList(ctx, obj1, js_map_funcs,
49213
4
                                       countof(js_map_funcs));
49214
4
        }
49215
8
        JS_NewGlobalCConstructor2(ctx, obj1, name, ctx->class_proto[JS_CLASS_MAP + i]);
49216
8
    }
49217
49218
6
    for(i = 0; i < 2; i++) {
49219
4
        ctx->class_proto[JS_CLASS_MAP_ITERATOR + i] =
49220
4
            JS_NewObjectProto(ctx, ctx->iterator_proto);
49221
4
        JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_MAP_ITERATOR + i],
49222
4
                                   js_map_proto_funcs_ptr[i + 4],
49223
4
                                   js_map_proto_funcs_count[i + 4]);
49224
4
    }
49225
2
}
49226
49227
/* Generator */
49228
static const JSCFunctionListEntry js_generator_function_proto_funcs[] = {
49229
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "GeneratorFunction", JS_PROP_CONFIGURABLE),
49230
};
49231
49232
static const JSCFunctionListEntry js_generator_proto_funcs[] = {
49233
    JS_ITERATOR_NEXT_DEF("next", 1, js_generator_next, GEN_MAGIC_NEXT ),
49234
    JS_ITERATOR_NEXT_DEF("return", 1, js_generator_next, GEN_MAGIC_RETURN ),
49235
    JS_ITERATOR_NEXT_DEF("throw", 1, js_generator_next, GEN_MAGIC_THROW ),
49236
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Generator", JS_PROP_CONFIGURABLE),
49237
};
49238
49239
/* Promise */
49240
49241
typedef struct JSPromiseData {
49242
    JSPromiseStateEnum promise_state;
49243
    /* 0=fulfill, 1=reject, list of JSPromiseReactionData.link */
49244
    struct list_head promise_reactions[2];
49245
    BOOL is_handled; /* Note: only useful to debug */
49246
    JSValue promise_result;
49247
} JSPromiseData;
49248
49249
typedef struct JSPromiseFunctionDataResolved {
49250
    int ref_count;
49251
    BOOL already_resolved;
49252
} JSPromiseFunctionDataResolved;
49253
49254
typedef struct JSPromiseFunctionData {
49255
    JSValue promise;
49256
    JSPromiseFunctionDataResolved *presolved;
49257
} JSPromiseFunctionData;
49258
49259
typedef struct JSPromiseReactionData {
49260
    struct list_head link; /* not used in promise_reaction_job */
49261
    JSValue resolving_funcs[2];
49262
    JSValue handler;
49263
} JSPromiseReactionData;
49264
49265
JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise)
49266
6
{
49267
6
    JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
49268
6
    if (!s)
49269
1
        return -1;
49270
5
    return s->promise_state;
49271
6
}
49272
49273
JSValue JS_PromiseResult(JSContext *ctx, JSValue promise)
49274
3
{
49275
3
    JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
49276
3
    if (!s)
49277
0
        return JS_UNDEFINED;
49278
3
    return JS_DupValue(ctx, s->promise_result);
49279
3
}
49280
49281
static int js_create_resolving_functions(JSContext *ctx, JSValue *args,
49282
                                         JSValueConst promise);
49283
49284
static void promise_reaction_data_free(JSRuntime *rt,
49285
                                       JSPromiseReactionData *rd)
49286
0
{
49287
0
    JS_FreeValueRT(rt, rd->resolving_funcs[0]);
49288
0
    JS_FreeValueRT(rt, rd->resolving_funcs[1]);
49289
0
    JS_FreeValueRT(rt, rd->handler);
49290
0
    js_free_rt(rt, rd);
49291
0
}
49292
49293
static JSValue promise_reaction_job(JSContext *ctx, int argc,
49294
                                    JSValueConst *argv)
49295
0
{
49296
0
    JSValueConst handler, arg, func;
49297
0
    JSValue res, res2;
49298
0
    BOOL is_reject;
49299
49300
0
    assert(argc == 5);
49301
0
    handler = argv[2];
49302
0
    is_reject = JS_ToBool(ctx, argv[3]);
49303
0
    arg = argv[4];
49304
#ifdef DUMP_PROMISE
49305
    printf("promise_reaction_job: is_reject=%d\n", is_reject);
49306
#endif
49307
49308
0
    if (JS_IsUndefined(handler)) {
49309
0
        if (is_reject) {
49310
0
            res = JS_Throw(ctx, JS_DupValue(ctx, arg));
49311
0
        } else {
49312
0
            res = JS_DupValue(ctx, arg);
49313
0
        }
49314
0
    } else {
49315
0
        res = JS_Call(ctx, handler, JS_UNDEFINED, 1, &arg);
49316
0
    }
49317
0
    is_reject = JS_IsException(res);
49318
0
    if (is_reject)
49319
0
        res = JS_GetException(ctx);
49320
0
    func = argv[is_reject];
49321
    /* as an extension, we support undefined as value to avoid
49322
       creating a dummy promise in the 'await' implementation of async
49323
       functions */
49324
0
    if (!JS_IsUndefined(func)) {
49325
0
        res2 = JS_Call(ctx, func, JS_UNDEFINED,
49326
0
                       1, (JSValueConst *)&res);
49327
0
    } else {
49328
0
        res2 = JS_UNDEFINED;
49329
0
    }
49330
0
    JS_FreeValue(ctx, res);
49331
49332
0
    return res2;
49333
0
}
49334
49335
void JS_SetHostPromiseRejectionTracker(JSRuntime *rt,
49336
                                       JSHostPromiseRejectionTracker *cb,
49337
                                       void *opaque)
49338
0
{
49339
0
    rt->host_promise_rejection_tracker = cb;
49340
0
    rt->host_promise_rejection_tracker_opaque = opaque;
49341
0
}
49342
49343
static void fulfill_or_reject_promise(JSContext *ctx, JSValueConst promise,
49344
                                      JSValueConst value, BOOL is_reject)
49345
6
{
49346
6
    JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
49347
6
    struct list_head *el, *el1;
49348
6
    JSPromiseReactionData *rd;
49349
6
    JSValueConst args[5];
49350
49351
6
    if (!s || s->promise_state != JS_PROMISE_PENDING)
49352
0
        return; /* should never happen */
49353
6
    set_value(ctx, &s->promise_result, JS_DupValue(ctx, value));
49354
6
    s->promise_state = JS_PROMISE_FULFILLED + is_reject;
49355
#ifdef DUMP_PROMISE
49356
    printf("fulfill_or_reject_promise: is_reject=%d\n", is_reject);
49357
#endif
49358
6
    if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {
49359
2
        JSRuntime *rt = ctx->rt;
49360
2
        if (rt->host_promise_rejection_tracker) {
49361
0
            rt->host_promise_rejection_tracker(ctx, promise, value, FALSE,
49362
0
                                               rt->host_promise_rejection_tracker_opaque);
49363
0
        }
49364
2
    }
49365
49366
6
    list_for_each_safe(el, el1, &s->promise_reactions[is_reject]) {
49367
0
        rd = list_entry(el, JSPromiseReactionData, link);
49368
0
        args[0] = rd->resolving_funcs[0];
49369
0
        args[1] = rd->resolving_funcs[1];
49370
0
        args[2] = rd->handler;
49371
0
        args[3] = JS_NewBool(ctx, is_reject);
49372
0
        args[4] = value;
49373
0
        JS_EnqueueJob(ctx, promise_reaction_job, 5, args);
49374
0
        list_del(&rd->link);
49375
0
        promise_reaction_data_free(ctx->rt, rd);
49376
0
    }
49377
49378
6
    list_for_each_safe(el, el1, &s->promise_reactions[1 - is_reject]) {
49379
0
        rd = list_entry(el, JSPromiseReactionData, link);
49380
0
        list_del(&rd->link);
49381
0
        promise_reaction_data_free(ctx->rt, rd);
49382
0
    }
49383
6
}
49384
49385
static void reject_promise(JSContext *ctx, JSValueConst promise,
49386
                           JSValueConst value)
49387
0
{
49388
0
    fulfill_or_reject_promise(ctx, promise, value, TRUE);
49389
0
}
49390
49391
static JSValue js_promise_resolve_thenable_job(JSContext *ctx,
49392
                                               int argc, JSValueConst *argv)
49393
0
{
49394
0
    JSValueConst promise, thenable, then;
49395
0
    JSValue args[2], res;
49396
49397
#ifdef DUMP_PROMISE
49398
    printf("js_promise_resolve_thenable_job\n");
49399
#endif
49400
0
    assert(argc == 3);
49401
0
    promise = argv[0];
49402
0
    thenable = argv[1];
49403
0
    then = argv[2];
49404
0
    if (js_create_resolving_functions(ctx, args, promise) < 0)
49405
0
        return JS_EXCEPTION;
49406
0
    res = JS_Call(ctx, then, thenable, 2, (JSValueConst *)args);
49407
0
    if (JS_IsException(res)) {
49408
0
        JSValue error = JS_GetException(ctx);
49409
0
        res = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error);
49410
0
        JS_FreeValue(ctx, error);
49411
0
    }
49412
0
    JS_FreeValue(ctx, args[0]);
49413
0
    JS_FreeValue(ctx, args[1]);
49414
0
    return res;
49415
0
}
49416
49417
static void js_promise_resolve_function_free_resolved(JSRuntime *rt,
49418
                                                      JSPromiseFunctionDataResolved *sr)
49419
18
{
49420
18
    if (--sr->ref_count == 0) {
49421
6
        js_free_rt(rt, sr);
49422
6
    }
49423
18
}
49424
49425
static int js_create_resolving_functions(JSContext *ctx,
49426
                                         JSValue *resolving_funcs,
49427
                                         JSValueConst promise)
49428
49429
6
{
49430
6
    JSValue obj;
49431
6
    JSPromiseFunctionData *s;
49432
6
    JSPromiseFunctionDataResolved *sr;
49433
6
    int i, ret;
49434
49435
6
    sr = js_malloc(ctx, sizeof(*sr));
49436
6
    if (!sr)
49437
0
        return -1;
49438
6
    sr->ref_count = 1;
49439
6
    sr->already_resolved = FALSE; /* must be shared between the two functions */
49440
6
    ret = 0;
49441
18
    for(i = 0; i < 2; i++) {
49442
12
        obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
49443
12
                                     JS_CLASS_PROMISE_RESOLVE_FUNCTION + i);
49444
12
        if (JS_IsException(obj))
49445
0
            goto fail;
49446
12
        s = js_malloc(ctx, sizeof(*s));
49447
12
        if (!s) {
49448
0
            JS_FreeValue(ctx, obj);
49449
0
        fail:
49450
49451
0
            if (i != 0)
49452
0
                JS_FreeValue(ctx, resolving_funcs[0]);
49453
0
            ret = -1;
49454
0
            break;
49455
0
        }
49456
12
        sr->ref_count++;
49457
12
        s->presolved = sr;
49458
12
        s->promise = JS_DupValue(ctx, promise);
49459
12
        JS_SetOpaque(obj, s);
49460
12
        js_function_set_properties(ctx, obj, JS_ATOM_empty_string, 1);
49461
12
        resolving_funcs[i] = obj;
49462
12
    }
49463
6
    js_promise_resolve_function_free_resolved(ctx->rt, sr);
49464
6
    return ret;
49465
6
}
49466
49467
static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val)
49468
12
{
49469
12
    JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data;
49470
12
    if (s) {
49471
12
        js_promise_resolve_function_free_resolved(rt, s->presolved);
49472
12
        JS_FreeValueRT(rt, s->promise);
49473
12
        js_free_rt(rt, s);
49474
12
    }
49475
12
}
49476
49477
static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
49478
                                             JS_MarkFunc *mark_func)
49479
12
{
49480
12
    JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data;
49481
12
    if (s) {
49482
12
        JS_MarkValue(rt, s->promise, mark_func);
49483
12
    }
49484
12
}
49485
49486
static JSValue js_promise_resolve_function_call(JSContext *ctx,
49487
                                                JSValueConst func_obj,
49488
                                                JSValueConst this_val,
49489
                                                int argc, JSValueConst *argv,
49490
                                                int flags)
49491
6
{
49492
6
    JSObject *p = JS_VALUE_GET_OBJ(func_obj);
49493
6
    JSPromiseFunctionData *s;
49494
6
    JSValueConst resolution, args[3];
49495
6
    JSValue then;
49496
6
    BOOL is_reject;
49497
49498
6
    s = p->u.promise_function_data;
49499
6
    if (!s || s->presolved->already_resolved)
49500
0
        return JS_UNDEFINED;
49501
6
    s->presolved->already_resolved = TRUE;
49502
6
    is_reject = p->class_id - JS_CLASS_PROMISE_RESOLVE_FUNCTION;
49503
6
    if (argc > 0)
49504
6
        resolution = argv[0];
49505
0
    else
49506
0
        resolution = JS_UNDEFINED;
49507
#ifdef DUMP_PROMISE
49508
    printf("js_promise_resolving_function_call: is_reject=%d ", is_reject);
49509
    JS_DumpValue(ctx, "resolution", resolution);
49510
    printf("\n");
49511
#endif
49512
6
    if (is_reject || !JS_IsObject(resolution)) {
49513
6
        goto done;
49514
6
    } else if (js_same_value(ctx, resolution, s->promise)) {
49515
0
        JS_ThrowTypeError(ctx, "promise self resolution");
49516
0
        goto fail_reject;
49517
0
    }
49518
0
    then = JS_GetProperty(ctx, resolution, JS_ATOM_then);
49519
0
    if (JS_IsException(then)) {
49520
0
        JSValue error;
49521
0
    fail_reject:
49522
0
        error = JS_GetException(ctx);
49523
0
        reject_promise(ctx, s->promise, error);
49524
0
        JS_FreeValue(ctx, error);
49525
0
    } else if (!JS_IsFunction(ctx, then)) {
49526
0
        JS_FreeValue(ctx, then);
49527
6
    done:
49528
6
        fulfill_or_reject_promise(ctx, s->promise, resolution, is_reject);
49529
6
    } else {
49530
0
        args[0] = s->promise;
49531
0
        args[1] = resolution;
49532
0
        args[2] = then;
49533
0
        JS_EnqueueJob(ctx, js_promise_resolve_thenable_job, 3, args);
49534
0
        JS_FreeValue(ctx, then);
49535
0
    }
49536
6
    return JS_UNDEFINED;
49537
0
}
49538
49539
static void js_promise_finalizer(JSRuntime *rt, JSValue val)
49540
6
{
49541
6
    JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE);
49542
6
    struct list_head *el, *el1;
49543
6
    int i;
49544
49545
6
    if (!s)
49546
0
        return;
49547
18
    for(i = 0; i < 2; i++) {
49548
12
        list_for_each_safe(el, el1, &s->promise_reactions[i]) {
49549
0
            JSPromiseReactionData *rd =
49550
0
                list_entry(el, JSPromiseReactionData, link);
49551
0
            promise_reaction_data_free(rt, rd);
49552
0
        }
49553
12
    }
49554
6
    JS_FreeValueRT(rt, s->promise_result);
49555
6
    js_free_rt(rt, s);
49556
6
}
49557
49558
static void js_promise_mark(JSRuntime *rt, JSValueConst val,
49559
                            JS_MarkFunc *mark_func)
49560
6
{
49561
6
    JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE);
49562
6
    struct list_head *el;
49563
6
    int i;
49564
49565
6
    if (!s)
49566
0
        return;
49567
18
    for(i = 0; i < 2; i++) {
49568
12
        list_for_each(el, &s->promise_reactions[i]) {
49569
0
            JSPromiseReactionData *rd =
49570
0
                list_entry(el, JSPromiseReactionData, link);
49571
0
            JS_MarkValue(rt, rd->resolving_funcs[0], mark_func);
49572
0
            JS_MarkValue(rt, rd->resolving_funcs[1], mark_func);
49573
0
            JS_MarkValue(rt, rd->handler, mark_func);
49574
0
        }
49575
12
    }
49576
6
    JS_MarkValue(rt, s->promise_result, mark_func);
49577
6
}
49578
49579
static JSValue js_promise_constructor(JSContext *ctx, JSValueConst new_target,
49580
                                      int argc, JSValueConst *argv)
49581
6
{
49582
6
    JSValueConst executor;
49583
6
    JSValue obj;
49584
6
    JSPromiseData *s;
49585
6
    JSValue args[2], ret;
49586
6
    int i;
49587
49588
6
    executor = argv[0];
49589
6
    if (check_function(ctx, executor))
49590
0
        return JS_EXCEPTION;
49591
6
    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_PROMISE);
49592
6
    if (JS_IsException(obj))
49593
0
        return JS_EXCEPTION;
49594
6
    s = js_mallocz(ctx, sizeof(*s));
49595
6
    if (!s)
49596
0
        goto fail;
49597
6
    s->promise_state = JS_PROMISE_PENDING;
49598
6
    s->is_handled = FALSE;
49599
18
    for(i = 0; i < 2; i++)
49600
12
        init_list_head(&s->promise_reactions[i]);
49601
6
    s->promise_result = JS_UNDEFINED;
49602
6
    JS_SetOpaque(obj, s);
49603
6
    if (js_create_resolving_functions(ctx, args, obj))
49604
0
        goto fail;
49605
6
    ret = JS_Call(ctx, executor, JS_UNDEFINED, 2, (JSValueConst *)args);
49606
6
    if (JS_IsException(ret)) {
49607
0
        JSValue ret2, error;
49608
0
        error = JS_GetException(ctx);
49609
0
        ret2 = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error);
49610
0
        JS_FreeValue(ctx, error);
49611
0
        if (JS_IsException(ret2))
49612
0
            goto fail1;
49613
0
        JS_FreeValue(ctx, ret2);
49614
0
    }
49615
6
    JS_FreeValue(ctx, ret);
49616
6
    JS_FreeValue(ctx, args[0]);
49617
6
    JS_FreeValue(ctx, args[1]);
49618
6
    return obj;
49619
0
 fail1:
49620
0
    JS_FreeValue(ctx, args[0]);
49621
0
    JS_FreeValue(ctx, args[1]);
49622
0
 fail:
49623
0
    JS_FreeValue(ctx, obj);
49624
0
    return JS_EXCEPTION;
49625
0
}
49626
49627
static JSValue js_promise_executor(JSContext *ctx,
49628
                                   JSValueConst this_val,
49629
                                   int argc, JSValueConst *argv,
49630
                                   int magic, JSValue *func_data)
49631
6
{
49632
6
    int i;
49633
49634
18
    for(i = 0; i < 2; i++) {
49635
12
        if (!JS_IsUndefined(func_data[i]))
49636
0
            return JS_ThrowTypeError(ctx, "resolving function already set");
49637
12
        func_data[i] = JS_DupValue(ctx, argv[i]);
49638
12
    }
49639
6
    return JS_UNDEFINED;
49640
6
}
49641
49642
static JSValue js_promise_executor_new(JSContext *ctx)
49643
6
{
49644
6
    JSValueConst func_data[2];
49645
49646
6
    func_data[0] = JS_UNDEFINED;
49647
6
    func_data[1] = JS_UNDEFINED;
49648
6
    return JS_NewCFunctionData(ctx, js_promise_executor, 2,
49649
6
                               0, 2, func_data);
49650
6
}
49651
49652
static JSValue js_new_promise_capability(JSContext *ctx,
49653
                                         JSValue *resolving_funcs,
49654
                                         JSValueConst ctor)
49655
6
{
49656
6
    JSValue executor, result_promise;
49657
6
    JSCFunctionDataRecord *s;
49658
6
    int i;
49659
49660
6
    executor = js_promise_executor_new(ctx);
49661
6
    if (JS_IsException(executor))
49662
0
        return executor;
49663
49664
6
    if (JS_IsUndefined(ctor)) {
49665
6
        result_promise = js_promise_constructor(ctx, ctor, 1,
49666
6
                                                (JSValueConst *)&executor);
49667
6
    } else {
49668
0
        result_promise = JS_CallConstructor(ctx, ctor, 1,
49669
0
                                            (JSValueConst *)&executor);
49670
0
    }
49671
6
    if (JS_IsException(result_promise))
49672
0
        goto fail;
49673
6
    s = JS_GetOpaque(executor, JS_CLASS_C_FUNCTION_DATA);
49674
18
    for(i = 0; i < 2; i++) {
49675
12
        if (check_function(ctx, s->data[i]))
49676
0
            goto fail;
49677
12
    }
49678
18
    for(i = 0; i < 2; i++)
49679
12
        resolving_funcs[i] = JS_DupValue(ctx, s->data[i]);
49680
6
    JS_FreeValue(ctx, executor);
49681
6
    return result_promise;
49682
0
 fail:
49683
0
    JS_FreeValue(ctx, executor);
49684
0
    JS_FreeValue(ctx, result_promise);
49685
0
    return JS_EXCEPTION;
49686
6
}
49687
49688
JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs)
49689
6
{
49690
6
    return js_new_promise_capability(ctx, resolving_funcs, JS_UNDEFINED);
49691
6
}
49692
49693
static JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,
49694
                                  int argc, JSValueConst *argv, int magic)
49695
0
{
49696
0
    JSValue result_promise, resolving_funcs[2], ret;
49697
0
    BOOL is_reject = magic;
49698
49699
0
    if (!JS_IsObject(this_val))
49700
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
49701
0
    if (!is_reject && JS_GetOpaque(argv[0], JS_CLASS_PROMISE)) {
49702
0
        JSValue ctor;
49703
0
        BOOL is_same;
49704
0
        ctor = JS_GetProperty(ctx, argv[0], JS_ATOM_constructor);
49705
0
        if (JS_IsException(ctor))
49706
0
            return ctor;
49707
0
        is_same = js_same_value(ctx, ctor, this_val);
49708
0
        JS_FreeValue(ctx, ctor);
49709
0
        if (is_same)
49710
0
            return JS_DupValue(ctx, argv[0]);
49711
0
    }
49712
0
    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
49713
0
    if (JS_IsException(result_promise))
49714
0
        return result_promise;
49715
0
    ret = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED, 1, argv);
49716
0
    JS_FreeValue(ctx, resolving_funcs[0]);
49717
0
    JS_FreeValue(ctx, resolving_funcs[1]);
49718
0
    if (JS_IsException(ret)) {
49719
0
        JS_FreeValue(ctx, result_promise);
49720
0
        return ret;
49721
0
    }
49722
0
    JS_FreeValue(ctx, ret);
49723
0
    return result_promise;
49724
0
}
49725
49726
static JSValue js_promise_withResolvers(JSContext *ctx,
49727
                                        JSValueConst this_val,
49728
                                        int argc, JSValueConst *argv)
49729
0
{
49730
0
    JSValue result_promise, resolving_funcs[2], obj;
49731
0
    if (!JS_IsObject(this_val))
49732
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
49733
0
    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
49734
0
    if (JS_IsException(result_promise))
49735
0
        return result_promise;
49736
0
    obj = JS_NewObject(ctx);
49737
0
    if (JS_IsException(obj)) {
49738
0
        JS_FreeValue(ctx, resolving_funcs[0]);
49739
0
        JS_FreeValue(ctx, resolving_funcs[1]);
49740
0
        JS_FreeValue(ctx, result_promise);
49741
0
        return JS_EXCEPTION;
49742
0
    }
49743
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_promise, result_promise, JS_PROP_C_W_E);
49744
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_resolve, resolving_funcs[0], JS_PROP_C_W_E);
49745
0
    JS_DefinePropertyValue(ctx, obj, JS_ATOM_reject, resolving_funcs[1], JS_PROP_C_W_E);
49746
0
    return obj;
49747
0
}
49748
49749
static JSValue js_promise_try(JSContext *ctx, JSValueConst this_val,
49750
                              int argc, JSValueConst *argv)
49751
0
{
49752
0
    JSValue result_promise, resolving_funcs[2], ret, ret2;
49753
0
    BOOL is_reject = 0;
49754
49755
0
    if (!JS_IsObject(this_val))
49756
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
49757
0
    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
49758
0
    if (JS_IsException(result_promise))
49759
0
        return result_promise;
49760
0
    ret = JS_Call(ctx, argv[0], JS_UNDEFINED, argc - 1, argv + 1);
49761
0
    if (JS_IsException(ret)) {
49762
0
        is_reject = 1;
49763
0
        ret = JS_GetException(ctx);
49764
0
    }
49765
0
    ret2 = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED, 1, (JSValueConst *)&ret);
49766
0
    JS_FreeValue(ctx, resolving_funcs[0]);
49767
0
    JS_FreeValue(ctx, resolving_funcs[1]);
49768
0
    JS_FreeValue(ctx, ret);
49769
0
    if (JS_IsException(ret2)) {
49770
0
        JS_FreeValue(ctx, result_promise);
49771
0
        return ret2;
49772
0
    }
49773
0
    JS_FreeValue(ctx, ret2);
49774
0
    return result_promise;
49775
0
}
49776
49777
static __exception int remainingElementsCount_add(JSContext *ctx,
49778
                                                  JSValueConst resolve_element_env,
49779
                                                  int addend)
49780
0
{
49781
0
    JSValue val;
49782
0
    int remainingElementsCount;
49783
49784
0
    val = JS_GetPropertyUint32(ctx, resolve_element_env, 0);
49785
0
    if (JS_IsException(val))
49786
0
        return -1;
49787
0
    if (JS_ToInt32Free(ctx, &remainingElementsCount, val))
49788
0
        return -1;
49789
0
    remainingElementsCount += addend;
49790
0
    if (JS_SetPropertyUint32(ctx, resolve_element_env, 0,
49791
0
                             JS_NewInt32(ctx, remainingElementsCount)) < 0)
49792
0
        return -1;
49793
0
    return (remainingElementsCount == 0);
49794
0
}
49795
49796
#define PROMISE_MAGIC_all        0
49797
0
#define PROMISE_MAGIC_allSettled 1
49798
0
#define PROMISE_MAGIC_any        2
49799
49800
static JSValue js_promise_all_resolve_element(JSContext *ctx,
49801
                                              JSValueConst this_val,
49802
                                              int argc, JSValueConst *argv,
49803
                                              int magic,
49804
                                              JSValue *func_data)
49805
0
{
49806
0
    int resolve_type = magic & 3;
49807
0
    int is_reject = magic & 4;
49808
0
    BOOL alreadyCalled = JS_ToBool(ctx, func_data[0]);
49809
0
    JSValueConst values = func_data[2];
49810
0
    JSValueConst resolve = func_data[3];
49811
0
    JSValueConst resolve_element_env = func_data[4];
49812
0
    JSValue ret, obj;
49813
0
    int is_zero, index;
49814
49815
0
    if (JS_ToInt32(ctx, &index, func_data[1]))
49816
0
        return JS_EXCEPTION;
49817
0
    if (alreadyCalled)
49818
0
        return JS_UNDEFINED;
49819
0
    func_data[0] = JS_NewBool(ctx, TRUE);
49820
49821
0
    if (resolve_type == PROMISE_MAGIC_allSettled) {
49822
0
        JSValue str;
49823
49824
0
        obj = JS_NewObject(ctx);
49825
0
        if (JS_IsException(obj))
49826
0
            return JS_EXCEPTION;
49827
0
        str = js_new_string8(ctx, is_reject ? "rejected" : "fulfilled");
49828
0
        if (JS_IsException(str))
49829
0
            goto fail1;
49830
0
        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_status,
49831
0
                                   str,
49832
0
                                   JS_PROP_C_W_E) < 0)
49833
0
            goto fail1;
49834
0
        if (JS_DefinePropertyValue(ctx, obj,
49835
0
                                   is_reject ? JS_ATOM_reason : JS_ATOM_value,
49836
0
                                   JS_DupValue(ctx, argv[0]),
49837
0
                                   JS_PROP_C_W_E) < 0) {
49838
0
        fail1:
49839
0
            JS_FreeValue(ctx, obj);
49840
0
            return JS_EXCEPTION;
49841
0
        }
49842
0
    } else {
49843
0
        obj = JS_DupValue(ctx, argv[0]);
49844
0
    }
49845
0
    if (JS_DefinePropertyValueUint32(ctx, values, index,
49846
0
                                     obj, JS_PROP_C_W_E) < 0)
49847
0
        return JS_EXCEPTION;
49848
49849
0
    is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1);
49850
0
    if (is_zero < 0)
49851
0
        return JS_EXCEPTION;
49852
0
    if (is_zero) {
49853
0
        if (resolve_type == PROMISE_MAGIC_any) {
49854
0
            JSValue error;
49855
0
            error = js_aggregate_error_constructor(ctx, values);
49856
0
            if (JS_IsException(error))
49857
0
                return JS_EXCEPTION;
49858
0
            ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&error);
49859
0
            JS_FreeValue(ctx, error);
49860
0
        } else {
49861
0
            ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&values);
49862
0
        }
49863
0
        if (JS_IsException(ret))
49864
0
            return ret;
49865
0
        JS_FreeValue(ctx, ret);
49866
0
    }
49867
0
    return JS_UNDEFINED;
49868
0
}
49869
49870
/* magic = 0: Promise.all 1: Promise.allSettled */
49871
static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
49872
                              int argc, JSValueConst *argv, int magic)
49873
0
{
49874
0
    JSValue result_promise, resolving_funcs[2], item, next_promise, ret;
49875
0
    JSValue next_method = JS_UNDEFINED, values = JS_UNDEFINED;
49876
0
    JSValue resolve_element_env = JS_UNDEFINED, resolve_element, reject_element;
49877
0
    JSValue promise_resolve = JS_UNDEFINED, iter = JS_UNDEFINED;
49878
0
    JSValueConst then_args[2], resolve_element_data[5];
49879
0
    BOOL done;
49880
0
    int index, is_zero, is_promise_any = (magic == PROMISE_MAGIC_any);
49881
49882
0
    if (!JS_IsObject(this_val))
49883
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
49884
0
    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
49885
0
    if (JS_IsException(result_promise))
49886
0
        return result_promise;
49887
0
    promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);
49888
0
    if (JS_IsException(promise_resolve) ||
49889
0
        check_function(ctx, promise_resolve))
49890
0
        goto fail_reject;
49891
0
    iter = JS_GetIterator(ctx, argv[0], FALSE);
49892
0
    if (JS_IsException(iter)) {
49893
0
        JSValue error;
49894
0
    fail_reject:
49895
0
        error = JS_GetException(ctx);
49896
0
        ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
49897
0
                       (JSValueConst *)&error);
49898
0
        JS_FreeValue(ctx, error);
49899
0
        if (JS_IsException(ret))
49900
0
            goto fail;
49901
0
        JS_FreeValue(ctx, ret);
49902
0
    } else {
49903
0
        next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
49904
0
        if (JS_IsException(next_method))
49905
0
            goto fail_reject;
49906
0
        values = JS_NewArray(ctx);
49907
0
        if (JS_IsException(values))
49908
0
            goto fail_reject;
49909
0
        resolve_element_env = JS_NewArray(ctx);
49910
0
        if (JS_IsException(resolve_element_env))
49911
0
            goto fail_reject;
49912
        /* remainingElementsCount field */
49913
0
        if (JS_DefinePropertyValueUint32(ctx, resolve_element_env, 0,
49914
0
                                         JS_NewInt32(ctx, 1),
49915
0
                                         JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
49916
0
            goto fail_reject;
49917
49918
0
        index = 0;
49919
0
        for(;;) {
49920
            /* XXX: conformance: should close the iterator if error on 'done'
49921
               access, but not on 'value' access */
49922
0
            item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
49923
0
            if (JS_IsException(item))
49924
0
                goto fail_reject;
49925
0
            if (done)
49926
0
                break;
49927
0
            next_promise = JS_Call(ctx, promise_resolve,
49928
0
                                   this_val, 1, (JSValueConst *)&item);
49929
0
            JS_FreeValue(ctx, item);
49930
0
            if (JS_IsException(next_promise)) {
49931
0
            fail_reject1:
49932
0
                JS_IteratorClose(ctx, iter, TRUE);
49933
0
                goto fail_reject;
49934
0
            }
49935
0
            resolve_element_data[0] = JS_NewBool(ctx, FALSE);
49936
0
            resolve_element_data[1] = (JSValueConst)JS_NewInt32(ctx, index);
49937
0
            resolve_element_data[2] = values;
49938
0
            resolve_element_data[3] = resolving_funcs[is_promise_any];
49939
0
            resolve_element_data[4] = resolve_element_env;
49940
0
            resolve_element =
49941
0
                JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,
49942
0
                                    magic, 5, resolve_element_data);
49943
0
            if (JS_IsException(resolve_element)) {
49944
0
                JS_FreeValue(ctx, next_promise);
49945
0
                goto fail_reject1;
49946
0
            }
49947
49948
0
            if (magic == PROMISE_MAGIC_allSettled) {
49949
0
                reject_element =
49950
0
                    JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,
49951
0
                                        magic | 4, 5, resolve_element_data);
49952
0
                if (JS_IsException(reject_element)) {
49953
0
                    JS_FreeValue(ctx, next_promise);
49954
0
                    goto fail_reject1;
49955
0
                }
49956
0
            } else if (magic == PROMISE_MAGIC_any) {
49957
0
                if (JS_DefinePropertyValueUint32(ctx, values, index,
49958
0
                                                 JS_UNDEFINED, JS_PROP_C_W_E) < 0)
49959
0
                    goto fail_reject1;
49960
0
                reject_element = resolve_element;
49961
0
                resolve_element = JS_DupValue(ctx, resolving_funcs[0]);
49962
0
            } else {
49963
0
                reject_element = JS_DupValue(ctx, resolving_funcs[1]);
49964
0
            }
49965
49966
0
            if (remainingElementsCount_add(ctx, resolve_element_env, 1) < 0) {
49967
0
                JS_FreeValue(ctx, next_promise);
49968
0
                JS_FreeValue(ctx, resolve_element);
49969
0
                JS_FreeValue(ctx, reject_element);
49970
0
                goto fail_reject1;
49971
0
            }
49972
49973
0
            then_args[0] = resolve_element;
49974
0
            then_args[1] = reject_element;
49975
0
            ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2, then_args);
49976
0
            JS_FreeValue(ctx, resolve_element);
49977
0
            JS_FreeValue(ctx, reject_element);
49978
0
            if (check_exception_free(ctx, ret))
49979
0
                goto fail_reject1;
49980
0
            index++;
49981
0
        }
49982
49983
0
        is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1);
49984
0
        if (is_zero < 0)
49985
0
            goto fail_reject;
49986
0
        if (is_zero) {
49987
0
            if (magic == PROMISE_MAGIC_any) {
49988
0
                JSValue error;
49989
0
                error = js_aggregate_error_constructor(ctx, values);
49990
0
                if (JS_IsException(error))
49991
0
                    goto fail_reject;
49992
0
                JS_FreeValue(ctx, values);
49993
0
                values = error;
49994
0
            }
49995
0
            ret = JS_Call(ctx, resolving_funcs[is_promise_any], JS_UNDEFINED,
49996
0
                          1, (JSValueConst *)&values);
49997
0
            if (check_exception_free(ctx, ret))
49998
0
                goto fail_reject;
49999
0
        }
50000
0
    }
50001
0
 done:
50002
0
    JS_FreeValue(ctx, promise_resolve);
50003
0
    JS_FreeValue(ctx, resolve_element_env);
50004
0
    JS_FreeValue(ctx, values);
50005
0
    JS_FreeValue(ctx, next_method);
50006
0
    JS_FreeValue(ctx, iter);
50007
0
    JS_FreeValue(ctx, resolving_funcs[0]);
50008
0
    JS_FreeValue(ctx, resolving_funcs[1]);
50009
0
    return result_promise;
50010
0
 fail:
50011
0
    JS_FreeValue(ctx, result_promise);
50012
0
    result_promise = JS_EXCEPTION;
50013
0
    goto done;
50014
0
}
50015
50016
static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val,
50017
                               int argc, JSValueConst *argv)
50018
0
{
50019
0
    JSValue result_promise, resolving_funcs[2], item, next_promise, ret;
50020
0
    JSValue next_method = JS_UNDEFINED, iter = JS_UNDEFINED;
50021
0
    JSValue promise_resolve = JS_UNDEFINED;
50022
0
    BOOL done;
50023
50024
0
    if (!JS_IsObject(this_val))
50025
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
50026
0
    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
50027
0
    if (JS_IsException(result_promise))
50028
0
        return result_promise;
50029
0
    promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);
50030
0
    if (JS_IsException(promise_resolve) ||
50031
0
        check_function(ctx, promise_resolve))
50032
0
        goto fail_reject;
50033
0
    iter = JS_GetIterator(ctx, argv[0], FALSE);
50034
0
    if (JS_IsException(iter)) {
50035
0
        JSValue error;
50036
0
    fail_reject:
50037
0
        error = JS_GetException(ctx);
50038
0
        ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,
50039
0
                       (JSValueConst *)&error);
50040
0
        JS_FreeValue(ctx, error);
50041
0
        if (JS_IsException(ret))
50042
0
            goto fail;
50043
0
        JS_FreeValue(ctx, ret);
50044
0
    } else {
50045
0
        next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
50046
0
        if (JS_IsException(next_method))
50047
0
            goto fail_reject;
50048
50049
0
        for(;;) {
50050
            /* XXX: conformance: should close the iterator if error on 'done'
50051
               access, but not on 'value' access */
50052
0
            item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
50053
0
            if (JS_IsException(item))
50054
0
                goto fail_reject;
50055
0
            if (done)
50056
0
                break;
50057
0
            next_promise = JS_Call(ctx, promise_resolve,
50058
0
                                   this_val, 1, (JSValueConst *)&item);
50059
0
            JS_FreeValue(ctx, item);
50060
0
            if (JS_IsException(next_promise)) {
50061
0
            fail_reject1:
50062
0
                JS_IteratorClose(ctx, iter, TRUE);
50063
0
                goto fail_reject;
50064
0
            }
50065
0
            ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2,
50066
0
                                (JSValueConst *)resolving_funcs);
50067
0
            if (check_exception_free(ctx, ret))
50068
0
                goto fail_reject1;
50069
0
        }
50070
0
    }
50071
0
 done:
50072
0
    JS_FreeValue(ctx, promise_resolve);
50073
0
    JS_FreeValue(ctx, next_method);
50074
0
    JS_FreeValue(ctx, iter);
50075
0
    JS_FreeValue(ctx, resolving_funcs[0]);
50076
0
    JS_FreeValue(ctx, resolving_funcs[1]);
50077
0
    return result_promise;
50078
0
 fail:
50079
    //JS_FreeValue(ctx, next_method); // why not???
50080
0
    JS_FreeValue(ctx, result_promise);
50081
0
    result_promise = JS_EXCEPTION;
50082
0
    goto done;
50083
0
}
50084
50085
static __exception int perform_promise_then(JSContext *ctx,
50086
                                            JSValueConst promise,
50087
                                            JSValueConst *resolve_reject,
50088
                                            JSValueConst *cap_resolving_funcs)
50089
0
{
50090
0
    JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);
50091
0
    JSPromiseReactionData *rd_array[2], *rd;
50092
0
    int i, j;
50093
50094
0
    rd_array[0] = NULL;
50095
0
    rd_array[1] = NULL;
50096
0
    for(i = 0; i < 2; i++) {
50097
0
        JSValueConst handler;
50098
0
        rd = js_mallocz(ctx, sizeof(*rd));
50099
0
        if (!rd) {
50100
0
            if (i == 1)
50101
0
                promise_reaction_data_free(ctx->rt, rd_array[0]);
50102
0
            return -1;
50103
0
        }
50104
0
        for(j = 0; j < 2; j++)
50105
0
            rd->resolving_funcs[j] = JS_DupValue(ctx, cap_resolving_funcs[j]);
50106
0
        handler = resolve_reject[i];
50107
0
        if (!JS_IsFunction(ctx, handler))
50108
0
            handler = JS_UNDEFINED;
50109
0
        rd->handler = JS_DupValue(ctx, handler);
50110
0
        rd_array[i] = rd;
50111
0
    }
50112
50113
0
    if (s->promise_state == JS_PROMISE_PENDING) {
50114
0
        for(i = 0; i < 2; i++)
50115
0
            list_add_tail(&rd_array[i]->link, &s->promise_reactions[i]);
50116
0
    } else {
50117
0
        JSValueConst args[5];
50118
0
        if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {
50119
0
            JSRuntime *rt = ctx->rt;
50120
0
            if (rt->host_promise_rejection_tracker) {
50121
0
                rt->host_promise_rejection_tracker(ctx, promise, s->promise_result,
50122
0
                                                   TRUE, rt->host_promise_rejection_tracker_opaque);
50123
0
            }
50124
0
        }
50125
0
        i = s->promise_state - JS_PROMISE_FULFILLED;
50126
0
        rd = rd_array[i];
50127
0
        args[0] = rd->resolving_funcs[0];
50128
0
        args[1] = rd->resolving_funcs[1];
50129
0
        args[2] = rd->handler;
50130
0
        args[3] = JS_NewBool(ctx, i);
50131
0
        args[4] = s->promise_result;
50132
0
        JS_EnqueueJob(ctx, promise_reaction_job, 5, args);
50133
0
        for(i = 0; i < 2; i++)
50134
0
            promise_reaction_data_free(ctx->rt, rd_array[i]);
50135
0
    }
50136
0
    s->is_handled = TRUE;
50137
0
    return 0;
50138
0
}
50139
50140
static JSValue js_promise_then(JSContext *ctx, JSValueConst this_val,
50141
                               int argc, JSValueConst *argv)
50142
0
{
50143
0
    JSValue ctor, result_promise, resolving_funcs[2];
50144
0
    JSPromiseData *s;
50145
0
    int i, ret;
50146
50147
0
    s = JS_GetOpaque2(ctx, this_val, JS_CLASS_PROMISE);
50148
0
    if (!s)
50149
0
        return JS_EXCEPTION;
50150
50151
0
    ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
50152
0
    if (JS_IsException(ctor))
50153
0
        return ctor;
50154
0
    result_promise = js_new_promise_capability(ctx, resolving_funcs, ctor);
50155
0
    JS_FreeValue(ctx, ctor);
50156
0
    if (JS_IsException(result_promise))
50157
0
        return result_promise;
50158
0
    ret = perform_promise_then(ctx, this_val, argv,
50159
0
                               (JSValueConst *)resolving_funcs);
50160
0
    for(i = 0; i < 2; i++)
50161
0
        JS_FreeValue(ctx, resolving_funcs[i]);
50162
0
    if (ret) {
50163
0
        JS_FreeValue(ctx, result_promise);
50164
0
        return JS_EXCEPTION;
50165
0
    }
50166
0
    return result_promise;
50167
0
}
50168
50169
static JSValue js_promise_catch(JSContext *ctx, JSValueConst this_val,
50170
                                int argc, JSValueConst *argv)
50171
0
{
50172
0
    JSValueConst args[2];
50173
0
    args[0] = JS_UNDEFINED;
50174
0
    args[1] = argv[0];
50175
0
    return JS_Invoke(ctx, this_val, JS_ATOM_then, 2, args);
50176
0
}
50177
50178
static JSValue js_promise_finally_value_thunk(JSContext *ctx, JSValueConst this_val,
50179
                                              int argc, JSValueConst *argv,
50180
                                              int magic, JSValue *func_data)
50181
0
{
50182
0
    return JS_DupValue(ctx, func_data[0]);
50183
0
}
50184
50185
static JSValue js_promise_finally_thrower(JSContext *ctx, JSValueConst this_val,
50186
                                          int argc, JSValueConst *argv,
50187
                                          int magic, JSValue *func_data)
50188
0
{
50189
0
    return JS_Throw(ctx, JS_DupValue(ctx, func_data[0]));
50190
0
}
50191
50192
static JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_val,
50193
                                            int argc, JSValueConst *argv,
50194
                                            int magic, JSValue *func_data)
50195
0
{
50196
0
    JSValueConst ctor = func_data[0];
50197
0
    JSValueConst onFinally = func_data[1];
50198
0
    JSValue res, promise, ret, then_func;
50199
50200
0
    res = JS_Call(ctx, onFinally, JS_UNDEFINED, 0, NULL);
50201
0
    if (JS_IsException(res))
50202
0
        return res;
50203
0
    promise = js_promise_resolve(ctx, ctor, 1, (JSValueConst *)&res, 0);
50204
0
    JS_FreeValue(ctx, res);
50205
0
    if (JS_IsException(promise))
50206
0
        return promise;
50207
0
    if (magic == 0) {
50208
0
        then_func = JS_NewCFunctionData(ctx, js_promise_finally_value_thunk, 0,
50209
0
                                        0, 1, argv);
50210
0
    } else {
50211
0
        then_func = JS_NewCFunctionData(ctx, js_promise_finally_thrower, 0,
50212
0
                                        0, 1, argv);
50213
0
    }
50214
0
    if (JS_IsException(then_func)) {
50215
0
        JS_FreeValue(ctx, promise);
50216
0
        return then_func;
50217
0
    }
50218
0
    ret = JS_InvokeFree(ctx, promise, JS_ATOM_then, 1, (JSValueConst *)&then_func);
50219
0
    JS_FreeValue(ctx, then_func);
50220
0
    return ret;
50221
0
}
50222
50223
static JSValue js_promise_finally(JSContext *ctx, JSValueConst this_val,
50224
                                  int argc, JSValueConst *argv)
50225
0
{
50226
0
    JSValueConst onFinally = argv[0];
50227
0
    JSValue ctor, ret;
50228
0
    JSValue then_funcs[2];
50229
0
    JSValueConst func_data[2];
50230
0
    int i;
50231
50232
0
    ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
50233
0
    if (JS_IsException(ctor))
50234
0
        return ctor;
50235
0
    if (!JS_IsFunction(ctx, onFinally)) {
50236
0
        then_funcs[0] = JS_DupValue(ctx, onFinally);
50237
0
        then_funcs[1] = JS_DupValue(ctx, onFinally);
50238
0
    } else {
50239
0
        func_data[0] = ctor;
50240
0
        func_data[1] = onFinally;
50241
0
        for(i = 0; i < 2; i++) {
50242
0
            then_funcs[i] = JS_NewCFunctionData(ctx, js_promise_then_finally_func, 1, i, 2, func_data);
50243
0
            if (JS_IsException(then_funcs[i])) {
50244
0
                if (i == 1)
50245
0
                    JS_FreeValue(ctx, then_funcs[0]);
50246
0
                JS_FreeValue(ctx, ctor);
50247
0
                return JS_EXCEPTION;
50248
0
            }
50249
0
        }
50250
0
    }
50251
0
    JS_FreeValue(ctx, ctor);
50252
0
    ret = JS_Invoke(ctx, this_val, JS_ATOM_then, 2, (JSValueConst *)then_funcs);
50253
0
    JS_FreeValue(ctx, then_funcs[0]);
50254
0
    JS_FreeValue(ctx, then_funcs[1]);
50255
0
    return ret;
50256
0
}
50257
50258
static const JSCFunctionListEntry js_promise_funcs[] = {
50259
    JS_CFUNC_MAGIC_DEF("resolve", 1, js_promise_resolve, 0 ),
50260
    JS_CFUNC_MAGIC_DEF("reject", 1, js_promise_resolve, 1 ),
50261
    JS_CFUNC_MAGIC_DEF("all", 1, js_promise_all, PROMISE_MAGIC_all ),
50262
    JS_CFUNC_MAGIC_DEF("allSettled", 1, js_promise_all, PROMISE_MAGIC_allSettled ),
50263
    JS_CFUNC_MAGIC_DEF("any", 1, js_promise_all, PROMISE_MAGIC_any ),
50264
    JS_CFUNC_DEF("try", 1, js_promise_try ),
50265
    JS_CFUNC_DEF("race", 1, js_promise_race ),
50266
    JS_CFUNC_DEF("withResolvers", 0, js_promise_withResolvers ),
50267
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL),
50268
};
50269
50270
static const JSCFunctionListEntry js_promise_proto_funcs[] = {
50271
    JS_CFUNC_DEF("then", 2, js_promise_then ),
50272
    JS_CFUNC_DEF("catch", 1, js_promise_catch ),
50273
    JS_CFUNC_DEF("finally", 1, js_promise_finally ),
50274
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Promise", JS_PROP_CONFIGURABLE ),
50275
};
50276
50277
/* AsyncFunction */
50278
static const JSCFunctionListEntry js_async_function_proto_funcs[] = {
50279
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncFunction", JS_PROP_CONFIGURABLE ),
50280
};
50281
50282
/* AsyncIteratorPrototype */
50283
50284
static const JSCFunctionListEntry js_async_iterator_proto_funcs[] = {
50285
    JS_CFUNC_DEF("[Symbol.asyncIterator]", 0, js_iterator_proto_iterator ),
50286
};
50287
50288
/* AsyncFromSyncIteratorPrototype */
50289
50290
typedef struct JSAsyncFromSyncIteratorData {
50291
    JSValue sync_iter;
50292
    JSValue next_method;
50293
} JSAsyncFromSyncIteratorData;
50294
50295
static void js_async_from_sync_iterator_finalizer(JSRuntime *rt, JSValue val)
50296
0
{
50297
0
    JSAsyncFromSyncIteratorData *s =
50298
0
        JS_GetOpaque(val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
50299
0
    if (s) {
50300
0
        JS_FreeValueRT(rt, s->sync_iter);
50301
0
        JS_FreeValueRT(rt, s->next_method);
50302
0
        js_free_rt(rt, s);
50303
0
    }
50304
0
}
50305
50306
static void js_async_from_sync_iterator_mark(JSRuntime *rt, JSValueConst val,
50307
                                             JS_MarkFunc *mark_func)
50308
0
{
50309
0
    JSAsyncFromSyncIteratorData *s =
50310
0
        JS_GetOpaque(val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
50311
0
    if (s) {
50312
0
        JS_MarkValue(rt, s->sync_iter, mark_func);
50313
0
        JS_MarkValue(rt, s->next_method, mark_func);
50314
0
    }
50315
0
}
50316
50317
static JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx,
50318
                                              JSValueConst sync_iter)
50319
0
{
50320
0
    JSValue async_iter, next_method;
50321
0
    JSAsyncFromSyncIteratorData *s;
50322
50323
0
    next_method = JS_GetProperty(ctx, sync_iter, JS_ATOM_next);
50324
0
    if (JS_IsException(next_method))
50325
0
        return JS_EXCEPTION;
50326
0
    async_iter = JS_NewObjectClass(ctx, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
50327
0
    if (JS_IsException(async_iter)) {
50328
0
        JS_FreeValue(ctx, next_method);
50329
0
        return async_iter;
50330
0
    }
50331
0
    s = js_mallocz(ctx, sizeof(*s));
50332
0
    if (!s) {
50333
0
        JS_FreeValue(ctx, async_iter);
50334
0
        JS_FreeValue(ctx, next_method);
50335
0
        return JS_EXCEPTION;
50336
0
    }
50337
0
    s->sync_iter = JS_DupValue(ctx, sync_iter);
50338
0
    s->next_method = next_method;
50339
0
    JS_SetOpaque(async_iter, s);
50340
0
    return async_iter;
50341
0
}
50342
50343
static JSValue js_async_from_sync_iterator_unwrap(JSContext *ctx,
50344
                                                  JSValueConst this_val,
50345
                                                  int argc, JSValueConst *argv,
50346
                                                  int magic, JSValue *func_data)
50347
0
{
50348
0
    return js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]),
50349
0
                                     JS_ToBool(ctx, func_data[0]));
50350
0
}
50351
50352
static JSValue js_async_from_sync_iterator_unwrap_func_create(JSContext *ctx,
50353
                                                              BOOL done)
50354
0
{
50355
0
    JSValueConst func_data[1];
50356
50357
0
    func_data[0] = (JSValueConst)JS_NewBool(ctx, done);
50358
0
    return JS_NewCFunctionData(ctx, js_async_from_sync_iterator_unwrap,
50359
0
                               1, 0, 1, func_data);
50360
0
}
50361
50362
static JSValue js_async_from_sync_iterator_close_wrap(JSContext *ctx,
50363
                                                      JSValueConst this_val,
50364
                                                      int argc, JSValueConst *argv,
50365
                                                      int magic, JSValue *func_data)
50366
0
{
50367
0
    JS_Throw(ctx, JS_DupValue(ctx, argv[0]));
50368
0
    JS_IteratorClose(ctx, func_data[0], TRUE);
50369
0
    return JS_EXCEPTION;
50370
0
}
50371
50372
static JSValue js_async_from_sync_iterator_close_wrap_func_create(JSContext *ctx, JSValueConst sync_iter)
50373
0
{
50374
0
    return JS_NewCFunctionData(ctx, js_async_from_sync_iterator_close_wrap,
50375
0
                               1, 0, 1, &sync_iter);
50376
0
}
50377
50378
static JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst this_val,
50379
                                                int argc, JSValueConst *argv,
50380
                                                int magic)
50381
0
{
50382
0
    JSValue promise, resolving_funcs[2], value, err, method;
50383
0
    JSAsyncFromSyncIteratorData *s;
50384
0
    int done;
50385
0
    int is_reject;
50386
50387
0
    promise = JS_NewPromiseCapability(ctx, resolving_funcs);
50388
0
    if (JS_IsException(promise))
50389
0
        return JS_EXCEPTION;
50390
0
    s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);
50391
0
    if (!s) {
50392
0
        JS_ThrowTypeError(ctx, "not an Async-from-Sync Iterator");
50393
0
        goto reject;
50394
0
    }
50395
50396
0
    if (magic == GEN_MAGIC_NEXT) {
50397
0
        method = JS_DupValue(ctx, s->next_method);
50398
0
    } else {
50399
0
        method = JS_GetProperty(ctx, s->sync_iter,
50400
0
                                magic == GEN_MAGIC_RETURN ? JS_ATOM_return :
50401
0
                                JS_ATOM_throw);
50402
0
        if (JS_IsException(method))
50403
0
            goto reject;
50404
0
        if (JS_IsUndefined(method) || JS_IsNull(method)) {
50405
0
            if (magic == GEN_MAGIC_RETURN) {
50406
0
                err = js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]), TRUE);
50407
0
                is_reject = 0;
50408
0
                goto done_resolve;
50409
0
            } else {
50410
0
                if (JS_IteratorClose(ctx, s->sync_iter, FALSE))
50411
0
                    goto reject;
50412
0
                JS_ThrowTypeError(ctx, "throw is not a method");
50413
0
                goto reject;
50414
0
            }
50415
0
        }
50416
0
    }
50417
0
    value = JS_IteratorNext2(ctx, s->sync_iter, method,
50418
0
                             argc >= 1 ? 1 : 0, argv, &done);
50419
0
    JS_FreeValue(ctx, method);
50420
0
    if (JS_IsException(value))
50421
0
        goto reject;
50422
0
    if (done == 2) {
50423
0
        JSValue obj = value;
50424
0
        value = JS_IteratorGetCompleteValue(ctx, obj, &done);
50425
0
        JS_FreeValue(ctx, obj);
50426
0
        if (JS_IsException(value))
50427
0
            goto reject;
50428
0
    }
50429
    
50430
0
    if (JS_IsException(value))
50431
0
        goto reject;
50432
0
    {
50433
0
        JSValue value_wrapper_promise, resolve_reject[2];
50434
0
        int res;
50435
50436
0
        value_wrapper_promise = js_promise_resolve(ctx, ctx->promise_ctor,
50437
0
                                                   1, (JSValueConst *)&value, 0);
50438
0
        if (JS_IsException(value_wrapper_promise)) {
50439
0
            JSValue res2;
50440
0
            JS_FreeValue(ctx, value);
50441
0
            if (magic != GEN_MAGIC_RETURN && !done) {
50442
0
                JS_IteratorClose(ctx, s->sync_iter, TRUE);
50443
0
            }
50444
0
        reject:
50445
0
            err = JS_GetException(ctx);
50446
0
            is_reject = 1;
50447
0
        done_resolve:
50448
0
            res2 = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED,
50449
0
                           1, (JSValueConst *)&err);
50450
0
            JS_FreeValue(ctx, err);
50451
0
            JS_FreeValue(ctx, res2);
50452
0
            JS_FreeValue(ctx, resolving_funcs[0]);
50453
0
            JS_FreeValue(ctx, resolving_funcs[1]);
50454
0
            return promise;
50455
0
        }
50456
50457
0
        resolve_reject[0] =
50458
0
            js_async_from_sync_iterator_unwrap_func_create(ctx, done);
50459
0
        if (JS_IsException(resolve_reject[0])) {
50460
0
            JS_FreeValue(ctx, value_wrapper_promise);
50461
0
            goto fail;
50462
0
        }
50463
0
        if (done || magic == GEN_MAGIC_RETURN) {
50464
0
            resolve_reject[1] = JS_UNDEFINED;
50465
0
        } else {
50466
0
            resolve_reject[1] =
50467
0
                js_async_from_sync_iterator_close_wrap_func_create(ctx, s->sync_iter);
50468
0
            if (JS_IsException(resolve_reject[1])) {
50469
0
                JS_FreeValue(ctx, value_wrapper_promise);
50470
0
                JS_FreeValue(ctx, resolve_reject[0]);
50471
0
                goto fail;
50472
0
            }
50473
0
        }
50474
0
        JS_FreeValue(ctx, value);
50475
0
        res = perform_promise_then(ctx, value_wrapper_promise,
50476
0
                                   (JSValueConst *)resolve_reject,
50477
0
                                   (JSValueConst *)resolving_funcs);
50478
0
        JS_FreeValue(ctx, resolve_reject[0]);
50479
0
        JS_FreeValue(ctx, resolve_reject[1]);
50480
0
        JS_FreeValue(ctx, value_wrapper_promise);
50481
0
        JS_FreeValue(ctx, resolving_funcs[0]);
50482
0
        JS_FreeValue(ctx, resolving_funcs[1]);
50483
0
        if (res) {
50484
0
            JS_FreeValue(ctx, promise);
50485
0
            return JS_EXCEPTION;
50486
0
        }
50487
0
    }
50488
0
    return promise;
50489
0
 fail:
50490
0
    JS_FreeValue(ctx, value);
50491
0
    JS_FreeValue(ctx, resolving_funcs[0]);
50492
0
    JS_FreeValue(ctx, resolving_funcs[1]);
50493
0
    JS_FreeValue(ctx, promise);
50494
0
    return JS_EXCEPTION;
50495
0
}
50496
50497
static const JSCFunctionListEntry js_async_from_sync_iterator_proto_funcs[] = {
50498
    JS_CFUNC_MAGIC_DEF("next", 1, js_async_from_sync_iterator_next, GEN_MAGIC_NEXT ),
50499
    JS_CFUNC_MAGIC_DEF("return", 1, js_async_from_sync_iterator_next, GEN_MAGIC_RETURN ),
50500
    JS_CFUNC_MAGIC_DEF("throw", 1, js_async_from_sync_iterator_next, GEN_MAGIC_THROW ),
50501
};
50502
50503
/* AsyncGeneratorFunction */
50504
50505
static const JSCFunctionListEntry js_async_generator_function_proto_funcs[] = {
50506
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncGeneratorFunction", JS_PROP_CONFIGURABLE ),
50507
};
50508
50509
/* AsyncGenerator prototype */
50510
50511
static const JSCFunctionListEntry js_async_generator_proto_funcs[] = {
50512
    JS_CFUNC_MAGIC_DEF("next", 1, js_async_generator_next, GEN_MAGIC_NEXT ),
50513
    JS_CFUNC_MAGIC_DEF("return", 1, js_async_generator_next, GEN_MAGIC_RETURN ),
50514
    JS_CFUNC_MAGIC_DEF("throw", 1, js_async_generator_next, GEN_MAGIC_THROW ),
50515
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "AsyncGenerator", JS_PROP_CONFIGURABLE ),
50516
};
50517
50518
static JSClassShortDef const js_async_class_def[] = {
50519
    { JS_ATOM_Promise, js_promise_finalizer, js_promise_mark },                      /* JS_CLASS_PROMISE */
50520
    { JS_ATOM_PromiseResolveFunction, js_promise_resolve_function_finalizer, js_promise_resolve_function_mark }, /* JS_CLASS_PROMISE_RESOLVE_FUNCTION */
50521
    { JS_ATOM_PromiseRejectFunction, js_promise_resolve_function_finalizer, js_promise_resolve_function_mark }, /* JS_CLASS_PROMISE_REJECT_FUNCTION */
50522
    { JS_ATOM_AsyncFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_ASYNC_FUNCTION */
50523
    { JS_ATOM_AsyncFunctionResolve, js_async_function_resolve_finalizer, js_async_function_resolve_mark }, /* JS_CLASS_ASYNC_FUNCTION_RESOLVE */
50524
    { JS_ATOM_AsyncFunctionReject, js_async_function_resolve_finalizer, js_async_function_resolve_mark }, /* JS_CLASS_ASYNC_FUNCTION_REJECT */
50525
    { JS_ATOM_empty_string, js_async_from_sync_iterator_finalizer, js_async_from_sync_iterator_mark }, /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */
50526
    { JS_ATOM_AsyncGeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_ASYNC_GENERATOR_FUNCTION */
50527
    { JS_ATOM_AsyncGenerator, js_async_generator_finalizer, js_async_generator_mark },  /* JS_CLASS_ASYNC_GENERATOR */
50528
};
50529
50530
void JS_AddIntrinsicPromise(JSContext *ctx)
50531
2
{
50532
2
    JSRuntime *rt = ctx->rt;
50533
2
    JSValue obj1;
50534
50535
2
    if (!JS_IsRegisteredClass(rt, JS_CLASS_PROMISE)) {
50536
2
        init_class_range(rt, js_async_class_def, JS_CLASS_PROMISE,
50537
2
                         countof(js_async_class_def));
50538
2
        rt->class_array[JS_CLASS_PROMISE_RESOLVE_FUNCTION].call = js_promise_resolve_function_call;
50539
2
        rt->class_array[JS_CLASS_PROMISE_REJECT_FUNCTION].call = js_promise_resolve_function_call;
50540
2
        rt->class_array[JS_CLASS_ASYNC_FUNCTION].call = js_async_function_call;
50541
2
        rt->class_array[JS_CLASS_ASYNC_FUNCTION_RESOLVE].call = js_async_function_resolve_call;
50542
2
        rt->class_array[JS_CLASS_ASYNC_FUNCTION_REJECT].call = js_async_function_resolve_call;
50543
2
        rt->class_array[JS_CLASS_ASYNC_GENERATOR_FUNCTION].call = js_async_generator_function_call;
50544
2
    }
50545
50546
    /* Promise */
50547
2
    ctx->class_proto[JS_CLASS_PROMISE] = JS_NewObject(ctx);
50548
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_PROMISE],
50549
2
                               js_promise_proto_funcs,
50550
2
                               countof(js_promise_proto_funcs));
50551
2
    obj1 = JS_NewCFunction2(ctx, js_promise_constructor, "Promise", 1,
50552
2
                            JS_CFUNC_constructor, 0);
50553
2
    ctx->promise_ctor = JS_DupValue(ctx, obj1);
50554
2
    JS_SetPropertyFunctionList(ctx, obj1,
50555
2
                               js_promise_funcs,
50556
2
                               countof(js_promise_funcs));
50557
2
    JS_NewGlobalCConstructor2(ctx, obj1, "Promise",
50558
2
                              ctx->class_proto[JS_CLASS_PROMISE]);
50559
50560
    /* AsyncFunction */
50561
2
    ctx->class_proto[JS_CLASS_ASYNC_FUNCTION] = JS_NewObjectProto(ctx, ctx->function_proto);
50562
2
    obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor,
50563
2
                            "AsyncFunction", 1,
50564
2
                            JS_CFUNC_constructor_or_func_magic, JS_FUNC_ASYNC,
50565
2
                            ctx->function_ctor);
50566
2
    JS_SetPropertyFunctionList(ctx,
50567
2
                               ctx->class_proto[JS_CLASS_ASYNC_FUNCTION],
50568
2
                               js_async_function_proto_funcs,
50569
2
                               countof(js_async_function_proto_funcs));
50570
2
    JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_ASYNC_FUNCTION],
50571
2
                       0, JS_PROP_CONFIGURABLE);
50572
2
    JS_FreeValue(ctx, obj1);
50573
50574
    /* AsyncIteratorPrototype */
50575
2
    ctx->async_iterator_proto = JS_NewObject(ctx);
50576
2
    JS_SetPropertyFunctionList(ctx, ctx->async_iterator_proto,
50577
2
                               js_async_iterator_proto_funcs,
50578
2
                               countof(js_async_iterator_proto_funcs));
50579
50580
    /* AsyncFromSyncIteratorPrototype */
50581
2
    ctx->class_proto[JS_CLASS_ASYNC_FROM_SYNC_ITERATOR] =
50582
2
        JS_NewObjectProto(ctx, ctx->async_iterator_proto);
50583
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ASYNC_FROM_SYNC_ITERATOR],
50584
2
                               js_async_from_sync_iterator_proto_funcs,
50585
2
                               countof(js_async_from_sync_iterator_proto_funcs));
50586
50587
    /* AsyncGeneratorPrototype */
50588
2
    ctx->class_proto[JS_CLASS_ASYNC_GENERATOR] =
50589
2
        JS_NewObjectProto(ctx, ctx->async_iterator_proto);
50590
2
    JS_SetPropertyFunctionList(ctx,
50591
2
                               ctx->class_proto[JS_CLASS_ASYNC_GENERATOR],
50592
2
                               js_async_generator_proto_funcs,
50593
2
                               countof(js_async_generator_proto_funcs));
50594
50595
    /* AsyncGeneratorFunction */
50596
2
    ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION] =
50597
2
        JS_NewObjectProto(ctx, ctx->function_proto);
50598
2
    obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor,
50599
2
                            "AsyncGeneratorFunction", 1,
50600
2
                            JS_CFUNC_constructor_or_func_magic,
50601
2
                            JS_FUNC_ASYNC_GENERATOR,
50602
2
                            ctx->function_ctor);
50603
2
    JS_SetPropertyFunctionList(ctx,
50604
2
                               ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
50605
2
                               js_async_generator_function_proto_funcs,
50606
2
                               countof(js_async_generator_function_proto_funcs));
50607
2
    JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
50608
2
                       ctx->class_proto[JS_CLASS_ASYNC_GENERATOR],
50609
2
                       JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE);
50610
2
    JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],
50611
2
                       0, JS_PROP_CONFIGURABLE);
50612
2
    JS_FreeValue(ctx, obj1);
50613
2
}
50614
50615
/* URI handling */
50616
50617
0
static int string_get_hex(JSString *p, int k, int n) {
50618
0
    int c = 0, h;
50619
0
    while (n-- > 0) {
50620
0
        if ((h = from_hex(string_get(p, k++))) < 0)
50621
0
            return -1;
50622
0
        c = (c << 4) | h;
50623
0
    }
50624
0
    return c;
50625
0
}
50626
50627
0
static int isURIReserved(int c) {
50628
0
    return c < 0x100 && memchr(";/?:@&=+$,#", c, sizeof(";/?:@&=+$,#") - 1) != NULL;
50629
0
}
50630
50631
static int __attribute__((format(printf, 2, 3))) js_throw_URIError(JSContext *ctx, const char *fmt, ...)
50632
0
{
50633
0
    va_list ap;
50634
50635
0
    va_start(ap, fmt);
50636
0
    JS_ThrowError(ctx, JS_URI_ERROR, fmt, ap);
50637
0
    va_end(ap);
50638
0
    return -1;
50639
0
}
50640
50641
0
static int hex_decode(JSContext *ctx, JSString *p, int k) {
50642
0
    int c;
50643
50644
0
    if (k >= p->len || string_get(p, k) != '%')
50645
0
        return js_throw_URIError(ctx, "expecting %%");
50646
0
    if (k + 2 >= p->len || (c = string_get_hex(p, k + 1, 2)) < 0)
50647
0
        return js_throw_URIError(ctx, "expecting hex digit");
50648
50649
0
    return c;
50650
0
}
50651
50652
static JSValue js_global_decodeURI(JSContext *ctx, JSValueConst this_val,
50653
                                   int argc, JSValueConst *argv, int isComponent)
50654
0
{
50655
0
    JSValue str;
50656
0
    StringBuffer b_s, *b = &b_s;
50657
0
    JSString *p;
50658
0
    int k, c, c1, n, c_min;
50659
50660
0
    str = JS_ToString(ctx, argv[0]);
50661
0
    if (JS_IsException(str))
50662
0
        return str;
50663
50664
0
    string_buffer_init(ctx, b, 0);
50665
50666
0
    p = JS_VALUE_GET_STRING(str);
50667
0
    for (k = 0; k < p->len;) {
50668
0
        c = string_get(p, k);
50669
0
        if (c == '%') {
50670
0
            c = hex_decode(ctx, p, k);
50671
0
            if (c < 0)
50672
0
                goto fail;
50673
0
            k += 3;
50674
0
            if (c < 0x80) {
50675
0
                if (!isComponent && isURIReserved(c)) {
50676
0
                    c = '%';
50677
0
                    k -= 2;
50678
0
                }
50679
0
            } else {
50680
                /* Decode URI-encoded UTF-8 sequence */
50681
0
                if (c >= 0xc0 && c <= 0xdf) {
50682
0
                    n = 1;
50683
0
                    c_min = 0x80;
50684
0
                    c &= 0x1f;
50685
0
                } else if (c >= 0xe0 && c <= 0xef) {
50686
0
                    n = 2;
50687
0
                    c_min = 0x800;
50688
0
                    c &= 0xf;
50689
0
                } else if (c >= 0xf0 && c <= 0xf7) {
50690
0
                    n = 3;
50691
0
                    c_min = 0x10000;
50692
0
                    c &= 0x7;
50693
0
                } else {
50694
0
                    n = 0;
50695
0
                    c_min = 1;
50696
0
                    c = 0;
50697
0
                }
50698
0
                while (n-- > 0) {
50699
0
                    c1 = hex_decode(ctx, p, k);
50700
0
                    if (c1 < 0)
50701
0
                        goto fail;
50702
0
                    k += 3;
50703
0
                    if ((c1 & 0xc0) != 0x80) {
50704
0
                        c = 0;
50705
0
                        break;
50706
0
                    }
50707
0
                    c = (c << 6) | (c1 & 0x3f);
50708
0
                }
50709
0
                if (c < c_min || c > 0x10FFFF || is_surrogate(c)) {
50710
0
                    js_throw_URIError(ctx, "malformed UTF-8");
50711
0
                    goto fail;
50712
0
                }
50713
0
            }
50714
0
        } else {
50715
0
            k++;
50716
0
        }
50717
0
        string_buffer_putc(b, c);
50718
0
    }
50719
0
    JS_FreeValue(ctx, str);
50720
0
    return string_buffer_end(b);
50721
50722
0
fail:
50723
0
    JS_FreeValue(ctx, str);
50724
0
    string_buffer_free(b);
50725
0
    return JS_EXCEPTION;
50726
0
}
50727
50728
0
static int isUnescaped(int c) {
50729
0
    static char const unescaped_chars[] =
50730
0
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
50731
0
        "abcdefghijklmnopqrstuvwxyz"
50732
0
        "0123456789"
50733
0
        "@*_+-./";
50734
0
    return c < 0x100 &&
50735
0
        memchr(unescaped_chars, c, sizeof(unescaped_chars) - 1);
50736
0
}
50737
50738
0
static int isURIUnescaped(int c, int isComponent) {
50739
0
    return c < 0x100 &&
50740
0
        ((c >= 0x61 && c <= 0x7a) ||
50741
0
         (c >= 0x41 && c <= 0x5a) ||
50742
0
         (c >= 0x30 && c <= 0x39) ||
50743
0
         memchr("-_.!~*'()", c, sizeof("-_.!~*'()") - 1) != NULL ||
50744
0
         (!isComponent && isURIReserved(c)));
50745
0
}
50746
50747
0
static int encodeURI_hex(StringBuffer *b, int c) {
50748
0
    uint8_t buf[6];
50749
0
    int n = 0;
50750
0
    const char *hex = "0123456789ABCDEF";
50751
50752
0
    buf[n++] = '%';
50753
0
    if (c >= 256) {
50754
0
        buf[n++] = 'u';
50755
0
        buf[n++] = hex[(c >> 12) & 15];
50756
0
        buf[n++] = hex[(c >>  8) & 15];
50757
0
    }
50758
0
    buf[n++] = hex[(c >> 4) & 15];
50759
0
    buf[n++] = hex[(c >> 0) & 15];
50760
0
    return string_buffer_write8(b, buf, n);
50761
0
}
50762
50763
static JSValue js_global_encodeURI(JSContext *ctx, JSValueConst this_val,
50764
                                   int argc, JSValueConst *argv,
50765
                                   int isComponent)
50766
0
{
50767
0
    JSValue str;
50768
0
    StringBuffer b_s, *b = &b_s;
50769
0
    JSString *p;
50770
0
    int k, c, c1;
50771
50772
0
    str = JS_ToString(ctx, argv[0]);
50773
0
    if (JS_IsException(str))
50774
0
        return str;
50775
50776
0
    p = JS_VALUE_GET_STRING(str);
50777
0
    string_buffer_init(ctx, b, p->len);
50778
0
    for (k = 0; k < p->len;) {
50779
0
        c = string_get(p, k);
50780
0
        k++;
50781
0
        if (isURIUnescaped(c, isComponent)) {
50782
0
            string_buffer_putc16(b, c);
50783
0
        } else {
50784
0
            if (is_lo_surrogate(c)) {
50785
0
                js_throw_URIError(ctx, "invalid character");
50786
0
                goto fail;
50787
0
            } else if (is_hi_surrogate(c)) {
50788
0
                if (k >= p->len) {
50789
0
                    js_throw_URIError(ctx, "expecting surrogate pair");
50790
0
                    goto fail;
50791
0
                }
50792
0
                c1 = string_get(p, k);
50793
0
                k++;
50794
0
                if (!is_lo_surrogate(c1)) {
50795
0
                    js_throw_URIError(ctx, "expecting surrogate pair");
50796
0
                    goto fail;
50797
0
                }
50798
0
                c = from_surrogate(c, c1);
50799
0
            }
50800
0
            if (c < 0x80) {
50801
0
                encodeURI_hex(b, c);
50802
0
            } else {
50803
                /* XXX: use C UTF-8 conversion ? */
50804
0
                if (c < 0x800) {
50805
0
                    encodeURI_hex(b, (c >> 6) | 0xc0);
50806
0
                } else {
50807
0
                    if (c < 0x10000) {
50808
0
                        encodeURI_hex(b, (c >> 12) | 0xe0);
50809
0
                    } else {
50810
0
                        encodeURI_hex(b, (c >> 18) | 0xf0);
50811
0
                        encodeURI_hex(b, ((c >> 12) & 0x3f) | 0x80);
50812
0
                    }
50813
0
                    encodeURI_hex(b, ((c >> 6) & 0x3f) | 0x80);
50814
0
                }
50815
0
                encodeURI_hex(b, (c & 0x3f) | 0x80);
50816
0
            }
50817
0
        }
50818
0
    }
50819
0
    JS_FreeValue(ctx, str);
50820
0
    return string_buffer_end(b);
50821
50822
0
fail:
50823
0
    JS_FreeValue(ctx, str);
50824
0
    string_buffer_free(b);
50825
0
    return JS_EXCEPTION;
50826
0
}
50827
50828
static JSValue js_global_escape(JSContext *ctx, JSValueConst this_val,
50829
                                int argc, JSValueConst *argv)
50830
0
{
50831
0
    JSValue str;
50832
0
    StringBuffer b_s, *b = &b_s;
50833
0
    JSString *p;
50834
0
    int i, len, c;
50835
50836
0
    str = JS_ToString(ctx, argv[0]);
50837
0
    if (JS_IsException(str))
50838
0
        return str;
50839
50840
0
    p = JS_VALUE_GET_STRING(str);
50841
0
    string_buffer_init(ctx, b, p->len);
50842
0
    for (i = 0, len = p->len; i < len; i++) {
50843
0
        c = string_get(p, i);
50844
0
        if (isUnescaped(c)) {
50845
0
            string_buffer_putc16(b, c);
50846
0
        } else {
50847
0
            encodeURI_hex(b, c);
50848
0
        }
50849
0
    }
50850
0
    JS_FreeValue(ctx, str);
50851
0
    return string_buffer_end(b);
50852
0
}
50853
50854
static JSValue js_global_unescape(JSContext *ctx, JSValueConst this_val,
50855
                                  int argc, JSValueConst *argv)
50856
0
{
50857
0
    JSValue str;
50858
0
    StringBuffer b_s, *b = &b_s;
50859
0
    JSString *p;
50860
0
    int i, len, c, n;
50861
50862
0
    str = JS_ToString(ctx, argv[0]);
50863
0
    if (JS_IsException(str))
50864
0
        return str;
50865
50866
0
    string_buffer_init(ctx, b, 0);
50867
0
    p = JS_VALUE_GET_STRING(str);
50868
0
    for (i = 0, len = p->len; i < len; i++) {
50869
0
        c = string_get(p, i);
50870
0
        if (c == '%') {
50871
0
            if (i + 6 <= len
50872
0
            &&  string_get(p, i + 1) == 'u'
50873
0
            &&  (n = string_get_hex(p, i + 2, 4)) >= 0) {
50874
0
                c = n;
50875
0
                i += 6 - 1;
50876
0
            } else
50877
0
            if (i + 3 <= len
50878
0
            &&  (n = string_get_hex(p, i + 1, 2)) >= 0) {
50879
0
                c = n;
50880
0
                i += 3 - 1;
50881
0
            }
50882
0
        }
50883
0
        string_buffer_putc16(b, c);
50884
0
    }
50885
0
    JS_FreeValue(ctx, str);
50886
0
    return string_buffer_end(b);
50887
0
}
50888
50889
/* global object */
50890
50891
static const JSCFunctionListEntry js_global_funcs[] = {
50892
    JS_CFUNC_DEF("parseInt", 2, js_parseInt ),
50893
    JS_CFUNC_DEF("parseFloat", 1, js_parseFloat ),
50894
    JS_CFUNC_DEF("isNaN", 1, js_global_isNaN ),
50895
    JS_CFUNC_DEF("isFinite", 1, js_global_isFinite ),
50896
50897
    JS_CFUNC_MAGIC_DEF("decodeURI", 1, js_global_decodeURI, 0 ),
50898
    JS_CFUNC_MAGIC_DEF("decodeURIComponent", 1, js_global_decodeURI, 1 ),
50899
    JS_CFUNC_MAGIC_DEF("encodeURI", 1, js_global_encodeURI, 0 ),
50900
    JS_CFUNC_MAGIC_DEF("encodeURIComponent", 1, js_global_encodeURI, 1 ),
50901
    JS_CFUNC_DEF("escape", 1, js_global_escape ),
50902
    JS_CFUNC_DEF("unescape", 1, js_global_unescape ),
50903
    JS_PROP_DOUBLE_DEF("Infinity", 1.0 / 0.0, 0 ),
50904
    JS_PROP_DOUBLE_DEF("NaN", NAN, 0 ),
50905
    JS_PROP_UNDEFINED_DEF("undefined", 0 ),
50906
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "global", JS_PROP_CONFIGURABLE ),
50907
};
50908
50909
/* Date */
50910
50911
0
static int64_t math_mod(int64_t a, int64_t b) {
50912
    /* return positive modulo */
50913
0
    int64_t m = a % b;
50914
0
    return m + (m < 0) * b;
50915
0
}
50916
50917
0
static int64_t floor_div(int64_t a, int64_t b) {
50918
    /* integer division rounding toward -Infinity */
50919
0
    int64_t m = a % b;
50920
0
    return (a - (m + (m < 0) * b)) / b;
50921
0
}
50922
50923
static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
50924
                             int argc, JSValueConst *argv);
50925
50926
static __exception int JS_ThisTimeValue(JSContext *ctx, double *valp, JSValueConst this_val)
50927
0
{
50928
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
50929
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
50930
0
        if (p->class_id == JS_CLASS_DATE && JS_IsNumber(p->u.object_data))
50931
0
            return JS_ToFloat64(ctx, valp, p->u.object_data);
50932
0
    }
50933
0
    JS_ThrowTypeError(ctx, "not a Date object");
50934
0
    return -1;
50935
0
}
50936
50937
static JSValue JS_SetThisTimeValue(JSContext *ctx, JSValueConst this_val, double v)
50938
0
{
50939
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
50940
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
50941
0
        if (p->class_id == JS_CLASS_DATE) {
50942
0
            JS_FreeValue(ctx, p->u.object_data);
50943
0
            p->u.object_data = JS_NewFloat64(ctx, v);
50944
0
            return JS_DupValue(ctx, p->u.object_data);
50945
0
        }
50946
0
    }
50947
0
    return JS_ThrowTypeError(ctx, "not a Date object");
50948
0
}
50949
50950
0
static int64_t days_from_year(int64_t y) {
50951
0
    return 365 * (y - 1970) + floor_div(y - 1969, 4) -
50952
0
        floor_div(y - 1901, 100) + floor_div(y - 1601, 400);
50953
0
}
50954
50955
0
static int64_t days_in_year(int64_t y) {
50956
0
    return 365 + !(y % 4) - !(y % 100) + !(y % 400);
50957
0
}
50958
50959
/* return the year, update days */
50960
0
static int64_t year_from_days(int64_t *days) {
50961
0
    int64_t y, d1, nd, d = *days;
50962
0
    y = floor_div(d * 10000, 3652425) + 1970;
50963
    /* the initial approximation is very good, so only a few
50964
       iterations are necessary */
50965
0
    for(;;) {
50966
0
        d1 = d - days_from_year(y);
50967
0
        if (d1 < 0) {
50968
0
            y--;
50969
0
            d1 += days_in_year(y);
50970
0
        } else {
50971
0
            nd = days_in_year(y);
50972
0
            if (d1 < nd)
50973
0
                break;
50974
0
            d1 -= nd;
50975
0
            y++;
50976
0
        }
50977
0
    }
50978
0
    *days = d1;
50979
0
    return y;
50980
0
}
50981
50982
static int const month_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
50983
static char const month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
50984
static char const day_names[] = "SunMonTueWedThuFriSat";
50985
50986
static __exception int get_date_fields(JSContext *ctx, JSValueConst obj,
50987
                                       double fields[minimum_length(9)], int is_local, int force)
50988
0
{
50989
0
    double dval;
50990
0
    int64_t d, days, wd, y, i, md, h, m, s, ms, tz = 0;
50991
50992
0
    if (JS_ThisTimeValue(ctx, &dval, obj))
50993
0
        return -1;
50994
50995
0
    if (isnan(dval)) {
50996
0
        if (!force)
50997
0
            return FALSE; /* NaN */
50998
0
        d = 0;        /* initialize all fields to 0 */
50999
0
    } else {
51000
0
        d = dval;     /* assuming -8.64e15 <= dval <= -8.64e15 */
51001
0
        if (is_local) {
51002
0
            tz = -getTimezoneOffset(d);
51003
0
            d += tz * 60000;
51004
0
        }
51005
0
    }
51006
51007
    /* result is >= 0, we can use % */
51008
0
    h = math_mod(d, 86400000);
51009
0
    days = (d - h) / 86400000;
51010
0
    ms = h % 1000;
51011
0
    h = (h - ms) / 1000;
51012
0
    s = h % 60;
51013
0
    h = (h - s) / 60;
51014
0
    m = h % 60;
51015
0
    h = (h - m) / 60;
51016
0
    wd = math_mod(days + 4, 7); /* week day */
51017
0
    y = year_from_days(&days);
51018
51019
0
    for(i = 0; i < 11; i++) {
51020
0
        md = month_days[i];
51021
0
        if (i == 1)
51022
0
            md += days_in_year(y) - 365;
51023
0
        if (days < md)
51024
0
            break;
51025
0
        days -= md;
51026
0
    }
51027
0
    fields[0] = y;
51028
0
    fields[1] = i;
51029
0
    fields[2] = days + 1;
51030
0
    fields[3] = h;
51031
0
    fields[4] = m;
51032
0
    fields[5] = s;
51033
0
    fields[6] = ms;
51034
0
    fields[7] = wd;
51035
0
    fields[8] = tz;
51036
0
    return TRUE;
51037
0
}
51038
51039
0
static double time_clip(double t) {
51040
0
    if (t >= -8.64e15 && t <= 8.64e15)
51041
0
        return trunc(t) + 0.0;  /* convert -0 to +0 */
51042
0
    else
51043
0
        return NAN;
51044
0
}
51045
51046
/* The spec mandates the use of 'double' and it specifies the order
51047
   of the operations */
51048
0
static double set_date_fields(double fields[minimum_length(7)], int is_local) {
51049
0
    double y, m, dt, ym, mn, day, h, s, milli, time, tv;
51050
0
    int yi, mi, i;
51051
0
    int64_t days;
51052
0
    volatile double temp;  /* enforce evaluation order */
51053
51054
    /* emulate 21.4.1.15 MakeDay ( year, month, date ) */
51055
0
    y = fields[0];
51056
0
    m = fields[1];
51057
0
    dt = fields[2];
51058
0
    ym = y + floor(m / 12);
51059
0
    mn = fmod(m, 12);
51060
0
    if (mn < 0)
51061
0
        mn += 12;
51062
0
    if (ym < -271821 || ym > 275760)
51063
0
        return NAN;
51064
51065
0
    yi = ym;
51066
0
    mi = mn;
51067
0
    days = days_from_year(yi);
51068
0
    for(i = 0; i < mi; i++) {
51069
0
        days += month_days[i];
51070
0
        if (i == 1)
51071
0
            days += days_in_year(yi) - 365;
51072
0
    }
51073
0
    day = days + dt - 1;
51074
51075
    /* emulate 21.4.1.14 MakeTime ( hour, min, sec, ms ) */
51076
0
    h = fields[3];
51077
0
    m = fields[4];
51078
0
    s = fields[5];
51079
0
    milli = fields[6];
51080
    /* Use a volatile intermediary variable to ensure order of evaluation
51081
     * as specified in ECMA. This fixes a test262 error on
51082
     * test262/test/built-ins/Date/UTC/fp-evaluation-order.js.
51083
     * Without the volatile qualifier, the compile can generate code
51084
     * that performs the computation in a different order or with instructions
51085
     * that produce a different result such as FMA (float multiply and add).
51086
     */
51087
0
    time = h * 3600000;
51088
0
    time += (temp = m * 60000);
51089
0
    time += (temp = s * 1000);
51090
0
    time += milli;
51091
51092
    /* emulate 21.4.1.16 MakeDate ( day, time ) */
51093
0
    tv = (temp = day * 86400000) + time;   /* prevent generation of FMA */
51094
0
    if (!isfinite(tv))
51095
0
        return NAN;
51096
51097
    /* adjust for local time and clip */
51098
0
    if (is_local) {
51099
0
        int64_t ti = tv < INT64_MIN ? INT64_MIN : tv >= 0x1p63 ? INT64_MAX : (int64_t)tv;
51100
0
        tv += getTimezoneOffset(ti) * 60000;
51101
0
    }
51102
0
    return time_clip(tv);
51103
0
}
51104
51105
static JSValue get_date_field(JSContext *ctx, JSValueConst this_val,
51106
                              int argc, JSValueConst *argv, int magic)
51107
0
{
51108
    // get_date_field(obj, n, is_local)
51109
0
    double fields[9];
51110
0
    int res, n, is_local;
51111
51112
0
    is_local = magic & 0x0F;
51113
0
    n = (magic >> 4) & 0x0F;
51114
0
    res = get_date_fields(ctx, this_val, fields, is_local, 0);
51115
0
    if (res < 0)
51116
0
        return JS_EXCEPTION;
51117
0
    if (!res)
51118
0
        return JS_NAN;
51119
51120
0
    if (magic & 0x100) {    // getYear
51121
0
        fields[0] -= 1900;
51122
0
    }
51123
0
    return JS_NewFloat64(ctx, fields[n]);
51124
0
}
51125
51126
static JSValue set_date_field(JSContext *ctx, JSValueConst this_val,
51127
                              int argc, JSValueConst *argv, int magic)
51128
0
{
51129
    // _field(obj, first_field, end_field, args, is_local)
51130
0
    double fields[9];
51131
0
    int res, first_field, end_field, is_local, i, n, res1;
51132
0
    double d, a;
51133
51134
0
    d = NAN;
51135
0
    first_field = (magic >> 8) & 0x0F;
51136
0
    end_field = (magic >> 4) & 0x0F;
51137
0
    is_local = magic & 0x0F;
51138
51139
0
    res = get_date_fields(ctx, this_val, fields, is_local, first_field == 0);
51140
0
    if (res < 0)
51141
0
        return JS_EXCEPTION;
51142
0
    res1 = res;
51143
    
51144
    // Argument coercion is observable and must be done unconditionally.
51145
0
    n = min_int(argc, end_field - first_field);
51146
0
    for(i = 0; i < n; i++) {
51147
0
        if (JS_ToFloat64(ctx, &a, argv[i]))
51148
0
            return JS_EXCEPTION;
51149
0
        if (!isfinite(a))
51150
0
            res = FALSE;
51151
0
        fields[first_field + i] = trunc(a);
51152
0
    }
51153
51154
0
    if (!res1)
51155
0
        return JS_NAN; /* thisTimeValue is NaN */
51156
51157
0
    if (res && argc > 0)
51158
0
        d = set_date_fields(fields, is_local);
51159
51160
0
    return JS_SetThisTimeValue(ctx, this_val, d);
51161
0
}
51162
51163
/* fmt:
51164
   0: toUTCString: "Tue, 02 Jan 2018 23:04:46 GMT"
51165
   1: toString: "Wed Jan 03 2018 00:05:22 GMT+0100 (CET)"
51166
   2: toISOString: "2018-01-02T23:02:56.927Z"
51167
   3: toLocaleString: "1/2/2018, 11:40:40 PM"
51168
   part: 1=date, 2=time 3=all
51169
   XXX: should use a variant of strftime().
51170
 */
51171
static JSValue get_date_string(JSContext *ctx, JSValueConst this_val,
51172
                               int argc, JSValueConst *argv, int magic)
51173
0
{
51174
    // _string(obj, fmt, part)
51175
0
    char buf[64];
51176
0
    double fields[9];
51177
0
    int res, fmt, part, pos;
51178
0
    int y, mon, d, h, m, s, ms, wd, tz;
51179
51180
0
    fmt = (magic >> 4) & 0x0F;
51181
0
    part = magic & 0x0F;
51182
51183
0
    res = get_date_fields(ctx, this_val, fields, fmt & 1, 0);
51184
0
    if (res < 0)
51185
0
        return JS_EXCEPTION;
51186
0
    if (!res) {
51187
0
        if (fmt == 2)
51188
0
            return JS_ThrowRangeError(ctx, "Date value is NaN");
51189
0
        else
51190
0
            return js_new_string8(ctx, "Invalid Date");
51191
0
    }
51192
51193
0
    y = fields[0];
51194
0
    mon = fields[1];
51195
0
    d = fields[2];
51196
0
    h = fields[3];
51197
0
    m = fields[4];
51198
0
    s = fields[5];
51199
0
    ms = fields[6];
51200
0
    wd = fields[7];
51201
0
    tz = fields[8];
51202
51203
0
    pos = 0;
51204
51205
0
    if (part & 1) { /* date part */
51206
0
        switch(fmt) {
51207
0
        case 0:
51208
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
51209
0
                            "%.3s, %02d %.3s %0*d ",
51210
0
                            day_names + wd * 3, d,
51211
0
                            month_names + mon * 3, 4 + (y < 0), y);
51212
0
            break;
51213
0
        case 1:
51214
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
51215
0
                            "%.3s %.3s %02d %0*d",
51216
0
                            day_names + wd * 3,
51217
0
                            month_names + mon * 3, d, 4 + (y < 0), y);
51218
0
            if (part == 3) {
51219
0
                buf[pos++] = ' ';
51220
0
            }
51221
0
            break;
51222
0
        case 2:
51223
0
            if (y >= 0 && y <= 9999) {
51224
0
                pos += snprintf(buf + pos, sizeof(buf) - pos,
51225
0
                                "%04d", y);
51226
0
            } else {
51227
0
                pos += snprintf(buf + pos, sizeof(buf) - pos,
51228
0
                                "%+07d", y);
51229
0
            }
51230
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
51231
0
                            "-%02d-%02dT", mon + 1, d);
51232
0
            break;
51233
0
        case 3:
51234
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
51235
0
                            "%02d/%02d/%0*d", mon + 1, d, 4 + (y < 0), y);
51236
0
            if (part == 3) {
51237
0
                buf[pos++] = ',';
51238
0
                buf[pos++] = ' ';
51239
0
            }
51240
0
            break;
51241
0
        }
51242
0
    }
51243
0
    if (part & 2) { /* time part */
51244
0
        switch(fmt) {
51245
0
        case 0:
51246
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
51247
0
                            "%02d:%02d:%02d GMT", h, m, s);
51248
0
            break;
51249
0
        case 1:
51250
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
51251
0
                            "%02d:%02d:%02d GMT", h, m, s);
51252
0
            if (tz < 0) {
51253
0
                buf[pos++] = '-';
51254
0
                tz = -tz;
51255
0
            } else {
51256
0
                buf[pos++] = '+';
51257
0
            }
51258
            /* tz is >= 0, can use % */
51259
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
51260
0
                            "%02d%02d", tz / 60, tz % 60);
51261
            /* XXX: tack the time zone code? */
51262
0
            break;
51263
0
        case 2:
51264
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
51265
0
                            "%02d:%02d:%02d.%03dZ", h, m, s, ms);
51266
0
            break;
51267
0
        case 3:
51268
0
            pos += snprintf(buf + pos, sizeof(buf) - pos,
51269
0
                            "%02d:%02d:%02d %cM", (h + 11) % 12 + 1, m, s,
51270
0
                            (h < 12) ? 'A' : 'P');
51271
0
            break;
51272
0
        }
51273
0
    }
51274
0
    return JS_NewStringLen(ctx, buf, pos);
51275
0
}
51276
51277
/* OS dependent: return the UTC time in ms since 1970. */
51278
0
static int64_t date_now(void) {
51279
0
    struct timeval tv;
51280
0
    gettimeofday(&tv, NULL);
51281
0
    return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
51282
0
}
51283
51284
static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target,
51285
                                   int argc, JSValueConst *argv)
51286
0
{
51287
    // Date(y, mon, d, h, m, s, ms)
51288
0
    JSValue rv;
51289
0
    int i, n;
51290
0
    double a, val;
51291
51292
0
    if (JS_IsUndefined(new_target)) {
51293
        /* invoked as function */
51294
0
        argc = 0;
51295
0
    }
51296
0
    n = argc;
51297
0
    if (n == 0) {
51298
0
        val = date_now();
51299
0
    } else if (n == 1) {
51300
0
        JSValue v, dv;
51301
0
        if (JS_VALUE_GET_TAG(argv[0]) == JS_TAG_OBJECT) {
51302
0
            JSObject *p = JS_VALUE_GET_OBJ(argv[0]);
51303
0
            if (p->class_id == JS_CLASS_DATE && JS_IsNumber(p->u.object_data)) {
51304
0
                if (JS_ToFloat64(ctx, &val, p->u.object_data))
51305
0
                    return JS_EXCEPTION;
51306
0
                val = time_clip(val);
51307
0
                goto has_val;
51308
0
            }
51309
0
        }
51310
0
        v = JS_ToPrimitive(ctx, argv[0], HINT_NONE);
51311
0
        if (JS_IsString(v)) {
51312
0
            dv = js_Date_parse(ctx, JS_UNDEFINED, 1, (JSValueConst *)&v);
51313
0
            JS_FreeValue(ctx, v);
51314
0
            if (JS_IsException(dv))
51315
0
                return JS_EXCEPTION;
51316
0
            if (JS_ToFloat64Free(ctx, &val, dv))
51317
0
                return JS_EXCEPTION;
51318
0
        } else {
51319
0
            if (JS_ToFloat64Free(ctx, &val, v))
51320
0
                return JS_EXCEPTION;
51321
0
        }
51322
0
        val = time_clip(val);
51323
0
    } else {
51324
0
        double fields[] = { 0, 0, 1, 0, 0, 0, 0 };
51325
0
        if (n > 7)
51326
0
            n = 7;
51327
0
        for(i = 0; i < n; i++) {
51328
0
            if (JS_ToFloat64(ctx, &a, argv[i]))
51329
0
                return JS_EXCEPTION;
51330
0
            if (!isfinite(a))
51331
0
                break;
51332
0
            fields[i] = trunc(a);
51333
0
            if (i == 0 && fields[0] >= 0 && fields[0] < 100)
51334
0
                fields[0] += 1900;
51335
0
        }
51336
0
        val = (i == n) ? set_date_fields(fields, 1) : NAN;
51337
0
    }
51338
0
has_val:
51339
#if 0
51340
    JSValueConst args[3];
51341
    args[0] = new_target;
51342
    args[1] = ctx->class_proto[JS_CLASS_DATE];
51343
    args[2] = JS_NewFloat64(ctx, val);
51344
    rv = js___date_create(ctx, JS_UNDEFINED, 3, args);
51345
#else
51346
0
    rv = js_create_from_ctor(ctx, new_target, JS_CLASS_DATE);
51347
0
    if (!JS_IsException(rv))
51348
0
        JS_SetObjectData(ctx, rv, JS_NewFloat64(ctx, val));
51349
0
#endif
51350
0
    if (!JS_IsException(rv) && JS_IsUndefined(new_target)) {
51351
        /* invoked as a function, return (new Date()).toString(); */
51352
0
        JSValue s;
51353
0
        s = get_date_string(ctx, rv, 0, NULL, 0x13);
51354
0
        JS_FreeValue(ctx, rv);
51355
0
        rv = s;
51356
0
    }
51357
0
    return rv;
51358
0
}
51359
51360
static JSValue js_Date_UTC(JSContext *ctx, JSValueConst this_val,
51361
                           int argc, JSValueConst *argv)
51362
0
{
51363
    // UTC(y, mon, d, h, m, s, ms)
51364
0
    double fields[] = { 0, 0, 1, 0, 0, 0, 0 };
51365
0
    int i, n;
51366
0
    double a;
51367
51368
0
    n = argc;
51369
0
    if (n == 0)
51370
0
        return JS_NAN;
51371
0
    if (n > 7)
51372
0
        n = 7;
51373
0
    for(i = 0; i < n; i++) {
51374
0
        if (JS_ToFloat64(ctx, &a, argv[i]))
51375
0
            return JS_EXCEPTION;
51376
0
        if (!isfinite(a))
51377
0
            return JS_NAN;
51378
0
        fields[i] = trunc(a);
51379
0
        if (i == 0 && fields[0] >= 0 && fields[0] < 100)
51380
0
            fields[0] += 1900;
51381
0
    }
51382
0
    return JS_NewFloat64(ctx, set_date_fields(fields, 0));
51383
0
}
51384
51385
/* Date string parsing */
51386
51387
0
static BOOL string_skip_char(const uint8_t *sp, int *pp, int c) {
51388
0
    if (sp[*pp] == c) {
51389
0
        *pp += 1;
51390
0
        return TRUE;
51391
0
    } else {
51392
0
        return FALSE;
51393
0
    }
51394
0
}
51395
51396
/* skip spaces, update offset, return next char */
51397
0
static int string_skip_spaces(const uint8_t *sp, int *pp) {
51398
0
    int c;
51399
0
    while ((c = sp[*pp]) == ' ')
51400
0
        *pp += 1;
51401
0
    return c;
51402
0
}
51403
51404
/* skip dashes dots and commas */
51405
0
static int string_skip_separators(const uint8_t *sp, int *pp) {
51406
0
    int c;
51407
0
    while ((c = sp[*pp]) == '-' || c == '/' || c == '.' || c == ',')
51408
0
        *pp += 1;
51409
0
    return c;
51410
0
}
51411
51412
/* skip a word, stop on spaces, digits and separators, update offset */
51413
0
static int string_skip_until(const uint8_t *sp, int *pp, const char *stoplist) {
51414
0
    int c;
51415
0
    while (!strchr(stoplist, c = sp[*pp]))
51416
0
        *pp += 1;
51417
0
    return c;
51418
0
}
51419
51420
/* parse a numeric field (max_digits = 0 -> no maximum) */
51421
static BOOL string_get_digits(const uint8_t *sp, int *pp, int *pval,
51422
                              int min_digits, int max_digits)
51423
0
{
51424
0
    int v = 0;
51425
0
    int c, p = *pp, p_start;
51426
51427
0
    p_start = p;
51428
0
    while ((c = sp[p]) >= '0' && c <= '9') {
51429
        /* arbitrary limit to 9 digits */
51430
0
        if (v >= 100000000)
51431
0
            return FALSE;
51432
0
        v = v * 10 + c - '0';
51433
0
        p++;
51434
0
        if (p - p_start == max_digits)
51435
0
            break;
51436
0
    }
51437
0
    if (p - p_start < min_digits)
51438
0
        return FALSE;
51439
0
    *pval = v;
51440
0
    *pp = p;
51441
0
    return TRUE;
51442
0
}
51443
51444
0
static BOOL string_get_milliseconds(const uint8_t *sp, int *pp, int *pval) {
51445
    /* parse optional fractional part as milliseconds and truncate. */
51446
    /* spec does not indicate which rounding should be used */
51447
0
    int mul = 100, ms = 0, c, p_start, p = *pp;
51448
51449
0
    c = sp[p];
51450
0
    if (c == '.' || c == ',') {
51451
0
        p++;
51452
0
        p_start = p;
51453
0
        while ((c = sp[p]) >= '0' && c <= '9') {
51454
0
            ms += (c - '0') * mul;
51455
0
            mul /= 10;
51456
0
            p++;
51457
0
            if (p - p_start == 9)
51458
0
                break;
51459
0
        }
51460
0
        if (p > p_start) {
51461
            /* only consume the separator if digits are present */
51462
0
            *pval = ms;
51463
0
            *pp = p;
51464
0
        }
51465
0
    }
51466
0
    return TRUE;
51467
0
}
51468
51469
0
static uint8_t upper_ascii(uint8_t c) {
51470
0
    return c >= 'a' && c <= 'z' ? c - 'a' + 'A' : c;
51471
0
}
51472
51473
0
static BOOL string_get_tzoffset(const uint8_t *sp, int *pp, int *tzp, BOOL strict) {
51474
0
    int tz = 0, sgn, hh, mm, p = *pp;
51475
51476
0
    sgn = sp[p++];
51477
0
    if (sgn == '+' || sgn == '-') {
51478
0
        int n = p;
51479
0
        if (!string_get_digits(sp, &p, &hh, 1, 0))
51480
0
            return FALSE;
51481
0
        n = p - n;
51482
0
        if (strict && n != 2 && n != 4)
51483
0
            return FALSE;
51484
0
        while (n > 4) {
51485
0
            n -= 2;
51486
0
            hh /= 100;
51487
0
        }
51488
0
        if (n > 2) {
51489
0
            mm = hh % 100;
51490
0
            hh = hh / 100;
51491
0
        } else {
51492
0
            mm = 0;
51493
0
            if (string_skip_char(sp, &p, ':')  /* optional separator */
51494
0
            &&  !string_get_digits(sp, &p, &mm, 2, 2))
51495
0
                return FALSE;
51496
0
        }
51497
0
        if (hh > 23 || mm > 59)
51498
0
            return FALSE;
51499
0
        tz = hh * 60 + mm;
51500
0
        if (sgn != '+')
51501
0
            tz = -tz;
51502
0
    } else
51503
0
    if (sgn != 'Z') {
51504
0
        return FALSE;
51505
0
    }
51506
0
    *pp = p;
51507
0
    *tzp = tz;
51508
0
    return TRUE;
51509
0
}
51510
51511
0
static BOOL string_match(const uint8_t *sp, int *pp, const char *s) {
51512
0
    int p = *pp;
51513
0
    while (*s != '\0') {
51514
0
        if (upper_ascii(sp[p]) != upper_ascii(*s++))
51515
0
            return FALSE;
51516
0
        p++;
51517
0
    }
51518
0
    *pp = p;
51519
0
    return TRUE;
51520
0
}
51521
51522
0
static int find_abbrev(const uint8_t *sp, int p, const char *list, int count) {
51523
0
    int n, i;
51524
51525
0
    for (n = 0; n < count; n++) {
51526
0
        for (i = 0;; i++) {
51527
0
            if (upper_ascii(sp[p + i]) != upper_ascii(list[n * 3 + i]))
51528
0
                break;
51529
0
            if (i == 2)
51530
0
                return n;
51531
0
        }
51532
0
    }
51533
0
    return -1;
51534
0
}
51535
51536
0
static BOOL string_get_month(const uint8_t *sp, int *pp, int *pval) {
51537
0
    int n;
51538
51539
0
    n = find_abbrev(sp, *pp, month_names, 12);
51540
0
    if (n < 0)
51541
0
        return FALSE;
51542
51543
0
    *pval = n + 1;
51544
0
    *pp += 3;
51545
0
    return TRUE;
51546
0
}
51547
51548
/* parse toISOString format */
51549
0
static BOOL js_date_parse_isostring(const uint8_t *sp, int fields[9], BOOL *is_local) {
51550
0
    int sgn, i, p = 0;
51551
51552
    /* initialize fields to the beginning of the Epoch */
51553
0
    for (i = 0; i < 9; i++) {
51554
0
        fields[i] = (i == 2);
51555
0
    }
51556
0
    *is_local = FALSE;
51557
51558
    /* year is either yyyy digits or [+-]yyyyyy */
51559
0
    sgn = sp[p];
51560
0
    if (sgn == '-' || sgn == '+') {
51561
0
        p++;
51562
0
        if (!string_get_digits(sp, &p, &fields[0], 6, 6))
51563
0
            return FALSE;
51564
0
        if (sgn == '-') {
51565
0
            if (fields[0] == 0)
51566
0
                return FALSE; // reject -000000
51567
0
            fields[0] = -fields[0];
51568
0
        }
51569
0
    } else {
51570
0
        if (!string_get_digits(sp, &p, &fields[0], 4, 4))
51571
0
            return FALSE;
51572
0
    }
51573
0
    if (string_skip_char(sp, &p, '-')) {
51574
0
        if (!string_get_digits(sp, &p, &fields[1], 2, 2))  /* month */
51575
0
            return FALSE;
51576
0
        if (fields[1] < 1)
51577
0
            return FALSE;
51578
0
        fields[1] -= 1;
51579
0
        if (string_skip_char(sp, &p, '-')) {
51580
0
            if (!string_get_digits(sp, &p, &fields[2], 2, 2))  /* day */
51581
0
                return FALSE;
51582
0
            if (fields[2] < 1)
51583
0
                return FALSE;
51584
0
        }
51585
0
    }
51586
0
    if (string_skip_char(sp, &p, 'T')) {
51587
0
        *is_local = TRUE;
51588
0
        if (!string_get_digits(sp, &p, &fields[3], 2, 2)  /* hour */
51589
0
        ||  !string_skip_char(sp, &p, ':')
51590
0
        ||  !string_get_digits(sp, &p, &fields[4], 2, 2)) {  /* minute */
51591
0
            fields[3] = 100;  // reject unconditionally
51592
0
            return TRUE;
51593
0
        }
51594
0
        if (string_skip_char(sp, &p, ':')) {
51595
0
            if (!string_get_digits(sp, &p, &fields[5], 2, 2))  /* second */
51596
0
                return FALSE;
51597
0
            string_get_milliseconds(sp, &p, &fields[6]);
51598
0
        }
51599
0
    }
51600
    /* parse the time zone offset if present: [+-]HH:mm or [+-]HHmm */
51601
0
    if (sp[p]) {
51602
0
        *is_local = FALSE;
51603
0
        if (!string_get_tzoffset(sp, &p, &fields[8], TRUE))
51604
0
            return FALSE;
51605
0
    }
51606
    /* error if extraneous characters */
51607
0
    return sp[p] == '\0';
51608
0
}
51609
51610
static struct {
51611
    char name[6];
51612
    int16_t offset;
51613
} const js_tzabbr[] = {
51614
    { "GMT",   0 },         // Greenwich Mean Time
51615
    { "UTC",   0 },         // Coordinated Universal Time
51616
    { "UT",    0 },         // Universal Time
51617
    { "Z",     0 },         // Zulu Time
51618
    { "EDT",  -4 * 60 },    // Eastern Daylight Time
51619
    { "EST",  -5 * 60 },    // Eastern Standard Time
51620
    { "CDT",  -5 * 60 },    // Central Daylight Time
51621
    { "CST",  -6 * 60 },    // Central Standard Time
51622
    { "MDT",  -6 * 60 },    // Mountain Daylight Time
51623
    { "MST",  -7 * 60 },    // Mountain Standard Time
51624
    { "PDT",  -7 * 60 },    // Pacific Daylight Time
51625
    { "PST",  -8 * 60 },    // Pacific Standard Time
51626
    { "WET",  +0 * 60 },    // Western European Time
51627
    { "WEST", +1 * 60 },    // Western European Summer Time
51628
    { "CET",  +1 * 60 },    // Central European Time
51629
    { "CEST", +2 * 60 },    // Central European Summer Time
51630
    { "EET",  +2 * 60 },    // Eastern European Time
51631
    { "EEST", +3 * 60 },    // Eastern European Summer Time
51632
};
51633
51634
0
static BOOL string_get_tzabbr(const uint8_t *sp, int *pp, int *offset) {
51635
0
    for (size_t i = 0; i < countof(js_tzabbr); i++) {
51636
0
        if (string_match(sp, pp, js_tzabbr[i].name)) {
51637
0
            *offset = js_tzabbr[i].offset;
51638
0
            return TRUE;
51639
0
        }
51640
0
    }
51641
0
    return FALSE;
51642
0
}
51643
51644
/* parse toString, toUTCString and other formats */
51645
static BOOL js_date_parse_otherstring(const uint8_t *sp,
51646
                                      int fields[minimum_length(9)],
51647
0
                                      BOOL *is_local) {
51648
0
    int c, i, val, p = 0, p_start;
51649
0
    int num[3];
51650
0
    BOOL has_year = FALSE;
51651
0
    BOOL has_mon = FALSE;
51652
0
    BOOL has_time = FALSE;
51653
0
    int num_index = 0;
51654
51655
    /* initialize fields to the beginning of 2001-01-01 */
51656
0
    fields[0] = 2001;
51657
0
    fields[1] = 1;
51658
0
    fields[2] = 1;
51659
0
    for (i = 3; i < 9; i++) {
51660
0
        fields[i] = 0;
51661
0
    }
51662
0
    *is_local = TRUE;
51663
51664
0
    while (string_skip_spaces(sp, &p)) {
51665
0
        p_start = p;
51666
0
        if ((c = sp[p]) == '+' || c == '-') {
51667
0
            if (has_time && string_get_tzoffset(sp, &p, &fields[8], FALSE)) {
51668
0
                *is_local = FALSE;
51669
0
            } else {
51670
0
                p++;
51671
0
                if (string_get_digits(sp, &p, &val, 1, 0)) {
51672
0
                    if (c == '-') {
51673
0
                        if (val == 0)
51674
0
                            return FALSE;
51675
0
                        val = -val;
51676
0
                    }
51677
0
                    fields[0] = val;
51678
0
                    has_year = TRUE;
51679
0
                }
51680
0
            }
51681
0
        } else
51682
0
        if (string_get_digits(sp, &p, &val, 1, 0)) {
51683
0
            if (string_skip_char(sp, &p, ':')) {
51684
                /* time part */
51685
0
                fields[3] = val;
51686
0
                if (!string_get_digits(sp, &p, &fields[4], 1, 2))
51687
0
                    return FALSE;
51688
0
                if (string_skip_char(sp, &p, ':')) {
51689
0
                    if (!string_get_digits(sp, &p, &fields[5], 1, 2))
51690
0
                        return FALSE;
51691
0
                    string_get_milliseconds(sp, &p, &fields[6]);
51692
0
                }
51693
0
                has_time = TRUE;
51694
0
            } else {
51695
0
                if (p - p_start > 2) {
51696
0
                    fields[0] = val;
51697
0
                    has_year = TRUE;
51698
0
                } else
51699
0
                if (val < 1 || val > 31) {
51700
0
                    fields[0] = val + (val < 100) * 1900 + (val < 50) * 100;
51701
0
                    has_year = TRUE;
51702
0
                } else {
51703
0
                    if (num_index == 3)
51704
0
                        return FALSE;
51705
0
                    num[num_index++] = val;
51706
0
                }
51707
0
            }
51708
0
        } else
51709
0
        if (string_get_month(sp, &p, &fields[1])) {
51710
0
            has_mon = TRUE;
51711
0
            string_skip_until(sp, &p, "0123456789 -/(");
51712
0
        } else
51713
0
        if (has_time && string_match(sp, &p, "PM")) {
51714
0
            if (fields[3] < 12)
51715
0
                fields[3] += 12;
51716
0
            continue;
51717
0
        } else
51718
0
        if (has_time && string_match(sp, &p, "AM")) {
51719
0
            if (fields[3] == 12)
51720
0
                fields[3] -= 12;
51721
0
            continue;
51722
0
        } else
51723
0
        if (string_get_tzabbr(sp, &p, &fields[8])) {
51724
0
            *is_local = FALSE;
51725
0
            continue;
51726
0
        } else
51727
0
        if (c == '(') {  /* skip parenthesized phrase */
51728
0
            int level = 0;
51729
0
            while ((c = sp[p]) != '\0') {
51730
0
                p++;
51731
0
                level += (c == '(');
51732
0
                level -= (c == ')');
51733
0
                if (!level)
51734
0
                    break;
51735
0
            }
51736
0
            if (level > 0)
51737
0
                return FALSE;
51738
0
        } else
51739
0
        if (c == ')') {
51740
0
            return FALSE;
51741
0
        } else {
51742
0
            if (has_year + has_mon + has_time + num_index)
51743
0
                return FALSE;
51744
            /* skip a word */
51745
0
            string_skip_until(sp, &p, " -/(");
51746
0
        }
51747
0
        string_skip_separators(sp, &p);
51748
0
    }
51749
0
    if (num_index + has_year + has_mon > 3)
51750
0
        return FALSE;
51751
51752
0
    switch (num_index) {
51753
0
    case 0:
51754
0
        if (!has_year)
51755
0
            return FALSE;
51756
0
        break;
51757
0
    case 1:
51758
0
        if (has_mon)
51759
0
            fields[2] = num[0];
51760
0
        else
51761
0
            fields[1] = num[0];
51762
0
        break;
51763
0
    case 2:
51764
0
        if (has_year) {
51765
0
            fields[1] = num[0];
51766
0
            fields[2] = num[1];
51767
0
        } else
51768
0
        if (has_mon) {
51769
0
            fields[0] = num[1] + (num[1] < 100) * 1900 + (num[1] < 50) * 100;
51770
0
            fields[2] = num[0];
51771
0
        } else {
51772
0
            fields[1] = num[0];
51773
0
            fields[2] = num[1];
51774
0
        }
51775
0
        break;
51776
0
    case 3:
51777
0
        fields[0] = num[2] + (num[2] < 100) * 1900 + (num[2] < 50) * 100;
51778
0
        fields[1] = num[0];
51779
0
        fields[2] = num[1];
51780
0
        break;
51781
0
    default:
51782
0
        return FALSE;
51783
0
    }
51784
0
    if (fields[1] < 1 || fields[2] < 1)
51785
0
        return FALSE;
51786
0
    fields[1] -= 1;
51787
0
    return TRUE;
51788
0
}
51789
51790
static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
51791
                             int argc, JSValueConst *argv)
51792
0
{
51793
0
    JSValue s, rv;
51794
0
    int fields[9];
51795
0
    double fields1[9];
51796
0
    double d;
51797
0
    int i, c;
51798
0
    JSString *sp;
51799
0
    uint8_t buf[128];
51800
0
    BOOL is_local;
51801
51802
0
    rv = JS_NAN;
51803
51804
0
    s = JS_ToString(ctx, argv[0]);
51805
0
    if (JS_IsException(s))
51806
0
        return JS_EXCEPTION;
51807
51808
0
    sp = JS_VALUE_GET_STRING(s);
51809
    /* convert the string as a byte array */
51810
0
    for (i = 0; i < sp->len && i < (int)countof(buf) - 1; i++) {
51811
0
        c = string_get(sp, i);
51812
0
        if (c > 255)
51813
0
            c = (c == 0x2212) ? '-' : 'x';
51814
0
        buf[i] = c;
51815
0
    }
51816
0
    buf[i] = '\0';
51817
0
    if (js_date_parse_isostring(buf, fields, &is_local)
51818
0
    ||  js_date_parse_otherstring(buf, fields, &is_local)) {
51819
0
        static int const field_max[6] = { 0, 11, 31, 24, 59, 59 };
51820
0
        BOOL valid = TRUE;
51821
        /* check field maximum values */
51822
0
        for (i = 1; i < 6; i++) {
51823
0
            if (fields[i] > field_max[i])
51824
0
                valid = FALSE;
51825
0
        }
51826
        /* special case 24:00:00.000 */
51827
0
        if (fields[3] == 24 && (fields[4] | fields[5] | fields[6]))
51828
0
            valid = FALSE;
51829
0
        if (valid) {
51830
0
            for(i = 0; i < 7; i++)
51831
0
                fields1[i] = fields[i];
51832
0
            d = set_date_fields(fields1, is_local) - fields[8] * 60000;
51833
0
            rv = JS_NewFloat64(ctx, d);
51834
0
        }
51835
0
    }
51836
0
    JS_FreeValue(ctx, s);
51837
0
    return rv;
51838
0
}
51839
51840
static JSValue js_Date_now(JSContext *ctx, JSValueConst this_val,
51841
                           int argc, JSValueConst *argv)
51842
0
{
51843
    // now()
51844
0
    return JS_NewInt64(ctx, date_now());
51845
0
}
51846
51847
static JSValue js_date_Symbol_toPrimitive(JSContext *ctx, JSValueConst this_val,
51848
                                          int argc, JSValueConst *argv)
51849
0
{
51850
    // Symbol_toPrimitive(hint)
51851
0
    JSValueConst obj = this_val;
51852
0
    JSAtom hint = JS_ATOM_NULL;
51853
0
    int hint_num;
51854
51855
0
    if (!JS_IsObject(obj))
51856
0
        return JS_ThrowTypeErrorNotAnObject(ctx);
51857
51858
0
    if (JS_IsString(argv[0])) {
51859
0
        hint = JS_ValueToAtom(ctx, argv[0]);
51860
0
        if (hint == JS_ATOM_NULL)
51861
0
            return JS_EXCEPTION;
51862
0
        JS_FreeAtom(ctx, hint);
51863
0
    }
51864
0
    switch (hint) {
51865
0
    case JS_ATOM_number:
51866
0
    case JS_ATOM_integer:
51867
0
        hint_num = HINT_NUMBER;
51868
0
        break;
51869
0
    case JS_ATOM_string:
51870
0
    case JS_ATOM_default:
51871
0
        hint_num = HINT_STRING;
51872
0
        break;
51873
0
    default:
51874
0
        return JS_ThrowTypeError(ctx, "invalid hint");
51875
0
    }
51876
0
    return JS_ToPrimitive(ctx, obj, hint_num | HINT_FORCE_ORDINARY);
51877
0
}
51878
51879
static JSValue js_date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val,
51880
                                         int argc, JSValueConst *argv)
51881
0
{
51882
    // getTimezoneOffset()
51883
0
    double v;
51884
51885
0
    if (JS_ThisTimeValue(ctx, &v, this_val))
51886
0
        return JS_EXCEPTION;
51887
0
    if (isnan(v))
51888
0
        return JS_NAN;
51889
0
    else
51890
        /* assuming -8.64e15 <= v <= -8.64e15 */
51891
0
        return JS_NewInt64(ctx, getTimezoneOffset((int64_t)trunc(v)));
51892
0
}
51893
51894
static JSValue js_date_getTime(JSContext *ctx, JSValueConst this_val,
51895
                               int argc, JSValueConst *argv)
51896
0
{
51897
    // getTime()
51898
0
    double v;
51899
51900
0
    if (JS_ThisTimeValue(ctx, &v, this_val))
51901
0
        return JS_EXCEPTION;
51902
0
    return JS_NewFloat64(ctx, v);
51903
0
}
51904
51905
static JSValue js_date_setTime(JSContext *ctx, JSValueConst this_val,
51906
                               int argc, JSValueConst *argv)
51907
0
{
51908
    // setTime(v)
51909
0
    double v;
51910
51911
0
    if (JS_ThisTimeValue(ctx, &v, this_val) || JS_ToFloat64(ctx, &v, argv[0]))
51912
0
        return JS_EXCEPTION;
51913
0
    return JS_SetThisTimeValue(ctx, this_val, time_clip(v));
51914
0
}
51915
51916
static JSValue js_date_setYear(JSContext *ctx, JSValueConst this_val,
51917
                               int argc, JSValueConst *argv)
51918
0
{
51919
    // setYear(y)
51920
0
    double y;
51921
0
    JSValueConst args[1];
51922
51923
0
    if (JS_ThisTimeValue(ctx, &y, this_val) || JS_ToFloat64(ctx, &y, argv[0]))
51924
0
        return JS_EXCEPTION;
51925
0
    y = +y;
51926
0
    if (isfinite(y)) {
51927
0
        y = trunc(y);
51928
0
        if (y >= 0 && y < 100)
51929
0
            y += 1900;
51930
0
    }
51931
0
    args[0] = JS_NewFloat64(ctx, y);
51932
0
    return set_date_field(ctx, this_val, 1, args, 0x011);
51933
0
}
51934
51935
static JSValue js_date_toJSON(JSContext *ctx, JSValueConst this_val,
51936
                              int argc, JSValueConst *argv)
51937
0
{
51938
    // toJSON(key)
51939
0
    JSValue obj, tv, method, rv;
51940
0
    double d;
51941
51942
0
    rv = JS_EXCEPTION;
51943
0
    tv = JS_UNDEFINED;
51944
51945
0
    obj = JS_ToObject(ctx, this_val);
51946
0
    tv = JS_ToPrimitive(ctx, obj, HINT_NUMBER);
51947
0
    if (JS_IsException(tv))
51948
0
        goto exception;
51949
0
    if (JS_IsNumber(tv)) {
51950
0
        if (JS_ToFloat64(ctx, &d, tv) < 0)
51951
0
            goto exception;
51952
0
        if (!isfinite(d)) {
51953
0
            rv = JS_NULL;
51954
0
            goto done;
51955
0
        }
51956
0
    }
51957
0
    method = JS_GetPropertyStr(ctx, obj, "toISOString");
51958
0
    if (JS_IsException(method))
51959
0
        goto exception;
51960
0
    if (!JS_IsFunction(ctx, method)) {
51961
0
        JS_ThrowTypeError(ctx, "object needs toISOString method");
51962
0
        JS_FreeValue(ctx, method);
51963
0
        goto exception;
51964
0
    }
51965
0
    rv = JS_CallFree(ctx, method, obj, 0, NULL);
51966
0
exception:
51967
0
done:
51968
0
    JS_FreeValue(ctx, obj);
51969
0
    JS_FreeValue(ctx, tv);
51970
0
    return rv;
51971
0
}
51972
51973
static const JSCFunctionListEntry js_date_funcs[] = {
51974
    JS_CFUNC_DEF("now", 0, js_Date_now ),
51975
    JS_CFUNC_DEF("parse", 1, js_Date_parse ),
51976
    JS_CFUNC_DEF("UTC", 7, js_Date_UTC ),
51977
};
51978
51979
static const JSCFunctionListEntry js_date_proto_funcs[] = {
51980
    JS_CFUNC_DEF("valueOf", 0, js_date_getTime ),
51981
    JS_CFUNC_MAGIC_DEF("toString", 0, get_date_string, 0x13 ),
51982
    JS_CFUNC_DEF("[Symbol.toPrimitive]", 1, js_date_Symbol_toPrimitive ),
51983
    JS_CFUNC_MAGIC_DEF("toUTCString", 0, get_date_string, 0x03 ),
51984
    JS_ALIAS_DEF("toGMTString", "toUTCString" ),
51985
    JS_CFUNC_MAGIC_DEF("toISOString", 0, get_date_string, 0x23 ),
51986
    JS_CFUNC_MAGIC_DEF("toDateString", 0, get_date_string, 0x11 ),
51987
    JS_CFUNC_MAGIC_DEF("toTimeString", 0, get_date_string, 0x12 ),
51988
    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, get_date_string, 0x33 ),
51989
    JS_CFUNC_MAGIC_DEF("toLocaleDateString", 0, get_date_string, 0x31 ),
51990
    JS_CFUNC_MAGIC_DEF("toLocaleTimeString", 0, get_date_string, 0x32 ),
51991
    JS_CFUNC_DEF("getTimezoneOffset", 0, js_date_getTimezoneOffset ),
51992
    JS_CFUNC_DEF("getTime", 0, js_date_getTime ),
51993
    JS_CFUNC_MAGIC_DEF("getYear", 0, get_date_field, 0x101 ),
51994
    JS_CFUNC_MAGIC_DEF("getFullYear", 0, get_date_field, 0x01 ),
51995
    JS_CFUNC_MAGIC_DEF("getUTCFullYear", 0, get_date_field, 0x00 ),
51996
    JS_CFUNC_MAGIC_DEF("getMonth", 0, get_date_field, 0x11 ),
51997
    JS_CFUNC_MAGIC_DEF("getUTCMonth", 0, get_date_field, 0x10 ),
51998
    JS_CFUNC_MAGIC_DEF("getDate", 0, get_date_field, 0x21 ),
51999
    JS_CFUNC_MAGIC_DEF("getUTCDate", 0, get_date_field, 0x20 ),
52000
    JS_CFUNC_MAGIC_DEF("getHours", 0, get_date_field, 0x31 ),
52001
    JS_CFUNC_MAGIC_DEF("getUTCHours", 0, get_date_field, 0x30 ),
52002
    JS_CFUNC_MAGIC_DEF("getMinutes", 0, get_date_field, 0x41 ),
52003
    JS_CFUNC_MAGIC_DEF("getUTCMinutes", 0, get_date_field, 0x40 ),
52004
    JS_CFUNC_MAGIC_DEF("getSeconds", 0, get_date_field, 0x51 ),
52005
    JS_CFUNC_MAGIC_DEF("getUTCSeconds", 0, get_date_field, 0x50 ),
52006
    JS_CFUNC_MAGIC_DEF("getMilliseconds", 0, get_date_field, 0x61 ),
52007
    JS_CFUNC_MAGIC_DEF("getUTCMilliseconds", 0, get_date_field, 0x60 ),
52008
    JS_CFUNC_MAGIC_DEF("getDay", 0, get_date_field, 0x71 ),
52009
    JS_CFUNC_MAGIC_DEF("getUTCDay", 0, get_date_field, 0x70 ),
52010
    JS_CFUNC_DEF("setTime", 1, js_date_setTime ),
52011
    JS_CFUNC_MAGIC_DEF("setMilliseconds", 1, set_date_field, 0x671 ),
52012
    JS_CFUNC_MAGIC_DEF("setUTCMilliseconds", 1, set_date_field, 0x670 ),
52013
    JS_CFUNC_MAGIC_DEF("setSeconds", 2, set_date_field, 0x571 ),
52014
    JS_CFUNC_MAGIC_DEF("setUTCSeconds", 2, set_date_field, 0x570 ),
52015
    JS_CFUNC_MAGIC_DEF("setMinutes", 3, set_date_field, 0x471 ),
52016
    JS_CFUNC_MAGIC_DEF("setUTCMinutes", 3, set_date_field, 0x470 ),
52017
    JS_CFUNC_MAGIC_DEF("setHours", 4, set_date_field, 0x371 ),
52018
    JS_CFUNC_MAGIC_DEF("setUTCHours", 4, set_date_field, 0x370 ),
52019
    JS_CFUNC_MAGIC_DEF("setDate", 1, set_date_field, 0x231 ),
52020
    JS_CFUNC_MAGIC_DEF("setUTCDate", 1, set_date_field, 0x230 ),
52021
    JS_CFUNC_MAGIC_DEF("setMonth", 2, set_date_field, 0x131 ),
52022
    JS_CFUNC_MAGIC_DEF("setUTCMonth", 2, set_date_field, 0x130 ),
52023
    JS_CFUNC_DEF("setYear", 1, js_date_setYear ),
52024
    JS_CFUNC_MAGIC_DEF("setFullYear", 3, set_date_field, 0x031 ),
52025
    JS_CFUNC_MAGIC_DEF("setUTCFullYear", 3, set_date_field, 0x030 ),
52026
    JS_CFUNC_DEF("toJSON", 1, js_date_toJSON ),
52027
};
52028
52029
JSValue JS_NewDate(JSContext *ctx, double epoch_ms)
52030
0
{
52031
0
    JSValue obj = js_create_from_ctor(ctx, JS_UNDEFINED, JS_CLASS_DATE);
52032
0
    if (JS_IsException(obj))
52033
0
        return JS_EXCEPTION;
52034
0
    JS_SetObjectData(ctx, obj, __JS_NewFloat64(ctx, time_clip(epoch_ms)));
52035
0
    return obj;
52036
0
}
52037
52038
void JS_AddIntrinsicDate(JSContext *ctx)
52039
2
{
52040
2
    JSValueConst obj;
52041
52042
    /* Date */
52043
2
    ctx->class_proto[JS_CLASS_DATE] = JS_NewObject(ctx);
52044
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_DATE], js_date_proto_funcs,
52045
2
                               countof(js_date_proto_funcs));
52046
2
    obj = JS_NewGlobalCConstructor(ctx, "Date", js_date_constructor, 7,
52047
2
                                   ctx->class_proto[JS_CLASS_DATE]);
52048
2
    JS_SetPropertyFunctionList(ctx, obj, js_date_funcs, countof(js_date_funcs));
52049
2
}
52050
52051
/* eval */
52052
52053
void JS_AddIntrinsicEval(JSContext *ctx)
52054
2
{
52055
2
    ctx->eval_internal = __JS_EvalInternal;
52056
2
}
52057
52058
/* BigInt */
52059
52060
static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)
52061
0
{
52062
0
    uint32_t tag;
52063
52064
0
 redo:
52065
0
    tag = JS_VALUE_GET_NORM_TAG(val);
52066
0
    switch(tag) {
52067
0
    case JS_TAG_INT:
52068
0
    case JS_TAG_BOOL:
52069
0
        val = JS_NewBigInt64(ctx, JS_VALUE_GET_INT(val));
52070
0
        break;
52071
0
    case JS_TAG_SHORT_BIG_INT:
52072
0
    case JS_TAG_BIG_INT:
52073
0
        break;
52074
0
    case JS_TAG_FLOAT64:
52075
0
        {
52076
0
            double d = JS_VALUE_GET_FLOAT64(val);
52077
0
            JSBigInt *r;
52078
0
            int res;
52079
0
            r = js_bigint_from_float64(ctx, &res, d);
52080
0
            if (!r) {
52081
0
                if (res == 0) {
52082
0
                    val = JS_EXCEPTION;
52083
0
                } else if (res == 1) {
52084
0
                    val = JS_ThrowRangeError(ctx, "cannot convert to BigInt: not an integer");
52085
0
                } else {
52086
0
                    val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to BigInt");                }
52087
0
            } else {
52088
0
                val = JS_CompactBigInt(ctx, r);
52089
0
            }
52090
0
        }
52091
0
        break;
52092
0
    case JS_TAG_STRING:
52093
0
    case JS_TAG_STRING_ROPE:
52094
0
        val = JS_StringToBigIntErr(ctx, val);
52095
0
        break;
52096
0
    case JS_TAG_OBJECT:
52097
0
        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
52098
0
        if (JS_IsException(val))
52099
0
            break;
52100
0
        goto redo;
52101
0
    case JS_TAG_NULL:
52102
0
    case JS_TAG_UNDEFINED:
52103
0
    default:
52104
0
        JS_FreeValue(ctx, val);
52105
0
        return JS_ThrowTypeError(ctx, "cannot convert to BigInt");
52106
0
    }
52107
0
    return val;
52108
0
}
52109
52110
static JSValue js_bigint_constructor(JSContext *ctx,
52111
                                     JSValueConst new_target,
52112
                                     int argc, JSValueConst *argv)
52113
0
{
52114
0
    if (!JS_IsUndefined(new_target))
52115
0
        return JS_ThrowTypeError(ctx, "not a constructor");
52116
0
    return JS_ToBigIntCtorFree(ctx, JS_DupValue(ctx, argv[0]));
52117
0
}
52118
52119
static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val)
52120
0
{
52121
0
    if (JS_IsBigInt(ctx, this_val))
52122
0
        return JS_DupValue(ctx, this_val);
52123
52124
0
    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
52125
0
        JSObject *p = JS_VALUE_GET_OBJ(this_val);
52126
0
        if (p->class_id == JS_CLASS_BIG_INT) {
52127
0
            if (JS_IsBigInt(ctx, p->u.object_data))
52128
0
                return JS_DupValue(ctx, p->u.object_data);
52129
0
        }
52130
0
    }
52131
0
    return JS_ThrowTypeError(ctx, "not a BigInt");
52132
0
}
52133
52134
static JSValue js_bigint_toString(JSContext *ctx, JSValueConst this_val,
52135
                                  int argc, JSValueConst *argv)
52136
0
{
52137
0
    JSValue val;
52138
0
    int base;
52139
0
    JSValue ret;
52140
52141
0
    val = js_thisBigIntValue(ctx, this_val);
52142
0
    if (JS_IsException(val))
52143
0
        return val;
52144
0
    if (argc == 0 || JS_IsUndefined(argv[0])) {
52145
0
        base = 10;
52146
0
    } else {
52147
0
        base = js_get_radix(ctx, argv[0]);
52148
0
        if (base < 0)
52149
0
            goto fail;
52150
0
    }
52151
0
    ret = js_bigint_to_string1(ctx, val, base);
52152
0
    JS_FreeValue(ctx, val);
52153
0
    return ret;
52154
0
 fail:
52155
0
    JS_FreeValue(ctx, val);
52156
0
    return JS_EXCEPTION;
52157
0
}
52158
52159
static JSValue js_bigint_valueOf(JSContext *ctx, JSValueConst this_val,
52160
                                 int argc, JSValueConst *argv)
52161
0
{
52162
0
    return js_thisBigIntValue(ctx, this_val);
52163
0
}
52164
52165
static JSValue js_bigint_asUintN(JSContext *ctx,
52166
                                  JSValueConst this_val,
52167
                                  int argc, JSValueConst *argv, int asIntN)
52168
0
{
52169
0
    uint64_t bits;
52170
0
    JSValue res, a;
52171
    
52172
0
    if (JS_ToIndex(ctx, &bits, argv[0]))
52173
0
        return JS_EXCEPTION;
52174
0
    a = JS_ToBigInt(ctx, argv[1]);
52175
0
    if (JS_IsException(a))
52176
0
        return JS_EXCEPTION;
52177
0
    if (bits == 0) {
52178
0
        JS_FreeValue(ctx, a);
52179
0
        res = __JS_NewShortBigInt(ctx, 0);
52180
0
    } else if (JS_VALUE_GET_TAG(a) == JS_TAG_SHORT_BIG_INT) {
52181
        /* fast case */
52182
0
        if (bits >= JS_SHORT_BIG_INT_BITS) {
52183
0
            res = a;
52184
0
        } else {
52185
0
            uint64_t v;
52186
0
            int shift;
52187
0
            shift = 64 - bits;
52188
0
            v = JS_VALUE_GET_SHORT_BIG_INT(a);
52189
0
            v = v << shift;
52190
0
            if (asIntN)
52191
0
                v = (int64_t)v >> shift;
52192
0
            else
52193
0
                v = v >> shift;
52194
0
            res = __JS_NewShortBigInt(ctx, v);
52195
0
        }
52196
0
    } else {
52197
0
        JSBigInt *r, *p = JS_VALUE_GET_PTR(a);
52198
0
        if (bits >= p->len * JS_LIMB_BITS) {
52199
0
            res = a;
52200
0
        } else {
52201
0
            int len, shift, i;
52202
0
            js_limb_t v;
52203
0
            len = (bits + JS_LIMB_BITS - 1) / JS_LIMB_BITS;
52204
0
            r = js_bigint_new(ctx, len);
52205
0
            if (!r) {
52206
0
                JS_FreeValue(ctx, a);
52207
0
                return JS_EXCEPTION;
52208
0
            }
52209
0
            r->len = len;
52210
0
            for(i = 0; i < len - 1; i++)
52211
0
                r->tab[i] = p->tab[i];
52212
0
            shift = (-bits) & (JS_LIMB_BITS - 1);
52213
            /* 0 <= shift <= JS_LIMB_BITS - 1 */
52214
0
            v = p->tab[len - 1] << shift;
52215
0
            if (asIntN)
52216
0
                v = (js_slimb_t)v >> shift;
52217
0
            else
52218
0
                v = v >> shift;
52219
0
            r->tab[len - 1] = v;
52220
0
            r = js_bigint_normalize(ctx, r);
52221
0
            JS_FreeValue(ctx, a);
52222
0
            res = JS_CompactBigInt(ctx, r);
52223
0
        }
52224
0
    }
52225
0
    return res;
52226
0
}
52227
52228
static const JSCFunctionListEntry js_bigint_funcs[] = {
52229
    JS_CFUNC_MAGIC_DEF("asUintN", 2, js_bigint_asUintN, 0 ),
52230
    JS_CFUNC_MAGIC_DEF("asIntN", 2, js_bigint_asUintN, 1 ),
52231
};
52232
52233
static const JSCFunctionListEntry js_bigint_proto_funcs[] = {
52234
    JS_CFUNC_DEF("toString", 0, js_bigint_toString ),
52235
    JS_CFUNC_DEF("valueOf", 0, js_bigint_valueOf ),
52236
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "BigInt", JS_PROP_CONFIGURABLE ),
52237
};
52238
52239
static void JS_AddIntrinsicBigInt(JSContext *ctx)
52240
2
{
52241
2
    JSValueConst obj1;
52242
52243
2
    ctx->class_proto[JS_CLASS_BIG_INT] = JS_NewObject(ctx);
52244
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_INT],
52245
2
                               js_bigint_proto_funcs,
52246
2
                               countof(js_bigint_proto_funcs));
52247
2
    obj1 = JS_NewGlobalCConstructor(ctx, "BigInt", js_bigint_constructor, 1,
52248
2
                                    ctx->class_proto[JS_CLASS_BIG_INT]);
52249
2
    JS_SetPropertyFunctionList(ctx, obj1, js_bigint_funcs,
52250
2
                               countof(js_bigint_funcs));
52251
2
}
52252
52253
static const char * const native_error_name[JS_NATIVE_ERROR_COUNT] = {
52254
    "EvalError", "RangeError", "ReferenceError",
52255
    "SyntaxError", "TypeError", "URIError",
52256
    "InternalError", "AggregateError",
52257
};
52258
52259
/* Minimum amount of objects to be able to compile code and display
52260
   error messages. No JSAtom should be allocated by this function. */
52261
static void JS_AddIntrinsicBasicObjects(JSContext *ctx)
52262
2
{
52263
2
    JSValue proto;
52264
2
    int i;
52265
52266
2
    ctx->class_proto[JS_CLASS_OBJECT] = JS_NewObjectProto(ctx, JS_NULL);
52267
2
    JS_SetImmutablePrototype(ctx, ctx->class_proto[JS_CLASS_OBJECT]);
52268
    
52269
2
    ctx->function_proto = JS_NewCFunction3(ctx, js_function_proto, "", 0,
52270
2
                                           JS_CFUNC_generic, 0,
52271
2
                                           ctx->class_proto[JS_CLASS_OBJECT]);
52272
2
    ctx->class_proto[JS_CLASS_BYTECODE_FUNCTION] = JS_DupValue(ctx, ctx->function_proto);
52273
2
    ctx->class_proto[JS_CLASS_ERROR] = JS_NewObject(ctx);
52274
#if 0
52275
    /* these are auto-initialized from js_error_proto_funcs,
52276
       but delaying might be a problem */
52277
    JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ERROR], JS_ATOM_name,
52278
                           JS_AtomToString(ctx, JS_ATOM_Error),
52279
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
52280
    JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ERROR], JS_ATOM_message,
52281
                           JS_AtomToString(ctx, JS_ATOM_empty_string),
52282
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
52283
#endif
52284
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ERROR],
52285
2
                               js_error_proto_funcs,
52286
2
                               countof(js_error_proto_funcs));
52287
52288
18
    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
52289
16
        proto = JS_NewObjectProto(ctx, ctx->class_proto[JS_CLASS_ERROR]);
52290
16
        JS_DefinePropertyValue(ctx, proto, JS_ATOM_name,
52291
16
                               JS_NewAtomString(ctx, native_error_name[i]),
52292
16
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
52293
16
        JS_DefinePropertyValue(ctx, proto, JS_ATOM_message,
52294
16
                               JS_AtomToString(ctx, JS_ATOM_empty_string),
52295
16
                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
52296
16
        ctx->native_error_proto[i] = proto;
52297
16
    }
52298
52299
    /* the array prototype is an array */
52300
2
    ctx->class_proto[JS_CLASS_ARRAY] =
52301
2
        JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
52302
2
                               JS_CLASS_ARRAY);
52303
52304
2
    ctx->array_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_ARRAY]),
52305
2
                                     JS_PROP_INITIAL_HASH_SIZE, 1);
52306
2
    add_shape_property(ctx, &ctx->array_shape, NULL,
52307
2
                       JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_LENGTH);
52308
52309
    /* XXX: could test it on first context creation to ensure that no
52310
       new atoms are created in JS_AddIntrinsicBasicObjects(). It is
52311
       necessary to avoid useless renumbering of atoms after
52312
       JS_EvalBinary() if it is done just after
52313
       JS_AddIntrinsicBasicObjects(). */
52314
    //    assert(ctx->rt->atom_count == JS_ATOM_END);
52315
2
}
52316
52317
void JS_AddIntrinsicBaseObjects(JSContext *ctx)
52318
2
{
52319
2
    int i;
52320
2
    JSValueConst obj, number_obj;
52321
2
    JSValue obj1;
52322
52323
2
    ctx->throw_type_error = JS_NewCFunction(ctx, js_throw_type_error, NULL, 0);
52324
52325
    /* add caller and arguments properties to throw a TypeError */
52326
2
    JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_caller, JS_UNDEFINED,
52327
2
                      ctx->throw_type_error, ctx->throw_type_error,
52328
2
                      JS_PROP_HAS_GET | JS_PROP_HAS_SET |
52329
2
                      JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE);
52330
2
    JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_arguments, JS_UNDEFINED,
52331
2
                      ctx->throw_type_error, ctx->throw_type_error,
52332
2
                      JS_PROP_HAS_GET | JS_PROP_HAS_SET |
52333
2
                      JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE);
52334
2
    JS_FreeValue(ctx, js_object_seal(ctx, JS_UNDEFINED, 1, (JSValueConst *)&ctx->throw_type_error, 1));
52335
52336
2
    ctx->global_obj = JS_NewObject(ctx);
52337
2
    ctx->global_var_obj = JS_NewObjectProto(ctx, JS_NULL);
52338
52339
    /* Object */
52340
2
    obj = JS_NewGlobalCConstructor(ctx, "Object", js_object_constructor, 1,
52341
2
                                   ctx->class_proto[JS_CLASS_OBJECT]);
52342
2
    JS_SetPropertyFunctionList(ctx, obj, js_object_funcs, countof(js_object_funcs));
52343
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_OBJECT],
52344
2
                               js_object_proto_funcs, countof(js_object_proto_funcs));
52345
52346
    /* Function */
52347
2
    JS_SetPropertyFunctionList(ctx, ctx->function_proto, js_function_proto_funcs, countof(js_function_proto_funcs));
52348
2
    ctx->function_ctor = JS_NewCFunctionMagic(ctx, js_function_constructor,
52349
2
                                              "Function", 1, JS_CFUNC_constructor_or_func_magic,
52350
2
                                              JS_FUNC_NORMAL);
52351
2
    JS_NewGlobalCConstructor2(ctx, JS_DupValue(ctx, ctx->function_ctor), "Function",
52352
2
                              ctx->function_proto);
52353
52354
    /* Error */
52355
2
    obj1 = JS_NewCFunctionMagic(ctx, js_error_constructor,
52356
2
                                "Error", 1, JS_CFUNC_constructor_or_func_magic, -1);
52357
2
    JS_NewGlobalCConstructor2(ctx, obj1,
52358
2
                              "Error", ctx->class_proto[JS_CLASS_ERROR]);
52359
2
    JS_SetPropertyFunctionList(ctx, obj1, js_error_funcs, countof(js_error_funcs));
52360
52361
    /* Used to squelch a -Wcast-function-type warning. */
52362
2
    JSCFunctionType ft = { .generic_magic = js_error_constructor };
52363
18
    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {
52364
16
        JSValue func_obj;
52365
16
        int n_args;
52366
16
        n_args = 1 + (i == JS_AGGREGATE_ERROR);
52367
16
        func_obj = JS_NewCFunction3(ctx, ft.generic,
52368
16
                                    native_error_name[i], n_args,
52369
16
                                    JS_CFUNC_constructor_or_func_magic, i, obj1);
52370
16
        JS_NewGlobalCConstructor2(ctx, func_obj, native_error_name[i],
52371
16
                                  ctx->native_error_proto[i]);
52372
16
    }
52373
52374
    /* Iterator prototype */
52375
2
    ctx->iterator_proto = JS_NewObject(ctx);
52376
2
    JS_SetPropertyFunctionList(ctx, ctx->iterator_proto,
52377
2
                               js_iterator_proto_funcs,
52378
2
                               countof(js_iterator_proto_funcs));
52379
52380
    /* Array */
52381
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY],
52382
2
                               js_array_proto_funcs,
52383
2
                               countof(js_array_proto_funcs));
52384
52385
2
    obj = JS_NewGlobalCConstructor(ctx, "Array", js_array_constructor, 1,
52386
2
                                   ctx->class_proto[JS_CLASS_ARRAY]);
52387
2
    ctx->array_ctor = JS_DupValue(ctx, obj);
52388
2
    JS_SetPropertyFunctionList(ctx, obj, js_array_funcs,
52389
2
                               countof(js_array_funcs));
52390
52391
    /* XXX: create auto_initializer */
52392
2
    {
52393
        /* initialize Array.prototype[Symbol.unscopables] */
52394
2
        static const char unscopables[] =
52395
2
            "at" "\0"
52396
2
            "copyWithin" "\0"
52397
2
            "entries" "\0"
52398
2
            "fill" "\0"
52399
2
            "find" "\0"
52400
2
            "findIndex" "\0"
52401
2
            "findLast" "\0"
52402
2
            "findLastIndex" "\0"
52403
2
            "flat" "\0"
52404
2
            "flatMap" "\0"
52405
2
            "includes" "\0"
52406
2
            "keys" "\0"
52407
2
            "toReversed" "\0"
52408
2
            "toSorted" "\0"
52409
2
            "toSpliced" "\0"
52410
2
            "values" "\0";
52411
2
        const char *p = unscopables;
52412
2
        obj1 = JS_NewObjectProto(ctx, JS_NULL);
52413
34
        for(p = unscopables; *p; p += strlen(p) + 1) {
52414
32
            JS_DefinePropertyValueStr(ctx, obj1, p, JS_TRUE, JS_PROP_C_W_E);
52415
32
        }
52416
2
        JS_DefinePropertyValue(ctx, ctx->class_proto[JS_CLASS_ARRAY],
52417
2
                               JS_ATOM_Symbol_unscopables, obj1,
52418
2
                               JS_PROP_CONFIGURABLE);
52419
2
    }
52420
52421
    /* needed to initialize arguments[Symbol.iterator] */
52422
2
    ctx->array_proto_values =
52423
2
        JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_values);
52424
52425
2
    ctx->class_proto[JS_CLASS_ARRAY_ITERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto);
52426
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY_ITERATOR],
52427
2
                               js_array_iterator_proto_funcs,
52428
2
                               countof(js_array_iterator_proto_funcs));
52429
52430
    /* parseFloat and parseInteger must be defined before Number
52431
       because of the Number.parseFloat and Number.parseInteger
52432
       aliases */
52433
2
    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_global_funcs,
52434
2
                               countof(js_global_funcs));
52435
52436
    /* Number */
52437
2
    ctx->class_proto[JS_CLASS_NUMBER] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
52438
2
                                                               JS_CLASS_NUMBER);
52439
2
    JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_NUMBER], JS_NewInt32(ctx, 0));
52440
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_NUMBER],
52441
2
                               js_number_proto_funcs,
52442
2
                               countof(js_number_proto_funcs));
52443
2
    number_obj = JS_NewGlobalCConstructor(ctx, "Number", js_number_constructor, 1,
52444
2
                                          ctx->class_proto[JS_CLASS_NUMBER]);
52445
2
    JS_SetPropertyFunctionList(ctx, number_obj, js_number_funcs, countof(js_number_funcs));
52446
52447
    /* Boolean */
52448
2
    ctx->class_proto[JS_CLASS_BOOLEAN] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
52449
2
                                                                JS_CLASS_BOOLEAN);
52450
2
    JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], JS_NewBool(ctx, FALSE));
52451
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], js_boolean_proto_funcs,
52452
2
                               countof(js_boolean_proto_funcs));
52453
2
    JS_NewGlobalCConstructor(ctx, "Boolean", js_boolean_constructor, 1,
52454
2
                             ctx->class_proto[JS_CLASS_BOOLEAN]);
52455
52456
    /* String */
52457
2
    ctx->class_proto[JS_CLASS_STRING] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT],
52458
2
                                                               JS_CLASS_STRING);
52459
2
    JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_STRING], JS_AtomToString(ctx, JS_ATOM_empty_string));
52460
2
    obj = JS_NewGlobalCConstructor(ctx, "String", js_string_constructor, 1,
52461
2
                                   ctx->class_proto[JS_CLASS_STRING]);
52462
2
    JS_SetPropertyFunctionList(ctx, obj, js_string_funcs,
52463
2
                               countof(js_string_funcs));
52464
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING], js_string_proto_funcs,
52465
2
                               countof(js_string_proto_funcs));
52466
52467
2
    ctx->class_proto[JS_CLASS_STRING_ITERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto);
52468
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING_ITERATOR],
52469
2
                               js_string_iterator_proto_funcs,
52470
2
                               countof(js_string_iterator_proto_funcs));
52471
52472
    /* Math: create as autoinit object */
52473
2
    js_random_init(ctx);
52474
2
    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_math_obj, countof(js_math_obj));
52475
52476
    /* ES6 Reflect: create as autoinit object */
52477
2
    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_reflect_obj, countof(js_reflect_obj));
52478
52479
    /* ES6 Symbol */
52480
2
    ctx->class_proto[JS_CLASS_SYMBOL] = JS_NewObject(ctx);
52481
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_SYMBOL], js_symbol_proto_funcs,
52482
2
                               countof(js_symbol_proto_funcs));
52483
2
    obj = JS_NewGlobalCConstructor(ctx, "Symbol", js_symbol_constructor, 0,
52484
2
                                   ctx->class_proto[JS_CLASS_SYMBOL]);
52485
2
    JS_SetPropertyFunctionList(ctx, obj, js_symbol_funcs,
52486
2
                               countof(js_symbol_funcs));
52487
28
    for(i = JS_ATOM_Symbol_toPrimitive; i < JS_ATOM_END; i++) {
52488
26
        char buf[ATOM_GET_STR_BUF_SIZE];
52489
26
        const char *str, *p;
52490
26
        str = JS_AtomGetStr(ctx, buf, sizeof(buf), i);
52491
        /* skip "Symbol." */
52492
26
        p = strchr(str, '.');
52493
26
        if (p)
52494
26
            str = p + 1;
52495
26
        JS_DefinePropertyValueStr(ctx, obj, str, JS_AtomToValue(ctx, i), 0);
52496
26
    }
52497
52498
    /* ES6 Generator */
52499
2
    ctx->class_proto[JS_CLASS_GENERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto);
52500
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_GENERATOR],
52501
2
                               js_generator_proto_funcs,
52502
2
                               countof(js_generator_proto_funcs));
52503
52504
2
    ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION] = JS_NewObjectProto(ctx, ctx->function_proto);
52505
2
    obj1 = JS_NewCFunction3(ctx, (JSCFunction *)js_function_constructor,
52506
2
                            "GeneratorFunction", 1,
52507
2
                            JS_CFUNC_constructor_or_func_magic, JS_FUNC_GENERATOR,
52508
2
                            ctx->function_ctor);
52509
2
    JS_SetPropertyFunctionList(ctx,
52510
2
                               ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
52511
2
                               js_generator_function_proto_funcs,
52512
2
                               countof(js_generator_function_proto_funcs));
52513
2
    JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
52514
2
                       ctx->class_proto[JS_CLASS_GENERATOR],
52515
2
                       JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE);
52516
2
    JS_SetConstructor2(ctx, obj1, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],
52517
2
                       0, JS_PROP_CONFIGURABLE);
52518
2
    JS_FreeValue(ctx, obj1);
52519
52520
    /* global properties */
52521
2
    ctx->eval_obj = JS_NewCFunction(ctx, js_global_eval, "eval", 1);
52522
2
    JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_eval,
52523
2
                           JS_DupValue(ctx, ctx->eval_obj),
52524
2
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
52525
52526
2
    JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_globalThis,
52527
2
                           JS_DupValue(ctx, ctx->global_obj),
52528
2
                           JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE);
52529
52530
    /* BigInt */
52531
2
    JS_AddIntrinsicBigInt(ctx);
52532
2
}
52533
52534
/* Typed Arrays */
52535
52536
static uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT] = {
52537
    0, 0, 0, 1, 1, 2, 2,
52538
    3, 3,                   // BigInt64Array, BigUint64Array
52539
    1, 2, 3                 // Float16Array, Float32Array, Float64Array
52540
};
52541
52542
static JSValue js_array_buffer_constructor3(JSContext *ctx,
52543
                                            JSValueConst new_target,
52544
                                            uint64_t len, JSClassID class_id,
52545
                                            uint8_t *buf,
52546
                                            JSFreeArrayBufferDataFunc *free_func,
52547
                                            void *opaque, BOOL alloc_flag)
52548
0
{
52549
0
    JSRuntime *rt = ctx->rt;
52550
0
    JSValue obj;
52551
0
    JSArrayBuffer *abuf = NULL;
52552
52553
0
    obj = js_create_from_ctor(ctx, new_target, class_id);
52554
0
    if (JS_IsException(obj))
52555
0
        return obj;
52556
    /* XXX: we are currently limited to 2 GB */
52557
0
    if (len > INT32_MAX) {
52558
0
        JS_ThrowRangeError(ctx, "invalid array buffer length");
52559
0
        goto fail;
52560
0
    }
52561
0
    abuf = js_malloc(ctx, sizeof(*abuf));
52562
0
    if (!abuf)
52563
0
        goto fail;
52564
0
    abuf->byte_length = len;
52565
0
    if (alloc_flag) {
52566
0
        if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER &&
52567
0
            rt->sab_funcs.sab_alloc) {
52568
0
            abuf->data = rt->sab_funcs.sab_alloc(rt->sab_funcs.sab_opaque,
52569
0
                                                 max_int(len, 1));
52570
0
            if (!abuf->data)
52571
0
                goto fail;
52572
0
            memset(abuf->data, 0, len);
52573
0
        } else {
52574
            /* the allocation must be done after the object creation */
52575
0
            abuf->data = js_mallocz(ctx, max_int(len, 1));
52576
0
            if (!abuf->data)
52577
0
                goto fail;
52578
0
        }
52579
0
    } else {
52580
0
        if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER &&
52581
0
            rt->sab_funcs.sab_dup) {
52582
0
            rt->sab_funcs.sab_dup(rt->sab_funcs.sab_opaque, buf);
52583
0
        }
52584
0
        abuf->data = buf;
52585
0
    }
52586
0
    init_list_head(&abuf->array_list);
52587
0
    abuf->detached = FALSE;
52588
0
    abuf->shared = (class_id == JS_CLASS_SHARED_ARRAY_BUFFER);
52589
0
    abuf->opaque = opaque;
52590
0
    abuf->free_func = free_func;
52591
0
    if (alloc_flag && buf)
52592
0
        memcpy(abuf->data, buf, len);
52593
0
    JS_SetOpaque(obj, abuf);
52594
0
    return obj;
52595
0
 fail:
52596
0
    JS_FreeValue(ctx, obj);
52597
0
    js_free(ctx, abuf);
52598
0
    return JS_EXCEPTION;
52599
0
}
52600
52601
static void js_array_buffer_free(JSRuntime *rt, void *opaque, void *ptr)
52602
0
{
52603
0
    js_free_rt(rt, ptr);
52604
0
}
52605
52606
static JSValue js_array_buffer_constructor2(JSContext *ctx,
52607
                                            JSValueConst new_target,
52608
                                            uint64_t len, JSClassID class_id)
52609
0
{
52610
0
    return js_array_buffer_constructor3(ctx, new_target, len, class_id,
52611
0
                                        NULL, js_array_buffer_free, NULL,
52612
0
                                        TRUE);
52613
0
}
52614
52615
static JSValue js_array_buffer_constructor1(JSContext *ctx,
52616
                                            JSValueConst new_target,
52617
                                            uint64_t len)
52618
0
{
52619
0
    return js_array_buffer_constructor2(ctx, new_target, len,
52620
0
                                        JS_CLASS_ARRAY_BUFFER);
52621
0
}
52622
52623
JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len,
52624
                          JSFreeArrayBufferDataFunc *free_func, void *opaque,
52625
                          BOOL is_shared)
52626
0
{
52627
0
    return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len,
52628
0
                                        is_shared ? JS_CLASS_SHARED_ARRAY_BUFFER : JS_CLASS_ARRAY_BUFFER,
52629
0
                                        buf, free_func, opaque, FALSE);
52630
0
}
52631
52632
/* create a new ArrayBuffer of length 'len' and copy 'buf' to it */
52633
JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len)
52634
0
{
52635
0
    return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len,
52636
0
                                        JS_CLASS_ARRAY_BUFFER,
52637
0
                                        (uint8_t *)buf,
52638
0
                                        js_array_buffer_free, NULL,
52639
0
                                        TRUE);
52640
0
}
52641
52642
static JSValue js_array_buffer_constructor(JSContext *ctx,
52643
                                           JSValueConst new_target,
52644
                                           int argc, JSValueConst *argv)
52645
0
{
52646
0
    uint64_t len;
52647
0
    if (JS_ToIndex(ctx, &len, argv[0]))
52648
0
        return JS_EXCEPTION;
52649
0
    return js_array_buffer_constructor1(ctx, new_target, len);
52650
0
}
52651
52652
static JSValue js_shared_array_buffer_constructor(JSContext *ctx,
52653
                                                  JSValueConst new_target,
52654
                                                  int argc, JSValueConst *argv)
52655
0
{
52656
0
    uint64_t len;
52657
0
    if (JS_ToIndex(ctx, &len, argv[0]))
52658
0
        return JS_EXCEPTION;
52659
0
    return js_array_buffer_constructor2(ctx, new_target, len,
52660
0
                                        JS_CLASS_SHARED_ARRAY_BUFFER);
52661
0
}
52662
52663
/* also used for SharedArrayBuffer */
52664
static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val)
52665
0
{
52666
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
52667
0
    JSArrayBuffer *abuf = p->u.array_buffer;
52668
0
    struct list_head *el, *el1;
52669
52670
0
    if (abuf) {
52671
        /* The ArrayBuffer finalizer may be called before the typed
52672
           array finalizers using it, so abuf->array_list is not
52673
           necessarily empty. */
52674
0
        list_for_each_safe(el, el1, &abuf->array_list) {
52675
0
            JSTypedArray *ta;
52676
0
            JSObject *p1;
52677
52678
0
            ta = list_entry(el, JSTypedArray, link);
52679
0
            ta->link.prev = NULL;
52680
0
            ta->link.next = NULL;
52681
0
            p1 = ta->obj;
52682
            /* Note: the typed array length and offset fields are not modified */
52683
0
            if (p1->class_id != JS_CLASS_DATAVIEW) {
52684
0
                p1->u.array.count = 0;
52685
0
                p1->u.array.u.ptr = NULL;
52686
0
            }
52687
0
        }
52688
0
        if (abuf->shared && rt->sab_funcs.sab_free) {
52689
0
            rt->sab_funcs.sab_free(rt->sab_funcs.sab_opaque, abuf->data);
52690
0
        } else {
52691
0
            if (abuf->free_func)
52692
0
                abuf->free_func(rt, abuf->opaque, abuf->data);
52693
0
        }
52694
0
        js_free_rt(rt, abuf);
52695
0
    }
52696
0
}
52697
52698
static JSValue js_array_buffer_isView(JSContext *ctx,
52699
                                      JSValueConst this_val,
52700
                                      int argc, JSValueConst *argv)
52701
0
{
52702
0
    JSObject *p;
52703
0
    BOOL res;
52704
0
    res = FALSE;
52705
0
    if (JS_VALUE_GET_TAG(argv[0]) == JS_TAG_OBJECT) {
52706
0
        p = JS_VALUE_GET_OBJ(argv[0]);
52707
0
        if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
52708
0
            p->class_id <= JS_CLASS_DATAVIEW) {
52709
0
            res = TRUE;
52710
0
        }
52711
0
    }
52712
0
    return JS_NewBool(ctx, res);
52713
0
}
52714
52715
static const JSCFunctionListEntry js_array_buffer_funcs[] = {
52716
    JS_CFUNC_DEF("isView", 1, js_array_buffer_isView ),
52717
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
52718
};
52719
52720
static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx)
52721
0
{
52722
0
    return JS_ThrowTypeError(ctx, "ArrayBuffer is detached");
52723
0
}
52724
52725
static JSValue js_array_buffer_get_byteLength(JSContext *ctx,
52726
                                              JSValueConst this_val,
52727
                                              int class_id)
52728
0
{
52729
0
    JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, class_id);
52730
0
    if (!abuf)
52731
0
        return JS_EXCEPTION;
52732
    /* return 0 if detached */
52733
0
    return JS_NewUint32(ctx, abuf->byte_length);
52734
0
}
52735
52736
void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj)
52737
0
{
52738
0
    JSArrayBuffer *abuf = JS_GetOpaque(obj, JS_CLASS_ARRAY_BUFFER);
52739
0
    struct list_head *el;
52740
52741
0
    if (!abuf || abuf->detached)
52742
0
        return;
52743
0
    if (abuf->free_func)
52744
0
        abuf->free_func(ctx->rt, abuf->opaque, abuf->data);
52745
0
    abuf->data = NULL;
52746
0
    abuf->byte_length = 0;
52747
0
    abuf->detached = TRUE;
52748
52749
0
    list_for_each(el, &abuf->array_list) {
52750
0
        JSTypedArray *ta;
52751
0
        JSObject *p;
52752
52753
0
        ta = list_entry(el, JSTypedArray, link);
52754
0
        p = ta->obj;
52755
        /* Note: the typed array length and offset fields are not modified */
52756
0
        if (p->class_id != JS_CLASS_DATAVIEW) {
52757
0
            p->u.array.count = 0;
52758
0
            p->u.array.u.ptr = NULL;
52759
0
        }
52760
0
    }
52761
0
}
52762
52763
/* get an ArrayBuffer or SharedArrayBuffer */
52764
static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj)
52765
0
{
52766
0
    JSObject *p;
52767
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
52768
0
        goto fail;
52769
0
    p = JS_VALUE_GET_OBJ(obj);
52770
0
    if (p->class_id != JS_CLASS_ARRAY_BUFFER &&
52771
0
        p->class_id != JS_CLASS_SHARED_ARRAY_BUFFER) {
52772
0
    fail:
52773
0
        JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_ARRAY_BUFFER);
52774
0
        return NULL;
52775
0
    }
52776
0
    return p->u.array_buffer;
52777
0
}
52778
52779
/* return NULL if exception. WARNING: any JS call can detach the
52780
   buffer and render the returned pointer invalid */
52781
uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj)
52782
0
{
52783
0
    JSArrayBuffer *abuf = js_get_array_buffer(ctx, obj);
52784
0
    if (!abuf)
52785
0
        goto fail;
52786
0
    if (abuf->detached) {
52787
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
52788
0
        goto fail;
52789
0
    }
52790
0
    *psize = abuf->byte_length;
52791
0
    return abuf->data;
52792
0
 fail:
52793
0
    *psize = 0;
52794
0
    return NULL;
52795
0
}
52796
52797
static JSValue js_array_buffer_slice(JSContext *ctx,
52798
                                     JSValueConst this_val,
52799
                                     int argc, JSValueConst *argv, int class_id)
52800
0
{
52801
0
    JSArrayBuffer *abuf, *new_abuf;
52802
0
    int64_t len, start, end, new_len;
52803
0
    JSValue ctor, new_obj;
52804
52805
0
    abuf = JS_GetOpaque2(ctx, this_val, class_id);
52806
0
    if (!abuf)
52807
0
        return JS_EXCEPTION;
52808
0
    if (abuf->detached)
52809
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
52810
0
    len = abuf->byte_length;
52811
52812
0
    if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))
52813
0
        return JS_EXCEPTION;
52814
52815
0
    end = len;
52816
0
    if (!JS_IsUndefined(argv[1])) {
52817
0
        if (JS_ToInt64Clamp(ctx, &end, argv[1], 0, len, len))
52818
0
            return JS_EXCEPTION;
52819
0
    }
52820
0
    new_len = max_int64(end - start, 0);
52821
0
    ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);
52822
0
    if (JS_IsException(ctor))
52823
0
        return ctor;
52824
0
    if (JS_IsUndefined(ctor)) {
52825
0
        new_obj = js_array_buffer_constructor2(ctx, JS_UNDEFINED, new_len,
52826
0
                                               class_id);
52827
0
    } else {
52828
0
        JSValue args[1];
52829
0
        args[0] = JS_NewInt64(ctx, new_len);
52830
0
        new_obj = JS_CallConstructor(ctx, ctor, 1, (JSValueConst *)args);
52831
0
        JS_FreeValue(ctx, ctor);
52832
0
        JS_FreeValue(ctx, args[0]);
52833
0
    }
52834
0
    if (JS_IsException(new_obj))
52835
0
        return new_obj;
52836
0
    new_abuf = JS_GetOpaque2(ctx, new_obj, class_id);
52837
0
    if (!new_abuf)
52838
0
        goto fail;
52839
0
    if (js_same_value(ctx, new_obj, this_val)) {
52840
0
        JS_ThrowTypeError(ctx, "cannot use identical ArrayBuffer");
52841
0
        goto fail;
52842
0
    }
52843
0
    if (new_abuf->detached) {
52844
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
52845
0
        goto fail;
52846
0
    }
52847
0
    if (new_abuf->byte_length < new_len) {
52848
0
        JS_ThrowTypeError(ctx, "new ArrayBuffer is too small");
52849
0
        goto fail;
52850
0
    }
52851
    /* must test again because of side effects */
52852
0
    if (abuf->detached) {
52853
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
52854
0
        goto fail;
52855
0
    }
52856
0
    memcpy(new_abuf->data, abuf->data + start, new_len);
52857
0
    return new_obj;
52858
0
 fail:
52859
0
    JS_FreeValue(ctx, new_obj);
52860
0
    return JS_EXCEPTION;
52861
0
}
52862
52863
static const JSCFunctionListEntry js_array_buffer_proto_funcs[] = {
52864
    JS_CGETSET_MAGIC_DEF("byteLength", js_array_buffer_get_byteLength, NULL, JS_CLASS_ARRAY_BUFFER ),
52865
    JS_CFUNC_MAGIC_DEF("slice", 2, js_array_buffer_slice, JS_CLASS_ARRAY_BUFFER ),
52866
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "ArrayBuffer", JS_PROP_CONFIGURABLE ),
52867
};
52868
52869
/* SharedArrayBuffer */
52870
52871
static const JSCFunctionListEntry js_shared_array_buffer_funcs[] = {
52872
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
52873
};
52874
52875
static const JSCFunctionListEntry js_shared_array_buffer_proto_funcs[] = {
52876
    JS_CGETSET_MAGIC_DEF("byteLength", js_array_buffer_get_byteLength, NULL, JS_CLASS_SHARED_ARRAY_BUFFER ),
52877
    JS_CFUNC_MAGIC_DEF("slice", 2, js_array_buffer_slice, JS_CLASS_SHARED_ARRAY_BUFFER ),
52878
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "SharedArrayBuffer", JS_PROP_CONFIGURABLE ),
52879
};
52880
52881
static JSObject *get_typed_array(JSContext *ctx,
52882
                                 JSValueConst this_val,
52883
                                 int is_dataview)
52884
0
{
52885
0
    JSObject *p;
52886
0
    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
52887
0
        goto fail;
52888
0
    p = JS_VALUE_GET_OBJ(this_val);
52889
0
    if (is_dataview) {
52890
0
        if (p->class_id != JS_CLASS_DATAVIEW)
52891
0
            goto fail;
52892
0
    } else {
52893
0
        if (!(p->class_id >= JS_CLASS_UINT8C_ARRAY &&
52894
0
              p->class_id <= JS_CLASS_FLOAT64_ARRAY)) {
52895
0
        fail:
52896
0
            JS_ThrowTypeError(ctx, "not a %s", is_dataview ? "DataView" : "TypedArray");
52897
0
            return NULL;
52898
0
        }
52899
0
    }
52900
0
    return p;
52901
0
}
52902
52903
/* WARNING: 'p' must be a typed array */
52904
static BOOL typed_array_is_detached(JSContext *ctx, JSObject *p)
52905
0
{
52906
0
    JSTypedArray *ta = p->u.typed_array;
52907
0
    JSArrayBuffer *abuf = ta->buffer->u.array_buffer;
52908
    /* XXX: could simplify test by ensuring that
52909
       p->u.array.u.ptr is NULL iff it is detached */
52910
0
    return abuf->detached;
52911
0
}
52912
52913
/* WARNING: 'p' must be a typed array. Works even if the array buffer
52914
   is detached */
52915
static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p)
52916
0
{
52917
0
    JSTypedArray *ta = p->u.typed_array;
52918
0
    int size_log2 = typed_array_size_log2(p->class_id);
52919
0
    return ta->length >> size_log2;
52920
0
}
52921
52922
static int validate_typed_array(JSContext *ctx, JSValueConst this_val)
52923
0
{
52924
0
    JSObject *p;
52925
0
    p = get_typed_array(ctx, this_val, 0);
52926
0
    if (!p)
52927
0
        return -1;
52928
0
    if (typed_array_is_detached(ctx, p)) {
52929
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
52930
0
        return -1;
52931
0
    }
52932
0
    return 0;
52933
0
}
52934
52935
static JSValue js_typed_array_get_length(JSContext *ctx,
52936
                                         JSValueConst this_val)
52937
0
{
52938
0
    JSObject *p;
52939
0
    p = get_typed_array(ctx, this_val, 0);
52940
0
    if (!p)
52941
0
        return JS_EXCEPTION;
52942
0
    return JS_NewInt32(ctx, p->u.array.count);
52943
0
}
52944
52945
static JSValue js_typed_array_get_buffer(JSContext *ctx,
52946
                                         JSValueConst this_val, int is_dataview)
52947
0
{
52948
0
    JSObject *p;
52949
0
    JSTypedArray *ta;
52950
0
    p = get_typed_array(ctx, this_val, is_dataview);
52951
0
    if (!p)
52952
0
        return JS_EXCEPTION;
52953
0
    ta = p->u.typed_array;
52954
0
    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
52955
0
}
52956
52957
static JSValue js_typed_array_get_byteLength(JSContext *ctx,
52958
                                             JSValueConst this_val,
52959
                                             int is_dataview)
52960
0
{
52961
0
    JSObject *p;
52962
0
    JSTypedArray *ta;
52963
0
    p = get_typed_array(ctx, this_val, is_dataview);
52964
0
    if (!p)
52965
0
        return JS_EXCEPTION;
52966
0
    if (typed_array_is_detached(ctx, p)) {
52967
0
        if (is_dataview) {
52968
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
52969
0
        } else {
52970
0
            return JS_NewInt32(ctx, 0);
52971
0
        }
52972
0
    }
52973
0
    ta = p->u.typed_array;
52974
0
    return JS_NewInt32(ctx, ta->length);
52975
0
}
52976
52977
static JSValue js_typed_array_get_byteOffset(JSContext *ctx,
52978
                                             JSValueConst this_val,
52979
                                             int is_dataview)
52980
0
{
52981
0
    JSObject *p;
52982
0
    JSTypedArray *ta;
52983
0
    p = get_typed_array(ctx, this_val, is_dataview);
52984
0
    if (!p)
52985
0
        return JS_EXCEPTION;
52986
0
    if (typed_array_is_detached(ctx, p)) {
52987
0
        if (is_dataview) {
52988
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
52989
0
        } else {
52990
0
            return JS_NewInt32(ctx, 0);
52991
0
        }
52992
0
    }
52993
0
    ta = p->u.typed_array;
52994
0
    return JS_NewInt32(ctx, ta->offset);
52995
0
}
52996
52997
JSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValueConst *argv,
52998
                         JSTypedArrayEnum type)
52999
0
{
53000
0
    if (type < JS_TYPED_ARRAY_UINT8C || type > JS_TYPED_ARRAY_FLOAT64)
53001
0
        return JS_ThrowRangeError(ctx, "invalid typed array type");
53002
53003
0
    return js_typed_array_constructor(ctx, JS_UNDEFINED, argc, argv,
53004
0
                                      JS_CLASS_UINT8C_ARRAY + type);
53005
0
}
53006
53007
/* Return the buffer associated to the typed array or an exception if
53008
   it is not a typed array or if the buffer is detached. pbyte_offset,
53009
   pbyte_length or pbytes_per_element can be NULL. */
53010
JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj,
53011
                               size_t *pbyte_offset,
53012
                               size_t *pbyte_length,
53013
                               size_t *pbytes_per_element)
53014
0
{
53015
0
    JSObject *p;
53016
0
    JSTypedArray *ta;
53017
0
    p = get_typed_array(ctx, obj, FALSE);
53018
0
    if (!p)
53019
0
        return JS_EXCEPTION;
53020
0
    if (typed_array_is_detached(ctx, p))
53021
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53022
0
    ta = p->u.typed_array;
53023
0
    if (pbyte_offset)
53024
0
        *pbyte_offset = ta->offset;
53025
0
    if (pbyte_length)
53026
0
        *pbyte_length = ta->length;
53027
0
    if (pbytes_per_element) {
53028
0
        *pbytes_per_element = 1 << typed_array_size_log2(p->class_id);
53029
0
    }
53030
0
    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
53031
0
}
53032
53033
static JSValue js_typed_array_get_toStringTag(JSContext *ctx,
53034
                                              JSValueConst this_val)
53035
0
{
53036
0
    JSObject *p;
53037
0
    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
53038
0
        return JS_UNDEFINED;
53039
0
    p = JS_VALUE_GET_OBJ(this_val);
53040
0
    if (!(p->class_id >= JS_CLASS_UINT8C_ARRAY &&
53041
0
          p->class_id <= JS_CLASS_FLOAT64_ARRAY))
53042
0
        return JS_UNDEFINED;
53043
0
    return JS_AtomToString(ctx, ctx->rt->class_array[p->class_id].class_name);
53044
0
}
53045
53046
static JSValue js_typed_array_set_internal(JSContext *ctx,
53047
                                           JSValueConst dst,
53048
                                           JSValueConst src,
53049
                                           JSValueConst off)
53050
0
{
53051
0
    JSObject *p;
53052
0
    JSObject *src_p;
53053
0
    uint32_t i;
53054
0
    int64_t src_len, offset;
53055
0
    JSValue val, src_obj = JS_UNDEFINED;
53056
53057
0
    p = get_typed_array(ctx, dst, 0);
53058
0
    if (!p)
53059
0
        goto fail;
53060
0
    if (JS_ToInt64Sat(ctx, &offset, off))
53061
0
        goto fail;
53062
0
    if (offset < 0)
53063
0
        goto range_error;
53064
0
    if (typed_array_is_detached(ctx, p)) {
53065
0
    detached:
53066
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53067
0
        goto fail;
53068
0
    }
53069
0
    src_obj = JS_ToObject(ctx, src);
53070
0
    if (JS_IsException(src_obj))
53071
0
        goto fail;
53072
0
    src_p = JS_VALUE_GET_OBJ(src_obj);
53073
0
    if (src_p->class_id >= JS_CLASS_UINT8C_ARRAY &&
53074
0
        src_p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
53075
0
        JSTypedArray *dest_ta = p->u.typed_array;
53076
0
        JSArrayBuffer *dest_abuf = dest_ta->buffer->u.array_buffer;
53077
0
        JSTypedArray *src_ta = src_p->u.typed_array;
53078
0
        JSArrayBuffer *src_abuf = src_ta->buffer->u.array_buffer;
53079
0
        int shift = typed_array_size_log2(p->class_id);
53080
53081
0
        if (src_abuf->detached)
53082
0
            goto detached;
53083
53084
0
        src_len = src_p->u.array.count;
53085
0
        if (offset > (int64_t)(p->u.array.count - src_len))
53086
0
            goto range_error;
53087
53088
        /* copying between typed objects */
53089
0
        if (src_p->class_id == p->class_id) {
53090
            /* same type, use memmove */
53091
0
            memmove(dest_abuf->data + dest_ta->offset + (offset << shift),
53092
0
                    src_abuf->data + src_ta->offset, src_len << shift);
53093
0
            goto done;
53094
0
        }
53095
0
        if (dest_abuf->data == src_abuf->data) {
53096
            /* copying between the same buffer using different types of mappings
53097
               would require a temporary buffer */
53098
0
        }
53099
        /* otherwise, default behavior is slow but correct */
53100
0
    } else {
53101
0
        if (js_get_length64(ctx, &src_len, src_obj))
53102
0
            goto fail;
53103
0
        if (offset > (int64_t)(p->u.array.count - src_len)) {
53104
0
        range_error:
53105
0
            JS_ThrowRangeError(ctx, "invalid array length");
53106
0
            goto fail;
53107
0
        }
53108
0
    }
53109
0
    for(i = 0; i < src_len; i++) {
53110
0
        val = JS_GetPropertyUint32(ctx, src_obj, i);
53111
0
        if (JS_IsException(val))
53112
0
            goto fail;
53113
0
        if (JS_SetPropertyUint32(ctx, dst, offset + i, val) < 0)
53114
0
            goto fail;
53115
0
    }
53116
0
done:
53117
0
    JS_FreeValue(ctx, src_obj);
53118
0
    return JS_UNDEFINED;
53119
0
fail:
53120
0
    JS_FreeValue(ctx, src_obj);
53121
0
    return JS_EXCEPTION;
53122
0
}
53123
53124
static JSValue js_typed_array_at(JSContext *ctx, JSValueConst this_val,
53125
                                 int argc, JSValueConst *argv)
53126
0
{
53127
0
    JSObject *p;
53128
0
    int64_t idx, len;
53129
53130
0
    p = get_typed_array(ctx, this_val, 0);
53131
0
    if (!p)
53132
0
        return JS_EXCEPTION;
53133
53134
0
    if (typed_array_is_detached(ctx, p)) {
53135
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53136
0
        return JS_EXCEPTION;
53137
0
    }
53138
53139
0
    if (JS_ToInt64Sat(ctx, &idx, argv[0]))
53140
0
        return JS_EXCEPTION;
53141
53142
0
    len = p->u.array.count;
53143
0
    if (idx < 0)
53144
0
        idx = len + idx;
53145
0
    if (idx < 0 || idx >= len)
53146
0
        return JS_UNDEFINED;
53147
0
    return JS_GetPropertyInt64(ctx, this_val, idx);
53148
0
}
53149
53150
static JSValue js_typed_array_with(JSContext *ctx, JSValueConst this_val,
53151
                                   int argc, JSValueConst *argv)
53152
0
{
53153
0
    JSValue arr, val;
53154
0
    JSObject *p;
53155
0
    int64_t idx, len;
53156
53157
0
    p = get_typed_array(ctx, this_val, /*is_dataview*/0);
53158
0
    if (!p)
53159
0
        return JS_EXCEPTION;
53160
0
    if (typed_array_is_detached(ctx, p))
53161
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53162
53163
0
    if (JS_ToInt64Sat(ctx, &idx, argv[0]))
53164
0
        return JS_EXCEPTION;
53165
53166
0
    len = p->u.array.count;
53167
0
    if (idx < 0)
53168
0
        idx = len + idx;
53169
53170
0
    val = JS_ToPrimitive(ctx, argv[1], HINT_NUMBER);
53171
0
    if (JS_IsException(val))
53172
0
        return JS_EXCEPTION;
53173
53174
0
    if (typed_array_is_detached(ctx, p) || idx < 0 || idx >= len)
53175
0
        return JS_ThrowRangeError(ctx, "invalid array index");
53176
53177
0
    arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,
53178
0
                                        p->class_id);
53179
0
    if (JS_IsException(arr)) {
53180
0
        JS_FreeValue(ctx, val);
53181
0
        return JS_EXCEPTION;
53182
0
    }
53183
0
    if (JS_SetPropertyInt64(ctx, arr, idx, val) < 0) {
53184
0
        JS_FreeValue(ctx, arr);
53185
0
        return JS_EXCEPTION;
53186
0
    }
53187
0
    return arr;
53188
0
}
53189
53190
static JSValue js_typed_array_set(JSContext *ctx,
53191
                                  JSValueConst this_val,
53192
                                  int argc, JSValueConst *argv)
53193
0
{
53194
0
    JSValueConst offset = JS_UNDEFINED;
53195
0
    if (argc > 1) {
53196
0
        offset = argv[1];
53197
0
    }
53198
0
    return js_typed_array_set_internal(ctx, this_val, argv[0], offset);
53199
0
}
53200
53201
static JSValue js_create_typed_array_iterator(JSContext *ctx, JSValueConst this_val,
53202
                                              int argc, JSValueConst *argv, int magic)
53203
0
{
53204
0
    if (validate_typed_array(ctx, this_val))
53205
0
        return JS_EXCEPTION;
53206
0
    return js_create_array_iterator(ctx, this_val, argc, argv, magic);
53207
0
}
53208
53209
/* return < 0 if exception */
53210
static int js_typed_array_get_length_internal(JSContext *ctx,
53211
                                              JSValueConst obj)
53212
0
{
53213
0
    JSObject *p;
53214
0
    p = get_typed_array(ctx, obj, 0);
53215
0
    if (!p)
53216
0
        return -1;
53217
0
    if (typed_array_is_detached(ctx, p)) {
53218
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53219
0
        return -1;
53220
0
    }
53221
0
    return p->u.array.count;
53222
0
}
53223
53224
#if 0
53225
/* validate a typed array and return its length */
53226
static JSValue js_typed_array___getLength(JSContext *ctx,
53227
                                          JSValueConst this_val,
53228
                                          int argc, JSValueConst *argv)
53229
{
53230
    BOOL ignore_detached = JS_ToBool(ctx, argv[1]);
53231
53232
    if (ignore_detached) {
53233
        return js_typed_array_get_length(ctx, argv[0]);
53234
    } else {
53235
        int len;
53236
        len = js_typed_array_get_length_internal(ctx, argv[0]);
53237
        if (len < 0)
53238
            return JS_EXCEPTION;
53239
        return JS_NewInt32(ctx, len);
53240
    }
53241
}
53242
#endif
53243
53244
static JSValue js_typed_array_create(JSContext *ctx, JSValueConst ctor,
53245
                                     int argc, JSValueConst *argv)
53246
0
{
53247
0
    JSValue ret;
53248
0
    int new_len;
53249
0
    int64_t len;
53250
53251
0
    ret = JS_CallConstructor(ctx, ctor, argc, argv);
53252
0
    if (JS_IsException(ret))
53253
0
        return ret;
53254
    /* validate the typed array */
53255
0
    new_len = js_typed_array_get_length_internal(ctx, ret);
53256
0
    if (new_len < 0)
53257
0
        goto fail;
53258
0
    if (argc == 1) {
53259
        /* ensure that it is large enough */
53260
0
        if (JS_ToLengthFree(ctx, &len, JS_DupValue(ctx, argv[0])))
53261
0
            goto fail;
53262
0
        if (new_len < len) {
53263
0
            JS_ThrowTypeError(ctx, "TypedArray length is too small");
53264
0
        fail:
53265
0
            JS_FreeValue(ctx, ret);
53266
0
            return JS_EXCEPTION;
53267
0
        }
53268
0
    }
53269
0
    return ret;
53270
0
}
53271
53272
#if 0
53273
static JSValue js_typed_array___create(JSContext *ctx,
53274
                                       JSValueConst this_val,
53275
                                       int argc, JSValueConst *argv)
53276
{
53277
    return js_typed_array_create(ctx, argv[0], max_int(argc - 1, 0), argv + 1);
53278
}
53279
#endif
53280
53281
static JSValue js_typed_array___speciesCreate(JSContext *ctx,
53282
                                              JSValueConst this_val,
53283
                                              int argc, JSValueConst *argv)
53284
0
{
53285
0
    JSValueConst obj;
53286
0
    JSObject *p;
53287
0
    JSValue ctor, ret;
53288
0
    int argc1;
53289
53290
0
    obj = argv[0];
53291
0
    p = get_typed_array(ctx, obj, 0);
53292
0
    if (!p)
53293
0
        return JS_EXCEPTION;
53294
0
    ctor = JS_SpeciesConstructor(ctx, obj, JS_UNDEFINED);
53295
0
    if (JS_IsException(ctor))
53296
0
        return ctor;
53297
0
    argc1 = max_int(argc - 1, 0);
53298
0
    if (JS_IsUndefined(ctor)) {
53299
0
        ret = js_typed_array_constructor(ctx, JS_UNDEFINED, argc1, argv + 1,
53300
0
                                         p->class_id);
53301
0
    } else {
53302
0
        ret = js_typed_array_create(ctx, ctor, argc1, argv + 1);
53303
0
        JS_FreeValue(ctx, ctor);
53304
0
    }
53305
0
    return ret;
53306
0
}
53307
53308
static JSValue js_typed_array_from(JSContext *ctx, JSValueConst this_val,
53309
                                   int argc, JSValueConst *argv)
53310
0
{
53311
    // from(items, mapfn = void 0, this_arg = void 0)
53312
0
    JSValueConst items = argv[0], mapfn, this_arg;
53313
0
    JSValueConst args[2];
53314
0
    JSValue iter, arr, r, v, v2;
53315
0
    int64_t k, len;
53316
0
    int mapping;
53317
53318
0
    mapping = FALSE;
53319
0
    mapfn = JS_UNDEFINED;
53320
0
    this_arg = JS_UNDEFINED;
53321
0
    r = JS_UNDEFINED;
53322
0
    arr = JS_UNDEFINED;
53323
0
    iter = JS_UNDEFINED;
53324
53325
0
    if (argc > 1) {
53326
0
        mapfn = argv[1];
53327
0
        if (!JS_IsUndefined(mapfn)) {
53328
0
            if (check_function(ctx, mapfn))
53329
0
                goto exception;
53330
0
            mapping = 1;
53331
0
            if (argc > 2)
53332
0
                this_arg = argv[2];
53333
0
        }
53334
0
    }
53335
0
    iter = JS_GetProperty(ctx, items, JS_ATOM_Symbol_iterator);
53336
0
    if (JS_IsException(iter))
53337
0
        goto exception;
53338
0
    if (!JS_IsUndefined(iter) && !JS_IsNull(iter)) {
53339
0
        uint32_t len1;
53340
0
        if (!JS_IsFunction(ctx, iter)) {
53341
0
            JS_ThrowTypeError(ctx, "value is not iterable");
53342
0
            goto exception;
53343
0
        }
53344
0
        arr = js_array_from_iterator(ctx, &len1, items, iter);
53345
0
        if (JS_IsException(arr))
53346
0
            goto exception;
53347
0
        len = len1;
53348
0
    } else {
53349
0
        arr = JS_ToObject(ctx, items);
53350
0
        if (JS_IsException(arr))
53351
0
            goto exception;
53352
0
        if (js_get_length64(ctx, &len, arr) < 0)
53353
0
            goto exception;
53354
0
    }
53355
0
    v = JS_NewInt64(ctx, len);
53356
0
    args[0] = v;
53357
0
    r = js_typed_array_create(ctx, this_val, 1, args);
53358
0
    JS_FreeValue(ctx, v);
53359
0
    if (JS_IsException(r))
53360
0
        goto exception;
53361
0
    for(k = 0; k < len; k++) {
53362
0
        v = JS_GetPropertyInt64(ctx, arr, k);
53363
0
        if (JS_IsException(v))
53364
0
            goto exception;
53365
0
        if (mapping) {
53366
0
            args[0] = v;
53367
0
            args[1] = JS_NewInt32(ctx, k);
53368
0
            v2 = JS_Call(ctx, mapfn, this_arg, 2, args);
53369
0
            JS_FreeValue(ctx, v);
53370
0
            v = v2;
53371
0
            if (JS_IsException(v))
53372
0
                goto exception;
53373
0
        }
53374
0
        if (JS_SetPropertyInt64(ctx, r, k, v) < 0)
53375
0
            goto exception;
53376
0
    }
53377
0
    goto done;
53378
0
 exception:
53379
0
    JS_FreeValue(ctx, r);
53380
0
    r = JS_EXCEPTION;
53381
0
 done:
53382
0
    JS_FreeValue(ctx, arr);
53383
0
    JS_FreeValue(ctx, iter);
53384
0
    return r;
53385
0
}
53386
53387
static JSValue js_typed_array_of(JSContext *ctx, JSValueConst this_val,
53388
                                 int argc, JSValueConst *argv)
53389
0
{
53390
0
    JSValue obj;
53391
0
    JSValueConst args[1];
53392
0
    int i;
53393
53394
0
    args[0] = JS_NewInt32(ctx, argc);
53395
0
    obj = js_typed_array_create(ctx, this_val, 1, args);
53396
0
    if (JS_IsException(obj))
53397
0
        return obj;
53398
53399
0
    for(i = 0; i < argc; i++) {
53400
0
        if (JS_SetPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i])) < 0) {
53401
0
            JS_FreeValue(ctx, obj);
53402
0
            return JS_EXCEPTION;
53403
0
        }
53404
0
    }
53405
0
    return obj;
53406
0
}
53407
53408
static JSValue js_typed_array_copyWithin(JSContext *ctx, JSValueConst this_val,
53409
                                         int argc, JSValueConst *argv)
53410
0
{
53411
0
    JSObject *p;
53412
0
    int len, to, from, final, count, shift;
53413
53414
0
    len = js_typed_array_get_length_internal(ctx, this_val);
53415
0
    if (len < 0)
53416
0
        return JS_EXCEPTION;
53417
53418
0
    if (JS_ToInt32Clamp(ctx, &to, argv[0], 0, len, len))
53419
0
        return JS_EXCEPTION;
53420
53421
0
    if (JS_ToInt32Clamp(ctx, &from, argv[1], 0, len, len))
53422
0
        return JS_EXCEPTION;
53423
53424
0
    final = len;
53425
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
53426
0
        if (JS_ToInt32Clamp(ctx, &final, argv[2], 0, len, len))
53427
0
            return JS_EXCEPTION;
53428
0
    }
53429
53430
0
    count = min_int(final - from, len - to);
53431
0
    if (count > 0) {
53432
0
        p = JS_VALUE_GET_OBJ(this_val);
53433
0
        if (typed_array_is_detached(ctx, p))
53434
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53435
0
        shift = typed_array_size_log2(p->class_id);
53436
0
        memmove(p->u.array.u.uint8_ptr + (to << shift),
53437
0
                p->u.array.u.uint8_ptr + (from << shift),
53438
0
                count << shift);
53439
0
    }
53440
0
    return JS_DupValue(ctx, this_val);
53441
0
}
53442
53443
static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val,
53444
                                   int argc, JSValueConst *argv)
53445
0
{
53446
0
    JSObject *p;
53447
0
    int len, k, final, shift;
53448
0
    uint64_t v64;
53449
53450
0
    len = js_typed_array_get_length_internal(ctx, this_val);
53451
0
    if (len < 0)
53452
0
        return JS_EXCEPTION;
53453
0
    p = JS_VALUE_GET_OBJ(this_val);
53454
53455
0
    if (p->class_id == JS_CLASS_UINT8C_ARRAY) {
53456
0
        int32_t v;
53457
0
        if (JS_ToUint8ClampFree(ctx, &v, JS_DupValue(ctx, argv[0])))
53458
0
            return JS_EXCEPTION;
53459
0
        v64 = v;
53460
0
    } else if (p->class_id <= JS_CLASS_UINT32_ARRAY) {
53461
0
        uint32_t v;
53462
0
        if (JS_ToUint32(ctx, &v, argv[0]))
53463
0
            return JS_EXCEPTION;
53464
0
        v64 = v;
53465
0
    } else if (p->class_id <= JS_CLASS_BIG_UINT64_ARRAY) {
53466
0
        if (JS_ToBigInt64(ctx, (int64_t *)&v64, argv[0]))
53467
0
            return JS_EXCEPTION;
53468
0
    } else {
53469
0
        double d;
53470
0
        if (JS_ToFloat64(ctx, &d, argv[0]))
53471
0
            return JS_EXCEPTION;
53472
0
        if (p->class_id == JS_CLASS_FLOAT16_ARRAY) {
53473
0
            v64 = tofp16(d);
53474
0
        } else if (p->class_id == JS_CLASS_FLOAT32_ARRAY) {
53475
0
            union {
53476
0
                float f;
53477
0
                uint32_t u32;
53478
0
            } u;
53479
0
            u.f = d;
53480
0
            v64 = u.u32;
53481
0
        } else {
53482
0
            JSFloat64Union u;
53483
0
            u.d = d;
53484
0
            v64 = u.u64;
53485
0
        }
53486
0
    }
53487
53488
0
    k = 0;
53489
0
    if (argc > 1) {
53490
0
        if (JS_ToInt32Clamp(ctx, &k, argv[1], 0, len, len))
53491
0
            return JS_EXCEPTION;
53492
0
    }
53493
53494
0
    final = len;
53495
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
53496
0
        if (JS_ToInt32Clamp(ctx, &final, argv[2], 0, len, len))
53497
0
            return JS_EXCEPTION;
53498
0
    }
53499
53500
0
    if (typed_array_is_detached(ctx, p))
53501
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
53502
53503
0
    shift = typed_array_size_log2(p->class_id);
53504
0
    switch(shift) {
53505
0
    case 0:
53506
0
        if (k < final) {
53507
0
            memset(p->u.array.u.uint8_ptr + k, v64, final - k);
53508
0
        }
53509
0
        break;
53510
0
    case 1:
53511
0
        for(; k < final; k++) {
53512
0
            p->u.array.u.uint16_ptr[k] = v64;
53513
0
        }
53514
0
        break;
53515
0
    case 2:
53516
0
        for(; k < final; k++) {
53517
0
            p->u.array.u.uint32_ptr[k] = v64;
53518
0
        }
53519
0
        break;
53520
0
    case 3:
53521
0
        for(; k < final; k++) {
53522
0
            p->u.array.u.uint64_ptr[k] = v64;
53523
0
        }
53524
0
        break;
53525
0
    default:
53526
0
        abort();
53527
0
    }
53528
0
    return JS_DupValue(ctx, this_val);
53529
0
}
53530
53531
static JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val,
53532
                                   int argc, JSValueConst *argv, int mode)
53533
0
{
53534
0
    JSValueConst func, this_arg;
53535
0
    JSValueConst args[3];
53536
0
    JSValue val, index_val, res;
53537
0
    int len, k, end;
53538
0
    int dir;
53539
53540
0
    val = JS_UNDEFINED;
53541
0
    len = js_typed_array_get_length_internal(ctx, this_val);
53542
0
    if (len < 0)
53543
0
        goto exception;
53544
53545
0
    func = argv[0];
53546
0
    if (check_function(ctx, func))
53547
0
        goto exception;
53548
53549
0
    this_arg = JS_UNDEFINED;
53550
0
    if (argc > 1)
53551
0
        this_arg = argv[1];
53552
53553
0
    k = 0;
53554
0
    dir = 1;
53555
0
    end = len;
53556
0
    if (mode == ArrayFindLast || mode == ArrayFindLastIndex) {
53557
0
        k = len - 1;
53558
0
        dir = -1;
53559
0
        end = -1;
53560
0
    }
53561
53562
0
    for(; k != end; k += dir) {
53563
0
        index_val = JS_NewInt32(ctx, k);
53564
0
        val = JS_GetPropertyValue(ctx, this_val, index_val);
53565
0
        if (JS_IsException(val))
53566
0
            goto exception;
53567
0
        args[0] = val;
53568
0
        args[1] = index_val;
53569
0
        args[2] = this_val;
53570
0
        res = JS_Call(ctx, func, this_arg, 3, args);
53571
0
        if (JS_IsException(res))
53572
0
            goto exception;
53573
0
        if (JS_ToBoolFree(ctx, res)) {
53574
0
            if (mode == ArrayFindIndex || mode == ArrayFindLastIndex) {
53575
0
                JS_FreeValue(ctx, val);
53576
0
                return index_val;
53577
0
            } else {
53578
0
                return val;
53579
0
            }
53580
0
        }
53581
0
        JS_FreeValue(ctx, val);
53582
0
    }
53583
0
    if (mode == ArrayFindIndex || mode == ArrayFindLastIndex)
53584
0
        return JS_NewInt32(ctx, -1);
53585
0
    else
53586
0
        return JS_UNDEFINED;
53587
53588
0
exception:
53589
0
    JS_FreeValue(ctx, val);
53590
0
    return JS_EXCEPTION;
53591
0
}
53592
53593
#define special_indexOf 0
53594
0
#define special_lastIndexOf 1
53595
0
#define special_includes -1
53596
53597
static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
53598
                                      int argc, JSValueConst *argv, int special)
53599
0
{
53600
0
    JSObject *p;
53601
0
    int len, tag, is_int, is_bigint, k, stop, inc, res = -1;
53602
0
    int64_t v64;
53603
0
    double d;
53604
0
    float f;
53605
0
    uint16_t hf;
53606
53607
0
    len = js_typed_array_get_length_internal(ctx, this_val);
53608
0
    if (len < 0)
53609
0
        goto exception;
53610
0
    if (len == 0)
53611
0
        goto done;
53612
53613
0
    if (special == special_lastIndexOf) {
53614
0
        k = len - 1;
53615
0
        if (argc > 1) {
53616
0
            if (JS_ToFloat64(ctx, &d, argv[1]))
53617
0
                goto exception;
53618
0
            if (isnan(d)) {
53619
0
                k = 0;
53620
0
            } else {
53621
0
                if (d >= 0) {
53622
0
                    if (d < k) {
53623
0
                        k = d;
53624
0
                    }
53625
0
                } else {
53626
0
                    d += len;
53627
0
                    if (d < 0)
53628
0
                        goto done;
53629
0
                    k = d;
53630
0
                }
53631
0
            }
53632
0
        }
53633
0
        stop = -1;
53634
0
        inc = -1;
53635
0
    } else {
53636
0
        k = 0;
53637
0
        if (argc > 1) {
53638
0
            if (JS_ToInt32Clamp(ctx, &k, argv[1], 0, len, len))
53639
0
                goto exception;
53640
0
        }
53641
0
        stop = len;
53642
0
        inc = 1;
53643
0
    }
53644
53645
0
    p = JS_VALUE_GET_OBJ(this_val);
53646
    /* if the array was detached, no need to go further (but no
53647
       exception is raised) */
53648
0
    if (typed_array_is_detached(ctx, p)) {
53649
        /* "includes" scans all the properties, so "undefined" can match */
53650
0
        if (special == special_includes && JS_IsUndefined(argv[0]) && len > 0)
53651
0
            res = 0;
53652
0
        goto done;
53653
0
    }
53654
53655
0
    is_bigint = 0;
53656
0
    is_int = 0; /* avoid warning */
53657
0
    v64 = 0; /* avoid warning */
53658
0
    tag = JS_VALUE_GET_NORM_TAG(argv[0]);
53659
0
    if (tag == JS_TAG_INT) {
53660
0
        is_int = 1;
53661
0
        v64 = JS_VALUE_GET_INT(argv[0]);
53662
0
        d = v64;
53663
0
    } else
53664
0
    if (tag == JS_TAG_FLOAT64) {
53665
0
        d = JS_VALUE_GET_FLOAT64(argv[0]);
53666
0
        if (d >= INT64_MIN && d < 0x1p63) {
53667
0
            v64 = d;
53668
0
            is_int = (v64 == d);
53669
0
        }
53670
0
    } else if (tag == JS_TAG_BIG_INT || tag == JS_TAG_SHORT_BIG_INT) {
53671
0
        JSBigIntBuf buf1;
53672
0
        JSBigInt *p1;
53673
0
        int sz = (64 / JS_LIMB_BITS);
53674
0
        if (tag == JS_TAG_SHORT_BIG_INT)
53675
0
            p1 = js_bigint_set_short(&buf1, argv[0]);
53676
0
        else
53677
0
            p1 = JS_VALUE_GET_PTR(argv[0]);
53678
        
53679
0
        if (p->class_id == JS_CLASS_BIG_INT64_ARRAY) {
53680
0
            if (p1->len > sz)
53681
0
                goto done; /* does not fit an int64 : cannot be found */
53682
0
        } else if (p->class_id == JS_CLASS_BIG_UINT64_ARRAY) {
53683
0
            if (js_bigint_sign(p1))
53684
0
                goto done; /* v < 0 */
53685
0
            if (p1->len <= sz) {
53686
                /* OK */
53687
0
            } else if (p1->len == sz + 1 && p1->tab[sz] == 0) {
53688
                /* 2^63 <= v <= 2^64-1 */
53689
0
            } else {
53690
0
                goto done;
53691
0
            }
53692
0
        } else {
53693
0
            goto done;
53694
0
        }
53695
0
        if (JS_ToBigInt64(ctx, &v64, argv[0]))
53696
0
            goto exception;
53697
0
        d = 0;
53698
0
        is_bigint = 1;
53699
0
    } else {
53700
0
        goto done;
53701
0
    }
53702
53703
0
    switch (p->class_id) {
53704
0
    case JS_CLASS_INT8_ARRAY:
53705
0
        if (is_int && (int8_t)v64 == v64)
53706
0
            goto scan8;
53707
0
        break;
53708
0
    case JS_CLASS_UINT8C_ARRAY:
53709
0
    case JS_CLASS_UINT8_ARRAY:
53710
0
        if (is_int && (uint8_t)v64 == v64) {
53711
0
            const uint8_t *pv, *pp;
53712
0
            uint16_t v;
53713
0
        scan8:
53714
0
            pv = p->u.array.u.uint8_ptr;
53715
0
            v = v64;
53716
0
            if (inc > 0) {
53717
0
                pp = memchr(pv + k, v, len - k);
53718
0
                if (pp)
53719
0
                    res = pp - pv;
53720
0
            } else {
53721
0
                for (; k != stop; k += inc) {
53722
0
                    if (pv[k] == v) {
53723
0
                        res = k;
53724
0
                        break;
53725
0
                    }
53726
0
                }
53727
0
            }
53728
0
        }
53729
0
        break;
53730
0
    case JS_CLASS_INT16_ARRAY:
53731
0
        if (is_int && (int16_t)v64 == v64)
53732
0
            goto scan16;
53733
0
        break;
53734
0
    case JS_CLASS_UINT16_ARRAY:
53735
0
        if (is_int && (uint16_t)v64 == v64) {
53736
0
            const uint16_t *pv;
53737
0
            uint16_t v;
53738
0
        scan16:
53739
0
            pv = p->u.array.u.uint16_ptr;
53740
0
            v = v64;
53741
0
            for (; k != stop; k += inc) {
53742
0
                if (pv[k] == v) {
53743
0
                    res = k;
53744
0
                    break;
53745
0
                }
53746
0
            }
53747
0
        }
53748
0
        break;
53749
0
    case JS_CLASS_INT32_ARRAY:
53750
0
        if (is_int && (int32_t)v64 == v64)
53751
0
            goto scan32;
53752
0
        break;
53753
0
    case JS_CLASS_UINT32_ARRAY:
53754
0
        if (is_int && (uint32_t)v64 == v64) {
53755
0
            const uint32_t *pv;
53756
0
            uint32_t v;
53757
0
        scan32:
53758
0
            pv = p->u.array.u.uint32_ptr;
53759
0
            v = v64;
53760
0
            for (; k != stop; k += inc) {
53761
0
                if (pv[k] == v) {
53762
0
                    res = k;
53763
0
                    break;
53764
0
                }
53765
0
            }
53766
0
        }
53767
0
        break;
53768
0
    case JS_CLASS_FLOAT16_ARRAY:
53769
0
        if (is_bigint)
53770
0
            break;
53771
0
        if (isnan(d)) {
53772
0
            const uint16_t *pv = p->u.array.u.fp16_ptr;
53773
            /* special case: indexOf returns -1, includes finds NaN */
53774
0
            if (special != special_includes)
53775
0
                goto done;
53776
0
            for (; k != stop; k += inc) {
53777
0
                if (isfp16nan(pv[k])) {
53778
0
                    res = k;
53779
0
                    break;
53780
0
                }
53781
0
            }
53782
0
        } else if (d == 0) {
53783
            // special case: includes also finds negative zero
53784
0
            const uint16_t *pv = p->u.array.u.fp16_ptr;
53785
0
            for (; k != stop; k += inc) {
53786
0
                if (isfp16zero(pv[k])) {
53787
0
                    res = k;
53788
0
                    break;
53789
0
                }
53790
0
            }
53791
0
        } else if (hf = tofp16(d), d == fromfp16(hf)) {
53792
0
            const uint16_t *pv = p->u.array.u.fp16_ptr;
53793
0
            for (; k != stop; k += inc) {
53794
0
                if (pv[k] == hf) {
53795
0
                    res = k;
53796
0
                    break;
53797
0
                }
53798
0
            }
53799
0
        }
53800
0
        break;
53801
0
    case JS_CLASS_FLOAT32_ARRAY:
53802
0
        if (is_bigint)
53803
0
            break;
53804
0
        if (isnan(d)) {
53805
0
            const float *pv = p->u.array.u.float_ptr;
53806
            /* special case: indexOf returns -1, includes finds NaN */
53807
0
            if (special != special_includes)
53808
0
                goto done;
53809
0
            for (; k != stop; k += inc) {
53810
0
                if (isnan(pv[k])) {
53811
0
                    res = k;
53812
0
                    break;
53813
0
                }
53814
0
            }
53815
0
        } else if ((f = (float)d) == d) {
53816
0
            const float *pv = p->u.array.u.float_ptr;
53817
0
            for (; k != stop; k += inc) {
53818
0
                if (pv[k] == f) {
53819
0
                    res = k;
53820
0
                    break;
53821
0
                }
53822
0
            }
53823
0
        }
53824
0
        break;
53825
0
    case JS_CLASS_FLOAT64_ARRAY:
53826
0
        if (is_bigint)
53827
0
            break;
53828
0
        if (isnan(d)) {
53829
0
            const double *pv = p->u.array.u.double_ptr;
53830
            /* special case: indexOf returns -1, includes finds NaN */
53831
0
            if (special != special_includes)
53832
0
                goto done;
53833
0
            for (; k != stop; k += inc) {
53834
0
                if (isnan(pv[k])) {
53835
0
                    res = k;
53836
0
                    break;
53837
0
                }
53838
0
            }
53839
0
        } else {
53840
0
            const double *pv = p->u.array.u.double_ptr;
53841
0
            for (; k != stop; k += inc) {
53842
0
                if (pv[k] == d) {
53843
0
                    res = k;
53844
0
                    break;
53845
0
                }
53846
0
            }
53847
0
        }
53848
0
        break;
53849
0
    case JS_CLASS_BIG_INT64_ARRAY:
53850
0
        if (is_bigint) {
53851
0
            goto scan64;
53852
0
        }
53853
0
        break;
53854
0
    case JS_CLASS_BIG_UINT64_ARRAY:
53855
0
        if (is_bigint) {
53856
0
            const uint64_t *pv;
53857
0
            uint64_t v;
53858
0
        scan64:
53859
0
            pv = p->u.array.u.uint64_ptr;
53860
0
            v = v64;
53861
0
            for (; k != stop; k += inc) {
53862
0
                if (pv[k] == v) {
53863
0
                    res = k;
53864
0
                    break;
53865
0
                }
53866
0
            }
53867
0
        }
53868
0
        break;
53869
0
    }
53870
53871
0
done:
53872
0
    if (special == special_includes)
53873
0
        return JS_NewBool(ctx, res >= 0);
53874
0
    else
53875
0
        return JS_NewInt32(ctx, res);
53876
53877
0
exception:
53878
0
    return JS_EXCEPTION;
53879
0
}
53880
53881
static JSValue js_typed_array_join(JSContext *ctx, JSValueConst this_val,
53882
                                   int argc, JSValueConst *argv, int toLocaleString)
53883
0
{
53884
0
    JSValue sep = JS_UNDEFINED, el;
53885
0
    StringBuffer b_s, *b = &b_s;
53886
0
    JSString *p = NULL;
53887
0
    int i, n;
53888
0
    int c;
53889
53890
0
    n = js_typed_array_get_length_internal(ctx, this_val);
53891
0
    if (n < 0)
53892
0
        goto exception;
53893
53894
0
    c = ',';    /* default separator */
53895
0
    if (!toLocaleString && argc > 0 && !JS_IsUndefined(argv[0])) {
53896
0
        sep = JS_ToString(ctx, argv[0]);
53897
0
        if (JS_IsException(sep))
53898
0
            goto exception;
53899
0
        p = JS_VALUE_GET_STRING(sep);
53900
0
        if (p->len == 1 && !p->is_wide_char)
53901
0
            c = p->u.str8[0];
53902
0
        else
53903
0
            c = -1;
53904
0
    }
53905
0
    string_buffer_init(ctx, b, 0);
53906
53907
    /* XXX: optimize with direct access */
53908
0
    for(i = 0; i < n; i++) {
53909
0
        if (i > 0) {
53910
0
            if (c >= 0) {
53911
0
                if (string_buffer_putc8(b, c))
53912
0
                    goto fail;
53913
0
            } else {
53914
0
                if (string_buffer_concat(b, p, 0, p->len))
53915
0
                    goto fail;
53916
0
            }
53917
0
        }
53918
0
        el = JS_GetPropertyUint32(ctx, this_val, i);
53919
        /* Can return undefined for example if the typed array is detached */
53920
0
        if (!JS_IsNull(el) && !JS_IsUndefined(el)) {
53921
0
            if (JS_IsException(el))
53922
0
                goto fail;
53923
0
            if (toLocaleString) {
53924
0
                el = JS_ToLocaleStringFree(ctx, el);
53925
0
            }
53926
0
            if (string_buffer_concat_value_free(b, el))
53927
0
                goto fail;
53928
0
        }
53929
0
    }
53930
0
    JS_FreeValue(ctx, sep);
53931
0
    return string_buffer_end(b);
53932
53933
0
fail:
53934
0
    string_buffer_free(b);
53935
0
    JS_FreeValue(ctx, sep);
53936
0
exception:
53937
0
    return JS_EXCEPTION;
53938
0
}
53939
53940
static JSValue js_typed_array_reverse(JSContext *ctx, JSValueConst this_val,
53941
                                      int argc, JSValueConst *argv)
53942
0
{
53943
0
    JSObject *p;
53944
0
    int len;
53945
53946
0
    len = js_typed_array_get_length_internal(ctx, this_val);
53947
0
    if (len < 0)
53948
0
        return JS_EXCEPTION;
53949
0
    if (len > 0) {
53950
0
        p = JS_VALUE_GET_OBJ(this_val);
53951
0
        switch (typed_array_size_log2(p->class_id)) {
53952
0
        case 0:
53953
0
            {
53954
0
                uint8_t *p1 = p->u.array.u.uint8_ptr;
53955
0
                uint8_t *p2 = p1 + len - 1;
53956
0
                while (p1 < p2) {
53957
0
                    uint8_t v = *p1;
53958
0
                    *p1++ = *p2;
53959
0
                    *p2-- = v;
53960
0
                }
53961
0
            }
53962
0
            break;
53963
0
        case 1:
53964
0
            {
53965
0
                uint16_t *p1 = p->u.array.u.uint16_ptr;
53966
0
                uint16_t *p2 = p1 + len - 1;
53967
0
                while (p1 < p2) {
53968
0
                    uint16_t v = *p1;
53969
0
                    *p1++ = *p2;
53970
0
                    *p2-- = v;
53971
0
                }
53972
0
            }
53973
0
            break;
53974
0
        case 2:
53975
0
            {
53976
0
                uint32_t *p1 = p->u.array.u.uint32_ptr;
53977
0
                uint32_t *p2 = p1 + len - 1;
53978
0
                while (p1 < p2) {
53979
0
                    uint32_t v = *p1;
53980
0
                    *p1++ = *p2;
53981
0
                    *p2-- = v;
53982
0
                }
53983
0
            }
53984
0
            break;
53985
0
        case 3:
53986
0
            {
53987
0
                uint64_t *p1 = p->u.array.u.uint64_ptr;
53988
0
                uint64_t *p2 = p1 + len - 1;
53989
0
                while (p1 < p2) {
53990
0
                    uint64_t v = *p1;
53991
0
                    *p1++ = *p2;
53992
0
                    *p2-- = v;
53993
0
                }
53994
0
            }
53995
0
            break;
53996
0
        default:
53997
0
            abort();
53998
0
        }
53999
0
    }
54000
0
    return JS_DupValue(ctx, this_val);
54001
0
}
54002
54003
static JSValue js_typed_array_toReversed(JSContext *ctx, JSValueConst this_val,
54004
                                         int argc, JSValueConst *argv)
54005
0
{
54006
0
    JSValue arr, ret;
54007
0
    JSObject *p;
54008
54009
0
    p = get_typed_array(ctx, this_val, /*is_dataview*/0);
54010
0
    if (!p)
54011
0
        return JS_EXCEPTION;
54012
0
    arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,
54013
0
                                        p->class_id);
54014
0
    if (JS_IsException(arr))
54015
0
        return JS_EXCEPTION;
54016
0
    ret = js_typed_array_reverse(ctx, arr, argc, argv);
54017
0
    JS_FreeValue(ctx, arr);
54018
0
    return ret;
54019
0
}
54020
54021
static void slice_memcpy(uint8_t *dst, const uint8_t *src, size_t len)
54022
0
{
54023
0
    if (dst + len <= src || dst >= src + len) {
54024
        /* no overlap: can use memcpy */
54025
0
        memcpy(dst, src, len);
54026
0
    } else {
54027
        /* otherwise the spec mandates byte copy */
54028
0
        while (len-- != 0)
54029
0
            *dst++ = *src++;
54030
0
    }
54031
0
}
54032
54033
static JSValue js_typed_array_slice(JSContext *ctx, JSValueConst this_val,
54034
                                    int argc, JSValueConst *argv)
54035
0
{
54036
0
    JSValueConst args[2];
54037
0
    JSValue arr, val;
54038
0
    JSObject *p, *p1;
54039
0
    int n, len, start, final, count, shift;
54040
54041
0
    arr = JS_UNDEFINED;
54042
0
    len = js_typed_array_get_length_internal(ctx, this_val);
54043
0
    if (len < 0)
54044
0
        goto exception;
54045
54046
0
    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))
54047
0
        goto exception;
54048
0
    final = len;
54049
0
    if (!JS_IsUndefined(argv[1])) {
54050
0
        if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len))
54051
0
            goto exception;
54052
0
    }
54053
0
    count = max_int(final - start, 0);
54054
54055
0
    p = get_typed_array(ctx, this_val, 0);
54056
0
    if (p == NULL)
54057
0
        goto exception;
54058
0
    shift = typed_array_size_log2(p->class_id);
54059
54060
0
    args[0] = this_val;
54061
0
    args[1] = JS_NewInt32(ctx, count);
54062
0
    arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);
54063
0
    if (JS_IsException(arr))
54064
0
        goto exception;
54065
54066
0
    if (count > 0) {
54067
0
        if (validate_typed_array(ctx, this_val)
54068
0
        ||  validate_typed_array(ctx, arr))
54069
0
            goto exception;
54070
54071
0
        p1 = get_typed_array(ctx, arr, 0);
54072
0
        if (p1 != NULL && p->class_id == p1->class_id &&
54073
0
            typed_array_get_length(ctx, p1) >= count &&
54074
0
            typed_array_get_length(ctx, p) >= start + count) {
54075
0
            slice_memcpy(p1->u.array.u.uint8_ptr,
54076
0
                         p->u.array.u.uint8_ptr + (start << shift),
54077
0
                         count << shift);
54078
0
        } else {
54079
0
            for (n = 0; n < count; n++) {
54080
0
                val = JS_GetPropertyValue(ctx, this_val, JS_NewInt32(ctx, start + n));
54081
0
                if (JS_IsException(val))
54082
0
                    goto exception;
54083
0
                if (JS_SetPropertyValue(ctx, arr, JS_NewInt32(ctx, n), val,
54084
0
                                        JS_PROP_THROW) < 0)
54085
0
                    goto exception;
54086
0
            }
54087
0
        }
54088
0
    }
54089
0
    return arr;
54090
54091
0
 exception:
54092
0
    JS_FreeValue(ctx, arr);
54093
0
    return JS_EXCEPTION;
54094
0
}
54095
54096
static JSValue js_typed_array_subarray(JSContext *ctx, JSValueConst this_val,
54097
                                       int argc, JSValueConst *argv)
54098
0
{
54099
0
    JSValueConst args[4];
54100
0
    JSValue arr, ta_buffer;
54101
0
    JSTypedArray *ta;
54102
0
    JSObject *p;
54103
0
    int len, start, final, count, shift, offset;
54104
54105
0
    p = get_typed_array(ctx, this_val, 0);
54106
0
    if (!p)
54107
0
        goto exception;
54108
0
    len = p->u.array.count;
54109
0
    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))
54110
0
        goto exception;
54111
54112
0
    final = len;
54113
0
    if (!JS_IsUndefined(argv[1])) {
54114
0
        if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len))
54115
0
            goto exception;
54116
0
    }
54117
0
    count = max_int(final - start, 0);
54118
0
    shift = typed_array_size_log2(p->class_id);
54119
0
    ta = p->u.typed_array;
54120
    /* Read byteOffset (ta->offset) even if detached */
54121
0
    offset = ta->offset + (start << shift);
54122
0
    ta_buffer = js_typed_array_get_buffer(ctx, this_val, 0);
54123
0
    if (JS_IsException(ta_buffer))
54124
0
        goto exception;
54125
0
    args[0] = this_val;
54126
0
    args[1] = ta_buffer;
54127
0
    args[2] = JS_NewInt32(ctx, offset);
54128
0
    args[3] = JS_NewInt32(ctx, count);
54129
0
    arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 4, args);
54130
0
    JS_FreeValue(ctx, ta_buffer);
54131
0
    return arr;
54132
54133
0
 exception:
54134
0
    return JS_EXCEPTION;
54135
0
}
54136
54137
/* TypedArray.prototype.sort */
54138
54139
static int js_cmp_doubles(double x, double y)
54140
0
{
54141
0
    if (isnan(x))    return isnan(y) ? 0 : +1;
54142
0
    if (isnan(y))    return -1;
54143
0
    if (x < y)       return -1;
54144
0
    if (x > y)       return 1;
54145
0
    if (x != 0)      return 0;
54146
0
    if (signbit(x))  return signbit(y) ? 0 : -1;
54147
0
    else             return signbit(y) ? 1 : 0;
54148
0
}
54149
54150
0
static int js_TA_cmp_int8(const void *a, const void *b, void *opaque) {
54151
0
    return *(const int8_t *)a - *(const int8_t *)b;
54152
0
}
54153
54154
0
static int js_TA_cmp_uint8(const void *a, const void *b, void *opaque) {
54155
0
    return *(const uint8_t *)a - *(const uint8_t *)b;
54156
0
}
54157
54158
0
static int js_TA_cmp_int16(const void *a, const void *b, void *opaque) {
54159
0
    return *(const int16_t *)a - *(const int16_t *)b;
54160
0
}
54161
54162
0
static int js_TA_cmp_uint16(const void *a, const void *b, void *opaque) {
54163
0
    return *(const uint16_t *)a - *(const uint16_t *)b;
54164
0
}
54165
54166
0
static int js_TA_cmp_int32(const void *a, const void *b, void *opaque) {
54167
0
    int32_t x = *(const int32_t *)a;
54168
0
    int32_t y = *(const int32_t *)b;
54169
0
    return (y < x) - (y > x);
54170
0
}
54171
54172
0
static int js_TA_cmp_uint32(const void *a, const void *b, void *opaque) {
54173
0
    uint32_t x = *(const uint32_t *)a;
54174
0
    uint32_t y = *(const uint32_t *)b;
54175
0
    return (y < x) - (y > x);
54176
0
}
54177
54178
0
static int js_TA_cmp_int64(const void *a, const void *b, void *opaque) {
54179
0
    int64_t x = *(const int64_t *)a;
54180
0
    int64_t y = *(const int64_t *)b;
54181
0
    return (y < x) - (y > x);
54182
0
}
54183
54184
0
static int js_TA_cmp_uint64(const void *a, const void *b, void *opaque) {
54185
0
    uint64_t x = *(const uint64_t *)a;
54186
0
    uint64_t y = *(const uint64_t *)b;
54187
0
    return (y < x) - (y > x);
54188
0
}
54189
54190
0
static int js_TA_cmp_float16(const void *a, const void *b, void *opaque) {
54191
0
    return js_cmp_doubles(fromfp16(*(const uint16_t *)a),
54192
0
                          fromfp16(*(const uint16_t *)b));
54193
0
}
54194
54195
0
static int js_TA_cmp_float32(const void *a, const void *b, void *opaque) {
54196
0
    return js_cmp_doubles(*(const float *)a, *(const float *)b);
54197
0
}
54198
54199
0
static int js_TA_cmp_float64(const void *a, const void *b, void *opaque) {
54200
0
    return js_cmp_doubles(*(const double *)a, *(const double *)b);
54201
0
}
54202
54203
0
static JSValue js_TA_get_int8(JSContext *ctx, const void *a) {
54204
0
    return JS_NewInt32(ctx, *(const int8_t *)a);
54205
0
}
54206
54207
0
static JSValue js_TA_get_uint8(JSContext *ctx, const void *a) {
54208
0
    return JS_NewInt32(ctx, *(const uint8_t *)a);
54209
0
}
54210
54211
0
static JSValue js_TA_get_int16(JSContext *ctx, const void *a) {
54212
0
    return JS_NewInt32(ctx, *(const int16_t *)a);
54213
0
}
54214
54215
0
static JSValue js_TA_get_uint16(JSContext *ctx, const void *a) {
54216
0
    return JS_NewInt32(ctx, *(const uint16_t *)a);
54217
0
}
54218
54219
0
static JSValue js_TA_get_int32(JSContext *ctx, const void *a) {
54220
0
    return JS_NewInt32(ctx, *(const int32_t *)a);
54221
0
}
54222
54223
0
static JSValue js_TA_get_uint32(JSContext *ctx, const void *a) {
54224
0
    return JS_NewUint32(ctx, *(const uint32_t *)a);
54225
0
}
54226
54227
0
static JSValue js_TA_get_int64(JSContext *ctx, const void *a) {
54228
0
    return JS_NewBigInt64(ctx, *(int64_t *)a);
54229
0
}
54230
54231
0
static JSValue js_TA_get_uint64(JSContext *ctx, const void *a) {
54232
0
    return JS_NewBigUint64(ctx, *(uint64_t *)a);
54233
0
}
54234
54235
0
static JSValue js_TA_get_float16(JSContext *ctx, const void *a) {
54236
0
    return __JS_NewFloat64(ctx, fromfp16(*(const uint16_t *)a));
54237
0
}
54238
54239
0
static JSValue js_TA_get_float32(JSContext *ctx, const void *a) {
54240
0
    return __JS_NewFloat64(ctx, *(const float *)a);
54241
0
}
54242
54243
0
static JSValue js_TA_get_float64(JSContext *ctx, const void *a) {
54244
0
    return __JS_NewFloat64(ctx, *(const double *)a);
54245
0
}
54246
54247
struct TA_sort_context {
54248
    JSContext *ctx;
54249
    int exception; /* 1 = exception, 2 = detached typed array */
54250
    JSValueConst arr;
54251
    JSValueConst cmp;
54252
    JSValue (*getfun)(JSContext *ctx, const void *a);
54253
    uint8_t *array_ptr; /* cannot change unless the array is detached */
54254
    int elt_size;
54255
};
54256
54257
0
static int js_TA_cmp_generic(const void *a, const void *b, void *opaque) {
54258
0
    struct TA_sort_context *psc = opaque;
54259
0
    JSContext *ctx = psc->ctx;
54260
0
    uint32_t a_idx, b_idx;
54261
0
    JSValueConst argv[2];
54262
0
    JSValue res;
54263
0
    int cmp;
54264
54265
0
    cmp = 0;
54266
0
    if (!psc->exception) {
54267
        /* Note: the typed array can be detached without causing an
54268
           error */
54269
0
        a_idx = *(uint32_t *)a;
54270
0
        b_idx = *(uint32_t *)b;
54271
0
        argv[0] = psc->getfun(ctx, psc->array_ptr +
54272
0
                              a_idx * (size_t)psc->elt_size);
54273
0
        argv[1] = psc->getfun(ctx, psc->array_ptr +
54274
0
                              b_idx * (size_t)(psc->elt_size));
54275
0
        res = JS_Call(ctx, psc->cmp, JS_UNDEFINED, 2, argv);
54276
0
        if (JS_IsException(res)) {
54277
0
            psc->exception = 1;
54278
0
            goto done;
54279
0
        }
54280
0
        if (JS_VALUE_GET_TAG(res) == JS_TAG_INT) {
54281
0
            int val = JS_VALUE_GET_INT(res);
54282
0
            cmp = (val > 0) - (val < 0);
54283
0
        } else {
54284
0
            double val;
54285
0
            if (JS_ToFloat64Free(ctx, &val, res) < 0) {
54286
0
                psc->exception = 1;
54287
0
                goto done;
54288
0
            } else {
54289
0
                cmp = (val > 0) - (val < 0);
54290
0
            }
54291
0
        }
54292
0
        if (cmp == 0) {
54293
            /* make sort stable: compare array offsets */
54294
0
            cmp = (a_idx > b_idx) - (a_idx < b_idx);
54295
0
        }
54296
0
        if (unlikely(typed_array_is_detached(ctx,
54297
0
                                             JS_VALUE_GET_PTR(psc->arr)))) {
54298
0
            psc->exception = 2;
54299
0
        }
54300
0
    done:
54301
0
        JS_FreeValue(ctx, (JSValue)argv[0]);
54302
0
        JS_FreeValue(ctx, (JSValue)argv[1]);
54303
0
    }
54304
0
    return cmp;
54305
0
}
54306
54307
static JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val,
54308
                                   int argc, JSValueConst *argv)
54309
0
{
54310
0
    JSObject *p;
54311
0
    int len;
54312
0
    size_t elt_size;
54313
0
    struct TA_sort_context tsc;
54314
0
    void *array_ptr;
54315
0
    int (*cmpfun)(const void *a, const void *b, void *opaque);
54316
54317
0
    tsc.ctx = ctx;
54318
0
    tsc.exception = 0;
54319
0
    tsc.arr = this_val;
54320
0
    tsc.cmp = argv[0];
54321
54322
0
    if (!JS_IsUndefined(tsc.cmp) && check_function(ctx, tsc.cmp))
54323
0
        return JS_EXCEPTION;
54324
0
    len = js_typed_array_get_length_internal(ctx, this_val);
54325
0
    if (len < 0)
54326
0
        return JS_EXCEPTION;
54327
54328
0
    if (len > 1) {
54329
0
        p = JS_VALUE_GET_OBJ(this_val);
54330
0
        switch (p->class_id) {
54331
0
        case JS_CLASS_INT8_ARRAY:
54332
0
            tsc.getfun = js_TA_get_int8;
54333
0
            cmpfun = js_TA_cmp_int8;
54334
0
            break;
54335
0
        case JS_CLASS_UINT8C_ARRAY:
54336
0
        case JS_CLASS_UINT8_ARRAY:
54337
0
            tsc.getfun = js_TA_get_uint8;
54338
0
            cmpfun = js_TA_cmp_uint8;
54339
0
            break;
54340
0
        case JS_CLASS_INT16_ARRAY:
54341
0
            tsc.getfun = js_TA_get_int16;
54342
0
            cmpfun = js_TA_cmp_int16;
54343
0
            break;
54344
0
        case JS_CLASS_UINT16_ARRAY:
54345
0
            tsc.getfun = js_TA_get_uint16;
54346
0
            cmpfun = js_TA_cmp_uint16;
54347
0
            break;
54348
0
        case JS_CLASS_INT32_ARRAY:
54349
0
            tsc.getfun = js_TA_get_int32;
54350
0
            cmpfun = js_TA_cmp_int32;
54351
0
            break;
54352
0
        case JS_CLASS_UINT32_ARRAY:
54353
0
            tsc.getfun = js_TA_get_uint32;
54354
0
            cmpfun = js_TA_cmp_uint32;
54355
0
            break;
54356
0
        case JS_CLASS_BIG_INT64_ARRAY:
54357
0
            tsc.getfun = js_TA_get_int64;
54358
0
            cmpfun = js_TA_cmp_int64;
54359
0
            break;
54360
0
        case JS_CLASS_BIG_UINT64_ARRAY:
54361
0
            tsc.getfun = js_TA_get_uint64;
54362
0
            cmpfun = js_TA_cmp_uint64;
54363
0
            break;
54364
0
        case JS_CLASS_FLOAT16_ARRAY:
54365
0
            tsc.getfun = js_TA_get_float16;
54366
0
            cmpfun = js_TA_cmp_float16;
54367
0
            break;
54368
0
        case JS_CLASS_FLOAT32_ARRAY:
54369
0
            tsc.getfun = js_TA_get_float32;
54370
0
            cmpfun = js_TA_cmp_float32;
54371
0
            break;
54372
0
        case JS_CLASS_FLOAT64_ARRAY:
54373
0
            tsc.getfun = js_TA_get_float64;
54374
0
            cmpfun = js_TA_cmp_float64;
54375
0
            break;
54376
0
        default:
54377
0
            abort();
54378
0
        }
54379
0
        array_ptr = p->u.array.u.ptr;
54380
0
        elt_size = 1 << typed_array_size_log2(p->class_id);
54381
0
        if (!JS_IsUndefined(tsc.cmp)) {
54382
0
            uint32_t *array_idx;
54383
0
            void *array_tmp;
54384
0
            size_t i, j;
54385
54386
            /* XXX: a stable sort would use less memory */
54387
0
            array_idx = js_malloc(ctx, len * sizeof(array_idx[0]));
54388
0
            if (!array_idx)
54389
0
                return JS_EXCEPTION;
54390
0
            for(i = 0; i < len; i++)
54391
0
                array_idx[i] = i;
54392
0
            tsc.array_ptr = array_ptr;
54393
0
            tsc.elt_size = elt_size;
54394
0
            rqsort(array_idx, len, sizeof(array_idx[0]),
54395
0
                   js_TA_cmp_generic, &tsc);
54396
0
            if (tsc.exception) {
54397
0
                if (tsc.exception == 1)
54398
0
                    goto fail;
54399
                /* detached typed array during the sort: no error */
54400
0
            } else {
54401
0
                array_tmp = js_malloc(ctx, len * elt_size);
54402
0
                if (!array_tmp) {
54403
0
                fail:
54404
0
                    js_free(ctx, array_idx);
54405
0
                    return JS_EXCEPTION;
54406
0
                }
54407
0
                memcpy(array_tmp, array_ptr, len * elt_size);
54408
0
                switch(elt_size) {
54409
0
                case 1:
54410
0
                    for(i = 0; i < len; i++) {
54411
0
                        j = array_idx[i];
54412
0
                        ((uint8_t *)array_ptr)[i] = ((uint8_t *)array_tmp)[j];
54413
0
                    }
54414
0
                    break;
54415
0
                case 2:
54416
0
                    for(i = 0; i < len; i++) {
54417
0
                        j = array_idx[i];
54418
0
                        ((uint16_t *)array_ptr)[i] = ((uint16_t *)array_tmp)[j];
54419
0
                    }
54420
0
                    break;
54421
0
                case 4:
54422
0
                    for(i = 0; i < len; i++) {
54423
0
                        j = array_idx[i];
54424
0
                        ((uint32_t *)array_ptr)[i] = ((uint32_t *)array_tmp)[j];
54425
0
                    }
54426
0
                    break;
54427
0
                case 8:
54428
0
                    for(i = 0; i < len; i++) {
54429
0
                        j = array_idx[i];
54430
0
                        ((uint64_t *)array_ptr)[i] = ((uint64_t *)array_tmp)[j];
54431
0
                    }
54432
0
                    break;
54433
0
                default:
54434
0
                    abort();
54435
0
                }
54436
0
                js_free(ctx, array_tmp);
54437
0
            }
54438
0
            js_free(ctx, array_idx);
54439
0
        } else {
54440
0
            rqsort(array_ptr, len, elt_size, cmpfun, &tsc);
54441
0
            if (tsc.exception)
54442
0
                return JS_EXCEPTION;
54443
0
        }
54444
0
    }
54445
0
    return JS_DupValue(ctx, this_val);
54446
0
}
54447
54448
static JSValue js_typed_array_toSorted(JSContext *ctx, JSValueConst this_val,
54449
                                       int argc, JSValueConst *argv)
54450
0
{
54451
0
    JSValue arr, ret;
54452
0
    JSObject *p;
54453
54454
0
    p = get_typed_array(ctx, this_val, /*is_dataview*/0);
54455
0
    if (!p)
54456
0
        return JS_EXCEPTION;
54457
0
    arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,
54458
0
                                        p->class_id);
54459
0
    if (JS_IsException(arr))
54460
0
        return JS_EXCEPTION;
54461
0
    ret = js_typed_array_sort(ctx, arr, argc, argv);
54462
0
    JS_FreeValue(ctx, arr);
54463
0
    return ret;
54464
0
}
54465
54466
static const JSCFunctionListEntry js_typed_array_base_funcs[] = {
54467
    JS_CFUNC_DEF("from", 1, js_typed_array_from ),
54468
    JS_CFUNC_DEF("of", 0, js_typed_array_of ),
54469
    JS_CGETSET_DEF("[Symbol.species]", js_get_this, NULL ),
54470
    //JS_CFUNC_DEF("__getLength", 2, js_typed_array___getLength ),
54471
    //JS_CFUNC_DEF("__create", 2, js_typed_array___create ),
54472
    //JS_CFUNC_DEF("__speciesCreate", 2, js_typed_array___speciesCreate ),
54473
};
54474
54475
static const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = {
54476
    JS_CGETSET_DEF("length", js_typed_array_get_length, NULL ),
54477
    JS_CFUNC_DEF("at", 1, js_typed_array_at ),
54478
    JS_CFUNC_DEF("with", 2, js_typed_array_with ),
54479
    JS_CGETSET_MAGIC_DEF("buffer", js_typed_array_get_buffer, NULL, 0 ),
54480
    JS_CGETSET_MAGIC_DEF("byteLength", js_typed_array_get_byteLength, NULL, 0 ),
54481
    JS_CGETSET_MAGIC_DEF("byteOffset", js_typed_array_get_byteOffset, NULL, 0 ),
54482
    JS_CFUNC_DEF("set", 1, js_typed_array_set ),
54483
    JS_CFUNC_MAGIC_DEF("values", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_VALUE ),
54484
    JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
54485
    JS_CFUNC_MAGIC_DEF("keys", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_KEY ),
54486
    JS_CFUNC_MAGIC_DEF("entries", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE ),
54487
    JS_CGETSET_DEF("[Symbol.toStringTag]", js_typed_array_get_toStringTag, NULL ),
54488
    JS_CFUNC_DEF("copyWithin", 2, js_typed_array_copyWithin ),
54489
    JS_CFUNC_MAGIC_DEF("every", 1, js_array_every, special_every | special_TA ),
54490
    JS_CFUNC_MAGIC_DEF("some", 1, js_array_every, special_some | special_TA ),
54491
    JS_CFUNC_MAGIC_DEF("forEach", 1, js_array_every, special_forEach | special_TA ),
54492
    JS_CFUNC_MAGIC_DEF("map", 1, js_array_every, special_map | special_TA ),
54493
    JS_CFUNC_MAGIC_DEF("filter", 1, js_array_every, special_filter | special_TA ),
54494
    JS_CFUNC_MAGIC_DEF("reduce", 1, js_array_reduce, special_reduce | special_TA ),
54495
    JS_CFUNC_MAGIC_DEF("reduceRight", 1, js_array_reduce, special_reduceRight | special_TA ),
54496
    JS_CFUNC_DEF("fill", 1, js_typed_array_fill ),
54497
    JS_CFUNC_MAGIC_DEF("find", 1, js_typed_array_find, ArrayFind ),
54498
    JS_CFUNC_MAGIC_DEF("findIndex", 1, js_typed_array_find, ArrayFindIndex ),
54499
    JS_CFUNC_MAGIC_DEF("findLast", 1, js_typed_array_find, ArrayFindLast ),
54500
    JS_CFUNC_MAGIC_DEF("findLastIndex", 1, js_typed_array_find, ArrayFindLastIndex ),
54501
    JS_CFUNC_DEF("reverse", 0, js_typed_array_reverse ),
54502
    JS_CFUNC_DEF("toReversed", 0, js_typed_array_toReversed ),
54503
    JS_CFUNC_DEF("slice", 2, js_typed_array_slice ),
54504
    JS_CFUNC_DEF("subarray", 2, js_typed_array_subarray ),
54505
    JS_CFUNC_DEF("sort", 1, js_typed_array_sort ),
54506
    JS_CFUNC_DEF("toSorted", 1, js_typed_array_toSorted ),
54507
    JS_CFUNC_MAGIC_DEF("join", 1, js_typed_array_join, 0 ),
54508
    JS_CFUNC_MAGIC_DEF("toLocaleString", 0, js_typed_array_join, 1 ),
54509
    JS_CFUNC_MAGIC_DEF("indexOf", 1, js_typed_array_indexOf, special_indexOf ),
54510
    JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_typed_array_indexOf, special_lastIndexOf ),
54511
    JS_CFUNC_MAGIC_DEF("includes", 1, js_typed_array_indexOf, special_includes ),
54512
    //JS_ALIAS_BASE_DEF("toString", "toString", 2 /* Array.prototype. */), @@@
54513
};
54514
54515
static JSValue js_typed_array_base_constructor(JSContext *ctx,
54516
                                               JSValueConst this_val,
54517
                                               int argc, JSValueConst *argv)
54518
0
{
54519
0
    return JS_ThrowTypeError(ctx, "cannot be called");
54520
0
}
54521
54522
/* 'obj' must be an allocated typed array object */
54523
static int typed_array_init(JSContext *ctx, JSValueConst obj,
54524
                            JSValue buffer, uint64_t offset, uint64_t len)
54525
0
{
54526
0
    JSTypedArray *ta;
54527
0
    JSObject *p, *pbuffer;
54528
0
    JSArrayBuffer *abuf;
54529
0
    int size_log2;
54530
54531
0
    p = JS_VALUE_GET_OBJ(obj);
54532
0
    size_log2 = typed_array_size_log2(p->class_id);
54533
0
    ta = js_malloc(ctx, sizeof(*ta));
54534
0
    if (!ta) {
54535
0
        JS_FreeValue(ctx, buffer);
54536
0
        return -1;
54537
0
    }
54538
0
    pbuffer = JS_VALUE_GET_OBJ(buffer);
54539
0
    abuf = pbuffer->u.array_buffer;
54540
0
    ta->obj = p;
54541
0
    ta->buffer = pbuffer;
54542
0
    ta->offset = offset;
54543
0
    ta->length = len << size_log2;
54544
0
    list_add_tail(&ta->link, &abuf->array_list);
54545
0
    p->u.typed_array = ta;
54546
0
    p->u.array.count = len;
54547
0
    p->u.array.u.ptr = abuf->data + offset;
54548
0
    return 0;
54549
0
}
54550
54551
54552
static JSValue js_array_from_iterator(JSContext *ctx, uint32_t *plen,
54553
                                      JSValueConst obj, JSValueConst method)
54554
0
{
54555
0
    JSValue arr, iter, next_method = JS_UNDEFINED, val;
54556
0
    BOOL done;
54557
0
    uint32_t k;
54558
54559
0
    *plen = 0;
54560
0
    arr = JS_NewArray(ctx);
54561
0
    if (JS_IsException(arr))
54562
0
        return arr;
54563
0
    iter = JS_GetIterator2(ctx, obj, method);
54564
0
    if (JS_IsException(iter))
54565
0
        goto fail;
54566
0
    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);
54567
0
    if (JS_IsException(next_method))
54568
0
        goto fail;
54569
0
    k = 0;
54570
0
    for(;;) {
54571
0
        val = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);
54572
0
        if (JS_IsException(val))
54573
0
            goto fail;
54574
0
        if (done)
54575
0
            break;
54576
0
        if (JS_CreateDataPropertyUint32(ctx, arr, k, val, JS_PROP_THROW) < 0)
54577
0
            goto fail;
54578
0
        k++;
54579
0
    }
54580
0
    JS_FreeValue(ctx, next_method);
54581
0
    JS_FreeValue(ctx, iter);
54582
0
    *plen = k;
54583
0
    return arr;
54584
0
 fail:
54585
0
    JS_FreeValue(ctx, next_method);
54586
0
    JS_FreeValue(ctx, iter);
54587
0
    JS_FreeValue(ctx, arr);
54588
0
    return JS_EXCEPTION;
54589
0
}
54590
54591
static JSValue js_typed_array_constructor_obj(JSContext *ctx,
54592
                                              JSValueConst new_target,
54593
                                              JSValueConst obj,
54594
                                              int classid)
54595
0
{
54596
0
    JSValue iter, ret, arr = JS_UNDEFINED, val, buffer;
54597
0
    uint32_t i;
54598
0
    int size_log2;
54599
0
    int64_t len;
54600
54601
0
    size_log2 = typed_array_size_log2(classid);
54602
0
    ret = js_create_from_ctor(ctx, new_target, classid);
54603
0
    if (JS_IsException(ret))
54604
0
        return JS_EXCEPTION;
54605
54606
0
    iter = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
54607
0
    if (JS_IsException(iter))
54608
0
        goto fail;
54609
0
    if (!JS_IsUndefined(iter) && !JS_IsNull(iter)) {
54610
0
        uint32_t len1;
54611
0
        arr = js_array_from_iterator(ctx, &len1, obj, iter);
54612
0
        JS_FreeValue(ctx, iter);
54613
0
        if (JS_IsException(arr))
54614
0
            goto fail;
54615
0
        len = len1;
54616
0
    } else {
54617
0
        if (js_get_length64(ctx, &len, obj))
54618
0
            goto fail;
54619
0
        arr = JS_DupValue(ctx, obj);
54620
0
    }
54621
54622
0
    buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,
54623
0
                                          len << size_log2);
54624
0
    if (JS_IsException(buffer))
54625
0
        goto fail;
54626
0
    if (typed_array_init(ctx, ret, buffer, 0, len))
54627
0
        goto fail;
54628
54629
0
    for(i = 0; i < len; i++) {
54630
0
        val = JS_GetPropertyUint32(ctx, arr, i);
54631
0
        if (JS_IsException(val))
54632
0
            goto fail;
54633
0
        if (JS_SetPropertyUint32(ctx, ret, i, val) < 0)
54634
0
            goto fail;
54635
0
    }
54636
0
    JS_FreeValue(ctx, arr);
54637
0
    return ret;
54638
0
 fail:
54639
0
    JS_FreeValue(ctx, arr);
54640
0
    JS_FreeValue(ctx, ret);
54641
0
    return JS_EXCEPTION;
54642
0
}
54643
54644
static JSValue js_typed_array_constructor_ta(JSContext *ctx,
54645
                                             JSValueConst new_target,
54646
                                             JSValueConst src_obj,
54647
                                             int classid)
54648
0
{
54649
0
    JSObject *p, *src_buffer;
54650
0
    JSTypedArray *ta;
54651
0
    JSValue obj, buffer;
54652
0
    uint32_t len, i;
54653
0
    int size_log2;
54654
0
    JSArrayBuffer *src_abuf, *abuf;
54655
54656
0
    obj = js_create_from_ctor(ctx, new_target, classid);
54657
0
    if (JS_IsException(obj))
54658
0
        return obj;
54659
0
    p = JS_VALUE_GET_OBJ(src_obj);
54660
0
    if (typed_array_is_detached(ctx, p)) {
54661
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
54662
0
        goto fail;
54663
0
    }
54664
0
    ta = p->u.typed_array;
54665
0
    len = p->u.array.count;
54666
0
    src_buffer = ta->buffer;
54667
0
    src_abuf = src_buffer->u.array_buffer;
54668
0
    size_log2 = typed_array_size_log2(classid);
54669
0
    buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,
54670
0
                                          (uint64_t)len << size_log2);
54671
0
    if (JS_IsException(buffer))
54672
0
        goto fail;
54673
    /* necessary because it could have been detached */
54674
0
    if (typed_array_is_detached(ctx, p)) {
54675
0
        JS_FreeValue(ctx, buffer);
54676
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
54677
0
        goto fail;
54678
0
    }
54679
0
    abuf = JS_GetOpaque(buffer, JS_CLASS_ARRAY_BUFFER);
54680
0
    if (typed_array_init(ctx, obj, buffer, 0, len))
54681
0
        goto fail;
54682
0
    if (p->class_id == classid) {
54683
        /* same type: copy the content */
54684
0
        memcpy(abuf->data, src_abuf->data + ta->offset, abuf->byte_length);
54685
0
    } else {
54686
0
        for(i = 0; i < len; i++) {
54687
0
            JSValue val;
54688
0
            val = JS_GetPropertyUint32(ctx, src_obj, i);
54689
0
            if (JS_IsException(val))
54690
0
                goto fail;
54691
0
            if (JS_SetPropertyUint32(ctx, obj, i, val) < 0)
54692
0
                goto fail;
54693
0
        }
54694
0
    }
54695
0
    return obj;
54696
0
 fail:
54697
0
    JS_FreeValue(ctx, obj);
54698
0
    return JS_EXCEPTION;
54699
0
}
54700
54701
static JSValue js_typed_array_constructor(JSContext *ctx,
54702
                                          JSValueConst new_target,
54703
                                          int argc, JSValueConst *argv,
54704
                                          int classid)
54705
0
{
54706
0
    JSValue buffer, obj;
54707
0
    JSArrayBuffer *abuf;
54708
0
    int size_log2;
54709
0
    uint64_t len, offset;
54710
54711
0
    size_log2 = typed_array_size_log2(classid);
54712
0
    if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT) {
54713
0
        if (JS_ToIndex(ctx, &len, argv[0]))
54714
0
            return JS_EXCEPTION;
54715
0
        buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,
54716
0
                                              len << size_log2);
54717
0
        if (JS_IsException(buffer))
54718
0
            return JS_EXCEPTION;
54719
0
        offset = 0;
54720
0
    } else {
54721
0
        JSObject *p = JS_VALUE_GET_OBJ(argv[0]);
54722
0
        if (p->class_id == JS_CLASS_ARRAY_BUFFER ||
54723
0
            p->class_id == JS_CLASS_SHARED_ARRAY_BUFFER) {
54724
0
            abuf = p->u.array_buffer;
54725
0
            if (JS_ToIndex(ctx, &offset, argv[1]))
54726
0
                return JS_EXCEPTION;
54727
0
            if (abuf->detached)
54728
0
                return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
54729
0
            if ((offset & ((1 << size_log2) - 1)) != 0 ||
54730
0
                offset > abuf->byte_length)
54731
0
                return JS_ThrowRangeError(ctx, "invalid offset");
54732
0
            if (JS_IsUndefined(argv[2])) {
54733
0
                if ((abuf->byte_length & ((1 << size_log2) - 1)) != 0)
54734
0
                    goto invalid_length;
54735
0
                len = (abuf->byte_length - offset) >> size_log2;
54736
0
            } else {
54737
0
                if (JS_ToIndex(ctx, &len, argv[2]))
54738
0
                    return JS_EXCEPTION;
54739
0
                if (abuf->detached)
54740
0
                    return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
54741
0
                if ((offset + (len << size_log2)) > abuf->byte_length) {
54742
0
                invalid_length:
54743
0
                    return JS_ThrowRangeError(ctx, "invalid length");
54744
0
                }
54745
0
            }
54746
0
            buffer = JS_DupValue(ctx, argv[0]);
54747
0
        } else {
54748
0
            if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
54749
0
                p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
54750
0
                return js_typed_array_constructor_ta(ctx, new_target, argv[0], classid);
54751
0
            } else {
54752
0
                return js_typed_array_constructor_obj(ctx, new_target, argv[0], classid);
54753
0
            }
54754
0
        }
54755
0
    }
54756
54757
0
    obj = js_create_from_ctor(ctx, new_target, classid);
54758
0
    if (JS_IsException(obj)) {
54759
0
        JS_FreeValue(ctx, buffer);
54760
0
        return JS_EXCEPTION;
54761
0
    }
54762
0
    if (typed_array_init(ctx, obj, buffer, offset, len)) {
54763
0
        JS_FreeValue(ctx, obj);
54764
0
        return JS_EXCEPTION;
54765
0
    }
54766
0
    return obj;
54767
0
}
54768
54769
static void js_typed_array_finalizer(JSRuntime *rt, JSValue val)
54770
0
{
54771
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
54772
0
    JSTypedArray *ta = p->u.typed_array;
54773
0
    if (ta) {
54774
        /* during the GC the finalizers are called in an arbitrary
54775
           order so the ArrayBuffer finalizer may have been called */
54776
0
        if (ta->link.next) {
54777
0
            list_del(&ta->link);
54778
0
        }
54779
0
        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));
54780
0
        js_free_rt(rt, ta);
54781
0
    }
54782
0
}
54783
54784
static void js_typed_array_mark(JSRuntime *rt, JSValueConst val,
54785
                                JS_MarkFunc *mark_func)
54786
0
{
54787
0
    JSObject *p = JS_VALUE_GET_OBJ(val);
54788
0
    JSTypedArray *ta = p->u.typed_array;
54789
0
    if (ta) {
54790
0
        JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer), mark_func);
54791
0
    }
54792
0
}
54793
54794
static JSValue js_dataview_constructor(JSContext *ctx,
54795
                                       JSValueConst new_target,
54796
                                       int argc, JSValueConst *argv)
54797
0
{
54798
0
    JSArrayBuffer *abuf;
54799
0
    uint64_t offset;
54800
0
    uint32_t len;
54801
0
    JSValueConst buffer;
54802
0
    JSValue obj;
54803
0
    JSTypedArray *ta;
54804
0
    JSObject *p;
54805
54806
0
    buffer = argv[0];
54807
0
    abuf = js_get_array_buffer(ctx, buffer);
54808
0
    if (!abuf)
54809
0
        return JS_EXCEPTION;
54810
0
    offset = 0;
54811
0
    if (argc > 1) {
54812
0
        if (JS_ToIndex(ctx, &offset, argv[1]))
54813
0
            return JS_EXCEPTION;
54814
0
    }
54815
0
    if (abuf->detached)
54816
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
54817
0
    if (offset > abuf->byte_length)
54818
0
        return JS_ThrowRangeError(ctx, "invalid byteOffset");
54819
0
    len = abuf->byte_length - offset;
54820
0
    if (argc > 2 && !JS_IsUndefined(argv[2])) {
54821
0
        uint64_t l;
54822
0
        if (JS_ToIndex(ctx, &l, argv[2]))
54823
0
            return JS_EXCEPTION;
54824
0
        if (l > len)
54825
0
            return JS_ThrowRangeError(ctx, "invalid byteLength");
54826
0
        len = l;
54827
0
    }
54828
54829
0
    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_DATAVIEW);
54830
0
    if (JS_IsException(obj))
54831
0
        return JS_EXCEPTION;
54832
0
    if (abuf->detached) {
54833
        /* could have been detached in js_create_from_ctor() */
54834
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
54835
0
        goto fail;
54836
0
    }
54837
0
    ta = js_malloc(ctx, sizeof(*ta));
54838
0
    if (!ta) {
54839
0
    fail:
54840
0
        JS_FreeValue(ctx, obj);
54841
0
        return JS_EXCEPTION;
54842
0
    }
54843
0
    p = JS_VALUE_GET_OBJ(obj);
54844
0
    ta->obj = p;
54845
0
    ta->buffer = JS_VALUE_GET_OBJ(JS_DupValue(ctx, buffer));
54846
0
    ta->offset = offset;
54847
0
    ta->length = len;
54848
0
    list_add_tail(&ta->link, &abuf->array_list);
54849
0
    p->u.typed_array = ta;
54850
0
    return obj;
54851
0
}
54852
54853
static JSValue js_dataview_getValue(JSContext *ctx,
54854
                                    JSValueConst this_obj,
54855
                                    int argc, JSValueConst *argv, int class_id)
54856
0
{
54857
0
    JSTypedArray *ta;
54858
0
    JSArrayBuffer *abuf;
54859
0
    BOOL littleEndian, is_swap;
54860
0
    int size;
54861
0
    uint8_t *ptr;
54862
0
    uint32_t v;
54863
0
    uint64_t pos;
54864
54865
0
    ta = JS_GetOpaque2(ctx, this_obj, JS_CLASS_DATAVIEW);
54866
0
    if (!ta)
54867
0
        return JS_EXCEPTION;
54868
0
    size = 1 << typed_array_size_log2(class_id);
54869
0
    if (JS_ToIndex(ctx, &pos, argv[0]))
54870
0
        return JS_EXCEPTION;
54871
0
    littleEndian = argc > 1 && JS_ToBool(ctx, argv[1]);
54872
0
    is_swap = littleEndian ^ !is_be();
54873
0
    abuf = ta->buffer->u.array_buffer;
54874
0
    if (abuf->detached)
54875
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
54876
0
    if ((pos + size) > ta->length)
54877
0
        return JS_ThrowRangeError(ctx, "out of bound");
54878
0
    ptr = abuf->data + ta->offset + pos;
54879
54880
0
    switch(class_id) {
54881
0
    case JS_CLASS_INT8_ARRAY:
54882
0
        return JS_NewInt32(ctx, *(int8_t *)ptr);
54883
0
    case JS_CLASS_UINT8_ARRAY:
54884
0
        return JS_NewInt32(ctx, *(uint8_t *)ptr);
54885
0
    case JS_CLASS_INT16_ARRAY:
54886
0
        v = get_u16(ptr);
54887
0
        if (is_swap)
54888
0
            v = bswap16(v);
54889
0
        return JS_NewInt32(ctx, (int16_t)v);
54890
0
    case JS_CLASS_UINT16_ARRAY:
54891
0
        v = get_u16(ptr);
54892
0
        if (is_swap)
54893
0
            v = bswap16(v);
54894
0
        return JS_NewInt32(ctx, v);
54895
0
    case JS_CLASS_INT32_ARRAY:
54896
0
        v = get_u32(ptr);
54897
0
        if (is_swap)
54898
0
            v = bswap32(v);
54899
0
        return JS_NewInt32(ctx, v);
54900
0
    case JS_CLASS_UINT32_ARRAY:
54901
0
        v = get_u32(ptr);
54902
0
        if (is_swap)
54903
0
            v = bswap32(v);
54904
0
        return JS_NewUint32(ctx, v);
54905
0
    case JS_CLASS_BIG_INT64_ARRAY:
54906
0
        {
54907
0
            uint64_t v;
54908
0
            v = get_u64(ptr);
54909
0
            if (is_swap)
54910
0
                v = bswap64(v);
54911
0
            return JS_NewBigInt64(ctx, v);
54912
0
        }
54913
0
        break;
54914
0
    case JS_CLASS_BIG_UINT64_ARRAY:
54915
0
        {
54916
0
            uint64_t v;
54917
0
            v = get_u64(ptr);
54918
0
            if (is_swap)
54919
0
                v = bswap64(v);
54920
0
            return JS_NewBigUint64(ctx, v);
54921
0
        }
54922
0
        break;
54923
0
    case JS_CLASS_FLOAT16_ARRAY:
54924
0
        {
54925
0
            uint16_t v;
54926
0
            v = get_u16(ptr);
54927
0
            if (is_swap)
54928
0
                v = bswap16(v);
54929
0
            return __JS_NewFloat64(ctx, fromfp16(v));
54930
0
        }
54931
0
    case JS_CLASS_FLOAT32_ARRAY:
54932
0
        {
54933
0
            union {
54934
0
                float f;
54935
0
                uint32_t i;
54936
0
            } u;
54937
0
            v = get_u32(ptr);
54938
0
            if (is_swap)
54939
0
                v = bswap32(v);
54940
0
            u.i = v;
54941
0
            return __JS_NewFloat64(ctx, u.f);
54942
0
        }
54943
0
    case JS_CLASS_FLOAT64_ARRAY:
54944
0
        {
54945
0
            union {
54946
0
                double f;
54947
0
                uint64_t i;
54948
0
            } u;
54949
0
            u.i = get_u64(ptr);
54950
0
            if (is_swap)
54951
0
                u.i = bswap64(u.i);
54952
0
            return __JS_NewFloat64(ctx, u.f);
54953
0
        }
54954
0
    default:
54955
0
        abort();
54956
0
    }
54957
0
}
54958
54959
static JSValue js_dataview_setValue(JSContext *ctx,
54960
                                    JSValueConst this_obj,
54961
                                    int argc, JSValueConst *argv, int class_id)
54962
0
{
54963
0
    JSTypedArray *ta;
54964
0
    JSArrayBuffer *abuf;
54965
0
    BOOL littleEndian, is_swap;
54966
0
    int size;
54967
0
    uint8_t *ptr;
54968
0
    uint64_t v64;
54969
0
    uint32_t v;
54970
0
    uint64_t pos;
54971
0
    JSValueConst val;
54972
54973
0
    ta = JS_GetOpaque2(ctx, this_obj, JS_CLASS_DATAVIEW);
54974
0
    if (!ta)
54975
0
        return JS_EXCEPTION;
54976
0
    size = 1 << typed_array_size_log2(class_id);
54977
0
    if (JS_ToIndex(ctx, &pos, argv[0]))
54978
0
        return JS_EXCEPTION;
54979
0
    val = argv[1];
54980
0
    v = 0; /* avoid warning */
54981
0
    v64 = 0; /* avoid warning */
54982
0
    if (class_id <= JS_CLASS_UINT32_ARRAY) {
54983
0
        if (JS_ToUint32(ctx, &v, val))
54984
0
            return JS_EXCEPTION;
54985
0
    } else if (class_id <= JS_CLASS_BIG_UINT64_ARRAY) {
54986
0
        if (JS_ToBigInt64(ctx, (int64_t *)&v64, val))
54987
0
            return JS_EXCEPTION;
54988
0
    } else {
54989
0
        double d;
54990
0
        if (JS_ToFloat64(ctx, &d, val))
54991
0
            return JS_EXCEPTION;
54992
0
        if (class_id == JS_CLASS_FLOAT16_ARRAY) {
54993
0
            v = tofp16(d);
54994
0
        } else if (class_id == JS_CLASS_FLOAT32_ARRAY) {
54995
0
            union {
54996
0
                float f;
54997
0
                uint32_t i;
54998
0
            } u;
54999
0
            u.f = d;
55000
0
            v = u.i;
55001
0
        } else {
55002
0
            JSFloat64Union u;
55003
0
            u.d = d;
55004
0
            v64 = u.u64;
55005
0
        }
55006
0
    }
55007
0
    littleEndian = argc > 2 && JS_ToBool(ctx, argv[2]);
55008
0
    is_swap = littleEndian ^ !is_be();
55009
0
    abuf = ta->buffer->u.array_buffer;
55010
0
    if (abuf->detached)
55011
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
55012
0
    if ((pos + size) > ta->length)
55013
0
        return JS_ThrowRangeError(ctx, "out of bound");
55014
0
    ptr = abuf->data + ta->offset + pos;
55015
55016
0
    switch(class_id) {
55017
0
    case JS_CLASS_INT8_ARRAY:
55018
0
    case JS_CLASS_UINT8_ARRAY:
55019
0
        *ptr = v;
55020
0
        break;
55021
0
    case JS_CLASS_INT16_ARRAY:
55022
0
    case JS_CLASS_UINT16_ARRAY:
55023
0
    case JS_CLASS_FLOAT16_ARRAY:
55024
0
        if (is_swap)
55025
0
            v = bswap16(v);
55026
0
        put_u16(ptr, v);
55027
0
        break;
55028
0
    case JS_CLASS_INT32_ARRAY:
55029
0
    case JS_CLASS_UINT32_ARRAY:
55030
0
    case JS_CLASS_FLOAT32_ARRAY:
55031
0
        if (is_swap)
55032
0
            v = bswap32(v);
55033
0
        put_u32(ptr, v);
55034
0
        break;
55035
0
    case JS_CLASS_BIG_INT64_ARRAY:
55036
0
    case JS_CLASS_BIG_UINT64_ARRAY:
55037
0
    case JS_CLASS_FLOAT64_ARRAY:
55038
0
        if (is_swap)
55039
0
            v64 = bswap64(v64);
55040
0
        put_u64(ptr, v64);
55041
0
        break;
55042
0
    default:
55043
0
        abort();
55044
0
    }
55045
0
    return JS_UNDEFINED;
55046
0
}
55047
55048
static const JSCFunctionListEntry js_dataview_proto_funcs[] = {
55049
    JS_CGETSET_MAGIC_DEF("buffer", js_typed_array_get_buffer, NULL, 1 ),
55050
    JS_CGETSET_MAGIC_DEF("byteLength", js_typed_array_get_byteLength, NULL, 1 ),
55051
    JS_CGETSET_MAGIC_DEF("byteOffset", js_typed_array_get_byteOffset, NULL, 1 ),
55052
    JS_CFUNC_MAGIC_DEF("getInt8", 1, js_dataview_getValue, JS_CLASS_INT8_ARRAY ),
55053
    JS_CFUNC_MAGIC_DEF("getUint8", 1, js_dataview_getValue, JS_CLASS_UINT8_ARRAY ),
55054
    JS_CFUNC_MAGIC_DEF("getInt16", 1, js_dataview_getValue, JS_CLASS_INT16_ARRAY ),
55055
    JS_CFUNC_MAGIC_DEF("getUint16", 1, js_dataview_getValue, JS_CLASS_UINT16_ARRAY ),
55056
    JS_CFUNC_MAGIC_DEF("getInt32", 1, js_dataview_getValue, JS_CLASS_INT32_ARRAY ),
55057
    JS_CFUNC_MAGIC_DEF("getUint32", 1, js_dataview_getValue, JS_CLASS_UINT32_ARRAY ),
55058
    JS_CFUNC_MAGIC_DEF("getBigInt64", 1, js_dataview_getValue, JS_CLASS_BIG_INT64_ARRAY ),
55059
    JS_CFUNC_MAGIC_DEF("getBigUint64", 1, js_dataview_getValue, JS_CLASS_BIG_UINT64_ARRAY ),
55060
    JS_CFUNC_MAGIC_DEF("getFloat16", 1, js_dataview_getValue, JS_CLASS_FLOAT16_ARRAY ),
55061
    JS_CFUNC_MAGIC_DEF("getFloat32", 1, js_dataview_getValue, JS_CLASS_FLOAT32_ARRAY ),
55062
    JS_CFUNC_MAGIC_DEF("getFloat64", 1, js_dataview_getValue, JS_CLASS_FLOAT64_ARRAY ),
55063
    JS_CFUNC_MAGIC_DEF("setInt8", 2, js_dataview_setValue, JS_CLASS_INT8_ARRAY ),
55064
    JS_CFUNC_MAGIC_DEF("setUint8", 2, js_dataview_setValue, JS_CLASS_UINT8_ARRAY ),
55065
    JS_CFUNC_MAGIC_DEF("setInt16", 2, js_dataview_setValue, JS_CLASS_INT16_ARRAY ),
55066
    JS_CFUNC_MAGIC_DEF("setUint16", 2, js_dataview_setValue, JS_CLASS_UINT16_ARRAY ),
55067
    JS_CFUNC_MAGIC_DEF("setInt32", 2, js_dataview_setValue, JS_CLASS_INT32_ARRAY ),
55068
    JS_CFUNC_MAGIC_DEF("setUint32", 2, js_dataview_setValue, JS_CLASS_UINT32_ARRAY ),
55069
    JS_CFUNC_MAGIC_DEF("setBigInt64", 2, js_dataview_setValue, JS_CLASS_BIG_INT64_ARRAY ),
55070
    JS_CFUNC_MAGIC_DEF("setBigUint64", 2, js_dataview_setValue, JS_CLASS_BIG_UINT64_ARRAY ),
55071
    JS_CFUNC_MAGIC_DEF("setFloat16", 2, js_dataview_setValue, JS_CLASS_FLOAT16_ARRAY ),
55072
    JS_CFUNC_MAGIC_DEF("setFloat32", 2, js_dataview_setValue, JS_CLASS_FLOAT32_ARRAY ),
55073
    JS_CFUNC_MAGIC_DEF("setFloat64", 2, js_dataview_setValue, JS_CLASS_FLOAT64_ARRAY ),
55074
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "DataView", JS_PROP_CONFIGURABLE ),
55075
};
55076
55077
/* Atomics */
55078
#ifdef CONFIG_ATOMICS
55079
55080
typedef enum AtomicsOpEnum {
55081
    ATOMICS_OP_ADD,
55082
    ATOMICS_OP_AND,
55083
    ATOMICS_OP_OR,
55084
    ATOMICS_OP_SUB,
55085
    ATOMICS_OP_XOR,
55086
    ATOMICS_OP_EXCHANGE,
55087
    ATOMICS_OP_COMPARE_EXCHANGE,
55088
    ATOMICS_OP_LOAD,
55089
} AtomicsOpEnum;
55090
55091
static void *js_atomics_get_ptr(JSContext *ctx,
55092
                                JSArrayBuffer **pabuf,
55093
                                int *psize_log2, JSClassID *pclass_id,
55094
                                JSValueConst obj, JSValueConst idx_val,
55095
                                int is_waitable)
55096
0
{
55097
0
    JSObject *p;
55098
0
    JSTypedArray *ta;
55099
0
    JSArrayBuffer *abuf;
55100
0
    void *ptr;
55101
0
    uint64_t idx;
55102
0
    BOOL err;
55103
0
    int size_log2;
55104
55105
0
    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
55106
0
        goto fail;
55107
0
    p = JS_VALUE_GET_OBJ(obj);
55108
0
    if (is_waitable)
55109
0
        err = (p->class_id != JS_CLASS_INT32_ARRAY &&
55110
0
               p->class_id != JS_CLASS_BIG_INT64_ARRAY);
55111
0
    else
55112
0
        err = !(p->class_id >= JS_CLASS_INT8_ARRAY &&
55113
0
                p->class_id <= JS_CLASS_BIG_UINT64_ARRAY);
55114
0
    if (err) {
55115
0
    fail:
55116
0
        JS_ThrowTypeError(ctx, "integer TypedArray expected");
55117
0
        return NULL;
55118
0
    }
55119
0
    ta = p->u.typed_array;
55120
0
    abuf = ta->buffer->u.array_buffer;
55121
0
    if (!abuf->shared) {
55122
0
        if (is_waitable == 2) {
55123
0
            JS_ThrowTypeError(ctx, "not a SharedArrayBuffer TypedArray");
55124
0
            return NULL;
55125
0
        }
55126
0
        if (abuf->detached) {
55127
0
            JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
55128
0
            return NULL;
55129
0
        }
55130
0
    }
55131
0
    if (JS_ToIndex(ctx, &idx, idx_val)) {
55132
0
        return NULL;
55133
0
    }
55134
    /* RevalidateAtomicAccess(): must test again detached after JS_ToIndex() */
55135
0
    if (abuf->detached) {
55136
0
        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
55137
0
        return NULL;
55138
0
    }
55139
    /* if the array buffer is detached, p->u.array.count = 0 */
55140
0
    if (idx >= p->u.array.count) {
55141
0
        JS_ThrowRangeError(ctx, "out-of-bound access");
55142
0
        return NULL;
55143
0
    }
55144
0
    size_log2 = typed_array_size_log2(p->class_id);
55145
0
    ptr = p->u.array.u.uint8_ptr + ((uintptr_t)idx << size_log2);
55146
0
    if (pabuf)
55147
0
        *pabuf = abuf;
55148
0
    if (psize_log2)
55149
0
        *psize_log2 = size_log2;
55150
0
    if (pclass_id)
55151
0
        *pclass_id = p->class_id;
55152
0
    return ptr;
55153
0
}
55154
55155
static JSValue js_atomics_op(JSContext *ctx,
55156
                             JSValueConst this_obj,
55157
                             int argc, JSValueConst *argv, int op)
55158
0
{
55159
0
    int size_log2;
55160
0
    uint64_t v, a, rep_val;
55161
0
    void *ptr;
55162
0
    JSValue ret;
55163
0
    JSClassID class_id;
55164
0
    JSArrayBuffer *abuf;
55165
55166
0
    ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, &class_id,
55167
0
                             argv[0], argv[1], 0);
55168
0
    if (!ptr)
55169
0
        return JS_EXCEPTION;
55170
0
    rep_val = 0;
55171
0
    if (op == ATOMICS_OP_LOAD) {
55172
0
        v = 0;
55173
0
    } else {
55174
0
        if (size_log2 == 3) {
55175
0
            int64_t v64;
55176
0
            if (JS_ToBigInt64(ctx, &v64, argv[2]))
55177
0
                return JS_EXCEPTION;
55178
0
            v = v64;
55179
0
            if (op == ATOMICS_OP_COMPARE_EXCHANGE) {
55180
0
                if (JS_ToBigInt64(ctx, &v64, argv[3]))
55181
0
                    return JS_EXCEPTION;
55182
0
                rep_val = v64;
55183
0
            }
55184
0
        } else {
55185
0
                uint32_t v32;
55186
0
                if (JS_ToUint32(ctx, &v32, argv[2]))
55187
0
                    return JS_EXCEPTION;
55188
0
                v = v32;
55189
0
                if (op == ATOMICS_OP_COMPARE_EXCHANGE) {
55190
0
                    if (JS_ToUint32(ctx, &v32, argv[3]))
55191
0
                        return JS_EXCEPTION;
55192
0
                    rep_val = v32;
55193
0
                }
55194
0
        }
55195
0
        if (abuf->detached)
55196
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
55197
0
   }
55198
55199
0
   switch(op | (size_log2 << 3)) {
55200
55201
0
#define OP(op_name, func_name)                          \
55202
0
    case ATOMICS_OP_ ## op_name | (0 << 3):             \
55203
0
       a = func_name((_Atomic(uint8_t) *)ptr, v);       \
55204
0
       break;                                           \
55205
0
    case ATOMICS_OP_ ## op_name | (1 << 3):             \
55206
0
        a = func_name((_Atomic(uint16_t) *)ptr, v);     \
55207
0
        break;                                          \
55208
0
    case ATOMICS_OP_ ## op_name | (2 << 3):             \
55209
0
        a = func_name((_Atomic(uint32_t) *)ptr, v);     \
55210
0
        break;                                          \
55211
0
    case ATOMICS_OP_ ## op_name | (3 << 3):             \
55212
0
        a = func_name((_Atomic(uint64_t) *)ptr, v);     \
55213
0
        break;
55214
55215
0
        OP(ADD, atomic_fetch_add)
55216
0
        OP(AND, atomic_fetch_and)
55217
0
        OP(OR, atomic_fetch_or)
55218
0
        OP(SUB, atomic_fetch_sub)
55219
0
        OP(XOR, atomic_fetch_xor)
55220
0
        OP(EXCHANGE, atomic_exchange)
55221
0
#undef OP
55222
55223
0
    case ATOMICS_OP_LOAD | (0 << 3):
55224
0
        a = atomic_load((_Atomic(uint8_t) *)ptr);
55225
0
        break;
55226
0
    case ATOMICS_OP_LOAD | (1 << 3):
55227
0
        a = atomic_load((_Atomic(uint16_t) *)ptr);
55228
0
        break;
55229
0
    case ATOMICS_OP_LOAD | (2 << 3):
55230
0
        a = atomic_load((_Atomic(uint32_t) *)ptr);
55231
0
        break;
55232
0
    case ATOMICS_OP_LOAD | (3 << 3):
55233
0
        a = atomic_load((_Atomic(uint64_t) *)ptr);
55234
0
        break;
55235
55236
0
    case ATOMICS_OP_COMPARE_EXCHANGE | (0 << 3):
55237
0
        {
55238
0
            uint8_t v1 = v;
55239
0
            atomic_compare_exchange_strong((_Atomic(uint8_t) *)ptr, &v1, rep_val);
55240
0
            a = v1;
55241
0
        }
55242
0
        break;
55243
0
    case ATOMICS_OP_COMPARE_EXCHANGE | (1 << 3):
55244
0
        {
55245
0
            uint16_t v1 = v;
55246
0
            atomic_compare_exchange_strong((_Atomic(uint16_t) *)ptr, &v1, rep_val);
55247
0
            a = v1;
55248
0
        }
55249
0
        break;
55250
0
    case ATOMICS_OP_COMPARE_EXCHANGE | (2 << 3):
55251
0
        {
55252
0
            uint32_t v1 = v;
55253
0
            atomic_compare_exchange_strong((_Atomic(uint32_t) *)ptr, &v1, rep_val);
55254
0
            a = v1;
55255
0
        }
55256
0
        break;
55257
0
    case ATOMICS_OP_COMPARE_EXCHANGE | (3 << 3):
55258
0
        {
55259
0
            uint64_t v1 = v;
55260
0
            atomic_compare_exchange_strong((_Atomic(uint64_t) *)ptr, &v1, rep_val);
55261
0
            a = v1;
55262
0
        }
55263
0
        break;
55264
0
    default:
55265
0
        abort();
55266
0
    }
55267
55268
0
    switch(class_id) {
55269
0
    case JS_CLASS_INT8_ARRAY:
55270
0
        a = (int8_t)a;
55271
0
        goto done;
55272
0
    case JS_CLASS_UINT8_ARRAY:
55273
0
        a = (uint8_t)a;
55274
0
        goto done;
55275
0
    case JS_CLASS_INT16_ARRAY:
55276
0
        a = (int16_t)a;
55277
0
        goto done;
55278
0
    case JS_CLASS_UINT16_ARRAY:
55279
0
        a = (uint16_t)a;
55280
0
        goto done;
55281
0
    case JS_CLASS_INT32_ARRAY:
55282
0
    done:
55283
0
        ret = JS_NewInt32(ctx, a);
55284
0
        break;
55285
0
    case JS_CLASS_UINT32_ARRAY:
55286
0
        ret = JS_NewUint32(ctx, a);
55287
0
        break;
55288
0
    case JS_CLASS_BIG_INT64_ARRAY:
55289
0
        ret = JS_NewBigInt64(ctx, a);
55290
0
        break;
55291
0
    case JS_CLASS_BIG_UINT64_ARRAY:
55292
0
        ret = JS_NewBigUint64(ctx, a);
55293
0
        break;
55294
0
    default:
55295
0
        abort();
55296
0
    }
55297
0
    return ret;
55298
0
}
55299
55300
static JSValue js_atomics_store(JSContext *ctx,
55301
                                JSValueConst this_obj,
55302
                                int argc, JSValueConst *argv)
55303
0
{
55304
0
    int size_log2;
55305
0
    void *ptr;
55306
0
    JSValue ret;
55307
0
    JSArrayBuffer *abuf;
55308
55309
0
    ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, NULL,
55310
0
                             argv[0], argv[1], 0);
55311
0
    if (!ptr)
55312
0
        return JS_EXCEPTION;
55313
0
    if (size_log2 == 3) {
55314
0
        int64_t v64;
55315
0
        ret = JS_ToBigIntFree(ctx, JS_DupValue(ctx, argv[2]));
55316
0
        if (JS_IsException(ret))
55317
0
            return ret;
55318
0
        if (JS_ToBigInt64(ctx, &v64, ret)) {
55319
0
            JS_FreeValue(ctx, ret);
55320
0
            return JS_EXCEPTION;
55321
0
        }
55322
0
        if (abuf->detached)
55323
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
55324
0
        atomic_store((_Atomic(uint64_t) *)ptr, v64);
55325
0
    } else {
55326
0
        uint32_t v;
55327
        /* XXX: spec, would be simpler to return the written value */
55328
0
        ret = JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[2]));
55329
0
        if (JS_IsException(ret))
55330
0
            return ret;
55331
0
        if (JS_ToUint32(ctx, &v, ret)) {
55332
0
            JS_FreeValue(ctx, ret);
55333
0
            return JS_EXCEPTION;
55334
0
        }
55335
0
        if (abuf->detached)
55336
0
            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
55337
0
        switch(size_log2) {
55338
0
        case 0:
55339
0
            atomic_store((_Atomic(uint8_t) *)ptr, v);
55340
0
            break;
55341
0
        case 1:
55342
0
            atomic_store((_Atomic(uint16_t) *)ptr, v);
55343
0
            break;
55344
0
        case 2:
55345
0
            atomic_store((_Atomic(uint32_t) *)ptr, v);
55346
0
            break;
55347
0
        default:
55348
0
            abort();
55349
0
        }
55350
0
    }
55351
0
    return ret;
55352
0
}
55353
55354
static JSValue js_atomics_isLockFree(JSContext *ctx,
55355
                                     JSValueConst this_obj,
55356
                                     int argc, JSValueConst *argv)
55357
0
{
55358
0
    int v, ret;
55359
0
    if (JS_ToInt32Sat(ctx, &v, argv[0]))
55360
0
        return JS_EXCEPTION;
55361
0
    ret = (v == 1 || v == 2 || v == 4 || v == 8);
55362
0
    return JS_NewBool(ctx, ret);
55363
0
}
55364
55365
typedef struct JSAtomicsWaiter {
55366
    struct list_head link;
55367
    BOOL linked;
55368
    pthread_cond_t cond;
55369
    int32_t *ptr;
55370
} JSAtomicsWaiter;
55371
55372
static pthread_mutex_t js_atomics_mutex = PTHREAD_MUTEX_INITIALIZER;
55373
static struct list_head js_atomics_waiter_list =
55374
    LIST_HEAD_INIT(js_atomics_waiter_list);
55375
55376
static JSValue js_atomics_wait(JSContext *ctx,
55377
                               JSValueConst this_obj,
55378
                               int argc, JSValueConst *argv)
55379
0
{
55380
0
    int64_t v;
55381
0
    int32_t v32;
55382
0
    void *ptr;
55383
0
    int64_t timeout;
55384
0
    struct timespec ts;
55385
0
    JSAtomicsWaiter waiter_s, *waiter;
55386
0
    int ret, size_log2, res;
55387
0
    double d;
55388
55389
0
    ptr = js_atomics_get_ptr(ctx, NULL, &size_log2, NULL,
55390
0
                             argv[0], argv[1], 2);
55391
0
    if (!ptr)
55392
0
        return JS_EXCEPTION;
55393
0
    if (size_log2 == 3) {
55394
0
        if (JS_ToBigInt64(ctx, &v, argv[2]))
55395
0
            return JS_EXCEPTION;
55396
0
    } else {
55397
0
        if (JS_ToInt32(ctx, &v32, argv[2]))
55398
0
            return JS_EXCEPTION;
55399
0
        v = v32;
55400
0
    }
55401
0
    if (JS_ToFloat64(ctx, &d, argv[3]))
55402
0
        return JS_EXCEPTION;
55403
    /* must use INT64_MAX + 1 because INT64_MAX cannot be exactly represented as a double */
55404
0
    if (isnan(d) || d >= 0x1p63)
55405
0
        timeout = INT64_MAX;
55406
0
    else if (d < 0)
55407
0
        timeout = 0;
55408
0
    else
55409
0
        timeout = (int64_t)d;
55410
0
    if (!ctx->rt->can_block)
55411
0
        return JS_ThrowTypeError(ctx, "cannot block in this thread");
55412
55413
    /* XXX: inefficient if large number of waiters, should hash on
55414
       'ptr' value */
55415
    /* XXX: use Linux futexes when available ? */
55416
0
    pthread_mutex_lock(&js_atomics_mutex);
55417
0
    if (size_log2 == 3) {
55418
0
        res = *(int64_t *)ptr != v;
55419
0
    } else {
55420
0
        res = *(int32_t *)ptr != v;
55421
0
    }
55422
0
    if (res) {
55423
0
        pthread_mutex_unlock(&js_atomics_mutex);
55424
0
        return JS_AtomToString(ctx, JS_ATOM_not_equal);
55425
0
    }
55426
55427
0
    waiter = &waiter_s;
55428
0
    waiter->ptr = ptr;
55429
0
    pthread_cond_init(&waiter->cond, NULL);
55430
0
    waiter->linked = TRUE;
55431
0
    list_add_tail(&waiter->link, &js_atomics_waiter_list);
55432
55433
0
    if (timeout == INT64_MAX) {
55434
0
        pthread_cond_wait(&waiter->cond, &js_atomics_mutex);
55435
0
        ret = 0;
55436
0
    } else {
55437
        /* XXX: use clock monotonic */
55438
0
        clock_gettime(CLOCK_REALTIME, &ts);
55439
0
        ts.tv_sec += timeout / 1000;
55440
0
        ts.tv_nsec += (timeout % 1000) * 1000000;
55441
0
        if (ts.tv_nsec >= 1000000000) {
55442
0
            ts.tv_nsec -= 1000000000;
55443
0
            ts.tv_sec++;
55444
0
        }
55445
0
        ret = pthread_cond_timedwait(&waiter->cond, &js_atomics_mutex,
55446
0
                                     &ts);
55447
0
    }
55448
0
    if (waiter->linked)
55449
0
        list_del(&waiter->link);
55450
0
    pthread_mutex_unlock(&js_atomics_mutex);
55451
0
    pthread_cond_destroy(&waiter->cond);
55452
0
    if (ret == ETIMEDOUT) {
55453
0
        return JS_AtomToString(ctx, JS_ATOM_timed_out);
55454
0
    } else {
55455
0
        return JS_AtomToString(ctx, JS_ATOM_ok);
55456
0
    }
55457
0
}
55458
55459
static JSValue js_atomics_notify(JSContext *ctx,
55460
                                 JSValueConst this_obj,
55461
                                 int argc, JSValueConst *argv)
55462
0
{
55463
0
    struct list_head *el, *el1, waiter_list;
55464
0
    int32_t count, n;
55465
0
    void *ptr;
55466
0
    JSAtomicsWaiter *waiter;
55467
0
    JSArrayBuffer *abuf;
55468
55469
0
    ptr = js_atomics_get_ptr(ctx, &abuf, NULL, NULL, argv[0], argv[1], 1);
55470
0
    if (!ptr)
55471
0
        return JS_EXCEPTION;
55472
55473
0
    if (JS_IsUndefined(argv[2])) {
55474
0
        count = INT32_MAX;
55475
0
    } else {
55476
0
        if (JS_ToInt32Clamp(ctx, &count, argv[2], 0, INT32_MAX, 0))
55477
0
            return JS_EXCEPTION;
55478
0
    }
55479
0
    if (abuf->detached)
55480
0
        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
55481
55482
0
    n = 0;
55483
0
    if (abuf->shared && count > 0) {
55484
0
        pthread_mutex_lock(&js_atomics_mutex);
55485
0
        init_list_head(&waiter_list);
55486
0
        list_for_each_safe(el, el1, &js_atomics_waiter_list) {
55487
0
            waiter = list_entry(el, JSAtomicsWaiter, link);
55488
0
            if (waiter->ptr == ptr) {
55489
0
                list_del(&waiter->link);
55490
0
                waiter->linked = FALSE;
55491
0
                list_add_tail(&waiter->link, &waiter_list);
55492
0
                n++;
55493
0
                if (n >= count)
55494
0
                    break;
55495
0
            }
55496
0
        }
55497
0
        list_for_each(el, &waiter_list) {
55498
0
            waiter = list_entry(el, JSAtomicsWaiter, link);
55499
0
            pthread_cond_signal(&waiter->cond);
55500
0
        }
55501
0
        pthread_mutex_unlock(&js_atomics_mutex);
55502
0
    }
55503
0
    return JS_NewInt32(ctx, n);
55504
0
}
55505
55506
static const JSCFunctionListEntry js_atomics_funcs[] = {
55507
    JS_CFUNC_MAGIC_DEF("add", 3, js_atomics_op, ATOMICS_OP_ADD ),
55508
    JS_CFUNC_MAGIC_DEF("and", 3, js_atomics_op, ATOMICS_OP_AND ),
55509
    JS_CFUNC_MAGIC_DEF("or", 3, js_atomics_op, ATOMICS_OP_OR ),
55510
    JS_CFUNC_MAGIC_DEF("sub", 3, js_atomics_op, ATOMICS_OP_SUB ),
55511
    JS_CFUNC_MAGIC_DEF("xor", 3, js_atomics_op, ATOMICS_OP_XOR ),
55512
    JS_CFUNC_MAGIC_DEF("exchange", 3, js_atomics_op, ATOMICS_OP_EXCHANGE ),
55513
    JS_CFUNC_MAGIC_DEF("compareExchange", 4, js_atomics_op, ATOMICS_OP_COMPARE_EXCHANGE ),
55514
    JS_CFUNC_MAGIC_DEF("load", 2, js_atomics_op, ATOMICS_OP_LOAD ),
55515
    JS_CFUNC_DEF("store", 3, js_atomics_store ),
55516
    JS_CFUNC_DEF("isLockFree", 1, js_atomics_isLockFree ),
55517
    JS_CFUNC_DEF("wait", 4, js_atomics_wait ),
55518
    JS_CFUNC_DEF("notify", 3, js_atomics_notify ),
55519
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Atomics", JS_PROP_CONFIGURABLE ),
55520
};
55521
55522
static const JSCFunctionListEntry js_atomics_obj[] = {
55523
    JS_OBJECT_DEF("Atomics", js_atomics_funcs, countof(js_atomics_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
55524
};
55525
55526
void JS_AddIntrinsicAtomics(JSContext *ctx)
55527
2
{
55528
    /* add Atomics as autoinit object */
55529
2
    JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_atomics_obj, countof(js_atomics_obj));
55530
2
}
55531
55532
#endif /* CONFIG_ATOMICS */
55533
55534
void JS_AddIntrinsicTypedArrays(JSContext *ctx)
55535
2
{
55536
2
    JSValue typed_array_base_proto, typed_array_base_func;
55537
2
    JSValueConst array_buffer_func, shared_array_buffer_func;
55538
2
    int i;
55539
55540
2
    ctx->class_proto[JS_CLASS_ARRAY_BUFFER] = JS_NewObject(ctx);
55541
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY_BUFFER],
55542
2
                               js_array_buffer_proto_funcs,
55543
2
                               countof(js_array_buffer_proto_funcs));
55544
55545
2
    array_buffer_func = JS_NewGlobalCConstructorOnly(ctx, "ArrayBuffer",
55546
2
                                                 js_array_buffer_constructor, 1,
55547
2
                                                 ctx->class_proto[JS_CLASS_ARRAY_BUFFER]);
55548
2
    JS_SetPropertyFunctionList(ctx, array_buffer_func,
55549
2
                               js_array_buffer_funcs,
55550
2
                               countof(js_array_buffer_funcs));
55551
55552
2
    ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER] = JS_NewObject(ctx);
55553
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER],
55554
2
                               js_shared_array_buffer_proto_funcs,
55555
2
                               countof(js_shared_array_buffer_proto_funcs));
55556
55557
2
    shared_array_buffer_func = JS_NewGlobalCConstructorOnly(ctx, "SharedArrayBuffer",
55558
2
                                                 js_shared_array_buffer_constructor, 1,
55559
2
                                                 ctx->class_proto[JS_CLASS_SHARED_ARRAY_BUFFER]);
55560
2
    JS_SetPropertyFunctionList(ctx, shared_array_buffer_func,
55561
2
                               js_shared_array_buffer_funcs,
55562
2
                               countof(js_shared_array_buffer_funcs));
55563
55564
2
    typed_array_base_proto = JS_NewObject(ctx);
55565
2
    JS_SetPropertyFunctionList(ctx, typed_array_base_proto,
55566
2
                               js_typed_array_base_proto_funcs,
55567
2
                               countof(js_typed_array_base_proto_funcs));
55568
55569
    /* TypedArray.prototype.toString must be the same object as Array.prototype.toString */
55570
2
    JSValue obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_toString);
55571
    /* XXX: should use alias method in JSCFunctionListEntry */ //@@@
55572
2
    JS_DefinePropertyValue(ctx, typed_array_base_proto, JS_ATOM_toString, obj,
55573
2
                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
55574
55575
2
    typed_array_base_func = JS_NewCFunction2(ctx, js_typed_array_base_constructor,
55576
2
                                             "TypedArray", 0, JS_CFUNC_constructor_or_func, 0);
55577
2
    JS_SetPropertyFunctionList(ctx, typed_array_base_func,
55578
2
                               js_typed_array_base_funcs,
55579
2
                               countof(js_typed_array_base_funcs));
55580
2
    JS_SetConstructor(ctx, typed_array_base_func, typed_array_base_proto);
55581
55582
    /* Used to squelch a -Wcast-function-type warning. */
55583
2
    JSCFunctionType ft = { .generic_magic = js_typed_array_constructor };
55584
26
    for(i = JS_CLASS_UINT8C_ARRAY; i < JS_CLASS_UINT8C_ARRAY + JS_TYPED_ARRAY_COUNT; i++) {
55585
24
        JSValue func_obj;
55586
24
        char buf[ATOM_GET_STR_BUF_SIZE];
55587
24
        const char *name;
55588
55589
24
        ctx->class_proto[i] = JS_NewObjectProto(ctx, typed_array_base_proto);
55590
24
        JS_DefinePropertyValueStr(ctx, ctx->class_proto[i],
55591
24
                                  "BYTES_PER_ELEMENT",
55592
24
                                  JS_NewInt32(ctx, 1 << typed_array_size_log2(i)),
55593
24
                                  0);
55594
24
        name = JS_AtomGetStr(ctx, buf, sizeof(buf),
55595
24
                             JS_ATOM_Uint8ClampedArray + i - JS_CLASS_UINT8C_ARRAY);
55596
24
        func_obj = JS_NewCFunction3(ctx, ft.generic,
55597
24
                                    name, 3, JS_CFUNC_constructor_magic, i,
55598
24
                                    typed_array_base_func);
55599
24
        JS_NewGlobalCConstructor2(ctx, func_obj, name, ctx->class_proto[i]);
55600
24
        JS_DefinePropertyValueStr(ctx, func_obj,
55601
24
                                  "BYTES_PER_ELEMENT",
55602
24
                                  JS_NewInt32(ctx, 1 << typed_array_size_log2(i)),
55603
24
                                  0);
55604
24
    }
55605
2
    JS_FreeValue(ctx, typed_array_base_proto);
55606
2
    JS_FreeValue(ctx, typed_array_base_func);
55607
55608
    /* DataView */
55609
2
    ctx->class_proto[JS_CLASS_DATAVIEW] = JS_NewObject(ctx);
55610
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_DATAVIEW],
55611
2
                               js_dataview_proto_funcs,
55612
2
                               countof(js_dataview_proto_funcs));
55613
2
    JS_NewGlobalCConstructorOnly(ctx, "DataView",
55614
2
                                 js_dataview_constructor, 1,
55615
2
                                 ctx->class_proto[JS_CLASS_DATAVIEW]);
55616
    /* Atomics */
55617
2
#ifdef CONFIG_ATOMICS
55618
2
    JS_AddIntrinsicAtomics(ctx);
55619
2
#endif
55620
2
}
55621
55622
/* WeakRef */
55623
55624
typedef struct JSWeakRefData {
55625
    JSWeakRefHeader weakref_header;
55626
    JSValue target;
55627
} JSWeakRefData;
55628
55629
static void js_weakref_finalizer(JSRuntime *rt, JSValue val)
55630
0
{
55631
0
    JSWeakRefData *wrd = JS_GetOpaque(val, JS_CLASS_WEAK_REF);
55632
0
    if (!wrd)
55633
0
        return;
55634
0
    js_weakref_free(rt, wrd->target);
55635
0
    list_del(&wrd->weakref_header.link);
55636
0
    js_free_rt(rt, wrd);
55637
0
}
55638
55639
static void weakref_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh)
55640
0
{
55641
0
    JSWeakRefData *wrd = container_of(wh, JSWeakRefData, weakref_header);
55642
55643
0
    if (!js_weakref_is_live(wrd->target)) {
55644
0
        js_weakref_free(rt, wrd->target);
55645
0
        wrd->target = JS_UNDEFINED;
55646
0
    }
55647
0
}
55648
55649
static JSValue js_weakref_constructor(JSContext *ctx, JSValueConst new_target,
55650
                                      int argc, JSValueConst *argv)
55651
0
{
55652
0
    JSValueConst arg;
55653
0
    JSValue obj;
55654
55655
0
    if (JS_IsUndefined(new_target))
55656
0
        return JS_ThrowTypeError(ctx, "constructor requires 'new'");
55657
0
    arg = argv[0];
55658
0
    if (!js_weakref_is_target(arg))
55659
0
        return JS_ThrowTypeError(ctx, "invalid target");
55660
0
    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_WEAK_REF);
55661
0
    if (JS_IsException(obj))
55662
0
        return JS_EXCEPTION;
55663
0
    JSWeakRefData *wrd = js_mallocz(ctx, sizeof(*wrd));
55664
0
    if (!wrd) {
55665
0
        JS_FreeValue(ctx, obj);
55666
0
        return JS_EXCEPTION;
55667
0
    }
55668
0
    wrd->target = js_weakref_new(ctx, arg);
55669
0
    wrd->weakref_header.weakref_type = JS_WEAKREF_TYPE_WEAKREF;
55670
0
    list_add_tail(&wrd->weakref_header.link, &ctx->rt->weakref_list);
55671
0
    JS_SetOpaque(obj, wrd);
55672
0
    return obj;
55673
0
}
55674
55675
static JSValue js_weakref_deref(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
55676
0
{
55677
0
    JSWeakRefData *wrd = JS_GetOpaque2(ctx, this_val, JS_CLASS_WEAK_REF);
55678
0
    if (!wrd)
55679
0
        return JS_EXCEPTION;
55680
0
    if (js_weakref_is_live(wrd->target)) 
55681
0
        return JS_DupValue(ctx, wrd->target);
55682
0
    else
55683
0
        return JS_UNDEFINED;
55684
0
}
55685
55686
static const JSCFunctionListEntry js_weakref_proto_funcs[] = {
55687
    JS_CFUNC_DEF("deref", 0, js_weakref_deref ),
55688
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "WeakRef", JS_PROP_CONFIGURABLE ),
55689
};
55690
55691
static const JSClassShortDef js_weakref_class_def[] = {
55692
    { JS_ATOM_WeakRef, js_weakref_finalizer, NULL }, /* JS_CLASS_WEAK_REF */
55693
};
55694
55695
typedef struct JSFinRecEntry {
55696
    struct list_head link;
55697
    JSValue target;
55698
    JSValue held_val;
55699
    JSValue token;
55700
} JSFinRecEntry;
55701
55702
typedef struct JSFinalizationRegistryData {
55703
    JSWeakRefHeader weakref_header;
55704
    struct list_head entries; /* list of JSFinRecEntry.link */
55705
    JSContext *realm;
55706
    JSValue cb;
55707
} JSFinalizationRegistryData;
55708
55709
static void js_finrec_finalizer(JSRuntime *rt, JSValue val)
55710
0
{
55711
0
    JSFinalizationRegistryData *frd = JS_GetOpaque(val, JS_CLASS_FINALIZATION_REGISTRY);
55712
0
    if (frd) {
55713
0
        struct list_head *el, *el1;
55714
0
        list_for_each_safe(el, el1, &frd->entries) {
55715
0
            JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link);
55716
0
            js_weakref_free(rt, fre->target);
55717
0
            js_weakref_free(rt, fre->token);
55718
0
            JS_FreeValueRT(rt, fre->held_val);
55719
0
            js_free_rt(rt, fre);
55720
0
        }
55721
0
        JS_FreeValueRT(rt, frd->cb);
55722
0
        JS_FreeContext(frd->realm);
55723
0
        list_del(&frd->weakref_header.link);
55724
0
        js_free_rt(rt, frd);
55725
0
    }
55726
0
}
55727
55728
static void js_finrec_mark(JSRuntime *rt, JSValueConst val,
55729
                           JS_MarkFunc *mark_func)
55730
0
{
55731
0
    JSFinalizationRegistryData *frd = JS_GetOpaque(val, JS_CLASS_FINALIZATION_REGISTRY);
55732
0
    struct list_head *el;
55733
0
    if (frd) {
55734
0
        list_for_each(el, &frd->entries) {
55735
0
            JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link);
55736
0
            JS_MarkValue(rt, fre->held_val, mark_func);
55737
0
        }
55738
0
        JS_MarkValue(rt, frd->cb, mark_func);
55739
0
        mark_func(rt, &frd->realm->header);
55740
0
    }
55741
0
}
55742
55743
static JSValue js_finrec_job(JSContext *ctx, int argc, JSValueConst *argv)
55744
0
{
55745
0
    return JS_Call(ctx, argv[0], JS_UNDEFINED, 1, &argv[1]);
55746
0
}
55747
55748
static void finrec_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh)
55749
0
{
55750
0
    JSFinalizationRegistryData *frd = container_of(wh, JSFinalizationRegistryData, weakref_header);
55751
0
    struct list_head *el, *el1;
55752
55753
0
    list_for_each_safe(el, el1, &frd->entries) {
55754
0
        JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link);
55755
55756
0
        if (!js_weakref_is_live(fre->token)) {
55757
0
            js_weakref_free(rt, fre->token);
55758
0
            fre->token = JS_UNDEFINED;
55759
0
        }
55760
55761
0
        if (!js_weakref_is_live(fre->target)) {
55762
0
            JSValueConst args[2];
55763
0
            args[0] = frd->cb;
55764
0
            args[1] = fre->held_val;
55765
0
            JS_EnqueueJob(frd->realm, js_finrec_job, 2, args);
55766
                
55767
0
            js_weakref_free(rt, fre->target);
55768
0
            js_weakref_free(rt, fre->token);
55769
0
            JS_FreeValueRT(rt, fre->held_val);
55770
0
            list_del(&fre->link);
55771
0
            js_free_rt(rt, fre);
55772
0
        }
55773
0
    }
55774
0
}
55775
55776
static JSValue js_finrec_constructor(JSContext *ctx, JSValueConst new_target,
55777
                                     int argc, JSValueConst *argv)
55778
0
{
55779
0
    JSValueConst cb;
55780
0
    JSValue obj;
55781
0
    JSFinalizationRegistryData *frd;
55782
    
55783
0
    if (JS_IsUndefined(new_target))
55784
0
        return JS_ThrowTypeError(ctx, "constructor requires 'new'");
55785
0
    cb = argv[0];
55786
0
    if (!JS_IsFunction(ctx, cb))
55787
0
        return JS_ThrowTypeError(ctx, "argument must be a function");
55788
55789
0
    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_FINALIZATION_REGISTRY);
55790
0
    if (JS_IsException(obj))
55791
0
        return JS_EXCEPTION;
55792
0
    frd = js_mallocz(ctx, sizeof(*frd));
55793
0
    if (!frd) {
55794
0
        JS_FreeValue(ctx, obj);
55795
0
        return JS_EXCEPTION;
55796
0
    }
55797
0
    frd->weakref_header.weakref_type = JS_WEAKREF_TYPE_FINREC;
55798
0
    list_add_tail(&frd->weakref_header.link, &ctx->rt->weakref_list);
55799
0
    init_list_head(&frd->entries);
55800
0
    frd->realm = JS_DupContext(ctx);
55801
0
    frd->cb = JS_DupValue(ctx, cb);
55802
0
    JS_SetOpaque(obj, frd);
55803
0
    return obj;
55804
0
}
55805
55806
static JSValue js_finrec_register(JSContext *ctx, JSValueConst this_val,
55807
                                  int argc, JSValueConst *argv)
55808
0
{
55809
0
    JSValueConst target, held_val, token;
55810
0
    JSFinalizationRegistryData *frd;
55811
0
    JSFinRecEntry *fre;
55812
55813
0
    frd = JS_GetOpaque2(ctx, this_val, JS_CLASS_FINALIZATION_REGISTRY);
55814
0
    if (!frd)
55815
0
        return JS_EXCEPTION;
55816
0
    target = argv[0];
55817
0
    held_val = argv[1];
55818
0
    token = argc > 2 ? argv[2] : JS_UNDEFINED;
55819
55820
0
    if (!js_weakref_is_target(target))
55821
0
        return JS_ThrowTypeError(ctx, "invalid target");
55822
0
    if (js_same_value(ctx, target, held_val))
55823
0
        return JS_ThrowTypeError(ctx, "held value cannot be the target");
55824
0
    if (!JS_IsUndefined(token) && !js_weakref_is_target(token))
55825
0
        return JS_ThrowTypeError(ctx, "invalid unregister token");
55826
0
    fre = js_malloc(ctx, sizeof(*fre));
55827
0
    if (!fre)
55828
0
        return JS_EXCEPTION;
55829
0
    fre->target = js_weakref_new(ctx, target);
55830
0
    fre->held_val = JS_DupValue(ctx, held_val);
55831
0
    fre->token = js_weakref_new(ctx, token);
55832
0
    list_add_tail(&fre->link, &frd->entries);
55833
0
    return JS_UNDEFINED;
55834
0
}
55835
55836
static JSValue js_finrec_unregister(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
55837
0
{
55838
0
    JSFinalizationRegistryData *frd = JS_GetOpaque2(ctx, this_val, JS_CLASS_FINALIZATION_REGISTRY);
55839
0
    JSValueConst token;
55840
0
    BOOL removed;
55841
0
    struct list_head *el, *el1;
55842
55843
0
    if (!frd)
55844
0
        return JS_EXCEPTION;
55845
0
    token = argv[0];
55846
0
    if (!js_weakref_is_target(token))
55847
0
        return JS_ThrowTypeError(ctx, "invalid unregister token");
55848
55849
0
    removed = FALSE;
55850
0
    list_for_each_safe(el, el1, &frd->entries) {
55851
0
        JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link);
55852
0
        if (js_weakref_is_live(fre->token) && js_same_value(ctx, fre->token, token)) {
55853
0
            js_weakref_free(ctx->rt, fre->target);
55854
0
            js_weakref_free(ctx->rt, fre->token);
55855
0
            JS_FreeValue(ctx, fre->held_val);
55856
0
            list_del(&fre->link);
55857
0
            js_free(ctx, fre);
55858
0
            removed = TRUE;
55859
0
        }
55860
0
    }
55861
0
    return JS_NewBool(ctx, removed);
55862
0
}
55863
55864
static const JSCFunctionListEntry js_finrec_proto_funcs[] = {
55865
    JS_CFUNC_DEF("register", 2, js_finrec_register ),
55866
    JS_CFUNC_DEF("unregister", 1, js_finrec_unregister ),
55867
    JS_PROP_STRING_DEF("[Symbol.toStringTag]", "FinalizationRegistry", JS_PROP_CONFIGURABLE ),
55868
};
55869
55870
static const JSClassShortDef js_finrec_class_def[] = {
55871
    { JS_ATOM_FinalizationRegistry, js_finrec_finalizer, js_finrec_mark }, /* JS_CLASS_FINALIZATION_REGISTRY */
55872
};
55873
55874
void JS_AddIntrinsicWeakRef(JSContext *ctx)
55875
2
{
55876
2
    JSRuntime *rt = ctx->rt;
55877
55878
    /* WeakRef */
55879
2
    if (!JS_IsRegisteredClass(rt, JS_CLASS_WEAK_REF)) {
55880
2
        init_class_range(rt, js_weakref_class_def, JS_CLASS_WEAK_REF,
55881
2
                         countof(js_weakref_class_def));
55882
2
    }
55883
2
    ctx->class_proto[JS_CLASS_WEAK_REF] = JS_NewObject(ctx);
55884
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_WEAK_REF],
55885
2
                               js_weakref_proto_funcs,
55886
2
                               countof(js_weakref_proto_funcs));
55887
2
    JS_NewGlobalCConstructor(ctx, "WeakRef", js_weakref_constructor, 1, ctx->class_proto[JS_CLASS_WEAK_REF]);
55888
55889
    /* FinalizationRegistry */
55890
2
    if (!JS_IsRegisteredClass(rt, JS_CLASS_FINALIZATION_REGISTRY)) {
55891
2
        init_class_range(rt, js_finrec_class_def, JS_CLASS_FINALIZATION_REGISTRY,
55892
2
                         countof(js_finrec_class_def));
55893
2
    }
55894
2
    ctx->class_proto[JS_CLASS_FINALIZATION_REGISTRY] = JS_NewObject(ctx);
55895
2
    JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_FINALIZATION_REGISTRY],
55896
2
                               js_finrec_proto_funcs,
55897
2
                               countof(js_finrec_proto_funcs));
55898
2
    JS_NewGlobalCConstructor(ctx, "FinalizationRegistry", js_finrec_constructor, 1, ctx->class_proto[JS_CLASS_FINALIZATION_REGISTRY]);
55899
2
}